mirror of
https://github.com/zen-browser/desktop.git
synced 2025-09-05 19:08:18 +00:00
feat: Full cross-window workspace syncing, b=no-bug, c=workspaces
This commit is contained in:
@@ -58,3 +58,4 @@
|
||||
<script type="text/javascript" src="chrome://browser/content/zen-components/ZenDownloadAnimation.mjs"></script>
|
||||
<script type="text/javascript" src="chrome://browser/content/zen-components/ZenEmojiPicker.mjs"></script>
|
||||
<script type="text/javascript" src="chrome://browser/content/zen-components/ZenWorkspaceCreation.mjs"></script>
|
||||
<script type="text/javascript" src="chrome://browser/content/zen-components/ZenWindowSyncing.mjs"></script>
|
||||
|
@@ -44,6 +44,7 @@
|
||||
content/browser/zen-components/ZenWorkspaceIcons.mjs (../../zen/workspaces/ZenWorkspaceIcons.mjs)
|
||||
content/browser/zen-components/ZenWorkspace.mjs (../../zen/workspaces/ZenWorkspace.mjs)
|
||||
content/browser/zen-components/ZenWorkspaces.mjs (../../zen/workspaces/ZenWorkspaces.mjs)
|
||||
content/browser/zen-components/ZenWindowSyncing.mjs (../../zen/workspaces/ZenWindowSyncing.mjs)
|
||||
content/browser/zen-components/ZenWorkspaceCreation.mjs (../../zen/workspaces/ZenWorkspaceCreation.mjs)
|
||||
content/browser/zen-components/ZenWorkspacesStorage.mjs (../../zen/workspaces/ZenWorkspacesStorage.mjs)
|
||||
content/browser/zen-components/ZenWorkspacesSync.mjs (../../zen/workspaces/ZenWorkspacesSync.mjs)
|
||||
|
226
src/zen/workspaces/ZenWindowSyncing.mjs
Normal file
226
src/zen/workspaces/ZenWindowSyncing.mjs
Normal file
@@ -0,0 +1,226 @@
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
{
|
||||
class nsZenWorkspaceWindowSync extends nsZenMultiWindowFeature {
|
||||
#ignoreNextEvents = false;
|
||||
#waitForPromise = null;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
if (!window.closed) {
|
||||
this.init();
|
||||
}
|
||||
}
|
||||
|
||||
async init() {
|
||||
await gZenWorkspaces.promiseInitialized;
|
||||
this.#makeSureAllTabsHaveIds();
|
||||
this.#setUpEventListeners();
|
||||
}
|
||||
|
||||
#makeSureAllTabsHaveIds() {
|
||||
const allTabs = gZenWorkspaces.allStoredTabs;
|
||||
for (const tab of allTabs) {
|
||||
if (!tab.hasAttribute('zen-sync-id')) {
|
||||
const tabId = gZenUIManager.generateUuidv4();
|
||||
tab.setAttribute('zen-sync-id', tabId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#setUpEventListeners() {
|
||||
const kEvents = [
|
||||
'TabClose',
|
||||
'TabOpen',
|
||||
'TabPinned',
|
||||
'TabUnpinned',
|
||||
'TabAddedToEssentials',
|
||||
'TabRemovedFromEssentials',
|
||||
'TabHide',
|
||||
'TabShow',
|
||||
'TabMove',
|
||||
];
|
||||
const eventListener = this.#handleEvent.bind(this);
|
||||
for (const event of kEvents) {
|
||||
window.addEventListener(event, eventListener);
|
||||
}
|
||||
|
||||
window.addEventListener('unload', () => {
|
||||
for (const event of kEvents) {
|
||||
window.removeEventListener(event, eventListener);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#handleEvent(event) {
|
||||
this.#propagateToOtherWindows(event);
|
||||
}
|
||||
|
||||
async #propagateToOtherWindows(event) {
|
||||
if (this.#ignoreNextEvents) {
|
||||
return;
|
||||
}
|
||||
if (this.#waitForPromise) {
|
||||
await this.#waitForPromise;
|
||||
}
|
||||
this.#waitForPromise = new Promise(async (resolve) => {
|
||||
await this.foreachWindowAsActive(async (browser) => {
|
||||
if (browser.gZenWorkspaceWindowSync && !this.windowIsActive(browser)) {
|
||||
await browser.gZenWorkspaceWindowSync.onExternalTabEvent(event);
|
||||
}
|
||||
});
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
async onExternalTabEvent(event) {
|
||||
this.#ignoreNextEvents = true;
|
||||
switch (event.type) {
|
||||
case 'TabClose':
|
||||
this.#onTabClose(event);
|
||||
break;
|
||||
case 'TabOpen':
|
||||
await this.#onTabOpen(event);
|
||||
break;
|
||||
case 'TabPinned':
|
||||
this.#onTabPinned(event);
|
||||
break;
|
||||
case 'TabUnpinned':
|
||||
this.#onTabUnpinned(event);
|
||||
break;
|
||||
case 'TabAddedToEssentials':
|
||||
this.#onTabAddedToEssentials(event);
|
||||
break;
|
||||
case 'TabRemovedFromEssentials':
|
||||
this.#onTabRemovedFromEssentials(event);
|
||||
break;
|
||||
case 'TabHide':
|
||||
this.#onTabHide(event);
|
||||
break;
|
||||
case 'TabShow':
|
||||
this.#onTabShow(event);
|
||||
break;
|
||||
case 'TabMove':
|
||||
this.#onTabMove(event);
|
||||
break;
|
||||
default:
|
||||
console.warn(`Unhandled event type: ${event.type}`);
|
||||
break;
|
||||
}
|
||||
this.#ignoreNextEvents = false;
|
||||
}
|
||||
|
||||
#getTabId(tab) {
|
||||
return tab.getAttribute('zen-sync-id');
|
||||
}
|
||||
|
||||
#getTabWithId(tabId) {
|
||||
for (const tab of gZenWorkspaces.allStoredTabs) {
|
||||
if (this.#getTabId(tab) === tabId) {
|
||||
return tab;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
#onTabClose(event) {
|
||||
const targetTab = event.target;
|
||||
const tabId = this.#getTabId(targetTab);
|
||||
const tabToClose = this.#getTabWithId(tabId);
|
||||
if (tabToClose) {
|
||||
gBrowser.removeTab(tabToClose);
|
||||
}
|
||||
}
|
||||
|
||||
#onTabPinned(event) {
|
||||
const targetTab = event.target;
|
||||
if (targetTab.hasAttribute('zen-essential')) {
|
||||
return this.#onTabAddedToEssentials(event);
|
||||
}
|
||||
const tabId = this.#getTabId(targetTab);
|
||||
const elementIndex = targetTab.elementIndex;
|
||||
const tabToPin = this.#getTabWithId(tabId);
|
||||
if (tabToPin) {
|
||||
gBrowser.pinTab(tabToPin);
|
||||
gBrowser.moveTabTo(tabToPin, { elementIndex, forceUngrouped: !!targetTab.group });
|
||||
}
|
||||
}
|
||||
|
||||
#onTabUnpinned(event) {
|
||||
const targetTab = event.target;
|
||||
const tabId = this.#getTabId(targetTab);
|
||||
const tabToUnpin = this.#getTabWithId(tabId);
|
||||
if (tabToUnpin) {
|
||||
gBrowser.unpinTab(tabToUnpin);
|
||||
}
|
||||
}
|
||||
|
||||
#onTabAddedToEssentials(event) {
|
||||
const targetTab = event.target;
|
||||
const tabId = this.#getTabId(targetTab);
|
||||
const tabToAdd = this.#getTabWithId(tabId);
|
||||
if (tabToAdd) {
|
||||
gZenPinnedTabManager.addToEssentials(tabToAdd);
|
||||
}
|
||||
}
|
||||
|
||||
#onTabRemovedFromEssentials(event) {
|
||||
const targetTab = event.target;
|
||||
const tabId = this.#getTabId(targetTab);
|
||||
const tabToRemove = this.#getTabWithId(tabId);
|
||||
if (tabToRemove) {
|
||||
gZenPinnedTabManager.removeFromEssentials(tabToRemove);
|
||||
}
|
||||
}
|
||||
|
||||
#onTabHide(event) {
|
||||
const targetTab = event.target;
|
||||
const tabId = this.#getTabId(targetTab);
|
||||
const tabToHide = this.#getTabWithId(tabId);
|
||||
if (tabToHide) {
|
||||
gBrowser.hideTab(tabToHide);
|
||||
}
|
||||
}
|
||||
|
||||
#onTabShow(event) {
|
||||
const targetTab = event.target;
|
||||
const tabId = this.#getTabId(targetTab);
|
||||
const tabToShow = this.#getTabWithId(tabId);
|
||||
if (tabToShow) {
|
||||
gBrowser.showTab(tabToShow);
|
||||
}
|
||||
}
|
||||
|
||||
#onTabMove(event) {
|
||||
const targetTab = event.target;
|
||||
const tabId = this.#getTabId(targetTab);
|
||||
const elementIndex = targetTab.elementIndex;
|
||||
const tabToMove = this.#getTabWithId(tabId);
|
||||
if (tabToMove) {
|
||||
gBrowser.moveTabTo(tabToMove, { elementIndex, forceUngrouped: !!targetTab.group });
|
||||
}
|
||||
}
|
||||
|
||||
async #onTabOpen(event) {
|
||||
await new Promise((resolve) => {
|
||||
const targetTab = event.target;
|
||||
const isPinned = targetTab.pinned;
|
||||
const isEssential = isPinned && targetTab.hasAttribute('zen-essential');
|
||||
const elementIndex = targetTab.elementIndex;
|
||||
|
||||
const duplicatedTab = SessionStore.duplicateTab(window, targetTab, 0, true);
|
||||
if (isEssential) {
|
||||
gZenPinnedTabManager.addToEssentials(duplicatedTab);
|
||||
} else if (isPinned) {
|
||||
gBrowser.pinTab(duplicatedTab);
|
||||
}
|
||||
|
||||
gBrowser.moveTabTo(duplicatedTab, { elementIndex, forceUngrouped: !!targetTab.group });
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
window.gZenWorkspaceWindowSync = new nsZenWorkspaceWindowSync();
|
||||
}
|
Reference in New Issue
Block a user