var AutoComplete=Class.create();AutoComplete.prototype={selector:null,input:null,_timeout:null,visible:false,drawn:false,_hideTimeout:null,initialize:function(input,action,options){this.action=action;this.input=$(input);this.options=new AutoComplete.Options();Object.extend(this.options,options||{});if(!this.input)alert('No input field/binding field given or found');if(!this.action)alert('No action url specified');this.selector=document.createElement('select');Event.observe(this.input,'focus',this._onInputFocus.bindAsEventListener(this));Event.observe(this.input,'keyup',this._onInputKeyUp.bindAsEventListener(this));Event.observe(this.input,'keydown',this._onInputKeyDown.bindAsEventListener(this));Event.observe(this.input,'blur',this._onInputBlur.bindAsEventListener(this));Event.observe(this.selector,'blur',this._onSelectorBlur.bindAsEventListener(this));Event.observe(this.selector,'focus',this._onSelectorFocus.bindAsEventListener(this));Event.observe(this.selector,'change',this._onSelectorChange.bindAsEventListener(this));Event.observe(window,'resize',this._reposition.bind(this));Event.observe(window,'scroll',this._reposition.bind(this));},_onInputFocus:function(event){this._onSelectorFocus(event);},_onSelectorBlur:function(event){this._onInputBlur(event);},_onInputBlur:function(event){this._hideTimeout=setTimeout(this._checkOnBlur.bind(this),100);},_checkOnBlur:function(){this._hideTimeout=null;this.hide();},_onInputKeyUp:function(event){this._suggest(event)},_onInputKeyDown:function(event){this._suggest(event)},_onSelectorFocus:function(event){if(this._hideTimeout){clearTimeout(this._hideTimeout);this._hideTimeout=null;}},_onSelectorChange:function(event){this.select();},draw:function(){if(this.drawn)return;if(this.options.cssClass)this.selector.className=this.options.cssClass;Element.setStyle(this.selector,{display:'none',position:'absolute',width:this.input.offsetWidth+'px'});this.selector.size=this.options.size;document.body.appendChild(this.selector);this.input.autocomplete='off';this.drawn=true;},hide:function(){if(!this.drawn|| !this.visible)return;this.visible=false;if(window.Scriptaculous){new Effect.BlindUp(this.selector,{duration:this.options.delay,queue:'end',afterFinish:function(event){Element.setStyle(this.selector,{display:'none'});this.selector.options.length=0;setTimeout(this._restoreFocus.bind(this),50);}.bind(this)});}else{Element.setStyle(this.selector,{display:'none'});this.selector.options.length=0;setTimeout(this._restoreFocus.bind(this),50);}},_restoreFocus:function(){this.input.focus();},show:function(){if(!this.drawn)this.draw();var trigger=null;if(this.selector.options.length){if(window.Scriptaculous){new Effect.BlindDown(this.selector,{duration:this.options.delay,queue:'end'});}else{Element.setStyle(this.selector,{display:'inline'});}this._reposition();this.visible=true;}},_cancelTimeout:function(){if(this._timeout){clearTimeout(this._timeout);this._timeout=null;}},_suggest:function(event){this._cancelTimeout();var key=Event.keyPressed(event);var ignoreKeys=[20,16,17,91,121,122,123,124,125,126,127,128,129,130,131,132,45,36,35,33,34,144,145,44,19,93,];if(ignoreKeys.indexOf(key)> -1)return true;if(event.type=='keydown'){if(Event.KEY_ESC==key){this.cancel();Event.stop(event);return false;}if(Event.KEY_TAB==key){this.cancel();return true;}if(!(key==Event.KEY_UP||key==Event.KEY_DOWN))return true;}switch(key){case Event.KEY_LEFT:case Event.KEY_RIGHT:return true;break;case Event.KEY_TAB:case Event.KEY_BACKSPACE:case 46:this.cancel();return true;break;case Event.KEY_RETURN:this.select();return true;break;case Event.KEY_ESC:this.cancel();return false;break;case Event.KEY_UP:case Event.KEY_DOWN:if(event.type=='keydown')this._interact(event);Event.stop(event);return false;break;default:break;}if(this.input.value.length<this.options.threshold){return true;}else{this._timeout=setTimeout(this._sendRequest.bind(this),1000*this.options.delay);return false;}},_sendRequest:function(){this._request=new Ajax.Request(this.action+this.input.value,{onComplete:this._process.bind(this),method:this.options.requestMethod});},_reposition:function(){if(!this.drawn)return;var pos=Position.cumulativeOffset(this.input);pos.push(pos[0]+this.input.offsetWidth);pos.push(pos[1]+this.input.offsetHeight);Element.setStyle(this.selector,{left:pos[0]+'px',top:pos[3]+'px'});},_process:function(objXML,jsonHeader){this.selector.options.length=0;switch(this.options.resultFormat){case AutoComplete.Options.RESULT_FORMAT_XML:this._parseXML(objXML.responseXML);break;case AutoComplete.Options.RESULT_FORMAT_JSON:if(!jsonHeader){jsonHeader=objXML.responseText&&objXML.responseText.isJSON()?objXML.responseText.evalJSON():null;}this._parseJSON(jsonHeader);break;case AutoComplete.Options.RESULT_FORMAT_TEXT:this._parseText(objXML.responseText);break;default:alert("Unable to parse result type. Make sure you've set the resultFormat option correctly");break;}if(this.selector.options.length>(this.options.size))this.selector.size=this.options.size;else this.selector.size=this.selector.options.length>1?this.selector.options.length:2;if(this.selector.options.length){this.selector.selectedIndex= -1;this.show();}else this.cancel();},_parseXML:function(xml){var suggestions=null;for(var i=0;i<xml.childNodes.length;i++){if(xml.childNodes[i].tagName){suggestions=xml.childNodes[i].childNodes;}}if(!suggestions){alert("Could not parse response XML.");return;}for(i=0;i<suggestions.length;i++){suggestion=suggestions.item(i).firstChild.nodeValue;this._addOption(suggestion);}},_parseJSON:function(json){if(!json)json=[];for(i=0;i<json.length;i++)this._addOption(json[i]);},_parseText:function(text){var suggestions=(text||"").split(/\n/);for(i=0;i<suggestions.length;i++)this._addOption(suggestions[i]);},_addOption:function(suggestion){var opt=new Option(suggestion,suggestion);Prototype.Browser.IE?this.selector.add(opt):this.selector.add(opt,null);},cancel:function(){this.hide();},select:function(){if(this.selector.options.length)this.input.value=this.selector.options[this.selector.selectedIndex].value;this.cancel();if(typeof this.options.onSelect=='function'){this.options['onSelect'](this.input);}},_interact:function(event){if(!this.visible)return;var key=Event.keyPressed(event);if(key!=Event.KEY_UP&&key!=Event.KEY_DOWN)return;var mx=this.selector.options.length;if(key==Event.KEY_UP){if(this.selector.selectedIndex==0)this.selector.selectedIndex=this.selector.options.length-1;else this.selector.selectedIndex--;}else{if(this.selector.selectedIndex==this.selector.options.length-1)this.selector.selectedIndex=0;else this.selector.selectedIndex++;}}};AutoComplete.Options=Object.extend(Class.create(),{RESULT_FORMAT_XML:'xml',RESULT_FORMAT_JSON:'json',RESULT_FORMAT_TEXT:'text'});AutoComplete.Options.prototype={size:10,cssClass:null,onSelect:null,threshold:3,delay:.2,requestMethod:'GET',resultFormat:AutoComplete.Options.RESULT_FORMAT_XML,initialize:function(overrides){if(overrides){for(var item in overrides)this[item]=overrides[item];}}};Object.extend(Event,{KEY_BACKSPACE:8,KEY_TAB:9,KEY_RETURN:13,KEY_ESC:27,KEY_LEFT:37,KEY_UP:38,KEY_RIGHT:39,KEY_DOWN:40,KEY_DELETE:46,KEY_SHIFT:16,KEY_CONTROL:17,KEY_CAPSLOCK:20,KEY_SPACE:32,keyPressed:function(event){return Prototype.Browser.IE?window.event.keyCode:event.which;}});