tor-browser

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

commit 9d7faf035e9590310b3f6c86171a06aa30c29132
parent 5b8fe027b47780542708a8b89a9c0f795235b04d
Author: mark <mkennedy@mozilla.com>
Date:   Fri,  3 Oct 2025 15:58:02 +0000

Bug 1969949 - Convert 'Default browser' Startup controls to config-based setting r=fluent-reviewers,desktop-theme-reviewers,akulyk,bolsson,mstriemer,hjones

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

Diffstat:
Mbrowser/components/preferences/main.inc.xhtml | 21---------------------
Mbrowser/components/preferences/main.js | 341+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Mbrowser/components/preferences/tests/browser_defaultbrowser_alwayscheck.js | 239++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Mbrowser/components/preferences/widgets/setting-control/setting-control.mjs | 1-
Mbrowser/locales/en-US/browser/preferences/preferences.ftl | 7+++++--
Mbrowser/themes/shared/preferences/preferences.css | 10----------
Apython/l10n/fluent_migrations/bug_1969949_convert_startup_config_controls.py | 36++++++++++++++++++++++++++++++++++++
Mtoolkit/content/preferences/Preferences.mjs | 2++
Mtoolkit/content/preferences/Setting.mjs | 8++++++--
9 files changed, 413 insertions(+), 252 deletions(-)

diff --git a/browser/components/preferences/main.inc.xhtml b/browser/components/preferences/main.inc.xhtml @@ -30,27 +30,6 @@ <html:setting-group groupid="startup"/> </vbox> -#ifdef HAVE_SHELL_SERVICE - <vbox id="defaultBrowserBox"> - <checkbox id="alwaysCheckDefault" preference="browser.shell.checkDefaultBrowser" - disabled="true" - data-l10n-id="always-check-default"/> - <stack id="setDefaultPane"> - <hbox id="isNotDefaultPane" align="center" class="indent"> - <label class="face-sad" id="isNotDefaultLabel" flex="1" data-l10n-id="is-not-default"/> - <button id="setDefaultButton" - is="highlightable-button" - class="accessory-button" - data-l10n-id="set-as-my-default-browser" - preference="pref.general.disable_button.default_browser"/> - </hbox> - <hbox id="isDefaultPane" align="center" class="indent"> - <label class="face-smile" id="isDefaultLabel" flex="1" data-l10n-id="is-default"/> - </hbox> - </stack> - </vbox> -#endif - </groupbox> <!-- Data migration --> diff --git a/browser/components/preferences/main.js b/browser/components/preferences/main.js @@ -2,7 +2,8 @@ * 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 { SettingGroup } from "./widgets/setting-group/setting-group.mjs" */ +/** @import MozButton from "chrome://global/content/elements/moz-button.mjs"; */ +/** @import { SettingGroup } from "./widgets/setting-group/setting-group.mjs" */ /** @import { PreferencesSettingsConfig } from "chrome://global/content/preferences/Preferences.mjs" */ /* import-globals-from extensionControlled.js */ @@ -849,6 +850,198 @@ Preferences.addSetting({ Services.prefs.setBoolPref("browser.download.deletePrivate.chosen", true); }, }); +/** + * A helper object containing all logic related to + * setting the browser as the user's default. + */ +const DefaultBrowserHelper = { + /** + * @type {number} + */ + _backoffIndex: 0, + + /** + * @type {number | undefined} + */ + _pollingTimer: undefined, + + /** + * Keeps track of the last known browser + * default value set to compare while polling. + * + * @type {boolean | undefined} + */ + _lastPolledIsDefault: undefined, + + /** + * @type {typeof import('../shell/ShellService.sys.mjs').ShellService | undefined} + */ + get shellSvc() { + return AppConstants.HAVE_SHELL_SERVICE && getShellService(); + }, + + /** + * Sets up polling of whether the browser is set to default, + * and calls provided hasChanged function when the state changes. + * + * @param {Function} hasChanged + */ + pollForDefaultChanges(hasChanged) { + if (this._pollingTimer) { + return; + } + this._lastPolledIsDefault = this.isBrowserDefault; + + // Exponential backoff mechanism will delay the polling times if user doesn't + // trigger SetDefaultBrowser for a long time. + const backoffTimes = [ + 1000, 1000, 1000, 1000, 2000, 2000, 2000, 5000, 5000, 10000, + ]; + + const pollForDefaultBrowser = () => { + if ( + (location.hash == "" || location.hash == "#general") && + document.visibilityState == "visible" + ) { + const { isBrowserDefault } = this; + if (isBrowserDefault !== this._lastPolledIsDefault) { + this._lastPolledIsDefault = isBrowserDefault; + hasChanged(); + } + } + + if (!this._pollingTimer) { + return; + } + + // approximately a "requestIdleInterval" + this._pollingTimer = window.setTimeout( + () => { + window.requestIdleCallback(pollForDefaultBrowser); + }, + backoffTimes[ + this._backoffIndex + 1 < backoffTimes.length + ? this._backoffIndex++ + : backoffTimes.length - 1 + ] + ); + }; + + this._pollingTimer = window.setTimeout(() => { + window.requestIdleCallback(pollForDefaultBrowser); + }, backoffTimes[this._backoffIndex]); + }, + + /** + * Stops timer for polling changes. + */ + clearPollingForDefaultChanges() { + if (this._pollingTimer) { + clearTimeout(this._pollingTimer); + this._pollingTimer = undefined; + } + }, + + /** + * Checks if the browser is default through the shell service. + */ + get isBrowserDefault() { + if (!this.canCheck) { + return false; + } + return this.shellSvc?.isDefaultBrowser(false, true); + }, + + /** + * Attempts to set the browser as the user's + * default through the shell service. + * + * @returns {Promise<void>} + */ + async setDefaultBrowser() { + // Reset exponential backoff delay time in order to do visual update in pollForDefaultBrowser. + this._backoffIndex = 0; + + try { + await this.shellSvc?.setDefaultBrowser(false); + } catch (e) { + console.error(e); + } + }, + + /** + * Checks whether the browser is capable of being made default. + * @type {boolean} + */ + get canCheck() { + return ( + this.shellSvc && + /** + * Flatpak does not support setting nor detection of default browser + */ + !gGIOService?.isRunningUnderFlatpak + ); + }, +}; + +Preferences.addSetting({ + id: "alwaysCheckDefault", + pref: "browser.shell.checkDefaultBrowser", + setup: emitChange => { + if (!DefaultBrowserHelper.canCheck) { + return; + } + DefaultBrowserHelper.pollForDefaultChanges(emitChange); + // eslint-disable-next-line consistent-return + return () => DefaultBrowserHelper.clearPollingForDefaultChanges(); + }, + /** + * Show button for setting browser as default browser or information that + * browser is already the default browser. + */ + visible: () => DefaultBrowserHelper.canCheck, + disabled: (deps, setting) => + !DefaultBrowserHelper.canCheck || + setting.locked || + DefaultBrowserHelper.isBrowserDefault, +}); + +Preferences.addSetting({ + id: "isDefaultPane", + deps: ["alwaysCheckDefault"], + visible: () => + DefaultBrowserHelper.canCheck && DefaultBrowserHelper.isBrowserDefault, +}); + +Preferences.addSetting({ + id: "isNotDefaultPane", + deps: ["alwaysCheckDefault"], + visible: () => + DefaultBrowserHelper.canCheck && !DefaultBrowserHelper.isBrowserDefault, + onUserClick: (e, { alwaysCheckDefault }) => { + if (!DefaultBrowserHelper.canCheck) { + return; + } + const setDefaultButton = /** @type {MozButton} */ (e.target); + + if (!setDefaultButton) { + return; + } + if (setDefaultButton.disabled) { + return; + } + + /** + * Disable the set default button, so that the user + * doesn't try to hit it again while browser is being set to default. + */ + setDefaultButton.disabled = true; + alwaysCheckDefault.value = true; + DefaultBrowserHelper.setDefaultBrowser().finally(() => { + setDefaultButton.disabled = false; + }); + }, +}); // Performance settings Preferences.addSetting({ @@ -934,6 +1127,31 @@ let SETTINGS_CONFIG = { l10nId: "startup-windows-launch-on-login-profile-disabled", }, }, + { + id: "alwaysCheckDefault", + l10nId: "always-check-default", + }, + { + id: "isDefaultPane", + l10nId: "is-default-browser", + control: "moz-promo", + }, + { + id: "isNotDefaultPane", + l10nId: "is-not-default-browser", + control: "moz-promo", + options: [ + { + control: "moz-button", + l10nId: "set-as-my-default-browser", + id: "setDefaultButton", + controlAttrs: { + slot: "actions", + type: "primary", + }, + }, + ], + }, ], }, zoom: { @@ -1365,8 +1583,6 @@ var gMainPane = { return (this._filter = document.getElementById("filter")); }, - _backoffIndex: 0, - /** * Initialization of gMainPane. */ @@ -1377,47 +1593,6 @@ var gMainPane = { .addEventListener(aEventType, aCallback.bind(gMainPane)); } - if (AppConstants.HAVE_SHELL_SERVICE) { - this.updateSetDefaultBrowser(); - let win = Services.wm.getMostRecentWindow("navigator:browser"); - - // Exponential backoff mechanism will delay the polling times if user doesn't - // trigger SetDefaultBrowser for a long time. - let backoffTimes = [ - 1000, 1000, 1000, 1000, 2000, 2000, 2000, 5000, 5000, 10000, - ]; - - let pollForDefaultBrowser = () => { - let uri = win.gBrowser.currentURI.spec; - - if ( - (uri == "about:preferences" || - uri == "about:preferences#general" || - uri == "about:settings" || - uri == "about:settings#general") && - document.visibilityState == "visible" - ) { - this.updateSetDefaultBrowser(); - } - - // approximately a "requestIdleInterval" - window.setTimeout( - () => { - window.requestIdleCallback(pollForDefaultBrowser); - }, - backoffTimes[ - this._backoffIndex + 1 < backoffTimes.length - ? this._backoffIndex++ - : backoffTimes.length - 1 - ] - ); - }; - - window.setTimeout(() => { - window.requestIdleCallback(pollForDefaultBrowser); - }, backoffTimes[this._backoffIndex]); - } - this.initBrowserContainers(); this.displayUseSystemLocale(); this.updateProxySettingsUI(); @@ -1522,13 +1697,6 @@ var gMainPane = { }); } - if (AppConstants.HAVE_SHELL_SERVICE) { - setEventListener( - "setDefaultButton", - "command", - gMainPane.setDefaultBrowser - ); - } setEventListener( "disableContainersExtension", "command", @@ -2707,77 +2875,6 @@ var gMainPane = { var linkTargeting = document.getElementById("linkTargeting"); return linkTargeting.checked ? 3 : 2; }, - /* - * Preferences: - * - * browser.shell.checkDefault - * - true if a default-browser check (and prompt to make it so if necessary) - * occurs at startup, false otherwise - */ - - /** - * Show button for setting browser as default browser or information that - * browser is already the default browser. - */ - updateSetDefaultBrowser() { - if (AppConstants.HAVE_SHELL_SERVICE) { - let shellSvc = getShellService(); - let defaultBrowserBox = document.getElementById("defaultBrowserBox"); - let isInFlatpak = gGIOService?.isRunningUnderFlatpak; - // Flatpak does not support setting nor detection of default browser - if (!shellSvc || isInFlatpak) { - defaultBrowserBox.hidden = true; - return; - } - let isDefault = shellSvc.isDefaultBrowser(false, true); - let setDefaultPane = document.getElementById("setDefaultPane"); - setDefaultPane.classList.toggle("is-default", isDefault); - let alwaysCheck = document.getElementById("alwaysCheckDefault"); - let alwaysCheckPref = Preferences.get( - "browser.shell.checkDefaultBrowser" - ); - alwaysCheck.disabled = alwaysCheckPref.locked || isDefault; - } - }, - - /** - * Set browser as the operating system default browser. - */ - async setDefaultBrowser() { - if (AppConstants.HAVE_SHELL_SERVICE) { - let alwaysCheckPref = Preferences.get( - "browser.shell.checkDefaultBrowser" - ); - alwaysCheckPref.value = true; - - // Reset exponential backoff delay time in order to do visual update in pollForDefaultBrowser. - this._backoffIndex = 0; - - let shellSvc = getShellService(); - if (!shellSvc) { - return; - } - - // Disable the set default button, so that the user doesn't try to hit it again - // while awaiting on setDefaultBrowser - let setDefaultButton = document.getElementById("setDefaultButton"); - setDefaultButton.disabled = true; - - try { - await shellSvc.setDefaultBrowser(false); - } catch (ex) { - console.error(ex); - return; - } finally { - // Make sure to re-enable the default button when we're finished, regardless of the outcome - setDefaultButton.disabled = false; - } - - let isDefault = shellSvc.isDefaultBrowser(false, true); - let setDefaultPane = document.getElementById("setDefaultPane"); - setDefaultPane.classList.toggle("is-default", isDefault); - } - }, /** * Shows a subdialog containing the profile selector page. diff --git a/browser/components/preferences/tests/browser_defaultbrowser_alwayscheck.js b/browser/components/preferences/tests/browser_defaultbrowser_alwayscheck.js @@ -1,24 +1,73 @@ "use strict"; -const CHECK_DEFAULT_INITIAL = Services.prefs.getBoolPref( - "browser.shell.checkDefaultBrowser" -); - -add_task(async function clicking_make_default_checks_alwaysCheck_checkbox() { +/** + * Sets up initial prefs and opens about:preferences page. + * @returns {Promise<void>} + */ +async function setup() { + await SpecialPowers.pushPrefEnv({ + set: [["browser.shell.checkDefaultBrowser", false]], + }); await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:preferences"); +} + +/** + * Closes out the about:preferences tab and clears out + * any prefs that could have potentially been manipulated. + * + * @returns {void} + */ +function teardown() { + Services.prefs.unlockPref("browser.shell.checkDefaultBrowser"); + gBrowser.removeCurrentTab(); +} + +/** + * Sets up the 'Make default' mock service to mimic + * whether the user has set the browser as default already or not. + * + * @param {{isDefault: boolean}} options + */ +async function setupInitialBrowserDefaultSetting(options) { + const win = gBrowser.selectedBrowser.contentWindow; + win.oldShellService = win.getShellService(); + const { isDefault } = options; + + const mockShellService = { + _isDefault: isDefault, + isDefaultBrowser() { + return this._isDefault; + }, + async setDefaultBrowser() { + this._isDefault = true; + }, + }; + win.getShellService = function () { + return mockShellService; + }; +} + +add_task( + /** + * Tests when clicking 'Make default' button, setting browser + * to default, and the side effects of the 'Always check' checkbox. + */ + async function clicking_make_default_checks_alwaysCheck_checkbox() { + await setup(); + await setupInitialBrowserDefaultSetting({ isDefault: false }); - await test_with_mock_shellservice({ isDefault: false }, async function () { let checkDefaultBrowserState = isDefault => { let isDefaultPane = content.document.getElementById("isDefaultPane"); let isNotDefaultPane = content.document.getElementById("isNotDefaultPane"); + Assert.equal( - ContentTaskUtils.isHidden(isDefaultPane), + BrowserTestUtils.isHidden(isDefaultPane.control), !isDefault, "The 'browser is default' pane should be hidden when browser is not default" ); Assert.equal( - ContentTaskUtils.isHidden(isNotDefaultPane), + BrowserTestUtils.isHidden(isNotDefaultPane.control), isDefault, "The 'make default' pane should be hidden when browser is default" ); @@ -26,18 +75,25 @@ add_task(async function clicking_make_default_checks_alwaysCheck_checkbox() { checkDefaultBrowserState(false); - let alwaysCheck = content.document.getElementById("alwaysCheckDefault"); + const alwaysCheck = content.document.getElementById("alwaysCheckDefault"); + Assert.ok(!alwaysCheck.checked, "Always Check is unchecked by default"); + Assert.ok( !Services.prefs.getBoolPref("browser.shell.checkDefaultBrowser"), "alwaysCheck pref should be false by default in test runs" ); - let setDefaultButton = content.document.getElementById("setDefaultButton"); + const setDefaultButton = + content.document.getElementById("setDefaultButton"); + /** + * Click 'Make default' button to trigger shell service that sets the browser to default. + */ setDefaultButton.click(); - content.window.gMainPane.updateSetDefaultBrowser(); - - await ContentTaskUtils.waitForCondition( + /** + * Deem complete when 'Always Check' checkbox is checked. + */ + await TestUtils.waitForCondition( () => alwaysCheck.checked, "'Always Check' checkbox should get checked after clicking the 'Set Default' button" ); @@ -59,30 +115,43 @@ add_task(async function clicking_make_default_checks_alwaysCheck_checkbox() { Services.prefs.getBoolPref("browser.shell.checkDefaultBrowser"), "checkDefaultBrowser pref is now enabled" ); - }); + teardown(); + } +); - gBrowser.removeCurrentTab(); - Services.prefs.clearUserPref("browser.shell.checkDefaultBrowser"); -}); +add_task( + /** + * Tests when clicking 'Make default' button, setting browser + * to default, and the side effects of the 'Always check' checkbox + * when browser.shell.checkDefaultBrowser pref is locked + */ + async function clicking_make_default_checks_alwaysCheck_checkbox_when_locked() { + await setup(); -add_task(async function clicking_make_default_checks_alwaysCheck_checkbox() { - Services.prefs.lockPref("browser.shell.checkDefaultBrowser"); - await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:preferences"); + Services.prefs.lockPref("browser.shell.checkDefaultBrowser"); + + const isDefault = false; + await setupInitialBrowserDefaultSetting({ isDefault }); - await test_with_mock_shellservice({ isDefault: false }, async function () { let isDefaultPane = content.document.getElementById("isDefaultPane"); let isNotDefaultPane = content.document.getElementById("isNotDefaultPane"); + + is(isDefaultPane.localName, "moz-promo", "Pane is a moz-promo"); + Assert.ok( - ContentTaskUtils.isHidden(isDefaultPane), + BrowserTestUtils.isHidden(isDefaultPane.control), "The 'browser is default' pane should be hidden when not default" ); + Assert.ok( - ContentTaskUtils.isVisible(isNotDefaultPane), - "The 'make default' pane should be visible when not default" + !BrowserTestUtils.isHidden(isNotDefaultPane.control), + "The 'is not default' pane should be visible when not default" ); let alwaysCheck = content.document.getElementById("alwaysCheckDefault"); + Assert.ok(alwaysCheck.disabled, "Always Check is disabled when locked"); + Assert.ok( alwaysCheck.checked, "Always Check is checked because defaultPref is true and pref is locked" @@ -91,14 +160,32 @@ add_task(async function clicking_make_default_checks_alwaysCheck_checkbox() { Services.prefs.getBoolPref("browser.shell.checkDefaultBrowser"), "alwaysCheck pref should ship with 'true' by default" ); - - let setDefaultButton = content.document.getElementById("setDefaultButton"); + const setDefaultButton = + content.document.getElementById("setDefaultButton"); + /** + * Click 'Make default' button to trigger shell service that sets the browser to default. + */ setDefaultButton.click(); - content.window.gMainPane.updateSetDefaultBrowser(); - await ContentTaskUtils.waitForCondition( - () => ContentTaskUtils.isVisible(isDefaultPane), - "Browser is now default" + const { TelemetryTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/TelemetryTestUtils.sys.mjs" + ); + let snapshot = TelemetryTestUtils.getProcessScalars("parent", true, true); + TelemetryTestUtils.assertKeyedScalar( + snapshot, + "browser.ui.interaction.preferences_paneGeneral", + "setDefaultButton", + 2 // button clicked + ); + + Assert.ok( + !BrowserTestUtils.isHidden(isNotDefaultPane.control), + "Browser default pane still shows after click because pref is locked" + ); + + Assert.ok( + BrowserTestUtils.isHidden(isDefaultPane.control), + "Browser is not default pane is NOT showing" ); Assert.ok( @@ -113,73 +200,37 @@ add_task(async function clicking_make_default_checks_alwaysCheck_checkbox() { Services.prefs.getBoolPref("browser.shell.checkDefaultBrowser"), "The pref is locked and so doesn't get changed" ); - }); + teardown(); + } +); - Services.prefs.unlockPref("browser.shell.checkDefaultBrowser"); - gBrowser.removeCurrentTab(); -}); +add_task( + /** + * Testcase with Firefox initially set as the default browser + */ + async function make_default_after_browser_set_as_default() { + await setup(); -add_task(async function make_default_disabled_until_prefs_are_loaded() { - // Testcase with Firefox not set as the default browser - await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:preferences"); - await test_with_mock_shellservice({ isDefault: false }, async function () { - let alwaysCheck = content.document.getElementById("alwaysCheckDefault"); - Assert.ok( - !alwaysCheck.disabled, - "'Always Check' is enabled after default browser updated" - ); - }); - gBrowser.removeCurrentTab(); + await setupInitialBrowserDefaultSetting({ isDefault: true }); + + const alwaysCheck = content.document.getElementById("alwaysCheckDefault"); + + is(alwaysCheck.localName, "moz-checkbox", "Checkbox is a moz-checkbox."); - // Testcase with Firefox set as the default browser - await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:preferences"); - await test_with_mock_shellservice({ isDefault: true }, async function () { - let alwaysCheck = content.document.getElementById("alwaysCheckDefault"); Assert.ok( - alwaysCheck.disabled, - "'Always Check' is still disabled after default browser updated" + !BrowserTestUtils.isHidden(alwaysCheck.control), + "Control element is visible by default" ); - }); - gBrowser.removeCurrentTab(); -}); -registerCleanupFunction(function () { - Services.prefs.unlockPref("browser.shell.checkDefaultBrowser"); - Services.prefs.setBoolPref( - "browser.shell.checkDefaultBrowser", - CHECK_DEFAULT_INITIAL - ); -}); - -async function test_with_mock_shellservice(options, testFn) { - await SpecialPowers.spawn( - gBrowser.selectedBrowser, - [options], - async function (contentOptions) { - let doc = content.document; - let win = doc.defaultView; - win.oldShellService = win.getShellService(); - let mockShellService = { - _isDefault: false, - isDefaultBrowser() { - return this._isDefault; - }, - async setDefaultBrowser() { - this._isDefault = true; - }, - }; - win.getShellService = function () { - return mockShellService; - }; - mockShellService._isDefault = contentOptions.isDefault; - win.gMainPane.updateSetDefaultBrowser(); - } - ); - - await SpecialPowers.spawn(gBrowser.selectedBrowser, [], testFn); - - Services.prefs.setBoolPref( - "browser.shell.checkDefaultBrowser", - CHECK_DEFAULT_INITIAL - ); -} + Assert.ok(!alwaysCheck.disabled, "'Always Check' is NOT disabled"); + + Assert.ok(!alwaysCheck.checked, "Checkbox is NOT checked initially"); + + is( + content.document.l10n.getAttributes(alwaysCheck).id, + "always-check-default", + `Checkbox has the correct data-l10n-id attribute` + ); + teardown(); + } +); diff --git a/browser/components/preferences/widgets/setting-control/setting-control.mjs b/browser/components/preferences/widgets/setting-control/setting-control.mjs @@ -261,7 +261,6 @@ export class SettingControl extends MozLitElement { getControlPropertyMapping(config) { const props = this.getCommonPropertyMapping(config); props[".parentDisabled"] = this.parentDisabled; - props[".control"] = this; props["?disabled"] = this.setting.disabled || this.setting.locked || diff --git a/browser/locales/en-US/browser/preferences/preferences.ftl b/browser/locales/en-US/browser/preferences/preferences.ftl @@ -142,8 +142,11 @@ always-check-default = .label = Always check if { -brand-short-name } is your default browser .accesskey = y -is-default = { -brand-short-name } is currently your default browser -is-not-default = { -brand-short-name } is not your default browser +is-default-browser = + .message = { -brand-short-name } is currently your default browser + +is-not-default-browser = + .message = { -brand-short-name } is not your default browser set-as-my-default-browser = .label = Make Default… diff --git a/browser/themes/shared/preferences/preferences.css b/browser/themes/shared/preferences/preferences.css @@ -250,16 +250,6 @@ radio { /* General Pane */ -.is-default > #isNotDefaultPane, -:not(.is-default) > #isDefaultPane { - visibility: hidden; -} - -#isDefaultLabel, -#isNotDefaultLabel { - font-weight: var(--font-weight-bold); -} - /* stylelint-disable-next-line media-query-no-invalid */ @media not -moz-pref("browser.migrate.preferences-entrypoint.enabled") { #dataMigrationGroup { diff --git a/python/l10n/fluent_migrations/bug_1969949_convert_startup_config_controls.py b/python/l10n/fluent_migrations/bug_1969949_convert_startup_config_controls.py @@ -0,0 +1,36 @@ +# Any copyright is dedicated to the Public Domain. +# http://creativecommons.org/publicdomain/zero/1.0/ + +import re +import fluent.syntax.ast as FTL +from fluent.migrate import COPY_PATTERN +from fluent.migrate.transforms import TransformPattern + + +def migrate(ctx): + """Bug 1969949 - Migrate startup controls to config-based, part {index}.""" + path = "browser/browser/preferences/preferences.ftl" + ctx.add_transforms( + path, + path, + [ + FTL.Message( + id=FTL.Identifier("is-default-browser"), + attributes=[ + FTL.Attribute( + id=FTL.Identifier("message"), + value=COPY_PATTERN(path, "is-default"), + ), + ], + ), + FTL.Message( + id=FTL.Identifier("is-not-default-browser"), + attributes=[ + FTL.Attribute( + id=FTL.Identifier("message"), + value=COPY_PATTERN(path, "is-not-default"), + ), + ], + ), + ], + ) diff --git a/toolkit/content/preferences/Preferences.mjs b/toolkit/content/preferences/Preferences.mjs @@ -75,6 +75,8 @@ import { Setting } from "chrome://global/content/preferences/Setting.mjs"; /** * @callback PreferencesSettingConfigOnUserClickFunction * @param {Event} event + * @param {PreferenceSettingDepsMap} deps + * @param {Setting} setting * @returns {void} */ diff --git a/toolkit/content/preferences/Setting.mjs b/toolkit/content/preferences/Setting.mjs @@ -31,6 +31,10 @@ ChromeUtils.defineESModuleGetters(lazy, { * @typedef {Record<string, Setting | undefined>} PreferenceSettingDepsMap */ +/** + * @typedef {string | boolean | number} SettingValue + */ + export class Setting extends EventEmitter { /** * @type {Preference | undefined | null} @@ -122,7 +126,7 @@ export class Setting extends EventEmitter { } /** - * @type {string | undefined} + * @type {SettingValue} */ get value() { let prefVal = this.pref?.value; @@ -133,7 +137,7 @@ export class Setting extends EventEmitter { } /** - * @param {string} val + * @param {SettingValue} val */ set value(val) { let newVal = this.config.set ? this.config.set(val, this.deps, this) : val;