/**
 * Autocompleter
 *
 * http://digitarald.de/project/autocompleter/
 *
 * @version		1.1.2
 *
 * @license		MIT-style license
 * @author		Harald Kirschner <mail [at] digitarald.de>
 * @copyright	Author
 */

var Autocompleter = new Class({

	Implements: [Options, Events],

	options: {/*
		onOver: $empty,
		onSelect: $empty,
		onSelection: $empty,
		onShow: $empty,
		onHide: $empty,
		onBlur: $empty,
		onFocus: $empty,*/
		minLength: 1,
		markQuery: true,
		width: 'inherit',
		maxChoices: 10,
		injectChoice: null,
		customChoices: null,
		emptyChoices: null,
		visibleChoices: true,
		className: 'autocompleter-choices',
		zIndex: 242,
		delay: 40,
		observerOptions: {},
		fxOptions: {},

		autoSubmit: false,
		overflow: true,
		overflowMargin: 25,
		selectFirst: true,
		filter: null,
		filterCase: false,
		filterSubset: false,
		forceSelect: true,
		selectMode: false,
		choicesMatch: null,

		multiple: false,
		separator: ', ',
		separatorSplit: /\s*[,;]\s*/,
		autoTrim: false,
		allowDupes: false,

		cache: true,
		relative: false,
		typeAhead: true,
		target: null,
		mOver: false
	},

	initialize: function(element, options) {
		this.element = $(element);
		this.setOptions(options);
		if(this.options.target) {
			this.options.target = $(this.options.target);
		} else {
			this.options.target = this.element;
		}
		this.build();
		this.observer = new Observer(this.element, this.prefetch.bind(this), $merge({
			'delay': this.options.delay
		}, this.options.observerOptions));
		this.queryValue = null;
		if (this.options.filter) this.filter = this.options.filter.bind(this);
		var mode = this.options.selectMode;
		this.typeAhead = (mode == 'type-ahead');
		this.selectMode = (mode === true) ? 'selection' : mode;
		this.cached = [];
	},

	/**
	 * build - Initialize DOM
	 *
	 * Builds the html structure for choices and appends the events to the element.
	 * Override this function to modify the html generation.
	 */
	build: function() {
		if ($(this.options.customChoices)) {
			this.choices = this.options.customChoices;
		} else {
			this.choices = new Element('ul', {
				'class': this.options.className,
				'styles': {					
					'zIndex': this.options.zIndex
				}
			}).inject(document.body);
			this.choices.addEvent('mousedown', function(){
			    this.mOver = true;
			});
			this.relative = false;
			if (this.options.relative) {
				this.choices.inject(this.element, 'after');
				this.relative = this.element.getOffsetParent();
			}
			this.fix = new OverlayFix(this.choices);
		}
		if (!this.options.separator.test(this.options.separatorSplit)) {
			this.options.separatorSplit = this.options.separator;
		}
		this.fx = (!this.options.fxOptions) ? null : new Fx.Tween(this.choices, $merge({
			'property': 'opacity',
			'link': 'cancel',
			'duration': 200
		}, this.options.fxOptions)).addEvent('onStart', Chain.prototype.clearChain).set(0);
		this.element.setProperty('autocomplete', 'off')
			.addEvent((Browser.Engine.trident || Browser.Engine.webkit) ? 'keydown' : 'keypress', this.onCommand.bind(this))
			.addEvent('click', this.onCommand.bind(this, [false]))
			.addEvent('focus', this.foo = this.toggleFocus.create({bind: this, arguments: true, delay: 100}))
			.addEvent('blur', this.foo = this.toggleFocus.create({bind: this, arguments: false, delay: 500}));		
	},

	destroy: function() {
		if (this.fix) this.fix.destroy();
		this.choices = this.selected = this.choices.destroy();
	},

	toggleFocus: function(state) {
		this.focussed = state;
		if (!state) this.hideChoices(true);
		this.fireEvent((state) ? 'onFocus' : 'onBlur', [this.element]);
	},

	onCommand: function(e) {
		if (!e && this.focussed) {
			return this.prefetch();
		}
		if (e && e.key && !e.shift) {
			switch (e.code) {
				case Event.Keys.enter:
				case Event.Keys.tab:
				case Event.Keys.space:
					if(this.options.target.id == 'tags') {
						if (this.element.value != this.opted) return true;
						if (this.selected && this.visible) {
							this.choiceSelect(this.selected);
							return !!(this.options.autoSubmit);
						}
					}
					else {						
						if(e.code == Event.Keys.enter) {	
							document.location = this.selected.getElement('a').getProperty('href');
							return false;
						}
					}
					break;
				case Event.Keys.up:
				case Event.Keys.down:
					if (!this.prefetch() && this.queryValue !== null) {
						var up = (e.key == 'up');
						this.choiceOver((this.selected || this.choices)[
							(this.selected) ? ((up) ? 'getPrevious' : 'getNext') : ((up) ? 'getLast' : 'getFirst')
						](this.options.choicesMatch), true);
					}
					return false;
				case Event.Keys.escape:
					this.hideChoices(true);
					break;
			}
		}
		return true;
	},

	setSelection: function(finish) {
		var input = this.selected.inputValue, value = input;
		var start = this.queryValue.length, end = input.length;
		if (input.substr(0, start).toLowerCase() != this.queryValue.toLowerCase()) start = 0;
		if (this.options.multiple) {
			var split = this.options.separatorSplit;
			value = this.element.value;
			start += this.queryIndex;
			end += this.queryIndex;
			var old = value.substr(this.queryIndex).split(split, 1)[0];
			value = value.substr(0, this.queryIndex) + input + value.substr(this.queryIndex + old.length);
			if (finish) {
				var tokens = value.split(this.options.separatorSplit).filter(function(entry) {
					return this.test(entry);
				}, /[^\s,]+/);
				if (!this.options.allowDupes) tokens = [].combine(tokens);
				var sep = this.options.separator;
				value = tokens.join(sep) + sep;
				end = value.length;
			}
		}
		this.observer.setValue(value);
		this.opted = value;
		if (finish || this.selectMode == 'pick') start = end;
		this.element.selectRange(start, end);
		this.element.fireEvent('selection', [this.element, this.selected, value, input]);
	},

	showChoices: function() {
		var match = this.options.choicesMatch, first = this.choices.getFirst(match);
		this.selected = this.selectedValue = null;
		if (this.fix) {
			var pos = this.options.target.getCoordinates();
			this.choices.setStyles({
				'left': pos.left,
				'top': pos.bottom + 1,
				'width': pos.width - 2
			});
		}
		if (!first) return;
		if (!this.visible) {
			this.visible = true;
			this.choices.setStyle('display', '');
			if (this.fx) this.fx.start(1);
			this.fireEvent('onShow', [this.element, this.choices]);
		}
		if (this.options.selectFirst || this.typeAhead || first.inputValue == this.queryValue) this.choiceOver(first, this.typeAhead);
		var items = this.choices.getChildren(match), max = this.options.maxChoices;
		var styles = {'overflowY': 'hidden', 'height': ''};
		this.overflown = false;
		if (items.length > max) {
			var item = items[max - 1];
			styles.overflowY = 'scroll';
			styles.height = item.getCoordinates(this.choices).bottom;
			this.overflown = true;
		};
		this.choices.setStyles(styles);
		this.fix.show();
		if (this.options.visibleChoices) {
			var scroll = document.getScroll(),
			size = document.getSize(),
			coords = this.choices.getCoordinates();
			if (coords.right > scroll.x + size.x) scroll.x = coords.right - size.x;
			if (coords.bottom > scroll.y + size.y) scroll.y = coords.bottom - size.y;
			window.scrollTo(Math.min(scroll.x, coords.left), Math.min(scroll.y, coords.top));
		}
	},
	
	hideAllowed: function() {
		// zum überschreiben		
		return true;
	},

	hideChoices: function(clear) {
		if(this.hideAllowed()) {						
			if (clear) {
				var value = this.element.value;
				if (this.options.forceSelect) value = this.opted;
				if (this.options.autoTrim) {
					value = value.split(this.options.separatorSplit).filter($arguments(0)).join(this.options.separator);
				}
				// this.observer.setValue(value);
			}
			if (!this.visible) return;
			this.visible = false;
			if (this.selected) this.selected.removeClass('autocompleter-selected');
			this.observer.clear();
			var hide = function(){
				this.choices.setStyle('display', 'none');
				this.fix.hide();
			}.bind(this);
			if (this.fx) this.fx.start(0).chain(hide);
			else hide();
			this.fireEvent('onHide', [this.element, this.choices]);			
		}
	},

	prefetch: function() {
		var value = this.element.value, query = value;
		if (this.options.multiple) {
			var split = this.options.separatorSplit;
			var values = value.split(split);
			var index = this.element.getSelectedRange().start;
			var toIndex = value.substr(0, index).split(split);
			var last = toIndex.length - 1;
			index -= toIndex[last].length;
			query = values[last];
		}
		if (query.length < this.options.minLength) {
			this.hideChoices();
		} else {
			if (query === this.queryValue || (this.visible && query == this.selectedValue)) {
				if (this.visible) return false;
				this.showChoices();
			} else {
				this.queryValue = query;
				this.queryIndex = index;
				if (!this.fetchCached()) this.query();
			}
		}
		return true;
	},

	fetchCached: function() {
		return false;
		if (!this.options.cache
			|| !this.cached
			|| !this.cached.length
			|| this.cached.length >= this.options.maxChoices
			|| this.queryValue) return false;
		this.update(this.filter(this.cached));
		return true;
	},

	update: function(tokens) {
		this.choices.empty();
		this.cached = tokens;
		var type = tokens && $type(tokens);
		if (!type || (type == 'array' && !tokens.length) || (type == 'hash' && !tokens.getLength())) {
			if(this.element.id == 'top-search') {
				this.update(['Drücke Enter für Suchergebnisse der erweiterten Suche']);
			}
			else {
				this.update(['Es wurden keine passende Einträge gefunden']);
			}
		/* (this.options.emptyChoices || this.hideChoices).call(this); */
		} else {
			if (this.options.maxChoices < tokens.length && !this.options.overflow) tokens.length = this.options.maxChoices;
			tokens.each(this.options.injectChoice || function(token){
				var choice = new Element('li', {'html': this.markQueryValue(token)});
				choice.inputValue = token;
				this.addChoiceEvents(choice).inject(this.choices);
			}, this);
			this.showChoices();
		}
	},

	choiceOver: function(choice, selection) {
		if (!choice || choice == this.selected) return;
		if (this.selected) this.selected.removeClass('autocompleter-selected');
		this.selected = choice.addClass('autocompleter-selected');
		this.fireEvent('onSelect', [this.element, this.selected, selection]);
		if (!this.selectMode) this.opted = this.element.value;
		if (!selection) return;
		this.selectedValue = this.selected.inputValue;
		if (this.overflown) {
			var coords = this.selected.getCoordinates(this.choices), margin = this.options.overflowMargin,
				top = this.choices.scrollTop, height = this.choices.offsetHeight, bottom = top + height;
			if (coords.top - margin < top && top) this.choices.scrollTop = Math.max(coords.top - margin, 0);
			else if (coords.bottom + margin > bottom) this.choices.scrollTop = Math.min(coords.bottom - height + margin, bottom);
		}
		if (this.selectMode) this.setSelection();
	},

	choiceSelect: function(choice) {
		if (choice) this.choiceOver(choice);
		this.setSelection(true);
		this.queryValue = false;
		this.hideChoices();
		// Hinzugefügt
		this.element.fireEvent('choiceSelect', this.selected.inputValue);
	},

	filter: function(tokens) {
		return (tokens || this.tokens).filter(function(token) {
			return this.test(token);
		}, new RegExp(((this.options.filterSubset) ? '' : '^') + this.queryValue.escapeRegExp(), (this.options.filterCase) ? '' : 'i'));
	},

	/**
	 * markQueryValue
	 *
	 * Marks the queried word in the given string with <span class="autocompleter-queried">*</span>
	 * Call this i.e. from your custom parseChoices, same for addChoiceEvents
	 *
	 * @param		{String} Text
	 * @return		{String} Text
	 */
	markQueryValue: function(str) {
		return (!this.options.markQuery || !this.queryValue) ? str
			: str.replace(new RegExp('(' + ((this.options.filterSubset) ? '' : '^') + this.queryValue.escapeRegExp() + ')', (this.options.filterCase) ? '' : 'i'), '<span class="autocompleter-queried">$1</span>');
	},

	/**
	 * addChoiceEvents
	 *
	 * Appends the needed event handlers for a choice-entry to the given element.
	 *
	 * @param		{Element} Choice entry
	 * @return		{Element} Choice entry
	 */
	addChoiceEvents: function(el) {
		return el.addEvents({
			'mouseover': this.choiceOver.bind(this, [el]),
			'click': this.choiceSelect.bind(this, [el])
		});
	}
});

var OverlayFix = new Class({

	initialize: function(el) {
		if (Browser.Engine.trident) {
			this.element = $(el);
			this.relative = this.element.getOffsetParent();
			this.fix = new Element('iframe', {
				'frameborder': '0',
				'scrolling': 'no',
				'src': 'javascript:false;',
				'styles': {
					'position': 'absolute',
					'border': 'none',
					'display': 'none',
					'filter': 'progid:DXImageTransform.Microsoft.Alpha(opacity=0)'
				}
			}).inject(this.element, 'after');
		}
	},

	show: function() {
		if (this.fix) {
			var coords = this.element.getCoordinates(this.relative);
			delete coords.right;
			delete coords.bottom;
			this.fix.setStyles($extend(coords, {
				'display': '',
				'zIndex': (this.element.getStyle('zIndex') || 1) - 1
			}));
		}
		return this;
	},

	hide: function() {
		if (this.fix) this.fix.setStyle('display', 'none');
		return this;
	},

	destroy: function() {
		if (this.fix) this.fix = this.fix.destroy();
	}

});

Element.implement({

	getSelectedRange: function() {
		if (!Browser.Engine.trident) return {start: this.selectionStart, end: this.selectionEnd};
		var pos = {start: 0, end: 0};
		var range = this.getDocument().selection.createRange();
		if (!range || range.parentElement() != this) return pos;
		var dup = range.duplicate();
		if (this.type == 'text') {
			pos.start = 0 - dup.moveStart('character', -100000);
			pos.end = pos.start + range.text.length;
		} else {
			var value = this.value;
			var offset = value.length - value.match(/[\n\r]*$/)[0].length;
			dup.moveToElementText(this);
			dup.setEndPoint('StartToEnd', range);
			pos.end = offset - dup.text.length;
			dup.setEndPoint('StartToStart', range);
			pos.start = offset - dup.text.length;
		}
		return pos;
	},

	selectRange: function(start, end) {
		if (Browser.Engine.trident) {
			var diff = this.value.substr(start, end - start).replace(/\r/g, '').length;
			start = this.value.substr(0, start).replace(/\r/g, '').length;
			var range = this.createTextRange();
			range.collapse(true);
			range.moveEnd('character', start + diff);
			range.moveStart('character', start);
			range.select();
		} else {
			this.focus();
			this.setSelectionRange(start, end);
		}
		return this;
	}

});





/**
 * Observer - Observe formelements for changes
 *
 * - Additional code from clientside.cnet.com
 *
 * @version		1.1
 *
 * @license		MIT-style license
 * @author		Harald Kirschner <mail [at] digitarald.de>
 * @copyright	Author
 */
var Observer = new Class({

	Implements: [Options, Events],

	options: {
		periodical: false,
		delay: 1000
	},

	initialize: function(el, onFired, options){
		this.element = $(el) || $$(el);
		this.addEvent('onFired', onFired);
		this.setOptions(options);
		this.bound = this.changed.bind(this);
		this.resume();
	},

	changed: function() {
		var value = this.element.get('value');
		if ($equals(this.value, value)) return;
		this.clear();
		this.value = value;
		this.timeout = this.onFired.delay(this.options.delay, this);
	},

	setValue: function(value) {
		this.value = value;
		this.element.set('value', value);
		return this.clear();
	},

	onFired: function() {
		this.fireEvent('onFired', [this.value, this.element]);
	},

	clear: function() {
		$clear(this.timeout || null);
		return this;
	},

	pause: function(){
		if (this.timer) $clear(this.timer);
		else this.element.removeEvent('keyup', this.bound);
		return this.clear();
	},

	resume: function(){
		this.value = this.element.get('value');
		if (this.options.periodical) this.timer = this.changed.periodical(this.options.periodical, this);
		else this.element.addEvent('keyup', this.bound);
		return this;
	}

});

var $equals = function(obj1, obj2) {
	return (obj1 == obj2 || JSON.encode(obj1) == JSON.encode(obj2));
};

/*
// Gears init
(function() {
  // We are already defined. Hooray!
  if (window.google && google.gears) {
    return;
  }

  var factory = null;

  // Firefox
  if (typeof GearsFactory != 'undefined') {
    factory = new GearsFactory();
  } else {
    // IE
    try {
      factory = new ActiveXObject('Gears.Factory');
      // privateSetGlobalObject is only required and supported on WinCE.
      if (factory.getBuildInfo().indexOf('ie_mobile') != -1) {
        factory.privateSetGlobalObject(this);
      }
    } catch (e) {
      // Safari
      if ((typeof navigator.mimeTypes != 'undefined')
           && navigator.mimeTypes["application/x-googlegears"]) {
        factory = document.createElement("object");
        factory.style.display = "none";
        factory.width = 0;
        factory.height = 0;
        factory.type = "application/x-googlegears";
        document.documentElement.appendChild(factory);
      }
    }
  }

  // *Do not* define any objects if Gears is not installed. This mimics the
  // behavior of Gears defining the objects in the future.
  if (!factory) {
    return;
  }

  // Now set up the objects, being careful not to overwrite anything.
  //
  // Note: In Internet Explorer for Windows Mobile, you can't add properties to
  // the window object. However, global objects are automatically added as
  // properties of the window object in all browsers.
  if (!window.google) {
    google = {};
  }

  if (!google.gears) {
    google.gears = {factory: factory};
  }
})();
*/

Autocompleter.Suggest = new Class({
	
	Extends: Autocompleter,
	db: false,	
	request: false,
	user: false,
	wpool: false,
	wdb: false,
	redirect: false,
	mOver: false,
	e: false,
	mouseX: 0,

	initialize: function(user, el, autocomplete_el, multiple, use_gears, target, url, redirect) {
		this.user = user;
		this.redirect = redirect;
		if(url == null) {
			url = '/freunde/autocomplete/';
		}
		this.request = new Request.JSON({
			'method': 'get',
			'url': url,
			'onComplete': this.queryResponse.bind(this)
		});
		
		var options = {
			injectChoice: this.injectChoice,			
			overflow: true,
			fxOptions: null,
			delay: 600,
			minLength: 1,
			target: target
		}
		if (multiple) {
			//options.selectMode = 'type-ahead';
			options.multiple = true;
		}
		if (use_gears && this.prepare_gears()) {
			options.cache = false;
			options.delay = 0;
			options.minLength = 1;
		}
		if (el != autocomplete_el) {
			options.customChoices = new Element('ul', {
				'class': this.options.className,
				'styles': {
					'zIndex': this.options.zIndex
				}
			}).inject(document.body);			
			if (this.options.relative) {
				options.customChoices.inject($(autocomplete_el), 'after');
				this.relative = $(autocomplete_el).getOffsetParent();
			}
			this.fix = new OverlayFix(options.customChoices);
			options.customChoices.addEvent('mouseenter', function(e){
			    this.mOver = true;			    
			});
			options.customChoices.addEvent('mousedown', function(e){			    
				this.mOver = true;			   
			});
			options.customChoices.addEvent('mouseleave', function(e){
				this.mOver = false;		   
			});
		}
		
		this.parent(el, options);		
	},	
	
	prepare_gears: function() {
		if (!window.google || !google.gears) return false;
		if (!google.gears.factory.hasPermission && !google.gears.factory.getPermission('Eraffe.de - Dein Lifestyleportal', 'http://www.eraffe.de/apple-touch-icon.png', 'Google Gears erhöht die Performance der Autovervollständigung und erweitert den Funktionsumfang von eraffe.')) {
			return false;
		}

		this.db = google.gears.factory.create('beta.database');
		this.db.open('lookups_' + this.user);
//this.db.execute('drop table friends'); console.info('drop table friends');
		this.db.execute('create table if not exists friends (nickname text unique, surname text, forename text, avatar text, birthday int, gender int, gendericon text)');
		
		this.wpool = google.gears.factory.create('beta.workerpool');
		this.wpool.onmessage = function(a, b, message) {
			//alert('Received message from worker ' + message.sender + ': \n' + message.body);
			if (message.text == 'finished') {
				$('autocomplete-friends').highlight();
			}
		};	
		
		var worker_script = 'google.gears.workerPool.onmessage = ' + String(function() {
			var data = message.body.data;
			var user = message.body.user;
			var db = google.gears.factory.create('beta.database');
			db.open('lookups_' + user);
			
			for (var i = 0; i < data.length; i++) {
				var d = data[i];
				db.execute('insert or ignore into friends values (?, ?, ?, ?, ?, ?, ?)', [d.nn, d.sn, d.fn, d.a, d.b, d.g, d.gi]);
			}
			wp.sendMessage('finished', message.sender);		
		});
		this.wdb = this.wpool.createWorker(worker_script);
		
		return true;
	},
	
	query: function(){
		var results = new Array();		
		if (this.db) {
			var rs = this.db.execute('select * from friends where nickname like ?', [ this.queryValue + '%' ]);			
			while (rs.isValidRow()) {
				results.push({
					'nn': rs.fieldByName('nickname'),
					'fn': rs.fieldByName('forename'),
					'sn': rs.fieldByName('surname'),
					'a': rs.fieldByName('avatar'),
					'b': rs.fieldByName('birthday'),
					'g': rs.fieldByName('gender'),
					'gi': rs.fieldByName('gendericon'),
					'l': rs.fieldByName('link')
				});
				rs.next();
			}			
		}		
		if (results.length == 0) {
			this.update(['Einträge werden geladen...']);
			this.request.send('lookup='+this.queryValue);
		}
		else {
			this.update(results);
		}
	},
	
	filter: function(tokens) {
		return (tokens || this.tokens).filter(function(token) {
			return this.test(token.nn);
		}, new RegExp(((this.options.filterSubset) ? '' : '^') + this.queryValue.escapeRegExp(), (this.options.filterCase) ? '' : 'i'));
	},

	queryResponse: function(response) {
		if ($type(response) != 'array') {
			//alert('Falscher Datentyp!');
			return false;
		}
		//this.update(this.filter(response)); wofür soll das gut sein wenn eh nach nickname geschaut wird
		this.update(response);
		if (this.db && this.wpool) {
			this.wpool.sendMessage({ 'data': response, 'user': this.user }, this.wdb);
		}		
	},	
	
	hideAllowed: function() {
		return !this.mOver;
	},
	
	injectChoice: function(token) {		
		var choice = new Element('li');
		
		if ($type(token) == 'string') {
			choice.appendText(token);
			choice.inputValue = '';
		}
		else {
			choice.appendChild(new Element('img', {
				'src': token.a,
				'alt': token.nn,
				'styles': {
					'float': 'left',
					'margin-top': '4px',
					'margin-right': '4px',
					'width': '25px',
					'height': '27px',
					'clear': 'left',
					'overflow': 'hidden'
				}
			}));
			var span = new Element('span', {
				'html': this.markQueryValue(token.nn)
			});
			choice.appendChild(span);
			span.appendText(' (' + token.b + ') ');
			if(token.gi) {
				span.appendChild(new Element('img', {
					'src': token.gi,
					'alt': '',
					'styles': {
						'margin-top': '4px'
					}
				}));
			}
			span.appendChild(new Element('a', {
				'href': token.l,			
				'styles': {
					'display': 'none'
				}
			}));
			span.appendChild(new Element('br'));
			span.appendText(token.fn + ' ' + token.sn);
			if(this.redirect) {
				span.parentNode.addEvent('click', function(){
				    document.location = token.l;
				});
			}
			if(token.ln != null) {
				choice.inputValue = token.ln;
			}
			else {
				choice.inputValue = token.nn;
			}
		}
		if(token.lt == 'user' || token.lt == 'group' || token.lt == 'place') {
			if(token.lt == 'user') { html = 'Mitglieder' };
			if(token.lt == 'group') { html = 'Gruppen' };
			if(token.lt == 'place') { html = 'Treffpunkte' };
			this.choices.appendChild(new Element('li', {
				'html': html,
				'styles': {
					'color': 'gray',
					'padding': '8px'
				}
			}));
		}
		this.addChoiceEvents(choice).inject(this.choices);		
	}	
});


var gears_db = false;
window.addEvent('domready', function () {
	if (typeof user != 'undefined') {
		var user_elem = $('autocomplete-friends');
		if (user_elem) {
			new Autocompleter.Suggest(user, user_elem, user_elem, false, false);
		}
		var user_elem_multiple = $('autocomplete-friends-multiple');
		if (user_elem_multiple) {
			new Autocompleter.Suggest(user, user_elem_multiple, user_elem_multiple, true, false);
		}
	}
});
