commit 99e19f8eb4a305195b0171788128c58f86d1ca7d
parent 1701edd25fab13dd634cea70961a7fb76bf00871
Author: Mike Conley <mconley@mozilla.com>
Date: Wed, 7 Jan 2026 23:40:27 +0000
Bug 2002027 - Part 1: Make contentSearchHandoffUI a module. r=search-reviewers,home-newtab-reviewers,Standard8,nbarrett
Differential Revision: https://phabricator.services.mozilla.com/D273882
Diffstat:
8 files changed, 174 insertions(+), 177 deletions(-)
diff --git a/browser/actors/AboutNewTabChild.sys.mjs b/browser/actors/AboutNewTabChild.sys.mjs
@@ -44,7 +44,6 @@ export class AboutNewTabChild extends RemotePageChild {
// This list must match any similar ones in render-activity-stream-html.js.
const scripts = [
- "chrome://browser/content/contentSearchHandoffUI.js",
"chrome://browser/content/contentTheme.js",
`chrome://global/content/vendor/react${debugString}.js`,
`chrome://global/content/vendor/react-dom${debugString}.js`,
diff --git a/browser/components/privatebrowsing/content/aboutPrivateBrowsing.html b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.html
@@ -28,7 +28,10 @@
<link rel="localization" href="toolkit/branding/brandings.ftl" />
<link rel="localization" href="browser/aboutPrivateBrowsing.ftl" />
<script src="chrome://browser/content/aboutPrivateBrowsing.js"></script>
- <script src="chrome://browser/content/contentSearchHandoffUI.js"></script>
+ <script
+ type="module"
+ src="chrome://browser/content/contentSearchHandoffUI.mjs"
+ ></script>
</head>
<body>
diff --git a/browser/components/search/content/contentSearchHandoffUI.js b/browser/components/search/content/contentSearchHandoffUI.js
@@ -1,171 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-/**
- * Handles handing off searches from an in-page search input field to the
- * browser's main URL bar. Communicates with the parent via the ContentSearch
- * actor, using custom events to talk to the child actor.
- */
-class ContentSearchHandoffUIController {
- constructor() {
- this._isPrivateEngine = false;
- this._engineIcon = null;
-
- window.addEventListener("ContentSearchService", this);
- this._sendMsg("GetEngine");
- this._sendMsg("GetHandoffSearchModePrefs");
- }
-
- handleEvent(event) {
- let methodName = "_onMsg" + event.detail.type;
- if (methodName in this) {
- this[methodName](event.detail.data);
- }
- }
-
- get defaultEngine() {
- return this._defaultEngine;
- }
-
- static privateBrowsingRegex = /^about:privatebrowsing([#?]|$)/i;
- get _isAboutPrivateBrowsing() {
- return ContentSearchHandoffUIController.privateBrowsingRegex.test(
- document.location.href
- );
- }
-
- _onMsgEngine({ isPrivateEngine, engine }) {
- this._isPrivateEngine = isPrivateEngine;
- this._updateEngine(engine);
- }
-
- _onMsgCurrentEngine(engine) {
- if (!this._isPrivateEngine) {
- this._updateEngine(engine);
- }
- }
-
- _onMsgCurrentPrivateEngine(engine) {
- if (this._isPrivateEngine) {
- this._updateEngine(engine);
- }
- }
-
- _onMsgHandoffSearchModePrefs(pref) {
- this._shouldHandOffToSearchMode = pref;
- this._updatel10nIds();
- }
-
- _updateEngine(engine) {
- this._defaultEngine = engine;
- if (this._engineIcon) {
- URL.revokeObjectURL(this._engineIcon);
- }
-
- // We only show the engines icon for config engines, otherwise show
- // a default. xref https://bugzilla.mozilla.org/show_bug.cgi?id=1449338#c19
- if (!engine.isConfigEngine) {
- this._engineIcon = "chrome://global/skin/icons/search-glass.svg";
- } else if (engine.iconData) {
- this._engineIcon = this._getFaviconURIFromIconData(engine.iconData);
- } else {
- this._engineIcon = "chrome://global/skin/icons/defaultFavicon.svg";
- }
-
- document.body.style.setProperty(
- "--newtab-search-icon",
- "url(" + this._engineIcon + ")"
- );
- this._updatel10nIds();
- }
-
- _updatel10nIds() {
- let engine = this._defaultEngine;
- let fakeButton = document.querySelector(".search-handoff-button");
- let fakeInput = document.querySelector(".fake-textbox");
- if (!fakeButton || !fakeInput) {
- return;
- }
- if (!engine || this._shouldHandOffToSearchMode) {
- document.l10n.setAttributes(
- fakeButton,
- this._isAboutPrivateBrowsing
- ? "about-private-browsing-search-btn"
- : "newtab-search-box-input"
- );
- document.l10n.setAttributes(
- fakeInput,
- this._isAboutPrivateBrowsing
- ? "about-private-browsing-search-placeholder"
- : "newtab-search-box-text"
- );
- } else if (!engine.isConfigEngine) {
- document.l10n.setAttributes(
- fakeButton,
- this._isAboutPrivateBrowsing
- ? "about-private-browsing-handoff-no-engine"
- : "newtab-search-box-handoff-input-no-engine"
- );
- document.l10n.setAttributes(
- fakeInput,
- this._isAboutPrivateBrowsing
- ? "about-private-browsing-handoff-text-no-engine"
- : "newtab-search-box-handoff-text-no-engine"
- );
- } else {
- document.l10n.setAttributes(
- fakeButton,
- this._isAboutPrivateBrowsing
- ? "about-private-browsing-handoff"
- : "newtab-search-box-handoff-input",
- {
- engine: engine.name,
- }
- );
- document.l10n.setAttributes(
- fakeInput,
- this._isAboutPrivateBrowsing
- ? "about-private-browsing-handoff-text"
- : "newtab-search-box-handoff-text",
- {
- engine: engine.name,
- }
- );
- }
- }
-
- /**
- * If the favicon is an iconData object, convert it into a Blob URI.
- * Otherwise just return the plain URI.
- *
- * @param {string|iconData} data
- * The icon's URL or an iconData object containing the icon data.
- * @returns {string}
- * A blob URL or the plain icon URI.
- */
- _getFaviconURIFromIconData(data) {
- if (typeof data == "string") {
- return data;
- }
-
- // If typeof(data) != "string", the iconData object is returned.
- let blob = new Blob([data.icon], { type: data.mimeType });
- return URL.createObjectURL(blob);
- }
-
- _sendMsg(type, data = null) {
- dispatchEvent(
- new CustomEvent("ContentSearchClient", {
- detail: {
- type,
- data,
- },
- })
- );
- }
-}
-
-window.ContentSearchHandoffUIController = ContentSearchHandoffUIController;
diff --git a/browser/components/search/content/contentSearchHandoffUI.mjs b/browser/components/search/content/contentSearchHandoffUI.mjs
@@ -0,0 +1,169 @@
+/* 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/. */
+
+/**
+ * Handles handing off searches from an in-page search input field to the
+ * browser's main URL bar. Communicates with the parent via the ContentSearch
+ * actor, using custom events to talk to the child actor.
+ */
+class ContentSearchHandoffUIController {
+ constructor() {
+ this._isPrivateEngine = false;
+ this._engineIcon = null;
+
+ window.addEventListener("ContentSearchService", this);
+ this._sendMsg("GetEngine");
+ this._sendMsg("GetHandoffSearchModePrefs");
+ }
+
+ handleEvent(event) {
+ let methodName = "_onMsg" + event.detail.type;
+ if (methodName in this) {
+ this[methodName](event.detail.data);
+ }
+ }
+
+ get defaultEngine() {
+ return this._defaultEngine;
+ }
+
+ static privateBrowsingRegex = /^about:privatebrowsing([#?]|$)/i;
+ get _isAboutPrivateBrowsing() {
+ return ContentSearchHandoffUIController.privateBrowsingRegex.test(
+ document.location.href
+ );
+ }
+
+ _onMsgEngine({ isPrivateEngine, engine }) {
+ this._isPrivateEngine = isPrivateEngine;
+ this._updateEngine(engine);
+ }
+
+ _onMsgCurrentEngine(engine) {
+ if (!this._isPrivateEngine) {
+ this._updateEngine(engine);
+ }
+ }
+
+ _onMsgCurrentPrivateEngine(engine) {
+ if (this._isPrivateEngine) {
+ this._updateEngine(engine);
+ }
+ }
+
+ _onMsgHandoffSearchModePrefs(pref) {
+ this._shouldHandOffToSearchMode = pref;
+ this._updatel10nIds();
+ }
+
+ _updateEngine(engine) {
+ this._defaultEngine = engine;
+ if (this._engineIcon) {
+ URL.revokeObjectURL(this._engineIcon);
+ }
+
+ // We only show the engines icon for config engines, otherwise show
+ // a default. xref https://bugzilla.mozilla.org/show_bug.cgi?id=1449338#c19
+ if (!engine.isConfigEngine) {
+ this._engineIcon = "chrome://global/skin/icons/search-glass.svg";
+ } else if (engine.iconData) {
+ this._engineIcon = this._getFaviconURIFromIconData(engine.iconData);
+ } else {
+ this._engineIcon = "chrome://global/skin/icons/defaultFavicon.svg";
+ }
+
+ document.body.style.setProperty(
+ "--newtab-search-icon",
+ "url(" + this._engineIcon + ")"
+ );
+ this._updatel10nIds();
+ }
+
+ _updatel10nIds() {
+ let engine = this._defaultEngine;
+ let fakeButton = document.querySelector(".search-handoff-button");
+ let fakeInput = document.querySelector(".fake-textbox");
+ if (!fakeButton || !fakeInput) {
+ return;
+ }
+ if (!engine || this._shouldHandOffToSearchMode) {
+ document.l10n.setAttributes(
+ fakeButton,
+ this._isAboutPrivateBrowsing
+ ? "about-private-browsing-search-btn"
+ : "newtab-search-box-input"
+ );
+ document.l10n.setAttributes(
+ fakeInput,
+ this._isAboutPrivateBrowsing
+ ? "about-private-browsing-search-placeholder"
+ : "newtab-search-box-text"
+ );
+ } else if (!engine.isConfigEngine) {
+ document.l10n.setAttributes(
+ fakeButton,
+ this._isAboutPrivateBrowsing
+ ? "about-private-browsing-handoff-no-engine"
+ : "newtab-search-box-handoff-input-no-engine"
+ );
+ document.l10n.setAttributes(
+ fakeInput,
+ this._isAboutPrivateBrowsing
+ ? "about-private-browsing-handoff-text-no-engine"
+ : "newtab-search-box-handoff-text-no-engine"
+ );
+ } else {
+ document.l10n.setAttributes(
+ fakeButton,
+ this._isAboutPrivateBrowsing
+ ? "about-private-browsing-handoff"
+ : "newtab-search-box-handoff-input",
+ {
+ engine: engine.name,
+ }
+ );
+ document.l10n.setAttributes(
+ fakeInput,
+ this._isAboutPrivateBrowsing
+ ? "about-private-browsing-handoff-text"
+ : "newtab-search-box-handoff-text",
+ {
+ engine: engine.name,
+ }
+ );
+ }
+ }
+
+ /**
+ * If the favicon is an iconData object, convert it into a Blob URI.
+ * Otherwise just return the plain URI.
+ *
+ * @param {string|iconData} data
+ * The icon's URL or an iconData object containing the icon data.
+ * @returns {string}
+ * A blob URL or the plain icon URI.
+ */
+ _getFaviconURIFromIconData(data) {
+ if (typeof data == "string") {
+ return data;
+ }
+
+ // If typeof(data) != "string", the iconData object is returned.
+ let blob = new Blob([data.icon], { type: data.mimeType });
+ return URL.createObjectURL(blob);
+ }
+
+ _sendMsg(type, data = null) {
+ dispatchEvent(
+ new CustomEvent("ContentSearchClient", {
+ detail: {
+ type,
+ data,
+ },
+ })
+ );
+ }
+}
+
+window.ContentSearchHandoffUIController = ContentSearchHandoffUIController;
diff --git a/browser/components/search/jar.mn b/browser/components/search/jar.mn
@@ -8,7 +8,7 @@ browser.jar:
content/browser/search/addEngine.xhtml (content/addEngine.xhtml)
content/browser/search/autocomplete-popup.js (content/autocomplete-popup.js)
content/browser/search/searchbar.js (content/searchbar.js)
- content/browser/contentSearchHandoffUI.js (content/contentSearchHandoffUI.js)
+ content/browser/contentSearchHandoffUI.mjs (content/contentSearchHandoffUI.mjs)
search-extensions/ (extensions/**)
% resource search-extensions %search-extensions/ contentaccessible=yes
diff --git a/browser/extensions/newtab/bin/render-activity-stream-html.js b/browser/extensions/newtab/bin/render-activity-stream-html.js
@@ -34,7 +34,6 @@ function templateHTML(options) {
const debugString = options.debug ? "-dev" : "";
// This list must match any similar ones in AboutNewTabChild.sys.mjs
const scripts = [
- "chrome://browser/content/contentSearchHandoffUI.js",
"chrome://browser/content/contentTheme.js",
`${options.baseVendorUrl}vendor/react${debugString}.js`,
`${options.baseVendorUrl}vendor/react-dom${debugString}.js`,
diff --git a/browser/extensions/newtab/prerendered/activity-stream-debug.html b/browser/extensions/newtab/prerendered/activity-stream-debug.html
@@ -35,7 +35,6 @@
</head>
<body class="activity-stream">
<div id="root"></div>
- <script src="chrome://browser/content/contentSearchHandoffUI.js"></script>
<script src="chrome://browser/content/contentTheme.js"></script>
<script src="chrome://global/content/vendor/react-dev.js"></script>
<script src="chrome://global/content/vendor/react-dom-dev.js"></script>
diff --git a/browser/extensions/newtab/prerendered/activity-stream.html b/browser/extensions/newtab/prerendered/activity-stream.html
@@ -35,7 +35,6 @@
</head>
<body class="activity-stream">
<div id="root"></div>
- <script src="chrome://browser/content/contentSearchHandoffUI.js"></script>
<script src="chrome://browser/content/contentTheme.js"></script>
<script src="chrome://global/content/vendor/react.js"></script>
<script src="chrome://global/content/vendor/react-dom.js"></script>