diff --git a/browser/components/tabbrowser/content/tabs.js b/browser/components/tabbrowser/content/tabs.js index 0fbdbf3aefc467880e6b0bae2615cb145735cb0f..bf956639f7d17d6d652f3b2d6cb174904b5b5da9 100644 --- a/browser/components/tabbrowser/content/tabs.js +++ b/browser/components/tabbrowser/content/tabs.js @@ -93,7 +93,7 @@ }; this.arrowScrollbox._canScrollToElement = element => { if (isTab(element)) { - return !element.pinned || !this.hasAttribute("positionpinnedtabs"); + return !element.hasAttribute("zen-essential") || !this.hasAttribute("positionpinnedtabs"); } return true; }; @@ -347,7 +347,7 @@ // and we're not hitting the scroll buttons. if ( event.button != 0 || - event.target != this.arrowScrollbox || + event.target != document.getElementById("zen-tabs-wrapper") || event.composedTarget.localName == "toolbarbutton" ) { return; @@ -396,6 +396,7 @@ // Reset the "ignored click" flag target._ignoredCloseButtonClicks = false; } + gZenUIManager.saveScrollbarState(); } /* Protects from close-tab-button errant doubleclick: @@ -693,7 +694,7 @@ if (this.#isContainerVerticalPinnedExpanded(tab)) { // In expanded vertical mode, the max number of pinned tabs per row is dynamic // Set this before adjusting dragged tab's position - let pinnedTabs = this.visibleTabs.slice(0, gBrowser.pinnedTabCount); + let pinnedTabs = this.visibleTabs.filter(tab => !tab.hasAttribute("zen-glance-tab")).slice(0, gBrowser._numZenVisibleEssentials); let tabsPerRow = 0; let position = 0; for (let pinnedTab of pinnedTabs) { @@ -899,6 +900,10 @@ } let draggedTab = event.dataTransfer.mozGetDataAt(TAB_DROP_TYPE, 0); + if (draggedTab && effects === "move") { + gZenPinnedTabManager.applyDragoverClass(event, draggedTab); + gZenViewSplitter.onBrowserDragEndToSplit(event); + } if ( (effects == "move" || effects == "copy") && this == draggedTab.container && @@ -1012,6 +1017,18 @@ this._tabDropIndicator.hidden = true; event.stopPropagation(); + if (draggedTab?.hasAttribute("zen-has-splitted")) { + draggedTab.removeAttribute("zen-has-splitted"); + draggedTab._visuallySelected = false; + } + if (draggedTab && dropEffect == "move") { + let moved = gZenPinnedTabManager.moveToAnotherTabContainerIfNecessary(event, movingTabs); + + if (moved) { + this._finishMoveTogetherSelectedTabs(draggedTab); + return; + } + } if (draggedTab && dropEffect == "copy") { // copy the dropped tab (wherever it's from) let newIndex = this._getDropIndex(event); @@ -1050,10 +1067,11 @@ } } else { let isPinned = draggedTab.pinned; - let numPinned = gBrowser.pinnedTabCount; - let tabs = this.ariaFocusableItems.slice( - isPinned ? 0 : numPinned, - isPinned ? numPinned : undefined + let numPinned = gBrowser._numVisiblePinTabsWithoutCollapsed; + let essential = draggedTab.hasAttribute("zen-essential"); + let tabs = this.ariaFocusableItems.filter(tab => !tab.hasAttribute("zen-glance-tab")).slice( + isPinned ? (essential ? 0 : gBrowser._numZenVisibleEssentials) : numPinned, + isPinned ? (essential ? gBrowser._numZenVisibleEssentials : numPinned) : undefined ); let size = this.verticalMode ? "height" : "width"; let screenAxis = this.verticalMode ? "screenY" : "screenX"; @@ -1129,7 +1147,7 @@ tab.removeAttribute("tabdrop-samewindow"); resolve(); }; - if (gReduceMotion) { + if (true || gReduceMotion) { postTransitionCleanup(); } else { let onTransitionEnd = transitionendEvent => { @@ -1246,7 +1264,7 @@ return; } } - + if (gZenViewSplitter.handleTabDrop(event, urls, replace, inBackground)) return; gBrowser.loadTabs(urls, { inBackground, replace, @@ -1276,13 +1294,23 @@ return; } - this._finishMoveTogetherSelectedTabs(draggedTab); this._finishAnimateTabMove(); + if (!dt.mozUserCancelled && dt.dropEffect == "none" && !this._isCustomizing) { + const moved = gZenViewSplitter.moveTabToSplitView(event, draggedTab); + if (moved) { + delete draggedTab._dragData; + return; + } + } + + this._finishMoveTogetherSelectedTabs(draggedTab); + if ( dt.mozUserCancelled || dt.dropEffect != "none" || - this._isCustomizing + this._isCustomizing || + draggedTab.pinned ) { delete draggedTab._dragData; return; @@ -1504,7 +1532,7 @@ } get newTabButton() { - return this.querySelector("#tabs-newtab-button"); + return ZenWorkspaces.activeWorkspaceStrip.querySelector("#tabs-newtab-button"); } get verticalMode() { @@ -1524,29 +1552,41 @@ if (this.#allTabs) { return this.#allTabs; } - let children = Array.from(this.arrowScrollbox.children); + let children = ZenWorkspaces.tabboxChildren; // remove arrowScrollbox periphery element children.pop(); // 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, + ...document.getElementById("zen-essentials-container").children, ...this.verticalPinnedTabsContainer.children, ...children, ]; + const lastPinnedTabIdx = gBrowser.pinnedTabCount; + for (let i = 0; i < this.#allTabs.length; i++) { + // add glance tabs (tabs inside tabs) to the list + const glanceTab = this.#allTabs[i].querySelector("tab[zen-glance-tab]"); + if (glanceTab) { + // insert right after the parent tab. note: it must be inserted before + // the last pinned tab so it can be inserted in the correct order + this.#allTabs.splice(Math.max(i + 1, lastPinnedTabIdx), 0, glanceTab); + i++; + } else if (this.#allTabs[i].classList.contains("vertical-pinned-tabs-container-separator")) { + // 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; } get allGroups() { let children = Array.from(this.arrowScrollbox.children); - return children.filter(node => node.tagName == "tab-group"); + return ZenWorkspaces.allTabGroups; } /** @@ -1566,7 +1606,7 @@ */ get visibleTabs() { if (!this.#visibleTabs) { - this.#visibleTabs = this.openTabs.filter(tab => tab.visible); + this.#visibleTabs = this.openTabs.filter(tab => tab.visible && !tab.hasAttribute("zen-empty-tab")); } return this.#visibleTabs; } @@ -1601,23 +1641,18 @@ } let elementIndex = 0; - let verticalPinnedTabsContainer = document.getElementById( - "vertical-pinned-tabs-container" - ); - for (let i = 0; i < verticalPinnedTabsContainer.childElementCount; i++) { - verticalPinnedTabsContainer.children[i].elementIndex = elementIndex++; - } - let children = Array.from(this.arrowScrollbox.children); + let verticalPinnedTabsContainer = this.verticalPinnedTabsContainer + let children = ZenWorkspaces.tabboxChildrenWithoutEmpty; let focusableItems = []; - for (let child of children) { + for (let child of [...document.getElementById("zen-essentials-container").children, ...verticalPinnedTabsContainer.children, ...children]) { if (isTab(child) && child.visible) { child.elementIndex = elementIndex++; focusableItems.push(child); } else if (isTabGroup(child)) { child.labelElement.elementIndex = elementIndex++; focusableItems.push(child.labelElement); - if (!child.collapsed) { + if (!child.collapsed && !child.hasAttribute("split-view-group")) { let visibleTabsInGroup = child.tabs.filter(tab => tab.visible); visibleTabsInGroup.forEach(tab => { tab.elementIndex = elementIndex++; @@ -1627,10 +1662,7 @@ } } - this.#focusableItems = [ - ...verticalPinnedTabsContainer.children, - ...focusableItems, - ]; + this.#focusableItems = focusableItems; return this.#focusableItems; } @@ -1638,6 +1670,7 @@ _invalidateCachedTabs() { this.#allTabs = null; this._invalidateCachedVisibleTabs(); + ZenWorkspaces._allStoredTabs = null; } _invalidateCachedVisibleTabs() { @@ -1652,8 +1685,8 @@ #isContainerVerticalPinnedExpanded(tab) { return ( this.verticalMode && - tab.hasAttribute("pinned") && - this.hasAttribute("expanded") + (tab.hasAttribute("zen-essential")) && + (this.hasAttribute("expanded") || document.documentElement.hasAttribute("zen-sidebar-expanded")) ); } @@ -1668,7 +1701,7 @@ if (node == null) { // We have a container for non-tab elements at the end of the scrollbox. - node = this.arrowScrollbox.lastChild; + node = ZenWorkspaces.activeWorkspaceStrip.lastChild; } node.before(tab); @@ -1763,7 +1796,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. - const newTab = document.getElementById("new-tab-button"); + const newTab = ZenWorkspaces.activeWorkspaceStrip.querySelector("#tabs-newtab-button"); const newTab2 = this.newTabButton; const newTabVertical = document.getElementById( "vertical-tabs-newtab-button" @@ -1846,7 +1879,7 @@ let rect = ele => { return window.windowUtils.getBoundsWithoutFlushing(ele); }; - let tab = this.visibleTabs[gBrowser.pinnedTabCount]; + let tab = this.visibleTabs[gBrowser._numVisiblePinTabs]; if (tab && rect(tab).width <= this._tabClipWidth) { this.setAttribute("closebuttons", "activetab"); } else { @@ -1858,10 +1891,12 @@ _handleTabSelect(aInstant) { let selectedTab = this.selectedItem; + if (!selectedTab) return; if (this.overflowing) { this.arrowScrollbox.ensureElementIsVisible(selectedTab, aInstant); } + gZenCompactModeManager.flashSidebarIfNecessary(aInstant); selectedTab._notselectedsinceload = false; } @@ -1873,7 +1908,7 @@ return; } - let tabs = this.visibleTabs; + let tabs = this.visibleTabs.filter(tab => !tab.hasAttribute("zen-glance-tab")); if (!tabs.length) { return; } @@ -1909,7 +1944,7 @@ if (isEndTab && !this._hasTabTempMaxWidth) { return; } - let numPinned = gBrowser.pinnedTabCount; + let numPinned = gBrowser._numVisiblePinTabs; // 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. @@ -1924,7 +1959,7 @@ let tabsToReset = []; for (let i = numPinned; i < tabs.length; i++) { let tab = tabs[i]; - tab.style.setProperty("max-width", aTabWidth, "important"); + //tab.style.setProperty("max-width", aTabWidth, "important"); if (!isEndTab) { // keep tabs the same width tab.style.transition = "none"; @@ -1990,16 +2025,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. - let verticalTabsContainer = document.getElementById( - "vertical-pinned-tabs-container" - ); + let verticalTabsContainer = this.verticalPinnedTabsContainer; let numPinned = gBrowser.pinnedTabCount; - - if (gBrowser.pinnedTabCount !== verticalTabsContainer.children.length) { - let tabs = this.visibleTabs; + if (!ZenWorkspaces._hasInitializedTabsStrip) return; + let count = ZenWorkspaces.makeSurePinTabIsInCorrectPosition(); + if (gBrowser.pinnedTabCount !== (verticalTabsContainer.children.length - count - 1 + document.getElementById("zen-essentials-container").children.length)) { + let tabs = this.allTabs.filter(tab => !tab.hasAttribute("zen-glance-tab")); 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].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); } } @@ -2007,9 +2041,7 @@ } _resetVerticalPinnedTabs() { - let verticalTabsContainer = document.getElementById( - "vertical-pinned-tabs-container" - ); + let verticalTabsContainer = this.verticalPinnedTabsContainer; if (!verticalTabsContainer.children.length) { return; @@ -2022,8 +2054,8 @@ } _positionPinnedTabs() { - let tabs = this.visibleTabs; - let numPinned = gBrowser.pinnedTabCount; + let tabs = this.visibleTabs.filter(tab => !tab.hasAttribute("zen-glance-tab")); + let numPinned = gBrowser._numVisiblePinTabs; let absPositionHorizontalTabs = this.overflowing && tabs.length > numPinned && numPinned > 0; @@ -2032,7 +2064,7 @@ if (this.verticalMode) { this._updateVerticalPinnedTabs(); - } else if (absPositionHorizontalTabs) { + } else if (absPositionHorizontalTabs && false) { let layoutData = this._pinnedTabsLayoutCache; let uiDensity = document.documentElement.getAttribute("uidensity"); if (!layoutData || layoutData.uiDensity != uiDensity) { @@ -2104,7 +2136,7 @@ return; } - let tabs = this.visibleTabs.slice(0, gBrowser.pinnedTabCount); + let tabs = this.visibleTabs.filter(tab => !tab.hasAttribute("zen-glance-tab")).slice(0, gBrowser._numZenVisibleEssentials); let directionX = screenX > dragData.animLastScreenX; let directionY = screenY > dragData.animLastScreenY; @@ -2112,7 +2144,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,11 +2328,15 @@ this.#clearDragOverCreateGroupTimer(); let isPinned = draggedTab.pinned; - let numPinned = gBrowser.pinnedTabCount; - let tabs = this.ariaFocusableItems.slice( - isPinned ? 0 : numPinned, - isPinned ? numPinned : undefined + let numPinned = gBrowser._numVisiblePinTabsWithoutCollapsed; + let essential = draggedTab.hasAttribute("zen-essential"); + let tabs = this.ariaFocusableItems.filter(tab => !tab.hasAttribute("zen-glance-tab")).slice( + isPinned ? (essential ? 0 : gBrowser._numZenVisibleEssentials) : numPinned, + isPinned ? (essential ? gBrowser._numZenVisibleEssentials : numPinned) : undefined ); + if (draggedTab.group?.hasAttribute("split-view-group")) { + draggedTab = draggedTab.group.labelElement; + } if (this.#rtlMode) { tabs.reverse(); @@ -2328,6 +2364,12 @@ let lastTab = tabs.at(-1); let lastMovingTab = movingTabs.at(-1); let firstMovingTab = movingTabs[0]; + if (lastMovingTab.group?.hasAttribute("split-view-group")) { + lastMovingTab = lastMovingTab.group; + } + if (firstMovingTab.group?.hasAttribute("split-view-group")) { + firstMovingTab = firstMovingTab.group; + } let endEdge = ele => ele[screenAxis] + bounds(ele)[size]; let lastMovingTabScreen = endEdge(lastMovingTab); let firstMovingTabScreen = firstMovingTab[screenAxis]; @@ -2348,7 +2390,11 @@ translate = Math.min(Math.max(translate, firstBound), lastBound); for (let tab of movingTabs) { - tab.style.transform = `${translateAxis}(${translate}px)`; + if (tab.group?.hasAttribute("split-view-group")) { + tab.group.style.transform = `${translateAxis}(${translate}px)`; + } else { + tab.style.transform = `${translateAxis}(${translate}px)`; + } } dragData.translatePos = translate; @@ -2379,7 +2425,7 @@ let getTabShift = (item, dropElementIndex) => { if ( item.elementIndex < draggedTab.elementIndex && - item.elementIndex >= dropElementIndex + item.elementIndex + !!item.closest("tab-group")?.hasAttribute("split-view-group") >= dropElementIndex ) { return this.#rtlMode ? -shiftSize : shiftSize; } @@ -2485,6 +2531,9 @@ break; } let element = tabs[mid]; + if (element?.group?.hasAttribute("split-view-group")) { + element = element.group.labelElement; + } let elementForSize = isTabGroupLabel(element) ? element.parentElement : element; @@ -2507,6 +2556,10 @@ if (!dropElement) { dropElement = this.ariaFocusableItems[oldDropElementIndex]; } + if (dropElement?.group?.hasAttribute("split-view-group")) { + // We focus the group label element, not the group itself. + dropElement = dropElement.group.labelElement; + } let newDropElementIndex = dropElement ? dropElement.elementIndex : oldDropElementIndex; @@ -2566,12 +2619,12 @@ } } - if (gBrowser._tabGroupsEnabled && !isPinned) { + if (true) { let dragOverGroupingThreshold = 1 - moveOverThreshold; // When dragging tab(s) over an ungrouped tab, signal to the user // that dropping the tab(s) will create a new tab group. - shouldCreateGroupOnDrop = + shouldCreateGroupOnDrop = false && dropElement != draggedTab && isTab(dropElement) && !dropElement?.group && @@ -2639,7 +2692,7 @@ // Shift background tabs to leave a gap where the dragged tab // would currently be dropped. for (let item of tabs) { - if (item == draggedTab) { + if (item == draggedTab || (item.group?.hasAttribute("split-view-group") && item.group == draggedTab.group)) { continue; } @@ -2648,6 +2701,9 @@ if (isTabGroupLabel(item)) { // Shift the `.tab-group-label-container` to shift the label element. item = item.parentElement; + if (item.parentElement?.hasAttribute("split-view-group")) { + item = item.parentElement; + } } item.style.transform = transform; } @@ -2697,8 +2753,9 @@ ); } - _finishAnimateTabMove() { - if (!this.hasAttribute("movingtab")) { + _finishAnimateTabMove(always = false) { + gZenPinnedTabManager.removeTabContainersDragoverClass(); + if (!this.hasAttribute("movingtab") && !always) { return; } @@ -2711,6 +2768,12 @@ item = item.parentElement; } item.style.transform = ""; + if (item.closest("tab-group")?.hasAttribute("split-view-group")) item.closest("tab-group").style.transform = ""; + if (item.closest("tab-group")?.hasAttribute("split-view-group")) { + for (let tab of item.closest("tab-group").tabs) { + tab.style.transform = ""; + } + } item.removeAttribute("dragover-createGroup"); } this.removeAttribute("movingtab-createGroup"); @@ -2754,7 +2817,7 @@ let postTransitionCleanup = () => { movingTab._moveTogetherSelectedTabsData.animate = false; }; - if (gReduceMotion) { + if (true || gReduceMotion) { postTransitionCleanup(); } else { let onTransitionEnd = transitionendEvent => { @@ -2924,7 +2987,7 @@ } _notifyBackgroundTab(aTab) { - if (aTab.pinned || !aTab.visible || !this.overflowing) { + if (aTab.hasAttribute("zen-essential") || !aTab.visible || !this.overflowing) { return; }