null null false null null null null null parseInt(this.getAttribute("shrinkdelay")) || 0 { let utils = {}; Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm", utils); utils.PrivateBrowsingUtils } 14 false false null = 1) this.mController.handleTab(); break; case KeyEvent.DOM_VK_UP: case KeyEvent.DOM_VK_DOWN: case KeyEvent.DOM_VK_PAGE_UP: case KeyEvent.DOM_VK_PAGE_DOWN: cancel = this.mController.handleKeyNavigation(aEvent.keyCode); break; } } // Handle keys we know aren't part of a shortcut, even with Alt or // Ctrl. switch (aEvent.keyCode) { case KeyEvent.DOM_VK_ESCAPE: cancel = this.mController.handleEscape(); break; case KeyEvent.DOM_VK_RETURN: if (AppConstants.platform == "macosx") { // Prevent the default action, since it will beep on Mac if (aEvent.metaKey) aEvent.preventDefault(); } this.mEnterEvent = aEvent; if (this.mController.selection) { this._selectionDetails = { index: this.mController.selection.currentIndex, kind: "key" }; } cancel = this.handleEnter(); break; case KeyEvent.DOM_VK_DELETE: if (AppConstants.platform == "macosx" && !aEvent.shiftKey) { break; } cancel = this.handleDelete(); break; case KeyEvent.DOM_VK_BACK_SPACE: if (AppConstants.platform == "macosx" && aEvent.shiftKey) { cancel = this.handleDelete(); } break; case KeyEvent.DOM_VK_DOWN: case KeyEvent.DOM_VK_UP: if (aEvent.altKey) this.toggleHistoryPopup(); break; case KeyEvent.DOM_VK_F4: if (AppConstants.platform != "macosx") { this.toggleHistoryPopup(); } break; } if (cancel) { aEvent.stopPropagation(); aEvent.preventDefault(); } return true; ]]> false aCommand == "cmd_paste", doCommand: function(aCommand) { this._autocomplete._valueIsPasted = true; this._autocomplete.editor.paste(this._kGlobalClipboard); this._autocomplete._valueIsPasted = false; }, isCommandEnabled: function(aCommand) { return this._autocomplete.editor.isSelectionEditable && this._autocomplete.editor.canPaste(this._kGlobalClipboard); }, onEvent: function() {} }) ]]> = 1) { // mousemove sets selected index. Don't blindly use that selected // index in this blur handler since if the popup is open you can // easily "select" another match just by moving the mouse over it. let filledVal = this.value.replace(/.+ >> /, "").toLowerCase(); let selectedVal = null; if (this.popup.selectedIndex >= 0) { selectedVal = this.mController.getFinalCompleteValueAt( this.popup.selectedIndex); } if (selectedVal && filledVal != selectedVal.toLowerCase()) { for (let i = 0; i < this.mController.matchCount; i++) { let matchVal = this.mController.getFinalCompleteValueAt(i); if (matchVal.toLowerCase() == filledVal) { this.popup.selectedIndex = i; break; } } } this.mController.handleEnter(false); } if (!this.ignoreBlurWhileSearching) this.detachController(); } ]]> false false 0) this.tree.treeBoxObject.ensureRowIsVisible(val < 0 ? 0 : val); // Fire select event on xul:tree so that accessibility API // support layer can fire appropriate accessibility events. var event = document.createEvent('Events'); event.initEvent("select", true, true); this.tree.dispatchEvent(event); return val; ]]> 100 ? width : 100); // Adjust the direction of the autocomplete popup list based on the textbox direction, bug 649840 var popupDirection = aElement.ownerDocument.defaultView.getComputedStyle(aElement).direction; this.style.direction = popupDirection; this.openPopup(aElement, "after_start", 0, 0, false, false); } ]]> document.getAnonymousElementByAttribute(this, "anonid", "tree"); document.getAnonymousElementByAttribute(this, "anonid", "treecols"); null false 6 -1 aMaxRow && aIndex != aMaxRow) newIdx = aMaxRow; else if (!aReverse && aIndex == -1 || newIdx < 0 && aIndex != 0) newIdx = 0; if (newIdx < 0 && aIndex == 0 || newIdx > aMaxRow && aIndex == aMaxRow) aIndex = -1; else aIndex = newIdx; return aIndex; ]]> 0 0 false 100 ? width : 100); // invalidate() depends on the width attribute this._invalidate(); this.openPopup(aElement, "after_start", 0, 0, false, false); } ]]> this.adjustHeight(), 0); this._currentIndex = 0; if (this._appendResultTimeout) { clearTimeout(this._appendResultTimeout); } this._appendCurrentResult(reason); ]]> currentHeight) { // Grow immediately. if (animate) { this.richlistbox.removeAttribute("height"); this.richlistbox.style.height = height + "px"; } else { this.richlistbox.style.removeProperty("height"); this.richlistbox.height = height; } } else { // Delay shrinking to avoid flicker. this._shrinkTimeout = setTimeout(() => { this._collapseUnusedItems(); if (animate) { this.richlistbox.removeAttribute("height"); this.richlistbox.style.height = height + "px"; } else { this.richlistbox.style.removeProperty("height"); this.richlistbox.height = height; } }, this.mInput.shrinkDelay); } ]]> = matchCount) break; var item; // trim the leading/trailing whitespace var trimmedSearchString = controller.searchString.replace(/^\s+/, "").replace(/\s+$/, ""); let url = controller.getValueAt(this._currentIndex); if (this._currentIndex < existingItemsCount) { // re-use the existing item item = this.richlistbox.childNodes[this._currentIndex]; // Completely reuse the existing richlistitem for invalidation // due to new results, but only when: the item is the same, *OR* // we are about to replace the currently mouse-selected item, to // avoid surprising the user. let iface = Components.interfaces.nsIAutoCompletePopup; if (item.getAttribute("text") == trimmedSearchString && invalidateReason == iface.INVALIDATE_REASON_NEW_RESULT && (item.getAttribute("url") == url || this.richlistbox.mouseSelectedIndex === this._currentIndex)) { item.collapsed = false; this._currentIndex++; continue; } } else { // need to create a new item item = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "richlistitem"); } // set these attributes before we set the class // so that we can use them from the constructor let iconURI = controller.getImageAt(this._currentIndex); item.setAttribute("image", iconURI); item.setAttribute("url", url); item.setAttribute("title", controller.getCommentAt(this._currentIndex)); item.setAttribute("type", controller.getStyleAt(this._currentIndex)); item.setAttribute("text", trimmedSearchString); if (this._currentIndex < existingItemsCount) { // re-use the existing item item._adjustAcItem(); item.collapsed = false; } else { // set the class at the end so we can use the attributes // in the xbl constructor item.className = "private-autocomplete-richlistitem"; this.richlistbox.appendChild(item); } this._currentIndex++; } if (typeof this.onResultsAdded == "function") this.onResultsAdded(); if (this._currentIndex < matchCount) { // yield after each batch of items so that typing the url bar is // responsive this._appendResultTimeout = setTimeout(() => this._appendCurrentResult(), 0); } ]]> document.getAnonymousElementByAttribute(this, "anonid", "richlistbox"); str).join(" ") // allow consumers that have extended popups to override // the label values for the richlistitems let panel = this.parentNode.parentNode; if (panel.createResultLabel) { return panel.createResultLabel(this, label); } return label; ]]> null = 0) { regions.push([matchIndex, matchIndex + searchLen]); } } // Sort the regions by start position then end position regions = regions.sort((a, b) => { let start = a[0] - b[0]; return (start == 0) ? a[1] - b[1] : start; }); // Generate the boundary indices from each region let start = 0; let end = 0; let boundaries = []; let len = regions.length; for (let i = 0; i < len; i++) { // We have a new boundary if the start of the next is past the end let region = regions[i]; if (region[0] > end) { // First index is the beginning of match boundaries.push(start); // Second index is the beginning of non-match boundaries.push(end); // Track the new region now that we've stored the previous one start = region[0]; } // Push back the end index for the current or new region end = Math.max(end, region[1]); } // Add the last region boundaries.push(start); boundaries.push(end); // Put on the end boundary if necessary if (end < aText.length) boundaries.push(aText.length); // Skip the first item because it's always 0 return boundaries.slice(1); ]]> = 0 && index < aReplacements.length) { pairs.push([...aReplacements[index]]); } } else { pairs.push([part]); } } return pairs; ]]> null = 0) { pairs = [ [searchSuggestion.substring(0, idx), ""], [searchQuery, "match"], [searchSuggestion.substring(idx + searchQuery.length), ""], ]; } else { pairs = [ [searchSuggestion, ""], ]; } } else { pairs = [ [searchQuery, ""], ]; } pairs.push([engineStr, "selected"]); let interpStr = pairs.map((pair, i) => `%${i + 1}$S`).join(""); title = this._generateEmphasisPairs(interpStr, pairs); // If this is a default search match, we remove the image so we // can style it ourselves with a generic search icon. // We don't do this when matching an aliased search engine, // because the icon helps with recognising which engine will be // used (when using the default engine, we don't need that // recognition). if (!action.params.alias) { this.removeAttribute("image"); } } else if (action.type == "visiturl") { emphasiseUrl = false; displayUrl = this._unescapeUrl(action.params.url); let sourceStr = this._stringBundle.GetStringFromName("visitURL"); title = this._generateEmphasisPairs(sourceStr, [ [displayUrl, "match"], ]); } } // Check if we have a search engine name if (initialTypes.has("search")) { emphasiseUrl = false; const TITLE_SEARCH_ENGINE_SEPARATOR = " \u00B7\u2013\u00B7 "; let searchEngine = ""; [title, searchEngine] = title.split(TITLE_SEARCH_ENGINE_SEPARATOR); displayUrl = this._stringBundle.formatStringFromName("searchWithEngine", [searchEngine], 1); } if (!displayUrl) { let input = this.parentNode.parentNode.input; let url = typeof(input.trimValue) == "function" ? input.trimValue(originalUrl) : originalUrl; displayUrl = this._unescapeUrl(url); } this.setAttribute("displayurl", displayUrl); // Check if we have an auto-fill URL if (initialTypes.has("autofill")) { emphasiseUrl = false; let sourceStr = this._stringBundle.GetStringFromName("visitURL"); title = this._generateEmphasisPairs(sourceStr, [ [displayUrl, "match"], ]); } // If we have a tag match, show the tags and icon if (type == "tag" || type == "bookmark-tag") { // Configure the extra box for tags display this._extraBox.hidden = false; this._extraBox.childNodes[0].hidden = false; this._extraBox.childNodes[1].hidden = true; this._extraBox.pack = "end"; this._titleBox.flex = 1; // The title is separated from the tags by an endash let tags; [, title, tags] = title.match(/^(.+) \u2013 (.+)$/); // Each tag is split by a comma in an undefined order, so sort it let sortedTags = tags.split(",").sort().join(", "); // Emphasize the matching text in the tags this._setUpDescription(this._extra, sortedTags); // If we're suggesting bookmarks, then treat tagged matches as // bookmarks for the star. if (type == "bookmark-tag") { type = "bookmark"; } else { this._typeImage.hidden = true; } // keyword and favicon type results for search engines // have an extra magnifying glass icon after them } else if (type == "keyword" || (initialTypes.has("search") && initialTypes.has("favicon"))) { // Configure the extra box for keyword display this._extraBox.hidden = false; this._extraBox.childNodes[0].hidden = true; // The second child node is ":" and it should be hidden for non keyword types this._extraBox.childNodes[1].hidden = type == "keyword" ? false : true; this._extraBox.pack = "start"; this._titleBox.flex = 0; // Hide the ellipsis so it doesn't take up space. this._titleOverflowEllipsis.hidden = true; if (type == "keyword") { // Put the parameters next to the title if we have any let search = this.getAttribute("text"); let params = ""; let paramsIndex = search.indexOf(" "); if (paramsIndex != -1) params = search.substr(paramsIndex + 1); // Emphasize the keyword parameters this._setUpDescription(this._extra, params); // Don't emphasize keyword searches in the title or url emphasiseUrl = false; emphasiseTitle = false; } else { // Don't show any description for non keyword types. this._setUpDescription(this._extra, "", true); } // If the result has the type favicon and a known search provider, // customize it the same way as a keyword result. type = "keyword"; } // Give the image the icon style and a special one for the type this._typeImage.className = "ac-type-icon" + (type ? " ac-result-type-" + type : ""); // Show the domain as the title if we don't have a title. if (title == "") { title = displayUrl; try { let uri = Services.io.newURI(originalUrl, null, null); // Not all valid URLs have a domain. if (uri.host) title = uri.host; } catch (e) {} } // Emphasize the matching search terms for the description if (Array.isArray(title)) this._setUpEmphasisedSections(this._title, title); else this._setUpDescription(this._title, title, !emphasiseTitle); this._setUpDescription(this._url, displayUrl, !emphasiseUrl); // Set up overflow on a timeout because the contents of the box // might not have a width yet even though we just changed them setTimeout(this._setUpOverflow, 0, this._titleBox, this._titleOverflowEllipsis); setTimeout(this._setUpOverflow, 0, this._urlBox, this._urlOverflowEllipsis); ]]> 0) { // Subtract a little less to account for subpixel rounding widthDiff -= childWidth - .5; // Add to the tooltip if it's not hidden and has text let childText = children[i].textContent; if (childText) tooltip.push(childText); } } // If the children take up more space than the parent.. overflow! if (widthDiff < 0) { // Re-show the ellipsis now that we know it's needed aEllipsis.style.visibility = "visible"; // Separate text components with a ndash -- aParentBox.tooltipText = tooltip.join(" \u2013 "); } ]]> Date.now() -1 30) { let item = event.target; while (item && item.localName != "richlistitem") { item = item.parentNode; } if (!item) return; let index = this.getIndexOfItem(item); if (index != this.selectedIndex) { this.mouseSelectedIndex = this.selectedIndex = index; } this.mLastMoveTime = Date.now(); } ]]> Date.now() 30) { var rc = this.parentNode.treeBoxObject.getRowAt(event.clientX, event.clientY); if (rc != this.parentNode.currentIndex) this.parentNode.view.selection.select(rc); this.mLastMoveTime = Date.now(); } ]]>