commit a0c4551d89f168be09eeed5e60367af1ac13174a
parent 8b6a7f8464a618aab8a17b2e1aada5e9ca1cf7eb
Author: Mike Conley <mconley@mozilla.com>
Date: Wed, 7 Jan 2026 17:39:20 +0000
Bug 2002027 - Part 3: Embed ContentSearchHandoffUI component into about:privatebrowsing. r=desktop-theme-reviewers,Standard8,urlbar-reviewers,emilio
Differential Revision: https://phabricator.services.mozilla.com/D273884
Diffstat:
7 files changed, 76 insertions(+), 248 deletions(-)
diff --git a/browser/components/privatebrowsing/content/aboutPrivateBrowsing.html b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.html
@@ -76,21 +76,7 @@
<div class="wordmark"></div>
</div>
<div class="search-inner-wrapper">
- <button
- id="search-handoff-button"
- class="search-handoff-button"
- tabindex="-1"
- aria-hidden="true"
- >
- <div class="fake-textbox"></div>
- <input
- id="fake-editable"
- class="fake-editable"
- tabindex="-1"
- aria-hidden="true"
- />
- <div class="fake-caret"></div>
- </button>
+ <content-search-handoff-ui></content-search-handoff-ui>
</div>
<div class="info-border">
<div class="info">
diff --git a/browser/components/privatebrowsing/content/aboutPrivateBrowsing.js b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.js
@@ -351,55 +351,4 @@ document.addEventListener("DOMContentLoaded", function () {
};
openSearchOptions.addEventListener("click", openSearchOptionsEvtHandler);
openSearchOptions.addEventListener("keypress", openSearchOptionsEvtHandler);
-
- // Setup the search hand-off box.
- let btn = document.getElementById("search-handoff-button");
-
- let editable = document.getElementById("fake-editable");
- let DISABLE_SEARCH_TOPIC = "DisableSearch";
- let SHOW_SEARCH_TOPIC = "ShowSearch";
- let SEARCH_HANDOFF_TOPIC = "SearchHandoff";
-
- function showSearch() {
- btn.classList.remove("focused");
- btn.classList.remove("disabled");
- RPMRemoveMessageListener(SHOW_SEARCH_TOPIC, showSearch);
- }
-
- function disableSearch() {
- btn.classList.add("disabled");
- }
-
- function handoffSearch(text) {
- RPMSendAsyncMessage(SEARCH_HANDOFF_TOPIC, { text });
- RPMAddMessageListener(SHOW_SEARCH_TOPIC, showSearch);
- if (text) {
- disableSearch();
- } else {
- btn.classList.add("focused");
- RPMAddMessageListener(DISABLE_SEARCH_TOPIC, disableSearch);
- }
- }
- btn.addEventListener("focus", function () {
- handoffSearch();
- });
- btn.addEventListener("click", function () {
- handoffSearch();
- });
-
- // Hand-off any text that gets dropped or pasted
- editable.addEventListener("drop", function (ev) {
- ev.preventDefault();
- let text = ev.dataTransfer.getData("text");
- if (text) {
- handoffSearch(text);
- }
- });
- editable.addEventListener("paste", function (ev) {
- ev.preventDefault();
- handoffSearch(ev.clipboardData.getData("Text"));
- });
-
- // Load contentSearchUI so it sets the search engine icon and name for us.
- new window.ContentSearchHandoffUIController();
});
diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_about.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_about.js
@@ -86,8 +86,10 @@ add_task(async function test_myths_link() {
await BrowserTestUtils.closeWindow(win);
});
-function urlBarHasHiddenFocus(win) {
- return win.gURLBar.focused && !win.gURLBar.hasAttribute("focused");
+async function urlBarHasHiddenFocus(win) {
+ return TestUtils.waitForCondition(() => {
+ return win.gURLBar.focused && !win.gURLBar.hasAttribute("focused");
+ }, "Urlbar has hidden focus");
}
function urlBarHasNormalFocus(win) {
@@ -138,11 +140,16 @@ add_task(async function test_search_handoff_on_keydown() {
let { win, tab } = await openAboutPrivateBrowsing();
await SpecialPowers.spawn(tab, [], async function () {
- let btn = content.document.getElementById("search-handoff-button");
+ let handoffUI = content.document.querySelector("content-search-handoff-ui");
+ let btn = handoffUI.shadowRoot.querySelector(".search-handoff-button");
btn.click();
- ok(btn.classList.contains("focused"), "in-content search has focus styles");
+ await handoffUI.updateComplete;
+ ok(
+ handoffUI.hasAttribute("fakefocus"),
+ "in-content search has focus styles"
+ );
});
- ok(urlBarHasHiddenFocus(win), "Urlbar has hidden focus");
+ await urlBarHasHiddenFocus(win);
// Expect two searches, one to enter search mode and then another in search
// mode.
@@ -152,8 +159,8 @@ add_task(async function test_search_handoff_on_keydown() {
await SpecialPowers.spawn(tab, [], async function () {
ok(
content.document
- .getElementById("search-handoff-button")
- .classList.contains("disabled"),
+ .querySelector("content-search-handoff-ui")
+ .hasAttribute("disabled"),
"in-content search is disabled"
);
});
@@ -169,8 +176,8 @@ add_task(async function test_search_handoff_on_keydown() {
await SpecialPowers.spawn(tab, [], async function () {
ok(
!content.document
- .getElementById("search-handoff-button")
- .classList.contains("disabled"),
+ .querySelector("content-search-handoff-ui")
+ .hasAttribute("disabled"),
"in-content search is not disabled"
);
});
@@ -185,9 +192,12 @@ add_task(async function test_search_handoff_on_composition_start() {
let { win, tab } = await openAboutPrivateBrowsing();
await SpecialPowers.spawn(tab, [], async function () {
- content.document.getElementById("search-handoff-button").click();
+ let btn = content.document
+ .querySelector("content-search-handoff-ui")
+ .shadowRoot.querySelector(".search-handoff-button");
+ btn.click();
});
- ok(urlBarHasHiddenFocus(win), "Urlbar has hidden focus");
+ await urlBarHasHiddenFocus(win);
await new Promise(r =>
EventUtils.synthesizeComposition({ type: "compositionstart" }, win, r)
);
@@ -203,9 +213,12 @@ add_task(async function test_search_handoff_on_paste() {
let { win, tab } = await openAboutPrivateBrowsing();
await SpecialPowers.spawn(tab, [], async function () {
- content.document.getElementById("search-handoff-button").click();
+ content.document
+ .querySelector("content-search-handoff-ui")
+ .shadowRoot.querySelector(".search-handoff-button")
+ .click();
});
- ok(urlBarHasHiddenFocus(win), "Urlbar has hidden focus");
+ await urlBarHasHiddenFocus(win);
var helper = SpecialPowers.Cc[
"@mozilla.org/widget/clipboardhelper;1"
].getService(SpecialPowers.Ci.nsIClipboardHelper);
@@ -238,11 +251,16 @@ add_task(async function test_search_handoff_search_mode() {
let { win, tab } = await openAboutPrivateBrowsing();
await SpecialPowers.spawn(tab, [], async function () {
- let btn = content.document.getElementById("search-handoff-button");
+ let handoffUI = content.document.querySelector("content-search-handoff-ui");
+ let btn = handoffUI.shadowRoot.querySelector(".search-handoff-button");
btn.click();
- ok(btn.classList.contains("focused"), "in-content search has focus styles");
+ await handoffUI.updateComplete;
+ ok(
+ handoffUI.hasAttribute("fakefocus"),
+ "in-content search has focus styles"
+ );
});
- ok(urlBarHasHiddenFocus(win), "Urlbar has hidden focus");
+ await urlBarHasHiddenFocus(win);
// Expect two searches, one to enter search mode and then another in search
// mode.
@@ -250,12 +268,11 @@ add_task(async function test_search_handoff_search_mode() {
await new Promise(r => EventUtils.synthesizeKey("f", {}, win, r));
await SpecialPowers.spawn(tab, [], async function () {
- ok(
- content.document
- .getElementById("search-handoff-button")
- .classList.contains("disabled"),
- "in-content search is disabled"
- );
+ await ContentTaskUtils.waitForCondition(() => {
+ return content.document
+ .querySelector("content-search-handoff-ui")
+ .hasAttribute("disabled");
+ }, "in-content search is disabled");
});
await searchPromise;
ok(urlBarHasNormalFocus(win), "Urlbar has normal focus");
@@ -275,8 +292,9 @@ add_task(async function test_search_handoff_search_mode() {
await SpecialPowers.spawn(tab, [], async function () {
ok(
!content.document
- .getElementById("search-handoff-button")
- .classList.contains("disabled"),
+ .querySelector("content-search-handoff-ui")
+ .shadowRoot.querySelector(".search-handoff-button")
+ .hasAttribute("disabled"),
"in-content search is not disabled"
);
});
diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_about_cookie_banners_promo.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_about_cookie_banners_promo.js
@@ -26,7 +26,6 @@ add_task(async function test_cookie_banners_promo_user_set_prefs() {
await ASRouter.onPrefChange();
const { win, tab } = await openTabAndWaitForRender();
-
await SpecialPowers.spawn(tab, [promoImgSrc], async function (imgSrc) {
const promoImage = content.document.querySelector(
".promo-image-large > img"
diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_about_default_pin_promo.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_about_default_pin_promo.js
@@ -9,7 +9,7 @@ const { sinon } = ChromeUtils.importESModule(
const sandbox = sinon.createSandbox();
add_setup(async function () {
- ASRouter.resetMessageState();
+ await ASRouter.resetMessageState();
await SpecialPowers.pushPrefEnv({
set: [["browser.promo.pin.enabled", true]],
});
diff --git a/browser/components/urlbar/tests/browser/browser_urlbar_telemetry_searchmode.js b/browser/components/urlbar/tests/browser/browser_urlbar_telemetry_searchmode.js
@@ -487,8 +487,12 @@ add_task(async function test_handoff_pbm() {
let tab = win.gBrowser.selectedBrowser;
await SpecialPowers.spawn(tab, [], async function () {
- let btn = content.document.getElementById("search-handoff-button");
- btn.click();
+ await ContentTaskUtils.waitForCondition(() =>
+ content.document.querySelector("content-search-handoff-ui")
+ );
+ let handoffUI = content.document.querySelector("content-search-handoff-ui");
+ await handoffUI.updateComplete;
+ handoffUI.shadowRoot.querySelector(".search-handoff-button").click();
});
let searchPromise = UrlbarTestUtils.promiseSearchComplete(win);
diff --git a/browser/themes/shared/privatebrowsing/aboutPrivateBrowsing.css b/browser/themes/shared/privatebrowsing/aboutPrivateBrowsing.css
@@ -160,162 +160,34 @@ p {
}
}
-.search-handoff-button,
-.search-handoff-button:active,
-.search-handoff-button:enabled:hover:active {
- background: white var(--newtab-search-icon) 12px center no-repeat;
- background-size: 24px;
- border: solid 1px rgba(249, 249, 250, 0.2);
- border-radius: var(--border-radius-xsmall);
- box-shadow:
- 0 1px 4px 0 rgba(12, 12, 13, 0.2),
- 0 0 0 1px rgba(0, 0, 0, 0.15);
- cursor: text;
- font-size: 15px;
- font-weight: normal;
- margin: 0;
- padding-block: 0;
- padding-inline: 46px 48px;
- position: relative;
- opacity: 1;
- width: 100%;
- -moz-context-properties: fill;
- fill: rgba(12, 12, 13, 0.4);
-}
-
-.search-handoff-button.focused:not(.disabled) {
- border: solid 1px #0060df;
- box-shadow:
- 0 0 0 1px #0060df,
- 0 0 0 4px rgba(0, 96, 223, 0.3);
-}
-
-.search-handoff-button.disabled {
- opacity: 0.5;
- box-shadow: none;
-}
-
-.search-handoff-button:dir(rtl),
-.search-handoff-button:active:dir(rtl),
-.search-handoff-button:enabled:hover:active:dir(rtl) {
- background-position-x: right 12px;
-}
-
-.search-inner-wrapper .search-handoff-button:hover,
-.search-inner-wrapper .search-handoff-button:hover:active {
- background-color: white;
- color: inherit;
-}
-
-.search-handoff-button.focused:not(.disabled) .fake-caret {
- display: block;
-}
-
-.fake-editable:focus {
- outline: none;
- caret-color: transparent;
-}
-
-.fake-editable {
- border: 0;
- height: 100%;
- top: 0;
- inset-inline-start: 0;
- opacity: 0;
- padding: 0;
- position: absolute;
- width: 100%;
-}
-
-.fake-textbox {
- color: rgb(12, 12, 13);
- opacity: 0.54;
- text-align: start;
-}
-
-@keyframes caret-animation {
- to {
- visibility: hidden;
- }
-}
-
-.fake-caret {
- animation: caret-animation 1.3s steps(5, start) infinite;
- background-color: rgb(12, 12, 13);
- display: none;
- inset-inline-start: 47px;
- height: 17px;
- position: absolute;
- top: 16px;
- width: 1px;
-}
-
-@media (prefers-contrast) {
- .fake-caret {
- background-color: ButtonText;
+content-search-handoff-ui {
+ --content-search-handoff-ui-background-color: white;
+ --content-search-handoff-ui-color: rgb(12, 12, 13);
+ --content-search-handoff-ui-fill: rgba(12, 12, 13, 0.4);
+ --content-search-handoff-ui-caret-color: rgb(12, 12, 13);
+ --content-search-handoff-ui-fakefocus-border-color: #0060df;
+ --content-search-handoff-ui-fakefocus-box-shadow-inner: #0060df;
+ --content-search-handoff-ui-fakefocus-box-shadow-outer: rgba(0, 96, 223, 0.3);
+
+ /* stylelint-disable-next-line media-query-no-invalid */
+ @media -moz-pref("browser.privatebrowsing.felt-privacy-v1") {
+ --content-search-handoff-ui-background-color: #321c64;
+ --content-search-handoff-ui-color: #fbfbfe;
+ --content-search-handoff-ui-fill: rgb(251, 251, 254);
+ --content-search-handoff-ui-caret-color: #fbfbfe;
+ --content-search-handoff-ui-border-width: 3px;
+ --content-search-handoff-ui-unfocused-border-color: rgb(149, 43, 185);
+ --content-search-handoff-ui-fakefocus-border-color: #0060df;
+ --content-search-handoff-ui-fakefocus-box-shadow-inner: #0060df;
+ --content-search-handoff-ui-fakefocus-box-shadow-outer: rgba(0, 96, 223, 0.3);
}
-}
-
-/* stylelint-disable-next-line media-query-no-invalid */
-@media -moz-pref("browser.privatebrowsing.felt-privacy-v1") {
- .search-handoff-button,
- .search-handoff-button:hover:not(.focused),
- .search-handoff-button:active,
- .search-handoff-button:enabled:hover:active {
- border: 3px solid ButtonText;
- border-radius: var(--border-radius-small);
- box-shadow: none;
-
- @media not (prefers-contrast) {
- border-color: #952bb9;
- }
- }
-
- .search-handoff-button,
- .search-handoff-button:hover:not(.focused),
- .search-handoff-button:active,
- .search-handoff-button:enabled:hover:active,
- .search-inner-wrapper .search-handoff-button:hover,
- .search-inner-wrapper .search-handoff-button:hover:active {
- background-color: ButtonFace;
- background-image: url(chrome://global/skin/icons/search-glass.svg);
- background-repeat: no-repeat;
- background-size: 16px;
- fill: ButtonText;
-
- @media (prefers-contrast) {
- border-color: ButtonText;
- color: ButtonText;
- }
- @media not (prefers-contrast) {
- background-color: #321c64;
- fill: rgb(251, 251, 254);
- }
- }
-
- .search-handoff-button.focused:not(.disabled) {
- border-width: 3px;
-
- @media (prefers-contrast) {
- outline: 2px solid SelectedItem;
- }
- }
-
- .fake-textbox {
- color: ButtonText;
- font-size: 0.87em;
- opacity: 1;
-
- @media not (prefers-contrast) {
- color: #fbfbfe;
- }
- }
-
- @media not (prefers-contrast) {
- .fake-caret {
- background-color: #fbfbfe;
- }
+ @media (forced-colors) {
+ --content-search-handoff-ui-background-color: ButtonFace;
+ --content-search-handoff-ui-color: ButtonText;
+ --content-search-handoff-ui-fill: ButtonText;
+ --content-search-handoff-ui-caret-color: ButtonText;
+ --content-search-handoff-ui-fakefocus-border-color: ButtonText;
}
}