Skip to content

Commit cbfa4e7

Browse files
committed
fix: preserve workspace tab index on workspace close -> approach change
1 parent 0d76c69 commit cbfa4e7

3 files changed

Lines changed: 116 additions & 56 deletions

File tree

src/browser/components/sessionstore/SessionStore-sys-mjs.patch

Lines changed: 80 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
diff --git a/browser/components/sessionstore/SessionStore.sys.mjs b/browser/components/sessionstore/SessionStore.sys.mjs
2-
index 2a055f0c5f34f0a2667f659185120c07d38f4e41..e0a1f2414d752f019c0a826ef71bc14c2045745f 100644
2+
index 2a055f0c5f34f0a2667f659185120c07d38f4e41..20cdd6721eeb8d8e2f85785f425f0edc3cb305bf 100644
33
--- a/browser/components/sessionstore/SessionStore.sys.mjs
44
+++ b/browser/components/sessionstore/SessionStore.sys.mjs
55
@@ -127,6 +127,9 @@ const TAB_EVENTS = [
@@ -170,7 +170,7 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..e0a1f2414d752f019c0a826ef71bc14c
170170
// If sidebar command is truthy, i.e. sidebar is open, store sidebar settings
171171
let shouldStore = hasSaveableTabs || isLastWindow;
172172

173-
@@ -3408,18 +3429,34 @@ var SessionStoreInternal = {
173+
@@ -3408,12 +3429,17 @@ var SessionStoreInternal = {
174174
if (!isPrivateWindow && tabState.isPrivate) {
175175
return;
176176
}
@@ -181,32 +181,15 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..e0a1f2414d752f019c0a826ef71bc14c
181181

182182
let permanentKey = aTab.linkedBrowser.permanentKey;
183183

184-
+ let zenWorkspaceTabIndex;
185-
+ let workspaceId = aTab.getAttribute("zen-workspace-id");
186-
+ if (workspaceId && aWindow.gZenWorkspaces?.workspaceEnabled) {
187-
+ let workspaceContainer = aWindow.gZenWorkspaces.workspaceElement(workspaceId);
188-
+ let wsTabContainer = aTab.pinned
189-
+ ? workspaceContainer?.pinnedTabsContainer
190-
+ : workspaceContainer?.tabsContainer;
191-
+ if (wsTabContainer) {
192-
+ let wsTabs = [...wsTabContainer.children].filter(
193-
+ child => aWindow.gBrowser.isTab(child) && !child.hasAttribute("zen-empty-tab")
194-
+ );
195-
+ zenWorkspaceTabIndex = wsTabs.indexOf(aTab);
196-
+ }
184+
+ const zenWorkspaceIndex = getZenWorkspaceIndex(aTab);
185+
+ if (Number.isInteger(zenWorkspaceIndex)) {
186+
+ tabState.zenWorkspaceIndex = zenWorkspaceIndex;
197187
+ }
198188
+
199189
let tabData = {
200190
permanentKey,
201191
state: tabState,
202-
title: aTab.label,
203-
image: aWindow.gBrowser.getIcon(aTab),
204-
pos: aTab._tPos,
205-
+ zenWorkspaceTabIndex,
206-
closedAt: Date.now(),
207-
closedInGroup: aTab._closedInMultiselection,
208-
closedInTabGroupId: closedInTabGroup ? tabState.groupId : null,
209-
@@ -4129,6 +4166,12 @@ var SessionStoreInternal = {
192+
@@ -4129,6 +4155,12 @@ var SessionStoreInternal = {
210193
Math.min(tabState.index, tabState.entries.length)
211194
);
212195
tabState.pinned = false;
@@ -219,26 +202,17 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..e0a1f2414d752f019c0a826ef71bc14c
219202

220203
if (inBackground === false) {
221204
aWindow.gBrowser.selectedTab = newTab;
222-
@@ -4534,7 +4577,7 @@ var SessionStoreInternal = {
223-
this._getClosedTabStateFromUnifiedIndex(sourceWinData, closedTabState);
224-
225-
// fetch the data of closed tab, while removing it from the array
226-
- let { state, pos } = this.removeClosedTabData(
227-
+ let { state, pos, zenWorkspaceTabIndex } = this.removeClosedTabData(
228-
sourceWinData,
229-
closedTabSet,
230-
closedTabIndex
231-
@@ -4565,6 +4608,9 @@ var SessionStoreInternal = {
205+
@@ -4565,6 +4597,9 @@ var SessionStoreInternal = {
232206
// Append the tab if we're opening into a different window,
233207
tabIndex: aSource == aTargetWindow ? pos : Infinity,
234208
pinned: state.pinned,
235209
+ essential: state.zenEssential,
236210
+ zenWorkspaceId: state.zenWorkspace,
237-
+ zenWorkspaceTabIndex,
211+
+ zenWorkspaceIndex: state.zenWorkspaceIndex,
238212
userContextId: state.userContextId,
239213
skipLoad: true,
240214
preferredRemoteType,
241-
@@ -5414,7 +5460,7 @@ var SessionStoreInternal = {
215+
@@ -5414,7 +5449,7 @@ var SessionStoreInternal = {
242216

243217
for (let i = tabbrowser.pinnedTabCount; i < tabbrowser.tabs.length; i++) {
244218
let tab = tabbrowser.tabs[i];
@@ -247,7 +221,7 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..e0a1f2414d752f019c0a826ef71bc14c
247221
removableTabs.push(tab);
248222
}
249223
}
250-
@@ -5525,7 +5571,7 @@ var SessionStoreInternal = {
224+
@@ -5525,7 +5560,7 @@ var SessionStoreInternal = {
251225

252226
// collect the data for all windows
253227
for (ix in this._windows) {
@@ -256,7 +230,7 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..e0a1f2414d752f019c0a826ef71bc14c
256230
// window data is still in _statesToRestore
257231
continue;
258232
}
259-
@@ -5668,11 +5714,12 @@ var SessionStoreInternal = {
233+
@@ -5668,11 +5703,12 @@ var SessionStoreInternal = {
260234
}
261235

262236
let tabbrowser = aWindow.gBrowser;
@@ -270,7 +244,7 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..e0a1f2414d752f019c0a826ef71bc14c
270244
// update the internal state data for this window
271245
for (let tab of tabs) {
272246
if (tab == aWindow.FirefoxViewHandler.tab) {
273-
@@ -5683,6 +5730,9 @@ var SessionStoreInternal = {
247+
@@ -5683,6 +5719,9 @@ var SessionStoreInternal = {
274248
tabsData.push(tabData);
275249
}
276250

@@ -280,7 +254,7 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..e0a1f2414d752f019c0a826ef71bc14c
280254
// update tab group state for this window
281255
winData.groups = [];
282256
for (let tabGroup of aWindow.gBrowser.tabGroups) {
283-
@@ -5695,7 +5745,7 @@ var SessionStoreInternal = {
257+
@@ -5695,7 +5734,7 @@ var SessionStoreInternal = {
284258
// a window is closed, point to the first item in the tab strip instead (it will never be the Firefox View tab,
285259
// since it's only inserted into the tab strip after it's selected).
286260
if (aWindow.FirefoxViewHandler.tab?.selected) {
@@ -289,7 +263,7 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..e0a1f2414d752f019c0a826ef71bc14c
289263
winData.title = tabbrowser.tabs[0].label;
290264
}
291265
winData.selected = selectedIndex;
292-
@@ -5810,8 +5860,8 @@ var SessionStoreInternal = {
266+
@@ -5810,8 +5849,8 @@ var SessionStoreInternal = {
293267
// selectTab represents.
294268
let selectTab = 0;
295269
if (overwriteTabs) {
@@ -300,15 +274,15 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..e0a1f2414d752f019c0a826ef71bc14c
300274
selectTab = Math.min(selectTab, winData.tabs.length);
301275
}
302276

303-
@@ -5833,6 +5883,7 @@ var SessionStoreInternal = {
277+
@@ -5833,6 +5872,7 @@ var SessionStoreInternal = {
304278
if (overwriteTabs) {
305279
for (let i = tabbrowser.browsers.length - 1; i >= 0; i--) {
306280
if (!tabbrowser.tabs[i].selected) {
307281
+ aWindow.gZenWorkspaces._shouldOverrideTabs = true;
308282
tabbrowser.removeTab(tabbrowser.tabs[i]);
309283
}
310284
}
311-
@@ -5866,6 +5917,12 @@ var SessionStoreInternal = {
285+
@@ -5866,6 +5906,12 @@ var SessionStoreInternal = {
312286
savedTabGroup => !openTabGroupIdsInWindow.has(savedTabGroup.id)
313287
);
314288
}
@@ -321,7 +295,7 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..e0a1f2414d752f019c0a826ef71bc14c
321295

322296
// Move the originally open tabs to the end.
323297
if (initialTabs) {
324-
@@ -6419,6 +6476,25 @@ var SessionStoreInternal = {
298+
@@ -6419,6 +6465,25 @@ var SessionStoreInternal = {
325299

326300
// Most of tabData has been restored, now continue with restoring
327301
// attributes that may trigger external events.
@@ -347,7 +321,7 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..e0a1f2414d752f019c0a826ef71bc14c
347321

348322
if (tabData.pinned) {
349323
tabbrowser.pinTab(tab);
350-
@@ -6567,6 +6643,9 @@ var SessionStoreInternal = {
324+
@@ -6567,6 +6632,9 @@ var SessionStoreInternal = {
351325
aWindow.gURLBar.readOnly = false;
352326
}
353327
}
@@ -357,7 +331,7 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..e0a1f2414d752f019c0a826ef71bc14c
357331

358332
let promiseParts = Promise.withResolvers();
359333
aWindow.setTimeout(() => {
360-
@@ -7343,7 +7422,7 @@ var SessionStoreInternal = {
334+
@@ -7343,7 +7411,7 @@ var SessionStoreInternal = {
361335

362336
let groupsToSave = new Map();
363337
for (let tIndex = 0; tIndex < window.tabs.length; ) {
@@ -366,7 +340,7 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..e0a1f2414d752f019c0a826ef71bc14c
366340
// Adjust window.selected
367341
if (tIndex + 1 < window.selected) {
368342
window.selected -= 1;
369-
@@ -7358,7 +7437,7 @@ var SessionStoreInternal = {
343+
@@ -7358,7 +7426,7 @@ var SessionStoreInternal = {
370344
);
371345
// We don't want to increment tIndex here.
372346
continue;
@@ -375,3 +349,63 @@ index 2a055f0c5f34f0a2667f659185120c07d38f4e41..e0a1f2414d752f019c0a826ef71bc14c
375349
// Convert any open groups into saved groups.
376350
let groupStateToSave = window.groups.find(
377351
groupState => groupState.id == window.tabs[tIndex].groupId
352+
@@ -8786,5 +8854,59 @@ function removeWhere(array, predicate) {
353+
}
354+
}
355+
356+
+function getZenWorkspaceIndex(tab) {
357+
+ const win = tab.ownerGlobal;
358+
+ if (!win?.gZenWorkspaces?.workspaceEnabled) {
359+
+ return null;
360+
+ }
361+
+
362+
+ if (
363+
+ tab.pinned ||
364+
+ tab.hasAttribute("zen-essential") ||
365+
+ tab.hasAttribute("zen-empty-tab") ||
366+
+ tab.hasAttribute("zen-glance-tab") ||
367+
+ tab.group?.isZenFolder
368+
+ ) {
369+
+ return null;
370+
+ }
371+
+
372+
+ const workspaceId = tab.getAttribute("zen-workspace-id");
373+
+ if (!workspaceId) {
374+
+ return null;
375+
+ }
376+
+
377+
+ const workspaceElement = win.gZenWorkspaces.workspaceElement(workspaceId);
378+
+ const container = workspaceElement?.tabsContainer;
379+
+ if (!container) {
380+
+ return null;
381+
+ }
382+
+
383+
+ const tabs = [];
384+
+ for (const child of container.children) {
385+
+ if (win.gBrowser.isTab(child)) {
386+
+ tabs.push(child);
387+
+ continue;
388+
+ }
389+
+ if (win.gBrowser.isTabGroup(child)) {
390+
+ for (const groupTab of child.tabs) {
391+
+ tabs.push(groupTab);
392+
+ }
393+
+ }
394+
+ }
395+
+
396+
+ const eligibleTabs = tabs.filter(
397+
+ t =>
398+
+ t.getAttribute("zen-workspace-id") === workspaceId &&
399+
+ !t.pinned &&
400+
+ !t.hasAttribute("zen-essential") &&
401+
+ !t.hasAttribute("zen-empty-tab") &&
402+
+ !t.hasAttribute("zen-glance-tab") &&
403+
+ !t.group?.isZenFolder
404+
+ );
405+
+
406+
+ const index = eligibleTabs.indexOf(tab);
407+
+ return index >= 0 ? index : null;
408+
+}
409+
+
410+
// Exposed for tests
411+
export const _LastSession = LastSession;

src/browser/components/tabbrowser/content/tabbrowser-js.patch

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/components/tabbrowser/content/tabbrowser.js
2-
index 0eaca7a58e0026237b71b2ad515efe84d9e8c779..28bbab3086d6d2447fd354d2eeca3673c255af72 100644
2+
index 0eaca7a58e0026237b71b2ad515efe84d9e8c779..9eba7866a119a4d683564ccfb9f50f3bff389d7d 100644
33
--- a/browser/components/tabbrowser/content/tabbrowser.js
44
+++ b/browser/components/tabbrowser/content/tabbrowser.js
55
@@ -398,6 +398,7 @@
@@ -260,7 +260,7 @@ index 0eaca7a58e0026237b71b2ad515efe84d9e8c779..28bbab3086d6d2447fd354d2eeca3673
260260
+ _forZenEmptyTab,
261261
+ essential,
262262
+ zenWorkspaceId,
263-
+ zenWorkspaceTabIndex,
263+
+ zenWorkspaceIndex,
264264
} = {}
265265
) {
266266
// all callers of addTab that pass a params object need to pass
@@ -304,8 +304,8 @@ index 0eaca7a58e0026237b71b2ad515efe84d9e8c779..28bbab3086d6d2447fd354d2eeca3673
304304
+ t.setAttribute("zen-workspace-id", zenForcedWorkspaceId);
305305
+ t.setAttribute("change-workspace", "")
306306
+ }
307-
+ if (typeof zenWorkspaceTabIndex === "number") {
308-
+ t.setAttribute("zen-workspace-tab-index", String(zenWorkspaceTabIndex));
307+
+ if (Number.isInteger(zenWorkspaceIndex)) {
308+
+ t.setAttribute("zen-workspace-index", String(zenWorkspaceIndex));
309309
+ }
310310
+ if (_forZenEmptyTab) {
311311
+ t.setAttribute("zen-empty-tab", "true");

src/zen/workspaces/ZenWorkspaces.mjs

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1568,11 +1568,37 @@ class nsZenWorkspaces {
15681568
if (typeof tabIndex !== "number" || tabIndex < 0) {
15691569
return container.lastChild;
15701570
}
1571-
const tabs = [...container.children].filter(
1572-
(child) => gBrowser.isTab(child) && !child.hasAttribute("zen-empty-tab")
1571+
const workspaceId = container.getAttribute("zen-workspace-id");
1572+
if (!workspaceId) {
1573+
return container.lastChild;
1574+
}
1575+
const tabs = [];
1576+
for (const child of container.children) {
1577+
if (gBrowser.isTab(child)) {
1578+
tabs.push(child);
1579+
continue;
1580+
}
1581+
if (gBrowser.isTabGroup(child)) {
1582+
for (const groupTab of child.tabs) {
1583+
tabs.push(groupTab);
1584+
}
1585+
}
1586+
}
1587+
const eligibleTabs = tabs.filter(
1588+
(tab) =>
1589+
tab.getAttribute("zen-workspace-id") === workspaceId &&
1590+
!tab.pinned &&
1591+
!tab.hasAttribute("zen-essential") &&
1592+
!tab.hasAttribute("zen-empty-tab") &&
1593+
!tab.hasAttribute("zen-glance-tab") &&
1594+
!tab.group?.isZenFolder
15731595
);
1574-
if (tabIndex < tabs.length) {
1575-
return tabs[tabIndex];
1596+
const targetTab = eligibleTabs[tabIndex];
1597+
if (targetTab) {
1598+
const targetNode = targetTab.group ?? targetTab;
1599+
if (targetNode.parentElement === container) {
1600+
return targetNode;
1601+
}
15761602
}
15771603
return container.lastChild;
15781604
}
@@ -2611,9 +2637,9 @@ class nsZenWorkspaces {
26112637
}
26122638

26132639
if (workspaceID) {
2614-
const rawTabIndex = tab.getAttribute("zen-workspace-tab-index");
2640+
const rawTabIndex = tab.getAttribute("zen-workspace-index");
26152641
const tabIndex = rawTabIndex !== null ? parseInt(rawTabIndex, 10) : undefined;
2616-
tab.removeAttribute("zen-workspace-tab-index");
2642+
tab.removeAttribute("zen-workspace-index");
26172643
if (
26182644
tab.hasAttribute("change-workspace") &&
26192645
this.moveTabToWorkspace(tab, workspaceID, tabIndex)

0 commit comments

Comments
 (0)