diff --git a/browser/components/tabbrowser/content/tabs.js b/browser/components/tabbrowser/content/tabs.js index e9aa0f03c26dc26e1a2e56d28fadb70e60c8e8ca..9c209752b01bd07a3f38452da4bc8efc7433466c 100644 --- a/browser/components/tabbrowser/content/tabs.js +++ b/browser/components/tabbrowser/content/tabs.js @@ -552,19 +552,36 @@ } dt.setDragImage(toDrag, dragImageOffset, dragImageOffset); + const zenVerticalTabs = Services.prefs.getBoolPref( + "zen.tabs.vertical", + false + ); + // _dragData.offsetX/Y give the coordinates that the mouse should be // positioned relative to the corner of the new window created upon // dragend such that the mouse appears to have the same position // relative to the corner of the dragged tab. function clientX(ele) { + if (zenVerticalTabs) { + return 0; + } return ele.getBoundingClientRect().left; } + function clientY(ele) { + if (!zenVerticalTabs) { + return 0; + } + return ele.getBoundingClientRect().top; + } let tabOffsetX = clientX(tab) - clientX(this); + let tabOffsetY = clientY(tab) - clientY(this); tab._dragData = { offsetX: event.screenX - window.screenX - tabOffsetX, - offsetY: event.screenY - window.screenY, + offsetY: event.screenY - window.screenY - tabOffsetY, scrollX: this.arrowScrollbox.scrollbox.scrollLeft, + scrollY: this.arrowScrollbox.scrollbox.scrollTop, screenX: event.screenX, + screenY: event.screenY, movingTabs: (tab.multiselected ? gBrowser.selectedTabs : [tab]).filter( t => t.pinned == tab.pinned ), @@ -651,21 +668,30 @@ } } + const verticalTabs = Services.prefs.getBoolPref( + "zen.tabs.vertical", + false + ); + const left = verticalTabs ? "top" : "left"; + const right = verticalTabs ? "bottom" : "right"; + const width = verticalTabs ? "height" : "width"; + const clientWidth = verticalTabs ? "clientHeight" : "clientWidth"; + var rect = arrowScrollbox.getBoundingClientRect(); var newMargin; if (pixelsToScroll) { // if we are scrolling, put the drop indicator at the edge // so that it doesn't jump while scrolling let scrollRect = arrowScrollbox.scrollClientRect; - let minMargin = scrollRect.left - rect.left; + let minMargin = scrollRect[left] - rect[left]; let maxMargin = Math.min( - minMargin + scrollRect.width, - scrollRect.right + minMargin + scrollRect[width], + scrollRect[right] ); if (RTL_UI) { [minMargin, maxMargin] = [ - this.clientWidth - maxMargin, - this.clientWidth - minMargin, + this[clientWidth] - maxMargin,, + this[clientWidth] - minMargin, ]; } newMargin = pixelsToScroll > 0 ? maxMargin : minMargin; @@ -675,29 +701,38 @@ if (newIndex == children.length) { let tabRect = this._getVisibleTabs().at(-1).getBoundingClientRect(); if (RTL_UI) { - newMargin = rect.right - tabRect.left; + newMargin = rect[right] - tabRect[left]; } else { - newMargin = tabRect.right - rect.left; + newMargin = tabRect[right] - rect[left]; } } else { let tabRect = children[newIndex].getBoundingClientRect(); if (RTL_UI) { - newMargin = rect.right - tabRect.right; + newMargin = rect[right] - tabRect[right]; } else { - newMargin = tabRect.left - rect.left; + newMargin = tabRect[left] - rect[left]; } } } ind.hidden = false; - newMargin += ind.clientWidth / 2; - if (RTL_UI) { + newMargin += ind[clientWidth] / 2; + if (RTL_UI && !verticalTabs) { newMargin *= -1; } ind.style.transform = "translate(" + Math.round(newMargin) + "px)"; + + ind.style.transform = + "translate(" + verticalTabs + ? "0, " + : "" + Math.round(newMargin) + "px)"; } on_drop(event) { + const verticalTabs = Services.prefs.getBoolPref( + "zen.tabs.vertical", + false + ); var dt = event.dataTransfer; var dropEffect = dt.dropEffect; var draggedTab; @@ -754,7 +789,7 @@ incrementDropIndex = false; } - if (oldTranslateX && oldTranslateX != newTranslateX && !gReduceMotion) { + if (oldTranslateX && oldTranslateX != newTranslateX && !(gReduceMotion || verticalTabs)) { for (let tab of movingTabs) { tab.toggleAttribute("tabdrop-samewindow", true); tab.style.transform = "translateX(" + newTranslateX + "px)"; @@ -1081,6 +1116,15 @@ return this._allTabs; } let children = Array.from(this.arrowScrollbox.children); + // Zen: We also need to exclude subgroups + // Zen: For example: tab-group(tab1, tab2), tab3, tab-group(tab4) + // Zen: In this case, we need to get [tab1, tab2, tab3, tab4] + // Zen: NOTE: There should be no tab-group inside of a tab-group + for (let i = 0; i < children.length; i++) { + if (children[i].classList.contains("zen-tab-group")) { + children.splice(i, 1, ...children[i].children); + } + } children.pop(); this._allTabs = children; return children; @@ -1476,11 +1520,11 @@ for (let i = numPinned - 1; i >= 0; i--) { let tab = tabs[i]; width += layoutData.pinnedTabWidth; - tab.style.setProperty( - "margin-inline-start", - -(width + layoutData.scrollStartOffset) + "px", - "important" - ); + //tab.style.setProperty( + // "margin-inline-start", + // -(width + layoutData.scrollStartOffset) + "px", + // "important" + //); tab._pinnedUnscrollable = true; } this.style.setProperty( @@ -1515,19 +1559,30 @@ } } - if (!("animLastScreenX" in draggedTab._dragData)) { - draggedTab._dragData.animLastScreenX = draggedTab._dragData.screenX; - } - - let screenX = event.screenX; - if (screenX == draggedTab._dragData.animLastScreenX) { - return; + const verticalTabs = Services.prefs.getBoolPref( + "zen.tabs.vertical", + false + ); + const animLastScreen = verticalTabs + ? "animLastScreenY" + : "animLastScreenX"; + const screen = verticalTabs ? "screenY" : "screenX"; + const dimensions = verticalTabs ? "height" : "width"; + const scrollEdge = verticalTabs ? "scrollTop" : "scrollLeft"; + const scrollDimension = verticalTabs ? "scrollY" : "scrollX"; + const translate = verticalTabs ? "translateY" : "translateX"; + if (!(animLastScreen in draggedTab._dragData)) { + draggedTab._dragData[animLastScreen] = draggedTab._dragData[screen]; + } + let screenX = event[screen]; + if (screenX == draggedTab._dragData[animLastScreen]) { + return; } // Direction of the mouse movement. - let ltrMove = screenX > draggedTab._dragData.animLastScreenX; + let ltrMove = screenX > draggedTab._dragData[animLastScreen]; - draggedTab._dragData.animLastScreenX = screenX; + draggedTab._dragData[animLastScreen] = screenX; let pinned = draggedTab.pinned; let numPinned = gBrowser._numPinnedTabs; @@ -1536,36 +1591,39 @@ pinned ? numPinned : undefined ); - if (RTL_UI) { + if (RTL_UI && !verticalTabs) { tabs.reverse(); // Copy moving tabs array to avoid infinite reversing. movingTabs = [...movingTabs].reverse(); } - let tabWidth = draggedTab.getBoundingClientRect().width; + let tabWidth = draggedTab.getBoundingClientRect()[dimensions]; let shiftWidth = tabWidth * movingTabs.length; + // We want to store the output value as the width and the height to force + // compatibility with code elsewhere draggedTab._dragData.tabWidth = tabWidth; + draggedTab._dragData.tabHeight = tabWidth; // Move the dragged tab based on the mouse position. let leftTab = tabs[0]; let rightTab = tabs[tabs.length - 1]; - let rightMovingTabScreenX = movingTabs[movingTabs.length - 1].screenX; - let leftMovingTabScreenX = movingTabs[0].screenX; - let translateX = screenX - draggedTab._dragData.screenX; + let rightMovingTabScreenX = movingTabs[movingTabs.length - 1][screen]; + let leftMovingTabScreenX = movingTabs[0][screen]; + let translateX = screenX - draggedTab._dragData[screen]; if (!pinned) { translateX += - this.arrowScrollbox.scrollbox.scrollLeft - - draggedTab._dragData.scrollX; + this.arrowScrollbox.scrollbox[scrollEdge] - + draggedTab._dragData[scrollDimension]; } - let leftBound = leftTab.screenX - leftMovingTabScreenX; + let leftBound = leftTab[screen] - leftMovingTabScreenX; let rightBound = - rightTab.screenX + - rightTab.getBoundingClientRect().width - + rightTab[screen] + + rightTab.getBoundingClientRect()[dimensions] - (rightMovingTabScreenX + tabWidth); translateX = Math.min(Math.max(translateX, leftBound), rightBound); for (let tab of movingTabs) { - tab.style.transform = "translateX(" + translateX + "px)"; + tab.style.transform = translate + "(" + translateX + "px)"; } draggedTab._dragData.translateX = translateX; @@ -1598,11 +1656,11 @@ if (tabs[mid] == draggedTab && ++mid > high) { break; } - screenX = tabs[mid].screenX + getTabShift(tabs[mid], oldIndex); + screenX = tabs[mid][screen] + getTabShift(tabs[mid], oldIndex); if (screenX > tabCenter) { high = mid - 1; } else if ( - screenX + tabs[mid].getBoundingClientRect().width < + screenX + tabs[mid].getBoundingClientRect()[dimensions] < tabCenter ) { low = mid + 1; @@ -1625,16 +1683,16 @@ for (let tab of tabs) { if (tab != draggedTab) { let shift = getTabShift(tab, newIndex); - tab.style.transform = shift ? "translateX(" + shift + "px)" : ""; + tab.style.transform = shift ? translate + "(" + shift + "px)" : ""; } } function getTabShift(tab, dropIndex) { if (tab._tPos < draggedTab._tPos && tab._tPos >= dropIndex) { - return RTL_UI ? -shiftWidth : shiftWidth; + return RTL_UI && !verticalTabs ? -shiftWidth : shiftWidth; } if (tab._tPos > draggedTab._tPos && tab._tPos < dropIndex) { - return RTL_UI ? shiftWidth : -shiftWidth; + return RTL_UI && !verticalTabs ? shiftWidth : -shiftWidth; } return 0; } @@ -1706,9 +1764,9 @@ // Slide the relevant tabs to their new position. for (let t of this._getVisibleTabs()) { - if (t.groupingTabsData && t.groupingTabsData.translateX) { - let translateX = (RTL_UI ? -1 : 1) * t.groupingTabsData.translateX; - t.style.transform = "translateX(" + translateX + "px)"; + if (t.groupingTabsData && t.groupingTabsData.translateY) { + let translateX = (RTL_UI ? -1 : 1) * t.groupingTabsData.translateY; + t.style.transform = "translateY(" + translateX + "px)"; } }