tor-browser

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

commit 56c1486eec04b58ab525bfb407678f2f55b26a8f
parent a4f1dd37708325f64e04ae0b16072f2bcc11953f
Author: Mike Conley <mconley@mozilla.com>
Date:   Wed,  7 Jan 2026 23:40:28 +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:
Mbrowser/components/privatebrowsing/content/aboutPrivateBrowsing.html | 16+---------------
Mbrowser/components/privatebrowsing/content/aboutPrivateBrowsing.js | 51---------------------------------------------------
Mbrowser/components/privatebrowsing/test/browser/browser_privatebrowsing_about.js | 66++++++++++++++++++++++++++++++++++++++++++------------------------
Mbrowser/components/privatebrowsing/test/browser/browser_privatebrowsing_about_cookie_banners_promo.js | 1-
Mbrowser/components/privatebrowsing/test/browser/browser_privatebrowsing_about_default_pin_promo.js | 2+-
Mbrowser/components/urlbar/tests/browser/browser_urlbar_telemetry_searchmode.js | 12++++++++++--
Mbrowser/themes/shared/privatebrowsing/aboutPrivateBrowsing.css | 180++++++++++++-------------------------------------------------------------------
7 files changed, 80 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,10 +487,18 @@ 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(); }); + await TestUtils.waitForCondition(() => { + return win.gURLBar.focused && !win.gURLBar.hasAttribute("focused"); + }, "Urlbar has hidden focus"); + let searchPromise = UrlbarTestUtils.promiseSearchComplete(win); await new Promise(r => EventUtils.synthesizeKey("f", {}, win, r)); await searchPromise; 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; } }