commit 0ed18902804f7903e4899b88b6a67dd1c9eab612 parent 19a5938d18760916e8ed3db568e874520f7b6b31 Author: Sandor Molnar <smolnar@mozilla.com> Date: Thu, 4 Dec 2025 19:14:22 +0200 Revert "Bug 2000938 - Add follow-up updates to about:opentabs r=desktop-theme-reviewers,fxview-reviewers,tabbrowser-reviewers,fluent-reviewers,sfoster,bolsson,sclements" for causing bc failures @ browser_tab_splitview_about_opentabs.js This reverts commit 8f2a37eba55599ed5bfb4bef07a5129cae63a5c1. Diffstat:
22 files changed, 182 insertions(+), 706 deletions(-)
diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js @@ -713,7 +713,6 @@ async function gLazyFindCommand(cmd, ...args) { var gPageIcons = { "about:home": "chrome://branding/content/icon32.png", "about:newtab": "chrome://branding/content/icon32.png", - "about:opentabs": "chrome://branding/content/icon32.png", "about:welcome": "chrome://branding/content/icon32.png", "about:privatebrowsing": "chrome://browser/skin/privatebrowsing/favicon.svg", }; @@ -723,7 +722,6 @@ var gInitialPages = [ "about:home", "about:firefoxview", "about:newtab", - "about:opentabs", "about:privatebrowsing", "about:sessionrestore", "about:welcome", diff --git a/browser/base/content/browser.xhtml b/browser/base/content/browser.xhtml @@ -66,7 +66,6 @@ <link rel="localization" href="browser/genai.ftl"/> <link rel="localization" href="browser/identityCredentialNotification.ftl" /> <link rel="localization" href="browser/menubar.ftl"/> - <link rel="localization" href="browser/openTabs.ftl"/> <link rel="localization" href="browser/originControls.ftl"/> <link rel="localization" href="browser/panelUI.ftl"/> <link rel="localization" href="browser/places.ftl"/> diff --git a/browser/components/firefoxview/OpenTabs.sys.mjs b/browser/components/firefoxview/OpenTabs.sys.mjs @@ -30,8 +30,6 @@ const TAB_CHANGE_EVENTS = Object.freeze([ "TabOpen", "TabPinned", "TabUnpinned", - "SplitViewCreated", - "SplitViewRemoved", ]); const TAB_RECENCY_CHANGE_EVENTS = Object.freeze([ "activate", @@ -254,8 +252,6 @@ class OpenTabsTarget extends EventTarget { tabContainer.addEventListener("TabPinned", this); tabContainer.addEventListener("TabUnpinned", this); tabContainer.addEventListener("TabSelect", this); - tabContainer.addEventListener("SplitViewCreated", this); - tabContainer.addEventListener("SplitViewRemoved", this); win.addEventListener("activate", this); win.addEventListener("sizemodechange", this); @@ -288,8 +284,6 @@ class OpenTabsTarget extends EventTarget { tabContainer.removeEventListener("TabPinned", this); tabContainer.removeEventListener("TabSelect", this); tabContainer.removeEventListener("TabUnpinned", this); - tabContainer.removeEventListener("SplitViewCreated", this); - tabContainer.removeEventListener("SplitViewRemoved", this); win.removeEventListener("activate", this); win.removeEventListener("sizemodechange", this); diff --git a/browser/components/firefoxview/OpenTabsController.sys.mjs b/browser/components/firefoxview/OpenTabsController.sys.mjs @@ -1,173 +0,0 @@ -/* 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 http://mozilla.org/MPL/2.0/. */ - -const lazy = {}; - -ChromeUtils.defineESModuleGetters(lazy, { - ContextualIdentityService: - "resource://gre/modules/ContextualIdentityService.sys.mjs", - NewTabUtils: "resource://gre/modules/NewTabUtils.sys.mjs", -}); - -export class OpenTabsController { - /** - * Checks if a given tab is within a container (contextual identity) - * - * @param {MozTabbrowserTab[]} tab - * Tab to fetch container info on. - * @returns {object[]} - * Container object. - */ - #getContainerObj(tab) { - let userContextId = tab.getAttribute("usercontextid"); - let containerObj = null; - if (userContextId) { - containerObj = - lazy.ContextualIdentityService.getPublicIdentityFromId(userContextId); - } - return containerObj; - } - - /** - * Gets an array of tab indicators (if any) when normalizing for fxview-tab-list - * - * @param {MozTabbrowserTab[]} tab - * Tab to fetch container info on. - * @returns {Array[]} - * Array of named tab indicators - */ - #getIndicatorsForTab(tab) { - const url = tab.linkedBrowser?.currentURI?.spec || ""; - let tabIndicators = []; - let hasAttention = - (tab.pinned && - (tab.hasAttribute("attention") || tab.hasAttribute("titlechanged"))) || - (!tab.pinned && tab.hasAttribute("attention")); - - if (tab.pinned) { - tabIndicators.push("pinned"); - } - if (this.#getContainerObj(tab)) { - tabIndicators.push("container"); - } - if (hasAttention) { - tabIndicators.push("attention"); - } - if (tab.hasAttribute("soundplaying") && !tab.hasAttribute("muted")) { - tabIndicators.push("soundplaying"); - } - if (tab.hasAttribute("muted")) { - tabIndicators.push("muted"); - } - if (this.#checkIfPinnedNewTab(url)) { - tabIndicators.push("pinnedOnNewTab"); - } - - return tabIndicators; - } - - /** - * Check if a given url is pinned on the new tab page - * - * @param {string} url - * url to check - * @returns {boolean} - * is tabbed pinned on new tab page - */ - #checkIfPinnedNewTab(url) { - return url && lazy.NewTabUtils.pinnedLinks.isPinned({ url }); - } - - /** - * Gets the primary l10n id for a tab when normalizing for fxview-tab-list - * - * @param {boolean} isRecentBrowsing - * Whether the tabs are going to be displayed on the Recent Browsing page or not - * @param {Array[]} tabIndicators - * Array of tab indicators for the given tab - * @returns {string} - * L10n ID string - */ - getPrimaryL10nId(isRecentBrowsing, tabIndicators) { - let indicatorL10nId = null; - if (isRecentBrowsing) { - return indicatorL10nId; - } - if ( - tabIndicators?.includes("pinned") && - tabIndicators?.includes("bookmark") - ) { - indicatorL10nId = "firefoxview-opentabs-bookmarked-pinned-tab"; - } else if (tabIndicators?.includes("pinned")) { - indicatorL10nId = "firefoxview-opentabs-pinned-tab"; - } else if (tabIndicators?.includes("bookmark")) { - indicatorL10nId = "firefoxview-opentabs-bookmarked-tab"; - } - return indicatorL10nId; - } - - /** - * Gets the primary l10n args for a tab when normalizing for fxview-tab-list - * - * @param {MozTabbrowserTab[]} tab - * Tab to fetch container info on. - * @param {boolean} isRecentBrowsing - * Whether the tabs are going to be displayed on the Recent Browsing page or not - * @param {string} url - * URL for the given tab - * @returns {string} - * L10n ID args - */ - #getPrimaryL10nArgs(tab, isRecentBrowsing, url) { - return JSON.stringify({ tabTitle: tab.label, url }); - } - - /** - * Convert a list of tabs into the format expected by the fxview-tab-list - * component. - * - * @param {MozTabbrowserTab[]} tabs - * Tabs to format. - * @param {boolean} isRecentBrowsing - * Whether the tabs are going to be displayed on the Recent Browsing page or not - * @returns {object[]} - * Formatted objects. - */ - getTabListItems(tabs, isRecentBrowsing) { - let filtered = tabs?.filter(tab => !tab.closing && !tab.hidden); - - return filtered.map(tab => { - let tabIndicators = this.#getIndicatorsForTab(tab); - let containerObj = this.#getContainerObj(tab); - const url = tab?.linkedBrowser?.currentURI?.spec || ""; - return { - containerObj, - indicators: tabIndicators, - icon: tab.getAttribute("image"), - primaryL10nId: this.getPrimaryL10nId(isRecentBrowsing, tabIndicators), - primaryL10nArgs: this.#getPrimaryL10nArgs(tab, isRecentBrowsing, url), - secondaryL10nId: - isRecentBrowsing || (!isRecentBrowsing && !tab.pinned) - ? "fxviewtabrow-options-menu-button" - : null, - secondaryL10nArgs: - isRecentBrowsing || (!isRecentBrowsing && !tab.pinned) - ? JSON.stringify({ tabTitle: tab.label }) - : null, - tertiaryL10nId: - isRecentBrowsing || (!isRecentBrowsing && !tab.pinned) - ? "fxviewtabrow-close-tab-button" - : null, - tertiaryL10nArgs: - isRecentBrowsing || (!isRecentBrowsing && !tab.pinned) - ? JSON.stringify({ tabTitle: tab.label }) - : null, - tabElement: tab, - time: tab.lastSeenActive, - title: tab.label, - url, - }; - }); - } -} diff --git a/browser/components/firefoxview/opentabs.mjs b/browser/components/firefoxview/opentabs.mjs @@ -20,8 +20,10 @@ const lazy = {}; ChromeUtils.defineESModuleGetters(lazy, { BookmarkList: "resource://gre/modules/BookmarkList.sys.mjs", BrowserUtils: "resource://gre/modules/BrowserUtils.sys.mjs", + ContextualIdentityService: + "resource://gre/modules/ContextualIdentityService.sys.mjs", + NewTabUtils: "resource://gre/modules/NewTabUtils.sys.mjs", NonPrivateTabs: "resource:///modules/OpenTabs.sys.mjs", - OpenTabsController: "resource:///modules/OpenTabsController.sys.mjs", getTabsTargetForWindow: "resource:///modules/OpenTabs.sys.mjs", PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs", TabMetrics: "moz-src:///browser/components/tabbrowser/TabMetrics.sys.mjs", @@ -416,7 +418,6 @@ class OpenTabsInViewCard extends ViewPageContent { this.searchResults = null; this.showAll = false; this.cumulativeSearches = 0; - this.controller = new lazy.OpenTabsController(this, {}); } static queries = { @@ -565,7 +566,7 @@ class OpenTabsInViewCard extends ViewPageContent { tertiaryActionClass="dismiss-button" .maxTabsLength=${this.getMaxTabsLength()} .tabItems=${this.searchResults || - this.controller.getTabListItems(this.tabs, this.recentBrowsing)} + getTabListItems(this.tabs, this.recentBrowsing)} .searchQuery=${this.searchQuery} .pinnedTabsGridView=${!this.recentBrowsing} ><view-opentabs-contextmenu slot="menu"></view-opentabs-contextmenu> @@ -614,10 +615,7 @@ class OpenTabsInViewCard extends ViewPageContent { updateSearchResults() { this.searchResults = this.searchQuery - ? searchTabList( - this.searchQuery, - this.controller.getTabListItems(this.tabs) - ) + ? searchTabList(this.searchQuery, getTabListItems(this.tabs)) : null; } @@ -635,7 +633,7 @@ class OpenTabsInViewCard extends ViewPageContent { if (!isBookmark && row.indicators.includes("bookmark")) { row.indicators = row.indicators.filter(i => i !== "bookmark"); } - row.primaryL10nId = this.controller.getPrimaryL10nId( + row.primaryL10nId = getPrimaryL10nId( this.isRecentBrowsing, row.indicators ); @@ -885,3 +883,161 @@ class OpenTabsContextMenu extends MozLitElement { } } customElements.define("view-opentabs-contextmenu", OpenTabsContextMenu); + +/** + * Checks if a given tab is within a container (contextual identity) + * + * @param {MozTabbrowserTab[]} tab + * Tab to fetch container info on. + * @returns {object[]} + * Container object. + */ +function getContainerObj(tab) { + let userContextId = tab.getAttribute("usercontextid"); + let containerObj = null; + if (userContextId) { + containerObj = + lazy.ContextualIdentityService.getPublicIdentityFromId(userContextId); + } + return containerObj; +} + +/** + * Gets an array of tab indicators (if any) when normalizing for fxview-tab-list + * + * @param {MozTabbrowserTab[]} tab + * Tab to fetch container info on. + * @returns {Array[]} + * Array of named tab indicators + */ +function getIndicatorsForTab(tab) { + const url = tab.linkedBrowser?.currentURI?.spec || ""; + let tabIndicators = []; + let hasAttention = + (tab.pinned && + (tab.hasAttribute("attention") || tab.hasAttribute("titlechanged"))) || + (!tab.pinned && tab.hasAttribute("attention")); + + if (tab.pinned) { + tabIndicators.push("pinned"); + } + if (getContainerObj(tab)) { + tabIndicators.push("container"); + } + if (hasAttention) { + tabIndicators.push("attention"); + } + if (tab.hasAttribute("soundplaying") && !tab.hasAttribute("muted")) { + tabIndicators.push("soundplaying"); + } + if (tab.hasAttribute("muted")) { + tabIndicators.push("muted"); + } + if (checkIfPinnedNewTab(url)) { + tabIndicators.push("pinnedOnNewTab"); + } + + return tabIndicators; +} +/** + * Gets the primary l10n id for a tab when normalizing for fxview-tab-list + * + * @param {boolean} isRecentBrowsing + * Whether the tabs are going to be displayed on the Recent Browsing page or not + * @param {Array[]} tabIndicators + * Array of tab indicators for the given tab + * @returns {string} + * L10n ID string + */ +function getPrimaryL10nId(isRecentBrowsing, tabIndicators) { + let indicatorL10nId = null; + if (!isRecentBrowsing) { + if ( + tabIndicators?.includes("pinned") && + tabIndicators?.includes("bookmark") + ) { + indicatorL10nId = "firefoxview-opentabs-bookmarked-pinned-tab"; + } else if (tabIndicators?.includes("pinned")) { + indicatorL10nId = "firefoxview-opentabs-pinned-tab"; + } else if (tabIndicators?.includes("bookmark")) { + indicatorL10nId = "firefoxview-opentabs-bookmarked-tab"; + } + } + return indicatorL10nId; +} + +/** + * Gets the primary l10n args for a tab when normalizing for fxview-tab-list + * + * @param {MozTabbrowserTab[]} tab + * Tab to fetch container info on. + * @param {boolean} isRecentBrowsing + * Whether the tabs are going to be displayed on the Recent Browsing page or not + * @param {string} url + * URL for the given tab + * @returns {string} + * L10n ID args + */ +function getPrimaryL10nArgs(tab, isRecentBrowsing, url) { + return JSON.stringify({ tabTitle: tab.label, url }); +} + +/** + * Check if a given url is pinned on the new tab page + * + * @param {string} url + * url to check + * @returns {boolean} + * is tabbed pinned on new tab page + */ +function checkIfPinnedNewTab(url) { + return url && lazy.NewTabUtils.pinnedLinks.isPinned({ url }); +} + +/** + * Convert a list of tabs into the format expected by the fxview-tab-list + * component. + * + * @param {MozTabbrowserTab[]} tabs + * Tabs to format. + * @param {boolean} isRecentBrowsing + * Whether the tabs are going to be displayed on the Recent Browsing page or not + * @returns {object[]} + * Formatted objects. + */ +function getTabListItems(tabs, isRecentBrowsing) { + let filtered = tabs?.filter(tab => !tab.closing && !tab.hidden); + + return filtered.map(tab => { + let tabIndicators = getIndicatorsForTab(tab); + let containerObj = getContainerObj(tab); + const url = tab?.linkedBrowser?.currentURI?.spec || ""; + return { + containerObj, + indicators: tabIndicators, + icon: tab.getAttribute("image"), + primaryL10nId: getPrimaryL10nId(isRecentBrowsing, tabIndicators), + primaryL10nArgs: getPrimaryL10nArgs(tab, isRecentBrowsing, url), + secondaryL10nId: + isRecentBrowsing || (!isRecentBrowsing && !tab.pinned) + ? "fxviewtabrow-options-menu-button" + : null, + secondaryL10nArgs: + isRecentBrowsing || (!isRecentBrowsing && !tab.pinned) + ? JSON.stringify({ tabTitle: tab.label }) + : null, + tertiaryL10nId: + isRecentBrowsing || (!isRecentBrowsing && !tab.pinned) + ? "fxviewtabrow-close-tab-button" + : null, + tertiaryL10nArgs: + isRecentBrowsing || (!isRecentBrowsing && !tab.pinned) + ? JSON.stringify({ tabTitle: tab.label }) + : null, + tabElement: tab, + time: tab.lastSeenActive, + title: tab.label, + url, + }; + }); +} diff --git a/browser/components/sidebar/sidebar-tab-list.mjs b/browser/components/sidebar/sidebar-tab-list.mjs @@ -169,8 +169,6 @@ export class SidebarTabList extends FxviewTabListBase { if ((this.searchQuery || this.sortOption == "lastvisited") && i == 0) { // Make the first row focusable if there is no header. tabIndex = 0; - } else if (!this.searchQuery) { - tabIndex = 0; } return html` <sidebar-tab-row @@ -184,7 +182,6 @@ export class SidebarTabList extends FxviewTabListBase { .favicon=${tabItem.icon} .guid=${tabItem.guid} .hasPopup=${this.hasPopup} - .indicators=${tabItem.indicators} .primaryL10nArgs=${ifDefined(tabItem.primaryL10nArgs)} .primaryL10nId=${tabItem.primaryL10nId} role="listitem" @@ -222,7 +219,6 @@ export class SidebarTabRow extends FxviewTabRowBase { static properties = { guid: { type: String }, selected: { type: Boolean, reflect: true }, - indicators: { type: Array }, }; /** @@ -264,12 +260,6 @@ export class SidebarTabRow extends FxviewTabRowBase { class=${classMap({ "fxview-tab-row-main": true, "no-action-button-row": this.canClose === false, - muted: this.indicators?.includes("muted"), - attention: this.indicators?.includes("attention"), - soundplaying: this.indicators?.includes("soundplaying"), - "activemedia-blocked": this.indicators?.includes( - "activemedia-blocked" - ), })} disabled=${this.closeRequested} data-l10n-args=${ifDefined(this.primaryL10nArgs)} diff --git a/browser/components/sidebar/sidebar-tab-row.css b/browser/components/sidebar/sidebar-tab-row.css @@ -42,60 +42,3 @@ --button-size-icon: 24px; --button-min-height: 24px; } - -.attention > #fxview-tab-row-favicon::after { - background-image: radial-gradient(circle, var(--attention-dot-color), var(--attention-dot-color) 2px, transparent 2px); - /* stylelint-disable-next-line stylelint-plugin-mozilla/use-size-tokens */ - height: 4px; - width: 100%; - inset-block-start: var(--icon-size-medium); -} - -.fxview-tab-row-favicon::after { - display: block; - content: ""; - background-size: var(--size-item-xsmall); - background-position: center; - background-repeat: no-repeat; - position: relative; - height: var(--size-item-xsmall); - width: var(--size-item-xsmall); - -moz-context-properties: fill, stroke; - fill: currentColor; - /* stylelint-disable-next-line stylelint-plugin-mozilla/no-non-semantic-token-usage */ - stroke: var(--background-color-box); - - .fxview-tab-row-main.attention > & { - background-image: radial-gradient(circle, var(--attention-dot-color), var(--attention-dot-color) 2px, transparent 2px); - /* stylelint-disable-next-line stylelint-plugin-mozilla/use-size-tokens */ - height: 4px; - width: 100%; - inset-block-start: var(--icon-size-medium); - } -} - -.fxview-tab-row-main:is(.muted, .soundplaying, .activemedia-blocked):not(.attention) .fxview-tab-row-favicon::after { - /* inset-inline-start set to half of the favicon - width to place it horizontally centered */ - /* stylelint-disable-next-line stylelint-plugin-mozilla/use-size-tokens */ - inset-inline-start: 8px; - /* inset-block-start set to display 6px above - the top of the favicon */ - /* stylelint-disable-next-line stylelint-plugin-mozilla/use-size-tokens */ - inset-block-start: -6px; - background-color: var(--background-color-box); - padding: 1px; - border-radius: var(--border-radius-circle); -} - -.fxview-tab-row-main.muted .fxview-tab-row-favicon::after { - background-image: url("chrome://global/skin/media/audio-muted.svg"); -} - -.fxview-tab-row-main.soundplaying .fxview-tab-row-favicon::after { - background-image: url("chrome://browser/skin/tabbrowser/tab-audio-playing-small.svg"); -} - -.fxview-tab-row-main.activemedia-blocked .fxview-tab-row-favicon::after { - background-image: url("chrome://browser/skin/tabbrowser/tab-audio-blocked-small.svg"); -} diff --git a/browser/components/tabbrowser/content/opentabs-splitview.css b/browser/components/tabbrowser/content/opentabs-splitview.css @@ -1,11 +0,0 @@ -/* 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 http://mozilla.org/MPL/2.0/. */ - -@import url("chrome://global/skin/in-content/common.css"); - -moz-card { - --card-padding: var(--space-medium); - --card-border-radius: var(--border-radius-large); - margin-block-end: var(--space-xxlarge); -} diff --git a/browser/components/tabbrowser/content/opentabs-splitview.mjs b/browser/components/tabbrowser/content/opentabs-splitview.mjs @@ -1,143 +0,0 @@ -/* 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 http://mozilla.org/MPL/2.0/. */ - -import { html } from "chrome://global/content/vendor/lit.all.mjs"; -import { MozLitElement } from "chrome://global/content/lit-utils.mjs"; - -const lazy = {}; -const BROWSER_NEW_TAB_URL = "about:newtab"; -const BROWSER_OPEN_TABS_URL = "about:opentabs"; - -ChromeUtils.defineESModuleGetters(lazy, { - OpenTabsController: "resource:///modules/OpenTabsController.sys.mjs", - NonPrivateTabs: "resource:///modules/OpenTabs.sys.mjs", - getTabsTargetForWindow: "resource:///modules/OpenTabs.sys.mjs", - PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs", -}); - -/** - * A collection of open, unpinned, unsplit tabs for the current by window. - */ -class OpenTabsInSplitView extends MozLitElement { - currentWindow = null; - openTabsTarget = null; - - constructor() { - super(); - this.currentWindow = - this.ownerGlobal.top.browsingContext.embedderWindowGlobal.browsingContext.window; - if (lazy.PrivateBrowsingUtils.isWindowPrivate(this.currentWindow)) { - this.openTabsTarget = lazy.getTabsTargetForWindow(this.currentWindow); - } else { - this.openTabsTarget = lazy.NonPrivateTabs; - } - this.controller = new lazy.OpenTabsController(this, { - component: "splitview", - }); - } - - static queries = { - sidebarTabList: "sidebar-tab-list", - }; - - connectedCallback() { - super.connectedCallback(); - this.addListeners(true); - this.currentWindow.addEventListener("TabSelect", this); - } - - disconnectedCallback() { - super.disconnectedCallback(); - this.removeListeners(); - this.currentWindow.removeEventListener("TabSelect", this); - } - - addListeners(skipUpdate) { - this.openTabsTarget.addEventListener("TabChange", this); - if (!skipUpdate) { - this.requestUpdate(); - } - } - - removeListeners() { - this.openTabsTarget.removeEventListener("TabChange", this); - } - - handleEvent(e) { - switch (e.type) { - case "TabChange": - this.requestUpdate(); - break; - case "TabSelect": - if (this.currentSplitView) { - this.addListeners(); - } else { - this.removeListeners(); - } - } - } - - getWindow() { - return window.browsingContext.embedderWindowGlobal.browsingContext.window; - } - - get currentSplitView() { - const { gBrowser } = this.getWindow(); - return gBrowser.selectedTab.splitview; - } - - onTabListRowClick(event) { - const { gBrowser } = this.getWindow(); - const tab = event.originalTarget.tabElement; - if (this.currentSplitView) { - this.currentSplitView.replaceTab(gBrowser.selectedTab, tab); - } - } - - get nonSplitViewUnpinnedTabs() { - const { gBrowser } = this.getWindow(); - return gBrowser.tabs.filter(tab => { - return ( - !tab.hidden && - !tab.pinned && - !tab.splitview && - tab?.linkedBrowser?.currentURI?.spec !== BROWSER_OPEN_TABS_URL - ); - }); - } - - render() { - const { gBrowser } = this.getWindow(); - let tabs = this.nonSplitViewUnpinnedTabs; - if ( - !tabs.length || - (gBrowser.selectedTab.linkedBrowser.currentURI.spec === - BROWSER_OPEN_TABS_URL && - !this.currentSplitView) - ) { - // If there are no unpinned, unsplit tabs to display or about:opentabs - // is opened outside of a split view, open about:newtab instead - this.getWindow().openTrustedLinkIn(BROWSER_NEW_TAB_URL, "current"); - } - return html` - <link - rel="stylesheet" - href="chrome://browser/content/tabbrowser/opentabs-splitview.css" - /> - <link - rel="stylesheet" - href="chrome://browser/content/firefoxview/firefoxview.css" - /> - <moz-card> - <sidebar-tab-list - maxTabsLength="-1" - .tabItems=${this.controller.getTabListItems(tabs)} - @fxview-tab-list-primary-action=${this.onTabListRowClick} - > - </sidebar-tab-list> - </moz-card> - `; - } -} -customElements.define("splitview-opentabs", OpenTabsInSplitView); diff --git a/browser/components/tabbrowser/content/opentabs.css b/browser/components/tabbrowser/content/opentabs.css @@ -6,39 +6,17 @@ :root { height: 100%; - --splitview-opentabs-card-width: 358px; } body { background: no-repeat light-dark(linear-gradient(#f0ebfd, #f7ebeb), linear-gradient(#332a50, #3f2a2f)); - background-attachment: fixed; display: flex; - flex-direction: column; - align-items: center; + justify-content: center; height: 100%; } -.sticky-header { - background: linear-gradient(to bottom, light-dark(#f0ebfd, #332a50) 0%, light-dark(#f0ebfd, #332a50) 95%, transparent 100%); - position: sticky; - top: 0; - z-index: 1; - display: flex; - flex-direction: column; - width: 100%; - align-items: center; -} - h3 { color: var(--text-color); /* stylelint-disable-next-line stylelint-plugin-mozilla/use-space-tokens */ - margin-block-start: calc(var(--size-item-large) * 3.375); - height: min-content; -} - -splitview-opentabs { - /* stylelint-disable-next-line stylelint-plugin-mozilla/use-size-tokens */ - width: var(--splitview-opentabs-card-width); - /* stylelint-disable-next-line stylelint-plugin-mozilla/use-size-tokens */ - max-width: var(--splitview-opentabs-card-width); + margin-block-start: calc(var(--size-item-large) * 5); } diff --git a/browser/components/tabbrowser/content/opentabs.html b/browser/components/tabbrowser/content/opentabs.html @@ -8,39 +8,17 @@ <meta charset="utf-8" /> <meta http-equiv="Content-Security-Policy" - content="default-src resource: chrome:; object-src 'none'; img-src chrome:;" + content="default-src resource: chrome:; object-src 'none'; img-src data: chrome:;" /> <meta name="color-scheme" content="light dark" /> - <link - rel="icon" - type="image/png" - id="favicon" - href="chrome://branding/content/icon32.png" - /> - <link rel="localization" href="browser/firefoxView.ftl" /> - <link rel="localization" href="browser/openTabs.ftl" /> - <title data-l10n-id="opentabs-page-title"></title> - <link - rel="stylesheet" - href="chrome://browser/content/sidebar/sidebar.css" - /> + <title>Open Tabs</title> <link rel="stylesheet" href="chrome://browser/content/tabbrowser/opentabs.css" /> - <script - type="module" - src="chrome://browser/content/tabbrowser/opentabs-splitview.mjs" - ></script> - <script - type="module" - src="chrome://browser/content/sidebar/sidebar-tab-list.mjs" - ></script> </head> <body> - <div class="sticky-header"> - <h3 data-l10n-id="opentabs-page-title"></h3> - </div> - <splitview-opentabs></splitview-opentabs> + <h3>Choose a tab to add to split view</h3> + <!-- TODO: Bug 2000938 - Add oepn tabs list --> </body> </html> diff --git a/browser/components/tabbrowser/content/split-view-footer.js b/browser/components/tabbrowser/content/split-view-footer.js @@ -161,7 +161,6 @@ * @param {nsIURI} uri */ #updateUri(uri) { - this.hidden = uri.specIgnoringRef === "about:opentabs"; this.#uri = uri; if (this.uriElement) { this.#updateUriElement(); diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/components/tabbrowser/content/tabbrowser.js @@ -3238,7 +3238,7 @@ return null; } - this.tabContainer.dispatchEvent( + this.dispatchEvent( new CustomEvent("SplitViewCreated", { bubbles: true, }) @@ -3247,7 +3247,7 @@ } /** - * Removes all tabs from a split view wrapper. This also removes the split view wrapper component + * Removes a tab from a split view wrapper. This also removes the split view wrapper component * * @param {MozTabSplitViewWrapper} [splitView] * The split view to remove. @@ -3265,7 +3265,6 @@ ) ); } - splitview.remove(); } @@ -3303,14 +3302,12 @@ */ #insertSplitViewFooter(tab) { const panelEl = document.getElementById(tab.linkedPanel); - if (panelEl?.querySelector("split-view-footer")) { + if (panelEl.querySelector("split-view-footer")) { return; } - if (panelEl) { - const footer = document.createXULElement("split-view-footer"); - footer.setTab(tab); - panelEl.appendChild(footer); - } + const footer = document.createXULElement("split-view-footer"); + footer.setTab(tab); + panelEl.appendChild(footer); } openSplitViewMenu(anchorElement) { @@ -10264,7 +10261,7 @@ var TabContextMenu = { let newTab = null; if (this.contextTabs.length < 2) { // Open new tab to split with context tab - newTab = gBrowser.addTrustedTab("about:opentabs"); + newTab = gBrowser.addTrustedTab(BROWSER_NEW_TAB_URL); tabsToAdd = [this.contextTabs[0], newTab]; } diff --git a/browser/components/tabbrowser/content/tabsplitview.js b/browser/components/tabbrowser/content/tabsplitview.js @@ -73,10 +73,6 @@ this.#observeTabChanges(); - if (this.hasActiveTab) { - this.#activate(); - } - if (this._initialized) { return; } @@ -93,10 +89,9 @@ this.#tabChangeObserver?.disconnect(); this.ownerGlobal.removeEventListener("TabSelect", this); this.#deactivate(); - this.container.dispatchEvent( + this.dispatchEvent( new CustomEvent("SplitViewRemoved", { bubbles: true, - composed: true, }) ); } @@ -205,15 +200,6 @@ } /** - * Replace a tab in the split view with another tab - */ - replaceTab(tabToReplace, newTab) { - this.#tabs = this.#tabs.filter(tab => tab != tabToReplace); - this.addTabs([newTab]); - gBrowser.removeTab(tabToReplace); - } - - /** * Reverse order of the tabs in the split view wrapper. */ reverseTabs() { diff --git a/browser/components/tabbrowser/jar.mn b/browser/components/tabbrowser/jar.mn @@ -9,8 +9,6 @@ browser.jar: content/browser/tabbrowser/drag-and-drop.js (content/drag-and-drop.js) content/browser/tabbrowser/opentabs.css (content/opentabs.css) content/browser/tabbrowser/opentabs.html (content/opentabs.html) - content/browser/tabbrowser/opentabs-splitview.css (content/opentabs-splitview.css) - content/browser/tabbrowser/opentabs-splitview.mjs (content/opentabs-splitview.mjs) content/browser/tabbrowser/tab-stacking.js (content/tab-stacking.js) content/browser/tabbrowser/split-view-footer.js (content/split-view-footer.js) content/browser/tabbrowser/tab.js (content/tab.js) diff --git a/browser/components/tabbrowser/test/browser/tabs/browser.toml b/browser/components/tabbrowser/test/browser/tabs/browser.toml @@ -623,8 +623,6 @@ tags = "vertical-tabs" ["browser_tab_splitview.js"] -["browser_tab_splitview_about_opentabs.js"] - ["browser_tab_splitview_contextmenu.js"] skip-if = [ "os == 'linux' && os_version == '24.04' && arch == 'x86_64' && display == 'x11' && opt", # Bug 1996471 diff --git a/browser/components/tabbrowser/test/browser/tabs/browser_tab_splitview_about_opentabs.js b/browser/components/tabbrowser/test/browser/tabs/browser_tab_splitview_about_opentabs.js @@ -1,199 +0,0 @@ -/* 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 http://mozilla.org/MPL/2.0/. */ - -add_setup(async function () { - await SpecialPowers.pushPrefEnv({ - set: [["browser.tabs.splitView.enabled", true]], - }); -}); - -registerCleanupFunction(async function () { - await SpecialPowers.pushPrefEnv({ - set: [["browser.tabs.splitView.enabled", false]], - }); -}); - -/** - * Synthesize a key press and wait for an element to be focused. - * - * @param {Element} element - * @param {string} keyCode - * @param {ChromeWindow} contentWindow - */ -async function focusWithKeyboard(element, keyCode, contentWindow) { - await SimpleTest.promiseFocus(contentWindow); - const focused = BrowserTestUtils.waitForEvent( - element, - "focus", - contentWindow - ); - EventUtils.synthesizeKey(keyCode, {}, contentWindow); - await focused; -} - -/** - * @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" - ); - - let contextMenuHidden = BrowserTestUtils.waitForPopupEvent( - tabContextMenu, - "hidden" - ); - await callback(moveTabToNewSplitViewItem); - tabContextMenu.hidePopup(); - info("Hide popup"); - return await contextMenuHidden; -}; - -add_task(async function test_contextMenuMoveTabsToNewSplitView() { - const tab1 = await addTab(); - const tab2 = await addTab(); - const tab3 = await addTab(); - - // 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, {}); - - // Test adding split view with one tab and new tab - - let tabToClick = tab1; - EventUtils.synthesizeMouseAtCenter(tab1, {}); - let openTabsPromise = BrowserTestUtils.waitForNewTab( - gBrowser, - "about:opentabs" - ); - let tabContainer = document.getElementById("tabbrowser-tabs"); - let splitViewCreated = BrowserTestUtils.waitForEvent( - tabContainer, - "SplitViewCreated" - ); - await withTabMenu(tabToClick, async moveTabToNewSplitViewItem => { - await BrowserTestUtils.waitForMutationCondition( - moveTabToNewSplitViewItem, - { attributes: true }, - () => - !moveTabToNewSplitViewItem.hidden && - !moveTabToNewSplitViewItem.disabled, - "moveTabToNewSplitViewItem is visible and not disabled" - ); - Assert.ok( - !moveTabToNewSplitViewItem.hidden && !moveTabToNewSplitViewItem.disabled, - "moveTabToNewSplitViewItem is visible and not disabled" - ); - - info("Click menu option to add new split view"); - moveTabToNewSplitViewItem.click(); - await splitViewCreated; - await openTabsPromise; - info("about:opentabs has been opened"); - Assert.equal( - gBrowser.selectedTab.linkedBrowser.currentURI.spec, - "about:opentabs", - "about:opentabs is active in split view" - ); - }); - - let splitview = tab1.splitview; - - Assert.equal(tab1.splitview, splitview, `tab1 is in split view`); - let aboutOpenTabsDocument = - gBrowser.selectedTab.linkedBrowser.contentDocument; - let openTabsComponent = await TestUtils.waitForCondition( - () => aboutOpenTabsDocument.querySelector("splitview-opentabs"), - "Open tabs component rendered" - ); - await TestUtils.waitForCondition( - () => openTabsComponent.nonSplitViewUnpinnedTabs?.length, - "Open tabs component has rendered items" - ); - - Assert.equal( - openTabsComponent.nonSplitViewUnpinnedTabs.length, - 3, - "3 tabs are shown in the open tabs list" - ); - - Assert.ok( - openTabsComponent.sidebarTabList.rowEls[1].__url === - tab2.linkedBrowser.currentURI.spec && - openTabsComponent.sidebarTabList.rowEls[2].__url === - tab3.linkedBrowser.currentURI.spec, - "tab2 and tab3 are listed on the about:opentabs page" - ); - - let aboutOpenTabsWindow = document.querySelector( - "hbox.deck-selected.split-view-panel browser" - ).contentWindow; - openTabsComponent.sidebarTabList.rowEls[0].focus(); - - info("Focus the next row."); - await focusWithKeyboard( - openTabsComponent.sidebarTabList.rowEls[1], - "KEY_ArrowDown", - aboutOpenTabsWindow - ); - - info("Focus the previous row."); - await focusWithKeyboard( - openTabsComponent.sidebarTabList.rowEls[0], - "KEY_ArrowUp", - aboutOpenTabsWindow - ); - - info("Focus the next row."); - await focusWithKeyboard( - openTabsComponent.sidebarTabList.rowEls[1], - "KEY_ArrowDown", - aboutOpenTabsWindow - ); - - info("Focus the next row."); - await focusWithKeyboard( - openTabsComponent.sidebarTabList.rowEls[2], - "KEY_ArrowDown", - aboutOpenTabsWindow - ); - - info("Focus the previous row."); - await focusWithKeyboard( - openTabsComponent.sidebarTabList.rowEls[1], - "KEY_ArrowUp", - aboutOpenTabsWindow - ); - - info("Open the focused link."); - EventUtils.synthesizeKey("KEY_Enter", {}, aboutOpenTabsWindow); - await TestUtils.waitForCondition( - () => splitview.tabs.includes(tab2), - "We've opened tab2 in the split view" - ); - - splitview.unsplitTabs(); - while (gBrowser.tabs.length > 1) { - BrowserTestUtils.removeTab(gBrowser.tabs.at(-1)); - } -}); diff --git a/browser/locales/en-US/browser/openTabs.ftl b/browser/locales/en-US/browser/openTabs.ftl @@ -1,5 +0,0 @@ -# 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 http://mozilla.org/MPL/2.0/. - -opentabs-page-title = Choose a tab to add to split view diff --git a/browser/themes/shared/tabbrowser/content-area.css b/browser/themes/shared/tabbrowser/content-area.css @@ -206,10 +206,6 @@ /* Display split view footer within inactive panels. */ .split-view-panel:not(.deck-selected) > split-view-footer { display: inherit; - - &[hidden] { - display: none; - } } } } diff --git a/toolkit/content/widgets/tabbox.js b/toolkit/content/widgets/tabbox.js @@ -284,19 +284,20 @@ handleEvent(e) { const browser = e.currentTarget; + const tabbrowser = browser.getTabBrowser(); switch (e.type) { case "click": case "focus": { - const tab = gBrowser.getTabForBrowser(browser); + const tab = tabbrowser.getTabForBrowser(browser); const tabstrip = this.tabbox.tabs; tabstrip.selectedItem = tab; break; } case "mouseover": - gBrowser.appendStatusPanel(browser); + tabbrowser.appendStatusPanel(browser); break; case "mouseout": - gBrowser.appendStatusPanel(); + tabbrowser.appendStatusPanel(); break; } } diff --git a/tools/@types/generated/lib.gecko.modules.d.ts b/tools/@types/generated/lib.gecko.modules.d.ts @@ -390,7 +390,6 @@ export interface Modules { "resource:///modules/MigrationUtils.sys.mjs": typeof import("resource:///modules/MigrationUtils.sys.mjs"), "resource:///modules/MigratorBase.sys.mjs": typeof import("resource:///modules/MigratorBase.sys.mjs"), "resource:///modules/OpenTabs.sys.mjs": typeof import("resource:///modules/OpenTabs.sys.mjs"), - "resource:///modules/OpenTabsController.sys.mjs": typeof import("resource:///modules/OpenTabs.sys.mjs"), "resource:///modules/PageActions.sys.mjs": typeof import("resource:///modules/PageActions.sys.mjs"), "resource:///modules/PartnerLinkAttribution.sys.mjs": typeof import("resource:///modules/PartnerLinkAttribution.sys.mjs"), "resource:///modules/PermissionUI.sys.mjs": typeof import("resource:///modules/PermissionUI.sys.mjs"), diff --git a/tools/@types/generated/tspaths.json b/tools/@types/generated/tspaths.json @@ -1046,9 +1046,6 @@ "resource:///modules/OpenTabs.sys.mjs": [ "browser/components/firefoxview/OpenTabs.sys.mjs" ], - "resource:///modules/OpenTabsController.sys.mjs": [ - "browser/components/firefoxview/OpenTabsController.sys.mjs" - ], "resource:///modules/PageActions.sys.mjs": [ "browser/modules/PageActions.sys.mjs" ],