From 7d041735ffd5e440aba330b10008db1ca6aff419 Mon Sep 17 00:00:00 2001 From: hackademix Date: Mon, 21 Nov 2022 22:22:18 +0100 Subject: [PATCH] Ensure theme changes are synchronized across windows, including private ones (thanks barbaz for reporting). --- src/common/themes.js | 32 +++++++++++++++++++++++--------- src/ui/options.js | 15 ++++++++++++++- src/ui/ui.js | 14 ++++++++------ 3 files changed, 45 insertions(+), 16 deletions(-) diff --git a/src/common/themes.js b/src/common/themes.js index 7cd73ee..1feae37 100644 --- a/src/common/themes.js +++ b/src/common/themes.js @@ -69,6 +69,9 @@ const VINTAGE = "vintageTheme"; let update = toTheme => { + if (window.localStorage) try { + localStorage.setItem("theme", toTheme); + } catch (e) {} return root.dataset.theme = toTheme; } @@ -85,6 +88,9 @@ } let refreshVintage = isVintage => { + if (localStorage) try { + localStorage.setItem(VINTAGE, isVintage || ""); + } catch (e) {} document.documentElement.classList.toggle("vintage", isVintage === true); if (browser.browserAction) { browser.browserAction.setIcon({path: {64: `/img${isVintage ? "/vintage/" : "/"}ui-maybe64.png` }}); @@ -94,11 +100,9 @@ const THEMES = ["dark", "light", "auto"]; var Themes = { - setup(theme = null) { + VINTAGE, + setup(theme = null) { if (theme) { - if (window.localStorage) { - localStorage.setItem("theme", theme); - } if (browser && browser.storage) { browser.storage.local.set({theme}); } @@ -114,7 +118,6 @@ return browser.storage.local.get(["theme"]).then(({theme}) => { update(theme); document.documentElement.style.visibility = ""; - if (localStorage && theme) localStorage.setItem("theme", theme) return theme || "auto"; }); } @@ -129,15 +132,11 @@ if (ret !== null) return !(ret === "false" || !ret); } ret = (await browser.storage.local.get([VINTAGE]))[VINTAGE]; - if (localStorage && typeof ret === "boolean") localStorage.setItem(VINTAGE, ret || ""); return ret; }, async setVintage(b) { refreshVintage(b); - if (localStorage) try { - localStorage.setItem(VINTAGE, b || ""); - } catch (e) {} await browser.storage.local.set({[VINTAGE]: b}); return b; }, @@ -148,4 +147,19 @@ refreshVintage(await Themes.isVintage()); })(); Promise.resolve(Themes.setup()); + + browser.storage.onChanged.addListener((changes, area) => { + if (area !== "local") return; + const ifChanged = (key, callback) => { + if (key in changes) { + let {oldValue, newValue} = changes[key]; + if (oldValue !== newValue) { + callback(newValue); + window.dispatchEvent(new CustomEvent("NoScriptThemeChanged", {detail: {[key]: newValue}})); + } + } + } + ifChanged("theme", update); + ifChanged(VINTAGE, refreshVintage); + }); } \ No newline at end of file diff --git a/src/ui/options.js b/src/ui/options.js index dc073df..9225140 100644 --- a/src/ui/options.js +++ b/src/ui/options.js @@ -155,8 +155,21 @@ document.querySelector("#version").textContent = _("Version", opt("showFullAddresses", "local"); UI.wireChoice("theme", o => Themes.setup(o && o.value) ); - opt("vintageTheme", async o => await (o ? Themes.setVintage(o.checked) : Themes.isVintage())); + addEventListener("NoScriptThemeChanged", ({detail}) => { + if ("theme" in detail) { + for (let i of UI.getChoiceElements("theme")) { + if (i.value === detail.theme) { + i.checked = true; + break; + } + } + } + if (Themes.VINTAGE in detail) { + UI.getOptionElement("vintageTheme").checked = !!detail[Themes.VINTAGE]; + } + }); + // PRESET CUSTOMIZER { diff --git a/src/ui/ui.js b/src/ui/ui.js index b23e5bc..98332ea 100644 --- a/src/ui/ui.js +++ b/src/ui/ui.js @@ -133,12 +133,11 @@ var UI = (() => { browser.tabs.create({url}); }, + getChoiceElements(name) { + return document.querySelectorAll(`input[type=radio][name="${name}"]`); + }, wireChoice(name, storage = "sync", onchange) { - let inputs = document.querySelectorAll(`input[type=radio][name="${name}"]`); - if (inputs.length === 0) { - error(`Radio button w/ name "${name}" not found.`); - return; - } + let inputs = UI.getChoiceElements(name); if (typeof storage === "function") { (async() => { let value = await storage(null); @@ -162,8 +161,11 @@ var UI = (() => { } }, + getOptionElement(name) { + return document.querySelector(`#opt-${name}`); + }, wireOption(name, storage = "sync", onchange) { - let input = document.querySelector(`#opt-${name}`); + let input = UI.getOptionElement(name); if (!input) { error(`Checkbox w/ id "opt-${name}" not found.`); return;