diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index a03a163..5fb2cfe 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -1,4 +1,5 @@ const assignManager = { + MENU_RELOAD_IN: "reopen-in-container", MENU_ASSIGN_ID: "open-in-this-container", MENU_REMOVE_ID: "remove-open-in-this-container", MENU_SEPARATOR_ID: "separator", @@ -241,6 +242,22 @@ const assignManager = { }, async _onClickedHandler(info, tab) { + const reopenCookieStoreId = this.getReloadMenuIdFromCookieStoreId(info.menuItemId); + + if (reopenCookieStoreId) { + const newTab = await browser.tabs.create({ + active: info.frameId !== undefined, + cookieStoreId: reopenCookieStoreId, + index: tab.index + 1, + openerTabId: tab.openerTabId, + pinned: tab.pinned, + url: tab.url, + }); + browser.tabs.update(newTab.id, {"muted": tab.mutedInfo.muted}); + browser.tabs.remove(tab.id); + return; + } + const userContextId = this.getUserContextIdFromCookieStore(tab); // Mapping ${URL(info.pageUrl).hostname} to ${userContextId} let remove; @@ -283,6 +300,16 @@ const assignManager = { return backgroundLogic.getUserContextIdFromCookieStoreId(tab.cookieStoreId); }, + getCookieStoreIdFromReloadMenuId(cookieStoreId) { + return "reopen-in-" + cookieStoreId; + }, + + getReloadMenuIdFromCookieStoreId(contextMenuId) { + if (contextMenuId.startsWith("reopen-in-")) + return contextMenuId.substring(10); + return false; + }, + isTabPermittedAssign(tab) { // Ensure we are not an important about url // Ensure we are not in incognito mode @@ -355,14 +382,68 @@ const assignManager = { // We also can't change for always private mode // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1352102 browser.contextMenus.remove(this.MENU_ASSIGN_ID); + browser.contextMenus.remove(this.MENU_RELOAD_IN); browser.contextMenus.remove(this.MENU_REMOVE_ID); browser.contextMenus.remove(this.MENU_SEPARATOR_ID); browser.contextMenus.remove(this.MENU_HIDE_ID); browser.contextMenus.remove(this.MENU_MOVE_ID); }, + addReloadMenuEntry(contextualIdentity, contexts) { + browser.contextMenus.create({ + id: this.getCookieStoreIdFromReloadMenuId(contextualIdentity.cookieStoreId), + title: contextualIdentity.name, + // TODO: colorized icons? + icons: { + "16": contextualIdentity.iconUrl + }, + contexts: contexts, + parentId: this.MENU_RELOAD_IN, + }); + }, + + removeReloadMenuEntry(contextualIdentity) { + browser.contextMenus.remove(this.getCookieStoreIdFromReloadMenuId(contextualIdentity.cookieStoreId)); + }, + async calculateContextMenu(tab) { this.removeContextMenu(); + + browser.contextMenus.create({ + id: this.MENU_RELOAD_IN, + title: "Reopen in container", + contexts: ["all", "tab"], + }); + + browser.contextMenus.create({ + id: this.getCookieStoreIdFromReloadMenuId("firefox-default"), + title: "Default", + contexts: ["all", "tab"], + parentId: this.MENU_RELOAD_IN, + }); + + browser.contextMenus.create({ + id: "reopen-separator", + contexts: ["all", "tab"], + type: "separator", + parentId: this.MENU_RELOAD_IN, + }); + + let identities; + try { + identities = await browser.contextualIdentities.query({}); + } catch (e) { + identities = []; + } + + identities.forEach(async (identity) => { + if (identity.cookieStoreId === tab.cookieStoreId) { + this.addReloadMenuEntry(identity, ["tab"], false); + } else { + this.addReloadMenuEntry(identity, ["all", "tab"], false); + } + }); + const siteSettings = await this._getAssignment(tab); // Return early and not add an item if we have false // False represents assignment is not permitted diff --git a/src/js/background/messageHandler.js b/src/js/background/messageHandler.js index 6e5fced..77b41b8 100644 --- a/src/js/background/messageHandler.js +++ b/src/js/background/messageHandler.js @@ -4,6 +4,7 @@ const messageHandler = { // If this were in platform we would change how the tab opens based on "new tab" link navigations such as ctrl+click LAST_CREATED_TAB_TIMER: 2000, unhideQueue: [], + activeTab: -1, init() { // Handles messages from webextension code @@ -112,11 +113,20 @@ const messageHandler = { browser.contextualIdentities.onRemoved.addListener(({contextualIdentity}) => { const userContextId = backgroundLogic.getUserContextIdFromCookieStoreId(contextualIdentity.cookieStoreId); backgroundLogic.deleteContainer(userContextId, true); + + assignManager.removeReloadMenuEntry(contextualIdentity); + }); + } + + if (browser.contextualIdentities.onCreated) { + browser.contextualIdentities.onCreated.addListener(({contextualIdentity}) => { + assignManager.addReloadMenuEntry(contextualIdentity, ["all", "tab"]); }); } browser.tabs.onActivated.addListener((info) => { assignManager.removeContextMenu(); + this.activeTab = info.tabId; browser.tabs.get(info.tabId).then((tab) => { assignManager.calculateContextMenu(tab); }).catch((e) => { @@ -134,11 +144,15 @@ const messageHandler = { } assignManager.removeContextMenu(); - browser.tabs.get(details.tabId).then((tab) => { - assignManager.calculateContextMenu(tab); - }).catch((e) => { - throw e; - }); + // make sure to update the context menu only if the request was completed + // for the currently active tab + if (details.tabId === this.activeTab) { + browser.tabs.get(details.tabId).then((tab) => { + assignManager.calculateContextMenu(tab); + }).catch((e) => { + throw e; + }); + } }, {urls: [""], types: ["main_frame"]}); browser.tabs.onCreated.addListener((tab) => {