diff --git a/src/browser/base/zen-components/ZenFolders.mjs b/src/browser/base/zen-components/ZenFolders.mjs index 42fcaad54..b4ec367e5 100644 --- a/src/browser/base/zen-components/ZenFolders.mjs +++ b/src/browser/base/zen-components/ZenFolders.mjs @@ -25,6 +25,38 @@ gBrowser.ungroupTab(tab); } } + + handleTabPin(tab) { + const group = tab.group; + if (!group) { + return false; + } + if (group.hasAttribute("split-view-group")) { + for (const tab of group.tabs) { + tab.setAttribute("pinned", "true"); + } + gBrowser.verticalPinnedTabsContainer.insertBefore(group, gBrowser.verticalPinnedTabsContainer.lastChild) + gBrowser.tabContainer._invalidateCachedTabs(); + return true; + } + return false; + } + + handleTabUnpin(tab) { + const group = tab.group; + if (!group) { + return false; + } + if (group.hasAttribute("split-view-group")) { + for (const tab of group.tabs) { + tab.removeAttribute("pinned"); + } + ZenWorkspaces.activeWorkspaceStrip.prepend(group); + gBrowser.tabContainer._invalidateCachedTabs(); + return true; + } + return false; + } } window.gZenFolders = new ZenFolders(); diff --git a/src/browser/base/zen-components/ZenViewSplitter.mjs b/src/browser/base/zen-components/ZenViewSplitter.mjs index 5aa7c9c8a..e45b3eda6 100644 --- a/src/browser/base/zen-components/ZenViewSplitter.mjs +++ b/src/browser/base/zen-components/ZenViewSplitter.mjs @@ -706,6 +706,8 @@ class ZenViewSplitter extends ZenDOMOperatedFeature { * @param {string} gridType - The type of grid layout. */ splitTabs(tabs, gridType) { + const firstisPinned = tabs[0].pinned; + tabs = tabs.filter((t) => t.pinned === firstisPinned); if (tabs.length < 2) { return; } @@ -1377,6 +1379,7 @@ class ZenViewSplitter extends ZenDOMOperatedFeature { const group = gBrowser.addTabGroup(tabs, { label: '', showCreateUI: false, + insertBefore: tabs[0], }); group.setAttribute('split-view-group', true); diff --git a/src/browser/components/tabbrowser/content/tabbrowser-js.patch b/src/browser/components/tabbrowser/content/tabbrowser-js.patch index 618746ef1..2f2f5c08f 100644 --- a/src/browser/components/tabbrowser/content/tabbrowser-js.patch +++ b/src/browser/components/tabbrowser/content/tabbrowser-js.patch @@ -1,5 +1,5 @@ diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/components/tabbrowser/content/tabbrowser.js -index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7472158f2 100644 +index 628aa6596627c85efe361fc1ece8fd58f7ee653e..287ff24e0fee10f435fd33914756d9e94798f4f7 100644 --- a/browser/components/tabbrowser/content/tabbrowser.js +++ b/browser/components/tabbrowser/content/tabbrowser.js @@ -412,11 +412,50 @@ @@ -55,25 +55,42 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 } return i; } -@@ -814,7 +853,7 @@ - this.ungroupTab(aTab); - if (this.tabContainer.verticalMode) { +@@ -811,12 +850,13 @@ + } + + this.showTab(aTab); +- this.ungroupTab(aTab); +- if (this.tabContainer.verticalMode) { ++ const handled = gZenFolders.handleTabPin(aTab); ++ if (!handled) this.ungroupTab(aTab); ++ if (this.tabContainer.verticalMode && !handled) { this._handleTabMove(aTab, () => - this.verticalPinnedTabsContainer.appendChild(aTab) + aTab.hasAttribute("zen-essential") ? document.getElementById("zen-essentials-container").appendChild(aTab) : this.verticalPinnedTabsContainer.insertBefore(aTab, this.verticalPinnedTabsContainer.lastChild) ); - } else { +- } else { ++ } else if (!handled) { this.moveTabTo(aTab, this.pinnedTabCount, { forceStandaloneTab: true }); -@@ -835,7 +874,7 @@ + } + aTab.setAttribute("pinned", "true"); +@@ -830,12 +870,15 @@ + } + + if (this.tabContainer.verticalMode) { ++ const handled = gZenFolders.handleTabUnpin(aTab); + this._handleTabMove(aTab, () => { + // we remove this attribute first, so that allTabs represents // the moving of a tab from the vertical pinned tabs container // and back into arrowscrollbox. aTab.removeAttribute("pinned"); - this.tabContainer.arrowScrollbox.prepend(aTab); -+ ZenWorkspaces.activeWorkspaceStrip.prepend(aTab); ++ if (!handled) { ++ ZenWorkspaces.activeWorkspaceStrip.prepend(aTab); ++ } }); } else { this.moveTabTo(aTab, this.pinnedTabCount - 1, { -@@ -1018,6 +1057,8 @@ +@@ -1018,6 +1061,8 @@ let LOCAL_PROTOCOLS = ["chrome:", "about:", "resource:", "data:"]; @@ -82,7 +99,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 if ( aIconURL && !aLoadingPrincipal && -@@ -1028,6 +1069,9 @@ +@@ -1028,6 +1073,9 @@ ); return; } @@ -92,7 +109,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 let browser = this.getBrowserForTab(aTab); browser.mIconURL = aIconURL; -@@ -1273,6 +1317,7 @@ +@@ -1273,6 +1321,7 @@ if (!this._previewMode) { newTab.recordTimeFromUnloadToReload(); newTab.updateLastAccessed(); @@ -100,7 +117,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 oldTab.updateLastAccessed(); // if this is the foreground window, update the last-seen timestamps. if (this.ownerGlobal == BrowserWindowTracker.getTopWindow()) { -@@ -1425,6 +1470,9 @@ +@@ -1425,6 +1474,9 @@ } let activeEl = document.activeElement; @@ -110,7 +127,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 // If focus is on the old tab, move it to the new tab. if (activeEl == oldTab) { newTab.focus(); -@@ -1748,7 +1796,7 @@ +@@ -1748,7 +1800,7 @@ } _setTabLabel(aTab, aLabel, { beforeTabOpen, isContentTitle, isURL } = {}) { @@ -119,7 +136,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 return false; } -@@ -1851,7 +1899,7 @@ +@@ -1851,7 +1903,7 @@ newIndex = this.selectedTab._tPos + 1; } @@ -128,7 +145,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 let browser; if (targetTab) { browser = this.getBrowserForTab(targetTab); -@@ -2108,6 +2156,7 @@ +@@ -2108,6 +2160,7 @@ uriIsAboutBlank, userContextId, skipLoad, @@ -136,7 +153,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 } = {}) { let b = document.createXULElement("browser"); // Use the JSM global to create the permanentKey, so that if the -@@ -2181,8 +2230,7 @@ +@@ -2181,8 +2234,7 @@ // we use a different attribute name for this? b.setAttribute("name", name); } @@ -146,7 +163,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 b.setAttribute("transparent", "true"); } -@@ -2347,7 +2395,7 @@ +@@ -2347,7 +2399,7 @@ let panel = this.getPanel(browser); let uniqueId = this._generateUniquePanelID(); @@ -155,7 +172,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 aTab.linkedPanel = uniqueId; // Inject the into the DOM if necessary. -@@ -2406,8 +2454,8 @@ +@@ -2406,8 +2458,8 @@ // If we transitioned from one browser to two browsers, we need to set // hasSiblings=false on both the existing browser and the new browser. if (this.tabs.length == 2) { @@ -166,7 +183,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 } else { aTab.linkedBrowser.browsingContext.hasSiblings = this.tabs.length > 1; } -@@ -2629,6 +2677,7 @@ +@@ -2629,6 +2681,7 @@ schemelessInput, hasValidUserGestureActivation = false, textDirectiveUserActivation = false, @@ -174,7 +191,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 } = {} ) { // all callers of addTab that pass a params object need to pass -@@ -2639,6 +2688,12 @@ +@@ -2639,6 +2692,12 @@ ); } @@ -187,7 +204,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 if (!UserInteraction.running("browser.tabs.opening", window)) { UserInteraction.start("browser.tabs.opening", "initting", window); } -@@ -2702,6 +2757,15 @@ +@@ -2702,6 +2761,15 @@ noInitialLabel, skipBackgroundNotify, }); @@ -203,7 +220,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 if (insertTab) { // insert the tab into the tab container in the correct position this._insertTabAtIndex(t, { -@@ -2726,6 +2790,7 @@ +@@ -2726,6 +2794,7 @@ initialBrowsingContextGroupId, openWindowInfo, skipLoad, @@ -211,7 +228,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 })); if (focusUrlBar) { -@@ -2845,6 +2910,9 @@ +@@ -2845,6 +2914,9 @@ } } @@ -221,7 +238,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 // Additionally send pinned tab events if (pinned) { this._notifyPinnedStatus(t); -@@ -2918,7 +2986,8 @@ +@@ -2918,7 +2990,8 @@ id = `${Date.now()}-${Math.round(Math.random() * 100)}`; } let group = this._createTabGroup(id, color, false, label); @@ -231,7 +248,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 group, insertBefore?.group ?? insertBefore ); -@@ -3126,6 +3195,7 @@ +@@ -3126,6 +3199,7 @@ initialBrowsingContextGroupId, openWindowInfo, skipLoad, @@ -239,7 +256,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 } ) { // If we don't have a preferred remote type, and we have a remote -@@ -3189,6 +3259,7 @@ +@@ -3189,6 +3263,7 @@ openWindowInfo, name, skipLoad, @@ -247,7 +264,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 }); } -@@ -3367,6 +3438,24 @@ +@@ -3367,6 +3442,24 @@ ) { tabWasReused = true; tab = this.selectedTab; @@ -272,7 +289,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 if (!tabData.pinned) { this.unpinTab(tab); } else { -@@ -3380,6 +3469,7 @@ +@@ -3380,6 +3473,7 @@ restoreTabsLazily && !select && !tabData.pinned; let url = "about:blank"; @@ -280,7 +297,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 if (tabData.entries?.length) { let activeIndex = (tabData.index || tabData.entries.length) - 1; // Ensure the index is in bounds. -@@ -3415,7 +3505,24 @@ +@@ -3415,7 +3509,24 @@ skipLoad: true, preferredRemoteType, }); @@ -306,7 +323,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 if (select) { tabToSelect = tab; } -@@ -3428,8 +3535,8 @@ +@@ -3428,8 +3539,8 @@ // inserted in the DOM. If the tab is not yet in the DOM, // just insert it in the right place from the start. if (!tab.parentNode) { @@ -317,7 +334,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 tab.toggleAttribute("pinned", true); this.tabContainer._invalidateCachedTabs(); // Then ensure all the tab open/pinning information is sent. -@@ -3693,7 +3800,7 @@ +@@ -3693,7 +3804,7 @@ // Ensure we have an index if one was not provided. if (typeof index != "number") { // Move the new tab after another tab if needed, to the end otherwise. @@ -326,7 +343,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 if ( !bulkOrderedOpen && ((openerTab && -@@ -3736,18 +3843,18 @@ +@@ -3736,18 +3847,18 @@ // Ensure index is within bounds. if (tab.pinned) { @@ -349,7 +366,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 if (tabAfter && tabAfter.group == tabGroup) { // Place at the front of, or between tabs in, the same tab group this.tabContainer.insertBefore(tab, tabAfter); -@@ -4059,6 +4166,9 @@ +@@ -4059,6 +4170,9 @@ return; } @@ -359,7 +376,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 this.removeTabs(selectedTabs); } -@@ -4391,6 +4501,7 @@ +@@ -4391,6 +4505,7 @@ skipSessionStore, } = {} ) { @@ -367,7 +384,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 if (UserInteraction.running("browser.tabs.opening", window)) { UserInteraction.finish("browser.tabs.opening", window); } -@@ -4407,6 +4518,12 @@ +@@ -4407,6 +4522,12 @@ TelemetryStopwatch.start("FX_TAB_CLOSE_TIME_NO_ANIM_MS", aTab); } @@ -380,7 +397,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 // Handle requests for synchronously removing an already // asynchronously closing tab. if (!animate && aTab.closing) { -@@ -4421,7 +4538,9 @@ +@@ -4421,7 +4542,9 @@ // frame created for it (for example, by updating the visually selected // state). let tabWidth = window.windowUtils.getBoundsWithoutFlushing(aTab).width; @@ -391,7 +408,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 if ( !this._beginRemoveTab(aTab, { closeWindowFastpath: true, -@@ -4435,7 +4554,6 @@ +@@ -4435,7 +4558,6 @@ TelemetryStopwatch.cancel("FX_TAB_CLOSE_TIME_NO_ANIM_MS", aTab); return; } @@ -399,7 +416,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 let lockTabSizing = !this.tabContainer.verticalMode && !aTab.pinned && -@@ -4574,14 +4692,14 @@ +@@ -4574,14 +4696,14 @@ !!this.tabsInCollapsedTabGroups.length; if ( aTab.visible && @@ -416,7 +433,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 if (closeWindow) { // We've already called beforeunload on all the relevant tabs if we get here, -@@ -4605,6 +4723,7 @@ +@@ -4605,6 +4727,7 @@ newTab = true; } @@ -424,7 +441,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 aTab._endRemoveArgs = [closeWindow, newTab]; // swapBrowsersAndCloseOther will take care of closing the window without animation. -@@ -4645,9 +4764,7 @@ +@@ -4645,9 +4768,7 @@ aTab._mouseleave(); if (newTab) { @@ -435,7 +452,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 } else { TabBarVisibility.update(); } -@@ -4776,6 +4893,8 @@ +@@ -4776,6 +4897,8 @@ this.tabs[i]._tPos = i; } @@ -444,7 +461,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 if (!this._windowIsClosing) { if (wasPinned) { this.tabContainer._positionPinnedTabs(); -@@ -4994,7 +5113,7 @@ +@@ -4994,7 +5117,7 @@ !excludeTabs.has(aTab.owner) && Services.prefs.getBoolPref("browser.tabs.selectOwnerOnClose") ) { @@ -453,7 +470,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 } // Try to find a remaining tab that comes after the given tab -@@ -5016,7 +5135,7 @@ +@@ -5016,7 +5139,7 @@ } if (tab) { @@ -462,7 +479,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 } // If no qualifying visible tab was found, see if there is a tab in -@@ -5434,10 +5553,10 @@ +@@ -5434,10 +5557,10 @@ SessionStore.deleteCustomTabValue(aTab, "hiddenBy"); } @@ -475,7 +492,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 aTab.selected || aTab.closing || // Tabs that are sharing the screen, microphone or camera cannot be hidden. -@@ -5675,7 +5794,7 @@ +@@ -5675,7 +5798,7 @@ // Don't allow mixing pinned and unpinned tabs. if (aTab.pinned) { @@ -484,7 +501,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 } else { aIndex = Math.max(aIndex, this.pinnedTabCount); } -@@ -5684,11 +5803,17 @@ +@@ -5684,11 +5807,17 @@ } this._handleTabMove(aTab, () => { @@ -505,7 +522,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 neighbor.after(aTab); } else { this.tabContainer.insertBefore(aTab, neighbor); -@@ -5697,7 +5822,7 @@ +@@ -5697,7 +5826,7 @@ } moveTabToGroup(aTab, aGroup) { @@ -514,7 +531,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 return; } if (aTab.group && aTab.group.id === aGroup.id) { -@@ -5721,6 +5846,8 @@ +@@ -5721,6 +5850,8 @@ moveActionCallback(); @@ -523,7 +540,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 // Clear tabs cache after moving nodes because the order of tabs may have // changed. this.tabContainer._invalidateCachedTabs(); -@@ -5771,7 +5898,7 @@ +@@ -5771,7 +5902,7 @@ createLazyBrowser, }; @@ -532,7 +549,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 if (aIndex < numPinned || (aTab.pinned && aIndex == numPinned)) { params.pinned = true; } -@@ -7415,6 +7542,7 @@ +@@ -7415,6 +7546,7 @@ aWebProgress.isTopLevel ) { this.mTab.setAttribute("busy", "true"); @@ -540,7 +557,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 gBrowser._tabAttrModified(this.mTab, ["busy"]); this.mTab._notselectedsinceload = !this.mTab.selected; } -@@ -8381,7 +8509,7 @@ var TabContextMenu = { +@@ -8381,7 +8513,7 @@ var TabContextMenu = { ); contextUnpinSelectedTabs.hidden = !this.contextTab.pinned || !multiselectionContext; @@ -549,7 +566,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 // Move Tab items let contextMoveTabOptions = document.getElementById( "context_moveTabOptions" -@@ -8414,7 +8542,7 @@ var TabContextMenu = { +@@ -8414,7 +8546,7 @@ var TabContextMenu = { let contextMoveTabToStart = document.getElementById("context_moveToStart"); let isFirstTab = tabsToMove[0] == visibleTabs[0] || @@ -558,7 +575,7 @@ index 628aa6596627c85efe361fc1ece8fd58f7ee653e..091194c85e35743c648f043a5fb7c8f7 contextMoveTabToStart.disabled = isFirstTab && allSelectedTabsAdjacent; document.getElementById("context_openTabInWindow").disabled = -@@ -8647,6 +8775,7 @@ var TabContextMenu = { +@@ -8647,6 +8779,7 @@ var TabContextMenu = { if (this.contextTab.multiselected) { gBrowser.removeMultiSelectedTabs(); } else { diff --git a/src/browser/components/tabbrowser/content/tabs-js.patch b/src/browser/components/tabbrowser/content/tabs-js.patch index 2c8855359..fa88040a7 100644 --- a/src/browser/components/tabbrowser/content/tabs-js.patch +++ b/src/browser/components/tabbrowser/content/tabs-js.patch @@ -1,5 +1,5 @@ diff --git a/browser/components/tabbrowser/content/tabs.js b/browser/components/tabbrowser/content/tabs.js -index fa96568d366fd3608f9bd583fa793150bd815c8b..03a525205457f723e204614834e32e7a917f41f7 100644 +index fa96568d366fd3608f9bd583fa793150bd815c8b..9a288957781277246b66a911590a13e7231958d0 100644 --- a/browser/components/tabbrowser/content/tabs.js +++ b/browser/components/tabbrowser/content/tabs.js @@ -94,7 +94,7 @@ @@ -62,18 +62,23 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..03a525205457f723e204614834e32e7a if (draggedTab && dropEffect == "copy") { // copy the dropped tab (wherever it's from) let newIndex = this._getDropIndex(event); -@@ -1034,8 +1046,8 @@ +@@ -1034,10 +1046,11 @@ } } else { let pinned = draggedTab.pinned; - let numPinned = gBrowser.pinnedTabCount; - let tabs = this.visibleTabs.slice( +- pinned ? 0 : numPinned, +- pinned ? numPinned : undefined + let numPinned = gBrowser._numVisiblePinTabs; ++ let essential = draggedTab.hasAttribute("zen-essential"); + let tabs = this.visibleTabs.filter(tab => !tab.hasAttribute("zen-glance-tab")).slice( - pinned ? 0 : numPinned, - pinned ? numPinned : undefined ++ pinned ? (essential ? 0 : gBrowser._numZenVisibleEssentials) : numPinned, ++ pinned ? (essential ? gBrowser._numZenVisibleEssentials : numPinned) : undefined ); -@@ -1114,7 +1126,7 @@ + let size = this.verticalMode ? "height" : "width"; + let screenAxis = this.verticalMode ? "screenY" : "screenX"; +@@ -1114,7 +1127,7 @@ let postTransitionCleanup = () => { tab.removeAttribute("tabdrop-samewindow"); @@ -82,7 +87,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..03a525205457f723e204614834e32e7a if (dropIndex !== false) { gBrowser.moveTabTo(tab, dropIndex); if (!directionForward) { -@@ -1122,7 +1134,7 @@ +@@ -1122,7 +1135,7 @@ } } }; @@ -91,7 +96,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..03a525205457f723e204614834e32e7a postTransitionCleanup(); } else { let onTransitionEnd = transitionendEvent => { -@@ -1279,13 +1291,23 @@ +@@ -1279,13 +1292,23 @@ return; } @@ -117,7 +122,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..03a525205457f723e204614834e32e7a ) { delete draggedTab._dragData; return; -@@ -1517,7 +1539,7 @@ +@@ -1517,7 +1540,7 @@ } get newTabButton() { @@ -126,7 +131,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..03a525205457f723e204614834e32e7a } get verticalMode() { -@@ -1537,7 +1559,7 @@ +@@ -1537,28 +1560,40 @@ if (this.#allTabs) { return this.#allTabs; } @@ -135,8 +140,14 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..03a525205457f723e204614834e32e7a // remove arrowScrollbox periphery element children.pop(); -@@ -1551,14 +1573,29 @@ - } + // explode tab groups + // Iterate backwards over the array to preserve indices while we modify + // things in place +- for (let i = children.length - 1; i >= 0; i--) { +- if (children[i].tagName == "tab-group") { +- children.splice(i, 1, ...children[i].tabs); +- } +- } this.#allTabs = [ - ...this.verticalPinnedTabsContainer.children, @@ -156,6 +167,8 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..03a525205457f723e204614834e32e7a + // remove the separator from the list + this.#allTabs.splice(i, 1); + i--; ++ } else if (this.#allTabs[i].tagName == "tab-group") { ++ this.#allTabs.splice(i, 1, ...this.#allTabs[i].tabs); + } + } return this.#allTabs; @@ -167,7 +180,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..03a525205457f723e204614834e32e7a return children.filter(node => node.tagName == "tab-group"); } -@@ -1579,7 +1616,7 @@ +@@ -1579,7 +1614,7 @@ */ get visibleTabs() { if (!this.#visibleTabs) { @@ -176,7 +189,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..03a525205457f723e204614834e32e7a } return this.#visibleTabs; } -@@ -1613,10 +1650,8 @@ +@@ -1613,10 +1648,8 @@ return this.#focusableItems; } @@ -189,7 +202,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..03a525205457f723e204614834e32e7a let focusableItems = []; for (let child of children) { -@@ -1632,6 +1667,7 @@ +@@ -1632,6 +1665,7 @@ } this.#focusableItems = [ @@ -197,7 +210,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..03a525205457f723e204614834e32e7a ...verticalPinnedTabsContainer.children, ...focusableItems, ]; -@@ -1642,6 +1678,7 @@ +@@ -1642,6 +1676,7 @@ _invalidateCachedTabs() { this.#allTabs = null; this._invalidateCachedVisibleTabs(); @@ -205,7 +218,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..03a525205457f723e204614834e32e7a } _invalidateCachedVisibleTabs() { -@@ -1656,8 +1693,8 @@ +@@ -1656,8 +1691,8 @@ #isContainerVerticalPinnedExpanded(tab) { return ( this.verticalMode && @@ -216,7 +229,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..03a525205457f723e204614834e32e7a ); } -@@ -1672,7 +1709,7 @@ +@@ -1672,7 +1707,7 @@ if (node == null) { // We have a container for non-tab elements at the end of the scrollbox. @@ -225,7 +238,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..03a525205457f723e204614834e32e7a } node.before(tab); -@@ -1772,7 +1809,7 @@ +@@ -1772,7 +1807,7 @@ // There are separate "new tab" buttons for horizontal tabs toolbar, vertical tabs and // for when the tab strip is overflowed (which is shared by vertical and horizontal tabs); // Attach the long click popup to all of them. @@ -234,7 +247,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..03a525205457f723e204614834e32e7a const newTab2 = this.newTabButton; const newTabVertical = document.getElementById( "vertical-tabs-newtab-button" -@@ -1855,7 +1892,7 @@ +@@ -1855,7 +1890,7 @@ let rect = ele => { return window.windowUtils.getBoundsWithoutFlushing(ele); }; @@ -243,7 +256,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..03a525205457f723e204614834e32e7a if (tab && rect(tab).width <= this._tabClipWidth) { this.setAttribute("closebuttons", "activetab"); } else { -@@ -1867,10 +1904,12 @@ +@@ -1867,10 +1902,12 @@ _handleTabSelect(aInstant) { let selectedTab = this.selectedItem; @@ -256,7 +269,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..03a525205457f723e204614834e32e7a selectedTab._notselectedsinceload = false; } -@@ -1882,7 +1921,7 @@ +@@ -1882,7 +1919,7 @@ return; } @@ -265,7 +278,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..03a525205457f723e204614834e32e7a if (!tabs.length) { return; } -@@ -1918,7 +1957,7 @@ +@@ -1918,7 +1955,7 @@ if (isEndTab && !this._hasTabTempMaxWidth) { return; } @@ -274,7 +287,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..03a525205457f723e204614834e32e7a // Force tabs to stay the same width, unless we're closing the last tab, // which case we need to let them expand just enough so that the overall // tabbar width is the same. -@@ -1933,7 +1972,7 @@ +@@ -1933,7 +1970,7 @@ let tabsToReset = []; for (let i = numPinned; i < tabs.length; i++) { let tab = tabs[i]; @@ -283,7 +296,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..03a525205457f723e204614834e32e7a if (!isEndTab) { // keep tabs the same width tab.style.transition = "none"; -@@ -1999,16 +2038,15 @@ +@@ -1999,16 +2036,15 @@ // Move pinned tabs to another container when the tabstrip is toggled to vertical // and when session restore code calls _positionPinnedTabs; update styling whenever // the number of pinned tabs changes. @@ -302,11 +315,11 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..03a525205457f723e204614834e32e7a for (let i = 0; i < numPinned; i++) { tabs[i].style.marginInlineStart = ""; - verticalTabsContainer.appendChild(tabs[i]); -+ tabs[i].hasAttribute("zen-essential") ? document.getElementById("zen-essentials-container").appendChild(tabs[i]) : verticalTabsContainer.insertBefore(tabs[i], verticalTabsContainer.lastChild); ++ tabs[i].hasAttribute("zen-essential") ? document.getElementById("zen-essentials-container").appendChild(tabs[i].group?.hasAttribute("split-view-group") ? tabs[i].group : tabs[i]) : verticalTabsContainer.insertBefore(tabs[i].group?.hasAttribute("split-view-group") ? tabs[i].group : tabs[i], verticalTabsContainer.lastChild); } } -@@ -2016,9 +2054,7 @@ +@@ -2016,9 +2052,7 @@ } _resetVerticalPinnedTabs() { @@ -317,7 +330,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..03a525205457f723e204614834e32e7a if (!verticalTabsContainer.children.length) { return; -@@ -2031,8 +2067,8 @@ +@@ -2031,8 +2065,8 @@ } _positionPinnedTabs() { @@ -328,7 +341,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..03a525205457f723e204614834e32e7a let absPositionHorizontalTabs = this.overflowing && tabs.length > numPinned && numPinned > 0; -@@ -2041,7 +2077,7 @@ +@@ -2041,7 +2075,7 @@ if (this.verticalMode) { this._updateVerticalPinnedTabs(); @@ -337,7 +350,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..03a525205457f723e204614834e32e7a let layoutData = this._pinnedTabsLayoutCache; let uiDensity = document.documentElement.getAttribute("uidensity"); if (!layoutData || layoutData.uiDensity != uiDensity) { -@@ -2113,7 +2149,7 @@ +@@ -2113,7 +2147,7 @@ return; } @@ -346,7 +359,16 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..03a525205457f723e204614834e32e7a let directionX = screenX > dragData.animLastScreenX; let directionY = screenY > dragData.animLastScreenY; -@@ -2296,10 +2332,11 @@ +@@ -2121,7 +2155,7 @@ + dragData.animLastScreenX = screenX; + + let { width: tabWidth, height: tabHeight } = +- draggedTab.getBoundingClientRect(); ++ (draggedTab.group?.hasAttribute("split-view-group") ? draggedTab.group : draggedTab).getBoundingClientRect(); + let shiftSizeX = tabWidth * movingTabs.length; + let shiftSizeY = tabHeight; + dragData.tabWidth = tabWidth; +@@ -2296,10 +2330,11 @@ } let pinned = draggedTab.pinned; @@ -358,11 +380,11 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..03a525205457f723e204614834e32e7a + let essential = draggedTab.hasAttribute("zen-essential"); + let tabs = this.visibleTabs.filter(tab => !tab.hasAttribute("zen-glance-tab")).slice( + pinned ? (essential ? 0 : gBrowser._numZenVisibleEssentials) : numPinned, -+ pinned ? (essential ? gBrowser._numZenVisibleEssentials : ((numPinned - gBrowser._numZenVisibleEssentials) + 1)) : undefined ++ pinned ? (essential ? gBrowser._numZenVisibleEssentials : numPinned) : undefined ); if (this.#rtlMode) { -@@ -2347,8 +2384,12 @@ +@@ -2347,8 +2382,12 @@ (lastMovingTabScreen + tabSize); translate = Math.min(Math.max(translate, firstBound), lastBound); @@ -377,7 +399,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..03a525205457f723e204614834e32e7a } dragData.translatePos = translate; -@@ -2484,12 +2525,16 @@ +@@ -2484,12 +2523,16 @@ // Shift background tabs to leave a gap where the dragged tab // would currently be dropped. for (let tab of tabs) { @@ -395,7 +417,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..03a525205457f723e204614834e32e7a if (tab.group?.tabs[0] == tab) { tab.group.style.setProperty( "--tabgroup-dragover-transform", -@@ -2541,8 +2586,9 @@ +@@ -2541,8 +2584,9 @@ ); } @@ -407,7 +429,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..03a525205457f723e204614834e32e7a return; } -@@ -2553,6 +2599,7 @@ +@@ -2553,6 +2597,7 @@ tab.style.transform = ""; if (tab.group) { tab.group.style.removeProperty("--tabgroup-dragover-transform"); @@ -415,7 +437,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..03a525205457f723e204614834e32e7a } tab.removeAttribute("dragover-createGroup"); } -@@ -2604,7 +2651,7 @@ +@@ -2604,7 +2649,7 @@ movingTab._moveTogetherSelectedTabsData.newIndex = movingTabNewIndex; movingTab._moveTogetherSelectedTabsData.animate = false; }; @@ -424,7 +446,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..03a525205457f723e204614834e32e7a postTransitionCleanup(); } else { let onTransitionEnd = transitionendEvent => { -@@ -2707,9 +2754,9 @@ +@@ -2707,9 +2752,9 @@ function newIndex(aTab, index) { // Don't allow mixing pinned and unpinned tabs. if (aTab.pinned) { @@ -436,7 +458,7 @@ index fa96568d366fd3608f9bd583fa793150bd815c8b..03a525205457f723e204614834e32e7a } } -@@ -2793,7 +2840,7 @@ +@@ -2793,7 +2838,7 @@ } _notifyBackgroundTab(aTab) {