tor-browser

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

commit e7948ea257d143e4f44771d0d2a59b07df9931b1
parent e61551b429cf31beaa4d56c8b159fa4b947b307b
Author: Moritz Beier <mbeier@mozilla.com>
Date:   Mon, 24 Nov 2025 10:37:20 +0000

Bug 1983016 - When the old or the new search bar are disabled, ensure they don't have active listeners and observers. r=dao,search-reviewers,urlbar-reviewers,scunnane

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

Diffstat:
Mbrowser/components/search/content/searchbar.js | 33+++++++++++++++++++++++++--------
Mbrowser/components/urlbar/content/UrlbarInput.mjs | 54++++++++++++++++++++++++++++++++++++++++++++----------
2 files changed, 69 insertions(+), 18 deletions(-)

diff --git a/browser/components/search/content/searchbar.js b/browser/components/search/content/searchbar.js @@ -49,14 +49,12 @@ constructor() { super(); - MozXULElement.insertFTLIfNeeded("browser/search.ftl"); - this.destroy = this.destroy.bind(this); this._setupEventListeners(); let searchbar = this; this.observer = { - observe(aEngine, aTopic) { + observe(aEngine, aTopic, aData) { if (aTopic == "browser-search-engine-modified") { // Make sure the engine list is refetched next time it's needed searchbar._engines = null; @@ -64,19 +62,41 @@ // Update the popup header and update the display after any modification. searchbar._textbox.popup.updateHeader(); searchbar.updateDisplay(); + } else if ( + aData == "browser.search.widget.new" && + searchbar.isConnected + ) { + if (Services.prefs.getBoolPref("browser.search.widget.new")) { + searchbar.disconnectedCallback(); + } else { + searchbar.connectedCallback(); + } } }, QueryInterface: ChromeUtils.generateQI(["nsIObserver"]), }; + Services.prefs.addObserver("browser.search.widget.new", this.observer); + + window.addEventListener("unload", () => { + this.destroy(); + Services.prefs.removeObserver( + "browser.search.widget.new", + this.observer + ); + }); + this._ignoreFocus = false; this._engines = null; this.telemetrySelectedIndex = -1; } connectedCallback() { - // Don't initialize if this isn't going to be visible - if (this.closest("#BrowserToolbarPalette")) { + // Don't initialize if this isn't going to be visible. + if ( + this.closest("#BrowserToolbarPalette") || + Services.prefs.getBoolPref("browser.search.widget.new") + ) { return; } @@ -108,8 +128,6 @@ this._setupTextboxEventListeners(); this._initTextbox(); - window.addEventListener("unload", this.destroy); - Services.obs.addObserver(this.observer, "browser-search-engine-modified"); this._initialized = true; @@ -225,7 +243,6 @@ destroy() { if (this._initialized) { this._initialized = false; - window.removeEventListener("unload", this.destroy); Services.obs.removeObserver( this.observer, diff --git a/browser/components/urlbar/content/UrlbarInput.mjs b/browser/components/urlbar/content/UrlbarInput.mjs @@ -235,6 +235,11 @@ export class UrlbarInput extends HTMLElement { this.isPrivate = lazy.PrivateBrowsingUtils.isWindowPrivate(this.window); lazy.UrlbarPrefs.addObserver(this); + window.addEventListener("unload", () => { + // Stop listening to pref changes to make sure we don't init the new + // searchbar in closed windows that have not been gc'd yet. + lazy.UrlbarPrefs.removeObserver(this); + }); } /** @@ -275,7 +280,7 @@ export class UrlbarInput extends HTMLElement { /** * Initialization that happens once on the first connect. */ - #init() { + #initOnce() { this.#sapName = this.getAttribute("sap-name"); this.#isAddressbar = this.#sapName == "urlbar"; @@ -350,8 +355,19 @@ export class UrlbarInput extends HTMLElement { } connectedCallback() { + if ( + this.sapName == "searchbar" && + !lazy.UrlbarPrefs.get("browser.search.widget.new") + ) { + return; + } + + this.#init(); + } + + #init() { if (!this.controller) { - this.#init(); + this.#initOnce(); } // Don't attach event listeners if the toolbar is not visible @@ -433,8 +449,21 @@ export class UrlbarInput extends HTMLElement { } disconnectedCallback() { - this.inputField.controllers.removeController(this._copyCutController); - delete this._copyCutController; + if ( + this.sapName == "searchbar" && + !lazy.UrlbarPrefs.get("browser.search.widget.new") + ) { + return; + } + + this.#uninit(); + } + + #uninit() { + if (this._copyCutController) { + this.inputField.controllers.removeController(this._copyCutController); + delete this._copyCutController; + } for (let event of UrlbarInput.#inputFieldEvents) { this.inputField.removeEventListener(event, this); @@ -562,12 +591,14 @@ export class UrlbarInput extends HTMLElement { ); break; case "browser.search.widget.new": { - if ( - this.#sapName == "searchbar" && - lazy.UrlbarPrefs.get("browser.search.widget.new") - ) { - // Update dimensions because the searchbar was invisible before. - this.#updateLayoutBreakout(); + if (this.sapName == "searchbar" && this.isConnected) { + if (lazy.UrlbarPrefs.get("browser.search.widget.new")) { + // The connectedCallback was skipped. Init now. + this.#init(); + } else { + // Uninit now, the disconnectedCallback will be skipped. + this.#uninit(); + } } } } @@ -3847,6 +3878,9 @@ export class UrlbarInput extends HTMLElement { } _initCopyCutController() { + if (this._copyCutController) { + return; + } this._copyCutController = new CopyCutController(this); this.inputField.controllers.insertControllerAt(0, this._copyCutController); }