diff --git a/webextension/background.js b/webextension/background.js index 26d4a10..c6c9d37 100644 --- a/webextension/background.js +++ b/webextension/background.js @@ -56,19 +56,25 @@ const assignManager = { return this.area.remove([siteStoreKey]); }, - deleteContainer(userContextId) { - const removeKeys = []; - this.area.get().then((siteConfigs) => { - Object.keys(siteConfigs).forEach((key) => { - // For some reason this is stored as string... lets check them both as that - if (String(siteConfigs[key].userContextId) === String(userContextId)) { - removeKeys.push(key); - } - }); - this.area.remove(removeKeys); - }).catch((e) => { - throw e; + async deleteContainer(userContextId) { + const sitesByContainer = await this.getByContainer(userContextId); + this.area.remove(Object.keys(sitesByContainer)); + }, + + async getByContainer(userContextId) { + const sites = {}; + const siteConfigs = await this.area.get(); + Object.keys(siteConfigs).forEach((key) => { + // For some reason this is stored as string... lets check them both as that + if (String(siteConfigs[key].userContextId) === String(userContextId)) { + const site = siteConfigs[key]; + // In hindsight we should have stored this + // TODO file a follow up to clean the storage onLoad + site.hostname = key.replace(/^siteContainerMap@@_/, ""); + sites[key] = site; + } }); + return sites; } }, @@ -152,12 +158,8 @@ const assignManager = { // let actionName; let remove; if (info.menuItemId === this.MENU_ASSIGN_ID) { - //actionName = "added"; - // storageAction = this._setAssignment(info.pageUrl, userContextId, setOrRemove); remove = false; } else { - // actionName = "removed"; - //storageAction = this.storageArea.remove(info.pageUrl); remove = true; } await this._setOrRemoveAssignment(info.pageUrl, userContextId, remove); @@ -228,6 +230,10 @@ const assignManager = { return false; }, + _getByContainer(userContextId) { + return this.storageArea.getByContainer(userContextId); + }, + removeContextMenu() { // There is a focus issue in this menu where if you change window with a context menu click // you get the wrong menu display because of async @@ -434,11 +440,11 @@ const messageHandler = { return assignManager._getAssignment(tab); }); break; + case "getAssignmentObjectByContainer": + response = assignManager._getByContainer(m.message.userContextId); + break; case "setOrRemoveAssignment": - response = browser.tabs.get(m.tabId).then((tab) => { - const userContextId = assignManager.getUserContextIdFromCookieStore(tab); - return assignManager._setOrRemoveAssignment(tab.url, userContextId, m.value); - }); + response = assignManager._setOrRemoveAssignment(m.url, m.userContextId, m.value); break; case "exemptContainerAssignment": response = assignManager._exemptTab(m); diff --git a/webextension/css/popup.css b/webextension/css/popup.css index ad2966e..6f5ce80 100644 --- a/webextension/css/popup.css +++ b/webextension/css/popup.css @@ -19,6 +19,13 @@ html { box-sizing: inherit; } +form { + margin-block-end: 0; + margin-block-start: 0; + margin-inline-end: 0; + margin-inline-start: 0; +} + table { border: 0; border-spacing: 0; @@ -581,6 +588,10 @@ span ~ .panel-header-text { padding-block-start: 4px; } +.container-info-list tbody { + display: contents; +} + .clickable { cursor: pointer; } @@ -631,6 +642,32 @@ span ~ .panel-header-text { padding-inline-start: 16px; } +#edit-sites-assigned { + flex: 1; +} + +#edit-sites-assigned h3 { + font-size: 14px; + font-weight: normal; + padding-block-end: 5px; + padding-inline-end: 16px; + padding-inline-start: 16px; +} + +#edit-sites-assigned table td { + display: flex; + padding-inline-end: 16px; + padding-inline-start: 16px; +} + +#edit-sites-assigned .delete-assignment { + display: none; +} + +#edit-sites-assigned tr:hover > td > .delete-assignment { + display: block; +} + .column-panel-content form span { align-items: center; block-size: 44px; @@ -679,6 +716,10 @@ span ~ .panel-header-text { padding-inline-start: 0; } +.edit-container-panel fieldset:last-of-type { + margin-block-end: 0; +} + .edit-container-panel input[type="text"] { block-size: 36px; border-radius: 3px; diff --git a/webextension/js/popup.js b/webextension/js/popup.js index 12ca299..1b47162 100644 --- a/webextension/js/popup.js +++ b/webextension/js/popup.js @@ -119,7 +119,9 @@ const Logic = { }, addEnterHandler(element, handler) { - element.addEventListener("click", handler); + element.addEventListener("click", (e) => { + handler(e); + }); element.addEventListener("keydown", (e) => { if (e.keyCode === 13) { handler(e); @@ -208,6 +210,11 @@ const Logic = { return this._currentIdentity; }, + currentUserContextId() { + const identity = Logic.currentIdentity(); + return Logic.userContextId(identity.cookieStoreId); + }, + sendTelemetryPayload(message = {}) { if (!message.event) { throw new Error("Missing event name for telemetry"); @@ -234,10 +241,18 @@ const Logic = { }); }, - setOrRemoveAssignment(tab, value) { + getAssignmentObjectByContainer(userContextId) { + return browser.runtime.sendMessage({ + method: "getAssignmentObjectByContainer", + message: {userContextId} + }); + }, + + setOrRemoveAssignment(url, userContextId, value) { return browser.runtime.sendMessage({ method: "setOrRemoveAssignment", - tabId: tab.id, + url, + userContextId, value }); }, @@ -437,7 +452,8 @@ Logic.registerPanel(P_CONTAINERS_LIST, { const currentTabElement = document.getElementById("current-tab"); const assignmentCheckboxElement = document.getElementById("container-page-assigned"); assignmentCheckboxElement.addEventListener("change", () => { - Logic.setOrRemoveAssignment(currentTab, !assignmentCheckboxElement.checked); + const userContextId = Logic.userContextId(currentTab.cookieStoreId); + Logic.setOrRemoveAssignment(currentTab.url, userContextId, !assignmentCheckboxElement.checked); }); currentTabElement.hidden = !currentTab; this.setupAssignmentCheckbox(false); @@ -561,7 +577,7 @@ Logic.registerPanel(P_CONTAINER_INFO, { const identity = Logic.currentIdentity(); browser.runtime.sendMessage({ method: identity.hasHiddenTabs ? "showTabs" : "hideTabs", - userContextId: Logic.userContextId(identity.cookieStoreId) + userContextId: Logic.currentUserContextId() }).then(() => { window.close(); }).catch(() => { @@ -633,7 +649,7 @@ Logic.registerPanel(P_CONTAINER_INFO, { // Let's retrieve the list of tabs. return browser.runtime.sendMessage({ method: "getTabs", - userContextId: Logic.userContextId(identity.cookieStoreId), + userContextId: Logic.currentUserContextId(), }).then(this.buildInfoTable); }, @@ -743,27 +759,19 @@ Logic.registerPanel(P_CONTAINER_EDIT, { this.initializeRadioButtons(); Logic.addEnterHandler(document.querySelector("#edit-container-panel-back-arrow"), () => { - Logic.showPreviousPanel(); + this._submitForm(); }); - - Logic.addEnterHandler(document.querySelector("#edit-container-cancel-link"), () => { - Logic.showPreviousPanel(); - }); - this._editForm = document.getElementById("edit-container-panel-form"); - const editLink = document.querySelector("#edit-container-ok-link"); - Logic.addEnterHandler(editLink, this._submitForm.bind(this)); - editLink.addEventListener("submit", this._submitForm.bind(this)); this._editForm.addEventListener("submit", this._submitForm.bind(this)); + }, _submitForm() { - const identity = Logic.currentIdentity(); const formValues = new FormData(this._editForm); return browser.runtime.sendMessage({ method: "createOrUpdateContainer", message: { - userContextId: Logic.userContextId(identity.cookieStoreId) || false, + userContextId: Logic.currentUserContextId() || false, params: { name: document.getElementById("edit-container-panel-name-input").value || Logic.generateIdentityName(), icon: formValues.get("container-icon") || DEFAULT_ICON, @@ -779,6 +787,44 @@ Logic.registerPanel(P_CONTAINER_EDIT, { }); }, + showAssignedContainers(assignments) { + const assignmentPanel = document.getElementById("edit-sites-assigned"); + const assignmentKeys = Object.keys(assignments); + assignmentPanel.hidden = !(assignmentKeys.length > 0); + if (assignments) { + const tableElement = assignmentPanel.querySelector("table > tbody"); + /* Remove previous assignment list, + after removing one we rerender the list */ + while (tableElement.firstChild) { + tableElement.firstChild.remove(); + } + assignmentKeys.forEach((siteKey) => { + const site = assignments[siteKey]; + const trElement = document.createElement("tr"); + /* As we don't have the full or correct path the best we can assume is the path is HTTPS and then replace with a broken icon later if it doesn't load. + This is pending a better solution for favicons from web extensions */ + const assumedUrl = `https://${site.hostname}`; + trElement.innerHTML = escaped` +