mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-20 16:55:40 +00:00
Bug 1482472 - Add animation when grouping tabs on drag start for multi-selected tabs. r=jaws
Differential Revision: https://phabricator.services.mozilla.com/D7239 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
abfc8a57a7
commit
5c93d6cac3
@ -216,11 +216,16 @@ panelview[mainview] > .panel-header {
|
||||
pointer-events: none; /* avoid blocking dragover events on scroll buttons */
|
||||
}
|
||||
|
||||
.tabbrowser-tab[tab-grouping],
|
||||
.tabbrowser-tab[tabdrop-samewindow],
|
||||
#tabbrowser-tabs[movingtab] > .tabbrowser-tab[fadein]:not([selected]):not([multiselected]) {
|
||||
transition: transform 200ms var(--animation-easing-function);
|
||||
}
|
||||
|
||||
.tabbrowser-tab[tab-grouping][multiselected]:not([selected]) {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
/* The next 3 rules allow dragging tabs slightly outside of the tabstrip
|
||||
* to make it easier to drag tabs. */
|
||||
#TabsToolbar[movingtab] {
|
||||
|
@ -586,6 +586,7 @@
|
||||
<parameter name="event"/>
|
||||
<body><![CDATA[
|
||||
let draggedTab = event.dataTransfer.mozGetDataAt(TAB_DROP_TYPE, 0);
|
||||
let movingTabs = draggedTab._dragData.movingTabs;
|
||||
|
||||
if (this.getAttribute("movingtab") != "true") {
|
||||
this.setAttribute("movingtab", "true");
|
||||
@ -612,7 +613,7 @@
|
||||
let tabs = this._getVisibleTabs()
|
||||
.slice(pinned ? 0 : numPinned,
|
||||
pinned ? numPinned : undefined);
|
||||
let movingTabs = draggedTab._dragData.movingTabs;
|
||||
|
||||
if (rtl) {
|
||||
tabs.reverse();
|
||||
// Copy moving tabs array to avoid infinite reversing.
|
||||
@ -722,6 +723,180 @@
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!-- Regroup all selected tabs around the
|
||||
tab in param -->
|
||||
<method name="_groupSelectedTabs">
|
||||
<parameter name="tab"/>
|
||||
<body><![CDATA[
|
||||
let draggedTabPos = tab._tPos;
|
||||
let selectedTabs = gBrowser.selectedTabs;
|
||||
let animate = gBrowser.animationsEnabled;
|
||||
|
||||
tab.groupingTabsData = {
|
||||
finished: !animate,
|
||||
};
|
||||
|
||||
|
||||
// Animate left selected tabs
|
||||
|
||||
let insertAtPos = draggedTabPos - 1;
|
||||
for (let i = selectedTabs.indexOf(tab) - 1; i > -1; i--) {
|
||||
let movingTab = selectedTabs[i];
|
||||
insertAtPos = newIndex(movingTab, insertAtPos);
|
||||
|
||||
if (animate) {
|
||||
movingTab.groupingTabsData = {};
|
||||
addAnimationData(movingTab, insertAtPos, "left");
|
||||
} else {
|
||||
gBrowser.moveTabTo(movingTab, insertAtPos);
|
||||
}
|
||||
insertAtPos--;
|
||||
}
|
||||
|
||||
// Animate right selected tabs
|
||||
|
||||
insertAtPos = draggedTabPos + 1;
|
||||
for (let i = selectedTabs.indexOf(tab) + 1; i < selectedTabs.length; i++) {
|
||||
let movingTab = selectedTabs[i];
|
||||
insertAtPos = newIndex(movingTab, insertAtPos);
|
||||
|
||||
if (animate) {
|
||||
movingTab.groupingTabsData = {};
|
||||
addAnimationData(movingTab, insertAtPos, "right");
|
||||
} else {
|
||||
gBrowser.moveTabTo(movingTab, insertAtPos);
|
||||
}
|
||||
insertAtPos++;
|
||||
}
|
||||
|
||||
// Slide the relevant tabs to their new position.
|
||||
let rtl = Services.locale.isAppLocaleRTL ? -1 : 1;
|
||||
for (let t of this._getVisibleTabs()) {
|
||||
if (t.groupingTabsData && t.groupingTabsData.translateX) {
|
||||
let translateX = rtl * t.groupingTabsData.translateX;
|
||||
t.style.transform = "translateX(" + translateX + "px)";
|
||||
}
|
||||
}
|
||||
|
||||
function newIndex(aTab, index) {
|
||||
// Don't allow mixing pinned and unpinned tabs.
|
||||
if (aTab.pinned) {
|
||||
return Math.min(index, gBrowser._numPinnedTabs - 1);
|
||||
}
|
||||
return Math.max(index, gBrowser._numPinnedTabs);
|
||||
}
|
||||
|
||||
function addAnimationData(movingTab, movingTabNewIndex, side) {
|
||||
let movingTabOldIndex = movingTab._tPos;
|
||||
|
||||
if (movingTabOldIndex == movingTabNewIndex) {
|
||||
// movingTab is already at the right position
|
||||
// and thus don't need to be animated.
|
||||
return;
|
||||
}
|
||||
|
||||
let movingTabWidth = movingTab.boxObject.width;
|
||||
let shift = (movingTabNewIndex - movingTabOldIndex) * movingTabWidth;
|
||||
|
||||
movingTab.groupingTabsData.animate = true;
|
||||
movingTab.setAttribute("tab-grouping", "true");
|
||||
|
||||
movingTab.groupingTabsData.translateX = shift;
|
||||
|
||||
let onTransitionEnd = transitionendEvent => {
|
||||
if (transitionendEvent.propertyName != "transform" ||
|
||||
transitionendEvent.originalTarget != movingTab) {
|
||||
return;
|
||||
}
|
||||
movingTab.removeEventListener("transitionend", onTransitionEnd);
|
||||
movingTab.groupingTabsData.newIndex = movingTabNewIndex;
|
||||
movingTab.groupingTabsData.animate = false;
|
||||
};
|
||||
|
||||
movingTab.addEventListener("transitionend", onTransitionEnd);
|
||||
|
||||
// Add animation data for tabs between movingTab (selected
|
||||
// tab moving towards the dragged tab) and draggedTab.
|
||||
// Those tabs in the middle should move in
|
||||
// the opposite direction of movingTab.
|
||||
|
||||
let lowerIndex = Math.min(movingTabOldIndex, draggedTabPos);
|
||||
let higherIndex = Math.max(movingTabOldIndex, draggedTabPos);
|
||||
|
||||
for (let i = lowerIndex + 1; i < higherIndex; i++) {
|
||||
let middleTab = gBrowser.visibleTabs[i];
|
||||
|
||||
if (middleTab.pinned != movingTab.pinned) {
|
||||
// Don't mix pinned and unpinned tabs
|
||||
break;
|
||||
}
|
||||
|
||||
if (middleTab.multiselected) {
|
||||
// Skip because this selected tab should
|
||||
// be shifted towards the dragged Tab.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!middleTab.groupingTabsData || !middleTab.groupingTabsData.translateX) {
|
||||
middleTab.groupingTabsData = { translateX: 0};
|
||||
}
|
||||
if (side == "left") {
|
||||
middleTab.groupingTabsData.translateX -= movingTabWidth;
|
||||
} else {
|
||||
middleTab.groupingTabsData.translateX += movingTabWidth;
|
||||
}
|
||||
|
||||
middleTab.setAttribute("tab-grouping", "true");
|
||||
}
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="_finishGroupSelectedTabs">
|
||||
<parameter name="tab"/>
|
||||
<body><![CDATA[
|
||||
if (!tab.groupingTabsData || tab.groupingTabsData.finished)
|
||||
return;
|
||||
|
||||
tab.groupingTabsData.finished = true;
|
||||
|
||||
let selectedTabs = gBrowser.selectedTabs;
|
||||
let tabIndex = selectedTabs.indexOf(tab);
|
||||
|
||||
// Moving left tabs
|
||||
for (let i = tabIndex - 1; i > -1; i--) {
|
||||
let movingTab = selectedTabs[i];
|
||||
if (movingTab.groupingTabsData.newIndex) {
|
||||
gBrowser.moveTabTo(movingTab, movingTab.groupingTabsData.newIndex);
|
||||
}
|
||||
}
|
||||
|
||||
// Moving right tabs
|
||||
for (let i = tabIndex + 1; i < selectedTabs.length; i++) {
|
||||
let movingTab = selectedTabs[i];
|
||||
if (movingTab.groupingTabsData.newIndex) {
|
||||
gBrowser.moveTabTo(movingTab, movingTab.groupingTabsData.newIndex);
|
||||
}
|
||||
}
|
||||
|
||||
for (let t of this._getVisibleTabs()) {
|
||||
t.style.transform = "";
|
||||
t.removeAttribute("tab-grouping");
|
||||
delete t.groupingTabsData;
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="_isGroupTabsAnimationOver">
|
||||
<body><![CDATA[
|
||||
for (let tab of gBrowser.selectedTabs) {
|
||||
if (tab.groupingTabsData && tab.groupingTabsData.animate)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="handleEvent">
|
||||
<parameter name="aEvent"/>
|
||||
<body><![CDATA[
|
||||
@ -1289,25 +1464,7 @@
|
||||
dt.addElement(tab);
|
||||
|
||||
if (tab.multiselected) {
|
||||
// Regroup all selected tabs around the dragged tab
|
||||
// for multiple tabs dragging
|
||||
let draggedTabPos = tab._tPos;
|
||||
|
||||
// Move left selected tabs
|
||||
let insertAtPos = draggedTabPos - 1;
|
||||
for (let i = selectedTabs.indexOf(tab) - 1; i > -1; i--) {
|
||||
let movingTab = selectedTabs[i];
|
||||
gBrowser.moveTabTo(movingTab, insertAtPos);
|
||||
insertAtPos--;
|
||||
}
|
||||
|
||||
// Move right selected tabs
|
||||
insertAtPos = draggedTabPos + 1;
|
||||
for (let i = selectedTabs.indexOf(tab) + 1; i < selectedTabs.length; i++) {
|
||||
let movingTab = selectedTabs[i];
|
||||
gBrowser.moveTabTo(movingTab, insertAtPos);
|
||||
insertAtPos++;
|
||||
}
|
||||
this._groupSelectedTabs(tab);
|
||||
}
|
||||
|
||||
// Create a canvas to which we capture the current tab.
|
||||
@ -1424,11 +1581,21 @@
|
||||
arrowScrollbox.scrollByPixels((ltr ? 1 : -1) * pixelsToScroll, true);
|
||||
}
|
||||
|
||||
if (effects == "move" &&
|
||||
this == event.dataTransfer.mozGetDataAt(TAB_DROP_TYPE, 0).parentNode) {
|
||||
let draggedTab = event.dataTransfer.mozGetDataAt(TAB_DROP_TYPE, 0);
|
||||
if ((effects == "move" || effects == "copy") &&
|
||||
this == draggedTab.parentNode) {
|
||||
ind.collapsed = true;
|
||||
this._animateTabMove(event);
|
||||
return;
|
||||
|
||||
if (!this._isGroupTabsAnimationOver()) {
|
||||
// Wait for grouping tabs animation to finish
|
||||
return;
|
||||
}
|
||||
this._finishGroupSelectedTabs(draggedTab);
|
||||
|
||||
if (effects == "move") {
|
||||
this._animateTabMove(event);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this._finishAnimateTabMove();
|
||||
@ -1496,6 +1663,7 @@
|
||||
if (!draggedTab)
|
||||
return;
|
||||
movingTabs = draggedTab._dragData.movingTabs;
|
||||
draggedTab.parentNode._finishGroupSelectedTabs(draggedTab);
|
||||
}
|
||||
|
||||
this._tabDropIndicator.collapsed = true;
|
||||
@ -1636,6 +1804,7 @@
|
||||
if (draggedTab.hasAttribute("tabdrop-samewindow"))
|
||||
return;
|
||||
|
||||
this._finishGroupSelectedTabs(draggedTab);
|
||||
this._finishAnimateTabMove();
|
||||
|
||||
if (dt.mozUserCancelled || dt.dropEffect != "none" || this._isCustomizing) {
|
||||
|
@ -2,10 +2,14 @@
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const PREF_MULTISELECT_TABS = "browser.tabs.multiselect";
|
||||
const PREF_ANIMATION = "toolkit.cosmeticAnimations.enabled";
|
||||
|
||||
add_task(async function setPref() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [[PREF_MULTISELECT_TABS, true]],
|
||||
set: [
|
||||
[PREF_MULTISELECT_TABS, true],
|
||||
[PREF_ANIMATION, false],
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user