function Sys$Preview$UI$AutoCompleteBehavior$_update(prefixText, completionItems, cacheResults) ...{ if (cacheResults &&this.get_enableCaching()) ...{ if (!this._cache) ...{ this._cache =...{}; } this._cache[prefixText] = completionItems; } this._completionListElement.innerHTML =''; this._selectIndex =-1; if (completionItems && completionItems.length) ...{ for (var i =0; i < completionItems.length; i++) ...{ var itemElement = document.createElement('div'); //Creates a text string from the specified value. Returns the created TextNode object.(TextNode, Represents a string of text as a node in the document hierarchy.) itemElement.appendChild(document.createTextNode(completionItems[i])); itemElement.__item =''; var itemElementStyle = itemElement.style; itemElementStyle.padding ='1px'; itemElementStyle.textAlign ='left'; itemElementStyle.textOverflow ='ellipsis'; itemElementStyle.backgroundColor ='window'; itemElementStyle.color ='windowtext'; this._completionListElement.appendChild(itemElement); } this._popupBehavior.show(); } else...{ this._popupBehavior.hide(); } }
具体相关 _completionListElement 函数实现
function Sys$Preview$UI$AutoCompleteBehavior$initializeCompletionList(element) ...{ $addHandler(element, "mouseover", this._mouseOverHandler); } function Sys$Preview$UI$AutoCompleteBehavior$_onListMouseDown(ev) ...{ if (ev.target !==this._completionListElement) ...{ this._setText(ev.target.firstChild.nodeValue); } } function Sys$Preview$UI$AutoCompleteBehavior$_onListMouseUp(ev) ...{ this.get_element().focus(); //光标返回到textbox上 } function Sys$Preview$UI$AutoCompleteBehavior$_onListMouseOver(ev) ...{ var item = ev.target; this._selectIndex =-1; this._highlightItem(item); }
/**//** * An autosuggest textbox control. * @class * @scope public */ function AutoSuggestControl(oTextbox /**//*:HTMLInputElement*/, oProvider /**//*:SuggestionProvider*/) ...{ /**//** * The currently selected suggestions. * @scope private */ this.cur /**//*:int*/=-1; /**//** * The dropdown list layer. * @scope private */ this.layer =null; /**//** * Suggestion provider for the autosuggest feature. * @scope private. */ this.provider /**//*:SuggestionProvider*/= oProvider; /**//** * The textbox to capture. * @scope private */ this.textbox /**//*:HTMLInputElement*/= oTextbox; /**//** * Timeout ID for fast typers. * @scope private */ this.timeoutId /**//*:int*/=null; /**//** * The text that the user typed. * @scope private */ this.userText /**//*:String*/= oTextbox.value; //initialize the control this.init(); } /**//** * Autosuggests one or more suggestions for what the user has typed. * If no suggestions are passed in, then no autosuggest occurs. * @scope private * @param aSuggestions An array of suggestion strings. * @param bTypeAhead If the control should provide a type ahead suggestion. */ AutoSuggestControl.prototype.autosuggest =function (aSuggestions /**//*:Array*/, bTypeAhead /**//*:boolean*/) ...{ //re-initialize pointer to current suggestion this.cur =-1; //make sure there's at least one suggestion if (aSuggestions.length >0) ...{ if (bTypeAhead) ...{ this.typeAhead(aSuggestions[0]); } this.showSuggestions(aSuggestions); }else...{ this.hideSuggestions(); } }; /**//** * Creates the dropdown layer to display multiple suggestions. * @scope private */ AutoSuggestControl.prototype.createDropDown =function () ...{ //create the layer and assign styles this.layer = document.createElement("div"); this.layer.className ="suggestions"; this.layer.style.visibility ="hidden"; this.layer.style.width =this.textbox.offsetWidth; document.body.appendChild(this.layer); //when the user clicks on the a suggestion, get the text (innerHTML) //and place it into a textbox var oThis =this; this.layer.onmousedown = this.layer.onmouseup = this.layer.onmouseover =function (oEvent) ...{ oEvent = oEvent || window.event; oTarget = oEvent.target || oEvent.srcElement; if (oEvent.type =="mousedown") ...{ oThis.textbox.value = oTarget.firstChild.nodeValue; oThis.hideSuggestions(); }elseif (oEvent.type =="mouseover") ...{ oThis.highlightSuggestion(oTarget); }else...{ oThis.textbox.focus(); } }; }; /**//** * Gets the left coordinate of the textbox. * @scope private * @return The left coordinate of the textbox in pixels. */ AutoSuggestControl.prototype.getLeft =function () /**//*:int*/...{ var oNode =this.textbox; var iLeft =0; while(oNode.tagName !="BODY") ...{ iLeft += oNode.offsetLeft; oNode = oNode.offsetParent; } return iLeft; }; /**//** * Gets the top coordinate of the textbox. * @scope private * @return The top coordinate of the textbox in pixels. */ AutoSuggestControl.prototype.getTop =function () /**//*:int*/...{ var oNode =this.textbox; var iTop =0; while(oNode.tagName !="BODY") ...{ iTop += oNode.offsetTop; oNode = oNode.offsetParent; } return iTop; }; /**//** * Highlights the next or previous suggestion in the dropdown and * places the suggestion into the textbox. * @param iDiff Either a positive or negative number indicating whether * to select the next or previous sugggestion, respectively. * @scope private */ AutoSuggestControl.prototype.goToSuggestion =function (iDiff /**//*:int*/) ...{ var cSuggestionNodes =this.layer.childNodes; if (cSuggestionNodes.length >0) ...{ var oNode =null; if (iDiff >0) ...{ if (this.cur < cSuggestionNodes.length-1) ...{ oNode = cSuggestionNodes[++this.cur]; } }else...{ if (this.cur >0) ...{ oNode = cSuggestionNodes[--this.cur]; } } if (oNode) ...{ this.highlightSuggestion(oNode); this.textbox.value = oNode.firstChild.nodeValue; } } }; /**//** * Handles three keydown events. * @scope private * @param oEvent The event object for the keydown event. */ AutoSuggestControl.prototype.handleKeyDown =function (oEvent /**//*:Event*/) ...{ switch(oEvent.keyCode) ...{ case38: //up arrow this.goToSuggestion(-1); break; case40: //down arrow this.goToSuggestion(1); break; case27: //esc this.textbox.value =this.userText; this.selectRange(this.userText.length, 0); /**//* falls through */ case13: //enter this.hideSuggestions(); oEvent.returnValue =false; if (oEvent.preventDefault) ...{ oEvent.preventDefault(); } break; } }; /**//** * Handles keyup events. * @scope private * @param oEvent The event object for the keyup event. */ AutoSuggestControl.prototype.handleKeyUp =function (oEvent /**//*:Event*/) ...{ var iKeyCode = oEvent.keyCode; var oThis =this; //get the currently entered text this.userText =this.textbox.value; clearTimeout(this.timeoutId); //for backspace (8) and delete (46), shows suggestions without typeahead if (iKeyCode ==8|| iKeyCode ==46) ...{ this.timeoutId = setTimeout( function () ...{ oThis.provider.requestSuggestions(oThis, false); }, 250); //make sure not to interfere with non-character keys }elseif (iKeyCode <32|| (iKeyCode >=33&& iKeyCode <46) || (iKeyCode >=112&& iKeyCode <=123)) ...{ //ignore }else...{ //request suggestions from the suggestion provider with typeahead this.timeoutId = setTimeout( function () ...{ oThis.provider.requestSuggestions(oThis, true); }, 250); } }; /**//** * Hides the suggestion dropdown. * @scope private */ AutoSuggestControl.prototype.hideSuggestions =function () ...{ this.layer.style.visibility ="hidden"; }; /**//** * Highlights the given node in the suggestions dropdown. * @scope private * @param oSuggestionNode The node representing a suggestion in the dropdown. */ AutoSuggestControl.prototype.highlightSuggestion =function (oSuggestionNode) ...{ for (var i=0; i <this.layer.childNodes.length; i++) ...{ var oNode =this.layer.childNodes[i]; if (oNode == oSuggestionNode) ...{ oNode.className ="current" }elseif (oNode.className =="current") ...{ oNode.className =""; } } }; /**//** * Initializes the textbox with event handlers for * auto suggest functionality. * @scope private */ AutoSuggestControl.prototype.init =function () ...{ //save a reference to this object var oThis =this; //assign the onkeyup event handler this.textbox.onkeyup =function (oEvent) ...{ //check for the proper location of the event object if (!oEvent) ...{ oEvent = window.event; } //call the handleKeyUp() method with the event object oThis.handleKeyUp(oEvent); }; //assign onkeydown event handler this.textbox.onkeydown =function (oEvent) ...{ //check for the proper location of the event object if (!oEvent) ...{ oEvent = window.event; } //call the handleKeyDown() method with the event object oThis.handleKeyDown(oEvent); }; //assign onblur event handler (hides suggestions) this.textbox.onblur =function () ...{ oThis.hideSuggestions(); }; //create the suggestions dropdown this.createDropDown(); }; /**//** * Selects a range of text in the textbox. * @scope public * @param iStart The start index (base 0) of the selection. * @param iEnd The end index of the selection. */ AutoSuggestControl.prototype.selectRange =function (iStart /**//*:int*/, iEnd /**//*:int*/) ...{ //use text ranges for Internet Explorer if (this.textbox.createTextRange) ...{ var oRange =this.textbox.createTextRange(); oRange.moveStart("character", iStart); oRange.moveEnd("character", iEnd -this.textbox.value.length); oRange.select(); //use setSelectionRange() for Mozilla }elseif (this.textbox.setSelectionRange) ...{ this.textbox.setSelectionRange(iStart, iEnd); } //set focus back to the textbox this.textbox.focus(); }; /**//** * Builds the suggestion layer contents, moves it into position, * and displays the layer. * @scope private * @param aSuggestions An array of suggestions for the control. */ AutoSuggestControl.prototype.showSuggestions =function (aSuggestions /**//*:Array*/) ...{ var oDiv =null; this.layer.innerHTML =""; //clear contents of the layer for (var i=0; i < aSuggestions.length; i++) ...{ oDiv = document.createElement("div"); oDiv.appendChild(document.createTextNode(aSuggestions[i])); this.layer.appendChild(oDiv); } this.layer.style.left =this.getLeft() +"px"; this.layer.style.top = (this.getTop()+this.textbox.offsetHeight) +"px"; this.layer.style.visibility ="visible"; }; /**//** * Inserts a suggestion into the textbox, highlighting the * suggested part of the text. * @scope private * @param sSuggestion The suggestion for the textbox. */ AutoSuggestControl.prototype.typeAhead =function (sSuggestion /**//*:String*/) ...{ //check for support of typeahead functionality if (this.textbox.createTextRange ||this.textbox.setSelectionRange)...{ var iLen =this.textbox.value.length; this.textbox.value = sSuggestion; this.selectRange(iLen, sSuggestion.length); } }; /**//** * Provides suggestions for state/province names. * @class * @scope public */ function SuggestionProvider() ...{ this.http = zXmlHttp.createRequest(); } /**//** * Request suggestions for the given autosuggest control. * @scope protected * @param oAutoSuggestControl The autosuggest control to provide suggestions for. */ SuggestionProvider.prototype.requestSuggestions =function (oAutoSuggestControl /**//*:AutoSuggestControl*/, bTypeAhead /**//*:boolean*/) ...{ var oHttp =this.http; //cancel any active requests if (oHttp.readyState !=0) ...{ oHttp.abort(); } //define the data var oData =...{ requesting: "StatesAndProvinces", text: oAutoSuggestControl.userText, limit: 5 }; //open connection to server oHttp.open("post", "suggestions.php", true); oHttp.onreadystatechange =function () ...{ if (oHttp.readyState ==4) ...{ //evaluate the returned text JavaScript (an array) var aSuggestions = JSON.parse(oHttp.responseText); //provide suggestions to the control oAutoSuggestControl.autosuggest(aSuggestions, bTypeAhead); } }; //send the request oHttp.send(JSON.stringify(oData)); };