tor-browser

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

commit 2c941048716c99e7f7f01c0815815a800d265026
parent e1becde5a12a97840e2d0f673b88c1c64e018a16
Author: Narcis Beleuzu <nbeleuzu@mozilla.com>
Date:   Tue, 14 Oct 2025 18:04:51 +0300

Revert "Bug 1986946 - Add context menu entry point for split view, and handle the single tab and multi-selected cases r=tabbrowser-reviewers,fluent-reviewers,jsudiaman,flod,sthompson,sclements,desktop-theme-reviewers,sfoster" for bc failure on browser_tab_splitview.js

This reverts commit 0f7b9bd615a8bda5995a0e58a71728ab76c27d58.

Diffstat:
Mbrowser/app/profile/firefox.js | 3---
Mbrowser/base/content/main-popupset.inc.xhtml | 7-------
Mbrowser/base/content/main-popupset.js | 9---------
Mbrowser/components/tabbrowser/content/tab.js | 5++++-
Mbrowser/components/tabbrowser/content/tabbrowser.js | 88++++---------------------------------------------------------------------------
Mbrowser/components/tabbrowser/content/tabgroup.js | 71+++++++++++++++++++++++++++--------------------------------------------
Mbrowser/components/tabbrowser/test/browser/tabs/browser_tab_splitview.js | 259+------------------------------------------------------------------------------
Mbrowser/locales/en-US/browser/tabbrowser.ftl | 14--------------
Mbrowser/themes/shared/tabbrowser/tabs.css | 34+---------------------------------
9 files changed, 37 insertions(+), 453 deletions(-)

diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js @@ -2633,9 +2633,6 @@ pref("browser.tabs.fadeOutExplicitlyUnloadedTabs", true); // they are explicitly unloaded) are faded out in the tab bar. pref("browser.tabs.fadeOutUnloadedTabs", false); -// Whether tabs can be "split" or displayed side by side at once. -pref("browser.tabs.splitView.enabled", false); - // If true, unprivileged extensions may use experimental APIs on // nightly and developer edition. pref("extensions.experiments.enabled", false); diff --git a/browser/base/content/main-popupset.inc.xhtml b/browser/base/content/main-popupset.inc.xhtml @@ -32,13 +32,6 @@ data-lazy-l10n-id="tab-context-ungroup-tab" data-l10n-args='{"groupCount": 1}' hidden="true"/> - <menuitem id="context_moveTabToSplitView" - class="badge-new" - hidden="true"/> - <menuitem id="context_separateSplitView" - class="badge-new" - data-lazy-l10n-id="tab-context-separate-split-view" - hidden="true"/> <menuseparator/> <menuitem id="context_reloadTab" data-lazy-l10n-id="reload-tab"/> <menuitem id="context_reloadSelectedTabs" data-lazy-l10n-id="reload-tabs" hidden="true"/> diff --git a/browser/base/content/main-popupset.js b/browser/base/content/main-popupset.js @@ -24,12 +24,6 @@ document.addEventListener( case "context_ungroupTab": TabContextMenu.ungroupTabs(); break; - case "context_moveTabToSplitView": - TabContextMenu.moveTabsToSplitView(); - break; - case "context_separateSplitView": - TabContextMenu.unsplitTabs(); - break; case "context_reloadTab": gBrowser.reloadTab(TabContextMenu.contextTab); break; @@ -527,9 +521,6 @@ document.addEventListener( case "bhTooltip": BookmarksEventHandler.fillInBHTooltip(event.target, event); break; - case "tabContextMenu": - TabContextMenu.addNewBadge(); - break; } }); diff --git a/browser/components/tabbrowser/content/tab.js b/browser/components/tabbrowser/content/tab.js @@ -374,7 +374,10 @@ } get group() { - return this.closest("tab-group"); + if (this.parentElement?.tagName == "tab-group") { + return this.parentElement; + } + return null; } get splitview() { diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/components/tabbrowser/content/tabbrowser.js @@ -3225,12 +3225,9 @@ return; } - for (let i = splitview.tabs.length - 1; i >= 0; i--) { - this.#handleTabMove(splitview.tabs[i], () => - gBrowser.tabContainer.insertBefore( - splitview.tabs[i], - splitview.nextElementSibling - ) + for (const tab of splitview.tabs) { + this.#handleTabMove(tab, () => + gBrowser.tabContainer.insertBefore(tab, splitview.nextElementSibling) ); } splitview.remove(); @@ -7411,7 +7408,7 @@ } getTabPids(tab) { - if (!tab?.linkedBrowser) { + if (!tab.linkedBrowser) { return []; } @@ -9493,34 +9490,6 @@ var TabContextMenu = { contextUngroupTab.hidden = true; } - // Split View - let splitViewEnabled = Services.prefs.getBoolPref( - "browser.tabs.splitView.enabled", - false - ); - let contextMoveTabToNewSplitView = document.getElementById( - "context_moveTabToSplitView" - ); - let contextSeparateSplitView = document.getElementById( - "context_separateSplitView" - ); - let hasSplitViewTab = this.contextTabs.some(tab => tab.splitview); - contextMoveTabToNewSplitView.hidden = !splitViewEnabled || hasSplitViewTab; - contextSeparateSplitView.hidden = !splitViewEnabled || !hasSplitViewTab; - if (splitViewEnabled) { - contextMoveTabToNewSplitView.removeAttribute("data-l10n-id"); - contextMoveTabToNewSplitView.setAttribute( - "data-l10n-id", - this.contextTabs.length < 2 - ? "tab-context-add-split-view" - : "tab-context-open-in-split-view" - ); - - let pinnedTabs = this.contextTabs.filter(t => t.pinned); - contextMoveTabToNewSplitView.disabled = - this.contextTabs.length > 2 || pinnedTabs.length; - } - // Only one of Reload_Tab/Reload_Selected_Tabs should be visible. document.getElementById("context_reloadTab").hidden = this.multiselected; document.getElementById("context_reloadSelectedTabs").hidden = @@ -9944,55 +9913,6 @@ var TabContextMenu = { gBrowser.ungroupTab(this.contextTabs[i]); } }, - - moveTabsToSplitView() { - let insertBefore = this.contextTabs.includes(gBrowser.selectedTab) - ? gBrowser.selectedTab - : this.contextTabs[0]; - let tabsToAdd = this.contextTabs; - - // Ensure selected tab is always first in split view - const selectedTabIndex = tabsToAdd.indexOf(gBrowser.selectedTab); - if (selectedTabIndex > -1 && selectedTabIndex != 0) { - const [removed] = tabsToAdd.splice(selectedTabIndex, 1); - tabsToAdd.unshift(removed); - } - - let newTab = null; - if (this.contextTabs.length < 2) { - // Open new tab to split with context tab - newTab = gBrowser.addTrustedTab(BROWSER_NEW_TAB_URL); - tabsToAdd = [this.contextTabs[0], newTab]; - } - - gBrowser.addTabSplitView(tabsToAdd, { - insertBefore, - }); - - if (newTab) { - gBrowser.selectedTab = newTab; - } - }, - - unsplitTabs() { - const splitviews = new Set( - this.contextTabs.map(tab => tab.splitview).filter(Boolean) - ); - splitviews.forEach(splitview => gBrowser.unsplitTabs(splitview)); - }, - - addNewBadge() { - let badgeNewMenuItems = document.querySelectorAll( - "#tabContextMenu menuitem.badge-new" - ); - - badgeNewMenuItems.forEach(badgedMenuItem => { - badgedMenuItem.setAttribute( - "badge", - gBrowser.tabLocalization.formatValueSync("tab-context-badge-new") - ); - }); - }, }; ChromeUtils.defineESModuleGetters(TabContextMenu, { diff --git a/browser/components/tabbrowser/content/tabgroup.js b/browser/components/tabbrowser/content/tabgroup.js @@ -186,7 +186,32 @@ tab.setAttribute("aria-setsize", tabCount); }); this.hasActiveTab = hasActiveTab; - this.#updateOverflowLabel(); + + // When a group containing the active tab is collapsed, + // the overflow count displays the number of additional tabs + // in the group adjacent to the active tab. + let overflowCountLabel = this.overflowContainer.querySelector( + ".tab-group-overflow-count" + ); + if (tabCount > 1) { + gBrowser.tabLocalization + .formatValue("tab-group-overflow-count", { + tabCount: tabCount - 1, + }) + .then(result => (overflowCountLabel.textContent = result)); + gBrowser.tabLocalization + .formatValue("tab-group-overflow-count-tooltip", { + tabCount: tabCount - 1, + }) + .then(result => { + overflowCountLabel.setAttribute("tooltiptext", result); + overflowCountLabel.setAttribute("aria-description", result); + }); + this.toggleAttribute("hasmultipletabs", true); + } else { + overflowCountLabel.textContent = ""; + this.toggleAttribute("hasmultipletabs", false); + } } for (const mutation of mutations) { for (const addedNode of mutation.addedNodes) { @@ -396,51 +421,11 @@ } } - #updateOverflowLabel() { - // When a group containing the active tab is collapsed, - // the overflow count displays the number of additional tabs - // in the group adjacent to the active tab. - let overflowCountLabel = this.overflowContainer.querySelector( - ".tab-group-overflow-count" - ); - let tabs = this.tabs; - let tabCount = tabs.length; - const overflowOffset = - this.hasActiveTab && gBrowser.selectedTab.splitview ? 2 : 1; - - if (tabCount > 1) { - this.toggleAttribute("hasmultipletabs", true); - } else { - overflowCountLabel.textContent = ""; - this.toggleAttribute("hasmultipletabs", false); - } - - gBrowser.tabLocalization - .formatValue("tab-group-overflow-count", { - tabCount: tabCount - overflowOffset, - }) - .then(result => (overflowCountLabel.textContent = result)); - gBrowser.tabLocalization - .formatValue("tab-group-overflow-count-tooltip", { - tabCount: tabCount - overflowOffset, - }) - .then(result => { - overflowCountLabel.setAttribute("tooltiptext", result); - overflowCountLabel.setAttribute("aria-description", result); - }); - } - /** * @returns {MozTabbrowserTab[]} */ get tabs() { - let childrenArray = Array.from(this.children); - for (let i = childrenArray.length - 1; i >= 0; i--) { - if (childrenArray[i].tagName == "tab-split-view-wrapper") { - childrenArray.splice(i, 1, ...childrenArray[i].tabs); - } - } - return childrenArray.filter(node => node.matches("tab")); + return Array.from(this.children).filter(node => node.matches("tab")); } /** @@ -637,8 +622,6 @@ if (previousTab.group === this) { this.#updateTabAriaHidden(previousTab); } - - this.#updateOverflowLabel(); } /** diff --git a/browser/components/tabbrowser/test/browser/tabs/browser_tab_splitview.js b/browser/components/tabbrowser/test/browser/tabs/browser_tab_splitview.js @@ -4,7 +4,7 @@ add_setup(async function () { await SpecialPowers.pushPrefEnv({ - set: [["sidebar.verticalTabs", true]], + set: [["sidebar.verticalTabs", false]], }); }); @@ -13,7 +13,6 @@ registerCleanupFunction(async function () { set: [ ["sidebar.verticalTabs", false], ["sidebar.revamp", false], - ["browser.tabs.splitView.enabled", false], ], }); }); @@ -52,43 +51,6 @@ function dragSplitter(deltaX, splitter) { AccessibilityUtils.resetEnv(); } -/** - * @param {MozTabbrowserTab} tab - * @param {function(splitViewMenuItem: Element, unsplitMenuItem: Element) => Promise<void>} callback - */ -const withTabMenu = async function (tab, callback) { - const tabContextMenu = document.getElementById("tabContextMenu"); - Assert.equal( - tabContextMenu.state, - "closed", - "context menu is initially closed" - ); - const contextMenuShown = BrowserTestUtils.waitForPopupEvent( - tabContextMenu, - "shown" - ); - - EventUtils.synthesizeMouseAtCenter( - tab, - { type: "contextmenu", button: 2 }, - window - ); - await contextMenuShown; - - const moveTabToNewSplitViewItem = document.getElementById( - "context_moveTabToSplitView" - ); - const unsplitTabItem = document.getElementById("context_separateSplitView"); - - let contextMenuHidden = BrowserTestUtils.waitForPopupEvent( - tabContextMenu, - "hidden" - ); - await callback(moveTabToNewSplitViewItem, unsplitTabItem); - tabContextMenu.hidePopup(); - return contextMenuHidden; -}; - add_task(async function test_splitViewCreateAndAddTabs() { let tab1 = BrowserTestUtils.addTab(gBrowser, "about:blank"); let tab2 = BrowserTestUtils.addTab(gBrowser, "about:blank"); @@ -277,222 +239,3 @@ add_task(async function test_resize_split_view_panels() { splitView.close(); }); - -add_task(async function test_tabGroupContextMenuMoveTabsToNewGroup() { - await SpecialPowers.pushPrefEnv({ - set: [["browser.tabs.splitView.enabled", true]], - }); - const tab1 = await addTabAndLoadBrowser(); - const tab2 = await addTabAndLoadBrowser(); - const tab3 = await addTabAndLoadBrowser(); - let tabs = [tab1, tab2, tab3]; - - // Click the first tab in our test split view to make sure the default tab at the - // start of the tab strip is deselected - EventUtils.synthesizeMouseAtCenter(tab1, {}); - - tabs.forEach(t => { - EventUtils.synthesizeMouseAtCenter( - t, - { ctrlKey: true, metaKey: true }, - window - ); - }); - - let tabToClick = tab3; - await withTabMenu( - tabToClick, - async (moveTabToNewSplitViewItem, unsplitTabItem) => { - await BrowserTestUtils.waitForMutationCondition( - moveTabToNewSplitViewItem, - { attributes: true }, - async () => { - return ( - !moveTabToNewSplitViewItem.hidden && - moveTabToNewSplitViewItem.disabled - ); - }, - "moveTabToNewSplitViewItem is visible and disabled" - ); - await BrowserTestUtils.waitForMutationCondition( - unsplitTabItem, - { attributes: true }, - async () => { - return unsplitTabItem.hidden; - }, - "unsplitTabItem is hidden" - ); - } - ); - - // Test opening split view from 2 non-consecutive tabs - let tabContainer = document.getElementById("tabbrowser-arrowscrollbox"); - let tab3Index = Array.from(tabContainer.children).indexOf(tab3); - EventUtils.synthesizeMouseAtCenter(tab3, {}); - tabToClick = tab3; - - [tabs[0], tabs[2]].forEach(t => { - gBrowser.addToMultiSelectedTabs(t); - ok(t.multiselected, "added tab to mutliselection"); - }); - - await withTabMenu( - tabToClick, - async (moveTabToNewSplitViewItem, unsplitTabItem) => { - await BrowserTestUtils.waitForMutationCondition( - moveTabToNewSplitViewItem, - { attributes: true }, - async () => { - return ( - !moveTabToNewSplitViewItem.hidden && - !moveTabToNewSplitViewItem.disabled - ); - }, - "moveTabToNewSplitViewItem is visible and not disabled" - ); - await BrowserTestUtils.waitForMutationCondition( - unsplitTabItem, - { attributes: true }, - async () => { - return unsplitTabItem.hidden; - }, - "unsplitTabItem is hidden" - ); - - moveTabToNewSplitViewItem.click(); - } - ); - - let splitview = tab1.splitview; - [tab1, tab3].forEach((t, idx) => { - Assert.equal(t.splitview, splitview, `tabs[${idx}] is in split view`); - }); - Assert.strictEqual( - Array.from(tabContainer.children).indexOf(splitview), - tab3Index - 1, - "Non-concecutive tabs have been added to split view and moved to active tab location" - ); - - splitview.unsplitTabs(); - - // Test adding consecutive tabs to a new split view - - EventUtils.synthesizeMouseAtCenter(tab1, {}); - - [tab1, tab2].forEach(t => { - EventUtils.synthesizeMouseAtCenter( - t, - { ctrlKey: true, metaKey: true }, - window - ); - }); - - tabToClick = tab2; - await withTabMenu( - tabToClick, - async (moveTabToNewSplitViewItem, unsplitTabItem) => { - await BrowserTestUtils.waitForMutationCondition( - moveTabToNewSplitViewItem, - { attributes: true }, - async () => { - return ( - !moveTabToNewSplitViewItem.hidden && - !moveTabToNewSplitViewItem.disabled - ); - }, - "moveTabToNewSplitViewItem is visible and not disabled" - ); - await BrowserTestUtils.waitForMutationCondition( - unsplitTabItem, - { attributes: true }, - async () => { - return unsplitTabItem.hidden; - }, - "unsplitTabItem is hidden" - ); - - moveTabToNewSplitViewItem.click(); - } - ); - - splitview = tab1.splitview; - - Assert.ok(tab1.splitview, "tab is in split view"); - [tab1, tab2].forEach((t, idx) => { - Assert.equal(t.splitview, splitview, `tabs[${idx}] is in split view`); - }); - - // Test unsplitting tabs using context menu - - await withTabMenu( - tabToClick, - async (moveTabToNewSplitViewItem, unsplitTabItem) => { - await BrowserTestUtils.waitForMutationCondition( - moveTabToNewSplitViewItem, - { attributes: true }, - async () => { - return moveTabToNewSplitViewItem.hidden; - }, - "moveTabToNewSplitViewItem is hidden" - ); - await BrowserTestUtils.waitForMutationCondition( - unsplitTabItem, - { attributes: true }, - async () => { - return !unsplitTabItem.hidden; - }, - "unsplitTabItem is visible" - ); - - unsplitTabItem.click(); - } - ); - - // Test adding split view with one tab and new tab - - tabToClick = tab1; - EventUtils.synthesizeMouseAtCenter(tab1, {}); - - await withTabMenu( - tabToClick, - async (moveTabToNewSplitViewItem, unsplitTabItem) => { - await BrowserTestUtils.waitForMutationCondition( - moveTabToNewSplitViewItem, - { attributes: true }, - async () => { - return ( - !moveTabToNewSplitViewItem.hidden && - !moveTabToNewSplitViewItem.disabled - ); - }, - "moveTabToNewSplitViewItem is visible and not disabled" - ); - await BrowserTestUtils.waitForMutationCondition( - unsplitTabItem, - { attributes: true }, - async () => { - return unsplitTabItem.hidden; - }, - "unsplitTabItem is hidden" - ); - - moveTabToNewSplitViewItem.click(); - } - ); - - splitview = tab1.splitview; - - Assert.equal(tab1.splitview, splitview, `tab1 is in split view`); - Assert.equal( - splitview.tabs[1], - gBrowser.selectedTab, - "New tab is active in split view" - ); - Assert.ok(!tab2.splitview, "tab2 is not in split view"); - Assert.ok(!tab3.splitview, "tab3 is not in split view"); - - splitview.close(); - while (gBrowser.tabs.length > 1) { - BrowserTestUtils.removeTab(gBrowser.tabs.at(-1)); - } -}); diff --git a/browser/locales/en-US/browser/tabbrowser.ftl b/browser/locales/en-US/browser/tabbrowser.ftl @@ -372,18 +372,4 @@ tab-group-context-open-saved-group-in-new-window = # Displayed within the tooltip on tabs inside of a tab split view tabbrowser-tab-label-tab-split-view = Split view -# Open a new tab next to the current tab and display their contents side by side -tab-context-add-split-view = - .label = Add Split View - .accesskey = t -# Display the two selected tabs' contents side by side -tab-context-open-in-split-view = - .label = Open in Split View - .accesskey = t -# Separate the two split view tabs and display the tabs and their contents as normal -tab-context-separate-split-view = - .label = Separate Split View - .accesskey = t -tab-context-badge-new = New - ## diff --git a/browser/themes/shared/tabbrowser/tabs.css b/browser/themes/shared/tabbrowser/tabs.css @@ -1045,37 +1045,6 @@ /* Split View */ -tab-group > tab-split-view-wrapper { - #tabbrowser-tabs[orient="vertical"] & { - margin-inline-start: var(--space-xxsmall); - margin-block: calc(var(--space-xsmall) * -1); - - .tabbrowser-tab:last-child { - .tab-group-line { - display: none; - } - } - } - - @container vertical-tabs-container (max-width: 210px) { - #tabbrowser-tabs[orient="vertical"] & { - margin-inline-start: 0; - - .tabbrowser-tab:last-child { - .tab-group-line { - display: flex; - } - } - } - } - - #tabbrowser-tabs[orient="horizontal"] & > .tab-split-view-container { - margin-inline: 0; - padding-block-end: 0; - padding-inline: 0; - } -} - #tabbrowser-tabs .tab-split-view-container { display: grid; grid-template-columns: 50% 50%; @@ -1264,8 +1233,7 @@ tab-group { } #tabbrowser-tabs[orient="vertical"] &[movingtabgroup][collapsed] > .tabbrowser-tab[visuallyselected], - #tabbrowser-tabs[orient="vertical"] &[collapsed] > .tabbrowser-tab:not([visuallyselected]), - #tabbrowser-tabs[orient="vertical"] &[collapsed] > tab-split-view-wrapper:not([hasactivetab]) { + #tabbrowser-tabs[orient="vertical"] &[collapsed] > .tabbrowser-tab:not([visuallyselected]) { display: none; }