mirror of
https://github.com/zen-browser/desktop.git
synced 2026-08-12 09:45:18 +00:00
feat: Start implementing old pinned tab behaviour we used to have, b=no-bug, c=common, tabs
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user