diff --git a/browser/components/urlbar/UrlbarView.jsm b/browser/components/urlbar/UrlbarView.jsm index 48c9c2e9a378..76deecb64d98 100644 --- a/browser/components/urlbar/UrlbarView.jsm +++ b/browser/components/urlbar/UrlbarView.jsm @@ -204,26 +204,16 @@ class UrlbarView { onQueryResults(queryContext) { this._queryContext = queryContext; - let resultIndex = 0; - for (let row of this._rows.children) { - if (resultIndex < queryContext.results.length) { - this._updateRow(row, resultIndex); - } else { - row.remove(); - } - resultIndex++; - } - for (; resultIndex < queryContext.results.length; resultIndex++) { - let row = this._createRow(); - this._updateRow(row, resultIndex); - this._rows.appendChild(row); + let fragment = this.document.createDocumentFragment(); + for (let resultIndex in queryContext.results) { + fragment.appendChild(this._createRow(resultIndex)); } let isFirstPreselectedResult = false; if (queryContext.lastResultCount == 0) { if (queryContext.preselected) { isFirstPreselectedResult = true; - this._selectItem(this._rows.firstElementChild, { + this._selectItem(fragment.firstElementChild, { updateInput: false, setAccessibleFocus: false, }); @@ -240,8 +230,22 @@ class UrlbarView { (trimmedValue[0] != UrlbarTokenizer.RESTRICT.SEARCH || trimmedValue.length != 1)) ); + } else if (this._selected) { + // Ensure the selection is stable. + // TODO bug 1523602: the selection should stay on the node that had it, if + // it's still in the current result set. + let resultIndex = this._selected.getAttribute("resultIndex"); + this._selectItem(fragment.children[resultIndex], { + updateInput: false, + setAccessibleFocus: false, + }); } + // TODO bug 1523602: For now, clear the results for each set received. + // We should be updating the existing list instead. + this._rows.textContent = ""; + this._rows.appendChild(fragment); + this._openPanel(); if (isFirstPreselectedResult) { @@ -390,11 +394,24 @@ class UrlbarView { this.panel.style.setProperty("--item-content-width", Math.round(contentWidth) + "px"); } - _createRow() { + _createRow(resultIndex) { + let result = this._queryContext.results[resultIndex]; let item = this._createElement("div"); + item.id = "urlbarView-row-" + resultIndex; item.className = "urlbarView-row"; + item.setAttribute("resultIndex", resultIndex); item.setAttribute("role", "option"); - item._elements = new Map; + + if (result.type == UrlbarUtils.RESULT_TYPE.SEARCH && + !result.payload.isKeywordOffer) { + item.setAttribute("type", "search"); + } else if (result.type == UrlbarUtils.RESULT_TYPE.REMOTE_TAB) { + item.setAttribute("type", "remotetab"); + } else if (result.type == UrlbarUtils.RESULT_TYPE.TAB_SWITCH) { + item.setAttribute("type", "switchtab"); + } else if (result.source == UrlbarUtils.RESULT_SOURCE.BOOKMARKS) { + item.setAttribute("type", "bookmark"); + } let content = this._createElement("span"); content.className = "urlbarView-row-inner"; @@ -406,67 +423,23 @@ class UrlbarView { let favicon = this._createElement("img"); favicon.className = "urlbarView-favicon"; - content.appendChild(favicon); - item._elements.set("favicon", favicon); - - let title = this._createElement("span"); - title.className = "urlbarView-title"; - content.appendChild(title); - item._elements.set("title", title); - - let tagsContainer = this._createElement("div"); - tagsContainer.className = "urlbarView-tags"; - content.appendChild(tagsContainer); - item._elements.set("tagsContainer", tagsContainer); - - let titleSeparator = this._createElement("span"); - titleSeparator.className = "urlbarView-title-separator"; - content.appendChild(titleSeparator); - - let action = this._createElement("span"); - action.className = "urlbarView-secondary urlbarView-action"; - content.appendChild(action); - item._elements.set("action", action); - - let url = this._createElement("span"); - url.className = "urlbarView-secondary urlbarView-url"; - content.appendChild(url); - item._elements.set("url", url); - - return item; - } - - _updateRow(item, resultIndex) { - let result = this._queryContext.results[resultIndex]; - item.id = "urlbarView-row-" + resultIndex; - item.setAttribute("resultIndex", resultIndex); - - if (result.type == UrlbarUtils.RESULT_TYPE.SEARCH && - !result.payload.isKeywordOffer) { - item.setAttribute("type", "search"); - } else if (result.type == UrlbarUtils.RESULT_TYPE.REMOTE_TAB) { - item.setAttribute("type", "remotetab"); - } else if (result.type == UrlbarUtils.RESULT_TYPE.TAB_SWITCH) { - item.setAttribute("type", "switchtab"); - } else if (result.source == UrlbarUtils.RESULT_SOURCE.BOOKMARKS) { - item.setAttribute("type", "bookmark"); - } else { - item.removeAttribute("type"); - } - - let favicon = item._elements.get("favicon"); if (result.type == UrlbarUtils.RESULT_TYPE.SEARCH || result.type == UrlbarUtils.RESULT_TYPE.KEYWORD) { favicon.src = result.payload.icon || UrlbarUtils.ICON.SEARCH_GLASS; } else { favicon.src = result.payload.icon || UrlbarUtils.ICON.DEFAULT; } + content.appendChild(favicon); + let title = this._createElement("span"); + title.className = "urlbarView-title"; this._addTextContentWithHighlights( - item._elements.get("title"), result.title, result.titleHighlights); + title, result.title, result.titleHighlights); + content.appendChild(title); - let tagsContainer = item._elements.get("tagsContainer"); if (result.payload.tags && result.payload.tags.length > 0) { + const tagsContainer = this._createElement("div"); + tagsContainer.className = "urlbarView-tags"; tagsContainer.append(...result.payload.tags.map((tag, i) => { const element = this._createElement("span"); element.className = "urlbarView-tag"; @@ -474,49 +447,63 @@ class UrlbarView { element, tag, result.payloadHighlights.tags[i]); return element; })); - } else { - tagsContainer.textContent = ""; + content.appendChild(tagsContainer); } - let action = ""; - let setURL = false; + let titleSeparator = this._createElement("span"); + titleSeparator.className = "urlbarView-title-separator"; + content.appendChild(titleSeparator); + + let action; + let url; + let setAction = text => { + action = this._createElement("span"); + action.className = "urlbarView-secondary urlbarView-action"; + action.textContent = text; + }; + let setURL = () => { + url = this._createElement("span"); + url.className = "urlbarView-secondary urlbarView-url"; + this._addTextContentWithHighlights(url, result.payload.displayUrl, + result.payloadHighlights.displayUrl || []); + }; switch (result.type) { case UrlbarUtils.RESULT_TYPE.TAB_SWITCH: - action = bundle.GetStringFromName("switchToTab2"); - setURL = true; + setAction(bundle.GetStringFromName("switchToTab2")); + setURL(); break; case UrlbarUtils.RESULT_TYPE.REMOTE_TAB: - action = result.payload.device; - setURL = true; + setAction(result.payload.device); + setURL(); break; case UrlbarUtils.RESULT_TYPE.SEARCH: - action = bundle.formatStringFromName("searchWithEngine", - [result.payload.engine], 1); + setAction(bundle.formatStringFromName("searchWithEngine", + [result.payload.engine], 1)); break; case UrlbarUtils.RESULT_TYPE.KEYWORD: if (result.payload.input.trim() == result.payload.keyword) { - action = bundle.GetStringFromName("visit"); + setAction(bundle.GetStringFromName("visit")); } break; case UrlbarUtils.RESULT_TYPE.OMNIBOX: - action = result.payload.content; + setAction(result.payload.content); break; default: if (result.heuristic) { - action = bundle.GetStringFromName("visit"); + setAction(bundle.GetStringFromName("visit")); } else { - setURL = true; + setURL(); } break; } - let url = item._elements.get("url"); - if (setURL) { - this._addTextContentWithHighlights(url, result.payload.displayUrl, - result.payloadHighlights.displayUrl || []); - } else { - url.textContent = ""; + if (action) { + content.appendChild(action); } - item._elements.get("action").textContent = action; + if (url) { + content.appendChild(url); + } + + return item; } _selectItem(item, { @@ -564,7 +551,6 @@ class UrlbarView { * The matches to highlight in the text. */ _addTextContentWithHighlights(parentNode, textContent, highlights) { - parentNode.textContent = ""; if (!textContent) { return; } diff --git a/browser/themes/shared/urlbar-autocomplete.inc.css b/browser/themes/shared/urlbar-autocomplete.inc.css index 2742d3e0cbaf..cf3aba78ca73 100644 --- a/browser/themes/shared/urlbar-autocomplete.inc.css +++ b/browser/themes/shared/urlbar-autocomplete.inc.css @@ -126,7 +126,7 @@ margin: 0 .4em; } -.urlbarView-title:empty + .urlbarView-tags:empty + .urlbarView-title-separator { +.urlbarView-title:empty + .urlbarView-title-separator { display: none; }