From d4fcd061f92374fd5a5baaa20d06e287fc2d8781 Mon Sep 17 00:00:00 2001 From: Tobias Laundal Date: Thu, 16 Nov 2017 19:59:58 +0100 Subject: [PATCH 1/4] Add hide/show buttons to main pane in popup Makes it more effective to hide and show containers. For the future, this should be fixed to not close the pane when hiding or showing a container, so multiple containers can be toggled with a single visit to the popup, but this has proven hard to do. --- webextension/js/popup.js | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/webextension/js/popup.js b/webextension/js/popup.js index 37666c1..2375d4c 100644 --- a/webextension/js/popup.js +++ b/webextension/js/popup.js @@ -595,6 +595,7 @@ Logic.registerPanel(P_CONTAINERS_LIST, { const hasTabs = (identity.hasHiddenTabs || identity.hasOpenTabs); const tr = document.createElement("tr"); const context = document.createElement("td"); + const hide = document.createElement("td"); const manage = document.createElement("td"); tr.classList.add("container-panel-row"); @@ -615,11 +616,24 @@ Logic.registerPanel(P_CONTAINERS_LIST, { context.querySelector(".container-name").textContent = identity.name; manage.innerHTML = ""; + hide.classList.add("hide-or-show-tabs", "pop-button"); + const img = document.createElement("img"); + img.classList.add("hide-or-show-tabs", "pop-button-image-small"); + if (identity.hasHiddenTabs) { + hide.title = escaped`Show ${identity.name} container`; + img.setAttribute("src", CONTAINER_HIDE_SRC); + } else { + hide.title = escaped`Hide ${identity.name} container`; + img.setAttribute("src", CONTAINER_UNHIDE_SRC); + } + hide.appendChild(img); + fragment.appendChild(tr); tr.appendChild(context); if (hasTabs) { + tr.appendChild(hide); tr.appendChild(manage); } @@ -627,16 +641,19 @@ Logic.registerPanel(P_CONTAINERS_LIST, { if (e.target.matches(".open-newtab") || e.target.parentNode.matches(".open-newtab") || e.type === "keydown") { - try { - browser.tabs.create({ - cookieStoreId: identity.cookieStoreId - }); - window.close(); - } catch (e) { - window.close(); - } - } else if (hasTabs) { + browser.tabs.create({ + cookieStoreId: identity.cookieStoreId + }).then(window.close).catch(window.close); + } else if (e.target.matches(".show-tabs") + || e.target.parentNode.matches(".show-tabs")) { Logic.showPanel(P_CONTAINER_INFO, identity); + } else if (e.target.matches(".hide-or-show-tabs") + || e.target.parentNode.matches(".hide-or-show-tabs")) { + browser.runtime.sendMessage({ + method: identity.hasHiddenTabs ? "showTabs" : "hideTabs", + windowId: browser.windows.WINDOW_ID_CURRENT, + cookieStoreId: identity.cookieStoreId + }).then(window.close).catch(window.close); } }); }); From ce0417b9d08006bfc29a1f9769a30b3953172380 Mon Sep 17 00:00:00 2001 From: Tobias Laundal Date: Thu, 16 Nov 2017 21:15:57 +0100 Subject: [PATCH 2/4] Add button to unhide all groups in popup. Adds a button with the text "Unhide all", next to the "Sort tabs" button in the popup menu. This button will show all tabs from all containers. --- webextension/css/popup.css | 7 ++++--- webextension/js/background/backgroundLogic.js | 20 ++++++++++++++++++- webextension/js/background/messageHandler.js | 3 +++ webextension/js/popup.js | 14 +++++++++++++ webextension/popup.html | 1 + 5 files changed, 41 insertions(+), 4 deletions(-) diff --git a/webextension/css/popup.css b/webextension/css/popup.css index af78306..d9899da 100644 --- a/webextension/css/popup.css +++ b/webextension/css/popup.css @@ -450,7 +450,7 @@ manage things like container crud */ margin-inline-start: var(--inline-item-space-size); } -#container-panel #sort-containers-link { +#container-panel .action-link { align-items: center; block-size: var(--block-url-label-size); border: 1px solid #d8d8d8; @@ -460,11 +460,12 @@ manage things like container crud */ font-size: var(--small-text-size); inline-size: var(--inline-button-size); justify-content: center; + margin-left: var(--block-line-space-size); text-decoration: none; } -#container-panel #sort-containers-link:hover, -#container-panel #sort-containers-link:focus { +#container-panel .action-link:hover, +#container-panel .action-link:focus { background: #f2f2f2; } diff --git a/webextension/js/background/backgroundLogic.js b/webextension/js/background/backgroundLogic.js index 36bcb47..cb62e06 100644 --- a/webextension/js/background/backgroundLogic.js +++ b/webextension/js/background/backgroundLogic.js @@ -299,8 +299,26 @@ const backgroundLogic = { return await identityState.storageArea.set(options.cookieStoreId, containerState); }, + async unhideAllTabs(windowId) { + const [identities, state] = await Promise.all([ + browser.contextualIdentities.query({}), + backgroundLogic.queryIdentitiesState(windowId) + ]); + + const promises = []; + identities.filter(identity => { + const stateObject = state[identity.cookieStoreId]; + return stateObject && stateObject.hasHiddenTabs; + }).map(identity => identity.cookieStoreId) + .forEach(cookieStoreId => { + // We need to call unhideContainer in messageHandler to prevent it from + // unhiding multiple times + promises.push(messageHandler.unhideContainer(cookieStoreId)); + }); + return Promise.all(promises); + }, + cookieStoreId(userContextId) { return `firefox-container-${userContextId}`; } }; - diff --git a/webextension/js/background/messageHandler.js b/webextension/js/background/messageHandler.js index 1971953..7648c9a 100644 --- a/webextension/js/background/messageHandler.js +++ b/webextension/js/background/messageHandler.js @@ -68,6 +68,9 @@ const messageHandler = { case "exemptContainerAssignment": response = assignManager._exemptTab(m); break; + case "unhideAllTabs": + response = backgroundLogic.unhideAllTabs(m.message.windowId); + break; } return response; }); diff --git a/webextension/js/popup.js b/webextension/js/popup.js index 2375d4c..3b8c399 100644 --- a/webextension/js/popup.js +++ b/webextension/js/popup.js @@ -500,6 +500,20 @@ Logic.registerPanel(P_CONTAINERS_LIST, { } }); + Logic.addEnterHandler(document.querySelector("#unhide-all-containers-link"), async function () { + try { + await browser.runtime.sendMessage({ + method: "unhideAllTabs", + message: { + windowId: browser.windows.WINDOW_ID_CURRENT + } + }); + window.close(); + } catch (e) { + window.close(); + } + }); + document.addEventListener("keydown", (e) => { const selectables = [...document.querySelectorAll("[tabindex='0'], [tabindex='-1']")]; const element = document.activeElement; diff --git a/webextension/popup.html b/webextension/popup.html index 8cde498..68c2d86 100644 --- a/webextension/popup.html +++ b/webextension/popup.html @@ -108,6 +108,7 @@
From 3d7dfba2f9c8ea0a64ad7e4eec30ba8a14f0e061 Mon Sep 17 00:00:00 2001 From: Tobias Laundal Date: Thu, 16 Nov 2017 22:00:36 +0100 Subject: [PATCH 3/4] Add button on container info pane to show only that container. Adds a button, located on the info pane for each container, to show only that container. This button will hide other containers, if they have visible tabs, and show the container the button was pressed for, if it has hidden tabs. This is a much-needed function to effectively use containers as workspaces, and will please most people coming to multi-account-containers from Panorama tabs. --- webextension/js/background/backgroundLogic.js | 29 +++++++++++++++++++ webextension/js/background/messageHandler.js | 6 ++++ webextension/js/popup.js | 16 ++++++++++ webextension/popup.html | 2 ++ 4 files changed, 53 insertions(+) diff --git a/webextension/js/background/backgroundLogic.js b/webextension/js/background/backgroundLogic.js index cb62e06..da59c33 100644 --- a/webextension/js/background/backgroundLogic.js +++ b/webextension/js/background/backgroundLogic.js @@ -318,6 +318,35 @@ const backgroundLogic = { return Promise.all(promises); }, + async showOnly(options) { + if (!("windowId" in options) || !("cookieStoreId" in options)) { + return Promise.reject("showOnly needs both a windowId and a cookieStoreId"); + } + + const [identities, state] = await Promise.all([ + browser.contextualIdentities.query({}), + backgroundLogic.queryIdentitiesState(options.windowId) + ]); + + const promises = []; + identities + .filter(identity => { + const stateObject = state[identity.cookieStoreId]; + const filt = identity.cookieStoreId !== options.cookieStoreId && + stateObject && stateObject.hasOpenTabs; + return filt; + }).map(identity => identity.cookieStoreId) + .forEach(cookieStoreId => { + promises.push(backgroundLogic.hideTabs({cookieStoreId, windowId: options.windowId})); + }); + + // We need to call unhideContainer in messageHandler to prevent it from + // unhiding multiple times + promises.push(messageHandler.unhideContainer(options.cookieStoreId)); + + return Promise.all(promises); + }, + cookieStoreId(userContextId) { return `firefox-container-${userContextId}`; } diff --git a/webextension/js/background/messageHandler.js b/webextension/js/background/messageHandler.js index 7648c9a..96e3628 100644 --- a/webextension/js/background/messageHandler.js +++ b/webextension/js/background/messageHandler.js @@ -71,6 +71,12 @@ const messageHandler = { case "unhideAllTabs": response = backgroundLogic.unhideAllTabs(m.message.windowId); break; + case "showOnly": + response = backgroundLogic.showOnly({ + windowId: m.windowId, + cookieStoreId: m.cookieStoreId + }); + break; } return response; }); diff --git a/webextension/js/popup.js b/webextension/js/popup.js index 3b8c399..59f032a 100644 --- a/webextension/js/popup.js +++ b/webextension/js/popup.js @@ -719,6 +719,19 @@ Logic.registerPanel(P_CONTAINER_INFO, { } }); + Logic.addEnterHandler(document.querySelector("#container-info-hideothers"), async function () { + try { + browser.runtime.sendMessage({ + method: "showOnly", + windowId: browser.windows.WINDOW_ID_CURRENT, + cookieStoreId: Logic.currentCookieStoreId() + }); + window.close(); + } catch (e) { + window.close(); + } + }); + // Check if the user has incompatible add-ons installed try { const incompatible = await browser.runtime.sendMessage({ @@ -775,6 +788,9 @@ Logic.registerPanel(P_CONTAINER_INFO, { const hideShowLabel = document.getElementById("container-info-hideorshow-label"); hideShowLabel.textContent = identity.hasHiddenTabs ? "Show this container" : "Hide this container"; + const hideOthersLabel = document.getElementById("container-info-hideothers"); + hideOthersLabel.textContent = identity.hasHiddenTabs ? "Show only this container" : "Hide other containers"; + // Let's remove all the previous tabs. const table = document.getElementById("container-info-table"); while (table.firstChild) { diff --git a/webextension/popup.html b/webextension/popup.html index 68c2d86..1634f4b 100644 --- a/webextension/popup.html +++ b/webextension/popup.html @@ -1,3 +1,4 @@ + @@ -141,6 +142,7 @@ Hide Container icon Hide this container
+
Hide other containers
Move tabs to a new window
From a27bbb131976a0ba0fed3f994cd4941324edd76b Mon Sep 17 00:00:00 2001 From: Tobias Laundal Date: Thu, 16 Nov 2017 22:12:07 +0100 Subject: [PATCH 4/4] Refactor out common code between backgroundLogic.unhideAllTabs and showOnly Refactors code to get all containers in window into the function getContainers. Reduces code duplication between unhideAllTabs and showOnly. --- webextension/js/background/backgroundLogic.js | 56 ++++++++++--------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/webextension/js/background/backgroundLogic.js b/webextension/js/background/backgroundLogic.js index da59c33..c16dfc1 100644 --- a/webextension/js/background/backgroundLogic.js +++ b/webextension/js/background/backgroundLogic.js @@ -14,6 +14,25 @@ const backgroundLogic = { return extensionInfo; }, + async getContainers(windowId) { + const [identities, state] = await Promise.all([ + browser.contextualIdentities.query({}), + backgroundLogic.queryIdentitiesState(windowId) + ]); + + return identities + .filter(identity => { + return identity.cookieStoreId in state; + }) + .map(identity => { + const stateObject = state[identity.cookieStoreId]; + identity.hasOpenTabs = stateObject.hasOpenTabs; + identity.hasHiddenTabs = stateObject.hasHiddenTabs; + + return identity; + }); + }, + getUserContextIdFromCookieStoreId(cookieStoreId) { if (!cookieStoreId) { return false; @@ -300,21 +319,15 @@ const backgroundLogic = { }, async unhideAllTabs(windowId) { - const [identities, state] = await Promise.all([ - browser.contextualIdentities.query({}), - backgroundLogic.queryIdentitiesState(windowId) - ]); - const promises = []; - identities.filter(identity => { - const stateObject = state[identity.cookieStoreId]; - return stateObject && stateObject.hasHiddenTabs; - }).map(identity => identity.cookieStoreId) - .forEach(cookieStoreId => { - // We need to call unhideContainer in messageHandler to prevent it from - // unhiding multiple times - promises.push(messageHandler.unhideContainer(cookieStoreId)); - }); + (await backgroundLogic.getContainers(windowId)) + .filter(identity => identity.hasHiddenTabs) + .map(identity => identity.cookieStoreId) + .forEach(cookieStoreId => { + // We need to call unhideContainer in messageHandler to prevent it from + // unhiding multiple times + promises.push(messageHandler.unhideContainer(cookieStoreId)); + }); return Promise.all(promises); }, @@ -323,19 +336,10 @@ const backgroundLogic = { return Promise.reject("showOnly needs both a windowId and a cookieStoreId"); } - const [identities, state] = await Promise.all([ - browser.contextualIdentities.query({}), - backgroundLogic.queryIdentitiesState(options.windowId) - ]); - const promises = []; - identities - .filter(identity => { - const stateObject = state[identity.cookieStoreId]; - const filt = identity.cookieStoreId !== options.cookieStoreId && - stateObject && stateObject.hasOpenTabs; - return filt; - }).map(identity => identity.cookieStoreId) + (await backgroundLogic.getContainers(options.windowId)) + .filter(identity => identity.cookieStoreId !== options.cookieStoreId && identity.hasOpenTabs) + .map(identity => identity.cookieStoreId) .forEach(cookieStoreId => { promises.push(backgroundLogic.hideTabs({cookieStoreId, windowId: options.windowId})); });