From 5f9fdafc5aabe6c045db2345e80374c01bee0b58 Mon Sep 17 00:00:00 2001 From: dmorlitz Date: Wed, 10 Nov 2021 12:56:21 -0500 Subject: [PATCH 1/6] Update containers.js Added line 71-76 - which reads the configuration string for "leave in current container", converts it to a Regex and decides if the URL being opened should remain in the current container regardless of other settings --- src/containers.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/containers.js b/src/containers.js index 3fc7475..ad3347a 100644 --- a/src/containers.js +++ b/src/containers.js @@ -68,6 +68,12 @@ async function handle(url, tabId) { delete creatingTabs[tabId]; } let preferences = await PreferenceStorage.getAll(true); + const OPEN_IN_CURRENT_CONTAINER = '(' + preferences.openInCurrentContainer + ')/'; + let OPEN_IN_CURRENT_CONTAINER_REGEX = new RegExp(OPEN_IN_CURRENT_CONTAINER); + if (OPEN_IN_CURRENT_CONTAINER_REGEX.test(url)) { + //console.debug('URL was left in current container due to Regex--> ', url); + return; + } let [hostMap, identities, currentTab] = await Promise.all([ Storage.get(url, preferences.matchDomainOnly), ContextualIdentity.getAll(), From 795b3583585b11c206632375357277c1938c5ecf Mon Sep 17 00:00:00 2001 From: dmorlitz Date: Wed, 10 Nov 2021 12:58:33 -0500 Subject: [PATCH 2/6] Added "keep in current container" config parm Added lines 15-20 - to create a preference for | separated list of domains which will always remain in the tab they are created in --- src/ui-preferences/preferences.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/ui-preferences/preferences.json b/src/ui-preferences/preferences.json index 3f92f07..8901e79 100644 --- a/src/ui-preferences/preferences.json +++ b/src/ui-preferences/preferences.json @@ -11,6 +11,13 @@ "label": "Keep old tabs", "description": "After a contained tab has been created, the old won't be closed" }, + { + "type": "string", + "name": "openInCurrentContainer", + "label": "Open in current container", + "description": "A list of domains separated by a pipe (|) which will *always* open in the current container that opened them", + "defaultValue": "" + }, { "type": "group", "name": "defaultContainer", From 46a07e09e9167f8644ec61af4de96a9f0be7e47a Mon Sep 17 00:00:00 2001 From: David Morlitz Date: Thu, 11 Nov 2021 12:13:51 -0500 Subject: [PATCH 3/6] Properly handle blank configuration variable --- containers.js | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 containers.js diff --git a/containers.js b/containers.js new file mode 100644 index 0000000..5839dbf --- /dev/null +++ b/containers.js @@ -0,0 +1,141 @@ +import Storage from './Storage/HostStorage'; +import ContextualIdentity, {NO_CONTAINER} from './ContextualIdentity'; +import Tabs from './Tabs'; +import PreferenceStorage from './Storage/PreferenceStorage'; +import {filterByKey} from './utils'; +import {buildDefaultContainer} from './defaultContainer'; + +const IGNORED_URLS_REGEX = /^(about|moz-extension|file|javascript|data|chrome):/; + +/** + * Keep track of the tabs we're creating + * tabId: url + */ +const creatingTabs = {}; + +const createTab = (url, newTabIndex, currentTabId, openerTabId, cookieStoreId) => { + Tabs.get(currentTabId).then((currentTab) => { + const createOptions = { + url, + index: newTabIndex, + cookieStoreId, + active: currentTab.active, + pinned: currentTab.pinned, + discarded: currentTab.discarded, + openInReaderMode: currentTab.isInReaderMode, + }; + // Passing the openerTabId without a cookieStoreId + // creates a tab in the same container as the opener + if (cookieStoreId && openerTabId) { + createOptions.openerTabId = openerTabId; + } + Tabs.create(createOptions).then((createdTab) => { + creatingTabs[createdTab.id] = url; + if (!cookieStoreId && openerTabId) { + Tabs.update(createdTab.id, { + openerTabId: openerTabId, + }); + } + }); + PreferenceStorage.get('keepOldTabs').then(({value}) => { + // if keepOldTabs is false, remove the 'old' tab + // -or- + // if the current tab is about:blank or about:newtab + // or some custom moz-extension pages + // we should still close the current tab even though + // keepOldTabs is true, because these are just + // interstitial tabs that are no longer used + if (!value || /^(about:)|(moz-extension:)/.test(currentTab.url)) { + Tabs.remove(currentTabId); + } + }).catch(() => { + Tabs.remove(currentTabId); + }); + + }); + + return { + cancel: true, + }; +}; + + +async function handle(url, tabId) { + const creatingUrl = creatingTabs[tabId]; + if (IGNORED_URLS_REGEX.test(url) || creatingUrl === url) { + return; + } else if (creatingUrl) { + delete creatingTabs[tabId]; + } + let preferences = await PreferenceStorage.getAll(true); + let currentContainer = preferences.openInCurrentContainer; + if (currentContainer !== null) { + console.debug('Always open in current container--> ', currentContainer.replace(/ /g,'')); + if (currentContainer !== '') { + const OPEN_IN_CURRENT_CONTAINER = '(' + currentContainer + ')/'; + console.debug('Non-blank always open in container --> ', OPEN_IN_CURRENT_CONTAINER); + let OPEN_IN_CURRENT_CONTAINER_REGEX = new RegExp(OPEN_IN_CURRENT_CONTAINER); + if (OPEN_IN_CURRENT_CONTAINER_REGEX.test(url)) { + console.debug('URL was left in current container due to Regex--> ', url); + return; + } + } + } + let [hostMap, identities, currentTab] = await Promise.all([ + Storage.get(url, preferences.matchDomainOnly), + ContextualIdentity.getAll(), + Tabs.get(tabId), + ]); + + if (currentTab.incognito || !hostMap) { + return {}; + } + + const hostIdentity = identities.find((identity) => identity.cookieStoreId === hostMap.cookieStoreId); + let targetCookieStoreId; + + if (!hostIdentity) { + if (preferences.defaultContainer) { + const defaultContainer = await buildDefaultContainer( + filterByKey(preferences, prefKey => prefKey.startsWith('defaultContainer')), + url + ); + targetCookieStoreId = defaultContainer.cookieStoreId; + // console.debug('Going to open', url, 'in default container', targetCookieStoreId, defaultContainer.name); + } else { + return {}; + } + } else { + targetCookieStoreId = hostIdentity.cookieStoreId; + } + + const targetIsNoContainer = targetCookieStoreId === NO_CONTAINER.cookieStoreId; + const tabHasContainer = currentTab.cookieStoreId !== NO_CONTAINER.cookieStoreId; + const tabInDifferentContainer = currentTab.cookieStoreId !== targetCookieStoreId; + const openInNoContainer = targetIsNoContainer && tabHasContainer; + if ((tabInDifferentContainer && !openInNoContainer) || openInNoContainer) { + return createTab( + url, + currentTab.index + 1, currentTab.id, + currentTab.openerTabId, + targetCookieStoreId); + } + + return {}; + +} + +export const webRequestListener = (requestDetails) => { + + if (requestDetails.frameId !== 0 || requestDetails.tabId === -1) { + return {}; + } + return handle(requestDetails.url, requestDetails.tabId); +}; + +export const tabUpdatedListener = (tabId, changeInfo) => { + if (!changeInfo.url) { + return; + } + return handle(changeInfo.url, tabId); +}; From 95833e719bf816e7883f483f2b2c91255f0341a5 Mon Sep 17 00:00:00 2001 From: dmorlitz Date: Thu, 11 Nov 2021 12:16:42 -0500 Subject: [PATCH 4/6] Delete containers.js File added in error --- containers.js | 141 -------------------------------------------------- 1 file changed, 141 deletions(-) delete mode 100644 containers.js diff --git a/containers.js b/containers.js deleted file mode 100644 index 5839dbf..0000000 --- a/containers.js +++ /dev/null @@ -1,141 +0,0 @@ -import Storage from './Storage/HostStorage'; -import ContextualIdentity, {NO_CONTAINER} from './ContextualIdentity'; -import Tabs from './Tabs'; -import PreferenceStorage from './Storage/PreferenceStorage'; -import {filterByKey} from './utils'; -import {buildDefaultContainer} from './defaultContainer'; - -const IGNORED_URLS_REGEX = /^(about|moz-extension|file|javascript|data|chrome):/; - -/** - * Keep track of the tabs we're creating - * tabId: url - */ -const creatingTabs = {}; - -const createTab = (url, newTabIndex, currentTabId, openerTabId, cookieStoreId) => { - Tabs.get(currentTabId).then((currentTab) => { - const createOptions = { - url, - index: newTabIndex, - cookieStoreId, - active: currentTab.active, - pinned: currentTab.pinned, - discarded: currentTab.discarded, - openInReaderMode: currentTab.isInReaderMode, - }; - // Passing the openerTabId without a cookieStoreId - // creates a tab in the same container as the opener - if (cookieStoreId && openerTabId) { - createOptions.openerTabId = openerTabId; - } - Tabs.create(createOptions).then((createdTab) => { - creatingTabs[createdTab.id] = url; - if (!cookieStoreId && openerTabId) { - Tabs.update(createdTab.id, { - openerTabId: openerTabId, - }); - } - }); - PreferenceStorage.get('keepOldTabs').then(({value}) => { - // if keepOldTabs is false, remove the 'old' tab - // -or- - // if the current tab is about:blank or about:newtab - // or some custom moz-extension pages - // we should still close the current tab even though - // keepOldTabs is true, because these are just - // interstitial tabs that are no longer used - if (!value || /^(about:)|(moz-extension:)/.test(currentTab.url)) { - Tabs.remove(currentTabId); - } - }).catch(() => { - Tabs.remove(currentTabId); - }); - - }); - - return { - cancel: true, - }; -}; - - -async function handle(url, tabId) { - const creatingUrl = creatingTabs[tabId]; - if (IGNORED_URLS_REGEX.test(url) || creatingUrl === url) { - return; - } else if (creatingUrl) { - delete creatingTabs[tabId]; - } - let preferences = await PreferenceStorage.getAll(true); - let currentContainer = preferences.openInCurrentContainer; - if (currentContainer !== null) { - console.debug('Always open in current container--> ', currentContainer.replace(/ /g,'')); - if (currentContainer !== '') { - const OPEN_IN_CURRENT_CONTAINER = '(' + currentContainer + ')/'; - console.debug('Non-blank always open in container --> ', OPEN_IN_CURRENT_CONTAINER); - let OPEN_IN_CURRENT_CONTAINER_REGEX = new RegExp(OPEN_IN_CURRENT_CONTAINER); - if (OPEN_IN_CURRENT_CONTAINER_REGEX.test(url)) { - console.debug('URL was left in current container due to Regex--> ', url); - return; - } - } - } - let [hostMap, identities, currentTab] = await Promise.all([ - Storage.get(url, preferences.matchDomainOnly), - ContextualIdentity.getAll(), - Tabs.get(tabId), - ]); - - if (currentTab.incognito || !hostMap) { - return {}; - } - - const hostIdentity = identities.find((identity) => identity.cookieStoreId === hostMap.cookieStoreId); - let targetCookieStoreId; - - if (!hostIdentity) { - if (preferences.defaultContainer) { - const defaultContainer = await buildDefaultContainer( - filterByKey(preferences, prefKey => prefKey.startsWith('defaultContainer')), - url - ); - targetCookieStoreId = defaultContainer.cookieStoreId; - // console.debug('Going to open', url, 'in default container', targetCookieStoreId, defaultContainer.name); - } else { - return {}; - } - } else { - targetCookieStoreId = hostIdentity.cookieStoreId; - } - - const targetIsNoContainer = targetCookieStoreId === NO_CONTAINER.cookieStoreId; - const tabHasContainer = currentTab.cookieStoreId !== NO_CONTAINER.cookieStoreId; - const tabInDifferentContainer = currentTab.cookieStoreId !== targetCookieStoreId; - const openInNoContainer = targetIsNoContainer && tabHasContainer; - if ((tabInDifferentContainer && !openInNoContainer) || openInNoContainer) { - return createTab( - url, - currentTab.index + 1, currentTab.id, - currentTab.openerTabId, - targetCookieStoreId); - } - - return {}; - -} - -export const webRequestListener = (requestDetails) => { - - if (requestDetails.frameId !== 0 || requestDetails.tabId === -1) { - return {}; - } - return handle(requestDetails.url, requestDetails.tabId); -}; - -export const tabUpdatedListener = (tabId, changeInfo) => { - if (!changeInfo.url) { - return; - } - return handle(changeInfo.url, tabId); -}; From c3d101c30003c77b5af4915e262f40db338406b8 Mon Sep 17 00:00:00 2001 From: David Morlitz Date: Thu, 11 Nov 2021 12:33:01 -0500 Subject: [PATCH 5/6] Gracefully handle undefined configuration variable --- containers.js | 141 -------------------------------------------------- 1 file changed, 141 deletions(-) delete mode 100644 containers.js diff --git a/containers.js b/containers.js deleted file mode 100644 index 5839dbf..0000000 --- a/containers.js +++ /dev/null @@ -1,141 +0,0 @@ -import Storage from './Storage/HostStorage'; -import ContextualIdentity, {NO_CONTAINER} from './ContextualIdentity'; -import Tabs from './Tabs'; -import PreferenceStorage from './Storage/PreferenceStorage'; -import {filterByKey} from './utils'; -import {buildDefaultContainer} from './defaultContainer'; - -const IGNORED_URLS_REGEX = /^(about|moz-extension|file|javascript|data|chrome):/; - -/** - * Keep track of the tabs we're creating - * tabId: url - */ -const creatingTabs = {}; - -const createTab = (url, newTabIndex, currentTabId, openerTabId, cookieStoreId) => { - Tabs.get(currentTabId).then((currentTab) => { - const createOptions = { - url, - index: newTabIndex, - cookieStoreId, - active: currentTab.active, - pinned: currentTab.pinned, - discarded: currentTab.discarded, - openInReaderMode: currentTab.isInReaderMode, - }; - // Passing the openerTabId without a cookieStoreId - // creates a tab in the same container as the opener - if (cookieStoreId && openerTabId) { - createOptions.openerTabId = openerTabId; - } - Tabs.create(createOptions).then((createdTab) => { - creatingTabs[createdTab.id] = url; - if (!cookieStoreId && openerTabId) { - Tabs.update(createdTab.id, { - openerTabId: openerTabId, - }); - } - }); - PreferenceStorage.get('keepOldTabs').then(({value}) => { - // if keepOldTabs is false, remove the 'old' tab - // -or- - // if the current tab is about:blank or about:newtab - // or some custom moz-extension pages - // we should still close the current tab even though - // keepOldTabs is true, because these are just - // interstitial tabs that are no longer used - if (!value || /^(about:)|(moz-extension:)/.test(currentTab.url)) { - Tabs.remove(currentTabId); - } - }).catch(() => { - Tabs.remove(currentTabId); - }); - - }); - - return { - cancel: true, - }; -}; - - -async function handle(url, tabId) { - const creatingUrl = creatingTabs[tabId]; - if (IGNORED_URLS_REGEX.test(url) || creatingUrl === url) { - return; - } else if (creatingUrl) { - delete creatingTabs[tabId]; - } - let preferences = await PreferenceStorage.getAll(true); - let currentContainer = preferences.openInCurrentContainer; - if (currentContainer !== null) { - console.debug('Always open in current container--> ', currentContainer.replace(/ /g,'')); - if (currentContainer !== '') { - const OPEN_IN_CURRENT_CONTAINER = '(' + currentContainer + ')/'; - console.debug('Non-blank always open in container --> ', OPEN_IN_CURRENT_CONTAINER); - let OPEN_IN_CURRENT_CONTAINER_REGEX = new RegExp(OPEN_IN_CURRENT_CONTAINER); - if (OPEN_IN_CURRENT_CONTAINER_REGEX.test(url)) { - console.debug('URL was left in current container due to Regex--> ', url); - return; - } - } - } - let [hostMap, identities, currentTab] = await Promise.all([ - Storage.get(url, preferences.matchDomainOnly), - ContextualIdentity.getAll(), - Tabs.get(tabId), - ]); - - if (currentTab.incognito || !hostMap) { - return {}; - } - - const hostIdentity = identities.find((identity) => identity.cookieStoreId === hostMap.cookieStoreId); - let targetCookieStoreId; - - if (!hostIdentity) { - if (preferences.defaultContainer) { - const defaultContainer = await buildDefaultContainer( - filterByKey(preferences, prefKey => prefKey.startsWith('defaultContainer')), - url - ); - targetCookieStoreId = defaultContainer.cookieStoreId; - // console.debug('Going to open', url, 'in default container', targetCookieStoreId, defaultContainer.name); - } else { - return {}; - } - } else { - targetCookieStoreId = hostIdentity.cookieStoreId; - } - - const targetIsNoContainer = targetCookieStoreId === NO_CONTAINER.cookieStoreId; - const tabHasContainer = currentTab.cookieStoreId !== NO_CONTAINER.cookieStoreId; - const tabInDifferentContainer = currentTab.cookieStoreId !== targetCookieStoreId; - const openInNoContainer = targetIsNoContainer && tabHasContainer; - if ((tabInDifferentContainer && !openInNoContainer) || openInNoContainer) { - return createTab( - url, - currentTab.index + 1, currentTab.id, - currentTab.openerTabId, - targetCookieStoreId); - } - - return {}; - -} - -export const webRequestListener = (requestDetails) => { - - if (requestDetails.frameId !== 0 || requestDetails.tabId === -1) { - return {}; - } - return handle(requestDetails.url, requestDetails.tabId); -}; - -export const tabUpdatedListener = (tabId, changeInfo) => { - if (!changeInfo.url) { - return; - } - return handle(changeInfo.url, tabId); -}; From 40b0151c95d94cd43df42fc4b7adfbe5ef1b3633 Mon Sep 17 00:00:00 2001 From: David Morlitz Date: Thu, 11 Nov 2021 12:36:12 -0500 Subject: [PATCH 6/6] Gracefully handle undefined configuration variable --- src/containers.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/containers.js b/src/containers.js index ad3347a..f1e60ac 100644 --- a/src/containers.js +++ b/src/containers.js @@ -68,11 +68,18 @@ async function handle(url, tabId) { delete creatingTabs[tabId]; } let preferences = await PreferenceStorage.getAll(true); - const OPEN_IN_CURRENT_CONTAINER = '(' + preferences.openInCurrentContainer + ')/'; - let OPEN_IN_CURRENT_CONTAINER_REGEX = new RegExp(OPEN_IN_CURRENT_CONTAINER); - if (OPEN_IN_CURRENT_CONTAINER_REGEX.test(url)) { - //console.debug('URL was left in current container due to Regex--> ', url); - return; + let OPEN_IN_CURRENT_CONTAINER_RAW = preferences.openInCurrentContainer; + //console.debug('Raw configuration variable --> ', OPEN_IN_CURRENT_CONTAINER_RAW); + if (typeof OPEN_IN_CURRENT_CONTAINER_RAW !== 'undefined') { + const OPEN_IN_CURRENT_CONTAINER = '(' + preferences.openInCurrentContainer.replace(/ /g, '') + ')/'; + //console.debug('Formatted configuration variable --> ', OPEN_IN_CURRENT_CONTAINER); + if (OPEN_IN_CURRENT_CONTAINER !== '') { + let OPEN_IN_CURRENT_CONTAINER_REGEX = new RegExp(OPEN_IN_CURRENT_CONTAINER); + if (OPEN_IN_CURRENT_CONTAINER_REGEX.test(url)) { + //console.debug('URL was left in current container due to Regex--> ', url); + return; + } + } } let [hostMap, identities, currentTab] = await Promise.all([ Storage.get(url, preferences.matchDomainOnly),