mirror of
https://github.com/zen-browser/desktop.git
synced 2026-08-18 04:22:12 +00:00
feat: Added transitions when reordering, b=no-bug, c=split-view, tabs
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
diff --git a/browser/components/tabbrowser/content/drag-and-drop.js b/browser/components/tabbrowser/content/drag-and-drop.js
|
||||
index 97b931c3c7385a52d20204369fcf6d6999053687..4fa28e4c00b746b34e63b3ece15b79edfecd9117 100644
|
||||
index 97b931c3c7385a52d20204369fcf6d6999053687..78c8f0ad686e72d281370c934d2dbf5f70311117 100644
|
||||
--- a/browser/components/tabbrowser/content/drag-and-drop.js
|
||||
+++ b/browser/components/tabbrowser/content/drag-and-drop.js
|
||||
@@ -32,6 +32,9 @@
|
||||
@@ -22,15 +22,12 @@ index 97b931c3c7385a52d20204369fcf6d6999053687..4fa28e4c00b746b34e63b3ece15b79ed
|
||||
if (
|
||||
(dropEffect == "move" || dropEffect == "copy") &&
|
||||
document == draggedTab.ownerDocument &&
|
||||
@@ -266,6 +272,18 @@
|
||||
@@ -266,6 +272,15 @@
|
||||
|
||||
this._tabDropIndicator.hidden = true;
|
||||
event.stopPropagation();
|
||||
+ if (draggedTab?.hasAttribute("zen-has-splitted")) {
|
||||
+ draggedTab.removeAttribute("zen-has-splitted");
|
||||
+ draggedTab._visuallySelected = false;
|
||||
+ }
|
||||
+ if (draggedTab && dropEffect == "move") {
|
||||
+ this.handle_drop_transition?.(draggedTab._dragData.dropElement, draggedTab, movingTabs, draggedTab._dragData.dropBefore);
|
||||
+ let moved = gZenPinnedTabManager.moveToAnotherTabContainerIfNecessary(event, movingTabs);
|
||||
+
|
||||
+ if (moved) {
|
||||
@@ -41,7 +38,7 @@ index 97b931c3c7385a52d20204369fcf6d6999053687..4fa28e4c00b746b34e63b3ece15b79ed
|
||||
if (draggedTab && dropEffect == "copy") {
|
||||
let duplicatedDraggedTab;
|
||||
let duplicatedTabs = [];
|
||||
@@ -291,8 +309,9 @@
|
||||
@@ -291,8 +306,9 @@
|
||||
let translateOffsetY = oldTranslateY % tabHeight;
|
||||
let newTranslateX = oldTranslateX - translateOffsetX;
|
||||
let newTranslateY = oldTranslateY - translateOffsetY;
|
||||
@@ -53,7 +50,7 @@ index 97b931c3c7385a52d20204369fcf6d6999053687..4fa28e4c00b746b34e63b3ece15b79ed
|
||||
|
||||
if (this._isContainerVerticalPinnedGrid(draggedTab)) {
|
||||
// Update both translate axis for pinned vertical expanded tabs
|
||||
@@ -308,8 +327,8 @@
|
||||
@@ -308,8 +324,8 @@
|
||||
}
|
||||
} else {
|
||||
let tabs = this._tabbrowserTabs.ariaFocusableItems.slice(
|
||||
@@ -64,7 +61,7 @@ index 97b931c3c7385a52d20204369fcf6d6999053687..4fa28e4c00b746b34e63b3ece15b79ed
|
||||
);
|
||||
let size = this._tabbrowserTabs.verticalMode ? "height" : "width";
|
||||
let screenAxis = this._tabbrowserTabs.verticalMode
|
||||
@@ -362,11 +381,13 @@
|
||||
@@ -362,11 +378,13 @@
|
||||
this._dragToPinPromoCard,
|
||||
];
|
||||
let shouldPin =
|
||||
@@ -78,7 +75,7 @@ index 97b931c3c7385a52d20204369fcf6d6999053687..4fa28e4c00b746b34e63b3ece15b79ed
|
||||
isTab(draggedTab) &&
|
||||
draggedTab.pinned &&
|
||||
this._tabbrowserTabs.arrowScrollbox.contains(event.target);
|
||||
@@ -384,6 +405,7 @@
|
||||
@@ -384,6 +402,7 @@
|
||||
(oldTranslateY && oldTranslateY != newTranslateY);
|
||||
} else if (this._tabbrowserTabs.verticalMode) {
|
||||
shouldTranslate &&= oldTranslateY && oldTranslateY != newTranslateY;
|
||||
@@ -86,7 +83,7 @@ index 97b931c3c7385a52d20204369fcf6d6999053687..4fa28e4c00b746b34e63b3ece15b79ed
|
||||
} else {
|
||||
shouldTranslate &&= oldTranslateX && oldTranslateX != newTranslateX;
|
||||
}
|
||||
@@ -440,7 +462,7 @@
|
||||
@@ -440,7 +459,7 @@
|
||||
item.removeAttribute("tabdrop-samewindow");
|
||||
resolve();
|
||||
};
|
||||
@@ -95,7 +92,7 @@ index 97b931c3c7385a52d20204369fcf6d6999053687..4fa28e4c00b746b34e63b3ece15b79ed
|
||||
postTransitionCleanup();
|
||||
} else {
|
||||
let onTransitionEnd = transitionendEvent => {
|
||||
@@ -581,6 +603,7 @@
|
||||
@@ -581,6 +600,7 @@
|
||||
|
||||
let nextItem = this._tabbrowserTabs.ariaFocusableItems[newIndex];
|
||||
let tabGroup = isTab(nextItem) && nextItem.group;
|
||||
@@ -103,7 +100,7 @@ index 97b931c3c7385a52d20204369fcf6d6999053687..4fa28e4c00b746b34e63b3ece15b79ed
|
||||
gBrowser.loadTabs(urls, {
|
||||
inBackground,
|
||||
replace,
|
||||
@@ -618,7 +641,16 @@
|
||||
@@ -618,7 +638,16 @@
|
||||
this._expandGroupOnDrop(draggedTab);
|
||||
}
|
||||
this._resetTabsAfterDrop(draggedTab.ownerDocument);
|
||||
@@ -121,7 +118,7 @@ index 97b931c3c7385a52d20204369fcf6d6999053687..4fa28e4c00b746b34e63b3ece15b79ed
|
||||
if (
|
||||
dt.mozUserCancelled ||
|
||||
dt.dropEffect != "none" ||
|
||||
@@ -822,7 +854,10 @@
|
||||
@@ -822,7 +851,10 @@
|
||||
_getDragTarget(event, { ignoreSides = false } = {}) {
|
||||
let { target } = event;
|
||||
while (target) {
|
||||
@@ -133,7 +130,7 @@ index 97b931c3c7385a52d20204369fcf6d6999053687..4fa28e4c00b746b34e63b3ece15b79ed
|
||||
break;
|
||||
}
|
||||
target = target.parentNode;
|
||||
@@ -839,14 +874,17 @@
|
||||
@@ -839,14 +871,17 @@
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -153,7 +150,7 @@ index 97b931c3c7385a52d20204369fcf6d6999053687..4fa28e4c00b746b34e63b3ece15b79ed
|
||||
!this._tabbrowserTabs.expandOnHover
|
||||
);
|
||||
}
|
||||
@@ -877,7 +915,8 @@
|
||||
@@ -877,7 +912,8 @@
|
||||
isTabGroupLabel(draggedTab) &&
|
||||
draggedTab._dragData?.expandGroupOnDrop
|
||||
) {
|
||||
@@ -163,7 +160,7 @@ index 97b931c3c7385a52d20204369fcf6d6999053687..4fa28e4c00b746b34e63b3ece15b79ed
|
||||
}
|
||||
}
|
||||
|
||||
@@ -942,10 +981,7 @@
|
||||
@@ -942,10 +978,7 @@
|
||||
if (this._isContainerVerticalPinnedGrid(tab)) {
|
||||
// In expanded vertical mode, the max number of pinned tabs per row is dynamic
|
||||
// Set this before adjusting dragged tab's position
|
||||
@@ -175,7 +172,7 @@ index 97b931c3c7385a52d20204369fcf6d6999053687..4fa28e4c00b746b34e63b3ece15b79ed
|
||||
let tabsPerRow = 0;
|
||||
let position = RTL_UI
|
||||
? window.windowUtils.getBoundsWithoutFlushing(
|
||||
@@ -1055,7 +1091,6 @@
|
||||
@@ -1055,7 +1088,6 @@
|
||||
// using updateDragImage. On Linux, we can use a panel.
|
||||
if (platform == "win" || platform == "macosx") {
|
||||
captureListener = function () {
|
||||
@@ -183,7 +180,7 @@ index 97b931c3c7385a52d20204369fcf6d6999053687..4fa28e4c00b746b34e63b3ece15b79ed
|
||||
};
|
||||
} else {
|
||||
// Create a panel to use it in setDragImage
|
||||
@@ -1093,7 +1128,6 @@
|
||||
@@ -1093,7 +1125,6 @@
|
||||
);
|
||||
dragImageOffset = dragImageOffset * scale;
|
||||
}
|
||||
@@ -191,7 +188,7 @@ index 97b931c3c7385a52d20204369fcf6d6999053687..4fa28e4c00b746b34e63b3ece15b79ed
|
||||
|
||||
// _dragData.offsetX/Y give the coordinates that the mouse should be
|
||||
// positioned relative to the corner of the new window created upon
|
||||
@@ -1112,7 +1146,7 @@
|
||||
@@ -1112,7 +1143,7 @@
|
||||
let dropEffect = this.getDropEffectForTabDrag(event);
|
||||
let isMovingInTabStrip = !fromTabList && dropEffect == "move";
|
||||
let collapseTabGroupDuringDrag =
|
||||
@@ -200,7 +197,7 @@ index 97b931c3c7385a52d20204369fcf6d6999053687..4fa28e4c00b746b34e63b3ece15b79ed
|
||||
|
||||
tab._dragData = {
|
||||
offsetX: this._tabbrowserTabs.verticalMode
|
||||
@@ -1122,7 +1156,7 @@
|
||||
@@ -1122,7 +1153,7 @@
|
||||
? event.screenY - window.screenY - tabOffset
|
||||
: event.screenY - window.screenY,
|
||||
scrollPos:
|
||||
@@ -209,7 +206,7 @@ index 97b931c3c7385a52d20204369fcf6d6999053687..4fa28e4c00b746b34e63b3ece15b79ed
|
||||
? this._tabbrowserTabs.pinnedTabsContainer.scrollPosition
|
||||
: this._tabbrowserTabs.arrowScrollbox.scrollPosition,
|
||||
screenX: event.screenX,
|
||||
@@ -1149,6 +1183,7 @@
|
||||
@@ -1149,6 +1180,7 @@
|
||||
|
||||
if (collapseTabGroupDuringDrag) {
|
||||
tab.group.collapsed = true;
|
||||
@@ -217,7 +214,7 @@ index 97b931c3c7385a52d20204369fcf6d6999053687..4fa28e4c00b746b34e63b3ece15b79ed
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1173,6 +1208,7 @@
|
||||
@@ -1173,6 +1205,7 @@
|
||||
if (tabStripItemElement.hasAttribute("dragtarget")) {
|
||||
return;
|
||||
}
|
||||
@@ -225,7 +222,7 @@ index 97b931c3c7385a52d20204369fcf6d6999053687..4fa28e4c00b746b34e63b3ece15b79ed
|
||||
let isPinned = tab.pinned;
|
||||
let numPinned = gBrowser.pinnedTabCount;
|
||||
let allTabs = this._tabbrowserTabs.ariaFocusableItems;
|
||||
@@ -1624,10 +1660,7 @@
|
||||
@@ -1624,10 +1657,7 @@
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -237,7 +234,7 @@ index 97b931c3c7385a52d20204369fcf6d6999053687..4fa28e4c00b746b34e63b3ece15b79ed
|
||||
|
||||
let directionX = screenX > dragData.animLastScreenX;
|
||||
let directionY = screenY > dragData.animLastScreenY;
|
||||
@@ -1636,6 +1669,8 @@
|
||||
@@ -1636,6 +1666,8 @@
|
||||
|
||||
let { width: tabWidth, height: tabHeight } =
|
||||
draggedTab.getBoundingClientRect();
|
||||
@@ -246,7 +243,7 @@ index 97b931c3c7385a52d20204369fcf6d6999053687..4fa28e4c00b746b34e63b3ece15b79ed
|
||||
let shiftSizeX = tabWidth * movingTabs.length;
|
||||
let shiftSizeY = tabHeight;
|
||||
dragData.tabWidth = tabWidth;
|
||||
@@ -1672,8 +1707,8 @@
|
||||
@@ -1672,8 +1704,8 @@
|
||||
let lastBoundX =
|
||||
lastTabInRow.screenX +
|
||||
lastTabInRow.getBoundingClientRect().width -
|
||||
@@ -257,15 +254,7 @@ index 97b931c3c7385a52d20204369fcf6d6999053687..4fa28e4c00b746b34e63b3ece15b79ed
|
||||
translateX = Math.min(Math.max(translateX, firstBoundX), lastBoundX);
|
||||
translateY = Math.min(Math.max(translateY, firstBoundY), lastBoundY);
|
||||
|
||||
@@ -2417,6 +2452,7 @@
|
||||
}
|
||||
|
||||
finishAnimateTabMove() {
|
||||
+ gZenPinnedTabManager.onDragFinish();
|
||||
if (!this.#isMovingTab()) {
|
||||
return;
|
||||
}
|
||||
@@ -2457,7 +2493,7 @@
|
||||
@@ -2457,7 +2489,7 @@
|
||||
tab.style.left = "";
|
||||
tab.style.top = "";
|
||||
tab.style.maxWidth = "";
|
||||
@@ -274,7 +263,7 @@ index 97b931c3c7385a52d20204369fcf6d6999053687..4fa28e4c00b746b34e63b3ece15b79ed
|
||||
}
|
||||
for (let label of draggedTabDocument.getElementsByClassName(
|
||||
"tab-group-label-container"
|
||||
@@ -2467,7 +2503,7 @@
|
||||
@@ -2467,7 +2499,7 @@
|
||||
label.style.left = "";
|
||||
label.style.top = "";
|
||||
label.style.maxWidth = "";
|
||||
|
||||
@@ -474,6 +474,16 @@
|
||||
return this._tabbrowserTabs.hasAttribute('movingtab');
|
||||
}
|
||||
|
||||
get #dragShiftableItems() {
|
||||
const separator = gZenWorkspaces.pinnedTabsContainer.querySelector(
|
||||
'.pinned-tabs-container-separator'
|
||||
);
|
||||
// Make sure to always return the separator at the start of the array
|
||||
return Services.prefs.getBoolPref('zen.view.show-newtab-button-top')
|
||||
? [separator, gZenWorkspaces.activeWorkspaceElement.newTabButton]
|
||||
: [separator];
|
||||
}
|
||||
|
||||
handle_dragover(event) {
|
||||
super.handle_dragover(event);
|
||||
if (event.target.closest('#tabbrowser-tabbox')) {
|
||||
@@ -518,6 +528,74 @@
|
||||
}
|
||||
}
|
||||
|
||||
handle_drop_transition(dropElement, draggedTab, movingTabs, dropBefore) {
|
||||
if (
|
||||
gReduceMotion ||
|
||||
dropElement.group !== draggedTab.group ||
|
||||
dropElement.hasAttribute('zen-essential') ||
|
||||
draggedTab.hasAttribute('zen-essential')
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const animateElement = (ele, translateY) => {
|
||||
ele.style.transform = `translateY(${translateY}px)`;
|
||||
setTimeout(() => {
|
||||
setTimeout(() => {
|
||||
gZenUIManager.motion
|
||||
.animate(
|
||||
ele,
|
||||
{
|
||||
y: [translateY, 0],
|
||||
},
|
||||
{
|
||||
duration: 0.1,
|
||||
bounce: 0,
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
ele.style.transform = '';
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
const items = this._tabbrowserTabs.ariaFocusableItems;
|
||||
let rect = window.windowUtils.getBoundsWithoutFlushing(draggedTab);
|
||||
let tabsInBetween = [];
|
||||
let startIndex = Math.min(draggedTab.elementIndex, dropElement.elementIndex + !dropBefore);
|
||||
let endIndex = Math.max(draggedTab.elementIndex, dropElement.elementIndex - dropBefore);
|
||||
for (let i = startIndex; i <= endIndex; i++) {
|
||||
let tab = items[i];
|
||||
if (!movingTabs.includes(tab) && isTab(tab)) {
|
||||
tabsInBetween.push(tab);
|
||||
}
|
||||
}
|
||||
let extraTranslate = 0;
|
||||
let translateY =
|
||||
draggedTab.elementIndex > dropElement.elementIndex ? -rect.height : rect.height;
|
||||
translateY *= movingTabs.length;
|
||||
if (draggedTab.pinned != dropElement.pinned) {
|
||||
const shiftableItems = this.#dragShiftableItems;
|
||||
for (let item of shiftableItems) {
|
||||
// We also need to animate these shiftable items and add it to the extraTranslate
|
||||
// so the dragged tab ends up in the right position.
|
||||
let itemRect = window.windowUtils.getBoundsWithoutFlushing(item);
|
||||
extraTranslate += itemRect.height;
|
||||
animateElement(item, translateY);
|
||||
}
|
||||
}
|
||||
// Animate tabs in between moving out of the way
|
||||
for (let tab of tabsInBetween) {
|
||||
animateElement(tab, translateY);
|
||||
}
|
||||
let draggedTabTranslateY =
|
||||
draggedTab.elementIndex > dropElement.elementIndex
|
||||
? rect.height * tabsInBetween.length
|
||||
: -rect.height * tabsInBetween.length;
|
||||
draggedTabTranslateY +=
|
||||
extraTranslate * (draggedTab.elementIndex > dropElement.elementIndex ? 1 : -1);
|
||||
animateElement(draggedTab, draggedTabTranslateY);
|
||||
}
|
||||
|
||||
handle_dragend(event) {
|
||||
this.ZenDragAndDropService.onDragEnd();
|
||||
super.handle_dragend(event);
|
||||
|
||||
@@ -437,7 +437,6 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature {
|
||||
return;
|
||||
}
|
||||
const side = this.fakeBrowser.getAttribute('side');
|
||||
if (this._draggingTab) this._draggingTab.setAttribute('zen-has-splitted', 'true');
|
||||
this._lastOpenedTab = gBrowser.selectedTab;
|
||||
this._draggingTab = null;
|
||||
event.dataTransfer.updateDragImage(
|
||||
|
||||
@@ -662,45 +662,6 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
|
||||
}
|
||||
}
|
||||
|
||||
onDragFinish() {
|
||||
for (const item of this.dragShiftableItems) {
|
||||
item.style.transform = '';
|
||||
}
|
||||
delete this._topToNormalTabs;
|
||||
for (const item of gBrowser.tabContainer.ariaFocusableItems) {
|
||||
if (gBrowser.isTab(item)) {
|
||||
let isVisible = true;
|
||||
let parent = item.group;
|
||||
while (parent) {
|
||||
if (!parent.visible) {
|
||||
isVisible = false;
|
||||
break;
|
||||
}
|
||||
parent = parent.group;
|
||||
}
|
||||
if (!isVisible) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
const itemToAnimate =
|
||||
item.group?.hasAttribute('split-view-group') || gBrowser.isTabGroupLabel(item)
|
||||
? item.group
|
||||
: item;
|
||||
itemToAnimate.style.removeProperty('--zen-folder-indent');
|
||||
}
|
||||
this.removeTabContainersDragoverClass();
|
||||
}
|
||||
|
||||
get dragShiftableItems() {
|
||||
const separator = gZenWorkspaces.pinnedTabsContainer.querySelector(
|
||||
'.pinned-tabs-container-separator'
|
||||
);
|
||||
// Make sure to always return the separator at the start of the array
|
||||
return Services.prefs.getBoolPref('zen.view.show-newtab-button-top')
|
||||
? [separator, gZenWorkspaces.activeWorkspaceElement.newTabButton]
|
||||
: [separator];
|
||||
}
|
||||
|
||||
get dragIndicator() {
|
||||
if (!this._dragIndicator) {
|
||||
this._dragIndicator = document.createElement('div');
|
||||
|
||||
Reference in New Issue
Block a user