From fbaf0bb26397aa498eb9156f06d5a6fe34dd7dd8 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 03:14:29 +0200 Subject: Merging upstream version 125.0.1. Signed-off-by: Daniel Baumann --- browser/components/urlbar/UrlbarView.sys.mjs | 115 +++++++++++++++++++-------- 1 file changed, 82 insertions(+), 33 deletions(-) (limited to 'browser/components/urlbar/UrlbarView.sys.mjs') diff --git a/browser/components/urlbar/UrlbarView.sys.mjs b/browser/components/urlbar/UrlbarView.sys.mjs index 440c06d4a1..b5fe1e1955 100644 --- a/browser/components/urlbar/UrlbarView.sys.mjs +++ b/browser/components/urlbar/UrlbarView.sys.mjs @@ -463,15 +463,18 @@ export class UrlbarView { this.#setRowSelectable(row, false); // Replace the row with a dismissal acknowledgment tip. - let tip = new lazy.UrlbarResult( - lazy.UrlbarUtils.RESULT_TYPE.TIP, - lazy.UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL, - { - type: "dismissalAcknowledgment", - titleL10n, - buttons: [{ l10n: { id: "urlbar-search-tips-confirm-short" } }], - icon: "chrome://branding/content/icon32.png", - } + let tip = Object.assign( + new lazy.UrlbarResult( + lazy.UrlbarUtils.RESULT_TYPE.TIP, + lazy.UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL, + { + type: "dismissalAcknowledgment", + titleL10n, + buttons: [{ l10n: { id: "urlbar-search-tips-confirm-short" } }], + icon: "chrome://branding/content/icon32.png", + } + ), + { rowLabel: this.#rowLabel(row) } ); this.#updateRow(row, tip); this.#updateIndices(); @@ -693,7 +696,7 @@ export class UrlbarView { this.#cacheL10nStrings(); } - onQueryCancelled(queryContext) { + onQueryCancelled() { this.#queryWasCancelled = true; this.#cancelRemoveStaleRowsTimer(); } @@ -1130,6 +1133,8 @@ export class UrlbarView { */ #rowCanUpdateToResult(rowIndex, result, seenSearchSuggestion) { // The heuristic result must always be current, thus it's always compatible. + // Note that the `updateResults` code, when updating the selection, relies + // on the fact the heuristic is the first selectable row. if (result.heuristic) { return true; } @@ -1176,6 +1181,10 @@ export class UrlbarView { // future we should make it support any type of result. Or, even better, // results should be grouped, thus we can directly update groups. + // Discard tentative exposures. This is analogous to marking the + // hypothetical hidden rows of hidden-exposure results as stale. + this.controller.engagementEvent.discardTentativeExposures(); + // Walk rows and find an insertion index for results. To avoid flicker, we // skip rows until we find one compatible with the result we want to apply. // If we couldn't find a compatible range, we'll just update. @@ -1212,7 +1221,7 @@ export class UrlbarView { ) { // We can replace the row's current result with the new one. if (result.exposureResultHidden) { - this.#addExposure(result); + this.controller.engagementEvent.addExposure(result); } else { this.#updateRow(row, result); } @@ -1282,7 +1291,13 @@ export class UrlbarView { newSpanCount <= this.#queryContext.maxResults && !seenMisplacedResult; if (result.exposureResultHidden) { if (canBeVisible) { - this.#addExposure(result); + this.controller.engagementEvent.addExposure(result); + } else { + // Add a tentative exposure: The hypothetical row for this + // hidden-exposure result can't be visible now, but as long as it were + // not marked stale in a later update, it would be shown when stale + // rows are removed. + this.controller.engagementEvent.addTentativeExposure(result); } continue; } @@ -1323,10 +1338,17 @@ export class UrlbarView { // on the row itself so that screen readers ignore it. item.setAttribute("role", "presentation"); + // These are used to cleanup result specific entities when row contents are + // cleared to reuse the row for a different result. + item._sharedAttributes = new Set( + [...item.attributes].map(v => v.name).concat(["stale", "id"]) + ); + item._sharedClassList = new Set(item.classList); + return item; } - #createRowContent(item, result) { + #createRowContent(item) { // The url is the only element that can wrap, thus all the other elements // are child of noWrap. let noWrap = this.#createElement("span"); @@ -1505,7 +1527,7 @@ export class UrlbarView { return classes; } - #createRowContentForRichSuggestion(item, result) { + #createRowContentForRichSuggestion(item) { item._content.toggleAttribute("selectable", true); let favicon = this.#createElement("img"); @@ -1615,7 +1637,7 @@ export class UrlbarView { // eslint-disable-next-line complexity #updateRow(item, result) { let oldResult = item.result; - let oldResultType = item.result && item.result.type; + let oldResultType = item.result?.type; let provider = lazy.UrlbarProvidersManager.getProvider(result.providerName); item.result = result; item.removeAttribute("stale"); @@ -1638,6 +1660,18 @@ export class UrlbarView { oldResult.payload.buttons, result.payload.buttons ) || + // Reusing a non-heuristic as a heuristic is risky as it may have DOM + // nodes/attributes/classes that are normally not present in a heuristic + // result. This may happen for example when switching from a zero-prefix + // search not having a heuristic to a search string one. + result.heuristic != oldResult.heuristic || + // Container switch-tab results have a more complex DOM content that is + // only updated correctly by another switch-tab result. + (oldResultType == lazy.UrlbarUtils.RESULT_TYPE.TAB_SWITCH && + lazy.UrlbarProviderOpenTabs.isContainerUserContextId( + oldResult.payload.userContextId + ) && + result.type != oldResultType) || result.testForceNewContent; if (needsNewContent) { @@ -1649,8 +1683,18 @@ export class UrlbarView { item._content = this.#createElement("span"); item._content.className = "urlbarView-row-inner"; item.appendChild(item._content); - item.removeAttribute("tip-type"); - item.removeAttribute("dynamicType"); + // Clear previously set attributes and classes that may refer to a + // different result type. + for (const attribute of item.attributes) { + if (!item._sharedAttributes.has(attribute.name)) { + item.removeAttribute(attribute.name); + } + } + for (const className of item.classList) { + if (!item._sharedClassList.has(className)) { + item.classList.remove(className); + } + } if (item.result.type == lazy.UrlbarUtils.RESULT_TYPE.DYNAMIC) { this.#createRowContentForDynamicType(item, result); } else if (result.isRichSuggestion) { @@ -1875,7 +1919,6 @@ export class UrlbarView { item.toggleAttribute("has-url", setURL); let url = item._elements.get("url"); if (setURL) { - item.setAttribute("has-url", "true"); let displayedUrl = result.payload.displayUrl; let urlHighlights = result.payloadHighlights.displayUrl || []; if (lazy.UrlbarUtils.isTextDirectionRTL(displayedUrl, this.window)) { @@ -2093,7 +2136,7 @@ export class UrlbarView { let visible = this.#isElementVisible(item); if (visible) { if (item.result.exposureResultType) { - this.#addExposure(item.result); + this.controller.engagementEvent.addExposure(item.result); } this.visibleResults.push(item.result); } @@ -2200,6 +2243,10 @@ export class UrlbarView { return null; } + if (row.result.rowLabel) { + return row.result.rowLabel; + } + let engineName = row.result.payload.engine || Services.search.defaultEngine.name; @@ -2326,6 +2373,10 @@ export class UrlbarView { row = next; } this.#updateIndices(); + + // Accept tentative exposures. This is analogous to unhiding the + // hypothetical non-stale hidden rows of hidden-exposure results. + this.controller.engagementEvent.acceptTentativeExposures(); } #startRemoveStaleRowsTimer() { @@ -2645,7 +2696,7 @@ export class UrlbarView { if ( actionNode.classList.contains("urlbarView-userContext") && label && - actionNode.querySelector("span").innerText == label + actionNode.querySelector("span")?.innerText == label ) { return; } @@ -2681,8 +2732,6 @@ export class UrlbarView { if (identity.icon) { let userContextIcon = this.#createElement("img"); userContextIcon.classList.add("urlbarView-userContext-icon"); - - userContextIcon.classList.add("identity-icon-" + identity.icon); userContextIcon.setAttribute("alt", label); userContextIcon.src = "resource://usercontext-content/" + identity.icon + ".svg"; @@ -3131,6 +3180,7 @@ export class UrlbarView { let engine = this.oneOffSearchButtons.selectedButton?.engine; let source = this.oneOffSearchButtons.selectedButton?.source; + let icon = this.oneOffSearchButtons.selectedButton?.image; let localSearchMode; if (source) { @@ -3254,7 +3304,15 @@ export class UrlbarView { } // Update result favicons. - let iconOverride = localSearchMode?.icon || engine?.getIconURL(); + let iconOverride = localSearchMode?.icon; + // If the icon is the default one-off search placeholder, assume we + // don't have an icon for the engine. + if ( + !iconOverride && + icon != "chrome://browser/skin/search-engine-placeholder.png" + ) { + iconOverride = icon; + } if (!iconOverride && (localSearchMode || engine)) { // For one-offs without an icon, do not allow restyled URL results to // use their own icons. @@ -3273,7 +3331,7 @@ export class UrlbarView { } } - on_blur(event) { + on_blur() { // If the view is open without the input being focused, it will not close // automatically when the window loses focus. We might be in this state // after a Search Tip is shown on an engine homepage. @@ -3416,15 +3474,6 @@ export class UrlbarView { this.#populateResultMenu(); } } - - /** - * Add result to exposure set on the controller. - * - * @param {UrlbarResult} result UrlbarResult for which to record an exposure. - */ - #addExposure(result) { - this.controller.engagementEvent.addExposure(result); - } } /** -- cgit v1.2.3