feat: Prevent folders from being removed if there are no tabs, b=(no-bug), c=folders

This commit is contained in:
mr. m 2025-05-24 21:59:34 +02:00
parent 1b68d6a2ef
commit 2a64d867cc
No known key found for this signature in database
GPG key ID: 419302196C23B258
3 changed files with 106 additions and 7 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 d5aa64842a35c6697263c63fd3a0571b64b01344..bb2fa534e387d8d935cc2812a7ce115916ba94db 100644 index d5aa64842a35c6697263c63fd3a0571b64b01344..475838b0fcfab3074116111d971d77c209d70f44 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
@@ -413,11 +413,41 @@ @@ -413,11 +413,41 @@
@ -9,7 +9,7 @@ index d5aa64842a35c6697263c63fd3a0571b64b01344..bb2fa534e387d8d935cc2812a7ce1159
+ get _numVisiblePinTabsWithoutCollapsed() { + get _numVisiblePinTabsWithoutCollapsed() {
+ let i = 0; + let i = 0;
+ for (let item of this.tabContainer.ariaFocusableItems) { + for (let item of this.tabContainer.ariaFocusableItems) {
+ if (!!item?.classList?.contains("tab-group-label") && item.closest("tab-folder")) + if (!!item?.classList?.contains("tab-group-label") && item.closest("tab-folder")) {
+ i += 1; + i += 1;
+ continue; + continue;
+ } + }
@ -546,6 +546,15 @@ index d5aa64842a35c6697263c63fd3a0571b64b01344..bb2fa534e387d8d935cc2812a7ce1159
aTab.selected || aTab.selected ||
aTab.closing || aTab.closing ||
// Tabs that are sharing the screen, microphone or camera cannot be hidden. // Tabs that are sharing the screen, microphone or camera cannot be hidden.
@@ -5909,7 +6035,7 @@
* `true` if element is a `<tab-group>`
*/
isTabGroup(element) {
- return !!(element?.tagName == "tab-group");
+ return !!(element?.tagName == "tab-group" || element?.tagName == "zen-folder");
}
/**
@@ -5986,7 +6112,7 @@ @@ -5986,7 +6112,7 @@
// Don't allow mixing pinned and unpinned tabs. // Don't allow mixing pinned and unpinned tabs.

View file

@ -1,8 +1,86 @@
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 6dc774ea335b0c5dba7dcf76cdb23728faae1343..75cd0f0471ca350852e9eb810b30e60d52f14aab 100644 index 6dc774ea335b0c5dba7dcf76cdb23728faae1343..f6a5742423342dec9394ce9d98011b5f388e5174 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
@@ -395,5 +395,6 @@ @@ -13,10 +13,13 @@
class MozTabbrowserTabGroup extends MozXULElement {
static markup = `
- <vbox class="tab-group-label-container" pack="center">
- <label class="tab-group-label" role="button"/>
- </vbox>
- <html:slot/>
+ <hbox class="tab-group-label-container" pack="center">
+ <image class="tab-group-folder-icon"/>
+ <label class="tab-group-label" role="button"/>
+ </hbox>
+ <html:div class="tab-group-container">
+ <html:div class="zen-tab-group-start" />
+ </html:div>
`;
/** @type {string} */
@@ -68,7 +71,7 @@
this.#labelElement.container = gBrowser.tabContainer;
this.#labelElement.group = this;
- this.#labelElement.addEventListener("click", this);
+ this.querySelector(".tab-group-label-container").addEventListener("click", this);
this.#labelElement.addEventListener("contextmenu", e => {
e.preventDefault();
gBrowser.tabGroupMenu.openEditModal(this);
@@ -93,6 +96,9 @@
// claim that a tab group was created by adoption the first time it
// mounts after getting created by `Tabbrowser.adoptTabGroup`.
this.#wasCreatedByAdoption = false;
+ this.appendChild = function (child) {
+ this.querySelector('.tab-group-container').appendChild(child);
+ }
}
disconnectedCallback() {
@@ -133,7 +139,7 @@
}
});
}
- if (!this.tabs.length) {
+ if (!this.tabs.length && !this.pinned) {
this.dispatchEvent(
new CustomEvent("TabGroupRemoved", { bubbles: true })
);
@@ -275,7 +281,21 @@
}
get tabs() {
- return Array.from(this.children).filter(node => node.matches("tab"));
+ // add other group tabs if they are under this group
+ let childs = Array.from(this.querySelector('.tab-group-container')?.children ?? []);
+ for (let item of childs) {
+ if (gBrowser.isTabGroup(item)) {
+ childs = childs.concat(item.tabs);
+ }
+ }
+ return childs.filter(node => node.matches("tab"));
+ }
+
+ get group() {
+ if (gBrowser.isTabGroup(this.parentElement)) {
+ return this.parentElement.parentElement;
+ }
+ return null;
}
/**
@@ -301,7 +321,7 @@
*/
addTabs(tabs, metricsContext) {
for (let tab of tabs) {
- if (tab.pinned) {
+ if (tab.pinned != this.pinned) {
tab.ownerGlobal.gBrowser.unpinTab(tab);
}
let tabToMove =
@@ -395,5 +415,6 @@
} }
} }

View file

@ -24,7 +24,7 @@
} }
} }
MozXULElement.registerXULElement('zen-folder', ZenFolder); customElements.define('zen-folder', ZenFolder);
class ZenFolders extends ZenPreloadedFeature { class ZenFolders extends ZenPreloadedFeature {
init() { init() {
@ -161,7 +161,7 @@
#onNewFolder(event) { #onNewFolder(event) {
const tabs = gBrowser.selectedTabs; const tabs = gBrowser.selectedTabs;
return this.createFolder(tabs); this.createFolder(tabs);
} }
createFolder(tabs, options = {}) { createFolder(tabs, options = {}) {
@ -187,7 +187,19 @@
folder.label = label; folder.label = label;
folder.collapsed = !!options.collapsed; folder.collapsed = !!options.collapsed;
folder.pinned = true; folder.pinned = true;
insertBefore.parentNode.insertBefore(folder, insertBefore); folder.addTabs(tabs);
insertBefore.before(folder);
// Fixes bug1953801 and bug1954689
// Ensure that the tab state cache is updated immediately after creating
// a group. This is necessary because we consider group creation a
// deliberate user action indicating the tab has importance for the user.
// Without this, it is not possible to save and close a tab group with
// a short lifetime.
folder.tabs.forEach((tab) => {
gBrowser.TabStateFlusher.flush(tab.linkedBrowser);
});
return folder; return folder;
} }