forked from GNUsocial/gnu-social
		
	
		
			
	
	
		
			759 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			759 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 * Autocomplete - jQuery plugin 1.0.2
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * Copyright (c) 2007 Dylan Verheul, Dan G. Switzer, Anjesh Tuladhar, Jörn Zaefferer
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * Dual licensed under the MIT and GPL licenses:
							 | 
						||
| 
								 | 
							
								 *   http://www.opensource.org/licenses/mit-license.php
							 | 
						||
| 
								 | 
							
								 *   http://www.gnu.org/licenses/gpl.html
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * Revision: $Id: jquery.autocomplete.js 5747 2008-06-25 18:30:55Z joern.zaefferer $
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								;(function($) {
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
								$.fn.extend({
							 | 
						||
| 
								 | 
							
									autocomplete: function(urlOrData, options) {
							 | 
						||
| 
								 | 
							
										var isUrl = typeof urlOrData == "string";
							 | 
						||
| 
								 | 
							
										options = $.extend({}, $.Autocompleter.defaults, {
							 | 
						||
| 
								 | 
							
											url: isUrl ? urlOrData : null,
							 | 
						||
| 
								 | 
							
											data: isUrl ? null : urlOrData,
							 | 
						||
| 
								 | 
							
											delay: isUrl ? $.Autocompleter.defaults.delay : 10,
							 | 
						||
| 
								 | 
							
											max: options && !options.scroll ? 10 : 150
							 | 
						||
| 
								 | 
							
										}, options);
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										// if highlight is set to false, replace it with a do-nothing function
							 | 
						||
| 
								 | 
							
										options.highlight = options.highlight || function(value) { return value; };
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										// if the formatMatch option is not specified, then use formatItem for backwards compatibility
							 | 
						||
| 
								 | 
							
										options.formatMatch = options.formatMatch || options.formatItem;
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										return this.each(function() {
							 | 
						||
| 
								 | 
							
											new $.Autocompleter(this, options);
							 | 
						||
| 
								 | 
							
										});
							 | 
						||
| 
								 | 
							
									},
							 | 
						||
| 
								 | 
							
									result: function(handler) {
							 | 
						||
| 
								 | 
							
										return this.bind("result", handler);
							 | 
						||
| 
								 | 
							
									},
							 | 
						||
| 
								 | 
							
									search: function(handler) {
							 | 
						||
| 
								 | 
							
										return this.trigger("search", [handler]);
							 | 
						||
| 
								 | 
							
									},
							 | 
						||
| 
								 | 
							
									flushCache: function() {
							 | 
						||
| 
								 | 
							
										return this.trigger("flushCache");
							 | 
						||
| 
								 | 
							
									},
							 | 
						||
| 
								 | 
							
									setOptions: function(options){
							 | 
						||
| 
								 | 
							
										return this.trigger("setOptions", [options]);
							 | 
						||
| 
								 | 
							
									},
							 | 
						||
| 
								 | 
							
									unautocomplete: function() {
							 | 
						||
| 
								 | 
							
										return this.trigger("unautocomplete");
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								$.Autocompleter = function(input, options) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									var KEY = {
							 | 
						||
| 
								 | 
							
										UP: 38,
							 | 
						||
| 
								 | 
							
										DOWN: 40,
							 | 
						||
| 
								 | 
							
										DEL: 46,
							 | 
						||
| 
								 | 
							
										TAB: 9,
							 | 
						||
| 
								 | 
							
										RETURN: 13,
							 | 
						||
| 
								 | 
							
										ESC: 27,
							 | 
						||
| 
								 | 
							
										COMMA: 188,
							 | 
						||
| 
								 | 
							
										PAGEUP: 33,
							 | 
						||
| 
								 | 
							
										PAGEDOWN: 34,
							 | 
						||
| 
								 | 
							
										BACKSPACE: 8
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Create $ object for input element
							 | 
						||
| 
								 | 
							
									var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									var timeout;
							 | 
						||
| 
								 | 
							
									var previousValue = "";
							 | 
						||
| 
								 | 
							
									var cache = $.Autocompleter.Cache(options);
							 | 
						||
| 
								 | 
							
									var hasFocus = 0;
							 | 
						||
| 
								 | 
							
									var lastKeyPressCode;
							 | 
						||
| 
								 | 
							
									var config = {
							 | 
						||
| 
								 | 
							
										mouseDownOnSelect: false
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
									var select = $.Autocompleter.Select(options, input, selectCurrent, config);
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									var blockSubmit;
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									// prevent form submit in opera when selecting with return key
							 | 
						||
| 
								 | 
							
									$.browser.opera && $(input.form).bind("submit.autocomplete", function() {
							 | 
						||
| 
								 | 
							
										if (blockSubmit) {
							 | 
						||
| 
								 | 
							
											blockSubmit = false;
							 | 
						||
| 
								 | 
							
											return false;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									});
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									// only opera doesn't trigger keydown multiple times while pressed, others don't work with keypress at all
							 | 
						||
| 
								 | 
							
									$input.bind(($.browser.opera ? "keypress" : "keydown") + ".autocomplete", function(event) {
							 | 
						||
| 
								 | 
							
										// track last key pressed
							 | 
						||
| 
								 | 
							
										lastKeyPressCode = event.keyCode;
							 | 
						||
| 
								 | 
							
										switch(event.keyCode) {
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
											case KEY.UP:
							 | 
						||
| 
								 | 
							
												event.preventDefault();
							 | 
						||
| 
								 | 
							
												if ( select.visible() ) {
							 | 
						||
| 
								 | 
							
													select.prev();
							 | 
						||
| 
								 | 
							
												} else {
							 | 
						||
| 
								 | 
							
													onChange(0, true);
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
												
							 | 
						||
| 
								 | 
							
											case KEY.DOWN:
							 | 
						||
| 
								 | 
							
												event.preventDefault();
							 | 
						||
| 
								 | 
							
												if ( select.visible() ) {
							 | 
						||
| 
								 | 
							
													select.next();
							 | 
						||
| 
								 | 
							
												} else {
							 | 
						||
| 
								 | 
							
													onChange(0, true);
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
												
							 | 
						||
| 
								 | 
							
											case KEY.PAGEUP:
							 | 
						||
| 
								 | 
							
												event.preventDefault();
							 | 
						||
| 
								 | 
							
												if ( select.visible() ) {
							 | 
						||
| 
								 | 
							
													select.pageUp();
							 | 
						||
| 
								 | 
							
												} else {
							 | 
						||
| 
								 | 
							
													onChange(0, true);
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
												
							 | 
						||
| 
								 | 
							
											case KEY.PAGEDOWN:
							 | 
						||
| 
								 | 
							
												event.preventDefault();
							 | 
						||
| 
								 | 
							
												if ( select.visible() ) {
							 | 
						||
| 
								 | 
							
													select.pageDown();
							 | 
						||
| 
								 | 
							
												} else {
							 | 
						||
| 
								 | 
							
													onChange(0, true);
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											// matches also semicolon
							 | 
						||
| 
								 | 
							
											case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA:
							 | 
						||
| 
								 | 
							
											case KEY.TAB:
							 | 
						||
| 
								 | 
							
											case KEY.RETURN:
							 | 
						||
| 
								 | 
							
												if( selectCurrent() ) {
							 | 
						||
| 
								 | 
							
													// stop default to prevent a form submit, Opera needs special handling
							 | 
						||
| 
								 | 
							
													event.preventDefault();
							 | 
						||
| 
								 | 
							
													blockSubmit = true;
							 | 
						||
| 
								 | 
							
													return false;
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
												
							 | 
						||
| 
								 | 
							
											case KEY.ESC:
							 | 
						||
| 
								 | 
							
												select.hide();
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
												
							 | 
						||
| 
								 | 
							
											default:
							 | 
						||
| 
								 | 
							
												clearTimeout(timeout);
							 | 
						||
| 
								 | 
							
												timeout = setTimeout(onChange, options.delay);
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}).focus(function(){
							 | 
						||
| 
								 | 
							
										// track whether the field has focus, we shouldn't process any
							 | 
						||
| 
								 | 
							
										// results if the field no longer has focus
							 | 
						||
| 
								 | 
							
										hasFocus++;
							 | 
						||
| 
								 | 
							
									}).blur(function() {
							 | 
						||
| 
								 | 
							
										hasFocus = 0;
							 | 
						||
| 
								 | 
							
										if (!config.mouseDownOnSelect) {
							 | 
						||
| 
								 | 
							
											hideResults();
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}).click(function() {
							 | 
						||
| 
								 | 
							
										// show select when clicking in a focused field
							 | 
						||
| 
								 | 
							
										if ( hasFocus++ > 1 && !select.visible() ) {
							 | 
						||
| 
								 | 
							
											onChange(0, true);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}).bind("search", function() {
							 | 
						||
| 
								 | 
							
										// TODO why not just specifying both arguments?
							 | 
						||
| 
								 | 
							
										var fn = (arguments.length > 1) ? arguments[1] : null;
							 | 
						||
| 
								 | 
							
										function findValueCallback(q, data) {
							 | 
						||
| 
								 | 
							
											var result;
							 | 
						||
| 
								 | 
							
											if( data && data.length ) {
							 | 
						||
| 
								 | 
							
												for (var i=0; i < data.length; i++) {
							 | 
						||
| 
								 | 
							
													if( data[i].result.toLowerCase() == q.toLowerCase() ) {
							 | 
						||
| 
								 | 
							
														result = data[i];
							 | 
						||
| 
								 | 
							
														break;
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											if( typeof fn == "function" ) fn(result);
							 | 
						||
| 
								 | 
							
											else $input.trigger("result", result && [result.data, result.value]);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										$.each(trimWords($input.val()), function(i, value) {
							 | 
						||
| 
								 | 
							
											request(value, findValueCallback, findValueCallback);
							 | 
						||
| 
								 | 
							
										});
							 | 
						||
| 
								 | 
							
									}).bind("flushCache", function() {
							 | 
						||
| 
								 | 
							
										cache.flush();
							 | 
						||
| 
								 | 
							
									}).bind("setOptions", function() {
							 | 
						||
| 
								 | 
							
										$.extend(options, arguments[1]);
							 | 
						||
| 
								 | 
							
										// if we've updated the data, repopulate
							 | 
						||
| 
								 | 
							
										if ( "data" in arguments[1] )
							 | 
						||
| 
								 | 
							
											cache.populate();
							 | 
						||
| 
								 | 
							
									}).bind("unautocomplete", function() {
							 | 
						||
| 
								 | 
							
										select.unbind();
							 | 
						||
| 
								 | 
							
										$input.unbind();
							 | 
						||
| 
								 | 
							
										$(input.form).unbind(".autocomplete");
							 | 
						||
| 
								 | 
							
									});
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									function selectCurrent() {
							 | 
						||
| 
								 | 
							
										var selected = select.selected();
							 | 
						||
| 
								 | 
							
										if( !selected )
							 | 
						||
| 
								 | 
							
											return false;
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										var v = selected.result;
							 | 
						||
| 
								 | 
							
										previousValue = v;
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										if ( options.multiple ) {
							 | 
						||
| 
								 | 
							
											var words = trimWords($input.val());
							 | 
						||
| 
								 | 
							
											if ( words.length > 1 ) {
							 | 
						||
| 
								 | 
							
												v = words.slice(0, words.length - 1).join( options.multipleSeparator ) + options.multipleSeparator + v;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											v += options.multipleSeparator;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										$input.val(v);
							 | 
						||
| 
								 | 
							
										hideResultsNow();
							 | 
						||
| 
								 | 
							
										$input.trigger("result", [selected.data, selected.value]);
							 | 
						||
| 
								 | 
							
										return true;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									function onChange(crap, skipPrevCheck) {
							 | 
						||
| 
								 | 
							
										if( lastKeyPressCode == KEY.DEL ) {
							 | 
						||
| 
								 | 
							
											select.hide();
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										var currentValue = $input.val();
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										if ( !skipPrevCheck && currentValue == previousValue )
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										previousValue = currentValue;
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										currentValue = lastWord(currentValue);
							 | 
						||
| 
								 | 
							
										if ( currentValue.length >= options.minChars) {
							 | 
						||
| 
								 | 
							
											$input.addClass(options.loadingClass);
							 | 
						||
| 
								 | 
							
											if (!options.matchCase)
							 | 
						||
| 
								 | 
							
												currentValue = currentValue.toLowerCase();
							 | 
						||
| 
								 | 
							
											request(currentValue, receiveData, hideResultsNow);
							 | 
						||
| 
								 | 
							
										} else {
							 | 
						||
| 
								 | 
							
											stopLoading();
							 | 
						||
| 
								 | 
							
											select.hide();
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									function trimWords(value) {
							 | 
						||
| 
								 | 
							
										if ( !value ) {
							 | 
						||
| 
								 | 
							
											return [""];
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										var words = value.split( options.multipleSeparator );
							 | 
						||
| 
								 | 
							
										var result = [];
							 | 
						||
| 
								 | 
							
										$.each(words, function(i, value) {
							 | 
						||
| 
								 | 
							
											if ( $.trim(value) )
							 | 
						||
| 
								 | 
							
												result[i] = $.trim(value);
							 | 
						||
| 
								 | 
							
										});
							 | 
						||
| 
								 | 
							
										return result;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									function lastWord(value) {
							 | 
						||
| 
								 | 
							
										if ( !options.multiple )
							 | 
						||
| 
								 | 
							
											return value;
							 | 
						||
| 
								 | 
							
										var words = trimWords(value);
							 | 
						||
| 
								 | 
							
										return words[words.length - 1];
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									// fills in the input box w/the first match (assumed to be the best match)
							 | 
						||
| 
								 | 
							
									// q: the term entered
							 | 
						||
| 
								 | 
							
									// sValue: the first matching result
							 | 
						||
| 
								 | 
							
									function autoFill(q, sValue){
							 | 
						||
| 
								 | 
							
										// autofill in the complete box w/the first match as long as the user hasn't entered in more data
							 | 
						||
| 
								 | 
							
										// if the last user key pressed was backspace, don't autofill
							 | 
						||
| 
								 | 
							
										if( options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE ) {
							 | 
						||
| 
								 | 
							
											// fill in the value (keep the case the user has typed)
							 | 
						||
| 
								 | 
							
											$input.val($input.val() + sValue.substring(lastWord(previousValue).length));
							 | 
						||
| 
								 | 
							
											// select the portion of the value not typed by the user (so the next character will erase)
							 | 
						||
| 
								 | 
							
											$.Autocompleter.Selection(input, previousValue.length, previousValue.length + sValue.length);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									function hideResults() {
							 | 
						||
| 
								 | 
							
										clearTimeout(timeout);
							 | 
						||
| 
								 | 
							
										timeout = setTimeout(hideResultsNow, 200);
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									function hideResultsNow() {
							 | 
						||
| 
								 | 
							
										var wasVisible = select.visible();
							 | 
						||
| 
								 | 
							
										select.hide();
							 | 
						||
| 
								 | 
							
										clearTimeout(timeout);
							 | 
						||
| 
								 | 
							
										stopLoading();
							 | 
						||
| 
								 | 
							
										if (options.mustMatch) {
							 | 
						||
| 
								 | 
							
											// call search and run callback
							 | 
						||
| 
								 | 
							
											$input.search(
							 | 
						||
| 
								 | 
							
												function (result){
							 | 
						||
| 
								 | 
							
													// if no value found, clear the input box
							 | 
						||
| 
								 | 
							
													if( !result ) {
							 | 
						||
| 
								 | 
							
														if (options.multiple) {
							 | 
						||
| 
								 | 
							
															var words = trimWords($input.val()).slice(0, -1);
							 | 
						||
| 
								 | 
							
															$input.val( words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : "") );
							 | 
						||
| 
								 | 
							
														}
							 | 
						||
| 
								 | 
							
														else
							 | 
						||
| 
								 | 
							
															$input.val( "" );
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if (wasVisible)
							 | 
						||
| 
								 | 
							
											// position cursor at end of input field
							 | 
						||
| 
								 | 
							
											$.Autocompleter.Selection(input, input.value.length, input.value.length);
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									function receiveData(q, data) {
							 | 
						||
| 
								 | 
							
										if ( data && data.length && hasFocus ) {
							 | 
						||
| 
								 | 
							
											stopLoading();
							 | 
						||
| 
								 | 
							
											select.display(data, q);
							 | 
						||
| 
								 | 
							
											autoFill(q, data[0].value);
							 | 
						||
| 
								 | 
							
											select.show();
							 | 
						||
| 
								 | 
							
										} else {
							 | 
						||
| 
								 | 
							
											hideResultsNow();
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									function request(term, success, failure) {
							 | 
						||
| 
								 | 
							
										if (!options.matchCase)
							 | 
						||
| 
								 | 
							
											term = term.toLowerCase();
							 | 
						||
| 
								 | 
							
										var data = cache.load(term);
							 | 
						||
| 
								 | 
							
										// recieve the cached data
							 | 
						||
| 
								 | 
							
										if (data && data.length) {
							 | 
						||
| 
								 | 
							
											success(term, data);
							 | 
						||
| 
								 | 
							
										// if an AJAX url has been supplied, try loading the data now
							 | 
						||
| 
								 | 
							
										} else if( (typeof options.url == "string") && (options.url.length > 0) ){
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											var extraParams = {
							 | 
						||
| 
								 | 
							
												timestamp: +new Date()
							 | 
						||
| 
								 | 
							
											};
							 | 
						||
| 
								 | 
							
											$.each(options.extraParams, function(key, param) {
							 | 
						||
| 
								 | 
							
												extraParams[key] = typeof param == "function" ? param() : param;
							 | 
						||
| 
								 | 
							
											});
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											$.ajax({
							 | 
						||
| 
								 | 
							
												// try to leverage ajaxQueue plugin to abort previous requests
							 | 
						||
| 
								 | 
							
												mode: "abort",
							 | 
						||
| 
								 | 
							
												// limit abortion to this input
							 | 
						||
| 
								 | 
							
												port: "autocomplete" + input.name,
							 | 
						||
| 
								 | 
							
												dataType: options.dataType,
							 | 
						||
| 
								 | 
							
												url: options.url,
							 | 
						||
| 
								 | 
							
												data: $.extend({
							 | 
						||
| 
								 | 
							
													q: lastWord(term),
							 | 
						||
| 
								 | 
							
													limit: options.max
							 | 
						||
| 
								 | 
							
												}, extraParams),
							 | 
						||
| 
								 | 
							
												success: function(data) {
							 | 
						||
| 
								 | 
							
													var parsed = options.parse && options.parse(data) || parse(data);
							 | 
						||
| 
								 | 
							
													cache.add(term, parsed);
							 | 
						||
| 
								 | 
							
													success(term, parsed);
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											});
							 | 
						||
| 
								 | 
							
										} else {
							 | 
						||
| 
								 | 
							
											// if we have a failure, we need to empty the list -- this prevents the the [TAB] key from selecting the last successful match
							 | 
						||
| 
								 | 
							
											select.emptyList();
							 | 
						||
| 
								 | 
							
											failure(term);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									function parse(data) {
							 | 
						||
| 
								 | 
							
										var parsed = [];
							 | 
						||
| 
								 | 
							
										var rows = data.split("\n");
							 | 
						||
| 
								 | 
							
										for (var i=0; i < rows.length; i++) {
							 | 
						||
| 
								 | 
							
											var row = $.trim(rows[i]);
							 | 
						||
| 
								 | 
							
											if (row) {
							 | 
						||
| 
								 | 
							
												row = row.split("|");
							 | 
						||
| 
								 | 
							
												parsed[parsed.length] = {
							 | 
						||
| 
								 | 
							
													data: row,
							 | 
						||
| 
								 | 
							
													value: row[0],
							 | 
						||
| 
								 | 
							
													result: options.formatResult && options.formatResult(row, row[0]) || row[0]
							 | 
						||
| 
								 | 
							
												};
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										return parsed;
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									function stopLoading() {
							 | 
						||
| 
								 | 
							
										$input.removeClass(options.loadingClass);
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								$.Autocompleter.defaults = {
							 | 
						||
| 
								 | 
							
									inputClass: "ac_input",
							 | 
						||
| 
								 | 
							
									resultsClass: "ac_results",
							 | 
						||
| 
								 | 
							
									loadingClass: "ac_loading",
							 | 
						||
| 
								 | 
							
									minChars: 1,
							 | 
						||
| 
								 | 
							
									delay: 400,
							 | 
						||
| 
								 | 
							
									matchCase: false,
							 | 
						||
| 
								 | 
							
									matchSubset: true,
							 | 
						||
| 
								 | 
							
									matchContains: false,
							 | 
						||
| 
								 | 
							
									cacheLength: 10,
							 | 
						||
| 
								 | 
							
									max: 100,
							 | 
						||
| 
								 | 
							
									mustMatch: false,
							 | 
						||
| 
								 | 
							
									extraParams: {},
							 | 
						||
| 
								 | 
							
									selectFirst: true,
							 | 
						||
| 
								 | 
							
									formatItem: function(row) { return row[0]; },
							 | 
						||
| 
								 | 
							
									formatMatch: null,
							 | 
						||
| 
								 | 
							
									autoFill: false,
							 | 
						||
| 
								 | 
							
									width: 0,
							 | 
						||
| 
								 | 
							
									multiple: false,
							 | 
						||
| 
								 | 
							
									multipleSeparator: ", ",
							 | 
						||
| 
								 | 
							
									highlight: function(value, term) {
							 | 
						||
| 
								 | 
							
										return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
							 | 
						||
| 
								 | 
							
									},
							 | 
						||
| 
								 | 
							
								    scroll: true,
							 | 
						||
| 
								 | 
							
								    scrollHeight: 180
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								$.Autocompleter.Cache = function(options) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									var data = {};
							 | 
						||
| 
								 | 
							
									var length = 0;
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									function matchSubset(s, sub) {
							 | 
						||
| 
								 | 
							
										if (!options.matchCase) 
							 | 
						||
| 
								 | 
							
											s = s.toLowerCase();
							 | 
						||
| 
								 | 
							
										var i = s.indexOf(sub);
							 | 
						||
| 
								 | 
							
										if (i == -1) return false;
							 | 
						||
| 
								 | 
							
										return i == 0 || options.matchContains;
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									function add(q, value) {
							 | 
						||
| 
								 | 
							
										if (length > options.cacheLength){
							 | 
						||
| 
								 | 
							
											flush();
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if (!data[q]){ 
							 | 
						||
| 
								 | 
							
											length++;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										data[q] = value;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									function populate(){
							 | 
						||
| 
								 | 
							
										if( !options.data ) return false;
							 | 
						||
| 
								 | 
							
										// track the matches
							 | 
						||
| 
								 | 
							
										var stMatchSets = {},
							 | 
						||
| 
								 | 
							
											nullData = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// no url was specified, we need to adjust the cache length to make sure it fits the local data store
							 | 
						||
| 
								 | 
							
										if( !options.url ) options.cacheLength = 1;
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										// track all options for minChars = 0
							 | 
						||
| 
								 | 
							
										stMatchSets[""] = [];
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										// loop through the array and create a lookup structure
							 | 
						||
| 
								 | 
							
										for ( var i = 0, ol = options.data.length; i < ol; i++ ) {
							 | 
						||
| 
								 | 
							
											var rawValue = options.data[i];
							 | 
						||
| 
								 | 
							
											// if rawValue is a string, make an array otherwise just reference the array
							 | 
						||
| 
								 | 
							
											rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue;
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											var value = options.formatMatch(rawValue, i+1, options.data.length);
							 | 
						||
| 
								 | 
							
											if ( value === false )
							 | 
						||
| 
								 | 
							
												continue;
							 | 
						||
| 
								 | 
							
												
							 | 
						||
| 
								 | 
							
											var firstChar = value.charAt(0).toLowerCase();
							 | 
						||
| 
								 | 
							
											// if no lookup array for this character exists, look it up now
							 | 
						||
| 
								 | 
							
											if( !stMatchSets[firstChar] ) 
							 | 
						||
| 
								 | 
							
												stMatchSets[firstChar] = [];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// if the match is a string
							 | 
						||
| 
								 | 
							
											var row = {
							 | 
						||
| 
								 | 
							
												value: value,
							 | 
						||
| 
								 | 
							
												data: rawValue,
							 | 
						||
| 
								 | 
							
												result: options.formatResult && options.formatResult(rawValue) || value
							 | 
						||
| 
								 | 
							
											};
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											// push the current match into the set list
							 | 
						||
| 
								 | 
							
											stMatchSets[firstChar].push(row);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// keep track of minChars zero items
							 | 
						||
| 
								 | 
							
											if ( nullData++ < options.max ) {
							 | 
						||
| 
								 | 
							
												stMatchSets[""].push(row);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// add the data items to the cache
							 | 
						||
| 
								 | 
							
										$.each(stMatchSets, function(i, value) {
							 | 
						||
| 
								 | 
							
											// increase the cache size
							 | 
						||
| 
								 | 
							
											options.cacheLength++;
							 | 
						||
| 
								 | 
							
											// add to the cache
							 | 
						||
| 
								 | 
							
											add(i, value);
							 | 
						||
| 
								 | 
							
										});
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									// populate any existing data
							 | 
						||
| 
								 | 
							
									setTimeout(populate, 25);
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									function flush(){
							 | 
						||
| 
								 | 
							
										data = {};
							 | 
						||
| 
								 | 
							
										length = 0;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									return {
							 | 
						||
| 
								 | 
							
										flush: flush,
							 | 
						||
| 
								 | 
							
										add: add,
							 | 
						||
| 
								 | 
							
										populate: populate,
							 | 
						||
| 
								 | 
							
										load: function(q) {
							 | 
						||
| 
								 | 
							
											if (!options.cacheLength || !length)
							 | 
						||
| 
								 | 
							
												return null;
							 | 
						||
| 
								 | 
							
											/* 
							 | 
						||
| 
								 | 
							
											 * if dealing w/local data and matchContains than we must make sure
							 | 
						||
| 
								 | 
							
											 * to loop through all the data collections looking for matches
							 | 
						||
| 
								 | 
							
											 */
							 | 
						||
| 
								 | 
							
											if( !options.url && options.matchContains ){
							 | 
						||
| 
								 | 
							
												// track all matches
							 | 
						||
| 
								 | 
							
												var csub = [];
							 | 
						||
| 
								 | 
							
												// loop through all the data grids for matches
							 | 
						||
| 
								 | 
							
												for( var k in data ){
							 | 
						||
| 
								 | 
							
													// don't search through the stMatchSets[""] (minChars: 0) cache
							 | 
						||
| 
								 | 
							
													// this prevents duplicates
							 | 
						||
| 
								 | 
							
													if( k.length > 0 ){
							 | 
						||
| 
								 | 
							
														var c = data[k];
							 | 
						||
| 
								 | 
							
														$.each(c, function(i, x) {
							 | 
						||
| 
								 | 
							
															// if we've got a match, add it to the array
							 | 
						||
| 
								 | 
							
															if (matchSubset(x.value, q)) {
							 | 
						||
| 
								 | 
							
																csub.push(x);
							 | 
						||
| 
								 | 
							
															}
							 | 
						||
| 
								 | 
							
														});
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
												}				
							 | 
						||
| 
								 | 
							
												return csub;
							 | 
						||
| 
								 | 
							
											} else 
							 | 
						||
| 
								 | 
							
											// if the exact item exists, use it
							 | 
						||
| 
								 | 
							
											if (data[q]){
							 | 
						||
| 
								 | 
							
												return data[q];
							 | 
						||
| 
								 | 
							
											} else
							 | 
						||
| 
								 | 
							
											if (options.matchSubset) {
							 | 
						||
| 
								 | 
							
												for (var i = q.length - 1; i >= options.minChars; i--) {
							 | 
						||
| 
								 | 
							
													var c = data[q.substr(0, i)];
							 | 
						||
| 
								 | 
							
													if (c) {
							 | 
						||
| 
								 | 
							
														var csub = [];
							 | 
						||
| 
								 | 
							
														$.each(c, function(i, x) {
							 | 
						||
| 
								 | 
							
															if (matchSubset(x.value, q)) {
							 | 
						||
| 
								 | 
							
																csub[csub.length] = x;
							 | 
						||
| 
								 | 
							
															}
							 | 
						||
| 
								 | 
							
														});
							 | 
						||
| 
								 | 
							
														return csub;
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											return null;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								$.Autocompleter.Select = function (options, input, select, config) {
							 | 
						||
| 
								 | 
							
									var CLASSES = {
							 | 
						||
| 
								 | 
							
										ACTIVE: "ac_over"
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									var listItems,
							 | 
						||
| 
								 | 
							
										active = -1,
							 | 
						||
| 
								 | 
							
										data,
							 | 
						||
| 
								 | 
							
										term = "",
							 | 
						||
| 
								 | 
							
										needsInit = true,
							 | 
						||
| 
								 | 
							
										element,
							 | 
						||
| 
								 | 
							
										list;
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									// Create results
							 | 
						||
| 
								 | 
							
									function init() {
							 | 
						||
| 
								 | 
							
										if (!needsInit)
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
										element = $("<div/>")
							 | 
						||
| 
								 | 
							
										.hide()
							 | 
						||
| 
								 | 
							
										.addClass(options.resultsClass)
							 | 
						||
| 
								 | 
							
										.css("position", "absolute")
							 | 
						||
| 
								 | 
							
										.appendTo(document.body);
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
										list = $("<ul/>").appendTo(element).mouseover( function(event) {
							 | 
						||
| 
								 | 
							
											if(target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') {
							 | 
						||
| 
								 | 
							
									            active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event));
							 | 
						||
| 
								 | 
							
											    $(target(event)).addClass(CLASSES.ACTIVE);            
							 | 
						||
| 
								 | 
							
									        }
							 | 
						||
| 
								 | 
							
										}).click(function(event) {
							 | 
						||
| 
								 | 
							
											$(target(event)).addClass(CLASSES.ACTIVE);
							 | 
						||
| 
								 | 
							
											select();
							 | 
						||
| 
								 | 
							
											// TODO provide option to avoid setting focus again after selection? useful for cleanup-on-focus
							 | 
						||
| 
								 | 
							
											input.focus();
							 | 
						||
| 
								 | 
							
											return false;
							 | 
						||
| 
								 | 
							
										}).mousedown(function() {
							 | 
						||
| 
								 | 
							
											config.mouseDownOnSelect = true;
							 | 
						||
| 
								 | 
							
										}).mouseup(function() {
							 | 
						||
| 
								 | 
							
											config.mouseDownOnSelect = false;
							 | 
						||
| 
								 | 
							
										});
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										if( options.width > 0 )
							 | 
						||
| 
								 | 
							
											element.css("width", options.width);
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
										needsInit = false;
							 | 
						||
| 
								 | 
							
									} 
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									function target(event) {
							 | 
						||
| 
								 | 
							
										var element = event.target;
							 | 
						||
| 
								 | 
							
										while(element && element.tagName != "LI")
							 | 
						||
| 
								 | 
							
											element = element.parentNode;
							 | 
						||
| 
								 | 
							
										// more fun with IE, sometimes event.target is empty, just ignore it then
							 | 
						||
| 
								 | 
							
										if(!element)
							 | 
						||
| 
								 | 
							
											return [];
							 | 
						||
| 
								 | 
							
										return element;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									function moveSelect(step) {
							 | 
						||
| 
								 | 
							
										listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE);
							 | 
						||
| 
								 | 
							
										movePosition(step);
							 | 
						||
| 
								 | 
							
								        var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE);
							 | 
						||
| 
								 | 
							
								        if(options.scroll) {
							 | 
						||
| 
								 | 
							
								            var offset = 0;
							 | 
						||
| 
								 | 
							
								            listItems.slice(0, active).each(function() {
							 | 
						||
| 
								 | 
							
												offset += this.offsetHeight;
							 | 
						||
| 
								 | 
							
											});
							 | 
						||
| 
								 | 
							
								            if((offset + activeItem[0].offsetHeight - list.scrollTop()) > list[0].clientHeight) {
							 | 
						||
| 
								 | 
							
								                list.scrollTop(offset + activeItem[0].offsetHeight - list.innerHeight());
							 | 
						||
| 
								 | 
							
								            } else if(offset < list.scrollTop()) {
							 | 
						||
| 
								 | 
							
								                list.scrollTop(offset);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									function movePosition(step) {
							 | 
						||
| 
								 | 
							
										active += step;
							 | 
						||
| 
								 | 
							
										if (active < 0) {
							 | 
						||
| 
								 | 
							
											active = listItems.size() - 1;
							 | 
						||
| 
								 | 
							
										} else if (active >= listItems.size()) {
							 | 
						||
| 
								 | 
							
											active = 0;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									function limitNumberOfItems(available) {
							 | 
						||
| 
								 | 
							
										return options.max && options.max < available
							 | 
						||
| 
								 | 
							
											? options.max
							 | 
						||
| 
								 | 
							
											: available;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									function fillList() {
							 | 
						||
| 
								 | 
							
										list.empty();
							 | 
						||
| 
								 | 
							
										var max = limitNumberOfItems(data.length);
							 | 
						||
| 
								 | 
							
										for (var i=0; i < max; i++) {
							 | 
						||
| 
								 | 
							
											if (!data[i])
							 | 
						||
| 
								 | 
							
												continue;
							 | 
						||
| 
								 | 
							
											var formatted = options.formatItem(data[i].data, i+1, max, data[i].value, term);
							 | 
						||
| 
								 | 
							
											if ( formatted === false )
							 | 
						||
| 
								 | 
							
												continue;
							 | 
						||
| 
								 | 
							
											var li = $("<li/>").html( options.highlight(formatted, term) ).addClass(i%2 == 0 ? "ac_even" : "ac_odd").appendTo(list)[0];
							 | 
						||
| 
								 | 
							
											$.data(li, "ac_data", data[i]);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										listItems = list.find("li");
							 | 
						||
| 
								 | 
							
										if ( options.selectFirst ) {
							 | 
						||
| 
								 | 
							
											listItems.slice(0, 1).addClass(CLASSES.ACTIVE);
							 | 
						||
| 
								 | 
							
											active = 0;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										// apply bgiframe if available
							 | 
						||
| 
								 | 
							
										if ( $.fn.bgiframe )
							 | 
						||
| 
								 | 
							
											list.bgiframe();
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									return {
							 | 
						||
| 
								 | 
							
										display: function(d, q) {
							 | 
						||
| 
								 | 
							
											init();
							 | 
						||
| 
								 | 
							
											data = d;
							 | 
						||
| 
								 | 
							
											term = q;
							 | 
						||
| 
								 | 
							
											fillList();
							 | 
						||
| 
								 | 
							
										},
							 | 
						||
| 
								 | 
							
										next: function() {
							 | 
						||
| 
								 | 
							
											moveSelect(1);
							 | 
						||
| 
								 | 
							
										},
							 | 
						||
| 
								 | 
							
										prev: function() {
							 | 
						||
| 
								 | 
							
											moveSelect(-1);
							 | 
						||
| 
								 | 
							
										},
							 | 
						||
| 
								 | 
							
										pageUp: function() {
							 | 
						||
| 
								 | 
							
											if (active != 0 && active - 8 < 0) {
							 | 
						||
| 
								 | 
							
												moveSelect( -active );
							 | 
						||
| 
								 | 
							
											} else {
							 | 
						||
| 
								 | 
							
												moveSelect(-8);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										},
							 | 
						||
| 
								 | 
							
										pageDown: function() {
							 | 
						||
| 
								 | 
							
											if (active != listItems.size() - 1 && active + 8 > listItems.size()) {
							 | 
						||
| 
								 | 
							
												moveSelect( listItems.size() - 1 - active );
							 | 
						||
| 
								 | 
							
											} else {
							 | 
						||
| 
								 | 
							
												moveSelect(8);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										},
							 | 
						||
| 
								 | 
							
										hide: function() {
							 | 
						||
| 
								 | 
							
											element && element.hide();
							 | 
						||
| 
								 | 
							
											listItems && listItems.removeClass(CLASSES.ACTIVE);
							 | 
						||
| 
								 | 
							
											active = -1;
							 | 
						||
| 
								 | 
							
										},
							 | 
						||
| 
								 | 
							
										visible : function() {
							 | 
						||
| 
								 | 
							
											return element && element.is(":visible");
							 | 
						||
| 
								 | 
							
										},
							 | 
						||
| 
								 | 
							
										current: function() {
							 | 
						||
| 
								 | 
							
											return this.visible() && (listItems.filter("." + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]);
							 | 
						||
| 
								 | 
							
										},
							 | 
						||
| 
								 | 
							
										show: function() {
							 | 
						||
| 
								 | 
							
											var offset = $(input).offset();
							 | 
						||
| 
								 | 
							
											element.css({
							 | 
						||
| 
								 | 
							
												width: typeof options.width == "string" || options.width > 0 ? options.width : $(input).width(),
							 | 
						||
| 
								 | 
							
												top: offset.top + input.offsetHeight,
							 | 
						||
| 
								 | 
							
												left: offset.left
							 | 
						||
| 
								 | 
							
											}).show();
							 | 
						||
| 
								 | 
							
								            if(options.scroll) {
							 | 
						||
| 
								 | 
							
								                list.scrollTop(0);
							 | 
						||
| 
								 | 
							
								                list.css({
							 | 
						||
| 
								 | 
							
													maxHeight: options.scrollHeight,
							 | 
						||
| 
								 | 
							
													overflow: 'auto'
							 | 
						||
| 
								 | 
							
												});
							 | 
						||
| 
								 | 
							
												
							 | 
						||
| 
								 | 
							
								                if($.browser.msie && typeof document.body.style.maxHeight === "undefined") {
							 | 
						||
| 
								 | 
							
													var listHeight = 0;
							 | 
						||
| 
								 | 
							
													listItems.each(function() {
							 | 
						||
| 
								 | 
							
														listHeight += this.offsetHeight;
							 | 
						||
| 
								 | 
							
													});
							 | 
						||
| 
								 | 
							
													var scrollbarsVisible = listHeight > options.scrollHeight;
							 | 
						||
| 
								 | 
							
								                    list.css('height', scrollbarsVisible ? options.scrollHeight : listHeight );
							 | 
						||
| 
								 | 
							
													if (!scrollbarsVisible) {
							 | 
						||
| 
								 | 
							
														// IE doesn't recalculate width when scrollbar disappears
							 | 
						||
| 
								 | 
							
														listItems.width( list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right")) );
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
										},
							 | 
						||
| 
								 | 
							
										selected: function() {
							 | 
						||
| 
								 | 
							
											var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);
							 | 
						||
| 
								 | 
							
											return selected && selected.length && $.data(selected[0], "ac_data");
							 | 
						||
| 
								 | 
							
										},
							 | 
						||
| 
								 | 
							
										emptyList: function (){
							 | 
						||
| 
								 | 
							
											list && list.empty();
							 | 
						||
| 
								 | 
							
										},
							 | 
						||
| 
								 | 
							
										unbind: function() {
							 | 
						||
| 
								 | 
							
											element && element.remove();
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								$.Autocompleter.Selection = function(field, start, end) {
							 | 
						||
| 
								 | 
							
									if( field.createTextRange ){
							 | 
						||
| 
								 | 
							
										var selRange = field.createTextRange();
							 | 
						||
| 
								 | 
							
										selRange.collapse(true);
							 | 
						||
| 
								 | 
							
										selRange.moveStart("character", start);
							 | 
						||
| 
								 | 
							
										selRange.moveEnd("character", end);
							 | 
						||
| 
								 | 
							
										selRange.select();
							 | 
						||
| 
								 | 
							
									} else if( field.setSelectionRange ){
							 | 
						||
| 
								 | 
							
										field.setSelectionRange(start, end);
							 | 
						||
| 
								 | 
							
									} else {
							 | 
						||
| 
								 | 
							
										if( field.selectionStart ){
							 | 
						||
| 
								 | 
							
											field.selectionStart = start;
							 | 
						||
| 
								 | 
							
											field.selectionEnd = end;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									field.focus();
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								})(jQuery);
							 |