tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit d4f70937db51f61e3524ce676174ed5921034086
parent acf02673980a1e28ea660340e393d366a814ec6f
Author: Moritz Beier <mbeier@mozilla.com>
Date:   Fri, 12 Dec 2025 14:04:01 +0000

Bug 2002978 - Make sure the new search bar's search mode does not depend on the selected tab. r=adw,search-reviewers,urlbar-reviewers

Differential Revision: https://phabricator.services.mozilla.com/D275807

Diffstat:
Mbrowser/components/search/test/browser/browser.toml | 2++
Abrowser/components/search/test/browser/browser_new_searchbar_searchmode.js | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mbrowser/components/urlbar/content/UrlbarInput.mjs | 76+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Mbrowser/components/urlbar/tests/UrlbarTestUtils.sys.mjs | 59++++++++++++++++++++++++++++++++++-------------------------
4 files changed, 152 insertions(+), 42 deletions(-)

diff --git a/browser/components/search/test/browser/browser.toml b/browser/components/search/test/browser/browser.toml @@ -85,6 +85,8 @@ skip-if = [ ["browser_new_searchbar_init.js"] +["browser_new_searchbar_searchmode.js"] + ["browser_oneOff.js"] ["browser_oneOffContextMenu.js"] diff --git a/browser/components/search/test/browser/browser_new_searchbar_searchmode.js b/browser/components/search/test/browser/browser_new_searchbar_searchmode.js @@ -0,0 +1,57 @@ +/* Any copyright is dedicated to the Public Domain. + https://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/** + * Tests whether search mode works as expected in the new search bar. + * E.g. there should be a global search mode and it + * should not be tied to the selected tab. + */ + +ChromeUtils.defineESModuleGetters(this, { + SearchbarTestUtils: "resource://testing-common/UrlbarTestUtils.sys.mjs", +}); + +add_setup(async function () { + SearchbarTestUtils.init(this); + SpecialPowers.pushPrefEnv({ + set: [["browser.search.widget.new", true]], + }); + await gCUITestUtils.addSearchBar(); + registerCleanupFunction(() => gCUITestUtils.removeSearchBar()); + + await SearchTestUtils.updateRemoteSettingsConfig([ + { identifier: "engine1" }, + { identifier: "engine2" }, + { identifier: "engine3" }, + ]); +}); + +add_task(async function searchModeSurvivesTabSwitch() { + let tab1 = gBrowser.selectedTab; + let tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser); + + let popup = await SearchbarTestUtils.openSearchModeSwitcher(window); + info("Press on the engine1 menu button to enter search mode"); + let popupHidden = SearchbarTestUtils.searchModeSwitcherPopupClosed(window); + popup.querySelector("menuitem[label=engine1]").click(); + await popupHidden; + + await SearchbarTestUtils.assertSearchMode(window, { + engineName: "engine1", + entry: "searchbutton", + source: 3, + }); + + info("Switching tab. Search mode should not be affected."); + await BrowserTestUtils.switchTab(gBrowser, tab1); + await SearchbarTestUtils.assertSearchMode(window, { + engineName: "engine1", + entry: "searchbutton", + source: 3, + }); + + SearchbarTestUtils.exitSearchMode(window); + gBrowser.removeTab(tab2); +}); diff --git a/browser/components/urlbar/content/UrlbarInput.mjs b/browser/components/urlbar/content/UrlbarInput.mjs @@ -2256,35 +2256,38 @@ export class UrlbarInput extends HTMLElement { } /** - * Gets the search mode for a specific browser instance. + * Addressbar: Gets the search mode for a specific browser instance. + * Searchbar: Gets the window-global search mode. * * @param {MozBrowser} browser * The search mode for this browser will be returned. + * Pass the selected browser for the searchbar. * @param {boolean} [confirmedOnly] * Normally, if the browser has both preview and confirmed modes, preview * mode will be returned since it takes precedence. If this argument is * true, then only confirmed search mode will be returned, or null if * search mode hasn't been confirmed. - * @returns {object} - * A search mode object. See setSearchMode documentation. If the browser - * is not in search mode, then null is returned. + * @returns {?object} + * A search mode object or null if the browser/window is not in search mode. + * See setSearchMode documentation. */ getSearchMode(browser, confirmedOnly = false) { - let modes = this.getBrowserState(browser).searchModes; + let modes = this.#getSearchModesObject(browser); // Return copies so that callers don't modify the stored values. - if (!confirmedOnly && modes?.preview) { + if (!confirmedOnly && modes.preview) { return { ...modes.preview }; } - if (modes?.confirmed) { + if (modes.confirmed) { return { ...modes.confirmed }; } return null; } /** - * Sets search mode for a specific browser instance. If the given browser is - * selected, then this will also enter search mode. + * Addressbar: Sets the search mode for a specific browser instance. + * Searchbar: Sets the window-global search mode. + * If the given browser is selected, then this will also enter search mode. * * @param {object} searchMode * A search mode object. @@ -2303,6 +2306,7 @@ export class UrlbarInput extends HTMLElement { * be interacted with right away. Defaults to true. * @param {MozBrowser} browser * The browser for which to set search mode. + * Pass the selected browser for the searchbar. */ async setSearchMode(searchMode, browser) { let currentSearchMode = this.getSearchMode(browser); @@ -2354,7 +2358,7 @@ export class UrlbarInput extends HTMLElement { } } - let state = this.getBrowserState(browser); + let modes = this.#getSearchModesObject(browser); if (searchMode) { searchMode.isPreview = isPreview; @@ -2366,16 +2370,15 @@ export class UrlbarInput extends HTMLElement { searchMode.entry = "other"; } - // Add the search mode to the map. if (!searchMode.isPreview) { - state.searchModes = { confirmed: searchMode }; + modes.confirmed = searchMode; + delete modes.preview; } else { - let modes = state.searchModes || {}; modes.preview = searchMode; - state.searchModes = modes; } } else { - delete state.searchModes; + delete modes.preview; + delete modes.confirmed; } if (restrictType) { @@ -2402,11 +2405,50 @@ export class UrlbarInput extends HTMLElement { } /** + * @typedef {object} SearchModesObject + * + * @property {object} [preview] preview search mode + * @property {object} [confirmed] confirmed search mode + */ + + /** + * @type {SearchModesObject|undefined} + * + * The (lazily initialized) search mode object for the searchbar. + * This is needed because the searchbar has one search mode per window that + * shouldn't change when switching tabs. For the address bar, the search mode + * is stored per browser in #browserStates and this is always undefined. + */ + #searchbarSearchModes; + + /** + * Addressbar: Gets the search modes object for a specific browser instance. + * Searchbar: Gets the window-global search modes object. + * + * @param {MozBrowser} browser + * The browser to get the search modes object for. + * Pass the selected browser for the searchbar. + * @returns {SearchModesObject} + */ + #getSearchModesObject(browser) { + if (!this.#isAddressbar) { + // The passed browser doesn't matter here, but it does in setSearchMode. + this.#searchbarSearchModes ??= {}; + return this.#searchbarSearchModes; + } + + let state = this.getBrowserState(browser); + state.searchModes ??= {}; + return state.searchModes; + } + + /** * Restores the current browser search mode from a previously stored state. */ restoreSearchModeState() { - let state = this.getBrowserState(this.window.gBrowser.selectedBrowser); - this.searchMode = state.searchModes?.confirmed; + this.searchMode = this.#getSearchModesObject( + this.window.gBrowser.selectedBrowser + ).confirmed; } /** diff --git a/browser/components/urlbar/tests/UrlbarTestUtils.sys.mjs b/browser/components/urlbar/tests/UrlbarTestUtils.sys.mjs @@ -951,37 +951,46 @@ class UrlbarInputTestUtils { "Expected searchMode" ); - // Check the textContent and l10n attributes of the indicator and label. - let expectedTextContent = ""; - let expectedL10n = { id: null, args: null }; - if (expectedSearchMode.engineName) { - expectedTextContent = expectedSearchMode.engineName; - } else if (expectedSearchMode.source) { - let name = UrlbarUtils.getResultSourceName(expectedSearchMode.source); - this.Assert.ok(name, "Expected result source should have a name"); - expectedL10n = { id: `urlbar-search-mode-${name}`, args: null }; - } else { - this.Assert.ok(false, "Unexpected searchMode"); - } + // Only the addressbar still has the legacy search mode indicator. + if (this.#urlbar(window).sapName == "urlbar") { + // Check the textContent and l10n attributes of the indicator and label. + let expectedTextContent = ""; + let expectedL10n = { id: null, args: null }; + if (expectedSearchMode.engineName) { + expectedTextContent = expectedSearchMode.engineName; + } else if (expectedSearchMode.source) { + let name = UrlbarUtils.getResultSourceName(expectedSearchMode.source); + this.Assert.ok(name, "Expected result source should have a name"); + expectedL10n = { id: `urlbar-search-mode-${name}`, args: null }; + } else { + this.Assert.ok(false, "Unexpected searchMode"); + } - if (expectedTextContent) { - this.Assert.equal( - this.#urlbar(window)._searchModeIndicatorTitle.textContent, - expectedTextContent, - "Expected textContent" + if (expectedTextContent) { + this.Assert.equal( + this.#urlbar(window)._searchModeIndicatorTitle.textContent, + expectedTextContent, + "Expected textContent" + ); + } + this.Assert.deepEqual( + window.document.l10n.getAttributes( + this.#urlbar(window)._searchModeIndicatorTitle + ), + expectedL10n, + "Expected l10n" ); } - this.Assert.deepEqual( - window.document.l10n.getAttributes( - this.#urlbar(window)._searchModeIndicatorTitle - ), - expectedL10n, - "Expected l10n" - ); // Check the input's placeholder. let expectedPlaceholderL10n; - if (expectedSearchMode.engineName) { + if (this.#urlbar(window).sapName == "searchbar") { + // Placeholder stays constant in searchbar. + expectedPlaceholderL10n = { + id: "searchbar-input", + args: null, + }; + } else if (expectedSearchMode.engineName) { expectedPlaceholderL10n = { id: isGeneralPurposeEngine ? "urlbar-placeholder-search-mode-web-2"