feat: Start implementing old pinned tab behaviour we used to have, b=no-bug, c=common, tabs

This commit is contained in:
mr. m
2025-12-13 17:40:34 +01:00
parent f5ae793ff0
commit cc31282ce2
7 changed files with 182 additions and 199 deletions

View File

@@ -1,5 +1,5 @@
diff --git a/browser/components/sessionstore/SessionStore.sys.mjs b/browser/components/sessionstore/SessionStore.sys.mjs
index 2c2f43bf743ef458b378e85e9ed44a971711e1d9..667b76e3065aafcc60ab146f40013ce791e59747 100644
index 2c2f43bf743ef458b378e85e9ed44a971711e1d9..fb0030061a3bd9df2c8a444970b56ce81600d3af 100644
--- a/browser/components/sessionstore/SessionStore.sys.mjs
+++ b/browser/components/sessionstore/SessionStore.sys.mjs
@@ -127,6 +127,8 @@ const TAB_EVENTS = [
@@ -63,19 +63,7 @@ index 2c2f43bf743ef458b378e85e9ed44a971711e1d9..667b76e3065aafcc60ab146f40013ce7
if (this._restoreLastWindow && aWindow.toolbar.visible) {
// always reset (if not a popup window)
@@ -2384,11 +2401,9 @@ var SessionStoreInternal = {
tabbrowser.selectedTab.label;
}
- if (AppConstants.platform != "macosx") {
// Until we decide otherwise elsewhere, this window is part of a series
// of closing windows to quit.
winData._shouldRestore = true;
- }
// Store the window's close date to figure out when each individual tab
// was closed. This timestamp should allow re-arranging data based on how
@@ -2465,7 +2480,7 @@ var SessionStoreInternal = {
@@ -2465,7 +2482,7 @@ var SessionStoreInternal = {
// 2) Flush the window.
// 3) When the flush is complete, revisit our decision to store the window
// in _closedWindows, and add/remove as necessary.
@@ -84,7 +72,7 @@ index 2c2f43bf743ef458b378e85e9ed44a971711e1d9..667b76e3065aafcc60ab146f40013ce7
this.maybeSaveClosedWindow(winData, isLastWindow);
}
@@ -2486,7 +2501,7 @@ var SessionStoreInternal = {
@@ -2486,7 +2503,7 @@ var SessionStoreInternal = {
// Save non-private windows if they have at
// least one saveable tab or are the last window.
@@ -93,7 +81,7 @@ index 2c2f43bf743ef458b378e85e9ed44a971711e1d9..667b76e3065aafcc60ab146f40013ce7
this.maybeSaveClosedWindow(winData, isLastWindow);
if (!isLastWindow && winData.closedId > -1) {
@@ -3373,7 +3388,7 @@ var SessionStoreInternal = {
@@ -3373,7 +3390,7 @@ var SessionStoreInternal = {
if (!isPrivateWindow && tabState.isPrivate) {
return;
}
@@ -102,7 +90,7 @@ index 2c2f43bf743ef458b378e85e9ed44a971711e1d9..667b76e3065aafcc60ab146f40013ce7
return;
}
@@ -4089,6 +4104,12 @@ var SessionStoreInternal = {
@@ -4089,6 +4106,12 @@ var SessionStoreInternal = {
Math.min(tabState.index, tabState.entries.length)
);
tabState.pinned = false;
@@ -115,7 +103,7 @@ index 2c2f43bf743ef458b378e85e9ed44a971711e1d9..667b76e3065aafcc60ab146f40013ce7
if (inBackground === false) {
aWindow.gBrowser.selectedTab = newTab;
@@ -4525,6 +4546,7 @@ var SessionStoreInternal = {
@@ -4525,6 +4548,7 @@ var SessionStoreInternal = {
// Append the tab if we're opening into a different window,
tabIndex: aSource == aTargetWindow ? pos : Infinity,
pinned: state.pinned,
@@ -123,7 +111,7 @@ index 2c2f43bf743ef458b378e85e9ed44a971711e1d9..667b76e3065aafcc60ab146f40013ce7
userContextId: state.userContextId,
skipLoad: true,
preferredRemoteType,
@@ -5374,7 +5396,7 @@ var SessionStoreInternal = {
@@ -5374,7 +5398,7 @@ var SessionStoreInternal = {
for (let i = tabbrowser.pinnedTabCount; i < tabbrowser.tabs.length; i++) {
let tab = tabbrowser.tabs[i];
@@ -132,16 +120,7 @@ index 2c2f43bf743ef458b378e85e9ed44a971711e1d9..667b76e3065aafcc60ab146f40013ce7
removableTabs.push(tab);
}
}
@@ -5434,7 +5456,7 @@ var SessionStoreInternal = {
}
let workspaceID = aWindow.getWorkspaceID();
- if (workspaceID) {
+ if (workspaceID && !(this.isLastRestorableWindow() && AppConstants.platform == "macosx")) {
winData.workspaceID = workspaceID;
}
},
@@ -5483,7 +5505,7 @@ var SessionStoreInternal = {
@@ -5483,7 +5507,7 @@ var SessionStoreInternal = {
// collect the data for all windows
for (ix in this._windows) {
@@ -150,7 +129,7 @@ index 2c2f43bf743ef458b378e85e9ed44a971711e1d9..667b76e3065aafcc60ab146f40013ce7
// window data is still in _statesToRestore
continue;
}
@@ -5625,11 +5647,12 @@ var SessionStoreInternal = {
@@ -5625,11 +5649,12 @@ var SessionStoreInternal = {
}
let tabbrowser = aWindow.gBrowser;
@@ -164,7 +143,7 @@ index 2c2f43bf743ef458b378e85e9ed44a971711e1d9..667b76e3065aafcc60ab146f40013ce7
// update the internal state data for this window
for (let tab of tabs) {
if (tab == aWindow.FirefoxViewHandler.tab) {
@@ -5640,6 +5663,7 @@ var SessionStoreInternal = {
@@ -5640,6 +5665,7 @@ var SessionStoreInternal = {
tabsData.push(tabData);
}
@@ -172,7 +151,7 @@ index 2c2f43bf743ef458b378e85e9ed44a971711e1d9..667b76e3065aafcc60ab146f40013ce7
// update tab group state for this window
winData.groups = [];
for (let tabGroup of aWindow.gBrowser.tabGroups) {
@@ -5652,7 +5676,7 @@ var SessionStoreInternal = {
@@ -5652,7 +5678,7 @@ var SessionStoreInternal = {
// a window is closed, point to the first item in the tab strip instead (it will never be the Firefox View tab,
// since it's only inserted into the tab strip after it's selected).
if (aWindow.FirefoxViewHandler.tab?.selected) {
@@ -181,7 +160,7 @@ index 2c2f43bf743ef458b378e85e9ed44a971711e1d9..667b76e3065aafcc60ab146f40013ce7
winData.title = tabbrowser.tabs[0].label;
}
winData.selected = selectedIndex;
@@ -5765,8 +5789,8 @@ var SessionStoreInternal = {
@@ -5765,8 +5791,8 @@ var SessionStoreInternal = {
// selectTab represents.
let selectTab = 0;
if (overwriteTabs) {
@@ -192,7 +171,7 @@ index 2c2f43bf743ef458b378e85e9ed44a971711e1d9..667b76e3065aafcc60ab146f40013ce7
selectTab = Math.min(selectTab, winData.tabs.length);
}
@@ -5809,6 +5833,8 @@ var SessionStoreInternal = {
@@ -5809,6 +5835,8 @@ var SessionStoreInternal = {
winData.tabs,
winData.groups ?? []
);
@@ -201,7 +180,7 @@ index 2c2f43bf743ef458b378e85e9ed44a971711e1d9..667b76e3065aafcc60ab146f40013ce7
this._log.debug(
`restoreWindow, createTabsForSessionRestore returned ${tabs.length} tabs`
);
@@ -6372,6 +6398,25 @@ var SessionStoreInternal = {
@@ -6372,6 +6400,25 @@ var SessionStoreInternal = {
// Most of tabData has been restored, now continue with restoring
// attributes that may trigger external events.
@@ -227,7 +206,7 @@ index 2c2f43bf743ef458b378e85e9ed44a971711e1d9..667b76e3065aafcc60ab146f40013ce7
if (tabData.pinned) {
tabbrowser.pinTab(tab);
@@ -7290,7 +7335,7 @@ var SessionStoreInternal = {
@@ -7290,7 +7337,7 @@ var SessionStoreInternal = {
let groupsToSave = new Map();
for (let tIndex = 0; tIndex < window.tabs.length; ) {
@@ -236,7 +215,7 @@ index 2c2f43bf743ef458b378e85e9ed44a971711e1d9..667b76e3065aafcc60ab146f40013ce7
// Adjust window.selected
if (tIndex + 1 < window.selected) {
window.selected -= 1;
@@ -7305,7 +7350,7 @@ var SessionStoreInternal = {
@@ -7305,7 +7352,7 @@ var SessionStoreInternal = {
);
// We don't want to increment tIndex here.
continue;

View File

@@ -1,8 +1,8 @@
diff --git a/browser/components/sessionstore/TabState.sys.mjs b/browser/components/sessionstore/TabState.sys.mjs
index 82721356d191055bec0d4b0ca49e481221988801..e1d2c5ca0cbe5431df01f8d6411f88e3325e0ee9 100644
index 82721356d191055bec0d4b0ca49e481221988801..80547ec951f881bef134b637730954eb1525c623 100644
--- a/browser/components/sessionstore/TabState.sys.mjs
+++ b/browser/components/sessionstore/TabState.sys.mjs
@@ -85,7 +85,23 @@ class _TabState {
@@ -85,7 +85,24 @@ class _TabState {
tabData.groupId = tab.group.id;
}
@@ -17,6 +17,7 @@ index 82721356d191055bec0d4b0ca49e481221988801..e1d2c5ca0cbe5431df01f8d6411f88e3
+ tabData.zenHasStaticLabel = tab.hasAttribute("zen-has-static-label");
+ tabData.zenGlanceId = tab.getAttribute("glance-id");
+ tabData.zenIsGlance = tab.hasAttribute("zen-glance-tab");
+ tabData._zenPinnedInitialState = tab._zenPinnedInitialState;
+ tabData._zenIsActiveTab = tab._zenContentsVisible;
+
tabData.searchMode = tab.ownerGlobal.gURLBar.getSearchMode(browser, true);
@@ -26,3 +27,12 @@ index 82721356d191055bec0d4b0ca49e481221988801..e1d2c5ca0cbe5431df01f8d6411f88e3
tabData.userContextId = tab.userContextId || 0;
@@ -98,7 +115,7 @@ class _TabState {
// Copy data from the tab state cache only if the tab has fully finished
// restoring. We don't want to overwrite data contained in __SS_data.
- this.copyFromCache(browser.permanentKey, tabData, options);
+ this.copyFromCache(tab.permanentKey, tabData, options);
// After copyFromCache() was called we check for properties that are kept
// in the cache only while the tab is pending or restoring. Once that

View File

@@ -1,5 +1,5 @@
diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/components/tabbrowser/content/tabbrowser.js
index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..577d459794a7259e95a0aff0d76400a39aa1a03b 100644
index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..d39d295c786fd9e6da29a8fa4b3b2a00a1cfd380 100644
--- a/browser/components/tabbrowser/content/tabbrowser.js
+++ b/browser/components/tabbrowser/content/tabbrowser.js
@@ -386,6 +386,7 @@
@@ -177,7 +177,7 @@ index 42027bfa55eab8ea9298a7d425f2ded45188f7f3..577d459794a7259e95a0aff0d76400a3
+ return false;
+ }
+ gZenPinnedTabManager.onTabLabelChanged(aTab);
+ if (!aLabel || aLabel.includes("about:reader?") || aTab.hasAttribute("zen-has-static-label")) {
+ if (!aLabel || aLabel.includes("about:reader?") || (aTab.hasAttribute("zen-has-static-label") && !aTab._zenChangeLabelFlag)) {
return false;
}

View File

@@ -33,6 +33,9 @@ class ZenSessionStore extends nsZenPreloadedFeature {
if (tabData.zenPinnedEntry) {
tab.setAttribute('zen-pinned-entry', tabData.zenPinnedEntry);
}
if (tabData._zenPinnedInitialState) {
tab._zenPinnedInitialState = tabData._zenPinnedInitialState;
}
}
async #waitAndCleanup() {

View File

@@ -250,44 +250,42 @@ export class nsZenSessionManager {
return;
}
this.log('Restoring new window with Zen session data');
lazy.setTimeout(() => {
const state = lazy.SessionStore.getCurrentState(true);
const windows = (state.windows || []).filter(
(win) => !win.isPrivate && !win.isPopup && !win.isTaskbarTab && !win.isZenUnsynced
);
let windowToClone = windows.length > 1 ? windows[windows.length - 2] : {};
let newWindow = Cu.cloneInto(windowToClone, {});
if (windows.length < 2) {
// We only want to restore the sidebar object if we found
// only one normal window to clone from (which is the one
// we are opening).
this.log('Restoring sidebar data into new window');
this.#restoreWindowData(newWindow);
}
newWindow.tabs = this.#filterUnusedTabs(newWindow.tabs || []);
const state = lazy.SessionStore.getCurrentState(true);
const windows = (state.windows || []).filter(
(win) => !win.isPrivate && !win.isPopup && !win.isTaskbarTab && !win.isZenUnsynced
);
let windowToClone = windows[0] || {};
let newWindow = Cu.cloneInto(windowToClone, {});
if (windows.length < 2) {
// We only want to restore the sidebar object if we found
// only one normal window to clone from (which is the one
// we are opening).
this.log('Restoring sidebar data into new window');
this.#restoreWindowData(newWindow);
}
newWindow.tabs = this.#filterUnusedTabs(newWindow.tabs || []);
// These are window-specific from the previous window state that
// we don't want to restore into the new window. Otherwise, new
// windows would appear overlapping the previous one, or with
// the same size and position, which should be decided by the
// window manager.
delete newWindow.selected;
delete newWindow.screenX;
delete newWindow.screenY;
delete newWindow.width;
delete newWindow.height;
delete newWindow.sizemode;
delete newWindow.sizemodeBeforeMinimized;
delete newWindow.zIndex;
// These are window-specific from the previous window state that
// we don't want to restore into the new window. Otherwise, new
// windows would appear overlapping the previous one, or with
// the same size and position, which should be decided by the
// window manager.
delete newWindow.selected;
delete newWindow.screenX;
delete newWindow.screenY;
delete newWindow.width;
delete newWindow.height;
delete newWindow.sizemode;
delete newWindow.sizemodeBeforeMinimized;
delete newWindow.zIndex;
const newState = { windows: [newWindow] };
this.log(`Cloning window with ${newWindow.tabs.length} tabs`);
SessionStoreInternal.restoreWindows(aWindow, newState, {
firstWindow: true,
});
lazy.setTimeout(resolvePromise);
const newState = { windows: [newWindow] };
this.log(`Cloning window with ${newWindow.tabs.length} tabs`);
SessionStoreInternal.restoreWindows(aWindow, newState, {
firstWindow: true,
});
lazy.setTimeout(resolvePromise);
}
}

View File

@@ -160,8 +160,7 @@ class nsZenWindowSync {
}
}
/** * Generates a unique tab ID.
*
/**
* @returns {string} A unique tab ID.
*/
get #newTabSyncId() {
@@ -248,14 +247,12 @@ class nsZenWindowSync {
});
// Wait for the last handler to finish before processing the next event.
lastHandlerPromise.then(() => {
try {
this.#handleNextEvent(aEvent);
} finally {
this.#handleNextEvent(aEvent).finally(() => {
if (--this.#eventHandlingContext.eventCount === 0) {
this.#eventHandlingContext.window = null;
}
resolveNewPromise();
}
});
});
}
@@ -267,12 +264,28 @@ class nsZenWindowSync {
#handleNextEvent(aEvent) {
const handler = `on_${aEvent.type}`;
if (typeof this[handler] === 'function') {
this[handler](aEvent);
return this[handler](aEvent) || Promise.resolve();
} else {
console.warn(`ZenWindowSync: No handler for event type: ${aEvent.type}`);
}
}
/**
* Ensures that all synced tabs with a given ID has the same permanentKey.
* @param {Object} aTab - The tab to ensure sync for.
*/
#makeSureTabSyncsPermanentKey(aTab) {
if (!aTab.id) {
return;
}
this.#runOnAllWindows(null, (win) => {
const tab = this.#getItemFromWindow(win, aTab.id);
if (tab) {
tab.permanentKey = aTab.linkedBrowser.permanentKey;
}
});
}
/**
* Retrieves a item element from a window by its ID.
*
@@ -284,6 +297,20 @@ class nsZenWindowSync {
return aWindow.document.getElementById(aItemId);
}
/**
* Synchronizes a specific attribute from the original item to the target item.
* @param {MozTabbrowserTab|MozTabbrowserTabGroup} aOriginalItem - The original item to copy from.
* @param {MozTabbrowserTab|MozTabbrowserTabGroup} aTargetItem - The target item to copy to.
* @param {string} aAttributeName - The name of the attribute to synchronize.
*/
#maybeSyncAttributeChange(aOriginalItem, aTargetItem, aAttributeName) {
if (aOriginalItem.hasAttribute(aAttributeName)) {
aTargetItem.setAttribute(aAttributeName, aOriginalItem.getAttribute(aAttributeName));
} else {
aTargetItem.removeAttribute(aAttributeName);
}
}
/**
* Synchronizes the icon and label of the target tab with the original tab.
*
@@ -310,17 +337,13 @@ class nsZenWindowSync {
aTargetItem._zenChangeLabelFlag = true;
gBrowser._setTabLabel(aTargetItem, aOriginalItem.label);
delete aTargetItem._zenChangeLabelFlag;
this.#maybeSyncAttributeChange(aOriginalItem, aTargetItem, 'zen-has-static-label');
} else if (gBrowser.isTabGroup(aOriginalItem)) {
aTargetItem.label = aOriginalItem.label;
}
}
if (flags & SYNC_FLAG_MOVE && !aTargetItem.hasAttribute('zen-empty-tab')) {
const workspaceId = aOriginalItem.getAttribute('zen-workspace-id');
if (workspaceId) {
aTargetItem.setAttribute('zen-workspace-id', workspaceId);
} else {
aTargetItem.removeAttribute('zen-workspace-id');
}
this.#maybeSyncAttributeChange(aOriginalItem, aTargetItem, 'zen-workspace-id');
this.#syncItemPosition(aOriginalItem, aTargetItem, aWindow);
}
if (gBrowser.isTab(aTargetItem)) {
@@ -440,8 +463,9 @@ class nsZenWindowSync {
* @param {Object} aOtherTab - The tab in the other window.
*/
async #swapBrowserDocShellsAsync(aOurTab, aOtherTab) {
await this.#styleSwapedBrowsers(aOurTab, aOtherTab);
this.#swapBrowserDocSheellsInner(aOurTab, aOtherTab);
await this.#styleSwapedBrowsers(aOurTab, aOtherTab, () => {
this.#swapBrowserDocSheellsInner(aOurTab, aOtherTab);
});
}
/**
@@ -512,6 +536,7 @@ class nsZenWindowSync {
() => {
this.log(`Swapping docshells between windows for tab ${aOurTab.id}`);
aOurTab.ownerGlobal.gBrowser.swapBrowsersAndCloseOther(aOurTab, aOtherTab, false);
this.#makeSureTabSyncsPermanentKey(aOurTab);
},
onClose
);
@@ -540,13 +565,13 @@ class nsZenWindowSync {
*
* @param {Object} aOurTab - The tab in the current window.
* @param {Object} aOtherTab - The tab in the other window.
* @param {boolean} onClose - Indicates if the styling is done during a tab close operation.
* @param {Function|undefined} callback - The callback function to execute after styling.
*/
async #styleSwapedBrowsers(aOurTab, aOtherTab, onClose = false) {
async #styleSwapedBrowsers(aOurTab, aOtherTab, callback = undefined) {
const ourBrowser = aOurTab.linkedBrowser;
const otherBrowser = aOtherTab.linkedBrowser;
if (!onClose) {
if (callback) {
const browserBlob = await aOtherTab.ownerGlobal.PageThumbs.captureToBlob(
aOtherTab.linkedBrowser,
{
@@ -572,6 +597,7 @@ class nsZenWindowSync {
void img.getBoundingClientRect();
await loadPromise;
otherBrowser.setAttribute('zen-pseudo-hidden', 'true');
callback();
}
this.#maybeRemovePseudoImageForBrowser(ourBrowser);
@@ -649,7 +675,7 @@ class nsZenWindowSync {
// We can animate later, whats important is to always stay on the same
// process and avoid async operations here to avoid the closed window
// being unloaded before the swap is done.
this.#styleSwapedBrowsers(targetTab, tab, /* onClose =*/ true);
this.#styleSwapedBrowsers(targetTab, tab);
}
}
}
@@ -660,7 +686,7 @@ class nsZenWindowSync {
* @param {Window} aWindow - The window that triggered the event.
* @param {Object} aPreviousTab - The previously selected tab.
*/
#onTabSwitchOrWindowFocus(aWindow, aPreviousTab = null) {
async #onTabSwitchOrWindowFocus(aWindow, aPreviousTab = null) {
const selectedTab = aWindow.gBrowser.selectedTab;
// On some occasions, such as when closing a window, this
// function might be called multiple times for the same tab.
@@ -676,7 +702,7 @@ class nsZenWindowSync {
if (otherTabToShow) {
otherTabToShow._zenContentsVisible = true;
delete aPreviousTab._zenContentsVisible;
this.#swapBrowserDocShellsAsync(otherTabToShow, aPreviousTab);
await this.#swapBrowserDocShellsAsync(otherTabToShow, aPreviousTab);
}
}
if (selectedTab._zenContentsVisible || selectedTab.hasAttribute('zen-empty-tab')) {
@@ -686,7 +712,7 @@ class nsZenWindowSync {
selectedTab._zenContentsVisible = true;
if (otherSelectedTab) {
delete otherSelectedTab._zenContentsVisible;
this.#swapBrowserDocShellsAsync(selectedTab, otherSelectedTab);
await this.#swapBrowserDocShellsAsync(selectedTab, otherSelectedTab);
}
}
@@ -701,6 +727,16 @@ class nsZenWindowSync {
this.#syncItemForAllWindows(item, flags);
}
/**
* Retrieves the tab state for a given tab.
*
* @param {Object} tab - The tab to retrieve the state for.
* @returns {Object} The tab state.
*/
#getTabState(tab) {
return JSON.parse(lazy.SessionStore.getTabState(tab));
}
/* Mark: Public API */
shouldLoadTab(aTab) {
@@ -721,6 +757,20 @@ class nsZenWindowSync {
);
}
setPinnedTabState(aTab) {
const state = this.#getTabState(aTab);
const initialState = {
entry: state.entries[state.index - 1],
image: state.image,
};
this.#runOnAllWindows(null, (win) => {
const targetTab = this.#getItemFromWindow(win, aTab.id);
if (targetTab) {
targetTab._zenPinnedInitialState = initialState;
}
});
}
moveTabsToSyncedWorkspace(aWindow, aWorkspaceId) {
const tabsToMove = aWindow.gZenWorkspaces.allStoredTabs.filter(
(tab) => !tab.hasAttribute('zen-empty-tab')
@@ -788,6 +838,7 @@ class nsZenWindowSync {
SYNC_FLAG_ICON | SYNC_FLAG_LABEL | SYNC_FLAG_MOVE
);
});
this.#makeSureTabSyncsPermanentKey(tab);
}
on_ZenTabIconChanged(aEvent) {
@@ -811,10 +862,19 @@ class nsZenWindowSync {
}
on_TabPinned(aEvent) {
const tab = aEvent.target;
this.setPinnedTabState(tab);
return this.on_TabMove(aEvent);
}
on_TabUnpinned(aEvent) {
const tab = aEvent.target;
this.#runOnAllWindows(null, (win) => {
const targetTab = this.#getItemFromWindow(win, tab.id);
if (targetTab) {
delete targetTab._zenPinnedInitialState;
}
});
return this.on_TabMove(aEvent);
}
@@ -849,7 +909,7 @@ class nsZenWindowSync {
}
this.#lastFocusedWindow = new WeakRef(window);
this.#lastSelectedTab = new WeakRef(window.gBrowser.selectedTab);
this.#onTabSwitchOrWindowFocus(window);
return this.#onTabSwitchOrWindowFocus(window);
}
on_TabSelect(aEvent) {
@@ -859,7 +919,7 @@ class nsZenWindowSync {
}
this.#lastSelectedTab = new WeakRef(tab);
const previousTab = aEvent.detail.previousTab;
this.#onTabSwitchOrWindowFocus(aEvent.target.ownerGlobal, previousTab);
return this.#onTabSwitchOrWindowFocus(aEvent.target.ownerGlobal, previousTab);
}
on_SSWindowClosing(aEvent) {

View File

@@ -95,22 +95,7 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
_onTabResetPinButton(event, tab) {
event.stopPropagation();
const pin = this._pinsCache?.find((pin) => pin.uuid === tab.getAttribute('zen-pin-id'));
if (!pin) {
return;
}
let userContextId;
if (tab.hasAttribute('usercontextid')) {
userContextId = tab.getAttribute('usercontextid');
}
const pinnedUrl = Services.io.newURI(pin.url);
const browser = tab.linkedBrowser;
browser.loadURI(pinnedUrl, {
triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal({
userContextId,
}),
});
this.resetPinChangedUrl(tab);
this._resetTabToStoredState(tab);
}
get enabled() {
@@ -146,6 +131,10 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
}
}
#getTabState(tab) {
return JSON.parse(SessionStore.getTabState(tab));
}
async _onTabClick(e) {
const tab = e.target?.closest('tab');
if (e.button === 1 && tab) {
@@ -169,10 +158,11 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
async replacePinnedUrlWithCurrent(tab = undefined) {
tab ??= TabContextMenu.contextTab;
if (!tab || !tab.pinned || !tab.getAttribute('zen-pin-id')) {
if (!tab || !tab.pinned) {
return;
}
window.gZenWindowSync.setPinnedTabState(tab);
this.resetPinChangedUrl(tab);
gZenUIManager.showToast('zen-pinned-tab-replaced');
}
@@ -332,35 +322,14 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
}
_resetTabToStoredState(tab) {
const id = tab.getAttribute('zen-pin-id');
if (!id) {
return;
}
const state = this.#getTabState(tab);
const pin = this._pinsCache.find((pin) => pin.uuid === id);
if (!pin) {
return;
}
const initialState = tab._zenPinnedInitialState;
const tabState = SessionStore.getTabState(tab);
const state = JSON.parse(tabState);
// Remove everything except the entry we want to keep
state.entries = [initialState.entry];
const foundEntryIndex = state.entries?.findIndex((entry) => entry.url === pin.url);
if (foundEntryIndex === -1) {
state.entries = [
{
url: pin.url,
title: pin.title,
triggeringPrincipal_base64: lazy.E10SUtils.SERIALIZED_SYSTEMPRINCIPAL,
},
];
} else {
// Remove everything except the entry we want to keep
const existingEntry = state.entries[foundEntryIndex];
existingEntry.title = pin.title;
state.entries = [existingEntry];
}
state.image = pin.iconUrl || state.image;
state.image = initialState.image;
state.index = 0;
SessionStore.setTabState(tab, state);
@@ -405,16 +374,15 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
if (tab.hasAttribute('zen-workspace-id')) {
tab.removeAttribute('zen-workspace-id');
}
if (tab.pinned && tab.hasAttribute('zen-pin-id')) {
if (tab.pinned) {
gBrowser.zenHandleTabMove(tab, () => {
if (tab.ownerGlobal !== window) {
tab = gBrowser.adoptTab(tab, {
selectTab: tab.selected,
});
tab.setAttribute('zen-essential', 'true');
} else {
section.appendChild(tab);
}
section.appendChild(tab);
});
} else {
gBrowser.pinTab(tab);
@@ -507,8 +475,7 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
}
const isVisible = contextTab.pinned && !contextTab.multiselected;
const zenAddEssential = document.getElementById('context_zen-add-essential');
document.getElementById('context_zen-reset-pinned-tab').hidden =
!isVisible || !contextTab.getAttribute('zen-pin-id');
document.getElementById('context_zen-reset-pinned-tab').hidden = !isVisible;
document.getElementById('context_zen-replace-pinned-url-with-current').hidden = !isVisible;
zenAddEssential.hidden = contextTab.getAttribute('zen-essential') || !!contextTab.group;
zenAddEssential.setAttribute(
@@ -646,22 +613,23 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
async onLocationChange(browser) {
const tab = gBrowser.getTabForBrowser(browser);
if (!tab || !tab.pinned || tab.hasAttribute('zen-essential') || !this._pinsCache) {
return;
}
const pin = this._pinsCache.find((pin) => pin.uuid === tab.getAttribute('zen-pin-id'));
if (!pin) {
if (
!tab ||
!tab.pinned ||
tab.hasAttribute('zen-essential') ||
!tab._zenPinnedInitialState?.entry
) {
return;
}
// Remove # and ? from the URL
const pinUrl = pin.url.split('#')[0];
const pinUrl = tab._zenPinnedInitialState.entry.url.split('#')[0];
const currentUrl = browser.currentURI.spec.split('#')[0];
// Add an indicator that the pin has been changed
if (pinUrl === currentUrl) {
this.resetPinChangedUrl(tab);
return;
}
this.pinHasChangedUrl(tab, pin);
this.pinHasChangedUrl(tab);
}
resetPinChangedUrl(tab) {
@@ -673,7 +641,7 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
tab.style.removeProperty('--zen-original-tab-icon');
}
pinHasChangedUrl(tab, pin) {
pinHasChangedUrl(tab) {
if (tab.hasAttribute('zen-pinned-changed')) {
return;
}
@@ -682,7 +650,7 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
} else {
tab.setAttribute('zen-pinned-changed', 'true');
}
tab.style.setProperty('--zen-original-tab-icon', `url(${pin.iconUrl?.spec})`);
tab.style.setProperty('--zen-original-tab-icon', `url(${tab._zenPinnedInitialState.image})`);
}
removeTabContainersDragoverClass(hideIndicator = true) {
@@ -799,35 +767,12 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
}
async updatePinTitle(tab, newTitle, isEdited = true) {
const uuid = tab.getAttribute('zen-pin-id');
const browsers = Services.wm.getEnumerator('navigator:browser');
// update the label for the same pin across all windows
for (const browser of browsers) {
const tabs = browser.gBrowser.tabs;
// Fix pinned cache for the browser
const browserCache = browser.gZenPinnedTabManager?._pinsCache;
if (browserCache) {
const pin = browserCache.find((pin) => pin.uuid === uuid);
if (pin) {
pin.title = newTitle;
pin.editedTitle = isEdited;
}
}
for (let i = 0; i < tabs.length; i++) {
const tabToEdit = tabs[i];
if (tabToEdit.getAttribute('zen-pin-id') === uuid && tabToEdit !== tab) {
tabToEdit.removeAttribute('zen-has-static-label');
if (isEdited) {
gBrowser._setTabLabel(tabToEdit, newTitle);
tabToEdit.setAttribute('zen-has-static-label', 'true');
} else {
gBrowser.setTabTitle(tabToEdit);
}
break;
}
}
tab.removeAttribute('zen-has-static-label');
if (isEdited) {
gBrowser._setTabLabel(tab, newTitle);
tab.setAttribute('zen-has-static-label', 'true');
} else {
gBrowser.setTabTitle(tab);
}
}
@@ -943,20 +888,8 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
}
}
async onTabLabelChanged(tab) {
onTabLabelChanged(tab) {
tab.dispatchEvent(new CustomEvent('ZenTabLabelChanged', { bubbles: true, detail: { tab } }));
if (!this._pinsCache) {
return;
}
// If our current pin in the cache point to about:blank, we need to update the entry
const pin = this._pinsCache.find((pin) => pin.uuid === tab.getAttribute('zen-pin-id'));
if (!pin) {
return;
}
if (pin.url === 'about:blank' && tab.linkedBrowser.currentURI.spec !== 'about:blank') {
await this.replacePinnedUrlWithCurrent(tab);
}
}
}