/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ const lazy = {}; ChromeUtils.defineESModuleGetters(lazy, { PanelMultiView: "resource:///modules/PanelMultiView.sys.mjs", UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs", UrlbarUtils: "resource:///modules/UrlbarUtils.sys.mjs", }); ChromeUtils.defineLazyGetter(lazy, "SearchModeSwitcherL10n", () => { return new Localization(["preview/enUS-searchFeatures.ftl"]); }); /** * Implements the SearchModeSwitcher in the urlbar. */ class _SearchModeSwitcher { #initialized = false; #engineListNeedsRebuild = true; /** * Initialise the SearchSwitcher, ensuring the correct engine favicon is shown. * * @param {DomeElement} win * The window currently in use. */ async init(win) { if (!this.#initialized) { await Services.search.init(); Services.obs.addObserver(this, "browser-search-engine-modified"); this.#initialized = true; } this.#updateSearchIcon(win); } /** * Open the SearchSwitcher popup. * * @param {DomeElement} anchor * The element the popup is anchored to. * @param {Event} event * The event that triggered the opening of the popup. */ async openPanel(anchor, event) { let win = event.target.ownerGlobal; event.stopPropagation(); if (win.document.documentElement.hasAttribute("customizing")) { return; } if (this.#engineListNeedsRebuild) { await this.#rebuildSearchModeList(win); this.#engineListNeedsRebuild = false; } if (anchor.getAttribute("open") != "true") { win.gURLBar.inputField.addEventListener("searchmodechanged", this); win.gURLBar.view.hideTemporarily(); this.#getPopup(win).addEventListener( "popuphidden", () => { win.gURLBar.inputField.removeEventListener("searchmodechanged", this); anchor.removeAttribute("open"); win.gURLBar.view.restoreVisibility(); }, { once: true } ); anchor.setAttribute("open", true); lazy.PanelMultiView.openPopup(this.#getPopup(win), anchor, { position: "bottomleft topleft", triggerEvent: event, }).catch(console.error); } } /** * Exit the engine specific searchMode. * * @param {DomeElement} _anchor * The element the popup is anchored to. * @param {Event} event * The event that triggered the searchMode exit. */ exitSearchMode(_anchor, event) { event.stopPropagation(); event.preventDefault(); event.target.ownerGlobal.gURLBar.searchMode = null; this.#updateSearchIcon(event.target.ownerGlobal); } handleEvent(event) { switch (event.type) { case "searchmodechanged": { this.#updateSearchIcon(event.target.ownerGlobal); break; } } } observe(_subject, topic, _data) { switch (topic) { case "browser-search-engine-modified": { this.#engineListNeedsRebuild = true; break; } } } #popup = null; #getPopup(win) { if (!this.#popup) { this.#popup = win.document.getElementById("searchmode-switcher-popup"); } return this.#popup; } async #updateSearchIcon(win) { let button = win.document.getElementById("searchmode-switcher-icon"); let iconURL = await this.#getIconForSearchMode(win.gURLBar.searchMode); if (iconURL) { button.style.listStyleImage = `url(${iconURL})`; } let label = win.document.getElementById("searchmode-switcher-title"); if (!win.gURLBar.searchMode) { label.replaceChildren(); } else if (win.gURLBar.searchMode?.engineName) { label.textContent = win.gURLBar.searchMode.engineName; } else if (win.gURLBar.searchMode?.source) { // Certainly the wrong way to do this, the same string is used // as a