mirror of
https://github.com/gorhill/uMatrix.git
synced 2024-09-29 08:41:11 +13:00
Fix #335
Additionally, performance improvements: - Reduce overhead of collapsing elements (see https://github.com/gorhill/uBlock/issues/2839) - Cache decomposition of source hostname when matrix-filtering Also, various code review.
This commit is contained in:
parent
8615f3b804
commit
73c8da05b7
11 changed files with 586 additions and 455 deletions
|
@ -342,6 +342,10 @@
|
||||||
"message": "Collapse placeholder of blocked elements",
|
"message": "Collapse placeholder of blocked elements",
|
||||||
"description": "English: Collapse placeholder of blocked elements"
|
"description": "English: Collapse placeholder of blocked elements"
|
||||||
},
|
},
|
||||||
|
"settingsCollapseBlacklisted" : {
|
||||||
|
"message": "Collapse placeholder of blacklisted elements",
|
||||||
|
"description": "A setting in the dashboard's Settings pane: 'blacklisted' means 'for which there is a specific block rule', 'specific' means 'a rule for which the destination hostname is not `*`'"
|
||||||
|
},
|
||||||
"settingsNoscriptTagsSpoofed" : {
|
"settingsNoscriptTagsSpoofed" : {
|
||||||
"message": "Spoof <code><noscript></code> tags when 1st-party scripts are blocked",
|
"message": "Spoof <code><noscript></code> tags when 1st-party scripts are blocked",
|
||||||
"description": "This appears in the Settings pane in the dashboard"
|
"description": "This appears in the Settings pane in the dashboard"
|
||||||
|
|
|
@ -36,7 +36,9 @@ a {
|
||||||
button {
|
button {
|
||||||
padding: 0.3em 0.5em;
|
padding: 0.3em 0.5em;
|
||||||
}
|
}
|
||||||
|
input[disabled] + label {
|
||||||
|
color: gray;
|
||||||
|
}
|
||||||
.para {
|
.para {
|
||||||
width: 40em;
|
width: 40em;
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,6 +91,7 @@ return {
|
||||||
clearBrowserCache: true,
|
clearBrowserCache: true,
|
||||||
clearBrowserCacheAfter: 60,
|
clearBrowserCacheAfter: 60,
|
||||||
cloudStorageEnabled: false,
|
cloudStorageEnabled: false,
|
||||||
|
collapseBlacklisted: true,
|
||||||
collapseBlocked: false,
|
collapseBlocked: false,
|
||||||
colorBlindFriendly: false,
|
colorBlindFriendly: false,
|
||||||
deleteCookies: false,
|
deleteCookies: false,
|
||||||
|
|
|
@ -109,71 +109,86 @@ vAPI.contentscriptEndInjected = true;
|
||||||
// https://github.com/gorhill/uMatrix/issues/45
|
// https://github.com/gorhill/uMatrix/issues/45
|
||||||
|
|
||||||
var collapser = (function() {
|
var collapser = (function() {
|
||||||
var timer = null;
|
var resquestIdGenerator = 1,
|
||||||
var requestId = 1;
|
processTimer,
|
||||||
var newRequests = [];
|
toProcess = [],
|
||||||
var pendingRequests = {};
|
toFilter = [],
|
||||||
var pendingRequestCount = 0;
|
toCollapse = new Map(),
|
||||||
var srcProps = {
|
cachedBlockedMap,
|
||||||
'img': 'src'
|
cachedBlockedMapHash,
|
||||||
|
cachedBlockedMapTimer,
|
||||||
|
reURLPlaceholder = /\{\{url\}\}/g;
|
||||||
|
var src1stProps = {
|
||||||
|
'embed': 'src',
|
||||||
|
'iframe': 'src',
|
||||||
|
'img': 'src',
|
||||||
|
'object': 'data'
|
||||||
};
|
};
|
||||||
var reURLplaceholder = /\{\{url\}\}/g;
|
var src2ndProps = {
|
||||||
|
'img': 'srcset'
|
||||||
var PendingRequest = function(target) {
|
};
|
||||||
this.id = requestId++;
|
var tagToTypeMap = {
|
||||||
this.target = target;
|
embed: 'media',
|
||||||
pendingRequests[this.id] = this;
|
iframe: 'frame',
|
||||||
pendingRequestCount += 1;
|
img: 'image',
|
||||||
};
|
object: 'media'
|
||||||
|
};
|
||||||
// Because a while ago I have observed constructors are faster than
|
var cachedBlockedSetClear = function() {
|
||||||
// literal object instanciations.
|
cachedBlockedMap =
|
||||||
var BouncingRequest = function(id, tagName, url) {
|
cachedBlockedMapHash =
|
||||||
this.id = id;
|
cachedBlockedMapTimer = undefined;
|
||||||
this.tagName = tagName;
|
|
||||||
this.url = url;
|
|
||||||
this.blocked = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// https://github.com/chrisaljoudi/uBlock/issues/174
|
||||||
|
// Do not remove fragment from src URL
|
||||||
var onProcessed = function(response) {
|
var onProcessed = function(response) {
|
||||||
if ( !response ) {
|
if ( !response ) { // This happens if uBO is disabled or restarted.
|
||||||
|
toCollapse.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var requests = response.requests;
|
|
||||||
if ( requests === null || Array.isArray(requests) === false ) {
|
var targets = toCollapse.get(response.id);
|
||||||
|
if ( targets === undefined ) { return; }
|
||||||
|
toCollapse.delete(response.id);
|
||||||
|
if ( cachedBlockedMapHash !== response.hash ) {
|
||||||
|
cachedBlockedMap = new Map(response.blockedResources);
|
||||||
|
cachedBlockedMapHash = response.hash;
|
||||||
|
if ( cachedBlockedMapTimer !== undefined ) {
|
||||||
|
clearTimeout(cachedBlockedMapTimer);
|
||||||
|
}
|
||||||
|
cachedBlockedMapTimer = vAPI.setTimeout(cachedBlockedSetClear, 30000);
|
||||||
|
}
|
||||||
|
if ( cachedBlockedMap === undefined || cachedBlockedMap.size === 0 ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var collapse = response.collapse;
|
|
||||||
var placeholders = response.placeholders;
|
var placeholders = response.placeholders,
|
||||||
var i = requests.length;
|
tag, prop, src, collapsed, docurl, replaced;
|
||||||
var request, entry, target, tagName, docurl, replaced;
|
|
||||||
while ( i-- ) {
|
for ( var target of targets ) {
|
||||||
request = requests[i];
|
tag = target.localName;
|
||||||
if ( pendingRequests.hasOwnProperty(request.id) === false ) {
|
prop = src1stProps[tag];
|
||||||
continue;
|
if ( prop === undefined ) { continue; }
|
||||||
|
src = target[prop];
|
||||||
|
if ( typeof src !== 'string' || src.length === 0 ) {
|
||||||
|
prop = src2ndProps[tag];
|
||||||
|
if ( prop === undefined ) { continue; }
|
||||||
|
src = target[prop];
|
||||||
|
if ( typeof src !== 'string' || src.length === 0 ) { continue; }
|
||||||
}
|
}
|
||||||
entry = pendingRequests[request.id];
|
collapsed = cachedBlockedMap.get(tagToTypeMap[tag] + ' ' + src);
|
||||||
delete pendingRequests[request.id];
|
if ( collapsed === undefined ) { continue; }
|
||||||
pendingRequestCount -= 1;
|
if ( collapsed ) {
|
||||||
|
|
||||||
// Not blocked
|
|
||||||
if ( !request.blocked ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
target = entry.target;
|
|
||||||
|
|
||||||
// No placeholders
|
|
||||||
if ( collapse ) {
|
|
||||||
target.style.setProperty('display', 'none', 'important');
|
target.style.setProperty('display', 'none', 'important');
|
||||||
|
target.hidden = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if ( tag === 'iframe' ) {
|
||||||
tagName = target.localName;
|
docurl =
|
||||||
|
'data:text/html,' +
|
||||||
// Special case: iframe
|
encodeURIComponent(
|
||||||
if ( tagName === 'iframe' ) {
|
placeholders.iframe.replace(reURLPlaceholder, src)
|
||||||
docurl = 'data:text/html,' + encodeURIComponent(placeholders.iframe.replace(reURLplaceholder, request.url));
|
);
|
||||||
replaced = false;
|
replaced = false;
|
||||||
// Using contentWindow.location prevent tainting browser
|
// Using contentWindow.location prevent tainting browser
|
||||||
// history -- i.e. breaking back button (seen on Chromium).
|
// history -- i.e. breaking back button (seen on Chromium).
|
||||||
|
@ -189,148 +204,125 @@ var collapser = (function() {
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
target.setAttribute(src1stProps[tag], placeholders[tag]);
|
||||||
// Everything else
|
|
||||||
target.setAttribute(srcProps[tagName], placeholders[tagName]);
|
|
||||||
target.style.setProperty('border', placeholders.border, 'important');
|
target.style.setProperty('border', placeholders.border, 'important');
|
||||||
target.style.setProperty('background', placeholders.background, 'important');
|
target.style.setProperty('background', placeholders.background, 'important');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Renew map: I believe that even if all properties are deleted, an
|
|
||||||
// object will still use more memory than a brand new one.
|
|
||||||
if ( pendingRequestCount === 0 ) {
|
|
||||||
pendingRequests = {};
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var send = function() {
|
var send = function() {
|
||||||
timer = null;
|
processTimer = undefined;
|
||||||
vAPI.messaging.send('contentscript.js', {
|
toCollapse.set(resquestIdGenerator, toProcess);
|
||||||
what: 'evaluateURLs',
|
var msg = {
|
||||||
requests: newRequests
|
what: 'lookupBlockedCollapsibles',
|
||||||
}, onProcessed);
|
id: resquestIdGenerator,
|
||||||
newRequests = [];
|
toFilter: toFilter,
|
||||||
|
hash: cachedBlockedMapHash
|
||||||
|
};
|
||||||
|
vAPI.messaging.send('contentscript.js', msg, onProcessed);
|
||||||
|
toProcess = [];
|
||||||
|
toFilter = [];
|
||||||
|
resquestIdGenerator += 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
var process = function(delay) {
|
var process = function(delay) {
|
||||||
if ( newRequests.length === 0 ) {
|
if ( toProcess.length === 0 ) { return; }
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ( delay === 0 ) {
|
if ( delay === 0 ) {
|
||||||
clearTimeout(timer);
|
if ( processTimer !== undefined ) {
|
||||||
|
clearTimeout(processTimer);
|
||||||
|
}
|
||||||
send();
|
send();
|
||||||
} else if ( timer === null ) {
|
} else if ( processTimer === undefined ) {
|
||||||
timer = vAPI.setTimeout(send, delay || 50);
|
processTimer = vAPI.setTimeout(send, delay || 47);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var add = function(target) {
|
||||||
|
toProcess.push(target);
|
||||||
|
};
|
||||||
|
|
||||||
|
var addMany = function(targets) {
|
||||||
|
var i = targets.length;
|
||||||
|
while ( i-- ) {
|
||||||
|
toProcess.push(targets[i]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var iframeSourceModified = function(mutations) {
|
var iframeSourceModified = function(mutations) {
|
||||||
var i = mutations.length;
|
var i = mutations.length;
|
||||||
while ( i-- ) {
|
while ( i-- ) {
|
||||||
addFrameNode(mutations[i].target, true);
|
addIFrame(mutations[i].target, true);
|
||||||
}
|
}
|
||||||
process();
|
process();
|
||||||
};
|
};
|
||||||
var iframeSourceObserver = null;
|
var iframeSourceObserver;
|
||||||
var iframeSourceObserverOptions = {
|
var iframeSourceObserverOptions = {
|
||||||
attributes: true,
|
attributes: true,
|
||||||
attributeFilter: [ 'src' ]
|
attributeFilter: [ 'src' ]
|
||||||
};
|
};
|
||||||
|
|
||||||
var addFrameNode = function(iframe, dontObserve) {
|
var addIFrame = function(iframe, dontObserve) {
|
||||||
// https://github.com/gorhill/uBlock/issues/162
|
// https://github.com/gorhill/uBlock/issues/162
|
||||||
// Be prepared to deal with possible change of src attribute.
|
// Be prepared to deal with possible change of src attribute.
|
||||||
if ( dontObserve !== true ) {
|
if ( dontObserve !== true ) {
|
||||||
if ( iframeSourceObserver === null ) {
|
if ( iframeSourceObserver === undefined ) {
|
||||||
iframeSourceObserver = new MutationObserver(iframeSourceModified);
|
iframeSourceObserver = new MutationObserver(iframeSourceModified);
|
||||||
}
|
}
|
||||||
iframeSourceObserver.observe(iframe, iframeSourceObserverOptions);
|
iframeSourceObserver.observe(iframe, iframeSourceObserverOptions);
|
||||||
}
|
}
|
||||||
// https://github.com/chrisaljoudi/uBlock/issues/174
|
|
||||||
// Do not remove fragment from src URL
|
|
||||||
var src = iframe.src;
|
var src = iframe.src;
|
||||||
if ( src.lastIndexOf('http', 0) !== 0 ) {
|
if ( src === '' || typeof src !== 'string' ) { return; }
|
||||||
return;
|
if ( src.startsWith('http') === false ) { return; }
|
||||||
}
|
toFilter.push({ type: 'frame', url: iframe.src });
|
||||||
var req = new PendingRequest(iframe);
|
add(iframe);
|
||||||
newRequests.push(new BouncingRequest(req.id, 'iframe', src));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var addNode = function(target) {
|
var addIFrames = function(iframes) {
|
||||||
var tagName = target.localName;
|
var i = iframes.length;
|
||||||
if ( tagName === 'iframe' ) {
|
|
||||||
addFrameNode(target);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var prop = srcProps[tagName];
|
|
||||||
if ( prop === undefined ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// https://github.com/chrisaljoudi/uBlock/issues/174
|
|
||||||
// Do not remove fragment from src URL
|
|
||||||
var src = target[prop];
|
|
||||||
if ( typeof src !== 'string' || src === '' ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ( src.lastIndexOf('http', 0) !== 0 ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var req = new PendingRequest(target);
|
|
||||||
newRequests.push(new BouncingRequest(req.id, tagName, src));
|
|
||||||
};
|
|
||||||
|
|
||||||
var addNodes = function(nodes) {
|
|
||||||
var node;
|
|
||||||
var i = nodes.length;
|
|
||||||
while ( i-- ) {
|
while ( i-- ) {
|
||||||
node = nodes[i];
|
addIFrame(iframes[i]);
|
||||||
if ( node.nodeType === 1 ) {
|
|
||||||
addNode(node);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var addBranches = function(branches) {
|
var addNodeList = function(nodeList) {
|
||||||
var root;
|
var node,
|
||||||
var i = branches.length;
|
i = nodeList.length;
|
||||||
while ( i-- ) {
|
while ( i-- ) {
|
||||||
root = branches[i];
|
node = nodeList[i];
|
||||||
if ( root.nodeType === 1 ) {
|
if ( node.nodeType !== 1 ) { continue; }
|
||||||
addNode(root);
|
if ( node.localName === 'iframe' ) {
|
||||||
// blocked images will be reported by onResourceFailed
|
addIFrame(node);
|
||||||
addNodes(root.querySelectorAll('iframe'));
|
}
|
||||||
|
if ( node.childElementCount !== 0 ) {
|
||||||
|
addIFrames(node.querySelectorAll('iframe'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Listener to collapse blocked resources.
|
|
||||||
// - Future requests not blocked yet
|
|
||||||
// - Elements dynamically added to the page
|
|
||||||
// - Elements which resource URL changes
|
|
||||||
var onResourceFailed = function(ev) {
|
var onResourceFailed = function(ev) {
|
||||||
addNode(ev.target);
|
if ( tagToTypeMap[ev.target.localName] !== undefined ) {
|
||||||
|
add(ev.target);
|
||||||
process();
|
process();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
document.addEventListener('error', onResourceFailed, true);
|
document.addEventListener('error', onResourceFailed, true);
|
||||||
|
|
||||||
vAPI.shutdown.add(function() {
|
vAPI.shutdown.add(function() {
|
||||||
if ( timer !== null ) {
|
|
||||||
clearTimeout(timer);
|
|
||||||
timer = null;
|
|
||||||
}
|
|
||||||
if ( iframeSourceObserver !== null ) {
|
|
||||||
iframeSourceObserver.disconnect();
|
|
||||||
iframeSourceObserver = null;
|
|
||||||
}
|
|
||||||
document.removeEventListener('error', onResourceFailed, true);
|
document.removeEventListener('error', onResourceFailed, true);
|
||||||
newRequests = [];
|
if ( iframeSourceObserver !== undefined ) {
|
||||||
pendingRequests = {};
|
iframeSourceObserver.disconnect();
|
||||||
pendingRequestCount = 0;
|
iframeSourceObserver = undefined;
|
||||||
|
}
|
||||||
|
if ( processTimer !== undefined ) {
|
||||||
|
clearTimeout(processTimer);
|
||||||
|
processTimer = undefined;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
addNodes: addNodes,
|
addMany: addMany,
|
||||||
addBranches: addBranches,
|
addIFrames: addIFrames,
|
||||||
|
addNodeList: addNodeList,
|
||||||
process: process
|
process: process
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
@ -345,10 +337,6 @@ var hasInlineScript = function(nodeList, summary) {
|
||||||
if ( node.nodeType !== 1 ) {
|
if ( node.nodeType !== 1 ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ( typeof node.localName !== 'string' ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( node.localName === 'script' ) {
|
if ( node.localName === 'script' ) {
|
||||||
text = node.textContent.trim();
|
text = node.textContent.trim();
|
||||||
if ( text === '' ) {
|
if ( text === '' ) {
|
||||||
|
@ -357,7 +345,6 @@ var hasInlineScript = function(nodeList, summary) {
|
||||||
summary.inlineScript = true;
|
summary.inlineScript = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( node.localName === 'a' && node.href.lastIndexOf('javascript', 0) === 0 ) {
|
if ( node.localName === 'a' && node.href.lastIndexOf('javascript', 0) === 0 ) {
|
||||||
summary.inlineScript = true;
|
summary.inlineScript = true;
|
||||||
break;
|
break;
|
||||||
|
@ -368,8 +355,6 @@ var hasInlineScript = function(nodeList, summary) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
var nodeListsAddedHandler = function(nodeLists) {
|
var nodeListsAddedHandler = function(nodeLists) {
|
||||||
var i = nodeLists.length;
|
var i = nodeLists.length;
|
||||||
if ( i === 0 ) {
|
if ( i === 0 ) {
|
||||||
|
@ -385,7 +370,7 @@ var nodeListsAddedHandler = function(nodeLists) {
|
||||||
if ( summary.inlineScript === false ) {
|
if ( summary.inlineScript === false ) {
|
||||||
hasInlineScript(nodeLists[i], summary);
|
hasInlineScript(nodeLists[i], summary);
|
||||||
}
|
}
|
||||||
collapser.addBranches(nodeLists[i]);
|
collapser.addNodeList(nodeLists[i]);
|
||||||
}
|
}
|
||||||
if ( summary.mustReport ) {
|
if ( summary.mustReport ) {
|
||||||
vAPI.messaging.send('contentscript.js', summary);
|
vAPI.messaging.send('contentscript.js', summary);
|
||||||
|
@ -415,7 +400,8 @@ var nodeListsAddedHandler = function(nodeLists) {
|
||||||
|
|
||||||
vAPI.messaging.send('contentscript.js', summary);
|
vAPI.messaging.send('contentscript.js', summary);
|
||||||
|
|
||||||
collapser.addNodes(document.querySelectorAll('iframe,img'));
|
collapser.addMany(document.querySelectorAll('img'));
|
||||||
|
collapser.addIFrames(document.querySelectorAll('iframe'));
|
||||||
collapser.process();
|
collapser.process();
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
@ -427,6 +413,9 @@ var nodeListsAddedHandler = function(nodeLists) {
|
||||||
// Added node lists will be cumulated here before being processed
|
// Added node lists will be cumulated here before being processed
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
|
// This fixes http://acid3.acidtests.org/
|
||||||
|
if ( !document.body ) { return; }
|
||||||
|
|
||||||
var addedNodeLists = [];
|
var addedNodeLists = [];
|
||||||
var addedNodeListsTimer = null;
|
var addedNodeListsTimer = null;
|
||||||
|
|
||||||
|
@ -439,28 +428,19 @@ var nodeListsAddedHandler = function(nodeLists) {
|
||||||
// https://github.com/gorhill/uBlock/issues/205
|
// https://github.com/gorhill/uBlock/issues/205
|
||||||
// Do not handle added node directly from within mutation observer.
|
// Do not handle added node directly from within mutation observer.
|
||||||
var treeMutationObservedHandlerAsync = function(mutations) {
|
var treeMutationObservedHandlerAsync = function(mutations) {
|
||||||
var iMutation = mutations.length;
|
var iMutation = mutations.length,
|
||||||
var nodeList;
|
nodeList;
|
||||||
while ( iMutation-- ) {
|
while ( iMutation-- ) {
|
||||||
nodeList = mutations[iMutation].addedNodes;
|
nodeList = mutations[iMutation].addedNodes;
|
||||||
if ( nodeList.length !== 0 ) {
|
if ( nodeList.length !== 0 ) {
|
||||||
addedNodeLists.push(nodeList);
|
addedNodeLists.push(nodeList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// I arbitrarily chose 250 ms for now:
|
|
||||||
// I have to compromise between the overhead of processing too few
|
|
||||||
// nodes too often and the delay of many nodes less often. There is nothing
|
|
||||||
// time critical here.
|
|
||||||
if ( addedNodeListsTimer === null ) {
|
if ( addedNodeListsTimer === null ) {
|
||||||
addedNodeListsTimer = vAPI.setTimeout(treeMutationObservedHandler, 250);
|
addedNodeListsTimer = vAPI.setTimeout(treeMutationObservedHandler, 47);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// This fixes http://acid3.acidtests.org/
|
|
||||||
if ( !document.body ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://github.com/gorhill/httpswitchboard/issues/176
|
// https://github.com/gorhill/httpswitchboard/issues/176
|
||||||
var treeObserver = new MutationObserver(treeMutationObservedHandlerAsync);
|
var treeObserver = new MutationObserver(treeMutationObservedHandlerAsync);
|
||||||
treeObserver.observe(document.body, {
|
treeObserver.observe(document.body, {
|
||||||
|
|
|
@ -39,6 +39,9 @@ var uniqueIdGenerator = 1;
|
||||||
var Matrix = function() {
|
var Matrix = function() {
|
||||||
this.id = uniqueIdGenerator++;
|
this.id = uniqueIdGenerator++;
|
||||||
this.reset();
|
this.reset();
|
||||||
|
this.sourceRegister = '';
|
||||||
|
this.decomposedSourceRegister = [''];
|
||||||
|
this.specificityRegister = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
@ -141,9 +144,7 @@ var isIPAddress = function(hostname) {
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
var toBroaderHostname = function(hostname) {
|
var toBroaderHostname = function(hostname) {
|
||||||
if ( hostname === '*' ) {
|
if ( hostname === '*' ) { return ''; }
|
||||||
return '';
|
|
||||||
}
|
|
||||||
if ( isIPAddress(hostname) ) {
|
if ( isIPAddress(hostname) ) {
|
||||||
return toBroaderIPAddress(hostname);
|
return toBroaderIPAddress(hostname);
|
||||||
}
|
}
|
||||||
|
@ -192,6 +193,20 @@ Matrix.prototype.reset = function() {
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
// Copy another matrix to self. Do this incrementally to minimize impact on
|
// Copy another matrix to self. Do this incrementally to minimize impact on
|
||||||
// a live matrix.
|
// a live matrix.
|
||||||
|
|
||||||
|
@ -331,10 +346,13 @@ Matrix.prototype.evaluateCell = function(srcHostname, desHostname, type) {
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
Matrix.prototype.evaluateCellZ = function(srcHostname, desHostname, type) {
|
Matrix.prototype.evaluateCellZ = function(srcHostname, desHostname, type) {
|
||||||
var bitOffset = typeBitOffsets.get(type);
|
this.decomposeSource(srcHostname);
|
||||||
var s = srcHostname;
|
|
||||||
var v;
|
var bitOffset = typeBitOffsets.get(type),
|
||||||
|
s, v, i = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
s = this.decomposedSourceRegister[i++];
|
||||||
|
if ( s === '' ) { break; }
|
||||||
v = this.rules.get(s + ' ' + desHostname);
|
v = this.rules.get(s + ' ' + desHostname);
|
||||||
if ( v !== undefined ) {
|
if ( v !== undefined ) {
|
||||||
v = v >> bitOffset & 3;
|
v = v >> bitOffset & 3;
|
||||||
|
@ -342,9 +360,6 @@ Matrix.prototype.evaluateCellZ = function(srcHostname, desHostname, type) {
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: external rules? (for presets)
|
|
||||||
s = toBroaderHostname(s);
|
|
||||||
if ( s === '' ) { break; }
|
|
||||||
}
|
}
|
||||||
// srcHostname is '*' at this point
|
// srcHostname is '*' at this point
|
||||||
|
|
||||||
|
@ -366,6 +381,7 @@ Matrix.prototype.evaluateCellZ = function(srcHostname, desHostname, type) {
|
||||||
|
|
||||||
Matrix.prototype.evaluateCellZXY = function(srcHostname, desHostname, type) {
|
Matrix.prototype.evaluateCellZXY = function(srcHostname, desHostname, type) {
|
||||||
// Matrix filtering switch
|
// Matrix filtering switch
|
||||||
|
this.specificityRegister = 0;
|
||||||
if ( this.evaluateSwitchZ('matrix-off', srcHostname) ) {
|
if ( this.evaluateSwitchZ('matrix-off', srcHostname) ) {
|
||||||
return Matrix.GreenIndirect;
|
return Matrix.GreenIndirect;
|
||||||
}
|
}
|
||||||
|
@ -377,11 +393,13 @@ Matrix.prototype.evaluateCellZXY = function(srcHostname, desHostname, type) {
|
||||||
// evaluating net requests.
|
// evaluating net requests.
|
||||||
|
|
||||||
// Specific-hostname specific-type cell
|
// Specific-hostname specific-type cell
|
||||||
|
this.specificityRegister = 1;
|
||||||
var r = this.evaluateCellZ(srcHostname, desHostname, type);
|
var r = this.evaluateCellZ(srcHostname, desHostname, type);
|
||||||
if ( r === 1 ) { return Matrix.RedDirect; }
|
if ( r === 1 ) { return Matrix.RedDirect; }
|
||||||
if ( r === 2 ) { return Matrix.GreenDirect; }
|
if ( r === 2 ) { return Matrix.GreenDirect; }
|
||||||
|
|
||||||
// Specific-hostname any-type cell
|
// Specific-hostname any-type cell
|
||||||
|
this.specificityRegister = 2;
|
||||||
var rl = this.evaluateCellZ(srcHostname, desHostname, '*');
|
var rl = this.evaluateCellZ(srcHostname, desHostname, '*');
|
||||||
if ( rl === 1 ) { return Matrix.RedIndirect; }
|
if ( rl === 1 ) { return Matrix.RedIndirect; }
|
||||||
|
|
||||||
|
@ -390,10 +408,9 @@ Matrix.prototype.evaluateCellZXY = function(srcHostname, desHostname, type) {
|
||||||
|
|
||||||
// Ancestor cells, up to 1st-party destination domain
|
// Ancestor cells, up to 1st-party destination domain
|
||||||
if ( firstPartyDesDomain !== '' ) {
|
if ( firstPartyDesDomain !== '' ) {
|
||||||
|
this.specificityRegister = 3;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if ( d === firstPartyDesDomain ) {
|
if ( d === firstPartyDesDomain ) { break; }
|
||||||
break;
|
|
||||||
}
|
|
||||||
d = d.slice(d.indexOf('.') + 1);
|
d = d.slice(d.indexOf('.') + 1);
|
||||||
|
|
||||||
// specific-hostname specific-type cell
|
// specific-hostname specific-type cell
|
||||||
|
@ -420,11 +437,10 @@ Matrix.prototype.evaluateCellZXY = function(srcHostname, desHostname, type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep going, up to root
|
// Keep going, up to root
|
||||||
|
this.specificityRegister = 4;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
d = toBroaderHostname(d);
|
d = toBroaderHostname(d);
|
||||||
if ( d === '*' ) {
|
if ( d === '*' ) { break; }
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// specific-hostname specific-type cell
|
// specific-hostname specific-type cell
|
||||||
r = this.evaluateCellZ(srcHostname, d, type);
|
r = this.evaluateCellZ(srcHostname, d, type);
|
||||||
|
@ -438,6 +454,7 @@ Matrix.prototype.evaluateCellZXY = function(srcHostname, desHostname, type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Any-hostname specific-type cells
|
// Any-hostname specific-type cells
|
||||||
|
this.specificityRegister = 5;
|
||||||
r = this.evaluateCellZ(srcHostname, '*', type);
|
r = this.evaluateCellZ(srcHostname, '*', type);
|
||||||
// Line below is strict-blocking
|
// Line below is strict-blocking
|
||||||
if ( r === 1 ) { return Matrix.RedIndirect; }
|
if ( r === 1 ) { return Matrix.RedIndirect; }
|
||||||
|
@ -446,6 +463,7 @@ Matrix.prototype.evaluateCellZXY = function(srcHostname, desHostname, type) {
|
||||||
if ( r === 2 ) { return Matrix.GreenIndirect; }
|
if ( r === 2 ) { return Matrix.GreenIndirect; }
|
||||||
|
|
||||||
// Any-hostname any-type cell
|
// Any-hostname any-type cell
|
||||||
|
this.specificityRegister = 6;
|
||||||
r = this.evaluateCellZ(srcHostname, '*', '*');
|
r = this.evaluateCellZ(srcHostname, '*', '*');
|
||||||
if ( r === 1 ) { return Matrix.RedIndirect; }
|
if ( r === 1 ) { return Matrix.RedIndirect; }
|
||||||
if ( r === 2 ) { return Matrix.GreenIndirect; }
|
if ( r === 2 ) { return Matrix.GreenIndirect; }
|
||||||
|
@ -534,12 +552,14 @@ Matrix.prototype.evaluateSwitch = function(switchName, srcHostname) {
|
||||||
|
|
||||||
Matrix.prototype.evaluateSwitchZ = function(switchName, srcHostname) {
|
Matrix.prototype.evaluateSwitchZ = function(switchName, srcHostname) {
|
||||||
var bitOffset = switchBitOffsets.get(switchName);
|
var bitOffset = switchBitOffsets.get(switchName);
|
||||||
if ( bitOffset === undefined ) {
|
if ( bitOffset === undefined ) { return false; }
|
||||||
return false;
|
|
||||||
}
|
this.decomposeSource(srcHostname);
|
||||||
var bits;
|
|
||||||
var s = srcHostname;
|
var s, bits, i = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
s = this.decomposedSourceRegister[i++];
|
||||||
|
if ( s === '' ) { break; }
|
||||||
bits = this.switches.get(s) || 0;
|
bits = this.switches.get(s) || 0;
|
||||||
if ( bits !== 0 ) {
|
if ( bits !== 0 ) {
|
||||||
bits = bits >> bitOffset & 3;
|
bits = bits >> bitOffset & 3;
|
||||||
|
@ -547,10 +567,6 @@ Matrix.prototype.evaluateSwitchZ = function(switchName, srcHostname) {
|
||||||
return bits === 1;
|
return bits === 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s = toBroaderHostname(s);
|
|
||||||
if ( s === '' ) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
|
@ -427,68 +427,58 @@ var contentScriptSummaryHandler = function(tabId, details) {
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
var contentScriptLocalStorageHandler = function(tabId, pageURL) {
|
var contentScriptLocalStorageHandler = function(tabId, pageURL) {
|
||||||
var µmuri = µm.URI.set(pageURL);
|
var tabContext = µm.tabContextManager.lookup(tabId);
|
||||||
var response = µm.mustBlock(µm.scopeFromURL(pageURL), µmuri.hostname, 'cookie');
|
if ( tabContext === null ) { return; }
|
||||||
µm.recordFromTabId(
|
|
||||||
tabId,
|
var blocked = µm.mustBlock(
|
||||||
'cookie',
|
tabContext.rootHostname,
|
||||||
µmuri.rootURL() + '/{localStorage}',
|
µm.URI.hostnameFromURI(pageURL),
|
||||||
response
|
'cookie'
|
||||||
);
|
);
|
||||||
response = response && µm.userSettings.deleteLocalStorage;
|
|
||||||
if ( response ) {
|
var pageStore = µm.pageStoreFromTabId(tabId);
|
||||||
|
if ( pageStore !== null ) {
|
||||||
|
var requestURL = µm.URI.originFromURI(pageURL) + '/{localStorage}';
|
||||||
|
pageStore.recordRequest('cookie', requestURL, blocked);
|
||||||
|
µm.logger.writeOne(tabId, 'net', tabContext.rootHostname, requestURL, 'cookie', blocked);
|
||||||
|
}
|
||||||
|
|
||||||
|
var removeStorage = blocked && µm.userSettings.deleteLocalStorage;
|
||||||
|
if ( removeStorage ) {
|
||||||
µm.localStorageRemovedCounter++;
|
µm.localStorageRemovedCounter++;
|
||||||
}
|
}
|
||||||
return response;
|
|
||||||
|
return removeStorage;
|
||||||
};
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
// Evaluate many URLs against the matrix.
|
// Evaluate many URLs against the matrix.
|
||||||
|
|
||||||
var evaluateURLs = function(tabId, requests) {
|
var lookupBlockedCollapsibles = function(tabId, requests) {
|
||||||
var collapse = µm.userSettings.collapseBlocked;
|
|
||||||
var response = {
|
var response = {
|
||||||
collapse: collapse,
|
blockedResources: [],
|
||||||
requests: requests
|
hash: requests.hash,
|
||||||
|
id: requests.id,
|
||||||
|
placeholders: placeholders
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create evaluation context
|
|
||||||
var tabContext = µm.tabContextManager.lookup(tabId);
|
var tabContext = µm.tabContextManager.lookup(tabId);
|
||||||
if ( tabContext === null ) {
|
if ( tabContext === null ) {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
var rootHostname = tabContext.rootHostname;
|
|
||||||
|
|
||||||
//console.debug('messaging.js/contentscript.js: processing %d requests', requests.length);
|
|
||||||
|
|
||||||
var pageStore = µm.pageStoreFromTabId(tabId);
|
var pageStore = µm.pageStoreFromTabId(tabId);
|
||||||
var µmuri = µm.URI;
|
if ( pageStore !== null ) {
|
||||||
var typeMap = tagNameToRequestTypeMap;
|
pageStore.lookupBlockedCollapsibles(requests, response);
|
||||||
var request, type;
|
}
|
||||||
var i = requests.length;
|
|
||||||
while ( i-- ) {
|
// TODO: evaluate whether the issue reported below still exists.
|
||||||
request = requests[i];
|
|
||||||
type = typeMap[request.tagName];
|
|
||||||
request.blocked = µm.mustBlock(
|
|
||||||
rootHostname,
|
|
||||||
µmuri.hostnameFromURI(request.url),
|
|
||||||
type
|
|
||||||
);
|
|
||||||
// https://github.com/gorhill/uMatrix/issues/205
|
// https://github.com/gorhill/uMatrix/issues/205
|
||||||
// If blocked, the URL must be recorded by the page store, so as to ensure
|
// If blocked, the URL must be recorded by the page store, so as to
|
||||||
// they are properly reflected in the matrix.
|
// ensure they are properly reflected in the matrix.
|
||||||
if ( request.blocked && pageStore ) {
|
|
||||||
pageStore.recordRequest(type, request.url, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( collapse ) {
|
if ( response.placeholders === null ) {
|
||||||
placeholders = null;
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( placeholders === null ) {
|
|
||||||
placeholders = {
|
placeholders = {
|
||||||
background:
|
background:
|
||||||
vAPI.localStorage.getItem('placeholderBackground') ||
|
vAPI.localStorage.getItem('placeholderBackground') ||
|
||||||
|
@ -505,19 +495,12 @@ var evaluateURLs = function(tabId, requests) {
|
||||||
};
|
};
|
||||||
placeholders.iframe =
|
placeholders.iframe =
|
||||||
placeholders.iframe.replace('{{bg}}', placeholders.background);
|
placeholders.iframe.replace('{{bg}}', placeholders.background);
|
||||||
}
|
|
||||||
response.placeholders = placeholders;
|
response.placeholders = placeholders;
|
||||||
|
}
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
};
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
var tagNameToRequestTypeMap = {
|
|
||||||
'iframe': 'frame',
|
|
||||||
'img': 'image'
|
|
||||||
};
|
|
||||||
|
|
||||||
var placeholders = null;
|
var placeholders = null;
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
@ -544,8 +527,8 @@ var onMessage = function(request, sender, callback) {
|
||||||
contentScriptSummaryHandler(tabId, request);
|
contentScriptSummaryHandler(tabId, request);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'evaluateURLs':
|
case 'lookupBlockedCollapsibles':
|
||||||
response = evaluateURLs(tabId, request.requests);
|
response = lookupBlockedCollapsibles(tabId, request);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'mustRenderNoscriptTags?':
|
case 'mustRenderNoscriptTags?':
|
||||||
|
|
|
@ -25,31 +25,89 @@
|
||||||
|
|
||||||
µMatrix.pageStoreFactory = (function() {
|
µMatrix.pageStoreFactory = (function() {
|
||||||
|
|
||||||
var µm = µMatrix;
|
/******************************************************************************/
|
||||||
var pageStoreJunkyard = [];
|
|
||||||
|
|
||||||
// Ref: Given a URL, returns a (somewhat) unique 32-bit value
|
var µm = µMatrix;
|
||||||
// Based on: FNV32a
|
|
||||||
// http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-reference-source
|
/******************************************************************************/
|
||||||
// The rest is custom, suited for µMatrix.
|
|
||||||
var uidFromURL = function(uri) {
|
var BlockedCollapsibles = function() {
|
||||||
var hint = 0x811c9dc5;
|
this.boundPruneAsyncCallback = this.pruneAsyncCallback.bind(this);
|
||||||
var i = uri.length;
|
this.blocked = new Map();
|
||||||
while ( i-- ) {
|
this.hash = 0;
|
||||||
hint ^= uri.charCodeAt(i) | 0;
|
this.timer = null;
|
||||||
hint += (hint<<1) + (hint<<4) + (hint<<7) + (hint<<8) + (hint<<24) | 0;
|
};
|
||||||
hint >>>= 0;
|
|
||||||
|
BlockedCollapsibles.prototype = {
|
||||||
|
|
||||||
|
shelfLife: 10 * 1000,
|
||||||
|
|
||||||
|
add: function(type, url, isSpecific) {
|
||||||
|
if ( this.blocked.size === 0 ) { this.pruneAsync(); }
|
||||||
|
var 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;
|
||||||
|
} else {
|
||||||
|
now &= 0xFFFFFFFE;
|
||||||
}
|
}
|
||||||
return hint;
|
this.blocked.set(type + ' ' + url, now);
|
||||||
};
|
this.hash = now;
|
||||||
|
},
|
||||||
|
|
||||||
function PageStore(tabContext) {
|
reset: function() {
|
||||||
|
this.blocked.clear();
|
||||||
|
this.hash = 0;
|
||||||
|
if ( this.timer !== null ) {
|
||||||
|
clearTimeout(this.timer);
|
||||||
|
this.timer = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
pruneAsync: function() {
|
||||||
|
if ( this.timer === null ) {
|
||||||
|
this.timer = vAPI.setTimeout(
|
||||||
|
this.boundPruneAsyncCallback,
|
||||||
|
this.shelfLife * 2
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
pruneAsyncCallback: function() {
|
||||||
|
this.timer = null;
|
||||||
|
var obsolete = Date.now() - this.shelfLife;
|
||||||
|
for ( var entry of this.blocked ) {
|
||||||
|
if ( entry[1] <= obsolete ) {
|
||||||
|
this.blocked.delete(entry[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( this.blocked.size !== 0 ) { this.pruneAsync(); }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
// Ref: Given a URL, returns a (somewhat) unique 32-bit value
|
||||||
|
// Based on: FNV32a
|
||||||
|
// http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-reference-source
|
||||||
|
// The rest is custom, suited for uMatrix.
|
||||||
|
|
||||||
|
var PageStore = function(tabContext) {
|
||||||
|
this.hostnameTypeCells = new Map();
|
||||||
|
this.domains = new Set();
|
||||||
|
this.blockedCollapsibles = new BlockedCollapsibles();
|
||||||
this.requestStats = µm.requestStatsFactory();
|
this.requestStats = µm.requestStatsFactory();
|
||||||
this.off = false;
|
this.off = false;
|
||||||
this.init(tabContext);
|
this.init(tabContext);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
PageStore.prototype = {
|
||||||
|
|
||||||
|
collapsibleTypes: new Set([ 'image' ]),
|
||||||
|
pageStoreJunkyard: [],
|
||||||
|
|
||||||
PageStore.prototype = {
|
|
||||||
init: function(tabContext) {
|
init: function(tabContext) {
|
||||||
this.tabId = tabContext.tabId;
|
this.tabId = tabContext.tabId;
|
||||||
this.rawUrl = tabContext.rawURL;
|
this.rawUrl = tabContext.rawURL;
|
||||||
|
@ -57,9 +115,10 @@
|
||||||
this.pageHostname = tabContext.rootHostname;
|
this.pageHostname = tabContext.rootHostname;
|
||||||
this.pageDomain = tabContext.rootDomain;
|
this.pageDomain = tabContext.rootDomain;
|
||||||
this.title = '';
|
this.title = '';
|
||||||
this.hostnameTypeCells = new Map();
|
this.hostnameTypeCells.clear();
|
||||||
this.domains = new Set();
|
this.domains.clear();
|
||||||
this.allHostnamesString = ' ';
|
this.allHostnamesString = ' ';
|
||||||
|
this.blockedCollapsibles.reset();
|
||||||
this.requestStats.reset();
|
this.requestStats.reset();
|
||||||
this.distinctRequestCount = 0;
|
this.distinctRequestCount = 0;
|
||||||
this.perLoadAllowedRequestCount = 0;
|
this.perLoadAllowedRequestCount = 0;
|
||||||
|
@ -69,38 +128,91 @@
|
||||||
this.mtxCountModifiedTime = 0;
|
this.mtxCountModifiedTime = 0;
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
dispose: function() {
|
dispose: function() {
|
||||||
this.hostnameTypeCells.clear();
|
|
||||||
this.rawUrl = '';
|
this.rawUrl = '';
|
||||||
this.pageUrl = '';
|
this.pageUrl = '';
|
||||||
this.pageHostname = '';
|
this.pageHostname = '';
|
||||||
this.pageDomain = '';
|
this.pageDomain = '';
|
||||||
this.title = '';
|
this.title = '';
|
||||||
|
this.hostnameTypeCells.clear();
|
||||||
this.domains.clear();
|
this.domains.clear();
|
||||||
this.allHostnamesString = ' ';
|
this.allHostnamesString = ' ';
|
||||||
|
this.blockedCollapsibles.reset();
|
||||||
if ( this.incinerationTimer !== null ) {
|
if ( this.incinerationTimer !== null ) {
|
||||||
clearTimeout(this.incinerationTimer);
|
clearTimeout(this.incinerationTimer);
|
||||||
this.incinerationTimer = null;
|
this.incinerationTimer = null;
|
||||||
}
|
}
|
||||||
if ( pageStoreJunkyard.length < 8 ) {
|
if ( this.pageStoreJunkyard.length < 8 ) {
|
||||||
pageStoreJunkyard.push(this);
|
this.pageStoreJunkyard.push(this);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
recordRequest: function(type, url, block) {
|
|
||||||
var hostname = µm.URI.hostnameFromURI(url);
|
|
||||||
|
|
||||||
|
cacheBlockedCollapsible: function(type, url, specificity) {
|
||||||
|
if ( this.collapsibleTypes.has(type) ) {
|
||||||
|
this.blockedCollapsibles.add(
|
||||||
|
type,
|
||||||
|
url,
|
||||||
|
specificity !== 0 && specificity < 5
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
lookupBlockedCollapsibles: function(request, response) {
|
||||||
|
var tabContext = µm.tabContextManager.lookup(this.tabId);
|
||||||
|
if ( tabContext === null ) { return; }
|
||||||
|
|
||||||
|
var collapseBlacklisted = µm.userSettings.collapseBlacklisted,
|
||||||
|
collapseBlocked = µm.userSettings.collapseBlocked,
|
||||||
|
entry;
|
||||||
|
|
||||||
|
var blockedResources = response.blockedResources;
|
||||||
|
|
||||||
|
if (
|
||||||
|
Array.isArray(request.toFilter) &&
|
||||||
|
request.toFilter.length !== 0
|
||||||
|
) {
|
||||||
|
var roothn = tabContext.rootHostname,
|
||||||
|
hnFromURI = µm.URI.hostnameFromURI,
|
||||||
|
tMatrix = µm.tMatrix;
|
||||||
|
for ( entry of request.toFilter ) {
|
||||||
|
if ( tMatrix.mustBlock(roothn, hnFromURI(entry.url), entry.type) === false ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
blockedResources.push([
|
||||||
|
entry.type + ' ' + entry.url,
|
||||||
|
collapseBlocked ||
|
||||||
|
collapseBlacklisted && tMatrix.specificityRegister !== 0 &&
|
||||||
|
tMatrix.specificityRegister < 5
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( this.blockedCollapsibles.hash === response.hash ) { return; }
|
||||||
|
response.hash = this.blockedCollapsibles.hash;
|
||||||
|
|
||||||
|
for ( entry of this.blockedCollapsibles.blocked ) {
|
||||||
|
blockedResources.push([
|
||||||
|
entry[0],
|
||||||
|
collapseBlocked || collapseBlacklisted && (entry[1] & 1) !== 0
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
recordRequest: function(type, url, block) {
|
||||||
// Store distinct network requests. This is used to:
|
// Store distinct network requests. This is used to:
|
||||||
// - remember which hostname/type were seen
|
// - remember which hostname/type were seen
|
||||||
// - count the number of distinct URLs for any given
|
// - count the number of distinct URLs for any given
|
||||||
// hostname-type pair
|
// hostname-type pair
|
||||||
var key = hostname + ' ' + type,
|
var hostname = µm.URI.hostnameFromURI(url),
|
||||||
|
key = hostname + ' ' + type,
|
||||||
uids = this.hostnameTypeCells.get(key);
|
uids = this.hostnameTypeCells.get(key);
|
||||||
if ( uids === undefined ) {
|
if ( uids === undefined ) {
|
||||||
this.hostnameTypeCells.set(key, (uids = new Set()));
|
this.hostnameTypeCells.set(key, (uids = new Set()));
|
||||||
} else if ( uids.size > 99 ) {
|
} else if ( uids.size > 99 ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var uid = uidFromURL(url);
|
var uid = this.uidFromURL(url);
|
||||||
if ( uids.has(uid) ) { return; }
|
if ( uids.has(uid) ) { return; }
|
||||||
uids.add(uid);
|
uids.add(uid);
|
||||||
|
|
||||||
|
@ -126,16 +238,32 @@
|
||||||
this.allHostnamesString += hostname + ' ';
|
this.allHostnamesString += hostname + ' ';
|
||||||
this.mtxContentModifiedTime = Date.now();
|
this.mtxContentModifiedTime = Date.now();
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
};
|
|
||||||
|
|
||||||
return function pageStoreFactory(tabContext) {
|
uidFromURL: function(uri) {
|
||||||
var entry = pageStoreJunkyard.pop();
|
var hint = 0x811c9dc5,
|
||||||
|
i = uri.length;
|
||||||
|
while ( i-- ) {
|
||||||
|
hint ^= uri.charCodeAt(i) | 0;
|
||||||
|
hint += (hint<<1) + (hint<<4) + (hint<<7) + (hint<<8) + (hint<<24) | 0;
|
||||||
|
hint >>>= 0;
|
||||||
|
}
|
||||||
|
return hint;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
return function pageStoreFactory(tabContext) {
|
||||||
|
var entry = PageStore.prototype.pageStoreJunkyard.pop();
|
||||||
if ( entry ) {
|
if ( entry ) {
|
||||||
return entry.init(tabContext);
|
return entry.init(tabContext);
|
||||||
}
|
}
|
||||||
return new PageStore(tabContext);
|
return new PageStore(tabContext);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
|
@ -53,16 +53,16 @@ function changeMatrixSwitch(name, state) {
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
function onChangeValueHandler(uelem, setting, min, max) {
|
function onChangeValueHandler(elem, setting, min, max) {
|
||||||
var oldVal = cachedSettings.userSettings[setting];
|
var oldVal = cachedSettings.userSettings[setting];
|
||||||
var newVal = Math.round(parseFloat(uelem.val()));
|
var newVal = Math.round(parseFloat(elem.value));
|
||||||
if ( typeof newVal !== 'number' ) {
|
if ( typeof newVal !== 'number' ) {
|
||||||
newVal = oldVal;
|
newVal = oldVal;
|
||||||
} else {
|
} else {
|
||||||
newVal = Math.max(newVal, min);
|
newVal = Math.max(newVal, min);
|
||||||
newVal = Math.min(newVal, max);
|
newVal = Math.min(newVal, max);
|
||||||
}
|
}
|
||||||
uelem.val(newVal);
|
elem.value = newVal;
|
||||||
if ( newVal !== oldVal ) {
|
if ( newVal !== oldVal ) {
|
||||||
changeUserSettings(setting, newVal);
|
changeUserSettings(setting, newVal);
|
||||||
}
|
}
|
||||||
|
@ -71,50 +71,89 @@ function onChangeValueHandler(uelem, setting, min, max) {
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
function prepareToDie() {
|
function prepareToDie() {
|
||||||
onChangeValueHandler(uDom('#delete-unused-session-cookies-after'), 'deleteUnusedSessionCookiesAfter', 15, 1440);
|
onChangeValueHandler(
|
||||||
onChangeValueHandler(uDom('#clear-browser-cache-after'), 'clearBrowserCacheAfter', 15, 1440);
|
uDom.nodeFromId('deleteUnusedSessionCookiesAfter'),
|
||||||
|
'deleteUnusedSessionCookiesAfter',
|
||||||
|
15, 1440
|
||||||
|
);
|
||||||
|
onChangeValueHandler(
|
||||||
|
uDom.nodeFromId('clearBrowserCacheAfter'),
|
||||||
|
'clearBrowserCacheAfter',
|
||||||
|
15, 1440
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
var installEventHandlers = function() {
|
function onInputChanged(ev) {
|
||||||
uDom('input[name="displayTextSize"]').on('change', function(){
|
var target = ev.target;
|
||||||
changeUserSettings('displayTextSize', this.value);
|
|
||||||
});
|
|
||||||
|
|
||||||
uDom('#popupScopeLevel').on('change', function(){
|
switch ( target.id ) {
|
||||||
changeUserSettings('popupScopeLevel', this.value);
|
case 'displayTextSizeNormal':
|
||||||
});
|
case 'displayTextSizeLarge':
|
||||||
|
changeUserSettings('displayTextSize', target.value);
|
||||||
uDom('[data-setting-bool]').on('change', function(){
|
break;
|
||||||
var settingName = this.getAttribute('data-setting-bool');
|
case 'clearBrowserCache':
|
||||||
if ( typeof settingName === 'string' && settingName !== '' ) {
|
case 'cloudStorageEnabled':
|
||||||
changeUserSettings(settingName, this.checked);
|
case 'collapseBlacklisted':
|
||||||
|
case 'collapseBlocked':
|
||||||
|
case 'colorBlindFriendly':
|
||||||
|
case 'deleteCookies':
|
||||||
|
case 'deleteLocalStorage':
|
||||||
|
case 'deleteUnusedSessionCookies':
|
||||||
|
case 'iconBadgeEnabled':
|
||||||
|
case 'processHyperlinkAuditing':
|
||||||
|
changeUserSettings(target.id, target.checked);
|
||||||
|
break;
|
||||||
|
case 'noMixedContent':
|
||||||
|
case 'processReferer':
|
||||||
|
changeMatrixSwitch(
|
||||||
|
target.getAttribute('data-matrix-switch'),
|
||||||
|
target.checked
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case 'deleteUnusedSessionCookiesAfter':
|
||||||
|
onChangeValueHandler(target, 'deleteUnusedSessionCookiesAfter', 15, 1440);
|
||||||
|
break;
|
||||||
|
case 'clearBrowserCacheAfter':
|
||||||
|
onChangeValueHandler(target, 'clearBrowserCacheAfter', 15, 1440);
|
||||||
|
break;
|
||||||
|
case 'popupScopeLevel':
|
||||||
|
changeUserSettings('popupScopeLevel', target.value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
uDom('[data-matrix-switch]').on('change', function(){
|
switch ( target.id ) {
|
||||||
var switchName = this.getAttribute('data-matrix-switch');
|
case 'collapseBlocked':
|
||||||
if ( typeof switchName === 'string' && switchName !== '' ) {
|
synchronizeWidgets();
|
||||||
changeMatrixSwitch(switchName, this.checked);
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
uDom('#delete-unused-session-cookies-after').on('change', function(){
|
|
||||||
onChangeValueHandler(uDom(this), 'deleteUnusedSessionCookiesAfter', 15, 1440);
|
|
||||||
});
|
|
||||||
uDom('#clear-browser-cache-after').on('change', function(){
|
|
||||||
onChangeValueHandler(uDom(this), 'clearBrowserCacheAfter', 15, 1440);
|
|
||||||
});
|
|
||||||
|
|
||||||
// https://github.com/gorhill/httpswitchboard/issues/197
|
|
||||||
uDom(window).on('beforeunload', prepareToDie);
|
|
||||||
};
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
uDom.onLoad(function() {
|
function synchronizeWidgets() {
|
||||||
var onSettingsReceived = function(settings) {
|
var e1, e2;
|
||||||
|
|
||||||
|
e1 = uDom.nodeFromId('collapseBlocked');
|
||||||
|
e2 = uDom.nodeFromId('collapseBlacklisted');
|
||||||
|
if ( e1.checked ) {
|
||||||
|
e2.setAttribute('disabled', '');
|
||||||
|
} else {
|
||||||
|
e2.removeAttribute('disabled');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
vAPI.messaging.send(
|
||||||
|
'settings.js',
|
||||||
|
{ what: 'getUserSettings' },
|
||||||
|
function onSettingsReceived(settings) {
|
||||||
// Cache copy
|
// Cache copy
|
||||||
cachedSettings = settings;
|
cachedSettings = settings;
|
||||||
|
|
||||||
|
@ -122,10 +161,7 @@ uDom.onLoad(function() {
|
||||||
var matrixSwitches = settings.matrixSwitches;
|
var matrixSwitches = settings.matrixSwitches;
|
||||||
|
|
||||||
uDom('[data-setting-bool]').forEach(function(elem){
|
uDom('[data-setting-bool]').forEach(function(elem){
|
||||||
var settingName = elem.attr('data-setting-bool');
|
elem.prop('checked', userSettings[elem.prop('id')] === true);
|
||||||
if ( typeof settingName === 'string' && settingName !== '' ) {
|
|
||||||
elem.prop('checked', userSettings[settingName] === true);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
uDom('[data-matrix-switch]').forEach(function(elem){
|
uDom('[data-matrix-switch]').forEach(function(elem){
|
||||||
|
@ -140,18 +176,19 @@ uDom.onLoad(function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
uDom.nodeFromId('popupScopeLevel').value = userSettings.popupScopeLevel;
|
uDom.nodeFromId('popupScopeLevel').value = userSettings.popupScopeLevel;
|
||||||
|
uDom.nodeFromId('deleteUnusedSessionCookiesAfter').value =
|
||||||
|
userSettings.deleteUnusedSessionCookiesAfter;
|
||||||
|
uDom.nodeFromId('clearBrowserCacheAfter').value =
|
||||||
|
userSettings.clearBrowserCacheAfter;
|
||||||
|
|
||||||
uDom('#delete-unused-session-cookies-after').val(userSettings.deleteUnusedSessionCookiesAfter);
|
synchronizeWidgets();
|
||||||
uDom('#clear-browser-cache-after').val(userSettings.clearBrowserCacheAfter);
|
|
||||||
|
|
||||||
installEventHandlers();
|
document.addEventListener('change', onInputChanged);
|
||||||
};
|
|
||||||
vAPI.messaging.send(
|
// https://github.com/gorhill/httpswitchboard/issues/197
|
||||||
'settings.js',
|
uDom(window).on('beforeunload', prepareToDie);
|
||||||
{ what: 'getUserSettings' },
|
}
|
||||||
onSettingsReceived
|
);
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
|
|
@ -552,19 +552,6 @@ vAPI.tabs.registerListeners();
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
// Log a request
|
|
||||||
|
|
||||||
µm.recordFromTabId = function(tabId, type, url, blocked) {
|
|
||||||
var pageStore = this.pageStoreFromTabId(tabId);
|
|
||||||
if ( pageStore === null ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pageStore.recordRequest(type, url, blocked);
|
|
||||||
this.logger.writeOne(tabId, 'net', pageStore.pageHostname, url, type, blocked);
|
|
||||||
};
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
µm.forceReload = function(tabId, bypassCache) {
|
µm.forceReload = function(tabId, bypassCache) {
|
||||||
vAPI.tabs.reload(tabId, bypassCache);
|
vAPI.tabs.reload(tabId, bypassCache);
|
||||||
};
|
};
|
||||||
|
|
|
@ -75,26 +75,19 @@ var onBeforeRootFrameRequestHandler = function(details) {
|
||||||
// Intercept and filter web requests according to white and black lists.
|
// Intercept and filter web requests according to white and black lists.
|
||||||
|
|
||||||
var onBeforeRequestHandler = function(details) {
|
var onBeforeRequestHandler = function(details) {
|
||||||
var µm = µMatrix,
|
|
||||||
µmuri = µm.URI;
|
|
||||||
|
|
||||||
// rhill 2014-02-17: Ignore 'filesystem:': this can happen when listening
|
|
||||||
// to 'chrome-extension://'.
|
|
||||||
var requestScheme = µmuri.schemeFromURI(details.url);
|
|
||||||
if ( requestScheme === 'filesystem' ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var requestType = requestTypeNormalizer[details.type] || 'other';
|
var requestType = requestTypeNormalizer[details.type] || 'other';
|
||||||
|
|
||||||
// https://github.com/gorhill/httpswitchboard/issues/303
|
// https://github.com/gorhill/httpswitchboard/issues/303
|
||||||
// Wherever the main doc comes from, create a receiver page URL: synthetize
|
// Wherever the main doc comes from, create a receiver page URL: synthetize
|
||||||
// one if needed.
|
// one if needed.
|
||||||
if ( requestType === 'doc' && details.parentFrameId < 0 ) {
|
if ( requestType === 'doc' && details.parentFrameId === -1 ) {
|
||||||
return onBeforeRootFrameRequestHandler(details);
|
return onBeforeRootFrameRequestHandler(details);
|
||||||
}
|
}
|
||||||
|
|
||||||
var requestURL = details.url;
|
var µm = µMatrix,
|
||||||
|
µmuri = µm.URI,
|
||||||
|
requestURL = details.url,
|
||||||
|
requestScheme = µmuri.schemeFromURI(requestURL);
|
||||||
|
|
||||||
// Ignore non-network schemes
|
// Ignore non-network schemes
|
||||||
if ( µmuri.isNetworkScheme(requestScheme) === false ) {
|
if ( µmuri.isNetworkScheme(requestScheme) === false ) {
|
||||||
|
@ -109,13 +102,24 @@ var onBeforeRequestHandler = function(details) {
|
||||||
// to scope on unknown scheme? Etc.
|
// to scope on unknown scheme? Etc.
|
||||||
// https://github.com/gorhill/httpswitchboard/issues/191
|
// https://github.com/gorhill/httpswitchboard/issues/191
|
||||||
// https://github.com/gorhill/httpswitchboard/issues/91#issuecomment-37180275
|
// https://github.com/gorhill/httpswitchboard/issues/91#issuecomment-37180275
|
||||||
var tabContext = µm.tabContextManager.mustLookup(details.tabId);
|
var tabContext = µm.tabContextManager.mustLookup(details.tabId),
|
||||||
var tabId = tabContext.tabId;
|
tabId = tabContext.tabId,
|
||||||
var rootHostname = tabContext.rootHostname;
|
rootHostname = tabContext.rootHostname,
|
||||||
|
specificity = 0;
|
||||||
|
|
||||||
|
// Filter through matrix
|
||||||
|
var block = µm.tMatrix.mustBlock(
|
||||||
|
rootHostname,
|
||||||
|
µmuri.hostnameFromURI(requestURL),
|
||||||
|
requestType
|
||||||
|
);
|
||||||
|
if ( block ) {
|
||||||
|
specificity = µm.tMatrix.specificityRegister;
|
||||||
|
}
|
||||||
|
|
||||||
// Enforce strict secure connection?
|
// Enforce strict secure connection?
|
||||||
var block = false;
|
|
||||||
if (
|
if (
|
||||||
|
block === false &&
|
||||||
tabContext.secure &&
|
tabContext.secure &&
|
||||||
µmuri.isSecureScheme(requestScheme) === false &&
|
µmuri.isSecureScheme(requestScheme) === false &&
|
||||||
µm.tMatrix.evaluateSwitchZ('https-strict', rootHostname)
|
µm.tMatrix.evaluateSwitchZ('https-strict', rootHostname)
|
||||||
|
@ -123,11 +127,6 @@ var onBeforeRequestHandler = function(details) {
|
||||||
block = true;
|
block = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disallow request as per temporary matrix?
|
|
||||||
if ( block === false ) {
|
|
||||||
block = µm.mustBlock(rootHostname, µmuri.hostnameFromURI(requestURL), requestType);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Record request.
|
// Record request.
|
||||||
// https://github.com/gorhill/httpswitchboard/issues/342
|
// https://github.com/gorhill/httpswitchboard/issues/342
|
||||||
// The way requests are handled now, it may happen at this point some
|
// The way requests are handled now, it may happen at this point some
|
||||||
|
@ -138,16 +137,10 @@ var onBeforeRequestHandler = function(details) {
|
||||||
pageStore.recordRequest(requestType, requestURL, block);
|
pageStore.recordRequest(requestType, requestURL, block);
|
||||||
µm.logger.writeOne(tabId, 'net', rootHostname, requestURL, details.type, block);
|
µm.logger.writeOne(tabId, 'net', rootHostname, requestURL, details.type, block);
|
||||||
|
|
||||||
// Allowed?
|
if ( block ) {
|
||||||
if ( !block ) {
|
pageStore.cacheBlockedCollapsible(requestType, requestURL, specificity);
|
||||||
// console.debug('onBeforeRequestHandler()> ALLOW "%s": %o', details.url, details);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Blocked
|
|
||||||
// console.debug('onBeforeRequestHandler()> BLOCK "%s": %o', details.url, details);
|
|
||||||
|
|
||||||
return { 'cancel': true };
|
return { 'cancel': true };
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
|
@ -33,17 +33,17 @@ ul > li.separator {
|
||||||
|
|
||||||
<h2 data-i18n="settingsMatrixConvenienceHeader"></h2>
|
<h2 data-i18n="settingsMatrixConvenienceHeader"></h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li><input id="iconBadgeEnabled" type="checkbox" data-setting-bool>
|
||||||
<input id="iconBadgeEnabled" type="checkbox" data-setting-bool="iconBadgeEnabled">
|
|
||||||
<label data-i18n="settingsIconBadgeEnabled" for="iconBadgeEnabled"></label>
|
<label data-i18n="settingsIconBadgeEnabled" for="iconBadgeEnabled"></label>
|
||||||
<li>
|
<li><input id="collapseBlocked" type="checkbox" data-setting-bool>
|
||||||
<input id="collapseBlocked" type="checkbox" data-setting-bool="collapseBlocked">
|
|
||||||
<label data-i18n="settingsCollapseBlocked" for="collapseBlocked"></label>
|
<label data-i18n="settingsCollapseBlocked" for="collapseBlocked"></label>
|
||||||
<li>
|
<ul>
|
||||||
<input id="noscriptTagsSpoofed" type="checkbox" data-matrix-switch="noscript-spoof">
|
<li><input id="collapseBlacklisted" type="checkbox" data-setting-bool>
|
||||||
|
<label data-i18n="settingsCollapseBlacklisted" for="collapseBlacklisted"></label>
|
||||||
|
</ul>
|
||||||
|
<li><input id="noscriptTagsSpoofed" type="checkbox" data-matrix-switch="noscript-spoof">
|
||||||
<label data-i18n="settingsNoscriptTagsSpoofed" for="noscriptTagsSpoofed"></label>
|
<label data-i18n="settingsNoscriptTagsSpoofed" for="noscriptTagsSpoofed"></label>
|
||||||
<li>
|
<li><input id="cloudStorageEnabled" type="checkbox" data-setting-bool>
|
||||||
<input id="cloudStorageEnabled" type="checkbox" data-setting-bool="cloudStorageEnabled">
|
|
||||||
<label data-i18n="settingsCloudStorageEnabled" for="cloudStorageEnabled"></label>
|
<label data-i18n="settingsCloudStorageEnabled" for="cloudStorageEnabled"></label>
|
||||||
</ul>
|
</ul>
|
||||||
<h2 data-i18n="settingsMatrixDisplayHeader"></h2>
|
<h2 data-i18n="settingsMatrixDisplayHeader"></h2>
|
||||||
|
@ -56,18 +56,18 @@ ul > li.separator {
|
||||||
<label data-i18n="settingsDefaultScopeLevel"></label> <select id="popupScopeLevel"><option data-i18n="settingsDefaultScopeLevel2" value="site"><option data-i18n="settingsDefaultScopeLevel1" value="domain"><option data-i18n="settingsDefaultScopeLevel0" value="*"></select>
|
<label data-i18n="settingsDefaultScopeLevel"></label> <select id="popupScopeLevel"><option data-i18n="settingsDefaultScopeLevel2" value="site"><option data-i18n="settingsDefaultScopeLevel1" value="domain"><option data-i18n="settingsDefaultScopeLevel0" value="*"></select>
|
||||||
<li class="separator">
|
<li class="separator">
|
||||||
<li>
|
<li>
|
||||||
<input id="colorBlindFriendly" type="checkbox" data-setting-bool="colorBlindFriendly">
|
<input id="colorBlindFriendly" type="checkbox" data-setting-bool>
|
||||||
<label data-i18n="settingsMatrixDisplayColorBlind" for="colorBlindFriendly"></label>
|
<label data-i18n="settingsMatrixDisplayColorBlind" for="colorBlindFriendly"></label>
|
||||||
</ul>
|
</ul>
|
||||||
<h2 data-i18n="privacyPageName"></h2>
|
<h2 data-i18n="privacyPageName"></h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<input id="delete-blacklisted-cookies" type="checkbox" data-setting-bool="deleteCookies"><label data-i18n="privacyDeleteBlockedCookiesPrompt" for="delete-blacklisted-cookies"></label>
|
<input id="deleteCookies" type="checkbox" data-setting-bool><label data-i18n="privacyDeleteBlockedCookiesPrompt" for="deleteCookies"></label>
|
||||||
<span class="whatisthis"></span>
|
<span class="whatisthis"></span>
|
||||||
<div class="whatisthis-expandable para" data-i18n="privacyDeleteBlockedCookiesHelp"></div>
|
<div class="whatisthis-expandable para" data-i18n="privacyDeleteBlockedCookiesHelp"></div>
|
||||||
<li>
|
<li>
|
||||||
<input id="delete-unused-session-cookies" type="checkbox" data-setting-bool="deleteUnusedSessionCookies"><label data-i18n="privacyDeleteNonBlockedSessionCookiesPrompt1" for="delete-unused-session-cookies"></label>
|
<input id="deleteUnusedSessionCookies" type="checkbox" data-setting-bool><label data-i18n="privacyDeleteNonBlockedSessionCookiesPrompt1" for="deleteUnusedSessionCookies"></label>
|
||||||
<input id="delete-unused-session-cookies-after" type="text" value="60" size="3"><span data-i18n="privacyDeleteNonBlockedSessionCookiesPrompt2"></span>
|
<input id="deleteUnusedSessionCookiesAfter" type="text" value="60" size="3"><span data-i18n="privacyDeleteNonBlockedSessionCookiesPrompt2"></span>
|
||||||
<span class="whatisthis"></span>
|
<span class="whatisthis"></span>
|
||||||
<div class="whatisthis-expandable para" data-i18n="privacyDeleteNonBlockedSessionCookiesHelp"></div>
|
<div class="whatisthis-expandable para" data-i18n="privacyDeleteNonBlockedSessionCookiesHelp"></div>
|
||||||
<!--
|
<!--
|
||||||
|
@ -89,22 +89,22 @@ ul > li.separator {
|
||||||
of these cookies so that they cannot be used to track you.
|
of these cookies so that they cannot be used to track you.
|
||||||
-->
|
-->
|
||||||
<li>
|
<li>
|
||||||
<input id="delete-blacklisted-localstorage" type="checkbox" data-setting-bool="deleteLocalStorage"><label data-i18n="privacyDeleteBlockedLocalStoragePrompt" for="delete-blacklisted-localstorage"></label>
|
<input id="deleteLocalStorage" type="checkbox" data-setting-bool><label data-i18n="privacyDeleteBlockedLocalStoragePrompt" for="deleteLocalStorage"></label>
|
||||||
<li>
|
<li>
|
||||||
<input id="clear-browser-cache" type="checkbox" data-setting-bool="clearBrowserCache"><label data-i18n="privacyClearCachePrompt1" for="clear-browser-cache"></label>
|
<input id="clearBrowserCache" type="checkbox" data-setting-bool><label data-i18n="privacyClearCachePrompt1" for="clearBrowserCache"></label>
|
||||||
<input id="clear-browser-cache-after" type="text" value="60" size="3"> <label data-i18n="privacyClearCachePrompt2" for="clear-browser-cache-after"></label>
|
<input id="clearBrowserCacheAfter" type="text" value="60" size="3"> <label data-i18n="privacyClearCachePrompt2" for="clearBrowserCacheAfter"></label>
|
||||||
<span class="whatisthis"></span>
|
<span class="whatisthis"></span>
|
||||||
<div class="whatisthis-expandable para" data-i18n="privacyClearCacheHelp"></div>
|
<div class="whatisthis-expandable para" data-i18n="privacyClearCacheHelp"></div>
|
||||||
<li>
|
<li>
|
||||||
<input id="process-referer" type="checkbox" data-matrix-switch="referrer-spoof"><label data-i18n="privacyProcessRefererPrompt" for="process-referer"></label>
|
<input id="processReferer" type="checkbox" data-matrix-switch="referrer-spoof"><label data-i18n="privacyProcessRefererPrompt" for="processReferer"></label>
|
||||||
<span class="whatisthis"></span>
|
<span class="whatisthis"></span>
|
||||||
<div class="whatisthis-expandable para" data-i18n="privacyProcessRefererHelp"></div>
|
<div class="whatisthis-expandable para" data-i18n="privacyProcessRefererHelp"></div>
|
||||||
<li>
|
<li>
|
||||||
<input id="no-mixed-content" type="checkbox" data-matrix-switch="https-strict"><label data-i18n="privacyNoMixedContentPrompt" for="no-mixed-content"></label>
|
<input id="noMixedContent" type="checkbox" data-matrix-switch="https-strict"><label data-i18n="privacyNoMixedContentPrompt" for="noMixedContent"></label>
|
||||||
<span class="whatisthis"></span>
|
<span class="whatisthis"></span>
|
||||||
<div class="whatisthis-expandable para" data-i18n="privacyNoMixedContentHelp"></div>
|
<div class="whatisthis-expandable para" data-i18n="privacyNoMixedContentHelp"></div>
|
||||||
<li>
|
<li>
|
||||||
<input id="process-hyperlink-auditing" type="checkbox" data-setting-bool="processHyperlinkAuditing"><label data-i18n="privacyProcessHyperlinkAuditingPrompt" for="process-hyperlink-auditing"></label>
|
<input id="processHyperlinkAuditing" type="checkbox" data-setting-bool><label data-i18n="privacyProcessHyperlinkAuditingPrompt" for="processHyperlinkAuditing"></label>
|
||||||
<span class="whatisthis"></span>
|
<span class="whatisthis"></span>
|
||||||
<div class="whatisthis-expandable para" data-i18n="privacyProcessHyperlinkAuditingHelp"></div>
|
<div class="whatisthis-expandable para" data-i18n="privacyProcessHyperlinkAuditingHelp"></div>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
Loading…
Reference in a new issue