tor-commits
Threads by month
- ----- 2026 -----
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- 1 participants
- 215696 discussions
[Git][tpo/applications/tor-browser][tor-browser-153.1.0esr-16.0-1] Bug 2063031 - Spoof video PiP size under RFP. r=media-playback-reviewers,kpatenio,alwu,tjr
by morgan (@morgan) 24 Aug '26
by morgan (@morgan) 24 Aug '26
24 Aug '26
morgan pushed to branch tor-browser-153.1.0esr-16.0-1 at The Tor Project / Applications / Tor Browser
Commits:
3c9945e2 by Pier Angelo Vendrame at 2026-08-24T13:35:37+00:00
Bug 2063031 - Spoof video PiP size under RFP. r=media-playback-reviewers,kpatenio,alwu,tjr
Differential Revision: https://phabricator.services.mozilla.com/D318184
- - - - -
6 changed files:
- dom/media/PictureInPictureWindow.cpp
- dom/media/PictureInPictureWindow.h
- dom/media/mediaelement/HTMLVideoElement.cpp
- dom/media/mediaelement/HTMLVideoElement.h
- toolkit/components/pictureinpicture/tests/browser.toml
- + toolkit/components/pictureinpicture/tests/browser_resistFingerprinting.js
Changes:
=====================================
dom/media/PictureInPictureWindow.cpp
=====================================
@@ -47,6 +47,11 @@ int32_t PictureInPictureWindow::Width() const {
if (!IsStateOpened()) {
return 0;
}
+ RefPtr<HTMLVideoElement> videoElement = mAssociatedVideoElement.get();
+ if (videoElement && videoElement->OwnerDoc()->ShouldResistFingerprinting(
+ RFPTarget::ScreenRect)) {
+ return VideoSizeForRFP().width;
+ }
return mWidth;
}
@@ -57,14 +62,54 @@ int32_t PictureInPictureWindow::Height() const {
if (!IsStateOpened()) {
return 0;
}
+ RefPtr<HTMLVideoElement> videoElement = mAssociatedVideoElement.get();
+ if (videoElement && videoElement->OwnerDoc()->ShouldResistFingerprinting(
+ RFPTarget::ScreenRect)) {
+ return VideoSizeForRFP().height;
+ }
return mHeight;
}
+gfx::IntSize PictureInPictureWindow::VideoSizeForRFP() const {
+ RefPtr<HTMLVideoElement> videoElement = mAssociatedVideoElement.get();
+ if (!videoElement) {
+ return {0, 0};
+ }
+
+ // From PictureInPicture.sys.mjs: "The Picture in Picture window will be a
+ // maximum of a quarter of the screen height, and a third of the screen
+ // width.".
+ // Pretend we are maximizing the video in a 1920x1080 display.
+ const uint32_t maxWidth = 1920 / 3;
+ const uint32_t maxHeight = 1080 / 4;
+ uint32_t width = videoElement->VideoWidth();
+ uint32_t height = videoElement->VideoHeight();
+ if ((height > maxHeight || width > maxWidth) && height > 0) {
+ double aspectRatio = static_cast<double>(width) / height;
+ if (width >= height) {
+ width = maxWidth;
+ height = static_cast<uint32_t>(round(maxWidth / aspectRatio));
+ } else {
+ height = maxHeight;
+ width = static_cast<uint32_t>(round(maxHeight * aspectRatio));
+ }
+ }
+ return {width, height};
+}
+
void PictureInPictureWindow::NotifyDimensionsChanged(int32_t aWidth,
int32_t aHeight) {
mWidth = aWidth;
mHeight = aHeight;
+ RefPtr<HTMLVideoElement> videoElement = mAssociatedVideoElement.get();
+ if (videoElement && videoElement->OwnerDoc()->ShouldResistFingerprinting(
+ RFPTarget::ScreenRect)) {
+ // With RFP, we spoof the window size to a fixed size that depends on the
+ // video, therefore it does not make sense to trigger a resize event.
+ return;
+ }
+
// When the size of a Picture-in-Picture window pipWindow changes,
// the user agent MUST queue a task to fire an event named resize at
// pipWindow.
=====================================
dom/media/PictureInPictureWindow.h
=====================================
@@ -47,6 +47,8 @@ class PictureInPictureWindow final : public DOMEventTargetHelper {
private:
bool IsStateOpened() const { return mOpened; }
+ gfx::IntSize VideoSizeForRFP() const;
+
WeakPtr<HTMLVideoElement> mAssociatedVideoElement;
int32_t mWidth = 0;
int32_t mHeight = 0;
=====================================
dom/media/mediaelement/HTMLVideoElement.cpp
=====================================
@@ -315,7 +315,7 @@ bool HTMLVideoElement::IsInteractiveHTMLContent() const {
HTMLMediaElement::IsInteractiveHTMLContent();
}
-gfx::IntSize HTMLVideoElement::GetVideoIntrinsicDimensions() {
+gfx::IntSize HTMLVideoElement::GetVideoIntrinsicDimensions() const {
const auto& sz = mMediaInfo.mVideo.mDisplay;
// Prefer the size of the container as it's more up to date.
@@ -324,7 +324,7 @@ gfx::IntSize HTMLVideoElement::GetVideoIntrinsicDimensions() {
.valueOr(sz);
}
-uint32_t HTMLVideoElement::VideoWidth() {
+uint32_t HTMLVideoElement::VideoWidth() const {
if (!HasVideo()) {
return 0;
}
@@ -336,7 +336,7 @@ uint32_t HTMLVideoElement::VideoWidth() {
return size.width;
}
-uint32_t HTMLVideoElement::VideoHeight() {
+uint32_t HTMLVideoElement::VideoHeight() const {
if (!HasVideo()) {
return 0;
}
=====================================
dom/media/mediaelement/HTMLVideoElement.h
=====================================
@@ -96,9 +96,9 @@ class HTMLVideoElement final : public HTMLMediaElement {
SetUnsignedIntAttr(nsGkAtoms::height, aValue, 0, aRv);
}
- uint32_t VideoWidth();
+ uint32_t VideoWidth() const;
- uint32_t VideoHeight();
+ uint32_t VideoHeight() const;
VideoRotation RotationDegrees() const { return mMediaInfo.mVideo.mRotation; }
@@ -179,7 +179,7 @@ class HTMLVideoElement final : public HTMLMediaElement {
void CreateVideoWakeLockIfNeeded();
void ReleaseVideoWakeLockIfExists();
- gfx::IntSize GetVideoIntrinsicDimensions();
+ gfx::IntSize GetVideoIntrinsicDimensions() const;
RefPtr<WakeLock> mScreenWakeLock;
=====================================
toolkit/components/pictureinpicture/tests/browser.toml
=====================================
@@ -158,6 +158,8 @@ support-files = ["test-page-with-nan-video-duration.html"]
["browser_removeVideoElement.js"]
+["browser_resistFingerprinting.js"]
+
["browser_resizeVideo.js"]
skip-if = [
"os == 'linux' && os_version == '24.04' && arch == 'x86_64' && display == 'x11'", # Bug 1594223
=====================================
toolkit/components/pictureinpicture/tests/browser_resistFingerprinting.js
=====================================
@@ -0,0 +1,154 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+async function testResizePip(isRFP, src) {
+ clearSavedPosition();
+
+ await BrowserTestUtils.withNewTab(
+ {
+ url: TEST_PAGE,
+ gBrowser,
+ },
+ async browser => {
+ let videoID = "with-controls";
+
+ let [width, height, pipWidth, pipHeight] = await SpecialPowers.spawn(
+ browser,
+ [videoID, src],
+ async (videoID, src) => {
+ content.window.resizeEverCalled = false;
+ let video = content.wrappedJSObject.document.getElementById(videoID);
+ if (src) {
+ let { promise, resolve } = Promise.withResolvers();
+ video.addEventListener("canplay", resolve);
+ video.src = src;
+ await promise;
+ }
+ content.document.notifyUserGestureActivation();
+ let pip = await video.requestPictureInPicture();
+ pip.addEventListener(
+ "resize",
+ () => (content.window.resizeEverCalled = true)
+ );
+ return [video.width, video.height, pip.width, pip.height];
+ }
+ );
+ info(
+ `Video size is ${width}x${height}. PiP size is ${pipWidth}x${pipHeight}`
+ );
+
+ const { PictureInPicture } = ChromeUtils.importESModule(
+ "moz-src:///toolkit/components/pictureinpicture/PictureInPicture.sys.mjs"
+ );
+ let pipWindow = PictureInPicture.apiPipWindow?.get();
+ Assert.ok(pipWindow, "We found the chrome PiP window.");
+
+ let pipBrowser = pipWindow.document.getElementById("browser");
+ await SpecialPowers.spawn(pipBrowser, [], async () => {
+ let {
+ promise: setupPromise,
+ resolve: setupResolve,
+ reject: setupReject,
+ } = Promise.withResolvers();
+ content.resizePromise = new Promise(resizeResolve => {
+ let firstObserved = false;
+ // Scope the observer to the content because we need to block on the
+ // setup before resizing, therefore we need two separate promises and
+ // the observer needs to outlive this spawn call.
+ content.observer = new content.ResizeObserver(() => {
+ // Attaching the element will trigger a first call to this callback.
+ // Therefore, we need to ignore it.
+ if (firstObserved) {
+ resizeResolve();
+ } else {
+ firstObserved = true;
+ setupResolve();
+ }
+ });
+ let video = content.document.querySelector("video");
+ if (video) {
+ content.observer.observe(video);
+ } else {
+ setupReject(new Error("Video not found in the PiP window."));
+ }
+ });
+ await setupPromise;
+ });
+
+ pipWindow.resizeTo(pipWidth * 2, pipHeight * 2);
+ await SpecialPowers.spawn(pipBrowser, [], async () => {
+ await content.resizePromise;
+ content.observer.disconnect();
+ await new Promise(resolve => content.requestAnimationFrame(resolve));
+ });
+
+ let [pipWidthAfter, pipHeightAfter] = await SpecialPowers.spawn(
+ browser,
+ [videoID],
+ async videoID => {
+ let video = content.wrappedJSObject.document.getElementById(videoID);
+ // We already have the window, no need to simulate another user
+ // interaction.
+ let pip = await video.requestPictureInPicture();
+ return [pip.width, pip.height];
+ }
+ );
+ info(
+ `PiP size after resizing ${isRFP ? "with" : "without"} RFP ` +
+ `is ${pipWidthAfter}x${pipHeightAfter}`
+ );
+
+ if (isRFP) {
+ Assert.equal(pipWidth, pipWidthAfter, "RFP spoofed PiP width.");
+ Assert.equal(pipHeight, pipHeightAfter, "RFP spoofed PiP height.");
+ } else {
+ Assert.notEqual(
+ pipWidth,
+ pipWidthAfter,
+ "After resizing the PiP window, PiP width was updated."
+ );
+ Assert.notEqual(
+ pipHeight,
+ pipHeightAfter,
+ "After resizing the PiP window, PiP height was updated."
+ );
+ }
+
+ let everResized = await SpecialPowers.spawn(browser, [], async () => {
+ await content.document.exitPictureInPicture();
+ return content.window.resizeEverCalled;
+ });
+ Assert.equal(
+ everResized,
+ !isRFP,
+ `We expected the resize handler ${isRFP ? "not " : ""}to be ever called.`
+ );
+ }
+ );
+}
+
+add_task(async function test_video_pip_size() {
+ await testResizePip(false, "test-video.mp4");
+});
+
+add_task(async function test_video_pip_size_vertical() {
+ await testResizePip(false, "test-video-vertical.mp4");
+});
+
+add_task(async function test_video_pip_size_rfp() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["privacy.resistFingerprinting", true]],
+ });
+ await testResizePip(true, "test-video.mp4");
+ await SpecialPowers.popPrefEnv();
+});
+
+add_task(async function test_video_pip_size_rfp_vertical() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["privacy.resistFingerprinting", true]],
+ });
+ await testResizePip(true, "test-video-vertical.mp4");
+ await SpecialPowers.popPrefEnv();
+});
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/3c9945e…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/3c9945e…
You're receiving this email because of your account on gitlab.torproject.org. Manage all notifications: https://gitlab.torproject.org/-/profile/notifications | Help: https://gitlab.torproject.org/help
1
0
[Git][tpo/applications/mullvad-browser][mullvad-browser-153.1.0esr-16.0-1] fixup! Firefox preference overrides.
by morgan (@morgan) 24 Aug '26
by morgan (@morgan) 24 Aug '26
24 Aug '26
morgan pushed to branch mullvad-browser-153.1.0esr-16.0-1 at The Tor Project / Applications / Mullvad Browser
Commits:
6fe0b290 by Henry Wilkes at 2026-08-24T13:31:33+00:00
fixup! Firefox preference overrides.
BB 45208: Enable the settings redesign.
- - - - -
1 changed file:
- browser/app/profile/001-base-profile.js
Changes:
=====================================
browser/app/profile/001-base-profile.js
=====================================
@@ -246,10 +246,6 @@ pref("browser.safebrowsing.provider.mozilla.gethashURL", "");
// https://bugzilla.mozilla.org/show_bug.cgi?id=1915280
pref("browser.uitour.enabled", false);
-// tor-browser#45110: Disable unified settings until we have migrated all our
-// settings and have applied our desired changes to upstream new designs.
-pref("browser.settings-redesign.enabled", false);
-
// Make sure Unified Telemetry is really disabled, see: #18738.
pref("toolkit.telemetry.unified", false);
// This needs to be locked, or nightly builds will automatically lock it to true
View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/commit/6fe…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/commit/6fe…
You're receiving this email because of your account on gitlab.torproject.org. Manage all notifications: https://gitlab.torproject.org/-/profile/notifications | Help: https://gitlab.torproject.org/help
1
0
[Git][tpo/applications/tor-browser][tor-browser-153.1.0esr-16.0-1] fixup! Firefox preference overrides.
by morgan (@morgan) 24 Aug '26
by morgan (@morgan) 24 Aug '26
24 Aug '26
morgan pushed to branch tor-browser-153.1.0esr-16.0-1 at The Tor Project / Applications / Tor Browser
Commits:
f0d9b219 by Henry Wilkes at 2026-08-24T13:27:33+00:00
fixup! Firefox preference overrides.
BB 45208: Enable the settings redesign.
- - - - -
1 changed file:
- browser/app/profile/001-base-profile.js
Changes:
=====================================
browser/app/profile/001-base-profile.js
=====================================
@@ -249,10 +249,6 @@ pref("browser.safebrowsing.provider.mozilla.gethashURL", "");
// https://bugzilla.mozilla.org/show_bug.cgi?id=1915280
pref("browser.uitour.enabled", false);
-// tor-browser#45110: Disable unified settings until we have migrated all our
-// settings and have applied our desired changes to upstream new designs.
-pref("browser.settings-redesign.enabled", false);
-
// Make sure Unified Telemetry is really disabled, see: #18738.
pref("toolkit.telemetry.unified", false);
// This needs to be locked, or nightly builds will automatically lock it to true
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/f0d9b21…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/commit/f0d9b21…
You're receiving this email because of your account on gitlab.torproject.org. Manage all notifications: https://gitlab.torproject.org/-/profile/notifications | Help: https://gitlab.torproject.org/help
1
0
[Git][tpo/applications/mullvad-browser][mullvad-browser-153.1.0esr-16.0-1] 2 commits: fixup! BB 41369: Improve Firefox language settings for multi-lingual packages
by morgan (@morgan) 24 Aug '26
by morgan (@morgan) 24 Aug '26
24 Aug '26
morgan pushed to branch mullvad-browser-153.1.0esr-16.0-1 at The Tor Project / Applications / Mullvad Browser
Commits:
54a1eb5f by Henry Wilkes at 2026-08-24T13:26:00+00:00
fixup! BB 41369: Improve Firefox language settings for multi-lingual packages
BB 45195: Change the subcategory for the language notification.
- - - - -
89ccd3f3 by Henry Wilkes at 2026-08-24T13:26:00+00:00
fixup! BB 41454: Move focus after calling openPreferences for a sub-category.
BB 43640: Modify the focus handling to work with the new settings
redesign.
- - - - -
5 changed files:
- browser/base/content/languageNotification.js
- browser/components/preferences/config/languages.mjs
- browser/components/preferences/findInPage.js
- browser/components/preferences/main.inc.xhtml
- browser/components/preferences/preferences.js
Changes:
=====================================
browser/base/content/languageNotification.js
=====================================
@@ -46,7 +46,7 @@ window.addEventListener("load", () => {
{
"l10n-id": "language-notification-button",
callback() {
- openPreferences("general-language");
+ openPreferences("languages-browser-languages");
},
},
];
=====================================
browser/components/preferences/config/languages.mjs
=====================================
@@ -862,6 +862,7 @@ SettingGroupManager.registerGroups({
inProgress: true,
l10nId: "browser-language-heading",
headingLevel: 2,
+ subcategory: "browser-languages",
iconSrc: "chrome://browser/skin/sidebar/firefox.svg",
items: [
{
=====================================
browser/components/preferences/findInPage.js
=====================================
@@ -72,7 +72,11 @@ var gSearchResultsPane = {
this.searchInput.addEventListener("input", this);
window.addEventListener("DOMContentLoaded", () => {
this.searchInput.updateComplete.then(() => {
- this.searchInput.focus();
+ // To avoid a race with `scrollAndHighlight`, we only move the focus
+ // if it remains at the top of the document. tor-browser#43640.
+ if (document.activeElement === document.body) {
+ this.searchInput.focus();
+ }
});
// Initialize other panes in an idle callback.
window.requestIdleCallback(() => this.initializeCategories());
=====================================
browser/components/preferences/main.inc.xhtml
=====================================
@@ -65,7 +65,7 @@
<!-- Languages -->
<html:setting-group groupid="browserLanguage" data-srd-migrated="" hidden="true" data-category="paneGeneral"></html:setting-group>
<html:setting-group groupid="websiteLanguage" data-srd-migrated="" hidden="true" data-category="paneGeneral"></html:setting-group>
-<groupbox id="languagesGroup" data-category="paneGeneral" hidden="true" data-subcategory="language" data-srd-groupid="browserLanguage">
+<groupbox id="languagesGroup" data-category="paneGeneral" hidden="true" data-srd-groupid="browserLanguage">
<label><html:h2 data-l10n-id="language-header"/></label>
<vbox id="browserLanguagesBox" align="start" hidden="true">
=====================================
browser/components/preferences/preferences.js
=====================================
@@ -961,24 +961,28 @@ function scrollAndHighlight(subcategory) {
return;
}
- // We assign a tabindex=-1 to the element so that we can focus it. This allows
- // us to move screen reader's focus to an arbitrary position on the page.
- // See tor-browser#41454 and mozilla bug 1799153.
- const doFocus = () => {
- elements[0].setAttribute("tabindex", "-1");
- Services.focus.setFocus(elements[0], Services.focus.FLAG_NOSCROLL);
- // Immediately remove again now that it has focus.
- elements[0].removeAttribute("tabindex");
- };
- // The element is not always immediately focusable, so we wait until document
- // load.
- if (document.readyState === "complete") {
- doFocus();
+ // We focus the first element that we can focus.
+ // See tor-browser#41454, tor-browser#45195 and mozilla bug 1799153.
+ let focusTarget = elements[0];
+ if (focusTarget.tagName === "setting-group") {
+ focusTarget = focusTarget.fieldsetEl;
+ // Make the heading focusable.
+ focusTarget.focusableHeading = true;
+ focusTarget.updateComplete.then(() => {
+ focusTarget.focusHeading();
+ });
} else {
- // Wait until document load to move focus.
- // NOTE: This should be called after DOMContentLoaded, where the searchInput
- // is focused.
- window.addEventListener("load", doFocus, { once: true });
+ // Try focus directly using the focus method, which can be overridden.
+ focusTarget.focus();
+ if (!focusTarget.contains(document.activeElement)) {
+ // Else, try focus the first focusable target.
+ Services.focus.moveFocus(
+ window,
+ focusTarget,
+ Services.focus.MOVEFOCUS_FIRST,
+ Services.focus.FLAG_NOSCROLL
+ );
+ }
}
elements[0].scrollIntoView({
View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/ff…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/ff…
You're receiving this email because of your account on gitlab.torproject.org. Manage all notifications: https://gitlab.torproject.org/-/profile/notifications | Help: https://gitlab.torproject.org/help
1
0
[Git][tpo/applications/tor-browser][tor-browser-153.1.0esr-16.0-1] 3 commits: fixup! BB 41369: Improve Firefox language settings for multi-lingual packages
by morgan (@morgan) 24 Aug '26
by morgan (@morgan) 24 Aug '26
24 Aug '26
morgan pushed to branch tor-browser-153.1.0esr-16.0-1 at The Tor Project / Applications / Tor Browser
Commits:
8eb85eec by Henry Wilkes at 2026-08-24T13:07:13+00:00
fixup! BB 41369: Improve Firefox language settings for multi-lingual packages
BB 45195: Change the subcategory for the language notification.
- - - - -
108ff310 by Henry Wilkes at 2026-08-24T13:07:13+00:00
fixup! BB 41454: Move focus after calling openPreferences for a sub-category.
BB 43640: Modify the focus handling to work with the new settings
redesign.
- - - - -
1ab24002 by Henry Wilkes at 2026-08-24T13:07:13+00:00
fixup! TB 31286: Implementation of bridge, proxy, and firewall settings in about:preferences#connection
TB 45195: Add the "viewlogs" subcategory.
- - - - -
6 changed files:
- browser/base/content/languageNotification.js
- browser/components/preferences/config/languages.mjs
- browser/components/preferences/findInPage.js
- browser/components/preferences/main.inc.xhtml
- browser/components/preferences/preferences.js
- browser/components/torpreferences/config/connection.mjs
Changes:
=====================================
browser/base/content/languageNotification.js
=====================================
@@ -46,7 +46,7 @@ window.addEventListener("load", () => {
{
"l10n-id": "language-notification-button",
callback() {
- openPreferences("general-language");
+ openPreferences("languages-browser-languages");
},
},
];
=====================================
browser/components/preferences/config/languages.mjs
=====================================
@@ -862,6 +862,7 @@ SettingGroupManager.registerGroups({
inProgress: true,
l10nId: "browser-language-heading",
headingLevel: 2,
+ subcategory: "browser-languages",
iconSrc: "chrome://browser/skin/sidebar/firefox.svg",
items: [
{
=====================================
browser/components/preferences/findInPage.js
=====================================
@@ -72,7 +72,11 @@ var gSearchResultsPane = {
this.searchInput.addEventListener("input", this);
window.addEventListener("DOMContentLoaded", () => {
this.searchInput.updateComplete.then(() => {
- this.searchInput.focus();
+ // To avoid a race with `scrollAndHighlight`, we only move the focus
+ // if it remains at the top of the document. tor-browser#43640.
+ if (document.activeElement === document.body) {
+ this.searchInput.focus();
+ }
});
// Initialize other panes in an idle callback.
window.requestIdleCallback(() => this.initializeCategories());
=====================================
browser/components/preferences/main.inc.xhtml
=====================================
@@ -65,7 +65,7 @@
<!-- Languages -->
<html:setting-group groupid="browserLanguage" data-srd-migrated="" hidden="true" data-category="paneGeneral"></html:setting-group>
<html:setting-group groupid="websiteLanguage" data-srd-migrated="" hidden="true" data-category="paneGeneral"></html:setting-group>
-<groupbox id="languagesGroup" data-category="paneGeneral" hidden="true" data-subcategory="language" data-srd-groupid="browserLanguage">
+<groupbox id="languagesGroup" data-category="paneGeneral" hidden="true" data-srd-groupid="browserLanguage">
<label><html:h2 data-l10n-id="language-header"/></label>
<vbox id="browserLanguagesBox" align="start" hidden="true">
=====================================
browser/components/preferences/preferences.js
=====================================
@@ -994,24 +994,28 @@ function scrollAndHighlight(subcategory) {
return;
}
- // We assign a tabindex=-1 to the element so that we can focus it. This allows
- // us to move screen reader's focus to an arbitrary position on the page.
- // See tor-browser#41454 and mozilla bug 1799153.
- const doFocus = () => {
- elements[0].setAttribute("tabindex", "-1");
- Services.focus.setFocus(elements[0], Services.focus.FLAG_NOSCROLL);
- // Immediately remove again now that it has focus.
- elements[0].removeAttribute("tabindex");
- };
- // The element is not always immediately focusable, so we wait until document
- // load.
- if (document.readyState === "complete") {
- doFocus();
+ // We focus the first element that we can focus.
+ // See tor-browser#41454, tor-browser#45195 and mozilla bug 1799153.
+ let focusTarget = elements[0];
+ if (focusTarget.tagName === "setting-group") {
+ focusTarget = focusTarget.fieldsetEl;
+ // Make the heading focusable.
+ focusTarget.focusableHeading = true;
+ focusTarget.updateComplete.then(() => {
+ focusTarget.focusHeading();
+ });
} else {
- // Wait until document load to move focus.
- // NOTE: This should be called after DOMContentLoaded, where the searchInput
- // is focused.
- window.addEventListener("load", doFocus, { once: true });
+ // Try focus directly using the focus method, which can be overridden.
+ focusTarget.focus();
+ if (!focusTarget.contains(document.activeElement)) {
+ // Else, try focus the first focusable target.
+ Services.focus.moveFocus(
+ window,
+ focusTarget,
+ Services.focus.MOVEFOCUS_FIRST,
+ Services.focus.FLAG_NOSCROLL
+ );
+ }
}
elements[0].scrollIntoView({
=====================================
browser/components/torpreferences/config/connection.mjs
=====================================
@@ -205,6 +205,7 @@ SettingGroupManager.registerGroups({
},
{
id: "torViewLog",
+ subcategory: "viewlogs",
l10nId: "tor-view-log-button2",
control: "moz-box-button",
},
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/abfb08…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/abfb08…
You're receiving this email because of your account on gitlab.torproject.org. Manage all notifications: https://gitlab.torproject.org/-/profile/notifications | Help: https://gitlab.torproject.org/help
1
0
[Git][tpo/applications/mullvad-browser][mullvad-browser-153.1.0esr-16.0-1] 2 commits: fixup! BB 31575: Disable Firefox Home (Activity Stream)
by morgan (@morgan) 24 Aug '26
by morgan (@morgan) 24 Aug '26
24 Aug '26
morgan pushed to branch mullvad-browser-153.1.0esr-16.0-1 at The Tor Project / Applications / Mullvad Browser
Commits:
1a8a3b08 by Henry Wilkes at 2026-08-24T12:59:37+00:00
fixup! BB 31575: Disable Firefox Home (Activity Stream)
BB 44830: Drop the "home" setting group.
- - - - -
ffecd665 by Henry Wilkes at 2026-08-24T12:59:37+00:00
BB 44830: Include the newtab AboutPreferences.sys.mjs file for the home settings.
Drop once we get the patch from bugzilla bug 2048379.
- - - - -
4 changed files:
- browser/components/preferences/config/home-startup.mjs
- browser/components/preferences/preferences.js
- browser/extensions/moz.build
- browser/extensions/newtab/lib/AboutPreferences.sys.mjs
Changes:
=====================================
browser/components/preferences/config/home-startup.mjs
=====================================
@@ -5,6 +5,10 @@
import { SettingGroupManager } from "chrome://browser/content/preferences/config/SettingGroupManager.mjs";
import { Preferences } from "chrome://global/content/preferences/Preferences.mjs";
+const { AboutPreferences } = ChromeUtils.importESModule(
+ "moz-src:///browser/extensions/newtab/lib/AboutPreferences.sys.mjs"
+);
+
/*
* Preferences:
*
@@ -32,4 +36,7 @@ if (Services.prefs.getBoolPref("browser.settings-redesign.enabled")) {
defaultBrowserHome: window.createDefaultBrowserConfig(),
startupHome: window.createStartupConfig(),
});
+ // Register the rest of the home settings using the "newtab" extension's file.
+ // tor-browser#44830.
+ new AboutPreferences().baseBrowserRegisterGroups(window);
}
=====================================
browser/components/preferences/preferences.js
=====================================
@@ -318,7 +318,9 @@ const CONFIG_PANES = Object.freeze({
home: {
l10nId: "home-section",
iconSrc: "chrome://browser/skin/home.svg",
- groupIds: ["defaultBrowserHome", "startupHome", "homepage", "home"],
+ // We drop the "home" settings entirely since they are only relevant for
+ // Firefox Home. tor-browser#44830.
+ groupIds: ["defaultBrowserHome", "startupHome", "homepage"],
module: "chrome://browser/content/preferences/config/home-startup.mjs",
replaces: "home",
},
=====================================
browser/extensions/moz.build
=====================================
@@ -5,3 +5,8 @@
DIRS += []
JAR_MANIFESTS += ["jar.mn"]
+
+# Hack in the AboutPreferences.sys.mjs file, which is needed for the home
+# settings pane, and can more-or-less function without the rest of the "newtab"
+# extension. tor-browser#44830.
+MOZ_SRC_FILES += ["newtab/lib/AboutPreferences.sys.mjs"]
=====================================
browser/extensions/newtab/lib/AboutPreferences.sys.mjs
=====================================
@@ -2,15 +2,14 @@
* 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/. */
-import {
- actionTypes as at,
- actionCreators as ac,
-} from "resource://newtab/common/Actions.mjs";
-import {
- WIDGET_REGISTRY,
- isWidgetToggleVisible,
- isWidgetsContainerVisible,
-} from "resource://newtab/common/WidgetsRegistry.mjs";
+// The newtab extension is not available in base browser, so we replace the
+// imports with empty objects that we do *not* expect to be used in practice.
+// See tor-browser#44830.
+const at = {};
+const ac = {};
+const WIDGET_REGISTRY = [];
+const isWidgetToggleVisible = () => {};
+const isWidgetsContainerVisible = () => {};
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
@@ -347,6 +346,23 @@ export class AboutPreferences {
this.toggleRestoreDefaults(window.gHomePane);
}
+ /**
+ * Register the setting groups for base browser.
+ *
+ * Added for tor-browser#44830.
+ *
+ * @param {Window} window - The about:preferences window.
+ */
+ baseBrowserRegisterGroups(window) {
+ // We do not register the "home" component, since this is specific for
+ // Firefox Home. tor-browser#44830.
+ window.MozXULElement.insertFTLIfNeeded("browser/newtab/newtab.ftl");
+ window.SettingGroupManager.registerGroups({
+ homepage: this._setupHomepageGroup(window),
+ customHomepage: this._setupCustomHomepageGroup(window),
+ });
+ }
+
/** @param {Window} window */
_registerPreferences(window) {
const { Preferences } = window;
View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/63…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/63…
You're receiving this email because of your account on gitlab.torproject.org. Manage all notifications: https://gitlab.torproject.org/-/profile/notifications | Help: https://gitlab.torproject.org/help
1
0
[Git][tpo/applications/tor-browser][tor-browser-153.1.0esr-16.0-1] 3 commits: fixup! BB 31575: Disable Firefox Home (Activity Stream)
by morgan (@morgan) 24 Aug '26
by morgan (@morgan) 24 Aug '26
24 Aug '26
morgan pushed to branch tor-browser-153.1.0esr-16.0-1 at The Tor Project / Applications / Tor Browser
Commits:
c837e500 by Henry Wilkes at 2026-08-24T12:55:55+00:00
fixup! BB 31575: Disable Firefox Home (Activity Stream)
BB 44830: Drop the "home" setting group.
- - - - -
dae6e877 by Henry Wilkes at 2026-08-24T12:55:55+00:00
BB 44830: Include the newtab AboutPreferences.sys.mjs file for the home settings.
Drop once we get the patch from bugzilla bug 2048379.
- - - - -
abfb085a by Henry Wilkes at 2026-08-24T12:55:55+00:00
fixup! TB 7494: Create local home page for TBB.
TB 44830: Replace Firefox Home with Tor Browser Home.
- - - - -
4 changed files:
- browser/components/preferences/config/home-startup.mjs
- browser/components/preferences/preferences.js
- browser/extensions/moz.build
- browser/extensions/newtab/lib/AboutPreferences.sys.mjs
Changes:
=====================================
browser/components/preferences/config/home-startup.mjs
=====================================
@@ -5,6 +5,10 @@
import { SettingGroupManager } from "chrome://browser/content/preferences/config/SettingGroupManager.mjs";
import { Preferences } from "chrome://global/content/preferences/Preferences.mjs";
+const { AboutPreferences } = ChromeUtils.importESModule(
+ "moz-src:///browser/extensions/newtab/lib/AboutPreferences.sys.mjs"
+);
+
/*
* Preferences:
*
@@ -32,4 +36,7 @@ if (Services.prefs.getBoolPref("browser.settings-redesign.enabled")) {
defaultBrowserHome: window.createDefaultBrowserConfig(),
startupHome: window.createStartupConfig(),
});
+ // Register the rest of the home settings using the "newtab" extension's file.
+ // tor-browser#44830.
+ new AboutPreferences().baseBrowserRegisterGroups(window);
}
=====================================
browser/components/preferences/preferences.js
=====================================
@@ -330,7 +330,9 @@ const CONFIG_PANES = Object.freeze({
home: {
l10nId: "home-section",
iconSrc: "chrome://browser/skin/home.svg",
- groupIds: ["defaultBrowserHome", "startupHome", "homepage", "home"],
+ // We drop the "home" settings entirely since they are only relevant for
+ // Firefox Home. tor-browser#44830.
+ groupIds: ["defaultBrowserHome", "startupHome", "homepage"],
module: "chrome://browser/content/preferences/config/home-startup.mjs",
replaces: "home",
},
=====================================
browser/extensions/moz.build
=====================================
@@ -5,3 +5,8 @@
DIRS += []
JAR_MANIFESTS += ["jar.mn"]
+
+# Hack in the AboutPreferences.sys.mjs file, which is needed for the home
+# settings pane, and can more-or-less function without the rest of the "newtab"
+# extension. tor-browser#44830.
+MOZ_SRC_FILES += ["newtab/lib/AboutPreferences.sys.mjs"]
=====================================
browser/extensions/newtab/lib/AboutPreferences.sys.mjs
=====================================
@@ -2,15 +2,14 @@
* 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/. */
-import {
- actionTypes as at,
- actionCreators as ac,
-} from "resource://newtab/common/Actions.mjs";
-import {
- WIDGET_REGISTRY,
- isWidgetToggleVisible,
- isWidgetsContainerVisible,
-} from "resource://newtab/common/WidgetsRegistry.mjs";
+// The newtab extension is not available in base browser, so we replace the
+// imports with empty objects that we do *not* expect to be used in practice.
+// See tor-browser#44830.
+const at = {};
+const ac = {};
+const WIDGET_REGISTRY = [];
+const isWidgetToggleVisible = () => {};
+const isWidgetsContainerVisible = () => {};
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
@@ -24,7 +23,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
Management: "resource://gre/modules/Extension.sys.mjs",
});
-const DEFAULT_HOMEPAGE_URL = "about:home";
+const DEFAULT_HOMEPAGE_URL = "about:tor";
const BLANK_HOMEPAGE_URL = "chrome://browser/content/blanktab.html";
const HOMEPAGE_OVERRIDE_KEY = "homepage_override";
const URL_OVERRIDES_TYPE = "url_overrides";
@@ -347,6 +346,23 @@ export class AboutPreferences {
this.toggleRestoreDefaults(window.gHomePane);
}
+ /**
+ * Register the setting groups for base browser.
+ *
+ * Added for tor-browser#44830.
+ *
+ * @param {Window} window - The about:preferences window.
+ */
+ baseBrowserRegisterGroups(window) {
+ // We do not register the "home" component, since this is specific for
+ // Firefox Home. tor-browser#44830.
+ window.MozXULElement.insertFTLIfNeeded("browser/newtab/newtab.ftl");
+ window.SettingGroupManager.registerGroups({
+ homepage: this._setupHomepageGroup(window),
+ customHomepage: this._setupCustomHomepageGroup(window),
+ });
+ }
+
/** @param {Window} window */
_registerPreferences(window) {
const { Preferences } = window;
@@ -822,10 +838,7 @@ export class AboutPreferences {
control: "moz-select",
l10nId: "home-homepage-new-windows",
options: [
- {
- value: "home",
- l10nId: "home-mode-choice-default-fx-srd",
- },
+ { value: "home", l10nId: "home-mode-choice-tor" },
{ value: "blank", l10nId: "home-mode-choice-blank-srd" },
{ value: "custom", l10nId: "home-mode-choice-custom-srd" },
],
@@ -842,10 +855,7 @@ export class AboutPreferences {
control: "moz-select",
l10nId: "home-homepage-new-tabs",
options: [
- {
- value: "home",
- l10nId: "home-mode-choice-default-fx-srd",
- },
+ { value: "home", l10nId: "home-mode-choice-tor" },
{ value: "blank", l10nId: "home-mode-choice-blank-srd" },
],
},
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/af6696…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/af6696…
You're receiving this email because of your account on gitlab.torproject.org. Manage all notifications: https://gitlab.torproject.org/-/profile/notifications | Help: https://gitlab.torproject.org/help
1
0
[Git][tpo/applications/mullvad-browser][mullvad-browser-153.1.0esr-16.0-1] 3 commits: fixup! BB 40925: Implemented the Security Level component
by morgan (@morgan) 24 Aug '26
by morgan (@morgan) 24 Aug '26
24 Aug '26
morgan pushed to branch mullvad-browser-153.1.0esr-16.0-1 at The Tor Project / Applications / Mullvad Browser
Commits:
12a5b451 by Henry Wilkes at 2026-08-24T12:22:50+00:00
fixup! BB 40925: Implemented the Security Level component
BB 45201: Move security level settings to the settings config.
- - - - -
893c9384 by Henry Wilkes at 2026-08-24T12:22:54+00:00
fixup! Base Browser strings
BB 45201: Update security level setting strings.
- - - - -
63592373 by Henry Wilkes at 2026-08-24T12:23:39+00:00
BB 45201: Customize moz- input widgets for Base Browser.
- - - - -
21 changed files:
- browser/components/preferences/config/privacy.mjs
- browser/components/preferences/preferences.js
- browser/components/preferences/preferences.xhtml
- browser/components/preferences/privacy.inc.xhtml
- browser/components/preferences/privacy.js
- − browser/components/securitylevel/SecurityLevelUIUtils.sys.mjs
- + browser/components/securitylevel/config/security-level.mjs
- browser/components/securitylevel/content/securityLevel.js
- + browser/components/securitylevel/content/securityLevelDialog.css
- browser/components/securitylevel/content/securityLevelDialog.js
- browser/components/securitylevel/content/securityLevelDialog.xhtml
- − browser/components/securitylevel/content/securityLevelPreferences.css
- − browser/components/securitylevel/content/securityLevelPreferences.inc.xhtml
- browser/components/securitylevel/jar.mn
- browser/components/securitylevel/moz.build
- + browser/components/securitylevel/widgets/security-level-description.css
- + browser/components/securitylevel/widgets/security-level-description.mjs
- + browser/components/securitylevel/widgets/security-level-display.css
- + browser/components/securitylevel/widgets/security-level-display.mjs
- toolkit/content/widgets/lit-utils.mjs
- toolkit/locales/en-US/toolkit/global/base-browser.ftl
Changes:
=====================================
browser/components/preferences/config/privacy.mjs
=====================================
@@ -7,6 +7,10 @@
import { SettingGroupManager } from "chrome://browser/content/preferences/config/SettingGroupManager.mjs";
import { Preferences } from "chrome://global/content/preferences/Preferences.mjs";
+ChromeUtils.importESModule(
+ "chrome://browser/content/securitylevel/config/security-level.mjs",
+ { global: "current" }
+);
ChromeUtils.importESModule(
"chrome://browser/content/preferences/config/protections-from-apps.mjs",
{ global: "current" }
=====================================
browser/components/preferences/preferences.js
=====================================
@@ -397,6 +397,7 @@ const CONFIG_PANES = Object.freeze({
"ipprotection",
"cookiesAndSiteData2",
"history2",
+ "securityLevelGroup",
"nonTechnicalPrivacy2",
"dnsOverHttps",
"connectionLink",
=====================================
browser/components/preferences/preferences.xhtml
=====================================
@@ -43,7 +43,6 @@
href="chrome://browser/content/preferences/letterboxing.css"
/>
- <link rel="stylesheet" href="chrome://browser/content/securitylevel/securityLevelPreferences.css" />
<link rel="localization" href="branding/brand.ftl"/>
<link rel="localization" href="browser/browser.ftl"/>
@@ -106,6 +105,8 @@
<script type="module" src="chrome://browser/content/preferences/widgets/update-information.mjs"></script>
<script type="module" src="chrome://browser/content/preferences/widgets/update-state.mjs"></script>
<script type="module" src="chrome://browser/content/ipprotection/bandwidth-usage.mjs"></script>
+ <script type="module" src="chrome://browser/content/securitylevel/widgets/security-level-description.mjs"></script>
+ <script type="module" src="chrome://browser/content/securitylevel/widgets/security-level-display.mjs"></script>
</head>
<html:body xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
=====================================
browser/components/preferences/privacy.inc.xhtml
=====================================
@@ -578,7 +578,7 @@
<html:h1 data-l10n-id="security-header"/>
</hbox>
-#include ../securitylevel/content/securityLevelPreferences.inc.xhtml
+<html:setting-group groupid="securityLevelGroup" data-category="panePrivacy" hidden="true" data-srd-migrated=""></html:setting-group>
<!-- addons, forgery (phishing) UI Security -->
<html:setting-group groupid="browsingProtection" data-category="panePrivacy" hidden="true" data-hidden-from-search="true" data-srd-migrated=""></html:setting-group>
=====================================
browser/components/preferences/privacy.js
=====================================
@@ -60,13 +60,6 @@ ChromeUtils.defineLazyGetter(lazy, "gParentalControlsService", () =>
: null
);
-// TODO: module import via ChromeUtils.defineModuleGetter
-XPCOMUtils.defineLazyScriptGetter(
- this,
- ["SecurityLevelPreferences"],
- "chrome://browser/content/securitylevel/securityLevel.js"
-);
-
XPCOMUtils.defineLazyPreferenceGetter(
this,
"gIsFirstPartyIsolated",
@@ -150,16 +143,6 @@ function initTCPStandardSection() {
var gPrivacyPane = {
_pane: null,
- /**
- * Show the Security Level UI
- */
- _initSecurityLevel() {
- SecurityLevelPreferences.init();
- window.addEventListener("unload", () => SecurityLevelPreferences.uninit(), {
- once: true,
- });
- },
-
/**
* Whether the prompt to restart Firefox should appear when changing the autostart pref.
*/
@@ -653,6 +636,7 @@ var gPrivacyPane = {
initSettingGroup("etpReset");
initSettingGroup("etpCustomize");
initSettingGroup("networkProxy");
+ initSettingGroup("securityLevelGroup");
/* Initialize Content Blocking */
this.initContentBlocking();
@@ -662,7 +646,6 @@ var gPrivacyPane = {
this.networkCookieBehaviorReadPrefs();
this._initTrackingProtectionExtensionControl();
this._ensureTrackingProtectionExceptionListMigration();
- this._initSecurityLevel();
Preferences.get("privacy.trackingprotection.enabled").on(
"change",
=====================================
browser/components/securitylevel/SecurityLevelUIUtils.sys.mjs deleted
=====================================
@@ -1,73 +0,0 @@
-/**
- * Common methods for the desktop security level components.
- */
-export const SecurityLevelUIUtils = {
- /**
- * Create an element that gives a description of the security level. To be
- * used in the settings.
- *
- * @param {string} level - The security level to describe.
- * @param {Document} doc - The document where the element will be inserted.
- *
- * @returns {Element} - The newly created element.
- */
- createDescriptionElement(level, doc) {
- const el = doc.createElement("div");
- el.classList.add("security-level-description");
-
- let l10nIdSummary;
- let bullets;
- switch (level) {
- case "standard":
- l10nIdSummary = "security-level-summary-standard";
- break;
- case "safer":
- l10nIdSummary = "security-level-summary-safer";
- bullets = [
- "security-level-preferences-bullet-https-only-javascript",
- "security-level-preferences-bullet-limit-font-and-symbols",
- "security-level-preferences-bullet-limit-media",
- ];
- break;
- case "safest":
- l10nIdSummary = "security-level-summary-safest";
- bullets = [
- "security-level-preferences-bullet-disabled-javascript",
- "security-level-preferences-bullet-limit-font-and-symbols-and-images",
- "security-level-preferences-bullet-limit-media",
- ];
- break;
- case "custom":
- l10nIdSummary = "security-level-summary-custom";
- break;
- default:
- throw Error(`Unhandled level: ${level}`);
- }
-
- const summaryEl = doc.createElement("div");
- summaryEl.classList.add("security-level-summary");
- doc.l10n.setAttributes(summaryEl, l10nIdSummary);
-
- el.append(summaryEl);
-
- if (!bullets) {
- return el;
- }
-
- const listEl = doc.createElement("ul");
- listEl.classList.add("security-level-description-extra");
- // Add a mozilla styling class as well:
- listEl.classList.add("privacy-extra-information");
- for (const l10nId of bullets) {
- const bulletEl = doc.createElement("li");
- bulletEl.classList.add("security-level-description-bullet");
-
- doc.l10n.setAttributes(bulletEl, l10nId);
-
- listEl.append(bulletEl);
- }
-
- el.append(listEl);
- return el;
- },
-};
=====================================
browser/components/securitylevel/config/security-level.mjs
=====================================
@@ -0,0 +1,81 @@
+/* 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 https://mozilla.org/MPL/2.0/. */
+
+import { SettingGroupManager } from "chrome://browser/content/preferences/config/SettingGroupManager.mjs";
+import { Preferences } from "chrome://global/content/preferences/Preferences.mjs";
+
+const lazy = {};
+
+ChromeUtils.defineESModuleGetters(lazy, {
+ SecurityLevelPrefs:
+ "moz-src:///toolkit/components/securitylevel/SecurityLevel.sys.mjs",
+});
+
+SettingGroupManager.registerGroups({
+ securityLevelGroup: {
+ subcategory: "securitylevel",
+ l10nId: "security-level-settings-group",
+ headingLevel: 2,
+ supportPage: "tor-manual:features__security-levels",
+ items: [
+ {
+ id: "securityLevelBoxGroup",
+ control: "moz-box-group",
+ items: [
+ {
+ id: "securityLevelCurrent",
+ control: "security-level-display",
+ },
+ {
+ id: "securityLevelChangeButton",
+ l10nId: "security-level-settings-change-button",
+ control: "moz-box-button",
+ },
+ ],
+ },
+ ],
+ },
+});
+
+Preferences.addSetting({
+ id: "securityLevelCurrent",
+ setup(emitChange) {
+ Services.prefs.addObserver(
+ "browser.security_level.security_slider",
+ emitChange
+ );
+ Services.prefs.addObserver(
+ "browser.security_level.security_custom",
+ emitChange
+ );
+
+ return () => {
+ Services.prefs.removeObserver(
+ "browser.security_level.security_slider",
+ emitChange
+ );
+ Services.prefs.removeObserver(
+ "browser.security_level.security_custom",
+ emitChange
+ );
+ };
+ },
+ get: () => {
+ return lazy.SecurityLevelPrefs.securityLevelSummary;
+ },
+});
+
+Preferences.addSetting({
+ id: "securityLevelBoxGroup",
+});
+
+Preferences.addSetting({
+ id: "securityLevelChangeButton",
+ onUserClick() {
+ window.gSubDialog.open(
+ "chrome://browser/content/securitylevel/securityLevelDialog.xhtml",
+ { features: "resizable=yes" }
+ );
+ },
+});
=====================================
browser/components/securitylevel/content/securityLevel.js
=====================================
@@ -5,8 +5,6 @@
ChromeUtils.defineESModuleGetters(this, {
SecurityLevelPrefs:
"moz-src:///toolkit/components/securitylevel/SecurityLevel.sys.mjs",
- SecurityLevelUIUtils:
- "moz-src:///browser/components/securitylevel/SecurityLevelUIUtils.sys.mjs",
});
/*
@@ -263,103 +261,3 @@ var SecurityLevelPanel = {
}
},
}; /* SecurityLevelPanel */
-
-/*
- Security Level Preferences Code
-
- Code to handle init and update of security level section in about:preferences#privacy
-*/
-
-var SecurityLevelPreferences = {
- _securityPrefsBranch: null,
-
- /**
- * The element that shows the current security level.
- *
- * @type {?Element}
- */
- _currentEl: null,
-
- _populateXUL() {
- this._currentEl = document.getElementById("security-level-current");
- const changeButton = document.getElementById("security-level-change");
- const badgeEl = this._currentEl.querySelector(
- ".security-level-current-badge"
- );
-
- for (const { level, nameId } of [
- { level: "standard", nameId: "security-level-panel-level-standard" },
- { level: "safer", nameId: "security-level-panel-level-safer" },
- { level: "safest", nameId: "security-level-panel-level-safest" },
- { level: "custom", nameId: "security-level-panel-level-custom" },
- ]) {
- // Classes that control visibility:
- // security-level-current-standard
- // security-level-current-safer
- // security-level-current-safest
- // security-level-current-custom
- const visibilityClass = `security-level-current-${level}`;
- const nameEl = document.createElement("div");
- nameEl.classList.add("security-level-name", visibilityClass);
- document.l10n.setAttributes(nameEl, nameId);
-
- const descriptionEl = SecurityLevelUIUtils.createDescriptionElement(
- level,
- document
- );
- descriptionEl.classList.add(visibilityClass);
-
- this._currentEl.insertBefore(nameEl, badgeEl);
- this._currentEl.insertBefore(descriptionEl, changeButton);
- }
-
- changeButton.addEventListener("click", () => {
- this._openDialog();
- });
- },
-
- _openDialog() {
- gSubDialog.open(
- "chrome://browser/content/securitylevel/securityLevelDialog.xhtml",
- { features: "resizable=yes" }
- );
- },
-
- _configUIFromPrefs() {
- // Set a data-current-level attribute for showing the current security
- // level, and hiding the rest.
- this._currentEl.dataset.currentLevel =
- SecurityLevelPrefs.securityLevelSummary;
- },
-
- init() {
- // populate XUL with localized strings
- this._populateXUL();
-
- // read prefs and populate UI
- this._configUIFromPrefs();
-
- // register for pref chagnes
- this._securityPrefsBranch = Services.prefs.getBranch(
- "browser.security_level."
- );
- this._securityPrefsBranch.addObserver("", this);
- },
-
- uninit() {
- // unregister for pref change events
- this._securityPrefsBranch.removeObserver("", this);
- this._securityPrefsBranch = null;
- },
-
- // callback for when prefs change
- observe(subject, topic, data) {
- switch (topic) {
- case "nsPref:changed":
- if (data == "security_slider" || data == "security_custom") {
- this._configUIFromPrefs();
- }
- break;
- }
- },
-}; /* SecurityLevelPreferences */
=====================================
browser/components/securitylevel/content/securityLevelDialog.css
=====================================
@@ -0,0 +1,29 @@
+/* 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 https://mozilla.org/MPL/2.0/. */
+
+/* Hack to gain the internal styling of <moz-badge>.
+ * TODO: Drop this once we can use moz-badge. tor-browser#45229. */
+@import url("chrome://global/content/elements/moz-badge.css");
+
+#security-level-radiogroup {
+ margin-block: var(--space-large) var(--space-xlarge);
+}
+
+.security-level-radio-label {
+ display: inline flex;
+ gap: var(--space-small);
+}
+
+.security-level-radio-label .moz-badge-label > span {
+ /* Still accessible to screen reader, but not visual.
+ * Keep inline, but with no layout width. */
+ display: inline-block;
+ width: 1px;
+ margin-inline-end: -1px;
+ clip-path: inset(50%);
+}
+
+.moz-badge[hidden] {
+ display: none;
+}
=====================================
browser/components/securitylevel/content/securityLevelDialog.js
=====================================
@@ -3,9 +3,6 @@
const { SecurityLevelPrefs } = ChromeUtils.importESModule(
"moz-src:///toolkit/components/securitylevel/SecurityLevel.sys.mjs"
);
-const { SecurityLevelUIUtils } = ChromeUtils.importESModule(
- "moz-src:///browser/components/securitylevel/SecurityLevelUIUtils.sys.mjs"
-);
const gSecurityLevelDialog = {
/**
@@ -27,9 +24,9 @@ const gSecurityLevelDialog = {
*/
_radiogroup: null,
/**
- * A list of radio options and their containers.
+ * A list of radio options and their descriptions.
*
- * @type {?Array<{ container: Element, radio: Element }>}
+ * @type {?Array<{ description: Element, radio: Element }>}
*/
_radioOptions: null,
@@ -56,85 +53,42 @@ const gSecurityLevelDialog = {
this._radiogroup = document.getElementById("security-level-radiogroup");
this._radioOptions = Array.from(
- this._radiogroup.querySelectorAll(".security-level-radio-container"),
- container => {
- return {
- container,
- radio: container.querySelector(".security-level-radio"),
- };
+ this._radiogroup.querySelectorAll("moz-radio"),
+ radio => {
+ const description = radio.querySelector("security-level-description");
+ // Hide bullets by default.
+ description.hideBullets = true;
+ return { radio, description };
}
);
- for (const { container, radio } of this._radioOptions) {
- const level = radio.value;
- radio.id = `security-level-radio-${level}`;
- const currentEl = container.querySelector(
- ".security-level-current-badge"
- );
- currentEl.id = `security-level-current-badge-${level}`;
- const descriptionEl = SecurityLevelUIUtils.createDescriptionElement(
- level,
- document
- );
- descriptionEl.classList.add("indent");
- descriptionEl.id = `security-level-description-${level}`;
-
- // Wait for the full translation of the element before adding it to the
- // DOM. In particular, we want to make sure the elements have text before
- // we measure the maxHeight below.
- await document.l10n.translateFragment(descriptionEl);
- document.l10n.pauseObserving();
- container.append(descriptionEl);
- document.l10n.resumeObserving();
-
- if (level === this._prevLevel) {
- currentEl.hidden = false;
- // When the currentEl is visible, include it in the accessible name for
- // the radio option.
- // NOTE: The currentEl has an accessible name which includes punctuation
- // to help separate it's content from the security level name.
- // E.g. "Standard (Current level)".
- radio.setAttribute("aria-labelledby", `${radio.id} ${currentEl.id}`);
- } else {
- currentEl.hidden = true;
- }
- // We point the accessible description to the wrapping
- // .security-level-description element, rather than its children
- // that define the actual text content. This means that when the
- // privacy-extra-information is shown or hidden, its text content is
- // included or excluded from the accessible description, respectively.
- radio.setAttribute("aria-describedby", descriptionEl.id);
+ for (const { radio } of this._radioOptions) {
+ radio.querySelector(".moz-badge").hidden =
+ radio.value !== this._prevLevel;
}
- // We want to reserve the maximum height of the radiogroup so that the
+ // We want to reserve the maximum height of the moz-radio-group so that the
// dialog has enough height when the user switches options. So we cycle
// through the options and measure the height when they are selected to set
// a minimum height that fits all of them.
- // NOTE: At the time of implementation, at this point the dialog may not
- // yet have the "subdialog" attribute, which means it is missing the
- // common.css stylesheet from its shadow root, which effects the size of the
- // .radio-check element and the font. Therefore, we have duplicated the
- // import of common.css in SecurityLevelDialog.xhtml to ensure it is applied
- // at this earlier stage.
let maxHeight = 0;
- for (const { container } of this._radioOptions) {
- container.classList.add("selected");
+ for (const { description } of this._radioOptions) {
+ description.hideBullets = false;
+ await this._settled();
maxHeight = Math.max(
maxHeight,
this._radiogroup.getBoundingClientRect().height
);
- container.classList.remove("selected");
+ description.hideBullets = true;
}
this._radiogroup.style.minHeight = `${maxHeight}px`;
if (this._prevLevel !== "custom") {
this._selectedLevel = this._prevLevel;
this._radiogroup.value = this._prevLevel;
- } else {
- this._radiogroup.selectedItem = null;
}
- this._radiogroup.addEventListener("select", () => {
+ this._radiogroup.addEventListener("change", () => {
this._selectedLevel = this._radiogroup.value;
this._updateSelected();
});
@@ -142,16 +96,31 @@ const gSecurityLevelDialog = {
this._updateSelected();
},
+ /**
+ * Wait for the DOM to be settled after some change.
+ */
+ async _settled() {
+ // Wait for the widgets to react to some change.
+ await Promise.all([
+ this._radiogroup.updateComplete,
+ ...this._radioOptions.map(({ radio }) => radio.updateComplete),
+ ]);
+ // Also wait for any string population.
+ if (document.hasPendingL10nMutations) {
+ await new Promise(r =>
+ document.addEventListener("L10nMutationsFinished", r, { once: true })
+ );
+ }
+ },
+
/**
* Update the UI in response to a change in selection.
*/
_updateSelected() {
this._acceptButton.disabled =
!this._selectedLevel || this._selectedLevel === this._prevLevel;
- // Have the container's `selected` CSS class match the selection state of
- // the radio elements.
- for (const { container, radio } of this._radioOptions) {
- container.classList.toggle("selected", radio.selected);
+ for (const { description, radio } of this._radioOptions) {
+ description.hideBullets = !radio.checked;
}
},
=====================================
browser/components/securitylevel/content/securityLevelDialog.xhtml
=====================================
@@ -10,18 +10,6 @@
<dialog id="security-level-dialog" buttons="accept,cancel">
<linkset>
<html:link rel="stylesheet" href="chrome://global/skin/global.css" />
- <!-- NOTE: We include common.css explicitly, rather than relying on
- - the dialog's shadowroot importing it, which is late loaded in
- - response to the dialog's "subdialog" attribute, which is set
- - in response to DOMFrameContentLoaded.
- - In particular, we need the .radio-check rule and font rules from
- - common-shared.css to be in place when gSecurityLevelDialog.init is
- - called, which will help ensure that the radio element has the correct
- - size when we measure its bounding box. -->
- <html:link
- rel="stylesheet"
- href="chrome://global/skin/in-content/common.css"
- />
<html:link
rel="stylesheet"
href="chrome://browser/skin/preferences/preferences.css"
@@ -32,57 +20,77 @@
/>
<html:link
rel="stylesheet"
- href="chrome://browser/content/securitylevel/securityLevelPreferences.css"
+ href="chrome://browser/content/securitylevel/securityLevelDialog.css"
/>
<html:link rel="localization" href="branding/brand.ftl" />
<html:link rel="localization" href="toolkit/global/base-browser.ftl" />
</linkset>
+ <html:script
+ type="module"
+ src="chrome://global/content/elements/moz-radio-group.mjs"
+ ></html:script>
+ <html:script
+ type="module"
+ src="chrome://browser/content/securitylevel/widgets/security-level-description.mjs"
+ ></html:script>
<script src="chrome://browser/content/securitylevel/securityLevelDialog.js" />
<description data-l10n-id="security-level-dialog-restart-description" />
- <radiogroup id="security-level-radiogroup" class="highlighting-group">
- <html:div
- class="security-level-radio-container security-level-grid privacy-detailedoption info-box-container"
- >
- <radio
- class="security-level-radio security-level-name"
+ <moz-radio-group
+ xmlns="http://www.w3.org/1999/xhtml"
+ id="security-level-radiogroup"
+ data-l10n-id="security-level-dialog-radio-group"
+ >
+ <moz-radio value="standard" use-label-slot="">
+ <span class="security-level-radio-label" slot="label">
+ <span data-l10n-id="security-level-panel-level-standard"></span>
+ <!-- TODO: Use <moz-badge> widget once bugzilla bug 2065204 is
+ - resolved. See tor-browser#45229. -->
+ <span class="moz-badge" hidden="hidden">
+ <span
+ class="moz-badge-label"
+ data-l10n-id="security-level-preferences-current-badge"
+ ></span>
+ </span>
+ </span>
+ <security-level-description
+ slot="description"
value="standard"
- data-l10n-id="security-level-preferences-level-standard"
- />
- <html:div
- class="security-level-current-badge"
- data-l10n-id="security-level-preferences-current-badge"
- ></html:div>
- </html:div>
- <html:div
- class="security-level-radio-container security-level-grid privacy-detailedoption info-box-container"
- >
- <radio
- class="security-level-radio security-level-name"
+ ></security-level-description>
+ </moz-radio>
+ <moz-radio value="safer" use-label-slot="">
+ <span class="security-level-radio-label" slot="label">
+ <span data-l10n-id="security-level-panel-level-safer"></span>
+ <span class="moz-badge" hidden="hidden">
+ <span
+ class="moz-badge-label"
+ data-l10n-id="security-level-preferences-current-badge"
+ ></span>
+ </span>
+ </span>
+ <security-level-description
+ slot="description"
value="safer"
- data-l10n-id="security-level-preferences-level-safer"
- />
- <html:div
- class="security-level-current-badge"
- data-l10n-id="security-level-preferences-current-badge"
- ></html:div>
- </html:div>
- <html:div
- class="security-level-radio-container security-level-grid privacy-detailedoption info-box-container"
- >
- <radio
- class="security-level-radio security-level-name"
+ ></security-level-description>
+ </moz-radio>
+ <moz-radio value="safest" use-label-slot="">
+ <span class="security-level-radio-label" slot="label">
+ <span data-l10n-id="security-level-panel-level-safest"></span>
+ <span class="moz-badge" hidden="hidden">
+ <span
+ class="moz-badge-label"
+ data-l10n-id="security-level-preferences-current-badge"
+ ></span>
+ </span>
+ </span>
+ <security-level-description
+ slot="description"
value="safest"
- data-l10n-id="security-level-preferences-level-safest"
- />
- <html:div
- class="security-level-current-badge"
- data-l10n-id="security-level-preferences-current-badge"
- ></html:div>
- </html:div>
- </radiogroup>
+ ></security-level-description>
+ </moz-radio>
+ </moz-radio-group>
</dialog>
</window>
=====================================
browser/components/securitylevel/content/securityLevelPreferences.css deleted
=====================================
@@ -1,171 +0,0 @@
-.security-level-grid {
- display: grid;
- grid-template:
- "icon name badge button" min-content
- "icon summary summary button" auto
- "icon extra extra ." auto
- / max-content max-content 1fr max-content;
-}
-
-.security-level-icon {
- grid-area: icon;
- align-self: start;
- width: var(--icon-size-large);
- height: var(--icon-size-large);
- -moz-context-properties: fill, stroke;
- fill: var(--icon-color);
- stroke: var(--icon-color-warning);
- margin-block-start: var(--space-xsmall);
- margin-inline-end: var(--space-large);
-}
-
-:-moz-locale-dir(rtl) .security-level-icon {
- transform: scaleX(-1);
-}
-
-.security-level-current-badge {
- grid-area: badge;
- align-self: center;
- justify-self: start;
- white-space: nowrap;
- background: var(--background-color-information);
- color: inherit;
- font-size: var(--font-size-small);
- border-radius: var(--border-radius-circle);
- margin-inline-start: var(--space-small);
- padding-block: var(--space-xsmall);
- padding-inline: var(--space-small);
-}
-
-.security-level-current-badge span {
- /* Still accessible to screen reader, but not visual.
- * Keep inline, but with no layout width. */
- display: inline-block;
- width: 1px;
- margin-inline-end: -1px;
- clip-path: inset(50%);
-}
-
-@media (prefers-contrast) and (not (forced-colors)) {
- .security-level-current-badge {
- /* Match the checkbox/radio colors. */
- background: var(--color-accent-primary);
- color: var(--button-text-color-primary);
- }
-}
-
-@media (forced-colors) {
- .security-level-current-badge {
- /* Match the checkbox/radio/selected colors. */
- background: SelectedItem;
- color: SelectedItemText;
- }
-}
-
-.security-level-name {
- grid-area: name;
- font-weight: var(--font-weight-bold);
- align-self: center;
- white-space: nowrap;
-}
-
-.security-level-description {
- display: grid;
- grid-column: summary-start / extra-end;
- grid-row: summary-start / extra-end;
- grid-template-rows: subgrid;
- grid-template-columns: subgrid;
- margin-block-start: var(--space-small);
-}
-
-.security-level-summary {
- grid-area: summary;
-}
-
-.security-level-description-extra {
- grid-area: extra;
- margin-block: var(--space-medium) 0;
- margin-inline: var(--space-large) 0;
- padding: 0;
-}
-
-.security-level-description-bullet:not(:last-child) {
- margin-block-end: var(--space-medium);
-}
-
-/* Tweak current security level display. */
-
-#security-level-current {
- margin-block-start: var(--space-large);
- background: var(--background-color-box);
- border: var(--border-width) solid var(--border-color);
- border-radius: var(--border-radius-small);
- padding: var(--space-medium);
-}
-
-#security-level-change {
- grid-area: button;
- align-self: center;
- margin: 0;
- margin-inline-start: var(--space-large);
-}
-
-/* Adjust which content is visible depending on the current security level. */
-
-#security-level-current:not([data-current-level="standard"]) .security-level-current-standard {
- display: none;
-}
-
-#security-level-current:not([data-current-level="safer"]) .security-level-current-safer {
- display: none;
-}
-
-#security-level-current:not([data-current-level="safest"]) .security-level-current-safest {
- display: none;
-}
-
-#security-level-current:not([data-current-level="custom"]) .security-level-current-custom {
- display: none;
-}
-
-#security-level-current[data-current-level="standard"] .security-level-icon {
- content: url("chrome://browser/content/securitylevel/security-level-standard.svg");
-}
-
-#security-level-current[data-current-level="safer"] .security-level-icon {
- content: url("chrome://browser/content/securitylevel/security-level-safer.svg");
-}
-
-#security-level-current[data-current-level="safest"] .security-level-icon {
- content: url("chrome://browser/content/securitylevel/security-level-safest.svg");
-}
-
-#security-level-current[data-current-level="custom"] .security-level-icon {
- content: url("chrome://browser/content/securitylevel/security-level-custom.svg");
-}
-
-/* Tweak security level dialog. */
-
-#security-level-radiogroup {
- margin-block: var(--space-large) var(--space-xlarge);
-}
-
-.security-level-radio-container {
- padding-block: var(--space-large);
-}
-
-#security-level-radiogroup .security-level-radio {
- margin: 0;
-}
-
-#security-level-radiogroup .radio-label-box {
- /* .security-level-current-badge already has a margin. */
- margin: 0;
-}
-
-#security-level-radiogroup .privacy-detailedoption.security-level-radio-container:not(.selected) .security-level-description-extra {
- /* .privacy-detailedoption uses visibility: hidden, which does not work with
- * our grid display (the margin is still reserved) so we use display: none
- * instead. */
- display: none;
-}
=====================================
browser/components/securitylevel/content/securityLevelPreferences.inc.xhtml deleted
=====================================
@@ -1,35 +0,0 @@
-<groupbox id="securityLevel-groupbox"
- data-category="panePrivacy"
- data-subcategory="securitylevel"
- hidden="true">
- <label>
- <html:h2 data-l10n-id="security-level-preferences-heading"></html:h2>
- </label>
- <vbox flex="1">
- <description class="description-deemphasized" flex="1">
- <html:span
- id="securityLevel-overview"
- data-l10n-id="security-level-preferences-overview"
- ></html:span>
- <html:a
- is="moz-support-link"
- support-page="tor-manual:features__security-levels"
- data-l10n-id="security-level-preferences-learn-more-link"
- ></html:a>
- </description>
- <html:div id="security-level-current" class="security-level-grid">
- <html:img
- class="security-level-icon"
- alt=""
- />
- <html:div
- class="security-level-current-badge"
- data-l10n-id="security-level-preferences-current-badge"
- ></html:div>
- <html:button
- id="security-level-change"
- data-l10n-id="security-level-preferences-change-button"
- ></html:button>
- </html:div>
- </vbox>
-</groupbox>
=====================================
browser/components/securitylevel/jar.mn
=====================================
@@ -1,11 +1,16 @@
browser.jar:
+ content/browser/securitylevel/config/security-level.mjs (config/security-level.mjs)
+ content/browser/securitylevel/widgets/security-level-description.mjs (widgets/security-level-description.mjs)
+ content/browser/securitylevel/widgets/security-level-description.css (widgets/security-level-description.css)
+ content/browser/securitylevel/widgets/security-level-display.mjs (widgets/security-level-display.mjs)
+ content/browser/securitylevel/widgets/security-level-display.css (widgets/security-level-display.css)
content/browser/securitylevel/securityLevel.js (content/securityLevel.js)
content/browser/securitylevel/securityLevelPanel.css (content/securityLevelPanel.css)
content/browser/securitylevel/securityLevelButton.css (content/securityLevelButton.css)
- content/browser/securitylevel/securityLevelPreferences.css (content/securityLevelPreferences.css)
content/browser/securitylevel/security-level-custom.svg (content/security-level-custom.svg)
content/browser/securitylevel/security-level-safer.svg (content/security-level-safer.svg)
content/browser/securitylevel/security-level-safest.svg (content/security-level-safest.svg)
content/browser/securitylevel/security-level-standard.svg (content/security-level-standard.svg)
content/browser/securitylevel/securityLevelDialog.xhtml (content/securityLevelDialog.xhtml)
content/browser/securitylevel/securityLevelDialog.js (content/securityLevelDialog.js)
+ content/browser/securitylevel/securityLevelDialog.css (content/securityLevelDialog.css)
=====================================
browser/components/securitylevel/moz.build
=====================================
@@ -1,5 +1 @@
JAR_MANIFESTS += ["jar.mn"]
-
-MOZ_SRC_FILES += [
- "SecurityLevelUIUtils.sys.mjs",
-]
=====================================
browser/components/securitylevel/widgets/security-level-description.css
=====================================
@@ -0,0 +1,20 @@
+/* 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 https://mozilla.org/MPL/2.0/. */
+
+p {
+ margin: 0;
+}
+
+:host([hide-bullets]) ul {
+ display: none;
+}
+
+ul {
+ margin: 0;
+ padding-inline: var(--space-large) 0;
+}
+
+li {
+ margin-block-start: var(--space-xsmall);
+}
=====================================
browser/components/securitylevel/widgets/security-level-description.mjs
=====================================
@@ -0,0 +1,79 @@
+/* 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 https://mozilla.org/MPL/2.0/. */
+
+import { MozLitElement } from "chrome://global/content/lit-utils.mjs";
+import { html, repeat } from "chrome://global/content/vendor/lit.all.mjs";
+
+/**
+ * Widget that displays the description for a given security level.
+ *
+ * @tagname security-level-description
+ * @property {string} value - The security level to show the description for.
+ * @property {boolean} hideBullets - Whether to hide the bullet points for the
+ * description.
+ */
+class SecurityLevelDescription extends MozLitElement {
+ static properties = {
+ value: { type: String },
+ hideBullets: { type: Boolean, reflect: true, attribute: "hide-bullets" },
+ };
+
+ static #config = {
+ standard: {
+ summaryL10nId: "security-level-summary-standard",
+ },
+ safer: {
+ summaryL10nId: "security-level-summary-safer",
+ bullets: [
+ "security-level-preferences-bullet-https-only-javascript",
+ "security-level-preferences-bullet-limit-font-and-symbols",
+ "security-level-preferences-bullet-limit-media",
+ ],
+ },
+ safest: {
+ summaryL10nId: "security-level-summary-safest",
+ bullets: [
+ "security-level-preferences-bullet-disabled-javascript",
+ "security-level-preferences-bullet-limit-font-and-symbols-and-images",
+ "security-level-preferences-bullet-limit-media",
+ ],
+ },
+ custom: {
+ summaryL10nId: "security-level-summary-custom",
+ },
+ };
+
+ listTemplate() {
+ const bullets = SecurityLevelDescription.#config[this.value]?.bullets;
+ if (!bullets) {
+ return "";
+ }
+ return html`
+ <ul>
+ ${repeat(
+ bullets,
+ l10nId => l10nId,
+ l10nId => html`<li data-l10n-id=${l10nId}></li>`
+ )}
+ </ul>
+ `;
+ }
+
+ render() {
+ let l10nId = SecurityLevelDescription.#config[this.value]?.summaryL10nId;
+ if (!l10nId) {
+ return "";
+ }
+
+ return html`
+ <link
+ rel="stylesheet"
+ href="chrome://browser/content/securitylevel/widgets/security-level-description.css"
+ />
+ <p data-l10n-id=${l10nId}></p>
+ ${this.listTemplate()}
+ `;
+ }
+}
+customElements.define("security-level-description", SecurityLevelDescription);
=====================================
browser/components/securitylevel/widgets/security-level-display.css
=====================================
@@ -0,0 +1,23 @@
+/* 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 https://mozilla.org/MPL/2.0/. */
+
+:host {
+ --box-icon-stroke: var(--icon-color-warning);
+}
+
+p {
+ margin: 0;
+}
+
+.text-content {
+ padding: var(--box-padding);
+}
+
+.icon:dir(rtl) {
+ transform: scaleX(-1);
+}
+
+security-level-description {
+ grid-area: description;
+}
=====================================
browser/components/securitylevel/widgets/security-level-display.mjs
=====================================
@@ -0,0 +1,71 @@
+/* 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 https://mozilla.org/MPL/2.0/. */
+
+import { MozBoxBase } from "chrome://global/content/lit-utils.mjs";
+import { html } from "chrome://global/content/vendor/lit.all.mjs";
+
+/**
+ * Widget for displaying the current security level.
+ *
+ * @tagname security-level-display
+ * @property {string} value - The current security level.
+ */
+class SecurityLevelDisplay extends MozBoxBase {
+ static properties = {
+ value: { type: String },
+ _nameL10nId: { type: String },
+ };
+
+ static #config = {
+ standard: {
+ nameL10nId: "security-level-panel-level-standard",
+ iconSrc:
+ "chrome://browser/content/securitylevel/security-level-standard.svg",
+ },
+ safer: {
+ nameL10nId: "security-level-panel-level-safer",
+ iconSrc:
+ "chrome://browser/content/securitylevel/security-level-safer.svg",
+ },
+ safest: {
+ nameL10nId: "security-level-panel-level-safest",
+ iconSrc:
+ "chrome://browser/content/securitylevel/security-level-safest.svg",
+ },
+ custom: {
+ nameL10nId: "security-level-panel-level-custom",
+ iconSrc:
+ "chrome://browser/content/securitylevel/security-level-custom.svg",
+ },
+ };
+
+ willUpdate() {
+ const levelConfig = SecurityLevelDisplay.#config[this.value];
+ this._nameL10nId = levelConfig?.nameL10nId ?? null;
+ this.iconSrc = levelConfig?.iconSrc ?? null;
+ }
+
+ render() {
+ if (!this._nameL10nId) {
+ return "";
+ }
+ // NOTE: styleTemplate and iconTemplate come from MozBoxBase.
+ return html`
+ ${this.stylesTemplate()}
+ <link
+ rel="stylesheet"
+ href="chrome://browser/content/securitylevel/widgets/security-level-display.css"
+ />
+ <div class="text-content has-icon has-description">
+ ${this.iconTemplate()}
+ <p class="label" data-l10n-id=${this._nameL10nId}></p>
+ <security-level-description
+ .value=${this.value}
+ class="text-deemphasized"
+ ></security-level-description>
+ </div>
+ `;
+ }
+}
+customElements.define("security-level-display", SecurityLevelDisplay);
=====================================
toolkit/content/widgets/lit-utils.mjs
=====================================
@@ -263,6 +263,9 @@ export class MozBaseInputElement extends MozLitElement {
ariaLabel: { type: String, mapped: true },
ariaDescription: { type: String, mapped: true },
inputLayout: { type: String, reflect: true, attribute: "inputlayout" },
+ // Allow us to set more complex content in a label (e.g. a moz-badge).
+ // See tor-browser#45201.
+ useLabelSlot: { type: Boolean, attribute: "use-label-slot" },
};
/** @type {"inline" | "block" | "inline-end"} */
static inputLayout = "inline";
@@ -461,7 +464,7 @@ export class MozBaseInputElement extends MozLitElement {
}
labelTemplate() {
- if (!this.label) {
+ if (!this.label && !this.useLabelSlot) {
return "";
}
let labelEl;
@@ -474,6 +477,12 @@ export class MozBaseInputElement extends MozLitElement {
class="text text-box-trim-start"
.textContent=${this.label}
></h3>`;
+ } else if (this.useLabelSlot) {
+ labelEl = html`<slot
+ class="text"
+ name="label"
+ @slotchange=${this.onSlotchange}
+ ></slot>`;
} else {
labelEl = html`<span class="text" .textContent=${this.label}></span>`;
}
=====================================
toolkit/locales/en-US/toolkit/global/base-browser.ftl
=====================================
@@ -175,13 +175,11 @@ security-level-panel-open-settings-button = Settings…
## Security level settings.
-security-level-preferences-heading = Security Level
-security-level-preferences-overview = Disable certain web features that can be used to attack your security and anonymity.
-security-level-preferences-learn-more-link = Learn more
-# Text for a badge that labels the currently active security level.
-# The text in between '<span>' and '</span>' should contain some kind of bracket, like '(' and ')', or other punctuation used in your language to separate out text from its surrounding context. This will not be visible, but will be use for screen readers to make it clear that the text is not part of the same sentence. For example, in US English this would be read as "(Current level)", and the full line of text would be read as "Safest (Current level)".
-security-level-preferences-current-badge = <span>(</span>Current level<span>)</span>
-security-level-preferences-change-button = Change…
+security-level-settings-group =
+ .label = Security level
+ .description = Disable certain web features that can be used to attack your security and anonymity.
+security-level-settings-change-button =
+ .label = Change security level
## Security level settings dialog.
@@ -191,13 +189,12 @@ security-level-dialog-window =
# '-brand-short-name' is the localized browser name, like "Tor Browser".
security-level-dialog-restart-description = You will need to restart { -brand-short-name } to apply any changes. This will close all windows and tabs.
-security-level-preferences-level-standard =
- .label = Standard
-security-level-preferences-level-safer =
- .label = Safer
-security-level-preferences-level-safest =
- .label = Safest
-
+# Text for a badge that labels the currently active security level.
+# The text in between '<span>' and '</span>' should contain some kind of bracket, like '(' and ')', or other punctuation used in your language to separate out text from its surrounding context. This will not be visible, but will be use for screen readers to make it clear that the text is not part of the same sentence. For example, in US English this would be read as "(Current level)", and the full line of text would be read as "Safest (Current level)".
+security-level-preferences-current-badge = <span>(</span>Current level<span>)</span>
+# The "aria-label" provides a name for the group of radio options. This is not visibly shown, but it is useful for screen reader users.
+security-level-dialog-radio-group =
+ .aria-label = Security level
security-level-dialog-save-restart =
.label = Save and restart
View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/ca…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/ca…
You're receiving this email because of your account on gitlab.torproject.org. Manage all notifications: https://gitlab.torproject.org/-/profile/notifications | Help: https://gitlab.torproject.org/help
1
0
[Git][tpo/applications/tor-browser][tor-browser-153.1.0esr-16.0-1] 3 commits: fixup! BB 40925: Implemented the Security Level component
by morgan (@morgan) 24 Aug '26
by morgan (@morgan) 24 Aug '26
24 Aug '26
morgan pushed to branch tor-browser-153.1.0esr-16.0-1 at The Tor Project / Applications / Tor Browser
Commits:
c6627585 by Henry Wilkes at 2026-08-24T12:19:25+00:00
fixup! BB 40925: Implemented the Security Level component
BB 45201: Move security level settings to the settings config.
- - - - -
9af10306 by Henry Wilkes at 2026-08-24T12:19:25+00:00
fixup! Base Browser strings
BB 45201: Update security level setting strings.
- - - - -
af669639 by Henry Wilkes at 2026-08-24T12:19:25+00:00
BB 45201: Customize moz- input widgets for Base Browser.
- - - - -
21 changed files:
- browser/components/preferences/config/privacy.mjs
- browser/components/preferences/preferences.js
- browser/components/preferences/preferences.xhtml
- browser/components/preferences/privacy.inc.xhtml
- browser/components/preferences/privacy.js
- − browser/components/securitylevel/SecurityLevelUIUtils.sys.mjs
- + browser/components/securitylevel/config/security-level.mjs
- browser/components/securitylevel/content/securityLevel.js
- + browser/components/securitylevel/content/securityLevelDialog.css
- browser/components/securitylevel/content/securityLevelDialog.js
- browser/components/securitylevel/content/securityLevelDialog.xhtml
- − browser/components/securitylevel/content/securityLevelPreferences.css
- − browser/components/securitylevel/content/securityLevelPreferences.inc.xhtml
- browser/components/securitylevel/jar.mn
- browser/components/securitylevel/moz.build
- + browser/components/securitylevel/widgets/security-level-description.css
- + browser/components/securitylevel/widgets/security-level-description.mjs
- + browser/components/securitylevel/widgets/security-level-display.css
- + browser/components/securitylevel/widgets/security-level-display.mjs
- toolkit/content/widgets/lit-utils.mjs
- toolkit/locales/en-US/toolkit/global/base-browser.ftl
Changes:
=====================================
browser/components/preferences/config/privacy.mjs
=====================================
@@ -7,6 +7,10 @@
import { SettingGroupManager } from "chrome://browser/content/preferences/config/SettingGroupManager.mjs";
import { Preferences } from "chrome://global/content/preferences/Preferences.mjs";
+ChromeUtils.importESModule(
+ "chrome://browser/content/securitylevel/config/security-level.mjs",
+ { global: "current" }
+);
ChromeUtils.importESModule(
"chrome://browser/content/preferences/config/protections-from-apps.mjs",
{ global: "current" }
=====================================
browser/components/preferences/preferences.js
=====================================
@@ -409,6 +409,7 @@ const CONFIG_PANES = Object.freeze({
"ipprotection",
"cookiesAndSiteData2",
"history2",
+ "securityLevelGroup",
"nonTechnicalPrivacy2",
"dnsOverHttps",
"connectionLink",
=====================================
browser/components/preferences/preferences.xhtml
=====================================
@@ -43,7 +43,6 @@
href="chrome://browser/content/preferences/letterboxing.css"
/>
- <link rel="stylesheet" href="chrome://browser/content/securitylevel/securityLevelPreferences.css" />
<link rel="stylesheet" href="chrome://browser/content/torpreferences/torPreferences.css" />
<link rel="stylesheet" href="chrome://browser/content/onionservices/authPreferences.css" />
@@ -108,6 +107,8 @@
<script type="module" src="chrome://browser/content/preferences/widgets/update-information.mjs"></script>
<script type="module" src="chrome://browser/content/preferences/widgets/update-state.mjs"></script>
<script type="module" src="chrome://browser/content/ipprotection/bandwidth-usage.mjs"></script>
+ <script type="module" src="chrome://browser/content/securitylevel/widgets/security-level-description.mjs"></script>
+ <script type="module" src="chrome://browser/content/securitylevel/widgets/security-level-display.mjs"></script>
<script type="module" src="chrome://browser/content/torpreferences/widgets/tor-bridges-display.mjs"></script>
<script type="module" src="chrome://browser/content/torpreferences/widgets/tor-connection-assist-banner.mjs"></script>
<script type="module" src="chrome://browser/content/torpreferences/widgets/tor-connection-status.mjs"></script>
=====================================
browser/components/preferences/privacy.inc.xhtml
=====================================
@@ -579,7 +579,7 @@
<html:h1 data-l10n-id="security-header"/>
</hbox>
-#include ../securitylevel/content/securityLevelPreferences.inc.xhtml
+<html:setting-group groupid="securityLevelGroup" data-category="panePrivacy" hidden="true" data-srd-migrated=""></html:setting-group>
<!-- addons, forgery (phishing) UI Security -->
<html:setting-group groupid="browsingProtection" data-category="panePrivacy" hidden="true" data-srd-migrated=""></html:setting-group>
=====================================
browser/components/preferences/privacy.js
=====================================
@@ -60,13 +60,6 @@ ChromeUtils.defineLazyGetter(lazy, "gParentalControlsService", () =>
: null
);
-// TODO: module import via ChromeUtils.defineModuleGetter
-XPCOMUtils.defineLazyScriptGetter(
- this,
- ["SecurityLevelPreferences"],
- "chrome://browser/content/securitylevel/securityLevel.js"
-);
-
XPCOMUtils.defineLazyPreferenceGetter(
this,
"gIsFirstPartyIsolated",
@@ -150,16 +143,6 @@ function initTCPStandardSection() {
var gPrivacyPane = {
_pane: null,
- /**
- * Show the Security Level UI
- */
- _initSecurityLevel() {
- SecurityLevelPreferences.init();
- window.addEventListener("unload", () => SecurityLevelPreferences.uninit(), {
- once: true,
- });
- },
-
/**
* Whether the prompt to restart Firefox should appear when changing the autostart pref.
*/
@@ -654,6 +637,7 @@ var gPrivacyPane = {
initSettingGroup("etpReset");
initSettingGroup("etpCustomize");
initSettingGroup("networkProxy");
+ initSettingGroup("securityLevelGroup");
/* Initialize Content Blocking */
this.initContentBlocking();
@@ -663,7 +647,6 @@ var gPrivacyPane = {
this.networkCookieBehaviorReadPrefs();
this._initTrackingProtectionExtensionControl();
this._ensureTrackingProtectionExceptionListMigration();
- this._initSecurityLevel();
Preferences.get("privacy.trackingprotection.enabled").on(
"change",
=====================================
browser/components/securitylevel/SecurityLevelUIUtils.sys.mjs deleted
=====================================
@@ -1,73 +0,0 @@
-/**
- * Common methods for the desktop security level components.
- */
-export const SecurityLevelUIUtils = {
- /**
- * Create an element that gives a description of the security level. To be
- * used in the settings.
- *
- * @param {string} level - The security level to describe.
- * @param {Document} doc - The document where the element will be inserted.
- *
- * @returns {Element} - The newly created element.
- */
- createDescriptionElement(level, doc) {
- const el = doc.createElement("div");
- el.classList.add("security-level-description");
-
- let l10nIdSummary;
- let bullets;
- switch (level) {
- case "standard":
- l10nIdSummary = "security-level-summary-standard";
- break;
- case "safer":
- l10nIdSummary = "security-level-summary-safer";
- bullets = [
- "security-level-preferences-bullet-https-only-javascript",
- "security-level-preferences-bullet-limit-font-and-symbols",
- "security-level-preferences-bullet-limit-media",
- ];
- break;
- case "safest":
- l10nIdSummary = "security-level-summary-safest";
- bullets = [
- "security-level-preferences-bullet-disabled-javascript",
- "security-level-preferences-bullet-limit-font-and-symbols-and-images",
- "security-level-preferences-bullet-limit-media",
- ];
- break;
- case "custom":
- l10nIdSummary = "security-level-summary-custom";
- break;
- default:
- throw Error(`Unhandled level: ${level}`);
- }
-
- const summaryEl = doc.createElement("div");
- summaryEl.classList.add("security-level-summary");
- doc.l10n.setAttributes(summaryEl, l10nIdSummary);
-
- el.append(summaryEl);
-
- if (!bullets) {
- return el;
- }
-
- const listEl = doc.createElement("ul");
- listEl.classList.add("security-level-description-extra");
- // Add a mozilla styling class as well:
- listEl.classList.add("privacy-extra-information");
- for (const l10nId of bullets) {
- const bulletEl = doc.createElement("li");
- bulletEl.classList.add("security-level-description-bullet");
-
- doc.l10n.setAttributes(bulletEl, l10nId);
-
- listEl.append(bulletEl);
- }
-
- el.append(listEl);
- return el;
- },
-};
=====================================
browser/components/securitylevel/config/security-level.mjs
=====================================
@@ -0,0 +1,81 @@
+/* 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 https://mozilla.org/MPL/2.0/. */
+
+import { SettingGroupManager } from "chrome://browser/content/preferences/config/SettingGroupManager.mjs";
+import { Preferences } from "chrome://global/content/preferences/Preferences.mjs";
+
+const lazy = {};
+
+ChromeUtils.defineESModuleGetters(lazy, {
+ SecurityLevelPrefs:
+ "moz-src:///toolkit/components/securitylevel/SecurityLevel.sys.mjs",
+});
+
+SettingGroupManager.registerGroups({
+ securityLevelGroup: {
+ subcategory: "securitylevel",
+ l10nId: "security-level-settings-group",
+ headingLevel: 2,
+ supportPage: "tor-manual:features__security-levels",
+ items: [
+ {
+ id: "securityLevelBoxGroup",
+ control: "moz-box-group",
+ items: [
+ {
+ id: "securityLevelCurrent",
+ control: "security-level-display",
+ },
+ {
+ id: "securityLevelChangeButton",
+ l10nId: "security-level-settings-change-button",
+ control: "moz-box-button",
+ },
+ ],
+ },
+ ],
+ },
+});
+
+Preferences.addSetting({
+ id: "securityLevelCurrent",
+ setup(emitChange) {
+ Services.prefs.addObserver(
+ "browser.security_level.security_slider",
+ emitChange
+ );
+ Services.prefs.addObserver(
+ "browser.security_level.security_custom",
+ emitChange
+ );
+
+ return () => {
+ Services.prefs.removeObserver(
+ "browser.security_level.security_slider",
+ emitChange
+ );
+ Services.prefs.removeObserver(
+ "browser.security_level.security_custom",
+ emitChange
+ );
+ };
+ },
+ get: () => {
+ return lazy.SecurityLevelPrefs.securityLevelSummary;
+ },
+});
+
+Preferences.addSetting({
+ id: "securityLevelBoxGroup",
+});
+
+Preferences.addSetting({
+ id: "securityLevelChangeButton",
+ onUserClick() {
+ window.gSubDialog.open(
+ "chrome://browser/content/securitylevel/securityLevelDialog.xhtml",
+ { features: "resizable=yes" }
+ );
+ },
+});
=====================================
browser/components/securitylevel/content/securityLevel.js
=====================================
@@ -5,8 +5,6 @@
ChromeUtils.defineESModuleGetters(this, {
SecurityLevelPrefs:
"moz-src:///toolkit/components/securitylevel/SecurityLevel.sys.mjs",
- SecurityLevelUIUtils:
- "moz-src:///browser/components/securitylevel/SecurityLevelUIUtils.sys.mjs",
});
/*
@@ -263,103 +261,3 @@ var SecurityLevelPanel = {
}
},
}; /* SecurityLevelPanel */
-
-/*
- Security Level Preferences Code
-
- Code to handle init and update of security level section in about:preferences#privacy
-*/
-
-var SecurityLevelPreferences = {
- _securityPrefsBranch: null,
-
- /**
- * The element that shows the current security level.
- *
- * @type {?Element}
- */
- _currentEl: null,
-
- _populateXUL() {
- this._currentEl = document.getElementById("security-level-current");
- const changeButton = document.getElementById("security-level-change");
- const badgeEl = this._currentEl.querySelector(
- ".security-level-current-badge"
- );
-
- for (const { level, nameId } of [
- { level: "standard", nameId: "security-level-panel-level-standard" },
- { level: "safer", nameId: "security-level-panel-level-safer" },
- { level: "safest", nameId: "security-level-panel-level-safest" },
- { level: "custom", nameId: "security-level-panel-level-custom" },
- ]) {
- // Classes that control visibility:
- // security-level-current-standard
- // security-level-current-safer
- // security-level-current-safest
- // security-level-current-custom
- const visibilityClass = `security-level-current-${level}`;
- const nameEl = document.createElement("div");
- nameEl.classList.add("security-level-name", visibilityClass);
- document.l10n.setAttributes(nameEl, nameId);
-
- const descriptionEl = SecurityLevelUIUtils.createDescriptionElement(
- level,
- document
- );
- descriptionEl.classList.add(visibilityClass);
-
- this._currentEl.insertBefore(nameEl, badgeEl);
- this._currentEl.insertBefore(descriptionEl, changeButton);
- }
-
- changeButton.addEventListener("click", () => {
- this._openDialog();
- });
- },
-
- _openDialog() {
- gSubDialog.open(
- "chrome://browser/content/securitylevel/securityLevelDialog.xhtml",
- { features: "resizable=yes" }
- );
- },
-
- _configUIFromPrefs() {
- // Set a data-current-level attribute for showing the current security
- // level, and hiding the rest.
- this._currentEl.dataset.currentLevel =
- SecurityLevelPrefs.securityLevelSummary;
- },
-
- init() {
- // populate XUL with localized strings
- this._populateXUL();
-
- // read prefs and populate UI
- this._configUIFromPrefs();
-
- // register for pref chagnes
- this._securityPrefsBranch = Services.prefs.getBranch(
- "browser.security_level."
- );
- this._securityPrefsBranch.addObserver("", this);
- },
-
- uninit() {
- // unregister for pref change events
- this._securityPrefsBranch.removeObserver("", this);
- this._securityPrefsBranch = null;
- },
-
- // callback for when prefs change
- observe(subject, topic, data) {
- switch (topic) {
- case "nsPref:changed":
- if (data == "security_slider" || data == "security_custom") {
- this._configUIFromPrefs();
- }
- break;
- }
- },
-}; /* SecurityLevelPreferences */
=====================================
browser/components/securitylevel/content/securityLevelDialog.css
=====================================
@@ -0,0 +1,29 @@
+/* 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 https://mozilla.org/MPL/2.0/. */
+
+/* Hack to gain the internal styling of <moz-badge>.
+ * TODO: Drop this once we can use moz-badge. tor-browser#45229. */
+@import url("chrome://global/content/elements/moz-badge.css");
+
+#security-level-radiogroup {
+ margin-block: var(--space-large) var(--space-xlarge);
+}
+
+.security-level-radio-label {
+ display: inline flex;
+ gap: var(--space-small);
+}
+
+.security-level-radio-label .moz-badge-label > span {
+ /* Still accessible to screen reader, but not visual.
+ * Keep inline, but with no layout width. */
+ display: inline-block;
+ width: 1px;
+ margin-inline-end: -1px;
+ clip-path: inset(50%);
+}
+
+.moz-badge[hidden] {
+ display: none;
+}
=====================================
browser/components/securitylevel/content/securityLevelDialog.js
=====================================
@@ -3,9 +3,6 @@
const { SecurityLevelPrefs } = ChromeUtils.importESModule(
"moz-src:///toolkit/components/securitylevel/SecurityLevel.sys.mjs"
);
-const { SecurityLevelUIUtils } = ChromeUtils.importESModule(
- "moz-src:///browser/components/securitylevel/SecurityLevelUIUtils.sys.mjs"
-);
const gSecurityLevelDialog = {
/**
@@ -27,9 +24,9 @@ const gSecurityLevelDialog = {
*/
_radiogroup: null,
/**
- * A list of radio options and their containers.
+ * A list of radio options and their descriptions.
*
- * @type {?Array<{ container: Element, radio: Element }>}
+ * @type {?Array<{ description: Element, radio: Element }>}
*/
_radioOptions: null,
@@ -56,85 +53,42 @@ const gSecurityLevelDialog = {
this._radiogroup = document.getElementById("security-level-radiogroup");
this._radioOptions = Array.from(
- this._radiogroup.querySelectorAll(".security-level-radio-container"),
- container => {
- return {
- container,
- radio: container.querySelector(".security-level-radio"),
- };
+ this._radiogroup.querySelectorAll("moz-radio"),
+ radio => {
+ const description = radio.querySelector("security-level-description");
+ // Hide bullets by default.
+ description.hideBullets = true;
+ return { radio, description };
}
);
- for (const { container, radio } of this._radioOptions) {
- const level = radio.value;
- radio.id = `security-level-radio-${level}`;
- const currentEl = container.querySelector(
- ".security-level-current-badge"
- );
- currentEl.id = `security-level-current-badge-${level}`;
- const descriptionEl = SecurityLevelUIUtils.createDescriptionElement(
- level,
- document
- );
- descriptionEl.classList.add("indent");
- descriptionEl.id = `security-level-description-${level}`;
-
- // Wait for the full translation of the element before adding it to the
- // DOM. In particular, we want to make sure the elements have text before
- // we measure the maxHeight below.
- await document.l10n.translateFragment(descriptionEl);
- document.l10n.pauseObserving();
- container.append(descriptionEl);
- document.l10n.resumeObserving();
-
- if (level === this._prevLevel) {
- currentEl.hidden = false;
- // When the currentEl is visible, include it in the accessible name for
- // the radio option.
- // NOTE: The currentEl has an accessible name which includes punctuation
- // to help separate it's content from the security level name.
- // E.g. "Standard (Current level)".
- radio.setAttribute("aria-labelledby", `${radio.id} ${currentEl.id}`);
- } else {
- currentEl.hidden = true;
- }
- // We point the accessible description to the wrapping
- // .security-level-description element, rather than its children
- // that define the actual text content. This means that when the
- // privacy-extra-information is shown or hidden, its text content is
- // included or excluded from the accessible description, respectively.
- radio.setAttribute("aria-describedby", descriptionEl.id);
+ for (const { radio } of this._radioOptions) {
+ radio.querySelector(".moz-badge").hidden =
+ radio.value !== this._prevLevel;
}
- // We want to reserve the maximum height of the radiogroup so that the
+ // We want to reserve the maximum height of the moz-radio-group so that the
// dialog has enough height when the user switches options. So we cycle
// through the options and measure the height when they are selected to set
// a minimum height that fits all of them.
- // NOTE: At the time of implementation, at this point the dialog may not
- // yet have the "subdialog" attribute, which means it is missing the
- // common.css stylesheet from its shadow root, which effects the size of the
- // .radio-check element and the font. Therefore, we have duplicated the
- // import of common.css in SecurityLevelDialog.xhtml to ensure it is applied
- // at this earlier stage.
let maxHeight = 0;
- for (const { container } of this._radioOptions) {
- container.classList.add("selected");
+ for (const { description } of this._radioOptions) {
+ description.hideBullets = false;
+ await this._settled();
maxHeight = Math.max(
maxHeight,
this._radiogroup.getBoundingClientRect().height
);
- container.classList.remove("selected");
+ description.hideBullets = true;
}
this._radiogroup.style.minHeight = `${maxHeight}px`;
if (this._prevLevel !== "custom") {
this._selectedLevel = this._prevLevel;
this._radiogroup.value = this._prevLevel;
- } else {
- this._radiogroup.selectedItem = null;
}
- this._radiogroup.addEventListener("select", () => {
+ this._radiogroup.addEventListener("change", () => {
this._selectedLevel = this._radiogroup.value;
this._updateSelected();
});
@@ -142,16 +96,31 @@ const gSecurityLevelDialog = {
this._updateSelected();
},
+ /**
+ * Wait for the DOM to be settled after some change.
+ */
+ async _settled() {
+ // Wait for the widgets to react to some change.
+ await Promise.all([
+ this._radiogroup.updateComplete,
+ ...this._radioOptions.map(({ radio }) => radio.updateComplete),
+ ]);
+ // Also wait for any string population.
+ if (document.hasPendingL10nMutations) {
+ await new Promise(r =>
+ document.addEventListener("L10nMutationsFinished", r, { once: true })
+ );
+ }
+ },
+
/**
* Update the UI in response to a change in selection.
*/
_updateSelected() {
this._acceptButton.disabled =
!this._selectedLevel || this._selectedLevel === this._prevLevel;
- // Have the container's `selected` CSS class match the selection state of
- // the radio elements.
- for (const { container, radio } of this._radioOptions) {
- container.classList.toggle("selected", radio.selected);
+ for (const { description, radio } of this._radioOptions) {
+ description.hideBullets = !radio.checked;
}
},
=====================================
browser/components/securitylevel/content/securityLevelDialog.xhtml
=====================================
@@ -10,18 +10,6 @@
<dialog id="security-level-dialog" buttons="accept,cancel">
<linkset>
<html:link rel="stylesheet" href="chrome://global/skin/global.css" />
- <!-- NOTE: We include common.css explicitly, rather than relying on
- - the dialog's shadowroot importing it, which is late loaded in
- - response to the dialog's "subdialog" attribute, which is set
- - in response to DOMFrameContentLoaded.
- - In particular, we need the .radio-check rule and font rules from
- - common-shared.css to be in place when gSecurityLevelDialog.init is
- - called, which will help ensure that the radio element has the correct
- - size when we measure its bounding box. -->
- <html:link
- rel="stylesheet"
- href="chrome://global/skin/in-content/common.css"
- />
<html:link
rel="stylesheet"
href="chrome://browser/skin/preferences/preferences.css"
@@ -32,57 +20,77 @@
/>
<html:link
rel="stylesheet"
- href="chrome://browser/content/securitylevel/securityLevelPreferences.css"
+ href="chrome://browser/content/securitylevel/securityLevelDialog.css"
/>
<html:link rel="localization" href="branding/brand.ftl" />
<html:link rel="localization" href="toolkit/global/base-browser.ftl" />
</linkset>
+ <html:script
+ type="module"
+ src="chrome://global/content/elements/moz-radio-group.mjs"
+ ></html:script>
+ <html:script
+ type="module"
+ src="chrome://browser/content/securitylevel/widgets/security-level-description.mjs"
+ ></html:script>
<script src="chrome://browser/content/securitylevel/securityLevelDialog.js" />
<description data-l10n-id="security-level-dialog-restart-description" />
- <radiogroup id="security-level-radiogroup" class="highlighting-group">
- <html:div
- class="security-level-radio-container security-level-grid privacy-detailedoption info-box-container"
- >
- <radio
- class="security-level-radio security-level-name"
+ <moz-radio-group
+ xmlns="http://www.w3.org/1999/xhtml"
+ id="security-level-radiogroup"
+ data-l10n-id="security-level-dialog-radio-group"
+ >
+ <moz-radio value="standard" use-label-slot="">
+ <span class="security-level-radio-label" slot="label">
+ <span data-l10n-id="security-level-panel-level-standard"></span>
+ <!-- TODO: Use <moz-badge> widget once bugzilla bug 2065204 is
+ - resolved. See tor-browser#45229. -->
+ <span class="moz-badge" hidden="hidden">
+ <span
+ class="moz-badge-label"
+ data-l10n-id="security-level-preferences-current-badge"
+ ></span>
+ </span>
+ </span>
+ <security-level-description
+ slot="description"
value="standard"
- data-l10n-id="security-level-preferences-level-standard"
- />
- <html:div
- class="security-level-current-badge"
- data-l10n-id="security-level-preferences-current-badge"
- ></html:div>
- </html:div>
- <html:div
- class="security-level-radio-container security-level-grid privacy-detailedoption info-box-container"
- >
- <radio
- class="security-level-radio security-level-name"
+ ></security-level-description>
+ </moz-radio>
+ <moz-radio value="safer" use-label-slot="">
+ <span class="security-level-radio-label" slot="label">
+ <span data-l10n-id="security-level-panel-level-safer"></span>
+ <span class="moz-badge" hidden="hidden">
+ <span
+ class="moz-badge-label"
+ data-l10n-id="security-level-preferences-current-badge"
+ ></span>
+ </span>
+ </span>
+ <security-level-description
+ slot="description"
value="safer"
- data-l10n-id="security-level-preferences-level-safer"
- />
- <html:div
- class="security-level-current-badge"
- data-l10n-id="security-level-preferences-current-badge"
- ></html:div>
- </html:div>
- <html:div
- class="security-level-radio-container security-level-grid privacy-detailedoption info-box-container"
- >
- <radio
- class="security-level-radio security-level-name"
+ ></security-level-description>
+ </moz-radio>
+ <moz-radio value="safest" use-label-slot="">
+ <span class="security-level-radio-label" slot="label">
+ <span data-l10n-id="security-level-panel-level-safest"></span>
+ <span class="moz-badge" hidden="hidden">
+ <span
+ class="moz-badge-label"
+ data-l10n-id="security-level-preferences-current-badge"
+ ></span>
+ </span>
+ </span>
+ <security-level-description
+ slot="description"
value="safest"
- data-l10n-id="security-level-preferences-level-safest"
- />
- <html:div
- class="security-level-current-badge"
- data-l10n-id="security-level-preferences-current-badge"
- ></html:div>
- </html:div>
- </radiogroup>
+ ></security-level-description>
+ </moz-radio>
+ </moz-radio-group>
</dialog>
</window>
=====================================
browser/components/securitylevel/content/securityLevelPreferences.css deleted
=====================================
@@ -1,171 +0,0 @@
-.security-level-grid {
- display: grid;
- grid-template:
- "icon name badge button" min-content
- "icon summary summary button" auto
- "icon extra extra ." auto
- / max-content max-content 1fr max-content;
-}
-
-.security-level-icon {
- grid-area: icon;
- align-self: start;
- width: var(--icon-size-large);
- height: var(--icon-size-large);
- -moz-context-properties: fill, stroke;
- fill: var(--icon-color);
- stroke: var(--icon-color-warning);
- margin-block-start: var(--space-xsmall);
- margin-inline-end: var(--space-large);
-}
-
-:-moz-locale-dir(rtl) .security-level-icon {
- transform: scaleX(-1);
-}
-
-.security-level-current-badge {
- grid-area: badge;
- align-self: center;
- justify-self: start;
- white-space: nowrap;
- background: var(--background-color-information);
- color: inherit;
- font-size: var(--font-size-small);
- border-radius: var(--border-radius-circle);
- margin-inline-start: var(--space-small);
- padding-block: var(--space-xsmall);
- padding-inline: var(--space-small);
-}
-
-.security-level-current-badge span {
- /* Still accessible to screen reader, but not visual.
- * Keep inline, but with no layout width. */
- display: inline-block;
- width: 1px;
- margin-inline-end: -1px;
- clip-path: inset(50%);
-}
-
-@media (prefers-contrast) and (not (forced-colors)) {
- .security-level-current-badge {
- /* Match the checkbox/radio colors. */
- background: var(--color-accent-primary);
- color: var(--button-text-color-primary);
- }
-}
-
-@media (forced-colors) {
- .security-level-current-badge {
- /* Match the checkbox/radio/selected colors. */
- background: SelectedItem;
- color: SelectedItemText;
- }
-}
-
-.security-level-name {
- grid-area: name;
- font-weight: var(--font-weight-bold);
- align-self: center;
- white-space: nowrap;
-}
-
-.security-level-description {
- display: grid;
- grid-column: summary-start / extra-end;
- grid-row: summary-start / extra-end;
- grid-template-rows: subgrid;
- grid-template-columns: subgrid;
- margin-block-start: var(--space-small);
-}
-
-.security-level-summary {
- grid-area: summary;
-}
-
-.security-level-description-extra {
- grid-area: extra;
- margin-block: var(--space-medium) 0;
- margin-inline: var(--space-large) 0;
- padding: 0;
-}
-
-.security-level-description-bullet:not(:last-child) {
- margin-block-end: var(--space-medium);
-}
-
-/* Tweak current security level display. */
-
-#security-level-current {
- margin-block-start: var(--space-large);
- background: var(--background-color-box);
- border: var(--border-width) solid var(--border-color);
- border-radius: var(--border-radius-small);
- padding: var(--space-medium);
-}
-
-#security-level-change {
- grid-area: button;
- align-self: center;
- margin: 0;
- margin-inline-start: var(--space-large);
-}
-
-/* Adjust which content is visible depending on the current security level. */
-
-#security-level-current:not([data-current-level="standard"]) .security-level-current-standard {
- display: none;
-}
-
-#security-level-current:not([data-current-level="safer"]) .security-level-current-safer {
- display: none;
-}
-
-#security-level-current:not([data-current-level="safest"]) .security-level-current-safest {
- display: none;
-}
-
-#security-level-current:not([data-current-level="custom"]) .security-level-current-custom {
- display: none;
-}
-
-#security-level-current[data-current-level="standard"] .security-level-icon {
- content: url("chrome://browser/content/securitylevel/security-level-standard.svg");
-}
-
-#security-level-current[data-current-level="safer"] .security-level-icon {
- content: url("chrome://browser/content/securitylevel/security-level-safer.svg");
-}
-
-#security-level-current[data-current-level="safest"] .security-level-icon {
- content: url("chrome://browser/content/securitylevel/security-level-safest.svg");
-}
-
-#security-level-current[data-current-level="custom"] .security-level-icon {
- content: url("chrome://browser/content/securitylevel/security-level-custom.svg");
-}
-
-/* Tweak security level dialog. */
-
-#security-level-radiogroup {
- margin-block: var(--space-large) var(--space-xlarge);
-}
-
-.security-level-radio-container {
- padding-block: var(--space-large);
-}
-
-#security-level-radiogroup .security-level-radio {
- margin: 0;
-}
-
-#security-level-radiogroup .radio-label-box {
- /* .security-level-current-badge already has a margin. */
- margin: 0;
-}
-
-#security-level-radiogroup .privacy-detailedoption.security-level-radio-container:not(.selected) .security-level-description-extra {
- /* .privacy-detailedoption uses visibility: hidden, which does not work with
- * our grid display (the margin is still reserved) so we use display: none
- * instead. */
- display: none;
-}
=====================================
browser/components/securitylevel/content/securityLevelPreferences.inc.xhtml deleted
=====================================
@@ -1,35 +0,0 @@
-<groupbox id="securityLevel-groupbox"
- data-category="panePrivacy"
- data-subcategory="securitylevel"
- hidden="true">
- <label>
- <html:h2 data-l10n-id="security-level-preferences-heading"></html:h2>
- </label>
- <vbox flex="1">
- <description class="description-deemphasized" flex="1">
- <html:span
- id="securityLevel-overview"
- data-l10n-id="security-level-preferences-overview"
- ></html:span>
- <html:a
- is="moz-support-link"
- support-page="tor-manual:features__security-levels"
- data-l10n-id="security-level-preferences-learn-more-link"
- ></html:a>
- </description>
- <html:div id="security-level-current" class="security-level-grid">
- <html:img
- class="security-level-icon"
- alt=""
- />
- <html:div
- class="security-level-current-badge"
- data-l10n-id="security-level-preferences-current-badge"
- ></html:div>
- <html:button
- id="security-level-change"
- data-l10n-id="security-level-preferences-change-button"
- ></html:button>
- </html:div>
- </vbox>
-</groupbox>
=====================================
browser/components/securitylevel/jar.mn
=====================================
@@ -1,11 +1,16 @@
browser.jar:
+ content/browser/securitylevel/config/security-level.mjs (config/security-level.mjs)
+ content/browser/securitylevel/widgets/security-level-description.mjs (widgets/security-level-description.mjs)
+ content/browser/securitylevel/widgets/security-level-description.css (widgets/security-level-description.css)
+ content/browser/securitylevel/widgets/security-level-display.mjs (widgets/security-level-display.mjs)
+ content/browser/securitylevel/widgets/security-level-display.css (widgets/security-level-display.css)
content/browser/securitylevel/securityLevel.js (content/securityLevel.js)
content/browser/securitylevel/securityLevelPanel.css (content/securityLevelPanel.css)
content/browser/securitylevel/securityLevelButton.css (content/securityLevelButton.css)
- content/browser/securitylevel/securityLevelPreferences.css (content/securityLevelPreferences.css)
content/browser/securitylevel/security-level-custom.svg (content/security-level-custom.svg)
content/browser/securitylevel/security-level-safer.svg (content/security-level-safer.svg)
content/browser/securitylevel/security-level-safest.svg (content/security-level-safest.svg)
content/browser/securitylevel/security-level-standard.svg (content/security-level-standard.svg)
content/browser/securitylevel/securityLevelDialog.xhtml (content/securityLevelDialog.xhtml)
content/browser/securitylevel/securityLevelDialog.js (content/securityLevelDialog.js)
+ content/browser/securitylevel/securityLevelDialog.css (content/securityLevelDialog.css)
=====================================
browser/components/securitylevel/moz.build
=====================================
@@ -1,5 +1 @@
JAR_MANIFESTS += ["jar.mn"]
-
-MOZ_SRC_FILES += [
- "SecurityLevelUIUtils.sys.mjs",
-]
=====================================
browser/components/securitylevel/widgets/security-level-description.css
=====================================
@@ -0,0 +1,20 @@
+/* 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 https://mozilla.org/MPL/2.0/. */
+
+p {
+ margin: 0;
+}
+
+:host([hide-bullets]) ul {
+ display: none;
+}
+
+ul {
+ margin: 0;
+ padding-inline: var(--space-large) 0;
+}
+
+li {
+ margin-block-start: var(--space-xsmall);
+}
=====================================
browser/components/securitylevel/widgets/security-level-description.mjs
=====================================
@@ -0,0 +1,79 @@
+/* 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 https://mozilla.org/MPL/2.0/. */
+
+import { MozLitElement } from "chrome://global/content/lit-utils.mjs";
+import { html, repeat } from "chrome://global/content/vendor/lit.all.mjs";
+
+/**
+ * Widget that displays the description for a given security level.
+ *
+ * @tagname security-level-description
+ * @property {string} value - The security level to show the description for.
+ * @property {boolean} hideBullets - Whether to hide the bullet points for the
+ * description.
+ */
+class SecurityLevelDescription extends MozLitElement {
+ static properties = {
+ value: { type: String },
+ hideBullets: { type: Boolean, reflect: true, attribute: "hide-bullets" },
+ };
+
+ static #config = {
+ standard: {
+ summaryL10nId: "security-level-summary-standard",
+ },
+ safer: {
+ summaryL10nId: "security-level-summary-safer",
+ bullets: [
+ "security-level-preferences-bullet-https-only-javascript",
+ "security-level-preferences-bullet-limit-font-and-symbols",
+ "security-level-preferences-bullet-limit-media",
+ ],
+ },
+ safest: {
+ summaryL10nId: "security-level-summary-safest",
+ bullets: [
+ "security-level-preferences-bullet-disabled-javascript",
+ "security-level-preferences-bullet-limit-font-and-symbols-and-images",
+ "security-level-preferences-bullet-limit-media",
+ ],
+ },
+ custom: {
+ summaryL10nId: "security-level-summary-custom",
+ },
+ };
+
+ listTemplate() {
+ const bullets = SecurityLevelDescription.#config[this.value]?.bullets;
+ if (!bullets) {
+ return "";
+ }
+ return html`
+ <ul>
+ ${repeat(
+ bullets,
+ l10nId => l10nId,
+ l10nId => html`<li data-l10n-id=${l10nId}></li>`
+ )}
+ </ul>
+ `;
+ }
+
+ render() {
+ let l10nId = SecurityLevelDescription.#config[this.value]?.summaryL10nId;
+ if (!l10nId) {
+ return "";
+ }
+
+ return html`
+ <link
+ rel="stylesheet"
+ href="chrome://browser/content/securitylevel/widgets/security-level-description.css"
+ />
+ <p data-l10n-id=${l10nId}></p>
+ ${this.listTemplate()}
+ `;
+ }
+}
+customElements.define("security-level-description", SecurityLevelDescription);
=====================================
browser/components/securitylevel/widgets/security-level-display.css
=====================================
@@ -0,0 +1,23 @@
+/* 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 https://mozilla.org/MPL/2.0/. */
+
+:host {
+ --box-icon-stroke: var(--icon-color-warning);
+}
+
+p {
+ margin: 0;
+}
+
+.text-content {
+ padding: var(--box-padding);
+}
+
+.icon:dir(rtl) {
+ transform: scaleX(-1);
+}
+
+security-level-description {
+ grid-area: description;
+}
=====================================
browser/components/securitylevel/widgets/security-level-display.mjs
=====================================
@@ -0,0 +1,71 @@
+/* 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 https://mozilla.org/MPL/2.0/. */
+
+import { MozBoxBase } from "chrome://global/content/lit-utils.mjs";
+import { html } from "chrome://global/content/vendor/lit.all.mjs";
+
+/**
+ * Widget for displaying the current security level.
+ *
+ * @tagname security-level-display
+ * @property {string} value - The current security level.
+ */
+class SecurityLevelDisplay extends MozBoxBase {
+ static properties = {
+ value: { type: String },
+ _nameL10nId: { type: String },
+ };
+
+ static #config = {
+ standard: {
+ nameL10nId: "security-level-panel-level-standard",
+ iconSrc:
+ "chrome://browser/content/securitylevel/security-level-standard.svg",
+ },
+ safer: {
+ nameL10nId: "security-level-panel-level-safer",
+ iconSrc:
+ "chrome://browser/content/securitylevel/security-level-safer.svg",
+ },
+ safest: {
+ nameL10nId: "security-level-panel-level-safest",
+ iconSrc:
+ "chrome://browser/content/securitylevel/security-level-safest.svg",
+ },
+ custom: {
+ nameL10nId: "security-level-panel-level-custom",
+ iconSrc:
+ "chrome://browser/content/securitylevel/security-level-custom.svg",
+ },
+ };
+
+ willUpdate() {
+ const levelConfig = SecurityLevelDisplay.#config[this.value];
+ this._nameL10nId = levelConfig?.nameL10nId ?? null;
+ this.iconSrc = levelConfig?.iconSrc ?? null;
+ }
+
+ render() {
+ if (!this._nameL10nId) {
+ return "";
+ }
+ // NOTE: styleTemplate and iconTemplate come from MozBoxBase.
+ return html`
+ ${this.stylesTemplate()}
+ <link
+ rel="stylesheet"
+ href="chrome://browser/content/securitylevel/widgets/security-level-display.css"
+ />
+ <div class="text-content has-icon has-description">
+ ${this.iconTemplate()}
+ <p class="label" data-l10n-id=${this._nameL10nId}></p>
+ <security-level-description
+ .value=${this.value}
+ class="text-deemphasized"
+ ></security-level-description>
+ </div>
+ `;
+ }
+}
+customElements.define("security-level-display", SecurityLevelDisplay);
=====================================
toolkit/content/widgets/lit-utils.mjs
=====================================
@@ -266,6 +266,9 @@ export class MozBaseInputElement extends MozLitElement {
// label-align-before is a customisation for the moz-toggle in about:tor.
// See tor-browser#43727.
labelAlignBefore: { type: Boolean, attribute: "label-align-before" },
+ // Allow us to set more complex content in a label (e.g. a moz-badge).
+ // See tor-browser#45201.
+ useLabelSlot: { type: Boolean, attribute: "use-label-slot" },
};
/** @type {"inline" | "block" | "inline-end"} */
static inputLayout = "inline";
@@ -465,7 +468,7 @@ export class MozBaseInputElement extends MozLitElement {
}
labelTemplate() {
- if (!this.label) {
+ if (!this.label && !this.useLabelSlot) {
return "";
}
let labelEl;
@@ -478,6 +481,12 @@ export class MozBaseInputElement extends MozLitElement {
class="text text-box-trim-start"
.textContent=${this.label}
></h3>`;
+ } else if (this.useLabelSlot) {
+ labelEl = html`<slot
+ class="text"
+ name="label"
+ @slotchange=${this.onSlotchange}
+ ></slot>`;
} else {
labelEl = html`<span class="text" .textContent=${this.label}></span>`;
}
=====================================
toolkit/locales/en-US/toolkit/global/base-browser.ftl
=====================================
@@ -185,13 +185,11 @@ security-level-panel-open-settings-button = Settings…
## Security level settings.
-security-level-preferences-heading = Security Level
-security-level-preferences-overview = Disable certain web features that can be used to attack your security and anonymity.
-security-level-preferences-learn-more-link = Learn more
-# Text for a badge that labels the currently active security level.
-# The text in between '<span>' and '</span>' should contain some kind of bracket, like '(' and ')', or other punctuation used in your language to separate out text from its surrounding context. This will not be visible, but will be use for screen readers to make it clear that the text is not part of the same sentence. For example, in US English this would be read as "(Current level)", and the full line of text would be read as "Safest (Current level)".
-security-level-preferences-current-badge = <span>(</span>Current level<span>)</span>
-security-level-preferences-change-button = Change…
+security-level-settings-group =
+ .label = Security level
+ .description = Disable certain web features that can be used to attack your security and anonymity.
+security-level-settings-change-button =
+ .label = Change security level
## Security level settings dialog.
@@ -201,13 +199,12 @@ security-level-dialog-window =
# '-brand-short-name' is the localized browser name, like "Tor Browser".
security-level-dialog-restart-description = You will need to restart { -brand-short-name } to apply any changes. This will close all windows and tabs.
-security-level-preferences-level-standard =
- .label = Standard
-security-level-preferences-level-safer =
- .label = Safer
-security-level-preferences-level-safest =
- .label = Safest
-
+# Text for a badge that labels the currently active security level.
+# The text in between '<span>' and '</span>' should contain some kind of bracket, like '(' and ')', or other punctuation used in your language to separate out text from its surrounding context. This will not be visible, but will be use for screen readers to make it clear that the text is not part of the same sentence. For example, in US English this would be read as "(Current level)", and the full line of text would be read as "Safest (Current level)".
+security-level-preferences-current-badge = <span>(</span>Current level<span>)</span>
+# The "aria-label" provides a name for the group of radio options. This is not visibly shown, but it is useful for screen reader users.
+security-level-dialog-radio-group =
+ .aria-label = Security level
security-level-dialog-save-restart =
.label = Save and restart
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/891501…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/891501…
You're receiving this email because of your account on gitlab.torproject.org. Manage all notifications: https://gitlab.torproject.org/-/profile/notifications | Help: https://gitlab.torproject.org/help
1
0
[Git][tpo/applications/mullvad-browser][mullvad-browser-153.1.0esr-16.0-1] Bug 2053518 - Handle the *-oe-linux-* rust targets added in rustc 1.98 in rust...
by Pier Angelo Vendrame (@pierov) 24 Aug '26
by Pier Angelo Vendrame (@pierov) 24 Aug '26
24 Aug '26
Pier Angelo Vendrame pushed to branch mullvad-browser-153.1.0esr-16.0-1 at The Tor Project / Applications / Mullvad Browser
Commits:
ca329cd8 by Jesse Schwartzentruber at 2026-08-24T12:36:58+02:00
Bug 2053518 - Handle the *-oe-linux-* rust targets added in rustc 1.98 in rust target detection. r=firefox-build-system-reviewers,glandium
Differential Revision: https://phabricator.services.mozilla.com/D311145
- - - - -
2 changed files:
- build/moz.configure/rust.configure
- python/mozbuild/mozbuild/test/configure/test_toolchain_configure.py
Changes:
=====================================
build/moz.configure/rust.configure
=====================================
@@ -300,6 +300,10 @@ def detect_rustc_target(
elif not candidates:
return None
+ # config.guess uses the "pc" vendor for x86/x86_64 where rust uses its
+ # generic "unknown" vendor; normalize so we correlate on the right one.
+ vendor = "unknown" if host_or_target.vendor == "pc" else host_or_target.vendor
+
# We have multiple candidates. There are two cases where we can try to
# narrow further down using extra information from the build system.
# - For windows targets, correlate with the C compiler type
@@ -367,11 +371,19 @@ def detect_rustc_target(
else:
suffix = ""
for p in prefixes:
- for c in candidates:
- if c.rust_target.startswith(
- "{}-".format(p)
- ) and c.rust_target.endswith(suffix):
+ matches = [
+ c
+ for c in candidates
+ if c.rust_target.startswith("{}-".format(p))
+ and c.rust_target.endswith(suffix)
+ ]
+ if not matches:
+ continue
+ # As below, correlate on the (normalized) vendor.
+ for c in matches:
+ if c.target.vendor == vendor:
return c.rust_target
+ return matches[0].rust_target
# See if we can narrow down on the exact alias.
# We use the sub_configure_alias to keep support mingw32 triplets as input.
@@ -400,6 +412,15 @@ def detect_rustc_target(
elif narrowed:
candidates = narrowed
+ # Correlate on the (normalized) vendor, so vendor-specific targets (e.g.
+ # the *-oe-linux-gnu targets added in rust 1.98) don't shadow the
+ # generic ones for aliases whose vendor doesn't match a rust target.
+ narrowed = [c for c in candidates if c.target.vendor == vendor]
+ if len(narrowed) == 1:
+ return narrowed[0].rust_target
+ elif narrowed:
+ candidates = narrowed
+
# See if we can narrow down with the raw OS and raw CPU
narrowed = [
c
=====================================
python/mozbuild/mozbuild/test/configure/test_toolchain_configure.py
=====================================
@@ -1779,6 +1779,15 @@ def gen_invoke_rustc(version, rustup_wrapper=False):
"xtensa-esp32s3-espidf",
"xtensa-esp32s3-none-elf",
]
+ # Additional targets from 1.98
+ if Version(version) >= "1.98.0":
+ rust_targets += [
+ "aarch64-oe-linux-gnu",
+ "armv7-oe-linux-gnueabihf",
+ "i686-oe-linux-gnu",
+ "riscv64-oe-linux-gnu",
+ "x86_64-oe-linux-gnu",
+ ]
return 0, "\n".join(sorted(rust_targets)), ""
if (
len(args) == 6
@@ -1869,6 +1878,7 @@ class RustTest(BaseConfigureTest):
("x86_64-unknown-linux-android", "x86_64-linux-android"),
("x86_64-unknown-linux-android21", "x86_64-linux-android"),
("x86_64-pc-linux-gnu", "x86_64-unknown-linux-gnu"),
+ ("riscv64-unknown-linux-gnu", "riscv64gc-unknown-linux-gnu"),
("sparcv9-sun-solaris2", "sparcv9-sun-solaris"),
("x86_64-sun-solaris2", "x86_64-pc-solaris"),
("x86_64-apple-darwin23.3.0", "x86_64-apple-darwin"),
@@ -1970,5 +1980,10 @@ class RustTest(BaseConfigureTest):
self.assertEqual(self.get_rust_target("wasm32-unknown-wasi"), "wasm32-wasip1")
+# Exercises the vendor-specific *-oe-linux-* targets added in rust 1.98.
+class Rust198Test(RustTest):
+ VERSION = "1.98.0"
+
+
if __name__ == "__main__":
main()
View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/commit/ca3…
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/commit/ca3…
You're receiving this email because of your account on gitlab.torproject.org. Manage all notifications: https://gitlab.torproject.org/-/profile/notifications | Help: https://gitlab.torproject.org/help
1
0