diff --git a/webextension/js/popup.js b/webextension/js/popup.js index 6353709..5cb0980 100644 --- a/webextension/js/popup.js +++ b/webextension/js/popup.js @@ -3,11 +3,21 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ /* global browser, window, document, localStorage */ + const CONTAINER_HIDE_SRC = "/img/container-hide.svg"; const CONTAINER_UNHIDE_SRC = "/img/container-unhide.svg"; // Let's set it to false before releasing!!! -const DEBUG = true; +const DEBUG = false; + +// List of panels +const P_ONBOARDING_1 = "onboarding1"; +const P_ONBOARDING_2 = "onboarding2"; +const P_CONTAINERS_LIST = "containersList"; +const P_CONTAINERS_EDIT = "containersEdit"; +const P_CONTAINER_INFO = "containerInfo"; +const P_CONTAINER_EDIT = "containerEdit"; +const P_CONTAINER_DELETE = "containerDelete"; function log(...args) { if (DEBUG) { @@ -15,145 +25,290 @@ function log(...args) { } } -function showPanel(panelSelector) { - for (let panelElement of document.querySelectorAll(".panel")) { - panelElement.classList.add("hide"); - } - document.querySelector(panelSelector).classList.remove("hide"); -} +// This object controls all the panels, identities and many other things. +let Logic = { + _identities: [], + _currentIdentity: null, + _panels: {}, -function showContainerTabsPanel(identity) { - // Populating the panel: name and icon - document.getElementById("container-info-name").innerText = identity.name; + init() { + // Retrieve the list of identities. + browser.runtime.sendMessage({ + method: "queryIdentities" + }) - let icon = document.getElementById("container-info-icon"); - icon.setAttribute("data-identity-icon", identity.image); - icon.setAttribute("data-identity-color", identity.color); + .then(identities => { + this._identities = identities; + }) - // Show or not the has-tabs section. - for (let trHasTabs of document.getElementsByClassName("container-info-has-tabs")) { - trHasTabs.hidden = !identity.hasHiddenTabs && !identity.hasOpenTabs; - trHasTabs.setAttribute("data-user-context-id", identity.userContextId); - } - - let hideOrShowRow = document.querySelector("#container-info-hideorshow"); - hideOrShowRow.setAttribute("data-user-context-id", identity.userContextId); - - const hideShowIcon = document.getElementById("container-info-hideorshow-icon"); - hideShowIcon.src = identity.hasHiddenTabs ? CONTAINER_UNHIDE_SRC : CONTAINER_HIDE_SRC; - - const hideShowLabel = document.getElementById("container-info-hideorshow-label"); - hideShowLabel.innerText = identity.hasHiddenTabs ? "Show these container tabs" : "Hide these container tabs"; - - // Let"s remove all the previous tabs. - for (let trTab of document.getElementsByClassName("container-info-tab")) { - trTab.remove(); - } - - // Let"s retrieve the list of tabs. - browser.runtime.sendMessage({ - method: "getTabs", - userContextId: identity.userContextId, - }).then(tabs => { - log('browser.runtime.sendMessage getTabs, tabs: ', tabs); - // For each one, let's create a new line. - let fragment = document.createDocumentFragment(); - for (let tab of tabs) { - let tr = document.createElement("tr"); - fragment.appendChild(tr); - tr.classList.add("container-info-tab"); - tr.classList.add("clickable"); - tr.innerHTML = ` - - ${tab.title}`; - // On click, we activate this tab. - tr.addEventListener("click", () => { - browser.runtime.sendMessage({ - method: "showTab", - tabId: tab.id, - }).then(() => { - window.close(); - }); - }); - } - - document.getElementById("container-info-table").appendChild(fragment); - }) - - // Finally we are ready to show the panel. - .then(() => { - // FIXME: the animation... - document.getElementById("container-panel").classList.add("hide"); - document.getElementById("container-info-panel").classList.remove("hide"); - }); -} - -if (localStorage.getItem("onboarded2")) { - showPanel("#container-panel"); -} else if (localStorage.getItem("onboarded1")) { - showPanel(".onboarding-panel-2"); -} else { - showPanel(".onboarding-panel-1"); -} - -document.querySelector("#onboarding-next-button").addEventListener("click", () => { - localStorage.setItem("onboarded1", true); - showPanel(".onboarding-panel-2"); -}); - -document.querySelector("#onboarding-done-button").addEventListener("click", () => { - localStorage.setItem("onboarded2", true); - showPanel("#container-panel"); -}); - -browser.runtime.sendMessage({method: "queryIdentities"}).then(identities => { - log('queryIdentities'); - let fragment = document.createDocumentFragment(); - - identities.forEach(identity => { - log('identities.forEach'); - let tr = document.createElement("tr"); - fragment.appendChild(tr); - tr.classList.add("container-panel-row"); - tr.classList.add("clickable"); - tr.setAttribute("data-identity-cookie-store-id", identity.userContextId); - tr.innerHTML = ` - -
-
- - ${identity.name} - >`; - - tr.addEventListener("click", e => { - if (e.target.matches(".open-newtab")) { - browser.runtime.sendMessage({ - method: "showTabs", - userContextId: identity.userContextId - }).then(() => { - return browser.runtime.sendMessage({ - method: "openTab", - userContextId: identity.userContextId, - }); - }).then(() => { - window.close(); - }); - } else if (e.target.matches(".info")) { - showContainerTabsPanel(identity); + // Routing to the correct panel. + .then(() => { + if (localStorage.getItem("onboarded2")) { + this.showPanel(P_CONTAINERS_LIST); + } else if (localStorage.getItem("onboarded1")) { + this.showPanel(P_ONBOARDING_2); + } else { + this.showPanel(P_ONBOARDING_1); } }); - }); + }, - document.querySelector(".identities-list").appendChild(fragment); + showPanel(panel, currentIdentity = null) { + // Invalid panel... ?!? + if (!(panel in this._panels)) { + throw("Something really bad happened. Unknown panel: " + panel + "\n"); + } + + this._currentIdentity = currentIdentity; + + // Initialize the panel before showing it. + this._panels[panel].prepare().then(() => { + for (let panelElement of document.querySelectorAll(".panel")) { + panelElement.classList.add("hide"); + } + document.querySelector(this._panels[panel].panelSelector).classList.remove("hide"); + }); + }, + + registerPanel(panelName, panelObject) { + this._panels[panelName] = panelObject; + panelObject.initialize(); + }, + + identities() { + return this._identities; + }, + + currentIdentity() { + if (!this._currentIdentity) { + throw("CurrentIdentity must be set before calling Logic.currentIdentity."); + } + return this._currentIdentity; + }, +}; + +// P_ONBOARDING_1: First page for Onboarding. +// ---------------------------------------------------------------------------- + +Logic.registerPanel(P_ONBOARDING_1, { + panelSelector: ".onboarding-panel-1", + + // This method is called when the object is registered. + initialize() { + // Let's move to the next panel. + document.querySelector("#onboarding-next-button").addEventListener("click", () => { + localStorage.setItem("onboarded1", true); + Logic.showPanel(P_ONBOARDING_2); + }); + }, + + // This method is called when the panel is shown. + prepare() { + return Promise.resolve(null); + }, }); -function showEditContainersPanel() { - browser.runtime.sendMessage({method: "queryIdentities"}).then(identities => { +// P_ONBOARDING_2: Second page for Onboarding. +// ---------------------------------------------------------------------------- + +Logic.registerPanel(P_ONBOARDING_2, { + panelSelector: ".onboarding-panel-2", + + // This method is called when the object is registered. + initialize() { + // Let's move to the containers list panel. + document.querySelector("#onboarding-done-button").addEventListener("click", () => { + localStorage.setItem("onboarded2", true); + Logic.showPanel(P_CONTAINERS_LIST); + }); + }, + + // This method is called when the panel is shown. + prepare() { + return Promise.resolve(null); + }, +}); + +// P_CONTAINERS_LIST: The list of containers. The main page. +// ---------------------------------------------------------------------------- + +Logic.registerPanel(P_CONTAINERS_LIST, { + panelSelector: "#container-panel", + + // This method is called when the object is registered. + initialize() { + document.querySelector(".add-container-link").addEventListener("click", () => { + Logic.showPanel(P_CONTAINER_EDIT, {}); + }); + + document.querySelector("#edit-containers-link").addEventListener("click", () => { + Logic.showPanel(P_CONTAINERS_EDIT); + }); + + document.querySelector("#sort-containers-link").addEventListener("click", () => { + browser.runtime.sendMessage({ + method: "sortTabs" + }).then(() => { + window.close(); + }); + }); + }, + + // This method is called when the panel is shown. + prepare() { let fragment = document.createDocumentFragment(); - identities.forEach(identity => { + Logic.identities().forEach(identity => { + log('identities.forEach'); + let tr = document.createElement("tr"); + fragment.appendChild(tr); + tr.classList.add("container-panel-row"); + tr.classList.add("clickable"); + tr.setAttribute("data-identity-cookie-store-id", identity.userContextId); + tr.innerHTML = ` + +
+
+ + ${identity.name} + >`; + + tr.addEventListener("click", e => { + if (e.target.matches(".open-newtab")) { + browser.runtime.sendMessage({ + method: "showTabs", + userContextId: identity.userContextId + }).then(() => { + return browser.runtime.sendMessage({ + method: "openTab", + userContextId: identity.userContextId, + }); + }).then(() => { + window.close(); + }); + } else if (e.target.matches(".info")) { + Logic.showPanel(P_CONTAINER_INFO, identity); + } + }); + }); + + document.querySelector(".identities-list").innerHTML = ""; + document.querySelector(".identities-list").appendChild(fragment); + + return Promise.resolve(); + }, +}); + +// P_CONTAINER_INFO: More info about a container. +// ---------------------------------------------------------------------------- + +Logic.registerPanel(P_CONTAINER_INFO, { + panelSelector: "#container-info-panel", + + // This method is called when the object is registered. + initialize() { + document.querySelector("#close-container-info-panel").addEventListener("click", () => { + Logic.showPanel(P_CONTAINERS_LIST); + }); + + document.querySelector("#container-info-hideorshow").addEventListener("click", e => { + let identity = Logic.currentIdentity(); + browser.runtime.sendMessage({ + method: identity.hasHiddenTabs ? "showTabs" : "hideTabs", + userContextId: identity.userContextId + }).then(() => { + window.close(); + }); + }); + + document.querySelector("#container-info-movetabs").addEventListener("click", e => { + return browser.runtime.sendMessage({ + method: "moveTabsToWindow", + userContextId: Logic.currentIdentity().userContextId, + }).then(() => { + window.close(); + }); + }); + }, + + // This method is called when the panel is shown. + prepare() { + let identity = Logic.currentIdentity(); + + // Populating the panel: name and icon + document.getElementById("container-info-name").innerText = identity.name; + + let icon = document.getElementById("container-info-icon"); + icon.setAttribute("data-identity-icon", identity.image); + icon.setAttribute("data-identity-color", identity.color); + + // Show or not the has-tabs section. + for (let trHasTabs of document.getElementsByClassName("container-info-has-tabs")) { + trHasTabs.hidden = !identity.hasHiddenTabs && !identity.hasOpenTabs; + } + + const hideShowIcon = document.getElementById("container-info-hideorshow-icon"); + hideShowIcon.src = identity.hasHiddenTabs ? CONTAINER_UNHIDE_SRC : CONTAINER_HIDE_SRC; + + const hideShowLabel = document.getElementById("container-info-hideorshow-label"); + hideShowLabel.innerText = identity.hasHiddenTabs ? "Show these container tabs" : "Hide these container tabs"; + + // Let's remove all the previous tabs. + for (let trTab of document.getElementsByClassName("container-info-tab")) { + trTab.remove(); + } + + // Let's retrieve the list of tabs. + return browser.runtime.sendMessage({ + method: "getTabs", + userContextId: identity.userContextId, + }).then(tabs => { + log('browser.runtime.sendMessage getTabs, tabs: ', tabs); + // For each one, let's create a new line. + let fragment = document.createDocumentFragment(); + for (let tab of tabs) { + let tr = document.createElement("tr"); + fragment.appendChild(tr); + tr.classList.add("container-info-tab"); + tr.classList.add("clickable"); + tr.innerHTML = ` + + ${tab.title}`; + // On click, we activate this tab. + tr.addEventListener("click", () => { + browser.runtime.sendMessage({ + method: "showTab", + tabId: tab.id, + }).then(() => { + window.close(); + }); + }); + } + + document.getElementById("container-info-table").appendChild(fragment); + }); + }, +}); + +// P_CONTAINERS_EDIT: Makes the list editable. +// ---------------------------------------------------------------------------- + +Logic.registerPanel(P_CONTAINERS_EDIT, { + panelSelector: "#edit-containers-panel", + + // This method is called when the object is registered. + initialize() { + document.querySelector("#exit-edit-mode-link").addEventListener("click", () => { + Logic.showPanel(P_CONTAINERS_LIST); + }); + }, + + // This method is called when the panel is shown. + prepare() { + let fragment = document.createDocumentFragment(); + Logic.identities().forEach(identity => { let tr = document.createElement("tr"); fragment.appendChild(tr); tr.setAttribute("data-identity-cookie-store-id", identity.userContextId); @@ -186,92 +341,71 @@ function showEditContainersPanel() { tr.addEventListener("click", e => { if (e.target.matches(".edit-container-icon")) { - showEditContainerPanel(identity); + Logic.showPanel(P_CONTAINER_EDIT, identity); } else if (e.target.matches(".delete-container-icon")) { - showDeleteContainerPanel(identity); + Logic.showPanel(P_CONTAINER_DELETE, identity); } }); }); document.querySelector("#edit-identities-list").innerHTML = ""; document.querySelector("#edit-identities-list").appendChild(fragment); - }); - showPanel("#edit-containers-panel"); -} -function showEditContainerPanel(identity) { - document.querySelector("#edit-container-panel-name-input").value = identity.name; - showPanel("#edit-container-panel"); -} - -function showDeleteContainerPanel(identity) { - // Populating the panel: name and icon - document.getElementById("delete-container-name").innerText = identity.name; - - let icon = document.getElementById("delete-container-icon"); - icon.setAttribute("data-identity-icon", identity.image); - icon.setAttribute("data-identity-color", identity.color); - - showPanel("#delete-container-panel"); -} - -document.querySelector(".add-container-link").addEventListener("click", () => { - showPanel("#edit-container-panel"); + return Promise.resolve(null); + }, }); -document.querySelector("#edit-containers-link").addEventListener("click", () => { - showEditContainersPanel(); -}); +// P_CONTAINER_EDIT: Editor for a container. +// ---------------------------------------------------------------------------- -document.querySelector("#exit-edit-mode-link").addEventListener("click", () => { - showPanel("#container-panel"); -}); +Logic.registerPanel(P_CONTAINER_EDIT, { + panelSelector: "#edit-container-panel", -document.querySelector("#edit-container-panel-back-arrow").addEventListener("click", () => { - showEditContainersPanel(); -}); - -document.querySelector("#edit-container-cancel-link").addEventListener("click", () => { - showEditContainersPanel(); -}); - -document.querySelector("#delete-container-cancel-link").addEventListener("click", () => { - showEditContainersPanel(); -}); - -document.querySelector("#sort-containers-link").addEventListener("click", () => { - browser.runtime.sendMessage({ - method: "sortTabs" - }).then(() => { - window.close(); - }); -}); - -document.querySelector("#close-container-info-panel").addEventListener("click", () => { - document.getElementById("container-info-panel").classList.add("hide"); - document.getElementById("container-panel").classList.remove("hide"); -}); - -document.querySelector("#container-info-hideorshow").addEventListener("click", e => { - let userContextId = e.target.parentElement.getAttribute("data-user-context-id"); - browser.runtime.sendMessage({ - method: "getIdentity", - userContextId, - }).then(identity => { - return browser.runtime.sendMessage({ - method: identity.hasHiddenTabs ? "showTabs" : "hideTabs", - userContextId: identity.userContextId + // This method is called when the object is registered. + initialize() { + document.querySelector("#edit-container-panel-back-arrow").addEventListener("click", () => { + Logic.showPanel(P_CONTAINERS_EDIT); }); - }).then(() => { - window.close(); - }); + + document.querySelector("#edit-container-cancel-link").addEventListener("click", () => { + Logic.showPanel(P_CONTAINERS_EDIT); + }); + }, + + // This method is called when the panel is shown. + prepare() { + let identity = Logic.currentIdentity(); + document.querySelector("#edit-container-panel-name-input").value = identity.name; + return Promise.resolve(null); + }, }); -document.querySelector("#container-info-movetabs").addEventListener("click", e => { - return browser.runtime.sendMessage({ - method: "moveTabsToWindow", - userContextId: e.target.parentElement.getAttribute("data-user-context-id"), - }).then(() => { - window.close(); - }); +// P_CONTAINER_DELETE: Delete a container. +// ---------------------------------------------------------------------------- + +Logic.registerPanel(P_CONTAINER_DELETE, { + panelSelector: "#delete-container-panel", + + // This method is called when the object is registered. + initialize() { + document.querySelector("#delete-container-cancel-link").addEventListener("click", () => { + Logic.showPanel(P_CONTAINERS_EDIT); + }); + }, + + // This method is called when the panel is shown. + prepare() { + let identity = Logic.currentIdentity(); + + // Populating the panel: name and icon + document.getElementById("delete-container-name").innerText = identity.name; + + let icon = document.getElementById("delete-container-icon"); + icon.setAttribute("data-identity-icon", identity.image); + icon.setAttribute("data-identity-color", identity.color); + + return Promise.resolve(null); + }, }); + +Logic.init(); diff --git a/webextension/popup.html b/webextension/popup.html index 9fd8beb..85a9346 100644 --- a/webextension/popup.html +++ b/webextension/popup.html @@ -135,8 +135,7 @@
-
«
-
+