tor-browser

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

commit 84d778b410212f9652ad116983e7790dc8aeb14b
parent f3ee8157720b30fa344aa80b6e09be42a13d792b
Author: Stephen Thompson <sthompson@mozilla.com>
Date:   Wed,  8 Oct 2025 16:20:06 +0000

Bug 1984234 - settings UI to toggle opening external links next to the active tab r=fluent-reviewers,mstriemer,bolsson

Add a new checkbox to the General > Tabs section of about:preferences to allow the user to open external links next to the active tab.

The current behavior defaults to looking up `browser.link.open_newwindow.override.external`, and if that's the default of `-1`, it falls back to `browser.link.open_newwindow` which defaults to `3` (open a new tab at the end of the tab strip).

We want the settings UI to be simple, so it's a checkbox to set the value of `browser.link.open_newwindow.override.external` to `7`, which indicates opening external links next to the active tab. However, when the user unchecks the box, the value returns to the browser default `-1` to force `browser.link.open_newwindow.override.external` back to the default `-1` rather than returning to any value that the user might have explicitly set before in about:config.

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

Diffstat:
Mbrowser/components/preferences/main.inc.xhtml | 3+++
Mbrowser/components/preferences/main.js | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mbrowser/components/preferences/tests/browser.toml | 2++
Abrowser/components/preferences/tests/browser_tabs_open_external_next_to_active_tab.js | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mbrowser/locales/en-US/browser/preferences/preferences.ftl | 3+++
Mtoolkit/content/preferences/Preferences.mjs | 10++++++++++
6 files changed, 133 insertions(+), 0 deletions(-)

diff --git a/browser/components/preferences/main.inc.xhtml b/browser/components/preferences/main.inc.xhtml @@ -77,6 +77,9 @@ <checkbox id="linkTargeting" data-l10n-id="open-new-link-as-tabs" preference="browser.link.open_newwindow"/> + <checkbox id="openAppLinksNextToActiveTab" data-l10n-id="open-external-link-next-to-active-tab" + preference="browser.link.open_newwindow.override.external"/> + <checkbox id="warnOpenMany" data-l10n-id="warn-on-open-many-tabs" preference="browser.tabs.warnOnOpen"/> diff --git a/browser/components/preferences/main.js b/browser/components/preferences/main.js @@ -52,6 +52,9 @@ const ICON_URL_APP = // was set by us to a custom handler icon and CSS should not try to override it. const APP_ICON_ATTR_NAME = "appHandlerIcon"; +const OPEN_EXTERNAL_LINK_NEXT_TO_ACTIVE_TAB_VALUE = + Ci.nsIBrowserDOMWindow.OPEN_NEWTAB_AFTER_CURRENT; + Preferences.addAll([ // Startup { id: "browser.startup.page", type: "int" }, @@ -73,6 +76,10 @@ Preferences.addAll([ 1 opens such links in the most recent window or tab, 2 opens such links in a new window, 3 opens such links in a new tab + browser.link.open_newwindow.override.external + - this setting overrides `browser.link.open_newwindow` for externally + opened links. + - see `nsIBrowserDOMWindow` constants for the meaning of each value. browser.tabs.loadInBackground - true if display should switch to a new tab which has been opened from a link, false if display shouldn't switch @@ -89,6 +96,7 @@ Preferences.addAll([ */ { id: "browser.link.open_newwindow", type: "int" }, + { id: "browser.link.open_newwindow.override.external", type: "int" }, { id: "browser.tabs.loadInBackground", type: "bool", inverted: true }, { id: "browser.tabs.warnOnClose", type: "bool" }, { id: "browser.warnOnQuitShortcut", type: "bool" }, @@ -1647,6 +1655,11 @@ var gMainPane = { * Initialization of gMainPane. */ init() { + /** + * @param {string} aId + * @param {string} aEventType + * @param {(ev: Event) => void} aCallback + */ function setEventListener(aId, aEventType, aCallback) { document .getElementById(aId) @@ -2033,6 +2046,14 @@ var gMainPane = { () => this.writeLinkTarget() ); Preferences.addSyncFromPrefListener( + document.getElementById("openAppLinksNextToActiveTab"), + () => this.readExternalLinkNextToActiveTab() + ); + Preferences.addSyncToPrefListener( + document.getElementById("openAppLinksNextToActiveTab"), + inputElement => this.writeExternalLinkNextToActiveTab(inputElement) + ); + Preferences.addSyncFromPrefListener( document.getElementById("browserContainersCheckbox"), () => this.readBrowserContainersCheckbox() ); @@ -2933,6 +2954,44 @@ var gMainPane = { }, /** + * @returns {boolean} + * Whether the "Open links in tabs instead of new windows" settings + * checkbox should be checked. Should only be checked if the + * `browser.link.open_newwindow.override.external` pref is set to the + * value of 7 (nsIBrowserDOMWindow.OPEN_NEWTAB_AFTER_CURRENT). + */ + readExternalLinkNextToActiveTab() { + const externalLinkOpenOverride = Preferences.get( + "browser.link.open_newwindow.override.external" + ); + + return ( + externalLinkOpenOverride.value == + Ci.nsIBrowserDOMWindow.OPEN_NEWTAB_AFTER_CURRENT + ); + }, + + /** + * This pref has at least 8 valid values but we are offering a checkbox + * to set one specific value (`7`). + * + * @param {HTMLInputElement} inputElement + * @returns {number} + * - `7` (`nsIBrowserDOMWindow.OPEN_NEWTAB_AFTER_CURRENT`) if checked + * - the default value of + * `browser.link.open_newwindow.override.external` if not checked + */ + writeExternalLinkNextToActiveTab(inputElement) { + const externalLinkOpenOverride = Preferences.get( + "browser.link.open_newwindow.override.external" + ); + + return inputElement.checked + ? Ci.nsIBrowserDOMWindow.OPEN_NEWTAB_AFTER_CURRENT + : externalLinkOpenOverride.defaultValue; + }, + + /** * Shows a subdialog containing the profile selector page. */ manageProfiles() { diff --git a/browser/components/preferences/tests/browser.toml b/browser/components/preferences/tests/browser.toml @@ -308,6 +308,8 @@ support-files = [ ["browser_sync_pairing.js"] +["browser_tabs_open_external_next_to_active_tab.js"] + ["browser_trendingsuggestions.js"] ["browser_usage_telemetry.js"] diff --git a/browser/components/preferences/tests/browser_tabs_open_external_next_to_active_tab.js b/browser/components/preferences/tests/browser_tabs_open_external_next_to_active_tab.js @@ -0,0 +1,56 @@ +/* Any copyright is dedicated to the Public Domain. + https://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const PREF_NAME = "browser.link.open_newwindow.override.external"; +const PREF_VALUE_FEATURE_OFF = Ci.nsIBrowserDOMWindow.OPEN_NEWTAB_BACKGROUND; +const PREF_VALUE_FEATURE_ON = Ci.nsIBrowserDOMWindow.OPEN_NEWTAB_AFTER_CURRENT; + +add_task(async function test_open_external_link_next_to_active_tab_pref() { + await SpecialPowers.pushPrefEnv({ + set: [[PREF_NAME, PREF_VALUE_FEATURE_OFF]], + }); + + await openPreferencesViaOpenPreferencesAPI("paneGeneral", { + leaveOpen: true, + }); + + const doc = gBrowser.contentDocument; + const checkbox = doc.getElementById("openAppLinksNextToActiveTab"); + + info("validate default starting conditions"); + Assert.ok(checkbox, "pref should have a checkbox"); + Assert.ok( + !checkbox.checked, + "pref checkbox should not be checked by default" + ); + + info( + "validate checking and unchecking the pref checkbox under default conditions" + ); + let becameChecked = BrowserTestUtils.waitForAttribute("checked", checkbox); + checkbox.click(); + await becameChecked; + + Assert.equal( + Services.prefs.getIntPref(PREF_NAME), + PREF_VALUE_FEATURE_ON, + "pref should be set to open external links after the active tab" + ); + + let becameUnchecked = BrowserTestUtils.waitForAttributeRemoval( + "checked", + checkbox + ); + checkbox.click(); + await becameUnchecked; + + Assert.ok( + !Services.prefs.prefHasUserValue(PREF_NAME), + "pref should have been reverted to its default value" + ); + + await SpecialPowers.popPrefEnv(); + BrowserTestUtils.removeTab(gBrowser.selectedTab, { animate: false }); +}); diff --git a/browser/locales/en-US/browser/preferences/preferences.ftl b/browser/locales/en-US/browser/preferences/preferences.ftl @@ -188,6 +188,9 @@ open-new-link-as-tabs = .label = Open links in tabs instead of new windows .accesskey = w +open-external-link-next-to-active-tab = + .label = Open links from apps next to your active tab + ask-on-close-multiple-tabs = .label = Ask before closing multiple tabs .accesskey = m diff --git a/toolkit/content/preferences/Preferences.mjs b/toolkit/content/preferences/Preferences.mjs @@ -415,9 +415,15 @@ export const Preferences = { } }, + /** @type {WeakMap<Element, (el: Element) => any>} */ _syncFromPrefListeners: new WeakMap(), + /** @type {WeakMap<Element, (el: Element) => any>} */ _syncToPrefListeners: new WeakMap(), + /** + * @param {Element} aElement + * @param {(el: Element) => any} callback + */ addSyncFromPrefListener(aElement, callback) { this._syncFromPrefListeners.set(aElement, callback); if (this.updateQueued) { @@ -433,6 +439,10 @@ export const Preferences = { } }, + /** + * @param {Element} aElement + * @param {(el: Element) => any} callback + */ addSyncToPrefListener(aElement, callback) { this._syncToPrefListeners.set(aElement, callback); if (this.updateQueued) {