📄 autocomplete.js
字号:
if(!oSelf._queryInterval && oSelf.queryInterval) { oSelf._queryInterval = setInterval(function() { oSelf._onInterval(); }, oSelf.queryInterval); }};/** * Enables query triggers based on text input detection by intervals (rather * than by key events). * * @method _onInterval * @private */YAHOO.widget.AutoComplete.prototype._onInterval = function() { var currValue = this._elTextbox.value; var lastValue = this._sLastTextboxValue; if(currValue != lastValue) { this._sLastTextboxValue = currValue; this._sendQuery(currValue); }};/** * Cancels text input detection by intervals. * * @method _clearInterval * @param oSelf {YAHOO.widget.AutoComplete} The AutoComplete instance. * @private */YAHOO.widget.AutoComplete.prototype._clearInterval = function() { if(this._queryInterval) { clearInterval(this._queryInterval); this._queryInterval = null; }};/** * Whether or not key is functional or should be ignored. Note that the right * arrow key is NOT an ignored key since it triggers queries for certain intl * charsets. * * @method _isIgnoreKey * @param nKeycode {Number} Code of key pressed. * @return {Boolean} True if key should be ignored, false otherwise. * @private */YAHOO.widget.AutoComplete.prototype._isIgnoreKey = function(nKeyCode) { if((nKeyCode == 9) || (nKeyCode == 13) || // tab, enter (nKeyCode == 16) || (nKeyCode == 17) || // shift, ctl (nKeyCode >= 18 && nKeyCode <= 20) || // alt, pause/break,caps lock (nKeyCode == 27) || // esc (nKeyCode >= 33 && nKeyCode <= 35) || // page up,page down,end /*(nKeyCode >= 36 && nKeyCode <= 38) || // home,left,up (nKeyCode == 40) || // down*/ (nKeyCode >= 36 && nKeyCode <= 40) || // home,left,up, right, down (nKeyCode >= 44 && nKeyCode <= 45) || // print screen,insert (nKeyCode == 229) // Bug 2041973: Korean XP fires 2 keyup events, the key and 229 ) { return true; } return false;};/** * Makes query request to the DataSource. * * @method _sendQuery * @param sQuery {String} Query string. * @private */YAHOO.widget.AutoComplete.prototype._sendQuery = function(sQuery) { // Widget has been effectively turned off if(this.minQueryLength < 0) { this._toggleContainer(false); return; } // Delimiter has been enabled var aDelimChar = (this.delimChar) ? this.delimChar : null; if(aDelimChar) { // Loop through all possible delimiters and find the rightmost one in the query // A " " may be a false positive if they are defined as delimiters AND // are used to separate delimited queries var nDelimIndex = -1; for(var i = aDelimChar.length-1; i >= 0; i--) { var nNewIndex = sQuery.lastIndexOf(aDelimChar[i]); if(nNewIndex > nDelimIndex) { nDelimIndex = nNewIndex; } } // If we think the last delimiter is a space (" "), make sure it is NOT // a false positive by also checking the char directly before it if(aDelimChar[i] == " ") { for (var j = aDelimChar.length-1; j >= 0; j--) { if(sQuery[nDelimIndex - 1] == aDelimChar[j]) { nDelimIndex--; break; } } } // A delimiter has been found in the query so extract the latest query from past selections if(nDelimIndex > -1) { var nQueryStart = nDelimIndex + 1; // Trim any white space from the beginning... while(sQuery.charAt(nQueryStart) == " ") { nQueryStart += 1; } // ...and save the rest of the string for later this._sPastSelections = sQuery.substring(0,nQueryStart); // Here is the query itself sQuery = sQuery.substr(nQueryStart); } // No delimiter found in the query, so there are no selections from past queries else { this._sPastSelections = ""; } } // Don't search queries that are too short if((sQuery && (sQuery.length < this.minQueryLength)) || (!sQuery && this.minQueryLength > 0)) { if(this._nDelayID != -1) { clearTimeout(this._nDelayID); } this._toggleContainer(false); return; } sQuery = encodeURIComponent(sQuery); this._nDelayID = -1; // Reset timeout ID because request is being made // Subset matching if(this.dataSource.queryMatchSubset || this.queryMatchSubset) { // backward compat var oResponse = this.getSubsetMatches(sQuery); if(oResponse) { this.handleResponse(sQuery, oResponse, {query: sQuery}); return; } } if(this.responseStripAfter) { this.dataSource.doBeforeParseData = this.preparseRawResponse; } if(this.applyLocalFilter) { this.dataSource.doBeforeCallback = this.filterResults; } var sRequest = this.generateRequest(sQuery); this.dataRequestEvent.fire(this, sQuery, sRequest); this.dataSource.sendRequest(sRequest, { success : this.handleResponse, failure : this.handleResponse, scope : this, argument: { query: sQuery } });};/** * Populates the array of <li> elements in the container with query * results. * * @method _populateList * @param sQuery {String} Original request. * @param oResponse {Object} Response object. * @param oPayload {MIXED} (optional) Additional argument(s) * @private */YAHOO.widget.AutoComplete.prototype._populateList = function(sQuery, oResponse, oPayload) { // Clear previous timeout if(this._nTypeAheadDelayID != -1) { clearTimeout(this._nTypeAheadDelayID); } sQuery = (oPayload && oPayload.query) ? oPayload.query : sQuery; // Pass data through abstract method for any transformations var ok = this.doBeforeLoadData(sQuery, oResponse, oPayload); // Data is ok if(ok && !oResponse.error) { this.dataReturnEvent.fire(this, sQuery, oResponse.results); // Continue only if instance is still focused (i.e., user hasn't already moved on) // Null indicates initialized state, which is ok too if(this._bFocused || (this._bFocused === null)) { //TODO: is this still necessary? /*var isOpera = (YAHOO.env.ua.opera); var contentStyle = this._elContent.style; contentStyle.width = (!isOpera) ? null : ""; contentStyle.height = (!isOpera) ? null : "";*/ // Store state for this interaction var sCurQuery = decodeURIComponent(sQuery); this._sCurQuery = sCurQuery; this._bItemSelected = false; var allResults = oResponse.results, nItemsToShow = Math.min(allResults.length,this.maxResultsDisplayed), sMatchKey = (this.dataSource.responseSchema.fields) ? (this.dataSource.responseSchema.fields[0].key || this.dataSource.responseSchema.fields[0]) : 0; if(nItemsToShow > 0) { // Make sure container and helpers are ready to go if(!this._elList || (this._elList.childNodes.length < nItemsToShow)) { this._initListEl(); } this._initContainerHelperEls(); var allListItemEls = this._elList.childNodes; // Fill items with data from the bottom up for(var i = nItemsToShow-1; i >= 0; i--) { var elListItem = allListItemEls[i], oResult = allResults[i]; // Backward compatibility if(this.resultTypeList) { // Results need to be converted back to an array var aResult = []; // Match key is first aResult[0] = (YAHOO.lang.isString(oResult)) ? oResult : oResult[sMatchKey] || oResult[this.key]; // Add additional data to the result array var fields = this.dataSource.responseSchema.fields; if(YAHOO.lang.isArray(fields) && (fields.length > 1)) { for(var k=1, len=fields.length; k<len; k++) { aResult[aResult.length] = oResult[fields[k].key || fields[k]]; } } // No specific fields defined, so pass along entire data object else { // Already an array if(YAHOO.lang.isArray(oResult)) { aResult = oResult; } // Simple string else if(YAHOO.lang.isString(oResult)) { aResult = [oResult]; } // Object else { aResult[1] = oResult; } } oResult = aResult; } // The matching value, including backward compatibility for array format and safety net elListItem._sResultMatch = (YAHOO.lang.isString(oResult)) ? oResult : (YAHOO.lang.isArray(oResult)) ? oResult[0] : (oResult[sMatchKey] || ""); elListItem._oResultData = oResult; // Additional data elListItem.innerHTML = this.formatResult(oResult, sCurQuery, elListItem._sResultMatch); elListItem.style.display = ""; } // Clear out extraneous items if(nItemsToShow < allListItemEls.length) { var extraListItem; for(var j = allListItemEls.length-1; j >= nItemsToShow; j--) { extraListItem = allListItemEls[j]; extraListItem.style.display = "none"; } } this._nDisplayedItems = nItemsToShow; this.containerPopulateEvent.fire(this, sQuery, allResults); // Highlight the first item if(this.autoHighlight) { var elFirstListItem = this._elList.firstChild; this._toggleHighlight(elFirstListItem,"to"); this.itemArrowToEvent.fire(this, elFirstListItem); this._typeAhead(elFirstListItem,sQuery); } // Unhighlight any previous time else { this._toggleHighlight(this._elCurListItem,"from"); } // Expand the container ok = this.doBeforeExpandContainer(this._elTextbox, this._elContainer, sQuery, allResults); this._toggleContainer(ok); } else { this._toggleContainer(false); } return; } } // Error else { this.dataErrorEvent.fire(this, sQuery); } };/** * When forceSelection is true and the user attempts * leave the text input box without selecting an item from the query results, * the user selection is cleared. * * @method _clearSelection * @private */YAHOO.widget.AutoComplete.prototype._clearSelection = function() { var sValue = this._elTextbox.value; //TODO: need to check against all delimChars? var sChar = (this.delimChar) ? this.delimChar[0] : null; var nIndex = (sChar) ? sValue.lastIndexOf(sChar, sValue.length-2) : -1; if(nIndex > -1) { this._elTextbox.value = sValue.substring(0,nIndex); } else { this._elTextbox.value = ""; } this._sPastSelections = this._elTextbox.value; // Fire custom event this.selectionEnforceEvent.fire(this);};/** * Whether or not user-typed value in the text input box matches any of the * query results. * * @method _textMatchesOption * @return {HTMLElement} Matching list item element if user-input text matches * a result, null otherwise. * @private */YAHOO.widget.AutoComplete.prototype._textMatchesOption = function() { var elMatch = null; for(var i = this._nDisplayedItems-1; i >= 0 ; i--) { var elListItem = this._elList.childNodes[i]; var sMatch = ("" + elListItem._sResultMatch).toLowerCase(); if(sMatch == this._sCurQuery.toLowerCase()) { elMatch = elListItem; break; } } return(elMatch);};/** * Updates in the text input box with the first query result as the user types, * selecting the substring that the user has not typed. * * @method _typeAhead * @param elListItem {HTMLElement} The <li> element item whose data populates the input field. * @param sQuery {String} Query string. * @private */YAHOO.widget.AutoComplete.prototype._typeAhead = function(elListItem, sQuery) { // Don't typeAhead if turned off or is backspace if(!this.typeAhead || (this._nKeyCode == 8)) { return; } var oSelf = this, elTextbox = this._elTextbox; // Only if text selection is supported if(elTextbox.setSelectionRange || elTextbox.createTextRange) { // Set and store timeout for this typeahead this._nTypeAheadDelayID = setTimeout(function() { // Select the portion of text that the user has not typed var nStart = elTextbox.value.length; // any saved queries plus what user has typed oSelf._updateValue(elListItem); var nEnd = elTextbox.value.length; oSelf._selectText(elTextbox,nStart,nEnd); var sPrefill = elTextbox.value.substr(nStart,nEnd); oSelf.typeAheadEvent.fire(oSelf,sQuery,sPrefill); },(this.typeAheadDelay*1000)); }};/** * Selects text in the input field. * * @method _selectText * @param elTextbox {HTMLElement} Text input box element in which to select text. * @param nStart {Number} Starting index of text string to select. * @param nEnd {Number} Ending index of text selection. * @private */YAHOO.widget.AutoComplete.prototype._selectText = function(elTextbox, nStart, nEnd) { if(elTextbox.setSelectionRange) { // For Mozilla elTextbox.setSelectionRange(nStar
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -