From 219331398043074395436a176df3f7448104f674 Mon Sep 17 00:00:00 2001 From: kkapsner Date: Tue, 7 Nov 2017 00:36:44 +0100 Subject: [PATCH] Centralized settings management --- .eslintrc.json | 3 +- .vscode/tasks.json | 25 +++ _locales/de/messages.json | 34 ++-- _locales/en/messages.json | 34 ++-- lib/callingStack.js | 2 + lib/check.js | 1 + lib/defaultSettings.js | 26 --- lib/frame.js | 32 +--- lib/intercept.js | 2 + lib/lists.js | 25 ++- lib/logging.js | 17 +- lib/main.js | 79 ++++---- lib/require.js | 45 +++-- lib/settingDefinitions.js | 118 ++++++++++++ lib/settings.js | 242 +++++++++++++------------ manifest.json | 6 +- options/buildPrefInputs.js | 362 ------------------------------------- options/options.html | 8 +- options/options.js | 163 +++++------------ options/optionsGui.js | 171 ++++++++++++++++++ options/settingsDisplay.js | 163 +++++++++++++++++ pageAction/pageAction.html | 5 +- pageAction/pageAction.js | 262 +++++++++++++-------------- releaseNotes.txt | 4 - 24 files changed, 917 insertions(+), 912 deletions(-) delete mode 100644 lib/defaultSettings.js create mode 100644 lib/settingDefinitions.js delete mode 100644 options/buildPrefInputs.js create mode 100644 options/optionsGui.js create mode 100644 options/settingsDisplay.js diff --git a/.eslintrc.json b/.eslintrc.json index 3b3cea4..0522970 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -13,8 +13,7 @@ }, "extends": "eslint:recommended", "globals": { - "exportFunction": false, - "settings": false + "exportFunction": false }, "rules": { "brace-style": ["error", "stroustrup", {"allowSingleLine": true}], diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 51b9e64..333629e 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -53,6 +53,31 @@ }, "problemMatcher": [] }, + { + "taskName": "run current", + "type": "shell", + "windows": { + "command": "web-ext" + }, + "linux": { + "command": "web-ext" + }, + "osx": { + "command": "web-ext" + }, + "args": [ + "run", + "--url", + "http://canvasblocker.local/test/" + ], + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared" + }, + "problemMatcher": [] + }, { "taskName": "build", "type": "shell", diff --git a/_locales/de/messages.json b/_locales/de/messages.json index cba7fce..358036b 100644 --- a/_locales/de/messages.json +++ b/_locales/de/messages.json @@ -91,39 +91,39 @@ "message": "", "description": "" }, - "blockMode_options.allow everything": { + "blockMode_options.allowEverything": { "message": "alles erlauben", "description": "" }, - "blockMode_options.allow only white list": { + "blockMode_options.block": { "message": "nur Einträge der Whitelist erlauben", "description": "" }, - "blockMode_options.ask for permission": { + "blockMode_options.ask": { "message": "um Erlaubnis fragen", "description": "" }, - "blockMode_options.ask for readout API permission": { + "blockMode_options.askReadout": { "message": "bei Auslese-API um Erlaubnis fragen", "description": "" }, - "blockMode_options.block everything": { + "blockMode_options.blockEverything": { "message": "alles blockieren", "description": "" }, - "blockMode_options.block only black list": { + "blockMode_options.allow": { "message": "nur Einträge der Blacklist blockieren", "description": "" }, - "blockMode_options.block readout API": { + "blockMode_options.blockReadout": { "message": "Auslese-API blockieren", "description": "" }, - "blockMode_options.fake readout API": { + "blockMode_options.fakeReadout": { "message": "Auslese-API vortäuschen", "description": "" }, - "blockMode_options.fake input API": { + "blockMode_options.fakeInput": { "message": "Bei Ausgabe vortäuschen", "description": "" }, @@ -162,7 +162,7 @@ "message": "konstant", "description": "" }, - "rng_options.non persistent": { + "rng_options.nonPersistent": { "message": "nicht persistent", "description": "" }, @@ -185,7 +185,7 @@ "description": "" }, "storePersistentRnd_description": { - "message": "Ob Daten für den persistenten Zufallszahlengenerator gespeichert werden sollen.", + "message": "Ob Daten für den persistenten Zufallszahlengenerator gespeichert werden sollen. Ansonsten werden die Daten beim Beenden des Browsers verworfen.", "description": "" }, @@ -390,27 +390,27 @@ "message": "Für eine Fehlersuche ist eine detaillierte Aufzeichnung der Addon-Aktivitäten hilfreich. Mit diesem Parameter kann der Grad der Detailliertheit dieser Aufzeichnung eingestellt werden.", "description": "" }, - "logLevel_options.none": { + "logLevel_options.0": { "message": "nichts", "description": "" }, - "logLevel_options.error": { + "logLevel_options.1": { "message": "Fehler", "description": "" }, - "logLevel_options.warning": { + "logLevel_options.25": { "message": "Warnungen", "description": "" }, - "logLevel_options.message": { + "logLevel_options.50": { "message": "Nachrichten", "description": "" }, - "logLevel_options.notice": { + "logLevel_options.75": { "message": "Notizen", "description": "" }, - "logLevel_options.verbose": { + "logLevel_options.100": { "message": "ausführlich", "description": "" } diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 02d74bd..5a71678 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -91,39 +91,39 @@ "message": "", "description": "" }, - "blockMode_options.allow everything": { + "blockMode_options.allowEverything": { "message": "allow everything", "description": "" }, - "blockMode_options.allow only white list": { + "blockMode_options.block": { "message": "allow only white list", "description": "" }, - "blockMode_options.ask for permission": { + "blockMode_options.ask": { "message": "ask for permission", "description": "" }, - "blockMode_options.ask for readout API permission": { + "blockMode_options.askReadout": { "message": "ask for readout API permission", "description": "" }, - "blockMode_options.block everything": { + "blockMode_options.blockEverything": { "message": "block everything", "description": "" }, - "blockMode_options.block only black list": { + "blockMode_options.allow": { "message": "block only black list", "description": "" }, - "blockMode_options.block readout API": { + "blockMode_options.blockReadout": { "message": "block readout API", "description": "" }, - "blockMode_options.fake readout API": { + "blockMode_options.fakeReadout": { "message": "fake readout API", "description": "" }, - "blockMode_options.fake input API": { + "blockMode_options.fakeInput": { "message": "fake at input", "description": "" }, @@ -162,7 +162,7 @@ "message": "constant", "description": "" }, - "rng_options.non persistent": { + "rng_options.nonPersistent": { "message": "non persistent", "description": "" }, @@ -185,7 +185,7 @@ "description": "" }, "storePersistentRnd_description": { - "message": "If data for the persistent random number generator should be stored.", + "message": "If data for the persistent random number generator should be stored. Otherwise it is discarded on browser shutdown.", "description": "" }, @@ -394,27 +394,27 @@ "message": "To find the cause for an error a detailed logging of the addon activities is helpful. This parameter controls the level of detail of the logging.", "description": "" }, - "logLevel_options.none": { + "logLevel_options.0": { "message": "none", "description": "" }, - "logLevel_options.error": { + "logLevel_options.1": { "message": "error", "description": "" }, - "logLevel_options.warning": { + "logLevel_options.25": { "message": "warning", "description": "" }, - "logLevel_options.message": { + "logLevel_options.50": { "message": "message", "description": "" }, - "logLevel_options.notice": { + "logLevel_options.75": { "message": "notice", "description": "" }, - "logLevel_options.verbose": { + "logLevel_options.100": { "message": "verbose", "description": "" } diff --git a/lib/callingStack.js b/lib/callingStack.js index a76ddf3..7c1c7de 100644 --- a/lib/callingStack.js +++ b/lib/callingStack.js @@ -12,6 +12,8 @@ window.scope.callingStack = {}; scope = window.scope.callingStack; } + + const settings = require("./settings"); // Translation var _ = function(name, replace, translateAPI){ diff --git a/lib/check.js b/lib/check.js index 5f22877..8d2314a 100644 --- a/lib/check.js +++ b/lib/check.js @@ -13,6 +13,7 @@ scope = window.scope.check; } + const settings = require("./settings"); const lists = require("./lists"); const {parseErrorStack} = require("./callingStack"); const logging = require("./logging"); diff --git a/lib/defaultSettings.js b/lib/defaultSettings.js deleted file mode 100644 index 5b756bc..0000000 --- a/lib/defaultSettings.js +++ /dev/null @@ -1,26 +0,0 @@ -const settings = { - logLevel: 1, - whiteList: "", - blackList: "", - blockMode: "fakeReadout", - minFakeSize: 1, - maxFakeSize: 0, - rng: "nonPersistent", - useCanvasCache: true, - ignoreFrequentColors: 0, - fakeAlphaChannel: false, - persistentRndStorage: "", - storePersistentRnd: false, - askOnlyOnce: true, - showNotifications: true, - storeImageForInspection: false, - ignoreList: "", - showCallingFile: false, - showCompleteCallingStack: false, - enableStackList: false, - stackList: "", - displayAdvancedSettings: false, - - // indicator if the real settings are loaded already - isStillDefault: true -}; \ No newline at end of file diff --git a/lib/frame.js b/lib/frame.js index c5c9d00..11fd61d 100644 --- a/lib/frame.js +++ b/lib/frame.js @@ -4,6 +4,7 @@ (function(){ "use strict"; + const settings = require("./settings"); const {intercept} = require("./intercept.js"); const {ask} = require("./askForPermission.js"); const lists = require("./lists.js"); @@ -46,6 +47,7 @@ var port = browser.runtime.connect(); var tabId; port.onMessage.addListener(function(data){ + message("Got data from port", data); if (data.hasOwnProperty("tabId")){ notice("my tab id is", data.tabId); tabId = data.tabId; @@ -64,8 +66,6 @@ settings[key] = data.settings[key]; }); settings.isStillDefault = false; - logging.clearQueue(); - lists.updateAll(); } }); var notifications = []; @@ -141,22 +141,9 @@ return true; } - if (settings.isStillDefault){ - message("load settings"); - browser.storage.local.get().then(function(data){ - Object.keys(data).forEach(function(key){ - notice("loaded setting:", key, ":", data[key]); - settings[key] = data[key]; - }); - settings.isStillDefault = false; - logging.clearQueue(); - lists.updateAll(); - interceptWindow(window); - }); - } - else { + settings.onloaded(function(){ interceptWindow(window); - } + }); message("register listener for messages from background script"); browser.runtime.onMessage.addListener(function(data){ @@ -175,15 +162,4 @@ notice("notifications sent"); } }); - - - message("register listener for settings changes"); - browser.storage.onChanged.addListener(function(change, area){ - if (area === "local"){ - Object.keys(change).forEach(function(key){ - notice("setting changed:", key, ":", change[key].newValue); - settings[key] = change[key].newValue; - }); - } - }); }()); \ No newline at end of file diff --git a/lib/intercept.js b/lib/intercept.js index 535796c..604a360 100644 --- a/lib/intercept.js +++ b/lib/intercept.js @@ -16,6 +16,7 @@ const {changedFunctions, setRandomSupply} = require("./modifiedAPI"); const randomSupplies = require("./randomSupplies"); const getWrapped = require("sdk/getWrapped"); + const logging = require("./logging"); setRandomSupply(randomSupplies.nonPersistent); var apiNames = Object.keys(changedFunctions); @@ -57,6 +58,7 @@ scope.intercept = function intercept({subject: window}, {check, checkStack, ask, notify, prefs}){ var siteStatus = check({url: getURL(window)}); + logging.verbose("status for page", window, siteStatus); if (siteStatus.mode !== "allow"){ apiNames.forEach(function(name){ var changedFunction = changedFunctions[name]; diff --git a/lib/lists.js b/lib/lists.js index 9c98183..6e87232 100644 --- a/lib/lists.js +++ b/lib/lists.js @@ -15,8 +15,7 @@ scope = window.scope.lists; } - var preferences = require("sdk/simple-prefs"); - var prefs = preferences.prefs; + var settings = require("./settings"); function getDomainRegExpList(domainList){ @@ -66,15 +65,15 @@ function updateList(type, value){ if (typeof value === "undefined"){ - value = prefs[type + "List"]; + value = settings[type + "List"]; } lists[type] = getDomainRegExpList(value); } Object.keys(lists).forEach(function(type){ - preferences.on(type + "List", function(value){ - updateList(type, value); + settings.on(type + "List", function({newValue}){ + updateList(type, newValue); }); - updateList(type, prefs[type + "List"]); + updateList(type, settings[type + "List"]); }); function updateStackList(value){ @@ -99,19 +98,16 @@ lists.stack = list; } lists.stack = []; - preferences.on("stackList", function(value){ - updateStackList(value); + settings.on("stackList", function({newValue}){ + updateStackList(newValue); }); - updateStackList(prefs.stackList); + updateStackList(settings.stackList); scope.get = function getList(type){ return lists[type]; }; scope.appendTo = function appendToList(type, entry){ - prefs[type + "List"] += (prefs[type + "List"]? ",": "") + entry; - var obj = {}; - obj[type + "List"] = prefs[type + "List"]; - browser.storage.local.set(obj); + settings[type + "List"] += (settings[type + "List"]? ",": "") + entry; updateList(type); }; scope.update = updateList; @@ -119,6 +115,7 @@ updateList("white"); updateList("ignore"); updateList("black"); - updateStackList(prefs.stackList); + updateStackList(settings.stackList); }; + settings.onloaded(scope.updateAll); }()); \ No newline at end of file diff --git a/lib/logging.js b/lib/logging.js index 6295ac5..7bfd49b 100644 --- a/lib/logging.js +++ b/lib/logging.js @@ -9,14 +9,14 @@ if ((typeof exports) !== "undefined"){ scope = exports; } - else if (window.scope){ - window.scope.logging = {}; + else { + if (!window.scope.logging){ + window.scope.logging = {}; + } scope = window.scope.logging; } - else { - window.logging = {}; - scope = window.logging; - } + + const settings = require("./settings"); var prefix = ""; @@ -85,9 +85,14 @@ metaLog("logging queue cleared"); } }; + settings.on("isStillDefault", scope.clearQueue); scope.error = error; scope.warning = warning; scope.message = message; scope.notice = notice; scope.verbose = verbose; + + require.emit("./logging"); + + metaLog("logging available"); }()); \ No newline at end of file diff --git a/lib/main.js b/lib/main.js index e303ca4..4145fc3 100644 --- a/lib/main.js +++ b/lib/main.js @@ -4,23 +4,16 @@ (function(){ "use strict"; + const settings = require("./settings"); const logging = require("./logging"); const {error, warning, message, notice, verbose, } = logging; + const lists = require("./lists"); logging.setPrefix("main script"); - message("start"); - message("loading storage"); - browser.storage.local.get().then(function(data){ - Object.keys(data).forEach(function(key){ - settings[key] = data[key]; - }); - settings.isStillDefault = false; - logging.clearQueue(); - return settings; - }).then(function(settings){ + message("start of background script"); + message("waiting for settings to be loaded"); + settings.onloaded(function(){ notice("everything loaded"); - const lists = require("./lists"); - lists.updateAll(); notice("build persistent storage"); var persistentRnd = Object.create(null); @@ -66,11 +59,17 @@ verbose("got new domain rnd", data["canvasBlocker-new-domain-rnd"]); data["canvasBlocker-set-domain-rnd"] = data["canvasBlocker-new-domain-rnd"]; persistentRnd[data["canvasBlocker-new-domain-rnd"].domain] = data["canvasBlocker-new-domain-rnd"].rnd; - browser.storage.local.get("storePersistentRnd").then(function(prefs){ - if (prefs.storePersistentRnd){ - browser.storage.local.set({persistentRndStorage: JSON.stringify(persistentRnd)}); - } - }); + if (settings.storePersistentRnd){ + settings.persistentRndStorage = JSON.stringify(persistentRnd); + } + updateContentScripts(); + } + if (data["canvasBlocker-clear-domain-rnd"]){ + verbose("domain rnd cleared"); + persistentRnd = Object.create(null); + if (settings.storePersistentRnd){ + settings.persistentRndStorage = JSON.stringify(persistentRnd); + } updateContentScripts(); } notice("pass the message to the tabs"); @@ -86,54 +85,40 @@ notice("got port", port); verbose("send back the tab id", port.sender.tab.id); verbose("send back the persistent random seeds", persistentRnd); - verbose("send back the settings", settings); port.postMessage({ tabId: port.sender.tab.id, - persistentRnd: persistentRnd, - settings: settings + persistentRnd: persistentRnd }); var url = new URL(port.sender.url); port.onMessage.addListener(function(data){ - browser.storage.local.get("showNotifications").then(function(data){ + if (data.hasOwnProperty("canvasBlocker-notify")){ if ( - ( - !data.hasOwnProperty("showNotifications") || - data.showNotifications - ) && + settings.showNotifications && !lists.get("ignore").match(url) ){ browser.pageAction.show(port.sender.tab.id); } - }); + } verbose("got data", data, "from port", port); }); }); message("register storage change event listener"); - browser.storage.onChanged.addListener(function(change, area){ - if (area === "local"){ - notice("settings changed", change); - notice("update settings object"); - Object.keys(change).forEach(function(key){ - settings[key] = change[key].newValue; + + settings.on("any", updateContentScripts); + settings.on("showNotifications", function({newValue}){ + if (!newValue){ + message("notifications were disabled -> hide all page actions"); + browser.tabs.query({}).then(function(tabs){ + tabs.forEach(function(tab){ + browser.pageAction.hide(tab.id); + }); }); - updateContentScripts(); - - if (change.hasOwnProperty("showNotifications") && !change.showNotifications.newValue){ - message("notifications were disabled -> hide all page actions"); - browser.tabs.query({}).then(function(tabs){ - tabs.forEach(function(tab){ - browser.pageAction.hide(tab.id); - }); - }); - } - if (change.hasOwnProperty("storePersistentRnd")){ - browser.storage.local.set({ - persistentRndStorage: change.storePersistentRnd.newValue? JSON.stringify(persistentRnd): "" - }); - } } }); + settings.on("storePersistentRnd", function({newValue}){ + settings.persistentRndStorage = newValue? JSON.stringify(persistentRnd): ""; + }); // hide page action when a tab is refreshed browser.tabs.onUpdated.addListener(function(tabId, data){ diff --git a/lib/require.js b/lib/require.js index 7549f60..a592874 100644 --- a/lib/require.js +++ b/lib/require.js @@ -6,9 +6,15 @@ const require = function(){ "use strict"; window.scope = {}; const scope = window.scope; + + function getScopeName(module){ + var scopeName = module.substr(2).replace(/\..+/, ""); + return scopeName; + } + function require(module){ if (module.startsWith("./")){ - var scopeName = module.substr(2).replace(/\..+/, ""); + var scopeName = getScopeName(module); return scope[scopeName]; } else if (module === "sdk/getWrapped"){ @@ -27,22 +33,31 @@ const require = function(){ return wrapped; }; } - else if (module === "sdk/simple-prefs"){ - return { - prefs: settings, - on: function(key, callback){ - browser.storage.onChanged.addListener(function(changes, area){ - if (area === "local"){ - if (changes.hasOwnProperty(key)){ - callback(changes[key].newValue); - } - } - }); - } - }; - } throw new ReferenceError("Unable to get non relative module " + module + "!"); } + var events = {}; + require.on = function(module, callback){ + var scopeName = getScopeName(module); + if (scope.hasOwnProperty(scopeName)){ + callback(scope[scopeName]); + } + else { + if (!events.hasOwnProperty(scopeName)){ + events[scopeName] = []; + } + events[scopeName].push(callback); + } + }; + require.emit = function(module){ + var scopeName = getScopeName(module); + if (events[scopeName]){ + events[scopeName].forEach(function(callback){ + callback(scope[scopeName]); + }); + events[scopeName] = []; + } + }; + return require; }(); \ No newline at end of file diff --git a/lib/settingDefinitions.js b/lib/settingDefinitions.js new file mode 100644 index 0000000..c71d23b --- /dev/null +++ b/lib/settingDefinitions.js @@ -0,0 +1,118 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +(function(){ + "use strict"; + + var settingDefinitions = [ + { + name: "logLevel", + defaultValue: 1, + options: [0, 1, 25, 50, 75, 100] + }, + { + name: "whiteList", + defaultValue: "" + }, + { + name: "blackList", + defaultValue: "" + }, + { + name: "blockMode", + defaultValue: "fakeReadout", + options: [ + "blockReadout", "fakeReadout", "fakeInput", "askReadout", null, + "blockEverything", "block", "ask", "allow", "allowEverything" + ] + }, + { + name: "minFakeSize", + defaultValue: 1 + }, + { + name: "maxFakeSize", + defaultValue: 0 + }, + { + name: "rng", + defaultValue: "nonPersistent", + options: ["nonPersistent", "constant", "persistent"] + }, + { + name: "useCanvasCache", + defaultValue: true + }, + { + name: "ignoreFrequentColors", + defaultValue: 0 + }, + { + name: "fakeAlphaChannel", + defaultValue: false + }, + { + name: "persistentRndStorage", + defaultValue: "" + }, + { + name: "storePersistentRnd", + defaultValue: false + }, + { + name: "askOnlyOnce", + defaultValue: true + }, + { + name: "showNotifications", + defaultValue: true + }, + { + name: "storeImageForInspection", + defaultValue: false + }, + { + name: "notificationDisplayTime", + defaultValue: 30 + }, + { + name: "ignoreList", + defaultValue: "" + }, + { + name: "showCallingFile", + defaultValue: false + }, + { + name: "showCompleteCallingStack", + defaultValue: false + }, + { + name: "enableStackList", + defaultValue: false + }, + { + name: "stackList", + defaultValue: "" + }, + { + name: "displayAdvancedSettings", + defaultValue: false + }, + { + name: "isStillDefault", + defaultValue: true + }, + { + name: "storageVersion", + defaultValue: 0.1 + } + ]; + + if ((typeof module) !== "undefined"){ + module.exports = settingDefinitions; + } + else { + window.scope.settingDefinitions = settingDefinitions; + } +}()); \ No newline at end of file diff --git a/lib/settings.js b/lib/settings.js index b0212e1..cf8a331 100644 --- a/lib/settings.js +++ b/lib/settings.js @@ -1,7 +1,7 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - (function(){ +(function(){ "use strict"; var scope; @@ -9,138 +9,144 @@ scope = exports; } else { - window.scope.settings = {}; - scope = window.scope.settings; + scope = {}; + window.scope.settings = scope; } - var settingDefinitions = [ - { - name: "logLevel", - defaultValue: 1 - }, - { - name: "whiteList", - defaultValue: "" - }, - { - name: "blackList", - defaultValue: "" - }, - { - name: "blockMode", - defaultValue: "fakeReadout", - options: ["blockReadout", "fakeReadout", "fakeInput", "askReadout", "blockEverything", "block", "ask", "allow", "allowEverything"] - }, - { - name: "minFakeSize", - defaultValue: 1 - }, - { - name: "maxFakeSize", - defaultValue: 0 - }, - { - name: "rng", - defaultValue: "nonPersistent", - options: ["nonPersistent", "constant", "persistent"] - }, - { - name: "useCanvasCache", - defaultValue: true - }, - { - name: "ignoreFrequentColors", - defaultValue: 0 - }, - { - name: "fakeAlphaChannel", - defaultValue: false - }, - { - name: "persistentRndStorage", - defaultValue: "" - }, - { - name: "storePersistentRnd", - defaultValue: false - }, - { - name: "askOnlyOnce", - defaultValue: true - }, - { - name: "showNotifications", - defaultValue: true - }, - { - name: "storeImageForInspection", - defaultValue: false - }, - { - name: "notificationDisplayTime", - defaultValue: 30 - }, - { - name: "ignoreList", - defaultValue: "" - }, - { - name: "showCallingFile", - defaultValue: false - }, - { - name: "showCompleteCallingStack", - defaultValue: false - }, - { - name: "enableStackList", - defaultValue: false - }, - { - name: "stackList", - defaultValue: "" - }, - { - name: "displayAdvancedSettings", - defaultValue: false - }, - { - name: "isStillDefault", - defaultValue: true - } - ]; - - var settings = {}; - window.settings = {}; + var logging = {}; + (function(){ + var loggingQueue = []; + require.on("./logging", function(realLogging){ + logging = realLogging; + + loggingQueue.forEach(function(logEntry){ + logging[logEntry.name](...logEntry.args, logEntry.date); + }); + loggingQueue = []; + }); + ["error", "warning", "message", "notice", "verbose"].forEach(function(name){ + logging[name] = function(...args){ + loggingQueue.push({name, args, date: new Date()}); + }; + }); + }()); + const settingDefinitions = require("./settingDefinitions.js"); + + const eventHandler = {any: []}; + eventHandler.all = eventHandler.any; + const settings = {}; settingDefinitions.forEach(function(settingDefinition){ var name = settingDefinition.name; settings[name] = settingDefinition.defaultValue; - Object.defineProperty( - window.settings, - { - name: name, - get: function(){ - return settings[name] - }, - set: function(newValue){ - if ((typeof newValue) === (typeof settingDefinition.defaultValue)){ - if ( - !settingDefinition.options || - settingDefinition.options.includes(newValue) - ){ - settings[name] = newValue; - - } + eventHandler[name] = []; + + settingDefinition.on = function on(callback){ + scope.on(name, callback); + }; + settingDefinition.get = function getValue(){ + return settings[name]; + }; + settingDefinition.set = function setValue(newValue){ + if ((typeof newValue) === (typeof settingDefinition.defaultValue)){ + if ( + !settingDefinition.options || + settingDefinition.options.includes(newValue) + ){ + settings[name] = newValue; + if (!settingDefinition.transient){ + var storeObject = {}; + storeObject[name] = newValue; + browser.storage.local.set(storeObject); } + } + else { + logging.warning("Provided value outside specified options for ", name, ":", newValue); + } + } + else { + logging.warning("Wrong type provided for setting", name, ":", newValue); + } + }; + Object.defineProperty( + scope, + name, + { + get: settingDefinition.get, + set: settingDefinition.set } ); }); + scope.getDefinition = function(name){ + var foundDefinitions = settingDefinitions.filter(function(settingDefinition){ + return name === settingDefinition.name; + }); + if (foundDefinitions.length){ + return Object.create(foundDefinitions[0]); + } + else { + return undefined; + } + }; + scope.forEach = function forEachSetting(...args){ settingDefinitions.map(function(settingDefinition){ return Object.create(settingDefinition); }).forEach(...args); + }; + scope.on = function onSettingsChange(name, callback){ + if (eventHandler.hasOwnProperty(name)){ + eventHandler[name].push(callback); + } + else { + logging.warning("Unable to register event handler for unknown setting", name); + } + }; + + function changeValue(name, newValue){ + var oldValue = settings[name]; + settings[name] = newValue; + (eventHandler[name] || []).forEach(function(callback){ + callback({name, newValue, oldValue}); + }); } + + logging.verbose("registering storage onchange listener"); + browser.storage.onChanged.addListener(function(changes, area){ + if (area === "local"){ + logging.notice("settings changed", changes); + Object.entries(changes).forEach(function(entry){ + const [name, change] = entry; + changeValue(name, change.newValue); + }); + eventHandler.any.forEach(function(callback){ + callback(); + }); + } + }); + + logging.verbose("loading settings"); + scope.loaded = browser.storage.local.get().then(function(storage){ + logging.message("settings loaded"); + Object.entries(storage).forEach(function(entry){ + const [name, value] = entry; + changeValue(name, value); + }); + changeValue("isStillDefault", false); + + eventHandler.any.forEach(function(callback){ + callback(); + }); + }); + scope.onloaded = function(callback){ + if (scope.isStillDefault){ + scope.loaded.then(function(){callback();}); + } + else { + callback(); + } + }; + Object.seal(scope); }()); \ No newline at end of file diff --git a/manifest.json b/manifest.json index 81a400b..67d2170 100644 --- a/manifest.json +++ b/manifest.json @@ -8,8 +8,9 @@ }, "background": { "scripts": [ - "lib/defaultSettings.js", "lib/require.js", + "lib/settingDefinitions.js", + "lib/settings.js", "lib/logging.js", "lib/lists.js", "lib/main.js" @@ -20,8 +21,9 @@ "all_frames": true, "run_at": "document_start", "js": [ - "lib/defaultSettings.js", "lib/require.js", + "lib/settingDefinitions.js", + "lib/settings.js", "lib/logging.js", diff --git a/options/buildPrefInputs.js b/options/buildPrefInputs.js deleted file mode 100644 index 345b3db..0000000 --- a/options/buildPrefInputs.js +++ /dev/null @@ -1,362 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -(function(){ - "use strict"; - - const logging = require("./logging"); - - var table = document.createElement("table"); - table.className = "settings"; - document.body.appendChild(table); - - [ - { - "name": "displayAdvancedSettings", - "title": "Display advanced settings", - "type": "bool", - "value": false - }, - { - "name": "blockMode", - "title": "block mode", - "type": "menulist", - "value": "fakeReadout", - "options": [ - { - "value": "blockReadout", - "label": "block readout API" - }, - { - "value": "fakeReadout", - "label": "fake readout API" - }, - { - "value": "fakeInput", - "label": "fake input API" - }, - { - "value": "askReadout", - "label": "ask for readout API permission" - }, - { - "value": "", - "label": "" - }, - { - "value": "blockEverything", - "label": "block everything" - }, - { - "value": "block", - "label": "allow only white list" - }, - { - "value": "ask", - "label": "ask for permission" - }, - { - "value": "allow", - "label": "block only black list" - }, - { - "value": "allowEverything", - "label": "allow everything" - } - ] - }, - { - "name": "whiteList", - "title": "White list", - "type": "string", - "value": "", - "displayDependencies": { - "blockMode": ["blockReadout", "fakeReadout", "fakeInput", "askReadout", "block", "ask"] - } - }, - { - "name": "blackList", - "title": "Black list", - "type": "string", - "value": "", - "displayDependencies": { - "blockMode": ["blockReadout", "fakeReadout", "fakeInput", "askReadout", "ask", "allow"] - } - }, - { - "name": "minFakeSize", - "title": "Minimal fake size", - "type": "integer", - "value": 1, - "displayDependencies": { - "blockMode": ["fakeReadout", "fakeInput"], - "displayAdvancedSettings": [true] - } - }, - { - "name": "maxFakeSize", - "title": "Maximal fake size", - "type": "integer", - "value": 0, - "displayDependencies": { - "blockMode": ["fakeReadout", "fakeInput"], - "displayAdvancedSettings": [true] - } - }, - { - "name": "rng", - "title": "Random number generator", - "type": "menulist", - "value": "nonPersistent", - "options": [ - { - "value": "nonPersistent", - "label": "non persistent" - }, - { - "value": "constant", - "label": "constant" - }, - { - "value": "persistent", - "label": "persistent" - } - ], - "displayDependencies": { - "blockMode": ["fakeReadout", "fakeInput"], - "displayAdvancedSettings": [true] - } - }, - { - "name": "storePersistentRnd", - "title": "Store persistent data", - "type": "bool", - "value": false, - "displayDependencies": { - "blockMode": ["fakeReadout", "fakeInput"], - "rng": ["persistent"], - "displayAdvancedSettings": [true] - } - }, - { - "name": "clearPersistentRnd", - "title": "Clear persistent random storage", - "type": "control", - "label": "Clear", - "displayDependencies": { - "blockMode": ["fakeReadout", "fakeInput"], - "rng": ["persistent"], - "displayAdvancedSettings": [true] - } - }, - { - "name": "ignoreFrequentColors", - "title": "Ignore most frequent colors", - "type": "integer", - "value": 0, - "displayDependencies": { - "blockMode": ["fakeReadout"], - "displayAdvancedSettings": [true] - } - }, - { - "name": "fakeAlphaChannel", - "title": "Fake the alpha channel", - "type": "bool", - "value": false, - "displayDependencies": { - "blockMode": ["fakeReadout"], - "displayAdvancedSettings": [true] - } - }, - { - "name": "useCanvasCache", - "title": "Use canvas cache", - "type": "bool", - "value": true, - "displayDependencies": { - "blockMode": ["fakeReadout"], - "displayAdvancedSettings": [true] - } - }, - { - "name": "askOnlyOnce", - "title": "Ask only once", - "type": "bool", - "value": true, - "displayDependencies": { - "blockMode": ["askReadout", "ask"] - } - }, - { - "name": "showNotifications", - "title": "Show notifications", - "type": "bool", - "value": true, - "displayDependencies": { - "blockMode": ["fakeReadout", "fakeInput"] - } - }, - { - "name": "storeImageForInspection", - "title": "Store image for inspection", - "type": "bool", - "value": false, - "displayDependencies": { - "blockMode": ["fakeReadout", "fakeInput"], - "showNotifications": [true], - "displayAdvancedSettings": [true] - } - }, - { - "name": "ignoreList", - "title": "Ignore list", - "type": "string", - "value": "", - "displayDependencies": { - "blockMode": ["fakeReadout", "fakeInput"], - "showNotifications": [true] - } - }, - { - "name": "showCallingFile", - "title": "Display calling file", - "type": "bool", - "value": false, - "displayDependencies": { - "blockMode": ["askReadout", "ask"], - "displayAdvancedSettings": [true] - } - }, - { - "name": "showCompleteCallingStack", - "title": "Display complete calling stack", - "type": "bool", - "value": false, - "displayDependencies": [ - { - "blockMode": ["fakeReadout", "fakeInput"], - "showNotifications": [true], - "displayAdvancedSettings": [true] - }, - { - "blockMode": ["askReadout", "ask"], - "displayAdvancedSettings": [true] - } - ] - }, - { - "name": "enableStackList", - "title": "Use file specific scoped white list", - "type": "bool", - "value": false, - "displayDependencies": { - "blockMode": ["blockReadout", "fakeReadout", "fakeInput", "askReadout", "block", "ask"], - "displayAdvancedSettings": [true] - } - }, - { - "name": "stackList", - "title": "File specific white list", - "type": "string", - "value": "", - "displayDependencies": { - "enableStackList": [true], - "displayAdvancedSettings": [true] - } - - }, - { - "name": "showReleaseNotes", - "title": "Release notes", - "type": "control", - "label": "Show" - }, - { - "name": "logLevel", - "title": "logging level", - "type": "menulist", - "value": 1, - "options": [ - { - "value": 0, - "label": "none" - }, - { - "value": 1, - "label": "error" - }, - { - "value": 25, - "label": "warning" - }, - { - "value": 50, - "label": "message" - }, - { - "value": 75, - "label": "notice" - }, - { - "value": 100, - "label": "verbose" - } - ], - "displayDependencies": { - "displayAdvancedSettings": [true] - } - } - ].forEach(function(pref){ - var html = "
" + - "__MSG_" + pref.name + "_title__" + - "
__MSG_" + pref.name + "_description__
" + - "
"; - var inputAttributes = - " data-storage-name=\"" + pref.name + "\"" + - " data-storage-type=\"" + pref.type + "\"" + - " class=\"setting\""; - switch (pref.type){ - case "integer": - html += ""; - break; - case "string": - html += ""; - break; - case "bool": - html += ""; - break; - case "menulist": - html += "" + - pref.options.map(function(option){ - if (option.value !== ""){ - return ""; - } - else { - return ""; - } - }).join("") + - ""; - break; - case "control": - html += "__MSG_" + pref.name + "_label__"; - break; - default: - logging.warning("Unknown preference type: " + pref.type); - } - html += "
"; - var tr = document.createElement("tr"); - tr.setting = pref; - tr.className = "settingRow"; - tr.innerHTML = html; - logging.verbose(html); - table.appendChild(tr); - }); -}()); \ No newline at end of file diff --git a/options/options.html b/options/options.html index 8dc3ad0..93c26e2 100644 --- a/options/options.html +++ b/options/options.html @@ -6,10 +6,12 @@ - - + + + - + + \ No newline at end of file diff --git a/options/options.js b/options/options.js index 790c817..87b4ec3 100644 --- a/options/options.js +++ b/options/options.js @@ -5,131 +5,64 @@ "use strict"; const logging = require("./logging"); + logging.setPrefix("options page"); + + const optionsGui = require("./optionsGui"); + const settings = require("./settings"); + const settingsDisplay = require("./settingsDisplay"); - browser.storage.local.get().then(function(data){ - Object.keys(data).forEach(function(key){ - settings[key] = data[key]; - }); - settings.isStillDefault = false; - logging.setPrefix("options page"); - logging.clearQueue(); - return settings; - }).then(function(settings){ - function traverse(node, func){ - func(node); - Array.from(node.childNodes).forEach(function(child){traverse(child, func);}); + var callbacks = { + showReleaseNotes: function(){ + logging.verbose("open release notes"); + window.open("../releaseNotes.txt", "_blank"); + }, + clearPersistentRnd: function(){ + logging.message("clear persistent rnd storage"); + logging.notice("empty storage"); + settings.persistentRndStorage = ""; + logging.notice("send message to main script"); + browser.runtime.sendMessage({"canvasBlocker-clear-domain-rnd": true}); } - - // getting the translation of all the messages - logging.message("translate all messages"); - traverse(document.body, function(node){ - if (node.nodeType === 3){ - var lines = node.nodeValue.replace(/\b__MSG_(.+)__\b/g, function(m, key){ - try { - return browser.i18n.getMessage(key); - } - catch (e){ - return "Unknown i18n key: " + key; - } - }).split(/\n/g); - node.nodeValue = lines.shift(); - lines.forEach(function(line){ - node.parentNode.appendChild(document.createElement("br")); - node.parentNode.appendChild(document.createTextNode(line)); - }); + }; + + var table = document.createElement("table"); + table.className = "settings"; + document.body.appendChild(table); + settingsDisplay.forEach(function(display){ + var setting = settings.getDefinition(display.name); + if (!setting){ + if (callbacks[display.name]){ + setting = { + name: display.name, + action: callbacks[display.name] + }; } - }); - - logging.message("register events to store changes in local storage"); - Array.from(document.querySelectorAll("input.setting, select.setting")).forEach(function(input){ - var storageName = input.dataset.storageName; - if (input.type === "checkbox"){ - input.checked = settings[storageName]; - - input.addEventListener("click", function(){ - logging.message("changed setting", storageName, ":", this.checked); - var value = this.checked; - var obj = {}; - obj[storageName] = value; - browser.storage.local.set(obj); - }); - } - else { - input.value = settings[storageName]; - - input.addEventListener("change", function(){ - var value = this.value; - if (this.type === "number" || this.dataset.type === "number"){ - value = parseFloat(value); - } - logging.message("changed setting", storageName, ":", value); - var obj = {}; - obj[storageName] = value; - browser.storage.local.set(obj); - }); - } - }); - - var callbacks = { - showReleaseNotes: function(){ - logging.verbose("open release notes"); - window.open("../releaseNotes.txt", "_blank"); - }, - clearPersistentRnd: function(){ - logging.message("clear persistent rnd storage"); - logging.notice("empty storage"); - browser.storage.local.set({persistentRndStorage: ""}); - logging.notice("send message to main script"); - browser.runtime.sendMessage({"canvasBlocker-clear-domain-rnd": true}); - } - }; - Array.from(document.querySelectorAll("button.setting")).forEach(function(button){ - var storageName = button.dataset.storageName; - button.addEventListener("click", function(){ - if (callbacks[storageName]){ - callbacks[storageName](); - } - }); - }); - - function updateDisplay(){ - logging.notice("update display"); - document.querySelectorAll("tr.settingRow").forEach(function(row){ - logging.verbose("evaluate display dependencies for", row.setting); - var displayDependencies = row.setting.displayDependencies; - if (displayDependencies){ + } + if (setting){ + var row = optionsGui.createSettingRow(setting); + table.appendChild(row); + if (display.displayDependencies){ + var displayDependencies = display.displayDependencies; + displayDependencies = Array.isArray(displayDependencies)? + displayDependencies: + [displayDependencies]; + var computeDependencies = function(){ + logging.verbose("evaluate display dependencies for", setting); row.classList[( - ( - Array.isArray(displayDependencies)? - displayDependencies: - [displayDependencies] - ).some(function(displayDependency){ + displayDependencies.some(function(displayDependency){ return Object.keys(displayDependency).every(function(key){ return displayDependency[key].indexOf(settings[key]) !== -1; }); }) )? "remove": "add"]("hidden"); - } - }); - } - updateDisplay(); - - browser.storage.onChanged.addListener(function(change, area){ - if (area === "local"){ - Object.keys(change).forEach(function(key){ - settings[key] = change[key].newValue; - var input = document.querySelector(".setting[data-storage-name=" + key + "]"); - if (input){ - if (input.type === "checkbox"){ - input.checked = change[key].newValue; - } - else { - input.value = change[key].newValue; - } - } + }; + computeDependencies(); + displayDependencies.forEach(function(displayDependency){ + Object.keys(displayDependency).forEach(function(name){ + settings.on(name, computeDependencies); + }); }); - updateDisplay(); } - }); + } }); }()); diff --git a/options/optionsGui.js b/options/optionsGui.js new file mode 100644 index 0000000..8787747 --- /dev/null +++ b/options/optionsGui.js @@ -0,0 +1,171 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +(function(){ + "use strict"; + + var scope; + if ((typeof exports) !== "undefined"){ + scope = exports; + } + else { + scope = {}; + window.scope.optionsGui = scope; + } + + const logging = require("./logging"); + + function createDescription(setting){ + var c = document.createElement("div"); + c.className = "content"; + + var title = document.createElement("span"); + title.className = "title"; + title.textContent = browser.i18n.getMessage(setting.name + "_title"); + c.appendChild(title); + + var description = document.createElement("div"); + description.className = "description"; + description.textContent = browser.i18n.getMessage(setting.name + "_description"); + c.appendChild(description); + + return c; + } + + function createSelect(setting){ + var select = document.createElement("select"); + select.dataset.type = typeof setting.defaultValue; + setting.options.forEach(function(value){ + var option = document.createElement("option"); + if (typeof value === typeof setting.defaultValue){ + option.value = value; + if (setting.defaultValue === value){ + option.selected = true; + } + option.text = browser.i18n.getMessage(setting.name + "_options." + value) || value; + } + else { + option.disabled = true; + option.text = "\u2500".repeat(20); + } + select.appendChild(option); + }); + return select; + } + + var inputTypes = { + number: { + input: function(input, value){ + input.type = "number"; + input.value = value; + return input; + }, + updateCallback: function(input, setting){ + input.value = setting.get(); + return input.value; + }, + changeCallback: function(input, setting){ + setting.set(parseFloat(input.value)); + return parseFloat(input.value); + } + }, + string: { + input: function(input, value){ + input.type = "text"; + input.value = value; + return input; + }, + updateCallback: function(input, setting){ + input.value = setting.get(); + return input.value; + }, + changeCallback: function(input, setting){ + setting.set(input.value); + return input.value; + } + }, + boolean: { + input: function(input, value){ + input.type = "checkbox"; + input.checked = value; + input.style.display = "inline"; + return input; + }, + updateCallback: function(input, setting){ + input.checked = setting.get(); + return input.checked; + }, + changeCallback: function(input, setting){ + setting.set(input.checked); + return input.checked; + } + } + }; + + function createInput(setting){ + var type = inputTypes[typeof setting.defaultValue]; + var input; + if (setting.options){ + input = createSelect(setting); + } + else { + input = document.createElement("input"); + if (type){ + type.input(input, setting.defaultValue); + } + } + if (type){ + setting.on(function(){type.updateCallback(input, setting);}); + input.addEventListener("change", function(){ + var value = type.changeCallback(input, setting); + logging.message("changed setting", setting.name, ":", value); + + }); + } + return input; + } + + function createButton(setting){ + var button = document.createElement("button"); + button.textContent = browser.i18n.getMessage(setting.name + "_label"); + button.addEventListener("click", setting.action); + return button; + } + + function createInteraction(setting){ + var c = document.createElement("div"); + c.className = "content"; + + var interaction; + if (setting.action){ + interaction = createButton(setting); + } + else { + interaction = createInput(setting); + } + + interaction.className = "setting"; + interaction.dataset.storageName = setting.name; + interaction.dataset.storageType = typeof setting.defaultValue; + + c.appendChild(interaction); + return c; + } + + function createSettingRow(setting){ + var tr = document.createElement("tr"); + tr.className = "settingRow"; + + var left = document.createElement("td"); + left.appendChild(createDescription(setting)); + tr.appendChild(left); + + var right = document.createElement("td"); + right.appendChild(createInteraction(setting)); + tr.appendChild(right); + + return tr; + } + + scope.createSettingRow = createSettingRow; +}()); \ No newline at end of file diff --git a/options/settingsDisplay.js b/options/settingsDisplay.js new file mode 100644 index 0000000..34c3ebf --- /dev/null +++ b/options/settingsDisplay.js @@ -0,0 +1,163 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +(function(){ + "use strict"; + var settingsDisplay = [ + { + "name": "displayAdvancedSettings" + }, + { + "name": "blockMode" + }, + { + "name": "whiteList", + "displayDependencies": { + "blockMode": ["blockReadout", "fakeReadout", "fakeInput", "askReadout", "block", "ask"] + } + }, + { + "name": "blackList", + "displayDependencies": { + "blockMode": ["blockReadout", "fakeReadout", "fakeInput", "askReadout", "ask", "allow"] + } + }, + { + "name": "minFakeSize", + "displayDependencies": { + "blockMode": ["fakeReadout", "fakeInput"], + "displayAdvancedSettings": [true] + } + }, + { + "name": "maxFakeSize", + "displayDependencies": { + "blockMode": ["fakeReadout", "fakeInput"], + "displayAdvancedSettings": [true] + } + }, + { + "name": "rng", + "displayDependencies": { + "blockMode": ["fakeReadout", "fakeInput"], + "displayAdvancedSettings": [true] + } + }, + { + "name": "storePersistentRnd", + "displayDependencies": { + "blockMode": ["fakeReadout", "fakeInput"], + "rng": ["persistent"], + "displayAdvancedSettings": [true] + } + }, + { + "name": "clearPersistentRnd", + "displayDependencies": { + "blockMode": ["fakeReadout", "fakeInput"], + "rng": ["persistent"], + "displayAdvancedSettings": [true] + } + }, + { + "name": "ignoreFrequentColors", + "displayDependencies": { + "blockMode": ["fakeReadout"], + "displayAdvancedSettings": [true] + } + }, + { + "name": "fakeAlphaChannel", + "displayDependencies": { + "blockMode": ["fakeReadout"], + "displayAdvancedSettings": [true] + } + }, + { + "name": "useCanvasCache", + "displayDependencies": { + "blockMode": ["fakeReadout"], + "displayAdvancedSettings": [true] + } + }, + { + "name": "askOnlyOnce", + "displayDependencies": { + "blockMode": ["askReadout", "ask"] + } + }, + { + "name": "showNotifications", + "displayDependencies": { + "blockMode": ["fakeReadout", "fakeInput"] + } + }, + { + "name": "storeImageForInspection", + "displayDependencies": { + "blockMode": ["fakeReadout", "fakeInput"], + "showNotifications": [true], + "displayAdvancedSettings": [true] + } + }, + { + "name": "ignoreList", + "displayDependencies": { + "blockMode": ["fakeReadout", "fakeInput"], + "showNotifications": [true] + } + }, + { + "name": "showCallingFile", + "displayDependencies": { + "blockMode": ["askReadout", "ask"], + "displayAdvancedSettings": [true] + } + }, + { + "name": "showCompleteCallingStack", + "displayDependencies": [ + { + "blockMode": ["fakeReadout", "fakeInput"], + "showNotifications": [true], + "displayAdvancedSettings": [true] + }, + { + "blockMode": ["askReadout", "ask"], + "displayAdvancedSettings": [true] + } + ] + }, + { + "name": "enableStackList", + "displayDependencies": { + "blockMode": ["blockReadout", "fakeReadout", "fakeInput", "askReadout", "block", "ask"], + "displayAdvancedSettings": [true] + } + }, + { + "name": "stackList", + "displayDependencies": { + "enableStackList": [true], + "displayAdvancedSettings": [true] + } + + }, + { + "name": "showReleaseNotes" + }, + { + "name": "logLevel", + "displayDependencies": { + "displayAdvancedSettings": [true] + } + } + ]; + + if ((typeof module) !== "undefined"){ + module.exports = settingsDisplay; + } + else { + window.scope.settingsDisplay = settingsDisplay; + } +}()); \ No newline at end of file diff --git a/pageAction/pageAction.html b/pageAction/pageAction.html index 8c79ef5..193df77 100644 --- a/pageAction/pageAction.html +++ b/pageAction/pageAction.html @@ -10,9 +10,10 @@ - - + + + diff --git a/pageAction/pageAction.js b/pageAction/pageAction.js index 8340972..fc784b1 100644 --- a/pageAction/pageAction.js +++ b/pageAction/pageAction.js @@ -1,149 +1,143 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -Promise.all([ - browser.tabs.query({active: true, currentWindow: true}), - browser.storage.local.get().then(function(data){ - "use strict"; - Object.keys(data).forEach(function(key){ - settings[key] = data[key]; - }); - settings.isStillDefault = false; - require("./logging").clearQueue(); - return settings; - }) -]).then(function(values){ +(function(){ "use strict"; - const [tabs, settings] = values; - + + const settings = require("./settings"); + const lists = require("./lists"); + const {parseErrorStack} = require("./callingStack"); const {error, warning, message, notice, verbose, setPrefix: setLogPrefix} = require("./logging"); + setLogPrefix("page action script"); + const domainNotification = require("./domainNotification"); const Notification = require("./Notification"); const {createActionButtons, modalPrompt} = require("./gui"); - setLogPrefix("page action script"); - notice("create global action buttons"); + Promise.all([ + browser.tabs.query({active: true, currentWindow: true}), + settings.loaded + ]).then(function(values){ + const tabs = values[0]; + + notice("create global action buttons"); - createActionButtons( - document.getElementById("globalActions"), - [{ - name: "disableNotifications", - isIcon: true, - callback: function(){ - browser.storage.local.set({showNotifications: false}); - window.close(); - } - }], - undefined - ); - - if (!tabs.length){ - throw new Error("noTabsFound"); - } - else if (tabs.length > 1){ - error(tabs); - throw new Error("tooManyTabsFound"); - } - - const lists = require("./lists"); - lists.updateAll(); - const {parseErrorStack} = require("./callingStack"); - - verbose("registering domain actions"); - [ - { - name: "ignorelistDomain", - isIcon: true, - callback: function(domain){ - modalPrompt( - browser.i18n.getMessage("inputIgnoreDomain"), - domain - ).then(function(domain){ - if (domain){ - lists.appendTo("ignore", domain); - } + createActionButtons( + document.getElementById("globalActions"), + [{ + name: "disableNotifications", + isIcon: true, + callback: function(){ + settings.showNotifications = false; window.close(); + } + }], + undefined + ); + + if (!tabs.length){ + throw new Error("noTabsFound"); + } + else if (tabs.length > 1){ + error(tabs); + throw new Error("tooManyTabsFound"); + } + + + verbose("registering domain actions"); + [ + { + name: "ignorelistDomain", + isIcon: true, + callback: function(domain){ + modalPrompt( + browser.i18n.getMessage("inputIgnoreDomain"), + domain + ).then(function(domain){ + if (domain){ + lists.appendTo("ignore", domain); + } + window.close(); + }); + } + }, + { + name: "whitelistDomain", + isIcon: true, + callback: function(domain){ + modalPrompt( + browser.i18n.getMessage("inputWhitelistURL"), + domain + ).then(function(domain){ + if (domain){ + lists.appendTo("white", domain); + } + window.close(); + }); + } + } + ].forEach(function(domainAction){ + domainNotification.addAction(domainAction); + }); + + verbose("registering notification actions"); + [ + { + name: "displayFullURL", + isIcon: true, + callback: function({url}){ + alert(url.href); + } + }, + { + name: "displayCallingStack", + isIcon: true, + callback: function({errorStack}){ + alert(parseErrorStack(errorStack)); + } + }, + { + name: "whitelistURL", + isIcon: true, + callback: function({url}){ + modalPrompt( + browser.i18n.getMessage("inputWhitelistDomain"), + "^" + url.href.replace(/([\\+*?[^\]$(){}=!|.])/g, "\\$1") + "$" + ).then(function(url){ + if (url){ + lists.appendTo("white", url); + } + window.close(); + }); + } + } + ].forEach(function(action){ + Notification.addAction(action); + }); + + var tab = tabs[0]; + browser.runtime.onMessage.addListener(function(data){ + if (Array.isArray(data["canvasBlocker-notifications"])){ + message("got notifications"); + data["canvasBlocker-notifications"].forEach(function(notification){ + verbose(notification); + notification.url = new URL(notification.url); + domainNotification( + notification.url.hostname, + notification.messageId + ).addNotification(new Notification(notification)); }); } - }, - { - name: "whitelistDomain", - isIcon: true, - callback: function(domain){ - modalPrompt( - browser.i18n.getMessage("inputWhitelistURL"), - domain - ).then(function(domain){ - if (domain){ - lists.appendTo("white", domain); - } - window.close(); - }); + }); + message("request notifications from tab", tab.id); + browser.tabs.sendMessage( + tab.id, + { + "canvasBlocker-sendNotifications": tab.id } - } - ].forEach(function(domainAction){ - domainNotification.addAction(domainAction); + ); + notice("waiting for notifications"); + }).catch(function(e){ + error(e); }); - - verbose("registering notification actions"); - [ - { - name: "displayFullURL", - isIcon: true, - callback: function({url}){ - alert(url.href); - } - }, - { - name: "displayCallingStack", - isIcon: true, - callback: function({errorStack}){ - alert(parseErrorStack(errorStack)); - } - }, - { - name: "whitelistURL", - isIcon: true, - callback: function({url}){ - modalPrompt( - browser.i18n.getMessage("inputWhitelistDomain"), - "^" + url.href.replace(/([\\+*?[^\]$(){}=!|.])/g, "\\$1") + "$" - ).then(function(url){ - if (url){ - lists.appendTo("white", url); - } - window.close(); - }); - } - } - ].forEach(function(action){ - Notification.addAction(action); - }); - - var tab = tabs[0]; - browser.runtime.onMessage.addListener(function(data){ - if (Array.isArray(data["canvasBlocker-notifications"])){ - message("got notifications"); - data["canvasBlocker-notifications"].forEach(function(notification){ - verbose(notification); - notification.url = new URL(notification.url); - domainNotification( - notification.url.hostname, - notification.messageId - ).addNotification(new Notification(notification)); - }); - } - }); - message("request notifications from tab", tab.id); - browser.tabs.sendMessage( - tab.id, - { - "canvasBlocker-sendNotifications": tab.id - } - ); - notice("waiting for notifications"); -}).catch(function(e){ - "use strict"; - require("./logging").error(e); -}); \ No newline at end of file +}()); \ No newline at end of file diff --git a/releaseNotes.txt b/releaseNotes.txt index 3b94cb9..7dcfb9c 100644 --- a/releaseNotes.txt +++ b/releaseNotes.txt @@ -1,8 +1,4 @@ Version 0.4.1: - todos: - - get rid of the .innerHTML assigments - - better and saver settings system - changes: - improved design of the page action display -