mirror of
https://github.com/gorhill/uBlock.git
synced 2024-09-14 23:12:28 +02:00
more refactoring of content script: better modularization of various components
This commit is contained in:
parent
01da277886
commit
6fd0bb4291
@ -67,6 +67,23 @@ if ( vAPI.sessionId ) {
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
var referenceCounter = 0;
|
||||||
|
|
||||||
|
vAPI.lock = function() {
|
||||||
|
referenceCounter += 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
vAPI.unlock = function() {
|
||||||
|
referenceCounter -= 1;
|
||||||
|
if ( referenceCounter === 0 ) {
|
||||||
|
// Eventually there will be code here to flush the javascript code
|
||||||
|
// from this file out of memory when it ends up unused.
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
vAPI.executionCost = {
|
vAPI.executionCost = {
|
||||||
start: function(){},
|
start: function(){},
|
||||||
stop: function(){}
|
stop: function(){}
|
||||||
|
@ -56,6 +56,18 @@ var vAPI = self.vAPI = self.vAPI || {};
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
var referenceCounter = 0;
|
||||||
|
|
||||||
|
vAPI.lock = function() {
|
||||||
|
referenceCounter += 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
vAPI.unlock = function() {
|
||||||
|
referenceCounter -= 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
vAPI.executionCost = {
|
vAPI.executionCost = {
|
||||||
start: function(){},
|
start: function(){},
|
||||||
stop: function(){}
|
stop: function(){}
|
||||||
|
@ -21,9 +21,50 @@
|
|||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
/******************************************************************************/
|
/*******************************************************************************
|
||||||
|
|
||||||
// Injected into content pages
|
+--> [[domSurveyor] --> domFilterer]
|
||||||
|
domWatcher--|
|
||||||
|
+--> [domCollapser]
|
||||||
|
|
||||||
|
domWatcher:
|
||||||
|
Watches for changes in the DOM, and notify the other components about these
|
||||||
|
changes.
|
||||||
|
|
||||||
|
domCollapser:
|
||||||
|
Enforces the collapsing of DOM elements for which a corresponding
|
||||||
|
resource was blocked through network filtering.
|
||||||
|
|
||||||
|
domFilterer:
|
||||||
|
Enforces the filtering of DOM elements, by feeding it cosmetic filters.
|
||||||
|
|
||||||
|
domSurveyor:
|
||||||
|
Surveys the DOM to find new cosmetic filters to apply to the current page.
|
||||||
|
|
||||||
|
If page is whitelisted:
|
||||||
|
- domWatcher: off
|
||||||
|
- domCollapser: off
|
||||||
|
- domFilterer: off
|
||||||
|
- domSurveyor: off
|
||||||
|
I verified that the code in this file is completely flushed out of memory
|
||||||
|
when a page is whitelisted.
|
||||||
|
|
||||||
|
If cosmetic filtering is disabled:
|
||||||
|
- domWatcher: on
|
||||||
|
- domCollapser: on
|
||||||
|
- domFilterer: off
|
||||||
|
- domSurveyor: off
|
||||||
|
|
||||||
|
If generic cosmetic filtering is disabled:
|
||||||
|
- domWatcher: on
|
||||||
|
- domCollapser: on
|
||||||
|
- domFilterer: on
|
||||||
|
- domSurveyor: off
|
||||||
|
|
||||||
|
Additionally, the domSurveyor can turn itself off once it decides that
|
||||||
|
it has become pointless (repeatedly not finding new cosmetic filters).
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
@ -32,14 +73,13 @@
|
|||||||
// Abort execution by throwing if an unexpected condition arise.
|
// Abort execution by throwing if an unexpected condition arise.
|
||||||
// - https://github.com/chrisaljoudi/uBlock/issues/456
|
// - https://github.com/chrisaljoudi/uBlock/issues/456
|
||||||
|
|
||||||
if ( typeof vAPI !== 'object' || vAPI.contentscriptInjected ) {
|
if ( typeof vAPI !== 'object' ) {
|
||||||
throw new Error('uBlock Origin: aborting content scripts for ' + window.location);
|
throw new Error('uBlock Origin: aborting content scripts for ' + window.location);
|
||||||
}
|
}
|
||||||
|
vAPI.lock();
|
||||||
|
|
||||||
vAPI.executionCost.start();
|
vAPI.executionCost.start();
|
||||||
|
|
||||||
vAPI.contentscriptInjected = true;
|
|
||||||
|
|
||||||
vAPI.matchesProp = (function() {
|
vAPI.matchesProp = (function() {
|
||||||
var docElem = document.documentElement;
|
var docElem = document.documentElement;
|
||||||
if ( typeof docElem.matches !== 'function' ) {
|
if ( typeof docElem.matches !== 'function' ) {
|
||||||
@ -119,16 +159,16 @@ var jobQueue = [
|
|||||||
|
|
||||||
var reParserEx = /:(?:matches-css|has|style|xpath)\(.+?\)$/;
|
var reParserEx = /:(?:matches-css|has|style|xpath)\(.+?\)$/;
|
||||||
|
|
||||||
var allExceptions = Object.create(null);
|
var allExceptions = Object.create(null),
|
||||||
var allSelectors = Object.create(null);
|
allSelectors = Object.create(null),
|
||||||
var stagedNodes = [];
|
stagedNodes = [],
|
||||||
var matchesProp = vAPI.matchesProp;
|
matchesProp = vAPI.matchesProp;
|
||||||
|
|
||||||
// Complex selectors, due to their nature may need to be "de-committed". A
|
// Complex selectors, due to their nature may need to be "de-committed". A
|
||||||
// Set() is used to implement this functionality.
|
// Set() is used to implement this functionality.
|
||||||
|
|
||||||
var complexSelectorsOldResultSet;
|
var complexSelectorsOldResultSet,
|
||||||
var complexSelectorsCurrentResultSet = new Set();
|
complexSelectorsCurrentResultSet = new Set();
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
@ -245,6 +285,7 @@ var domFilterer = {
|
|||||||
enabled: true,
|
enabled: true,
|
||||||
hiddenId: vAPI.randomToken(),
|
hiddenId: vAPI.randomToken(),
|
||||||
hiddenNodeCount: 0,
|
hiddenNodeCount: 0,
|
||||||
|
loggerEnabled: undefined,
|
||||||
styleTags: [],
|
styleTags: [],
|
||||||
|
|
||||||
jobQueue: jobQueue,
|
jobQueue: jobQueue,
|
||||||
@ -352,6 +393,10 @@ var domFilterer = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
commit_: function() {
|
commit_: function() {
|
||||||
|
if ( stagedNodes.length === 0 ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var beforeHiddenNodeCount = this.hiddenNodeCount,
|
var beforeHiddenNodeCount = this.hiddenNodeCount,
|
||||||
styleText = '', i, n;
|
styleText = '', i, n;
|
||||||
|
|
||||||
@ -423,7 +468,11 @@ var domFilterer = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If DOM nodes have been affected, lazily notify core process.
|
// If DOM nodes have been affected, lazily notify core process.
|
||||||
if ( commitHit && cosmeticFiltersActivatedTimer === null ) {
|
if (
|
||||||
|
this.loggerEnabled !== false &&
|
||||||
|
commitHit &&
|
||||||
|
cosmeticFiltersActivatedTimer === null
|
||||||
|
) {
|
||||||
cosmeticFiltersActivatedTimer = vAPI.setTimeout(
|
cosmeticFiltersActivatedTimer = vAPI.setTimeout(
|
||||||
cosmeticFiltersActivated,
|
cosmeticFiltersActivated,
|
||||||
503
|
503
|
||||||
@ -512,6 +561,10 @@ var domFilterer = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
toggleLogging: function(state) {
|
||||||
|
this.loggerEnabled = state;
|
||||||
|
},
|
||||||
|
|
||||||
toggleOff: function() {
|
toggleOff: function() {
|
||||||
this.enabled = false;
|
this.enabled = false;
|
||||||
},
|
},
|
||||||
@ -583,49 +636,54 @@ return domFilterer;
|
|||||||
|
|
||||||
(function domIsLoading() {
|
(function domIsLoading() {
|
||||||
|
|
||||||
// Domain-based ABP cosmetic filters.
|
var responseHandler = function(response) {
|
||||||
// These can be inserted before the DOM is loaded.
|
// cosmetic filtering engine aka 'cfe'
|
||||||
|
var cfeDetails = response && response.specificCosmeticFilters;
|
||||||
var cosmeticFilters = function(details) {
|
if ( !cfeDetails || !cfeDetails.ready ) {
|
||||||
var domFilterer = vAPI.domFilterer;
|
vAPI.domWatcher = vAPI.domCollapser = vAPI.domFilterer =
|
||||||
domFilterer.addExceptions(details.cosmeticDonthide);
|
vAPI.domSurveyor = vAPI.domIsLoaded = null;
|
||||||
// https://github.com/chrisaljoudi/uBlock/issues/143
|
vAPI.unlock();
|
||||||
domFilterer.addSelectors(details.cosmeticHide);
|
|
||||||
domFilterer.commit(undefined, true);
|
|
||||||
};
|
|
||||||
|
|
||||||
var netFilters = function(details) {
|
|
||||||
var parent = document.head || document.documentElement;
|
|
||||||
if ( !parent ) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var styleTag = document.createElement('style');
|
|
||||||
styleTag.setAttribute('type', 'text/css');
|
vAPI.executionCost.start();
|
||||||
var text = details.netHide.join(',\n');
|
|
||||||
var css = details.netCollapse ?
|
if ( response.noCosmeticFiltering ) {
|
||||||
|
vAPI.domFilterer = null;
|
||||||
|
vAPI.domSurveyor = null;
|
||||||
|
} else {
|
||||||
|
var domFilterer = vAPI.domFilterer;
|
||||||
|
domFilterer.toggleLogging(response.loggerEnabled);
|
||||||
|
if ( response.noGenericCosmeticFiltering || cfeDetails.noDOMSurveying ) {
|
||||||
|
vAPI.domSurveyor = null;
|
||||||
|
}
|
||||||
|
if ( cfeDetails.cosmeticHide.length !== 0 || cfeDetails.cosmeticDonthide.length !== 0 ) {
|
||||||
|
domFilterer.addExceptions(cfeDetails.cosmeticDonthide);
|
||||||
|
domFilterer.addSelectors(cfeDetails.cosmeticHide);
|
||||||
|
domFilterer.commit(undefined, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var parent = document.head || document.documentElement;
|
||||||
|
if ( parent ) {
|
||||||
|
var elem, text;
|
||||||
|
if ( cfeDetails.netHide.length !== 0 ) {
|
||||||
|
elem = document.createElement('style');
|
||||||
|
elem.setAttribute('type', 'text/css');
|
||||||
|
text = cfeDetails.netHide.join(',\n');
|
||||||
|
text += response.collapseBlocked ?
|
||||||
'\n{display:none !important;}' :
|
'\n{display:none !important;}' :
|
||||||
'\n{visibility:hidden !important;}';
|
'\n{visibility:hidden !important;}';
|
||||||
styleTag.appendChild(document.createTextNode(text + css));
|
elem.appendChild(document.createTextNode(text));
|
||||||
parent.appendChild(styleTag);
|
parent.appendChild(elem);
|
||||||
};
|
|
||||||
|
|
||||||
// Create script tags and assign data URIs looked up from our library of
|
|
||||||
// redirection resources: Sometimes it is useful to use these resources as
|
|
||||||
// standalone scriptlets. These scriptlets are injected from within the
|
|
||||||
// content scripts because what must be injected, if anything, depends on
|
|
||||||
// the currently active filters, as selected by the user.
|
|
||||||
// Library of redirection resources is located at:
|
|
||||||
// https://github.com/gorhill/uBlock/blob/master/assets/ublock/resources.txt
|
|
||||||
|
|
||||||
var injectScripts = function(scripts) {
|
|
||||||
var parent = document.head || document.documentElement;
|
|
||||||
if ( !parent ) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
var scriptTag = document.createElement('script');
|
// Library of resources is located at:
|
||||||
|
// https://github.com/gorhill/uBlock/blob/master/assets/ublock/resources.txt
|
||||||
|
if ( cfeDetails.scripts ) {
|
||||||
|
elem = document.createElement('script');
|
||||||
// Have the injected script tag remove itself when execution completes:
|
// Have the injected script tag remove itself when execution completes:
|
||||||
// to keep DOM as clean as possible.
|
// to keep DOM as clean as possible.
|
||||||
scripts +=
|
text = cfeDetails.scripts +
|
||||||
"\n" +
|
"\n" +
|
||||||
"(function() {\n" +
|
"(function() {\n" +
|
||||||
" var c = document.currentScript,\n" +
|
" var c = document.currentScript,\n" +
|
||||||
@ -634,38 +692,21 @@ return domFilterer;
|
|||||||
" p.removeChild(c);\n" +
|
" p.removeChild(c);\n" +
|
||||||
" }\n" +
|
" }\n" +
|
||||||
"})();";
|
"})();";
|
||||||
scriptTag.appendChild(document.createTextNode(scripts));
|
elem.appendChild(document.createTextNode(text));
|
||||||
parent.appendChild(scriptTag);
|
parent.appendChild(elem);
|
||||||
vAPI.injectedScripts = scripts;
|
vAPI.injectedScripts = text;
|
||||||
};
|
|
||||||
|
|
||||||
var responseHandler = function(details) {
|
|
||||||
vAPI.executionCost.start();
|
|
||||||
|
|
||||||
if ( details ) {
|
|
||||||
vAPI.skipCosmeticFiltering = details.skipCosmeticFiltering;
|
|
||||||
vAPI.skipCosmeticSurveying = details.skipCosmeticSurveying;
|
|
||||||
if (
|
|
||||||
(details.skipCosmeticFiltering !== true) &&
|
|
||||||
(details.cosmeticHide.length !== 0 || details.cosmeticDonthide.length !== 0)
|
|
||||||
) {
|
|
||||||
cosmeticFilters(details);
|
|
||||||
}
|
}
|
||||||
if ( details.netHide.length !== 0 ) {
|
|
||||||
netFilters(details);
|
|
||||||
}
|
|
||||||
if ( details.scripts ) {
|
|
||||||
injectScripts(details.scripts);
|
|
||||||
}
|
|
||||||
// The port will never be used again at this point, disconnecting
|
|
||||||
// allows the browser to flush this script from memory.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://github.com/chrisaljoudi/uBlock/issues/587
|
// https://github.com/chrisaljoudi/uBlock/issues/587
|
||||||
// If no filters were found, maybe the script was injected before
|
// If no filters were found, maybe the script was injected before
|
||||||
// uBlock's process was fully initialized. When this happens, pages
|
// uBlock's process was fully initialized. When this happens, pages
|
||||||
// won't be cleaned right after browser launch.
|
// won't be cleaned right after browser launch.
|
||||||
vAPI.contentscriptInjected = details && details.ready;
|
if ( document.readyState !== 'loading' ) {
|
||||||
|
window.requestAnimationFrame(vAPI.domIsLoaded);
|
||||||
|
} else {
|
||||||
|
document.addEventListener('DOMContentLoaded', vAPI.domIsLoaded);
|
||||||
|
}
|
||||||
|
|
||||||
vAPI.executionCost.stop('domIsLoading/responseHandler');
|
vAPI.executionCost.stop('domIsLoading/responseHandler');
|
||||||
};
|
};
|
||||||
@ -674,7 +715,7 @@ return domFilterer;
|
|||||||
vAPI.messaging.send(
|
vAPI.messaging.send(
|
||||||
'contentscript',
|
'contentscript',
|
||||||
{
|
{
|
||||||
what: 'retrieveDomainCosmeticSelectors',
|
what: 'retrieveContentScriptParameters',
|
||||||
pageURL: url,
|
pageURL: url,
|
||||||
locationURL: url
|
locationURL: url
|
||||||
},
|
},
|
||||||
@ -687,7 +728,137 @@ return domFilterer;
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
var domCollapser = (function() {
|
vAPI.domWatcher = (function() {
|
||||||
|
|
||||||
|
var domLayoutObserver = null,
|
||||||
|
ignoreTags = { 'head': 1, 'link': 1, 'meta': 1, 'script': 1, 'style': 1 },
|
||||||
|
addedNodeLists = [],
|
||||||
|
addedNodes = [],
|
||||||
|
removedNodes = false,
|
||||||
|
safeObserverHandlerTimer = null,
|
||||||
|
listeners = [];
|
||||||
|
|
||||||
|
var safeObserverHandler = function() {
|
||||||
|
vAPI.executionCost.start();
|
||||||
|
|
||||||
|
safeObserverHandlerTimer = null;
|
||||||
|
var i = addedNodeLists.length,
|
||||||
|
nodeList, iNode, node;
|
||||||
|
while ( i-- ) {
|
||||||
|
nodeList = addedNodeLists[i];
|
||||||
|
iNode = nodeList.length;
|
||||||
|
while ( iNode-- ) {
|
||||||
|
node = nodeList[iNode];
|
||||||
|
if ( node.nodeType !== 1 ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ( ignoreTags[node.localName] === 1 ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
addedNodes.push(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addedNodeLists.length = 0;
|
||||||
|
if ( addedNodes.length !== 0 ) {
|
||||||
|
listeners[0](addedNodes, removedNodes);
|
||||||
|
if ( listeners[1] ) {
|
||||||
|
listeners[1](addedNodes, removedNodes);
|
||||||
|
}
|
||||||
|
addedNodes.length = 0;
|
||||||
|
removedNodes = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
vAPI.executionCost.stop('domWatcher/safeObserverHandler');
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://github.com/chrisaljoudi/uBlock/issues/205
|
||||||
|
// Do not handle added node directly from within mutation observer.
|
||||||
|
var observerHandler = function(mutations) {
|
||||||
|
vAPI.executionCost.start();
|
||||||
|
|
||||||
|
var nodeList, mutation,
|
||||||
|
i = mutations.length;
|
||||||
|
while ( i-- ) {
|
||||||
|
mutation = mutations[i];
|
||||||
|
nodeList = mutation.addedNodes;
|
||||||
|
if ( nodeList.length !== 0 ) {
|
||||||
|
addedNodeLists.push(nodeList);
|
||||||
|
}
|
||||||
|
if ( mutation.removedNodes.length !== 0 ) {
|
||||||
|
removedNodes = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( (addedNodeLists.length !== 0 || removedNodes) && safeObserverHandlerTimer === null ) {
|
||||||
|
safeObserverHandlerTimer = window.requestAnimationFrame(safeObserverHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
vAPI.executionCost.stop('domWatcher/observerHandler');
|
||||||
|
};
|
||||||
|
|
||||||
|
var addListener = function(listener) {
|
||||||
|
if ( listeners.indexOf(listener) !== -1 ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
listeners.push(listener);
|
||||||
|
if ( domLayoutObserver !== null ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
domLayoutObserver = new MutationObserver(observerHandler);
|
||||||
|
domLayoutObserver.observe(document.documentElement, {
|
||||||
|
//attributeFilter: [ 'class', 'id' ],
|
||||||
|
//attributes: true,
|
||||||
|
childList: true,
|
||||||
|
subtree: true
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var removeListener = function(listener) {
|
||||||
|
var pos = listeners.indexOf(listener);
|
||||||
|
if ( pos === -1 ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
listeners.splice(pos, 1);
|
||||||
|
if ( listeners.length !== 0 || domLayoutObserver === null ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
domLayoutObserver.disconnect();
|
||||||
|
domLayoutObserver = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
var stop = function() {
|
||||||
|
if ( domLayoutObserver !== null ) {
|
||||||
|
domLayoutObserver.disconnect();
|
||||||
|
domLayoutObserver = null;
|
||||||
|
}
|
||||||
|
if ( safeObserverHandlerTimer !== null ) {
|
||||||
|
window.cancelAnimationFrame(safeObserverHandlerTimer);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var start = function() {
|
||||||
|
// Observe changes in the DOM only if...
|
||||||
|
// - there is a document.body
|
||||||
|
// - there is at least one `script` tag
|
||||||
|
if ( document.body === null || document.querySelector('script') === null ) {
|
||||||
|
vAPI.domWatcher = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// https://github.com/gorhill/uMatrix/issues/144
|
||||||
|
vAPI.shutdown.add(stop);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
addListener: addListener,
|
||||||
|
removeListener: removeListener,
|
||||||
|
start: start
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
vAPI.domCollapser = (function() {
|
||||||
var timer = null;
|
var timer = null;
|
||||||
var pendingRequests = Object.create(null);
|
var pendingRequests = Object.create(null);
|
||||||
var roundtripRequests = [];
|
var roundtripRequests = [];
|
||||||
@ -913,18 +1084,64 @@ var domCollapser = (function() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var iframesFromNode = function(node) {
|
var domChangedHandler = function(nodes) {
|
||||||
|
var node;
|
||||||
|
for ( var i = 0, ni = nodes.length; i < ni; i++ ) {
|
||||||
|
node = nodes[i];
|
||||||
if ( node.localName === 'iframe' ) {
|
if ( node.localName === 'iframe' ) {
|
||||||
addIFrame(node);
|
addIFrame(node);
|
||||||
process();
|
|
||||||
}
|
}
|
||||||
if ( node.children.length !== 0 ) {
|
if ( node.children.length !== 0 ) {
|
||||||
var iframes = node.getElementsByTagName('iframe');
|
var iframes = node.getElementsByTagName('iframe');
|
||||||
if ( iframes.length !== 0 ) {
|
if ( iframes.length !== 0 ) {
|
||||||
addIFrames(iframes);
|
addIFrames(iframes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
process();
|
process();
|
||||||
|
};
|
||||||
|
|
||||||
|
var onResourceFailed = function(ev) {
|
||||||
|
vAPI.executionCost.start();
|
||||||
|
vAPI.domCollapser.add(ev.target);
|
||||||
|
vAPI.domCollapser.process();
|
||||||
|
vAPI.executionCost.stop('domIsLoaded/onResourceFailed');
|
||||||
|
};
|
||||||
|
|
||||||
|
var start = function() {
|
||||||
|
// Listener to collapse blocked resources.
|
||||||
|
// - Future requests not blocked yet
|
||||||
|
// - Elements dynamically added to the page
|
||||||
|
// - Elements which resource URL changes
|
||||||
|
|
||||||
|
// https://github.com/chrisaljoudi/uBlock/issues/7
|
||||||
|
// Preferring getElementsByTagName over querySelectorAll:
|
||||||
|
// http://jsperf.com/queryselectorall-vs-getelementsbytagname/145
|
||||||
|
var elems = document.images || document.getElementsByTagName('img'),
|
||||||
|
i = elems.length, elem;
|
||||||
|
while ( i-- ) {
|
||||||
|
elem = elems[i];
|
||||||
|
if ( elem.complete ) {
|
||||||
|
add(elem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
addMany(document.embeds || document.getElementsByTagName('embed'));
|
||||||
|
addMany(document.getElementsByTagName('object'));
|
||||||
|
addIFrames(document.getElementsByTagName('iframe'));
|
||||||
|
process(0);
|
||||||
|
|
||||||
|
document.addEventListener('error', onResourceFailed, true);
|
||||||
|
if ( vAPI.domWatcher ) {
|
||||||
|
vAPI.domWatcher.addListener(domChangedHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/gorhill/uMatrix/issues/144
|
||||||
|
vAPI.shutdown.add(function() {
|
||||||
|
document.removeEventListener('error', onResourceFailed, true);
|
||||||
|
if ( vAPI.domWatcher ) {
|
||||||
|
vAPI.domWatcher.removeListener(domChangedHandler);
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -932,8 +1149,8 @@ var domCollapser = (function() {
|
|||||||
addMany: addMany,
|
addMany: addMany,
|
||||||
addIFrame: addIFrame,
|
addIFrame: addIFrame,
|
||||||
addIFrames: addIFrames,
|
addIFrames: addIFrames,
|
||||||
iframesFromNode: iframesFromNode,
|
process: process,
|
||||||
process: process
|
start: start
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
@ -941,62 +1158,20 @@ var domCollapser = (function() {
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
var domIsLoaded = function(ev) {
|
vAPI.domSurveyor = (function() {
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
if ( ev ) {
|
|
||||||
document.removeEventListener('DOMContentLoaded', domIsLoaded);
|
|
||||||
}
|
|
||||||
|
|
||||||
// I've seen this happens on Firefox
|
|
||||||
if ( window.location === null ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://github.com/chrisaljoudi/uBlock/issues/587
|
|
||||||
// Pointless to execute without the start script having done its job.
|
|
||||||
if ( !vAPI.contentscriptInjected ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
vAPI.executionCost.start();
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
|
|
||||||
skip-survey=false: survey-phase-1 => survey-phase-2 => survey-phase-3 => commit
|
|
||||||
skip-survey=true: commit
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Cosmetic filtering.
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
if ( vAPI.skipCosmeticFiltering ) {
|
|
||||||
//console.debug('Abort cosmetic filtering');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://github.com/chrisaljoudi/uBlock/issues/789
|
// https://github.com/chrisaljoudi/uBlock/issues/789
|
||||||
// https://github.com/gorhill/uBlock/issues/873
|
// https://github.com/gorhill/uBlock/issues/873
|
||||||
// Be sure that our style tags used for cosmetic filtering are still
|
// Be sure that our style tags used for cosmetic filtering are still
|
||||||
// applied.
|
// applied.
|
||||||
var domFilterer = vAPI.domFilterer;
|
|
||||||
domFilterer.checkStyleTags(false);
|
|
||||||
domFilterer.commit();
|
|
||||||
|
|
||||||
var contextNodes = [ document.documentElement ],
|
var domFilterer = null,
|
||||||
messaging = vAPI.messaging;
|
messaging = vAPI.messaging,
|
||||||
|
surveyPhase3Nodes = [],
|
||||||
var domSurveyor = (function() {
|
cosmeticSurveyingMissCount = 0,
|
||||||
if ( vAPI.skipCosmeticSurveying === true ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var cosmeticSurveyingMissCount = 0,
|
|
||||||
highGenerics = null,
|
highGenerics = null,
|
||||||
lowGenericSelectors = [],
|
lowGenericSelectors = [],
|
||||||
queriedSelectors = Object.create(null);
|
queriedSelectors = Object.create(null),
|
||||||
|
removedNodesHandlerMissCount = 0;
|
||||||
|
|
||||||
// Handle main process' response.
|
// Handle main process' response.
|
||||||
|
|
||||||
@ -1050,22 +1225,20 @@ skip-survey=false: survey-phase-1 => survey-phase-2 => survey-phase-3 => commit
|
|||||||
// Shutdown surveyor if too many consecutive empty resultsets.
|
// Shutdown surveyor if too many consecutive empty resultsets.
|
||||||
if ( domFilterer.job0._0.length === 0 ) {
|
if ( domFilterer.job0._0.length === 0 ) {
|
||||||
cosmeticSurveyingMissCount += 1;
|
cosmeticSurveyingMissCount += 1;
|
||||||
if ( cosmeticSurveyingMissCount > 255 ) {
|
|
||||||
domSurveyor = undefined;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
cosmeticSurveyingMissCount = 0;
|
cosmeticSurveyingMissCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
domFilterer.commit(contextNodes);
|
domFilterer.commit(surveyPhase3Nodes);
|
||||||
contextNodes = [];
|
surveyPhase3Nodes = [];
|
||||||
|
|
||||||
vAPI.executionCost.stop('domIsLoaded/surveyPhase2');
|
vAPI.executionCost.stop('domIsLoaded/surveyPhase2');
|
||||||
};
|
};
|
||||||
|
|
||||||
// Query main process.
|
// Query main process.
|
||||||
|
|
||||||
var surveyPhase2 = function() {
|
var surveyPhase2 = function(addedNodes) {
|
||||||
|
surveyPhase3Nodes = surveyPhase3Nodes.concat(addedNodes);
|
||||||
if ( lowGenericSelectors.length !== 0 || highGenerics === null ) {
|
if ( lowGenericSelectors.length !== 0 || highGenerics === null ) {
|
||||||
messaging.send(
|
messaging.send(
|
||||||
'contentscript',
|
'contentscript',
|
||||||
@ -1100,7 +1273,7 @@ skip-survey=false: survey-phase-1 => survey-phase-2 => survey-phase-3 => commit
|
|||||||
var attr, attrValue, nodeList, iNode, node;
|
var attr, attrValue, nodeList, iNode, node;
|
||||||
var selector;
|
var selector;
|
||||||
while ( (attr = attrs.pop()) ) {
|
while ( (attr = attrs.pop()) ) {
|
||||||
nodeList = selectNodes('[' + attr + ']');
|
nodeList = selectNodes('[' + attr + ']', surveyPhase3Nodes);
|
||||||
iNode = nodeList.length;
|
iNode = nodeList.length;
|
||||||
while ( iNode-- ) {
|
while ( iNode-- ) {
|
||||||
node = nodeList[iNode];
|
node = nodeList[iNode];
|
||||||
@ -1128,7 +1301,7 @@ skip-survey=false: survey-phase-1 => survey-phase-2 => survey-phase-3 => commit
|
|||||||
// - [href^="http"]
|
// - [href^="http"]
|
||||||
|
|
||||||
var processHighMediumGenerics = function(generics) {
|
var processHighMediumGenerics = function(generics) {
|
||||||
var stagedNodes = contextNodes,
|
var stagedNodes = surveyPhase3Nodes,
|
||||||
i = stagedNodes.length;
|
i = stagedNodes.length;
|
||||||
if ( i === 1 && stagedNodes[0] === document.documentElement ) {
|
if ( i === 1 && stagedNodes[0] === document.documentElement ) {
|
||||||
processHighMediumGenericsForNodes(document.links, generics);
|
processHighMediumGenericsForNodes(document.links, generics);
|
||||||
@ -1191,7 +1364,7 @@ skip-survey=false: survey-phase-1 => survey-phase-2 => survey-phase-3 => commit
|
|||||||
) {
|
) {
|
||||||
tstart = window.performance.now();
|
tstart = window.performance.now();
|
||||||
var matchesProp = vAPI.matchesProp,
|
var matchesProp = vAPI.matchesProp,
|
||||||
nodes = contextNodes,
|
nodes = surveyPhase3Nodes,
|
||||||
i = nodes.length, node;
|
i = nodes.length, node;
|
||||||
while ( i-- ) {
|
while ( i-- ) {
|
||||||
node = nodes[i];
|
node = nodes[i];
|
||||||
@ -1216,7 +1389,6 @@ skip-survey=false: survey-phase-1 => survey-phase-2 => survey-phase-3 => commit
|
|||||||
if ( document.querySelector(highGenerics.hideHighComplex) !== null ) {
|
if ( document.querySelector(highGenerics.hideHighComplex) !== null ) {
|
||||||
highHighComplexGenericsInjected = true;
|
highHighComplexGenericsInjected = true;
|
||||||
domFilterer.addSelectors(highGenerics.hideHighComplex.split(',\n'));
|
domFilterer.addSelectors(highGenerics.hideHighComplex.split(',\n'));
|
||||||
domFilterer.commit();
|
|
||||||
}
|
}
|
||||||
highHighComplexGenericsCost += window.performance.now() - tstart;
|
highHighComplexGenericsCost += window.performance.now() - tstart;
|
||||||
}
|
}
|
||||||
@ -1224,8 +1396,8 @@ skip-survey=false: survey-phase-1 => survey-phase-2 => survey-phase-3 => commit
|
|||||||
|
|
||||||
// Extract and return the staged nodes which (may) match the selectors.
|
// Extract and return the staged nodes which (may) match the selectors.
|
||||||
|
|
||||||
var selectNodes = function(selector) {
|
var selectNodes = function(selector, nodes) {
|
||||||
var stagedNodes = contextNodes,
|
var stagedNodes = nodes,
|
||||||
i = stagedNodes.length;
|
i = stagedNodes.length;
|
||||||
if ( i === 1 && stagedNodes[0] === document.documentElement ) {
|
if ( i === 1 && stagedNodes[0] === document.documentElement ) {
|
||||||
return document.querySelectorAll(selector);
|
return document.querySelectorAll(selector);
|
||||||
@ -1252,8 +1424,8 @@ skip-survey=false: survey-phase-1 => survey-phase-2 => survey-phase-3 => commit
|
|||||||
// http://www.w3.org/TR/2014/REC-html5-20141028/infrastructure.html#space-separated-tokens
|
// http://www.w3.org/TR/2014/REC-html5-20141028/infrastructure.html#space-separated-tokens
|
||||||
// http://jsperf.com/enumerate-classes/6
|
// http://jsperf.com/enumerate-classes/6
|
||||||
|
|
||||||
var surveyPhase1 = function() {
|
var surveyPhase1 = function(addedNodes) {
|
||||||
var nodes = selectNodes('[class],[id]');
|
var nodes = selectNodes('[class],[id]', addedNodes);
|
||||||
var qq = queriedSelectors;
|
var qq = queriedSelectors;
|
||||||
var ll = lowGenericSelectors;
|
var ll = lowGenericSelectors;
|
||||||
var node, v, vv, j;
|
var node, v, vv, j;
|
||||||
@ -1289,209 +1461,80 @@ skip-survey=false: survey-phase-1 => survey-phase-2 => survey-phase-3 => commit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
surveyPhase2();
|
surveyPhase2(addedNodes);
|
||||||
};
|
};
|
||||||
|
|
||||||
return surveyPhase1;
|
var domChangedHandler = function(addedNodes, removedNodes) {
|
||||||
})();
|
if ( cosmeticSurveyingMissCount < 256 ) {
|
||||||
|
surveyPhase1(addedNodes);
|
||||||
// Start cosmetic filtering.
|
|
||||||
|
|
||||||
if ( domSurveyor ) {
|
|
||||||
domSurveyor();
|
|
||||||
}
|
|
||||||
|
|
||||||
//console.debug('%f: uBlock: survey time', timer.now() - tStart);
|
|
||||||
|
|
||||||
// Below this point is the code which takes care to observe changes in
|
|
||||||
// the page and to add if needed relevant CSS rules as a result of the
|
|
||||||
// changes.
|
|
||||||
|
|
||||||
// Observe changes in the DOM only if...
|
|
||||||
// - there is a document.body
|
|
||||||
// - there is at least one `script` tag
|
|
||||||
if ( !document.body || !document.querySelector('script') ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://github.com/chrisaljoudi/uBlock/issues/618
|
|
||||||
// Following is to observe dynamically added iframes:
|
|
||||||
// - On Firefox, the iframes fails to fire a `load` event
|
|
||||||
|
|
||||||
var ignoreTags = {
|
|
||||||
'link': true,
|
|
||||||
'meta': true,
|
|
||||||
'script': true,
|
|
||||||
'style': true
|
|
||||||
};
|
|
||||||
|
|
||||||
// Added node lists will be cumulated here before being processed
|
|
||||||
var addedNodeLists = [],
|
|
||||||
addedNodeListsTimer = null,
|
|
||||||
removedNodeListsTimer = null,
|
|
||||||
removedNodesHandlerMissCount = 0,
|
|
||||||
collapser = domCollapser;
|
|
||||||
|
|
||||||
var addedNodesHandler = function() {
|
|
||||||
vAPI.executionCost.start();
|
|
||||||
|
|
||||||
addedNodeListsTimer = null;
|
|
||||||
var iNodeList = addedNodeLists.length,
|
|
||||||
nodeList, iNode, node;
|
|
||||||
while ( iNodeList-- ) {
|
|
||||||
nodeList = addedNodeLists[iNodeList];
|
|
||||||
iNode = nodeList.length;
|
|
||||||
while ( iNode-- ) {
|
|
||||||
node = nodeList[iNode];
|
|
||||||
if ( node.nodeType !== 1 ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ( ignoreTags.hasOwnProperty(node.localName) ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
contextNodes.push(node);
|
|
||||||
collapser.iframesFromNode(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
addedNodeLists.length = 0;
|
|
||||||
if ( contextNodes.length !== 0 ) {
|
|
||||||
if ( domSurveyor ) {
|
|
||||||
domSurveyor();
|
|
||||||
} else {
|
} else {
|
||||||
domFilterer.commit(contextNodes);
|
domFilterer.commit(addedNodes);
|
||||||
contextNodes = [];
|
|
||||||
if ( domFilterer.commitMissCount > 255 ) {
|
|
||||||
domLayoutObserver.disconnect();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vAPI.executionCost.stop('domIsLoaded/addedNodesHandler');
|
|
||||||
};
|
|
||||||
|
|
||||||
// https://github.com/gorhill/uBlock/issues/873
|
// https://github.com/gorhill/uBlock/issues/873
|
||||||
// This will ensure our style elements will stay in the DOM.
|
// This will ensure our style elements will stay in the DOM.
|
||||||
var removedNodesHandler = function() {
|
if ( removedNodes && removedNodesHandlerMissCount < 16 ) {
|
||||||
if ( domFilterer.checkStyleTags(true) === false ) {
|
if ( domFilterer.checkStyleTags(true) === false ) {
|
||||||
removedNodesHandlerMissCount += 1;
|
removedNodesHandlerMissCount += 1;
|
||||||
}
|
}
|
||||||
if ( removedNodesHandlerMissCount < 16 ) {
|
|
||||||
removedNodeListsTimer = null;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// https://github.com/chrisaljoudi/uBlock/issues/205
|
var start = function() {
|
||||||
// Do not handle added node directly from within mutation observer.
|
domFilterer = vAPI.domFilterer;
|
||||||
// I arbitrarily chose 100 ms for now: I have to compromise between the
|
if ( domFilterer === null ) {
|
||||||
// overhead of processing too few nodes too often and the delay of many
|
return;
|
||||||
// nodes less often.
|
}
|
||||||
var domLayoutChanged = function(mutations) {
|
domFilterer.checkStyleTags(false);
|
||||||
|
domFilterer.commit();
|
||||||
|
domChangedHandler([ document.documentElement ]);
|
||||||
|
if ( vAPI.domWatcher ) {
|
||||||
|
vAPI.domWatcher.addListener(domChangedHandler);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
start: start
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
vAPI.domIsLoaded = function(ev) {
|
||||||
|
if ( ev ) {
|
||||||
|
document.removeEventListener('DOMContentLoaded', vAPI.domIsLoaded);
|
||||||
|
}
|
||||||
|
vAPI.domIsLoaded = null;
|
||||||
|
|
||||||
|
// I've seen this happens on Firefox
|
||||||
|
if ( window.location === null ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
vAPI.executionCost.start();
|
vAPI.executionCost.start();
|
||||||
|
|
||||||
var removedNodeLists = false;
|
if ( vAPI.domWatcher ) {
|
||||||
var iMutation = mutations.length;
|
vAPI.domWatcher.start();
|
||||||
var nodeList, mutation;
|
|
||||||
while ( iMutation-- ) {
|
|
||||||
mutation = mutations[iMutation];
|
|
||||||
nodeList = mutation.addedNodes;
|
|
||||||
if ( nodeList.length !== 0 ) {
|
|
||||||
addedNodeLists.push(nodeList);
|
|
||||||
}
|
|
||||||
if ( mutation.removedNodes.length !== 0 ) {
|
|
||||||
removedNodeLists = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( addedNodeLists.length !== 0 && addedNodeListsTimer === null ) {
|
|
||||||
addedNodeListsTimer = window.requestAnimationFrame(addedNodesHandler);
|
|
||||||
}
|
|
||||||
if ( removedNodeLists && removedNodeListsTimer === null ) {
|
|
||||||
removedNodeListsTimer = window.requestAnimationFrame(removedNodesHandler);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vAPI.executionCost.stop('domIsLoaded/domLayoutChanged');
|
if ( vAPI.domCollapser ) {
|
||||||
};
|
vAPI.domCollapser.start();
|
||||||
|
|
||||||
//console.debug('Starts cosmetic filtering\'s mutations observer');
|
|
||||||
|
|
||||||
// https://github.com/gorhill/httpswitchboard/issues/176
|
|
||||||
var domLayoutObserver = new MutationObserver(domLayoutChanged);
|
|
||||||
domLayoutObserver.observe(document.documentElement, {
|
|
||||||
childList: true,
|
|
||||||
subtree: true
|
|
||||||
});
|
|
||||||
|
|
||||||
// https://github.com/gorhill/uMatrix/issues/144
|
|
||||||
vAPI.shutdown.add(function() {
|
|
||||||
domLayoutObserver.disconnect();
|
|
||||||
if ( addedNodeListsTimer !== null ) {
|
|
||||||
window.cancelAnimationFrame(addedNodeListsTimer);
|
|
||||||
}
|
}
|
||||||
if ( removedNodeListsTimer !== null ) {
|
|
||||||
window.cancelAnimationFrame(removedNodeListsTimer);
|
if ( vAPI.domFilterer && vAPI.domSurveyor ) {
|
||||||
|
vAPI.domSurveyor.start();
|
||||||
}
|
}
|
||||||
});
|
|
||||||
})();
|
|
||||||
|
|
||||||
/******************************************************************************/
|
// To send mouse coordinates to main process, as the chrome API fails
|
||||||
|
// to provide the mouse position to context menu listeners.
|
||||||
|
// https://github.com/chrisaljoudi/uBlock/issues/1143
|
||||||
|
// Also, find a link under the mouse, to try to avoid confusing new tabs
|
||||||
|
// as nuisance popups.
|
||||||
|
// Ref.: https://developer.mozilla.org/en-US/docs/Web/Events/contextmenu
|
||||||
|
|
||||||
// Permanent
|
(function() {
|
||||||
|
if ( window !== window.top || !vAPI.domFilterer ) {
|
||||||
// Listener to collapse blocked resources.
|
|
||||||
// - Future requests not blocked yet
|
|
||||||
// - Elements dynamically added to the page
|
|
||||||
// - Elements which resource URL changes
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
var onResourceFailed = function(ev) {
|
|
||||||
vAPI.executionCost.start();
|
|
||||||
domCollapser.add(ev.target);
|
|
||||||
domCollapser.process();
|
|
||||||
vAPI.executionCost.stop('domIsLoaded/onResourceFailed');
|
|
||||||
};
|
|
||||||
document.addEventListener('error', onResourceFailed, true);
|
|
||||||
|
|
||||||
// https://github.com/gorhill/uMatrix/issues/144
|
|
||||||
vAPI.shutdown.add(function() {
|
|
||||||
document.removeEventListener('error', onResourceFailed, true);
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
// https://github.com/chrisaljoudi/uBlock/issues/7
|
|
||||||
// Executed only once.
|
|
||||||
// Preferring getElementsByTagName over querySelectorAll:
|
|
||||||
// http://jsperf.com/queryselectorall-vs-getelementsbytagname/145
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
var collapser = domCollapser,
|
|
||||||
elems = document.images || document.getElementsByTagName('img'),
|
|
||||||
i = elems.length, elem;
|
|
||||||
while ( i-- ) {
|
|
||||||
elem = elems[i];
|
|
||||||
if ( elem.complete ) {
|
|
||||||
collapser.add(elem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
collapser.addMany(document.embeds || document.getElementsByTagName('embed'));
|
|
||||||
collapser.addMany(document.getElementsByTagName('object'));
|
|
||||||
collapser.addIFrames(document.getElementsByTagName('iframe'));
|
|
||||||
collapser.process(0);
|
|
||||||
})();
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
// To send mouse coordinates to main process, as the chrome API fails
|
|
||||||
// to provide the mouse position to context menu listeners.
|
|
||||||
|
|
||||||
// https://github.com/chrisaljoudi/uBlock/issues/1143
|
|
||||||
// Also, find a link under the mouse, to try to avoid confusing new tabs
|
|
||||||
// as nuisance popups.
|
|
||||||
|
|
||||||
// Ref.: https://developer.mozilla.org/en-US/docs/Web/Events/contextmenu
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
if ( window !== window.top ) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1520,22 +1563,13 @@ skip-survey=false: survey-phase-1 => survey-phase-2 => survey-phase-3 => commit
|
|||||||
vAPI.shutdown.add(function() {
|
vAPI.shutdown.add(function() {
|
||||||
document.removeEventListener('mousedown', onMouseClick, true);
|
document.removeEventListener('mousedown', onMouseClick, true);
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
vAPI.executionCost.stop('domIsLoaded');
|
|
||||||
|
|
||||||
|
vAPI.executionCost.stop('domIsLoaded');
|
||||||
};
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
if ( document.readyState !== 'loading' ) {
|
|
||||||
window.requestAnimationFrame(domIsLoaded);
|
|
||||||
} else {
|
|
||||||
document.addEventListener('DOMContentLoaded', domIsLoaded);
|
|
||||||
}
|
|
||||||
|
|
||||||
vAPI.executionCost.stop('contentscript.js');
|
vAPI.executionCost.stop('contentscript.js');
|
||||||
|
@ -1550,16 +1550,17 @@ FilterContainer.prototype.retrieveGenericSelectors = function(request) {
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
FilterContainer.prototype.retrieveDomainSelectors = function(request) {
|
FilterContainer.prototype.retrieveDomainSelectors = function(request, noCosmeticFiltering) {
|
||||||
if ( !request.locationURL ) {
|
if ( !request.locationURL ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//quickProfiler.start('FilterContainer.retrieve()');
|
//quickProfiler.start('FilterContainer.retrieve()');
|
||||||
|
|
||||||
var hostname = this.µburi.hostnameFromURI(request.locationURL);
|
var hostname = this.µburi.hostnameFromURI(request.locationURL),
|
||||||
var domain = this.µburi.domainFromHostname(hostname) || hostname;
|
domain = this.µburi.domainFromHostname(hostname) || hostname,
|
||||||
var pos = domain.indexOf('.');
|
pos = domain.indexOf('.'),
|
||||||
|
cacheEntry = this.selectorCache[hostname];
|
||||||
|
|
||||||
// https://github.com/chrisaljoudi/uBlock/issues/587
|
// https://github.com/chrisaljoudi/uBlock/issues/587
|
||||||
// r.ready will tell the content script the cosmetic filtering engine is
|
// r.ready will tell the content script the cosmetic filtering engine is
|
||||||
@ -1572,15 +1573,14 @@ FilterContainer.prototype.retrieveDomainSelectors = function(request) {
|
|||||||
ready: this.frozen,
|
ready: this.frozen,
|
||||||
domain: domain,
|
domain: domain,
|
||||||
entity: pos === -1 ? domain : domain.slice(0, pos - domain.length),
|
entity: pos === -1 ? domain : domain.slice(0, pos - domain.length),
|
||||||
skipCosmeticSurveying: false,
|
noDOMSurveying: false,
|
||||||
skipCosmeticFiltering: this.acceptedCount === 0,
|
|
||||||
cosmeticHide: [],
|
cosmeticHide: [],
|
||||||
cosmeticDonthide: this.genericDonthide.slice(),
|
cosmeticDonthide: [],
|
||||||
netHide: [],
|
netHide: [],
|
||||||
netCollapse: µb.userSettings.collapseBlocked,
|
|
||||||
scripts: this.retrieveScriptTags(domain, hostname)
|
scripts: this.retrieveScriptTags(domain, hostname)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if ( !noCosmeticFiltering ) {
|
||||||
var hash, bucket;
|
var hash, bucket;
|
||||||
hash = makeHash(0, domain, this.domainHashMask);
|
hash = makeHash(0, domain, this.domainHashMask);
|
||||||
if ( (bucket = this.hostnameFilters[hash]) ) {
|
if ( (bucket = this.hostnameFilters[hash]) ) {
|
||||||
@ -1596,7 +1596,15 @@ FilterContainer.prototype.retrieveDomainSelectors = function(request) {
|
|||||||
if ( this.entityFilters.hasOwnProperty(r.entity) ) {
|
if ( this.entityFilters.hasOwnProperty(r.entity) ) {
|
||||||
r.cosmeticHide = r.cosmeticHide.concat(this.entityFilters[r.entity]);
|
r.cosmeticHide = r.cosmeticHide.concat(this.entityFilters[r.entity]);
|
||||||
}
|
}
|
||||||
// No entity exceptions as of now
|
|
||||||
|
// cached cosmetic filters.
|
||||||
|
if ( cacheEntry ) {
|
||||||
|
cacheEntry.retrieve('cosmetic', r.cosmeticHide);
|
||||||
|
r.noDOMSurveying = cacheEntry.cosmeticSurveyingMissCount > cosmeticSurveyingMissCountMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exception cosmetic filters.
|
||||||
|
r.cosmeticDonthide = this.genericDonthide.slice();
|
||||||
|
|
||||||
hash = makeHash(1, domain, this.domainHashMask);
|
hash = makeHash(1, domain, this.domainHashMask);
|
||||||
if ( (bucket = this.hostnameFilters[hash]) ) {
|
if ( (bucket = this.hostnameFilters[hash]) ) {
|
||||||
@ -1608,22 +1616,16 @@ FilterContainer.prototype.retrieveDomainSelectors = function(request) {
|
|||||||
if ( (bucket = this.hostnameFilters[this.type1NoDomainHash]) ) {
|
if ( (bucket = this.hostnameFilters[this.type1NoDomainHash]) ) {
|
||||||
bucket.retrieve(hostname, r.cosmeticDonthide);
|
bucket.retrieve(hostname, r.cosmeticDonthide);
|
||||||
}
|
}
|
||||||
|
// No entity exceptions as of now
|
||||||
|
}
|
||||||
|
|
||||||
var cacheEntry = this.selectorCache[hostname];
|
// Collapsible blocked resources.
|
||||||
if ( cacheEntry ) {
|
if ( cacheEntry ) {
|
||||||
cacheEntry.retrieve('cosmetic', r.cosmeticHide);
|
|
||||||
cacheEntry.retrieve('net', r.netHide);
|
cacheEntry.retrieve('net', r.netHide);
|
||||||
r.skipCosmeticSurveying = cacheEntry.cosmeticSurveyingMissCount > cosmeticSurveyingMissCountMax;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//quickProfiler.stop();
|
//quickProfiler.stop();
|
||||||
|
|
||||||
//console.log(
|
|
||||||
// 'µBlock> abp-hide-filters.js: "%s" => %d selectors out',
|
|
||||||
// request.locationURL,
|
|
||||||
// r.cosmeticHide.length + r.cosmeticDonthide.length
|
|
||||||
//);
|
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -518,12 +518,18 @@ var onMessage = function(request, sender, callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch ( request.what ) {
|
switch ( request.what ) {
|
||||||
case 'retrieveDomainCosmeticSelectors':
|
case 'retrieveContentScriptParameters':
|
||||||
if ( pageStore && pageStore.getNetFilteringSwitch() ) {
|
if ( pageStore && pageStore.getNetFilteringSwitch() ) {
|
||||||
response = µb.cosmeticFilteringEngine.retrieveDomainSelectors(request);
|
response = {
|
||||||
if ( response && response.skipCosmeticFiltering !== true ) {
|
loggerEnabled: µb.logger.isEnabled(),
|
||||||
response.skipCosmeticFiltering = !pageStore.getSpecificCosmeticFilteringSwitch();
|
collapseBlocked: µb.userSettings.collapseBlocked,
|
||||||
}
|
noCosmeticFiltering: µb.cosmeticFilteringEngine.acceptedCount === 0 || pageStore.noCosmeticFiltering === true,
|
||||||
|
noGenericCosmeticFiltering: pageStore.noGenericCosmeticFiltering === true
|
||||||
|
};
|
||||||
|
response.specificCosmeticFilters = µb.cosmeticFilteringEngine.retrieveDomainSelectors(
|
||||||
|
request,
|
||||||
|
response.noCosmeticFiltering
|
||||||
|
);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -310,14 +310,28 @@ PageStore.prototype.init = function(tabId) {
|
|||||||
this.largeMediaTimer = null;
|
this.largeMediaTimer = null;
|
||||||
this.netFilteringCache = NetFilteringResultCache.factory();
|
this.netFilteringCache = NetFilteringResultCache.factory();
|
||||||
|
|
||||||
// Support `elemhide` filter option. Called at this point so the required
|
this.noCosmeticFiltering = µb.hnSwitches.evaluateZ('no-cosmetic-filtering', tabContext.rootHostname) === true;
|
||||||
// context is all setup at this point.
|
if ( µb.logger.isEnabled() && this.noCosmeticFiltering ) {
|
||||||
this.skipCosmeticFiltering = µb.staticNetFilteringEngine.matchStringExactType(
|
µb.logger.writeOne(
|
||||||
|
tabId,
|
||||||
|
'cosmetic',
|
||||||
|
µb.hnSwitches.toResultString(),
|
||||||
|
'dom',
|
||||||
|
tabContext.rawURL,
|
||||||
|
this.tabHostname,
|
||||||
|
this.tabHostname
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Support `generichide` filter option.
|
||||||
|
this.noGenericCosmeticFiltering = this.noCosmeticFiltering;
|
||||||
|
if ( this.noGenericCosmeticFiltering !== true ) {
|
||||||
|
this.noGenericCosmeticFiltering = µb.staticNetFilteringEngine.matchStringExactType(
|
||||||
this.createContextFromPage(),
|
this.createContextFromPage(),
|
||||||
tabContext.normalURL,
|
tabContext.normalURL,
|
||||||
'elemhide'
|
'elemhide'
|
||||||
) === false;
|
) === false;
|
||||||
if ( this.skipCosmeticFiltering && µb.logger.isEnabled() ) {
|
if ( µb.logger.isEnabled() && this.noGenericCosmeticFiltering ) {
|
||||||
// https://github.com/gorhill/uBlock/issues/370
|
// https://github.com/gorhill/uBlock/issues/370
|
||||||
// Log using `cosmetic-filtering`, not `elemhide`.
|
// Log using `cosmetic-filtering`, not `elemhide`.
|
||||||
µb.logger.writeOne(
|
µb.logger.writeOne(
|
||||||
@ -330,6 +344,8 @@ PageStore.prototype.init = function(tabId) {
|
|||||||
this.tabHostname
|
this.tabHostname
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -458,16 +474,14 @@ PageStore.prototype.getNetFilteringSwitch = function() {
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
PageStore.prototype.getSpecificCosmeticFilteringSwitch = function() {
|
PageStore.prototype.getSpecificCosmeticFilteringSwitch = function() {
|
||||||
var tabContext = µb.tabContextManager.lookup(this.tabId);
|
return this.noCosmeticFiltering !== true;
|
||||||
return tabContext !== null &&
|
|
||||||
µb.hnSwitches.evaluateZ('no-cosmetic-filtering', tabContext.rootHostname) !== true;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
PageStore.prototype.getGenericCosmeticFilteringSwitch = function() {
|
PageStore.prototype.getGenericCosmeticFilteringSwitch = function() {
|
||||||
return this.skipCosmeticFiltering !== true &&
|
return this.noGenericCosmeticFiltering !== true &&
|
||||||
this.getSpecificCosmeticFilteringSwitch();
|
this.noCosmeticFiltering !== true;
|
||||||
};
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
if ( typeof vAPI !== 'object' || typeof vAPI.domFilterer !== 'object' ) {
|
if ( typeof vAPI !== 'object' || !vAPI.domFilterer ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
if ( typeof vAPI !== 'object' || typeof vAPI.domFilterer !== 'object' ) {
|
if ( typeof vAPI !== 'object' || !vAPI.domFilterer ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
if ( typeof vAPI !== 'object' || typeof vAPI.domFilterer !== 'object' ) {
|
if ( typeof vAPI !== 'object' || !vAPI.domFilterer ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
if ( typeof vAPI !== 'object' || typeof vAPI.domFilterer !== 'object' ) {
|
if ( typeof vAPI !== 'object' || !vAPI.domFilterer ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
if ( typeof vAPI !== 'object' || typeof vAPI.domFilterer !== 'object' ) {
|
if ( typeof vAPI !== 'object' || !vAPI.domFilterer ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user