mirror of
https://github.com/zen-browser/desktop.git
synced 2026-01-03 20:12:43 +00:00
fix: animateUnload for folder, p=#10440
* fix: `animateUnload` for folder * fix: Formatting * fix: Some fixes * fix: Formatting * fix: Fix unloading split views, b=no-bug, c=folders, split-view * test: Fixed tests, b=no-bug, c=folders, tabs Signed-off-by: mr. m <91018726+mr-cheffy@users.noreply.github.com> --------- Signed-off-by: mr. m <91018726+mr-cheffy@users.noreply.github.com>
This commit is contained in:
@@ -144,6 +144,10 @@
|
||||
return activeGroups;
|
||||
}
|
||||
|
||||
get childActiveGroups() {
|
||||
return Array.from(this.querySelectorAll('zen-folder[has-active]'));
|
||||
}
|
||||
|
||||
rename() {
|
||||
if (!document.documentElement.hasAttribute('zen-sidebar-expanded')) {
|
||||
return;
|
||||
@@ -246,6 +250,7 @@
|
||||
let activeGroup = folders.get(group?.id);
|
||||
if (!activeGroup) {
|
||||
tab.removeAttribute('folder-active');
|
||||
tab.style.removeProperty('--zen-folder-indent');
|
||||
}
|
||||
}
|
||||
this._activeTabs = [];
|
||||
@@ -266,12 +271,10 @@
|
||||
}
|
||||
|
||||
async #unloadAllActiveTabs(event, noClose = false) {
|
||||
for (const tab of this.tabs) {
|
||||
await gZenPinnedTabManager._onCloseTabShortcut(event, tab, {
|
||||
noClose,
|
||||
expandSplitViewList: false,
|
||||
});
|
||||
}
|
||||
await gZenPinnedTabManager._onCloseTabShortcut(event, this.tabs, {
|
||||
noClose,
|
||||
folderToUnload: this,
|
||||
});
|
||||
this.activeTabs = [];
|
||||
}
|
||||
|
||||
|
||||
@@ -1398,7 +1398,7 @@
|
||||
|
||||
const groupStart = group.querySelector('.zen-tab-group-start');
|
||||
const itemsToShow = this.#normalizeGroupItems(group.childGroupsAndTabs);
|
||||
const activeFolders = Array.from(group.querySelectorAll('zen-folder[has-active]'));
|
||||
const activeFolders = group.childActiveGroups;
|
||||
|
||||
for (const folder of activeFolders) {
|
||||
const splitViewIds = new Set();
|
||||
@@ -1502,6 +1502,45 @@
|
||||
this.styleCleanup(itemsToHide);
|
||||
}
|
||||
|
||||
async animateUnloadAll(group) {
|
||||
const animations = [];
|
||||
|
||||
const activeGroups = [group, ...group.childActiveGroups];
|
||||
for (const folder of activeGroups) {
|
||||
folder.removeAttribute('has-active');
|
||||
folder.activeTabs = [];
|
||||
const groupItems = this.#normalizeGroupItems(folder.allItems);
|
||||
const tabsContainer = folder.querySelector('.tab-group-container');
|
||||
|
||||
this.styleCleanup(groupItems);
|
||||
|
||||
const groupStart = folder.querySelector('.zen-tab-group-start');
|
||||
|
||||
// Trigger a reflow
|
||||
tabsContainer.offsetHeight;
|
||||
// tabsContainer.setAttribute('hidden', true);
|
||||
|
||||
const heightUntilSelected = this.#calculateHeightShift(tabsContainer, []);
|
||||
|
||||
// Collect animations for this specific folder becoming inactive
|
||||
animations.push(
|
||||
...this.updateFolderIcon(folder, 'close', false),
|
||||
...this.#createAnimation(
|
||||
groupStart,
|
||||
{
|
||||
marginTop: -(heightUntilSelected + 4),
|
||||
},
|
||||
{ duration: 0.12, ease: 'easeInOut' }
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
this.#animationCount += 1;
|
||||
await Promise.all(animations);
|
||||
this.#animationCount -= 1;
|
||||
gBrowser.tabContainer._invalidateCachedTabs();
|
||||
}
|
||||
|
||||
async animateUnload(group, tabToUnload, ungroup = false) {
|
||||
const isSplitView = tabToUnload.group?.hasAttribute('split-view-group');
|
||||
if ((!group?.isZenFolder || !isSplitView) && !tabToUnload.hasAttribute('folder-active'))
|
||||
@@ -1513,29 +1552,34 @@
|
||||
folder.activeTabs = folder.activeTabs.filter((tab) => tab !== tabToUnload);
|
||||
|
||||
if (folder.activeTabs.length === 0) {
|
||||
folder.removeAttribute('has-active');
|
||||
const groupItems = this.#normalizeGroupItems(folder.allItems);
|
||||
const tabsContainer = folder.querySelector('.tab-group-container');
|
||||
animations.push(async () => {
|
||||
folder.removeAttribute('has-active');
|
||||
const groupItems = this.#normalizeGroupItems(folder.allItems);
|
||||
const tabsContainer = folder.querySelector('.tab-group-container');
|
||||
|
||||
this.styleCleanup(groupItems);
|
||||
this.styleCleanup(groupItems);
|
||||
|
||||
const groupStart = folder.querySelector('.zen-tab-group-start');
|
||||
const groupStart = folder.querySelector('.zen-tab-group-start');
|
||||
|
||||
tabsContainer.offsetHeight;
|
||||
tabsContainer.setAttribute('hidden', true);
|
||||
// Trigger a reflow
|
||||
tabsContainer.offsetHeight;
|
||||
tabsContainer.setAttribute('hidden', true);
|
||||
|
||||
const heightUntilSelected = this.#calculateHeightShift(tabsContainer, []);
|
||||
const heightUntilSelected = this.#calculateHeightShift(tabsContainer, []);
|
||||
|
||||
animations.push(
|
||||
...this.updateFolderIcon(folder, 'close', false),
|
||||
...this.#createAnimation(
|
||||
groupStart,
|
||||
{
|
||||
marginTop: -(heightUntilSelected + 4),
|
||||
},
|
||||
{ duration: 0.12, ease: 'easeInOut' }
|
||||
)
|
||||
);
|
||||
// Collect animations for this specific folder becoming inactive
|
||||
const folderAnimation = [
|
||||
...this.updateFolderIcon(folder, 'close', false),
|
||||
...this.#createAnimation(
|
||||
groupStart,
|
||||
{
|
||||
marginTop: -(heightUntilSelected + 4),
|
||||
},
|
||||
{ duration: 0.12, ease: 'easeInOut' }
|
||||
),
|
||||
];
|
||||
await Promise.all(folderAnimation);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1546,24 +1590,27 @@
|
||||
|
||||
tabToUnload.style.removeProperty('--zen-folder-indent');
|
||||
|
||||
let tabUnloadAnimations = [];
|
||||
if (!ungroup) {
|
||||
animations.push(
|
||||
...this.#createAnimation(
|
||||
tabToUnload,
|
||||
{
|
||||
opacity: 0,
|
||||
height: 0,
|
||||
},
|
||||
{
|
||||
duration: 0.12,
|
||||
ease: 'easeInOut',
|
||||
}
|
||||
)
|
||||
tabUnloadAnimations = this.#createAnimation(
|
||||
tabToUnload,
|
||||
{
|
||||
opacity: 0,
|
||||
height: 0,
|
||||
},
|
||||
{
|
||||
duration: 0.12,
|
||||
ease: 'easeInOut',
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Manage global animation count
|
||||
this.#animationCount += 1;
|
||||
await Promise.all(animations);
|
||||
|
||||
// Await the tab unload animation first
|
||||
await Promise.all(tabUnloadAnimations);
|
||||
await Promise.all(animations.map((item) => (typeof item === 'function' ? item() : item)));
|
||||
this.#animationCount -= 1;
|
||||
gBrowser.tabContainer._invalidateCachedTabs();
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
border: 2px solid var(--zen-primary-color);
|
||||
background: rgba(255, 255, 255, 0.01);
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: var(--zen-native-inner-radius);
|
||||
box-shadow: var(--zen-big-shadow);
|
||||
overflow: hidden;
|
||||
|
||||
@@ -774,14 +774,30 @@
|
||||
behavior = lazy.zenPinnedTabCloseShortcutBehavior,
|
||||
noClose = false,
|
||||
closeIfPending = false,
|
||||
expandSplitViewList = true,
|
||||
folderToUnload = null,
|
||||
} = {}
|
||||
) {
|
||||
try {
|
||||
if (!selectedTab?.pinned) {
|
||||
const tabs = Array.isArray(selectedTab) ? selectedTab : [selectedTab];
|
||||
const pinnedTabs = [
|
||||
...new Set(
|
||||
tabs
|
||||
.flatMap((tab) => {
|
||||
if (tab.group?.hasAttribute('split-view-group')) {
|
||||
return tab.group.tabs;
|
||||
}
|
||||
return tab;
|
||||
})
|
||||
.filter((tab) => tab?.pinned)
|
||||
),
|
||||
];
|
||||
|
||||
if (!pinnedTabs.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedTabs = pinnedTabs.filter((tab) => tab.selected);
|
||||
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
@@ -791,63 +807,80 @@
|
||||
|
||||
switch (behavior) {
|
||||
case 'close':
|
||||
this._removePinnedAttributes(selectedTab, true);
|
||||
gBrowser.removeTab(selectedTab, { animate: true });
|
||||
for (const tab of pinnedTabs) {
|
||||
this._removePinnedAttributes(tab, true);
|
||||
gBrowser.removeTab(tab, { animate: true });
|
||||
}
|
||||
break;
|
||||
case 'reset-unload-switch':
|
||||
case 'unload-switch':
|
||||
case 'reset-switch':
|
||||
case 'switch':
|
||||
if (behavior.includes('unload')) {
|
||||
if (selectedTab.hasAttribute('glance-id')) {
|
||||
// We have a glance tab inside the tab we are trying to unload,
|
||||
// before we used to just ignore it but now we need to fully close
|
||||
// it as well.
|
||||
gZenGlanceManager.manageTabClose(selectedTab.glanceTab);
|
||||
await new Promise((resolve) => {
|
||||
let hasRan = false;
|
||||
const onGlanceClose = () => {
|
||||
hasRan = true;
|
||||
resolve();
|
||||
};
|
||||
window.addEventListener('GlanceClose', onGlanceClose, { once: true });
|
||||
// Set a timeout to resolve the promise if the event doesn't fire.
|
||||
// We do this to prevent any future issues where glance woudnt close such as
|
||||
// glance requering to ask for permit unload.
|
||||
setTimeout(() => {
|
||||
if (!hasRan) {
|
||||
console.warn('GlanceClose event did not fire within 3 seconds');
|
||||
for (const tab of pinnedTabs) {
|
||||
if (tab.hasAttribute('glance-id')) {
|
||||
// We have a glance tab inside the tab we are trying to unload,
|
||||
// before we used to just ignore it but now we need to fully close
|
||||
// it as well.
|
||||
gZenGlanceManager.manageTabClose(tab.glanceTab);
|
||||
await new Promise((resolve) => {
|
||||
let hasRan = false;
|
||||
const onGlanceClose = () => {
|
||||
hasRan = true;
|
||||
resolve();
|
||||
}
|
||||
}, 3000);
|
||||
});
|
||||
};
|
||||
window.addEventListener('GlanceClose', onGlanceClose, { once: true });
|
||||
// Set a timeout to resolve the promise if the event doesn't fire.
|
||||
// We do this to prevent any future issues where glance woudnt close such as
|
||||
// glance requering to ask for permit unload.
|
||||
setTimeout(() => {
|
||||
if (!hasRan) {
|
||||
console.warn('GlanceClose event did not fire within 3 seconds');
|
||||
resolve();
|
||||
}
|
||||
}, 3000);
|
||||
});
|
||||
}
|
||||
const isSpltView = tab.group?.hasAttribute('split-view-group');
|
||||
const group = isSpltView ? tab.group.group : tab.group;
|
||||
|
||||
if (!folderToUnload && tab.hasAttribute('folder-active')) {
|
||||
await gZenFolders.animateUnload(group, tab);
|
||||
}
|
||||
}
|
||||
const group = selectedTab.group?.hasAttribute('split-view-group')
|
||||
? selectedTab.group.group
|
||||
: selectedTab.group;
|
||||
await gZenFolders.animateUnload(group, selectedTab);
|
||||
let tabsToUnload = [selectedTab];
|
||||
if (selectedTab.group?.hasAttribute('split-view-group') && expandSplitViewList) {
|
||||
tabsToUnload = selectedTab.group.tabs;
|
||||
|
||||
if (folderToUnload) {
|
||||
await gZenFolders.animateUnloadAll(folderToUnload);
|
||||
}
|
||||
const allAreUnloaded = tabsToUnload.every(
|
||||
|
||||
const allAreUnloaded = pinnedTabs.every(
|
||||
(tab) => tab.hasAttribute('pending') && !tab.hasAttribute('zen-essential')
|
||||
);
|
||||
if (allAreUnloaded && closeIfPending) {
|
||||
return await this._onCloseTabShortcut(event, selectedTab, { behavior: 'close' });
|
||||
|
||||
for (const tab of pinnedTabs) {
|
||||
if (allAreUnloaded && closeIfPending) {
|
||||
return await this._onCloseTabShortcut(event, tab, { behavior: 'close' });
|
||||
}
|
||||
}
|
||||
|
||||
await gBrowser.explicitUnloadTabs(pinnedTabs);
|
||||
for (const tab of pinnedTabs) {
|
||||
tab.removeAttribute('discarded');
|
||||
}
|
||||
await gBrowser.explicitUnloadTabs(tabsToUnload);
|
||||
selectedTab.removeAttribute('discarded');
|
||||
}
|
||||
if (selectedTab.selected) {
|
||||
this._handleTabSwitch(selectedTab);
|
||||
if (selectedTabs.length) {
|
||||
this._handleTabSwitch(selectedTabs[0]);
|
||||
}
|
||||
if (behavior.includes('reset')) {
|
||||
this._resetTabToStoredState(selectedTab);
|
||||
for (const tab of pinnedTabs) {
|
||||
this._resetTabToStoredState(tab);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'reset':
|
||||
this._resetTabToStoredState(selectedTab);
|
||||
for (const tab of pinnedTabs) {
|
||||
this._resetTabToStoredState(tab);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user