feat: Improved indentation when dragging tabs and folders (#9908)

* feat: Improved indentation when dragging tabs and folders

* fix: Formatting
This commit is contained in:
octaviusz
2025-08-16 21:09:53 +03:00
committed by GitHub
parent fcaac2ee0c
commit ce2311c086
5 changed files with 66 additions and 53 deletions

View File

@@ -1,5 +1,5 @@
diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/components/tabbrowser/content/tabbrowser.js diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/components/tabbrowser/content/tabbrowser.js
index d80a66a01002e78a9c65545d08fe786328ddf124..50ff735a4621110ff3691186139cabf76482a941 100644 index d80a66a01002e78a9c65545d08fe786328ddf124..94497c80328551ac5bc14179bfc16722ec0c0158 100644
--- a/browser/components/tabbrowser/content/tabbrowser.js --- a/browser/components/tabbrowser/content/tabbrowser.js
+++ b/browser/components/tabbrowser/content/tabbrowser.js +++ b/browser/components/tabbrowser/content/tabbrowser.js
@@ -422,15 +422,60 @@ @@ -422,15 +422,60 @@
@@ -646,7 +646,7 @@ index d80a66a01002e78a9c65545d08fe786328ddf124..50ff735a4621110ff3691186139cabf7
if (neighbor && this.isTab(element) && tabIndex > element._tPos) { if (neighbor && this.isTab(element) && tabIndex > element._tPos) {
neighbor.after(element); neighbor.after(element);
} else { } else {
@@ -6136,22 +6273,26 @@ @@ -6136,22 +6273,23 @@
#moveTabNextTo(element, targetElement, moveBefore = false, metricsContext) { #moveTabNextTo(element, targetElement, moveBefore = false, metricsContext) {
if (this.isTabGroupLabel(targetElement)) { if (this.isTabGroupLabel(targetElement)) {
targetElement = targetElement.group; targetElement = targetElement.group;
@@ -667,9 +667,6 @@ index d80a66a01002e78a9c65545d08fe786328ddf124..50ff735a4621110ff3691186139cabf7
// Don't allow mixing pinned and unpinned tabs. // Don't allow mixing pinned and unpinned tabs.
+ targetElement = gZenGlanceManager.getTabOrGlanceParent(targetElement); + targetElement = gZenGlanceManager.getTabOrGlanceParent(targetElement);
+ if (targetElement?.group?.hasAttribute("split-view-group")) {
+ targetElement = targetElement.group;
+ }
+ if (element.hasAttribute('zen-essential') && !targetElement?.hasAttribute('zen-essential')) { + if (element.hasAttribute('zen-essential') && !targetElement?.hasAttribute('zen-essential')) {
+ targetElement = this.tabsWithoutGlance[this._numZenEssentials - 1]; + targetElement = this.tabsWithoutGlance[this._numZenEssentials - 1];
+ } else + } else
@@ -679,7 +676,7 @@ index d80a66a01002e78a9c65545d08fe786328ddf124..50ff735a4621110ff3691186139cabf7
moveBefore = false; moveBefore = false;
} else if (!element.pinned && targetElement && targetElement.pinned) { } else if (!element.pinned && targetElement && targetElement.pinned) {
// If the caller asks to move an unpinned element next to a pinned // If the caller asks to move an unpinned element next to a pinned
@@ -6165,14 +6306,18 @@ @@ -6165,14 +6303,29 @@
// move the tab group right before the first unpinned tab. // move the tab group right before the first unpinned tab.
// 4. Moving a tab group and the first unpinned tab is grouped: // 4. Moving a tab group and the first unpinned tab is grouped:
// move the tab group right before the first unpinned tab's tab group. // move the tab group right before the first unpinned tab's tab group.
@@ -692,6 +689,17 @@ index d80a66a01002e78a9c65545d08fe786328ddf124..50ff735a4621110ff3691186139cabf7
} }
+ if (!gZenFolders.canDropElement(element, targetElement)) { + if (!gZenFolders.canDropElement(element, targetElement)) {
+ element = element.group; + element = element.group;
+ }
+ // It is necessary to place the check below to avoid inserting an element
+ // inside when the split group is the last element.
+ if (targetElement?.group?.hasAttribute("split-view-group")) {
+ targetElement = targetElement.group;
+ }
+ // When the folder is the last element in the pinned section,
+ // targetElement is a tab with the zen-empty-tab attribute.
+ // If the movement is from top to bottom, it must be redefined as a folder.
+ if (targetElement?.hasAttribute("zen-empty-tab") && !moveBefore) {
+ targetElement = targetElement.group;
+ } + }
let getContainer = () => let getContainer = () =>
@@ -699,7 +707,7 @@ index d80a66a01002e78a9c65545d08fe786328ddf124..50ff735a4621110ff3691186139cabf7
element.pinned element.pinned
? this.tabContainer.pinnedTabsContainer ? this.tabContainer.pinnedTabsContainer
: this.tabContainer; : this.tabContainer;
@@ -6181,7 +6326,7 @@ @@ -6181,7 +6334,7 @@
element, element,
() => { () => {
if (moveBefore) { if (moveBefore) {
@@ -708,7 +716,7 @@ index d80a66a01002e78a9c65545d08fe786328ddf124..50ff735a4621110ff3691186139cabf7
} else if (targetElement) { } else if (targetElement) {
targetElement.after(element); targetElement.after(element);
} else { } else {
@@ -6230,7 +6375,7 @@ @@ -6230,7 +6383,7 @@
if (!this.isTab(aTab)) { if (!this.isTab(aTab)) {
throw new Error("Can only move a tab into a tab group"); throw new Error("Can only move a tab into a tab group");
} }
@@ -717,7 +725,7 @@ index d80a66a01002e78a9c65545d08fe786328ddf124..50ff735a4621110ff3691186139cabf7
return; return;
} }
if (aTab.group && aTab.group.id === aGroup.id) { if (aTab.group && aTab.group.id === aGroup.id) {
@@ -6324,6 +6469,10 @@ @@ -6324,6 +6477,10 @@
moveActionCallback(); moveActionCallback();
@@ -728,7 +736,7 @@ index d80a66a01002e78a9c65545d08fe786328ddf124..50ff735a4621110ff3691186139cabf7
// Clear tabs cache after moving nodes because the order of tabs may have // Clear tabs cache after moving nodes because the order of tabs may have
// changed. // changed.
this.tabContainer._invalidateCachedTabs(); this.tabContainer._invalidateCachedTabs();
@@ -7221,7 +7370,7 @@ @@ -7221,7 +7378,7 @@
// preventDefault(). It will still raise the window if appropriate. // preventDefault(). It will still raise the window if appropriate.
break; break;
} }
@@ -737,7 +745,7 @@ index d80a66a01002e78a9c65545d08fe786328ddf124..50ff735a4621110ff3691186139cabf7
window.focus(); window.focus();
aEvent.preventDefault(); aEvent.preventDefault();
break; break;
@@ -8166,6 +8315,7 @@ @@ -8166,6 +8323,7 @@
aWebProgress.isTopLevel aWebProgress.isTopLevel
) { ) {
this.mTab.setAttribute("busy", "true"); this.mTab.setAttribute("busy", "true");
@@ -745,7 +753,7 @@ index d80a66a01002e78a9c65545d08fe786328ddf124..50ff735a4621110ff3691186139cabf7
gBrowser._tabAttrModified(this.mTab, ["busy"]); gBrowser._tabAttrModified(this.mTab, ["busy"]);
this.mTab._notselectedsinceload = !this.mTab.selected; this.mTab._notselectedsinceload = !this.mTab.selected;
} }
@@ -9157,7 +9307,7 @@ var TabContextMenu = { @@ -9157,7 +9315,7 @@ var TabContextMenu = {
); );
contextUnpinSelectedTabs.hidden = contextUnpinSelectedTabs.hidden =
!this.contextTab.pinned || !this.multiselected; !this.contextTab.pinned || !this.multiselected;
@@ -754,7 +762,7 @@ index d80a66a01002e78a9c65545d08fe786328ddf124..50ff735a4621110ff3691186139cabf7
// Build Ask Chat items // Build Ask Chat items
TabContextMenu.GenAI.buildTabMenu( TabContextMenu.GenAI.buildTabMenu(
document.getElementById("context_askChat"), document.getElementById("context_askChat"),
@@ -9476,6 +9626,7 @@ var TabContextMenu = { @@ -9476,6 +9634,7 @@ var TabContextMenu = {
) )
); );
} else { } else {
@@ -762,3 +770,4 @@ index d80a66a01002e78a9c65545d08fe786328ddf124..50ff735a4621110ff3691186139cabf7
gBrowser.removeTab(this.contextTab, { gBrowser.removeTab(this.contextTab, {
animate: true, animate: true,
...gBrowser.TabMetrics.userTriggeredContext( ...gBrowser.TabMetrics.userTriggeredContext(

View File

@@ -1,5 +1,5 @@
diff --git a/browser/components/tabbrowser/content/tabgroup.js b/browser/components/tabbrowser/content/tabgroup.js diff --git a/browser/components/tabbrowser/content/tabgroup.js b/browser/components/tabbrowser/content/tabgroup.js
index caea196b22b4689f55780a528661d87b52f4e728..ef687c6c693abab2b62023cfa7f44705acc5d04f 100644 index caea196b22b4689f55780a528661d87b52f4e728..54f3be2b115f6b3691792796f758534aec90206d 100644
--- a/browser/components/tabbrowser/content/tabgroup.js --- a/browser/components/tabbrowser/content/tabgroup.js
+++ b/browser/components/tabbrowser/content/tabgroup.js +++ b/browser/components/tabbrowser/content/tabgroup.js
@@ -13,10 +13,12 @@ @@ -13,10 +13,12 @@
@@ -87,7 +87,7 @@ index caea196b22b4689f55780a528661d87b52f4e728..ef687c6c693abab2b62023cfa7f44705
} }
get color() { get color() {
@@ -338,12 +351,57 @@ @@ -338,12 +351,61 @@
tabGroupName, tabGroupName,
}) })
.then(result => { .then(result => {
@@ -144,10 +144,14 @@ index caea196b22b4689f55780a528661d87b52f4e728..ef687c6c693abab2b62023cfa7f44705
+ } + }
+ } + }
+ return true; + return true;
+ }
+
+ get level() {
+ return this.group?.level + 1 || 0;
} }
/** /**
@@ -373,7 +431,7 @@ @@ -373,7 +435,7 @@
*/ */
addTabs(tabs, metricsContext) { addTabs(tabs, metricsContext) {
for (let tab of tabs) { for (let tab of tabs) {
@@ -156,7 +160,7 @@ index caea196b22b4689f55780a528661d87b52f4e728..ef687c6c693abab2b62023cfa7f44705
tab.ownerGlobal.gBrowser.unpinTab(tab); tab.ownerGlobal.gBrowser.unpinTab(tab);
} }
let tabToMove = let tabToMove =
@@ -437,7 +495,7 @@ @@ -437,7 +499,7 @@
*/ */
on_click(event) { on_click(event) {
let isToggleElement = let isToggleElement =
@@ -165,10 +169,11 @@ index caea196b22b4689f55780a528661d87b52f4e728..ef687c6c693abab2b62023cfa7f44705
event.target === this.#overflowCountLabel; event.target === this.#overflowCountLabel;
if (isToggleElement && event.button === 0) { if (isToggleElement && event.button === 0) {
event.preventDefault(); event.preventDefault();
@@ -470,5 +528,6 @@ @@ -470,5 +532,6 @@
} }
} }
+ window.MozTabbrowserTabGroup = MozTabbrowserTabGroup; + window.MozTabbrowserTabGroup = MozTabbrowserTabGroup;
customElements.define("tab-group", MozTabbrowserTabGroup); customElements.define("tab-group", MozTabbrowserTabGroup);
} }

View File

@@ -1,5 +1,5 @@
diff --git a/browser/components/tabbrowser/content/tabs.js b/browser/components/tabbrowser/content/tabs.js diff --git a/browser/components/tabbrowser/content/tabs.js b/browser/components/tabbrowser/content/tabs.js
index e47f735e4e4563c9b7537944628418d1478c068d..1e821868ef0de97e19f46cc63ed03cb77ecf75a9 100644 index e47f735e4e4563c9b7537944628418d1478c068d..858f6aa20bc06701facf75ee673f618464a406ab 100644
--- a/browser/components/tabbrowser/content/tabs.js --- a/browser/components/tabbrowser/content/tabs.js
+++ b/browser/components/tabbrowser/content/tabs.js +++ b/browser/components/tabbrowser/content/tabs.js
@@ -332,7 +332,7 @@ @@ -332,7 +332,7 @@
@@ -455,16 +455,19 @@ index e47f735e4e4563c9b7537944628418d1478c068d..1e821868ef0de97e19f46cc63ed03cb7
let newDropElementIndex; let newDropElementIndex;
if (dropElement) { if (dropElement) {
@@ -2856,7 +2936,7 @@ @@ -2856,7 +2936,10 @@
let shouldCreateGroupOnDrop; let shouldCreateGroupOnDrop;
let dropBefore; let dropBefore;
if (dropElement) { if (dropElement) {
- let dropElementForOverlap = isTabGroupLabel(dropElement) - let dropElementForOverlap = isTabGroupLabel(dropElement)
+ if (dropElement?.group?.hasAttribute("split-view-group") || dropElement.hasAttribute("split-view-group")) {
+ dropElement = dropElement.group.labelElement;
+ }
+ let dropElementForOverlap = isTabGroupLabel(dropElement) && !dropElement.group?.hasAttribute("split-view-group") + let dropElementForOverlap = isTabGroupLabel(dropElement) && !dropElement.group?.hasAttribute("split-view-group")
? dropElement.parentElement ? dropElement.parentElement
: dropElement; : dropElement;
@@ -2876,7 +2956,7 @@ @@ -2876,7 +2959,7 @@
? Services.prefs.getIntPref( ? Services.prefs.getIntPref(
"browser.tabs.dragDrop.moveOverThresholdPercent" "browser.tabs.dragDrop.moveOverThresholdPercent"
) / 100 ) / 100
@@ -473,7 +476,7 @@ index e47f735e4e4563c9b7537944628418d1478c068d..1e821868ef0de97e19f46cc63ed03cb7
moveOverThreshold = Math.min(1, Math.max(0, moveOverThreshold)); moveOverThreshold = Math.min(1, Math.max(0, moveOverThreshold));
let shouldMoveOver = overlapPercent > moveOverThreshold; let shouldMoveOver = overlapPercent > moveOverThreshold;
if (logicalForward && shouldMoveOver) { if (logicalForward && shouldMoveOver) {
@@ -2908,44 +2988,21 @@ @@ -2908,44 +2991,21 @@
// If dragging a group over another group, don't make it look like it is // If dragging a group over another group, don't make it look like it is
// possible to drop the dragged group inside the other group. // possible to drop the dragged group inside the other group.
@@ -523,7 +526,7 @@ index e47f735e4e4563c9b7537944628418d1478c068d..1e821868ef0de97e19f46cc63ed03cb7
// When dragging tab(s) over an ungrouped tab, signal to the user // When dragging tab(s) over an ungrouped tab, signal to the user
// that dropping the tab(s) will create a new tab group. // that dropping the tab(s) will create a new tab group.
shouldCreateGroupOnDrop = shouldCreateGroupOnDrop =
@@ -2955,12 +3012,6 @@ @@ -2955,12 +3015,6 @@
overlapPercent > dragOverGroupingThreshold; overlapPercent > dragOverGroupingThreshold;
if (shouldCreateGroupOnDrop) { if (shouldCreateGroupOnDrop) {
@@ -536,7 +539,7 @@ index e47f735e4e4563c9b7537944628418d1478c068d..1e821868ef0de97e19f46cc63ed03cb7
} else { } else {
this.removeAttribute("movingtab-createGroup"); this.removeAttribute("movingtab-createGroup");
document document
@@ -2987,19 +3038,14 @@ @@ -2987,19 +3041,14 @@
dropElement = dropElementGroup; dropElement = dropElementGroup;
colorCode = undefined; colorCode = undefined;
} else if (isTabGroupLabel(dropElement)) { } else if (isTabGroupLabel(dropElement)) {
@@ -564,7 +567,7 @@ index e47f735e4e4563c9b7537944628418d1478c068d..1e821868ef0de97e19f46cc63ed03cb7
} }
this.#setDragOverGroupColor(colorCode); this.#setDragOverGroupColor(colorCode);
this.toggleAttribute("movingtab-ungroup", !colorCode); this.toggleAttribute("movingtab-ungroup", !colorCode);
@@ -3017,19 +3063,28 @@ @@ -3017,19 +3066,28 @@
dragData.dropElement = dropElement; dragData.dropElement = dropElement;
dragData.dropBefore = dropBefore; dragData.dropBefore = dropBefore;
dragData.animDropElementIndex = newDropElementIndex; dragData.animDropElementIndex = newDropElementIndex;
@@ -595,7 +598,7 @@ index e47f735e4e4563c9b7537944628418d1478c068d..1e821868ef0de97e19f46cc63ed03cb7
} }
item.style.transform = transform; item.style.transform = transform;
} }
@@ -3082,12 +3137,14 @@ @@ -3082,12 +3140,14 @@
); );
} }
@@ -612,7 +615,7 @@ index e47f735e4e4563c9b7537944628418d1478c068d..1e821868ef0de97e19f46cc63ed03cb7
for (let item of this.ariaFocusableItems) { for (let item of this.ariaFocusableItems) {
if (isTabGroupLabel(item)) { if (isTabGroupLabel(item)) {
@@ -3095,6 +3152,18 @@ @@ -3095,6 +3155,18 @@
item = item.parentElement; item = item.parentElement;
} }
item.style.transform = ""; item.style.transform = "";
@@ -631,7 +634,7 @@ index e47f735e4e4563c9b7537944628418d1478c068d..1e821868ef0de97e19f46cc63ed03cb7
item.removeAttribute("dragover-createGroup"); item.removeAttribute("dragover-createGroup");
} }
this.removeAttribute("movingtab-createGroup"); this.removeAttribute("movingtab-createGroup");
@@ -3198,7 +3267,7 @@ @@ -3198,7 +3270,7 @@
let postTransitionCleanup = () => { let postTransitionCleanup = () => {
movingTab._moveTogetherSelectedTabsData.animate = false; movingTab._moveTogetherSelectedTabsData.animate = false;
}; };
@@ -640,7 +643,7 @@ index e47f735e4e4563c9b7537944628418d1478c068d..1e821868ef0de97e19f46cc63ed03cb7
postTransitionCleanup(); postTransitionCleanup();
} else { } else {
let onTransitionEnd = transitionendEvent => { let onTransitionEnd = transitionendEvent => {
@@ -3371,7 +3440,7 @@ @@ -3371,7 +3443,7 @@
} }
_notifyBackgroundTab(aTab) { _notifyBackgroundTab(aTab) {
@@ -649,7 +652,7 @@ index e47f735e4e4563c9b7537944628418d1478c068d..1e821868ef0de97e19f46cc63ed03cb7
return; return;
} }
@@ -3480,7 +3549,10 @@ @@ -3480,7 +3552,10 @@
#getDragTarget(event, { ignoreSides = false } = {}) { #getDragTarget(event, { ignoreSides = false } = {}) {
let { target } = event; let { target } = event;
while (target) { while (target) {
@@ -661,7 +664,7 @@ index e47f735e4e4563c9b7537944628418d1478c068d..1e821868ef0de97e19f46cc63ed03cb7
break; break;
} }
target = target.parentNode; target = target.parentNode;
@@ -3497,6 +3569,9 @@ @@ -3497,6 +3572,9 @@
return null; return null;
} }
} }

View File

@@ -179,10 +179,6 @@
return items; return items;
} }
get level() {
return this.group?.level + 1 || 0;
}
get allItems() { get allItems() {
return [...this.querySelector('.tab-group-container').children].filter( return [...this.querySelector('.tab-group-container').children].filter(
(child) => !child.classList.contains('zen-tab-group-start') (child) => !child.classList.contains('zen-tab-group-start')

View File

@@ -887,26 +887,30 @@
return []; return [];
} }
setFolderIndentation(tabs, group = undefined, forCollapse = true) { setFolderIndentation(tabs, groupElem = undefined, forCollapse = true) {
if (!gZenPinnedTabManager.expandedSidebarMode) { if (!gZenPinnedTabManager.expandedSidebarMode) {
return; return;
} }
const tab = tabs[0]; const tab = tabs[0];
let isTab = false; let isTab = false;
if (!group && tab?.group) { if (!groupElem && tab?.group) {
group = tab; // So we can set isTab later groupElem = tab; // So we can set isTab later
} }
if ( if (
gBrowser.isTab(group) && gBrowser.isTab(groupElem) &&
!(group.hasAttribute('zen-empty-tab') && group.group === tab.group) !(groupElem.hasAttribute('zen-empty-tab') && groupElem.group === tab.group)
) { ) {
group = group.group; groupElem = groupElem.group;
isTab = true; isTab = true;
} }
if (!isTab && !group?.hasAttribute('selected') && !forCollapse) { if (!isTab && !groupElem?.hasAttribute('selected') && !forCollapse) {
group = null; // Don't indent if the group is not selected groupElem = null; // Don't indent if the group is not selected
}
let level = groupElem?.level + 1 || 0;
if (gBrowser.isTabGroupLabel(groupElem)) {
// If it is a group label, we should not increase its level by one.
level = groupElem.group.level;
} }
const level = group?.level + 1 || 0;
const baseSpacing = 14; // Base spacing for each level const baseSpacing = 14; // Base spacing for each level
let tabToAnimate = tab; let tabToAnimate = tab;
if (gBrowser.isTabGroupLabel(tab)) { if (gBrowser.isTabGroupLabel(tab)) {
@@ -1348,10 +1352,11 @@
let dragDownThreshold = let dragDownThreshold =
Services.prefs.getIntPref('zen.view.drag-and-drop.drop-inside-lower-threshold') / 100; Services.prefs.getIntPref('zen.view.drag-and-drop.drop-inside-lower-threshold') / 100;
let dropElementGroup = dropElement.group; const dropElementGroup = dropElement.group;
const isSplitGroup = dropElement?.group?.hasAttribute('split-view-group'); const isSplitGroup = dropElement?.group?.hasAttribute('split-view-group');
let firstGroupElem = let firstGroupElem =
dropElementGroup.querySelector('.zen-tab-group-start').nextElementSibling; dropElementGroup.querySelector('.zen-tab-group-start').nextElementSibling;
if (gBrowser.isTabGroup(firstGroupElem)) firstGroupElem = firstGroupElem.labelElement;
const isRestrictedGroup = isSplitGroup || dropElementGroup.collapsed; const isRestrictedGroup = isSplitGroup || dropElementGroup.collapsed;
@@ -1368,16 +1373,11 @@
this.highlightGroupOnDragOver(dropElementGroup, movingTabs); this.highlightGroupOnDragOver(dropElementGroup, movingTabs);
} else if (shouldDropNear) { } else if (shouldDropNear) {
if (dropBefore) { if (dropBefore) {
dropElement = dropElementGroup;
colorCode = undefined; colorCode = undefined;
} else { } else if (!isRestrictedGroup) {
if (isRestrictedGroup) {
dropElement = dropElementGroup;
} else {
dropElement = firstGroupElem; dropElement = firstGroupElem;
dropBefore = true; dropBefore = true;
} }
}
this.highlightGroupOnDragOver(null); this.highlightGroupOnDragOver(null);
} }