mirror of
https://github.com/kkapsner/CanvasBlocker
synced 2025-05-19 19:02:21 +02:00
Added URL specific settings
For blockMode and showNotifications. Fixes #148.
This commit is contained in:
parent
78a0ccc243
commit
01780da9f5
@ -168,6 +168,28 @@
|
|||||||
"message": "Blockiermodus",
|
"message": "Blockiermodus",
|
||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"urlSettings_title": {
|
||||||
|
"message": "Seitenspezifische Einstellungen",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"urlSettings_description": {
|
||||||
|
"message": "",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
|
||||||
|
"url_title": {
|
||||||
|
"message": "URL",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"url_description": {
|
||||||
|
"message": "",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"inputURL": {
|
||||||
|
"message": "Input domain or URL RegExp:",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
|
||||||
"minFakeSize_description": {
|
"minFakeSize_description": {
|
||||||
"message": "Canvas, die eine kleiner oder gleich große Fläche als die hier angegebene Zahl haben, werden nicht vorgetäuscht. Dies ist ein Parameter, der die Detektion des Addons erschweren soll.\nACHTUNG: Dies verringert die Sicherheit des Addons. Deswegen wird stark empfohlen, diesen Wert nicht über 100 zu setzen.",
|
"message": "Canvas, die eine kleiner oder gleich große Fläche als die hier angegebene Zahl haben, werden nicht vorgetäuscht. Dies ist ein Parameter, der die Detektion des Addons erschweren soll.\nACHTUNG: Dies verringert die Sicherheit des Addons. Deswegen wird stark empfohlen, diesen Wert nicht über 100 zu setzen.",
|
||||||
|
@ -169,6 +169,28 @@
|
|||||||
"description": ""
|
"description": ""
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"urlSettings_title": {
|
||||||
|
"message": "Site specific settings",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"urlSettings_description": {
|
||||||
|
"message": "",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
|
||||||
|
"url_title": {
|
||||||
|
"message": "URL",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"url_description": {
|
||||||
|
"message": "",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"inputURL": {
|
||||||
|
"message": "Input domain or URL RegExp:",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
|
||||||
"minFakeSize_description": {
|
"minFakeSize_description": {
|
||||||
"message": "Canvas with a smaller or equal area than this number will not be faked. This is a parameter to prevent detection.\nCAUTION: This lowers the safety of the addon, therefore it is highly recommended not to set this value above 100.",
|
"message": "Canvas with a smaller or equal area than this number will not be faked. This is a parameter to prevent detection.\nCAUTION: This lowers the safety of the addon, therefore it is highly recommended not to set this value above 100.",
|
||||||
"description": ""
|
"description": ""
|
||||||
|
@ -19,7 +19,8 @@
|
|||||||
const logging = require("./logging");
|
const logging = require("./logging");
|
||||||
|
|
||||||
scope.check = function check({url, errorStack}){
|
scope.check = function check({url, errorStack}){
|
||||||
var match = checkBoth(errorStack, url, settings.blockMode).match(
|
url = new URL(url || "about:blank");
|
||||||
|
var match = checkBoth(errorStack, url, settings.get("blockMode", url)).match(
|
||||||
/^(block|allow|fake|ask)(|Readout|Everything|Context|Input|Internal)$/
|
/^(block|allow|fake|ask)(|Readout|Everything|Context|Input|Internal)$/
|
||||||
);
|
);
|
||||||
if (match){
|
if (match){
|
||||||
@ -50,7 +51,6 @@
|
|||||||
|
|
||||||
function checkURL(url, blockMode){
|
function checkURL(url, blockMode){
|
||||||
logging.message("check url %s for block mode %s", url, blockMode);
|
logging.message("check url %s for block mode %s", url, blockMode);
|
||||||
url = new URL(url || "about:blank");
|
|
||||||
switch (url.protocol){
|
switch (url.protocol){
|
||||||
case "about:":
|
case "about:":
|
||||||
if (url.href === "about:blank"){
|
if (url.href === "about:blank"){
|
||||||
|
@ -78,8 +78,8 @@
|
|||||||
port.postMessage({"canvasBlocker-notify": data});
|
port.postMessage({"canvasBlocker-notify": data});
|
||||||
}
|
}
|
||||||
|
|
||||||
function prefs(name){
|
function prefs(...args){
|
||||||
return settings[name];
|
return settings.get(...args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@
|
|||||||
port.onMessage.addListener(function(data){
|
port.onMessage.addListener(function(data){
|
||||||
if (data.hasOwnProperty("canvasBlocker-notify")){
|
if (data.hasOwnProperty("canvasBlocker-notify")){
|
||||||
if (
|
if (
|
||||||
settings.showNotifications &&
|
settings.get("showNotifications", url) &&
|
||||||
!lists.get("ignore").match(url)
|
!lists.get("ignore").match(url)
|
||||||
){
|
){
|
||||||
browser.pageAction.show(port.sender.tab.id);
|
browser.pageAction.show(port.sender.tab.id);
|
||||||
|
@ -10,6 +10,25 @@
|
|||||||
defaultValue: 1,
|
defaultValue: 1,
|
||||||
options: [0, 1, 25, 50, 75, 100]
|
options: [0, 1, 25, 50, 75, 100]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "urlSettings",
|
||||||
|
defaultValue: [],
|
||||||
|
urlContainer: true,
|
||||||
|
entries: [
|
||||||
|
{name: "url", defaultValue: ""}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "urls",
|
||||||
|
defaultValue: [],
|
||||||
|
dynamic: true,
|
||||||
|
dependencies: ["urlSettings"],
|
||||||
|
getter: function(settings){
|
||||||
|
return settings.urlSettings.map(function(urlSetting){
|
||||||
|
return urlSetting.url;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "whiteList",
|
name: "whiteList",
|
||||||
defaultValue: ""
|
defaultValue: ""
|
||||||
@ -21,6 +40,7 @@
|
|||||||
{
|
{
|
||||||
name: "blockMode",
|
name: "blockMode",
|
||||||
defaultValue: "fakeReadout",
|
defaultValue: "fakeReadout",
|
||||||
|
urlSpecific: true,
|
||||||
options: [
|
options: [
|
||||||
"blockReadout", "fakeReadout", "fakeInput", "askReadout", null,
|
"blockReadout", "fakeReadout", "fakeInput", "askReadout", null,
|
||||||
"blockEverything", "block", "ask", "allow", "allowEverything"
|
"blockEverything", "block", "ask", "allow", "allowEverything"
|
||||||
@ -84,7 +104,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "showNotifications",
|
name: "showNotifications",
|
||||||
defaultValue: true
|
defaultValue: true,
|
||||||
|
urlSpecific: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "storeImageForInspection",
|
name: "storeImageForInspection",
|
||||||
|
468
lib/settings.js
468
lib/settings.js
@ -31,64 +31,240 @@
|
|||||||
});
|
});
|
||||||
}());
|
}());
|
||||||
const settingDefinitions = require("./settingDefinitions.js");
|
const settingDefinitions = require("./settingDefinitions.js");
|
||||||
|
const definitionsByName = {};
|
||||||
|
const defaultSymbol = "";
|
||||||
|
|
||||||
const eventHandler = {any: []};
|
const eventHandler = {any: {}};
|
||||||
|
eventHandler.any[defaultSymbol] = [];
|
||||||
eventHandler.all = eventHandler.any;
|
eventHandler.all = eventHandler.any;
|
||||||
const settings = {};
|
const settings = {};
|
||||||
|
let urlContainer;
|
||||||
|
|
||||||
settingDefinitions.forEach(function(settingDefinition){
|
function isDefinitionInvalid(settingDefinition, newValue){
|
||||||
var name = settingDefinition.name;
|
if (newValue === undefined && settingDefinition.optional){
|
||||||
settings[name] = settingDefinition.defaultValue;
|
return false;
|
||||||
eventHandler[name] = [];
|
}
|
||||||
|
else if (settingDefinition.fixed){
|
||||||
settingDefinition.on = function on(callback){
|
return "fixed";
|
||||||
scope.on(name, callback);
|
}
|
||||||
};
|
else if ((typeof newValue) !== (typeof settingDefinition.defaultValue)){
|
||||||
settingDefinition.invalid = function invalid(newValue){
|
return "wrongType";
|
||||||
if (settingDefinition.fixed){
|
}
|
||||||
return "fixed";
|
else if (Array.isArray(settingDefinition.defaultValue)){
|
||||||
}
|
if (!Array.isArray(newValue)){
|
||||||
else if ((typeof newValue) !== (typeof settingDefinition.defaultValue)){
|
|
||||||
return "wrongType";
|
return "wrongType";
|
||||||
}
|
}
|
||||||
else if (
|
var entriesInvalid = newValue.reduce(function(v, entry){
|
||||||
settingDefinition.options &&
|
v = v || settingDefinition.entries.reduce(function(v, entryDefinition){
|
||||||
!settingDefinition.options.includes(newValue)
|
return v || isDefinitionInvalid(entryDefinition, entry[entryDefinition.name]);
|
||||||
){
|
}, false);
|
||||||
return "noOption";
|
if (!v){
|
||||||
|
if (Object.keys(entry).some(function(key){
|
||||||
|
return !settingDefinition.entries.some(function(entryDefinition){
|
||||||
|
return key === entryDefinition.name;
|
||||||
|
});
|
||||||
|
})){
|
||||||
|
return "noOption";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}, false);
|
||||||
|
if (entriesInvalid){
|
||||||
|
return entriesInvalid;
|
||||||
}
|
}
|
||||||
return false;
|
}
|
||||||
};
|
else if (
|
||||||
settingDefinition.get = function getValue(){
|
settingDefinition.options &&
|
||||||
return settings[name];
|
!settingDefinition.options.includes(newValue)
|
||||||
};
|
){
|
||||||
settingDefinition.set = function setValue(newValue){
|
return "noOption";
|
||||||
logging.verbose("New value for %s:", name, newValue);
|
}
|
||||||
var invalid = settingDefinition.invalid(newValue);
|
return false;
|
||||||
if (invalid){
|
}
|
||||||
if (invalid === "fixed"){
|
|
||||||
logging.warning("Trying to set the fixed setting", name, ":", newValue);
|
function createGetter(settingDefinition){
|
||||||
|
if (settingDefinition.dynamic){
|
||||||
|
return function getValue(){
|
||||||
|
return settingDefinition.getter(scope);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if (settingDefinition.urlSpecific){
|
||||||
|
return function getValue(url){
|
||||||
|
if (url){
|
||||||
|
var matching = urlContainer.get().filter(function(urlSetting){
|
||||||
|
return urlSetting.hasOwnProperty(settingDefinition.name);
|
||||||
|
}).filter(function(urlSetting){
|
||||||
|
return urlSetting.match(url);
|
||||||
|
});
|
||||||
|
if (matching.length){
|
||||||
|
return matching[0][settingDefinition.name];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (invalid === "wrongType"){
|
return settings[settingDefinition.name];
|
||||||
logging.warning("Wrong type provided for setting", name, ":", newValue);
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return function getValue(){
|
||||||
|
return settings[settingDefinition.name];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createSetter(settingDefinition){
|
||||||
|
if (settingDefinition.dynamic){
|
||||||
|
return function setValue(newValue){
|
||||||
|
settingDefinition.setter(scope);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const name = settingDefinition.name;
|
||||||
|
const isValid = function isValid(newValue){
|
||||||
|
var invalid = settingDefinition.invalid(newValue);
|
||||||
|
if (invalid){
|
||||||
|
if (invalid === "fixed"){
|
||||||
|
logging.warning("Trying to set the fixed setting", name, ":", newValue);
|
||||||
|
}
|
||||||
|
else if (invalid === "wrongType"){
|
||||||
|
logging.warning("Wrong type provided for setting", name, ":", newValue);
|
||||||
|
}
|
||||||
|
else if (invalid === "noOption"){
|
||||||
|
logging.warning("Provided value outside specified options for ", name, ":", newValue);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
logging.warning("Unknown invalid state:", invalid);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
else if (invalid === "noOption"){
|
return true;
|
||||||
logging.warning("Provided value outside specified options for ", name, ":", newValue);
|
};
|
||||||
}
|
const storeValue = function storeValue(newValue){
|
||||||
else {
|
|
||||||
logging.warning("Unknown invalid state:", invalid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
settings[name] = newValue;
|
settings[name] = newValue;
|
||||||
if (!settingDefinition.transient){
|
if (!settingDefinition.transient){
|
||||||
var storeObject = {};
|
var storeObject = {};
|
||||||
storeObject[name] = newValue;
|
storeObject[name] = newValue;
|
||||||
browser.storage.local.set(storeObject);
|
browser.storage.local.set(storeObject);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (settingDefinition.urlSpecific){
|
||||||
|
return function setValue(newValue, url){
|
||||||
|
logging.verbose("New value for %s:", name, newValue);
|
||||||
|
if (isValid(newValue)){
|
||||||
|
if (url){
|
||||||
|
var urlContainerValue = urlContainer.get();
|
||||||
|
var matching = urlContainerValue.filter(function(urlSetting){
|
||||||
|
return urlSetting.match(url);
|
||||||
|
});
|
||||||
|
if (!matching.length){
|
||||||
|
let newEntry = {url};
|
||||||
|
newEntry[settingDefinition.name] = newValue;
|
||||||
|
urlContainerValue.push(newEntry);
|
||||||
|
matching = [newEntry];
|
||||||
|
}
|
||||||
|
matching[0][settingDefinition.name] = newValue;
|
||||||
|
urlContainer.set(urlContainerValue);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
storeValue(newValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return function setValue(newValue){
|
||||||
|
logging.verbose("New value for %s:", name, newValue);
|
||||||
|
if (isValid(newValue)){
|
||||||
|
storeValue(newValue);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createResetter(settingDefinition){
|
||||||
|
if (settingDefinition.dynamic){
|
||||||
|
return function(){};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const name = settingDefinition.name;
|
||||||
|
let reset = function(){
|
||||||
|
settings[name] = settingDefinition.defaultValue;
|
||||||
|
browser.storage.local.remove(name);
|
||||||
|
};
|
||||||
|
if (settingDefinition.urlSpecific){
|
||||||
|
return function(url){
|
||||||
|
if (url){
|
||||||
|
var urlContainerValue = urlContainer.get();
|
||||||
|
var matching = urlContainerValue.filter(function(urlSetting){
|
||||||
|
return urlSetting.match(url);
|
||||||
|
});
|
||||||
|
if (matching.length){
|
||||||
|
delete matching[0][name];
|
||||||
|
if (Object.keys(matching[0]).every(function(key){return key === "url";})){
|
||||||
|
urlContainerValue = urlContainerValue.filter(function(urlSetting){
|
||||||
|
return urlSetting !== matching[0];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
urlContainer.set(urlContainerValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return reset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
settingDefinitions.forEach(function(settingDefinition){
|
||||||
|
if (settingDefinition.urlContainer){
|
||||||
|
urlContainer = settingDefinition;
|
||||||
|
settingDefinition.refresh = function(){
|
||||||
|
settingDefinition.set(settingDefinition.get());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var name = settingDefinition.name;
|
||||||
|
definitionsByName[name] = settingDefinition;
|
||||||
|
settings[name] = settingDefinition.defaultValue;
|
||||||
|
eventHandler[name] = {};
|
||||||
|
|
||||||
|
settingDefinition.on = function on(callback, url){
|
||||||
|
if (!settingDefinition.dynamic){
|
||||||
|
scope.on(name, callback, url);
|
||||||
|
}
|
||||||
|
if (settingDefinition.dependencies){
|
||||||
|
settingDefinition.dependencies.forEach(function(dependency){
|
||||||
|
scope.on(dependency, function(){
|
||||||
|
callback({name, newValue: settingDefinition.get()});
|
||||||
|
}, url);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
settingDefinition.invalid = function invalid(newValue){
|
||||||
|
return isDefinitionInvalid(settingDefinition, newValue);
|
||||||
|
};
|
||||||
|
settingDefinition.get = createGetter(settingDefinition);
|
||||||
|
|
||||||
|
settingDefinition.set = createSetter(settingDefinition);
|
||||||
|
|
||||||
|
settingDefinition.reset = createResetter(settingDefinition);
|
||||||
|
|
||||||
|
if (settingDefinition.urlSpecific){
|
||||||
|
if (!urlContainer){
|
||||||
|
logging.error("Unable to use url specific settings without url-container");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
settingDefinition.urlContainer = urlContainer;
|
||||||
|
let entry = Object.create(settingDefinition);
|
||||||
|
entry.optional = true;
|
||||||
|
urlContainer.entries.push(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Object.defineProperty(
|
Object.defineProperty(
|
||||||
scope,
|
scope,
|
||||||
name,
|
name,
|
||||||
@ -101,31 +277,57 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
scope.getDefinition = function(name){
|
scope.getDefinition = function(name){
|
||||||
var foundDefinitions = settingDefinitions.filter(function(settingDefinition){
|
var foundDefinition = definitionsByName[name];
|
||||||
return name === settingDefinition.name;
|
if (foundDefinition){
|
||||||
});
|
return Object.create(foundDefinition);
|
||||||
if (foundDefinitions.length){
|
|
||||||
return Object.create(foundDefinitions[0]);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
scope.set = function(name, ...args){
|
||||||
|
var foundDefinition = definitionsByName[name];
|
||||||
|
if (foundDefinition){
|
||||||
|
return foundDefinition.set(...args);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
logging.error("Try to set unkown setting:", name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
scope.get = function(name, ...args){
|
||||||
|
var foundDefinition = definitionsByName[name];
|
||||||
|
if (foundDefinition){
|
||||||
|
return foundDefinition.get(...args);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
logging.error("Try to get unkown setting:", name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
scope.forEach = function forEachSetting(...args){
|
scope.forEach = function forEachSetting(...args){
|
||||||
settingDefinitions.map(function(settingDefinition){
|
settingDefinitions.filter(function(settingDefinition){
|
||||||
|
return !settingDefinition.dynamic;
|
||||||
|
}).map(function(settingDefinition){
|
||||||
return Object.create(settingDefinition);
|
return Object.create(settingDefinition);
|
||||||
}).forEach(...args);
|
}).forEach(...args);
|
||||||
};
|
};
|
||||||
scope.on = function onSettingsChange(name, callback){
|
|
||||||
|
scope.on = function onSettingsChange(name, callback, url){
|
||||||
if (Array.isArray(name)){
|
if (Array.isArray(name)){
|
||||||
name.forEach(function(name){
|
name.forEach(function(name){
|
||||||
onSettingsChange(name, callback);
|
onSettingsChange(name, callback, url);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (eventHandler.hasOwnProperty(name)){
|
if (eventHandler.hasOwnProperty(name)){
|
||||||
eventHandler[name].push(callback);
|
if (!url){
|
||||||
|
url = defaultSymbol;
|
||||||
|
}
|
||||||
|
if (!eventHandler[name].hasOwnProperty(url)){
|
||||||
|
eventHandler[name][url] = [];
|
||||||
|
}
|
||||||
|
eventHandler[name][url].push(callback);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
logging.warning("Unable to register event handler for unknown setting", name);
|
logging.warning("Unable to register event handler for unknown setting", name);
|
||||||
@ -133,28 +335,136 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const resetSymbol = Symbol("reset");
|
||||||
function changeValue(name, newValue){
|
function changeValue(name, newValue){
|
||||||
|
var settingDefinition = scope.getDefinition(name);
|
||||||
var oldValue = settings[name];
|
var oldValue = settings[name];
|
||||||
|
if (newValue === resetSymbol){
|
||||||
|
newValue = settingDefinition.defaultValue;
|
||||||
|
}
|
||||||
settings[name] = newValue;
|
settings[name] = newValue;
|
||||||
(eventHandler[name] || []).forEach(function(callback){
|
((eventHandler[name] || {})[defaultSymbol] || []).forEach(function(callback){
|
||||||
callback({name, newValue, oldValue});
|
callback({name, newValue, oldValue});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (settingDefinition.urlSpecific){
|
||||||
|
urlContainer.get().forEach(function(entry){
|
||||||
|
if (!entry.hasOwnProperty(name)){
|
||||||
|
((eventHandler[name] || {})[entry.url] || []).forEach(function(callback){
|
||||||
|
callback({name, newValue, oldValue, url: entry.url});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logging.verbose("registering storage onchange listener");
|
logging.verbose("registering storage onchange listener");
|
||||||
browser.storage.onChanged.addListener(function(changes, area){
|
browser.storage.onChanged.addListener(function(changes, area){
|
||||||
if (area === "local"){
|
if (area === "local"){
|
||||||
logging.notice("settings changed", changes);
|
logging.notice("settings changed", changes);
|
||||||
|
var delayedChange = [];
|
||||||
Object.entries(changes).forEach(function(entry){
|
Object.entries(changes).forEach(function(entry){
|
||||||
const [name, change] = entry;
|
const [name, change] = entry;
|
||||||
changeValue(name, change.newValue);
|
if (urlContainer && name === urlContainer.name){
|
||||||
|
// changes in the url container have to trigger after the other changes
|
||||||
|
delayedChange.push(entry);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (change.hasOwnProperty("newValue")){
|
||||||
|
changeValue(name, change.newValue);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
changeValue(name, resetSymbol);
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
eventHandler.any.forEach(function(callback){
|
delayedChange.forEach(function(entry){
|
||||||
|
const [name, change] = entry;
|
||||||
|
if (change.hasOwnProperty("newValue")){
|
||||||
|
changeValue(name, change.newValue);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
changeValue(name, resetSymbol);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
eventHandler.any[""].forEach(function(callback){
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (urlContainer){
|
||||||
|
urlContainer.on(function({newValue, oldValue}){
|
||||||
|
newValue.forEach(function(urlSetting){
|
||||||
|
var regExp;
|
||||||
|
var domain = !!urlSetting.url.match(/^[\w.]+$/);
|
||||||
|
if (domain){
|
||||||
|
regExp = new RegExp(
|
||||||
|
"(?:^|\\.)" + urlSetting.url.replace(/([\\+*?[^\]$(){}=!|.])/g, "\\$1") + "\\.?$",
|
||||||
|
"i"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
regExp = new RegExp(urlSetting.url, "i");
|
||||||
|
}
|
||||||
|
const match = function(url){
|
||||||
|
if (!url){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (
|
||||||
|
url instanceof String ||
|
||||||
|
(typeof url) === "string"
|
||||||
|
){
|
||||||
|
return url === urlSetting.url;
|
||||||
|
}
|
||||||
|
else if (domain){
|
||||||
|
return (url.hostname || "").match(regExp);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return url.href.match(regExp);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Object.defineProperty(
|
||||||
|
urlSetting,
|
||||||
|
"match",
|
||||||
|
{
|
||||||
|
enumerable: false,
|
||||||
|
writable: true,
|
||||||
|
configurable: true,
|
||||||
|
value: match
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
var newUrls = newValue.map(function(entry){return entry.url;});
|
||||||
|
var oldUrls = oldValue.map(function(entry){return entry.url;});
|
||||||
|
var matching = {};
|
||||||
|
newUrls.forEach(function(url, i){
|
||||||
|
matching[url] = {new: i, old: oldUrls.indexOf(url)};
|
||||||
|
});
|
||||||
|
oldUrls.forEach(function(url, i){
|
||||||
|
if (!matching[url]){
|
||||||
|
matching[url] = {new: -1, old: i};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Object.keys(matching).forEach(function(url){
|
||||||
|
var oldEntry = oldValue[matching[url].old] || {};
|
||||||
|
var newEntry = newValue[matching[url].new] || {};
|
||||||
|
urlContainer.entries.forEach(function(settingDefinition){
|
||||||
|
var name = settingDefinition.name;
|
||||||
|
var oldValue = oldEntry[name];
|
||||||
|
var newValue = newEntry[name];
|
||||||
|
|
||||||
|
if (oldValue !== newValue){
|
||||||
|
((eventHandler[name] || {})[url] || []).forEach(function(callback){
|
||||||
|
callback({name, newValue, oldValue, url});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const settingsMigration = {
|
const settingsMigration = {
|
||||||
validVersions: [undefined, 0.1, 0.2],
|
validVersions: [undefined, 0.1, 0.2],
|
||||||
transitions: {
|
transitions: {
|
||||||
@ -170,6 +480,47 @@
|
|||||||
if (oldStorage.hasOwnProperty("askOnlyOnce")){
|
if (oldStorage.hasOwnProperty("askOnlyOnce")){
|
||||||
newStorage.askOnlyOnce = oldStorage.askOnlyOnce? "individual": "no";
|
newStorage.askOnlyOnce = oldStorage.askOnlyOnce? "individual": "no";
|
||||||
}
|
}
|
||||||
|
return newStorage;
|
||||||
|
},
|
||||||
|
0.2: function(oldStorage){
|
||||||
|
var newStorage = {
|
||||||
|
storageVersion: 0.3,
|
||||||
|
urlSettings: (
|
||||||
|
oldStorage.urlSettings &&
|
||||||
|
Array.isArray(oldStorage.urlSettings)
|
||||||
|
)? oldStorage.urlSettings: []
|
||||||
|
};
|
||||||
|
|
||||||
|
var urlSettings = {};
|
||||||
|
|
||||||
|
(oldStorage.blackList || "").split(",").forEach(function(url){
|
||||||
|
var entry = urlSettings[url];
|
||||||
|
if (!entry){
|
||||||
|
entry = {url, blockMode: "block"};
|
||||||
|
urlSettings[url] = entry;
|
||||||
|
newStorage.urlSettings.push(entry);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
(oldStorage.whiteList || "").split(",").forEach(function(url){
|
||||||
|
var entry = urlSettings[url];
|
||||||
|
if (!entry){
|
||||||
|
entry = {url, blockMode: "allow"};
|
||||||
|
urlSettings[url] = entry;
|
||||||
|
newStorage.urlSettings.push(entry);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
(oldStorage.ignoreList || "").split(",").forEach(function(url){
|
||||||
|
var entry = urlSettings[url];
|
||||||
|
if (!entry){
|
||||||
|
entry = {url, showNotifications: false};
|
||||||
|
urlSettings[url] = entry;
|
||||||
|
newStorage.urlSettings.push(entry);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
entry.showNotifications = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return newStorage;
|
return newStorage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -210,7 +561,18 @@
|
|||||||
logging.notice("Changed settings:", toChange);
|
logging.notice("Changed settings:", toChange);
|
||||||
browser.storage.local.set(toChange);
|
browser.storage.local.set(toChange);
|
||||||
}
|
}
|
||||||
|
var delayedChange = [];
|
||||||
Object.entries(storage).forEach(function(entry){
|
Object.entries(storage).forEach(function(entry){
|
||||||
|
const [name, value] = entry;
|
||||||
|
if (urlContainer && name === urlContainer.name){
|
||||||
|
// changes in the url container have to trigger after the other changes
|
||||||
|
delayedChange.push(entry);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
changeValue(name, value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
delayedChange.forEach(function(entry){
|
||||||
const [name, value] = entry;
|
const [name, value] = entry;
|
||||||
changeValue(name, value);
|
changeValue(name, value);
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
.settings {
|
.settings {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-spacing: 0;
|
border-spacing: 0;
|
||||||
|
border-collapse: collapse;
|
||||||
}
|
}
|
||||||
.settings.displayDescriptions {
|
.settings.displayDescriptions {
|
||||||
table-layout: fixed;
|
table-layout: fixed;
|
||||||
@ -70,4 +71,45 @@ input[type=""], input[type="text"], input[type="number"], select {
|
|||||||
}
|
}
|
||||||
*.multiple4 {
|
*.multiple4 {
|
||||||
width: 25% !important;
|
width: 25% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.urlValues {
|
||||||
|
padding-right: 1em;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.urlValues.collapsed table {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.urlValues.expanded table {
|
||||||
|
display: block;
|
||||||
|
margin: 0.5em auto;
|
||||||
|
}
|
||||||
|
.urlValues table caption {
|
||||||
|
text-align: center;
|
||||||
|
font-weight: bold;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.urlValues table td {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
.urlValues table .reset, .urlValues table .add, .urlValues table .url {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.urlValues .collapser {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
text-align: center;
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.urlValues.collapsed .collapser::after {
|
||||||
|
content: "\25B6";
|
||||||
|
}
|
||||||
|
.urlValues.expanded .collapser::after {
|
||||||
|
content: "\25BC";
|
||||||
|
}
|
||||||
|
.urlValues .notSpecifiedForUrl {
|
||||||
|
opacity: 0.5;
|
||||||
}
|
}
|
@ -66,12 +66,11 @@
|
|||||||
input.value = value;
|
input.value = value;
|
||||||
return input;
|
return input;
|
||||||
},
|
},
|
||||||
updateCallback: function(input, setting){
|
updateCallback: function(input, value){
|
||||||
input.value = setting.get();
|
input.value = value;
|
||||||
return input.value;
|
return input.value;
|
||||||
},
|
},
|
||||||
changeCallback: function(input, setting){
|
getValue: function(input){
|
||||||
setting.set(parseFloat(input.value));
|
|
||||||
return parseFloat(input.value);
|
return parseFloat(input.value);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -81,12 +80,11 @@
|
|||||||
input.value = value;
|
input.value = value;
|
||||||
return input;
|
return input;
|
||||||
},
|
},
|
||||||
updateCallback: function(input, setting){
|
updateCallback: function(input, value){
|
||||||
input.value = setting.get();
|
input.value = value;
|
||||||
return input.value;
|
return input.value;
|
||||||
},
|
},
|
||||||
changeCallback: function(input, setting){
|
getValue: function(input){
|
||||||
setting.set(input.value);
|
|
||||||
return input.value;
|
return input.value;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -97,38 +95,110 @@
|
|||||||
input.style.display = "inline";
|
input.style.display = "inline";
|
||||||
return input;
|
return input;
|
||||||
},
|
},
|
||||||
updateCallback: function(input, setting){
|
updateCallback: function(input, value){
|
||||||
input.checked = setting.get();
|
input.checked = value;
|
||||||
return input.checked;
|
return input.checked;
|
||||||
},
|
},
|
||||||
changeCallback: function(input, setting){
|
getValue: function(input){
|
||||||
setting.set(input.checked);
|
|
||||||
return input.checked;
|
return input.checked;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
object: false
|
||||||
};
|
};
|
||||||
|
|
||||||
function createInput(setting){
|
function createInput(setting, url = ""){
|
||||||
var type = inputTypes[typeof setting.defaultValue];
|
var type = inputTypes[typeof setting.defaultValue];
|
||||||
var input;
|
var input;
|
||||||
if (setting.options){
|
if (setting.options){
|
||||||
input = createSelect(setting);
|
input = createSelect(setting);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
input = document.createElement("input");
|
|
||||||
if (type){
|
if (type){
|
||||||
|
input = document.createElement("input");
|
||||||
type.input(input, setting.defaultValue);
|
type.input(input, setting.defaultValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (type){
|
if (type){
|
||||||
setting.on(function(){type.updateCallback(input, setting);});
|
setting.on(function(){type.updateCallback(input, setting.get(url));}, url);
|
||||||
input.addEventListener("change", function(){
|
input.addEventListener("change", function(){
|
||||||
var value = type.changeCallback(input, setting);
|
var value = type.getValue(input);
|
||||||
|
setting.set(value, url);
|
||||||
logging.message("changed setting", setting.name, ":", value);
|
logging.message("changed setting", setting.name, ":", value);
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return input;
|
if (setting.urlSpecific && url === ""){
|
||||||
|
let container = document.createElement("div");
|
||||||
|
container.className = "urlValues collapsed";
|
||||||
|
container.appendChild(input);
|
||||||
|
var collapser = document.createElement("span");
|
||||||
|
collapser.classList.add("collapser");
|
||||||
|
container.appendChild(collapser);
|
||||||
|
collapser.addEventListener("click", function(){
|
||||||
|
container.classList.toggle("collapsed");
|
||||||
|
container.classList.toggle("expanded");
|
||||||
|
});
|
||||||
|
let urlTable = document.createElement("table");
|
||||||
|
let caption = document.createElement("caption");
|
||||||
|
caption.textContent = browser.i18n.getMessage(setting.urlContainer.name + "_title");
|
||||||
|
urlTable.appendChild(caption);
|
||||||
|
let body = document.createElement("tbody");
|
||||||
|
urlTable.appendChild(body);
|
||||||
|
let foot = document.createElement("tfoot");
|
||||||
|
let footRow = document.createElement("tr");
|
||||||
|
let footCell = document.createElement("td");
|
||||||
|
footCell.colSpan = 3;
|
||||||
|
let footPlus = document.createElement("span");
|
||||||
|
footPlus.classList.add("add");
|
||||||
|
footPlus.textContent = "+";
|
||||||
|
footPlus.addEventListener("click", function(){
|
||||||
|
var url = prompt(browser.i18n.getMessage("inputURL")).trim();
|
||||||
|
if (url){
|
||||||
|
setting.set(setting.get(url), url);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
footCell.appendChild(footPlus);
|
||||||
|
footRow.appendChild(footCell);
|
||||||
|
foot.appendChild(footRow);
|
||||||
|
urlTable.appendChild(foot);
|
||||||
|
container.appendChild(urlTable);
|
||||||
|
|
||||||
|
setting.urlContainer.on(function({newValue}){
|
||||||
|
body.innerHTML = "";
|
||||||
|
newValue.forEach(function(entry){
|
||||||
|
let row = document.createElement("tr");
|
||||||
|
let urlCell = document.createElement("td");
|
||||||
|
urlCell.classList.add("url");
|
||||||
|
urlCell.addEventListener("click", function(){
|
||||||
|
var url = prompt(browser.i18n.getMessage("inputURL"), entry.url).trim();
|
||||||
|
if (url){
|
||||||
|
entry.url = url;
|
||||||
|
setting.urlContainer.refresh();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
urlCell.textContent = entry.url;
|
||||||
|
row.appendChild(urlCell);
|
||||||
|
let input = createInput(setting, entry.url);
|
||||||
|
type.updateCallback(input, setting.get(entry.url));
|
||||||
|
if (!entry.hasOwnProperty(setting.name)){
|
||||||
|
input.classList.add("notSpecifiedForUrl");
|
||||||
|
}
|
||||||
|
let inputCell = document.createElement("td");
|
||||||
|
inputCell.appendChild(input);
|
||||||
|
row.appendChild(inputCell);
|
||||||
|
let clearCell = document.createElement("td");
|
||||||
|
clearCell.className = "reset";
|
||||||
|
clearCell.textContent = "\xD7";
|
||||||
|
clearCell.addEventListener("click", function(){
|
||||||
|
setting.reset(entry.url);
|
||||||
|
});
|
||||||
|
row.appendChild(clearCell);
|
||||||
|
body.appendChild(row);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
return input || document.createElement("span");
|
||||||
}
|
}
|
||||||
|
|
||||||
function createButton(setting){
|
function createButton(setting){
|
||||||
@ -158,7 +228,7 @@
|
|||||||
interaction = createInput(setting);
|
interaction = createInput(setting);
|
||||||
}
|
}
|
||||||
|
|
||||||
interaction.className = "setting";
|
interaction.classList.add("setting");
|
||||||
interaction.dataset.storageName = setting.name;
|
interaction.dataset.storageName = setting.name;
|
||||||
interaction.dataset.storageType = typeof setting.defaultValue;
|
interaction.dataset.storageType = typeof setting.defaultValue;
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ Version 0.4.3:
|
|||||||
new features:
|
new features:
|
||||||
- reset settings
|
- reset settings
|
||||||
- new white random generator - creates output similar to Tor browser
|
- new white random generator - creates output similar to Tor browser
|
||||||
|
- blockMode and showNotifications can now be chosen url specific
|
||||||
|
|
||||||
fixes:
|
fixes:
|
||||||
- page action was not always showing
|
- page action was not always showing
|
||||||
|
Loading…
x
Reference in New Issue
Block a user