From e25e0961d61f2f8f29b14bf11b96e74894fc48b8 Mon Sep 17 00:00:00 2001 From: tunefish Date: Mon, 19 Feb 2018 00:52:25 +0100 Subject: [PATCH 1/9] Add context menu entry: 'Reopen in container' --- src/js/background/assignManager.js | 56 ++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index 0051e09..cd2fd83 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -1,4 +1,5 @@ const assignManager = { + MENU_REOPEN_IN: "reopen-in-container", MENU_ASSIGN_ID: "open-in-this-container", MENU_REMOVE_ID: "remove-open-in-this-container", MENU_SEPARATOR_ID: "separator", @@ -180,6 +181,22 @@ const assignManager = { }, async _onClickedHandler(info, tab) { + const reopenCookieStoreId = this.menuId2cookieStoreId(info.menuItemId); + + if (reopenCookieStoreId) { + browser.tabs.create({ + active: info.frameId !== undefined, + cookieStoreId: reopenCookieStoreId, + index: tab.index + 1, + openerTabId: tab.id, + pinned: tab.pinned, + url: tab.url, + }).then(() => { + browser.tabs.remove(tab.id); + }); + return; + } + const userContextId = this.getUserContextIdFromCookieStore(tab); // Mapping ${URL(info.pageUrl).hostname} to ${userContextId} let remove; @@ -222,6 +239,16 @@ const assignManager = { return backgroundLogic.getUserContextIdFromCookieStoreId(tab.cookieStoreId); }, + cookieStoreId2menuId(cookieStoreId) { + return "reopen-in-" + cookieStoreId; + }, + + menuId2cookieStoreId(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 @@ -294,6 +321,12 @@ 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.contextualIdentities.query({}).then((identities) => { + identities.forEach((identity) => { + browser.contextMenus.remove(this.cookieStoreId2menuId(identity.cookieStoreId)); + }); + }); + browser.contextMenus.remove(this.MENU_REOPEN_IN); browser.contextMenus.remove(this.MENU_REMOVE_ID); browser.contextMenus.remove(this.MENU_SEPARATOR_ID); browser.contextMenus.remove(this.MENU_HIDE_ID); @@ -302,6 +335,29 @@ const assignManager = { async calculateContextMenu(tab) { this.removeContextMenu(); + + browser.contextMenus.create({ + id: this.MENU_REOPEN_IN, + title: "Reopen in container", + contexts: ["all", "tab"], + }); + + const identities = await browser.contextualIdentities.query({}); + identities.forEach((identity) => { + browser.contextMenus.create({ + id: this.cookieStoreId2menuId(identity.cookieStoreId), + title: identity.name, + // TODO: colorized icons? + icons: { + "16": identity.iconUrl + }, + // TODO: hide entry for current container in context menu of tabs + contexts: (identity.cookieStoreId !== tab.cookieStoreId) ? + ["all", "tab"] : ["tab"], + parentId: this.MENU_REOPEN_IN, + }); + }); + const siteSettings = await this._getAssignment(tab); // Return early and not add an item if we have false // False represents assignment is not permitted From 2a6775ab120ea43f3e2dc8289dc2a8f4c299c16f Mon Sep 17 00:00:00 2001 From: tunefish Date: Mon, 19 Feb 2018 01:03:10 +0100 Subject: [PATCH 2/9] Adding error handling --- src/js/background/assignManager.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index cd2fd83..81c1ef8 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -193,6 +193,8 @@ const assignManager = { url: tab.url, }).then(() => { browser.tabs.remove(tab.id); + }).catch((e) => { + throw e; }); return; } @@ -325,7 +327,7 @@ const assignManager = { identities.forEach((identity) => { browser.contextMenus.remove(this.cookieStoreId2menuId(identity.cookieStoreId)); }); - }); + }).catch(() => {}); browser.contextMenus.remove(this.MENU_REOPEN_IN); browser.contextMenus.remove(this.MENU_REMOVE_ID); browser.contextMenus.remove(this.MENU_SEPARATOR_ID); From 396c96efc906e68b53308f726c8f17dcd1e29a3d Mon Sep 17 00:00:00 2001 From: tunefish Date: Tue, 20 Feb 2018 01:50:00 +0100 Subject: [PATCH 3/9] Update context menu when a container is created/deleted --- src/js/background/assignManager.js | 34 ++++++++++++++++++----------- src/js/background/messageHandler.js | 8 +++++++ 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index 81c1ef8..ddf0985 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -325,7 +325,7 @@ const assignManager = { browser.contextMenus.remove(this.MENU_ASSIGN_ID); browser.contextualIdentities.query({}).then((identities) => { identities.forEach((identity) => { - browser.contextMenus.remove(this.cookieStoreId2menuId(identity.cookieStoreId)); + this.removeContainerMenuEntry(identity); }); }).catch(() => {}); browser.contextMenus.remove(this.MENU_REOPEN_IN); @@ -335,6 +335,24 @@ const assignManager = { browser.contextMenus.remove(this.MENU_MOVE_ID); }, + addContainerMenuEntry(contextualIdentity, contexts) { + browser.contextMenus.create({ + id: this.cookieStoreId2menuId(contextualIdentity.cookieStoreId), + title: contextualIdentity.name, + // TODO: colorized icons? + icons: { + "16": contextualIdentity.iconUrl + }, + // TODO: hide entry for current container in context menu of tabs + contexts: contexts, + parentId: this.MENU_REOPEN_IN, + }); + }, + + removeContainerMenuEntry(contextualIdentity) { + browser.contextMenus.remove(this.cookieStoreId2menuId(contextualIdentity.cookieStoreId)); + }, + async calculateContextMenu(tab) { this.removeContextMenu(); @@ -346,18 +364,8 @@ const assignManager = { const identities = await browser.contextualIdentities.query({}); identities.forEach((identity) => { - browser.contextMenus.create({ - id: this.cookieStoreId2menuId(identity.cookieStoreId), - title: identity.name, - // TODO: colorized icons? - icons: { - "16": identity.iconUrl - }, - // TODO: hide entry for current container in context menu of tabs - contexts: (identity.cookieStoreId !== tab.cookieStoreId) ? - ["all", "tab"] : ["tab"], - parentId: this.MENU_REOPEN_IN, - }); + this.addContainerMenuEntry(identity, (identity.cookieStoreId !== tab.cookieStoreId) ? + ["all", "tab"] : ["tab"]); }); const siteSettings = await this._getAssignment(tab); diff --git a/src/js/background/messageHandler.js b/src/js/background/messageHandler.js index 1971953..2e39510 100644 --- a/src/js/background/messageHandler.js +++ b/src/js/background/messageHandler.js @@ -76,6 +76,14 @@ const messageHandler = { browser.contextualIdentities.onRemoved.addListener(({contextualIdentity}) => { const userContextId = backgroundLogic.getUserContextIdFromCookieStoreId(contextualIdentity.cookieStoreId); backgroundLogic.deleteContainer(userContextId, true); + + assignManager.removeContainerMenuEntry(contextualIdentity); + }); + } + + if (browser.contextualIdentities.onCreated) { + browser.contextualIdentities.onCreated.addListener(({contextualIdentity}) => { + assignManager.addContainerMenuEntry(contextualIdentity, ["all", "tab"]) }); } From 351feb4495d571098ffb98ec596d98734039b0ab Mon Sep 17 00:00:00 2001 From: tunefish Date: Tue, 20 Feb 2018 01:53:35 +0100 Subject: [PATCH 4/9] Missing ; --- src/js/background/messageHandler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/background/messageHandler.js b/src/js/background/messageHandler.js index 2e39510..f7e0669 100644 --- a/src/js/background/messageHandler.js +++ b/src/js/background/messageHandler.js @@ -83,7 +83,7 @@ const messageHandler = { if (browser.contextualIdentities.onCreated) { browser.contextualIdentities.onCreated.addListener(({contextualIdentity}) => { - assignManager.addContainerMenuEntry(contextualIdentity, ["all", "tab"]) + assignManager.addContainerMenuEntry(contextualIdentity, ["all", "tab"]); }); } From 0edb67224d66873c1747e6d96868e94b689577b5 Mon Sep 17 00:00:00 2001 From: tunefish Date: Fri, 16 Mar 2018 19:02:56 +0100 Subject: [PATCH 5/9] Fix concurrency bug for completed request in inactive tab --- src/js/background/messageHandler.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/js/background/messageHandler.js b/src/js/background/messageHandler.js index f7e0669..b283c42 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 @@ -89,6 +90,7 @@ const messageHandler = { browser.tabs.onActivated.addListener((info) => { assignManager.removeContextMenu(); + this.activeTab = info.tabId; browser.tabs.get(info.tabId).then((tab) => { assignManager.calculateContextMenu(tab); }).catch((e) => { @@ -106,11 +108,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) => { From 884b55c67991d37d879602165dd1225a1bd94eb2 Mon Sep 17 00:00:00 2001 From: tunefish Date: Fri, 16 Mar 2018 19:25:23 +0100 Subject: [PATCH 6/9] Show default profile in context menu --- src/js/background/assignManager.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index ddf0985..5e50a63 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -188,7 +188,7 @@ const assignManager = { active: info.frameId !== undefined, cookieStoreId: reopenCookieStoreId, index: tab.index + 1, - openerTabId: tab.id, + openerTabId: tab.openerTabId, pinned: tab.pinned, url: tab.url, }).then(() => { @@ -362,6 +362,20 @@ const assignManager = { 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, + }); + const identities = await browser.contextualIdentities.query({}); identities.forEach((identity) => { this.addContainerMenuEntry(identity, (identity.cookieStoreId !== tab.cookieStoreId) ? From 628e85b81d235a4bfffb4d060ec7e437c8af1ce7 Mon Sep 17 00:00:00 2001 From: tunefish Date: Fri, 16 Mar 2018 19:39:15 +0100 Subject: [PATCH 7/9] Use await instead of then() --- src/js/background/assignManager.js | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index 5e50a63..2f9c771 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -184,18 +184,15 @@ const assignManager = { const reopenCookieStoreId = this.menuId2cookieStoreId(info.menuItemId); if (reopenCookieStoreId) { - browser.tabs.create({ + 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, - }).then(() => { - browser.tabs.remove(tab.id); - }).catch((e) => { - throw e; }); + browser.tabs.remove(tab.id); return; } @@ -376,10 +373,19 @@ const assignManager = { parentId: this.MENU_RELOAD_IN, }); - const identities = await browser.contextualIdentities.query({}); - identities.forEach((identity) => { - this.addContainerMenuEntry(identity, (identity.cookieStoreId !== tab.cookieStoreId) ? - ["all", "tab"] : ["tab"]); + 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); From c58c9811410feb10b0bac08fa2d5a845f1cb2ca9 Mon Sep 17 00:00:00 2001 From: tunefish Date: Fri, 16 Mar 2018 19:42:13 +0100 Subject: [PATCH 8/9] Rename functions/variables according to naming scheme, remove TODO, simplify --- src/js/background/assignManager.js | 28 +++++++++++----------------- src/js/background/messageHandler.js | 4 ++-- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index 2f9c771..e435bd6 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -1,5 +1,5 @@ const assignManager = { - MENU_REOPEN_IN: "reopen-in-container", + 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", @@ -181,7 +181,7 @@ const assignManager = { }, async _onClickedHandler(info, tab) { - const reopenCookieStoreId = this.menuId2cookieStoreId(info.menuItemId); + const reopenCookieStoreId = this.getReloadMenuIdFromCookieStoreId(info.menuItemId); if (reopenCookieStoreId) { const newTab = await browser.tabs.create({ @@ -238,11 +238,11 @@ const assignManager = { return backgroundLogic.getUserContextIdFromCookieStoreId(tab.cookieStoreId); }, - cookieStoreId2menuId(cookieStoreId) { + getCookieStoreIdFromReloadMenuId(cookieStoreId) { return "reopen-in-" + cookieStoreId; }, - menuId2cookieStoreId(contextMenuId) { + getReloadMenuIdFromCookieStoreId(contextMenuId) { if (contextMenuId.startsWith("reopen-in-")) return contextMenuId.substring(10); return false; @@ -320,41 +320,35 @@ 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.contextualIdentities.query({}).then((identities) => { - identities.forEach((identity) => { - this.removeContainerMenuEntry(identity); - }); - }).catch(() => {}); - browser.contextMenus.remove(this.MENU_REOPEN_IN); + 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); }, - addContainerMenuEntry(contextualIdentity, contexts) { + addReloadMenuEntry(contextualIdentity, contexts) { browser.contextMenus.create({ - id: this.cookieStoreId2menuId(contextualIdentity.cookieStoreId), + id: this.getCookieStoreIdFromReloadMenuId(contextualIdentity.cookieStoreId), title: contextualIdentity.name, // TODO: colorized icons? icons: { "16": contextualIdentity.iconUrl }, - // TODO: hide entry for current container in context menu of tabs contexts: contexts, - parentId: this.MENU_REOPEN_IN, + parentId: this.MENU_RELOAD_IN, }); }, - removeContainerMenuEntry(contextualIdentity) { - browser.contextMenus.remove(this.cookieStoreId2menuId(contextualIdentity.cookieStoreId)); + removeReloadMenuEntry(contextualIdentity) { + browser.contextMenus.remove(this.getCookieStoreIdFromReloadMenuId(contextualIdentity.cookieStoreId)); }, async calculateContextMenu(tab) { this.removeContextMenu(); browser.contextMenus.create({ - id: this.MENU_REOPEN_IN, + id: this.MENU_RELOAD_IN, title: "Reopen in container", contexts: ["all", "tab"], }); diff --git a/src/js/background/messageHandler.js b/src/js/background/messageHandler.js index b283c42..6f6e62c 100644 --- a/src/js/background/messageHandler.js +++ b/src/js/background/messageHandler.js @@ -78,13 +78,13 @@ const messageHandler = { const userContextId = backgroundLogic.getUserContextIdFromCookieStoreId(contextualIdentity.cookieStoreId); backgroundLogic.deleteContainer(userContextId, true); - assignManager.removeContainerMenuEntry(contextualIdentity); + assignManager.removeReloadMenuEntry(contextualIdentity); }); } if (browser.contextualIdentities.onCreated) { browser.contextualIdentities.onCreated.addListener(({contextualIdentity}) => { - assignManager.addContainerMenuEntry(contextualIdentity, ["all", "tab"]); + assignManager.addReloadMenuEntry(contextualIdentity, ["all", "tab"]); }); } From 68d0f18ec92ed8f19925041643ab4648b43c1917 Mon Sep 17 00:00:00 2001 From: tunefish Date: Fri, 16 Mar 2018 19:46:45 +0100 Subject: [PATCH 9/9] Mute reopened tab if original tab was muted --- src/js/background/assignManager.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/js/background/assignManager.js b/src/js/background/assignManager.js index e435bd6..a2151fd 100644 --- a/src/js/background/assignManager.js +++ b/src/js/background/assignManager.js @@ -192,6 +192,7 @@ const assignManager = { pinned: tab.pinned, url: tab.url, }); + browser.tabs.update(newTab.id, {"muted": tab.mutedInfo.muted}); browser.tabs.remove(tab.id); return; }