aboutsummaryrefslogtreecommitdiffstats
path: root/js
diff options
context:
space:
mode:
Diffstat (limited to 'js')
-rw-r--r--js/about.js2
-rw-r--r--js/asset-viewer.js8
-rw-r--r--js/assets.js1744
-rw-r--r--js/background.js170
-rw-r--r--js/browsercache.js34
-rw-r--r--js/cloud-ui.js132
-rw-r--r--js/contentscript-start.js20
-rw-r--r--js/contentscript.js558
-rw-r--r--js/cookies.js374
-rw-r--r--js/dashboard-common.js8
-rw-r--r--js/dashboard.js6
-rw-r--r--js/hosts-files.js340
-rw-r--r--js/httpsb.js4
-rw-r--r--js/i18n.js208
-rw-r--r--js/liquid-dict.js314
-rw-r--r--js/logger-ui.js798
-rw-r--r--js/logger.js10
-rw-r--r--js/main-blocked.js2
-rw-r--r--js/matrix.js1394
-rw-r--r--js/messaging.js24
-rw-r--r--js/pagestats.js186
-rw-r--r--js/polyfill.js4
-rw-r--r--js/popup.js1572
-rw-r--r--js/profiler.js4
-rw-r--r--js/raw-settings.js144
-rw-r--r--js/settings.js124
-rw-r--r--js/start.js70
-rw-r--r--js/storage.js14
-rw-r--r--js/tab.js562
-rw-r--r--js/traffic.js4
-rw-r--r--js/udom.js7
-rw-r--r--js/uritools.js886
-rw-r--r--js/user-rules.js308
-rw-r--r--js/usersettings.js4
-rw-r--r--js/utils.js4
-rw-r--r--js/vapi-background.js1241
-rw-r--r--js/vapi-browser.js244
-rw-r--r--js/vapi-client.js170
-rw-r--r--js/vapi-cloud.js110
-rw-r--r--js/vapi-common.js142
-rw-r--r--js/vapi-contextmenu.js182
-rw-r--r--js/vapi-cookies.js96
-rw-r--r--js/vapi-core.js114
-rw-r--r--js/vapi-messaging.js132
-rw-r--r--js/vapi-net.js50
-rw-r--r--js/vapi-popup.js4
-rw-r--r--js/vapi-storage.js260
-rw-r--r--js/vapi-tabs.js666
-rw-r--r--js/vapi-window.js170
-rw-r--r--js/xal.js60
50 files changed, 6725 insertions, 6959 deletions
diff --git a/js/about.js b/js/about.js
index a35b45c..9ada80e 100644
--- a/js/about.js
+++ b/js/about.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/js/asset-viewer.js b/js/asset-viewer.js
index 8998892..12f0e3b 100644
--- a/js/asset-viewer.js
+++ b/js/asset-viewer.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -36,7 +36,7 @@
}
vAPI.messaging.send('asset-viewer.js', {
- what : 'getAssetContent',
- url: matches[1]
+ what : 'getAssetContent',
+ url: matches[1]
}, onAssetContentReceived);
})();
diff --git a/js/assets.js b/js/assets.js
index 286cf0d..9bb2470 100644
--- a/js/assets.js
+++ b/js/assets.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2013-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,14 +17,12 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
'use strict';
-/******************************************************************************/
-
ηMatrix.assets = (function() {
let api = {};
@@ -33,21 +31,21 @@
let connectionError = vAPI.i18n('errorCantConnectTo');
let notifyObservers = function (topic, details) {
- let result;
+ let result;
- for (let i=0; i<observers.length; ++i) {
- result = observers[i](topic, details);
- }
+ for (let i=0; i<observers.length; ++i) {
+ result = observers[i](topic, details);
+ }
- return result;
+ return result;
}
function isEmptyString(s) {
- return (typeof s === 'string' && s === '');
+ return (typeof s === 'string' && s === '');
}
function noOp() {
- return;
+ return;
}
// Cache Registry
@@ -57,308 +55,257 @@
let cacheRegistryStart = Date.now();
let saveCacheRegistry = (function () {
- let timer;
-
- function save() {
- timer = undefined;
- vAPI.cacheStorage.set({
- assetCacheRegistry: cacheRegistry,
- });
- }
-
- return function (lazy) {
- if (timer !== undefined) {
- clearTimeout(timer);
- }
-
- if (lazy === true) {
- timer = vAPI.setTimeout(save, 500);
- } else {
- save();
- }
- };
+ let timer;
+
+ let save = function () {
+ timer = undefined;
+ vAPI.cacheStorage.set({
+ assetCacheRegistry: cacheRegistry,
+ });
+ }
+
+ return function (lazy) {
+ if (timer !== undefined) {
+ clearTimeout(timer);
+ }
+
+ if (lazy === true) {
+ timer = vAPI.setTimeout(save, 500);
+ } else {
+ save();
+ }
+ };
})();
let getCacheRegistry = function (callback) {
- if (cacheRegistryReady == true) {
- callback(cacheRegistry);
- return;
- }
-
- if (cacheRegistryCallbacks !== undefined) {
- // If it's not undefined it's always an array
- //
- // eMatrix: this block in particular is probably never
- // called: originally, it was used because uMatrix called
- // some code in a callback that could wait
- //
- // While waiting, more elements could've been pushed in
- // the array
- //
- // Since the waiting callback is not used here, any
- // further callback are likely to be handled by the
- // condition above
- // This block is left here just in case
- cacheRegistryCallbacks.push(callback);
- return;
- }
-
- cacheRegistryCallbacks = [callback];
- cacheRegistryReady = true;
-
- let onRead = function (bin) {
- if (!bin || !bin['assetCacheRegistry']) {
- cacheRegistry = {};
- } else {
- cacheRegistry = bin['assetCacheRegistry'];
- }
- };
-
- vAPI.cacheStorage.get('assetCacheRegistry', onRead);
-
- let f;
- while ((f = cacheRegistryCallbacks.shift())) {
- f(cacheRegistry);
- }
+ if (cacheRegistryReady == true) {
+ callback(cacheRegistry);
+ return;
+ }
+
+ if (cacheRegistryCallbacks !== undefined) {
+ // If it's not undefined it's always an array
+ //
+ // eMatrix: this block in particular is probably never
+ // called: originally, it was used because uMatrix called
+ // some code in a callback that could wait
+ //
+ // While waiting, more elements could've been pushed in
+ // the array
+ //
+ // Since the waiting callback is not used here, any
+ // further callback are likely to be handled by the
+ // condition above
+ // This block is left here just in case
+ cacheRegistryCallbacks.push(callback);
+ return;
+ }
+
+ cacheRegistryCallbacks = [callback];
+
+ let onRead = function (bin) {
+ if (!bin || !bin['assetCacheRegistry']) {
+ cacheRegistry = {};
+ } else {
+ cacheRegistry = bin['assetCacheRegistry'];
+ }
+
+ cacheRegistryReady = true;
+
+ let f;
+ while ((f = cacheRegistryCallbacks.shift())) {
+ f(cacheRegistry);
+ }
+ };
+
+ vAPI.cacheStorage.get('assetCacheRegistry', onRead);
};
let readCache = function (key, callback) {
- let report = function (content, error) {
- let details = {
- assetKey: key,
- content: content,
- };
-
- if (error) {
- details.error = error;
- }
-
- callback(details);
- };
-
- let onRead = function (bin) {
- if (!bin || !bin[key]) {
- report('', 'E_NOTFOUND');
- return;
- }
-
- let entry = cacheRegistry[key];
- if (entry === undefined) {
- let onRead2 = function (bin) {
- if (!bin || !bin['assetCacheRegistry']) {
- cacheRegistry = {};
- } else {
- cacheRegistry = bin['assetCacheRegistry'];
- }
- };
-
- vAPI.cacheStorage.get('assetCacheRegistry', onRead2);
-
- entry = cacheRegistry[key];
- if (entry === undefined) {
- report('', 'E_NOTFOUND');
- return;
- }
- }
-
- entry.readTime = Date.now();
- saveCacheRegistry(true);
-
- report(bin[key]);
- };
-
- let onReady = function () {
- vAPI.cacheStorage.get(key, onRead);
- };
-
- getCacheRegistry(onReady);
- };
-
- let writeCache = function (key, details, callback) {
- let content = '';
-
- if (typeof details === 'string') {
- content = details;
- } else if (details instanceof Object) {
- content = details.content || '';
- }
-
- if (content === '') {
- removeCache(key, callback);
- return;
- }
-
- let report = function (content) {
- let details = {
- assetKey: key,
- content: content,
- };
-
- if (typeof callback === 'function') {
- callback(details);
- }
-
- notifyObservers('after-asset-updated', details);
- };
-
- let onReady = function () {
- let entry = cacheRegistry[key];
- if (entry === undefined) {
- entry = cacheRegistry[key] = {};
- }
-
- entry.writeTime = entry.readTime = Date.now();
- if (details instanceof Object && typeof details.url === 'string') {
- entry.remoteURL = details.url;
- }
-
- let bin = {
- assetCacheRegistry: cacheRegistry,
- };
-
- bin[key] = content;
- vAPI.cacheStorage.set(bin);
- report(content);
- };
-
- getCacheRegistry(onReady);
- };
-
- let cacheRemove = function (pattern, callback) {
- let onReady = function (cache) {
- let entries = [];
+ let fullkey = 'cache/' + key;
+ let cache = { placeholder: true };
- for (let key in cache) {
- if (pattern instanceof RegExp && !pattern.test(key)) {
- continue;
- }
+ let report = function (content, error) {
+ let details = {
+ assetKey: key,
+ content: content,
+ };
- if (typeof pattern === 'string' && key !== pattern) {
- continue;
- }
+ if (error) {
+ details.error = error;
+ }
- entries.push(key);
+ return callback(details);
+ };
- delete cache[key];
- }
+ let onRead = function (bin) {
+ if (!bin || !bin[fullkey]) {
+ return report('', 'E_NOTFOUND');
+ }
- if (entries.length !== 0) {
- vAPI.cacheStorage.remove(content);
+ let entry = cache[key];
+ if (entry === undefined) {
+ return report('', 'E_NOTFOUND');
+ }
- let bin = {
- assetCacheRegistry: cache,
- };
- vAPI.cacheStorage.set(bin);
- }
+ entry.readTime = Date.now();
+ saveCacheRegistry(true);
- if (typeof callback === 'function') {
- callback();
- }
+ report(bin[fullkey]);
+ };
- for (let i=0; i<entries.length; ++i) {
- notifyObservers('after-asset-updated', {
- assetKey: entries[i],
- });
- }
- };
+ let onReady = function (registry) {
+ cache = registry;
+ vAPI.cacheStorage.get(fullkey, onRead);
+ };
- getCacheRegistry(onReady);
+ getCacheRegistry(onReady);
};
- let markDirtyCache = function (pattern, exclude, callback) {
- let onReady = function (registry) {
- let entry;
- let mustSave = false;
-
- for (let key in registry) {
- if (pattern instanceof RegExp && pattern.test(key) === false) {
- continue;
- } else if (typeof pattern === 'string' && key !== pattern) {
- continue;
- } else if (Array.isArray(pattern)
- && pattern.indexOf(key) === -1) {
- continue;
- }
-
- if (exclude instanceof RegExp && exclude.test(key)) {
- continue;
- } else if (typeof exclude === 'string' && key === exclude) {
- continue;
- } else if (Array.isArray(exclude)
- && exclude.indexOf(key) !== -1) {
- continue;
- }
-
- entry = registry[key];
- if (!entry.writeTime) {
- continue;
- }
-
- registry[key].writeTime = 0;
- mustSave = true;
- }
-
- if (mustSave) {
- let bin = {
- assetCacheRegistry: registry,
- };
- vAPI.cacheStorage.set(bin);
- }
-
- if (typeof callback === 'function') {
- callback();
- }
- };
-
- if (typeof exclude === 'function') {
- callback = exclude;
- exclude = undefined;
- }
-
- getCacheRegistry(onReady);
+ let writeCache = function (key, details, callback) {
+ let fullkey = 'cache/' + key;
+ let content = '';
+
+ if (typeof details === 'string') {
+ content = details;
+ } else if (details instanceof Object) {
+ content = details.content || '';
+ }
+
+ if (content === '') {
+ return removeCache(key, callback);
+ }
+
+ let report = function (content) {
+ let details = {
+ assetKey: key,
+ content: content,
+ };
+
+ if (typeof callback === 'function') {
+ callback(details);
+ }
+
+ notifyObservers('after-asset-updated', details);
+ };
+
+ let onReady = function (registry) {
+ let entry = registry[key];
+ if (entry === undefined) {
+ entry = registry[key] = {};
+ }
+
+ entry.writeTime = entry.readTime = Date.now();
+ if (details instanceof Object && typeof details.url === 'string') {
+ entry.remoteURL = details.url;
+ }
+
+ let bin = {
+ assetCacheRegistry: cacheRegistry,
+ };
+
+ bin[fullkey] = content;
+ vAPI.cacheStorage.set(bin);
+ report(content);
+ };
+
+ getCacheRegistry(onReady);
};
- let removeCache = function (key, callback) {
- let onReady = function (cacheRegistry) {
- let removedEntries = [];
- let removedContent = [];
+ let removeCache = function (pattern, callback) {
+ let onReady = function (cache) {
+ let entries = [];
+ let contents = [];
+
+ for (let key in cache) {
+ if (pattern instanceof RegExp && !pattern.test(key)) {
+ continue;
+ }
- for (let k in cacheRegistry) {
- if (key instanceof RegExp && !key.test(k)) {
- continue;
- }
- if (typeof key === 'string' && k !== key) {
- continue;
- }
+ if (typeof pattern === 'string' && key !== pattern) {
+ continue;
+ }
- removedEntries.push(k);
- removedContent.push(k);
+ entries.push(key);
+ contents.push('cache/' + key);
- delete cacheRegistry[k];
- }
+ delete cache[key];
+ }
- if (removedContent.length > 0) {
- vAPI.cacheStorage.remove(removedContent);
+ if (contents.length !== 0) {
+ vAPI.cacheStorage.remove(contents);
- let bin = {
- assetCacheRegistry: cacheRegistry,
- };
+ let bin = {
+ assetCacheRegistry: cache,
+ };
+ vAPI.cacheStorage.set(bin);
+ }
- vAPI.cacheStorage.set(bin);
- }
+ if (typeof callback === 'function') {
+ callback();
+ }
- if (typeof callback === 'function') {
- callback();
- }
+ for (let i=0; i<entries.length; ++i) {
+ notifyObservers('after-asset-updated', {
+ assetKey: entries[i],
+ });
+ }
+ };
- for (let i=0; i<removedEntries.length; ++i) {
- notifyObservers('after-asset-updated', {
- assetKey: removedEntries[i],
- });
- }
- };
+ getCacheRegistry(onReady);
+ };
- getCacheRegistry(onReady);
+ let markDirtyCache = function (pattern, exclude, callback) {
+ let onReady = function (registry) {
+ let entry;
+ let mustSave = false;
+
+ for (let key in registry) {
+ if (pattern instanceof RegExp && pattern.test(key) === false) {
+ continue;
+ } else if (typeof pattern === 'string' && key !== pattern) {
+ continue;
+ } else if (Array.isArray(pattern)
+ && pattern.indexOf(key) === -1) {
+ continue;
+ }
+
+ if (exclude instanceof RegExp && exclude.test(key)) {
+ continue;
+ } else if (typeof exclude === 'string' && key === exclude) {
+ continue;
+ } else if (Array.isArray(exclude)
+ && exclude.indexOf(key) !== -1) {
+ continue;
+ }
+
+ entry = registry[key];
+ if (!entry.writeTime) {
+ continue;
+ }
+
+ registry[key].writeTime = 0;
+ mustSave = true;
+ }
+
+ if (mustSave) {
+ let bin = {
+ assetCacheRegistry: registry,
+ };
+ vAPI.cacheStorage.set(bin);
+ }
+
+ if (typeof callback === 'function') {
+ callback();
+ }
+ };
+
+ if (typeof exclude === 'function') {
+ callback = exclude;
+ exclude = undefined;
+ }
+
+ getCacheRegistry(onReady);
};
// Source Registry
@@ -367,248 +314,252 @@
let sourceRegistryCallbacks = undefined;
let saveSourceRegistry = (function () {
- let timer;
-
- function save() {
- timer = undefined;
- vAPI.cacheStorage.set({
- assetSourceRegistry: sourceRegistry,
- });
- }
-
- return function (lazy) {
- if (timer !== undefined) {
- clearTimeout(timer);
- }
-
- if (lazy === true) {
- timer = vAPI.setTimeout(save, 500);
- } else {
- save();
- }
- };
+ let timer;
+
+ let save = function () {
+ timer = undefined;
+ vAPI.cacheStorage.set({
+ assetSourceRegistry: sourceRegistry,
+ });
+ }
+
+ return function (lazy) {
+ if (timer !== undefined) {
+ clearTimeout(timer);
+ }
+
+ if (lazy === true) {
+ timer = vAPI.setTimeout(save, 500);
+ } else {
+ save();
+ }
+ };
})();
let registerSource = function (key, details) {
- let entry = sourceRegistry[key] || {};
-
- for (let p in details) {
- if (details.hasOwnProperty(p) === false) {
- continue;
- }
-
- if (details[p] !== undefined) {
- entry[p] = details[p];
- } else {
- delete entry[p];
- }
- }
-
- let contentUrl = details.contentURL;
- if (contentUrl) {
- if (typeof contentUrl === 'string') {
- contentUrl = entry.contentURL = [contentUrl];
- } else if (Array.isArray(contentUrl) === false) {
- contentUrl = entry.contentURL = [];
- }
-
- let remoteCount = 0;
-
- for (let i=0; i<contentUrl.length; ++i) {
- if (externalPathRegex.test(contentUrl[i])) {
- ++remoteCount;
- }
- }
-
- entry.hasLocalURL = (remoteCount !== contentUrl.length);
- entry.hasRemoteURL = (remoteCount !== 0);
- } else {
- entry.contentURL = [];
- }
-
- if (typeof entry.updateAfter !== 'number') {
- entry.updateAfter = 13;
- }
-
- if (entry.submitter) {
- entry.submitTime = Date.now(); // Detects stale entries
- }
-
- sourceRegistry[key] = entry;
+ let entry = sourceRegistry[key] || {};
+
+ for (let p in details) {
+ if (details.hasOwnProperty(p) === false) {
+ continue;
+ }
+
+ if (details[p] !== undefined) {
+ entry[p] = details[p];
+ } else {
+ delete entry[p];
+ }
+ }
+
+ let contentUrl = details.contentURL;
+ if (contentUrl) {
+ if (typeof contentUrl === 'string') {
+ contentUrl = entry.contentURL = [contentUrl];
+ } else if (Array.isArray(contentUrl) === false) {
+ contentUrl = entry.contentURL = [];
+ }
+
+ let remoteCount = 0;
+
+ for (let i=0; i<contentUrl.length; ++i) {
+ if (externalPathRegex.test(contentUrl[i])) {
+ ++remoteCount;
+ }
+ }
+
+ entry.hasLocalURL = (remoteCount !== contentUrl.length);
+ entry.hasRemoteURL = (remoteCount !== 0);
+ } else {
+ entry.contentURL = [];
+ }
+
+ if (typeof entry.updateAfter !== 'number') {
+ entry.updateAfter = 13;
+ }
+
+ if (entry.submitter) {
+ entry.submitTime = Date.now(); // Detects stale entries
+ }
+
+ sourceRegistry[key] = entry;
};
let unregisterSource = function (key) {
- removeCache(key);
- delete sourceRegistry[key];
- saveSourceRegistry();
+ removeCache(key);
+ delete sourceRegistry[key];
+ saveSourceRegistry();
};
let updateSourceRegistry = function (string, silent) {
- let json;
-
- try {
- json = JSON.parse(string);
- } catch (e) {
- return;
- }
-
- for (let key in sourceRegistry) {
- if (json[key] === undefined
- && sourceRegistry[key].submitter === undefined) {
- unregisterSource(key);
- }
- }
-
- for (let key in json) {
- if (sourceRegistry[key] === undefined && !silent) {
- notifyObservers('builtin-asset-source-added', {
- assetKey: key,
- entry: json[key],
- });
- }
-
- registerSource(key, json[key]);
- }
-
- saveSourceRegistry();
+ let json;
+
+ try {
+ json = JSON.parse(string);
+ } catch (e) {
+ return;
+ }
+
+ if (json instanceof Object === false) {
+ return;
+ }
+
+ for (let key in sourceRegistry) {
+ if (json[key] === undefined
+ && sourceRegistry[key].submitter === undefined) {
+ unregisterSource(key);
+ }
+ }
+
+ for (let key in json) {
+ if (sourceRegistry[key] === undefined && !silent) {
+ notifyObservers('builtin-asset-source-added', {
+ assetKey: key,
+ entry: json[key],
+ });
+ }
+
+ registerSource(key, json[key]);
+ }
+
+ saveSourceRegistry();
};
let getSourceRegistry = function (callback) {
- if (sourceRegistryReady === true) {
- callback(sourceRegistry);
- return;
- }
-
- if (sourceRegistryCallbacks !== undefined) {
- // If it's not undefined it's always an array
- sourceRegistryCallbacks.push(callback);
- return;
- }
-
- sourceRegistryCallbacks = [callback];
-
- let onReady = function () {
- sourceRegistryReady = true;
-
- let f;
- while ((f = sourceRegistryCallbacks.shift())) {
- f(sourceRegistry);
- }
- };
-
- let createRegistry = function () {
- api.fetchText
- (ηMatrix.assetsBootstrapLocation || 'assets/assets.json',
- function (details) {
- updateSourceRegistry(details.content, true);
- onReady();
- });
- };
-
- let onRead = function (bin) {
- if (!bin || !bin.assetSourceRegistry
- || Object.keys(bin.assetSourceRegistry).length == 0) {
- createRegistry();
- return;
- }
-
- sourceRegistry = bin.assetSourceRegistry;
- onReady();
- };
-
- vAPI.cacheStorage.get('assetSourceRegistry', onRead);
+ if (sourceRegistryReady === true) {
+ callback(sourceRegistry);
+ return;
+ }
+
+ if (sourceRegistryCallbacks !== undefined) {
+ // If it's not undefined it's always an array
+ sourceRegistryCallbacks.push(callback);
+ return;
+ }
+
+ sourceRegistryCallbacks = [callback];
+
+ let onReady = function () {
+ sourceRegistryReady = true;
+
+ let f;
+ while ((f = sourceRegistryCallbacks.shift())) {
+ f(sourceRegistry);
+ }
+ };
+
+ let createRegistry = function () {
+ api.fetchText
+ (ηMatrix.assetsBootstrapLocation || 'assets/assets.json',
+ function (details) {
+ updateSourceRegistry(details.content, true);
+ onReady();
+ });
+ };
+
+ let onRead = function (bin) {
+ if (!bin || !bin.assetSourceRegistry
+ || Object.keys(bin.assetSourceRegistry).length == 0) {
+ createRegistry();
+ return;
+ }
+
+ sourceRegistry = bin.assetSourceRegistry;
+ onReady();
+ };
+
+ vAPI.cacheStorage.get('assetSourceRegistry', onRead);
};
// Remote
let getRemote = function (key, callback) {
- let assetDetails = {};
- let contentUrl;
-
- let report = function (content, error) {
- let details = {
- assetKey: key,
- content: content,
- };
- if (error) {
- details.error = assetDetails.lastError = error;
- } else {
- assetDetails.lastError = undefined;
- }
- callback(details);
- };
-
- let tryLoad = function (tries) {
- let urls = [];
-
- let tr = (tries === undefined) ? 10 : tries;
-
- if (tr <= 0) {
- console.warn('ηMatrix could not load the asset '
- +assetDetails.title);
- return;
- }
-
- if (typeof assetDetails.contentURL === 'string') {
- urls = [assetDetails.contentURL];
- } else if (Array.isArray(assetDetails.contentURL)) {
- urls = assetDetails.contentURL.slice(0);
- }
-
- while ((contentUrl = urls.shift())) {
- if (externalPathRegex.test(contentUrl)) {
- break;
- }
- }
-
- if (!contentUrl) {
- report('', 'E_NOTFOUND');
- return;
- }
-
- api.fetchText(contentUrl, onRemoteContentLoad, onRemoteContentError,
- tr-1);
- };
-
- let onRemoteContentLoad = function (details, tries) {
- if (isEmptyString(details.content) === true) {
- registerSource(key, {
- error: {
- time: Date.now(),
- error: 'No content'
- }
- });
- tryLoad(tries);
- }
-
- writeCache(key, {
- content: details.content,
- url: contentUrl,
- });
-
- registerSource(key, {error: undefined});
- report(details.content);
- };
-
- let onRemoteContentError = function (details, tries) {
- let text = details.statusText;
- if (details.statusCode === 0) {
- text = 'network error';
- }
- registerSource(key, {
- error: {
- time: Date.now(),
- error: text,
- }
- });
- tryLoad(tries);
- };
-
- let onReady = function (registry) {
- assetDetails = registry[key] || {};
- tryLoad();
- };
-
- getSourceRegistry(onReady);
+ let assetDetails = {};
+ let contentUrl = '';
+ let urls = [];
+
+ let report = function (content, error) {
+ let details = {
+ assetKey: key,
+ content: content,
+ };
+ if (error) {
+ details.error = assetDetails.lastError = error;
+ } else {
+ assetDetails.lastError = undefined;
+ }
+ callback(details);
+ };
+
+ let tryLoad = function (tries) {
+ let tr = (tries === undefined) ? 10 : tries;
+
+ if (tr <= 0) {
+ console.warn('ηMatrix could not load the asset '
+ +assetDetails.title);
+ return;
+ }
+
+ while ((contentUrl = urls.shift())) {
+ if (externalPathRegex.test(contentUrl)) {
+ break;
+ }
+ }
+
+ if (!contentUrl) {
+ report('', 'E_NOTFOUND');
+ return;
+ }
+
+ api.fetchText(contentUrl,
+ onRemoteContentLoad,
+ onRemoteContentError,
+ tr-1);
+ };
+
+ let onRemoteContentLoad = function (details, tries) {
+ if (isEmptyString(details.content) === true) {
+ registerSource(key, {
+ error: {
+ time: Date.now(),
+ error: 'No content'
+ }
+ });
+ return tryLoad(tries);
+ }
+
+ writeCache(key, {
+ content: details.content,
+ url: contentUrl,
+ });
+
+ registerSource(key, {error: undefined});
+ report(details.content);
+ };
+
+ let onRemoteContentError = function (details, tries) {
+ let text = details.statusText;
+ if (details.statusCode === 0) {
+ text = 'network error';
+ }
+ registerSource(key, {
+ error: {
+ time: Date.now(),
+ error: text,
+ }
+ });
+ tryLoad(tries);
+ };
+
+ let onReady = function (registry) {
+ assetDetails = registry[key] || {};
+ if (typeof assetDetails.contentURL === 'string') {
+ urls = [assetDetails.contentURL];
+ } else if (Array.isArray(assetDetails.contentURL)) {
+ urls = assetDetails.contentURL.slice(0);
+ }
+ tryLoad();
+ };
+
+ getSourceRegistry(onReady);
};
// Updater
@@ -620,443 +571,446 @@
let updateFetch = new Set();
let updateStart = function () {
- updateStatus = 'running';
- updateFetch.clear();
- updated = [];
- notifyObservers('before-assets-updated');
- updateNext();
+ updateStatus = 'running';
+ updateFetch.clear();
+ updated = [];
+ notifyObservers('before-assets-updated');
+ updateNext();
};
let updateNext = function () {
- let cacheReg = undefined;
- let sourceReg = undefined;
-
- let gcOne = function (key) {
- let entry = cacheReg[key];
- if (entry && entry.readTime < cacheRegistryStart) {
- cacheRemove(key);
- }
- };
-
- let findOne = function () {
- let now = Date.now();
- let sourceEntry;
- let cacheEntry;
-
- for (let key in sourceReg) {
- sourceEntry = sourceReg[key];
- if (sourceEntry.hasRemoteURL !== true) {
- continue;
- }
- if (updateFetch.has(key)) {
- continue;
- }
-
- cacheEntry = cacheReg[key];
- if (cacheEntry
- && (cacheEntry.writeTime
- + sourceEntry.updateAfter*86400000) > now) {
- continue;
- }
- if (notifyObservers('before-asset-updated', {assetKey: key})) {
- return key;
- }
-
- gcOne(key);
- }
-
- return undefined;
- };
-
- let onUpdate = function (details) {
- if (details.content !== '') {
- updated.push(details.assetKey);
- if (details.assetKey === 'assets.json') {
- updateSourceRegistry(details.content);
- }
- } else {
- notifyObservers('asset-update-failed', {
- assetKey: details.assetKey,
- });
- }
-
- if (findOne() !== undefined) {
- vAPI.setTimeout(updateNext, updateDelay);
- } else {
- updateEnd();
- }
- };
-
- let updateOne = function () {
- let key = findOne();
- if (key === undefined) {
- updateEnd();
- return;
- }
-
- updateFetch.add(key);
- getRemote(key, onUpdate);
- };
-
- let onSourceReady = function (registry) {
- sourceReg = registry;
- updateOne();
- };
-
- let onCacheReady = function (registry) {
- cacheReg = registry;
- getSourceRegistry(onSourceReady);
- };
-
- getCacheRegistry(onCacheReady);
+ let cacheReg = undefined;
+ let sourceReg = undefined;
+
+ let gcOne = function (key) {
+ let entry = cacheReg[key];
+ if (entry && entry.readTime < cacheRegistryStart) {
+ removeCache(key);
+ }
+ };
+
+ let findOne = function () {
+ let now = Date.now();
+ let sourceEntry;
+ let cacheEntry;
+
+ for (let key in sourceReg) {
+ sourceEntry = sourceReg[key];
+ if (sourceEntry.hasRemoteURL !== true) {
+ continue;
+ }
+ if (updateFetch.has(key)) {
+ continue;
+ }
+
+ cacheEntry = cacheReg[key];
+ if (cacheEntry
+ && (cacheEntry.writeTime
+ + sourceEntry.updateAfter*86400000) > now) {
+ continue;
+ }
+ if (notifyObservers('before-asset-updated', {assetKey: key})) {
+ return key;
+ }
+
+ gcOne(key);
+ }
+
+ return undefined;
+ };
+
+ let onUpdate = function (details) {
+ if (details.content !== '') {
+ updated.push(details.assetKey);
+ if (details.assetKey === 'assets.json') {
+ updateSourceRegistry(details.content);
+ }
+ } else {
+ notifyObservers('asset-update-failed', {
+ assetKey: details.assetKey,
+ });
+ }
+
+ if (findOne() !== undefined) {
+ vAPI.setTimeout(updateNext, updateDelay);
+ } else {
+ updateEnd();
+ }
+ };
+
+ let updateOne = function () {
+ let key = findOne();
+ if (key === undefined) {
+ updateEnd();
+ return;
+ }
+
+ updateFetch.add(key);
+ getRemote(key, onUpdate);
+ };
+
+ let onSourceReady = function (registry) {
+ sourceReg = registry;
+ updateOne();
+ };
+
+ let onCacheReady = function (registry) {
+ cacheReg = registry;
+ getSourceRegistry(onSourceReady);
+ };
+
+ getCacheRegistry(onCacheReady);
};
let updateEnd = function () {
- let keys = updated.slice(0);
- updateFetch.clear();
- updateStatus = 'stop';
- updateDelay = updateDefaultDelay;
- notifyObservers('after-asset-updated', {
- assetKeys: keys,
- });
+ let keys = updated.slice(0);
+ updateFetch.clear();
+ updateStatus = 'stop';
+ updateDelay = updateDefaultDelay;
+ notifyObservers('after-asset-updated', {
+ assetKeys: keys,
+ });
};
// Assets API
api.addObserver = function (observer) {
- if (observers.indexOf(observer) === -1) {
- observers.push(observer);
- }
+ if (observers.indexOf(observer) === -1) {
+ observers.push(observer);
+ }
};
api.removeObserver = function (observer) {
- let pos = observers.indexOf(observer);
- if (pos !== -1) {
- observers.splice(pos, 1);
- }
+ let pos = observers.indexOf(observer);
+ while (pos !== -1) {
+ observers.splice(pos, 1);
+ pos = observers.indexOf(observer);
+ }
};
api.fetchText = function (url, onLoad, onError, tries) {
- let iurl = externalPathRegex.test(url) ? url : vAPI.getURL(url);
- let tr = (tries === undefined) ? 10 : tries;
-
- if (typeof onError !== 'function') {
- onError = onLoad;
- }
-
- let onResponseReceived = function () {
- this.onload = this.onerror = this.ontimeout = null;
-
- let details = {
- url: url,
- content: '',
- // On local files this.status is 0, but the request
- // is successful
- statusCode: this.status || 200,
- statusText: this.statusText || '',
- };
-
- if (details.statusCode < 200 || details.statusCode >= 300) {
- onError.call(null, details, tr);
- return;
- }
-
- if (isEmptyString(this.responseText) === true) {
- onError.call(null, details, tr);
- return;
- }
-
- let t = this.responseText.trim();
-
- // Discard HTML as it's probably an error
- // (the request expects plain text as a response)
- if (t.startsWith('<') && t.endsWith('>')) {
- onError.call(null, details, tr);
- return;
- }
-
- details.content = t;
- onLoad.call(null, details, tr);
- };
-
- let onErrorReceived = function () {
- this.onload = this.onerror = this.ontimeout = null;
-
- ηMatrix.logger.writeOne('', 'error',
- connectionError.replace('{{url}}', iurl));
-
- onError.call(null, {
- url: url,
- content: '',
- }, tr);
- };
-
- let req = new XMLHttpRequest();
- req.open('GET', iurl, true);
- req.timeout = 30000;
- req.onload = onResponseReceived;
- req.onerror = onErrorReceived;
- req.ontimeout = onErrorReceived;
- req.responseType = 'text';
-
- try {
- // This can throw in some cases
- req.send();
- } catch (e) {
- onErrorReceived.call(req);
- }
+ let iurl = externalPathRegex.test(url) ? url : vAPI.getURL(url);
+ let tr = (tries === undefined) ? 10 : tries;
+
+ if (typeof onError !== 'function') {
+ onError = onLoad;
+ }
+
+ let onResponseReceived = function () {
+ this.onload = this.onerror = this.ontimeout = null;
+
+ let details = {
+ url: url,
+ content: '',
+ // On local files this.status is 0, but the request
+ // is successful
+ statusCode: this.status || 200,
+ statusText: this.statusText || '',
+ };
+
+ if (details.statusCode < 200 || details.statusCode >= 300) {
+ return onError.call(null, details, tr);
+ }
+
+ if (isEmptyString(this.responseText) === true) {
+ return onError.call(null, details, tr);
+ }
+
+ let t = this.responseText.trim();
+
+ // Discard HTML as it's probably an error
+ // (the request expects plain text as a response)
+ if (t.startsWith('<') && t.endsWith('>')) {
+ return onError.call(null, details, tr);
+ }
+
+ details.content = t;
+ return onLoad.call(null, details, tr);
+ };
+
+ let onErrorReceived = function () {
+ this.onload = this.onerror = this.ontimeout = null;
+
+ ηMatrix.logger.writeOne('', 'error',
+ connectionError.replace('{{url}}', iurl));
+
+ onError.call(null, {
+ url: url,
+ content: '',
+ }, tr);
+ };
+
+ let req = new XMLHttpRequest();
+ req.open('GET', iurl, true);
+ req.timeout = 30000;
+ req.onload = onResponseReceived;
+ req.onerror = onErrorReceived;
+ req.ontimeout = onErrorReceived;
+ req.responseType = 'text';
+
+ try {
+ // This can throw in some cases
+ req.send();
+ } catch (e) {
+ onErrorReceived.call(req);
+ }
};
api.registerAssetSource = function (key, details) {
- getSourceRegistry(function () {
- registerSource(key, details);
- saveSourceRegistry(true);
- });
+ getSourceRegistry(function () {
+ registerSource(key, details);
+ saveSourceRegistry(true);
+ });
};
api.unregisterAssetSource = function (key) {
- getSourceRegistry(function () {
- unregisterSource(key);
- saveSourceRegistry(true);
- });
+ getSourceRegistry(function () {
+ unregisterSource(key);
+ saveSourceRegistry(true);
+ });
};
api.get = function (key, options, callback) {
- let cb;
- let opt;
-
- if (typeof options === 'function') {
- cb = options;
- opt = {};
- } else if (typeof callback !== 'function') {
- cb = noOp;
- opt = options;
- } else {
- cb = callback;
- opt = options;
- }
-
- let assetDetails = {};
- let contentUrl = undefined;
-
- let report = function (content, error) {
- let details = {
- assetKey: key,
- content: content,
- };
-
- if (error) {
- details.error = assetDetails.error = error;
- } else {
- assetDetails.error = undefined;
- }
-
- cb(details);
- };
-
- let onContentNotLoaded = function (details, tries) {
- let external;
- let urls = [];
-
- let tr = (tries === undefined) ? 10 : tries;
-
- if (tr <= 0) {
- console.warn('ηMatrix couldn\'t download the asset '
- +assetDetails.title);
- return;
- }
-
- if (typeof assetDetails.contentURL === 'string') {
- urls = [assetDetails.contentURL];
- } else if (Array.isArray(assetDetails.contentURL)) {
- urls = assetDetails.contentURL.slice(0);
- }
-
- while ((contentUrl = urls.shift())) {
- external = externalPathRegex.test(contentUrl);
- if (external === true && assetDetails.loaded !== true) {
- break;
- }
- if (external === false || assetDetails.hasLocalURL !== true) {
- break;
- }
- }
-
- if (!contentUrl) {
- report('', 'E_NOTFOUND');
- return;
- }
-
- api.fetchText(contentUrl, onContentLoaded, onContentNotLoaded,
- tr-1);
- };
-
- let onContentLoaded = function (details, tries) {
- if (isEmptyString(details.content) === true) {
- onContentNotLoaded(undefined, tries);
- return;
- }
-
- if (externalPathRegex.test(details.url)
- && opt.dontCache !== true) {
- writeCache(key, {
- content: details.content,
- url: contentUrl,
- });
- }
-
- assetDetails.loaded = true;
-
- report(details.content);
- };
-
- let onCachedContentLoad = function (details) {
- if (details.content !== '') {
- report(details.content);
- return;
- }
-
- let onReady = function (registry) {
- assetDetails = registry[key] || {};
- onContentNotLoaded();
- }
-
- getSourceRegistry(onReady);
- };
-
- readCache(key, onCachedContentLoad);
+ let cb;
+ let opt;
+
+ if (typeof options === 'function') {
+ cb = options;
+ opt = {};
+ } else if (typeof callback !== 'function') {
+ cb = noOp;
+ opt = options;
+ } else {
+ cb = callback;
+ opt = options;
+ }
+
+ let assetDetails = {};
+ let urls = [];
+ let contentUrl = '';
+
+ let report = function (content, error) {
+ let details = {
+ assetKey: key,
+ content: content,
+ };
+
+ if (error) {
+ details.error = assetDetails.error = error;
+ } else {
+ assetDetails.error = undefined;
+ }
+
+ cb(details);
+ };
+
+ let onContentNotLoaded = function (details, tries) {
+ let external;
+
+ let tr = (tries === undefined) ? 10 : tries;
+
+ if (tr <= 0) {
+ console.warn('ηMatrix couldn\'t download the asset '
+ +assetDetails.title);
+ return;
+ }
+
+ while ((contentUrl = urls.shift())) {
+ external = externalPathRegex.test(contentUrl);
+ if (external === true && assetDetails.loaded !== true) {
+ break;
+ }
+ if (external === false || assetDetails.hasLocalURL !== true) {
+ break;
+ }
+ }
+
+ if (!contentUrl) {
+ return report('', 'E_NOTFOUND');
+ }
+
+ api.fetchText(contentUrl,
+ onContentLoaded,
+ onContentNotLoaded,
+ tr-1);
+ };
+
+ let onContentLoaded = function (details, tries) {
+ if (isEmptyString(details.content) === true) {
+ return onContentNotLoaded(undefined, tries);
+ }
+
+ if (externalPathRegex.test(details.url)
+ && opt.dontCache !== true) {
+ writeCache(key, {
+ content: details.content,
+ url: contentUrl,
+ });
+ }
+
+ assetDetails.loaded = true;
+
+ report(details.content);
+ };
+
+ let onCachedContentLoad = function (details) {
+ if (details.content !== '') {
+ return report(details.content);
+ }
+
+ let onRead = function (details) {
+ console.debug(details);
+ report(details.content || 'missing contents');
+ }
+
+ let onReady = function (registry) {
+ assetDetails = registry[key] || {};
+ if (typeof assetDetails.contentURL === 'string') {
+ urls = [assetDetails.contentURL];
+ } else if (Array.isArray(assetDetails.contentURL)) {
+ urls = assetDetails.contentURL.slice(0);
+ }
+ if (true === assetDetails.loaded) {
+ readCache(key, onRead);
+ } else {
+ onContentNotLoaded();
+ }
+ }
+
+ getSourceRegistry(onReady);
+ };
+
+ readCache(key, onCachedContentLoad);
};
api.put = function (key, content, callback) {
- writeCache(key, content, callback);
+ writeCache(key, content, callback);
};
api.metadata = function (callback) {
- let onSourceReady = function (registry) {
- let source = JSON.parse(JSON.stringify(registry));
- let cache = cacheRegistry;
- let sourceEntry;
- let cacheEntry;
- let now = Date.now();
- let obsoleteAfter;
-
- for (let key in source) {
- sourceEntry = source[key];
- cacheEntry = cache[key];
-
- if (cacheEntry) {
- sourceEntry.cached = true;
- sourceEntry.writeTime = cacheEntry.writeTime;
- obsoleteAfter = cacheEntry.writeTime
- + sourceEntry.updateAfter * 86400000;
- sourceEntry.obsolete = obsoleteAfter < now;
- sourceEntry.remoteURL = cacheEntry.remoteURL;
- } else {
- sourceEntry.writeTime = 0;
- obsoleteAfter = 0;
- sourceEntry.obsolete = true;
- }
- }
-
- callback(source);
- }
-
- let onCacheReady = function () {
- getSourceRegistry(onSourceReady);
- }
-
- getCacheRegistry(onCacheReady);
+ let onSourceReady = function (registry) {
+ let source = JSON.parse(JSON.stringify(registry));
+ let cache = cacheRegistry;
+ let sourceEntry;
+ let cacheEntry;
+ let now = Date.now();
+ let obsoleteAfter;
+
+ for (let key in source) {
+ sourceEntry = source[key];
+ cacheEntry = cache[key];
+
+ if (cacheEntry) {
+ sourceEntry.cached = true;
+ sourceEntry.writeTime = cacheEntry.writeTime;
+ obsoleteAfter = cacheEntry.writeTime
+ + sourceEntry.updateAfter * 86400000;
+ sourceEntry.obsolete = obsoleteAfter < now;
+ sourceEntry.remoteURL = cacheEntry.remoteURL;
+ } else {
+ sourceEntry.writeTime = 0;
+ obsoleteAfter = 0;
+ sourceEntry.obsolete = true;
+ }
+ }
+
+ callback(source);
+ }
+
+ let onCacheReady = function () {
+ getSourceRegistry(onSourceReady);
+ }
+
+ getCacheRegistry(onCacheReady);
};
api.purge = function (pattern, exclude, callback) {
- markDirtyCache(pattern, exclude, callback);
+ markDirtyCache(pattern, exclude, callback);
};
api.remove = function (pattern, callback) {
- cacheRemove(pattern, callback);
+ removeCache(pattern, callback);
};
api.rmrf = function () {
- cacheRemove(/./);
+ removeCache(/./);
};
api.updateStart = function (details) {
- let oldDelay = updateDelay;
- let newDelay = details.delay || updateDefaultDelay;
+ let oldDelay = updateDelay;
+ let newDelay = details.delay || updateDefaultDelay;
- updateDelay = Math.min(oldDelay, newDelay);
+ updateDelay = Math.min(oldDelay, newDelay);
- if (updateStatus !== undefined) {
- if (newDelay < oldDelay) {
- clearTimeout(updateTimer);
- updateTimer = vAPI.setTimeout(updateNext, updateDelay);
- }
- return;
- }
+ if (updateStatus !== 'stop') {
+ if (newDelay < oldDelay) {
+ clearTimeout(updateTimer);
+ updateTimer = vAPI.setTimeout(updateNext, updateDelay);
+ }
+ return;
+ }
- updateStart();
+ updateStart();
};
api.updateStop = function () {
- if (updateTimer) {
- clearTimeout(updateTimer);
- updateTimer = undefined;
- }
- if (updateStatus === 'running') {
- updateEnd();
- }
+ if (updateTimer) {
+ clearTimeout(updateTimer);
+ updateTimer = undefined;
+ }
+ if (updateStatus === 'running') {
+ updateEnd();
+ }
};
api.checkVersion = function () {
- let cache;
-
- let onSourceReady = function (registry) {
- let source = JSON.parse(JSON.stringify(registry));
- let version = ηMatrix.userSettings.assetVersion;
-
- if (!version) {
- ηMatrix.userSettings.assetVersion = 1;
- version = 1;
- }
-
- if (!source["assets.json"].version
- || version > source["assets.json"].version) {
- for (let key in source) {
- switch (key) {
- case "hphosts":
- case "malware-0":
- case "malware-1":
- delete source[key];
- api.remove(key, function () {});
- break;
- default:
- break;
- }
-
- source["assets.json"].version = version;
- }
-
- let createRegistry = function () {
- api.fetchText
- (ηMatrix.assetsBootstrapLocation || 'assets/assets.json',
- function (details) {
- updateSourceRegistry(details.content, true);
- });
- };
-
- createRegistry();
- }
- };
-
- let onCacheReady = function (registry) {
- cache = JSON.parse(JSON.stringify(registry));
-
- getSourceRegistry(onSourceReady);
- };
-
- getCacheRegistry(onCacheReady);
+ let cache;
+
+ let onSourceReady = function (registry) {
+ let source = JSON.parse(JSON.stringify(registry));
+ let version = ηMatrix.userSettings.assetVersion;
+
+ if (!version) {
+ ηMatrix.userSettings.assetVersion = 1;
+ version = 1;
+ }
+
+ if (!source["assets.json"].version
+ || version > source["assets.json"].version) {
+ for (let key in source) {
+ switch (key) {
+ case "hphosts":
+ case "malware-0":
+ case "malware-1":
+ delete source[key];
+ api.remove(key, function () {});
+ break;
+ default:
+ break;
+ }
+
+ source["assets.json"].version = version;
+ }
+
+ let createRegistry = function () {
+ api.fetchText
+ (ηMatrix.assetsBootstrapLocation || 'assets/assets.json',
+ function (details) {
+ updateSourceRegistry(details.content, true);
+ });
+ };
+
+ createRegistry();
+ }
+ };
+
+ let onCacheReady = function (registry) {
+ cache = JSON.parse(JSON.stringify(registry));
+
+ getSourceRegistry(onSourceReady);
+ };
+
+ getCacheRegistry(onCacheReady);
};
return api;
})();
-
-/******************************************************************************/
diff --git a/js/background.js b/js/background.js
index 889decd..b31bbed 100644
--- a/js/background.js
+++ b/js/background.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -32,45 +32,45 @@ var ηMatrix = (function () {
let oneDay = 24 * oneHour;
let _RequestStats = function () {
- this.reset();
+ this.reset();
};
_RequestStats.prototype.reset = function () {
- this.all =
- this.doc =
- this.frame =
- this.script =
- this.css =
- this.image =
- this.media =
- this.xhr =
- this.other =
- this.cookie = 0;
+ this.all =
+ this.doc =
+ this.frame =
+ this.script =
+ this.css =
+ this.image =
+ this.media =
+ this.xhr =
+ this.other =
+ this.cookie = 0;
};
var RequestStats = function () {
- this.allowed = new _RequestStats ();
- this.blocked = new _RequestStats ();
+ this.allowed = new _RequestStats ();
+ this.blocked = new _RequestStats ();
};
RequestStats.prototype.reset = function () {
- this.blocked.reset();
- this.allowed.reset();
+ this.blocked.reset();
+ this.allowed.reset();
};
RequestStats.prototype.record = function (type, blocked) {
- // Remember: always test against **false**
- if (blocked !== false) {
+ // Remember: always test against **false**
+ if (blocked !== false) {
this.blocked[type] += 1;
this.blocked.all += 1;
- } else {
+ } else {
this.allowed[type] += 1;
this.allowed.all += 1;
- }
+ }
};
var requestStatsFactory = function () {
- return new RequestStats();
+ return new RequestStats();
};
/**
@@ -93,8 +93,8 @@ var ηMatrix = (function () {
*/
var rawSettingsDefault = {
- disableCSPReportInjection: false,
- placeholderBackground: [
+ disableCSPReportInjection: false,
+ placeholderBackground: [
'url("data:image/png;base64,',
'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAK',
'CAAAAACoWZBhAAAABGdBTUEAALGPC/xh',
@@ -108,13 +108,13 @@ var ηMatrix = (function () {
'KzAzOjAwa+9TNQAAAABJRU5ErkJggg==',
'") ',
'repeat scroll #fff'
- ].join(''),
- placeholderBorder: '1px solid rgba(0, 0, 0, 0.1)',
- imagePlaceholder: true,
- imagePlaceholderBackground: 'default',
- imagePlaceholderBorder: 'default',
- framePlaceholder: true,
- framePlaceholderDocument: [
+ ].join(''),
+ placeholderBorder: '1px solid rgba(0, 0, 0, 0.1)',
+ imagePlaceholder: true,
+ imagePlaceholderBackground: 'default',
+ imagePlaceholderBorder: 'default',
+ framePlaceholder: true,
+ framePlaceholderDocument: [
'<html><head>',
'<meta charset="utf-8">',
'<style>',
@@ -145,13 +145,13 @@ var ηMatrix = (function () {
'</a>{{url}}</span>',
'</body></html>'
].join(''),
- framePlaceholderBackground: 'default',
+ framePlaceholderBackground: 'default',
};
return {
- onBeforeStartQueue: [],
+ onBeforeStartQueue: [],
- userSettings: {
+ userSettings: {
alwaysDetachLogger: false,
autoUpdate: false,
clearBrowserCache: true,
@@ -173,56 +173,56 @@ var ηMatrix = (function () {
popupScopeLevel: 'domain',
processHyperlinkAuditing: true,
processReferer: false,
- disableUpdateIcon: false,
- resolveCname: false,
- assetsVersion: 1,
- },
-
- rawSettingsDefault: rawSettingsDefault,
- rawSettings: Object.assign({}, rawSettingsDefault),
- rawSettingsWriteTime: 0,
-
- clearBrowserCacheCycle: 0,
- cspNoInlineScript: "script-src 'unsafe-eval' blob: *",
- cspNoInlineStyle: "style-src blob: *",
- cspNoWorker: undefined,
- updateAssetsEvery: 11 * oneDay + 1 * oneHour + 1 * oneMinute + 1 * oneSecond,
- firstUpdateAfter: 11 * oneMinute,
- nextUpdateAfter: 11 * oneHour,
- assetsBootstrapLocation: 'assets/assets.json',
- pslAssetKey: 'public_suffix_list.dat',
-
- // list of live hosts files
- liveHostsFiles: {
- },
-
- // urls stats are kept on the back burner while waiting to be
- // reactivated in a tab or another.
- pageStores: {},
- pageStoresToken: 0,
- pageStoreCemetery: {},
-
- // page url => permission scope
- tMatrix: null,
- pMatrix: null,
-
- ubiquitousBlacklist: new LiquidDict(),
- ubiquitousWhitelist: new LiquidDict(),
-
- // various stats
- requestStatsFactory: requestStatsFactory,
- requestStats: requestStatsFactory(),
- cookieRemovedCounter: 0,
- localStorageRemovedCounter: 0,
- cookieHeaderFoiledCounter: 0,
- refererHeaderFoiledCounter: 0,
- hyperlinkAuditingFoiledCounter: 0,
- browserCacheClearedCounter: 0,
- storageUsed: 0,
-
- // record what the browser is doing behind the scene
- behindTheSceneScope: 'behind-the-scene',
-
- noopFunc: function () {},
+ disableUpdateIcon: false,
+ resolveCname: false,
+ assetsVersion: 1,
+ },
+
+ rawSettingsDefault: rawSettingsDefault,
+ rawSettings: Object.assign({}, rawSettingsDefault),
+ rawSettingsWriteTime: 0,
+
+ clearBrowserCacheCycle: 0,
+ cspNoInlineScript: "script-src 'unsafe-eval' blob: *",
+ cspNoInlineStyle: "style-src blob: *",
+ cspNoWorker: undefined,
+ updateAssetsEvery: 11 * oneDay + 1 * oneHour + 1 * oneMinute + 1 * oneSecond,
+ firstUpdateAfter: 11 * oneMinute,
+ nextUpdateAfter: 11 * oneHour,
+ assetsBootstrapLocation: 'assets/assets.json',
+ pslAssetKey: 'public_suffix_list.dat',
+
+ // list of live hosts files
+ liveHostsFiles: {
+ },
+
+ // urls stats are kept on the back burner while waiting to be
+ // reactivated in a tab or another.
+ pageStores: {},
+ pageStoresToken: 0,
+ pageStoreCemetery: {},
+
+ // page url => permission scope
+ tMatrix: null,
+ pMatrix: null,
+
+ ubiquitousBlacklist: new LiquidDict(),
+ ubiquitousWhitelist: new LiquidDict(),
+
+ // various stats
+ requestStatsFactory: requestStatsFactory,
+ requestStats: requestStatsFactory(),
+ cookieRemovedCounter: 0,
+ localStorageRemovedCounter: 0,
+ cookieHeaderFoiledCounter: 0,
+ refererHeaderFoiledCounter: 0,
+ hyperlinkAuditingFoiledCounter: 0,
+ browserCacheClearedCounter: 0,
+ storageUsed: 0,
+
+ // record what the browser is doing behind the scene
+ behindTheSceneScope: 'behind-the-scene',
+
+ noopFunc: function () {},
};
})();
diff --git a/js/browsercache.js b/js/browsercache.js
index 496d2d2..283820e 100644
--- a/js/browsercache.js
+++ b/js/browsercache.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2015-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -27,29 +27,29 @@
// Browser data jobs
let clearCache = function () {
- vAPI.setTimeout(clearCache, 15 * 60 * 1000);
+ vAPI.setTimeout(clearCache, 15 * 60 * 1000);
- var ηm = ηMatrix;
- if (!ηm.userSettings.clearBrowserCache) {
+ var ηm = ηMatrix;
+ if (!ηm.userSettings.clearBrowserCache) {
return;
- }
+ }
- ηm.clearBrowserCacheCycle -= 15;
- if (ηm.clearBrowserCacheCycle > 0) {
+ ηm.clearBrowserCacheCycle -= 15;
+ if (ηm.clearBrowserCacheCycle > 0) {
return;
- }
+ }
- vAPI.browser.data.clearCache();
+ vAPI.browser.data.clearCache();
- ηm.clearBrowserCacheCycle = ηm.userSettings.clearBrowserCacheAfter;
- ++ηm.browserCacheClearedCounter;
+ ηm.clearBrowserCacheCycle = ηm.userSettings.clearBrowserCacheAfter;
+ ++ηm.browserCacheClearedCounter;
- // TODO: i18n
- ηm.logger.writeOne('', 'info',
- vAPI.i18n('loggerEntryBrowserCacheCleared'));
+ // TODO: i18n
+ ηm.logger.writeOne('', 'info',
+ vAPI.i18n('loggerEntryBrowserCacheCleared'));
- // console.debug('clearBrowserCacheCallback()> '
- // + 'vAPI.browser.data.clearCache() called');
+ // console.debug('clearBrowserCacheCallback()> '
+ // + 'vAPI.browser.data.clearCache() called');
};
vAPI.setTimeout(clearCache, 15 * 60 * 1000);
diff --git a/js/cloud-ui.js b/js/cloud-ui.js
index 6d5e875..51919af 100644
--- a/js/cloud-ui.js
+++ b/js/cloud-ui.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2015-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uBlock
*/
@@ -25,34 +25,34 @@
(function () {
self.cloud = {
- options: {},
- datakey: '',
- data: undefined,
- onPush: null,
- onPull: null
+ options: {},
+ datakey: '',
+ data: undefined,
+ onPush: null,
+ onPull: null
};
let widget = uDom.nodeFromId('cloudWidget');
if (widget === null) {
- return;
+ return;
}
self.cloud.datakey = widget.getAttribute('data-cloud-entry') || '';
if (self.cloud.datakey === '') {
- return;
+ return;
}
let onCloudDataReceived = function (entry) {
- if (typeof entry !== 'object' || entry === null) {
+ if (typeof entry !== 'object' || entry === null) {
return;
- }
+ }
- self.cloud.data = entry.data;
+ self.cloud.data = entry.data;
- uDom.nodeFromId('cloudPull').removeAttribute('disabled');
- uDom.nodeFromId('cloudPullAndMerge').removeAttribute('disabled');
+ uDom.nodeFromId('cloudPull').removeAttribute('disabled');
+ uDom.nodeFromId('cloudPullAndMerge').removeAttribute('disabled');
- let timeOptions = {
+ let timeOptions = {
weekday: 'short',
year: 'numeric',
month: 'short',
@@ -61,100 +61,100 @@
minute: 'numeric',
second: 'numeric',
timeZoneName: 'short',
- };
+ };
- let time = new Date(entry.tstamp);
- widget.querySelector('span').textContent = entry.source
- + '\n'
- + time.toLocaleString('fullwide', timeOptions);
+ let time = new Date(entry.tstamp);
+ widget.querySelector('span').textContent = entry.source
+ + '\n'
+ + time.toLocaleString('fullwide', timeOptions);
};
let fetchCloudData = function () {
- vAPI.messaging.send('cloud-ui.js', {
- what: 'cloudPull',
- datakey: self.cloud.datakey
+ vAPI.messaging.send('cloud-ui.js', {
+ what: 'cloudPull',
+ datakey: self.cloud.datakey
}, onCloudDataReceived);
};
let pushData = function () {
- if (typeof self.cloud.onPush !== 'function') {
+ if (typeof self.cloud.onPush !== 'function') {
return;
- }
+ }
- vAPI.messaging.send('cloud-ui.js', {
- what: 'cloudPush',
- datakey: self.cloud.datakey,
- data: self.cloud.onPush()
+ vAPI.messaging.send('cloud-ui.js', {
+ what: 'cloudPush',
+ datakey: self.cloud.datakey,
+ data: self.cloud.onPush()
}, fetchCloudData);
};
let pullData = function (ev) {
- if (typeof self.cloud.onPull === 'function') {
+ if (typeof self.cloud.onPull === 'function') {
self.cloud.onPull(self.cloud.data, ev.shiftKey);
- }
+ }
};
let pullAndMergeData = function () {
- if (typeof self.cloud.onPull === 'function') {
+ if (typeof self.cloud.onPull === 'function') {
self.cloud.onPull(self.cloud.data, true);
- }
+ }
};
let openOptions = function () {
- let input = uDom.nodeFromId('cloudDeviceName');
- input.value = self.cloud.options.deviceName;
- input.setAttribute('placeholder', self.cloud.options.defaultDeviceName);
- uDom.nodeFromId('cloudOptions').classList.add('show');
+ let input = uDom.nodeFromId('cloudDeviceName');
+ input.value = self.cloud.options.deviceName;
+ input.setAttribute('placeholder', self.cloud.options.defaultDeviceName);
+ uDom.nodeFromId('cloudOptions').classList.add('show');
};
let closeOptions = function (ev) {
- let root = uDom.nodeFromId('cloudOptions');
- if (ev.target !== root) {
+ let root = uDom.nodeFromId('cloudOptions');
+ if (ev.target !== root) {
return;
- }
- root.classList.remove('show');
+ }
+ root.classList.remove('show');
};
let submitOptions = function () {
- let onOptions = function (options) {
+ let onOptions = function (options) {
if (typeof options !== 'object' || options === null) {
- return;
+ return;
}
self.cloud.options = options;
- };
+ };
- vAPI.messaging.send('cloud-ui.js', {
+ vAPI.messaging.send('cloud-ui.js', {
what: 'cloudSetOptions',
options: {
- deviceName: uDom.nodeFromId('cloudDeviceName').value
+ deviceName: uDom.nodeFromId('cloudDeviceName').value
}
- }, onOptions);
- uDom.nodeFromId('cloudOptions').classList.remove('show');
+ }, onOptions);
+ uDom.nodeFromId('cloudOptions').classList.remove('show');
};
let onInitialize = function (options) {
- if (typeof options !== 'object' || options === null) {
+ if (typeof options !== 'object' || options === null) {
return;
- }
+ }
- if (!options.enabled) {
+ if (!options.enabled) {
return;
- }
- self.cloud.options = options;
-
- let xhr = new XMLHttpRequest();
- xhr.open('GET', 'cloud-ui.html', true);
- xhr.overrideMimeType('text/html;charset=utf-8');
- xhr.responseType = 'text';
- xhr.onload = function () {
+ }
+ self.cloud.options = options;
+
+ let xhr = new XMLHttpRequest();
+ xhr.open('GET', 'cloud-ui.html', true);
+ xhr.overrideMimeType('text/html;charset=utf-8');
+ xhr.responseType = 'text';
+ xhr.onload = function () {
this.onload = null;
let parser = new DOMParser();
- let parsed = parser.parseFromString(this.responseText, 'text/html');
- let fromParent = parsed.body;
+ let parsed = parser.parseFromString(this.responseText, 'text/html');
+ let fromParent = parsed.body;
while (fromParent.firstElementChild !== null) {
- widget.appendChild(document
- .adoptNode(fromParent.firstElementChild));
+ widget.appendChild(document
+ .adoptNode(fromParent.firstElementChild));
}
vAPI.i18n.render(widget);
@@ -168,13 +168,13 @@
uDom('#cloudOptionsSubmit').on('click', submitOptions);
fetchCloudData();
- };
+ };
- xhr.send();
+ xhr.send();
};
vAPI.messaging.send('cloud-ui.js', {
- what: 'cloudGetOptions'
+ what: 'cloudGetOptions'
}, onInitialize);
// https://www.youtube.com/watch?v=aQFp67VoiDA
diff --git a/js/contentscript-start.js b/js/contentscript-start.js
index 4680e8c..b7d74ba 100644
--- a/js/contentscript-start.js
+++ b/js/contentscript-start.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2017-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -26,7 +26,7 @@
// Injected into content pages
(function () {
if (typeof vAPI !== 'object') {
- return;
+ return;
}
vAPI.selfWorkerSrcReported = vAPI.selfWorkerSrcReported || false;
@@ -35,15 +35,15 @@
var handler = function(ev) {
if (ev.isTrusted !== true
- || ev.originalPolicy.includes('report-uri about:blank') === false) {
+ || ev.originalPolicy.includes('report-uri about:blank') === false) {
return false;
}
// Firefox and Chromium differs in how they fill the
// 'effectiveDirective' property.
- // ηMatrix: what does Pale Moon/Basilisk do?
+ // ηMatrix: what does Pale Moon/Basilisk do?
if (ev.effectiveDirective.startsWith('worker-src') === false
- && ev.effectiveDirective.startsWith('frame-src') === false) {
+ && ev.effectiveDirective.startsWith('frame-src') === false) {
return false;
}
@@ -62,8 +62,8 @@
// reports.
if (ev.blockedURI.includes('://') === false) {
if (vAPI.selfWorkerSrcReported) {
- return true;
- }
+ return true;
+ }
vAPI.selfWorkerSrcReported = true;
}
@@ -80,8 +80,8 @@
document.addEventListener('securitypolicyviolation', function (ev) {
if (!handler(ev)) {
- return;
- }
+ return;
+ }
ev.stopPropagation();
ev.preventDefault();
}, true);
diff --git a/js/contentscript.js b/js/contentscript.js
index 21fbcf1..9fb15f8 100644
--- a/js/contentscript.js
+++ b/js/contentscript.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -29,54 +29,54 @@
// https://github.com/chrisaljoudi/uBlock/issues/464
// https://github.com/gorhill/uMatrix/issues/621
if (document instanceof HTMLDocument === false
- && document instanceof XMLDocument === false) {
- return;
+ && document instanceof XMLDocument === false) {
+ return;
}
// This can also happen (for example if script injected into a
// `data:` URI doc)
if (!window.location) {
- return;
+ return;
}
// This can happen
if (typeof vAPI !== 'object') {
- //console.debug('contentscript.js > vAPI not found');
- return;
+ //console.debug('contentscript.js > vAPI not found');
+ return;
}
// https://github.com/chrisaljoudi/uBlock/issues/456
// Already injected?
if (vAPI.contentscriptEndInjected) {
- //console.debug('contentscript.js > content script already injected');
- return;
+ //console.debug('contentscript.js > content script already injected');
+ return;
}
vAPI.contentscriptEndInjected = true;
// Executed only once.
(function () {
- let localStorageHandler = function (mustRemove) {
+ let localStorageHandler = function (mustRemove) {
if (mustRemove) {
- window.localStorage.clear();
- window.sessionStorage.clear();
+ window.localStorage.clear();
+ window.sessionStorage.clear();
}
- };
+ };
- // Check with extension whether local storage must be emptied
- // rhill 2014-03-28: we need an exception handler in case
- // 3rd-party access to site data is disabled.
- // https://github.com/gorhill/httpswitchboard/issues/215
- try {
+ // Check with extension whether local storage must be emptied
+ // rhill 2014-03-28: we need an exception handler in case
+ // 3rd-party access to site data is disabled.
+ // https://github.com/gorhill/httpswitchboard/issues/215
+ try {
let hasLocalStorage =
- window.localStorage && window.localStorage.length !== 0;
+ window.localStorage && window.localStorage.length !== 0;
let hasSessionStorage =
- window.sessionStorage && window.sessionStorage.length !== 0;
+ window.sessionStorage && window.sessionStorage.length !== 0;
if (hasLocalStorage || hasSessionStorage) {
- vAPI.messaging.send('contentscript.js', {
+ vAPI.messaging.send('contentscript.js', {
what: 'contentScriptHasLocalStorage',
originURL: window.location.origin
- }, localStorageHandler);
+ }, localStorageHandler);
}
// TODO: indexedDB
@@ -92,13 +92,13 @@
// "There is no way to enumerate or delete the databases available for an origin from this API."
// Ref.: http://www.w3.org/TR/webdatabase/#databases
// }
- } catch (e) {
- }
+ } catch (e) {
+ }
})();
// https://github.com/gorhill/uMatrix/issues/45
let collapser = (function () {
- let resquestIdGenerator = 1;
+ let resquestIdGenerator = 1;
let processTimer;
let toProcess = [];
let toFilter = [];
@@ -107,320 +107,320 @@
let cachedBlockedMapHash;
let cachedBlockedMapTimer;
let reURLPlaceholder = /\{\{url\}\}/g;
- let src1stProps = {
+ let src1stProps = {
embed: 'src',
iframe: 'src',
img: 'src',
object: 'data',
- };
- let src2ndProps = {
+ };
+ let src2ndProps = {
img: 'srcset',
- };
- let tagToTypeMap = {
+ };
+ let tagToTypeMap = {
embed: 'media',
iframe: 'frame',
img: 'image',
object: 'media',
- };
- let cachedBlockedSetClear = function () {
+ };
+ let cachedBlockedSetClear = function () {
cachedBlockedMap =
- cachedBlockedMapHash =
- cachedBlockedMapTimer = undefined;
- };
+ cachedBlockedMapHash =
+ cachedBlockedMapTimer = undefined;
+ };
- // https://github.com/chrisaljoudi/uBlock/issues/174
- // Do not remove fragment from src URL
- let onProcessed = function (response) {
+ // https://github.com/chrisaljoudi/uBlock/issues/174
+ // Do not remove fragment from src URL
+ let onProcessed = function (response) {
if (!response) { // This happens if uBO is disabled or restarted.
- toCollapse.clear();
- return;
+ toCollapse.clear();
+ return;
}
let targets = toCollapse.get(response.id);
if (targets === undefined) {
- return;
- }
+ return;
+ }
toCollapse.delete(response.id);
if (cachedBlockedMapHash !== response.hash) {
- cachedBlockedMap = new Map(response.blockedResources);
- cachedBlockedMapHash = response.hash;
- if (cachedBlockedMapTimer !== undefined) {
+ cachedBlockedMap = new Map(response.blockedResources);
+ cachedBlockedMapHash = response.hash;
+ if (cachedBlockedMapTimer !== undefined) {
clearTimeout(cachedBlockedMapTimer);
- }
- cachedBlockedMapTimer =
- vAPI.setTimeout(cachedBlockedSetClear, 30000);
+ }
+ cachedBlockedMapTimer =
+ vAPI.setTimeout(cachedBlockedSetClear, 30000);
}
if (cachedBlockedMap === undefined || cachedBlockedMap.size === 0) {
- return;
+ return;
}
let placeholders = response.placeholders;
for (let target of targets) {
- let tag = target.localName;
+ let tag = target.localName;
- let prop = src1stProps[tag];
- if (prop === undefined) {
- continue;
- }
+ let prop = src1stProps[tag];
+ if (prop === undefined) {
+ continue;
+ }
- let src = target[prop];
- if (typeof src !== 'string' || src.length === 0) {
+ let src = target[prop];
+ if (typeof src !== 'string' || src.length === 0) {
prop = src2ndProps[tag];
if (prop === undefined) {
- continue;
- }
+ continue;
+ }
src = target[prop];
if (typeof src !== 'string' || src.length === 0) {
- continue;
- }
- }
-
- let collapsed = cachedBlockedMap.get(tagToTypeMap[tag]
- + ' '
- + src);
- if (collapsed === undefined) {
- continue;
- }
-
- if (collapsed) {
+ continue;
+ }
+ }
+
+ let collapsed = cachedBlockedMap.get(tagToTypeMap[tag]
+ + ' '
+ + src);
+ if (collapsed === undefined) {
+ continue;
+ }
+
+ if (collapsed) {
target.style.setProperty('display', 'none', 'important');
target.hidden = true;
continue;
- }
+ }
- switch (tag) {
- case 'iframe':
+ switch (tag) {
+ case 'iframe':
if (placeholders.frame !== true) {
- break;
- }
+ break;
+ }
let docurl = 'data:text/html,'
- + encodeURIComponent(placeholders
- .frameDocument
- .replace(reURLPlaceholder, src));
+ + encodeURIComponent(placeholders
+ .frameDocument
+ .replace(reURLPlaceholder, src));
let replaced = false;
// Using contentWindow.location prevent tainting browser
// history -- i.e. breaking back button (seen on Chromium).
if (target.contentWindow) {
- try {
+ try {
target.contentWindow.location.replace(docurl);
replaced = true;
- } catch(ex) {
- }
+ } catch(ex) {
+ }
}
if (!replaced) {
- target.setAttribute('src', docurl);
+ target.setAttribute('src', docurl);
}
break;
- case 'img':
+ case 'img':
if (placeholders.image !== true) {
- break;
- }
+ break;
+ }
target.style.setProperty('display', 'inline-block');
target.style.setProperty('min-width', '20px', 'important');
target.style.setProperty('min-height', '20px', 'important');
target.style.setProperty('border', placeholders.imageBorder,
- 'important');
+ 'important');
target.style.setProperty('background',
- placeholders.imageBackground,
- 'important');
+ placeholders.imageBackground,
+ 'important');
break;
- }
+ }
}
- };
+ };
- let send = function () {
+ let send = function () {
processTimer = undefined;
toCollapse.set(resquestIdGenerator, toProcess);
let msg = {
- what: 'lookupBlockedCollapsibles',
- id: resquestIdGenerator,
- toFilter: toFilter,
- hash: cachedBlockedMapHash
+ what: 'lookupBlockedCollapsibles',
+ id: resquestIdGenerator,
+ toFilter: toFilter,
+ hash: cachedBlockedMapHash
};
vAPI.messaging.send('contentscript.js', msg, onProcessed);
toProcess = [];
toFilter = [];
resquestIdGenerator += 1;
- };
+ };
- let process = function (delay) {
+ let process = function (delay) {
if (toProcess.length === 0) {
- return;
- }
+ return;
+ }
if (delay === 0) {
- if (processTimer !== undefined) {
+ if (processTimer !== undefined) {
clearTimeout(processTimer);
- }
- send();
+ }
+ send();
} else if (processTimer === undefined) {
- processTimer = vAPI.setTimeout(send, delay || 47);
+ processTimer = vAPI.setTimeout(send, delay || 47);
}
- };
+ };
- let add = function (target) {
+ let add = function (target) {
toProcess.push(target);
- };
+ };
- let addMany = function (targets) {
- for (let i=targets.length-1; i>=0; --i) {
- toProcess.push(targets[i]);
+ let addMany = function (targets) {
+ for (let i=targets.length-1; i>=0; --i) {
+ toProcess.push(targets[i]);
}
- };
+ };
- let iframeSourceModified = function (mutations) {
- for (let i=mutations.length-1; i>=0; --i) {
- addIFrame(mutations[i].target, true);
+ let iframeSourceModified = function (mutations) {
+ for (let i=mutations.length-1; i>=0; --i) {
+ addIFrame(mutations[i].target, true);
}
process();
- };
+ };
- let iframeSourceObserver;
- let iframeSourceObserverOptions = {
+ let iframeSourceObserver;
+ let iframeSourceObserverOptions = {
attributes: true,
attributeFilter: [ 'src' ]
- };
+ };
- let addIFrame = function (iframe, dontObserve) {
+ let addIFrame = function (iframe, dontObserve) {
// https://github.com/gorhill/uBlock/issues/162
// Be prepared to deal with possible change of src attribute.
if (dontObserve !== true) {
- if (iframeSourceObserver === undefined) {
+ if (iframeSourceObserver === undefined) {
iframeSourceObserver =
- new MutationObserver(iframeSourceModified);
- }
- iframeSourceObserver.observe(iframe,
- iframeSourceObserverOptions);
+ new MutationObserver(iframeSourceModified);
+ }
+ iframeSourceObserver.observe(iframe,
+ iframeSourceObserverOptions);
}
let src = iframe.src;
if (src === '' || typeof src !== 'string') {
- return;
- }
+ return;
+ }
if (src.startsWith('http') === false) {
- return;
- }
+ return;
+ }
toFilter.push({
- type: 'frame',
- url: iframe.src,
- });
+ type: 'frame',
+ url: iframe.src,
+ });
add(iframe);
- };
+ };
- let addIFrames = function (iframes) {
- for (let i=iframes.length-1; i>=0; --i) {
- addIFrame(iframes[i]);
+ let addIFrames = function (iframes) {
+ for (let i=iframes.length-1; i>=0; --i) {
+ addIFrame(iframes[i]);
}
- };
-
- let addNodeList = function (nodeList) {
- for (let i=nodeList.length-1; i>=0; --i) {
- let node = nodeList[i];
- if (node.nodeType !== 1) {
- continue;
- }
- if (node.localName === 'iframe') {
+ };
+
+ let addNodeList = function (nodeList) {
+ for (let i=nodeList.length-1; i>=0; --i) {
+ let node = nodeList[i];
+ if (node.nodeType !== 1) {
+ continue;
+ }
+ if (node.localName === 'iframe') {
addIFrame(node);
- }
- if (node.childElementCount !== 0) {
+ }
+ if (node.childElementCount !== 0) {
addIFrames(node.querySelectorAll('iframe'));
- }
+ }
}
- };
+ };
- let onResourceFailed = function (ev) {
+ let onResourceFailed = function (ev) {
if (tagToTypeMap[ev.target.localName] !== undefined) {
- add(ev.target);
- process();
+ add(ev.target);
+ process();
}
- };
- document.addEventListener('error', onResourceFailed, true);
+ };
+ document.addEventListener('error', onResourceFailed, true);
- vAPI.shutdown.add(function () {
+ vAPI.shutdown.add(function () {
document.removeEventListener('error', onResourceFailed, true);
if (iframeSourceObserver !== undefined) {
- iframeSourceObserver.disconnect();
- iframeSourceObserver = undefined;
+ iframeSourceObserver.disconnect();
+ iframeSourceObserver = undefined;
}
if (processTimer !== undefined) {
- clearTimeout(processTimer);
- processTimer = undefined;
+ clearTimeout(processTimer);
+ processTimer = undefined;
}
- });
+ });
- return {
+ return {
addMany: addMany,
addIFrames: addIFrames,
addNodeList: addNodeList,
process: process
- };
+ };
})();
// Observe changes in the DOM
// Added node lists will be cumulated here before being processed
(function () {
- // This fixes http://acid3.acidtests.org/
- if (!document.body) {
- return;
- }
+ // This fixes http://acid3.acidtests.org/
+ if (!document.body) {
+ return;
+ }
- let addedNodeLists = [];
- let addedNodeListsTimer;
+ let addedNodeLists = [];
+ let addedNodeListsTimer;
- let treeMutationObservedHandler = function () {
+ let treeMutationObservedHandler = function () {
addedNodeListsTimer = undefined;
- for (let i=addedNodeLists.length-1; i>=0; --i) {
- collapser.addNodeList(addedNodeLists[i]);
+ for (let i=addedNodeLists.length-1; i>=0; --i) {
+ collapser.addNodeList(addedNodeLists[i]);
}
collapser.process();
addedNodeLists = [];
- };
-
- // https://github.com/gorhill/uBlock/issues/205
- // Do not handle added node directly from within mutation observer.
- let treeMutationObservedHandlerAsync = function (mutations) {
- for (let i=mutations.length-1; i>=0; --i) {
- let nodeList = mutations[i].addedNodes;
- if (nodeList.length !== 0) {
+ };
+
+ // https://github.com/gorhill/uBlock/issues/205
+ // Do not handle added node directly from within mutation observer.
+ let treeMutationObservedHandlerAsync = function (mutations) {
+ for (let i=mutations.length-1; i>=0; --i) {
+ let nodeList = mutations[i].addedNodes;
+ if (nodeList.length !== 0) {
addedNodeLists.push(nodeList);
- }
+ }
}
if (addedNodeListsTimer === undefined) {
- addedNodeListsTimer =
- vAPI.setTimeout(treeMutationObservedHandler, 47);
+ addedNodeListsTimer =
+ vAPI.setTimeout(treeMutationObservedHandler, 47);
}
- };
+ };
- // https://github.com/gorhill/httpswitchboard/issues/176
- let treeObserver =
- new MutationObserver(treeMutationObservedHandlerAsync);
- treeObserver.observe(document.body, {
+ // https://github.com/gorhill/httpswitchboard/issues/176
+ let treeObserver =
+ new MutationObserver(treeMutationObservedHandlerAsync);
+ treeObserver.observe(document.body, {
childList: true,
subtree: true
- });
+ });
- vAPI.shutdown.add(function () {
+ vAPI.shutdown.add(function () {
if (addedNodeListsTimer !== undefined) {
- clearTimeout(addedNodeListsTimer);
- addedNodeListsTimer = undefined;
+ clearTimeout(addedNodeListsTimer);
+ addedNodeListsTimer = undefined;
}
if (treeObserver !== null) {
- treeObserver.disconnect();
- treeObserver = undefined;
+ treeObserver.disconnect();
+ treeObserver = undefined;
}
addedNodeLists = [];
- });
+ });
})();
// Executed only once.
@@ -437,58 +437,58 @@
// Report inline styles.
(function () {
- if (document.querySelector('script:not([src])') !== null
- || document.querySelector('a[href^="javascript:"]') !== null
- || document.querySelector('[onabort],[onblur],[oncancel],'
- + '[oncanplay],[oncanplaythrough],'
- + '[onchange],[onclick],[onclose],'
- + '[oncontextmenu],[oncuechange],'
- + '[ondblclick],[ondrag],[ondragend],'
- + '[ondragenter],[ondragexit],'
- + '[ondragleave],[ondragover],'
- + '[ondragstart],[ondrop],'
- + '[ondurationchange],[onemptied],'
- + '[onended],[onerror],[onfocus],'
- + '[oninput],[oninvalid],[onkeydown],'
- + '[onkeypress],[onkeyup],[onload],'
- + '[onloadeddata],[onloadedmetadata],'
- + '[onloadstart],[onmousedown],'
- + '[onmouseenter],[onmouseleave],'
- + '[onmousemove],[onmouseout],'
- + '[onmouseover],[onmouseup],[onwheel],'
- + '[onpause],[onplay],[onplaying],'
- + '[onprogress],[onratechange],[onreset],'
- + '[onresize],[onscroll],[onseeked],'
- + '[onseeking],[onselect],[onshow],'
- + '[onstalled],[onsubmit],[onsuspend],'
- + '[ontimeupdate],[ontoggle],'
- + '[onvolumechange],[onwaiting],'
- + '[onafterprint],[onbeforeprint],'
- + '[onbeforeunload],[onhashchange],'
- + '[onlanguagechange],[onmessage],'
- + '[onoffline],[ononline],[onpagehide],'
- + '[onpageshow],[onrejectionhandled],'
- + '[onpopstate],[onstorage],'
- + '[onunhandledrejection],[onunload],'
- + '[oncopy],[oncut],[onpaste]') !== null) {
+ if (document.querySelector('script:not([src])') !== null
+ || document.querySelector('a[href^="javascript:"]') !== null
+ || document.querySelector('[onabort],[onblur],[oncancel],'
+ + '[oncanplay],[oncanplaythrough],'
+ + '[onchange],[onclick],[onclose],'
+ + '[oncontextmenu],[oncuechange],'
+ + '[ondblclick],[ondrag],[ondragend],'
+ + '[ondragenter],[ondragexit],'
+ + '[ondragleave],[ondragover],'
+ + '[ondragstart],[ondrop],'
+ + '[ondurationchange],[onemptied],'
+ + '[onended],[onerror],[onfocus],'
+ + '[oninput],[oninvalid],[onkeydown],'
+ + '[onkeypress],[onkeyup],[onload],'
+ + '[onloadeddata],[onloadedmetadata],'
+ + '[onloadstart],[onmousedown],'
+ + '[onmouseenter],[onmouseleave],'
+ + '[onmousemove],[onmouseout],'
+ + '[onmouseover],[onmouseup],[onwheel],'
+ + '[onpause],[onplay],[onplaying],'
+ + '[onprogress],[onratechange],[onreset],'
+ + '[onresize],[onscroll],[onseeked],'
+ + '[onseeking],[onselect],[onshow],'
+ + '[onstalled],[onsubmit],[onsuspend],'
+ + '[ontimeupdate],[ontoggle],'
+ + '[onvolumechange],[onwaiting],'
+ + '[onafterprint],[onbeforeprint],'
+ + '[onbeforeunload],[onhashchange],'
+ + '[onlanguagechange],[onmessage],'
+ + '[onoffline],[ononline],[onpagehide],'
+ + '[onpageshow],[onrejectionhandled],'
+ + '[onpopstate],[onstorage],'
+ + '[onunhandledrejection],[onunload],'
+ + '[oncopy],[oncut],[onpaste]') !== null) {
vAPI.messaging.send('contentscript.js', {
- what: 'securityPolicyViolation',
- directive: 'script-src',
- documentURI: window.location.href
+ what: 'securityPolicyViolation',
+ directive: 'script-src',
+ documentURI: window.location.href
});
- }
+ }
- if (document.querySelector('style,[style]') !== null) {
+ if (document.querySelector('style,[style]') !== null) {
vAPI.messaging.send('contentscript.js', {
- what: 'securityPolicyViolation',
- directive: 'style-src',
- documentURI: window.location.href
+ what: 'securityPolicyViolation',
+ directive: 'style-src',
+ documentURI: window.location.href
});
- }
+ }
- collapser.addMany(document.querySelectorAll('img'));
- collapser.addIFrames(document.querySelectorAll('iframe'));
- collapser.process();
+ collapser.addMany(document.querySelectorAll('img'));
+ collapser.addIFrames(document.querySelectorAll('iframe'));
+ collapser.process();
})();
// Executed only once.
@@ -496,88 +496,88 @@
// Force `display` property, Firefox is still affected by the issue.
(function () {
- let noscripts = document.querySelectorAll('noscript');
- if (noscripts.length === 0) {
- return;
- }
+ let noscripts = document.querySelectorAll('noscript');
+ if (noscripts.length === 0) {
+ return;
+ }
- let redirectTimer;
+ let redirectTimer;
let reMetaContent = /^\s*(\d+)\s*;\s*url=(['"]?)([^'"]+)\2/i;
let reSafeURL = /^https?:\/\//;
- let autoRefresh = function (root) {
+ let autoRefresh = function (root) {
let meta =
- root.querySelector('meta[http-equiv="refresh"][content]');
+ root.querySelector('meta[http-equiv="refresh"][content]');
if (meta === null) {
- return;
- }
+ return;
+ }
let match = reMetaContent.exec(meta.getAttribute('content'));
if (match === null || match[3].trim() === '') {
- return;
- }
+ return;
+ }
let url = new URL(match[3], document.baseURI);
if (reSafeURL.test(url.href) === false) {
- return;
- }
+ return;
+ }
redirectTimer = setTimeout(function () {
location.assign(url.href);
- }, parseInt(match[1], 10) * 1000 + 1);
+ }, parseInt(match[1], 10) * 1000 + 1);
meta.parentNode.removeChild(meta);
- };
+ };
- let morphNoscript = function (from) {
+ let morphNoscript = function (from) {
if (/^application\/(?:xhtml\+)?xml/.test(document.contentType)) {
- let to = document.createElement('span');
- while (from.firstChild !== null) {
+ let to = document.createElement('span');
+ while (from.firstChild !== null) {
to.appendChild(from.firstChild);
- }
- return to;
+ }
+ return to;
}
let parser = new DOMParser();
let doc =
- parser.parseFromString('<span>' + from.textContent + '</span>',
- 'text/html');
+ parser.parseFromString('<span>' + from.textContent + '</span>',
+ 'text/html');
return document.adoptNode(doc.querySelector('span'));
- };
+ };
- let renderNoscriptTags = function (response) {
+ let renderNoscriptTags = function (response) {
if (response !== true) {
- return;
- }
+ return;
+ }
for (let noscript of noscripts) {
- let parent = noscript.parentNode;
- if (parent === null) {
- continue;
- }
+ let parent = noscript.parentNode;
+ if (parent === null) {
+ continue;
+ }
- let span = morphNoscript(noscript);
- span.style.setProperty('display', 'inline', 'important');
+ let span = morphNoscript(noscript);
+ span.style.setProperty('display', 'inline', 'important');
- if (redirectTimer === undefined) {
+ if (redirectTimer === undefined) {
autoRefresh(span);
- }
+ }
- parent.replaceChild(span, noscript);
+ parent.replaceChild(span, noscript);
}
- };
+ };
- vAPI.messaging.send('contentscript.js', {
- what: 'mustRenderNoscriptTags?'
- }, renderNoscriptTags);
+ vAPI.messaging.send('contentscript.js', {
+ what: 'mustRenderNoscriptTags?'
+ }, renderNoscriptTags);
})();
vAPI.messaging.send('contentscript.js', {
- what: 'shutdown?'
+ what: 'shutdown?'
}, function (response) {
if (response === true) {
- vAPI.shutdown.exec();
+ vAPI.shutdown.exec();
}
});
})();
diff --git a/js/cookies.js b/js/cookies.js
index 217468b..b176fbb 100644
--- a/js/cookies.js
+++ b/js/cookies.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2013-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -50,205 +50,205 @@
// Look for cookies to record for a specific web page
let recordPageCookiesAsync = function (pageStats) {
- // Store the page stats objects so that it doesn't go away
- // before we handle the job.
- // rhill 2013-10-19: pageStats could be nil, for example, this can
- // happens if a file:// ... makes an xmlHttpRequest
- if (!pageStats) {
+ // Store the page stats objects so that it doesn't go away
+ // before we handle the job.
+ // rhill 2013-10-19: pageStats could be nil, for example, this can
+ // happens if a file:// ... makes an xmlHttpRequest
+ if (!pageStats) {
return;
- }
- recordPageCookiesQueue.set(pageStats.pageUrl, pageStats);
- if (processPageRecordQueueTimer === null) {
+ }
+ recordPageCookiesQueue.set(pageStats.pageUrl, pageStats);
+ if (processPageRecordQueueTimer === null) {
processPageRecordQueueTimer =
- vAPI.setTimeout(processPageRecordQueue, 1000);
- }
+ vAPI.setTimeout(processPageRecordQueue, 1000);
+ }
};
let cookieLogEntryBuilder = [
- '',
- '{',
- '',
- '-cookie:',
- '',
- '}'
+ '',
+ '{',
+ '',
+ '-cookie:',
+ '',
+ '}'
];
let recordPageCookie = function (pageStore, key) {
- if (vAPI.isBehindTheSceneTabId(pageStore.tabId)) {
+ if (vAPI.isBehindTheSceneTabId(pageStore.tabId)) {
+ return;
+ }
+
+ let entry = CookieCache.get(key);
+ let pageHostname = pageStore.pageHostname;
+ let block = ηm.mustBlock(pageHostname, entry.hostname, 'cookie');
+
+ cookieLogEntryBuilder[0] = CookieUtils.urlFromEntry(entry);
+ cookieLogEntryBuilder[2] = entry.session ? 'session' : 'persistent';
+ cookieLogEntryBuilder[4] = encodeURIComponent(entry.name);
+
+ let cookieURL = cookieLogEntryBuilder.join('');
+
+ // rhill 2013-11-20:
+ // https://github.com/gorhill/httpswitchboard/issues/60
+ // Need to URL-encode cookie name
+ pageStore.recordRequest('cookie', cookieURL, block);
+ ηm.logger.writeOne(pageStore.tabId, 'net',
+ pageHostname, cookieURL, 'cookie', block);
+
+ entry.usedOn.add(pageHostname);
+
+ // rhill 2013-11-21:
+ // https://github.com/gorhill/httpswitchboard/issues/65
+ // Leave alone cookies from behind-the-scene requests if
+ // behind-the-scene processing is disabled.
+ if (!block) {
return;
- }
-
- let entry = CookieCache.get(key);
- let pageHostname = pageStore.pageHostname;
- let block = ηm.mustBlock(pageHostname, entry.hostname, 'cookie');
-
- cookieLogEntryBuilder[0] = CookieUtils.urlFromEntry(entry);
- cookieLogEntryBuilder[2] = entry.session ? 'session' : 'persistent';
- cookieLogEntryBuilder[4] = encodeURIComponent(entry.name);
-
- let cookieURL = cookieLogEntryBuilder.join('');
-
- // rhill 2013-11-20:
- // https://github.com/gorhill/httpswitchboard/issues/60
- // Need to URL-encode cookie name
- pageStore.recordRequest('cookie', cookieURL, block);
- ηm.logger.writeOne(pageStore.tabId, 'net',
- pageHostname, cookieURL, 'cookie', block);
-
- entry.usedOn.add(pageHostname);
-
- // rhill 2013-11-21:
- // https://github.com/gorhill/httpswitchboard/issues/65
- // Leave alone cookies from behind-the-scene requests if
- // behind-the-scene processing is disabled.
- if (!block) {
- return;
- }
- if (!ηm.userSettings.deleteCookies) {
+ }
+ if (!ηm.userSettings.deleteCookies) {
return;
- }
- removeCookieAsync(key);
+ }
+ removeCookieAsync(key);
};
// Look for cookies to potentially remove for a specific web page
let removePageCookiesAsync = function (pageStats) {
- // Hold onto pageStats objects so that it doesn't go away
- // before we handle the job.
- // rhill 2013-10-19: pageStats could be nil, for example, this can
- // happens if a file:// ... makes an xmlHttpRequest
- if (!pageStats) {
+ // Hold onto pageStats objects so that it doesn't go away
+ // before we handle the job.
+ // rhill 2013-10-19: pageStats could be nil, for example, this can
+ // happens if a file:// ... makes an xmlHttpRequest
+ if (!pageStats) {
return;
- }
- removePageCookiesQueue.set(pageStats.pageUrl, pageStats);
- if (processPageRemoveQueueTimer === null) {
+ }
+ removePageCookiesQueue.set(pageStats.pageUrl, pageStats);
+ if (processPageRemoveQueueTimer === null) {
processPageRemoveQueueTimer =
- vAPI.setTimeout(processPageRemoveQueue, 15 * 1000);
- }
+ vAPI.setTimeout(processPageRemoveQueue, 15 * 1000);
+ }
};
// Candidate for removal
let removeCookieAsync = function (key) {
- removeCookieQueue.add(key);
+ removeCookieQueue.add(key);
};
let chromeCookieRemove = function (entry, name) {
- let url = CookieUtils.urlFromEntry(entry);
- if (url === '') {
+ let url = CookieUtils.urlFromEntry(entry);
+ if (url === '') {
return;
- }
- let sessionKey = CookieUtils.keyFromURL(UriTools.set(url),
- 'session', name);
- let persistKey = CookieUtils.keyFromURL(UriTools.set(url),
- 'persistent', name);
+ }
+ let sessionKey = CookieUtils.keyFromURL(UriTools.set(url),
+ 'session', name);
+ let persistKey = CookieUtils.keyFromURL(UriTools.set(url),
+ 'persistent', name);
- let callback = function(details) {
+ let callback = function(details) {
let success = !!details;
let template = success ?
- i18nCookieDeleteSuccess :
- i18nCookieDeleteFailure;
+ i18nCookieDeleteSuccess :
+ i18nCookieDeleteFailure;
if (CookieCache.remove(sessionKey)) {
- if (success) {
+ if (success) {
ηm.cookieRemovedCounter += 1;
- }
- ηm.logger.writeOne('', 'info', 'cookie',
- template.replace('{{value}}',
- sessionKey));
+ }
+ ηm.logger.writeOne('', 'info', 'cookie',
+ template.replace('{{value}}',
+ sessionKey));
}
if (CookieCache.remove(persistKey)) {
- if (success) {
+ if (success) {
ηm.cookieRemovedCounter += 1;
- }
- ηm.logger.writeOne('', 'info', 'cookie',
- template.replace('{{value}}',
- persistKey));
+ }
+ ηm.logger.writeOne('', 'info', 'cookie',
+ template.replace('{{value}}',
+ persistKey));
}
- };
+ };
- vAPI.cookies.remove({
- url: url, name: name
- }, callback);
+ vAPI.cookies.remove({
+ url: url, name: name
+ }, callback);
};
let i18nCookieDeleteSuccess = vAPI.i18n('loggerEntryCookieDeleted');
let i18nCookieDeleteFailure = vAPI.i18n('loggerEntryDeleteCookieError');
let processPageRecordQueue = function () {
- processPageRecordQueueTimer = null;
+ processPageRecordQueueTimer = null;
- for (let pageStore of recordPageCookiesQueue.values()) {
+ for (let pageStore of recordPageCookiesQueue.values()) {
findAndRecordPageCookies(pageStore);
- }
- recordPageCookiesQueue.clear();
+ }
+ recordPageCookiesQueue.clear();
};
let processPageRemoveQueue = function () {
- processPageRemoveQueueTimer = null;
+ processPageRemoveQueueTimer = null;
- for (let pageStore of removePageCookiesQueue.values()) {
+ for (let pageStore of removePageCookiesQueue.values()) {
findAndRemovePageCookies(pageStore);
- }
- removePageCookiesQueue.clear();
+ }
+ removePageCookiesQueue.clear();
};
// Effectively remove cookies.
let processRemoveQueue = function () {
- let userSettings = ηm.userSettings;
- let deleteCookies = userSettings.deleteCookies;
-
- // Session cookies which timestamp is *after* tstampObsolete will
- // be left untouched
- // https://github.com/gorhill/httpswitchboard/issues/257
- let dusc = userSettings.deleteUnusedSessionCookies;
- let dusca = userSettings.deleteUnusedSessionCookiesAfter;
- let tstampObsolete = dusc ?
- Date.now() - dusca * 60 * 1000 :
+ let userSettings = ηm.userSettings;
+ let deleteCookies = userSettings.deleteCookies;
+
+ // Session cookies which timestamp is *after* tstampObsolete will
+ // be left untouched
+ // https://github.com/gorhill/httpswitchboard/issues/257
+ let dusc = userSettings.deleteUnusedSessionCookies;
+ let dusca = userSettings.deleteUnusedSessionCookiesAfter;
+ let tstampObsolete = dusc ?
+ Date.now() - dusca * 60 * 1000 :
0;
- let srcHostnames;
- let entry;
+ let srcHostnames;
+ let entry;
- for (let key of removeCookieQueue) {
+ for (let key of removeCookieQueue) {
// rhill 2014-05-12: Apparently this can happen. I have to
// investigate how (A session cookie has same name as a
// persistent cookie?)
entry = CookieCache.get(key);
if (entry === undefined) {
- continue;
- }
+ continue;
+ }
// Delete obsolete session cookies: enabled.
if (tstampObsolete !== 0 && entry.session) {
- if (entry.tstamp < tstampObsolete) {
+ if (entry.tstamp < tstampObsolete) {
chromeCookieRemove(entry, entry.name);
continue;
- }
+ }
}
// Delete all blocked cookies: disabled.
if (deleteCookies === false) {
- continue;
+ continue;
}
// Query scopes only if we are going to use them
if (srcHostnames === undefined) {
- srcHostnames = ηm.tMatrix.extractAllSourceHostnames();
+ srcHostnames = ηm.tMatrix.extractAllSourceHostnames();
}
// Ensure cookie is not allowed on ALL current web pages: It can
// happen that a cookie is blacklisted on one web page while
// being whitelisted on another (because of per-page permissions).
if (canRemoveCookie(key, srcHostnames)) {
- chromeCookieRemove(entry, entry.name);
+ chromeCookieRemove(entry, entry.name);
}
- }
+ }
- removeCookieQueue.clear();
+ removeCookieQueue.clear();
- vAPI.setTimeout(processRemoveQueue, processRemoveQueuePeriod);
+ vAPI.setTimeout(processRemoveQueue, processRemoveQueuePeriod);
};
// Once in a while, we go ahead and clean everything that might have been
@@ -258,145 +258,145 @@
// maybe a user has 1000s of cookies sitting in his browser...
let processClean = function () {
- let us = ηm.userSettings;
+ let us = ηm.userSettings;
- if (us.deleteCookies || us.deleteUnusedSessionCookies) {
+ if (us.deleteCookies || us.deleteUnusedSessionCookies) {
let keys = Array.from(CookieCache.keys());
- let len = keys.length;
- let step, offset, n;
+ let len = keys.length;
+ let step, offset, n;
if (len > 25) {
- step = len / 25;
- offset = Math.floor(Math.random() * len);
- n = 25;
+ step = len / 25;
+ offset = Math.floor(Math.random() * len);
+ n = 25;
} else {
- step = 1;
- offset = 0;
- n = len;
+ step = 1;
+ offset = 0;
+ n = len;
}
let i = offset;
while (n--) {
- removeCookieAsync(keys[Math.floor(i % len)]);
- i += step;
+ removeCookieAsync(keys[Math.floor(i % len)]);
+ i += step;
}
- }
+ }
- vAPI.setTimeout(processClean, processCleanPeriod);
+ vAPI.setTimeout(processClean, processCleanPeriod);
};
let findAndRecordPageCookies = function (pageStore) {
- for (let key of CookieCache.keys()) {
+ for (let key of CookieCache.keys()) {
if (CookieUtils.matchDomains(key, pageStore.allHostnamesString)) {
- recordPageCookie(pageStore, key);
+ recordPageCookie(pageStore, key);
}
- }
+ }
};
let findAndRemovePageCookies = function (pageStore) {
- for (let key of CookieCache.keys()) {
+ for (let key of CookieCache.keys()) {
if (CookieUtils.matchDomains(key, pageStore.allHostnamesString)) {
- removeCookieAsync(key);
+ removeCookieAsync(key);
}
- }
+ }
};
let canRemoveCookie = function (key, srcHostnames) {
- let entry = CookieCache.get(key);
- if (entry === undefined) {
- return false;
- }
+ let entry = CookieCache.get(key);
+ if (entry === undefined) {
+ return false;
+ }
- let cookieHostname = entry.hostname;
- let srcHostname;
+ let cookieHostname = entry.hostname;
+ let srcHostname;
- for (srcHostname of entry.usedOn) {
+ for (srcHostname of entry.usedOn) {
if (ηm.mustAllow(srcHostname, cookieHostname, 'cookie')) {
- return false;
+ return false;
}
- }
+ }
- // Maybe there is a scope in which the cookie is 1st-party-allowed.
- // For example, if I am logged in into `github.com`, I do not want to be
- // logged out just because I did not yet open a `github.com` page after
- // re-starting the browser.
- srcHostname = cookieHostname;
+ // Maybe there is a scope in which the cookie is 1st-party-allowed.
+ // For example, if I am logged in into `github.com`, I do not want to be
+ // logged out just because I did not yet open a `github.com` page after
+ // re-starting the browser.
+ srcHostname = cookieHostname;
- let pos;
+ let pos;
- for (;;) {
+ for (;;) {
if (srcHostnames.has(srcHostname)) {
- if (ηm.mustAllow(srcHostname, cookieHostname, 'cookie')) {
+ if (ηm.mustAllow(srcHostname, cookieHostname, 'cookie')) {
return false;
- }
+ }
}
if (srcHostname === entry.domain) {
- break;
+ break;
}
pos = srcHostname.indexOf('.');
if (pos === -1) {
- break;
+ break;
}
srcHostname = srcHostname.slice(pos + 1);
- }
- return true;
+ }
+ return true;
};
// Listen to any change in cookieland, we will update page stats accordingly.
vAPI.cookies.onChanged = function (cookie) {
- // rhill 2013-12-11: If cookie value didn't change, no need to record.
- // https://github.com/gorhill/httpswitchboard/issues/79
- let key = CookieUtils.keyFromCookie(cookie);
- let entry = CookieCache.get(key);
+ // rhill 2013-12-11: If cookie value didn't change, no need to record.
+ // https://github.com/gorhill/httpswitchboard/issues/79
+ let key = CookieUtils.keyFromCookie(cookie);
+ let entry = CookieCache.get(key);
- if (entry === undefined) {
+ if (entry === undefined) {
entry = CookieCache.add(cookie);
- } else {
+ } else {
entry.tstamp = Date.now();
if (cookie.value === entry.value) {
- return;
- }
+ return;
+ }
entry.value = cookie.value;
- }
+ }
- // Go through all pages and update if needed, as one cookie can be used
- // by many web pages, so they need to be recorded for all these pages.
- let pageStores = ηm.pageStores;
- let pageStore;
- for (let tabId in pageStores) {
+ // Go through all pages and update if needed, as one cookie can be used
+ // by many web pages, so they need to be recorded for all these pages.
+ let pageStores = ηm.pageStores;
+ let pageStore;
+ for (let tabId in pageStores) {
if (pageStores.hasOwnProperty(tabId) === false) {
- continue;
+ continue;
}
pageStore = pageStores[tabId];
if (!CookieUtils.matchDomains(key, pageStore.allHostnamesString)) {
- continue;
+ continue;
}
recordPageCookie(pageStore, key);
- }
+ }
};
// Listen to any change in cookieland, we will update page stats accordingly.
vAPI.cookies.onRemoved = function (cookie) {
- let key = CookieUtils.keyFromCookie(cookie);
- if (CookieCache.remove(key)) {
+ let key = CookieUtils.keyFromCookie(cookie);
+ if (CookieCache.remove(key)) {
ηm.logger.writeOne('', 'info', 'cookie',
- i18nCookieDeleteSuccess.replace('{{value}}',
- key));
- }
+ i18nCookieDeleteSuccess.replace('{{value}}',
+ key));
+ }
};
// Listen to any change in cookieland, we will update page stats accordingly.
vAPI.cookies.onAllRemoved = function () {
- for (let key of CookieCache.keys()) {
+ for (let key of CookieCache.keys()) {
if (CookieCache.remove(key)) {
- ηm.logger.writeOne('', 'info', 'cookie',
- i18nCookieDeleteSuccess.replace('{{value}}',
- key));
+ ηm.logger.writeOne('', 'info', 'cookie',
+ i18nCookieDeleteSuccess.replace('{{value}}',
+ key));
}
- }
+ }
};
vAPI.cookies.getAll(CookieCache.addVector);
@@ -408,7 +408,7 @@
// Expose only what is necessary
return {
- recordPageCookies: recordPageCookiesAsync,
- removePageCookies: removePageCookiesAsync
+ recordPageCookies: recordPageCookiesAsync,
+ removePageCookies: removePageCookiesAsync
};
})();
diff --git a/js/dashboard-common.js b/js/dashboard-common.js
index 677a3f3..b0eb9cf 100644
--- a/js/dashboard-common.js
+++ b/js/dashboard-common.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -28,8 +28,8 @@ uDom.onLoad(function () {
uDom('a').attr('target', '_blank');
uDom('a[href*="dashboard.html"]').attr('target', '_parent');
uDom('.whatisthis').on('click', function () {
- uDom(this)
- .parent()
+ uDom(this)
+ .parent()
.descendants('.whatisthis-expandable')
.toggleClass('whatisthis-expanded');
});
diff --git a/js/dashboard.js b/js/dashboard.js
index 8e565f6..6a466be 100644
--- a/js/dashboard.js
+++ b/js/dashboard.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -30,7 +30,7 @@
uDom('iframe').attr('src', url);
uDom('.tabButton').forEach(function (button) {
button.toggleClass('selected',
- button.attr('data-dashboard-panel-url') === url);
+ button.attr('data-dashboard-panel-url') === url);
});
};
diff --git a/js/hosts-files.js b/js/hosts-files.js
index b2f19f6..92a7efc 100644
--- a/js/hosts-files.js
+++ b/js/hosts-files.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -30,104 +30,104 @@
let reValidExternalList = /[a-z-]+:\/\/\S*\/\S+/;
vAPI.messaging.addListener(function (msg) {
- switch (msg.what) {
- case 'assetUpdated':
+ switch (msg.what) {
+ case 'assetUpdated':
updateAssetStatus(msg);
break;
- case 'assetsUpdated':
+ case 'assetsUpdated':
document.body.classList.remove('updating');
break;
- case 'loadHostsFilesCompleted':
+ case 'loadHostsFilesCompleted':
renderHostsFiles();
break;
- default:
+ default:
break;
- }
+ }
});
let renderNumber = function (value) {
- return value.toLocaleString();
+ return value.toLocaleString();
};
let renderHostsFiles = function (soft) {
- let listEntryTemplate = uDom('#templates .listEntry');
+ let listEntryTemplate = uDom('#templates .listEntry');
let listStatsTemplate = vAPI.i18n('hostsFilesPerFileStats');
let renderETTS = vAPI.i18n.renderElapsedTimeToString;
let reExternalHostFile = /^https?:/;
- // Assemble a pretty list name if possible
- let listNameFromListKey = function (listKey) {
+ // Assemble a pretty list name if possible
+ let listNameFromListKey = function (listKey) {
let list =
- listDetails.current[listKey] || listDetails.available[listKey];
+ listDetails.current[listKey] || listDetails.available[listKey];
let listTitle = list ? list.title : '';
if (listTitle === '') {
- return listKey;
- }
+ return listKey;
+ }
return listTitle;
- };
+ };
- let liFromListEntry = function (listKey, li) {
+ let liFromListEntry = function (listKey, li) {
let entry = listDetails.available[listKey];
- let elem;
+ let elem;
if (!li) {
- li = listEntryTemplate.clone().nodeAt(0);
+ li = listEntryTemplate.clone().nodeAt(0);
}
if (li.getAttribute('data-listkey') !== listKey) {
- li.setAttribute('data-listkey', listKey);
+ li.setAttribute('data-listkey', listKey);
- elem = li.querySelector('input[type="checkbox"]');
- elem.checked = (entry.off !== true);
- elem = li.querySelector('a:nth-of-type(1)');
- elem.setAttribute('href',
- 'asset-viewer.html?url=' + encodeURI(listKey));
- elem.setAttribute('type', 'text/html');
- elem.textContent = listNameFromListKey(listKey);
+ elem = li.querySelector('input[type="checkbox"]');
+ elem.checked = (entry.off !== true);
+ elem = li.querySelector('a:nth-of-type(1)');
+ elem.setAttribute('href',
+ 'asset-viewer.html?url=' + encodeURI(listKey));
+ elem.setAttribute('type', 'text/html');
+ elem.textContent = listNameFromListKey(listKey);
- li.classList.remove('toRemove');
+ li.classList.remove('toRemove');
- if (entry.supportName) {
+ if (entry.supportName) {
li.classList.add('support');
elem = li.querySelector('a.support');
elem.setAttribute('href', entry.supportURL);
elem.setAttribute('title', entry.supportName);
- } else {
+ } else {
li.classList.remove('support');
- }
+ }
- if (entry.external) {
+ if (entry.external) {
li.classList.add('external');
- } else {
+ } else {
li.classList.remove('external');
- }
+ }
- if (entry.instructionURL) {
+ if (entry.instructionURL) {
li.classList.add('mustread');
elem = li.querySelector('a.mustread');
elem.setAttribute('href', entry.instructionURL);
- } else {
+ } else {
li.classList.remove('mustread');
- }
+ }
}
// https://github.com/gorhill/uBlock/issues/1429
if (!soft) {
- elem = li.querySelector('input[type="checkbox"]');
- elem.checked = entry.off !== true;
+ elem = li.querySelector('input[type="checkbox"]');
+ elem.checked = entry.off !== true;
}
elem = li.querySelector('span.counts');
let text = '';
if (!isNaN(+entry.entryUsedCount) && !isNaN(+entry.entryCount)) {
- text = listStatsTemplate
+ text = listStatsTemplate
.replace('{{used}}',
- renderNumber(entry.off ? 0 : entry.entryUsedCount))
+ renderNumber(entry.off ? 0 : entry.entryUsedCount))
.replace('{{total}}',
- renderNumber(entry.entryCount));
+ renderNumber(entry.entryCount));
}
elem.textContent = text;
@@ -137,26 +137,26 @@
let remoteURL = asset.remoteURL;
li.classList.toggle('unsecure',
- typeof remoteURL === 'string'
- && remoteURL.lastIndexOf('http:', 0) === 0);
+ typeof remoteURL === 'string'
+ && remoteURL.lastIndexOf('http:', 0) === 0);
li.classList.toggle('failed', asset.error !== undefined);
li.classList.toggle('obsolete', asset.obsolete === true);
li.classList.toggle('cached',
- asset.cached === true && asset.writeTime > 0);
+ asset.cached === true && asset.writeTime > 0);
if (asset.cached) {
- li.querySelector('.status.cache')
- .setAttribute('title',
- lastUpdateTemplateString
- .replace('{{ago}}',
- renderETTS(asset.writeTime)));
+ li.querySelector('.status.cache')
+ .setAttribute('title',
+ lastUpdateTemplateString
+ .replace('{{ago}}',
+ renderETTS(asset.writeTime)));
}
li.classList.remove('discard');
return li;
- };
+ };
- let onListsReceived = function (details) {
+ let onListsReceived = function (details) {
// Before all, set context vars
listDetails = details;
@@ -165,225 +165,227 @@
uDom('#lists .listEntry').addClass('discard');
let availableLists = details.available;
- let listKeys = Object.keys(details.available);
+ let listKeys = Object.keys(details.available);
// Sort works this way:
// - Send /^https?:/ items at the end (custom hosts file URL)
listKeys.sort(function (a, b) {
- let ta = availableLists[a].title || a;
+ let ta = availableLists[a].title || a;
let tb = availableLists[b].title || b;
+ let ca = reExternalHostFile.test(ta);
+ let cb = reExternalHostFile.test(tb);
- if (reExternalHostFile.test(ta) === reExternalHostFile.test(tb)) {
+ if (ca === cb) {
return ta.localeCompare(tb);
- }
+ }
- return reExternalHostFile.test(tb) ? -1 : 1;
+ return (cb) ? -1 : 1;
});
let ulList = document.querySelector('#lists');
for (let i=0; i<listKeys.length; ++i) {
- let liEntry = liFromListEntry(listKeys[i], ulList.children[i]);
- if (liEntry.parentElement === null) {
+ let liEntry = liFromListEntry(listKeys[i], ulList.children[i]);
+ if (liEntry.parentElement === null) {
ulList.appendChild(liEntry);
- }
+ }
}
uDom('#lists .listEntry.discard').remove();
uDom('#listsOfBlockedHostsPrompt')
- .text(vAPI.i18n('hostsFilesStats')
- .replace('{{blockedHostnameCount}}',
- renderNumber(details.blockedHostnameCount)));
+ .text(vAPI.i18n('hostsFilesStats')
+ .replace('{{blockedHostnameCount}}',
+ renderNumber(details.blockedHostnameCount)));
uDom('#autoUpdate').prop('checked',
- listDetails.autoUpdate === true);
+ listDetails.autoUpdate === true);
if (!soft) {
- hostsFilesSettingsHash = hashFromCurrentFromSettings();
+ hostsFilesSettingsHash = hashFromCurrentFromSettings();
}
renderWidgets();
- };
+ };
- vAPI.messaging.send('hosts-files.js', {
- what: 'getLists'
- }, onListsReceived);
+ vAPI.messaging.send('hosts-files.js', {
+ what: 'getLists'
+ }, onListsReceived);
};
let renderWidgets = function () {
- let sel1 =
- 'body:not(.updating) #lists .listEntry.obsolete '
- + '> input[type="checkbox"]:checked';
- let sel2 = '#lists .listEntry.cached';
-
- uDom('#buttonUpdate')
- .toggleClass('disabled', document.querySelector(sel1) === null);
- uDom('#buttonPurgeAll')
- .toggleClass('disabled', document.querySelector(sel2) === null);
- uDom('#buttonApply')
- .toggleClass('disabled',
- hostsFilesSettingsHash ===
- hashFromCurrentFromSettings());
+ let sel1 =
+ 'body:not(.updating) #lists .listEntry.obsolete '
+ + '> input[type="checkbox"]:checked';
+ let sel2 = '#lists .listEntry.cached';
+
+ uDom('#buttonUpdate')
+ .toggleClass('disabled', document.querySelector(sel1) === null);
+ uDom('#buttonPurgeAll')
+ .toggleClass('disabled', document.querySelector(sel2) === null);
+ uDom('#buttonApply')
+ .toggleClass('disabled',
+ hostsFilesSettingsHash ===
+ hashFromCurrentFromSettings());
};
let updateAssetStatus = function (details) {
- let li = document
- .querySelector('#lists .listEntry[data-listkey="'+details.key+'"]');
- if (li === null) {
- return;
- }
-
- li.classList.toggle('failed', !!details.failed);
- li.classList.toggle('obsolete', !details.cached);
- li.classList.toggle('cached', !!details.cached);
-
- if (details.cached) {
- let str = vAPI.i18n.renderElapsedTimeToString(Date.now());
+ let li = document
+ .querySelector('#lists .listEntry[data-listkey="'+details.key+'"]');
+ if (li === null) {
+ return;
+ }
+
+ li.classList.toggle('failed', !!details.failed);
+ li.classList.toggle('obsolete', !details.cached);
+ li.classList.toggle('cached', !!details.cached);
+
+ if (details.cached) {
+ let str = vAPI.i18n.renderElapsedTimeToString(Date.now());
li.querySelector('.status.cache')
- .setAttribute('title',
- lastUpdateTemplateString.replace('{{ago}}', str));
- }
+ .setAttribute('title',
+ lastUpdateTemplateString.replace('{{ago}}', str));
+ }
- renderWidgets();
+ renderWidgets();
};
/**
- Compute a hash from all the settings affecting how filter lists are loaded
- in memory.
+ Compute a hash from all the settings affecting how filter lists are loaded
+ in memory.
**/
let hashFromCurrentFromSettings = function () {
- let hash = [];
+ let hash = [];
let listHash = [];
- let sel = '#lists .listEntry[data-listkey]:not(.toRemove)';
- let ext = 'externalHostsFiles';
+ let sel = '#lists .listEntry[data-listkey]:not(.toRemove)';
+ let ext = 'externalHostsFiles';
let listEntries = document.querySelectorAll(sel);
for (let i=listEntries.length-1; i>=0; --i) {
let li = listEntries[i];
if (li.querySelector('input[type="checkbox"]:checked') !== null) {
- listHash.push(li.getAttribute('data-listkey'));
+ listHash.push(li.getAttribute('data-listkey'));
}
- }
+ }
- hash.push(listHash.sort().join(),
- reValidExternalList.test(document.getElementById(ext).value),
- document.querySelector('#lists .listEntry.toRemove') !== null);
+ hash.push(listHash.sort().join(),
+ reValidExternalList.test(document.getElementById(ext).value),
+ document.querySelector('#lists .listEntry.toRemove') !== null);
- return hash.join();
+ return hash.join();
};
let onHostsFilesSettingsChanged = function () {
- renderWidgets();
+ renderWidgets();
};
let onRemoveExternalHostsFile = function (ev) {
- let liEntry = uDom(this).ancestors('[data-listkey]');
+ let liEntry = uDom(this).ancestors('[data-listkey]');
let listKey = liEntry.attr('data-listkey');
- if (listKey) {
+ if (listKey) {
liEntry.toggleClass('toRemove');
renderWidgets();
- }
+ }
- ev.preventDefault();
+ ev.preventDefault();
};
let onPurgeClicked = function () {
- let button = uDom(this);
+ let button = uDom(this);
let liEntry = button.ancestors('[data-listkey]');
let listKey = liEntry.attr('data-listkey');
- if (!listKey) {
- return;
- }
+ if (!listKey) {
+ return;
+ }
- vAPI.messaging.send('hosts-files.js', {
- what: 'purgeCache',
- assetKey: listKey
- });
+ vAPI.messaging.send('hosts-files.js', {
+ what: 'purgeCache',
+ assetKey: listKey
+ });
- liEntry.addClass('obsolete');
- liEntry.removeClass('cached');
+ liEntry.addClass('obsolete');
+ liEntry.removeClass('cached');
- if (liEntry.descendants('input').first().prop('checked')) {
+ if (liEntry.descendants('input').first().prop('checked')) {
renderWidgets();
- }
+ }
};
let selectHostsFiles = function (callback) {
- // Hosts files to select
- let toSelect = [];
- let sel = '#lists .listEntry[data-listkey]:not(.toRemove)';
- let sel2 = '#lists .listEntry.toRemove[data-listkey]';
+ // Hosts files to select
+ let toSelect = [];
+ let sel = '#lists .listEntry[data-listkey]:not(.toRemove)';
+ let sel2 = '#lists .listEntry.toRemove[data-listkey]';
let liEntries = document.querySelectorAll(sel);
for (let i=liEntries.length-1; i>=0; --i) {
let li = liEntries[i];
if (li.querySelector('input[type="checkbox"]:checked') !== null) {
- toSelect.push(li.getAttribute('data-listkey'));
+ toSelect.push(li.getAttribute('data-listkey'));
}
- }
+ }
- // External hosts files to remove
- let toRemove = [];
- liEntries = document.querySelectorAll(sel2);
+ // External hosts files to remove
+ let toRemove = [];
+ liEntries = document.querySelectorAll(sel2);
- for (let i=liEntries.length-1; i>=0; --i) {
+ for (let i=liEntries.length-1; i>=0; --i) {
toRemove.push(liEntries[i].getAttribute('data-listkey'));
- }
+ }
- // External hosts files to import
- let externalListsElem = document.getElementById('externalHostsFiles');
+ // External hosts files to import
+ let externalListsElem = document.getElementById('externalHostsFiles');
let toImport = externalListsElem.value.trim();
- externalListsElem.value = '';
+ externalListsElem.value = '';
- vAPI.messaging.send('hosts-files.js', {
- what: 'selectHostsFiles',
- toSelect: toSelect,
- toImport: toImport,
- toRemove: toRemove
+ vAPI.messaging.send('hosts-files.js', {
+ what: 'selectHostsFiles',
+ toSelect: toSelect,
+ toImport: toImport,
+ toRemove: toRemove
}, callback);
- hostsFilesSettingsHash = hashFromCurrentFromSettings();
+ hostsFilesSettingsHash = hashFromCurrentFromSettings();
};
let buttonApplyHandler = function () {
- uDom('#buttonApply').removeClass('enabled');
- selectHostsFiles(function () {
+ uDom('#buttonApply').removeClass('enabled');
+ selectHostsFiles(function () {
vAPI.messaging.send('hosts-files.js', {
- what: 'reloadHostsFiles'
- });
- });
+ what: 'reloadHostsFiles'
+ });
+ });
- renderWidgets();
+ renderWidgets();
};
let buttonUpdateHandler = function () {
- uDom('#buttonUpdate').removeClass('enabled');
- selectHostsFiles(function () {
+ uDom('#buttonUpdate').removeClass('enabled');
+ selectHostsFiles(function () {
document.body.classList.add('updating');
vAPI.messaging.send('hosts-files.js', {
- what: 'forceUpdateAssets'
- });
+ what: 'forceUpdateAssets'
+ });
renderWidgets();
- });
- renderWidgets();
+ });
+ renderWidgets();
};
let buttonPurgeAllHandler = function () {
- uDom('#buttonPurgeAll').removeClass('enabled');
- vAPI.messaging.send('hosts-files.js', {
- what: 'purgeAllCaches'
- }, function () {
- renderHostsFiles(true);
+ uDom('#buttonPurgeAll').removeClass('enabled');
+ vAPI.messaging.send('hosts-files.js', {
+ what: 'purgeAllCaches'
+ }, function () {
+ renderHostsFiles(true);
});
};
let autoUpdateCheckboxChanged = function () {
- vAPI.messaging.send('hosts-files.js', {
- what: 'userSettings',
- name: 'autoUpdate',
- value: this.checked
+ vAPI.messaging.send('hosts-files.js', {
+ what: 'userSettings',
+ name: 'autoUpdate',
+ value: this.checked
});
};
@@ -392,9 +394,9 @@
uDom('#buttonUpdate').on('click', buttonUpdateHandler);
uDom('#buttonPurgeAll').on('click', buttonPurgeAllHandler);
uDom('#lists').on('change', '.listEntry > input',
- onHostsFilesSettingsChanged);
+ onHostsFilesSettingsChanged);
uDom('#lists').on('click', '.listEntry > a.remove',
- onRemoveExternalHostsFile);
+ onRemoveExternalHostsFile);
uDom('#lists').on('click', 'span.cache', onPurgeClicked);
uDom('#externalHostsFiles').on('input', onHostsFilesSettingsChanged);
diff --git a/js/httpsb.js b/js/httpsb.js
index be487d5..1a8362a 100644
--- a/js/httpsb.js
+++ b/js/httpsb.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
diff --git a/js/i18n.js b/js/i18n.js
index cf27a69..7996584 100644
--- a/js/i18n.js
+++ b/js/i18n.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -44,187 +44,187 @@
// in case.
let reSafeTags =
- /^([\s\S]*?)<(b|blockquote|code|em|i|kbd|span|sup)>(.+?)<\/\2>([\s\S]*)$/;
+ /^([\s\S]*?)<(b|blockquote|code|em|i|kbd|span|sup)>(.+?)<\/\2>([\s\S]*)$/;
let reSafeInput = /^([\s\S]*?)<(input type="[^"]+")>(.*?)([\s\S]*)$/;
let reInput = /^input type=(['"])([a-z]+)\1$/;
let reSafeLink =
- /^([\s\S]*?)<(a href=['"]https?:\/\/[^'" <>]+['"])>(.+?)<\/a>([\s\S]*)$/;
+ /^([\s\S]*?)<(a href=['"]https?:\/\/[^'" <>]+['"])>(.+?)<\/a>([\s\S]*)$/;
let reLink = /^a href=(['"])(https?:\/\/[^'"]+)\1$/;
let safeTextToTagNode = function (text) {
- let matches;
- let node;
+ let matches;
+ let node;
- if (text.lastIndexOf('a ', 0) === 0) {
+ if (text.lastIndexOf('a ', 0) === 0) {
matches = reLink.exec(text);
if (matches === null) {
- return null;
- }
+ return null;
+ }
node = document.createElement('a');
node.setAttribute('href', matches[2]);
return node;
- }
- if (text.lastIndexOf('input ', 0) === 0) {
+ }
+ if (text.lastIndexOf('input ', 0) === 0) {
matches = reInput.exec(text);
if (matches === null) {
- return null;
- }
+ return null;
+ }
node = document.createElement('input');
node.setAttribute('type', matches[2]);
return node;
- }
- // Firefox extension validator warns if using a variable as
- // argument for document.createElement().
- // ηMatrix: is it important for us?
- // ηMatrix (4.4.3 onwards): let's just use the variable and
- // hope for the best, no need to have a redundant switch.
- /*
- switch (text) {
- case 'b':
+ }
+ // Firefox extension validator warns if using a variable as
+ // argument for document.createElement().
+ // ηMatrix: is it important for us?
+ // ηMatrix (4.4.3 onwards): let's just use the variable and
+ // hope for the best, no need to have a redundant switch.
+ /*
+ switch (text) {
+ case 'b':
return document.createElement('b');
- case 'blockquote':
+ case 'blockquote':
return document.createElement('blockquote');
- case 'code':
+ case 'code':
return document.createElement('code');
- case 'em':
+ case 'em':
return document.createElement('em');
- case 'i':
+ case 'i':
return document.createElement('i');
- case 'kbd':
+ case 'kbd':
return document.createElement('kbd');
- case 'span':
+ case 'span':
return document.createElement('span');
- case 'sup':
+ case 'sup':
return document.createElement('sup');
- default:
+ default:
break;
- }
- */
- return document.createElement(text);
+ }
+ */
+ return document.createElement(text);
};
let safeTextToTextNode = function (text) {
- if (text.indexOf('&') !== -1) {
+ if (text.indexOf('&') !== -1) {
text = text
- .replace(/&ldquo;/g, '“')
- .replace(/&rdquo;/g, '”')
- .replace(/&lsquo;/g, '‘')
- .replace(/&rsquo;/g, '’')
- .replace(/&lt;/g, '<')
- .replace(/&gt;/g, '>')
- .replace(/&apos;/g, '\'');
- }
- return document.createTextNode(text);
+ .replace(/&ldquo;/g, '“')
+ .replace(/&rdquo;/g, '”')
+ .replace(/&lsquo;/g, '‘')
+ .replace(/&rsquo;/g, '’')
+ .replace(/&lt;/g, '<')
+ .replace(/&gt;/g, '>')
+ .replace(/&apos;/g, '\'');
+ }
+ return document.createTextNode(text);
};
let safeTextToDOM = function (text, parent) {
- if (text === '') {
- return;
- }
+ if (text === '') {
+ return;
+ }
- if (text.indexOf('<') === -1) {
+ if (text.indexOf('<') === -1) {
return parent.appendChild(safeTextToTextNode(text));
- }
+ }
- // Using the raw <p> element is not allowed for security reason,
- // but it's good for formatting content, so here it's substituted
- // for a safer equivalent (for the extension.)
- text = text
- .replace(/^<p>|<\/p>/g, '')
+ // Using the raw <p> element is not allowed for security reason,
+ // but it's good for formatting content, so here it's substituted
+ // for a safer equivalent (for the extension.)
+ text = text
+ .replace(/^<p>|<\/p>/g, '')
.replace(/<p>/g, '\n\n');
- let matches;
- let matches1 = reSafeTags.exec(text);
- let matches2 = reSafeLink.exec(text);
- if (matches1 !== null && matches2 !== null) {
+ let matches;
+ let matches1 = reSafeTags.exec(text);
+ let matches2 = reSafeLink.exec(text);
+ if (matches1 !== null && matches2 !== null) {
matches = matches1.index < matches2.index ? matches1 : matches2;
- } else if (matches1 !== null) {
+ } else if (matches1 !== null) {
matches = matches1;
- } else if (matches2 !== null) {
+ } else if (matches2 !== null) {
matches = matches2;
- } else {
+ } else {
matches = reSafeInput.exec(text);
- }
- if (matches === null) {
+ }
+ if (matches === null) {
parent.appendChild(safeTextToTextNode(text));
return;
- }
+ }
- safeTextToDOM(matches[1], parent);
- let node = safeTextToTagNode(matches[2]) || parent;
- safeTextToDOM(matches[3], node);
- parent.appendChild(node);
- safeTextToDOM(matches[4], parent);
+ safeTextToDOM(matches[1], parent);
+ let node = safeTextToTagNode(matches[2]) || parent;
+ safeTextToDOM(matches[3], node);
+ parent.appendChild(node);
+ safeTextToDOM(matches[4], parent);
};
// Helper to deal with the i18n'ing of HTML files.
vAPI.i18n.render = function (context) {
- let docu = document;
+ let docu = document;
let root = context || docu;
let i, elem, text;
- let elems = root.querySelectorAll('[data-i18n]');
- let n = elems.length;
- for (i=0; i<n; ++i) {
+ let elems = root.querySelectorAll('[data-i18n]');
+ let n = elems.length;
+ for (i=0; i<n; ++i) {
elem = elems[i];
text = vAPI.i18n(elem.getAttribute('data-i18n'));
if (!text) {
- continue;
- }
+ continue;
+ }
// TODO: remove once it's all replaced with <input type="...">
if (text.indexOf('{') !== -1) {
- text =
- text.replace(/\{\{input:([^}]+)\}\}/g, '<input type="$1">');
+ text =
+ text.replace(/\{\{input:([^}]+)\}\}/g, '<input type="$1">');
}
safeTextToDOM(text, elem);
- }
+ }
- uDom('[title]', context).forEach(function (elem) {
+ uDom('[title]', context).forEach(function (elem) {
let title = vAPI.i18n(elem.attr('title'));
if (title) {
- elem.attr('title', title);
+ elem.attr('title', title);
}
- });
+ });
- uDom('[placeholder]', context).forEach(function (elem) {
+ uDom('[placeholder]', context).forEach(function (elem) {
elem.attr('placeholder', vAPI.i18n(elem.attr('placeholder')));
- });
+ });
- uDom('[data-i18n-tip]', context).forEach(function (elem) {
+ uDom('[data-i18n-tip]', context).forEach(function (elem) {
elem.attr('data-tip',
- vAPI.i18n(elem.attr('data-i18n-tip'))
+ vAPI.i18n(elem.attr('data-i18n-tip'))
.replace(/<br>/g, '\n')
.replace(/\n{3,}/g, '\n\n'));
- });
+ });
};
vAPI.i18n.render();
vAPI.i18n.renderElapsedTimeToString = function (tstamp) {
- let value = (Date.now() - tstamp) / 60000;
- if (value < 2) {
+ let value = (Date.now() - tstamp) / 60000;
+ if (value < 2) {
return vAPI.i18n('elapsedOneMinuteAgo');
- }
- if (value < 60) {
+ }
+ if (value < 60) {
return vAPI
- .i18n('elapsedManyMinutesAgo')
- .replace('{{value}}', Math.floor(value).toLocaleString());
- }
- value /= 60;
- if (value < 2) {
+ .i18n('elapsedManyMinutesAgo')
+ .replace('{{value}}', Math.floor(value).toLocaleString());
+ }
+ value /= 60;
+ if (value < 2) {
return vAPI.i18n('elapsedOneHourAgo');
- }
- if (value < 24) {
+ }
+ if (value < 24) {
return vAPI
- .i18n('elapsedManyHoursAgo')
- .replace('{{value}}', Math.floor(value).toLocaleString());
- }
- value /= 24;
- if (value < 2) {
+ .i18n('elapsedManyHoursAgo')
+ .replace('{{value}}', Math.floor(value).toLocaleString());
+ }
+ value /= 24;
+ if (value < 2) {
return vAPI.i18n('elapsedOneDayAgo');
- }
- return vAPI
- .i18n('elapsedManyDaysAgo')
- .replace('{{value}}', Math.floor(value).toLocaleString());
+ }
+ return vAPI
+ .i18n('elapsedManyDaysAgo')
+ .replace('{{value}}', Math.floor(value).toLocaleString());
};
})();
diff --git a/js/liquid-dict.js b/js/liquid-dict.js
index 8a03d7a..085f67e 100644
--- a/js/liquid-dict.js
+++ b/js/liquid-dict.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -27,176 +27,176 @@
ηMatrix.LiquidDict = (function() {
- /******************************************************************************/
-
- var LiquidDict = function() {
- this.dict = {};
- this.count = 0;
- this.duplicateCount = 0;
- this.bucketCount = 0;
- this.frozenBucketCount = 0;
-
- // Somewhat arbitrary: I need to come up with hard data to know at which
- // point binary search is better than indexOf.
- this.cutoff = 500;
- };
-
- /******************************************************************************/
-
- var meltBucket = function(ldict, len, bucket) {
- ldict.frozenBucketCount -= 1;
- var map = {};
- if ( bucket.charAt(0) === ' ' ) {
- bucket.trim().split(' ').map(function(k) {
- map[k] = true;
- });
- } else {
- var offset = 0;
- while ( offset < bucket.length ) {
- map[bucket.substring(offset, len)] = true;
- offset += len;
- }
- }
- return map;
- };
-
- /******************************************************************************/
-
- var melt = function(ldict) {
- var buckets = ldict.dict;
- var bucket;
- for ( var key in buckets ) {
- bucket = buckets[key];
- if ( typeof bucket === 'string' ) {
- buckets[key] = meltBucket(ldict, key.charCodeAt(0) & 0xFF, bucket);
- }
- }
- };
+/******************************************************************************/
- /******************************************************************************/
+var LiquidDict = function() {
+ this.dict = {};
+ this.count = 0;
+ this.duplicateCount = 0;
+ this.bucketCount = 0;
+ this.frozenBucketCount = 0;
- var freezeBucket = function(ldict, bucket) {
- ldict.frozenBucketCount += 1;
- var words = Object.keys(bucket);
- var wordLen = words[0].length;
- if ( wordLen * words.length < ldict.cutoff ) {
- return ' ' + words.join(' ') + ' ';
- }
- return words.sort().join('');
- };
-
- /******************************************************************************/
-
- // How the key is derived dictates the number and size of buckets.
- //
- // http://jsperf.com/makekey-concat-vs-join/3
- //
- // Question: Why is using a prototyped function better than a standalone
- // helper function?
-
- LiquidDict.prototype.makeKey = function(word) {
- var len = word.length;
- if ( len > 255 ) {
- len = 255;
- }
- var i = len >> 2;
- return String.fromCharCode(
- (word.charCodeAt( 0) & 0x03) << 14 |
- (word.charCodeAt( i) & 0x03) << 12 |
- (word.charCodeAt( i+i) & 0x03) << 10 |
- (word.charCodeAt(i+i+i) & 0x03) << 8 |
- len
- );
- };
-
- /******************************************************************************/
-
- LiquidDict.prototype.test = function(word) {
- var key = this.makeKey(word);
- var bucket = this.dict[key];
- if ( bucket === undefined ) {
- return false;
- }
- if ( typeof bucket === 'object' ) {
- return bucket[word] !== undefined;
- }
- if ( bucket.charAt(0) === ' ' ) {
- return bucket.indexOf(' ' + word + ' ') >= 0;
- }
- // binary search
- var len = word.length;
- var left = 0;
- // http://jsperf.com/or-vs-floor/3
- var right = ~~(bucket.length / len + 0.5);
- var i, needle;
- while ( left < right ) {
- i = left + right >> 1;
- needle = bucket.substr( len * i, len );
- if ( word < needle ) {
- right = i;
- } else if ( word > needle ) {
- left = i + 1;
- } else {
- return true;
- }
- }
- return false;
- };
+ // Somewhat arbitrary: I need to come up with hard data to know at which
+ // point binary search is better than indexOf.
+ this.cutoff = 500;
+};
- /******************************************************************************/
+/******************************************************************************/
- LiquidDict.prototype.add = function(word) {
- var key = this.makeKey(word);
- if ( key === undefined ) {
- return false;
+var meltBucket = function(ldict, len, bucket) {
+ ldict.frozenBucketCount -= 1;
+ var map = {};
+ if ( bucket.charAt(0) === ' ' ) {
+ bucket.trim().split(' ').map(function(k) {
+ map[k] = true;
+ });
+ } else {
+ var offset = 0;
+ while ( offset < bucket.length ) {
+ map[bucket.substring(offset, len)] = true;
+ offset += len;
}
- var bucket = this.dict[key];
- if ( bucket === undefined ) {
- this.dict[key] = bucket = {};
- this.bucketCount += 1;
- bucket[word] = true;
- this.count += 1;
- return true;
- } else if ( typeof bucket === 'string' ) {
- this.dict[key] = bucket = meltBucket(this, word.len, bucket);
+ }
+ return map;
+};
+
+/******************************************************************************/
+
+var melt = function(ldict) {
+ var buckets = ldict.dict;
+ var bucket;
+ for ( var key in buckets ) {
+ bucket = buckets[key];
+ if ( typeof bucket === 'string' ) {
+ buckets[key] = meltBucket(ldict, key.charCodeAt(0) & 0xFF, bucket);
}
- if ( bucket[word] === undefined ) {
- bucket[word] = true;
- this.count += 1;
+ }
+};
+
+/******************************************************************************/
+
+var freezeBucket = function(ldict, bucket) {
+ ldict.frozenBucketCount += 1;
+ var words = Object.keys(bucket);
+ var wordLen = words[0].length;
+ if ( wordLen * words.length < ldict.cutoff ) {
+ return ' ' + words.join(' ') + ' ';
+ }
+ return words.sort().join('');
+};
+
+/******************************************************************************/
+
+// How the key is derived dictates the number and size of buckets.
+//
+// http://jsperf.com/makekey-concat-vs-join/3
+//
+// Question: Why is using a prototyped function better than a standalone
+// helper function?
+
+LiquidDict.prototype.makeKey = function(word) {
+ var len = word.length;
+ if ( len > 255 ) {
+ len = 255;
+ }
+ var i = len >> 2;
+ return String.fromCharCode(
+ (word.charCodeAt( 0) & 0x03) << 14 |
+ (word.charCodeAt( i) & 0x03) << 12 |
+ (word.charCodeAt( i+i) & 0x03) << 10 |
+ (word.charCodeAt(i+i+i) & 0x03) << 8 |
+ len
+ );
+};
+
+/******************************************************************************/
+
+LiquidDict.prototype.test = function(word) {
+ var key = this.makeKey(word);
+ var bucket = this.dict[key];
+ if ( bucket === undefined ) {
+ return false;
+ }
+ if ( typeof bucket === 'object' ) {
+ return bucket[word] !== undefined;
+ }
+ if ( bucket.charAt(0) === ' ' ) {
+ return bucket.indexOf(' ' + word + ' ') >= 0;
+ }
+ // binary search
+ var len = word.length;
+ var left = 0;
+ // http://jsperf.com/or-vs-floor/3
+ var right = ~~(bucket.length / len + 0.5);
+ var i, needle;
+ while ( left < right ) {
+ i = left + right >> 1;
+ needle = bucket.substr( len * i, len );
+ if ( word < needle ) {
+ right = i;
+ } else if ( word > needle ) {
+ left = i + 1;
+ } else {
return true;
}
- this.duplicateCount += 1;
+ }
+ return false;
+};
+
+/******************************************************************************/
+
+LiquidDict.prototype.add = function(word) {
+ var key = this.makeKey(word);
+ if ( key === undefined ) {
return false;
- };
-
- /******************************************************************************/
-
- LiquidDict.prototype.freeze = function() {
- var buckets = this.dict;
- var bucket;
- for ( var key in buckets ) {
- bucket = buckets[key];
- if ( typeof bucket === 'object' ) {
- buckets[key] = freezeBucket(this, bucket);
- }
+ }
+ var bucket = this.dict[key];
+ if ( bucket === undefined ) {
+ this.dict[key] = bucket = {};
+ this.bucketCount += 1;
+ bucket[word] = true;
+ this.count += 1;
+ return true;
+ } else if ( typeof bucket === 'string' ) {
+ this.dict[key] = bucket = meltBucket(this, word.len, bucket);
+ }
+ if ( bucket[word] === undefined ) {
+ bucket[word] = true;
+ this.count += 1;
+ return true;
+ }
+ this.duplicateCount += 1;
+ return false;
+};
+
+/******************************************************************************/
+
+LiquidDict.prototype.freeze = function() {
+ var buckets = this.dict;
+ var bucket;
+ for ( var key in buckets ) {
+ bucket = buckets[key];
+ if ( typeof bucket === 'object' ) {
+ buckets[key] = freezeBucket(this, bucket);
}
- };
+ }
+};
- /******************************************************************************/
+/******************************************************************************/
- LiquidDict.prototype.reset = function() {
- this.dict = {};
- this.count = 0;
- this.duplicateCount = 0;
- this.bucketCount = 0;
- this.frozenBucketCount = 0;
- };
+LiquidDict.prototype.reset = function() {
+ this.dict = {};
+ this.count = 0;
+ this.duplicateCount = 0;
+ this.bucketCount = 0;
+ this.frozenBucketCount = 0;
+};
- /******************************************************************************/
+/******************************************************************************/
- return LiquidDict;
+return LiquidDict;
- /******************************************************************************/
+/******************************************************************************/
})();
diff --git a/js/logger-ui.js b/js/logger-ui.js
index 8f4ffbf..5f9aedb 100644
--- a/js/logger-ui.js
+++ b/js/logger-ui.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2015-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/sessbench
*/
@@ -39,249 +39,249 @@
let hiddenTemplate = document.querySelector('#hiddenTemplate > span');
let prettyRequestTypes = {
- 'main_frame': 'doc',
- 'stylesheet': 'css',
- 'sub_frame': 'frame',
- 'xmlhttprequest': 'xhr'
+ 'main_frame': 'doc',
+ 'stylesheet': 'css',
+ 'sub_frame': 'frame',
+ 'xmlhttprequest': 'xhr'
};
let dontEmphasizeSet = new Set([
- 'COOKIE',
- 'CSP',
- 'REFERER'
+ 'COOKIE',
+ 'CSP',
+ 'REFERER'
]);
// Adjust top padding of content table, to match that of toolbar height.
document
- .getElementById('content')
- .style
- .setProperty('margin-top',
- document.getElementById('toolbar').clientHeight + 'px');
+ .getElementById('content')
+ .style
+ .setProperty('margin-top',
+ document.getElementById('toolbar').clientHeight + 'px');
let classNameFromTabId = function (tabId) {
- if (tabId === noTabId) {
+ if (tabId === noTabId) {
return 'tab_bts';
- }
- if (tabId !== '') {
+ }
+ if (tabId !== '') {
return 'tab_' + tabId;
- }
- return '';
+ }
+ return '';
};
// Emphasize hostname and cookie name.
let emphasizeCookie = function (s) {
- let pnode = emphasizeHostname(s);
- if (pnode.childNodes.length !== 3) {
+ let pnode = emphasizeHostname(s);
+ if (pnode.childNodes.length !== 3) {
return pnode;
- }
+ }
- let prefix = '-cookie:';
- let text = pnode.childNodes[2].textContent;
+ let prefix = '-cookie:';
+ let text = pnode.childNodes[2].textContent;
- let beg = text.indexOf(prefix);
- if (beg === -1) {
+ let beg = text.indexOf(prefix);
+ if (beg === -1) {
return pnode;
- }
- beg += prefix.length;
+ }
+ beg += prefix.length;
- let end = text.indexOf('}', beg);
- if (end === -1) {
+ let end = text.indexOf('}', beg);
+ if (end === -1) {
return pnode;
- }
+ }
- let cnode = emphasizeTemplate.cloneNode(true);
- cnode.childNodes[0].textContent = text.slice(0, beg);
- cnode.childNodes[1].textContent = text.slice(beg, end);
- cnode.childNodes[2].textContent = text.slice(end);
- pnode.replaceChild(cnode.childNodes[0], pnode.childNodes[2]);
- pnode.appendChild(cnode.childNodes[0]);
- pnode.appendChild(cnode.childNodes[0]);
+ let cnode = emphasizeTemplate.cloneNode(true);
+ cnode.childNodes[0].textContent = text.slice(0, beg);
+ cnode.childNodes[1].textContent = text.slice(beg, end);
+ cnode.childNodes[2].textContent = text.slice(end);
+ pnode.replaceChild(cnode.childNodes[0], pnode.childNodes[2]);
+ pnode.appendChild(cnode.childNodes[0]);
+ pnode.appendChild(cnode.childNodes[0]);
- return pnode;
+ return pnode;
};
// Emphasize hostname in URL.
let emphasizeHostname = function (url) {
- let hnbeg = url.indexOf('://');
- if (hnbeg === -1) {
+ let hnbeg = url.indexOf('://');
+ if (hnbeg === -1) {
return document.createTextNode(url);
- }
- hnbeg += 3;
+ }
+ hnbeg += 3;
- let hnend = url.indexOf('/', hnbeg);
- if (hnend === -1) {
+ let hnend = url.indexOf('/', hnbeg);
+ if (hnend === -1) {
hnend = url.slice(hnbeg).search(/\?#/);
if (hnend !== -1) {
- hnend += hnbeg;
+ hnend += hnbeg;
} else {
- hnend = url.length;
+ hnend = url.length;
}
- }
+ }
- let node = emphasizeTemplate.cloneNode(true);
- node.childNodes[0].textContent = url.slice(0, hnbeg);
- node.childNodes[1].textContent = url.slice(hnbeg, hnend);
- node.childNodes[2].textContent = url.slice(hnend);
+ let node = emphasizeTemplate.cloneNode(true);
+ node.childNodes[0].textContent = url.slice(0, hnbeg);
+ node.childNodes[1].textContent = url.slice(hnbeg, hnend);
+ node.childNodes[2].textContent = url.slice(hnend);
- return node;
+ return node;
};
let createCellAt = function (tr, index) {
- let td = tr.cells[index];
- let mustAppend = !td;
- if (mustAppend) {
+ let td = tr.cells[index];
+ let mustAppend = !td;
+ if (mustAppend) {
td = tdJunkyard.pop();
- }
+ }
- if (td) {
+ if (td) {
td.removeAttribute('colspan');
td.textContent = '';
- } else {
+ } else {
td = document.createElement('td');
- }
- if (mustAppend) {
+ }
+ if (mustAppend) {
tr.appendChild(td);
- }
+ }
- return td;
+ return td;
};
let createRow = function (layout) {
- let tr = trJunkyard.pop();
- if (tr) {
+ let tr = trJunkyard.pop();
+ if (tr) {
tr.className = '';
- } else {
+ } else {
tr = document.createElement('tr');
- }
+ }
- let index;
- for (index=0; index<firstVarDataCol; ++index) {
+ let index;
+ for (index=0; index<firstVarDataCol; ++index) {
createCellAt(tr, index);
- }
+ }
- let i = 1, span = 1, td;
- for (;;) {
+ let i = 1, span = 1, td;
+ for (;;) {
td = createCellAt(tr, index);
if (i === lastVarDataIndex) {
- break;
+ break;
}
if (layout.charAt(i) !== '1') {
- span += 1;
+ span += 1;
} else {
- if (span !== 1) {
+ if (span !== 1) {
td.setAttribute('colspan', span);
- }
- index += 1;
- span = 1;
+ }
+ index += 1;
+ span = 1;
}
i += 1;
- }
+ }
- if (span !== 1) {
+ if (span !== 1) {
td.setAttribute('colspan', span);
- }
- index += 1;
- while ((td = tr.cells[index])) {
+ }
+ index += 1;
+ while ((td = tr.cells[index])) {
tdJunkyard.push(tr.removeChild(td));
- }
+ }
- return tr;
+ return tr;
};
let createHiddenTextNode = function (text) {
- let node = hiddenTemplate.cloneNode(true);
- node.textContent = text;
- return node;
+ let node = hiddenTemplate.cloneNode(true);
+ node.textContent = text;
+ return node;
};
let padTo2 = function (v) {
- return v < 10 ? '0' + v : v;
+ return v < 10 ? '0' + v : v;
};
let createGap = function (tabId, url) {
- let tr = createRow('1');
- tr.classList.add('doc');
- tr.classList.add('tab');
- tr.classList.add('canMtx');
- tr.classList.add('tab_' + tabId);
- tr.cells[firstVarDataCol].textContent = url;
- tbody.insertBefore(tr, tbody.firstChild);
+ let tr = createRow('1');
+ tr.classList.add('doc');
+ tr.classList.add('tab');
+ tr.classList.add('canMtx');
+ tr.classList.add('tab_' + tabId);
+ tr.cells[firstVarDataCol].textContent = url;
+ tbody.insertBefore(tr, tbody.firstChild);
};
let renderLogEntry = function (entry) {
- let tr;
- let fvdc = firstVarDataCol;
+ let tr;
+ let fvdc = firstVarDataCol;
- switch (entry.cat) {
- case 'error':
- case 'info':
+ switch (entry.cat) {
+ case 'error':
+ case 'info':
tr = createRow('1');
if (entry.d0 === 'cookie') {
- tr.cells[fvdc].appendChild(emphasizeCookie(entry.d1));
+ tr.cells[fvdc].appendChild(emphasizeCookie(entry.d1));
} else {
- tr.cells[fvdc].textContent = entry.d0;
+ tr.cells[fvdc].textContent = entry.d0;
}
break;
- case 'net':
+ case 'net':
tr = createRow('111');
tr.classList.add('canMtx');
// If the request is that of a root frame, insert a gap in the table
// in order to visually separate entries for different documents.
if (entry.d2 === 'doc' && entry.tab !== noTabId) {
- createGap(entry.tab, entry.d1);
+ createGap(entry.tab, entry.d1);
}
if (entry.d3) {
- tr.classList.add('blocked');
- tr.cells[fvdc].textContent = '--';
+ tr.classList.add('blocked');
+ tr.cells[fvdc].textContent = '--';
} else {
- tr.cells[fvdc].textContent = '';
+ tr.cells[fvdc].textContent = '';
}
tr.cells[fvdc+1].textContent =
- (prettyRequestTypes[entry.d2] || entry.d2);
+ (prettyRequestTypes[entry.d2] || entry.d2);
if (dontEmphasizeSet.has(entry.d2)) {
- tr.cells[fvdc+2].textContent = entry.d1;
+ tr.cells[fvdc+2].textContent = entry.d1;
} else if ( entry.d2 === 'cookie' ) {
- tr.cells[fvdc+2].appendChild(emphasizeCookie(entry.d1));
+ tr.cells[fvdc+2].appendChild(emphasizeCookie(entry.d1));
} else {
- tr.cells[fvdc+2].appendChild(emphasizeHostname(entry.d1));
+ tr.cells[fvdc+2].appendChild(emphasizeHostname(entry.d1));
}
break;
- default:
+ default:
tr = createRow('1');
tr.cells[fvdc].textContent = entry.d0;
break;
- }
-
- // Fields common to all rows.
- let time = logDate;
- time.setTime(entry.tstamp - logDateTimezoneOffset);
- tr.cells[0].textContent = padTo2(time.getUTCHours())
- + ':'
- + padTo2(time.getUTCMinutes())
- + ':'
- + padTo2(time.getSeconds());
-
- if (entry.tab) {
+ }
+
+ // Fields common to all rows.
+ let time = logDate;
+ time.setTime(entry.tstamp - logDateTimezoneOffset);
+ tr.cells[0].textContent = padTo2(time.getUTCHours())
+ + ':'
+ + padTo2(time.getUTCMinutes())
+ + ':'
+ + padTo2(time.getSeconds());
+
+ if (entry.tab) {
tr.classList.add('tab');
tr.classList.add(classNameFromTabId(entry.tab));
if (entry.tab === noTabId) {
- tr.cells[1].appendChild(createHiddenTextNode('bts'));
+ tr.cells[1].appendChild(createHiddenTextNode('bts'));
}
- }
- if (entry.cat !== '') {
+ }
+ if (entry.cat !== '') {
tr.classList.add('cat_' + entry.cat);
- }
+ }
- rowFilterer.filterOne(tr, true);
+ rowFilterer.filterOne(tr, true);
- tbody.insertBefore(tr, tbody.firstChild);
+ tbody.insertBefore(tr, tbody.firstChild);
};
// Reuse date objects.
@@ -289,180 +289,180 @@
let logDateTimezoneOffset = logDate.getTimezoneOffset() * 60000;
let renderLogEntries = function (response) {
- let entries = response.entries;
- if (entries.length === 0) {
+ let entries = response.entries;
+ if (entries.length === 0) {
return;
- }
+ }
- // Preserve scroll position
- let height = tbody.offsetHeight;
+ // Preserve scroll position
+ let height = tbody.offsetHeight;
- let tabIds = response.tabIds;
- let n = entries.length;
- let entry;
- for (let i=0; i<n; ++i) {
+ let tabIds = response.tabIds;
+ let n = entries.length;
+ let entry;
+ for (let i=0; i<n; ++i) {
entry = entries[i];
// Unlikely, but it may happen
if (entry.tab && tabIds.hasOwnProperty(entry.tab) === false) {
- continue;
+ continue;
}
renderLogEntry(entries[i]);
- }
+ }
- // Prevent logger from growing infinitely and eating all memory. For
- // instance someone could forget that it is left opened for some
- // dynamically refreshed pages.
- truncateLog(maxEntries);
+ // Prevent logger from growing infinitely and eating all memory. For
+ // instance someone could forget that it is left opened for some
+ // dynamically refreshed pages.
+ truncateLog(maxEntries);
- let yDelta = tbody.offsetHeight - height;
- if (yDelta === 0) {
+ let yDelta = tbody.offsetHeight - height;
+ if (yDelta === 0) {
return;
- }
+ }
- // Chromium:
- // body.scrollTop = good value
- // body.parentNode.scrollTop = 0
- // if (document.body.scrollTop !== 0) {
+ // Chromium:
+ // body.scrollTop = good value
+ // body.parentNode.scrollTop = 0
+ // if (document.body.scrollTop !== 0) {
// document.body.scrollTop += yDelta;
// return;
- // }
+ // }
- // Firefox:
- // body.scrollTop = 0
- // body.parentNode.scrollTop = good value
- let parentNode = document.body.parentNode;
- if (parentNode && parentNode.scrollTop !== 0) {
+ // Firefox:
+ // body.scrollTop = 0
+ // body.parentNode.scrollTop = good value
+ let parentNode = document.body.parentNode;
+ if (parentNode && parentNode.scrollTop !== 0) {
parentNode.scrollTop += yDelta;
- }
+ }
};
let synchronizeTabIds = function (newTabIds) {
- let oldTabIds = allTabIds;
- let autoDeleteVoidRows =
- !!vAPI.localStorage.getItem('loggerAutoDeleteVoidRows');
- let rowVoided = false;
- let trs;
+ let oldTabIds = allTabIds;
+ let autoDeleteVoidRows =
+ !!vAPI.localStorage.getItem('loggerAutoDeleteVoidRows');
+ let rowVoided = false;
+ let trs;
- for (let tabId in oldTabIds) {
+ for (let tabId in oldTabIds) {
if (oldTabIds.hasOwnProperty(tabId) === false) {
- continue;
+ continue;
}
if (newTabIds.hasOwnProperty(tabId)) {
- continue;
+ continue;
}
// Mark or remove voided rows
trs = uDom('.tab_' + tabId);
if (autoDeleteVoidRows) {
- toJunkyard(trs);
+ toJunkyard(trs);
} else {
- trs.removeClass('canMtx');
- rowVoided = true;
+ trs.removeClass('canMtx');
+ rowVoided = true;
}
// Remove popup if it is currently bound to a removed tab.
if (tabId === popupManager.tabId) {
- popupManager.toggleOff();
+ popupManager.toggleOff();
}
- }
+ }
- let select = document.getElementById('pageSelector');
- let selectValue = select.value;
- let tabIds = Object.keys(newTabIds).sort(function (a, b) {
+ let select = document.getElementById('pageSelector');
+ let selectValue = select.value;
+ let tabIds = Object.keys(newTabIds).sort(function (a, b) {
return newTabIds[a].localeCompare(newTabIds[b]);
- });
+ });
- let i, j;
- for (i=0, j=2; i<tabIds.length; ++i) {
+ let i, j;
+ for (i=0, j=2; i<tabIds.length; ++i) {
let tabId = tabIds[i];
if (tabId === noTabId) {
- continue;
+ continue;
}
let option = select.options[j];
j += 1;
if (!option) {
- option = document.createElement('option');
- select.appendChild(option);
+ option = document.createElement('option');
+ select.appendChild(option);
}
option.textContent = newTabIds[tabId];
option.value = classNameFromTabId(tabId);
if (option.value === selectValue) {
- option.setAttribute('selected', '');
+ option.setAttribute('selected', '');
} else {
- option.removeAttribute('selected');
+ option.removeAttribute('selected');
}
- }
+ }
- while (j < select.options.length) {
+ while (j < select.options.length) {
select.removeChild(select.options[j]);
- }
+ }
- if (select.value !== selectValue) {
+ if (select.value !== selectValue) {
select.selectedIndex = 0;
select.value = '';
select.options[0].setAttribute('selected', '');
pageSelectorChanged();
- }
+ }
- allTabIds = newTabIds;
+ allTabIds = newTabIds;
- return rowVoided;
+ return rowVoided;
};
let truncateLog = function (size) {
- if (size === 0) {
+ if (size === 0) {
size = 5000;
- }
+ }
- let tbody = document.querySelector('#content tbody');
- size = Math.min(size, 10000);
+ let tbody = document.querySelector('#content tbody');
+ size = Math.min(size, 10000);
- while (tbody.childElementCount > size) {
+ while (tbody.childElementCount > size) {
let tr = tbody.lastElementChild;
trJunkyard.push(tbody.removeChild(tr));
- }
+ }
};
let onLogBufferRead = function (response) {
- if (!response || response.unavailable) {
+ if (!response || response.unavailable) {
readLogBufferAsync();
return;
- }
+ }
- // This tells us the behind-the-scene tab id
- noTabId = response.noTabId;
+ // This tells us the behind-the-scene tab id
+ noTabId = response.noTabId;
- // This may have changed meanwhile
- if (response.maxLoggedRequests !== maxEntries) {
+ // This may have changed meanwhile
+ if (response.maxLoggedRequests !== maxEntries) {
maxEntries = response.maxLoggedRequests;
uDom('#maxEntries').val(maxEntries || '');
- }
+ }
- // Neuter rows for which a tab does not exist anymore
- let rowVoided = false;
- if (response.tabIdsToken !== allTabIdsToken) {
+ // Neuter rows for which a tab does not exist anymore
+ let rowVoided = false;
+ if (response.tabIdsToken !== allTabIdsToken) {
rowVoided = synchronizeTabIds(response.tabIds);
allTabIdsToken = response.tabIdsToken;
- }
+ }
- renderLogEntries(response);
+ renderLogEntries(response);
- if (rowVoided) {
+ if (rowVoided) {
uDom('#clean')
- .toggleClass('disabled',
- tbody
- .querySelector('tr.tab:not(.canMtx)') === null);
- }
+ .toggleClass('disabled',
+ tbody
+ .querySelector('tr.tab:not(.canMtx)') === null);
+ }
- // Synchronize toolbar with content of log
- uDom('#clear').toggleClass('disabled',
- tbody.querySelector('tr') === null);
+ // Synchronize toolbar with content of log
+ uDom('#clear').toggleClass('disabled',
+ tbody.querySelector('tr') === null);
- readLogBufferAsync();
+ readLogBufferAsync();
};
// This can be called only once, at init time. After that, this
@@ -471,83 +471,83 @@
// no multi time out events.
let readLogBuffer = function () {
- if (ownerId === undefined) {
- return;
- }
-
- vAPI.messaging.send('logger-ui.js', {
- what: 'readMany',
- ownerId: ownerId
- }, onLogBufferRead);
+ if (ownerId === undefined) {
+ return;
+ }
+
+ vAPI.messaging.send('logger-ui.js', {
+ what: 'readMany',
+ ownerId: ownerId
+ }, onLogBufferRead);
};
let readLogBufferAsync = function () {
- if (ownerId === undefined) {
- return;
- }
- vAPI.setTimeout(readLogBuffer, 1200);
+ if (ownerId === undefined) {
+ return;
+ }
+ vAPI.setTimeout(readLogBuffer, 1200);
};
let pageSelectorChanged = function () {
- let style = document.getElementById('tabFilterer');
- let tabClass = document.getElementById('pageSelector').value;
- let sheet = style.sheet;
+ let style = document.getElementById('tabFilterer');
+ let tabClass = document.getElementById('pageSelector').value;
+ let sheet = style.sheet;
- while (sheet.cssRules.length !== 0) {
+ while (sheet.cssRules.length !== 0) {
sheet.deleteRule(0);
- }
+ }
- if (tabClass !== '') {
+ if (tabClass !== '') {
sheet.insertRule('#content table tr:not(.'
- + tabClass
- + ') { display: none; }', 0);
- }
- uDom('#refresh').toggleClass('disabled',
- tabClass === '' || tabClass === 'tab_bts');
+ + tabClass
+ + ') { display: none; }', 0);
+ }
+ uDom('#refresh').toggleClass('disabled',
+ tabClass === '' || tabClass === 'tab_bts');
};
let refreshTab = function () {
- let tabClass = document.getElementById('pageSelector').value;
- let matches = tabClass.match(/^tab_(.+)$/);
- if (matches === null) {
+ let tabClass = document.getElementById('pageSelector').value;
+ let matches = tabClass.match(/^tab_(.+)$/);
+ if (matches === null) {
return;
- }
+ }
- if (matches[1] === 'bts') {
+ if (matches[1] === 'bts') {
return;
- }
+ }
- vAPI.messaging.send('logger-ui.js', {
- what: 'forceReloadTab',
- tabId: matches[1]
- });
+ vAPI.messaging.send('logger-ui.js', {
+ what: 'forceReloadTab',
+ tabId: matches[1]
+ });
};
let onMaxEntriesChanged = function () {
- let raw = uDom(this).val();
+ let raw = uDom(this).val();
- try {
+ try {
maxEntries = parseInt(raw, 10);
if (isNaN(maxEntries)) {
- maxEntries = 0;
+ maxEntries = 0;
}
- } catch (e) {
+ } catch (e) {
maxEntries = 0;
- }
+ }
- vAPI.messaging.send('logger-ui.js', {
+ vAPI.messaging.send('logger-ui.js', {
what: 'userSettings',
name: 'maxLoggedRequests',
value: maxEntries
- });
+ });
- truncateLog(maxEntries);
+ truncateLog(maxEntries);
};
let rowFilterer = (function () {
- let filters = [];
+ let filters = [];
- let parseInput = function () {
+ let parseInput = function () {
filters = [];
let rawPart, hardBeg, hardEnd;
@@ -557,69 +557,69 @@
let n = rawParts.length;
for (let i=0; i<n; ++i) {
- rawPart = rawParts[i];
- if (rawPart.charAt(0) === '!') {
+ rawPart = rawParts[i];
+ if (rawPart.charAt(0) === '!') {
if (reStrs.length === 0) {
- not = true;
+ not = true;
}
rawPart = rawPart.slice(1);
- }
+ }
- hardBeg = rawPart.charAt(0) === '|';
- if (hardBeg) {
+ hardBeg = rawPart.charAt(0) === '|';
+ if (hardBeg) {
rawPart = rawPart.slice(1);
- }
+ }
- hardEnd = rawPart.slice(-1) === '|';
- if (hardEnd) {
+ hardEnd = rawPart.slice(-1) === '|';
+ if (hardEnd) {
rawPart = rawPart.slice(0, -1);
- }
+ }
- if ( rawPart === '' ) {
+ if ( rawPart === '' ) {
continue;
- }
+ }
- reStr = rawPart.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
- if (hardBeg) {
+ reStr = rawPart.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+ if (hardBeg) {
reStr = '(?:^|\\s)' + reStr;
- }
- if (hardEnd) {
+ }
+ if (hardEnd) {
reStr += '(?:\\s|$)';
- }
+ }
- reStrs.push(reStr);
- if (i < (n - 1) && rawParts[i + 1] === '||') {
+ reStrs.push(reStr);
+ if (i < (n - 1) && rawParts[i + 1] === '||') {
i += 1;
continue;
- }
+ }
- reStr = reStrs.length === 1 ? reStrs[0] : reStrs.join('|');
- filters.push({
+ reStr = reStrs.length === 1 ? reStrs[0] : reStrs.join('|');
+ filters.push({
re: new RegExp(reStr, 'i'),
r: !not
- });
- reStrs = [];
- not = false;
+ });
+ reStrs = [];
+ not = false;
}
- };
+ };
- let filterOne = function (tr, clean) {
+ let filterOne = function (tr, clean) {
let ff = filters;
let fcount = ff.length;
if (fcount === 0 && clean === true) {
- return;
+ return;
}
// do not filter out doc boundaries, they help separate
// important section of log.
let cl = tr.classList;
if (cl.contains('doc')) {
- return;
+ return;
}
if (fcount === 0) {
- cl.remove('f');
- return;
+ cl.remove('f');
+ return;
}
let cc = tr.cells;
@@ -631,141 +631,141 @@
// positive filter expression = there must one hit on any field
// negative filter expression = there must be no hit on all fields
for (let i=0; i<fcount; ++i) {
- f = ff[i];
- hit = !f.r;
+ f = ff[i];
+ hit = !f.r;
- for (j=0; j<ccount; ++j) {
+ for (j=0; j<ccount; ++j) {
if (f.re.test(cc[j].textContent)) {
- hit = f.r;
- break;
+ hit = f.r;
+ break;
}
- }
+ }
- if (!hit) {
+ if (!hit) {
cl.add('f');
return;
- }
+ }
}
cl.remove('f');
- };
+ };
- let filterAll = function () {
+ let filterAll = function () {
// Special case: no filter
if (filters.length === 0) {
- uDom('#content tr').removeClass('f');
- return;
+ uDom('#content tr').removeClass('f');
+ return;
}
let tbody = document.querySelector('#content tbody');
let rows = tbody.rows;
for (let i=rows.length-1; i>=0; --i) {
- filterOne(rows[i]);
+ filterOne(rows[i]);
}
- };
+ };
- let onFilterChangedAsync = (function () {
+ let onFilterChangedAsync = (function () {
let timer = null;
let commit = function () {
- timer = null;
- parseInput();
- filterAll();
+ timer = null;
+ parseInput();
+ filterAll();
};
return function () {
- if (timer !== null) {
+ if (timer !== null) {
clearTimeout(timer);
- }
- timer = vAPI.setTimeout(commit, 750);
+ }
+ timer = vAPI.setTimeout(commit, 750);
};
- })();
+ })();
- let onFilterButton = function () {
+ let onFilterButton = function () {
let cl = document.body.classList;
cl.toggle('f', cl.contains('f') === false);
- };
+ };
- uDom('#filterButton').on('click', onFilterButton);
- uDom('#filterInput').on('input', onFilterChangedAsync);
+ uDom('#filterButton').on('click', onFilterButton);
+ uDom('#filterInput').on('input', onFilterChangedAsync);
- return {
+ return {
filterOne: filterOne,
filterAll: filterAll,
- };
+ };
})();
let toJunkyard = function (trs) {
- trs.remove();
- for (let i=trs.length-1; i>=0; --i) {
+ trs.remove();
+ for (let i=trs.length-1; i>=0; --i) {
trJunkyard.push(trs.nodeAt(i));
- }
+ }
};
let clearBuffer = function () {
- let tbody = document.querySelector('#content tbody');
- let tr;
+ let tbody = document.querySelector('#content tbody');
+ let tr;
- while (tbody.firstChild !== null) {
+ while (tbody.firstChild !== null) {
tr = tbody.lastElementChild;
trJunkyard.push(tbody.removeChild(tr));
- }
+ }
- uDom('#clear').addClass('disabled');
- uDom('#clean').addClass('disabled');
+ uDom('#clear').addClass('disabled');
+ uDom('#clean').addClass('disabled');
};
let cleanBuffer = function () {
- let rows = uDom('#content tr.tab:not(.canMtx)').remove();
- for (let i=rows.length-1; i>=0; --i) {
+ let rows = uDom('#content tr.tab:not(.canMtx)').remove();
+ for (let i=rows.length-1; i>=0; --i) {
trJunkyard.push(rows.nodeAt(i));
- }
- uDom('#clean').addClass('disabled');
+ }
+ uDom('#clean').addClass('disabled');
};
let toggleCompactView = function () {
- document.body.classList.toggle('compactView');
- uDom('#content table .vExpanded').removeClass('vExpanded');
+ document.body.classList.toggle('compactView');
+ uDom('#content table .vExpanded').removeClass('vExpanded');
};
let toggleCompactRow = function (ev) {
- ev.target.parentElement.classList.toggle('vExpanded');
+ ev.target.parentElement.classList.toggle('vExpanded');
};
let popupManager = (function () {
- let realTabId = null;
- let localTabId = null;
- let container = null;
- let popup = null;
- let popupObserver = null;
- let style = null;
- let styleTemplate = [
+ let realTabId = null;
+ let localTabId = null;
+ let container = null;
+ let popup = null;
+ let popupObserver = null;
+ let style = null;
+ let styleTemplate = [
'tr:not(.tab_{{tabId}}) {',
'cursor: not-allowed;',
'opacity: 0.2;',
'}'
- ].join('\n');
+ ].join('\n');
- let resizePopup = function () {
+ let resizePopup = function () {
if (popup === null) {
- return;
+ return;
}
let popupBody = popup.contentWindow.document.body;
if (popupBody.clientWidth !== 0
- && container.clientWidth !== popupBody.clientWidth) {
- container.style.setProperty('width', popupBody.clientWidth + 'px');
+ && container.clientWidth !== popupBody.clientWidth) {
+ container.style.setProperty('width', popupBody.clientWidth + 'px');
}
popup.style.removeProperty('height');
if (popupBody.clientHeight !== 0
- && popup.clientHeight !== popupBody.clientHeight) {
- popup.style.setProperty('height', popupBody.clientHeight + 'px');
+ && popup.clientHeight !== popupBody.clientHeight) {
+ popup.style.setProperty('height', popupBody.clientHeight + 'px');
}
let ph = document.documentElement.clientHeight;
let crect = container.getBoundingClientRect();
if (crect.height > ph) {
- popup.style.setProperty('height', 'calc(' + ph + 'px - 1.8em)');
+ popup.style.setProperty('height', 'calc(' + ph + 'px - 1.8em)');
}
// Adjust width for presence/absence of vertical scroll bar which may
@@ -773,54 +773,54 @@
let cw = container.clientWidth;
let dw = popup.contentWindow.document.documentElement.clientWidth;
if (cw !== dw) {
- container.style.setProperty('width', (2 * cw - dw) + 'px');
+ container.style.setProperty('width', (2 * cw - dw) + 'px');
}
- };
+ };
- let toggleSize = function () {
+ let toggleSize = function () {
container.classList.toggle('hide');
- };
+ };
- let onResizeRequested = function () {
+ let onResizeRequested = function () {
let popupBody = popup.contentWindow.document.body;
if (popupBody.hasAttribute('data-resize-popup') === false) {
- return;
+ return;
}
popupBody.removeAttribute('data-resize-popup');
resizePopup();
- };
+ };
- let onLoad = function () {
+ let onLoad = function () {
resizePopup();
let popupBody = popup.contentDocument.body;
popupBody.removeAttribute('data-resize-popup');
popupObserver.observe(popupBody, {
- attributes: true,
- attributesFilter: [ 'data-resize-popup' ]
+ attributes: true,
+ attributesFilter: [ 'data-resize-popup' ]
});
- };
+ };
- let toggleOn = function (td) {
+ let toggleOn = function (td) {
let tr = td.parentNode;
let matches = tr.className.match(/(?:^| )tab_([^ ]+)/);
if (matches === null) {
- return;
+ return;
}
realTabId = localTabId = matches[1];
if (localTabId === 'bts') {
- realTabId = noTabId;
+ realTabId = noTabId;
}
container = document.getElementById('popupContainer');
container
- .querySelector('div > span:nth-of-type(1)')
- .addEventListener('click', toggleSize);
+ .querySelector('div > span:nth-of-type(1)')
+ .addEventListener('click', toggleSize);
container
- .querySelector('div > span:nth-of-type(2)')
- .addEventListener('click', toggleOff);
+ .querySelector('div > span:nth-of-type(2)')
+ .addEventListener('click', toggleOff);
popup = document.createElement('iframe');
popup.addEventListener('load', onLoad);
@@ -832,17 +832,17 @@
style.textContent = styleTemplate.replace('{{tabId}}', localTabId);
document.body.classList.add('popupOn');
- };
+ };
- let toggleOff = function () {
+ let toggleOff = function () {
document.body.classList.remove('popupOn');
container
- .querySelector('div > span:nth-of-type(1)')
- .removeEventListener('click', toggleSize);
+ .querySelector('div > span:nth-of-type(1)')
+ .removeEventListener('click', toggleSize);
container
- .querySelector('div > span:nth-of-type(2)')
- .removeEventListener('click', toggleOff);
+ .querySelector('div > span:nth-of-type(2)')
+ .removeEventListener('click', toggleOff);
container.classList.remove('hide');
popup.removeEventListener('load', onLoad);
@@ -857,48 +857,48 @@
container = null;
realTabId = null;
- };
+ };
- let exports = {
+ let exports = {
toggleOn: function (ev) {
- if (realTabId === null) {
+ if (realTabId === null) {
toggleOn(ev.target);
- }
+ }
},
toggleOff: function () {
- if (realTabId !== null) {
+ if (realTabId !== null) {
toggleOff();
- }
+ }
}
- };
+ };
- Object.defineProperty(exports, 'tabId', {
+ Object.defineProperty(exports, 'tabId', {
get: function () {
- return realTabId || 0;
- },
- });
+ return realTabId || 0;
+ },
+ });
- return exports;
+ return exports;
})();
let grabView = function () {
- if (ownerId === undefined) {
+ if (ownerId === undefined) {
ownerId = Date.now();
- }
- readLogBufferAsync();
+ }
+ readLogBufferAsync();
};
let releaseView = function () {
- if (ownerId === undefined) {
- return;
- }
+ if (ownerId === undefined) {
+ return;
+ }
- vAPI.messaging.send('logger-ui.js', {
- what: 'releaseView',
- ownerId: ownerId
- });
+ vAPI.messaging.send('logger-ui.js', {
+ what: 'releaseView',
+ ownerId: ownerId
+ });
- ownerId = undefined;
+ ownerId = undefined;
};
window.addEventListener('pagehide', releaseView);
@@ -915,7 +915,7 @@
uDom('#clear').on('click', clearBuffer);
uDom('#maxEntries').on('change', onMaxEntriesChanged);
uDom('#content table').on('click', 'tr > td:nth-of-type(1)',
- toggleCompactRow);
+ toggleCompactRow);
uDom('#content table').on('click', 'tr.canMtx > td:nth-of-type(2)',
- popupManager.toggleOn);
+ popupManager.toggleOn);
})();
diff --git a/js/logger.js b/js/logger.js
index a602d91..86f8c9c 100644
--- a/js/logger.js
+++ b/js/logger.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2015-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uBlock
*/
@@ -48,7 +48,7 @@
var janitor = function () {
if (buffer !== null
- && lastReadTime < (Date.now() - logBufferObsoleteAfter)) {
+ && lastReadTime < (Date.now() - logBufferObsoleteAfter)) {
buffer = null;
writePtr = 0;
api.ownerId = undefined;
@@ -63,8 +63,8 @@
writeOne: function () {
if (buffer === null) {
- return;
- }
+ return;
+ }
if (writePtr === buffer.length) {
buffer.push(new LogEntry(arguments));
diff --git a/js/main-blocked.js b/js/main-blocked.js
index cea79ce..20703a7 100644
--- a/js/main-blocked.js
+++ b/js/main-blocked.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2015-2019 Raymond Hill
- Copyright (C) 2019-2020-2021 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/js/matrix.js b/js/matrix.js
index fc0c90d..58276f6 100644
--- a/js/matrix.js
+++ b/js/matrix.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -32,844 +32,844 @@
Cu.import('chrome://ematrix/content/lib/Punycode.jsm');
Cu.import('chrome://ematrix/content/lib/UriTools.jsm');
- /******************************************************************************/
+/******************************************************************************/
- var ηm = ηMatrix;
- var magicId = 'axyorpwxtmnf';
- var uniqueIdGenerator = 1;
+var ηm = ηMatrix;
+var magicId = 'axyorpwxtmnf';
+var uniqueIdGenerator = 1;
- /******************************************************************************/
+/******************************************************************************/
- var Matrix = function() {
- this.id = uniqueIdGenerator++;
- this.reset();
- this.sourceRegister = '';
- this.decomposedSourceRegister = [''];
- this.specificityRegister = 0;
- };
+var Matrix = function() {
+ this.id = uniqueIdGenerator++;
+ this.reset();
+ this.sourceRegister = '';
+ this.decomposedSourceRegister = [''];
+ this.specificityRegister = 0;
+};
- /******************************************************************************/
-
- Matrix.Transparent = 0;
- Matrix.Red = 1;
- Matrix.Green = 2;
- Matrix.Gray = 3;
-
- Matrix.Indirect = 0x00;
- Matrix.Direct = 0x80;
-
- Matrix.RedDirect = Matrix.Red | Matrix.Direct;
- Matrix.RedIndirect = Matrix.Red | Matrix.Indirect;
- Matrix.GreenDirect = Matrix.Green | Matrix.Direct;
- Matrix.GreenIndirect = Matrix.Green | Matrix.Indirect;
- Matrix.GrayDirect = Matrix.Gray | Matrix.Direct;
- Matrix.GrayIndirect = Matrix.Gray | Matrix.Indirect;
-
- /******************************************************************************/
-
- var typeBitOffsets = new Map([
- [ '*', 0 ],
- [ 'doc', 2 ],
- [ 'cookie', 4 ],
- [ 'css', 6 ],
- [ 'image', 8 ],
- [ 'media', 10 ],
- [ 'script', 12 ],
- [ 'xhr', 14 ],
- [ 'frame', 16 ],
- [ 'other', 18 ]
- ]);
-
- var stateToNameMap = new Map([
- [ 1, 'block' ],
- [ 2, 'allow' ],
- [ 3, 'inherit' ]
- ]);
-
- var nameToStateMap = {
- 'block': 1,
- 'allow': 2,
- 'noop': 2,
- 'inherit': 3
- };
+/******************************************************************************/
- var switchBitOffsets = new Map([
- [ 'matrix-off', 0 ],
- [ 'https-strict', 2 ],
- /* 4 is now unused, formerly assigned to UA spoofing */
- [ 'referrer-spoof', 6 ],
- [ 'noscript-spoof', 8 ],
- [ 'no-workers', 10 ]
- ]);
-
- var switchStateToNameMap = new Map([
- [ 1, 'true' ],
- [ 2, 'false' ]
- ]);
-
- var nameToSwitchStateMap = {
- 'true': 1,
- 'false': 2
- };
+Matrix.Transparent = 0;
+Matrix.Red = 1;
+Matrix.Green = 2;
+Matrix.Gray = 3;
- /******************************************************************************/
+Matrix.Indirect = 0x00;
+Matrix.Direct = 0x80;
- Matrix.columnHeaderIndices = (function() {
- var out = new Map(),
- i = 0;
- for ( var type of typeBitOffsets.keys() ) {
- out.set(type, i++);
- }
- return out;
- })();
+Matrix.RedDirect = Matrix.Red | Matrix.Direct;
+Matrix.RedIndirect = Matrix.Red | Matrix.Indirect;
+Matrix.GreenDirect = Matrix.Green | Matrix.Direct;
+Matrix.GreenIndirect = Matrix.Green | Matrix.Indirect;
+Matrix.GrayDirect = Matrix.Gray | Matrix.Direct;
+Matrix.GrayIndirect = Matrix.Gray | Matrix.Indirect;
+/******************************************************************************/
- Matrix.switchNames = new Set(switchBitOffsets.keys());
+var typeBitOffsets = new Map([
+ [ '*', 0 ],
+ [ 'doc', 2 ],
+ [ 'cookie', 4 ],
+ [ 'css', 6 ],
+ [ 'image', 8 ],
+ [ 'media', 10 ],
+ [ 'script', 12 ],
+ [ 'xhr', 14 ],
+ [ 'frame', 16 ],
+ [ 'other', 18 ]
+]);
+
+var stateToNameMap = new Map([
+ [ 1, 'block' ],
+ [ 2, 'allow' ],
+ [ 3, 'inherit' ]
+]);
+
+var nameToStateMap = {
+ 'block': 1,
+ 'allow': 2,
+ 'noop': 2,
+ 'inherit': 3
+};
+
+var switchBitOffsets = new Map([
+ [ 'matrix-off', 0 ],
+ [ 'https-strict', 2 ],
+ /* 4 is now unused, formerly assigned to UA spoofing */
+ [ 'referrer-spoof', 6 ],
+ [ 'noscript-spoof', 8 ],
+ [ 'no-workers', 10 ]
+]);
+
+var switchStateToNameMap = new Map([
+ [ 1, 'true' ],
+ [ 2, 'false' ]
+]);
+
+var nameToSwitchStateMap = {
+ 'true': 1,
+ 'false': 2
+};
- /******************************************************************************/
+/******************************************************************************/
- // For performance purpose, as simple tests as possible
- var reHostnameVeryCoarse = /[g-z_-]/;
- var reIPv4VeryCoarse = /\.\d+$/;
+Matrix.columnHeaderIndices = (function() {
+ var out = new Map(),
+ i = 0;
+ for ( var type of typeBitOffsets.keys() ) {
+ out.set(type, i++);
+ }
+ return out;
+})();
- // http://tools.ietf.org/html/rfc5952
- // 4.3: "MUST be represented in lowercase"
- // Also: http://en.wikipedia.org/wiki/IPv6_address#Literal_IPv6_addresses_in_network_resource_identifiers
- var isIPAddress = function(hostname) {
- if ( reHostnameVeryCoarse.test(hostname) ) {
- return false;
- }
- if ( reIPv4VeryCoarse.test(hostname) ) {
- return true;
- }
- return hostname.charAt(0) === '[';
- };
+Matrix.switchNames = new Set(switchBitOffsets.keys());
- /******************************************************************************/
+/******************************************************************************/
- var toBroaderHostname = function(hostname) {
- if ( hostname === '*' ) { return ''; }
- if ( isIPAddress(hostname) ) {
- return toBroaderIPAddress(hostname);
- }
- var pos = hostname.indexOf('.');
- if ( pos === -1 ) {
- return '*';
- }
- return hostname.slice(pos + 1);
- };
+// For performance purpose, as simple tests as possible
+var reHostnameVeryCoarse = /[g-z_-]/;
+var reIPv4VeryCoarse = /\.\d+$/;
- var toBroaderIPAddress = function(ipaddress) {
- // Can't broaden IPv6 (for now)
- if ( ipaddress.charAt(0) === '[' ) {
- return '*';
- }
- var pos = ipaddress.lastIndexOf('.');
- return pos !== -1 ? ipaddress.slice(0, pos) : '*';
- };
+// http://tools.ietf.org/html/rfc5952
+// 4.3: "MUST be represented in lowercase"
+// Also: http://en.wikipedia.org/wiki/IPv6_address#Literal_IPv6_addresses_in_network_resource_identifiers
- Matrix.toBroaderHostname = toBroaderHostname;
+var isIPAddress = function(hostname) {
+ if ( reHostnameVeryCoarse.test(hostname) ) {
+ return false;
+ }
+ if ( reIPv4VeryCoarse.test(hostname) ) {
+ return true;
+ }
+ return hostname.charAt(0) === '[';
+};
- /******************************************************************************/
+/******************************************************************************/
- // Find out src-des relationship, using coarse-to-fine grained tests for
- // speed. If desHostname is 1st-party to srcHostname, the domain is returned,
- // otherwise the empty string.
+var toBroaderHostname = function(hostname) {
+ if ( hostname === '*' ) { return ''; }
+ if ( isIPAddress(hostname) ) {
+ return toBroaderIPAddress(hostname);
+ }
+ var pos = hostname.indexOf('.');
+ if ( pos === -1 ) {
+ return '*';
+ }
+ return hostname.slice(pos + 1);
+};
+
+var toBroaderIPAddress = function(ipaddress) {
+ // Can't broaden IPv6 (for now)
+ if ( ipaddress.charAt(0) === '[' ) {
+ return '*';
+ }
+ var pos = ipaddress.lastIndexOf('.');
+ return pos !== -1 ? ipaddress.slice(0, pos) : '*';
+};
+
+Matrix.toBroaderHostname = toBroaderHostname;
- var extractFirstPartyDesDomain = function(srcHostname, desHostname) {
- if ( srcHostname === '*' || desHostname === '*' || desHostname === '1st-party' ) {
- return '';
- }
- var ηmuri = UriTools;
- var srcDomain = ηmuri.domainFromHostname(srcHostname) || srcHostname;
- var desDomain = ηmuri.domainFromHostname(desHostname) || desHostname;
- return desDomain === srcDomain ? desDomain : '';
- };
+/******************************************************************************/
- /******************************************************************************/
+// Find out src-des relationship, using coarse-to-fine grained tests for
+// speed. If desHostname is 1st-party to srcHostname, the domain is returned,
+// otherwise the empty string.
- Matrix.prototype.reset = function() {
- this.switches = new Map();
- this.rules = new Map();
- this.rootValue = Matrix.RedIndirect;
- this.modifiedTime = 0;
- };
+var extractFirstPartyDesDomain = function(srcHostname, desHostname) {
+ if ( srcHostname === '*' || desHostname === '*' || desHostname === '1st-party' ) {
+ return '';
+ }
+ var ηmuri = UriTools;
+ var srcDomain = ηmuri.domainFromHostname(srcHostname) || srcHostname;
+ var desDomain = ηmuri.domainFromHostname(desHostname) || desHostname;
+ return desDomain === srcDomain ? desDomain : '';
+};
- /******************************************************************************/
+/******************************************************************************/
- Matrix.prototype.decomposeSource = function(srcHostname) {
- if ( srcHostname === this.sourceRegister ) { return; }
- var hn = srcHostname;
- this.decomposedSourceRegister[0] = this.sourceRegister = hn;
- var i = 1;
- for (;;) {
- hn = toBroaderHostname(hn);
- this.decomposedSourceRegister[i++] = hn;
- if ( hn === '' ) { break; }
- }
- };
+Matrix.prototype.reset = function() {
+ this.switches = new Map();
+ this.rules = new Map();
+ this.rootValue = Matrix.RedIndirect;
+ this.modifiedTime = 0;
+};
- /******************************************************************************/
+/******************************************************************************/
- // Copy another matrix to self. Do this incrementally to minimize impact on
- // a live matrix.
+Matrix.prototype.decomposeSource = function(srcHostname) {
+ if ( srcHostname === this.sourceRegister ) { return; }
+ var hn = srcHostname;
+ this.decomposedSourceRegister[0] = this.sourceRegister = hn;
+ var i = 1;
+ for (;;) {
+ hn = toBroaderHostname(hn);
+ this.decomposedSourceRegister[i++] = hn;
+ if ( hn === '' ) { break; }
+ }
+};
- Matrix.prototype.assign = function(other) {
- var k, entry;
- // Remove rules not in other
- for ( k of this.rules.keys() ) {
- if ( other.rules.has(k) === false ) {
- this.rules.delete(k);
- }
- }
- // Remove switches not in other
- for ( k of this.switches.keys() ) {
- if ( other.switches.has(k) === false ) {
- this.switches.delete(k);
- }
- }
- // Add/change rules in other
- for ( entry of other.rules ) {
- this.rules.set(entry[0], entry[1]);
- }
- // Add/change switches in other
- for ( entry of other.switches ) {
- this.switches.set(entry[0], entry[1]);
- }
- this.modifiedTime = other.modifiedTime;
- return this;
- };
+/******************************************************************************/
- // https://www.youtube.com/watch?v=e9RS4biqyAc
+// Copy another matrix to self. Do this incrementally to minimize impact on
+// a live matrix.
- /******************************************************************************/
+Matrix.prototype.assign = function(other) {
+ var k, entry;
+ // Remove rules not in other
+ for ( k of this.rules.keys() ) {
+ if ( other.rules.has(k) === false ) {
+ this.rules.delete(k);
+ }
+ }
+ // Remove switches not in other
+ for ( k of this.switches.keys() ) {
+ if ( other.switches.has(k) === false ) {
+ this.switches.delete(k);
+ }
+ }
+ // Add/change rules in other
+ for ( entry of other.rules ) {
+ this.rules.set(entry[0], entry[1]);
+ }
+ // Add/change switches in other
+ for ( entry of other.switches ) {
+ this.switches.set(entry[0], entry[1]);
+ }
+ this.modifiedTime = other.modifiedTime;
+ return this;
+};
+
+// https://www.youtube.com/watch?v=e9RS4biqyAc
- // If value is undefined, the switch is removed
+/******************************************************************************/
- Matrix.prototype.setSwitch = function(switchName, srcHostname, newVal) {
- var bitOffset = switchBitOffsets.get(switchName);
- if ( bitOffset === undefined ) {
- return false;
- }
- if ( newVal === this.evaluateSwitch(switchName, srcHostname) ) {
- return false;
- }
- var bits = this.switches.get(srcHostname) || 0;
- bits &= ~(3 << bitOffset);
- bits |= newVal << bitOffset;
- if ( bits === 0 ) {
- this.switches.delete(srcHostname);
- } else {
- this.switches.set(srcHostname, bits);
- }
- this.modifiedTime = Date.now();
- return true;
- };
+// If value is undefined, the switch is removed
- /******************************************************************************/
+Matrix.prototype.setSwitch = function(switchName, srcHostname, newVal) {
+ var bitOffset = switchBitOffsets.get(switchName);
+ if ( bitOffset === undefined ) {
+ return false;
+ }
+ if ( newVal === this.evaluateSwitch(switchName, srcHostname) ) {
+ return false;
+ }
+ var bits = this.switches.get(srcHostname) || 0;
+ bits &= ~(3 << bitOffset);
+ bits |= newVal << bitOffset;
+ if ( bits === 0 ) {
+ this.switches.delete(srcHostname);
+ } else {
+ this.switches.set(srcHostname, bits);
+ }
+ this.modifiedTime = Date.now();
+ return true;
+};
- Matrix.prototype.setCell = function(srcHostname, desHostname, type, state) {
- var bitOffset = typeBitOffsets.get(type),
- k = srcHostname + ' ' + desHostname,
- oldBitmap = this.rules.get(k);
- if ( oldBitmap === undefined ) {
- oldBitmap = 0;
- }
- var newBitmap = oldBitmap & ~(3 << bitOffset) | (state << bitOffset);
- if ( newBitmap === oldBitmap ) {
- return false;
- }
- if ( newBitmap === 0 ) {
- this.rules.delete(k);
- } else {
- this.rules.set(k, newBitmap);
- }
- this.modifiedTime = Date.now();
- return true;
- };
+/******************************************************************************/
- /******************************************************************************/
+Matrix.prototype.setCell = function(srcHostname, desHostname, type, state) {
+ var bitOffset = typeBitOffsets.get(type),
+ k = srcHostname + ' ' + desHostname,
+ oldBitmap = this.rules.get(k);
+ if ( oldBitmap === undefined ) {
+ oldBitmap = 0;
+ }
+ var newBitmap = oldBitmap & ~(3 << bitOffset) | (state << bitOffset);
+ if ( newBitmap === oldBitmap ) {
+ return false;
+ }
+ if ( newBitmap === 0 ) {
+ this.rules.delete(k);
+ } else {
+ this.rules.set(k, newBitmap);
+ }
+ this.modifiedTime = Date.now();
+ return true;
+};
- Matrix.prototype.blacklistCell = function(srcHostname, desHostname, type) {
- var r = this.evaluateCellZ(srcHostname, desHostname, type);
- if ( r === 1 ) {
- return false;
- }
- this.setCell(srcHostname, desHostname, type, 0);
- r = this.evaluateCellZ(srcHostname, desHostname, type);
- if ( r === 1 ) {
- return true;
- }
- this.setCell(srcHostname, desHostname, type, 1);
+/******************************************************************************/
+
+Matrix.prototype.blacklistCell = function(srcHostname, desHostname, type) {
+ var r = this.evaluateCellZ(srcHostname, desHostname, type);
+ if ( r === 1 ) {
+ return false;
+ }
+ this.setCell(srcHostname, desHostname, type, 0);
+ r = this.evaluateCellZ(srcHostname, desHostname, type);
+ if ( r === 1 ) {
return true;
- };
+ }
+ this.setCell(srcHostname, desHostname, type, 1);
+ return true;
+};
- /******************************************************************************/
+/******************************************************************************/
- Matrix.prototype.whitelistCell = function(srcHostname, desHostname, type) {
- var r = this.evaluateCellZ(srcHostname, desHostname, type);
- if ( r === 2 ) {
- return false;
- }
- this.setCell(srcHostname, desHostname, type, 0);
- r = this.evaluateCellZ(srcHostname, desHostname, type);
- if ( r === 2 ) {
- return true;
- }
- this.setCell(srcHostname, desHostname, type, 2);
+Matrix.prototype.whitelistCell = function(srcHostname, desHostname, type) {
+ var r = this.evaluateCellZ(srcHostname, desHostname, type);
+ if ( r === 2 ) {
+ return false;
+ }
+ this.setCell(srcHostname, desHostname, type, 0);
+ r = this.evaluateCellZ(srcHostname, desHostname, type);
+ if ( r === 2 ) {
return true;
- };
+ }
+ this.setCell(srcHostname, desHostname, type, 2);
+ return true;
+};
- /******************************************************************************/
+/******************************************************************************/
- Matrix.prototype.graylistCell = function(srcHostname, desHostname, type) {
- var r = this.evaluateCellZ(srcHostname, desHostname, type);
- if ( r === 0 || r === 3 ) {
- return false;
- }
- this.setCell(srcHostname, desHostname, type, 0);
- r = this.evaluateCellZ(srcHostname, desHostname, type);
- if ( r === 0 || r === 3 ) {
- return true;
- }
- this.setCell(srcHostname, desHostname, type, 3);
+Matrix.prototype.graylistCell = function(srcHostname, desHostname, type) {
+ var r = this.evaluateCellZ(srcHostname, desHostname, type);
+ if ( r === 0 || r === 3 ) {
+ return false;
+ }
+ this.setCell(srcHostname, desHostname, type, 0);
+ r = this.evaluateCellZ(srcHostname, desHostname, type);
+ if ( r === 0 || r === 3 ) {
return true;
- };
-
- /******************************************************************************/
+ }
+ this.setCell(srcHostname, desHostname, type, 3);
+ return true;
+};
- Matrix.prototype.evaluateCell = function(srcHostname, desHostname, type) {
- var key = srcHostname + ' ' + desHostname;
- var bitmap = this.rules.get(key);
- if ( bitmap === undefined ) {
- return 0;
- }
- return bitmap >> typeBitOffsets.get(type) & 3;
- };
+/******************************************************************************/
- /******************************************************************************/
+Matrix.prototype.evaluateCell = function(srcHostname, desHostname, type) {
+ var key = srcHostname + ' ' + desHostname;
+ var bitmap = this.rules.get(key);
+ if ( bitmap === undefined ) {
+ return 0;
+ }
+ return bitmap >> typeBitOffsets.get(type) & 3;
+};
- Matrix.prototype.evaluateCellZ = function(srcHostname, desHostname, type) {
- this.decomposeSource(srcHostname);
+/******************************************************************************/
- var bitOffset = typeBitOffsets.get(type),
- s, v, i = 0;
- for (;;) {
- s = this.decomposedSourceRegister[i++];
- if ( s === '' ) { break; }
- v = this.rules.get(s + ' ' + desHostname);
- if ( v !== undefined ) {
- v = v >> bitOffset & 3;
- if ( v !== 0 ) {
- return v;
- }
+Matrix.prototype.evaluateCellZ = function(srcHostname, desHostname, type) {
+ this.decomposeSource(srcHostname);
+
+ var bitOffset = typeBitOffsets.get(type),
+ s, v, i = 0;
+ for (;;) {
+ s = this.decomposedSourceRegister[i++];
+ if ( s === '' ) { break; }
+ v = this.rules.get(s + ' ' + desHostname);
+ if ( v !== undefined ) {
+ v = v >> bitOffset & 3;
+ if ( v !== 0 ) {
+ return v;
}
}
- // srcHostname is '*' at this point
+ }
+ // srcHostname is '*' at this point
- // Preset blacklisted hostnames are blacklisted in global scope
- if ( type === '*' && ηm.ubiquitousBlacklist.test(desHostname) ) {
- return 1;
- }
+ // Preset blacklisted hostnames are blacklisted in global scope
+ if ( type === '*' && ηm.ubiquitousBlacklist.test(desHostname) ) {
+ return 1;
+ }
- // https://github.com/gorhill/uMatrix/issues/65
- // Hardcoded global `doc` rule
- if ( type === 'doc' && desHostname === '*' ) {
- return 2;
- }
+ // https://github.com/gorhill/uMatrix/issues/65
+ // Hardcoded global `doc` rule
+ if ( type === 'doc' && desHostname === '*' ) {
+ return 2;
+ }
- return 0;
- };
-
- /******************************************************************************/
+ return 0;
+};
- Matrix.prototype.evaluateCellZXY = function(srcHostname, desHostname, type) {
- // Matrix filtering switch
- this.specificityRegister = 0;
- if ( this.evaluateSwitchZ('matrix-off', srcHostname) ) {
- return Matrix.GreenIndirect;
- }
-
- // TODO: There are cells evaluated twice when the type is '*'. Unsure
- // whether it's worth trying to avoid that, as this could introduce
- // overhead which may not be gained back by skipping the redundant tests.
- // And this happens *only* when building the matrix UI, not when
- // evaluating net requests.
-
- // Specific-hostname specific-type cell
- this.specificityRegister = 1;
- var r = this.evaluateCellZ(srcHostname, desHostname, type);
- if ( r === 1 ) { return Matrix.RedDirect; }
- if ( r === 2 ) { return Matrix.GreenDirect; }
-
- // Specific-hostname any-type cell
- this.specificityRegister = 2;
- var rl = this.evaluateCellZ(srcHostname, desHostname, '*');
- if ( rl === 1 ) { return Matrix.RedIndirect; }
-
- var d = desHostname;
- var firstPartyDesDomain = extractFirstPartyDesDomain(srcHostname, desHostname);
-
- // Ancestor cells, up to 1st-party destination domain
- if ( firstPartyDesDomain !== '' ) {
- this.specificityRegister = 3;
- for (;;) {
- if ( d === firstPartyDesDomain ) { break; }
- d = d.slice(d.indexOf('.') + 1);
-
- // specific-hostname specific-type cell
- r = this.evaluateCellZ(srcHostname, d, type);
- if ( r === 1 ) { return Matrix.RedIndirect; }
- if ( r === 2 ) { return Matrix.GreenIndirect; }
- // Do not override a narrower rule
- if ( rl !== 2 ) {
- rl = this.evaluateCellZ(srcHostname, d, '*');
- if ( rl === 1 ) { return Matrix.RedIndirect; }
- }
- }
-
- // 1st-party specific-type cell: it's a special row, looked up only
- // when destination is 1st-party to source.
- r = this.evaluateCellZ(srcHostname, '1st-party', type);
- if ( r === 1 ) { return Matrix.RedIndirect; }
- if ( r === 2 ) { return Matrix.GreenIndirect; }
- // Do not override narrower rule
- if ( rl !== 2 ) {
- rl = this.evaluateCellZ(srcHostname, '1st-party', '*');
- if ( rl === 1 ) { return Matrix.RedIndirect; }
- }
- }
+/******************************************************************************/
- // Keep going, up to root
- this.specificityRegister = 4;
+Matrix.prototype.evaluateCellZXY = function(srcHostname, desHostname, type) {
+ // Matrix filtering switch
+ this.specificityRegister = 0;
+ if ( this.evaluateSwitchZ('matrix-off', srcHostname) ) {
+ return Matrix.GreenIndirect;
+ }
+
+ // TODO: There are cells evaluated twice when the type is '*'. Unsure
+ // whether it's worth trying to avoid that, as this could introduce
+ // overhead which may not be gained back by skipping the redundant tests.
+ // And this happens *only* when building the matrix UI, not when
+ // evaluating net requests.
+
+ // Specific-hostname specific-type cell
+ this.specificityRegister = 1;
+ var r = this.evaluateCellZ(srcHostname, desHostname, type);
+ if ( r === 1 ) { return Matrix.RedDirect; }
+ if ( r === 2 ) { return Matrix.GreenDirect; }
+
+ // Specific-hostname any-type cell
+ this.specificityRegister = 2;
+ var rl = this.evaluateCellZ(srcHostname, desHostname, '*');
+ if ( rl === 1 ) { return Matrix.RedIndirect; }
+
+ var d = desHostname;
+ var firstPartyDesDomain = extractFirstPartyDesDomain(srcHostname, desHostname);
+
+ // Ancestor cells, up to 1st-party destination domain
+ if ( firstPartyDesDomain !== '' ) {
+ this.specificityRegister = 3;
for (;;) {
- d = toBroaderHostname(d);
- if ( d === '*' ) { break; }
+ if ( d === firstPartyDesDomain ) { break; }
+ d = d.slice(d.indexOf('.') + 1);
// specific-hostname specific-type cell
r = this.evaluateCellZ(srcHostname, d, type);
if ( r === 1 ) { return Matrix.RedIndirect; }
if ( r === 2 ) { return Matrix.GreenIndirect; }
- // Do not override narrower rule
+ // Do not override a narrower rule
if ( rl !== 2 ) {
rl = this.evaluateCellZ(srcHostname, d, '*');
if ( rl === 1 ) { return Matrix.RedIndirect; }
}
}
- // Any-hostname specific-type cells
- this.specificityRegister = 5;
- r = this.evaluateCellZ(srcHostname, '*', type);
- // Line below is strict-blocking
+ // 1st-party specific-type cell: it's a special row, looked up only
+ // when destination is 1st-party to source.
+ r = this.evaluateCellZ(srcHostname, '1st-party', type);
if ( r === 1 ) { return Matrix.RedIndirect; }
- // Narrower rule wins
- if ( rl === 2 ) { return Matrix.GreenIndirect; }
if ( r === 2 ) { return Matrix.GreenIndirect; }
+ // Do not override narrower rule
+ if ( rl !== 2 ) {
+ rl = this.evaluateCellZ(srcHostname, '1st-party', '*');
+ if ( rl === 1 ) { return Matrix.RedIndirect; }
+ }
+ }
- // Any-hostname any-type cell
- this.specificityRegister = 6;
- r = this.evaluateCellZ(srcHostname, '*', '*');
+ // Keep going, up to root
+ this.specificityRegister = 4;
+ for (;;) {
+ d = toBroaderHostname(d);
+ if ( d === '*' ) { break; }
+
+ // specific-hostname specific-type cell
+ r = this.evaluateCellZ(srcHostname, d, type);
if ( r === 1 ) { return Matrix.RedIndirect; }
if ( r === 2 ) { return Matrix.GreenIndirect; }
- return this.rootValue;
- };
-
- // https://www.youtube.com/watch?v=4C5ZkwrnVfM
+ // Do not override narrower rule
+ if ( rl !== 2 ) {
+ rl = this.evaluateCellZ(srcHostname, d, '*');
+ if ( rl === 1 ) { return Matrix.RedIndirect; }
+ }
+ }
+
+ // Any-hostname specific-type cells
+ this.specificityRegister = 5;
+ r = this.evaluateCellZ(srcHostname, '*', type);
+ // Line below is strict-blocking
+ if ( r === 1 ) { return Matrix.RedIndirect; }
+ // Narrower rule wins
+ if ( rl === 2 ) { return Matrix.GreenIndirect; }
+ if ( r === 2 ) { return Matrix.GreenIndirect; }
+
+ // Any-hostname any-type cell
+ this.specificityRegister = 6;
+ r = this.evaluateCellZ(srcHostname, '*', '*');
+ if ( r === 1 ) { return Matrix.RedIndirect; }
+ if ( r === 2 ) { return Matrix.GreenIndirect; }
+ return this.rootValue;
+};
+
+// https://www.youtube.com/watch?v=4C5ZkwrnVfM
- /******************************************************************************/
+/******************************************************************************/
- Matrix.prototype.evaluateRowZXY = function(srcHostname, desHostname) {
- var out = [];
- for ( var type of typeBitOffsets.keys() ) {
- out.push(this.evaluateCellZXY(srcHostname, desHostname, type));
- }
- return out;
- };
+Matrix.prototype.evaluateRowZXY = function(srcHostname, desHostname) {
+ var out = [];
+ for ( var type of typeBitOffsets.keys() ) {
+ out.push(this.evaluateCellZXY(srcHostname, desHostname, type));
+ }
+ return out;
+};
- /******************************************************************************/
+/******************************************************************************/
- Matrix.prototype.mustBlock = function(srcHostname, desHostname, type) {
- return (this.evaluateCellZXY(srcHostname, desHostname, type) & 3) === Matrix.Red;
- };
+Matrix.prototype.mustBlock = function(srcHostname, desHostname, type) {
+ return (this.evaluateCellZXY(srcHostname, desHostname, type) & 3) === Matrix.Red;
+};
- /******************************************************************************/
+/******************************************************************************/
- Matrix.prototype.srcHostnameFromRule = function(rule) {
- return rule.slice(0, rule.indexOf(' '));
- };
+Matrix.prototype.srcHostnameFromRule = function(rule) {
+ return rule.slice(0, rule.indexOf(' '));
+};
- /******************************************************************************/
+/******************************************************************************/
- Matrix.prototype.desHostnameFromRule = function(rule) {
- return rule.slice(rule.indexOf(' ') + 1);
- };
+Matrix.prototype.desHostnameFromRule = function(rule) {
+ return rule.slice(rule.indexOf(' ') + 1);
+};
- /******************************************************************************/
+/******************************************************************************/
- Matrix.prototype.setSwitchZ = function(switchName, srcHostname, newState) {
- var bitOffset = switchBitOffsets.get(switchName);
- if ( bitOffset === undefined ) {
- return false;
- }
- var state = this.evaluateSwitchZ(switchName, srcHostname);
- if ( newState === state ) {
- return false;
- }
- if ( newState === undefined ) {
- newState = !state;
- }
- var bits = this.switches.get(srcHostname) || 0;
- bits &= ~(3 << bitOffset);
- if ( bits === 0 ) {
- this.switches.delete(srcHostname);
- } else {
- this.switches.set(srcHostname, bits);
- }
- this.modifiedTime = Date.now();
- state = this.evaluateSwitchZ(switchName, srcHostname);
- if ( state === newState ) {
- return true;
- }
- this.switches.set(srcHostname, bits | ((newState ? 1 : 2) << bitOffset));
+Matrix.prototype.setSwitchZ = function(switchName, srcHostname, newState) {
+ var bitOffset = switchBitOffsets.get(switchName);
+ if ( bitOffset === undefined ) {
+ return false;
+ }
+ var state = this.evaluateSwitchZ(switchName, srcHostname);
+ if ( newState === state ) {
+ return false;
+ }
+ if ( newState === undefined ) {
+ newState = !state;
+ }
+ var bits = this.switches.get(srcHostname) || 0;
+ bits &= ~(3 << bitOffset);
+ if ( bits === 0 ) {
+ this.switches.delete(srcHostname);
+ } else {
+ this.switches.set(srcHostname, bits);
+ }
+ this.modifiedTime = Date.now();
+ state = this.evaluateSwitchZ(switchName, srcHostname);
+ if ( state === newState ) {
return true;
- };
+ }
+ this.switches.set(srcHostname, bits | ((newState ? 1 : 2) << bitOffset));
+ return true;
+};
- /******************************************************************************/
+/******************************************************************************/
- // 0 = inherit from broader scope, up to default state
- // 1 = non-default state
- // 2 = forced default state (to override a broader non-default state)
+// 0 = inherit from broader scope, up to default state
+// 1 = non-default state
+// 2 = forced default state (to override a broader non-default state)
- Matrix.prototype.evaluateSwitch = function(switchName, srcHostname) {
- var bits = this.switches.get(srcHostname) || 0;
- if ( bits === 0 ) {
- return 0;
- }
- var bitOffset = switchBitOffsets.get(switchName);
- if ( bitOffset === undefined ) {
- return 0;
- }
- return (bits >> bitOffset) & 3;
- };
+Matrix.prototype.evaluateSwitch = function(switchName, srcHostname) {
+ var bits = this.switches.get(srcHostname) || 0;
+ if ( bits === 0 ) {
+ return 0;
+ }
+ var bitOffset = switchBitOffsets.get(switchName);
+ if ( bitOffset === undefined ) {
+ return 0;
+ }
+ return (bits >> bitOffset) & 3;
+};
- /******************************************************************************/
+/******************************************************************************/
- Matrix.prototype.evaluateSwitchZ = function(switchName, srcHostname) {
- var bitOffset = switchBitOffsets.get(switchName);
- if ( bitOffset === undefined ) { return false; }
+Matrix.prototype.evaluateSwitchZ = function(switchName, srcHostname) {
+ var bitOffset = switchBitOffsets.get(switchName);
+ if ( bitOffset === undefined ) { return false; }
- this.decomposeSource(srcHostname);
+ this.decomposeSource(srcHostname);
- var s, bits, i = 0;
- for (;;) {
- s = this.decomposedSourceRegister[i++];
- if ( s === '' ) { break; }
- bits = this.switches.get(s) || 0;
+ var s, bits, i = 0;
+ for (;;) {
+ s = this.decomposedSourceRegister[i++];
+ if ( s === '' ) { break; }
+ bits = this.switches.get(s) || 0;
+ if ( bits !== 0 ) {
+ bits = bits >> bitOffset & 3;
if ( bits !== 0 ) {
- bits = bits >> bitOffset & 3;
- if ( bits !== 0 ) {
- return bits === 1;
- }
+ return bits === 1;
}
}
- return false;
- };
+ }
+ return false;
+};
- /******************************************************************************/
-
- Matrix.prototype.extractAllSourceHostnames = (function() {
- var cachedResult = new Set();
- var matrixId = 0;
- var readTime = 0;
-
- return function() {
- if ( matrixId !== this.id || readTime !== this.modifiedTime ) {
- cachedResult.clear();
- for ( var rule of this.rules.keys() ) {
- cachedResult.add(rule.slice(0, rule.indexOf(' ')));
- }
- matrixId = this.id;
- readTime = this.modifiedTime;
- }
- return cachedResult;
- };
- })();
-
- /******************************************************************************/
-
- Matrix.prototype.toString = function() {
- var out = [];
- var rule, type, switchName, val;
- var srcHostname, desHostname;
- for ( rule of this.rules.keys() ) {
- srcHostname = this.srcHostnameFromRule(rule);
- desHostname = this.desHostnameFromRule(rule);
- for ( type of typeBitOffsets.keys() ) {
- val = this.evaluateCell(srcHostname, desHostname, type);
- if ( val === 0 ) { continue; }
- out.push(
- Punycode.toUnicode(srcHostname) + ' ' +
- Punycode.toUnicode(desHostname) + ' ' +
- type + ' ' +
- stateToNameMap.get(val)
- );
- }
- }
- for ( srcHostname of this.switches.keys() ) {
- for ( switchName of switchBitOffsets.keys() ) {
- val = this.evaluateSwitch(switchName, srcHostname);
- if ( val === 0 ) { continue; }
- out.push(switchName + ': ' + srcHostname + ' ' + switchStateToNameMap.get(val));
+/******************************************************************************/
+
+Matrix.prototype.extractAllSourceHostnames = (function() {
+ var cachedResult = new Set();
+ var matrixId = 0;
+ var readTime = 0;
+
+ return function() {
+ if ( matrixId !== this.id || readTime !== this.modifiedTime ) {
+ cachedResult.clear();
+ for ( var rule of this.rules.keys() ) {
+ cachedResult.add(rule.slice(0, rule.indexOf(' ')));
}
+ matrixId = this.id;
+ readTime = this.modifiedTime;
}
- return out.sort().join('\n');
+ return cachedResult;
};
+})();
+
+/******************************************************************************/
- /******************************************************************************/
-
- Matrix.prototype.fromString = function(text, append) {
- var matrix = append ? this : new Matrix();
- var textEnd = text.length;
- var lineBeg = 0, lineEnd;
- var line, pos;
- var fields, fieldVal;
- var switchName;
- var srcHostname = '';
- var desHostname = '';
- var type, state;
-
- while ( lineBeg < textEnd ) {
- lineEnd = text.indexOf('\n', lineBeg);
+Matrix.prototype.toString = function() {
+ var out = [];
+ var rule, type, switchName, val;
+ var srcHostname, desHostname;
+ for ( rule of this.rules.keys() ) {
+ srcHostname = this.srcHostnameFromRule(rule);
+ desHostname = this.desHostnameFromRule(rule);
+ for ( type of typeBitOffsets.keys() ) {
+ val = this.evaluateCell(srcHostname, desHostname, type);
+ if ( val === 0 ) { continue; }
+ out.push(
+ Punycode.toUnicode(srcHostname) + ' ' +
+ Punycode.toUnicode(desHostname) + ' ' +
+ type + ' ' +
+ stateToNameMap.get(val)
+ );
+ }
+ }
+ for ( srcHostname of this.switches.keys() ) {
+ for ( switchName of switchBitOffsets.keys() ) {
+ val = this.evaluateSwitch(switchName, srcHostname);
+ if ( val === 0 ) { continue; }
+ out.push(switchName + ': ' + srcHostname + ' ' + switchStateToNameMap.get(val));
+ }
+ }
+ return out.sort().join('\n');
+};
+
+/******************************************************************************/
+
+Matrix.prototype.fromString = function(text, append) {
+ var matrix = append ? this : new Matrix();
+ var textEnd = text.length;
+ var lineBeg = 0, lineEnd;
+ var line, pos;
+ var fields, fieldVal;
+ var switchName;
+ var srcHostname = '';
+ var desHostname = '';
+ var type, state;
+
+ while ( lineBeg < textEnd ) {
+ lineEnd = text.indexOf('\n', lineBeg);
+ if ( lineEnd < 0 ) {
+ lineEnd = text.indexOf('\r', lineBeg);
if ( lineEnd < 0 ) {
- lineEnd = text.indexOf('\r', lineBeg);
- if ( lineEnd < 0 ) {
- lineEnd = textEnd;
- }
+ lineEnd = textEnd;
}
- line = text.slice(lineBeg, lineEnd).trim();
- lineBeg = lineEnd + 1;
+ }
+ line = text.slice(lineBeg, lineEnd).trim();
+ lineBeg = lineEnd + 1;
- pos = line.indexOf('# ');
- if ( pos !== -1 ) {
- line = line.slice(0, pos).trim();
- }
- if ( line === '' ) {
- continue;
- }
+ pos = line.indexOf('# ');
+ if ( pos !== -1 ) {
+ line = line.slice(0, pos).trim();
+ }
+ if ( line === '' ) {
+ continue;
+ }
- fields = line.split(/\s+/);
+ fields = line.split(/\s+/);
- // Less than 2 fields makes no sense
- if ( fields.length < 2 ) {
- continue;
- }
+ // Less than 2 fields makes no sense
+ if ( fields.length < 2 ) {
+ continue;
+ }
- fieldVal = fields[0];
+ fieldVal = fields[0];
- // Special directives:
+ // Special directives:
- // title
- pos = fieldVal.indexOf('title:');
- if ( pos !== -1 ) {
- // TODO
- continue;
- }
+ // title
+ pos = fieldVal.indexOf('title:');
+ if ( pos !== -1 ) {
+ // TODO
+ continue;
+ }
- // Name
- pos = fieldVal.indexOf('name:');
- if ( pos !== -1 ) {
- // TODO
- continue;
- }
+ // Name
+ pos = fieldVal.indexOf('name:');
+ if ( pos !== -1 ) {
+ // TODO
+ continue;
+ }
- // Switch on/off
+ // Switch on/off
- // `switch:` srcHostname state
- // state = [`true`, `false`]
- switchName = '';
- if ( fieldVal === 'switch:' || fieldVal === 'matrix:' ) {
- fieldVal = 'matrix-off:';
- }
- pos = fieldVal.indexOf(':');
- if ( pos !== -1 ) {
- switchName = fieldVal.slice(0, pos);
+ // `switch:` srcHostname state
+ // state = [`true`, `false`]
+ switchName = '';
+ if ( fieldVal === 'switch:' || fieldVal === 'matrix:' ) {
+ fieldVal = 'matrix-off:';
+ }
+ pos = fieldVal.indexOf(':');
+ if ( pos !== -1 ) {
+ switchName = fieldVal.slice(0, pos);
+ }
+ if ( switchBitOffsets.has(switchName) ) {
+ srcHostname = Punycode.toASCII(fields[1]);
+
+ // No state field: reject
+ fieldVal = fields[2];
+ if ( fieldVal === null ) {
+ continue;
}
- if ( switchBitOffsets.has(switchName) ) {
- srcHostname = Punycode.toASCII(fields[1]);
-
- // No state field: reject
- fieldVal = fields[2];
- if ( fieldVal === null ) {
- continue;
- }
- // Unknown state: reject
- if ( nameToSwitchStateMap.hasOwnProperty(fieldVal) === false ) {
- continue;
- }
-
- // Backward compatibility:
- // `chromium-behind-the-scene` is now `behind-the-scene`
- if ( srcHostname === 'chromium-behind-the-scene' ) {
- srcHostname = 'behind-the-scene';
- }
-
- matrix.setSwitch(switchName, srcHostname, nameToSwitchStateMap[fieldVal]);
+ // Unknown state: reject
+ if ( nameToSwitchStateMap.hasOwnProperty(fieldVal) === false ) {
continue;
}
- // Unknown directive
- if ( fieldVal.endsWith(':') ) {
- continue;
+ // Backward compatibility:
+ // `chromium-behind-the-scene` is now `behind-the-scene`
+ if ( srcHostname === 'chromium-behind-the-scene' ) {
+ srcHostname = 'behind-the-scene';
}
- // Valid rule syntax:
+ matrix.setSwitch(switchName, srcHostname, nameToSwitchStateMap[fieldVal]);
+ continue;
+ }
- // srcHostname desHostname [type [state]]
- // type = a valid request type
- // state = [`block`, `allow`, `inherit`]
+ // Unknown directive
+ if ( fieldVal.endsWith(':') ) {
+ continue;
+ }
- // srcHostname desHostname type
- // type = a valid request type
- // state = `allow`
+ // Valid rule syntax:
- // srcHostname desHostname
- // type = `*`
- // state = `allow`
+ // srcHostname desHostname [type [state]]
+ // type = a valid request type
+ // state = [`block`, `allow`, `inherit`]
- // Lines with invalid syntax silently ignored
+ // srcHostname desHostname type
+ // type = a valid request type
+ // state = `allow`
- srcHostname = Punycode.toASCII(fields[0]);
- desHostname = Punycode.toASCII(fields[1]);
+ // srcHostname desHostname
+ // type = `*`
+ // state = `allow`
- fieldVal = fields[2];
+ // Lines with invalid syntax silently ignored
- if ( fieldVal !== undefined ) {
- type = fieldVal;
- // https://github.com/gorhill/uMatrix/issues/759
- // Backward compatibility.
- if ( type === 'plugin' ) {
- type = 'media';
- }
- // Unknown type: reject
- if ( typeBitOffsets.has(type) === false ) {
- continue;
- }
- } else {
- type = '*';
- }
+ srcHostname = Punycode.toASCII(fields[0]);
+ desHostname = Punycode.toASCII(fields[1]);
- fieldVal = fields[3];
+ fieldVal = fields[2];
- if ( fieldVal !== undefined ) {
- // Unknown state: reject
- if ( nameToStateMap.hasOwnProperty(fieldVal) === false ) {
- continue;
- }
- state = nameToStateMap[fieldVal];
- } else {
- state = 2;
+ if ( fieldVal !== undefined ) {
+ type = fieldVal;
+ // https://github.com/gorhill/uMatrix/issues/759
+ // Backward compatibility.
+ if ( type === 'plugin' ) {
+ type = 'media';
}
-
- matrix.setCell(srcHostname, desHostname, type, state);
+ // Unknown type: reject
+ if ( typeBitOffsets.has(type) === false ) {
+ continue;
+ }
+ } else {
+ type = '*';
}
- if ( !append ) {
- this.assign(matrix);
+ fieldVal = fields[3];
+
+ if ( fieldVal !== undefined ) {
+ // Unknown state: reject
+ if ( nameToStateMap.hasOwnProperty(fieldVal) === false ) {
+ continue;
+ }
+ state = nameToStateMap[fieldVal];
+ } else {
+ state = 2;
}
- this.modifiedTime = Date.now();
- };
+ matrix.setCell(srcHostname, desHostname, type, state);
+ }
- /******************************************************************************/
+ if ( !append ) {
+ this.assign(matrix);
+ }
- Matrix.prototype.toSelfie = function() {
- return {
- magicId: magicId,
- switches: Array.from(this.switches),
- rules: Array.from(this.rules)
- };
- };
+ this.modifiedTime = Date.now();
+};
- /******************************************************************************/
+/******************************************************************************/
- Matrix.prototype.fromSelfie = function(selfie) {
- if ( selfie.magicId !== magicId ) { return false; }
- this.switches = new Map(selfie.switches);
- this.rules = new Map(selfie.rules);
- this.modifiedTime = Date.now();
- return true;
+Matrix.prototype.toSelfie = function() {
+ return {
+ magicId: magicId,
+ switches: Array.from(this.switches),
+ rules: Array.from(this.rules)
};
+};
- /******************************************************************************/
+/******************************************************************************/
- Matrix.prototype.diff = function(other, srcHostname, desHostnames) {
- var out = [];
- var desHostname, type;
- var switchName, i, thisVal, otherVal;
- for (;;) {
- for ( switchName of switchBitOffsets.keys() ) {
- thisVal = this.evaluateSwitch(switchName, srcHostname);
- otherVal = other.evaluateSwitch(switchName, srcHostname);
- if ( thisVal !== otherVal ) {
- out.push({
- 'what': switchName,
- 'src': srcHostname
- });
- }
- }
- i = desHostnames.length;
- while ( i-- ) {
- desHostname = desHostnames[i];
- for ( type of typeBitOffsets.keys() ) {
- thisVal = this.evaluateCell(srcHostname, desHostname, type);
- otherVal = other.evaluateCell(srcHostname, desHostname, type);
- if ( thisVal === otherVal ) { continue; }
- out.push({
- 'what': 'rule',
- 'src': srcHostname,
- 'des': desHostname,
- 'type': type
- });
- }
- }
- srcHostname = toBroaderHostname(srcHostname);
- if ( srcHostname === '' ) {
- break;
- }
- }
- return out;
- };
+Matrix.prototype.fromSelfie = function(selfie) {
+ if ( selfie.magicId !== magicId ) { return false; }
+ this.switches = new Map(selfie.switches);
+ this.rules = new Map(selfie.rules);
+ this.modifiedTime = Date.now();
+ return true;
+};
- /******************************************************************************/
+/******************************************************************************/
- Matrix.prototype.applyDiff = function(diff, from) {
- var changed = false;
- var i = diff.length;
- var action, val;
- while ( i-- ) {
- action = diff[i];
- if ( action.what === 'rule' ) {
- val = from.evaluateCell(action.src, action.des, action.type);
- changed = this.setCell(action.src, action.des, action.type, val) || changed;
- continue;
+Matrix.prototype.diff = function(other, srcHostname, desHostnames) {
+ var out = [];
+ var desHostname, type;
+ var switchName, i, thisVal, otherVal;
+ for (;;) {
+ for ( switchName of switchBitOffsets.keys() ) {
+ thisVal = this.evaluateSwitch(switchName, srcHostname);
+ otherVal = other.evaluateSwitch(switchName, srcHostname);
+ if ( thisVal !== otherVal ) {
+ out.push({
+ 'what': switchName,
+ 'src': srcHostname
+ });
}
- if ( switchBitOffsets.has(action.what) ) {
- val = from.evaluateSwitch(action.what, action.src);
- changed = this.setSwitch(action.what, action.src, val) || changed;
- continue;
+ }
+ i = desHostnames.length;
+ while ( i-- ) {
+ desHostname = desHostnames[i];
+ for ( type of typeBitOffsets.keys() ) {
+ thisVal = this.evaluateCell(srcHostname, desHostname, type);
+ otherVal = other.evaluateCell(srcHostname, desHostname, type);
+ if ( thisVal === otherVal ) { continue; }
+ out.push({
+ 'what': 'rule',
+ 'src': srcHostname,
+ 'des': desHostname,
+ 'type': type
+ });
}
}
- return changed;
- };
+ srcHostname = toBroaderHostname(srcHostname);
+ if ( srcHostname === '' ) {
+ break;
+ }
+ }
+ return out;
+};
+
+/******************************************************************************/
- /******************************************************************************/
+Matrix.prototype.applyDiff = function(diff, from) {
+ var changed = false;
+ var i = diff.length;
+ var action, val;
+ while ( i-- ) {
+ action = diff[i];
+ if ( action.what === 'rule' ) {
+ val = from.evaluateCell(action.src, action.des, action.type);
+ changed = this.setCell(action.src, action.des, action.type, val) || changed;
+ continue;
+ }
+ if ( switchBitOffsets.has(action.what) ) {
+ val = from.evaluateSwitch(action.what, action.src);
+ changed = this.setSwitch(action.what, action.src, val) || changed;
+ continue;
+ }
+ }
+ return changed;
+};
- return Matrix;
+/******************************************************************************/
+
+return Matrix;
- /******************************************************************************/
+/******************************************************************************/
- // https://www.youtube.com/watch?v=wlNrQGmj6oQ
+// https://www.youtube.com/watch?v=wlNrQGmj6oQ
})();
diff --git a/js/messaging.js b/js/messaging.js
index 6dd0979..86ac038 100644
--- a/js/messaging.js
+++ b/js/messaging.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://notabug.org/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -343,7 +343,7 @@
let sz = ηm.tMatrix.evaluateSwitchZ(request.switchName,
request.srcHostname);
ηm.tMatrix.setSwitchZ(request.switchName,
- request.scrHostname,
+ request.srcHostname,
sz === false);
return undefined;
});
@@ -676,7 +676,7 @@
addMethod('purgeCache', function (request, sender, cb) {
ηm.assets.purge(request.assetKey);
- ηm.assets.remove('compiled/' + request.assetKey);
+ ηm.assets.remove('cache/' + request.assetKey);
return undefined;
});
@@ -722,16 +722,16 @@
};
let onAllRemoved = function () {
- vAPI.storage.set(userData.settings, onCountdown);
+ vAPI.storage.set(data.settings, onCountdown);
vAPI.storage.set({
- userMatrix: userData.rules,
+ userMatrix: data.rules,
}, onCountdown);
vAPI.storage.set({
- liveHostsFiles: userData.hostsFiles,
+ liveHostsFiles: data.hostsFiles,
}, onCountdown);
- if (userData.rawSettings instanceof Object) {
- ηMatrix.saveRawSettings(userData.rawSettings, onCountdown);
+ if (data.rawSettings instanceof Object) {
+ ηMatrix.saveRawSettings(data.rawSettings, onCountdown);
}
};
@@ -740,7 +740,7 @@
ηm.XAL.keyvalRemoveAll(onAllRemoved);
};
- restoreUserData(request.userData);
+ restoreData(request.userData);
return undefined;
});
@@ -750,6 +750,8 @@
};
ηm.XAL.keyvalRemoveAll(onAllRemoved);
+ /* Let's also clear the database, just to really make it a reset */
+ ηm.assets.rmrf();
return undefined;
});
@@ -768,7 +770,7 @@
let tabIds = {};
for (let id in ηm.pageStores) {
- let store = ηm.pageStoreFromTabId(tabId);
+ let store = ηm.pageStoreFromTabId(id);
if (store === null) {
continue;
diff --git a/js/pagestats.js b/js/pagestats.js
index b4c65c1..fd1757d 100644
--- a/js/pagestats.js
+++ b/js/pagestats.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2013-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -30,58 +30,58 @@
let ηm = ηMatrix;
let BlockedCollapsibles = function () {
- this.boundPruneAsyncCallback = this.pruneAsyncCallback.bind(this);
- this.blocked = new Map();
- this.hash = 0;
- this.timer = null;
+ this.boundPruneAsyncCallback = this.pruneAsyncCallback.bind(this);
+ this.blocked = new Map();
+ this.hash = 0;
+ this.timer = null;
};
BlockedCollapsibles.prototype = {
- shelfLife: 10 * 1000,
+ shelfLife: 10 * 1000,
- add: function (type, url, isSpecific) {
+ add: function (type, url, isSpecific) {
if (this.blocked.size === 0) {
- this.pruneAsync();
- }
+ this.pruneAsync();
+ }
let now = Date.now() / 1000 | 0;
// The following "trick" is to encode the specifity into
// the lsb of the time stamp so as to avoid to have to
// allocate a memory structure to store both time stamp
// and specificity.
if (isSpecific) {
- now |= 0x00000001;
+ now |= 0x00000001;
} else {
- now &= 0xFFFFFFFE;
+ now &= 0xFFFFFFFE;
}
this.blocked.set(type + ' ' + url, now);
this.hash = now;
- },
- reset: function () {
+ },
+ reset: function () {
this.blocked.clear();
this.hash = 0;
if (this.timer !== null) {
- clearTimeout(this.timer);
- this.timer = null;
+ clearTimeout(this.timer);
+ this.timer = null;
}
- },
- pruneAsync: function () {
+ },
+ pruneAsync: function () {
if (this.timer === null) {
- this.timer = vAPI.setTimeout(this.boundPruneAsyncCallback,
- this.shelfLife * 2);
+ this.timer = vAPI.setTimeout(this.boundPruneAsyncCallback,
+ this.shelfLife * 2);
}
- },
- pruneAsyncCallback: function () {
+ },
+ pruneAsyncCallback: function () {
this.timer = null;
let obsolete = Date.now() - this.shelfLife;
for (let entry of this.blocked) {
- if (entry[1] <= obsolete) {
+ if (entry[1] <= obsolete) {
this.blocked.delete(entry[0]);
- }
+ }
}
if (this.blocked.size !== 0) {
- this.pruneAsync();
- }
- }
+ this.pruneAsync();
+ }
+ }
};
// Ref: Given a URL, returns a (somewhat) unique 32-bit value
@@ -89,19 +89,19 @@
// http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-reference-source
// The rest is custom, suited for uMatrix.
let PageStore = function (tabContext) {
- this.hostnameTypeCells = new Map();
- this.domains = new Set();
- this.blockedCollapsibles = new BlockedCollapsibles();
- this.requestStats = ηm.requestStatsFactory();
- this.off = false;
- this.init(tabContext);
+ this.hostnameTypeCells = new Map();
+ this.domains = new Set();
+ this.blockedCollapsibles = new BlockedCollapsibles();
+ this.requestStats = ηm.requestStatsFactory();
+ this.off = false;
+ this.init(tabContext);
};
PageStore.prototype = {
- collapsibleTypes: new Set([ 'image' ]),
- pageStoreJunkyard: [],
+ collapsibleTypes: new Set([ 'image' ]),
+ pageStoreJunkyard: [],
- init: function (tabContext) {
+ init: function (tabContext) {
this.tabId = tabContext.tabId;
this.rawUrl = tabContext.rawURL;
this.pageUrl = tabContext.normalURL;
@@ -124,8 +124,8 @@
this.mtxContentModifiedTime = 0;
this.mtxCountModifiedTime = 0;
return this;
- },
- dispose: function () {
+ },
+ dispose: function () {
this.rawUrl = '';
this.pageUrl = '';
this.pageHostname = '';
@@ -136,72 +136,72 @@
this.allHostnamesString = ' ';
this.blockedCollapsibles.reset();
if (this.incinerationTimer !== null) {
- clearTimeout(this.incinerationTimer);
- this.incinerationTimer = null;
+ clearTimeout(this.incinerationTimer);
+ this.incinerationTimer = null;
}
if (this.pageStoreJunkyard.length < 8) {
- this.pageStoreJunkyard.push(this);
+ this.pageStoreJunkyard.push(this);
}
- },
- cacheBlockedCollapsible: function (type, url, specificity) {
+ },
+ cacheBlockedCollapsible: function (type, url, specificity) {
if (this.collapsibleTypes.has(type)) {
- this.blockedCollapsibles.add(type,
- url,
- specificity !== 0
- && specificity < 5);
+ this.blockedCollapsibles.add(type,
+ url,
+ specificity !== 0
+ && specificity < 5);
}
- },
- lookupBlockedCollapsibles: function (request, response) {
+ },
+ lookupBlockedCollapsibles: function (request, response) {
let tabContext = ηm.tabContextManager.lookup(this.tabId);
if (tabContext === null) {
- return;
- }
+ return;
+ }
let collapseBlacklisted = ηm.userSettings.collapseBlacklisted;
- let collapseBlocked = ηm.userSettings.collapseBlocked;
+ let collapseBlocked = ηm.userSettings.collapseBlocked;
let blockedResources = response.blockedResources;
if (Array.isArray(request.toFilter) && request.toFilter.length !== 0) {
- let roothn = tabContext.rootHostname;
+ let roothn = tabContext.rootHostname;
let hnFromURI = UriTools.hostnameFromURI;
let tMatrix = ηm.tMatrix;
- for (let entry of request.toFilter) {
+ for (let entry of request.toFilter) {
if (tMatrix.mustBlock(roothn,
- hnFromURI(entry.url),
- entry.type) === false) {
- continue;
+ hnFromURI(entry.url),
+ entry.type) === false) {
+ continue;
}
blockedResources.push([
- entry.type + ' ' + entry.url,
- collapseBlocked
- || collapseBlacklisted
- && tMatrix.specificityRegister !== 0
- && tMatrix.specificityRegister < 5
+ entry.type + ' ' + entry.url,
+ collapseBlocked
+ || collapseBlacklisted
+ && tMatrix.specificityRegister !== 0
+ && tMatrix.specificityRegister < 5
]);
- }
+ }
}
if (this.blockedCollapsibles.hash === response.hash) {
- return;
- }
+ return;
+ }
response.hash = this.blockedCollapsibles.hash;
for (let entry of this.blockedCollapsibles.blocked) {
- blockedResources.push([
+ blockedResources.push([
entry[0],
collapseBlocked
- || collapseBlacklisted
- && (entry[1] & 1) !== 0
- ]);
+ || collapseBlacklisted
+ && (entry[1] & 1) !== 0
+ ]);
}
- },
- recordRequest: function (type, url, block) {
- if (block !== false) {
- this.perLoadBlockedRequestCount++;
+ },
+ recordRequest: function (type, url, block) {
+ if (block !== false) {
+ this.perLoadBlockedRequestCount++;
} else {
- this.perLoadAllowedRequestCount++;
+ this.perLoadAllowedRequestCount++;
}
// Store distinct network requests. This is used to:
@@ -209,19 +209,19 @@
// - count the number of distinct URLs for any given
// hostname-type pair
let hostname = UriTools.hostnameFromURI(url);
- let key = hostname + ' ' + type;
- let uids = this.hostnameTypeCells.get(key);
+ let key = hostname + ' ' + type;
+ let uids = this.hostnameTypeCells.get(key);
if (uids === undefined) {
- this.hostnameTypeCells.set(key, (uids = new Set()));
+ this.hostnameTypeCells.set(key, (uids = new Set()));
} else if (uids.size > 99) {
- return;
+ return;
}
let uid = this.uidFromURL(url);
if (uids.has(uid)) {
- return;
- }
+ return;
+ }
uids.add(uid);
// Count blocked/allowed requests
@@ -236,28 +236,28 @@
this.mtxCountModifiedTime = Date.now();
if (this.domains.has(hostname) === false) {
- this.domains.add(hostname);
- this.allHostnamesString += hostname + ' ';
- this.mtxContentModifiedTime = Date.now();
+ this.domains.add(hostname);
+ this.allHostnamesString += hostname + ' ';
+ this.mtxContentModifiedTime = Date.now();
}
- },
- uidFromURL: function (uri) {
+ },
+ uidFromURL: function (uri) {
var hint = 0x811c9dc5;
- let i = uri.length;
+ let i = uri.length;
while (i--) {
- hint ^= uri.charCodeAt(i) | 0;
- hint += (hint<<1) + (hint<<4) + (hint<<7) + (hint<<8) + (hint<<24) | 0;
- hint >>>= 0;
+ hint ^= uri.charCodeAt(i) | 0;
+ hint += (hint<<1) + (hint<<4) + (hint<<7) + (hint<<8) + (hint<<24) | 0;
+ hint >>>= 0;
}
return hint;
- }
+ }
};
return function (tabContext) {
- let entry = PageStore.prototype.pageStoreJunkyard.pop();
- if (entry) {
+ let entry = PageStore.prototype.pageStoreJunkyard.pop();
+ if (entry) {
return entry.init(tabContext);
- }
- return new PageStore(tabContext);
+ }
+ return new PageStore(tabContext);
};
})();
diff --git a/js/polyfill.js b/js/polyfill.js
index 27f2984..83f2fdb 100644
--- a/js/polyfill.js
+++ b/js/polyfill.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2017-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
This file has been originally imported from:
diff --git a/js/popup.js b/js/popup.js
index d750997..073f57a 100644
--- a/js/popup.js
+++ b/js/popup.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -29,67 +29,67 @@
// Stuff which is good to do very early so as to avoid visual glitches.
(function () {
- let paneContentPaddingTop =
- vAPI.localStorage.getItem('paneContentPaddingTop');
+ let paneContentPaddingTop =
+ vAPI.localStorage.getItem('paneContentPaddingTop');
let touchDevice = vAPI.localStorage.getItem('touchDevice');
- if (typeof paneContentPaddingTop === 'string') {
+ if (typeof paneContentPaddingTop === 'string') {
document
- .querySelector('.paneContent')
- .style
- .setProperty('padding-top',
- paneContentPaddingTop);
- }
-
- /* This is for CSS */
- if (touchDevice === 'true') {
+ .querySelector('.paneContent')
+ .style
+ .setProperty('padding-top',
+ paneContentPaddingTop);
+ }
+
+ /* This is for CSS */
+ if (touchDevice === 'true') {
document.body.setAttribute('data-touch', 'true');
- } else {
+ } else {
document.addEventListener('touchstart', function onTouched(ev) {
- document.removeEventListener(ev.type, onTouched);
- document.body.setAttribute('data-touch', 'true');
- vAPI.localStorage.setItem('touchDevice', 'true');
- resizePopup();
+ document.removeEventListener(ev.type, onTouched);
+ document.body.setAttribute('data-touch', 'true');
+ vAPI.localStorage.setItem('touchDevice', 'true');
+ resizePopup();
});
- }
+ }
})();
let popupWasResized = function () {
- document.body.setAttribute('data-resize-popup', '');
+ document.body.setAttribute('data-resize-popup', '');
};
let resizePopup = (function () {
- let timer;
+ let timer;
- let fix = function () {
+ let fix = function () {
timer = undefined;
let doc = document;
// Manually adjust the position of the main matrix according to the
// height of the toolbar/matrix header.
let paddingTop =
- (doc.querySelector('.paneHead').clientHeight + 2) + 'px';
+ (doc.querySelector('.paneHead').clientHeight + 2) + 'px';
let paneContent = doc.querySelector('.paneContent');
if (paddingTop !== paneContent.style.paddingTop) {
- paneContent.style.setProperty('padding-top', paddingTop);
- vAPI.localStorage.setItem('paneContentPaddingTop', paddingTop);
+ paneContent.style.setProperty('padding-top', paddingTop);
+ vAPI.localStorage.setItem('paneContentPaddingTop', paddingTop);
}
document
- .body
- .classList
- .toggle('hConstrained',
- window.innerWidth < document.body.clientWidth);
+ .body
+ .classList
+ .toggle('hConstrained',
+ window.innerWidth < document.body.clientWidth);
popupWasResized();
- };
+ };
- return function () {
+ return function () {
if (timer !== undefined) {
- clearTimeout(timer);
+ clearTimeout(timer);
}
timer = vAPI.setTimeout(fix, 97);
- };
+ };
})();
// Must be consistent with definitions in matrix.js
@@ -106,15 +106,15 @@
let matrixCellHotspots = null;
let matrixHeaderPrettyNames = {
- 'all': '',
- 'cookie': '',
- 'css': '',
- 'image': '',
- 'media': '',
- 'script': '',
- 'xhr': '',
- 'frame': '',
- 'other': ''
+ 'all': '',
+ 'cookie': '',
+ 'css': '',
+ 'image': '',
+ 'media': '',
+ 'script': '',
+ 'xhr': '',
+ 'frame': '',
+ 'other': ''
};
let firstPartyLabel = '';
@@ -122,30 +122,30 @@
let expandosIdGenerator = 1;
let nodeToExpandosMap = (function () {
- if (typeof window.Map === 'function') {
+ if (typeof window.Map === 'function') {
return new window.Map();
- }
+ }
})();
let expandosFromNode = function (node) {
- if (node instanceof HTMLElement === false
- && typeof node.nodeAt === 'function') {
+ if (node instanceof HTMLElement === false
+ && typeof node.nodeAt === 'function') {
node = node.nodeAt(0);
- }
- if (nodeToExpandosMap) {
+ }
+ if (nodeToExpandosMap) {
let expandosId = node.getAttribute('data-expandos');
if (!expandosId) {
- expandosId = '' + (expandosIdGenerator++);
- node.setAttribute('data-expandos', expandosId);
+ expandosId = '' + (expandosIdGenerator++);
+ node.setAttribute('data-expandos', expandosId);
}
let expandos = nodeToExpandosMap.get(expandosId);
if (expandos === undefined) {
- expandos = Object.create(null);
- nodeToExpandosMap.set(expandosId, expandos);
+ expandos = Object.create(null);
+ nodeToExpandosMap.set(expandosId, expandos);
}
return expandos;
- }
- return node;
+ }
+ return node;
};
function getUserSetting(setting) {
@@ -153,28 +153,28 @@
}
function setUserSetting(setting, value) {
- matrixSnapshot.userSettings[setting] = value;
- vAPI.messaging.send('popup.js', {
+ matrixSnapshot.userSettings[setting] = value;
+ vAPI.messaging.send('popup.js', {
what: 'userSettings',
name: setting,
value: value
- });
+ });
}
function getUISetting(setting) {
- let r = vAPI.localStorage.getItem(setting);
- if (typeof r !== 'string') {
+ let r = vAPI.localStorage.getItem(setting);
+ if (typeof r !== 'string') {
return undefined;
- }
- return JSON.parse(r);
+ }
+ return JSON.parse(r);
}
function setUISetting(setting, value) {
- vAPI.localStorage.setItem(setting, JSON.stringify(value));
+ vAPI.localStorage.setItem(setting, JSON.stringify(value));
}
function updateMatrixSnapshot() {
- matrixSnapshotPoller.pollNow();
+ matrixSnapshotPoller.pollNow();
}
// For display purpose, create four distinct groups of rows:
@@ -186,162 +186,162 @@
function getGroupStats() {
- // Try to not reshuffle groups around while popup is opened if
- // no new hostname added.
- let latestDomainListSnapshot =
- Object.keys(matrixSnapshot.rows).sort().join();
- if (latestDomainListSnapshot === allHostnamesSnapshot) {
+ // Try to not reshuffle groups around while popup is opened if
+ // no new hostname added.
+ let latestDomainListSnapshot =
+ Object.keys(matrixSnapshot.rows).sort().join();
+ if (latestDomainListSnapshot === allHostnamesSnapshot) {
return groupsSnapshot;
- }
- allHostnamesSnapshot = latestDomainListSnapshot;
-
- // First, group according to whether at least one node in the domain
- // hierarchy is white or blacklisted
- let pageDomain = matrixSnapshot.domain;
- let rows = matrixSnapshot.rows;
- let anyTypeOffset = matrixSnapshot.headerIndices.get('*');
- let hostname, domain;
- let row, color, count;
- let domainToGroupMap = {};
-
- // These have hard-coded position which cannot be overriden
- domainToGroupMap['1st-party'] = 0;
- domainToGroupMap[pageDomain] = 1;
-
- // 1st pass: domain wins if it has an explicit rule or a count
- for (hostname in rows) {
+ }
+ allHostnamesSnapshot = latestDomainListSnapshot;
+
+ // First, group according to whether at least one node in the domain
+ // hierarchy is white or blacklisted
+ let pageDomain = matrixSnapshot.domain;
+ let rows = matrixSnapshot.rows;
+ let anyTypeOffset = matrixSnapshot.headerIndices.get('*');
+ let hostname, domain;
+ let row, color, count;
+ let domainToGroupMap = {};
+
+ // These have hard-coded position which cannot be overriden
+ domainToGroupMap['1st-party'] = 0;
+ domainToGroupMap[pageDomain] = 1;
+
+ // 1st pass: domain wins if it has an explicit rule or a count
+ for (hostname in rows) {
if (rows.hasOwnProperty(hostname) === false) {
- continue;
+ continue;
}
if (hostname === '*' || hostname === '1st-party') {
- continue;
+ continue;
}
domain = rows[hostname].domain;
if (domain === pageDomain || hostname !== domain) {
- continue;
+ continue;
}
row = rows[domain];
color = row.temporary[anyTypeOffset];
if (color === DarkGreen) {
- domainToGroupMap[domain] = 2;
- continue;
+ domainToGroupMap[domain] = 2;
+ continue;
}
if (color === DarkRed) {
- domainToGroupMap[domain] = 4;
- continue;
+ domainToGroupMap[domain] = 4;
+ continue;
}
count = row.counts[anyTypeOffset];
if (count !== 0) {
- domainToGroupMap[domain] = 3;
- continue;
+ domainToGroupMap[domain] = 3;
+ continue;
}
- }
+ }
- // 2nd pass: green wins
- for (hostname in rows) {
+ // 2nd pass: green wins
+ for (hostname in rows) {
if (rows.hasOwnProperty(hostname) === false) {
- continue;
+ continue;
}
row = rows[hostname];
domain = row.domain;
if (domainToGroupMap.hasOwnProperty(domain)) {
- continue;
+ continue;
}
color = row.temporary[anyTypeOffset];
if (color === DarkGreen) {
- domainToGroupMap[domain] = 2;
+ domainToGroupMap[domain] = 2;
}
- }
+ }
- // 3rd pass: gray with count wins
- for (hostname in rows) {
+ // 3rd pass: gray with count wins
+ for (hostname in rows) {
if (rows.hasOwnProperty(hostname) === false) {
- continue;
+ continue;
}
row = rows[hostname];
domain = row.domain;
if (domainToGroupMap.hasOwnProperty(domain)) {
- continue;
+ continue;
}
color = row.temporary[anyTypeOffset];
count = row.counts[anyTypeOffset];
if ( color !== DarkRed && count !== 0 ) {
- domainToGroupMap[domain] = 3;
+ domainToGroupMap[domain] = 3;
}
- }
+ }
- // 4th pass: red wins whatever is left
- for (hostname in rows) {
+ // 4th pass: red wins whatever is left
+ for (hostname in rows) {
if (rows.hasOwnProperty(hostname) === false) {
- continue;
+ continue;
}
row = rows[hostname];
domain = row.domain;
if (domainToGroupMap.hasOwnProperty(domain)) {
- continue;
+ continue;
}
color = row.temporary[anyTypeOffset];
if (color === DarkRed) {
- domainToGroupMap[domain] = 4;
+ domainToGroupMap[domain] = 4;
}
- }
+ }
- // 5th pass: gray wins whatever is left
- for (hostname in rows) {
+ // 5th pass: gray wins whatever is left
+ for (hostname in rows) {
if (rows.hasOwnProperty(hostname) === false) {
- continue;
+ continue;
}
domain = rows[hostname].domain;
if (domainToGroupMap.hasOwnProperty(domain)) {
- continue;
+ continue;
}
domainToGroupMap[domain] = 3;
- }
+ }
- // Last pass: put each domain in a group
- let groups = [
- {}, {}, {}, {}, {}
- ];
+ // Last pass: put each domain in a group
+ let groups = [
+ {}, {}, {}, {}, {}
+ ];
- for (hostname in rows) {
+ for (hostname in rows) {
if (rows.hasOwnProperty(hostname) === false) {
- continue;
+ continue;
}
if ( hostname === '*' ) {
- continue;
+ continue;
}
domain = rows[hostname].domain;
let groupIndex = domainToGroupMap[domain];
let group = groups[groupIndex];
if (group.hasOwnProperty(domain) === false) {
- group[domain] = {};
+ group[domain] = {};
}
group[domain][hostname] = true;
- }
+ }
- groupsSnapshot = groups;
+ groupsSnapshot = groups;
- return groups;
+ return groups;
}
// helpers
function getTemporaryColor(hostname, type) {
- return matrixSnapshot
- .rows[hostname]
- .temporary[matrixSnapshot.headerIndices.get(type)];
+ return matrixSnapshot
+ .rows[hostname]
+ .temporary[matrixSnapshot.headerIndices.get(type)];
}
function getPermanentColor(hostname, type) {
- return matrixSnapshot
- .rows[hostname]
- .permanent[matrixSnapshot.headerIndices.get(type)];
+ return matrixSnapshot
+ .rows[hostname]
+ .permanent[matrixSnapshot.headerIndices.get(type)];
}
function addCellClass(cell, hostname, type) {
- let cl = cell.classList;
- cl.add('matCell');
- cl.add('t' + getTemporaryColor(hostname, type).toString(16));
- cl.add('p' + getPermanentColor(hostname, type).toString(16));
+ let cl = cell.classList;
+ cl.add('matCell');
+ cl.add('t' + getTemporaryColor(hostname, type).toString(16));
+ cl.add('p' + getPermanentColor(hostname, type).toString(16));
}
// This is required for when we update the matrix while it is open:
@@ -349,118 +349,118 @@
// want to lose all his hardwork.
function getCollapseState(domain) {
- let states = getUISetting('popupCollapseSpecificDomains');
- if (typeof states === 'object' && states[domain] !== undefined) {
+ let states = getUISetting('popupCollapseSpecificDomains');
+ if (typeof states === 'object' && states[domain] !== undefined) {
return states[domain];
- }
- return matrixSnapshot.collapseAllDomains === true;
+ }
+ return matrixSnapshot.collapseAllDomains === true;
}
function toggleCollapseState(elem) {
- if (elem.ancestors('#matHead.collapsible').length > 0) {
+ if (elem.ancestors('#matHead.collapsible').length > 0) {
toggleMainCollapseState(elem);
- } else {
+ } else {
toggleSpecificCollapseState(elem);
- }
- popupWasResized();
+ }
+ popupWasResized();
}
function toggleMainCollapseState(uelem) {
- let matHead =
- uelem.ancestors('#matHead.collapsible').toggleClass('collapsed');
- let collapsed =
- matrixSnapshot.collapseAllDomains = matHead.hasClass('collapsed');
-
- uDom('#matList .matSection.collapsible')
- .toggleClass('collapsed', collapsed);
- setUserSetting('popupCollapseAllDomains', collapsed);
-
- let specificCollapseStates =
- getUISetting('popupCollapseSpecificDomains') || {};
- let domains = Object.keys(specificCollapseStates);
- for (let i=domains.length-1; i>=0; --i) {
+ let matHead =
+ uelem.ancestors('#matHead.collapsible').toggleClass('collapsed');
+ let collapsed =
+ matrixSnapshot.collapseAllDomains = matHead.hasClass('collapsed');
+
+ uDom('#matList .matSection.collapsible')
+ .toggleClass('collapsed', collapsed);
+ setUserSetting('popupCollapseAllDomains', collapsed);
+
+ let specificCollapseStates =
+ getUISetting('popupCollapseSpecificDomains') || {};
+ let domains = Object.keys(specificCollapseStates);
+ for (let i=domains.length-1; i>=0; --i) {
let domain = domains[i];
if (specificCollapseStates[domain] === collapsed) {
- delete specificCollapseStates[domain];
+ delete specificCollapseStates[domain];
}
- }
- setUISetting('popupCollapseSpecificDomains', specificCollapseStates);
+ }
+ setUISetting('popupCollapseSpecificDomains', specificCollapseStates);
}
function toggleSpecificCollapseState(uelem) {
- // Remember collapse state forever, but only if it is different
- // from main collapse switch.
- let section =
- uelem.ancestors('.matSection.collapsible').toggleClass('collapsed');
+ // Remember collapse state forever, but only if it is different
+ // from main collapse switch.
+ let section =
+ uelem.ancestors('.matSection.collapsible').toggleClass('collapsed');
let domain = expandosFromNode(section).domain;
let collapsed = section.hasClass('collapsed');
let mainCollapseState = matrixSnapshot.collapseAllDomains === true;
let specificCollapseStates =
- getUISetting('popupCollapseSpecificDomains') || {};
+ getUISetting('popupCollapseSpecificDomains') || {};
- if (collapsed !== mainCollapseState) {
+ if (collapsed !== mainCollapseState) {
specificCollapseStates[domain] = collapsed;
setUISetting('popupCollapseSpecificDomains',
- specificCollapseStates);
- } else if (specificCollapseStates[domain] !== undefined) {
+ specificCollapseStates);
+ } else if (specificCollapseStates[domain] !== undefined) {
delete specificCollapseStates[domain];
setUISetting('popupCollapseSpecificDomains',
- specificCollapseStates);
- }
+ specificCollapseStates);
+ }
}
// Update count value of matrix cells(s)
function updateMatrixCounts() {
- let matCells = uDom('.matrix .matRow.rw > .matCell');
+ let matCells = uDom('.matrix .matRow.rw > .matCell');
let matRow, matCell, count, counts;
let headerIndices = matrixSnapshot.headerIndices;
let rows = matrixSnapshot.rows;
let expandos;
- for (let i=matCells.length-1; i>=0; --i) {
+ for (let i=matCells.length-1; i>=0; --i) {
matCell = matCells.nodeAt(i);
expandos = expandosFromNode(matCell);
if (expandos.hostname === '*' || expandos.reqType === '*') {
- continue;
+ continue;
}
matRow = matCell.parentNode;
counts = matRow.classList.contains('meta') ? 'totals' : 'counts';
count = rows[expandos.hostname][counts][headerIndices
- .get(expandos.reqType)];
+ .get(expandos.reqType)];
if (count === expandos.count) {
- continue;
- }
+ continue;
+ }
expandos.count = count;
matCell.textContent = cellTextFromCount(count);
- }
+ }
}
function cellTextFromCount(count) {
- if (count === 0) {
- return '\u00A0';
- }
+ if (count === 0) {
+ return '\u00A0';
+ }
- if (count < 100) {
- return count;
- }
+ if (count < 100) {
+ return count;
+ }
- return '99+';
+ return '99+';
}
// Update color of matrix cells(s)
// Color changes when rules change
function updateMatrixColors() {
- let cells = uDom('.matrix .matRow.rw > .matCell').removeClass();
+ let cells = uDom('.matrix .matRow.rw > .matCell').removeClass();
let cell, expandos;
- for (let i=cells.length-1; i>=0; --i) {
+ for (let i=cells.length-1; i>=0; --i) {
cell = cells.nodeAt(i);
expandos = expandosFromNode(cell);
addCellClass(cell, expandos.hostname, expandos.reqType);
- }
+ }
- popupWasResized();
+ popupWasResized();
}
// Update behavior of matrix:
@@ -470,78 +470,78 @@
// - It is not part of group 3 (blacklisted hostnames)
function updateMatrixBehavior() {
- matrixList = matrixList || uDom('#matList');
- let sections = matrixList.descendants('.matSection');
- let section, subdomainRows, subdomainRow;
- for (let i=sections.length-1; i>=0; --i) {
+ matrixList = matrixList || uDom('#matList');
+ let sections = matrixList.descendants('.matSection');
+ let section, subdomainRows, subdomainRow;
+ for (let i=sections.length-1; i>=0; --i) {
section = sections.at(i);
subdomainRows = section.descendants('.l2:not(.g4)');
for (let j=subdomainRows.length-1; j>=0; --j) {
- subdomainRow = subdomainRows.at(j);
- subdomainRow.toggleClass('collapsible',
- subdomainRow
- .descendants('.t81,.t82')
- .length === 0);
+ subdomainRow = subdomainRows.at(j);
+ subdomainRow.toggleClass('collapsible',
+ subdomainRow
+ .descendants('.t81,.t82')
+ .length === 0);
}
section.toggleClass('collapsible',
- subdomainRows.filter('.collapsible').length > 0);
- }
+ subdomainRows.filter('.collapsible').length > 0);
+ }
}
// handle user interaction with filters
function getCellAction(hostname, type, leaning) {
- let temporaryColor = getTemporaryColor(hostname, type);
- let hue = temporaryColor & 0x03;
+ let temporaryColor = getTemporaryColor(hostname, type);
+ let hue = temporaryColor & 0x03;
- // Special case: root toggle only between two states
- if (type === '*' && hostname === '*') {
+ // Special case: root toggle only between two states
+ if (type === '*' && hostname === '*') {
return hue === Green ?
- 'blacklistMatrixCell' :
- 'whitelistMatrixCell';
- }
+ 'blacklistMatrixCell' :
+ 'whitelistMatrixCell';
+ }
- // When explicitly blocked/allowed, can only graylist
- let saturation = temporaryColor & 0x80;
- if (saturation === Dark) {
+ // When explicitly blocked/allowed, can only graylist
+ let saturation = temporaryColor & 0x80;
+ if (saturation === Dark) {
return 'graylistMatrixCell';
- }
+ }
- return leaning === 'whitelisting' ?
- 'whitelistMatrixCell' :
- 'blacklistMatrixCell';
+ return leaning === 'whitelisting' ?
+ 'whitelistMatrixCell' :
+ 'blacklistMatrixCell';
}
function handleFilter(button, leaning) {
- // our parent cell knows who we are
- let cell = button.ancestors('div.matCell');
+ // our parent cell knows who we are
+ let cell = button.ancestors('div.matCell');
let expandos = expandosFromNode(cell);
let type = expandos.reqType;
let desHostname = expandos.hostname;
- // https://github.com/gorhill/uMatrix/issues/24
- // No hostname can happen -- like with blacklist meta row
- if (desHostname === '') {
+ // https://github.com/gorhill/uMatrix/issues/24
+ // No hostname can happen -- like with blacklist meta row
+ if (desHostname === '') {
return;
- }
+ }
- let request = {
+ let request = {
what: getCellAction(desHostname, type, leaning),
srcHostname: matrixSnapshot.scope,
desHostname: desHostname,
type: type
- };
+ };
- vAPI.messaging.send('popup.js', request, updateMatrixSnapshot);
+ vAPI.messaging.send('popup.js', request, updateMatrixSnapshot);
}
function handleWhitelistFilter(button) {
- handleFilter(button, 'whitelisting');
+ handleFilter(button, 'whitelisting');
}
function handleBlacklistFilter(button) {
- handleFilter(button, 'blacklisting');
+ handleFilter(button, 'blacklisting');
}
let matrixRowPool = [];
@@ -551,299 +551,299 @@
let matrixList = null;
let startMatrixUpdate = function () {
- matrixList = matrixList || uDom('#matList');
- matrixList.detach();
- let rows = matrixList.descendants('.matRow');
- rows.detach();
- matrixRowPool = matrixRowPool.concat(rows.toArray());
- let sections = matrixList.descendants('.matSection');
- sections.detach();
- matrixSectionPool = matrixSectionPool.concat(sections.toArray());
- let groups = matrixList.descendants('.matGroup');
- groups.detach();
- matrixGroupPool = matrixGroupPool.concat(groups.toArray());
+ matrixList = matrixList || uDom('#matList');
+ matrixList.detach();
+ let rows = matrixList.descendants('.matRow');
+ rows.detach();
+ matrixRowPool = matrixRowPool.concat(rows.toArray());
+ let sections = matrixList.descendants('.matSection');
+ sections.detach();
+ matrixSectionPool = matrixSectionPool.concat(sections.toArray());
+ let groups = matrixList.descendants('.matGroup');
+ groups.detach();
+ matrixGroupPool = matrixGroupPool.concat(groups.toArray());
};
let endMatrixUpdate = function () {
- // https://github.com/gorhill/httpswitchboard/issues/246 If
- // the matrix has no rows, we need to insert a dummy one,
- // invisible, to ensure the extension pop-up is properly
- // sized. This is needed because the header pane's `position`
- // property is `fixed`, which means it doesn't affect layout
- // size, hence the matrix header row will be truncated.
- if (matrixSnapshot.rowCount <= 1) {
+ // https://github.com/gorhill/httpswitchboard/issues/246 If
+ // the matrix has no rows, we need to insert a dummy one,
+ // invisible, to ensure the extension pop-up is properly
+ // sized. This is needed because the header pane's `position`
+ // property is `fixed`, which means it doesn't affect layout
+ // size, hence the matrix header row will be truncated.
+ if (matrixSnapshot.rowCount <= 1) {
matrixList.append(createMatrixRow().css('visibility', 'hidden'));
- }
+ }
- updateMatrixBehavior();
- matrixList.css('display', '');
- matrixList.appendTo('.paneContent');
+ updateMatrixBehavior();
+ matrixList.css('display', '');
+ matrixList.appendTo('.paneContent');
};
let createMatrixGroup = function () {
- let group = matrixGroupPool.pop();
- if (group) {
+ let group = matrixGroupPool.pop();
+ if (group) {
return uDom(group).removeClass().addClass('matGroup');
- }
- return uDom(document.createElement('div')).addClass('matGroup');
+ }
+ return uDom(document.createElement('div')).addClass('matGroup');
};
let createMatrixSection = function () {
- let section = matrixSectionPool.pop();
- if (section) {
+ let section = matrixSectionPool.pop();
+ if (section) {
return uDom(section).removeClass().addClass('matSection');
- }
- return uDom(document.createElement('div')).addClass('matSection');
+ }
+ return uDom(document.createElement('div')).addClass('matSection');
};
let createMatrixRow = function () {
- let row = matrixRowPool.pop();
- if (row) {
+ let row = matrixRowPool.pop();
+ if (row) {
row.style.visibility = '';
row = uDom(row);
row.descendants('.matCell').removeClass().addClass('matCell');
row.removeClass().addClass('matRow');
return row;
- }
+ }
- if (matrixRowTemplate === null) {
+ if (matrixRowTemplate === null) {
matrixRowTemplate = uDom('#templates .matRow');
- }
+ }
- return matrixRowTemplate.clone();
+ return matrixRowTemplate.clone();
};
function renderMatrixHeaderRow() {
- let matHead = uDom('#matHead.collapsible');
- matHead.toggleClass('collapsed',
- matrixSnapshot.collapseAllDomains === true);
-
- let cells = matHead.descendants('.matCell')
- let cell = cells.nodeAt(0);
- let expandos = expandosFromNode(cell);
- expandos.reqType = '*';
- expandos.hostname = '*';
- addCellClass(cell, '*', '*');
-
- cell = cells.nodeAt(1);
- expandos = expandosFromNode(cell);
- expandos.reqType = 'cookie';
- expandos.hostname = '*';
- addCellClass(cell, '*', 'cookie');
-
- cell = cells.nodeAt(2);
- expandos = expandosFromNode(cell);
- expandos.reqType = 'css';
- expandos.hostname = '*';
- addCellClass(cell, '*', 'css');
-
- cell = cells.nodeAt(3);
- expandos = expandosFromNode(cell);
- expandos.reqType = 'image';
- expandos.hostname = '*';
- addCellClass(cell, '*', 'image');
-
- cell = cells.nodeAt(4);
- expandos = expandosFromNode(cell);
- expandos.reqType = 'media';
- expandos.hostname = '*';
- addCellClass(cell, '*', 'media');
-
- cell = cells.nodeAt(5);
- expandos = expandosFromNode(cell);
- expandos.reqType = 'script';
- expandos.hostname = '*';
- addCellClass(cell, '*', 'script');
-
- cell = cells.nodeAt(6);
- expandos = expandosFromNode(cell);
- expandos.reqType = 'xhr';
- expandos.hostname = '*';
- addCellClass(cell, '*', 'xhr');
-
- cell = cells.nodeAt(7);
- expandos = expandosFromNode(cell);
- expandos.reqType = 'frame';
- expandos.hostname = '*';
- addCellClass(cell, '*', 'frame');
-
- cell = cells.nodeAt(8);
- expandos = expandosFromNode(cell);
- expandos.reqType = 'other';
- expandos.hostname = '*';
- addCellClass(cell, '*', 'other');
-
- uDom('#matHead .matRow').css('display', '');
+ let matHead = uDom('#matHead.collapsible');
+ matHead.toggleClass('collapsed',
+ matrixSnapshot.collapseAllDomains === true);
+
+ let cells = matHead.descendants('.matCell')
+ let cell = cells.nodeAt(0);
+ let expandos = expandosFromNode(cell);
+ expandos.reqType = '*';
+ expandos.hostname = '*';
+ addCellClass(cell, '*', '*');
+
+ cell = cells.nodeAt(1);
+ expandos = expandosFromNode(cell);
+ expandos.reqType = 'cookie';
+ expandos.hostname = '*';
+ addCellClass(cell, '*', 'cookie');
+
+ cell = cells.nodeAt(2);
+ expandos = expandosFromNode(cell);
+ expandos.reqType = 'css';
+ expandos.hostname = '*';
+ addCellClass(cell, '*', 'css');
+
+ cell = cells.nodeAt(3);
+ expandos = expandosFromNode(cell);
+ expandos.reqType = 'image';
+ expandos.hostname = '*';
+ addCellClass(cell, '*', 'image');
+
+ cell = cells.nodeAt(4);
+ expandos = expandosFromNode(cell);
+ expandos.reqType = 'media';
+ expandos.hostname = '*';
+ addCellClass(cell, '*', 'media');
+
+ cell = cells.nodeAt(5);
+ expandos = expandosFromNode(cell);
+ expandos.reqType = 'script';
+ expandos.hostname = '*';
+ addCellClass(cell, '*', 'script');
+
+ cell = cells.nodeAt(6);
+ expandos = expandosFromNode(cell);
+ expandos.reqType = 'xhr';
+ expandos.hostname = '*';
+ addCellClass(cell, '*', 'xhr');
+
+ cell = cells.nodeAt(7);
+ expandos = expandosFromNode(cell);
+ expandos.reqType = 'frame';
+ expandos.hostname = '*';
+ addCellClass(cell, '*', 'frame');
+
+ cell = cells.nodeAt(8);
+ expandos = expandosFromNode(cell);
+ expandos.reqType = 'other';
+ expandos.hostname = '*';
+ addCellClass(cell, '*', 'other');
+
+ uDom('#matHead .matRow').css('display', '');
}
function renderMatrixCellDomain(cell, domain) {
- let expandos = expandosFromNode(cell);
- expandos.hostname = domain;
- expandos.reqType = '*';
- addCellClass(cell.nodeAt(0), domain, '*');
+ let expandos = expandosFromNode(cell);
+ expandos.hostname = domain;
+ expandos.reqType = '*';
+ addCellClass(cell.nodeAt(0), domain, '*');
- let contents = cell.contents();
- contents.nodeAt(0).textContent = domain === '1st-party' ?
+ let contents = cell.contents();
+ contents.nodeAt(0).textContent = domain === '1st-party' ?
firstPartyLabel :
Punycode.toUnicode(domain);
- contents.nodeAt(1).textContent = ' ';
+ contents.nodeAt(1).textContent = ' ';
}
function renderMatrixCellSubdomain(cell, domain, subomain) {
- let expandos = expandosFromNode(cell);
- expandos.hostname = subomain;
- expandos.reqType = '*';
- addCellClass(cell.nodeAt(0), subomain, '*');
+ let expandos = expandosFromNode(cell);
+ expandos.hostname = subomain;
+ expandos.reqType = '*';
+ addCellClass(cell.nodeAt(0), subomain, '*');
- let contents = cell.contents();
- contents.nodeAt(0).textContent =
- Punycode.toUnicode(subomain.slice(0,
- subomain.lastIndexOf(domain)-1))
- + '.';
- contents.nodeAt(1).textContent = Punycode.toUnicode(domain);
+ let contents = cell.contents();
+ contents.nodeAt(0).textContent =
+ Punycode.toUnicode(subomain.slice(0,
+ subomain.lastIndexOf(domain)-1))
+ + '.';
+ contents.nodeAt(1).textContent = Punycode.toUnicode(domain);
}
function renderMatrixMetaCellDomain(cell, domain) {
- let expandos = expandosFromNode(cell);
- expandos.hostname = domain;
- expandos.reqType = '*';
- addCellClass(cell.nodeAt(0), domain, '*');
+ let expandos = expandosFromNode(cell);
+ expandos.hostname = domain;
+ expandos.reqType = '*';
+ addCellClass(cell.nodeAt(0), domain, '*');
- let contents = cell.contents();
- contents.nodeAt(0).textContent = '\u2217.' + Punycode.toUnicode(domain);
- contents.nodeAt(1).textContent = ' ';
+ let contents = cell.contents();
+ contents.nodeAt(0).textContent = '\u2217.' + Punycode.toUnicode(domain);
+ contents.nodeAt(1).textContent = ' ';
}
function renderMatrixCellType(cell, hostname, type, count) {
- let node = cell.nodeAt(0);
+ let node = cell.nodeAt(0);
let expandos = expandosFromNode(node);
- expandos.hostname = hostname;
- expandos.reqType = type;
- expandos.count = count;
- addCellClass(node, hostname, type);
- node.textContent = cellTextFromCount(count);
+ expandos.hostname = hostname;
+ expandos.reqType = type;
+ expandos.count = count;
+ addCellClass(node, hostname, type);
+ node.textContent = cellTextFromCount(count);
}
function renderMatrixCellTypes(cells, hostname, countName) {
- let counts = matrixSnapshot.rows[hostname][countName];
- let headerIndices = matrixSnapshot.headerIndices;
- renderMatrixCellType(cells.at(1), hostname, 'cookie',
- counts[headerIndices.get('cookie')]);
- renderMatrixCellType(cells.at(2), hostname, 'css',
- counts[headerIndices.get('css')]);
- renderMatrixCellType(cells.at(3), hostname, 'image',
- counts[headerIndices.get('image')]);
- renderMatrixCellType(cells.at(4), hostname, 'media',
- counts[headerIndices.get('media')]);
- renderMatrixCellType(cells.at(5), hostname, 'script',
- counts[headerIndices.get('script')]);
- renderMatrixCellType(cells.at(6), hostname, 'xhr',
- counts[headerIndices.get('xhr')]);
- renderMatrixCellType(cells.at(7), hostname, 'frame',
- counts[headerIndices.get('frame')]);
- renderMatrixCellType(cells.at(8), hostname, 'other',
- counts[headerIndices.get('other')]);
+ let counts = matrixSnapshot.rows[hostname][countName];
+ let headerIndices = matrixSnapshot.headerIndices;
+ renderMatrixCellType(cells.at(1), hostname, 'cookie',
+ counts[headerIndices.get('cookie')]);
+ renderMatrixCellType(cells.at(2), hostname, 'css',
+ counts[headerIndices.get('css')]);
+ renderMatrixCellType(cells.at(3), hostname, 'image',
+ counts[headerIndices.get('image')]);
+ renderMatrixCellType(cells.at(4), hostname, 'media',
+ counts[headerIndices.get('media')]);
+ renderMatrixCellType(cells.at(5), hostname, 'script',
+ counts[headerIndices.get('script')]);
+ renderMatrixCellType(cells.at(6), hostname, 'xhr',
+ counts[headerIndices.get('xhr')]);
+ renderMatrixCellType(cells.at(7), hostname, 'frame',
+ counts[headerIndices.get('frame')]);
+ renderMatrixCellType(cells.at(8), hostname, 'other',
+ counts[headerIndices.get('other')]);
}
function makeMatrixRowDomain(domain) {
- let matrixRow = createMatrixRow().addClass('rw');
- let cells = matrixRow.descendants('.matCell');
- renderMatrixCellDomain(cells.at(0), domain);
- renderMatrixCellTypes(cells, domain, 'counts');
- return matrixRow;
+ let matrixRow = createMatrixRow().addClass('rw');
+ let cells = matrixRow.descendants('.matCell');
+ renderMatrixCellDomain(cells.at(0), domain);
+ renderMatrixCellTypes(cells, domain, 'counts');
+ return matrixRow;
}
function makeMatrixRowSubdomain(domain, subdomain) {
- let matrixRow = createMatrixRow().addClass('rw');
- let cells = matrixRow.descendants('.matCell');
- renderMatrixCellSubdomain(cells.at(0), domain, subdomain);
- renderMatrixCellTypes(cells, subdomain, 'counts');
- return matrixRow;
+ let matrixRow = createMatrixRow().addClass('rw');
+ let cells = matrixRow.descendants('.matCell');
+ renderMatrixCellSubdomain(cells.at(0), domain, subdomain);
+ renderMatrixCellTypes(cells, subdomain, 'counts');
+ return matrixRow;
}
function makeMatrixMetaRowDomain(domain) {
- let matrixRow = createMatrixRow().addClass('rw');
- let cells = matrixRow.descendants('.matCell');
- renderMatrixMetaCellDomain(cells.at(0), domain);
- renderMatrixCellTypes(cells, domain, 'totals');
- return matrixRow;
+ let matrixRow = createMatrixRow().addClass('rw');
+ let cells = matrixRow.descendants('.matCell');
+ renderMatrixMetaCellDomain(cells.at(0), domain);
+ renderMatrixCellTypes(cells, domain, 'totals');
+ return matrixRow;
}
function renderMatrixMetaCellType(cell, count) {
- // https://github.com/gorhill/uMatrix/issues/24
- // Don't forget to reset cell properties
- let node = cell.nodeAt(0);
+ // https://github.com/gorhill/uMatrix/issues/24
+ // Don't forget to reset cell properties
+ let node = cell.nodeAt(0);
let expandos = expandosFromNode(node);
- expandos.hostname = '';
- expandos.reqType = '';
- expandos.count = count;
- cell.addClass('t1');
- node.textContent = cellTextFromCount(count);
+ expandos.hostname = '';
+ expandos.reqType = '';
+ expandos.count = count;
+ cell.addClass('t1');
+ node.textContent = cellTextFromCount(count);
}
function makeMatrixMetaRow(totals) {
- let headerIndices = matrixSnapshot.headerIndices;
+ let headerIndices = matrixSnapshot.headerIndices;
let matrixRow = createMatrixRow().at(0).addClass('ro');
let cells = matrixRow.descendants('.matCell');
let contents = cells.at(0).addClass('t81').contents();
let expandos = expandosFromNode(cells.nodeAt(0));
- expandos.hostname = '';
- expandos.reqType = '*';
- contents.nodeAt(0).textContent = ' ';
- contents.nodeAt(1).textContent =
- blacklistedHostnamesLabel
- .replace('{{count}}',
- totals[headerIndices.get('*')].toLocaleString());
-
- renderMatrixMetaCellType(cells.at(1),
- totals[headerIndices.get('cookie')]);
- renderMatrixMetaCellType(cells.at(2),
- totals[headerIndices.get('css')]);
- renderMatrixMetaCellType(cells.at(3),
- totals[headerIndices.get('image')]);
- renderMatrixMetaCellType(cells.at(4),
- totals[headerIndices.get('media')]);
- renderMatrixMetaCellType(cells.at(5),
- totals[headerIndices.get('script')]);
- renderMatrixMetaCellType(cells.at(6),
- totals[headerIndices.get('xhr')]);
- renderMatrixMetaCellType(cells.at(7),
- totals[headerIndices.get('frame')]);
- renderMatrixMetaCellType(cells.at(8),
- totals[headerIndices.get('other')]);
- return matrixRow;
+ expandos.hostname = '';
+ expandos.reqType = '*';
+ contents.nodeAt(0).textContent = ' ';
+ contents.nodeAt(1).textContent =
+ blacklistedHostnamesLabel
+ .replace('{{count}}',
+ totals[headerIndices.get('*')].toLocaleString());
+
+ renderMatrixMetaCellType(cells.at(1),
+ totals[headerIndices.get('cookie')]);
+ renderMatrixMetaCellType(cells.at(2),
+ totals[headerIndices.get('css')]);
+ renderMatrixMetaCellType(cells.at(3),
+ totals[headerIndices.get('image')]);
+ renderMatrixMetaCellType(cells.at(4),
+ totals[headerIndices.get('media')]);
+ renderMatrixMetaCellType(cells.at(5),
+ totals[headerIndices.get('script')]);
+ renderMatrixMetaCellType(cells.at(6),
+ totals[headerIndices.get('xhr')]);
+ renderMatrixMetaCellType(cells.at(7),
+ totals[headerIndices.get('frame')]);
+ renderMatrixMetaCellType(cells.at(8),
+ totals[headerIndices.get('other')]);
+ return matrixRow;
}
function computeMatrixGroupMetaStats(group) {
- let headerIndices = matrixSnapshot.headerIndices;
+ let headerIndices = matrixSnapshot.headerIndices;
let anyTypeIndex = headerIndices.get('*');
let totals = new Array(headerIndices.size);
for (let i=headerIndices.size-1; i>=0; --i) {
totals[i] = 0;
- }
+ }
- let rows = matrixSnapshot.rows;
- let row;
- for (let hostname in rows) {
+ let rows = matrixSnapshot.rows;
+ let row;
+ for (let hostname in rows) {
if (rows.hasOwnProperty(hostname) === false) {
- continue;
+ continue;
}
row = rows[hostname];
if (group.hasOwnProperty(row.domain) === false) {
- continue;
+ continue;
}
if (row.counts[anyTypeIndex] === 0) {
- continue;
+ continue;
}
totals[0] += 1;
for (let i=1; i<headerIndices.size; ++i) {
- totals[i] += row.counts[i];
+ totals[i] += row.counts[i];
}
- }
+ }
- return totals;
+ return totals;
}
// Compare hostname helper, to order hostname in a logical manner:
@@ -851,667 +851,667 @@
// named hostname
function hostnameCompare(a, b) {
- // Normalize: most significant parts first
- if (!a.match(/^\d+(\.\d+){1,3}$/)) {
+ // Normalize: most significant parts first
+ if (!a.match(/^\d+(\.\d+){1,3}$/)) {
let aa = a.split('.');
a = aa.slice(-2).concat(aa.slice(0,-2).reverse()).join('.');
- }
+ }
- if (!b.match(/^\d+(\.\d+){1,3}$/)) {
+ if (!b.match(/^\d+(\.\d+){1,3}$/)) {
let bb = b.split('.');
b = bb.slice(-2).concat(bb.slice(0,-2).reverse()).join('.');
- }
+ }
- return a.localeCompare(b);
+ return a.localeCompare(b);
}
function makeMatrixGroup0SectionDomain() {
- return makeMatrixRowDomain('1st-party').addClass('g0 l1');
+ return makeMatrixRowDomain('1st-party').addClass('g0 l1');
}
function makeMatrixGroup0Section() {
- let domainDiv = createMatrixSection();
- expandosFromNode(domainDiv).domain = '1st-party';
- makeMatrixGroup0SectionDomain().appendTo(domainDiv);
- return domainDiv;
+ let domainDiv = createMatrixSection();
+ expandosFromNode(domainDiv).domain = '1st-party';
+ makeMatrixGroup0SectionDomain().appendTo(domainDiv);
+ return domainDiv;
}
function makeMatrixGroup0() {
- // Show literal "1st-party" row only if there is
- // at least one 1st-party hostname
- if (Object.keys(groupsSnapshot[1]).length === 0) {
+ // Show literal "1st-party" row only if there is
+ // at least one 1st-party hostname
+ if (Object.keys(groupsSnapshot[1]).length === 0) {
return;
- }
- let groupDiv = createMatrixGroup().addClass('g0');
- makeMatrixGroup0Section().appendTo(groupDiv);
- groupDiv.appendTo(matrixList);
+ }
+ let groupDiv = createMatrixGroup().addClass('g0');
+ makeMatrixGroup0Section().appendTo(groupDiv);
+ groupDiv.appendTo(matrixList);
}
function makeMatrixGroup1SectionDomain(domain) {
- return makeMatrixRowDomain(domain).addClass('g1 l1');
+ return makeMatrixRowDomain(domain).addClass('g1 l1');
}
function makeMatrixGroup1SectionSubomain(domain, subdomain) {
- return makeMatrixRowSubdomain(domain, subdomain).addClass('g1 l2');
+ return makeMatrixRowSubdomain(domain, subdomain).addClass('g1 l2');
}
function makeMatrixGroup1SectionMetaDomain(domain) {
- return makeMatrixMetaRowDomain(domain).addClass('g1 l1 meta');
+ return makeMatrixMetaRowDomain(domain).addClass('g1 l1 meta');
}
function makeMatrixGroup1Section(hostnames) {
- let domain = hostnames[0];
- let domainDiv =
- createMatrixSection().toggleClass('collapsed',
- getCollapseState(domain));
- expandosFromNode(domainDiv).domain = domain;
- if (hostnames.length > 1) {
+ let domain = hostnames[0];
+ let domainDiv =
+ createMatrixSection().toggleClass('collapsed',
+ getCollapseState(domain));
+ expandosFromNode(domainDiv).domain = domain;
+ if (hostnames.length > 1) {
makeMatrixGroup1SectionMetaDomain(domain).appendTo(domainDiv);
- }
- makeMatrixGroup1SectionDomain(domain).appendTo(domainDiv);
- for (let i=1; i<hostnames.length; ++i) {
+ }
+ makeMatrixGroup1SectionDomain(domain).appendTo(domainDiv);
+ for (let i=1; i<hostnames.length; ++i) {
makeMatrixGroup1SectionSubomain(domain, hostnames[i])
- .appendTo(domainDiv);
- }
- return domainDiv;
+ .appendTo(domainDiv);
+ }
+ return domainDiv;
}
function makeMatrixGroup1(group) {
- let domains = Object.keys(group).sort(hostnameCompare);
- if (domains.length) {
+ let domains = Object.keys(group).sort(hostnameCompare);
+ if (domains.length) {
let groupDiv = createMatrixGroup().addClass('g1');
makeMatrixGroup1Section(Object.keys(group[domains[0]])
- .sort(hostnameCompare))
- .appendTo(groupDiv);
+ .sort(hostnameCompare))
+ .appendTo(groupDiv);
for (let i=1; i<domains.length; ++i) {
- makeMatrixGroup1Section(Object.keys(group[domains[i]])
- .sort(hostnameCompare))
+ makeMatrixGroup1Section(Object.keys(group[domains[i]])
+ .sort(hostnameCompare))
.appendTo(groupDiv);
}
groupDiv.appendTo(matrixList);
- }
+ }
}
function makeMatrixGroup2SectionDomain(domain) {
- return makeMatrixRowDomain(domain).addClass('g2 l1');
+ return makeMatrixRowDomain(domain).addClass('g2 l1');
}
function makeMatrixGroup2SectionSubomain(domain, subdomain) {
- return makeMatrixRowSubdomain(domain, subdomain).addClass('g2 l2');
+ return makeMatrixRowSubdomain(domain, subdomain).addClass('g2 l2');
}
function makeMatrixGroup2SectionMetaDomain(domain) {
- return makeMatrixMetaRowDomain(domain).addClass('g2 l1 meta');
+ return makeMatrixMetaRowDomain(domain).addClass('g2 l1 meta');
}
function makeMatrixGroup2Section(hostnames) {
- let domain = hostnames[0];
- let domainDiv =
- createMatrixSection().toggleClass('collapsed',
- getCollapseState(domain));
- expandosFromNode(domainDiv).domain = domain;
- if (hostnames.length > 1) {
+ let domain = hostnames[0];
+ let domainDiv =
+ createMatrixSection().toggleClass('collapsed',
+ getCollapseState(domain));
+ expandosFromNode(domainDiv).domain = domain;
+ if (hostnames.length > 1) {
makeMatrixGroup2SectionMetaDomain(domain).appendTo(domainDiv);
- }
- makeMatrixGroup2SectionDomain(domain).appendTo(domainDiv);
- for (let i=1; i<hostnames.length; ++i) {
+ }
+ makeMatrixGroup2SectionDomain(domain).appendTo(domainDiv);
+ for (let i=1; i<hostnames.length; ++i) {
makeMatrixGroup2SectionSubomain(domain, hostnames[i])
- .appendTo(domainDiv);
- }
- return domainDiv;
+ .appendTo(domainDiv);
+ }
+ return domainDiv;
}
function makeMatrixGroup2(group) {
- let domains = Object.keys(group).sort(hostnameCompare);
- if (domains.length) {
+ let domains = Object.keys(group).sort(hostnameCompare);
+ if (domains.length) {
let groupDiv = createMatrixGroup().addClass('g2');
makeMatrixGroup2Section(Object.keys(group[domains[0]])
- .sort(hostnameCompare))
- .appendTo(groupDiv);
+ .sort(hostnameCompare))
+ .appendTo(groupDiv);
for (let i=1; i<domains.length; ++i) {
- makeMatrixGroup2Section(Object.keys(group[domains[i]])
- .sort(hostnameCompare))
+ makeMatrixGroup2Section(Object.keys(group[domains[i]])
+ .sort(hostnameCompare))
.appendTo(groupDiv);
}
groupDiv.appendTo(matrixList);
- }
+ }
}
function makeMatrixGroup3SectionDomain(domain) {
- return makeMatrixRowDomain(domain).addClass('g3 l1');
+ return makeMatrixRowDomain(domain).addClass('g3 l1');
}
function makeMatrixGroup3SectionSubomain(domain, subdomain) {
- return makeMatrixRowSubdomain(domain, subdomain).addClass('g3 l2');
+ return makeMatrixRowSubdomain(domain, subdomain).addClass('g3 l2');
}
function makeMatrixGroup3SectionMetaDomain(domain) {
- return makeMatrixMetaRowDomain(domain).addClass('g3 l1 meta');
+ return makeMatrixMetaRowDomain(domain).addClass('g3 l1 meta');
}
function makeMatrixGroup3Section(hostnames) {
- let domain = hostnames[0];
- let domainDiv = createMatrixSection().toggleClass('collapsed',
- getCollapseState(domain));
- expandosFromNode(domainDiv).domain = domain;
- if (hostnames.length > 1) {
+ let domain = hostnames[0];
+ let domainDiv = createMatrixSection().toggleClass('collapsed',
+ getCollapseState(domain));
+ expandosFromNode(domainDiv).domain = domain;
+ if (hostnames.length > 1) {
makeMatrixGroup3SectionMetaDomain(domain).appendTo(domainDiv);
- }
- makeMatrixGroup3SectionDomain(domain).appendTo(domainDiv);
- for (let i=1; i<hostnames.length; ++i) {
+ }
+ makeMatrixGroup3SectionDomain(domain).appendTo(domainDiv);
+ for (let i=1; i<hostnames.length; ++i) {
makeMatrixGroup3SectionSubomain(domain, hostnames[i])
- .appendTo(domainDiv);
- }
- return domainDiv;
+ .appendTo(domainDiv);
+ }
+ return domainDiv;
}
function makeMatrixGroup3(group) {
- let domains = Object.keys(group).sort(hostnameCompare);
- if (domains.length) {
+ let domains = Object.keys(group).sort(hostnameCompare);
+ if (domains.length) {
let groupDiv = createMatrixGroup().addClass('g3');
makeMatrixGroup3Section(Object.keys(group[domains[0]])
- .sort(hostnameCompare))
- .appendTo(groupDiv);
+ .sort(hostnameCompare))
+ .appendTo(groupDiv);
for (let i=1; i<domains.length; ++i) {
- makeMatrixGroup3Section(Object.keys(group[domains[i]])
- .sort(hostnameCompare))
+ makeMatrixGroup3Section(Object.keys(group[domains[i]])
+ .sort(hostnameCompare))
.appendTo(groupDiv);
}
groupDiv.appendTo(matrixList);
- }
+ }
}
function makeMatrixGroup4SectionDomain(domain) {
- return makeMatrixRowDomain(domain).addClass('g4 l1');
+ return makeMatrixRowDomain(domain).addClass('g4 l1');
}
function makeMatrixGroup4SectionSubomain(domain, subdomain) {
- return makeMatrixRowSubdomain(domain, subdomain).addClass('g4 l2');
+ return makeMatrixRowSubdomain(domain, subdomain).addClass('g4 l2');
}
function makeMatrixGroup4Section(hostnames) {
- let domain = hostnames[0];
- let domainDiv = createMatrixSection();
- expandosFromNode(domainDiv).domain = domain;
- makeMatrixGroup4SectionDomain(domain).appendTo(domainDiv);
- for (let i=1; i<hostnames.length; ++i) {
+ let domain = hostnames[0];
+ let domainDiv = createMatrixSection();
+ expandosFromNode(domainDiv).domain = domain;
+ makeMatrixGroup4SectionDomain(domain).appendTo(domainDiv);
+ for (let i=1; i<hostnames.length; ++i) {
makeMatrixGroup4SectionSubomain(domain, hostnames[i])
- .appendTo(domainDiv);
- }
- return domainDiv;
+ .appendTo(domainDiv);
+ }
+ return domainDiv;
}
function makeMatrixGroup4(group) {
- let domains = Object.keys(group).sort(hostnameCompare);
- if (domains.length === 0) {
+ let domains = Object.keys(group).sort(hostnameCompare);
+ if (domains.length === 0) {
return;
- }
- let groupDiv = createMatrixGroup().addClass('g4');
- createMatrixSection()
+ }
+ let groupDiv = createMatrixGroup().addClass('g4');
+ createMatrixSection()
.addClass('g4Meta')
.toggleClass('g4Collapsed',
- !!matrixSnapshot.collapseBlacklistedDomains)
+ !!matrixSnapshot.collapseBlacklistedDomains)
.appendTo(groupDiv);
- makeMatrixMetaRow(computeMatrixGroupMetaStats(group), 'g4')
+ makeMatrixMetaRow(computeMatrixGroupMetaStats(group), 'g4')
.appendTo(groupDiv);
- makeMatrixGroup4Section(Object.keys(group[domains[0]])
- .sort(hostnameCompare))
+ makeMatrixGroup4Section(Object.keys(group[domains[0]])
+ .sort(hostnameCompare))
.appendTo(groupDiv);
- for (let i=1; i<domains.length; ++i) {
+ for (let i=1; i<domains.length; ++i) {
makeMatrixGroup4Section(Object.keys(group[domains[i]])
- .sort(hostnameCompare))
- .appendTo(groupDiv);
- }
- groupDiv.appendTo(matrixList);
+ .sort(hostnameCompare))
+ .appendTo(groupDiv);
+ }
+ groupDiv.appendTo(matrixList);
}
let makeMenu = function () {
- let groupStats = getGroupStats();
+ let groupStats = getGroupStats();
- if (Object.keys(groupStats).length === 0) {
- return;
- }
+ if (Object.keys(groupStats).length === 0) {
+ return;
+ }
- // https://github.com/gorhill/httpswitchboard/issues/31
- if (matrixCellHotspots) {
+ // https://github.com/gorhill/httpswitchboard/issues/31
+ if (matrixCellHotspots) {
matrixCellHotspots.detach();
- }
+ }
- renderMatrixHeaderRow();
+ renderMatrixHeaderRow();
- startMatrixUpdate();
- makeMatrixGroup0(groupStats[0]);
- makeMatrixGroup1(groupStats[1]);
- makeMatrixGroup2(groupStats[2]);
- makeMatrixGroup3(groupStats[3]);
- makeMatrixGroup4(groupStats[4]);
- endMatrixUpdate();
+ startMatrixUpdate();
+ makeMatrixGroup0(groupStats[0]);
+ makeMatrixGroup1(groupStats[1]);
+ makeMatrixGroup2(groupStats[2]);
+ makeMatrixGroup3(groupStats[3]);
+ makeMatrixGroup4(groupStats[4]);
+ endMatrixUpdate();
- initScopeCell();
- updateMatrixButtons();
- resizePopup();
+ initScopeCell();
+ updateMatrixButtons();
+ resizePopup();
};
// Do all the stuff that needs to be done before building menu et al.
function initMenuEnvironment() {
- document.body.style.setProperty('font-size',
- getUserSetting('displayTextSize'));
- document.body.classList.toggle('colorblind',
- getUserSetting('colorBlindFriendly'));
- uDom.nodeFromId('version').textContent =
- matrixSnapshot.appVersion || '';
-
- let prettyNames = matrixHeaderPrettyNames;
- let keys = Object.keys(prettyNames);
- for (let i=keys.length-1; i>=0; --i) {
+ document.body.style.setProperty('font-size',
+ getUserSetting('displayTextSize'));
+ document.body.classList.toggle('colorblind',
+ getUserSetting('colorBlindFriendly'));
+ uDom.nodeFromId('version').textContent =
+ matrixSnapshot.appVersion || '';
+
+ let prettyNames = matrixHeaderPrettyNames;
+ let keys = Object.keys(prettyNames);
+ for (let i=keys.length-1; i>=0; --i) {
let key = keys[i];
let cell = uDom('#matHead .matCell[data-req-type="'+ key +'"]');
let text = vAPI.i18n(key + 'PrettyName');
cell.text(text);
prettyNames[key] = text;
- }
+ }
- firstPartyLabel = uDom('[data-i18n="matrix1stPartyLabel"]').text();
- blacklistedHostnamesLabel =
- uDom('[data-i18n="matrixBlacklistedHostnames"]').text();
+ firstPartyLabel = uDom('[data-i18n="matrix1stPartyLabel"]').text();
+ blacklistedHostnamesLabel =
+ uDom('[data-i18n="matrixBlacklistedHostnames"]').text();
}
// Create page scopes for the web page
function selectGlobalScope() {
- if (matrixSnapshot.scope === '*') {
- return;
- }
- matrixSnapshot.scope = '*';
- document.body.classList.add('globalScope');
- matrixSnapshot.tMatrixModifiedTime = undefined;
- updateMatrixSnapshot();
- dropDownMenuHide();
+ if (matrixSnapshot.scope === '*') {
+ return;
+ }
+ matrixSnapshot.scope = '*';
+ document.body.classList.add('globalScope');
+ matrixSnapshot.tMatrixModifiedTime = undefined;
+ updateMatrixSnapshot();
+ dropDownMenuHide();
}
function selectSpecificScope(ev) {
- let newScope = ev.target.getAttribute('data-scope');
- if (!newScope || matrixSnapshot.scope === newScope) {
- return;
- }
- document.body.classList.remove('globalScope');
- matrixSnapshot.scope = newScope;
- matrixSnapshot.tMatrixModifiedTime = undefined;
- updateMatrixSnapshot();
- dropDownMenuHide();
+ let newScope = ev.target.getAttribute('data-scope');
+ if (!newScope || matrixSnapshot.scope === newScope) {
+ return;
+ }
+ document.body.classList.remove('globalScope');
+ matrixSnapshot.scope = newScope;
+ matrixSnapshot.tMatrixModifiedTime = undefined;
+ updateMatrixSnapshot();
+ dropDownMenuHide();
}
function initScopeCell() {
- // It's possible there is no page URL at this point: some pages cannot
- // be filtered by ηMatrix.
- if (matrixSnapshot.url === '') {
- return;
- }
- let specificScope = uDom.nodeFromId('specificScope');
-
- while (specificScope.firstChild !== null) {
+ // It's possible there is no page URL at this point: some pages cannot
+ // be filtered by ηMatrix.
+ if (matrixSnapshot.url === '') {
+ return;
+ }
+ let specificScope = uDom.nodeFromId('specificScope');
+
+ while (specificScope.firstChild !== null) {
specificScope.removeChild(specificScope.firstChild);
- }
+ }
- // Fill in the scope menu entries
- let pos = matrixSnapshot.domain.indexOf('.');
- let tld, labels;
- if (pos === -1) {
+ // Fill in the scope menu entries
+ let pos = matrixSnapshot.domain.indexOf('.');
+ let tld, labels;
+ if (pos === -1) {
tld = '';
labels = matrixSnapshot.hostname;
- } else {
+ } else {
tld = matrixSnapshot.domain.slice(pos + 1);
labels = matrixSnapshot.hostname.slice(0, -tld.length);
- }
- let beg = 0;
- let span, label;
- while (beg < labels.length) {
+ }
+ let beg = 0;
+ let span, label;
+ while (beg < labels.length) {
pos = labels.indexOf('.', beg);
if (pos === -1) {
- pos = labels.length;
+ pos = labels.length;
} else {
- pos += 1;
+ pos += 1;
}
label = document.createElement('span');
label.appendChild(document
- .createTextNode(Punycode
- .toUnicode(labels.slice(beg,
- pos))));
+ .createTextNode(Punycode
+ .toUnicode(labels.slice(beg,
+ pos))));
span = document.createElement('span');
span.setAttribute('data-scope', labels.slice(beg) + tld);
span.appendChild(label);
specificScope.appendChild(span);
beg = pos;
- }
- if (tld !== '') {
+ }
+ if (tld !== '') {
label = document.createElement('span');
label.appendChild(document.createTextNode(Punycode.toUnicode(tld)));
span = document.createElement('span');
span.setAttribute('data-scope', tld);
span.appendChild(label);
specificScope.appendChild(span);
- }
- updateScopeCell();
+ }
+ updateScopeCell();
}
function updateScopeCell() {
- let specificScope = uDom.nodeFromId('specificScope');
+ let specificScope = uDom.nodeFromId('specificScope');
let isGlobal = matrixSnapshot.scope === '*';
- document.body.classList.toggle('globalScope', isGlobal);
- specificScope.classList.toggle('on', !isGlobal);
- uDom.nodeFromId('globalScope').classList.toggle('on', isGlobal);
+ document.body.classList.toggle('globalScope', isGlobal);
+ specificScope.classList.toggle('on', !isGlobal);
+ uDom.nodeFromId('globalScope').classList.toggle('on', isGlobal);
- for (let node of specificScope.children) {
+ for (let node of specificScope.children) {
node.classList.toggle('on',
- !isGlobal
- && matrixSnapshot
- .scope
- .endsWith(node.getAttribute('data-scope')));
- }
+ !isGlobal
+ && matrixSnapshot
+ .scope
+ .endsWith(node.getAttribute('data-scope')));
+ }
}
function updateMatrixSwitches() {
- let count = 0;
+ let count = 0;
let enabled;
let switches = matrixSnapshot.tSwitches;
- for (let switchName in switches) {
+ for (let switchName in switches) {
if (switches.hasOwnProperty(switchName) === false) {
- continue;
- }
+ continue;
+ }
enabled = switches[switchName];
if (enabled && switchName !== 'matrix-off') {
- count += 1;
+ count += 1;
}
uDom('#mtxSwitch_' + switchName).toggleClass('switchTrue', enabled);
- }
- uDom.nodeFromId('mtxSwitch_https-strict')
- .classList
- .toggle('relevant', matrixSnapshot.hasMixedContent);
- uDom.nodeFromId('mtxSwitch_no-workers')
- .classList
- .toggle('relevant', matrixSnapshot.hasWebWorkers);
- uDom.nodeFromId('mtxSwitch_referrer-spoof')
- .classList.toggle('relevant', matrixSnapshot.has3pReferrer);
- uDom.nodeFromId('mtxSwitch_noscript-spoof')
- .classList
- .toggle('relevant', matrixSnapshot.hasNoscriptTags);
- uDom.nodeFromSelector('#buttonMtxSwitches span.badge').textContent =
+ }
+ uDom.nodeFromId('mtxSwitch_https-strict')
+ .classList
+ .toggle('relevant', matrixSnapshot.hasMixedContent);
+ uDom.nodeFromId('mtxSwitch_no-workers')
+ .classList
+ .toggle('relevant', matrixSnapshot.hasWebWorkers);
+ uDom.nodeFromId('mtxSwitch_referrer-spoof')
+ .classList.toggle('relevant', matrixSnapshot.has3pReferrer);
+ uDom.nodeFromId('mtxSwitch_noscript-spoof')
+ .classList
+ .toggle('relevant', matrixSnapshot.hasNoscriptTags);
+ uDom.nodeFromSelector('#buttonMtxSwitches span.badge').textContent =
count.toLocaleString();
- uDom.nodeFromSelector('#mtxSwitch_matrix-off span.badge').textContent =
+ uDom.nodeFromSelector('#mtxSwitch_matrix-off span.badge').textContent =
matrixSnapshot.blockedCount.toLocaleString();
- document.body.classList.toggle('powerOff', switches['matrix-off']);
+ document.body.classList.toggle('powerOff', switches['matrix-off']);
}
function toggleMatrixSwitch(ev) {
- if (ev.target.localName === 'a') {
- return;
- }
-
- let elem = ev.currentTarget;
- let pos = elem.id.indexOf('_');
- if (pos === -1) {
- return;
- }
-
- let switchName = elem.id.slice(pos + 1);
- let request = {
+ if (ev.target.localName === 'a') {
+ return;
+ }
+
+ let elem = ev.currentTarget;
+ let pos = elem.id.indexOf('_');
+ if (pos === -1) {
+ return;
+ }
+
+ let switchName = elem.id.slice(pos + 1);
+ let request = {
what: 'toggleMatrixSwitch',
switchName: switchName,
srcHostname: matrixSnapshot.scope
- };
- vAPI.messaging.send('popup.js', request, updateMatrixSnapshot);
+ };
+ vAPI.messaging.send('popup.js', request, updateMatrixSnapshot);
}
function updatePersistButton() {
- let diffCount = matrixSnapshot.diff.length;
- let button = uDom('#buttonPersist');
+ let diffCount = matrixSnapshot.diff.length;
+ let button = uDom('#buttonPersist');
- button.contents()
+ button.contents()
.filter(function () {
- return this.nodeType===3;
- })
- .first()
+ return this.nodeType===3;
+ })
+ .first()
.text(diffCount > 0 ? '\uf13e' : '\uf023');
- button.descendants('span.badge').text(diffCount > 0 ? diffCount : '');
+ button.descendants('span.badge').text(diffCount > 0 ? diffCount : '');
- let disabled = diffCount === 0;
+ let disabled = diffCount === 0;
- button.toggleClass('disabled', disabled);
- uDom('#buttonRevertScope').toggleClass('disabled', disabled);
+ button.toggleClass('disabled', disabled);
+ uDom('#buttonRevertScope').toggleClass('disabled', disabled);
}
function persistMatrix() {
- let request = {
+ let request = {
what: 'applyDiffToPermanentMatrix',
diff: matrixSnapshot.diff
- };
- vAPI.messaging.send('popup.js', request, updateMatrixSnapshot);
+ };
+ vAPI.messaging.send('popup.js', request, updateMatrixSnapshot);
}
// rhill 2014-03-12: revert completely ALL changes related to the
// current page, including scopes.
function revertMatrix() {
- let request = {
+ let request = {
what: 'applyDiffToTemporaryMatrix',
diff: matrixSnapshot.diff
- };
- vAPI.messaging.send('popup.js', request, updateMatrixSnapshot);
+ };
+ vAPI.messaging.send('popup.js', request, updateMatrixSnapshot);
}
// Buttons which are affected by any changes in the matrix
function updateMatrixButtons() {
- updateScopeCell();
- updateMatrixSwitches();
- updatePersistButton();
+ updateScopeCell();
+ updateMatrixSwitches();
+ updatePersistButton();
}
function revertAll() {
- let request = {
+ let request = {
what: 'revertTemporaryMatrix'
- };
- vAPI.messaging.send('popup.js', request, updateMatrixSnapshot);
- dropDownMenuHide();
+ };
+ vAPI.messaging.send('popup.js', request, updateMatrixSnapshot);
+ dropDownMenuHide();
}
function buttonReloadHandler(ev) {
- vAPI.messaging.send('popup.js', {
+ vAPI.messaging.send('popup.js', {
what: 'forceReloadTab',
tabId: matrixSnapshot.tabId,
bypassCache: ev.ctrlKey || ev.metaKey || ev.shiftKey
- });
+ });
}
function mouseenterMatrixCellHandler(ev) {
- matrixCellHotspots.appendTo(ev.target);
+ matrixCellHotspots.appendTo(ev.target);
}
function mouseleaveMatrixCellHandler() {
- matrixCellHotspots.detach();
+ matrixCellHotspots.detach();
}
function gotoExtensionURL(ev) {
- let url = uDom(ev.currentTarget).attr('data-extension-url');
- if (url) {
+ let url = uDom(ev.currentTarget).attr('data-extension-url');
+ if (url) {
vAPI.messaging.send('popup.js', {
- what: 'gotoExtensionURL',
- url: url,
- shiftKey: ev.shiftKey
+ what: 'gotoExtensionURL',
+ url: url,
+ shiftKey: ev.shiftKey
});
- }
- dropDownMenuHide();
- vAPI.closePopup();
+ }
+ dropDownMenuHide();
+ vAPI.closePopup();
}
function dropDownMenuShow(ev) {
- let button = ev.target;
- let menuOverlay = document.getElementById(button.getAttribute('data-dropdown-menu'));
- let butnRect = button.getBoundingClientRect();
- let viewRect = document.body.getBoundingClientRect();
- let butnNormalLeft = butnRect.left / (viewRect.width - butnRect.width);
- menuOverlay.classList.add('show');
- let menu = menuOverlay.querySelector('.dropdown-menu');
- let menuRect = menu.getBoundingClientRect();
- let menuLeft = butnNormalLeft * (viewRect.width - menuRect.width);
- menu.style.left = menuLeft.toFixed(0) + 'px';
- menu.style.top = butnRect.bottom + 'px';
+ let button = ev.target;
+ let menuOverlay = document.getElementById(button.getAttribute('data-dropdown-menu'));
+ let butnRect = button.getBoundingClientRect();
+ let viewRect = document.body.getBoundingClientRect();
+ let butnNormalLeft = butnRect.left / (viewRect.width - butnRect.width);
+ menuOverlay.classList.add('show');
+ let menu = menuOverlay.querySelector('.dropdown-menu');
+ let menuRect = menu.getBoundingClientRect();
+ let menuLeft = butnNormalLeft * (viewRect.width - menuRect.width);
+ menu.style.left = menuLeft.toFixed(0) + 'px';
+ menu.style.top = butnRect.bottom + 'px';
}
function dropDownMenuHide() {
- uDom('.dropdown-menu-capture').removeClass('show');
+ uDom('.dropdown-menu-capture').removeClass('show');
}
let onMatrixSnapshotReady = function (response) {
- if (response === 'ENOTFOUND') {
+ if (response === 'ENOTFOUND') {
uDom.nodeFromId('noTabFound').textContent =
- vAPI.i18n('matrixNoTabFound');
+ vAPI.i18n('matrixNoTabFound');
document.body.classList.add('noTabFound');
return;
- }
+ }
- // Now that tabId and pageURL are set, we can build our menu
- initMenuEnvironment();
- makeMenu();
+ // Now that tabId and pageURL are set, we can build our menu
+ initMenuEnvironment();
+ makeMenu();
- // After popup menu is built, check whether there is a non-empty matrix
- if (matrixSnapshot.url === '') {
+ // After popup menu is built, check whether there is a non-empty matrix
+ if (matrixSnapshot.url === '') {
uDom('#matHead').remove();
uDom('#toolbarContainer').remove();
// https://github.com/gorhill/httpswitchboard/issues/191
uDom('#noNetTrafficPrompt').text(vAPI.i18n('matrixNoNetTrafficPrompt'));
uDom('#noNetTrafficPrompt').css('display', '');
- }
-
- // Create a hash to find out whether the reload button needs to be
- // highlighted.
- // TODO:
- // ηMatrix: not sure what the purpose of highlighting is...
- // Maybe telling the user that the page needs refreshing? But
- // that's hardly useful (and by now people have gotten used to
- // the lack of such a feature.)
- // Not really going to do it, but let's leave the comment.
+ }
+
+ // Create a hash to find out whether the reload button needs to be
+ // highlighted.
+ // TODO:
+ // ηMatrix: not sure what the purpose of highlighting is...
+ // Maybe telling the user that the page needs refreshing? But
+ // that's hardly useful (and by now people have gotten used to
+ // the lack of such a feature.)
+ // Not really going to do it, but let's leave the comment.
};
let matrixSnapshotPoller = (function () {
- let timer = null;
+ let timer = null;
- let preprocessMatrixSnapshot = function (snapshot) {
+ let preprocessMatrixSnapshot = function (snapshot) {
if (Array.isArray(snapshot.headerIndices)) {
- snapshot.headerIndices = new Map(snapshot.headerIndices);
+ snapshot.headerIndices = new Map(snapshot.headerIndices);
}
return snapshot;
- };
+ };
- let processPollResult = function (response) {
+ let processPollResult = function (response) {
if (typeof response !== 'object') {
- return;
+ return;
}
if (response.mtxContentModified === false
- && response.mtxCountModified === false
- && response.pMatrixModified === false
- && response.tMatrixModified === false) {
- return;
+ && response.mtxCountModified === false
+ && response.pMatrixModified === false
+ && response.tMatrixModified === false) {
+ return;
}
matrixSnapshot = preprocessMatrixSnapshot(response);
if (response.mtxContentModified) {
- makeMenu();
- return;
+ makeMenu();
+ return;
}
if (response.mtxCountModified) {
- updateMatrixCounts();
+ updateMatrixCounts();
}
if (response.pMatrixModified
- || response.tMatrixModified
- || response.scopeModified) {
- updateMatrixColors();
- updateMatrixBehavior();
- updateMatrixButtons();
+ || response.tMatrixModified
+ || response.scopeModified) {
+ updateMatrixColors();
+ updateMatrixBehavior();
+ updateMatrixButtons();
}
- };
+ };
- let onPolled = function (response) {
+ let onPolled = function (response) {
processPollResult(response);
pollAsync();
- };
+ };
- let pollNow = function () {
+ let pollNow = function () {
unpollAsync();
vAPI.messaging.send('popup.js', {
- what: 'matrixSnapshot',
- tabId: matrixSnapshot.tabId,
- scope: matrixSnapshot.scope,
- mtxContentModifiedTime: matrixSnapshot.mtxContentModifiedTime,
- mtxCountModifiedTime: matrixSnapshot.mtxCountModifiedTime,
- mtxDiffCount: matrixSnapshot.diff.length,
- pMatrixModifiedTime: matrixSnapshot.pMatrixModifiedTime,
- tMatrixModifiedTime: matrixSnapshot.tMatrixModifiedTime,
+ what: 'matrixSnapshot',
+ tabId: matrixSnapshot.tabId,
+ scope: matrixSnapshot.scope,
+ mtxContentModifiedTime: matrixSnapshot.mtxContentModifiedTime,
+ mtxCountModifiedTime: matrixSnapshot.mtxCountModifiedTime,
+ mtxDiffCount: matrixSnapshot.diff.length,
+ pMatrixModifiedTime: matrixSnapshot.pMatrixModifiedTime,
+ tMatrixModifiedTime: matrixSnapshot.tMatrixModifiedTime,
}, onPolled);
- };
+ };
- let poll = function () {
+ let poll = function () {
timer = null;
pollNow();
- };
+ };
- let pollAsync = function () {
+ let pollAsync = function () {
if (timer !== null) {
- return;
+ return;
}
if (document.defaultView === null) {
- return;
+ return;
}
timer = vAPI.setTimeout(poll, 1414);
- };
+ };
- let unpollAsync = function () {
+ let unpollAsync = function () {
if (timer !== null) {
- clearTimeout(timer);
- timer = null;
+ clearTimeout(timer);
+ timer = null;
}
- };
+ };
- (function () {
+ (function () {
let tabId = matrixSnapshot.tabId;
// If no tab id yet, see if there is one specified in our URL
if (tabId === undefined) {
- let matches = window
- .location
- .search
- .match(/(?:\?|&)tabId=([^&]+)/);
+ let matches = window
+ .location
+ .search
+ .match(/(?:\?|&)tabId=([^&]+)/);
- if (matches !== null) {
+ if (matches !== null) {
tabId = matches[1];
// No need for logger button when embedded in logger
uDom('[data-extension-url="logger-ui.html"]').remove();
- }
+ }
}
let snapshotFetched = function (response) {
- if (typeof response === 'object') {
+ if (typeof response === 'object') {
matrixSnapshot = preprocessMatrixSnapshot(response);
- }
- onMatrixSnapshotReady(response);
- pollAsync();
+ }
+ onMatrixSnapshotReady(response);
+ pollAsync();
};
vAPI.messaging.send('popup.js', {
- what: 'matrixSnapshot',
- tabId: tabId
+ what: 'matrixSnapshot',
+ tabId: tabId
}, snapshotFetched);
- })();
+ })();
- return {
+ return {
pollNow: pollNow
- };
+ };
})();
// Below is UI stuff which is not key to make the menu, so this can
@@ -1536,8 +1536,8 @@
matrixCellHotspots = uDom('#cellHotspots').detach();
uDom('body')
- .on('mouseenter', '.matCell', mouseenterMatrixCellHandler)
- .on('mouseleave', '.matCell', mouseleaveMatrixCellHandler);
+ .on('mouseenter', '.matCell', mouseenterMatrixCellHandler)
+ .on('mouseleave', '.matCell', mouseleaveMatrixCellHandler);
uDom('#specificScope').on('click', selectSpecificScope);
uDom('#globalScope').on('click', selectGlobalScope);
@@ -1553,9 +1553,9 @@
uDom('body').on('click', '.dropdown-menu-capture', dropDownMenuHide);
uDom('#matList').on('click', '.g4Meta', function (ev) {
- matrixSnapshot.collapseBlacklistedDomains =
+ matrixSnapshot.collapseBlacklistedDomains =
ev.target.classList.toggle('g4Collapsed');
- setUserSetting('popupCollapseBlacklistedDomains',
- matrixSnapshot.collapseBlacklistedDomains);
+ setUserSetting('popupCollapseBlacklistedDomains',
+ matrixSnapshot.collapseBlacklistedDomains);
});
})();
diff --git a/js/profiler.js b/js/profiler.js
index 7406e92..49fe7d9 100644
--- a/js/profiler.js
+++ b/js/profiler.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
diff --git a/js/raw-settings.js b/js/raw-settings.js
index 5940188..54c5b3c 100644
--- a/js/raw-settings.js
+++ b/js/raw-settings.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2018-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uBlock
*/
@@ -29,89 +29,89 @@
(function() {
- /******************************************************************************/
+/******************************************************************************/
- var messaging = vAPI.messaging;
- var cachedData = '';
- var rawSettingsInput = uDom.nodeFromId('rawSettings');
+var messaging = vAPI.messaging;
+var cachedData = '';
+var rawSettingsInput = uDom.nodeFromId('rawSettings');
- /******************************************************************************/
+/******************************************************************************/
- var hashFromRawSettings = function(raw) {
- return raw.trim().replace(/\s+/g, '|');
- };
+var hashFromRawSettings = function(raw) {
+ return raw.trim().replace(/\s+/g, '|');
+};
- /******************************************************************************/
+/******************************************************************************/
- // This is to give a visual hint that the content of user blacklist has changed.
+// This is to give a visual hint that the content of user blacklist has changed.
- var rawSettingsChanged = (function () {
- var timer = null;
+var rawSettingsChanged = (function () {
+ var timer = null;
- var handler = function() {
- timer = null;
- var changed =
- hashFromRawSettings(rawSettingsInput.value) !== cachedData;
- uDom.nodeFromId('rawSettingsApply').disabled = !changed;
- };
+ var handler = function() {
+ timer = null;
+ var changed =
+ hashFromRawSettings(rawSettingsInput.value) !== cachedData;
+ uDom.nodeFromId('rawSettingsApply').disabled = !changed;
+ };
- return function() {
- if ( timer !== null ) {
- clearTimeout(timer);
- }
- timer = vAPI.setTimeout(handler, 100);
- };
- })();
-
- /******************************************************************************/
-
- function renderRawSettings() {
- var onRead = function(raw) {
- cachedData = hashFromRawSettings(raw);
- var pretty = [],
- whitespaces = ' ',
- lines = raw.split('\n'),
- max = 0,
- pos,
- i, n = lines.length;
- for ( i = 0; i < n; i++ ) {
- pos = lines[i].indexOf(' ');
- if ( pos > max ) {
- max = pos;
- }
- }
- for ( i = 0; i < n; i++ ) {
- pos = lines[i].indexOf(' ');
- pretty.push(whitespaces.slice(0, max - pos) + lines[i]);
+ return function() {
+ if ( timer !== null ) {
+ clearTimeout(timer);
+ }
+ timer = vAPI.setTimeout(handler, 100);
+ };
+})();
+
+/******************************************************************************/
+
+function renderRawSettings() {
+ var onRead = function(raw) {
+ cachedData = hashFromRawSettings(raw);
+ var pretty = [],
+ whitespaces = ' ',
+ lines = raw.split('\n'),
+ max = 0,
+ pos,
+ i, n = lines.length;
+ for ( i = 0; i < n; i++ ) {
+ pos = lines[i].indexOf(' ');
+ if ( pos > max ) {
+ max = pos;
}
- rawSettingsInput.value = pretty.join('\n') + '\n';
- rawSettingsChanged();
- rawSettingsInput.focus();
- };
- messaging.send('dashboard', { what: 'readRawSettings' }, onRead);
- }
-
- /******************************************************************************/
-
- var applyChanges = function() {
- messaging.send(
- 'dashboard',
- {
- what: 'writeRawSettings',
- content: rawSettingsInput.value
- },
- renderRawSettings
- );
+ }
+ for ( i = 0; i < n; i++ ) {
+ pos = lines[i].indexOf(' ');
+ pretty.push(whitespaces.slice(0, max - pos) + lines[i]);
+ }
+ rawSettingsInput.value = pretty.join('\n') + '\n';
+ rawSettingsChanged();
+ rawSettingsInput.focus();
};
+ messaging.send('dashboard', { what: 'readRawSettings' }, onRead);
+}
+
+/******************************************************************************/
+
+var applyChanges = function() {
+ messaging.send(
+ 'dashboard',
+ {
+ what: 'writeRawSettings',
+ content: rawSettingsInput.value
+ },
+ renderRawSettings
+ );
+};
- /******************************************************************************/
+/******************************************************************************/
- // Handle user interaction
- uDom('#rawSettings').on('input', rawSettingsChanged);
- uDom('#rawSettingsApply').on('click', applyChanges);
+// Handle user interaction
+uDom('#rawSettings').on('input', rawSettingsChanged);
+uDom('#rawSettingsApply').on('click', applyChanges);
- renderRawSettings();
+renderRawSettings();
- /******************************************************************************/
+/******************************************************************************/
})();
diff --git a/js/settings.js b/js/settings.js
index 5694b83..a9e11b4 100644
--- a/js/settings.js
+++ b/js/settings.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -27,100 +27,100 @@
let cachedSettings = {};
function changeUserSettings(name, value) {
- vAPI.messaging.send('settings.js', {
+ vAPI.messaging.send('settings.js', {
what: 'userSettings',
name: name,
value: value
- });
+ });
}
function changeMatrixSwitch(name, state) {
- vAPI.messaging.send('settings.js', {
+ vAPI.messaging.send('settings.js', {
what: 'setMatrixSwitch',
switchName: name,
state: state
- });
+ });
}
function onChangeValueHandler(elem, setting, min, max) {
- let oldVal = cachedSettings.userSettings[setting];
- let newVal = Math.round(parseFloat(elem.value));
- if (typeof newVal !== 'number') {
+ let oldVal = cachedSettings.userSettings[setting];
+ let newVal = Math.round(parseFloat(elem.value));
+ if (typeof newVal !== 'number') {
newVal = oldVal;
- } else {
+ } else {
newVal = Math.max(newVal, min);
newVal = Math.min(newVal, max);
- }
- elem.value = newVal;
- if (newVal !== oldVal) {
+ }
+ elem.value = newVal;
+ if (newVal !== oldVal) {
changeUserSettings(setting, newVal);
- }
+ }
}
function prepareToDie() {
- onChangeValueHandler(uDom.nodeFromId('deleteUnusedSessionCookiesAfter'),
- 'deleteUnusedSessionCookiesAfter',
- 15, 1440);
- onChangeValueHandler(uDom.nodeFromId('clearBrowserCacheAfter'),
- 'clearBrowserCacheAfter',
- 15, 1440);
+ onChangeValueHandler(uDom.nodeFromId('deleteUnusedSessionCookiesAfter'),
+ 'deleteUnusedSessionCookiesAfter',
+ 15, 1440);
+ onChangeValueHandler(uDom.nodeFromId('clearBrowserCacheAfter'),
+ 'clearBrowserCacheAfter',
+ 15, 1440);
}
function onInputChanged(ev) {
- let target = ev.target;
+ let target = ev.target;
- switch (target.id) {
- case 'displayTextSize':
+ switch (target.id) {
+ case 'displayTextSize':
changeUserSettings('displayTextSize', target.value + 'px');
break;
- case 'clearBrowserCache':
- case 'cloudStorageEnabled':
- case 'collapseBlacklisted':
- case 'colorBlindFriendly':
- case 'deleteCookies':
- case 'deleteLocalStorage':
- case 'deleteUnusedSessionCookies':
- case 'iconBadgeEnabled':
- case 'processHyperlinkAuditing':
- case 'disableUpdateIcon':
- case 'resolveCname':
- changeUserSettings(target.id, target.checked);
- break;
- case 'collapseBlocked':
+ case 'clearBrowserCache':
+ case 'cloudStorageEnabled':
+ case 'collapseBlacklisted':
+ case 'colorBlindFriendly':
+ case 'deleteCookies':
+ case 'deleteLocalStorage':
+ case 'deleteUnusedSessionCookies':
+ case 'iconBadgeEnabled':
+ case 'processHyperlinkAuditing':
+ case 'disableUpdateIcon':
+ case 'resolveCname':
changeUserSettings(target.id, target.checked);
- synchronizeWidgets();
break;
- case 'noMixedContent':
- case 'noscriptTagsSpoofed':
- case 'processReferer':
+ case 'collapseBlocked':
+ changeUserSettings(target.id, target.checked);
+ synchronizeWidgets();
+ break;
+ case 'noMixedContent':
+ case 'noscriptTagsSpoofed':
+ case 'processReferer':
changeMatrixSwitch(target.getAttribute('data-matrix-switch'),
- target.checked);
+ target.checked);
break;
- case 'deleteUnusedSessionCookiesAfter':
+ case 'deleteUnusedSessionCookiesAfter':
onChangeValueHandler(target, 'deleteUnusedSessionCookiesAfter',
- 15, 1440);
+ 15, 1440);
break;
- case 'clearBrowserCacheAfter':
+ case 'clearBrowserCacheAfter':
onChangeValueHandler(target, 'clearBrowserCacheAfter', 15, 1440);
break;
- case 'popupScopeLevel':
+ case 'popupScopeLevel':
changeUserSettings('popupScopeLevel', target.value);
break;
- default:
+ default:
break;
- }
+ }
}
function synchronizeWidgets() {
- let e1, e2;
+ let e1, e2;
- e1 = uDom.nodeFromId('collapseBlocked');
- e2 = uDom.nodeFromId('collapseBlacklisted');
- if (e1.checked) {
+ e1 = uDom.nodeFromId('collapseBlocked');
+ e2 = uDom.nodeFromId('collapseBlacklisted');
+ if (e1.checked) {
e2.setAttribute('disabled', '');
- } else {
+ } else {
e2.removeAttribute('disabled');
- }
+ }
}
let onSettingsReceived = function (settings) {
@@ -131,24 +131,24 @@
let matrixSwitches = settings.matrixSwitches;
uDom('[data-setting-bool]').forEach(function (elem) {
- elem.prop('checked', userSettings[elem.prop('id')] === true);
+ elem.prop('checked', userSettings[elem.prop('id')] === true);
});
uDom('[data-matrix-switch]').forEach(function (elem) {
- let switchName = elem.attr('data-matrix-switch');
- if (typeof switchName === 'string' && switchName !== '') {
+ let switchName = elem.attr('data-matrix-switch');
+ if (typeof switchName === 'string' && switchName !== '') {
elem.prop('checked', matrixSwitches[switchName] === true);
- }
+ }
});
uDom.nodeFromId('displayTextSize').value =
- parseInt(userSettings.displayTextSize, 10) || 14;
+ parseInt(userSettings.displayTextSize, 10) || 14;
uDom.nodeFromId('popupScopeLevel').value = userSettings.popupScopeLevel;
uDom.nodeFromId('deleteUnusedSessionCookiesAfter').value =
- userSettings.deleteUnusedSessionCookiesAfter;
+ userSettings.deleteUnusedSessionCookiesAfter;
uDom.nodeFromId('clearBrowserCacheAfter').value =
- userSettings.clearBrowserCacheAfter;
+ userSettings.clearBrowserCacheAfter;
synchronizeWidgets();
@@ -159,6 +159,6 @@
}
vAPI.messaging.send('settings.js', {
- what: 'getUserSettings'
+ what: 'getUserSettings'
}, onSettingsReceived);
})();
diff --git a/js/start.js b/js/start.js
index b0f3970..f7867ee 100644
--- a/js/start.js
+++ b/js/start.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -31,58 +31,58 @@
let ηm = ηMatrix;
let processCallbackQueue = function (queue, callback) {
- while (queue.length > 0) {
- let fn = queue.pop();
- fn();
- }
-
- if (typeof callback === 'function') {
- callback();
- }
+ while (queue.length > 0) {
+ let fn = queue.pop();
+ fn();
+ }
+
+ if (typeof callback === 'function') {
+ callback();
+ }
};
let onAllDone = function () {
- ηm.webRequest.start();
+ ηm.webRequest.start();
- ηm.assets.checkVersion();
- ηm.assets.addObserver(ηm.assetObserver.bind(ηm));
- ηm.scheduleAssetUpdater(ηm.userSettings.autoUpdate ? 7 * 60 * 1000 : 0);
+ ηm.assets.checkVersion();
+ ηm.assets.addObserver(ηm.assetObserver.bind(ηm));
+ ηm.scheduleAssetUpdater(ηm.userSettings.autoUpdate ? 7 * 60 * 1000 : 0);
- vAPI.cloud.start([ 'myRulesPane' ]);
+ vAPI.cloud.start([ 'myRulesPane' ]);
};
let onTabsReady = function (tabs) {
- for (let i=tabs.length-1; i>=0; --i) {
- // console.debug('start.js > binding %d tabs', i);
+ for (let i=tabs.length-1; i>=0; --i) {
+ // console.debug('start.js > binding %d tabs', i);
let tab = tabs[i];
ηm.tabContextManager.push(tab.id, tab.url, 'newURL');
- }
+ }
- onAllDone();
+ onAllDone();
};
let onUserSettingsLoaded = function () {
- ηm.loadHostsFiles();
+ ηm.loadHostsFiles();
};
let onPSLReady = function () {
- ηm.loadUserSettings(onUserSettingsLoaded);
- ηm.loadRawSettings();
- ηm.loadMatrix();
-
- // rhill 2013-11-24: bind behind-the-scene virtual tab/url
- // manually, since the normal way forbid binding behind the
- // scene tab.
- // https://github.com/gorhill/httpswitchboard/issues/67
- ηm.pageStores[vAPI.noTabId] =
- ηm.pageStoreFactory(ηm.tabContextManager.mustLookup(vAPI.noTabId));
- ηm.pageStores[vAPI.noTabId].title =
- vAPI.i18n('statsPageDetailedBehindTheScenePage');
-
- vAPI.tabs.getAll(onTabsReady);
+ ηm.loadUserSettings(onUserSettingsLoaded);
+ ηm.loadRawSettings();
+ ηm.loadMatrix();
+
+ // rhill 2013-11-24: bind behind-the-scene virtual tab/url
+ // manually, since the normal way forbid binding behind the
+ // scene tab.
+ // https://github.com/gorhill/httpswitchboard/issues/67
+ ηm.pageStores[vAPI.noTabId] =
+ ηm.pageStoreFactory(ηm.tabContextManager.mustLookup(vAPI.noTabId));
+ ηm.pageStores[vAPI.noTabId].title =
+ vAPI.i18n('statsPageDetailedBehindTheScenePage');
+
+ vAPI.tabs.getAll(onTabsReady);
};
processCallbackQueue(ηm.onBeforeStartQueue, function () {
- ηm.loadPublicSuffixList(onPSLReady);
+ ηm.loadPublicSuffixList(onPSLReady);
});
})();
diff --git a/js/storage.js b/js/storage.js
index f5afca8..24249ab 100644
--- a/js/storage.js
+++ b/js/storage.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -552,7 +552,7 @@ Components.utils.import('chrome://ematrix/content/lib/Tools.jsm');
};
ηMatrix.scheduleAssetUpdater = (function () {
- let timer;
+ let timer = undefined;
let next = 0;
return function (updateDelay) {
@@ -618,11 +618,11 @@ Components.utils.import('chrome://ematrix/content/lib/Tools.jsm');
if (details.assetKeys.length !== 0) {
this.loadHostsFiles();
}
- if (this.userSettings.autoUpdate) {
- this.scheduleAssetUpdater(25200000);
- } else {
- this.scheduleAssetUpdater(0);
- }
+
+ ηm.scheduleAssetUpdater(ηm.userSettings.autoUpdate ?
+ 7 * 60 * 100000 :
+ 0);
+
vAPI.messaging.broadcast({
what: 'assetsUpdated',
assetKeys: details.assetKeys
diff --git a/js/tab.js b/js/tab.js
index a01eecf..bcfca33 100644
--- a/js/tab.js
+++ b/js/tab.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -40,47 +40,47 @@
// apply only to that scheme.
ηm.normalizePageURL = function (tabId, pageURL) {
- if (vAPI.isBehindTheSceneTabId(tabId)) {
+ if (vAPI.isBehindTheSceneTabId(tabId)) {
return 'http://' + this.behindTheSceneScope + '/';
- }
-
- // https://github.com/gorhill/uMatrix/issues/992
- if (pageURL.startsWith('wyciwyg:')) {
- // Matches strings like 'wyciwyg://101/'
- let filter = /^wyciwyg:\/\/\d+\//.exec(pageURL);
- if (filter) {
- pageURL = pageURL.slice(filter[0].length);
- }
- }
-
- // If the URL is that of our "blocked page" document, return
- // the URL of the blocked page.
- if (pageURL.lastIndexOf(vAPI.getURL('main-blocked.html'), 0) === 0) {
+ }
+
+ // https://github.com/gorhill/uMatrix/issues/992
+ if (pageURL.startsWith('wyciwyg:')) {
+ // Matches strings like 'wyciwyg://101/'
+ let filter = /^wyciwyg:\/\/\d+\//.exec(pageURL);
+ if (filter) {
+ pageURL = pageURL.slice(filter[0].length);
+ }
+ }
+
+ // If the URL is that of our "blocked page" document, return
+ // the URL of the blocked page.
+ if (pageURL.lastIndexOf(vAPI.getURL('main-blocked.html'), 0) === 0) {
let matches = /main-blocked\.html\?details=([^&]+)/.exec(pageURL);
if (matches && matches.length === 2) {
- try {
+ try {
let details = JSON.parse(atob(matches[1]));
pageURL = details.url;
- } catch (e) {
- }
+ } catch (e) {
+ }
}
- }
+ }
- let uri = UriTools.set(pageURL);
- let scheme = uri.scheme;
- if (scheme === 'https' || scheme === 'http') {
+ let uri = UriTools.set(pageURL);
+ let scheme = uri.scheme;
+ if (scheme === 'https' || scheme === 'http') {
return UriTools.normalizedURI();
- }
+ }
- let fakeHostname = scheme + '-scheme';
+ let fakeHostname = scheme + '-scheme';
- if (uri.hostname !== '') {
+ if (uri.hostname !== '') {
fakeHostname = uri.hostname + '.' + fakeHostname;
- } else if (scheme === 'about') {
+ } else if (scheme === 'about') {
fakeHostname = uri.path + '.' + fakeHostname;
- }
+ }
- return 'http://' + fakeHostname + '/';
+ return 'http://' + fakeHostname + '/';
};
/*
@@ -149,119 +149,119 @@
*/
ηm.tabContextManager = (function () {
- let tabContexts = Object.create(null);
+ let tabContexts = Object.create(null);
- // https://github.com/chrisaljoudi/uBlock/issues/1001
- // This is to be used as last-resort fallback in case a tab is
- // found to not be bound while network requests are fired for
- // the tab.
- let mostRecentRootDocURL = '';
- let mostRecentRootDocURLTimestamp = 0;
+ // https://github.com/chrisaljoudi/uBlock/issues/1001
+ // This is to be used as last-resort fallback in case a tab is
+ // found to not be bound while network requests are fired for
+ // the tab.
+ let mostRecentRootDocURL = '';
+ let mostRecentRootDocURLTimestamp = 0;
- let gcPeriod = 31 * 60 * 1000; // every 31 minutes
+ let gcPeriod = 31 * 60 * 1000; // every 31 minutes
- // A pushed entry is removed from the stack unless it is
- // committed with a set time.
- let StackEntry = function (url, commit) {
+ // A pushed entry is removed from the stack unless it is
+ // committed with a set time.
+ let StackEntry = function (url, commit) {
this.url = url;
this.committed = commit;
this.tstamp = Date.now();
- };
+ };
- let TabContext = function (tabId) {
+ let TabContext = function (tabId) {
this.tabId = tabId;
this.stack = [];
this.rawURL =
- this.normalURL =
- this.scheme =
- this.rootHostname =
- this.rootDomain = '';
+ this.normalURL =
+ this.scheme =
+ this.rootHostname =
+ this.rootDomain = '';
this.secure = false;
this.commitTimer = null;
this.gcTimer = null;
tabContexts[tabId] = this;
- };
+ };
- TabContext.prototype.destroy = function () {
+ TabContext.prototype.destroy = function () {
if (vAPI.isBehindTheSceneTabId(this.tabId)) {
- return;
+ return;
}
if (this.gcTimer !== null) {
- clearTimeout(this.gcTimer);
- this.gcTimer = null;
+ clearTimeout(this.gcTimer);
+ this.gcTimer = null;
}
delete tabContexts[this.tabId];
- };
+ };
- TabContext.prototype.onTab = function (tab) {
+ TabContext.prototype.onTab = function (tab) {
if (tab) {
- this.gcTimer = vAPI.setTimeout(this.onGC.bind(this), gcPeriod);
+ this.gcTimer = vAPI.setTimeout(this.onGC.bind(this), gcPeriod);
} else {
- this.destroy();
+ this.destroy();
}
- };
+ };
- TabContext.prototype.onGC = function () {
+ TabContext.prototype.onGC = function () {
this.gcTimer = null;
if (vAPI.isBehindTheSceneTabId(this.tabId)) {
- return;
+ return;
}
vAPI.tabs.get(this.tabId, this.onTab.bind(this));
- };
+ };
- // https://github.com/gorhill/uBlock/issues/248
- // Stack entries have to be committed to stick. Non-committed
- // stack entries are removed after a set delay.
- TabContext.prototype.onCommit = function () {
+ // https://github.com/gorhill/uBlock/issues/248
+ // Stack entries have to be committed to stick. Non-committed
+ // stack entries are removed after a set delay.
+ TabContext.prototype.onCommit = function () {
if (vAPI.isBehindTheSceneTabId(this.tabId)) {
- return;
+ return;
}
this.commitTimer = null;
// Remove uncommitted entries at the top of the stack.
let i = this.stack.length;
while (i--) {
- if (this.stack[i].committed) {
+ if (this.stack[i].committed) {
break;
- }
+ }
}
// https://github.com/gorhill/uBlock/issues/300
// If no committed entry was found, fall back on the bottom-most one
// as being the committed one by default.
if (i === -1 && this.stack.length !== 0) {
- this.stack[0].committed = true;
- i = 0;
+ this.stack[0].committed = true;
+ i = 0;
}
++i;
if (i < this.stack.length) {
- this.stack.length = i;
- this.update();
- ηm.bindTabToPageStats(this.tabId, 'newURL');
+ this.stack.length = i;
+ this.update();
+ ηm.bindTabToPageStats(this.tabId, 'newURL');
}
- };
+ };
- // This takes care of orphanized tab contexts. Can't be
- // started for all contexts, as the behind-the-scene context
- // is permanent -- so we do not want to flush it.
- TabContext.prototype.autodestroy = function () {
+ // This takes care of orphanized tab contexts. Can't be
+ // started for all contexts, as the behind-the-scene context
+ // is permanent -- so we do not want to flush it.
+ TabContext.prototype.autodestroy = function () {
if (vAPI.isBehindTheSceneTabId(this.tabId)) {
- return;
+ return;
}
this.gcTimer = vAPI.setTimeout(this.onGC.bind(this), gcPeriod);
- };
+ };
- // Update just force all properties to be updated to match the
- // most recent root URL.
- TabContext.prototype.update = function () {
+ // Update just force all properties to be updated to match the
+ // most recent root URL.
+ TabContext.prototype.update = function () {
if (this.stack.length === 0) {
- this.rawURL =
- this.normalURL =
- this.scheme =
- this.rootHostname =
- this.rootDomain = '';
- this.secure = false;
- return;
+ this.rawURL =
+ this.normalURL =
+ this.scheme =
+ this.rootHostname =
+ this.rootDomain = '';
+ this.secure = false;
+ return;
}
this.rawURL = this.stack[this.stack.length - 1].url;
@@ -269,71 +269,71 @@
this.scheme = UriTools.schemeFromURI(this.rawURL);
this.rootHostname = UriTools.hostnameFromURI(this.normalURL);
this.rootDomain = UriTools.domainFromHostname(this.rootHostname)
- || this.rootHostname;
+ || this.rootHostname;
this.secure = UriTools.isSecureScheme(this.scheme);
- };
+ };
- // Called whenever a candidate root URL is spotted for the tab.
- TabContext.prototype.push = function (url, context) {
+ // Called whenever a candidate root URL is spotted for the tab.
+ TabContext.prototype.push = function (url, context) {
if (vAPI.isBehindTheSceneTabId(this.tabId)) {
- return;
- }
+ return;
+ }
let committed = context !== undefined;
let count = this.stack.length;
let topEntry = this.stack[count - 1];
if (topEntry && topEntry.url === url) {
- if (committed) {
+ if (committed) {
topEntry.committed = true;
- }
- return;
+ }
+ return;
}
if (this.commitTimer !== null) {
- clearTimeout(this.commitTimer);
+ clearTimeout(this.commitTimer);
}
if (committed) {
- this.stack = [new StackEntry(url, true)];
+ this.stack = [new StackEntry(url, true)];
} else {
- this.stack.push(new StackEntry(url));
- this.commitTimer =
- vAPI.setTimeout(this.onCommit.bind(this), 1000);
+ this.stack.push(new StackEntry(url));
+ this.commitTimer =
+ vAPI.setTimeout(this.onCommit.bind(this), 1000);
}
this.update();
ηm.bindTabToPageStats(this.tabId, context);
- };
+ };
- // These are to be used for the API of the tab context manager.
+ // These are to be used for the API of the tab context manager.
- let push = function (tabId, url, context) {
+ let push = function (tabId, url, context) {
let entry = tabContexts[tabId];
if (entry === undefined) {
- entry = new TabContext(tabId);
- entry.autodestroy();
+ entry = new TabContext(tabId);
+ entry.autodestroy();
}
entry.push(url, context);
mostRecentRootDocURL = url;
mostRecentRootDocURLTimestamp = Date.now();
return entry;
- };
+ };
- // Find a tab context for a specific tab. If none is found,
- // attempt to fix this. When all fail, the behind-the-scene
- // context is returned.
- let mustLookup = function (tabId, url) {
+ // Find a tab context for a specific tab. If none is found,
+ // attempt to fix this. When all fail, the behind-the-scene
+ // context is returned.
+ let mustLookup = function (tabId, url) {
let entry;
if (url !== undefined) {
- entry = push(tabId, url);
+ entry = push(tabId, url);
} else {
- entry = tabContexts[tabId];
+ entry = tabContexts[tabId];
}
if (entry !== undefined) {
- return entry;
+ return entry;
}
// https://github.com/chrisaljoudi/uBlock/issues/1025
@@ -342,8 +342,8 @@
// it is too far in the future, at which point it ceases
// to be a "best guess".
if (mostRecentRootDocURL
- !== '' && mostRecentRootDocURLTimestamp + 500 < Date.now()) {
- mostRecentRootDocURL = '';
+ !== '' && mostRecentRootDocURLTimestamp + 500 < Date.now()) {
+ mostRecentRootDocURL = '';
}
// https://github.com/chrisaljoudi/uBlock/issues/1001
@@ -352,7 +352,7 @@
// document to the unbound tab. It's a guess, but better
// than ending up filtering nothing at all.
if (mostRecentRootDocURL !== '') {
- return push(tabId, mostRecentRootDocURL);
+ return push(tabId, mostRecentRootDocURL);
}
// If all else fail at finding a page store, re-categorize
@@ -363,69 +363,69 @@
// Example: Chromium + case #12 at
// http://raymondhill.net/ublock/popup.html
return tabContexts[vAPI.noTabId];
- };
+ };
- let lookup = function (tabId) {
+ let lookup = function (tabId) {
return tabContexts[tabId] || null;
- };
+ };
- // Behind-the-scene tab context
- (function () {
+ // Behind-the-scene tab context
+ (function () {
let entry = new TabContext(vAPI.noTabId);
entry.stack.push(new StackEntry('', true));
entry.rawURL = '';
entry.normalURL = ηm.normalizePageURL(entry.tabId);
entry.rootHostname = UriTools.hostnameFromURI(entry.normalURL);
entry.rootDomain = UriTools.domainFromHostname(entry.rootHostname)
- || entry.rootHostname;
- })();
+ || entry.rootHostname;
+ })();
- // https://github.com/gorhill/uMatrix/issues/513
- // Force a badge update here, it could happen that all the
- // subsequent network requests are already in the page
- // store, which would cause the badge to no be updated for
- // these network requests.
+ // https://github.com/gorhill/uMatrix/issues/513
+ // Force a badge update here, it could happen that all the
+ // subsequent network requests are already in the page
+ // store, which would cause the badge to no be updated for
+ // these network requests.
- vAPI.tabs.onNavigation = function (details) {
+ vAPI.tabs.onNavigation = function (details) {
let tabId = details.tabId;
if (vAPI.isBehindTheSceneTabId(tabId)) {
- return;
- }
+ return;
+ }
push(tabId, details.url, 'newURL');
ηm.updateBadgeAsync(tabId);
- };
+ };
- // https://github.com/gorhill/uMatrix/issues/872
- // `changeInfo.url` may not always be available (Firefox).
+ // https://github.com/gorhill/uMatrix/issues/872
+ // `changeInfo.url` may not always be available (Firefox).
- vAPI.tabs.onUpdated = function (tabId, changeInfo, tab) {
+ vAPI.tabs.onUpdated = function (tabId, changeInfo, tab) {
if (vAPI.isBehindTheSceneTabId(tabId)) {
- return;
- }
+ return;
+ }
if (typeof tab.url !== 'string' || tab.url === '') {
- return;
- }
+ return;
+ }
let url = changeInfo.url || tab.url;
if (url) {
- push(tabId, url, 'updateURL');
+ push(tabId, url, 'updateURL');
}
- };
+ };
- vAPI.tabs.onClosed = function (tabId) {
+ vAPI.tabs.onClosed = function (tabId) {
ηm.unbindTabFromPageStats(tabId);
let entry = tabContexts[tabId];
if (entry instanceof TabContext) {
- entry.destroy();
+ entry.destroy();
}
- };
+ };
- return {
+ return {
push: push,
lookup: lookup,
mustLookup: mustLookup
- };
+ };
})();
vAPI.tabs.registerListeners();
@@ -433,30 +433,30 @@
// Create an entry for the tab if it doesn't exist
ηm.bindTabToPageStats = function (tabId, context) {
- this.updateBadgeAsync(tabId);
+ this.updateBadgeAsync(tabId);
- // Do not create a page store for URLs which are of no
- // interests Example: dev console
- let tabContext = this.tabContextManager.lookup(tabId);
- if (tabContext === null) {
+ // Do not create a page store for URLs which are of no
+ // interests Example: dev console
+ let tabContext = this.tabContextManager.lookup(tabId);
+ if (tabContext === null) {
throw new Error('Unmanaged tab id: ' + tabId);
- }
+ }
- // rhill 2013-11-24: Never ever rebind behind-the-scene
- // virtual tab.
- // https://github.com/gorhill/httpswitchboard/issues/67
- if (vAPI.isBehindTheSceneTabId(tabId)) {
+ // rhill 2013-11-24: Never ever rebind behind-the-scene
+ // virtual tab.
+ // https://github.com/gorhill/httpswitchboard/issues/67
+ if (vAPI.isBehindTheSceneTabId(tabId)) {
return this.pageStores[tabId];
- }
+ }
- let normalURL = tabContext.normalURL;
- let pageStore = this.pageStores[tabId] || null;
+ let normalURL = tabContext.normalURL;
+ let pageStore = this.pageStores[tabId] || null;
- // The previous page URL, if any, associated with the tab
- if (pageStore !== null) {
+ // The previous page URL, if any, associated with the tab
+ if (pageStore !== null) {
// No change, do not rebind
if (pageStore.pageUrl === normalURL) {
- return pageStore;
+ return pageStore;
}
// https://github.com/gorhill/uMatrix/issues/37
@@ -466,124 +466,124 @@
// https://github.com/gorhill/uMatrix/issues/72
// Need to double-check that the new scope is same as old scope
if (context === 'updateURL'
- && pageStore.pageHostname === tabContext.rootHostname) {
- pageStore.rawURL = tabContext.rawURL;
- pageStore.normalURL = normalURL;
- this.updateTitle(tabId);
- this.pageStoresToken = Date.now();
- return pageStore;
+ && pageStore.pageHostname === tabContext.rootHostname) {
+ pageStore.rawURL = tabContext.rawURL;
+ pageStore.normalURL = normalURL;
+ this.updateTitle(tabId);
+ this.pageStoresToken = Date.now();
+ return pageStore;
}
// We won't be reusing this page store.
this.unbindTabFromPageStats(tabId);
- }
+ }
- // Try to resurrect first.
- pageStore = this.resurrectPageStore(tabId, normalURL);
- if (pageStore === null) {
+ // Try to resurrect first.
+ pageStore = this.resurrectPageStore(tabId, normalURL);
+ if (pageStore === null) {
pageStore = this.pageStoreFactory(tabContext);
- }
- this.pageStores[tabId] = pageStore;
- this.updateTitle(tabId);
- this.pageStoresToken = Date.now();
+ }
+ this.pageStores[tabId] = pageStore;
+ this.updateTitle(tabId);
+ this.pageStoresToken = Date.now();
- return pageStore;
+ return pageStore;
};
ηm.unbindTabFromPageStats = function (tabId) {
- if (vAPI.isBehindTheSceneTabId(tabId)) {
+ if (vAPI.isBehindTheSceneTabId(tabId)) {
return;
- }
+ }
- let pageStore = this.pageStores[tabId] || null;
- if (pageStore === null) {
+ let pageStore = this.pageStores[tabId] || null;
+ if (pageStore === null) {
return;
- }
+ }
- delete this.pageStores[tabId];
- this.pageStoresToken = Date.now();
+ delete this.pageStores[tabId];
+ this.pageStoresToken = Date.now();
- if (pageStore.incinerationTimer) {
+ if (pageStore.incinerationTimer) {
clearTimeout(pageStore.incinerationTimer);
pageStore.incinerationTimer = null;
- }
+ }
- if (this.pageStoreCemetery.hasOwnProperty(tabId) === false) {
+ if (this.pageStoreCemetery.hasOwnProperty(tabId) === false) {
this.pageStoreCemetery[tabId] = {};
- }
- let pageStoreCrypt = this.pageStoreCemetery[tabId];
+ }
+ let pageStoreCrypt = this.pageStoreCemetery[tabId];
- let pageURL = pageStore.pageUrl;
- pageStoreCrypt[pageURL] = pageStore;
+ let pageURL = pageStore.pageUrl;
+ pageStoreCrypt[pageURL] = pageStore;
- pageStore.incinerationTimer =
- vAPI.setTimeout(this.incineratePageStore.bind(this, tabId, pageURL),
- 4 * 60 * 1000);
+ pageStore.incinerationTimer =
+ vAPI.setTimeout(this.incineratePageStore.bind(this, tabId, pageURL),
+ 4 * 60 * 1000);
};
ηm.resurrectPageStore = function (tabId, pageURL) {
- if (this.pageStoreCemetery.hasOwnProperty(tabId) === false) {
+ if (this.pageStoreCemetery.hasOwnProperty(tabId) === false) {
return null;
- }
+ }
- let pageStoreCrypt = this.pageStoreCemetery[tabId];
+ let pageStoreCrypt = this.pageStoreCemetery[tabId];
- if (pageStoreCrypt.hasOwnProperty(pageURL) === false) {
+ if (pageStoreCrypt.hasOwnProperty(pageURL) === false) {
return null;
- }
+ }
- let pageStore = pageStoreCrypt[pageURL];
+ let pageStore = pageStoreCrypt[pageURL];
- if (pageStore.incinerationTimer !== null) {
+ if (pageStore.incinerationTimer !== null) {
clearTimeout(pageStore.incinerationTimer);
pageStore.incinerationTimer = null;
- }
+ }
- delete pageStoreCrypt[pageURL];
- if (Object.keys(pageStoreCrypt).length === 0) {
+ delete pageStoreCrypt[pageURL];
+ if (Object.keys(pageStoreCrypt).length === 0) {
delete this.pageStoreCemetery[tabId];
- }
+ }
- return pageStore;
+ return pageStore;
};
ηm.incineratePageStore = function (tabId, pageURL) {
- if (this.pageStoreCemetery.hasOwnProperty(tabId) === false) {
+ if (this.pageStoreCemetery.hasOwnProperty(tabId) === false) {
return;
- }
+ }
- let pageStoreCrypt = this.pageStoreCemetery[tabId];
+ let pageStoreCrypt = this.pageStoreCemetery[tabId];
- if (pageStoreCrypt.hasOwnProperty(pageURL) === false) {
+ if (pageStoreCrypt.hasOwnProperty(pageURL) === false) {
return;
- }
+ }
- let pageStore = pageStoreCrypt[pageURL];
- if (pageStore.incinerationTimer !== null) {
+ let pageStore = pageStoreCrypt[pageURL];
+ if (pageStore.incinerationTimer !== null) {
clearTimeout(pageStore.incinerationTimer);
pageStore.incinerationTimer = null;
- }
+ }
- delete pageStoreCrypt[pageURL];
+ delete pageStoreCrypt[pageURL];
- if (Object.keys(pageStoreCrypt).length === 0) {
+ if (Object.keys(pageStoreCrypt).length === 0) {
delete this.pageStoreCemetery[tabId];
- }
+ }
- pageStore.dispose();
+ pageStore.dispose();
};
ηm.pageStoreFromTabId = function (tabId) {
- return this.pageStores[tabId] || null;
+ return this.pageStores[tabId] || null;
};
// Never return null
ηm.mustPageStoreFromTabId = function (tabId) {
- return this.pageStores[tabId] || this.pageStores[vAPI.noTabId];
+ return this.pageStores[tabId] || this.pageStores[vAPI.noTabId];
};
ηm.forceReload = function (tabId, bypassCache) {
- vAPI.tabs.reload(tabId, bypassCache);
+ vAPI.tabs.reload(tabId, bypassCache);
};
// Update badge
@@ -595,9 +595,9 @@
// ηMatrix: does it matter to us?
ηm.updateBadgeAsync = (function () {
- let tabIdToTimer = Object.create(null);
+ let tabIdToTimer = Object.create(null);
- let updateBadge = function (tabId) {
+ let updateBadge = function (tabId) {
delete tabIdToTimer[tabId];
let iconId = null;
@@ -605,81 +605,81 @@
let pageStore = this.pageStoreFromTabId(tabId);
if (pageStore !== null) {
- let total = pageStore.perLoadAllowedRequestCount +
+ let total = pageStore.perLoadAllowedRequestCount +
pageStore.perLoadBlockedRequestCount;
- if (total) {
+ if (total) {
let squareSize = 19;
let greenSize = squareSize *
- Math.sqrt(pageStore.perLoadAllowedRequestCount / total);
+ Math.sqrt(pageStore.perLoadAllowedRequestCount / total);
iconId = greenSize < squareSize/2 ?
- Math.ceil(greenSize) :
- Math.floor(greenSize);
- }
+ Math.ceil(greenSize) :
+ Math.floor(greenSize);
+ }
- if (this.userSettings.iconBadgeEnabled
- && pageStore.perLoadBlockedRequestCount !== 0) {
+ if (this.userSettings.iconBadgeEnabled
+ && pageStore.perLoadBlockedRequestCount !== 0) {
badgeStr =
- this.formatCount(pageStore.perLoadBlockedRequestCount);
- }
+ this.formatCount(pageStore.perLoadBlockedRequestCount);
+ }
}
vAPI.setIcon(tabId, iconId, badgeStr);
- };
+ };
- return function (tabId) {
+ return function (tabId) {
if (tabIdToTimer[tabId]) {
- return;
+ return;
}
if (vAPI.isBehindTheSceneTabId(tabId)) {
- return;
+ return;
}
tabIdToTimer[tabId] =
- vAPI.setTimeout(updateBadge.bind(this, tabId), 750);
- };
+ vAPI.setTimeout(updateBadge.bind(this, tabId), 750);
+ };
})();
ηm.updateTitle = (function () {
- let tabIdToTimer = Object.create(null);
- let tabIdToTryCount = Object.create(null);
- let delay = 499;
+ let tabIdToTimer = Object.create(null);
+ let tabIdToTryCount = Object.create(null);
+ let delay = 499;
- let tryNoMore = function (tabId) {
+ let tryNoMore = function (tabId) {
delete tabIdToTryCount[tabId];
- };
+ };
- let tryAgain = function (tabId) {
+ let tryAgain = function (tabId) {
let count = tabIdToTryCount[tabId];
if (count === undefined) {
- return false;
+ return false;
}
if (count === 1) {
- delete tabIdToTryCount[tabId];
- return false;
+ delete tabIdToTryCount[tabId];
+ return false;
}
tabIdToTryCount[tabId] = count - 1;
tabIdToTimer[tabId] =
- vAPI.setTimeout(updateTitle.bind(ηm, tabId), delay);
+ vAPI.setTimeout(updateTitle.bind(ηm, tabId), delay);
return true;
- };
+ };
- let onTabReady = function (tabId, tab) {
+ let onTabReady = function (tabId, tab) {
if (!tab) {
- return tryNoMore(tabId);
+ return tryNoMore(tabId);
}
let pageStore = this.pageStoreFromTabId(tabId);
if (pageStore === null) {
- return tryNoMore(tabId);
+ return tryNoMore(tabId);
}
if (!tab.title && tryAgain(tabId)) {
- return;
+ return;
}
// https://github.com/gorhill/uMatrix/issues/225
@@ -688,67 +688,67 @@
pageStore.title = tab.title || tab.url || '';
this.pageStoresToken = Date.now();
if (settled || !tryAgain(tabId)) {
- tryNoMore(tabId);
+ tryNoMore(tabId);
}
- };
+ };
- let updateTitle = function (tabId) {
+ let updateTitle = function (tabId) {
delete tabIdToTimer[tabId];
vAPI.tabs.get(tabId, onTabReady.bind(this, tabId));
- };
+ };
- return function (tabId) {
+ return function (tabId) {
if (vAPI.isBehindTheSceneTabId(tabId)) {
- return;
+ return;
}
if (tabIdToTimer[tabId]) {
- clearTimeout(tabIdToTimer[tabId]);
+ clearTimeout(tabIdToTimer[tabId]);
}
tabIdToTimer[tabId] =
- vAPI.setTimeout(updateTitle.bind(this, tabId), delay);
+ vAPI.setTimeout(updateTitle.bind(this, tabId), delay);
tabIdToTryCount[tabId] = 5;
- };
+ };
})();
// Stale page store entries janitor
// https://github.com/chrisaljoudi/uBlock/issues/455
(function () {
- let cleanupPeriod = 7 * 60 * 1000;
- let cleanupSampleAt = 0;
- let cleanupSampleSize = 11;
+ let cleanupPeriod = 7 * 60 * 1000;
+ let cleanupSampleAt = 0;
+ let cleanupSampleSize = 11;
- let cleanup = function () {
+ let cleanup = function () {
let tabIds = Object.keys(ηm.pageStores).sort();
let checkTab = function(tabId) {
- vAPI.tabs.get(tabId, function (tab) {
+ vAPI.tabs.get(tabId, function (tab) {
if (!tab) {
- ηm.unbindTabFromPageStats(tabId);
+ ηm.unbindTabFromPageStats(tabId);
}
- });
+ });
};
if (cleanupSampleAt >= tabIds.length) {
- cleanupSampleAt = 0;
+ cleanupSampleAt = 0;
}
let tabId;
let n =
- Math.min(cleanupSampleAt + cleanupSampleSize, tabIds.length);
+ Math.min(cleanupSampleAt + cleanupSampleSize, tabIds.length);
for (let i=cleanupSampleAt; i<n; i++) {
- tabId = tabIds[i];
- if (vAPI.isBehindTheSceneTabId(tabId)) {
+ tabId = tabIds[i];
+ if (vAPI.isBehindTheSceneTabId(tabId)) {
continue;
- }
- checkTab(tabId);
+ }
+ checkTab(tabId);
}
cleanupSampleAt = n;
vAPI.setTimeout(cleanup, cleanupPeriod);
- };
+ };
- vAPI.setTimeout(cleanup, cleanupPeriod);
+ vAPI.setTimeout(cleanup, cleanupPeriod);
})();
})();
diff --git a/js/traffic.js b/js/traffic.js
index aae4070..e2d6a3e 100644
--- a/js/traffic.js
+++ b/js/traffic.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://notabug.org/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
diff --git a/js/udom.js b/js/udom.js
index 848351e..855861d 100644
--- a/js/udom.js
+++ b/js/udom.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -26,8 +26,6 @@
'use strict';
-/******************************************************************************/
-
// It's just a silly, minimalist DOM framework: this allows me to not rely
// on jQuery. jQuery contains way too much stuff than I need, and as per
// Opera rules, I am not allowed to use a cut-down version of jQuery. So
@@ -288,7 +286,8 @@ var uDom = (function () {
let i = this.nodes.length;
while (i--) {
let cn = this.nodes[i];
- if ((p = cn.parentNode)) {
+ let p = cn.parentNode;
+ if (p) {
p.removeChild(cn);
}
}
diff --git a/js/uritools.js b/js/uritools.js
index 770d54a..9ec928f 100644
--- a/js/uritools.js
+++ b/js/uritools.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -37,500 +37,500 @@ Naming convention from https://en.wikipedia.org/wiki/URI_scheme#Examples
ηMatrix.URI = (function() {
- /******************************************************************************/
-
- // Favorite regex tool: http://regex101.com/
-
- // Ref: <http://tools.ietf.org/html/rfc3986#page-50>
- // I removed redundant capture groups: capture less = peform faster. See
- // <http://jsperf.com/old-uritools-vs-new-uritools>
- // Performance improvements welcomed.
- // jsperf: <http://jsperf.com/old-uritools-vs-new-uritools>
- var reRFC3986 = /^([^:\/?#]+:)?(\/\/[^\/?#]*)?([^?#]*)(\?[^#]*)?(#.*)?/;
-
- // Derived
- var reSchemeFromURI = /^[^:\/?#]+:/;
- var reAuthorityFromURI = /^(?:[^:\/?#]+:)?(\/\/[^\/?#]+)/;
- var reOriginFromURI = /^(?:[^:\/?#]+:)?(?:\/\/[^\/?#]+)/;
- var reCommonHostnameFromURL = /^https?:\/\/([0-9a-z_][0-9a-z._-]*[0-9a-z])\//;
- var rePathFromURI = /^(?:[^:\/?#]+:)?(?:\/\/[^\/?#]*)?([^?#]*)/;
- var reMustNormalizeHostname = /[^0-9a-z._-]/;
-
- // These are to parse authority field, not parsed by above official regex
- // IPv6 is seen as an exception: a non-compatible IPv6 is first tried, and
- // if it fails, the IPv6 compatible regex istr used. This helps
- // peformance by avoiding the use of a too complicated regex first.
-
- // https://github.com/gorhill/httpswitchboard/issues/211
- // "While a hostname may not contain other characters, such as the
- // "underscore character (_), other DNS names may contain the underscore"
- var reHostPortFromAuthority = /^(?:[^@]*@)?([^:]*)(:\d*)?$/;
- var reIPv6PortFromAuthority = /^(?:[^@]*@)?(\[[0-9a-f:]*\])(:\d*)?$/i;
-
- var reHostFromNakedAuthority = /^[0-9a-z._-]+[0-9a-z]$/i;
- var reHostFromAuthority = /^(?:[^@]*@)?([^:]+)(?::\d*)?$/;
- var reIPv6FromAuthority = /^(?:[^@]*@)?(\[[0-9a-f:]+\])(?::\d*)?$/i;
-
- // Coarse (but fast) tests
- var reValidHostname = /^([a-z\d]+(-*[a-z\d]+)*)(\.[a-z\d]+(-*[a-z\d])*)*$/;
- var reIPAddressNaive = /^\d+\.\d+\.\d+\.\d+$|^\[[\da-zA-Z:]+\]$/;
-
- // Accurate tests
- // Source.: http://stackoverflow.com/questions/5284147/validating-ipv4-addresses-with-regexp/5284410#5284410
- //var reIPv4 = /^((25[0-5]|2[0-4]\d|[01]?\d\d?)(\.|$)){4}/;
-
- // Source: http://forums.intermapper.com/viewtopic.php?p=1096#1096
- //var reIPv6 = /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/;
-
- /******************************************************************************/
-
- var reset = function(o) {
- o.scheme = '';
- o.hostname = '';
- o._ipv4 = undefined;
- o._ipv6 = undefined;
- o.port = '';
- o.path = '';
- o.query = '';
- o.fragment = '';
- return o;
- };
-
- var resetAuthority = function(o) {
- o.hostname = '';
- o._ipv4 = undefined;
- o._ipv6 = undefined;
- o.port = '';
- return o;
- };
-
- /******************************************************************************/
-
- // This will be exported
-
- var URI = {
- scheme: '',
- authority: '',
- hostname: '',
- _ipv4: undefined,
- _ipv6: undefined,
- port: '',
- domain: undefined,
- path: '',
- query: '',
- fragment: '',
- schemeBit: (1 << 0),
- userBit: (1 << 1),
- passwordBit: (1 << 2),
- hostnameBit: (1 << 3),
- portBit: (1 << 4),
- pathBit: (1 << 5),
- queryBit: (1 << 6),
- fragmentBit: (1 << 7),
- allBits: (0xFFFF)
- };
-
- URI.authorityBit = (URI.userBit | URI.passwordBit | URI.hostnameBit | URI.portBit);
- URI.normalizeBits = (URI.schemeBit | URI.hostnameBit | URI.pathBit | URI.queryBit);
-
- /******************************************************************************/
-
- // See: https://en.wikipedia.org/wiki/URI_scheme#Examples
- // URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
- //
- // foo://example.com:8042/over/there?name=ferret#nose
- // \_/ \______________/\_________/ \_________/ \__/
- // | | | | |
- // scheme authority path query fragment
- // | _____________________|__
- // / \ / \
- // urn:example:animal:ferret:nose
-
- URI.set = function(uri) {
- if ( uri === undefined ) {
- return reset(URI);
- }
- var matches = reRFC3986.exec(uri);
- if ( !matches ) {
- return reset(URI);
- }
- this.scheme = matches[1] !== undefined ? matches[1].slice(0, -1) : '';
- this.authority = matches[2] !== undefined ? matches[2].slice(2).toLowerCase() : '';
- this.path = matches[3] !== undefined ? matches[3] : '';
-
- // <http://tools.ietf.org/html/rfc3986#section-6.2.3>
- // "In general, a URI that uses the generic syntax for authority
- // "with an empty path should be normalized to a path of '/'."
- if ( this.authority !== '' && this.path === '' ) {
- this.path = '/';
- }
- this.query = matches[4] !== undefined ? matches[4].slice(1) : '';
- this.fragment = matches[5] !== undefined ? matches[5].slice(1) : '';
-
- // Assume very simple authority, i.e. just a hostname (highest likelihood
- // case for ηMatrix)
- if ( reHostFromNakedAuthority.test(this.authority) ) {
- this.hostname = this.authority;
- this.port = '';
- return this;
- }
- // Authority contains more than just a hostname
- matches = reHostPortFromAuthority.exec(this.authority);
- if ( !matches ) {
- matches = reIPv6PortFromAuthority.exec(this.authority);
- if ( !matches ) {
- return resetAuthority(URI);
- }
- }
- this.hostname = matches[1] !== undefined ? matches[1] : '';
- // http://en.wikipedia.org/wiki/FQDN
- if ( this.hostname.slice(-1) === '.' ) {
- this.hostname = this.hostname.slice(0, -1);
- }
- this.port = matches[2] !== undefined ? matches[2].slice(1) : '';
- return this;
- };
-
- /******************************************************************************/
-
- // URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
- //
- // foo://example.com:8042/over/there?name=ferret#nose
- // \_/ \______________/\_________/ \_________/ \__/
- // | | | | |
- // scheme authority path query fragment
- // | _____________________|__
- // / \ / \
- // urn:example:animal:ferret:nose
-
- URI.assemble = function(bits) {
- if ( bits === undefined ) {
- bits = this.allBits;
- }
- var s = [];
- if ( this.scheme && (bits & this.schemeBit) ) {
- s.push(this.scheme, ':');
- }
- if ( this.hostname && (bits & this.hostnameBit) ) {
- s.push('//', this.hostname);
- }
- if ( this.port && (bits & this.portBit) ) {
- s.push(':', this.port);
- }
- if ( this.path && (bits & this.pathBit) ) {
- s.push(this.path);
- }
- if ( this.query && (bits & this.queryBit) ) {
- s.push('?', this.query);
- }
- if ( this.fragment && (bits & this.fragmentBit) ) {
- s.push('#', this.fragment);
- }
- return s.join('');
- };
+/******************************************************************************/
- /******************************************************************************/
+// Favorite regex tool: http://regex101.com/
+
+// Ref: <http://tools.ietf.org/html/rfc3986#page-50>
+// I removed redundant capture groups: capture less = peform faster. See
+// <http://jsperf.com/old-uritools-vs-new-uritools>
+// Performance improvements welcomed.
+// jsperf: <http://jsperf.com/old-uritools-vs-new-uritools>
+var reRFC3986 = /^([^:\/?#]+:)?(\/\/[^\/?#]*)?([^?#]*)(\?[^#]*)?(#.*)?/;
+
+// Derived
+var reSchemeFromURI = /^[^:\/?#]+:/;
+var reAuthorityFromURI = /^(?:[^:\/?#]+:)?(\/\/[^\/?#]+)/;
+var reOriginFromURI = /^(?:[^:\/?#]+:)?(?:\/\/[^\/?#]+)/;
+var reCommonHostnameFromURL = /^https?:\/\/([0-9a-z_][0-9a-z._-]*[0-9a-z])\//;
+var rePathFromURI = /^(?:[^:\/?#]+:)?(?:\/\/[^\/?#]*)?([^?#]*)/;
+var reMustNormalizeHostname = /[^0-9a-z._-]/;
+
+// These are to parse authority field, not parsed by above official regex
+// IPv6 is seen as an exception: a non-compatible IPv6 is first tried, and
+// if it fails, the IPv6 compatible regex istr used. This helps
+// peformance by avoiding the use of a too complicated regex first.
+
+// https://github.com/gorhill/httpswitchboard/issues/211
+// "While a hostname may not contain other characters, such as the
+// "underscore character (_), other DNS names may contain the underscore"
+var reHostPortFromAuthority = /^(?:[^@]*@)?([^:]*)(:\d*)?$/;
+var reIPv6PortFromAuthority = /^(?:[^@]*@)?(\[[0-9a-f:]*\])(:\d*)?$/i;
+
+var reHostFromNakedAuthority = /^[0-9a-z._-]+[0-9a-z]$/i;
+var reHostFromAuthority = /^(?:[^@]*@)?([^:]+)(?::\d*)?$/;
+var reIPv6FromAuthority = /^(?:[^@]*@)?(\[[0-9a-f:]+\])(?::\d*)?$/i;
+
+// Coarse (but fast) tests
+var reValidHostname = /^([a-z\d]+(-*[a-z\d]+)*)(\.[a-z\d]+(-*[a-z\d])*)*$/;
+var reIPAddressNaive = /^\d+\.\d+\.\d+\.\d+$|^\[[\da-zA-Z:]+\]$/;
+
+// Accurate tests
+// Source.: http://stackoverflow.com/questions/5284147/validating-ipv4-addresses-with-regexp/5284410#5284410
+//var reIPv4 = /^((25[0-5]|2[0-4]\d|[01]?\d\d?)(\.|$)){4}/;
+
+// Source: http://forums.intermapper.com/viewtopic.php?p=1096#1096
+//var reIPv6 = /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/;
- URI.originFromURI = function(uri) {
- var matches = reOriginFromURI.exec(uri);
- return matches !== null ? matches[0].toLowerCase() : '';
- };
+/******************************************************************************/
- /******************************************************************************/
+var reset = function(o) {
+ o.scheme = '';
+ o.hostname = '';
+ o._ipv4 = undefined;
+ o._ipv6 = undefined;
+ o.port = '';
+ o.path = '';
+ o.query = '';
+ o.fragment = '';
+ return o;
+};
+
+var resetAuthority = function(o) {
+ o.hostname = '';
+ o._ipv4 = undefined;
+ o._ipv6 = undefined;
+ o.port = '';
+ return o;
+};
- URI.schemeFromURI = function(uri) {
- var matches = reSchemeFromURI.exec(uri);
- if ( matches === null ) {
- return '';
- }
- return matches[0].slice(0, -1).toLowerCase();
- };
+/******************************************************************************/
- /******************************************************************************/
+// This will be exported
+
+var URI = {
+ scheme: '',
+ authority: '',
+ hostname: '',
+ _ipv4: undefined,
+ _ipv6: undefined,
+ port: '',
+ domain: undefined,
+ path: '',
+ query: '',
+ fragment: '',
+ schemeBit: (1 << 0),
+ userBit: (1 << 1),
+ passwordBit: (1 << 2),
+ hostnameBit: (1 << 3),
+ portBit: (1 << 4),
+ pathBit: (1 << 5),
+ queryBit: (1 << 6),
+ fragmentBit: (1 << 7),
+ allBits: (0xFFFF)
+};
+
+URI.authorityBit = (URI.userBit | URI.passwordBit | URI.hostnameBit | URI.portBit);
+URI.normalizeBits = (URI.schemeBit | URI.hostnameBit | URI.pathBit | URI.queryBit);
- URI.isNetworkScheme = function(scheme) {
- return this.reNetworkScheme.test(scheme);
- };
+/******************************************************************************/
- URI.reNetworkScheme = /^(?:https?|wss?|ftps?)\b/;
+// See: https://en.wikipedia.org/wiki/URI_scheme#Examples
+// URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
+//
+// foo://example.com:8042/over/there?name=ferret#nose
+// \_/ \______________/\_________/ \_________/ \__/
+// | | | | |
+// scheme authority path query fragment
+// | _____________________|__
+// / \ / \
+// urn:example:animal:ferret:nose
+
+URI.set = function(uri) {
+ if ( uri === undefined ) {
+ return reset(URI);
+ }
+ var matches = reRFC3986.exec(uri);
+ if ( !matches ) {
+ return reset(URI);
+ }
+ this.scheme = matches[1] !== undefined ? matches[1].slice(0, -1) : '';
+ this.authority = matches[2] !== undefined ? matches[2].slice(2).toLowerCase() : '';
+ this.path = matches[3] !== undefined ? matches[3] : '';
+
+ // <http://tools.ietf.org/html/rfc3986#section-6.2.3>
+ // "In general, a URI that uses the generic syntax for authority
+ // "with an empty path should be normalized to a path of '/'."
+ if ( this.authority !== '' && this.path === '' ) {
+ this.path = '/';
+ }
+ this.query = matches[4] !== undefined ? matches[4].slice(1) : '';
+ this.fragment = matches[5] !== undefined ? matches[5].slice(1) : '';
+
+ // Assume very simple authority, i.e. just a hostname (highest likelihood
+ // case for ηMatrix)
+ if ( reHostFromNakedAuthority.test(this.authority) ) {
+ this.hostname = this.authority;
+ this.port = '';
+ return this;
+ }
+ // Authority contains more than just a hostname
+ matches = reHostPortFromAuthority.exec(this.authority);
+ if ( !matches ) {
+ matches = reIPv6PortFromAuthority.exec(this.authority);
+ if ( !matches ) {
+ return resetAuthority(URI);
+ }
+ }
+ this.hostname = matches[1] !== undefined ? matches[1] : '';
+ // http://en.wikipedia.org/wiki/FQDN
+ if ( this.hostname.slice(-1) === '.' ) {
+ this.hostname = this.hostname.slice(0, -1);
+ }
+ this.port = matches[2] !== undefined ? matches[2].slice(1) : '';
+ return this;
+};
- /******************************************************************************/
+/******************************************************************************/
- URI.isSecureScheme = function(scheme) {
- return this.reSecureScheme.test(scheme);
- };
+// URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
+//
+// foo://example.com:8042/over/there?name=ferret#nose
+// \_/ \______________/\_________/ \_________/ \__/
+// | | | | |
+// scheme authority path query fragment
+// | _____________________|__
+// / \ / \
+// urn:example:animal:ferret:nose
+
+URI.assemble = function(bits) {
+ if ( bits === undefined ) {
+ bits = this.allBits;
+ }
+ var s = [];
+ if ( this.scheme && (bits & this.schemeBit) ) {
+ s.push(this.scheme, ':');
+ }
+ if ( this.hostname && (bits & this.hostnameBit) ) {
+ s.push('//', this.hostname);
+ }
+ if ( this.port && (bits & this.portBit) ) {
+ s.push(':', this.port);
+ }
+ if ( this.path && (bits & this.pathBit) ) {
+ s.push(this.path);
+ }
+ if ( this.query && (bits & this.queryBit) ) {
+ s.push('?', this.query);
+ }
+ if ( this.fragment && (bits & this.fragmentBit) ) {
+ s.push('#', this.fragment);
+ }
+ return s.join('');
+};
- URI.reSecureScheme = /^(?:https|wss|ftps)\b/;
+/******************************************************************************/
- /******************************************************************************/
+URI.originFromURI = function(uri) {
+ var matches = reOriginFromURI.exec(uri);
+ return matches !== null ? matches[0].toLowerCase() : '';
+};
- URI.authorityFromURI = function(uri) {
- var matches = reAuthorityFromURI.exec(uri);
- if ( !matches ) {
- return '';
- }
- return matches[1].slice(2).toLowerCase();
- };
+/******************************************************************************/
- /******************************************************************************/
+URI.schemeFromURI = function(uri) {
+ var matches = reSchemeFromURI.exec(uri);
+ if ( matches === null ) {
+ return '';
+ }
+ return matches[0].slice(0, -1).toLowerCase();
+};
- // The most used function, so it better be fast.
+/******************************************************************************/
- // https://github.com/gorhill/uBlock/issues/1559
- // See http://en.wikipedia.org/wiki/FQDN
- // https://bugzilla.mozilla.org/show_bug.cgi?id=1360285
- // Revisit punycode dependency when above issue is fixed in Firefox.
+URI.isNetworkScheme = function(scheme) {
+ return this.reNetworkScheme.test(scheme);
+};
- URI.hostnameFromURI = function(uri) {
- var matches = reCommonHostnameFromURL.exec(uri);
- if ( matches !== null ) { return matches[1]; }
- matches = reAuthorityFromURI.exec(uri);
- if ( matches === null ) { return ''; }
- var authority = matches[1].slice(2);
- // Assume very simple authority (most common case for ηBlock)
- if ( reHostFromNakedAuthority.test(authority) ) {
- return authority.toLowerCase();
- }
- matches = reHostFromAuthority.exec(authority);
- if ( matches === null ) {
- matches = reIPv6FromAuthority.exec(authority);
- if ( matches === null ) { return ''; }
- }
- var hostname = matches[1];
- while ( hostname.endsWith('.') ) {
- hostname = hostname.slice(0, -1);
- }
- if ( reMustNormalizeHostname.test(hostname) ) {
- hostname = punycode.toASCII(hostname.toLowerCase());
- }
- return hostname;
- };
+URI.reNetworkScheme = /^(?:https?|wss?|ftps?)\b/;
- /******************************************************************************/
+/******************************************************************************/
- URI.domainFromHostname = function(hostname) {
- // Try to skip looking up the PSL database
- var entry = domainCache.get(hostname);
- if ( entry !== undefined ) {
- entry.tstamp = Date.now();
- return entry.domain;
- }
- // Meh.. will have to search it
- if ( reIPAddressNaive.test(hostname) === false ) {
- return domainCacheAdd(hostname, psl.getDomain(hostname));
- }
- return domainCacheAdd(hostname, hostname);
- };
+URI.isSecureScheme = function(scheme) {
+ return this.reSecureScheme.test(scheme);
+};
- URI.domain = function() {
- return this.domainFromHostname(this.hostname);
- };
+URI.reSecureScheme = /^(?:https|wss|ftps)\b/;
- // It is expected that there is higher-scoped `publicSuffixList` lingering
- // somewhere. Cache it. See <https://github.com/gorhill/publicsuffixlist.js>.
- var psl = publicSuffixList;
+/******************************************************************************/
- /******************************************************************************/
+URI.authorityFromURI = function(uri) {
+ var matches = reAuthorityFromURI.exec(uri);
+ if ( !matches ) {
+ return '';
+ }
+ return matches[1].slice(2).toLowerCase();
+};
- URI.pathFromURI = function(uri) {
- var matches = rePathFromURI.exec(uri);
- return matches !== null ? matches[1] : '';
- };
+/******************************************************************************/
- /******************************************************************************/
+// The most used function, so it better be fast.
+
+// https://github.com/gorhill/uBlock/issues/1559
+// See http://en.wikipedia.org/wiki/FQDN
+// https://bugzilla.mozilla.org/show_bug.cgi?id=1360285
+// Revisit punycode dependency when above issue is fixed in Firefox.
+
+URI.hostnameFromURI = function(uri) {
+ var matches = reCommonHostnameFromURL.exec(uri);
+ if ( matches !== null ) { return matches[1]; }
+ matches = reAuthorityFromURI.exec(uri);
+ if ( matches === null ) { return ''; }
+ var authority = matches[1].slice(2);
+ // Assume very simple authority (most common case for ηBlock)
+ if ( reHostFromNakedAuthority.test(authority) ) {
+ return authority.toLowerCase();
+ }
+ matches = reHostFromAuthority.exec(authority);
+ if ( matches === null ) {
+ matches = reIPv6FromAuthority.exec(authority);
+ if ( matches === null ) { return ''; }
+ }
+ var hostname = matches[1];
+ while ( hostname.endsWith('.') ) {
+ hostname = hostname.slice(0, -1);
+ }
+ if ( reMustNormalizeHostname.test(hostname) ) {
+ hostname = punycode.toASCII(hostname.toLowerCase());
+ }
+ return hostname;
+};
- // Trying to alleviate the worries of looking up too often the domain name from
- // a hostname. With a cache, uBlock benefits given that it deals with a
- // specific set of hostnames within a narrow time span -- in other words, I
- // believe probability of cache hit are high in uBlock.
+/******************************************************************************/
- var domainCache = new Map();
- var domainCacheCountLowWaterMark = 75;
- var domainCacheCountHighWaterMark = 100;
- var domainCacheEntryJunkyard = [];
- var domainCacheEntryJunkyardMax = domainCacheCountHighWaterMark - domainCacheCountLowWaterMark;
+URI.domainFromHostname = function(hostname) {
+ // Try to skip looking up the PSL database
+ var entry = domainCache.get(hostname);
+ if ( entry !== undefined ) {
+ entry.tstamp = Date.now();
+ return entry.domain;
+ }
+ // Meh.. will have to search it
+ if ( reIPAddressNaive.test(hostname) === false ) {
+ return domainCacheAdd(hostname, psl.getDomain(hostname));
+ }
+ return domainCacheAdd(hostname, hostname);
+};
+
+URI.domain = function() {
+ return this.domainFromHostname(this.hostname);
+};
+
+// It is expected that there is higher-scoped `publicSuffixList` lingering
+// somewhere. Cache it. See <https://github.com/gorhill/publicsuffixlist.js>.
+var psl = publicSuffixList;
- var DomainCacheEntry = function(domain) {
- this.init(domain);
- };
+/******************************************************************************/
- DomainCacheEntry.prototype.init = function(domain) {
- this.domain = domain;
- this.tstamp = Date.now();
- return this;
- };
+URI.pathFromURI = function(uri) {
+ var matches = rePathFromURI.exec(uri);
+ return matches !== null ? matches[1] : '';
+};
- DomainCacheEntry.prototype.dispose = function() {
- this.domain = '';
- if ( domainCacheEntryJunkyard.length < domainCacheEntryJunkyardMax ) {
- domainCacheEntryJunkyard.push(this);
- }
- };
+/******************************************************************************/
- var domainCacheEntryFactory = function(domain) {
- var entry = domainCacheEntryJunkyard.pop();
- if ( entry ) {
- return entry.init(domain);
- }
- return new DomainCacheEntry(domain);
- };
-
- var domainCacheAdd = function(hostname, domain) {
- var entry = domainCache.get(hostname);
- if ( entry !== undefined ) {
- entry.tstamp = Date.now();
- } else {
- domainCache.set(hostname, domainCacheEntryFactory(domain));
- if ( domainCache.size === domainCacheCountHighWaterMark ) {
- domainCachePrune();
- }
- }
- return domain;
- };
-
- var domainCacheEntrySort = function(a, b) {
- return domainCache.get(b).tstamp - domainCache.get(a).tstamp;
- };
-
- var domainCachePrune = function() {
- var hostnames = Array.from(domainCache.keys())
- .sort(domainCacheEntrySort)
- .slice(domainCacheCountLowWaterMark);
- var i = hostnames.length;
- var hostname;
- while ( i-- ) {
- hostname = hostnames[i];
- domainCache.get(hostname).dispose();
- domainCache.delete(hostname);
- }
- };
+ // Trying to alleviate the worries of looking up too often the domain name from
+// a hostname. With a cache, uBlock benefits given that it deals with a
+// specific set of hostnames within a narrow time span -- in other words, I
+// believe probability of cache hit are high in uBlock.
+
+var domainCache = new Map();
+var domainCacheCountLowWaterMark = 75;
+var domainCacheCountHighWaterMark = 100;
+var domainCacheEntryJunkyard = [];
+var domainCacheEntryJunkyardMax = domainCacheCountHighWaterMark - domainCacheCountLowWaterMark;
+
+var DomainCacheEntry = function(domain) {
+ this.init(domain);
+};
+
+DomainCacheEntry.prototype.init = function(domain) {
+ this.domain = domain;
+ this.tstamp = Date.now();
+ return this;
+};
+
+DomainCacheEntry.prototype.dispose = function() {
+ this.domain = '';
+ if ( domainCacheEntryJunkyard.length < domainCacheEntryJunkyardMax ) {
+ domainCacheEntryJunkyard.push(this);
+ }
+};
+
+var domainCacheEntryFactory = function(domain) {
+ var entry = domainCacheEntryJunkyard.pop();
+ if ( entry ) {
+ return entry.init(domain);
+ }
+ return new DomainCacheEntry(domain);
+};
+
+var domainCacheAdd = function(hostname, domain) {
+ var entry = domainCache.get(hostname);
+ if ( entry !== undefined ) {
+ entry.tstamp = Date.now();
+ } else {
+ domainCache.set(hostname, domainCacheEntryFactory(domain));
+ if ( domainCache.size === domainCacheCountHighWaterMark ) {
+ domainCachePrune();
+ }
+ }
+ return domain;
+};
+
+var domainCacheEntrySort = function(a, b) {
+ return domainCache.get(b).tstamp - domainCache.get(a).tstamp;
+};
+
+var domainCachePrune = function() {
+ var hostnames = Array.from(domainCache.keys())
+ .sort(domainCacheEntrySort)
+ .slice(domainCacheCountLowWaterMark);
+ var i = hostnames.length;
+ var hostname;
+ while ( i-- ) {
+ hostname = hostnames[i];
+ domainCache.get(hostname).dispose();
+ domainCache.delete(hostname);
+ }
+};
+
+var domainCacheReset = function() {
+ domainCache.clear();
+};
+
+psl.onChanged.addListener(domainCacheReset);
- var domainCacheReset = function() {
- domainCache.clear();
- };
+/******************************************************************************/
- psl.onChanged.addListener(domainCacheReset);
+URI.domainFromURI = function(uri) {
+ if ( !uri ) {
+ return '';
+ }
+ return this.domainFromHostname(this.hostnameFromURI(uri));
+};
- /******************************************************************************/
+/******************************************************************************/
- URI.domainFromURI = function(uri) {
- if ( !uri ) {
- return '';
- }
- return this.domainFromHostname(this.hostnameFromURI(uri));
- };
+// Normalize the way ηMatrix expects it
- /******************************************************************************/
+URI.normalizedURI = function() {
+ // Will be removed:
+ // - port
+ // - user id/password
+ // - fragment
+ return this.assemble(this.normalizeBits);
+};
- // Normalize the way ηMatrix expects it
+/******************************************************************************/
- URI.normalizedURI = function() {
- // Will be removed:
- // - port
- // - user id/password
- // - fragment
- return this.assemble(this.normalizeBits);
- };
+URI.rootURL = function() {
+ if ( !this.hostname ) {
+ return '';
+ }
+ return this.assemble(this.schemeBit | this.hostnameBit);
+};
- /******************************************************************************/
+/******************************************************************************/
- URI.rootURL = function() {
- if ( !this.hostname ) {
- return '';
- }
- return this.assemble(this.schemeBit | this.hostnameBit);
- };
+URI.isValidHostname = function(hostname) {
+ var r;
+ try {
+ r = reValidHostname.test(hostname);
+ }
+ catch (e) {
+ return false;
+ }
+ return r;
+};
- /******************************************************************************/
+/******************************************************************************/
- URI.isValidHostname = function(hostname) {
- var r;
- try {
- r = reValidHostname.test(hostname);
- }
- catch (e) {
- return false;
- }
- return r;
- };
-
- /******************************************************************************/
-
- // Return the parent domain. For IP address, there is no parent domain.
-
- URI.parentHostnameFromHostname = function(hostname) {
- // `locahost` => ``
- // `example.org` => `example.org`
- // `www.example.org` => `example.org`
- // `tomato.www.example.org` => `example.org`
- var domain = this.domainFromHostname(hostname);
-
- // `locahost` === `` => bye
- // `example.org` === `example.org` => bye
- // `www.example.org` !== `example.org` => stay
- // `tomato.www.example.org` !== `example.org` => stay
- if ( domain === '' || domain === hostname ) {
- return undefined;
- }
+// Return the parent domain. For IP address, there is no parent domain.
- // Parent is hostname minus first label
- return hostname.slice(hostname.indexOf('.') + 1);
- };
+URI.parentHostnameFromHostname = function(hostname) {
+ // `locahost` => ``
+ // `example.org` => `example.org`
+ // `www.example.org` => `example.org`
+ // `tomato.www.example.org` => `example.org`
+ var domain = this.domainFromHostname(hostname);
- /******************************************************************************/
+ // `locahost` === `` => bye
+ // `example.org` === `example.org` => bye
+ // `www.example.org` !== `example.org` => stay
+ // `tomato.www.example.org` !== `example.org` => stay
+ if ( domain === '' || domain === hostname ) {
+ return undefined;
+ }
- // Return all possible parent hostnames which can be derived from `hostname`,
- // ordered from direct parent up to domain inclusively.
+ // Parent is hostname minus first label
+ return hostname.slice(hostname.indexOf('.') + 1);
+};
- URI.parentHostnamesFromHostname = function(hostname) {
- // TODO: I should create an object which is optimized to receive
- // the list of hostnames by making it reusable (junkyard etc.) and which
- // has its own element counter property in order to avoid memory
- // alloc/dealloc.
- var domain = this.domainFromHostname(hostname);
- if ( domain === '' || domain === hostname ) {
- return [];
- }
- var nodes = [];
- var pos;
- for (;;) {
- pos = hostname.indexOf('.');
- if ( pos < 0 ) {
- break;
- }
- hostname = hostname.slice(pos + 1);
- nodes.push(hostname);
- if ( hostname === domain ) {
- break;
- }
- }
- return nodes;
- };
+/******************************************************************************/
+
+// Return all possible parent hostnames which can be derived from `hostname`,
+// ordered from direct parent up to domain inclusively.
+
+URI.parentHostnamesFromHostname = function(hostname) {
+ // TODO: I should create an object which is optimized to receive
+ // the list of hostnames by making it reusable (junkyard etc.) and which
+ // has its own element counter property in order to avoid memory
+ // alloc/dealloc.
+ var domain = this.domainFromHostname(hostname);
+ if ( domain === '' || domain === hostname ) {
+ return [];
+ }
+ var nodes = [];
+ var pos;
+ for (;;) {
+ pos = hostname.indexOf('.');
+ if ( pos < 0 ) {
+ break;
+ }
+ hostname = hostname.slice(pos + 1);
+ nodes.push(hostname);
+ if ( hostname === domain ) {
+ break;
+ }
+ }
+ return nodes;
+};
- /******************************************************************************/
+/******************************************************************************/
- // Return all possible hostnames which can be derived from `hostname`,
- // ordered from self up to domain inclusively.
+// Return all possible hostnames which can be derived from `hostname`,
+// ordered from self up to domain inclusively.
- URI.allHostnamesFromHostname = function(hostname) {
- var nodes = this.parentHostnamesFromHostname(hostname);
- nodes.unshift(hostname);
- return nodes;
- };
+URI.allHostnamesFromHostname = function(hostname) {
+ var nodes = this.parentHostnamesFromHostname(hostname);
+ nodes.unshift(hostname);
+ return nodes;
+};
- /******************************************************************************/
+/******************************************************************************/
- URI.toString = function() {
- return this.assemble();
- };
+URI.toString = function() {
+ return this.assemble();
+};
- /******************************************************************************/
+/******************************************************************************/
- // Export
+// Export
- return URI;
+return URI;
- /******************************************************************************/
+/******************************************************************************/
})();
diff --git a/js/user-rules.js b/js/user-rules.js
index ccd15c2..b8933b0 100644
--- a/js/user-rules.js
+++ b/js/user-rules.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -27,303 +27,303 @@
// Switches before, rules after
let directiveSort = function (a, b) {
- let aIsSwitch = a.indexOf(':') !== -1;
- let bIsSwitch = b.indexOf(':') !== -1;
+ let aIsSwitch = a.indexOf(':') !== -1;
+ let bIsSwitch = b.indexOf(':') !== -1;
- if (aIsSwitch === bIsSwitch) {
+ if (aIsSwitch === bIsSwitch) {
return a.localeCompare(b);
- }
+ }
- return aIsSwitch ? -1 : 1;
+ return aIsSwitch ? -1 : 1;
};
let processUserRules = function (response) {
- let allRules = {};
- let permanentRules = {};
- let temporaryRules = {};
+ let allRules = {};
+ let permanentRules = {};
+ let temporaryRules = {};
- let rules = response.permanentRules.split(/\n+/);
- for (let i=rules.length-1; i>=0; --i) {
+ let rules = response.permanentRules.split(/\n+/);
+ for (let i=rules.length-1; i>=0; --i) {
let rule = rules[i].trim();
if (rule.length !== 0) {
- permanentRules[rule] = allRules[rule] = true;
+ permanentRules[rule] = allRules[rule] = true;
}
- }
+ }
- rules = response.temporaryRules.split(/\n+/);
- for (let i=rules.length-1; i>=0; --i) {
+ rules = response.temporaryRules.split(/\n+/);
+ for (let i=rules.length-1; i>=0; --i) {
let rule = rules[i].trim();
if (rule.length !== 0) {
- temporaryRules[rule] = allRules[rule] = true;
+ temporaryRules[rule] = allRules[rule] = true;
}
- }
+ }
- let permanentList = document.createDocumentFragment();
+ let permanentList = document.createDocumentFragment();
let temporaryList = document.createDocumentFragment();
let li;
- rules = Object.keys(allRules).sort(directiveSort);
- for (let i=0; i<rules.length; ++i) {
+ rules = Object.keys(allRules).sort(directiveSort);
+ for (let i=0; i<rules.length; ++i) {
let rule = rules[i];
let onLeft = permanentRules.hasOwnProperty(rule);
let onRight = temporaryRules.hasOwnProperty(rule);
- li = document.createElement('li');
+ li = document.createElement('li');
if (onLeft && onRight) {
- li.textContent = rule;
- permanentList.appendChild(li);
- li = document.createElement('li');
- li.textContent = rule;
- temporaryList.appendChild(li);
+ li.textContent = rule;
+ permanentList.appendChild(li);
+ li = document.createElement('li');
+ li.textContent = rule;
+ temporaryList.appendChild(li);
} else if (onLeft) {
- li.textContent = rule;
- permanentList.appendChild(li);
- li = document.createElement('li');
- li.textContent = rule;
- li.className = 'notRight toRemove';
- temporaryList.appendChild(li);
+ li.textContent = rule;
+ permanentList.appendChild(li);
+ li = document.createElement('li');
+ li.textContent = rule;
+ li.className = 'notRight toRemove';
+ temporaryList.appendChild(li);
} else if (onRight) {
- li.textContent = '\xA0';
- permanentList.appendChild(li);
- li = document.createElement('li');
- li.textContent = rule;
- li.className = 'notLeft';
- temporaryList.appendChild(li);
+ li.textContent = '\xA0';
+ permanentList.appendChild(li);
+ li = document.createElement('li');
+ li.textContent = rule;
+ li.className = 'notLeft';
+ temporaryList.appendChild(li);
}
- }
+ }
- // TODO: build incrementally.
+ // TODO: build incrementally.
- uDom('#diff > .left > ul > li').remove();
- document.querySelector('#diff > .left > ul').appendChild(permanentList);
- uDom('#diff > .right > ul > li').remove();
- document.querySelector('#diff > .right > ul').appendChild(temporaryList);
- uDom('#diff')
- .toggleClass('dirty',
- response.temporaryRules !== response.permanentRules);
+ uDom('#diff > .left > ul > li').remove();
+ document.querySelector('#diff > .left > ul').appendChild(permanentList);
+ uDom('#diff > .right > ul > li').remove();
+ document.querySelector('#diff > .right > ul').appendChild(temporaryList);
+ uDom('#diff')
+ .toggleClass('dirty',
+ response.temporaryRules !== response.permanentRules);
};
// https://github.com/chrisaljoudi/uBlock/issues/757
// Support RequestPolicy rule syntax
let fromRequestPolicy = function (content) {
- let matches = /\[origins-to-destinations\]([^\[]+)/.exec(content);
- if (matches === null || matches.length !== 2) {
+ let matches = /\[origins-to-destinations\]([^\[]+)/.exec(content);
+ if (matches === null || matches.length !== 2) {
return;
- }
- return matches[1].trim()
+ }
+ return matches[1].trim()
.replace(/\|/g, ' ')
.replace(/\n/g, ' * allow\n');
};
// https://github.com/gorhill/uMatrix/issues/270
let fromNoScript = function (content) {
- let noscript = null;
+ let noscript = null;
- try {
+ try {
noscript = JSON.parse(content);
- } catch (e) {
- }
-
- if (noscript === null
- || typeof noscript !== 'object'
- || typeof noscript.prefs !== 'object'
- || typeof noscript.prefs.clearClick === 'undefined'
- || typeof noscript.whitelist !== 'string'
- || typeof noscript.V !== 'string') {
+ } catch (e) {
+ }
+
+ if (noscript === null
+ || typeof noscript !== 'object'
+ || typeof noscript.prefs !== 'object'
+ || typeof noscript.prefs.clearClick === 'undefined'
+ || typeof noscript.whitelist !== 'string'
+ || typeof noscript.V !== 'string') {
return;
- }
+ }
- let out = new Set();
- let reBad = /[a-z]+:\w*$/;
- let reURL = /[a-z]+:\/\/([0-9a-z.-]+)/;
- let directives = noscript.whitelist.split(/\s+/);
+ let out = new Set();
+ let reBad = /[a-z]+:\w*$/;
+ let reURL = /[a-z]+:\/\/([0-9a-z.-]+)/;
+ let directives = noscript.whitelist.split(/\s+/);
- for (let i=directives.length-1; i>=0; --i) {
+ for (let i=directives.length-1; i>=0; --i) {
let directive = directives[i].trim();
if (directive === '') {
- continue;
+ continue;
}
if (reBad.test(directive)) {
- continue;
+ continue;
}
let matches = reURL.exec(directive);
if (matches !== null) {
- directive = matches[1];
+ directive = matches[1];
}
out.add('* ' + directive + ' * allow');
out.add('* ' + directive + ' script allow');
out.add('* ' + directive + ' frame allow');
- }
+ }
- return Array.from(out).join('\n');
+ return Array.from(out).join('\n');
};
let handleImportFilePicker = function () {
- let fileReaderOnLoadHandler = function () {
+ let fileReaderOnLoadHandler = function () {
if (typeof this.result !== 'string' || this.result === '') {
- return;
+ return;
}
let result = fromRequestPolicy(this.result);
if (result === undefined) {
- result = fromNoScript(this.result);
- if (result === undefined) {
+ result = fromNoScript(this.result);
+ if (result === undefined) {
result = this.result;
- }
+ }
}
if (this.result === '') {
- return;
- }
+ return;
+ }
let request = {
- 'what': 'setUserRules',
- 'temporaryRules': rulesFromHTML('#diff .right li')
- + '\n' + result,
+ 'what': 'setUserRules',
+ 'temporaryRules': rulesFromHTML('#diff .right li')
+ + '\n' + result,
};
vAPI.messaging.send('user-rules.js', request, processUserRules);
- };
+ };
- var file = this.files[0];
- if (file === undefined || file.name === '') {
+ var file = this.files[0];
+ if (file === undefined || file.name === '') {
return;
- }
+ }
- if (file.type.indexOf('text') !== 0
- && file.type !== 'application/json') {
+ if (file.type.indexOf('text') !== 0
+ && file.type !== 'application/json') {
return;
- }
+ }
- let fr = new FileReader();
- fr.onload = fileReaderOnLoadHandler;
- fr.readAsText(file);
+ let fr = new FileReader();
+ fr.onload = fileReaderOnLoadHandler;
+ fr.readAsText(file);
};
let startImportFilePicker = function () {
- let input = document.getElementById('importFilePicker');
- // Reset to empty string, this will ensure an change event is properly
- // triggered if the user pick a file, even if it is the same as the last
- // one picked.
- input.value = '';
- input.click();
+ let input = document.getElementById('importFilePicker');
+ // Reset to empty string, this will ensure an change event is properly
+ // triggered if the user pick a file, even if it is the same as the last
+ // one picked.
+ input.value = '';
+ input.click();
};
function exportUserRulesToFile() {
- vAPI.download({
+ vAPI.download({
'url': 'data:text/plain,'
- + encodeURIComponent(rulesFromHTML('#diff .left li') + '\n'),
+ + encodeURIComponent(rulesFromHTML('#diff .left li') + '\n'),
'filename': uDom('[data-i18n="userRulesDefaultFileName"]').text(),
- });
+ });
}
var rulesFromHTML = function(selector) {
- let rules = [];
- let lis = uDom(selector);
+ let rules = [];
+ let lis = uDom(selector);
- for (let i=0; i<lis.length; ++i) {
+ for (let i=0; i<lis.length; ++i) {
let li = lis.at(i);
if (li.hasClassName('toRemove')) {
- rules.push('');
+ rules.push('');
} else {
- rules.push(li.text());
+ rules.push(li.text());
}
- }
+ }
- return rules.join('\n');
+ return rules.join('\n');
};
let revertHandler = function () {
- let request = {
+ let request = {
'what': 'setUserRules',
'temporaryRules': rulesFromHTML('#diff .left li'),
- };
+ };
- vAPI.messaging.send('user-rules.js', request, processUserRules);
+ vAPI.messaging.send('user-rules.js', request, processUserRules);
};
let commitHandler = function () {
- var request = {
+ var request = {
'what': 'setUserRules',
'permanentRules': rulesFromHTML('#diff .right li'),
- };
+ };
- vAPI.messaging.send('user-rules.js', request, processUserRules);
+ vAPI.messaging.send('user-rules.js', request, processUserRules);
};
let editStartHandler = function () {
- uDom('#diff .right textarea').val(rulesFromHTML('#diff .right li'));
- let parent = uDom(this).ancestors('#diff');
- parent.toggleClass('edit', true);
+ uDom('#diff .right textarea').val(rulesFromHTML('#diff .right li'));
+ let parent = uDom(this).ancestors('#diff');
+ parent.toggleClass('edit', true);
};
let editStopHandler = function () {
- let parent = uDom(this).ancestors('#diff');
- parent.toggleClass('edit', false);
+ let parent = uDom(this).ancestors('#diff');
+ parent.toggleClass('edit', false);
- let request = {
+ let request = {
'what': 'setUserRules',
'temporaryRules': uDom('#diff .right textarea').val(),
- };
+ };
- vAPI.messaging.send('user-rules.js', request, processUserRules);
+ vAPI.messaging.send('user-rules.js', request, processUserRules);
};
let editCancelHandler = function () {
- let parent = uDom(this).ancestors('#diff');
- parent.toggleClass('edit', false);
+ let parent = uDom(this).ancestors('#diff');
+ parent.toggleClass('edit', false);
};
let temporaryRulesToggler = function() {
- var li = uDom(this);
- li.toggleClass('toRemove');
+ var li = uDom(this);
+ li.toggleClass('toRemove');
- let request = {
+ let request = {
'what': 'setUserRules',
'temporaryRules': rulesFromHTML('#diff .right li'),
- };
+ };
- vAPI.messaging.send('user-rules.js', request, processUserRules);
+ vAPI.messaging.send('user-rules.js', request, processUserRules);
};
self.cloud.onPush = function () {
- return rulesFromHTML('#diff .left li');
+ return rulesFromHTML('#diff .left li');
};
self.cloud.onPull = function (data, append) {
- if (typeof data !== 'string') {
- return;
- }
+ if (typeof data !== 'string') {
+ return;
+ }
- if (append) {
+ if (append) {
data = rulesFromHTML('#diff .right li') + '\n' + data;
- }
+ }
- let request = {
+ let request = {
'what': 'setUserRules',
'temporaryRules': data,
- };
+ };
- vAPI.messaging.send('user-rules.js', request, processUserRules);
+ vAPI.messaging.send('user-rules.js', request, processUserRules);
};
uDom.onLoad(function () {
- // Handle user interaction
- uDom('#importButton').on('click', startImportFilePicker);
- uDom('#importFilePicker').on('change', handleImportFilePicker);
- uDom('#exportButton').on('click', exportUserRulesToFile);
- uDom('#revertButton').on('click', revertHandler);
- uDom('#commitButton').on('click', commitHandler);
- uDom('#editEnterButton').on('click', editStartHandler);
- uDom('#editStopButton').on('click', editStopHandler);
- uDom('#editCancelButton').on('click', editCancelHandler);
- uDom('#diff > .right > ul').on('click', 'li', temporaryRulesToggler);
-
- vAPI.messaging.send('user-rules.js', {
- what: 'getUserRules',
- }, processUserRules);
+ // Handle user interaction
+ uDom('#importButton').on('click', startImportFilePicker);
+ uDom('#importFilePicker').on('change', handleImportFilePicker);
+ uDom('#exportButton').on('click', exportUserRulesToFile);
+ uDom('#revertButton').on('click', revertHandler);
+ uDom('#commitButton').on('click', commitHandler);
+ uDom('#editEnterButton').on('click', editStartHandler);
+ uDom('#editStopButton').on('click', editStopHandler);
+ uDom('#editCancelButton').on('click', editCancelHandler);
+ uDom('#diff > .right > ul').on('click', 'li', temporaryRulesToggler);
+
+ vAPI.messaging.send('user-rules.js', {
+ what: 'getUserRules',
+ }, processUserRules);
});
})();
diff --git a/js/usersettings.js b/js/usersettings.js
index 2dffa5e..0125e10 100644
--- a/js/usersettings.js
+++ b/js/usersettings.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
diff --git a/js/utils.js b/js/utils.js
index be6ed9c..d545e28 100644
--- a/js/utils.js
+++ b/js/utils.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
diff --git a/js/vapi-background.js b/js/vapi-background.js
index ff64178..2e79839 100644
--- a/js/vapi-background.js
+++ b/js/vapi-background.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 The uMatrix/uBlock Origin authors
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -38,53 +38,53 @@
// Icon-related stuff
vAPI.setIcon = function (tabId, iconId, badge) {
- // If badge is undefined, then setIcon was called from the
- // TabSelect event
- let win;
- if (badge === undefined) {
+ // If badge is undefined, then setIcon was called from the
+ // TabSelect event
+ let win;
+ if (badge === undefined) {
win = iconId;
- } else {
+ } else {
win = vAPI.window.getCurrentWindow();
- }
+ }
- let tabBrowser = vAPI.browser.getTabBrowser(win);
- if (tabBrowser === null) {
+ let tabBrowser = vAPI.browser.getTabBrowser(win);
+ if (tabBrowser === null) {
return;
- }
+ }
- let curTabId = vAPI.tabs.manager.tabIdFromTarget(tabBrowser.selectedTab);
- let tb = vAPI.toolbarButton;
+ let curTabId = vAPI.tabs.manager.tabIdFromTarget(tabBrowser.selectedTab);
+ let tb = vAPI.toolbarButton;
- // from 'TabSelect' event
- if (tabId === undefined) {
+ // from 'TabSelect' event
+ if (tabId === undefined) {
tabId = curTabId;
- } else if (badge !== undefined) {
+ } else if (badge !== undefined) {
tb.tabs[tabId] = {
- badge: badge, img: iconId
- };
- }
+ badge: badge, img: iconId
+ };
+ }
- if (tabId === curTabId) {
+ if (tabId === curTabId) {
tb.updateState(win, tabId);
- }
+ }
};
vAPI.httpObserver = {
- classDescription: 'net-channel-event-sinks for ' + location.host,
- classID: Components.ID('{5d2e2797-6d68-42e2-8aeb-81ce6ba16b95}'),
- contractID: '@' + location.host + '/net-channel-event-sinks;1',
- REQDATAKEY: location.host + 'reqdata',
- ABORT: Components.results.NS_BINDING_ABORTED,
- ACCEPT: Components.results.NS_SUCCEEDED,
- // Request types:
- // https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIContentPolicy#Constants
- // eMatrix: we can just use nsIContentPolicy's built-in
- // constants, can we?
- frameTypeMap: {
+ classDescription: 'net-channel-event-sinks for ' + location.host,
+ classID: Components.ID('{5d2e2797-6d68-42e2-8aeb-81ce6ba16b95}'),
+ contractID: '@' + location.host + '/net-channel-event-sinks;1',
+ REQDATAKEY: location.host + 'reqdata',
+ ABORT: Components.results.NS_BINDING_ABORTED,
+ ACCEPT: Components.results.NS_SUCCEEDED,
+ // Request types:
+ // https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIContentPolicy#Constants
+ // eMatrix: we can just use nsIContentPolicy's built-in
+ // constants, can we?
+ frameTypeMap: {
6: 'main_frame',
7: 'sub_frame'
- },
- typeMap: {
+ },
+ typeMap: {
1: 'other',
2: 'script',
3: 'image',
@@ -106,434 +106,434 @@
20: 'xmlhttprequest',
21: 'imageset',
22: 'web_manifest'
- },
- mimeTypeMap: {
+ },
+ mimeTypeMap: {
'audio': 15,
'video': 15
- },
- get componentRegistrar () {
+ },
+ get componentRegistrar () {
return Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
- },
- get categoryManager () {
+ },
+ get categoryManager () {
return Cc['@mozilla.org/categorymanager;1']
.getService(Ci.nsICategoryManager);
- },
- QueryInterface: (function () {
+ },
+ QueryInterface: (function () {
var {XPCOMUtils} =
- Cu.import('resource://gre/modules/XPCOMUtils.jsm', null);
+ Cu.import('resource://gre/modules/XPCOMUtils.jsm', null);
return XPCOMUtils.generateQI([
- Ci.nsIFactory,
- Ci.nsIObserver,
- Ci.nsIChannelEventSink,
- Ci.nsISupportsWeakReference
+ Ci.nsIFactory,
+ Ci.nsIObserver,
+ Ci.nsIChannelEventSink,
+ Ci.nsISupportsWeakReference
]);
- })(),
- createInstance: function (outer, iid) {
+ })(),
+ createInstance: function (outer, iid) {
if (outer) {
- throw Components.results.NS_ERROR_NO_AGGREGATION;
+ throw Components.results.NS_ERROR_NO_AGGREGATION;
}
return this.QueryInterface(iid);
- },
- register: function () {
+ },
+ register: function () {
Services.obs.addObserver(this, 'http-on-modify-request', true);
Services.obs.addObserver(this, 'http-on-examine-response', true);
Services.obs.addObserver(this, 'http-on-examine-cached-response', true);
// Guard against stale instances not having been unregistered
if (this.componentRegistrar.isCIDRegistered(this.classID)) {
- try {
+ try {
this.componentRegistrar
- .unregisterFactory(this.classID,
- Components.manager
- .getClassObject(this.classID,
- Ci.nsIFactory));
- } catch (ex) {
+ .unregisterFactory(this.classID,
+ Components.manager
+ .getClassObject(this.classID,
+ Ci.nsIFactory));
+ } catch (ex) {
console.error('eMatrix> httpObserver > '
- +'unable to unregister stale instance: ', ex);
- }
+ +'unable to unregister stale instance: ', ex);
+ }
}
this.componentRegistrar.registerFactory(this.classID,
- this.classDescription,
- this.contractID,
- this);
+ this.classDescription,
+ this.contractID,
+ this);
this.categoryManager.addCategoryEntry('net-channel-event-sinks',
- this.contractID,
- this.contractID,
- false,
- true);
- },
- unregister: function () {
+ this.contractID,
+ this.contractID,
+ false,
+ true);
+ },
+ unregister: function () {
Services.obs.removeObserver(this, 'http-on-modify-request');
Services.obs.removeObserver(this, 'http-on-examine-response');
Services.obs.removeObserver(this, 'http-on-examine-cached-response');
this.componentRegistrar.unregisterFactory(this.classID, this);
this.categoryManager.deleteCategoryEntry('net-channel-event-sinks',
- this.contractID,
- false);
- },
- handleRequest: function (channel, URI, tabId, rawType) {
+ this.contractID,
+ false);
+ },
+ handleRequest: function (channel, URI, tabId, rawType) {
let type = this.typeMap[rawType] || 'other';
let onBeforeRequest = vAPI.net.onBeforeRequest;
if (onBeforeRequest.types === null
- || onBeforeRequest.types.has(type)) {
- let result = onBeforeRequest.callback({
+ || onBeforeRequest.types.has(type)) {
+ let result = onBeforeRequest.callback({
parentFrameId: type === 'main_frame' ? -1 : 0,
tabId: tabId,
type: type,
url: URI.asciiSpec
- });
+ });
- if (typeof result === 'object') {
+ if (typeof result === 'object') {
channel.cancel(this.ABORT);
return true;
- }
+ }
}
let onBeforeSendHeaders = vAPI.net.onBeforeSendHeaders;
if (onBeforeSendHeaders.types === null
- || onBeforeSendHeaders.types.has(type)) {
- let requestHeaders = HTTPRequestHeaders.factory(channel);
- let newHeaders = onBeforeSendHeaders.callback({
+ || onBeforeSendHeaders.types.has(type)) {
+ let requestHeaders = HTTPRequestHeaders.factory(channel);
+ let newHeaders = onBeforeSendHeaders.callback({
parentFrameId: type === 'main_frame' ? -1 : 0,
requestHeaders: requestHeaders.headers,
tabId: tabId,
type: type,
url: URI.asciiSpec,
method: channel.requestMethod
- });
+ });
- if (newHeaders) {
+ if (newHeaders) {
requestHeaders.update();
- }
- requestHeaders.dispose();
+ }
+ requestHeaders.dispose();
}
return false;
- },
- channelDataFromChannel: function (channel) {
+ },
+ channelDataFromChannel: function (channel) {
if (channel instanceof Ci.nsIWritablePropertyBag) {
- try {
+ try {
return channel.getProperty(this.REQDATAKEY) || null;
- } catch (ex) {
- // Ignore
- }
+ } catch (ex) {
+ // Ignore
+ }
}
return null;
- },
- // https://github.com/gorhill/uMatrix/issues/165
- // https://developer.mozilla.org/en-US/Firefox/Releases/3.5/Updating_extensions#Getting_a_load_context_from_a_request
- // Not sure `ematrix:shouldLoad` is still needed, eMatrix does
- // not care about embedded frames topography.
- // Also:
- // https://developer.mozilla.org/en-US/Firefox/Multiprocess_Firefox/Limitations_of_chrome_scripts
- tabIdFromChannel: function (channel) {
+ },
+ // https://github.com/gorhill/uMatrix/issues/165
+ // https://developer.mozilla.org/en-US/Firefox/Releases/3.5/Updating_extensions#Getting_a_load_context_from_a_request
+ // Not sure `ematrix:shouldLoad` is still needed, eMatrix does
+ // not care about embedded frames topography.
+ // Also:
+ // https://developer.mozilla.org/en-US/Firefox/Multiprocess_Firefox/Limitations_of_chrome_scripts
+ tabIdFromChannel: function (channel) {
let lc;
try {
- lc = channel.notificationCallbacks.getInterface(Ci.nsILoadContext);
+ lc = channel.notificationCallbacks.getInterface(Ci.nsILoadContext);
} catch(ex) {
- // Ignore
+ // Ignore
}
if (!lc) {
- try {
+ try {
lc = channel.loadGroup.notificationCallbacks
- .getInterface(Ci.nsILoadContext);
- } catch(ex) {
- // Ignore
- }
+ .getInterface(Ci.nsILoadContext);
+ } catch(ex) {
+ // Ignore
+ }
- if (!lc) {
+ if (!lc) {
return vAPI.noTabId;
- }
+ }
}
if (lc.topFrameElement) {
- return vAPI.tabs.manager.tabIdFromTarget(lc.topFrameElement);
+ return vAPI.tabs.manager.tabIdFromTarget(lc.topFrameElement);
}
let win;
try {
- win = lc.associatedWindow;
+ win = lc.associatedWindow;
} catch (ex) {
- // Ignore
- }
+ // Ignore
+ }
if (!win) {
- return vAPI.noTabId;
+ return vAPI.noTabId;
}
if (win.top) {
- win = win.top;
+ win = win.top;
}
let tabBrowser;
try {
- tabBrowser =
- vAPI.browser.getTabBrowser
- (win.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIWebNavigation)
- .QueryInterface(Ci.nsIDocShell).rootTreeItem
- .QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindow));
+ tabBrowser =
+ vAPI.browser.getTabBrowser
+ (win.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebNavigation)
+ .QueryInterface(Ci.nsIDocShell).rootTreeItem
+ .QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindow));
} catch (ex) {
- // Ignore
- }
+ // Ignore
+ }
if (!tabBrowser) {
- return vAPI.noTabId;
+ return vAPI.noTabId;
}
if (tabBrowser.getBrowserForContentWindow) {
- return vAPI.tabs.manager
- .tabIdFromTarget(tabBrowser.getBrowserForContentWindow(win));
+ return vAPI.tabs.manager
+ .tabIdFromTarget(tabBrowser.getBrowserForContentWindow(win));
}
// Falling back onto _getTabForContentWindow to ensure older
// versions of Firefox work well.
return tabBrowser._getTabForContentWindow
- ? vAPI.tabs.manager
- .tabIdFromTarget(tabBrowser._getTabForContentWindow(win))
- : vAPI.noTabId;
- },
- rawtypeFromContentType: function (channel) {
+ ? vAPI.tabs.manager
+ .tabIdFromTarget(tabBrowser._getTabForContentWindow(win))
+ : vAPI.noTabId;
+ },
+ rawtypeFromContentType: function (channel) {
let mime = channel.contentType;
if (!mime) {
- return 0;
+ return 0;
}
let pos = mime.indexOf('/');
if (pos === -1) {
- pos = mime.length;
+ pos = mime.length;
}
return this.mimeTypeMap[mime.slice(0, pos)] || 0;
- },
- operate: function (channel, URI, topic) {
- let channelData = this.channelDataFromChannel(channel);
+ },
+ operate: function (channel, URI, topic) {
+ let channelData = this.channelDataFromChannel(channel);
- if (topic.lastIndexOf('http-on-examine-', 0) === 0) {
- if (channelData === null) {
+ if (topic.lastIndexOf('http-on-examine-', 0) === 0) {
+ if (channelData === null) {
return;
- }
+ }
- let type = this.frameTypeMap[channelData[1]];
- if (!type) {
+ let type = this.frameTypeMap[channelData[1]];
+ if (!type) {
return;
- }
-
- // topic = ['Content-Security-Policy',
- // 'Content-Security-Policy-Report-Only'];
- //
- // Can send empty responseHeaders as these headers are
- // only added to and then merged.
- //
- // TODO: Find better place for this, needs to be set
- // before onHeadersReceived.callback. Web workers not
- // blocked in Pale Moon as child-src currently
- // unavailable, see:
- //
- // https://github.com/MoonchildProductions/Pale-Moon/issues/949
- //
- // eMatrix: as of Pale Moon 28 it seems child-src is
- // available and depracated(?)
- if (ηMatrix.cspNoWorker === undefined) {
+ }
+
+ // topic = ['Content-Security-Policy',
+ // 'Content-Security-Policy-Report-Only'];
+ //
+ // Can send empty responseHeaders as these headers are
+ // only added to and then merged.
+ //
+ // TODO: Find better place for this, needs to be set
+ // before onHeadersReceived.callback. Web workers not
+ // blocked in Pale Moon as child-src currently
+ // unavailable, see:
+ //
+ // https://github.com/MoonchildProductions/Pale-Moon/issues/949
+ //
+ // eMatrix: as of Pale Moon 28 it seems child-src is
+ // available and depracated(?)
+ if (ηMatrix.cspNoWorker === undefined) {
// ηMatrix.cspNoWorker = "child-src 'none'; "
- // +"frame-src data: blob: *; "
- // +"report-uri about:blank";
- ηMatrix.cspNoWorker = "worker-src 'none'; "
- +"frame-src data: blob: *; "
- +"report-uri about:blank";
- }
-
- let result = vAPI.net.onHeadersReceived.callback({
+ // +"frame-src data: blob: *; "
+ // +"report-uri about:blank";
+ ηMatrix.cspNoWorker = "worker-src 'none'; "
+ +"frame-src data: blob: *; "
+ +"report-uri about:blank";
+ }
+
+ let result = vAPI.net.onHeadersReceived.callback({
parentFrameId: type === 'main_frame' ? -1 : 0,
responseHeaders: [],
tabId: channelData[0],
type: type,
url: URI.asciiSpec
- });
+ });
- if (result) {
+ if (result) {
for (let header of result.responseHeaders) {
- channel.setResponseHeader(header.name,
- header.value,
- true);
+ channel.setResponseHeader(header.name,
+ header.value,
+ true);
}
- }
+ }
- return;
+ return;
}
- // http-on-modify-request
+ // http-on-modify-request
// The channel was previously serviced.
if (channelData !== null) {
- this.handleRequest(channel, URI,
- channelData[0], channelData[1]);
- return;
+ this.handleRequest(channel, URI,
+ channelData[0], channelData[1]);
+ return;
}
// The channel was never serviced.
let tabId;
let pendingRequest =
- PendingRequestBuffer.lookupRequest(URI.asciiSpec);
+ PendingRequestBuffer.lookupRequest(URI.asciiSpec);
let rawType = 1;
let loadInfo = channel.loadInfo;
// https://github.com/gorhill/uMatrix/issues/390#issuecomment-155717004
if (loadInfo) {
- rawType = (loadInfo.externalContentPolicyType !== undefined)
- ? loadInfo.externalContentPolicyType
- : loadInfo.contentPolicyType;
- if (!rawType) {
+ rawType = (loadInfo.externalContentPolicyType !== undefined)
+ ? loadInfo.externalContentPolicyType
+ : loadInfo.contentPolicyType;
+ if (!rawType) {
rawType = 1;
- }
+ }
}
if (pendingRequest !== null) {
- tabId = pendingRequest.tabId;
- // https://github.com/gorhill/uBlock/issues/654
- // Use the request type from the HTTP observer point of view.
- if (rawType !== 1) {
+ tabId = pendingRequest.tabId;
+ // https://github.com/gorhill/uBlock/issues/654
+ // Use the request type from the HTTP observer point of view.
+ if (rawType !== 1) {
pendingRequest.rawType = rawType;
- } else {
+ } else {
rawType = pendingRequest.rawType;
- }
+ }
} else {
- tabId = this.tabIdFromChannel(channel);
+ tabId = this.tabIdFromChannel(channel);
}
if (this.handleRequest(channel, URI, tabId, rawType)) {
- return;
+ return;
}
if (channel instanceof Ci.nsIWritablePropertyBag === false) {
- return;
+ return;
}
// Carry data for behind-the-scene redirects
channel.setProperty(this.REQDATAKEY, [tabId, rawType]);
- },
- observe: function (channel, topic) {
+ },
+ observe: function (channel, topic) {
if (channel instanceof Ci.nsIHttpChannel === false) {
- return;
+ return;
}
let URI = channel.URI;
let channelData = this.channelDataFromChannel(channel);
- if (ηMatrix.userSettings.resolveCname === true) {
- let key = URI.scheme + '://' + URI.host;
- if (HostMap.get(key)) {
- this.operate(channel, HostMap.get(key), topic);
- return;
- }
-
- let CC = Components.classes;
- let CI = Components.interfaces;
-
- let tab = this.tabIdFromChannel(channel);
-
- let dns = CC['@mozilla.org/network/dns-service;1']
- .createInstance(CI.nsIDNSService);
-
- let listener = {
- onLookupComplete: function (req, rec, stat) {
- if (!Components.isSuccessCode(stat)) {
- console.error("can't resolve canonical name");
- return;
- }
- let addr = rec.canonicalName;
-
- ηMatrix.logger.writeOne(tab, 'info',
- URI.host + ' => ' + addr);
-
- let ios = CC['@mozilla.org/network/io-service;1']
- .createInstance(CI.nsIIOService);
-
- let uri = ios.newURI(URI.scheme+'://'+addr, null, null);
-
- HostMap.put(key, uri);
-
- vAPI.httpObserver.operate(channel, uri, topic);
- },
- };
-
- dns.asyncResolve(URI.host,
- CI.nsIDNSService.RESOLVE_CANONICAL_NAME,
- listener,
- null);
- } else {
- this.operate(channel, URI, topic);
- }
- },
- asyncOnChannelRedirect: function (oldChannel, newChannel,
- flags, callback) {
- // contentPolicy.shouldLoad doesn't detect redirects, this
- // needs to be used
+ if (ηMatrix.userSettings.resolveCname === true) {
+ let key = URI.scheme + '://' + URI.host;
+ if (HostMap.get(key)) {
+ this.operate(channel, HostMap.get(key), topic);
+ return;
+ }
+
+ let CC = Components.classes;
+ let CI = Components.interfaces;
+
+ let tab = this.tabIdFromChannel(channel);
+
+ let dns = CC['@mozilla.org/network/dns-service;1']
+ .createInstance(CI.nsIDNSService);
+
+ let listener = {
+ onLookupComplete: function (req, rec, stat) {
+ if (!Components.isSuccessCode(stat)) {
+ console.error("can't resolve canonical name");
+ return;
+ }
+ let addr = rec.canonicalName;
+
+ ηMatrix.logger.writeOne(tab, 'info',
+ URI.host + ' => ' + addr);
+
+ let ios = CC['@mozilla.org/network/io-service;1']
+ .createInstance(CI.nsIIOService);
+
+ let uri = ios.newURI(URI.scheme+'://'+addr, null, null);
+
+ HostMap.put(key, uri);
+
+ vAPI.httpObserver.operate(channel, uri, topic);
+ },
+ };
+
+ dns.asyncResolve(URI.host,
+ CI.nsIDNSService.RESOLVE_CANONICAL_NAME,
+ listener,
+ null);
+ } else {
+ this.operate(channel, URI, topic);
+ }
+ },
+ asyncOnChannelRedirect: function (oldChannel, newChannel,
+ flags, callback) {
+ // contentPolicy.shouldLoad doesn't detect redirects, this
+ // needs to be used
// If error thrown, the redirect will fail
try {
- let URI = newChannel.URI;
- if (!URI.schemeIs('http') && !URI.schemeIs('https')) {
+ let URI = newChannel.URI;
+ if (!URI.schemeIs('http') && !URI.schemeIs('https')) {
return;
- }
+ }
- if (newChannel instanceof Ci.nsIWritablePropertyBag === false) {
+ if (newChannel instanceof Ci.nsIWritablePropertyBag === false) {
return;
- }
+ }
- let channelData = this.channelDataFromChannel(oldChannel);
- if (channelData === null) {
+ let channelData = this.channelDataFromChannel(oldChannel);
+ if (channelData === null) {
return;
- }
+ }
- // Carry the data on in case of multiple redirects
- newChannel.setProperty(this.REQDATAKEY, channelData);
+ // Carry the data on in case of multiple redirects
+ newChannel.setProperty(this.REQDATAKEY, channelData);
} catch (ex) {
- // console.error(ex);
- // Ignore
+ // console.error(ex);
+ // Ignore
} finally {
- callback.onRedirectVerifyCallback(this.ACCEPT);
+ callback.onRedirectVerifyCallback(this.ACCEPT);
}
- }
+ }
};
vAPI.toolbarButton = {
- id: location.host + '-button',
- type: 'view',
- viewId: location.host + '-panel',
- label: vAPI.app.name,
- tooltiptext: vAPI.app.name,
- tabs: {/*tabId: {badge: 0, img: boolean}*/},
- init: null,
- codePath: ''
+ id: location.host + '-button',
+ type: 'view',
+ viewId: location.host + '-panel',
+ label: vAPI.app.name,
+ tooltiptext: vAPI.app.name,
+ tabs: {/*tabId: {badge: 0, img: boolean}*/},
+ init: null,
+ codePath: ''
};
(function () {
- let tbb = vAPI.toolbarButton;
- let popupCommittedWidth = 0;
- let popupCommittedHeight = 0;
+ let tbb = vAPI.toolbarButton;
+ let popupCommittedWidth = 0;
+ let popupCommittedHeight = 0;
- tbb.onViewShowing = function ({target}) {
+ tbb.onViewShowing = function ({target}) {
popupCommittedWidth = popupCommittedHeight = 0;
target.firstChild.setAttribute('src', vAPI.getURL('popup.html'));
- };
+ };
- tbb.onViewHiding = function ({target}) {
+ tbb.onViewHiding = function ({target}) {
target.parentNode.style.maxWidth = '';
target.firstChild.setAttribute('src', 'about:blank');
- };
+ };
- tbb.updateState = function (win, tabId) {
+ tbb.updateState = function (win, tabId) {
let button = win.document.getElementById(this.id);
if (!button) {
- return;
+ return;
}
let icon = this.tabs[tabId];
@@ -541,19 +541,19 @@
button.classList.toggle('off', !icon || !icon.img);
let iconId = (ηMatrix.userSettings.disableUpdateIcon) ?
- icon && icon.img ? '19' : 'off' :
- icon && icon.img ? icon.img : 'off';
+ icon && icon.img ? '19' : 'off' :
+ icon && icon.img ? icon.img : 'off';
icon = 'url('
- + vAPI.getURL('img/browsericons/icon19-'
- + iconId
- + '.png')
- + ')';
+ + vAPI.getURL('img/browsericons/icon19-'
+ + iconId
+ + '.png')
+ + ')';
- button.style.listStyleImage = icon;
- };
+ button.style.listStyleImage = icon;
+ };
- tbb.populatePanel = function (doc, panel) {
+ tbb.populatePanel = function (doc, panel) {
panel.setAttribute('id', this.viewId);
let iframe = doc.createElement('iframe');
@@ -562,135 +562,130 @@
panel.appendChild(iframe);
let toPx = function (pixels) {
- return pixels.toString() + 'px';
+ return pixels.toString() + 'px';
};
let scrollBarWidth = 0;
let resizeTimer = null;
let resizePopupDelayed = function (attempts) {
- if (resizeTimer !== null) {
+ if (resizeTimer !== null) {
return false;
- }
+ }
- // Sanity check
- attempts = (attempts || 0) + 1;
- if ( attempts > 1/*000*/ ) {
+ // Sanity check
+ attempts = (attempts || 0) + 1;
+ if ( attempts > 1/*000*/ ) {
//console.error('eMatrix> resizePopupDelayed: giving up after too many attempts');
return false;
- }
+ }
- resizeTimer = vAPI.setTimeout(resizePopup, 10, attempts);
- return true;
+ resizeTimer = vAPI.setTimeout(resizePopup, 10, attempts);
+ return true;
};
let resizePopup = function (attempts) {
- resizeTimer = null;
+ resizeTimer = null;
- panel.parentNode.style.maxWidth = 'none';
- let body = iframe.contentDocument.body;
+ panel.parentNode.style.maxWidth = 'none';
+ let body = iframe.contentDocument.body;
- // https://github.com/gorhill/uMatrix/issues/301
- // Don't resize if committed size did not change.
- if (popupCommittedWidth === body.clientWidth
- && popupCommittedHeight === body.clientHeight) {
+ // https://github.com/gorhill/uMatrix/issues/301
+ // Don't resize if committed size did not change.
+ if (popupCommittedWidth === body.clientWidth
+ && popupCommittedHeight === body.clientHeight) {
return;
- }
+ }
- // We set a limit for height
- let height = Math.min(body.clientHeight, 600);
+ // We set a limit for height
+ let height = Math.min(body.clientHeight, 600);
- // https://github.com/chrisaljoudi/uBlock/issues/730
- // Voodoo programming: this recipe works
- panel.style.setProperty('height', toPx(height));
- iframe.style.setProperty('height', toPx(height));
+ // https://github.com/chrisaljoudi/uBlock/issues/730
+ // Voodoo programming: this recipe works
+ panel.style.setProperty('height', toPx(height));
+ iframe.style.setProperty('height', toPx(height));
- // Adjust width for presence/absence of vertical scroll bar which may
- // have appeared as a result of last operation.
- let contentWindow = iframe.contentWindow;
- let width = body.clientWidth;
- if (contentWindow.scrollMaxY !== 0) {
+ // Adjust width for presence/absence of vertical scroll bar which may
+ // have appeared as a result of last operation.
+ let contentWindow = iframe.contentWindow;
+ let width = body.clientWidth;
+ if (contentWindow.scrollMaxY !== 0) {
width += scrollBarWidth;
- }
- panel.style.setProperty('width', toPx(width));
+ }
+ panel.style.setProperty('width', toPx(width));
- // scrollMaxX should always be zero once we know the scrollbar width
- if (contentWindow.scrollMaxX !== 0) {
+ // scrollMaxX should always be zero once we know the scrollbar width
+ if (contentWindow.scrollMaxX !== 0) {
scrollBarWidth = contentWindow.scrollMaxX;
width += scrollBarWidth;
panel.style.setProperty('width', toPx(width));
- }
+ }
- if (iframe.clientHeight !== height
- || panel.clientWidth !== width) {
+ if (iframe.clientHeight !== height
+ || panel.clientWidth !== width) {
if (resizePopupDelayed(attempts)) {
- return;
+ return;
}
// resizePopupDelayed won't be called again, so commit
// dimentsions.
- }
+ }
- popupCommittedWidth = body.clientWidth;
- popupCommittedHeight = body.clientHeight;
+ popupCommittedWidth = body.clientWidth;
+ popupCommittedHeight = body.clientHeight;
};
let onResizeRequested = function () {
- let body = iframe.contentDocument.body;
- if (body.getAttribute('data-resize-popup') !== 'true') {
+ let body = iframe.contentDocument.body;
+ if (body.getAttribute('data-resize-popup') !== 'true') {
return;
- }
- body.removeAttribute('data-resize-popup');
- resizePopupDelayed();
+ }
+ body.removeAttribute('data-resize-popup');
+ resizePopupDelayed();
};
let onPopupReady = function () {
- let win = this.contentWindow;
+ let win = this.contentWindow;
- if (!win || win.location.host !== location.host) {
+ if (!win || win.location.host !== location.host) {
return;
- }
+ }
- if (typeof tbb.onBeforePopupReady === 'function') {
+ if (typeof tbb.onBeforePopupReady === 'function') {
tbb.onBeforePopupReady.call(this);
- }
+ }
- resizePopupDelayed();
+ resizePopupDelayed();
- let body = win.document.body;
- body.removeAttribute('data-resize-popup');
+ let body = win.document.body;
+ body.removeAttribute('data-resize-popup');
- let mutationObserver =
- new win.MutationObserver(onResizeRequested);
+ let mutationObserver =
+ new win.MutationObserver(onResizeRequested);
- mutationObserver.observe(body, {
+ mutationObserver.observe(body, {
attributes: true,
attributeFilter: [ 'data-resize-popup' ]
- });
+ });
};
iframe.addEventListener('load', onPopupReady, true);
- };
+ };
})();
/******************************************************************************/
(function () {
- // Add toolbar button for not-Basilisk
- if (Services.appinfo.ID === "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}") {
+ let tbb = vAPI.toolbarButton;
+ if (tbb.init !== null) {
return;
- }
+ }
- let tbb = vAPI.toolbarButton;
- if (tbb.init !== null) {
- return;
- }
+ tbb.codePath = 'legacy';
+ tbb.viewId = tbb.id + '-panel';
- tbb.codePath = 'legacy';
- tbb.viewId = tbb.id + '-panel';
+ let styleSheetUri = null;
- let styleSheetUri = null;
-
- let createToolbarButton = function (window) {
+ let createToolbarButton = function (window) {
let document = window.document;
let toolbarButton = document.createElement('toolbarbutton');
@@ -699,40 +694,40 @@
toolbarButton.setAttribute('type', 'menu');
toolbarButton.setAttribute('removable', 'true');
toolbarButton.setAttribute('class', 'toolbarbutton-1 '
- +'chromeclass-toolbar-additional');
+ +'chromeclass-toolbar-additional');
toolbarButton.setAttribute('label', tbb.label);
- toolbarButton.setAttribute('tooltiptext', tbb.tooltiptext);
+ toolbarButton.setAttribute('tooltiptext', tbb.tooltiptext);
let toolbarButtonPanel = document.createElement('panel');
// NOTE: Setting level to parent breaks the popup for PaleMoon under
// linux (mouse pointer misaligned with content). For some reason.
- // eMatrix: TODO check if it's still true
+ // eMatrix: TODO check if it's still true
// toolbarButtonPanel.setAttribute('level', 'parent');
tbb.populatePanel(document, toolbarButtonPanel);
toolbarButtonPanel.addEventListener('popupshowing',
- tbb.onViewShowing);
+ tbb.onViewShowing);
toolbarButtonPanel.addEventListener('popuphiding',
- tbb.onViewHiding);
+ tbb.onViewHiding);
toolbarButton.appendChild(toolbarButtonPanel);
- toolbarButtonPanel.setAttribute('tooltiptext', '');
+ toolbarButtonPanel.setAttribute('tooltiptext', '');
return toolbarButton;
- };
+ };
- let addLegacyToolbarButton = function (window) {
+ let addLegacyToolbarButton = function (window) {
// eMatrix's stylesheet lazily added.
if (styleSheetUri === null) {
- var sss = Cc["@mozilla.org/content/style-sheet-service;1"]
+ var sss = Cc["@mozilla.org/content/style-sheet-service;1"]
.getService(Ci.nsIStyleSheetService);
- styleSheetUri = Services.io
- .newURI(vAPI.getURL("css/legacy-toolbar-button.css"),
- null, null);
+ styleSheetUri = Services.io
+ .newURI(vAPI.getURL("css/legacy-toolbar-button.css"),
+ null, null);
- // Register global so it works in all windows, including palette
- if (!sss.sheetRegistered(styleSheetUri, sss.AUTHOR_SHEET)) {
+ // Register global so it works in all windows, including palette
+ if (!sss.sheetRegistered(styleSheetUri, sss.AUTHOR_SHEET)) {
sss.loadAndRegisterSheet(styleSheetUri, sss.AUTHOR_SHEET);
- }
+ }
}
let document = window.document;
@@ -740,21 +735,21 @@
// https://github.com/gorhill/uMatrix/issues/357
// Already installed?
if (document.getElementById(tbb.id) !== null) {
- return;
+ return;
}
let toolbox = document.getElementById('navigator-toolbox')
- || document.getElementById('mail-toolbox');
+ || document.getElementById('mail-toolbox');
if (toolbox === null) {
- return;
+ return;
}
let toolbarButton = createToolbarButton(window);
let palette = toolbox.palette;
if (palette && palette.querySelector('#' + tbb.id) === null) {
- palette.appendChild(toolbarButton);
+ palette.appendChild(toolbarButton);
}
// Find the place to put the button.
@@ -762,75 +757,75 @@
// undefined. Seen while testing popup test number 3:
// http://raymondhill.net/ublock/popup.html
let toolbars = toolbox.externalToolbars
- ? toolbox.externalToolbars.slice()
- : [];
+ ? toolbox.externalToolbars.slice()
+ : [];
for (let child of toolbox.children) {
- if (child.localName === 'toolbar') {
+ if (child.localName === 'toolbar') {
toolbars.push(child);
- }
+ }
}
for (let toolbar of toolbars) {
- let currentsetString = toolbar.getAttribute('currentset');
- if (!currentsetString) {
+ let currentsetString = toolbar.getAttribute('currentset');
+ if (!currentsetString) {
continue;
- }
+ }
- let currentset = currentsetString.split(/\s*,\s*/);
- let index = currentset.indexOf(tbb.id);
- if (index === -1) {
+ let currentset = currentsetString.split(/\s*,\s*/);
+ let index = currentset.indexOf(tbb.id);
+ if (index === -1) {
continue;
- }
+ }
- // This can occur with Pale Moon:
- // "TypeError: toolbar.insertItem is not a function"
- if (typeof toolbar.insertItem !== 'function') {
+ // This can occur with Pale Moon:
+ // "TypeError: toolbar.insertItem is not a function"
+ if (typeof toolbar.insertItem !== 'function') {
continue;
- }
-
- // Found our button on this toolbar - but where on it?
- let before = null;
- for (let i=index+1; i<currentset.length; ++i) {
- // The [id=...] notation doesn't work on
- // space elements as they get a random ID each session
- // (or something like that)
- // https://gitlab.com/vannilla/ematrix/issues/5
- // https://gitlab.com/vannilla/ematrix/issues/6
-
- // Based on JustOff's snippet from the Pale Moon
- // forum. It was reorganized because I find it
- // more readable like this, but he did most of the
- // work.
- let space = /^(spring|spacer|separator)$/.exec(currentset[i]);
- if (space !== null) {
- let elems = toolbar.querySelectorAll('toolbar'+space[1]);
-
- let count = currentset.slice(i-currentset.length)
- .filter(function (x) {return x == space[1];})
- .length;
-
- before =
- toolbar.querySelector('[id="'
- + elems[elems.length-count].id
- + '"]');
- } else {
- before = toolbar.querySelector('[id="'+currentset[i]+'"]');
- }
+ }
+
+ // Found our button on this toolbar - but where on it?
+ let before = null;
+ for (let i=index+1; i<currentset.length; ++i) {
+ // The [id=...] notation doesn't work on
+ // space elements as they get a random ID each session
+ // (or something like that)
+ // https://gitlab.com/vannilla/ematrix/issues/5
+ // https://gitlab.com/vannilla/ematrix/issues/6
+
+ // Based on JustOff's snippet from the Pale Moon
+ // forum. It was reorganized because I find it
+ // more readable like this, but he did most of the
+ // work.
+ let space = /^(spring|spacer|separator)$/.exec(currentset[i]);
+ if (space !== null) {
+ let elems = toolbar.querySelectorAll('toolbar'+space[1]);
+
+ let count = currentset.slice(i-currentset.length)
+ .filter(function (x) {return x == space[1];})
+ .length;
+
+ before =
+ toolbar.querySelector('[id="'
+ + elems[elems.length-count].id
+ + '"]');
+ } else {
+ before = toolbar.querySelector('[id="'+currentset[i]+'"]');
+ }
if ( before !== null ) {
- break;
+ break;
}
- }
+ }
- toolbar.insertItem(tbb.id, before);
- break;
+ toolbar.insertItem(tbb.id, before);
+ break;
}
// https://github.com/gorhill/uBlock/issues/763
// We are done if our toolbar button is already installed
// in one of the toolbar.
if (palette !== null && toolbarButton.parentElement !== palette) {
- return;
+ return;
}
// No button yet so give it a default location. If forcing
@@ -839,386 +834,200 @@
// available or visible!)
let navbar = document.getElementById('nav-bar');
if (navbar !== null
- && !vAPI.localStorage.getBool('legacyToolbarButtonAdded')) {
- // https://github.com/gorhill/uBlock/issues/264
- // Find a child customizable palette, if any.
- navbar = navbar.querySelector('.customization-target') || navbar;
- navbar.appendChild(toolbarButton);
- navbar.setAttribute('currentset', navbar.currentSet);
- document.persist(navbar.id, 'currentset');
- vAPI.localStorage.setBool('legacyToolbarButtonAdded', 'true');
+ && !vAPI.localStorage.getBool('legacyToolbarButtonAdded')) {
+ // https://github.com/gorhill/uBlock/issues/264
+ // Find a child customizable palette, if any.
+ navbar = navbar.querySelector('.customization-target') || navbar;
+ navbar.appendChild(toolbarButton);
+ navbar.setAttribute('currentset', navbar.currentSet);
+ document.persist(navbar.id, 'currentset');
+ vAPI.localStorage.setBool('legacyToolbarButtonAdded', 'true');
}
- };
+ };
- let canAddLegacyToolbarButton = function (window) {
+ let canAddLegacyToolbarButton = function (window) {
let document = window.document;
if (!document
- || document.readyState !== 'complete'
- || document.getElementById('nav-bar') === null) {
- return false;
+ || document.readyState !== 'complete'
+ || document.getElementById('nav-bar') === null) {
+ return false;
}
let toolbox = document.getElementById('navigator-toolbox')
- || document.getElementById('mail-toolbox');
+ || document.getElementById('mail-toolbox');
return toolbox !== null && !!toolbox.palette;
- };
+ };
- let onPopupCloseRequested = function ({target}) {
+ let onPopupCloseRequested = function ({target}) {
let document = target.ownerDocument;
if (!document) {
- return;
+ return;
}
let toolbarButtonPanel = document.getElementById(tbb.viewId);
if (toolbarButtonPanel === null) {
- return;
+ return;
}
// `hidePopup` reported as not existing while testing
// legacy button on FF 41.0.2.
// https://bugzilla.mozilla.org/show_bug.cgi?id=1151796
if (typeof toolbarButtonPanel.hidePopup === 'function') {
- toolbarButtonPanel.hidePopup();
+ toolbarButtonPanel.hidePopup();
}
- };
+ };
- let shutdown = function () {
+ let shutdown = function () {
for (let win of vAPI.window.getWindows()) {
- let toolbarButton = win.document.getElementById(tbb.id);
- if (toolbarButton) {
+ let toolbarButton = win.document.getElementById(tbb.id);
+ if (toolbarButton) {
toolbarButton.parentNode.removeChild(toolbarButton);
- }
+ }
}
if (styleSheetUri !== null) {
- var sss = Cc["@mozilla.org/content/style-sheet-service;1"]
+ var sss = Cc["@mozilla.org/content/style-sheet-service;1"]
.getService(Ci.nsIStyleSheetService);
- if (sss.sheetRegistered(styleSheetUri, sss.AUTHOR_SHEET)) {
+ if (sss.sheetRegistered(styleSheetUri, sss.AUTHOR_SHEET)) {
sss.unregisterSheet(styleSheetUri, sss.AUTHOR_SHEET);
- }
- styleSheetUri = null;
+ }
+ styleSheetUri = null;
}
vAPI.messaging.globalMessageManager
- .removeMessageListener(location.host + ':closePopup',
- onPopupCloseRequested);
- };
+ .removeMessageListener(location.host + ':closePopup',
+ onPopupCloseRequested);
+ };
- tbb.attachToNewWindow = function (win) {
+ tbb.attachToNewWindow = function (win) {
vAPI.deferUntil(canAddLegacyToolbarButton.bind(null, win),
- addLegacyToolbarButton.bind(null, win));
- };
-
- tbb.init = function () {
- vAPI.messaging.globalMessageManager
- .addMessageListener(location.host + ':closePopup',
- onPopupCloseRequested);
-
- vAPI.addCleanUpTask(shutdown);
- };
- })();
-
- (function() {
- // Add toolbar button for Basilisk
- if (Services.appinfo.ID !== "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}") {
- return;
- }
-
- let tbb = vAPI.toolbarButton;
- if (tbb.init !== null) {
- return;
- }
- // if ( Services.vc.compare(Services.appinfo.version, '36.0') < 0 ) {
- // return null;
- // }
- let CustomizableUI = null;
- try {
- CustomizableUI =
- Cu.import('resource:///modules/CustomizableUI.jsm', null)
- .CustomizableUI;
- } catch (ex) {
- // Ignore
- }
- if (CustomizableUI === null) {
- return null;
- }
- tbb.codePath = 'australis';
- tbb.CustomizableUI = CustomizableUI;
- tbb.defaultArea = CustomizableUI.AREA_NAVBAR;
-
- let CUIEvents = {};
-
- let badgeCSSRules = 'background: #000;color: #fff';
-
- let updateBadgeStyle = function () {
- for (let win of vAPI.window.getWindows()) {
- let button = win.document.getElementById(tbb.id);
- if (button === null) {
- continue;
- }
- let badge = button.ownerDocument
- .getAnonymousElementByAttribute(button,
- 'class',
- 'toolbarbutton-badge');
- if (!badge) {
- continue;
- }
-
- badge.style.cssText = badgeCSSRules;
- }
- };
-
- let updateBadge = function () {
- let wId = tbb.id;
- let buttonInPanel =
- CustomizableUI.getWidget(wId).areaType
- === CustomizableUI.TYPE_MENU_PANEL;
-
- for (let win of vAPI.window.getWindows()) {
- let button = win.document.getElementById(wId);
- if (button === null) {
- continue;
- }
-
- if (buttonInPanel) {
- button.classList.remove('badged-button');
- continue;
- }
-
- button.classList.add('badged-button');
- }
-
- if (buttonInPanel) {
- return;
- }
-
- // Anonymous elements need some time to be reachable
- vAPI.setTimeout(updateBadgeStyle, 250);
- }.bind(CUIEvents);
-
- CUIEvents.onCustomizeEnd = updateBadge;
- CUIEvents.onWidgetAdded = updateBadge;
- CUIEvents.onWidgetUnderflow = updateBadge;
-
- let onPopupCloseRequested = function ({target}) {
- if (typeof tbb.closePopup === 'function') {
- tbb.closePopup(target);
- }
- };
-
- let shutdown = function () {
- for (let win of vAPI.window.getWindows()) {
- let panel = win.document.getElementById(tbb.viewId);
- if (panel !== null && panel.parentNode !== null) {
- panel.parentNode.removeChild(panel);
- }
-
- win.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindowUtils)
- .removeSheet(styleURI, 1);
- }
-
- CustomizableUI.removeListener(CUIEvents);
- CustomizableUI.destroyWidget(tbb.id);
-
- vAPI.messaging.globalMessageManager
- .removeMessageListener(location.host + ':closePopup',
- onPopupCloseRequested);
- };
-
- let styleURI = null;
-
- tbb.onBeforeCreated = function (doc) {
- let panel = doc.createElement('panelview');
-
- this.populatePanel(doc, panel);
-
- doc.getElementById('PanelUI-multiView').appendChild(panel);
-
- doc.defaultView.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindowUtils)
- .loadSheet(styleURI, 1);
- };
-
- tbb.onCreated = function (button) {
- button.setAttribute('badge', '');
- vAPI.setTimeout(updateBadge, 250);
- };
-
- tbb.onBeforePopupReady = function () {
- // https://github.com/gorhill/uBlock/issues/83
- // Add `portrait` class if width is constrained.
- try {
- this.contentDocument.body
- .classList.toggle('portrait',
- CustomizableUI.getWidget(tbb.id).areaType
- === CustomizableUI.TYPE_MENU_PANEL);
- } catch (ex) {
- // Ignore
- }
- };
-
- tbb.closePopup = function (tabBrowser) {
- CustomizableUI.hidePanelForNode(tabBrowser
- .ownerDocument
- .getElementById(tbb.viewId));
- };
+ addLegacyToolbarButton.bind(null, win));
+ };
- tbb.init = function () {
+ tbb.init = function () {
vAPI.messaging.globalMessageManager
- .addMessageListener(location.host + ':closePopup',
- onPopupCloseRequested);
-
- CustomizableUI.addListener(CUIEvents);
-
- var style = [
- '#' + this.id + '.off {',
- 'list-style-image: url(',
- vAPI.getURL('img/browsericons/icon19-off.png'),
- ');',
- '}',
- '#' + this.id + ' {',
- 'list-style-image: url(',
- vAPI.getURL('img/browsericons/icon19-19.png'),
- ');',
- '}',
- '#' + this.viewId + ', #' + this.viewId + ' > iframe {',
- 'height: 290px;',
- 'max-width: none !important;',
- 'min-width: 0 !important;',
- 'overflow: hidden !important;',
- 'padding: 0 !important;',
- 'width: 160px;',
- '}'
- ];
-
- styleURI =
- Services.io.newURI('data:text/css,'
- +encodeURIComponent(style.join('')),
- null,
- null);
-
- CustomizableUI.createWidget(this);
+ .addMessageListener(location.host + ':closePopup',
+ onPopupCloseRequested);
vAPI.addCleanUpTask(shutdown);
- };
+ };
})();
// No toolbar button.
(function () {
- // Just to ensure the number of cleanup tasks is as expected: toolbar
- // button code is one single cleanup task regardless of platform.
- // eMatrix: might not be needed anymore
- if (vAPI.toolbarButton.init === null) {
+ // Just to ensure the number of cleanup tasks is as expected: toolbar
+ // button code is one single cleanup task regardless of platform.
+ // eMatrix: might not be needed anymore
+ if (vAPI.toolbarButton.init === null) {
vAPI.addCleanUpTask(function(){});
- }
+ }
})();
if (vAPI.toolbarButton.init !== null) {
- vAPI.toolbarButton.init();
+ vAPI.toolbarButton.init();
}
let optionsObserver = (function () {
- let addonId = 'eMatrix@vannilla.org';
+ let addonId = 'eMatrix@vannilla.org';
- let commandHandler = function () {
+ let commandHandler = function () {
switch (this.id) {
case 'showDashboardButton':
- vAPI.tabs.open({
- url: 'dashboard.html',
- index: -1,
- });
- break;
+ vAPI.tabs.open({
+ url: 'dashboard.html',
+ index: -1,
+ });
+ break;
case 'showLoggerButton':
- vAPI.tabs.open({
- url: 'logger-ui.html',
- index: -1,
- });
- break;
+ vAPI.tabs.open({
+ url: 'logger-ui.html',
+ index: -1,
+ });
+ break;
default:
- break;
+ break;
}
- };
+ };
- let setupOptionsButton = function (doc, id) {
+ let setupOptionsButton = function (doc, id) {
let button = doc.getElementById(id);
if (button === null) {
- return;
+ return;
}
button.addEventListener('command', commandHandler);
button.label = vAPI.i18n(id);
- };
+ };
- let setupOptionsButtons = function (doc) {
+ let setupOptionsButtons = function (doc) {
setupOptionsButton(doc, 'showDashboardButton');
setupOptionsButton(doc, 'showLoggerButton');
- };
+ };
- let observer = {
+ let observer = {
observe: function (doc, topic, id) {
- if (id !== addonId) {
+ if (id !== addonId) {
return;
- }
+ }
- setupOptionsButtons(doc);
+ setupOptionsButtons(doc);
}
- };
+ };
- var canInit = function() {
- // https://github.com/gorhill/uBlock/issues/948
- // Older versions of Firefox can throw here when looking
- // up `currentURI`.
+ var canInit = function() {
+ // https://github.com/gorhill/uBlock/issues/948
+ // Older versions of Firefox can throw here when looking
+ // up `currentURI`.
try {
- let tabBrowser = vAPI.tabs.manager.currentBrowser();
- return tabBrowser
- && tabBrowser.currentURI
- && tabBrowser.currentURI.spec === 'about:addons'
- && tabBrowser.contentDocument
- && tabBrowser.contentDocument.readyState === 'complete';
+ let tabBrowser = vAPI.tabs.manager.currentBrowser();
+ return tabBrowser
+ && tabBrowser.currentURI
+ && tabBrowser.currentURI.spec === 'about:addons'
+ && tabBrowser.contentDocument
+ && tabBrowser.contentDocument.readyState === 'complete';
} catch (ex) {
- // Ignore
+ // Ignore
}
- };
+ };
- // Manually add the buttons if the `about:addons` page is
- // already opened.
- let init = function () {
+ // Manually add the buttons if the `about:addons` page is
+ // already opened.
+ let init = function () {
if (canInit()) {
- setupOptionsButtons(vAPI.tabs.manager
- .currentBrowser().contentDocument);
+ setupOptionsButtons(vAPI.tabs.manager
+ .currentBrowser().contentDocument);
}
- };
+ };
- let unregister = function () {
+ let unregister = function () {
Services.obs.removeObserver(observer, 'addon-options-displayed');
- };
+ };
- let register = function () {
+ let register = function () {
Services.obs.addObserver(observer,
- 'addon-options-displayed',
- false);
+ 'addon-options-displayed',
+ false);
vAPI.addCleanUpTask(unregister);
vAPI.deferUntil(canInit, init, { next: 463 });
- };
+ };
- return {
+ return {
register: register,
unregister: unregister
- };
+ };
})();
optionsObserver.register();
vAPI.onLoadAllCompleted = function() {
- // This is called only once, when everything has been loaded
- // in memory after the extension was launched. It can be used
- // to inject content scripts in already opened web pages, to
- // remove whatever nuisance could make it to the web pages
- // before uBlock was ready.
- for (let browser of vAPI.tabs.manager.browsers()) {
+ // This is called only once, when everything has been loaded
+ // in memory after the extension was launched. It can be used
+ // to inject content scripts in already opened web pages, to
+ // remove whatever nuisance could make it to the web pages
+ // before uBlock was ready.
+ for (let browser of vAPI.tabs.manager.browsers()) {
browser.messageManager
- .sendAsyncMessage(location.host + '-load-completed');
- }
+ .sendAsyncMessage(location.host + '-load-completed');
+ }
};
// Likelihood is that we do not have to punycode: given punycode overhead,
@@ -1227,16 +1036,16 @@
var isNotASCII = /[^\x21-\x7F]/;
vAPI.punycodeHostname = function (hostname) {
- return isNotASCII.test(hostname)
- ? punycodeHostname(hostname)
- : hostname;
+ return isNotASCII.test(hostname)
+ ? punycodeHostname(hostname)
+ : hostname;
};
vAPI.punycodeURL = function (url) {
- if (isNotASCII.test(url)) {
+ if (isNotASCII.test(url)) {
return Services.io.newURI(url, null, null).asciiSpec;
- }
+ }
- return url;
+ return url;
};
})();
diff --git a/js/vapi-browser.js b/js/vapi-browser.js
index 48474f9..2d92498 100644
--- a/js/vapi-browser.js
+++ b/js/vapi-browser.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 The uMatrix/uBlock Origin authors
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -29,48 +29,48 @@
vAPI.browser = {};
vAPI.browser.getTabBrowser = function (win) {
- return win && win.gBrowser || null;
+ return win && win.gBrowser || null;
};
vAPI.browser.getOwnerWindow = function (target) {
- if (target.ownerDocument) {
+ if (target.ownerDocument) {
return target.ownerDocument.defaultView;
- }
+ }
- return null;
+ return null;
};
vAPI.browser.settings = {
- // For now, only booleans.
- originalValues: {},
+ // For now, only booleans.
+ originalValues: {},
- rememberOriginalValue: function (path, setting) {
+ rememberOriginalValue: function (path, setting) {
let key = path + '.' + setting;
if (this.originalValues.hasOwnProperty(key)) {
- return;
+ return;
}
let hasUserValue;
let branch = Services.prefs.getBranch(path + '.');
try {
- hasUserValue = branch.prefHasUserValue(setting);
+ hasUserValue = branch.prefHasUserValue(setting);
} catch (ex) {
- // Ignore
+ // Ignore
}
if (hasUserValue !== undefined) {
- this.originalValues[key] = hasUserValue
- ? this.getValue(path, setting)
- : undefined;
+ this.originalValues[key] = hasUserValue
+ ? this.getValue(path, setting)
+ : undefined;
}
- },
- clear: function (path, setting) {
+ },
+ clear: function (path, setting) {
let key = path + '.' + setting;
// Value was not overriden -- nothing to restore
if (this.originalValues.hasOwnProperty(key) === false) {
- return;
+ return;
}
let value = this.originalValues[key];
@@ -82,160 +82,160 @@
// Original value was a default one
if (value === undefined) {
- try {
+ try {
Services.prefs.getBranch(path + '.').clearUserPref(setting);
- } catch (ex) {
- // Ignore
- }
- return;
+ } catch (ex) {
+ // Ignore
+ }
+ return;
}
// Reset to original value
this.setValue(path, setting, value);
- },
- getValue: function (path, setting) {
+ },
+ getValue: function (path, setting) {
let branch = Services.prefs.getBranch(path + '.');
- try {
- switch (branch.getPrefType(setting)) {
- case branch.PREF_INT:
- return branch.getIntPref(setting);
- case branch.PREF_BOOL:
- return branch.getBoolPref(setting);
- default:
- // not supported
- return;
- }
- } catch (e) {
- // Ignore
- }
- },
- setValue: function (path, setting, value) {
- let branch = Services.prefs.getBranch(path + '.');
-
- try {
- switch (typeof value) {
- case 'number':
- return branch.setIntPref(setting, value);
- case 'boolean':
- return branch.setBoolPref(setting, value);
- default:
- // not supported
- return;
- }
- } catch (e) {
- // Ignore
- }
- },
- setSetting: function (setting, value) {
+ try {
+ switch (branch.getPrefType(setting)) {
+ case branch.PREF_INT:
+ return branch.getIntPref(setting);
+ case branch.PREF_BOOL:
+ return branch.getBoolPref(setting);
+ default:
+ // not supported
+ return;
+ }
+ } catch (e) {
+ // Ignore
+ }
+ },
+ setValue: function (path, setting, value) {
+ let branch = Services.prefs.getBranch(path + '.');
+
+ try {
+ switch (typeof value) {
+ case 'number':
+ return branch.setIntPref(setting, value);
+ case 'boolean':
+ return branch.setBoolPref(setting, value);
+ default:
+ // not supported
+ return;
+ }
+ } catch (e) {
+ // Ignore
+ }
+ },
+ setSetting: function (setting, value) {
switch (setting) {
case 'prefetching':
- this.rememberOriginalValue('network', 'prefetch-next');
- // https://bugzilla.mozilla.org/show_bug.cgi?id=814169
- // Sigh.
- // eMatrix: doesn't seem the case for Pale
- // Moon/Basilisk, but let's keep this anyway
- this.rememberOriginalValue('network.http', 'speculative-parallel-limit');
-
- // https://github.com/gorhill/uBlock/issues/292
- // "true" means "do not disable", i.e. leave entry alone
- if (value) {
+ this.rememberOriginalValue('network', 'prefetch-next');
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=814169
+ // Sigh.
+ // eMatrix: doesn't seem the case for Pale
+ // Moon/Basilisk, but let's keep this anyway
+ this.rememberOriginalValue('network.http', 'speculative-parallel-limit');
+
+ // https://github.com/gorhill/uBlock/issues/292
+ // "true" means "do not disable", i.e. leave entry alone
+ if (value) {
this.clear('network', 'prefetch-next');
this.clear('network.http', 'speculative-parallel-limit');
- } else {
+ } else {
this.setValue('network', 'prefetch-next', false);
this.setValue('network.http',
- 'speculative-parallel-limit', 0);
- }
- break;
+ 'speculative-parallel-limit', 0);
+ }
+ break;
case 'hyperlinkAuditing':
- this.rememberOriginalValue('browser', 'send_pings');
- this.rememberOriginalValue('beacon', 'enabled');
+ this.rememberOriginalValue('browser', 'send_pings');
+ this.rememberOriginalValue('beacon', 'enabled');
- // https://github.com/gorhill/uBlock/issues/292
- // "true" means "do not disable", i.e. leave entry alone
- if (value) {
+ // https://github.com/gorhill/uBlock/issues/292
+ // "true" means "do not disable", i.e. leave entry alone
+ if (value) {
this.clear('browser', 'send_pings');
this.clear('beacon', 'enabled');
- } else {
+ } else {
this.setValue('browser', 'send_pings', false);
this.setValue('beacon', 'enabled', false);
- }
- break;
+ }
+ break;
case 'webrtcIPAddress':
- let prefName;
- let prefVal;
-
- // https://github.com/gorhill/uBlock/issues/894
- // Do not disable completely WebRTC if it can be avoided. FF42+
- // has a `media.peerconnection.ice.default_address_only` pref which
- // purpose is to prevent local IP address leakage.
- if (this.getValue('media.peerconnection',
- 'ice.default_address_only') !== undefined) {
+ let prefName;
+ let prefVal;
+
+ // https://github.com/gorhill/uBlock/issues/894
+ // Do not disable completely WebRTC if it can be avoided. FF42+
+ // has a `media.peerconnection.ice.default_address_only` pref which
+ // purpose is to prevent local IP address leakage.
+ if (this.getValue('media.peerconnection',
+ 'ice.default_address_only') !== undefined) {
prefName = 'ice.default_address_only';
prefVal = true;
- } else {
+ } else {
prefName = 'enabled';
prefVal = false;
- }
+ }
- this.rememberOriginalValue('media.peerconnection', prefName);
- if (value) {
+ this.rememberOriginalValue('media.peerconnection', prefName);
+ if (value) {
this.clear('media.peerconnection', prefName);
- } else {
+ } else {
this.setValue('media.peerconnection', prefName, prefVal);
- }
- break;
+ }
+ break;
default:
- break;
+ break;
}
- },
- set: function (details) {
+ },
+ set: function (details) {
for (let setting in details) {
- if (details.hasOwnProperty(setting) === false) {
+ if (details.hasOwnProperty(setting) === false) {
continue;
- }
- this.setSetting(setting, !!details[setting]);
+ }
+ this.setSetting(setting, !!details[setting]);
}
- },
- restoreAll: function () {
+ },
+ restoreAll: function () {
let pos;
for (let key in this.originalValues) {
- if (this.originalValues.hasOwnProperty(key) === false) {
+ if (this.originalValues.hasOwnProperty(key) === false) {
continue;
- }
+ }
- pos = key.lastIndexOf('.');
- this.clear(key.slice(0, pos), key.slice(pos + 1));
+ pos = key.lastIndexOf('.');
+ this.clear(key.slice(0, pos), key.slice(pos + 1));
}
- },
+ },
};
vAPI.addCleanUpTask(vAPI.browser.settings
- .restoreAll.bind(vAPI.browser.settings));
+ .restoreAll.bind(vAPI.browser.settings));
vAPI.browser.data = {};
vAPI.browser.data.clearCache = function (callback) {
- // PURGE_DISK_DATA_ONLY:1
- // PURGE_DISK_ALL:2
- // PURGE_EVERYTHING:3
- // However I verified that no argument does clear the cache data.
- // There is no cache2 for older versions of Firefox.
- if (Services.cache2) {
+ // PURGE_DISK_DATA_ONLY:1
+ // PURGE_DISK_ALL:2
+ // PURGE_EVERYTHING:3
+ // However I verified that no argument does clear the cache data.
+ // There is no cache2 for older versions of Firefox.
+ if (Services.cache2) {
Services.cache2.clear();
- } else if (Services.cache) {
+ } else if (Services.cache) {
Services.cache.evictEntries(Services.cache.STORE_ON_DISK);
- }
+ }
- if (typeof callback === 'function') {
+ if (typeof callback === 'function') {
callback();
- }
+ }
};
vAPI.browser.data.clearOrigin = function(/* domain */) {
- // TODO
- // eMatrix: is this actually needed? I don't really know what
- // it's supposed to do anyway.
+ // TODO
+ // eMatrix: is this actually needed? I don't really know what
+ // it's supposed to do anyway.
};
})();
diff --git a/js/vapi-client.js b/js/vapi-client.js
index 40598b8..4635853 100644
--- a/js/vapi-client.js
+++ b/js/vapi-client.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 The uMatrix/uBlock Origin authors
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -27,66 +27,66 @@
(function (self) {
if (self.vAPI === undefined) {
- self.vAPI = {};
+ self.vAPI = {};
}
let vAPI = self.vAPI;
vAPI.setTimeout = vAPI.setTimeout || function (callback, delay, extra) {
- return setTimeout(function (a) {
- callback(a);
- }, delay, extra);
+ return setTimeout(function (a) {
+ callback(a);
+ }, delay, extra);
};
vAPI.sessionId = String.fromCharCode(Date.now() % 25 + 97) +
- Math.random().toString(36).slice(2);
+ Math.random().toString(36).slice(2);
vAPI.shutdown = (function () {
- let jobs = [];
+ let jobs = [];
- let add = function (job) {
+ let add = function (job) {
jobs.push(job);
- };
+ };
- let exec = function () {
+ let exec = function () {
//console.debug('Shutting down...');
let job;
while ((job = jobs.pop())) {
- job();
+ job();
}
- };
+ };
- return {
+ return {
add: add,
exec: exec
- };
+ };
})();
vAPI.messaging = {
- listeners: new Set(),
- pending: new Map(),
- requestId: 1,
- connected: false,
- messageListenerCallback: null,
- toggleListenerCallback: null,
-
- start: function () {
+ listeners: new Set(),
+ pending: new Map(),
+ requestId: 1,
+ connected: false,
+ messageListenerCallback: null,
+ toggleListenerCallback: null,
+
+ start: function () {
this.addListener(this.builtinListener);
if (this.toggleListenerCallback === null) {
- this.toggleListenerCallback = this.toggleListener.bind(this);
+ this.toggleListenerCallback = this.toggleListener.bind(this);
}
window.addEventListener('pagehide',
- this.toggleListenerCallback, true);
+ this.toggleListenerCallback, true);
window.addEventListener('pageshow',
- this.toggleListenerCallback, true);
- },
- shutdown: function () {
+ this.toggleListenerCallback, true);
+ },
+ shutdown: function () {
if (this.toggleListenerCallback !== null) {
- window.removeEventListener('pagehide',
- this.toggleListenerCallback, true);
- window.removeEventListener('pageshow',
- this.toggleListenerCallback, true);
+ window.removeEventListener('pagehide',
+ this.toggleListenerCallback, true);
+ window.removeEventListener('pageshow',
+ this.toggleListenerCallback, true);
}
this.removeAllListeners();
@@ -94,100 +94,100 @@
var pending = this.pending;
this.pending.clear();
for (let callback of pending.values()) {
- if (typeof callback === 'function') {
+ if (typeof callback === 'function') {
callback(null);
- }
+ }
}
- },
- connect: function () {
+ },
+ connect: function () {
if (!this.connected) {
- if (this.messageListenerCallback === null) {
+ if (this.messageListenerCallback === null) {
this.messageListenerCallback =
- this.messageListener.bind(this);
- }
- addMessageListener(this.messageListenerCallback);
- this.connected = true;
+ this.messageListener.bind(this);
+ }
+ addMessageListener(this.messageListenerCallback);
+ this.connected = true;
}
- },
- disconnect: function () {
+ },
+ disconnect: function () {
if (this.connected) {
- removeMessageListener();
- this.connected = false;
+ removeMessageListener();
+ this.connected = false;
}
- },
- messageListener: function (msg) {
+ },
+ messageListener: function (msg) {
let details = JSON.parse(msg);
if (!details) {
- return;
+ return;
}
if (details.broadcast) {
- this.sendToListeners(details.msg);
- return;
+ this.sendToListeners(details.msg);
+ return;
}
if (details.requestId) {
- let listener = this.pending.get(details.requestId);
- if (listener !== undefined) {
+ let listener = this.pending.get(details.requestId);
+ if (listener !== undefined) {
this.pending.delete(details.requestId);
listener(details.msg);
return;
- }
+ }
}
- },
- builtinListener: function (msg) {
+ },
+ builtinListener: function (msg) {
if (typeof msg.cmd === 'string' && msg.cmd === 'injectScript') {
- let details = msg.details;
- if (!details.allFrames && window !== window.top) {
+ let details = msg.details;
+ if (!details.allFrames && window !== window.top) {
return;
- }
- self.injectScript(details.file);
+ }
+ self.injectScript(details.file);
}
- },
- send: function (channelName, message, callback) {
+ },
+ send: function (channelName, message, callback) {
this.connect()
message = {
- channelName: self._sandboxId_ + '|' + channelName,
- msg: message
+ channelName: self._sandboxId_ + '|' + channelName,
+ msg: message
};
if (callback) {
- message.requestId = this.requestId++;
- this.pending.set(message.requestId, callback);
+ message.requestId = this.requestId++;
+ this.pending.set(message.requestId, callback);
}
sendAsyncMessage('ematrix:background', message);
- },
- toggleListener: function ({type, persisted}) {
+ },
+ toggleListener: function ({type, persisted}) {
if (type === 'pagehide' && !persisted) {
- vAPI.shutdown.exec();
- this.shutdown();
- return;
+ vAPI.shutdown.exec();
+ this.shutdown();
+ return;
}
if (type === 'pagehide') {
- this.disconnect();
+ this.disconnect();
} else {
- this.connect();
+ this.connect();
}
- },
- sendToListeners: function (msg) {
+ },
+ sendToListeners: function (msg) {
for (let listener of this.listeners) {
- listener(msg);
+ listener(msg);
}
- },
- addListener: function (listener) {
+ },
+ addListener: function (listener) {
this.listeners.add(listener);
this.connect()
- },
- removeListener: function (listener) {
+ },
+ removeListener: function (listener) {
this.listeners.delete(listener);
- },
- removeAllListeners: function () {
+ },
+ removeAllListeners: function () {
this.disconnect();
this.listeners.clear();
- }
+ }
};
vAPI.messaging.start()
@@ -197,8 +197,8 @@
// be injected in top window).
// Needs more investigating
// if ( window !== window.top ) {
- // vAPI.shutdown.add(function() {
- // vAPI = null;
- // });
+ // vAPI.shutdown.add(function() {
+ // vAPI = null;
+ // });
// }
})(this);
diff --git a/js/vapi-cloud.js b/js/vapi-cloud.js
index 70d7907..c86f351 100644
--- a/js/vapi-cloud.js
+++ b/js/vapi-cloud.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 The uMatrix/uBlock Origin authors
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -27,130 +27,130 @@
(function () {
vAPI.cloud = (function () {
- let extensionBranchPath = 'extensions.' + location.host;
- let cloudBranchPath = extensionBranchPath + '.cloudStorage';
-
- // https://github.com/gorhill/uBlock/issues/80#issuecomment-132081658
- // We must use get/setComplexValue in order to properly handle strings
- // with unicode characters.
- let iss = Ci.nsISupportsString;
- let argstr = Components.classes['@mozilla.org/supports-string;1']
+ let extensionBranchPath = 'extensions.' + location.host;
+ let cloudBranchPath = extensionBranchPath + '.cloudStorage';
+
+ // https://github.com/gorhill/uBlock/issues/80#issuecomment-132081658
+ // We must use get/setComplexValue in order to properly handle strings
+ // with unicode characters.
+ let iss = Ci.nsISupportsString;
+ let argstr = Components.classes['@mozilla.org/supports-string;1']
.createInstance(iss);
- let options = {
+ let options = {
defaultDeviceName: '',
deviceName: ''
- };
+ };
- // User-supplied device name.
- try {
+ // User-supplied device name.
+ try {
options.deviceName = Services.prefs
.getBranch(extensionBranchPath + '.')
.getComplexValue('deviceName', iss)
.data;
- } catch(ex) {
- // Ignore
- }
+ } catch(ex) {
+ // Ignore
+ }
- var getDefaultDeviceName = function() {
+ var getDefaultDeviceName = function() {
var name = '';
try {
- name = Services.prefs
+ name = Services.prefs
.getBranch('services.sync.client.')
.getComplexValue('name', iss)
.data;
} catch(ex) {
- // Ignore
+ // Ignore
}
return name || window.navigator.platform || window.navigator.oscpu;
- };
+ };
- let start = function (dataKeys) {
+ let start = function (dataKeys) {
let extensionBranch =
- Services.prefs.getBranch(extensionBranchPath + '.');
+ Services.prefs.getBranch(extensionBranchPath + '.');
let syncBranch =
- Services.prefs.getBranch('services.sync.prefs.sync.');
+ Services.prefs.getBranch('services.sync.prefs.sync.');
// Mark config entries as syncable
argstr.data = '';
let dataKey;
for (let i=0; i<dataKeys.length; ++i) {
- dataKey = dataKeys[i];
- if (extensionBranch.prefHasUserValue('cloudStorage.' + dataKey)
- === false) {
+ dataKey = dataKeys[i];
+ if (extensionBranch.prefHasUserValue('cloudStorage.' + dataKey)
+ === false) {
extensionBranch.setComplexValue('cloudStorage.' + dataKey,
- iss, argstr);
- }
+ iss, argstr);
+ }
- syncBranch.setBoolPref(cloudBranchPath + '.' + dataKey, true);
+ syncBranch.setBoolPref(cloudBranchPath + '.' + dataKey, true);
}
- };
+ };
- let push = function (datakey, data, callback) {
+ let push = function (datakey, data, callback) {
let branch = Services.prefs.getBranch(cloudBranchPath + '.');
let bin = {
- 'source': options.deviceName || getDefaultDeviceName(),
- 'tstamp': Date.now(),
- 'data': data,
- 'size': 0
+ 'source': options.deviceName || getDefaultDeviceName(),
+ 'tstamp': Date.now(),
+ 'data': data,
+ 'size': 0
};
bin.size = JSON.stringify(bin).length;
argstr.data = JSON.stringify(bin);
branch.setComplexValue(datakey, iss, argstr);
if (typeof callback === 'function') {
- callback();
+ callback();
}
- };
+ };
- let pull = function (datakey, callback) {
+ let pull = function (datakey, callback) {
let result = null;
let branch = Services.prefs.getBranch(cloudBranchPath + '.');
try {
- let json = branch.getComplexValue(datakey, iss).data;
- if (typeof json === 'string') {
+ let json = branch.getComplexValue(datakey, iss).data;
+ if (typeof json === 'string') {
result = JSON.parse(json);
- }
+ }
} catch(ex) {
- // Ignore
+ // Ignore
}
callback(result);
- };
+ };
- let getOptions = function (callback) {
+ let getOptions = function (callback) {
if (typeof callback !== 'function') {
- return;
+ return;
}
options.defaultDeviceName = getDefaultDeviceName();
callback(options);
- };
+ };
- let setOptions = function (details, callback) {
+ let setOptions = function (details, callback) {
if (typeof details !== 'object' || details === null) {
- return;
+ return;
}
let branch = Services.prefs.getBranch(extensionBranchPath + '.');
if (typeof details.deviceName === 'string') {
- argstr.data = details.deviceName;
- branch.setComplexValue('deviceName', iss, argstr);
- options.deviceName = details.deviceName;
+ argstr.data = details.deviceName;
+ branch.setComplexValue('deviceName', iss, argstr);
+ options.deviceName = details.deviceName;
}
getOptions(callback);
- };
+ };
- return {
+ return {
start: start,
push: push,
pull: pull,
getOptions: getOptions,
setOptions: setOptions
- };
+ };
})();
})();
diff --git a/js/vapi-common.js b/js/vapi-common.js
index db48206..d541070 100644
--- a/js/vapi-common.js
+++ b/js/vapi-common.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 The uMatrix/uBlock Origin authors
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -32,86 +32,86 @@ Cu.import('resource://gre/modules/Services.jsm');
(function (self) {
if (self.vAPI === undefined) {
- self.vAPI = vAPI;
+ self.vAPI = vAPI;
}
vAPI.setTimeout = vAPI.setTimeout || function (callback, delay, extra) {
- return setTimeout(function (a) {
- callback(a);
- }, delay, extra);
+ return setTimeout(function (a) {
+ callback(a);
+ }, delay, extra);
};
// http://www.w3.org/International/questions/qa-scripts#directions
let setScriptDirection = function(language) {
- let dir =
- ['ar', 'he', 'fa', 'ps', 'ur'].indexOf(language) !== -1
- ? 'rtl'
- : 'ltr';
+ let dir =
+ ['ar', 'he', 'fa', 'ps', 'ur'].indexOf(language) !== -1
+ ? 'rtl'
+ : 'ltr';
- document.body.setAttribute('dir', dir);
+ document.body.setAttribute('dir', dir);
};
vAPI.download = function (details) {
- if (!details.url) {
+ if (!details.url) {
return;
- }
+ }
- let a = document.createElement('a');
- a.href = details.url;
- a.setAttribute('download', details.filename || '');
- a.dispatchEvent(new MouseEvent('click'));
+ let a = document.createElement('a');
+ a.href = details.url;
+ a.setAttribute('download', details.filename || '');
+ a.dispatchEvent(new MouseEvent('click'));
};
vAPI.insertHTML = (function () {
- const parser = Cc['@mozilla.org/parserutils;1']
+ const parser = Cc['@mozilla.org/parserutils;1']
.getService(Ci.nsIParserUtils);
- // https://github.com/gorhill/uBlock/issues/845
- // Apparently dashboard pages execute with `about:blank` principal.
+ // https://github.com/gorhill/uBlock/issues/845
+ // Apparently dashboard pages execute with `about:blank` principal.
- return function (node, html) {
+ return function (node, html) {
while (node.firstChild) {
- node.removeChild(node.firstChild);
+ node.removeChild(node.firstChild);
}
- let parsed =
- parser.parseFragment(html,
- parser.SanitizerAllowStyle,
- false,
- Services.io.newURI('about:blank',
- null, null),
- document.documentElement);
+ let parsed =
+ parser.parseFragment(html,
+ parser.SanitizerAllowStyle,
+ false,
+ Services.io.newURI('about:blank',
+ null, null),
+ document.documentElement);
node.appendChild(parsed);
- };
+ };
})();
vAPI.getURL = function (path) {
- return 'chrome://'
- + location.host
- + '/content/'
- + path.replace(/^\/+/, '');
+ return 'chrome://'
+ + location.host
+ + '/content/'
+ + path.replace(/^\/+/, '');
};
vAPI.i18n = (function () {
- let stringBundle =
- Services.strings.createBundle('chrome://'
- + location.host
- + '/locale/messages.properties');
+ let stringBundle =
+ Services.strings.createBundle('chrome://'
+ + location.host
+ + '/locale/messages.properties');
- return function (s) {
+ return function (s) {
try {
- return stringBundle.GetStringFromName(s);
+ return stringBundle.GetStringFromName(s);
} catch (ex) {
- return '';
+ return '';
}
- };
+ };
})();
setScriptDirection(navigator.language);
vAPI.closePopup = function() {
- sendAsyncMessage(location.host + ':closePopup');
+ sendAsyncMessage(location.host + ':closePopup');
};
// A localStorage-like object which should be accessible from the
@@ -119,50 +119,50 @@ Cu.import('resource://gre/modules/Services.jsm');
// This storage is optional, but it is nice to have, for a more polished user
// experience.
vAPI.localStorage = {
- pbName: '',
- pb: null,
- str: Cc['@mozilla.org/supports-string;1']
+ pbName: '',
+ pb: null,
+ str: Cc['@mozilla.org/supports-string;1']
.createInstance(Ci.nsISupportsString),
- init: function (pbName) {
+ init: function (pbName) {
this.pbName = pbName;
this.pb = Services.prefs.getBranch(pbName);
- },
- getItem: function (key) {
+ },
+ getItem: function (key) {
try {
- return this.pb
- .getComplexValue(key,
- Ci.nsISupportsString).data;
+ return this.pb
+ .getComplexValue(key,
+ Ci.nsISupportsString).data;
} catch (ex) {
- return null;
+ return null;
}
- },
- setItem: function (key, value) {
+ },
+ setItem: function (key, value) {
this.str.data = value;
this.pb.setComplexValue(key,
- Ci.nsISupportsString,
- this.str);
- },
- getBool: function (key) {
+ Ci.nsISupportsString,
+ this.str);
+ },
+ getBool: function (key) {
try {
- return this.pb.getBoolPref(key);
+ return this.pb.getBoolPref(key);
} catch (ex) {
- return null;
+ return null;
}
- },
- setBool: function (key, value) {
+ },
+ setBool: function (key, value) {
this.pb.setBoolPref(key, value);
- },
- setDefaultBool: function (key, defaultValue) {
+ },
+ setDefaultBool: function (key, defaultValue) {
Services.prefs.getDefaultBranch(this.pbName)
- .setBoolPref(key, defaultValue);
- },
- removeItem: function (key) {
+ .setBoolPref(key, defaultValue);
+ },
+ removeItem: function (key) {
this.pb.clearUserPref(key);
- },
- clear: function () {
+ },
+ clear: function () {
this.pb.deleteBranch('');
- }
+ }
};
vAPI.localStorage.init('extensions.' + location.host + '.');
diff --git a/js/vapi-contextmenu.js b/js/vapi-contextmenu.js
index 271e30b..9e20b23 100644
--- a/js/vapi-contextmenu.js
+++ b/js/vapi-contextmenu.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 The uMatrix/uBlock Origin authors
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -27,73 +27,73 @@
(function () {
vAPI.contextMenu = {
- contextMap: {
+ contextMap: {
frame: 'inFrame',
link: 'onLink',
image: 'onImage',
audio: 'onAudio',
video: 'onVideo',
editable: 'onEditableArea'
- }
+ }
};
vAPI.contextMenu.displayMenuItem = function ({target}) {
- let doc = target.ownerDocument;
- let gContextMenu = doc.defaultView.gContextMenu;
- if (!gContextMenu.browser) {
+ let doc = target.ownerDocument;
+ let gContextMenu = doc.defaultView.gContextMenu;
+ if (!gContextMenu.browser) {
return;
- }
+ }
- let menuitem = doc.getElementById(vAPI.contextMenu.menuItemId);
- let currentURI = gContextMenu.browser.currentURI;
+ let menuitem = doc.getElementById(vAPI.contextMenu.menuItemId);
+ let currentURI = gContextMenu.browser.currentURI;
- // https://github.com/chrisaljoudi/uBlock/issues/105
- // TODO: Should the element picker works on any kind of pages?
- if (!currentURI.schemeIs('http') && !currentURI.schemeIs('https')) {
+ // https://github.com/chrisaljoudi/uBlock/issues/105
+ // TODO: Should the element picker works on any kind of pages?
+ if (!currentURI.schemeIs('http') && !currentURI.schemeIs('https')) {
menuitem.setAttribute('hidden', true);
return;
- }
+ }
- let ctx = vAPI.contextMenu.contexts;
+ let ctx = vAPI.contextMenu.contexts;
- if (!ctx) {
+ if (!ctx) {
menuitem.setAttribute('hidden', false);
return;
- }
+ }
- let ctxMap = vAPI.contextMenu.contextMap;
+ let ctxMap = vAPI.contextMenu.contextMap;
- for (let context of ctx) {
+ for (let context of ctx) {
if (context === 'page'
- && !gContextMenu.onLink
- && !gContextMenu.onImage
- && !gContextMenu.onEditableArea
- && !gContextMenu.inFrame
- && !gContextMenu.onVideo
- && !gContextMenu.onAudio) {
- menuitem.setAttribute('hidden', false);
- return;
+ && !gContextMenu.onLink
+ && !gContextMenu.onImage
+ && !gContextMenu.onEditableArea
+ && !gContextMenu.inFrame
+ && !gContextMenu.onVideo
+ && !gContextMenu.onAudio) {
+ menuitem.setAttribute('hidden', false);
+ return;
}
if (ctxMap.hasOwnProperty(context)
- && gContextMenu[ctxMap[context]]) {
- menuitem.setAttribute('hidden', false);
- return;
+ && gContextMenu[ctxMap[context]]) {
+ menuitem.setAttribute('hidden', false);
+ return;
}
- }
+ }
- menuitem.setAttribute('hidden', true);
+ menuitem.setAttribute('hidden', true);
};
vAPI.contextMenu.register = (function () {
- let register = function (doc) {
+ let register = function (doc) {
if (!this.menuItemId) {
- return;
+ return;
}
// Already installed?
if (doc.getElementById(this.menuItemId) !== null) {
- return;
+ return;
}
let contextMenu = doc.getElementById('contentAreaContextMenu');
@@ -107,106 +107,106 @@
contextMenu.addEventListener('popupshowing', this.displayMenuItem);
contextMenu.insertBefore(menuitem, doc.getElementById('inspect-separator'));
- };
-
- let registerSafely = function (doc, tryCount) {
- // https://github.com/gorhill/uBlock/issues/906
- // Be sure document.readyState is 'complete': it could happen
- // at launch time that we are called by
- // vAPI.contextMenu.create() directly before the environment
- // is properly initialized.
+ };
+
+ let registerSafely = function (doc, tryCount) {
+ // https://github.com/gorhill/uBlock/issues/906
+ // Be sure document.readyState is 'complete': it could happen
+ // at launch time that we are called by
+ // vAPI.contextMenu.create() directly before the environment
+ // is properly initialized.
if (doc.readyState === 'complete') {
- register.call(this, doc);
- return;
+ register.call(this, doc);
+ return;
}
if (typeof tryCount !== 'number') {
- tryCount = 0;
+ tryCount = 0;
}
tryCount += 1;
if (tryCount < 8) {
- vAPI.setTimeout(registerSafely.bind(this, doc, tryCount), 200);
+ vAPI.setTimeout(registerSafely.bind(this, doc, tryCount), 200);
}
- };
+ };
- return registerSafely;
+ return registerSafely;
})();
vAPI.contextMenu.unregister = function (doc) {
- if (!this.menuItemId) {
+ if (!this.menuItemId) {
return;
- }
+ }
- let menuitem = doc.getElementById(this.menuItemId);
- if (menuitem === null) {
+ let menuitem = doc.getElementById(this.menuItemId);
+ if (menuitem === null) {
return;
- }
+ }
- let contextMenu = menuitem.parentNode;
- menuitem.removeEventListener('command', this.onCommand);
- contextMenu.removeEventListener('popupshowing', this.displayMenuItem);
- contextMenu.removeChild(menuitem);
+ let contextMenu = menuitem.parentNode;
+ menuitem.removeEventListener('command', this.onCommand);
+ contextMenu.removeEventListener('popupshowing', this.displayMenuItem);
+ contextMenu.removeChild(menuitem);
};
vAPI.contextMenu.create = function (details, callback) {
- this.menuItemId = details.id;
- this.menuLabel = details.title;
- this.contexts = details.contexts;
+ this.menuItemId = details.id;
+ this.menuLabel = details.title;
+ this.contexts = details.contexts;
- if (Array.isArray(this.contexts) && this.contexts.length) {
+ if (Array.isArray(this.contexts) && this.contexts.length) {
this.contexts = this.contexts.indexOf('all') === -1
- ? this.contexts
- : null;
- } else {
+ ? this.contexts
+ : null;
+ } else {
// default in Chrome
this.contexts = ['page'];
- }
+ }
- this.onCommand = function () {
+ this.onCommand = function () {
let gContextMenu = vAPI.browser.getOwnerWindow(this).gContextMenu;
let details = {
- menuItemId: this.id
+ menuItemId: this.id
};
if (gContextMenu.inFrame) {
- details.tagName = 'iframe';
- // Probably won't work with e10s
- // eMatrix: doesn't matter ;)
- details.frameUrl = gContextMenu.focusedWindow.location.href;
+ details.tagName = 'iframe';
+ // Probably won't work with e10s
+ // eMatrix: doesn't matter ;)
+ details.frameUrl = gContextMenu.focusedWindow.location.href;
} else if (gContextMenu.onImage) {
- details.tagName = 'img';
- details.srcUrl = gContextMenu.mediaURL;
+ details.tagName = 'img';
+ details.srcUrl = gContextMenu.mediaURL;
} else if (gContextMenu.onAudio) {
- details.tagName = 'audio';
- details.srcUrl = gContextMenu.mediaURL;
+ details.tagName = 'audio';
+ details.srcUrl = gContextMenu.mediaURL;
} else if (gContextMenu.onVideo) {
- details.tagName = 'video';
- details.srcUrl = gContextMenu.mediaURL;
+ details.tagName = 'video';
+ details.srcUrl = gContextMenu.mediaURL;
} else if (gContextMenu.onLink) {
- details.tagName = 'a';
- details.linkUrl = gContextMenu.linkURL;
+ details.tagName = 'a';
+ details.linkUrl = gContextMenu.linkURL;
}
callback(details, {
- id: vAPI.tabs.manager.tabIdFromTarget(gContextMenu.browser),
- url: gContextMenu.browser.currentURI.asciiSpec
+ id: vAPI.tabs.manager.tabIdFromTarget(gContextMenu.browser),
+ url: gContextMenu.browser.currentURI.asciiSpec
});
- };
+ };
- for (let win of vAPI.window.getWindows()) {
+ for (let win of vAPI.window.getWindows()) {
this.register(win.document);
- }
+ }
};
vAPI.contextMenu.remove = function () {
- for (let win of vAPI.window.getWindows()) {
+ for (let win of vAPI.window.getWindows()) {
this.unregister(win.document);
- }
+ }
- this.menuItemId = null;
- this.menuLabel = null;
- this.contexts = null;
- this.onCommand = null;
+ this.menuItemId = null;
+ this.menuLabel = null;
+ this.contexts = null;
+ this.onCommand = null;
};
})();
diff --git a/js/vapi-cookies.js b/js/vapi-cookies.js
index c694b8d..b6635a5 100644
--- a/js/vapi-cookies.js
+++ b/js/vapi-cookies.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 The uMatrix/uBlock Origin authors
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -29,90 +29,90 @@
vAPI.cookies = {};
vAPI.cookies.CookieEntry = function (ffCookie) {
- this.domain = ffCookie.host;
- this.name = ffCookie.name;
- this.path = ffCookie.path;
- this.secure = ffCookie.isSecure === true;
- this.session = ffCookie.expires === 0;
- this.value = ffCookie.value;
+ this.domain = ffCookie.host;
+ this.name = ffCookie.name;
+ this.path = ffCookie.path;
+ this.secure = ffCookie.isSecure === true;
+ this.session = ffCookie.expires === 0;
+ this.value = ffCookie.value;
};
vAPI.cookies.start = function () {
- Services.obs.addObserver(this, 'cookie-changed', false);
- Services.obs.addObserver(this, 'private-cookie-changed', false);
- vAPI.addCleanUpTask(this.stop.bind(this));
+ Services.obs.addObserver(this, 'cookie-changed', false);
+ Services.obs.addObserver(this, 'private-cookie-changed', false);
+ vAPI.addCleanUpTask(this.stop.bind(this));
};
vAPI.cookies.stop = function () {
- Services.obs.removeObserver(this, 'cookie-changed');
- Services.obs.removeObserver(this, 'private-cookie-changed');
+ Services.obs.removeObserver(this, 'cookie-changed');
+ Services.obs.removeObserver(this, 'private-cookie-changed');
};
vAPI.cookies.observe = function (subject, topic, reason) {
- //if ( topic !== 'cookie-changed' && topic !== 'private-cookie-changed' ) {
- // return;
- //}
- //
- if (reason === 'cleared' && typeof this.onAllRemoved === 'function') {
+ //if ( topic !== 'cookie-changed' && topic !== 'private-cookie-changed' ) {
+ // return;
+ //}
+ //
+ if (reason === 'cleared' && typeof this.onAllRemoved === 'function') {
this.onAllRemoved();
return;
- }
- if (subject === null) {
+ }
+ if (subject === null) {
return;
- }
- if (subject instanceof Ci.nsICookie2 === false) {
+ }
+ if (subject instanceof Ci.nsICookie2 === false) {
try {
- subject = subject.QueryInterface(Ci.nsICookie2);
+ subject = subject.QueryInterface(Ci.nsICookie2);
} catch (ex) {
- return;
+ return;
}
- }
- if (reason === 'deleted') {
+ }
+ if (reason === 'deleted') {
if (typeof this.onRemoved === 'function') {
- this.onRemoved(new this.CookieEntry(subject));
+ this.onRemoved(new this.CookieEntry(subject));
}
return;
- }
- if (typeof this.onChanged === 'function') {
+ }
+ if (typeof this.onChanged === 'function') {
this.onChanged(new this.CookieEntry(subject));
- }
+ }
};
vAPI.cookies.getAll = function(callback) {
- // Meant and expected to be asynchronous.
- if (typeof callback !== 'function') {
+ // Meant and expected to be asynchronous.
+ if (typeof callback !== 'function') {
return;
- }
+ }
- let onAsync = function () {
+ let onAsync = function () {
let out = [];
let enumerator = Services.cookies.enumerator;
let ffcookie;
while (enumerator.hasMoreElements()) {
- ffcookie = enumerator.getNext();
- if (ffcookie instanceof Ci.nsICookie) {
+ ffcookie = enumerator.getNext();
+ if (ffcookie instanceof Ci.nsICookie) {
out.push(new this.CookieEntry(ffcookie));
- }
+ }
}
callback(out);
- };
+ };
- vAPI.setTimeout(onAsync.bind(this), 0);
+ vAPI.setTimeout(onAsync.bind(this), 0);
};
vAPI.cookies.remove = function (details, callback) {
- let uri = Services.io.newURI(details.url, null, null);
- let cookies = Services.cookies;
- cookies.remove(uri.asciiHost, details.name, uri.path, false, {});
- cookies.remove( '.' + uri.asciiHost, details.name, uri.path, false, {});
+ let uri = Services.io.newURI(details.url, null, null);
+ let cookies = Services.cookies;
+ cookies.remove(uri.asciiHost, details.name, uri.path, false, {});
+ cookies.remove( '.' + uri.asciiHost, details.name, uri.path, false, {});
- if (typeof callback === 'function') {
+ if (typeof callback === 'function') {
callback({
- domain: uri.asciiHost,
- name: details.name,
- path: uri.path
+ domain: uri.asciiHost,
+ name: details.name,
+ path: uri.path
});
- }
+ }
};
})();
diff --git a/js/vapi-core.js b/js/vapi-core.js
index 5d33a60..0a9cc0b 100644
--- a/js/vapi-core.js
+++ b/js/vapi-core.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 The uMatrix/uBlock Origin authors
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -27,24 +27,24 @@
(function (self) {
vAPI.modernFirefox =
- Services.appinfo.ID === '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}'
- && Services.vc.compare(Services.appinfo.version, '44') > 0;
+ Services.appinfo.ID === '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}'
+ && Services.vc.compare(Services.appinfo.version, '44') > 0;
vAPI.app = {
- name: 'eMatrix',
- version: location.hash.slice(1),
-
- start: function () {
- return;
- },
- stop: function () {
- return;
- },
- restart: function () {
- Cc['@mozilla.org/childprocessmessagemanager;1']
- .getService(Ci.nsIMessageSender)
- .sendAsyncMessage(location.host + '-restart');
- },
+ name: 'eMatrix',
+ version: location.hash.slice(1),
+
+ start: function () {
+ return;
+ },
+ stop: function () {
+ return;
+ },
+ restart: function () {
+ Cc['@mozilla.org/childprocessmessagemanager;1']
+ .getService(Ci.nsIMessageSender)
+ .sendAsyncMessage(location.host + '-restart');
+ },
};
// List of things that needs to be destroyed when disabling the extension
@@ -57,72 +57,72 @@
let expectedNumberOfCleanups = 7;
vAPI.addCleanUpTask = function (task) {
- if (typeof task !== 'function') {
- return;
- }
+ if (typeof task !== 'function') {
+ return;
+ }
- cleanupTasks.push(task);
+ cleanupTasks.push(task);
};
vAPI.deferUntil = function (testFn, mainFn, details) {
- let dtls = (typeof details !== 'object') ? {} : details;
- let now = 0;
- let next = dtls.next || 200;
- let until = dtls.until || 2000;
+ let dtls = (typeof details !== 'object') ? {} : details;
+ let now = 0;
+ let next = dtls.next || 200;
+ let until = dtls.until || 2000;
- let check = function () {
+ let check = function () {
if (testFn() === true || now >= until) {
- mainFn();
- return;
+ mainFn();
+ return;
}
now += next;
vAPI.setTimeout(check, next);
- };
+ };
- if ('sync' in dtls && dtls.sync === true) {
+ if ('sync' in dtls && dtls.sync === true) {
check();
- } else {
+ } else {
vAPI.setTimeout(check, 1);
- }
+ }
};
window.addEventListener('unload', function () {
- // if (typeof vAPI.app.onShutdown === 'function') {
+ // if (typeof vAPI.app.onShutdown === 'function') {
// vAPI.app.onShutdown();
- // }
-
- // IMPORTANT: cleanup tasks must be executed using LIFO order.
- for (let i=cleanupTasks.length-1; i>=0; --i) {
- try {
- cleanupTasks[i]();
- } catch (e) {
- // Just in case a clean up task ends up throwing for
- // no reason
- console.error(e);
- }
- }
-
- // eMatrix: temporarily disabled
- // if (cleanupTasks.length < expectedNumberOfCleanups) {
+ // }
+
+ // IMPORTANT: cleanup tasks must be executed using LIFO order.
+ for (let i=cleanupTasks.length-1; i>=0; --i) {
+ try {
+ cleanupTasks[i]();
+ } catch (e) {
+ // Just in case a clean up task ends up throwing for
+ // no reason
+ console.error(e);
+ }
+ }
+
+ // eMatrix: temporarily disabled
+ // if (cleanupTasks.length < expectedNumberOfCleanups) {
// console.error
- // ('eMatrix> Cleanup tasks performed: %s (out of %s)',
+ // ('eMatrix> Cleanup tasks performed: %s (out of %s)',
// cleanupTasks.length,
// expectedNumberOfCleanups);
- // }
+ // }
- // frameModule needs to be cleared too
- Cu.import('chrome://ematrix/content/lib/FrameModule.jsm');
- contentObserver.unregister();
- Cu.unload('chrome://ematrix/content/lib/FrameModule.jsm');
+ // frameModule needs to be cleared too
+ Cu.import('chrome://ematrix/content/lib/FrameModule.jsm');
+ contentObserver.unregister();
+ Cu.unload('chrome://ematrix/content/lib/FrameModule.jsm');
});
vAPI.noTabId = '-1';
vAPI.isBehindTheSceneTabId = function (tabId) {
- return tabId.toString() === '-1';
+ return tabId.toString() === '-1';
};
vAPI.lastError = function () {
- return null;
+ return null;
};
})(this);
diff --git a/js/vapi-messaging.js b/js/vapi-messaging.js
index afc18a1..5fb4b59 100644
--- a/js/vapi-messaging.js
+++ b/js/vapi-messaging.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 The uMatrix/uBlock Origin authors
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -29,109 +29,109 @@
Cu.import('chrome://ematrix/content/lib/CallbackWrapper.jsm');
vAPI.messaging = {
- get globalMessageManager() {
+ get globalMessageManager() {
return Cc['@mozilla.org/globalmessagemanager;1']
.getService(Ci.nsIMessageListenerManager);
- },
- frameScript: vAPI.getURL('frameScript.js'),
- listeners: {},
- defaultHandler: null,
- NOOPFUNC: function(){},
- UNHANDLED: 'vAPI.messaging.notHandled'
+ },
+ frameScript: vAPI.getURL('frameScript.js'),
+ listeners: {},
+ defaultHandler: null,
+ NOOPFUNC: function(){},
+ UNHANDLED: 'vAPI.messaging.notHandled'
};
vAPI.messaging.listen = function (listenerName, callback) {
- this.listeners[listenerName] = callback;
+ this.listeners[listenerName] = callback;
};
vAPI.messaging.onMessage = function ({target, data}) {
- let messageManager = target.messageManager;
+ let messageManager = target.messageManager;
- if (!messageManager) {
+ if (!messageManager) {
// Message came from a popup, and its message manager is
// not usable. So instead we broadcast to the parent
// window.
messageManager =
- vAPI.browser.
- getOwnerWindow(target.webNavigation
- .QueryInterface(Ci.nsIDocShell)
- .chromeEventHandler).messageManager;
- }
-
- let channelNameRaw = data.channelName;
- let pos = channelNameRaw.indexOf('|');
- let channelName = channelNameRaw.slice(pos + 1);
-
- let callback = vAPI.messaging.NOOPFUNC;
- if (data.requestId !== undefined) {
+ vAPI.browser.
+ getOwnerWindow(target.webNavigation
+ .QueryInterface(Ci.nsIDocShell)
+ .chromeEventHandler).messageManager;
+ }
+
+ let channelNameRaw = data.channelName;
+ let pos = channelNameRaw.indexOf('|');
+ let channelName = channelNameRaw.slice(pos + 1);
+
+ let callback = vAPI.messaging.NOOPFUNC;
+ if (data.requestId !== undefined) {
callback = CallbackWrapper.factory(messageManager,
- channelName,
- channelNameRaw.slice(0, pos),
- data.requestId).callback;
- }
+ channelName,
+ channelNameRaw.slice(0, pos),
+ data.requestId).callback;
+ }
- let sender = {
+ let sender = {
tab: {
- id: vAPI.tabs.manager.tabIdFromTarget(target)
+ id: vAPI.tabs.manager.tabIdFromTarget(target)
}
- };
+ };
- // Specific handler
- let r = vAPI.messaging.UNHANDLED;
- let listener = vAPI.messaging.listeners[channelName];
+ // Specific handler
+ let r = vAPI.messaging.UNHANDLED;
+ let listener = vAPI.messaging.listeners[channelName];
- if (typeof listener === 'function') {
+ if (typeof listener === 'function') {
r = listener(data.msg, sender, callback);
- }
- if (r !== vAPI.messaging.UNHANDLED) {
+ }
+ if (r !== vAPI.messaging.UNHANDLED) {
return;
- }
+ }
- // Default handler
- r = vAPI.messaging.defaultHandler(data.msg, sender, callback);
- if (r !== vAPI.messaging.UNHANDLED) {
+ // Default handler
+ r = vAPI.messaging.defaultHandler(data.msg, sender, callback);
+ if (r !== vAPI.messaging.UNHANDLED) {
return;
- }
+ }
- console.error('eMatrix> messaging > unknown request: %o', data);
+ console.error('eMatrix> messaging > unknown request: %o', data);
- // Unhandled: Need to callback anyways in case caller expected
- // an answer, or else there is a memory leak on caller's side
- callback();
+ // Unhandled: Need to callback anyways in case caller expected
+ // an answer, or else there is a memory leak on caller's side
+ callback();
};
vAPI.messaging.setup = function (defaultHandler) {
- // Already setup?
- if (this.defaultHandler !== null) {
+ // Already setup?
+ if (this.defaultHandler !== null) {
return;
- }
+ }
- if (typeof defaultHandler !== 'function') {
+ if (typeof defaultHandler !== 'function') {
defaultHandler = function () {
- return vAPI.messaging.UNHANDLED;
- };
- }
+ return vAPI.messaging.UNHANDLED;
+ };
+ }
- this.defaultHandler = defaultHandler;
- this.globalMessageManager.addMessageListener(location.host
- + ':background',
- this.onMessage);
- this.globalMessageManager.loadFrameScript(this.frameScript, true);
+ this.defaultHandler = defaultHandler;
+ this.globalMessageManager.addMessageListener(location.host
+ + ':background',
+ this.onMessage);
+ this.globalMessageManager.loadFrameScript(this.frameScript, true);
- vAPI.addCleanUpTask(function () {
+ vAPI.addCleanUpTask(function () {
let gmm = vAPI.messaging.globalMessageManager;
gmm.removeDelayedFrameScript(vAPI.messaging.frameScript);
gmm.removeMessageListener(location.host + ':background',
- vAPI.messaging.onMessage);
- });
+ vAPI.messaging.onMessage);
+ });
};
vAPI.messaging.broadcast = function (message) {
- this.globalMessageManager
- .broadcastAsyncMessage(location.host + ':broadcast',
- JSON.stringify({
- broadcast: true,
- msg: message}));
+ this.globalMessageManager
+ .broadcastAsyncMessage(location.host + ':broadcast',
+ JSON.stringify({
+ broadcast: true,
+ msg: message}));
};
})();
diff --git a/js/vapi-net.js b/js/vapi-net.js
index 41cbc4f..9212c7b 100644
--- a/js/vapi-net.js
+++ b/js/vapi-net.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 The uMatrix/uBlock Origin authors
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -31,42 +31,42 @@
vAPI.net = {};
vAPI.net.registerListeners = function () {
- this.onBeforeRequest.types = this.onBeforeRequest.types
- ? new Set(this.onBeforeRequest.types)
- : null;
+ this.onBeforeRequest.types = this.onBeforeRequest.types
+ ? new Set(this.onBeforeRequest.types)
+ : null;
- this.onBeforeSendHeaders.types = this.onBeforeSendHeaders.types
- ? new Set(this.onBeforeSendHeaders.types)
- : null;
+ this.onBeforeSendHeaders.types = this.onBeforeSendHeaders.types
+ ? new Set(this.onBeforeSendHeaders.types)
+ : null;
- let shouldLoadListenerMessageName = location.host + ':shouldLoad';
- let shouldLoadListener = function (e) {
+ let shouldLoadListenerMessageName = location.host + ':shouldLoad';
+ let shouldLoadListener = function (e) {
let details = e.data;
let pendingReq =
- PendingRequestBuffer.createRequest(details.url);
+ PendingRequestBuffer.createRequest(details.url);
pendingReq.rawType = details.rawType;
pendingReq.tabId = vAPI.tabs.manager.tabIdFromTarget(e.target);
- };
+ };
- // https://github.com/gorhill/uMatrix/issues/200
- // We need this only for Firefox 34 and less: the tab id is derived from
- // the origin of the message.
- if (!vAPI.modernFirefox) {
+ // https://github.com/gorhill/uMatrix/issues/200
+ // We need this only for Firefox 34 and less: the tab id is derived from
+ // the origin of the message.
+ if (!vAPI.modernFirefox) {
vAPI.messaging.globalMessageManager
- .addMessageListener(shouldLoadListenerMessageName,
- shouldLoadListener);
- }
+ .addMessageListener(shouldLoadListenerMessageName,
+ shouldLoadListener);
+ }
- vAPI.httpObserver.register();
+ vAPI.httpObserver.register();
- vAPI.addCleanUpTask(function () {
+ vAPI.addCleanUpTask(function () {
if (!vAPI.modernFirefox) {
- vAPI.messaging.globalMessageManager
- .removeMessageListener(shouldLoadListenerMessageName,
- shouldLoadListener);
+ vAPI.messaging.globalMessageManager
+ .removeMessageListener(shouldLoadListenerMessageName,
+ shouldLoadListener);
}
vAPI.httpObserver.unregister();
- });
+ });
};
})();
diff --git a/js/vapi-popup.js b/js/vapi-popup.js
index 0859e81..12280e7 100644
--- a/js/vapi-popup.js
+++ b/js/vapi-popup.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 The uMatrix/uBlock Origin authors
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
diff --git a/js/vapi-storage.js b/js/vapi-storage.js
index 8e46b90..bcc3a9a 100644
--- a/js/vapi-storage.js
+++ b/js/vapi-storage.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 The uMatrix/uBlock Origin authors
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -29,60 +29,60 @@
// API matches that of chrome.storage.local:
// https://developer.chrome.com/extensions/storage
vAPI.storage = (function () {
- let db = null;
- let vacuumTimer = null;
+ let db = null;
+ let vacuumTimer = null;
- let close = function () {
+ let close = function () {
if (vacuumTimer !== null) {
- clearTimeout(vacuumTimer);
- vacuumTimer = null;
+ clearTimeout(vacuumTimer);
+ vacuumTimer = null;
}
if (db === null) {
- return;
+ return;
}
db.asyncClose();
db = null;
- };
+ };
- let open = function () {
+ let open = function () {
if (db !== null) {
- return db;
+ return db;
}
// Create path
let path = Services.dirsvc.get('ProfD', Ci.nsIFile);
path.append('ematrix-data');
if (!path.exists()) {
- path.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt('0774', 8));
+ path.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt('0774', 8));
}
if (!path.isDirectory()) {
- throw Error('Should be a directory...');
+ throw Error('Should be a directory...');
}
- let path2 = Services.dirsvc.get('ProfD', Ci.nsIFile);
- path2.append('extension-data');
- path2.append(location.host + '.sqlite');
- if (path2.exists()) {
- path2.moveTo(path, location.host+'.sqlite');
- }
+ let path2 = Services.dirsvc.get('ProfD', Ci.nsIFile);
+ path2.append('extension-data');
+ path2.append(location.host + '.sqlite');
+ if (path2.exists()) {
+ path2.moveTo(path, location.host+'.sqlite');
+ }
- path.append(location.host + '.sqlite');
+ path.append(location.host + '.sqlite');
// Open database
try {
- db = Services.storage.openDatabase(path);
- if (db.connectionReady === false) {
+ db = Services.storage.openDatabase(path);
+ if (db.connectionReady === false) {
db.asyncClose();
db = null;
- }
+ }
} catch (ex) {
- // Ignore
+ // Ignore
}
if (db === null) {
- return null;
+ return null;
}
// Database was opened, register cleanup task
@@ -90,240 +90,240 @@
// Setup database
db.createAsyncStatement('CREATE TABLE IF NOT EXISTS '
- +'"settings" ("name" '
- +'TEXT PRIMARY KEY NOT NULL, '
- +'"value" TEXT);')
- .executeAsync();
+ +'"settings" ("name" '
+ +'TEXT PRIMARY KEY NOT NULL, '
+ +'"value" TEXT);')
+ .executeAsync();
if (vacuum !== null) {
- vacuumTimer = vAPI.setTimeout(vacuum, 60000);
+ vacuumTimer = vAPI.setTimeout(vacuum, 60000);
}
return db;
- };
+ };
- // Vacuum only once, and only while idle
- let vacuum = function () {
+ // Vacuum only once, and only while idle
+ let vacuum = function () {
vacuumTimer = null;
if (db === null) {
- return;
+ return;
}
let idleSvc =
- Cc['@mozilla.org/widget/idleservice;1']
- .getService(Ci.nsIIdleService);
+ Cc['@mozilla.org/widget/idleservice;1']
+ .getService(Ci.nsIIdleService);
if (idleSvc.idleTime < 60000) {
- vacuumTimer = vAPI.setTimeout(vacuum, 60000);
- return;
+ vacuumTimer = vAPI.setTimeout(vacuum, 60000);
+ return;
}
db.createAsyncStatement('VACUUM').executeAsync();
vacuum = null;
- };
+ };
- // Execute a query
- let runStatement = function (stmt, callback) {
+ // Execute a query
+ let runStatement = function (stmt, callback) {
let result = {};
stmt.executeAsync({
- handleResult: function (rows) {
+ handleResult: function (rows) {
if (!rows || typeof callback !== 'function') {
- return;
+ return;
}
let row;
while ((row = rows.getNextRow())) {
- // we assume that there will be two columns, since we're
- // using it only for preferences
- // eMatrix: the above comment is obsolete
- // (it's not used just for preferences
- // anymore), but we still expect two columns.
- let res = row.getResultByIndex(0);
- result[res] = row.getResultByIndex(1);
+ // we assume that there will be two columns, since we're
+ // using it only for preferences
+ // eMatrix: the above comment is obsolete
+ // (it's not used just for preferences
+ // anymore), but we still expect two columns.
+ let res = row.getResultByIndex(0);
+ result[res] = row.getResultByIndex(1);
}
- },
- handleCompletion: function (reason) {
+ },
+ handleCompletion: function (reason) {
if (typeof callback === 'function' && reason === 0) {
- callback(result);
+ callback(result);
}
- },
- handleError: function (error) {
+ },
+ handleError: function (error) {
console.error('SQLite error ', error.result, error.message);
// Caller expects an answer regardless of failure.
if (typeof callback === 'function' ) {
- callback(null);
+ callback(null);
}
- },
+ },
});
- };
+ };
- let bindNames = function (stmt, names) {
+ let bindNames = function (stmt, names) {
if (Array.isArray(names) === false || names.length === 0) {
- return;
+ return;
}
let params = stmt.newBindingParamsArray();
- for (let i=names.length-1; i>=0; --i) {
- let bp = params.newBindingParams();
- bp.bindByName('name', names[i]);
- params.addParams(bp);
+ for (let i=names.length-1; i>=0; --i) {
+ let bp = params.newBindingParams();
+ bp.bindByName('name', names[i]);
+ params.addParams(bp);
}
stmt.bindParameters(params);
- };
+ };
- let clear = function (callback) {
+ let clear = function (callback) {
if (open() === null) {
- if (typeof callback === 'function') {
+ if (typeof callback === 'function') {
callback();
- }
- return;
+ }
+ return;
}
runStatement(db.createAsyncStatement('DELETE FROM "settings";'),
- callback);
- };
+ callback);
+ };
- let getBytesInUse = function (keys, callback) {
+ let getBytesInUse = function (keys, callback) {
if (typeof callback !== 'function') {
- return;
+ return;
}
if (open() === null) {
- callback(0);
- return;
+ callback(0);
+ return;
}
let stmt;
if (Array.isArray(keys)) {
- stmt = db.createAsyncStatement('SELECT "size" AS "size", '
- +'SUM(LENGTH("value")) '
- +'FROM "settings" WHERE '
- +'"name" = :name');
- bindNames(keys);
+ stmt = db.createAsyncStatement('SELECT "size" AS "size", '
+ +'SUM(LENGTH("value")) '
+ +'FROM "settings" WHERE '
+ +'"name" = :name');
+ bindNames(keys);
} else {
- stmt = db.createAsyncStatement('SELECT "size" AS "size", '
- +'SUM(LENGTH("value")) '
- +'FROM "settings"');
+ stmt = db.createAsyncStatement('SELECT "size" AS "size", '
+ +'SUM(LENGTH("value")) '
+ +'FROM "settings"');
}
runStatement(stmt, function (result) {
- callback(result.size);
+ callback(result.size);
});
- };
+ };
- let read = function (details, callback) {
+ let read = function (details, callback) {
if (typeof callback !== 'function') {
- return;
+ return;
}
let prepareResult = function (result) {
- for (let key in result) {
+ for (let key in result) {
if (result.hasOwnProperty(key) === false) {
- continue;
+ continue;
}
result[key] = JSON.parse(result[key]);
- }
+ }
- if (typeof details === 'object' && details !== null) {
+ if (typeof details === 'object' && details !== null) {
for (let key in details) {
- if (result.hasOwnProperty(key) === false) {
+ if (result.hasOwnProperty(key) === false) {
result[key] = details[key];
- }
+ }
}
- }
+ }
- callback(result);
+ callback(result);
};
if (open() === null) {
- prepareResult({});
- return;
+ prepareResult({});
+ return;
}
let names = [];
if (details !== null) {
- if (Array.isArray(details)) {
+ if (Array.isArray(details)) {
names = details;
- } else if (typeof details === 'object') {
+ } else if (typeof details === 'object') {
names = Object.keys(details);
- } else {
+ } else {
names = [details.toString()];
- }
+ }
}
let stmt;
if (names.length === 0) {
- stmt = db.createAsyncStatement('SELECT * FROM "settings"');
+ stmt = db.createAsyncStatement('SELECT * FROM "settings"');
} else {
- stmt = db.createAsyncStatement('SELECT * FROM "settings" '
- +'WHERE "name" = :name');
- bindNames(stmt, names);
+ stmt = db.createAsyncStatement('SELECT * FROM "settings" '
+ +'WHERE "name" = :name');
+ bindNames(stmt, names);
}
runStatement(stmt, prepareResult);
- };
+ };
- let remove = function (keys, callback) {
+ let remove = function (keys, callback) {
if (open() === null) {
- if (typeof callback === 'function') {
+ if (typeof callback === 'function') {
callback();
- }
- return;
+ }
+ return;
}
var stmt = db.createAsyncStatement('DELETE FROM "settings" '
- +'WHERE "name" = :name');
+ +'WHERE "name" = :name');
bindNames(stmt, typeof keys === 'string' ? [keys] : keys);
runStatement(stmt, callback);
- };
+ };
- let write = function (details, callback) {
+ let write = function (details, callback) {
if (open() === null) {
- if (typeof callback === 'function') {
+ if (typeof callback === 'function') {
callback();
- }
- return;
+ }
+ return;
}
let stmt = db.createAsyncStatement('INSERT OR REPLACE INTO '
- +'"settings" ("name", "value") '
- +'VALUES(:name, :value)');
+ +'"settings" ("name", "value") '
+ +'VALUES(:name, :value)');
let params = stmt.newBindingParamsArray();
for (let key in details) {
- if (details.hasOwnProperty(key) === false) {
+ if (details.hasOwnProperty(key) === false) {
continue;
- }
+ }
- let bp = params.newBindingParams();
- bp.bindByName('name', key);
- bp.bindByName('value', JSON.stringify(details[key]));
- params.addParams(bp);
+ let bp = params.newBindingParams();
+ bp.bindByName('name', key);
+ bp.bindByName('value', JSON.stringify(details[key]));
+ params.addParams(bp);
}
if (params.length === 0) {
- return;
+ return;
}
stmt.bindParameters(params);
runStatement(stmt, callback);
- };
+ };
- // Export API
- var api = {
+ // Export API
+ var api = {
QUOTA_BYTES: 100 * 1024 * 1024,
clear: clear,
get: read,
getBytesInUse: getBytesInUse,
remove: remove,
set: write
- };
+ };
- return api;
+ return api;
})();
vAPI.cacheStorage = vAPI.storage;
diff --git a/js/vapi-tabs.js b/js/vapi-tabs.js
index 02c3644..e5eab6b 100644
--- a/js/vapi-tabs.js
+++ b/js/vapi-tabs.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 The uMatrix/uBlock Origin authors
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -29,548 +29,548 @@
vAPI.tabs = {};
vAPI.tabs.registerListeners = function() {
- vAPI.tabs.manager.start();
+ vAPI.tabs.manager.start();
};
vAPI.tabs.get = function (tabId, callback) {
- // eMatrix: the following might be obsoleted (though probably
- // still relevant at least for Pale Moon.)
- //
- // Firefox:
- //
- // browser -> ownerDocument -> defaultView -> gBrowser -> browsers --+
- // ^ |
- // | |
- // +--------------------------------------------------------------+
- //
- // browser (browser)
- // contentTitle
- // currentURI
- // ownerDocument (XULDocument)
- // defaultView (ChromeWindow)
- // gBrowser (tabbrowser OR browser)
- // browsers (browser)
- // selectedBrowser
- // selectedTab
- // tabs (tab.tabbrowser-tab)
- //
- // Fennec: (what I figured so far)
- //
- // tab -> browser windows -> window -> BrowserApp -> tabs --+
- // ^ window |
- // | |
- // +-----------------------------------------------------------+
- //
- // tab
- // browser
- // [manual search to go back to tab from list of windows]
- let browser;
-
- if (tabId === null) {
+ // eMatrix: the following might be obsoleted (though probably
+ // still relevant at least for Pale Moon.)
+ //
+ // Firefox:
+ //
+ // browser -> ownerDocument -> defaultView -> gBrowser -> browsers --+
+ // ^ |
+ // | |
+ // +--------------------------------------------------------------+
+ //
+ // browser (browser)
+ // contentTitle
+ // currentURI
+ // ownerDocument (XULDocument)
+ // defaultView (ChromeWindow)
+ // gBrowser (tabbrowser OR browser)
+ // browsers (browser)
+ // selectedBrowser
+ // selectedTab
+ // tabs (tab.tabbrowser-tab)
+ //
+ // Fennec: (what I figured so far)
+ //
+ // tab -> browser windows -> window -> BrowserApp -> tabs --+
+ // ^ window |
+ // | |
+ // +-----------------------------------------------------------+
+ //
+ // tab
+ // browser
+ // [manual search to go back to tab from list of windows]
+ let browser;
+
+ if (tabId === null) {
browser = vAPI.tabs.manager.currentBrowser();
tabId = vAPI.tabs.manager.tabIdFromTarget(browser);
- } else {
+ } else {
browser = vAPI.tabs.manager.browserFromTabId(tabId);
- }
+ }
- // For internal use
- if (typeof callback !== 'function') {
+ // For internal use
+ if (typeof callback !== 'function') {
return browser;
- }
+ }
- if (!browser || !browser.currentURI) {
+ if (!browser || !browser.currentURI) {
callback();
return;
- }
+ }
- let win = vAPI.browser.getOwnerWindow(browser);
- let tabBrowser = vAPI.browser.getTabBrowser(win);
+ let win = vAPI.browser.getOwnerWindow(browser);
+ let tabBrowser = vAPI.browser.getTabBrowser(win);
- callback({
+ callback({
id: tabId,
windowId: vAPI.window.idFromWindow(win),
active: tabBrowser !== null
- && browser === tabBrowser.selectedBrowser,
+ && browser === tabBrowser.selectedBrowser,
url: browser.currentURI.asciiSpec,
title: browser.contentTitle
- });
+ });
};
vAPI.tabs.getAllSync = function (window) {
- let win;
- let tabs = [];
+ let win;
+ let tabs = [];
- for (let win of vAPI.window.getWindows()) {
+ for (let win of vAPI.window.getWindows()) {
if (window && window !== win) {
- continue;
+ continue;
}
let tabBrowser = vAPI.browser.getTabBrowser(win);
if (tabBrowser === null) {
- continue;
+ continue;
}
// This can happens if a tab-less window is currently opened.
// Example of a tab-less window: one opened from clicking
// "View Page Source".
if (!tabBrowser.tabs) {
- continue;
+ continue;
}
for (let tab of tabBrowser.tabs) {
- tabs.push(tab);
+ tabs.push(tab);
}
- }
+ }
- return tabs;
+ return tabs;
};
vAPI.tabs.getAll = function (callback) {
- let tabs = [];
+ let tabs = [];
- for (let browser of vAPI.tabs.manager.browsers()) {
+ for (let browser of vAPI.tabs.manager.browsers()) {
let tab = vAPI.tabs.manager.tabFromBrowser(browser);
if (tab === null) {
- continue;
+ continue;
}
if (tab.hasAttribute('pending')) {
- continue;
+ continue;
}
tabs.push({
- id: vAPI.tabs.manager.tabIdFromTarget(browser),
- url: browser.currentURI.asciiSpec
+ id: vAPI.tabs.manager.tabIdFromTarget(browser),
+ url: browser.currentURI.asciiSpec
});
- }
+ }
- callback(tabs);
+ callback(tabs);
};
vAPI.tabs.open = function (details) {
- // properties of the details object:
- // + url - the address that will be opened
- // + tabId:- the tab is used if set, instead of creating a new one
- // + index: - undefined: end of the list, -1: following tab, or
- // after index
- // + active: - opens the tab in background - true and undefined:
- // foreground
- // + select: - if a tab is already opened with that url, then
- // select it instead of opening a new one
- if (!details.url) {
+ // properties of the details object:
+ // + url - the address that will be opened
+ // + tabId:- the tab is used if set, instead of creating a new one
+ // + index: - undefined: end of the list, -1: following tab, or
+ // after index
+ // + active: - opens the tab in background - true and undefined:
+ // foreground
+ // + select: - if a tab is already opened with that url, then
+ // select it instead of opening a new one
+ if (!details.url) {
return null;
- }
+ }
- // extension pages
- if (/^[\w-]{2,}:/.test(details.url) === false) {
+ // extension pages
+ if (/^[\w-]{2,}:/.test(details.url) === false) {
details.url = vAPI.getURL(details.url);
- }
+ }
- if (details.select) {
+ if (details.select) {
let URI = Services.io.newURI(details.url, null, null);
for (let tab of this.getAllSync()) {
- let browser = vAPI.tabs.manager.browserFromTarget(tab);
+ let browser = vAPI.tabs.manager.browserFromTarget(tab);
- // https://github.com/gorhill/uBlock/issues/2558
- if (browser === null) {
- continue;
- }
+ // https://github.com/gorhill/uBlock/issues/2558
+ if (browser === null) {
+ continue;
+ }
- // Or simply .equals if we care about the fragment
- if (URI.equalsExceptRef(browser.currentURI) === false) {
+ // Or simply .equals if we care about the fragment
+ if (URI.equalsExceptRef(browser.currentURI) === false) {
continue;
- }
+ }
- this.select(tab);
+ this.select(tab);
- // Update URL if fragment is different
- if (URI.equals(browser.currentURI) === false) {
+ // Update URL if fragment is different
+ if (URI.equals(browser.currentURI) === false) {
browser.loadURI(URI.asciiSpec);
- }
+ }
- return;
+ return;
}
- }
+ }
- if (details.active === undefined) {
+ if (details.active === undefined) {
details.active = true;
- }
+ }
- if (details.tabId) {
+ if (details.tabId) {
let tab = vAPI.tabs.manager.browserFromTabId(details.tabId);
if (tab) {
- vAPI.tabs.manager.browserFromTarget(tab).loadURI(details.url);
- return;
+ vAPI.tabs.manager.browserFromTarget(tab).loadURI(details.url);
+ return;
}
- }
+ }
- // Open in a standalone window
- if (details.popup === true) {
+ // Open in a standalone window
+ if (details.popup === true) {
Services.ww.openWindow(self,
- details.url,
- null,
- 'location=1,menubar=1,personalbar=1,'
- +'resizable=1,toolbar=1',
- null);
+ details.url,
+ null,
+ 'location=1,menubar=1,personalbar=1,'
+ +'resizable=1,toolbar=1',
+ null);
return;
- }
+ }
- let win = vAPI.window.getCurrentWindow();
- let tabBrowser = vAPI.browser.getTabBrowser(win);
+ let win = vAPI.window.getCurrentWindow();
+ let tabBrowser = vAPI.browser.getTabBrowser(win);
- if (tabBrowser === null) {
+ if (tabBrowser === null) {
return;
- }
+ }
- if (details.index === -1) {
+ if (details.index === -1) {
details.index =
- tabBrowser.browsers.indexOf(tabBrowser.selectedBrowser) + 1;
- }
+ tabBrowser.browsers.indexOf(tabBrowser.selectedBrowser) + 1;
+ }
- let tab = tabBrowser.loadOneTab(details.url, {
- inBackground: !details.active
- });
+ let tab = tabBrowser.loadOneTab(details.url, {
+ inBackground: !details.active
+ });
- if (details.index !== undefined) {
+ if (details.index !== undefined) {
tabBrowser.moveTabTo(tab, details.index);
- }
+ }
};
vAPI.tabs.replace = function (tabId, url) {
- // Replace the URL of a tab. Noop if the tab does not exist.
- let targetURL = url;
+ // Replace the URL of a tab. Noop if the tab does not exist.
+ let targetURL = url;
- // extension pages
- if (/^[\w-]{2,}:/.test(targetURL) !== true) {
+ // extension pages
+ if (/^[\w-]{2,}:/.test(targetURL) !== true) {
targetURL = vAPI.getURL(targetURL);
- }
+ }
- let browser = vAPI.tabs.manager.browserFromTabId(tabId);
- if (browser) {
+ let browser = vAPI.tabs.manager.browserFromTabId(tabId);
+ if (browser) {
browser.loadURI(targetURL);
- }
+ }
};
function removeInternal(tab, tabBrowser) {
- if (tabBrowser) {
- tabBrowser.removeTab(tab);
- }
+ if (tabBrowser) {
+ tabBrowser.removeTab(tab);
+ }
}
vAPI.tabs.remove = function (tabId) {
- let browser = vAPI.tabs.manager.browserFromTabId(tabId);
- if (!browser) {
+ let browser = vAPI.tabs.manager.browserFromTabId(tabId);
+ if (!browser) {
return;
- }
+ }
- let tab = vAPI.tabs.manager.tabFromBrowser(browser);
- if (!tab) {
+ let tab = vAPI.tabs.manager.tabFromBrowser(browser);
+ if (!tab) {
return;
- }
+ }
- removeInternal(tab,
- vAPI.browser.getTabBrowser
- (vAPI.browser.getOwnerWindow(browser)));
+ removeInternal(tab,
+ vAPI.browser.getTabBrowser
+ (vAPI.browser.getOwnerWindow(browser)));
};
vAPI.tabs.reload = function (tabId) {
- let browser = vAPI.tabs.manager.browserFromTabId(tabId);
- if (!browser) {
+ let browser = vAPI.tabs.manager.browserFromTabId(tabId);
+ if (!browser) {
return;
- }
+ }
- browser.webNavigation.reload(Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE);
+ browser.webNavigation.reload(Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE);
};
vAPI.tabs.select = function (tab) {
- if (typeof tab !== 'object') {
+ if (typeof tab !== 'object') {
tab = vAPI.tabs.manager
- .tabFromBrowser(vAPI.tabs.manager.browserFromTabId(tab));
- }
- if (!tab) {
+ .tabFromBrowser(vAPI.tabs.manager.browserFromTabId(tab));
+ }
+ if (!tab) {
return;
- }
+ }
- // https://github.com/gorhill/uBlock/issues/470
- let win = vAPI.browser.getOwnerWindow(tab);
- win.focus();
+ // https://github.com/gorhill/uBlock/issues/470
+ let win = vAPI.browser.getOwnerWindow(tab);
+ win.focus();
- let tabBrowser = vAPI.browser.getTabBrowser(win);
- if (tabBrowser) {
+ let tabBrowser = vAPI.browser.getTabBrowser(win);
+ if (tabBrowser) {
tabBrowser.selectedTab = tab;
- }
+ }
};
vAPI.tabs.injectScript = function (tabId, details, callback) {
- let browser = vAPI.tabs.manager.browserFromTabId(tabId);
- if (!browser) {
+ let browser = vAPI.tabs.manager.browserFromTabId(tabId);
+ if (!browser) {
return;
- }
+ }
- if (typeof details.file !== 'string') {
+ if (typeof details.file !== 'string') {
return;
- }
-
- details.file = vAPI.getURL(details.file);
- browser.messageManager.sendAsyncMessage(location.host + ':broadcast',
- JSON.stringify({
- broadcast: true,
- channelName: 'vAPI',
- msg: {
- cmd: 'injectScript',
- details: details
- }
- }));
-
- if (typeof callback === 'function') {
+ }
+
+ details.file = vAPI.getURL(details.file);
+ browser.messageManager.sendAsyncMessage(location.host + ':broadcast',
+ JSON.stringify({
+ broadcast: true,
+ channelName: 'vAPI',
+ msg: {
+ cmd: 'injectScript',
+ details: details
+ }
+ }));
+
+ if (typeof callback === 'function') {
vAPI.setTimeout(callback, 13);
- }
+ }
};
vAPI.tabs.manager = (function () {
- // TODO: find out whether we need a janitor to take care of stale entries.
+ // TODO: find out whether we need a janitor to take care of stale entries.
- // https://github.com/gorhill/uMatrix/issues/540
- // Use only weak references to hold onto browser references.
- let browserToTabIdMap = new WeakMap();
- let tabIdToBrowserMap = new Map();
- let tabIdGenerator = 1;
+ // https://github.com/gorhill/uMatrix/issues/540
+ // Use only weak references to hold onto browser references.
+ let browserToTabIdMap = new WeakMap();
+ let tabIdToBrowserMap = new Map();
+ let tabIdGenerator = 1;
- let indexFromBrowser = function (browser) {
+ let indexFromBrowser = function (browser) {
if (!browser) {
- return -1;
+ return -1;
}
- let win = vAPI.browser.getOwnerWindow(browser);
+ let win = vAPI.browser.getOwnerWindow(browser);
if (!win) {
- return -1;
+ return -1;
}
let tabBrowser = vAPI.browser.getTabBrowser(win);
if (tabBrowser === null) {
- return -1;
+ return -1;
}
// This can happen, for example, the `view-source:`
// window, there is no tabbrowser object, the browser
// object sits directly in the window.
if (tabBrowser === browser) {
- return 0;
+ return 0;
}
return tabBrowser.browsers.indexOf(browser);
- };
+ };
- let indexFromTarget = function (target) {
+ let indexFromTarget = function (target) {
return indexFromBrowser(browserFromTarget(target));
- };
+ };
- let tabFromBrowser = function (browser) {
+ let tabFromBrowser = function (browser) {
let i = indexFromBrowser(browser);
if (i === -1) {
- return null;
+ return null;
}
let win = vAPI.browser.getOwnerWindow(browser);
if (!win) {
- return null;
+ return null;
}
let tabBrowser = vAPI.browser.getTabBrowser(win);
if (tabBrowser === null) {
- return null;
+ return null;
}
if (!tabBrowser.tabs || i >= tabBrowser.tabs.length) {
- return null;
+ return null;
}
return tabBrowser.tabs[i];
- };
+ };
- let browserFromTarget = function (target) {
+ let browserFromTarget = function (target) {
if (!target) {
- return null;
+ return null;
}
if (target.linkedPanel) {
- // target is a tab
- target = target.linkedBrowser;
+ // target is a tab
+ target = target.linkedBrowser;
}
if (target.localName !== 'browser') {
- return null;
+ return null;
}
return target;
- };
+ };
- let tabIdFromTarget = function (target) {
+ let tabIdFromTarget = function (target) {
let browser = browserFromTarget(target);
if (browser === null) {
- return vAPI.noTabId;
+ return vAPI.noTabId;
}
let tabId = browserToTabIdMap.get(browser);
if (tabId === undefined) {
- tabId = '' + tabIdGenerator++;
- browserToTabIdMap.set(browser, tabId);
- tabIdToBrowserMap.set(tabId, Cu.getWeakReference(browser));
+ tabId = '' + tabIdGenerator++;
+ browserToTabIdMap.set(browser, tabId);
+ tabIdToBrowserMap.set(tabId, Cu.getWeakReference(browser));
}
return tabId;
- };
+ };
- let browserFromTabId = function (tabId) {
+ let browserFromTabId = function (tabId) {
let weakref = tabIdToBrowserMap.get(tabId);
let browser = weakref && weakref.get();
return browser || null;
- };
+ };
- let currentBrowser = function () {
+ let currentBrowser = function () {
let win = vAPI.window.getCurrentWindow();
// https://github.com/gorhill/uBlock/issues/399
// getTabBrowser() can return null at browser launch time.
let tabBrowser = vAPI.browser.getTabBrowser(win);
if (tabBrowser === null) {
- return null;
+ return null;
}
return browserFromTarget(tabBrowser.selectedTab);
- };
+ };
- let removeBrowserEntry = function (tabId, browser) {
+ let removeBrowserEntry = function (tabId, browser) {
if (tabId && tabId !== vAPI.noTabId) {
- vAPI.tabs.onClosed(tabId);
- delete vAPI.toolbarButton.tabs[tabId];
- tabIdToBrowserMap.delete(tabId);
+ vAPI.tabs.onClosed(tabId);
+ delete vAPI.toolbarButton.tabs[tabId];
+ tabIdToBrowserMap.delete(tabId);
}
if (browser) {
- browserToTabIdMap.delete(browser);
+ browserToTabIdMap.delete(browser);
}
- };
+ };
- let removeTarget = function (target) {
+ let removeTarget = function (target) {
onClose({
- target: target
- });
- };
+ target: target
+ });
+ };
- let getAllBrowsers = function () {
+ let getAllBrowsers = function () {
let browsers = [];
- for (let [tabId, weakref] of tabIdToBrowserMap) {
- let browser = weakref.get();
+ for (let [tabId, weakref] of tabIdToBrowserMap) {
+ let browser = weakref.get();
- // TODO: Maybe call removeBrowserEntry() if the
- // browser no longer exists?
- if (browser) {
+ // TODO: Maybe call removeBrowserEntry() if the
+ // browser no longer exists?
+ if (browser) {
browsers.push(browser);
- }
+ }
}
return browsers;
- };
-
- // var onOpen = function (target) {
- // var tabId = tabIdFromTarget(target);
- // var browser = browserFromTabId(tabId);
- // vAPI.tabs.onNavigation({
- // frameId: 0,
- // tabId: tabId,
- // url: browser.currentURI.asciiSpec,
- // });
- // };
-
- var onShow = function ({target}) {
+ };
+
+ // var onOpen = function (target) {
+ // var tabId = tabIdFromTarget(target);
+ // var browser = browserFromTabId(tabId);
+ // vAPI.tabs.onNavigation({
+ // frameId: 0,
+ // tabId: tabId,
+ // url: browser.currentURI.asciiSpec,
+ // });
+ // };
+
+ var onShow = function ({target}) {
tabIdFromTarget(target);
- };
+ };
- var onClose = function ({target}) {
+ var onClose = function ({target}) {
// target is tab in Firefox, browser in Fennec
let browser = browserFromTarget(target);
let tabId = browserToTabIdMap.get(browser);
removeBrowserEntry(tabId, browser);
- };
+ };
- var onSelect = function ({target}) {
- // This is an entry point: when creating a new tab, it is
- // not always reported through onLocationChanged...
- // Sigh. It is "reported" here however.
+ var onSelect = function ({target}) {
+ // This is an entry point: when creating a new tab, it is
+ // not always reported through onLocationChanged...
+ // Sigh. It is "reported" here however.
let browser = browserFromTarget(target);
let tabId = browserToTabIdMap.get(browser);
- if (tabId === undefined) {
- tabId = tabIdFromTarget(target);
- vAPI.tabs.onNavigation({
+ if (tabId === undefined) {
+ tabId = tabIdFromTarget(target);
+ vAPI.tabs.onNavigation({
frameId: 0,
tabId: tabId,
url: browser.currentURI.asciiSpec
- });
+ });
}
vAPI.setIcon(tabId, vAPI.browser.getOwnerWindow(target));
- };
+ };
- let locationChangedMessageName = location.host + ':locationChanged';
+ let locationChangedMessageName = location.host + ':locationChanged';
- let onLocationChanged = function (e) {
+ let onLocationChanged = function (e) {
let details = e.data;
// Ignore notifications related to our popup
if (details.url.lastIndexOf(vAPI.getURL('popup.html'), 0) === 0) {
- return;
+ return;
}
let browser = e.target;
let tabId = tabIdFromTarget(browser);
if (tabId === vAPI.noTabId) {
- return;
+ return;
}
// LOCATION_CHANGE_SAME_DOCUMENT = "did not load a new document"
if (details.flags
- & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT) {
- vAPI.tabs.onUpdated(tabId, {url: details.url}, {
+ & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT) {
+ vAPI.tabs.onUpdated(tabId, {url: details.url}, {
frameId: 0,
tabId: tabId,
url: browser.currentURI.asciiSpec
- });
- return;
+ });
+ return;
}
// https://github.com/chrisaljoudi/uBlock/issues/105
// Allow any kind of pages
vAPI.tabs.onNavigation({
- frameId: 0,
- tabId: tabId,
- url: details.url
+ frameId: 0,
+ tabId: tabId,
+ url: details.url
});
- };
+ };
- let attachToTabBrowser = function (window) {
+ let attachToTabBrowser = function (window) {
if (typeof vAPI.toolbarButton.attachToNewWindow === 'function') {
- vAPI.toolbarButton.attachToNewWindow(window);
+ vAPI.toolbarButton.attachToNewWindow(window);
}
let tabBrowser = vAPI.browser.getTabBrowser(window);
if (tabBrowser === null) {
- return;
+ return;
}
let tabContainer;
if (tabBrowser.deck) {
// Fennec
- tabContainer = tabBrowser.deck;
+ tabContainer = tabBrowser.deck;
} else if (tabBrowser.tabContainer) {
- // Firefox
- tabContainer = tabBrowser.tabContainer;
+ // Firefox
+ tabContainer = tabBrowser.tabContainer;
}
// https://github.com/gorhill/uBlock/issues/697
@@ -579,20 +579,20 @@
// of session restore -- it is set *after* the event is
// fired in such case.
if (tabContainer) {
- tabContainer.addEventListener('TabShow', onShow);
- tabContainer.addEventListener('TabClose', onClose);
- // when new window is opened TabSelect doesn't run on
- // the selected tab?
- tabContainer.addEventListener('TabSelect', onSelect);
+ tabContainer.addEventListener('TabShow', onShow);
+ tabContainer.addEventListener('TabClose', onClose);
+ // when new window is opened TabSelect doesn't run on
+ // the selected tab?
+ tabContainer.addEventListener('TabSelect', onSelect);
}
- };
+ };
- var canAttachToTabBrowser = function (window) {
- // https://github.com/gorhill/uBlock/issues/906
- // Ensure the environment is ready before trying to attaching.
+ var canAttachToTabBrowser = function (window) {
+ // https://github.com/gorhill/uBlock/issues/906
+ // Ensure the environment is ready before trying to attaching.
let document = window && window.document;
if (!document || document.readyState !== 'complete') {
- return false;
+ return false;
}
// On some platforms, the tab browser isn't immediately
@@ -602,28 +602,28 @@
// attaching ourself to the window.
let tabBrowser = vAPI.browser.getTabBrowser(window);
if (tabBrowser === null) {
- return false;
+ return false;
}
return vAPI.window.toBrowserWindow(window) !== null;
- };
+ };
- let onWindowLoad = function (win) {
+ let onWindowLoad = function (win) {
vAPI.deferUntil(canAttachToTabBrowser.bind(null, win),
- attachToTabBrowser.bind(null, win));
- };
+ attachToTabBrowser.bind(null, win));
+ };
- let onWindowUnload = function (win) {
+ let onWindowUnload = function (win) {
let tabBrowser = vAPI.browser.getTabBrowser(win);
if (tabBrowser === null) {
- return;
+ return;
}
let tabContainer = tabBrowser.tabContainer;
if (tabContainer) {
- tabContainer.removeEventListener('TabShow', onShow);
- tabContainer.removeEventListener('TabClose', onClose);
- tabContainer.removeEventListener('TabSelect', onSelect);
+ tabContainer.removeEventListener('TabShow', onShow);
+ tabContainer.removeEventListener('TabClose', onClose);
+ tabContainer.removeEventListener('TabSelect', onSelect);
}
// https://github.com/gorhill/uBlock/issues/574
@@ -631,85 +631,85 @@
// sometimes the window IS the tab.
let tabs;
if (tabBrowser.tabs) {
- tabs = tabBrowser.tabs;
+ tabs = tabBrowser.tabs;
} else if (tabBrowser.localName === 'browser') {
- tabs = [tabBrowser];
+ tabs = [tabBrowser];
} else {
- tabs = [];
+ tabs = [];
}
let browser;
- let URI;
- let tabId;
- for (let i=tabs.length-1; i>=0; --i) {
- let tab = tabs[i];
- browser = browserFromTarget(tab);
- if (browser === null) {
+ let URI;
+ let tabId;
+ for (let i=tabs.length-1; i>=0; --i) {
+ let tab = tabs[i];
+ browser = browserFromTarget(tab);
+ if (browser === null) {
continue;
- }
+ }
- URI = browser.currentURI;
- // Close extension tabs
- if (URI.schemeIs('chrome') && URI.host === location.host) {
+ URI = browser.currentURI;
+ // Close extension tabs
+ if (URI.schemeIs('chrome') && URI.host === location.host) {
removeInternal(tab, vAPI.browser.getTabBrowser(win));
- }
+ }
- tabId = browserToTabIdMap.get(browser);
- if (tabId !== undefined) {
+ tabId = browserToTabIdMap.get(browser);
+ if (tabId !== undefined) {
removeBrowserEntry(tabId, browser);
tabIdToBrowserMap.delete(tabId);
- }
- browserToTabIdMap.delete(browser);
+ }
+ browserToTabIdMap.delete(browser);
}
- };
+ };
- var start = function () {
- // Initialize map with existing active tabs
+ var start = function () {
+ // Initialize map with existing active tabs
let tabBrowser;
- let tabs;
+ let tabs;
for (let win of vAPI.window.getWindows()) {
- onWindowLoad(win);
+ onWindowLoad(win);
- tabBrowser = vAPI.browser.getTabBrowser(win);
- if (tabBrowser === null) {
+ tabBrowser = vAPI.browser.getTabBrowser(win);
+ if (tabBrowser === null) {
continue;
- }
+ }
- for (let tab of tabBrowser.tabs) {
+ for (let tab of tabBrowser.tabs) {
if (!tab.hasAttribute('pending')) {
- tabIdFromTarget(tab);
+ tabIdFromTarget(tab);
}
- }
+ }
}
vAPI.window.onOpenWindow = onWindowLoad;
vAPI.window.onCloseWindow = onWindowUnload;
vAPI.messaging.globalMessageManager
- .addMessageListener(locationChangedMessageName,
- onLocationChanged);
- };
+ .addMessageListener(locationChangedMessageName,
+ onLocationChanged);
+ };
- let stop = function () {
+ let stop = function () {
vAPI.window.onOpenWindow = null;
vAPI.window.onCloseWindow = null;
vAPI.messaging.globalMessageManager
- .removeMessageListener(locationChangedMessageName,
- onLocationChanged);
+ .removeMessageListener(locationChangedMessageName,
+ onLocationChanged);
for (let win of vAPI.window.getWindows()) {
- onWindowUnload(win);
+ onWindowUnload(win);
}
browserToTabIdMap = new WeakMap();
tabIdToBrowserMap.clear();
- };
+ };
- vAPI.addCleanUpTask(stop);
+ vAPI.addCleanUpTask(stop);
- return {
+ return {
browsers: getAllBrowsers,
browserFromTabId: browserFromTabId,
browserFromTarget: browserFromTarget,
@@ -719,6 +719,6 @@
start: start,
tabFromBrowser: tabFromBrowser,
tabIdFromTarget: tabIdFromTarget
- };
+ };
})();
})();
diff --git a/js/vapi-window.js b/js/vapi-window.js
index 9e35db8..c7baede 100644
--- a/js/vapi-window.js
+++ b/js/vapi-window.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 The uMatrix/uBlock Origin authors
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -27,157 +27,157 @@
(function () {
vAPI.window = (function () {
- let windowToIdMap = new Map();
- let windowIdGenerator = 1;
- let api = {
+ let windowToIdMap = new Map();
+ let windowIdGenerator = 1;
+ let api = {
onOpenWindow: null,
onCloseWindow: null
- };
-
- // https://github.com/gorhill/uMatrix/issues/586 This is
- // necessary hack because on SeaMonkey 2.40, for unknown
- // reasons private windows do not have the attribute
- // `windowtype` set to `navigator:browser`. As a fallback, the
- // code here will also test whether the id attribute is
- // `main-window`.
- api.toBrowserWindow = function (win) {
+ };
+
+ // https://github.com/gorhill/uMatrix/issues/586 This is
+ // necessary hack because on SeaMonkey 2.40, for unknown
+ // reasons private windows do not have the attribute
+ // `windowtype` set to `navigator:browser`. As a fallback, the
+ // code here will also test whether the id attribute is
+ // `main-window`.
+ api.toBrowserWindow = function (win) {
let docElement = win && win.document
- && win.document.documentElement;
+ && win.document.documentElement;
if (!docElement) {
- return null;
+ return null;
}
if (vAPI.thunderbird) {
- return docElement.getAttribute('windowtype') === 'mail:3pane'
- ? win
- : null;
+ return docElement.getAttribute('windowtype') === 'mail:3pane'
+ ? win
+ : null;
}
return docElement.getAttribute('windowtype') === 'navigator:browser'
- || docElement.getAttribute('id') === 'main-window'
- ? win
- : null;
- };
+ || docElement.getAttribute('id') === 'main-window'
+ ? win
+ : null;
+ };
- api.getWindows = function () {
+ api.getWindows = function () {
return windowToIdMap.keys();
- };
+ };
- api.idFromWindow = function (win) {
+ api.idFromWindow = function (win) {
return windowToIdMap.get(win) || 0;
- };
+ };
- api.getCurrentWindow = function () {
+ api.getCurrentWindow = function () {
return this.toBrowserWindow(Services.wm.getMostRecentWindow(null));
- };
+ };
- let addWindow = function (win) {
+ let addWindow = function (win) {
if (!win || windowToIdMap.has(win)) {
- return;
+ return;
}
windowToIdMap.set(win, windowIdGenerator++);
if (typeof api.onOpenWindow === 'function') {
- api.onOpenWindow(win);
+ api.onOpenWindow(win);
}
- };
+ };
- let removeWindow = function (win) {
+ let removeWindow = function (win) {
if (!win || windowToIdMap.delete(win) !== true) {
- return;
+ return;
}
if (typeof api.onCloseWindow === 'function') {
- api.onCloseWindow(win);
+ api.onCloseWindow(win);
}
- };
+ };
- // https://github.com/gorhill/uMatrix/issues/357
- // Use nsIWindowMediator for being notified of opened/closed windows.
- let listeners = {
+ // https://github.com/gorhill/uMatrix/issues/357
+ // Use nsIWindowMediator for being notified of opened/closed windows.
+ let listeners = {
onOpenWindow: function (aWindow) {
- let win;
- try {
+ let win;
+ try {
win = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
- } catch (e) {
- // Ignore
- }
+ } catch (e) {
+ // Ignore
+ }
- addWindow(win);
+ addWindow(win);
},
onCloseWindow: function (aWindow) {
- let win;
- try {
+ let win;
+ try {
win = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
- } catch (e) {
- // Ignore
- }
+ } catch (e) {
+ // Ignore
+ }
- removeWindow(win);
+ removeWindow(win);
},
observe: function (aSubject, topic) {
- let win;
- try {
+ let win;
+ try {
win = aSubject.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
- } catch (e) {
- // Ignore
- }
-
- if (!win) {
- return;
- }
-
- switch (topic) {
- case 'domwindowopened':
- addWindow(win);
- break;
- case 'domwindowclosed':
- removeWindow(win);
- break;
- default:
- console.error('unknown observer topic');
- break;
- }
+ } catch (e) {
+ // Ignore
+ }
+
+ if (!win) {
+ return;
+ }
+
+ switch (topic) {
+ case 'domwindowopened':
+ addWindow(win);
+ break;
+ case 'domwindowclosed':
+ removeWindow(win);
+ break;
+ default:
+ console.error('unknown observer topic');
+ break;
+ }
}
- };
+ };
- (function() {
+ (function() {
let winumerator;
winumerator = Services.wm.getEnumerator(null);
while (winumerator.hasMoreElements()) {
- let win = winumerator.getNext();
+ let win = winumerator.getNext();
- if (!win.closed) {
+ if (!win.closed) {
windowToIdMap.set(win, windowIdGenerator++);
- }
+ }
}
winumerator = Services.ww.getWindowEnumerator();
while (winumerator.hasMoreElements()) {
- let win = winumerator.getNext()
+ let win = winumerator.getNext()
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
- if (!win.closed) {
+ if (!win.closed) {
windowToIdMap.set(win, windowIdGenerator++);
- }
+ }
}
Services.wm.addListener(listeners);
Services.ww.registerNotification(listeners);
- })();
+ })();
- vAPI.addCleanUpTask(function() {
+ vAPI.addCleanUpTask(function() {
Services.wm.removeListener(listeners);
Services.ww.unregisterNotification(listeners);
windowToIdMap.clear();
- });
+ });
- return api;
+ return api;
})();
})();
diff --git a/js/xal.js b/js/xal.js
index ffbd21a..fe42e19 100644
--- a/js/xal.js
+++ b/js/xal.js
@@ -2,7 +2,7 @@
ηMatrix - a browser extension to black/white list requests.
Copyright (C) 2014-2019 Raymond Hill
- Copyright (C) 2019-2020 Alessio Vanni
+ Copyright (C) 2019-2022 Alessio Vanni
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
- Home: https://libregit.spks.xyz/heckyel/ematrix
+ Home: https://gitlab.com/vannilla/ematrix
uMatrix Home: https://github.com/gorhill/uMatrix
*/
@@ -29,47 +29,47 @@
ηMatrix.XAL = (function(){
- /******************************************************************************/
+/******************************************************************************/
- var exports = {};
- var noopFunc = function(){};
+var exports = {};
+var noopFunc = function(){};
- /******************************************************************************/
+/******************************************************************************/
- exports.keyvalSetOne = function(key, val, callback) {
- var bin = {};
- bin[key] = val;
- vAPI.storage.set(bin, callback || noopFunc);
- };
+exports.keyvalSetOne = function(key, val, callback) {
+ var bin = {};
+ bin[key] = val;
+ vAPI.storage.set(bin, callback || noopFunc);
+};
- /******************************************************************************/
+/******************************************************************************/
- exports.keyvalGetOne = function(key, callback) {
- vAPI.storage.get(key, callback);
- };
+exports.keyvalGetOne = function(key, callback) {
+ vAPI.storage.get(key, callback);
+};
- /******************************************************************************/
+/******************************************************************************/
- exports.keyvalSetMany = function(dict, callback) {
- vAPI.storage.set(dict, callback || noopFunc);
- };
+exports.keyvalSetMany = function(dict, callback) {
+ vAPI.storage.set(dict, callback || noopFunc);
+};
- /******************************************************************************/
+/******************************************************************************/
- exports.keyvalRemoveOne = function(key, callback) {
- vAPI.storage.remove(key, callback || noopFunc);
- };
+exports.keyvalRemoveOne = function(key, callback) {
+ vAPI.storage.remove(key, callback || noopFunc);
+};
- /******************************************************************************/
+/******************************************************************************/
- exports.keyvalRemoveAll = function(callback) {
- vAPI.storage.clear(callback || noopFunc);
- };
+exports.keyvalRemoveAll = function(callback) {
+ vAPI.storage.clear(callback || noopFunc);
+};
- /******************************************************************************/
+/******************************************************************************/
- return exports;
+return exports;
- /******************************************************************************/
+/******************************************************************************/
})();