mirror of https://github.com/gorhill/uBlock.git
refactor content script code + add support for new `:has` & `:xpath` filters
Aside extending cosmetic filtering abilities, I expect this will also take care of some long standing issues (I will have to find them and mark them as "resolved" by this commit, as time allow).
This commit is contained in:
parent
72fdce64f0
commit
6c513629bf
|
@ -27,16 +27,10 @@
|
||||||
"content_scripts": [
|
"content_scripts": [
|
||||||
{
|
{
|
||||||
"matches": ["http://*/*", "https://*/*"],
|
"matches": ["http://*/*", "https://*/*"],
|
||||||
"js": ["js/vapi-client.js", "js/contentscript-start.js"],
|
"js": ["js/vapi-client.js", "js/contentscript.js"],
|
||||||
"run_at": "document_start",
|
"run_at": "document_start",
|
||||||
"all_frames": true
|
"all_frames": true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"matches": ["http://*/*", "https://*/*"],
|
|
||||||
"js": ["js/contentscript-end.js"],
|
|
||||||
"run_at": "document_end",
|
|
||||||
"all_frames": true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"matches": ["http://*/*", "https://*/*"],
|
"matches": ["http://*/*", "https://*/*"],
|
||||||
"js": ["js/scriptlets/subscriber.js"],
|
"js": ["js/scriptlets/subscriber.js"],
|
||||||
|
|
|
@ -1076,16 +1076,6 @@ vAPI.onLoadAllCompleted = function() {
|
||||||
var scriptDone = function() {
|
var scriptDone = function() {
|
||||||
vAPI.lastError();
|
vAPI.lastError();
|
||||||
};
|
};
|
||||||
var scriptEnd = function(tabId) {
|
|
||||||
if ( vAPI.lastError() ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
vAPI.tabs.injectScript(tabId, {
|
|
||||||
file: 'js/contentscript-end.js',
|
|
||||||
allFrames: true,
|
|
||||||
runAt: 'document_idle'
|
|
||||||
}, scriptDone);
|
|
||||||
};
|
|
||||||
var scriptStart = function(tabId) {
|
var scriptStart = function(tabId) {
|
||||||
vAPI.tabs.injectScript(tabId, {
|
vAPI.tabs.injectScript(tabId, {
|
||||||
file: 'js/vapi-client.js',
|
file: 'js/vapi-client.js',
|
||||||
|
@ -1093,10 +1083,10 @@ vAPI.onLoadAllCompleted = function() {
|
||||||
runAt: 'document_idle'
|
runAt: 'document_idle'
|
||||||
}, function(){ });
|
}, function(){ });
|
||||||
vAPI.tabs.injectScript(tabId, {
|
vAPI.tabs.injectScript(tabId, {
|
||||||
file: 'js/contentscript-start.js',
|
file: 'js/contentscript.js',
|
||||||
allFrames: true,
|
allFrames: true,
|
||||||
runAt: 'document_idle'
|
runAt: 'document_idle'
|
||||||
}, function(){ scriptEnd(tabId); });
|
}, scriptDone);
|
||||||
};
|
};
|
||||||
var bindToTabs = function(tabs) {
|
var bindToTabs = function(tabs) {
|
||||||
var µb = µBlock;
|
var µb = µBlock;
|
||||||
|
|
|
@ -21,14 +21,14 @@
|
||||||
|
|
||||||
/* global HTMLDocument, XMLDocument */
|
/* global HTMLDocument, XMLDocument */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
// For non background pages
|
// For non background pages
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
(function(self) {
|
(function(self) {
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
|
||||||
µBlock - a browser extension to block requests.
|
uBlock Origin - a browser extension to block requests.
|
||||||
Copyright (C) 2014 The µBlock authors
|
Copyright (C) 2014-2016 The uBlock Origin authors
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -442,7 +442,7 @@ var contentObserver = {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
lss(this.contentBaseURI + 'vapi-client.js', sandbox);
|
lss(this.contentBaseURI + 'vapi-client.js', sandbox);
|
||||||
lss(this.contentBaseURI + 'contentscript-start.js', sandbox);
|
lss(this.contentBaseURI + 'contentscript.js', sandbox);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
//console.exception(ex.msg, ex.stack);
|
//console.exception(ex.msg, ex.stack);
|
||||||
return;
|
return;
|
||||||
|
@ -451,7 +451,6 @@ var contentObserver = {
|
||||||
let docReady = (e) => {
|
let docReady = (e) => {
|
||||||
let doc = e.target;
|
let doc = e.target;
|
||||||
doc.removeEventListener(e.type, docReady, true);
|
doc.removeEventListener(e.type, docReady, true);
|
||||||
lss(this.contentBaseURI + 'contentscript-end.js', sandbox);
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
doc.querySelector('a[href^="abp:"],a[href^="https://subscribe.adblockplus.org/?"]') ||
|
doc.querySelector('a[href^="abp:"],a[href^="https://subscribe.adblockplus.org/?"]') ||
|
||||||
|
|
|
@ -27,16 +27,10 @@
|
||||||
"content_scripts": [
|
"content_scripts": [
|
||||||
{
|
{
|
||||||
"matches": ["http://*/*", "https://*/*"],
|
"matches": ["http://*/*", "https://*/*"],
|
||||||
"js": ["js/vapi-client.js", "js/contentscript-start.js"],
|
"js": ["js/vapi-client.js", "js/contentscript.js"],
|
||||||
"run_at": "document_start",
|
"run_at": "document_start",
|
||||||
"all_frames": true
|
"all_frames": true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"matches": ["http://*/*", "https://*/*"],
|
|
||||||
"js": ["js/contentscript-end.js"],
|
|
||||||
"run_at": "document_end",
|
|
||||||
"all_frames": true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"matches": ["http://*/*", "https://*/*"],
|
"matches": ["http://*/*", "https://*/*"],
|
||||||
"js": ["js/scriptlets/subscriber.js"],
|
"js": ["js/scriptlets/subscriber.js"],
|
||||||
|
|
|
@ -1,242 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
|
|
||||||
uBlock Origin - a browser extension to block requests.
|
|
||||||
Copyright (C) 2014-2016 Raymond Hill
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see {http://www.gnu.org/licenses/}.
|
|
||||||
|
|
||||||
Home: https://github.com/gorhill/uBlock
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* jshint multistr: true */
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
// Injected into content pages
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
// This can happen
|
|
||||||
if ( typeof vAPI !== 'object' ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://github.com/chrisaljoudi/uBlock/issues/456
|
|
||||||
// Already injected?
|
|
||||||
if ( vAPI.contentscriptStartInjected ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
vAPI.contentscriptStartInjected = true;
|
|
||||||
vAPI.styles = vAPI.styles || [];
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
// Domain-based ABP cosmetic filters.
|
|
||||||
// These can be inserted before the DOM is loaded.
|
|
||||||
|
|
||||||
var cosmeticFilters = function(details) {
|
|
||||||
var donthideCosmeticFilters = {};
|
|
||||||
var hideCosmeticFilters = {};
|
|
||||||
var donthide = details.cosmeticDonthide;
|
|
||||||
var hide = details.cosmeticHide;
|
|
||||||
var i;
|
|
||||||
if ( donthide.length !== 0 ) {
|
|
||||||
i = donthide.length;
|
|
||||||
while ( i-- ) {
|
|
||||||
donthideCosmeticFilters[donthide[i]] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// https://github.com/chrisaljoudi/uBlock/issues/143
|
|
||||||
if ( hide.length !== 0 ) {
|
|
||||||
i = hide.length;
|
|
||||||
var selector;
|
|
||||||
while ( i-- ) {
|
|
||||||
selector = hide[i];
|
|
||||||
if ( donthideCosmeticFilters[selector] ) {
|
|
||||||
hide.splice(i, 1);
|
|
||||||
} else {
|
|
||||||
hideCosmeticFilters[selector] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( hide.length !== 0 ) {
|
|
||||||
// https://github.com/gorhill/uBlock/issues/1015
|
|
||||||
// Boost specificity of our CSS rules.
|
|
||||||
var styleText = ':root ' + hide.join(',\n:root ');
|
|
||||||
var style = document.createElement('style');
|
|
||||||
style.setAttribute('type', 'text/css');
|
|
||||||
// The linefeed before the style block is very important: do not remove!
|
|
||||||
style.appendChild(document.createTextNode(styleText + '\n{display:none !important;}'));
|
|
||||||
//console.debug('µBlock> "%s" cosmetic filters: injecting %d CSS rules:', details.domain, details.hide.length, hideStyleText);
|
|
||||||
var parent = document.head || document.documentElement;
|
|
||||||
if ( parent ) {
|
|
||||||
parent.appendChild(style);
|
|
||||||
vAPI.styles.push(style);
|
|
||||||
}
|
|
||||||
hideElements(styleText);
|
|
||||||
}
|
|
||||||
vAPI.donthideCosmeticFilters = donthideCosmeticFilters;
|
|
||||||
vAPI.hideCosmeticFilters = hideCosmeticFilters;
|
|
||||||
};
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
var netFilters = function(details) {
|
|
||||||
var parent = document.head || document.documentElement;
|
|
||||||
if ( !parent ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var style = document.createElement('style');
|
|
||||||
var text = details.netHide.join(',\n');
|
|
||||||
var css = details.netCollapse ?
|
|
||||||
'\n{display:none !important;}' :
|
|
||||||
'\n{visibility:hidden !important;}';
|
|
||||||
style.appendChild(document.createTextNode(text + css));
|
|
||||||
parent.appendChild(style);
|
|
||||||
//console.debug('document.querySelectorAll("%s") = %o', text, document.querySelectorAll(text));
|
|
||||||
};
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
// 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');
|
|
||||||
scriptTag.appendChild(document.createTextNode(scripts));
|
|
||||||
parent.appendChild(scriptTag);
|
|
||||||
vAPI.injectedScripts = scripts;
|
|
||||||
};
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
var filteringHandler = function(details) {
|
|
||||||
var styleTagCount = vAPI.styles.length;
|
|
||||||
|
|
||||||
if ( details ) {
|
|
||||||
if (
|
|
||||||
(vAPI.skipCosmeticFiltering = 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.
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is just to inform the background process that cosmetic filters were
|
|
||||||
// actually injected.
|
|
||||||
if ( vAPI.styles.length !== styleTagCount ) {
|
|
||||||
vAPI.messaging.send('contentscript', { what: 'cosmeticFiltersActivated' });
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://github.com/chrisaljoudi/uBlock/issues/587
|
|
||||||
// If no filters were found, maybe the script was injected before uBlock's
|
|
||||||
// process was fully initialized. When this happens, pages won't be
|
|
||||||
// cleaned right after browser launch.
|
|
||||||
vAPI.contentscriptStartInjected = details && details.ready;
|
|
||||||
};
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
var hideElements = function(selectors) {
|
|
||||||
if ( document.body === null ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var elems = document.querySelectorAll(selectors);
|
|
||||||
var i = elems.length;
|
|
||||||
if ( i === 0 ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// https://github.com/chrisaljoudi/uBlock/issues/158
|
|
||||||
// Using CSSStyleDeclaration.setProperty is more reliable
|
|
||||||
if ( document.body.shadowRoot === undefined ) {
|
|
||||||
while ( i-- ) {
|
|
||||||
elems[i].style.setProperty('display', 'none', 'important');
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// https://github.com/gorhill/uBlock/issues/435
|
|
||||||
// Using shadow content so that we do not have to modify style
|
|
||||||
// attribute.
|
|
||||||
var sessionId = vAPI.sessionId;
|
|
||||||
var elem, shadow;
|
|
||||||
while ( i-- ) {
|
|
||||||
elem = elems[i];
|
|
||||||
shadow = elem.shadowRoot;
|
|
||||||
// https://www.chromestatus.com/features/4668884095336448
|
|
||||||
// "Multiple shadow roots is being deprecated."
|
|
||||||
if ( shadow !== null ) {
|
|
||||||
if ( shadow.className !== sessionId ) {
|
|
||||||
elem.style.setProperty('display', 'none', 'important');
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// https://github.com/gorhill/uBlock/pull/555
|
|
||||||
// Not all nodes can be shadowed:
|
|
||||||
// https://github.com/w3c/webcomponents/issues/102
|
|
||||||
// https://github.com/gorhill/uBlock/issues/762
|
|
||||||
// Remove display style that might get in the way of the shadow
|
|
||||||
// node doing its magic.
|
|
||||||
try {
|
|
||||||
shadow = elem.createShadowRoot();
|
|
||||||
shadow.className = sessionId;
|
|
||||||
elem.style.removeProperty('display');
|
|
||||||
} catch (ex) {
|
|
||||||
elem.style.setProperty('display', 'none', 'important');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
var url = window.location.href;
|
|
||||||
vAPI.messaging.send(
|
|
||||||
'contentscript',
|
|
||||||
{
|
|
||||||
what: 'retrieveDomainCosmeticSelectors',
|
|
||||||
pageURL: url,
|
|
||||||
locationURL: url
|
|
||||||
},
|
|
||||||
filteringHandler
|
|
||||||
);
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
})();
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,7 +1,7 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
|
||||||
µBlock - a browser extension to block requests.
|
uBlock Origin - a browser extension to block requests.
|
||||||
Copyright (C) 2014 Raymond Hill
|
Copyright (C) 2014-2016 Raymond Hill
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -20,14 +20,14 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* jshint bitwise: false */
|
/* jshint bitwise: false */
|
||||||
/* global punycode, µBlock */
|
/* global punycode */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
µBlock.cosmeticFilteringEngine = (function(){
|
µBlock.cosmeticFilteringEngine = (function(){
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
var µb = µBlock;
|
var µb = µBlock;
|
||||||
|
@ -141,40 +141,6 @@ FilterPlainMore.fromSelfie = function(s) {
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
var FilterBucket = function(a, b) {
|
|
||||||
this.f = null;
|
|
||||||
this.filters = [];
|
|
||||||
if ( a !== undefined ) {
|
|
||||||
this.filters[0] = a;
|
|
||||||
if ( b !== undefined ) {
|
|
||||||
this.filters[1] = b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
FilterBucket.prototype.add = function(a) {
|
|
||||||
this.filters.push(a);
|
|
||||||
};
|
|
||||||
|
|
||||||
FilterBucket.prototype.retrieve = function(s, out) {
|
|
||||||
var i = this.filters.length;
|
|
||||||
while ( i-- ) {
|
|
||||||
this.filters[i].retrieve(s, out);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
FilterBucket.prototype.fid = '[]';
|
|
||||||
|
|
||||||
FilterBucket.prototype.toSelfie = function() {
|
|
||||||
return this.filters.length.toString();
|
|
||||||
};
|
|
||||||
|
|
||||||
FilterBucket.fromSelfie = function() {
|
|
||||||
return new FilterBucket();
|
|
||||||
};
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
// Any selector specific to a hostname
|
// Any selector specific to a hostname
|
||||||
// Examples:
|
// Examples:
|
||||||
// search.snapdo.com###ABottomD
|
// search.snapdo.com###ABottomD
|
||||||
|
@ -235,6 +201,40 @@ FilterEntity.fromSelfie = function(s) {
|
||||||
return new FilterEntity(decode(s.slice(0, pos)), s.slice(pos + 1));
|
return new FilterEntity(decode(s.slice(0, pos)), s.slice(pos + 1));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
var FilterBucket = function(a, b) {
|
||||||
|
this.f = null;
|
||||||
|
this.filters = [];
|
||||||
|
if ( a !== undefined ) {
|
||||||
|
this.filters[0] = a;
|
||||||
|
if ( b !== undefined ) {
|
||||||
|
this.filters[1] = b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
FilterBucket.prototype.add = function(a) {
|
||||||
|
this.filters.push(a);
|
||||||
|
};
|
||||||
|
|
||||||
|
FilterBucket.prototype.retrieve = function(s, out) {
|
||||||
|
var i = this.filters.length;
|
||||||
|
while ( i-- ) {
|
||||||
|
this.filters[i].retrieve(s, out);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
FilterBucket.prototype.fid = '[]';
|
||||||
|
|
||||||
|
FilterBucket.prototype.toSelfie = function() {
|
||||||
|
return this.filters.length.toString();
|
||||||
|
};
|
||||||
|
|
||||||
|
FilterBucket.fromSelfie = function() {
|
||||||
|
return new FilterBucket();
|
||||||
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
@ -245,11 +245,13 @@ var FilterParser = function() {
|
||||||
this.invalid = false;
|
this.invalid = false;
|
||||||
this.cosmetic = true;
|
this.cosmetic = true;
|
||||||
this.reScriptTagFilter = /^script:(contains|inject)\((.+?)\)$/;
|
this.reScriptTagFilter = /^script:(contains|inject)\((.+?)\)$/;
|
||||||
|
this.reNeedHostname = /^(?:.+?:has|:xpath)\(.+?\)$/;
|
||||||
};
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
FilterParser.prototype.reset = function() {
|
FilterParser.prototype.reset = function() {
|
||||||
|
this.raw = '';
|
||||||
this.prefix = this.suffix = this.style = '';
|
this.prefix = this.suffix = this.style = '';
|
||||||
this.unhide = 0;
|
this.unhide = 0;
|
||||||
this.hostnames.length = 0;
|
this.hostnames.length = 0;
|
||||||
|
@ -264,6 +266,8 @@ FilterParser.prototype.parse = function(raw) {
|
||||||
// important!
|
// important!
|
||||||
this.reset();
|
this.reset();
|
||||||
|
|
||||||
|
this.raw = raw;
|
||||||
|
|
||||||
// Find the bounds of the anchor.
|
// Find the bounds of the anchor.
|
||||||
var lpos = raw.indexOf('#');
|
var lpos = raw.indexOf('#');
|
||||||
if ( lpos === -1 ) {
|
if ( lpos === -1 ) {
|
||||||
|
@ -349,6 +353,16 @@ FilterParser.prototype.parse = function(raw) {
|
||||||
this.hostnames = this.prefix.split(/\s*,\s*/);
|
this.hostnames = this.prefix.split(/\s*,\s*/);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For some selectors, it is mandatory to have a hostname or entity.
|
||||||
|
if (
|
||||||
|
this.hostnames.length === 0 &&
|
||||||
|
this.unhide === 0 &&
|
||||||
|
this.reNeedHostname.test(this.suffix)
|
||||||
|
) {
|
||||||
|
this.invalid = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
// Script tag filters: pre-process them so that can be used with minimal
|
// Script tag filters: pre-process them so that can be used with minimal
|
||||||
// overhead in the content script.
|
// overhead in the content script.
|
||||||
// Examples:
|
// Examples:
|
||||||
|
@ -357,10 +371,16 @@ FilterParser.prototype.parse = function(raw) {
|
||||||
// focus.de##script:inject(uabinject-defuser.js)
|
// focus.de##script:inject(uabinject-defuser.js)
|
||||||
|
|
||||||
var matches = this.reScriptTagFilter.exec(this.suffix);
|
var matches = this.reScriptTagFilter.exec(this.suffix);
|
||||||
if ( matches === null ) {
|
if ( matches !== null ) {
|
||||||
return this;
|
return this.parseScriptTagFilter(matches);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
FilterParser.prototype.parseScriptTagFilter = function(matches) {
|
||||||
// Currently supported only as non-generic selector. Also, exception
|
// Currently supported only as non-generic selector. Also, exception
|
||||||
// script tag filter makes no sense, ignore.
|
// script tag filter makes no sense, ignore.
|
||||||
if ( this.hostnames.length === 0 || this.unhide === 1 ) {
|
if ( this.hostnames.length === 0 || this.unhide === 1 ) {
|
||||||
|
@ -378,7 +398,7 @@ FilterParser.prototype.parse = function(raw) {
|
||||||
} else {
|
} else {
|
||||||
token = token.slice(1, -1);
|
token = token.slice(1, -1);
|
||||||
if ( isBadRegex(token) ) {
|
if ( isBadRegex(token) ) {
|
||||||
µb.logger.writeOne('', 'error', 'Cosmetic filtering – bad regular expression: ' + raw + ' (' + isBadRegex.message + ')');
|
µb.logger.writeOne('', 'error', 'Cosmetic filtering – bad regular expression: ' + this.raw + ' (' + isBadRegex.message + ')');
|
||||||
this.invalid = true;
|
this.invalid = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -676,19 +696,33 @@ FilterContainer.prototype.reset = function() {
|
||||||
|
|
||||||
FilterContainer.prototype.isValidSelector = (function() {
|
FilterContainer.prototype.isValidSelector = (function() {
|
||||||
var div = document.createElement('div');
|
var div = document.createElement('div');
|
||||||
|
var matchesProp = (function() {
|
||||||
|
if ( typeof div.matches === 'function' ) {
|
||||||
|
return 'matches';
|
||||||
|
}
|
||||||
|
if ( typeof div.mozMatchesSelector === 'function' ) {
|
||||||
|
return 'mozMatchesSelector';
|
||||||
|
}
|
||||||
|
if ( typeof div.webkitMatchesSelector === 'function' ) {
|
||||||
|
return 'webkitMatchesSelector';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
})();
|
||||||
// Not all browsers support `Element.matches`:
|
// Not all browsers support `Element.matches`:
|
||||||
// http://caniuse.com/#feat=matchesselector
|
// http://caniuse.com/#feat=matchesselector
|
||||||
if ( typeof div.matches !== 'function' ) {
|
if ( matchesProp === '' ) {
|
||||||
return function() {
|
return function() {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var reHasSelector = /^(.+?):has\((.+?)\)$/;
|
||||||
|
var reXpathSelector = /^:xpath\((.+?)\)$/;
|
||||||
|
|
||||||
return function(s) {
|
return function(s) {
|
||||||
try {
|
try {
|
||||||
// https://github.com/gorhill/uBlock/issues/693
|
// https://github.com/gorhill/uBlock/issues/693
|
||||||
div.matches(s + ',\n#foo');
|
div[matchesProp](s + ',\n#foo');
|
||||||
// Discard new ABP's `-abp-properties` directive until it is
|
// Discard new ABP's `-abp-properties` directive until it is
|
||||||
// implemented (if ever).
|
// implemented (if ever).
|
||||||
if ( s.indexOf('[-abp-properties=') === -1 ) {
|
if ( s.indexOf('[-abp-properties=') === -1 ) {
|
||||||
|
@ -697,6 +731,24 @@ FilterContainer.prototype.isValidSelector = (function() {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
}
|
}
|
||||||
// We reach this point very rarely.
|
// We reach this point very rarely.
|
||||||
|
var matches;
|
||||||
|
|
||||||
|
// Future `:has`-based filter? If so, validate both parts of the whole
|
||||||
|
// selector.
|
||||||
|
matches = reHasSelector.exec(s);
|
||||||
|
if ( matches !== null ) {
|
||||||
|
return this.isValidSelector(matches[1]) && this.isValidSelector(matches[2]);
|
||||||
|
}
|
||||||
|
// Custom `:xpath`-based filter?
|
||||||
|
matches = reXpathSelector.exec(s);
|
||||||
|
if ( matches !== null ) {
|
||||||
|
try {
|
||||||
|
return document.createExpression(matches[1], null) instanceof XPathExpression;
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Special `script:` filter?
|
||||||
if ( s.startsWith('script') ) {
|
if ( s.startsWith('script') ) {
|
||||||
if ( s.startsWith('?', 6) || s.startsWith('+', 6) ) {
|
if ( s.startsWith('?', 6) || s.startsWith('+', 6) ) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -924,7 +976,7 @@ FilterContainer.prototype.fromCompiledContent = function(text, lineBeg, skip) {
|
||||||
|
|
||||||
fields = line.split('\v');
|
fields = line.split('\v');
|
||||||
|
|
||||||
// h ir twitter.com .promoted-tweet
|
// h [\t] ir [\t] twitter.com [\t] .promoted-tweet
|
||||||
if ( fields[0] === 'h' ) {
|
if ( fields[0] === 'h' ) {
|
||||||
// Special filter: script tags. Not a real CSS selector.
|
// Special filter: script tags. Not a real CSS selector.
|
||||||
if ( fields[3].startsWith('script') ) {
|
if ( fields[3].startsWith('script') ) {
|
||||||
|
@ -943,8 +995,8 @@ FilterContainer.prototype.fromCompiledContent = function(text, lineBeg, skip) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// lg 105 .largeAd
|
// lg [\t] 105 [\t] .largeAd
|
||||||
// lg+ 2jx .Mpopup + #Mad > #MadZone
|
// lg+ [\t] 2jx [\t] .Mpopup + #Mad > #MadZone
|
||||||
if ( fields[0] === 'lg' || fields[0] === 'lg+' ) {
|
if ( fields[0] === 'lg' || fields[0] === 'lg+' ) {
|
||||||
filter = fields[0] === 'lg' ?
|
filter = fields[0] === 'lg' ?
|
||||||
filterPlain :
|
filterPlain :
|
||||||
|
@ -960,7 +1012,7 @@ FilterContainer.prototype.fromCompiledContent = function(text, lineBeg, skip) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// entity selector
|
// entity [\t] selector
|
||||||
if ( fields[0] === 'e' ) {
|
if ( fields[0] === 'e' ) {
|
||||||
// Special filter: script tags. Not a real CSS selector.
|
// Special filter: script tags. Not a real CSS selector.
|
||||||
if ( fields[2].startsWith('script') ) {
|
if ( fields[2].startsWith('script') ) {
|
||||||
|
@ -1392,8 +1444,6 @@ FilterContainer.prototype.retrieveGenericSelectors = function(request) {
|
||||||
hideHigh: this.highHighGenericHide,
|
hideHigh: this.highHighGenericHide,
|
||||||
hideHighCount: this.highHighGenericHideCount
|
hideHighCount: this.highHighGenericHideCount
|
||||||
};
|
};
|
||||||
// https://github.com/chrisaljoudi/uBlock/issues/497
|
|
||||||
r.donthide = this.genericDonthide;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var hideSelectors = r.hide;
|
var hideSelectors = r.hide;
|
||||||
|
@ -1437,13 +1487,16 @@ FilterContainer.prototype.retrieveDomainSelectors = function(request) {
|
||||||
// r.ready will tell the content script the cosmetic filtering engine is
|
// r.ready will tell the content script the cosmetic filtering engine is
|
||||||
// up and ready.
|
// up and ready.
|
||||||
|
|
||||||
|
// https://github.com/chrisaljoudi/uBlock/issues/497
|
||||||
|
// Generic exception filters are to be applied on all pages.
|
||||||
|
|
||||||
var r = {
|
var r = {
|
||||||
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),
|
||||||
skipCosmeticFiltering: this.acceptedCount === 0,
|
skipCosmeticFiltering: this.acceptedCount === 0,
|
||||||
cosmeticHide: [],
|
cosmeticHide: [],
|
||||||
cosmeticDonthide: [],
|
cosmeticDonthide: this.genericDonthide,
|
||||||
netHide: [],
|
netHide: [],
|
||||||
netCollapse: µb.userSettings.collapseBlocked,
|
netCollapse: µb.userSettings.collapseBlocked,
|
||||||
scripts: this.retrieveScriptTags(domain, hostname)
|
scripts: this.retrieveScriptTags(domain, hostname)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
|
||||||
uBlock Origin - a browser extension to block requests.
|
uBlock Origin - a browser extension to block requests.
|
||||||
Copyright (C) 2015 Raymond Hill
|
Copyright (C) 2015-2016 Raymond Hill
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -19,14 +19,14 @@
|
||||||
Home: https://github.com/gorhill/uBlock
|
Home: https://github.com/gorhill/uBlock
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* global vAPI, uDom */
|
/* global uDom */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
var showdomButton = uDom.nodeFromId('showdom');
|
var showdomButton = uDom.nodeFromId('showdom');
|
||||||
|
@ -257,21 +257,17 @@ var countFromNode = function(li) {
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
var selectorFromNode = function(node, nth) {
|
var selectorFromNode = function(node) {
|
||||||
var selector = '';
|
var selector = '';
|
||||||
var code;
|
var code;
|
||||||
if ( nth === undefined ) {
|
|
||||||
nth = 1;
|
|
||||||
}
|
|
||||||
while ( node !== null ) {
|
while ( node !== null ) {
|
||||||
if ( node.localName === 'li' ) {
|
if ( node.localName === 'li' ) {
|
||||||
code = node.querySelector('code:nth-of-type(' + nth + ')');
|
code = node.querySelector('code');
|
||||||
if ( code !== null ) {
|
if ( code !== null ) {
|
||||||
selector = code.textContent + ' > ' + selector;
|
selector = code.textContent + ' > ' + selector;
|
||||||
if ( selector.indexOf('#') !== -1 ) {
|
if ( selector.indexOf('#') !== -1 ) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
nth = 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
node = node.parentElement;
|
node = node.parentElement;
|
||||||
|
@ -281,6 +277,21 @@ var selectorFromNode = function(node, nth) {
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
var selectorFromFilter = function(node) {
|
||||||
|
while ( node !== null ) {
|
||||||
|
if ( node.localName === 'li' ) {
|
||||||
|
var code = node.querySelector('code:nth-of-type(2)');
|
||||||
|
if ( code !== null ) {
|
||||||
|
return code.textContent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node = node.parentElement;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
var nidFromNode = function(node) {
|
var nidFromNode = function(node) {
|
||||||
var li = node;
|
var li = node;
|
||||||
while ( li !== null ) {
|
while ( li !== null ) {
|
||||||
|
@ -482,10 +493,11 @@ var onClick = function(ev) {
|
||||||
messaging.sendTo(
|
messaging.sendTo(
|
||||||
'loggerUI',
|
'loggerUI',
|
||||||
{
|
{
|
||||||
what: 'toggleNodes',
|
what: 'toggleFilter',
|
||||||
original: false,
|
original: false,
|
||||||
target: target.classList.toggle('off'),
|
target: target.classList.toggle('off'),
|
||||||
selector: selectorFromNode(target, 2),
|
selector: selectorFromNode(target),
|
||||||
|
filter: selectorFromFilter(target),
|
||||||
nid: ''
|
nid: ''
|
||||||
},
|
},
|
||||||
inspectedTabId,
|
inspectedTabId,
|
||||||
|
@ -504,7 +516,7 @@ var onClick = function(ev) {
|
||||||
what: 'toggleNodes',
|
what: 'toggleNodes',
|
||||||
original: true,
|
original: true,
|
||||||
target: target.classList.toggle('off') === false,
|
target: target.classList.toggle('off') === false,
|
||||||
selector: selectorFromNode(target, 1),
|
selector: selectorFromNode(target),
|
||||||
nid: nidFromNode(target)
|
nid: nidFromNode(target)
|
||||||
},
|
},
|
||||||
inspectedTabId,
|
inspectedTabId,
|
||||||
|
|
|
@ -19,42 +19,27 @@
|
||||||
Home: https://github.com/gorhill/uBlock
|
Home: https://github.com/gorhill/uBlock
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
if ( typeof vAPI !== 'object' ) {
|
(function() {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
var loggedSelectors = vAPI.loggedSelectors || {};
|
if ( typeof vAPI !== 'object' || typeof vAPI.domFilterer !== 'object' ) {
|
||||||
|
|
||||||
var injectedSelectors = [];
|
|
||||||
var reProperties = /\s*\{[^}]+\}\s*/;
|
|
||||||
var i;
|
|
||||||
var styles = vAPI.styles || [];
|
|
||||||
|
|
||||||
i = styles.length;
|
|
||||||
while ( i-- ) {
|
|
||||||
injectedSelectors = injectedSelectors.concat(styles[i].textContent.replace(reProperties, '').split(/\s*,\n\s*/));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( injectedSelectors.length === 0 ) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var matchedSelectors = [];
|
var loggedSelectors = vAPI.loggedSelectors || {},
|
||||||
var selector;
|
matchedSelectors = [],
|
||||||
|
selectors, i, selector, entry, nodes, j;
|
||||||
|
|
||||||
i = injectedSelectors.length;
|
// CSS-based selectors.
|
||||||
|
selectors = vAPI.domFilterer.simpleSelectors.concat(vAPI.domFilterer.complexSelectors);
|
||||||
|
i = selectors.length;
|
||||||
while ( i-- ) {
|
while ( i-- ) {
|
||||||
selector = injectedSelectors[i];
|
selector = selectors[i];
|
||||||
if ( loggedSelectors.hasOwnProperty(selector) ) {
|
if ( loggedSelectors.hasOwnProperty(selector) ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -62,16 +47,57 @@ while ( i-- ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
loggedSelectors[selector] = true;
|
loggedSelectors[selector] = true;
|
||||||
// https://github.com/gorhill/uBlock/issues/1015
|
matchedSelectors.push(selector);
|
||||||
// Discard `:root ` prefix.
|
}
|
||||||
matchedSelectors.push(selector.slice(6));
|
|
||||||
|
// `:has`-based selectors.
|
||||||
|
selectors = vAPI.domFilterer.simpleHasSelectors.concat(vAPI.domFilterer.complexHasSelectors);
|
||||||
|
i = selectors.length;
|
||||||
|
while ( i-- ) {
|
||||||
|
entry = selectors[i];
|
||||||
|
selector = entry.a + ':has(' + entry.b + ')';
|
||||||
|
if ( loggedSelectors.hasOwnProperty(selector) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
nodes = document.querySelectorAll(entry.a);
|
||||||
|
j = nodes.length;
|
||||||
|
while ( j-- ) {
|
||||||
|
if ( nodes[j].querySelector(entry.b) !== null ) {
|
||||||
|
loggedSelectors[selector] = true;
|
||||||
|
matchedSelectors.push(selector);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// `:xpath`-based selectors.
|
||||||
|
var xpr = null,
|
||||||
|
xpathexpr;
|
||||||
|
selectors = vAPI.domFilterer.xpathSelectors;
|
||||||
|
i = selectors.length;
|
||||||
|
while ( i-- ) {
|
||||||
|
xpathexpr = selectors[i];
|
||||||
|
selector = ':xpath(' + xpathexpr + ')';
|
||||||
|
if ( loggedSelectors.hasOwnProperty(selector) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
xpr = document.evaluate(
|
||||||
|
'boolean(' + xpathexpr + ')',
|
||||||
|
document,
|
||||||
|
null,
|
||||||
|
XPathResult.BOOLEAN_TYPE,
|
||||||
|
xpr
|
||||||
|
);
|
||||||
|
if ( xpr.booleanValue ) {
|
||||||
|
loggedSelectors[selector] = true;
|
||||||
|
matchedSelectors.push(selector);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vAPI.loggedSelectors = loggedSelectors;
|
vAPI.loggedSelectors = loggedSelectors;
|
||||||
|
|
||||||
/******************************************************************************/
|
if ( matchedSelectors.length ) {
|
||||||
|
vAPI.messaging.send(
|
||||||
vAPI.messaging.send(
|
|
||||||
'scriptlets',
|
'scriptlets',
|
||||||
{
|
{
|
||||||
what: 'logCosmeticFilteringData',
|
what: 'logCosmeticFilteringData',
|
||||||
|
@ -79,10 +105,9 @@ vAPI.messaging.send(
|
||||||
frameHostname: window.location.hostname,
|
frameHostname: window.location.hostname,
|
||||||
matchedSelectors: matchedSelectors
|
matchedSelectors: matchedSelectors
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
|
||||||
uBlock - a browser extension to block requests.
|
uBlock Origin - a browser extension to block requests.
|
||||||
Copyright (C) 2015 Raymond Hill
|
Copyright (C) 2015-2016 Raymond Hill
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -19,61 +19,36 @@
|
||||||
Home: https://github.com/gorhill/uBlock
|
Home: https://github.com/gorhill/uBlock
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
if ( typeof vAPI !== 'object' ) {
|
(function() {
|
||||||
|
if ( typeof vAPI !== 'object' || typeof vAPI.domFilterer !== 'object' ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
var styles = vAPI.domFilterer.styleTags;
|
||||||
|
|
||||||
var styles = vAPI.styles;
|
// Disable all cosmetic filtering-related styles from the DOM
|
||||||
|
var i = styles.length, style;
|
||||||
if ( Array.isArray(styles) === false ) {
|
while ( i-- ) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var sessionId = vAPI.sessionId;
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
// Remove all cosmetic filtering-related styles from the DOM
|
|
||||||
|
|
||||||
var selectors = [];
|
|
||||||
var reProperties = /\s*\{[^}]+\}\s*/;
|
|
||||||
var style, i;
|
|
||||||
|
|
||||||
i = styles.length;
|
|
||||||
while ( i-- ) {
|
|
||||||
style = styles[i];
|
style = styles[i];
|
||||||
selectors.push(style.textContent.replace(reProperties, ''));
|
|
||||||
if ( style.sheet !== null ) {
|
if ( style.sheet !== null ) {
|
||||||
style.sheet.disabled = true;
|
style.sheet.disabled = true;
|
||||||
style[vAPI.sessionId] = true;
|
style[vAPI.sessionId] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( selectors.length === 0 ) {
|
var elems = [];
|
||||||
return;
|
try {
|
||||||
}
|
elems = document.querySelectorAll('[' + vAPI.domFilterer.hiddenId + ']');
|
||||||
|
} catch (e) {
|
||||||
var elems = [];
|
}
|
||||||
try {
|
i = elems.length;
|
||||||
elems = document.querySelectorAll(selectors.join(','));
|
while ( i-- ) {
|
||||||
} catch (e) {
|
var elem = elems[i];
|
||||||
}
|
var shadow = elem.shadowRoot;
|
||||||
i = elems.length;
|
|
||||||
|
|
||||||
var elem, shadow;
|
|
||||||
while ( i-- ) {
|
|
||||||
elem = elems[i];
|
|
||||||
shadow = elem.shadowRoot;
|
|
||||||
if ( shadow === undefined ) {
|
if ( shadow === undefined ) {
|
||||||
style = elem.style;
|
style = elem.style;
|
||||||
if ( typeof style === 'object' || typeof style.removeProperty === 'function' ) {
|
if ( typeof style === 'object' || typeof style.removeProperty === 'function' ) {
|
||||||
|
@ -81,13 +56,14 @@ while ( i-- ) {
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ( shadow !== null && shadow.className === sessionId && shadow.firstElementChild === null ) {
|
if (
|
||||||
|
shadow !== null &&
|
||||||
|
shadow.className === vAPI.domFilterer.shadowId &&
|
||||||
|
shadow.firstElementChild === null
|
||||||
|
) {
|
||||||
shadow.appendChild(document.createElement('content'));
|
shadow.appendChild(document.createElement('content'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
|
vAPI.domFilterer.toggleOff();
|
||||||
})();
|
})();
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
|
||||||
uBlock - a browser extension to block requests.
|
uBlock Origin - a browser extension to block requests.
|
||||||
Copyright (C) 2015 Raymond Hill
|
Copyright (C) 2015-2016 Raymond Hill
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -19,61 +19,36 @@
|
||||||
Home: https://github.com/gorhill/uBlock
|
Home: https://github.com/gorhill/uBlock
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
if ( typeof vAPI !== 'object' ) {
|
(function() {
|
||||||
|
if ( typeof vAPI !== 'object' || typeof vAPI.domFilterer !== 'object' ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
// Insert all cosmetic filtering-related style tags in the DOM
|
||||||
|
|
||||||
var styles = vAPI.styles;
|
var styles = vAPI.domFilterer.styleTags;
|
||||||
|
var i = styles.length, style;
|
||||||
if ( Array.isArray(styles) === false ) {
|
while ( i-- ) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var sessionId = vAPI.sessionId;
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
// Insert all cosmetic filtering-related style tags in the DOM
|
|
||||||
|
|
||||||
var selectors = [];
|
|
||||||
var reProperties = /\s*\{[^}]+\}\s*/;
|
|
||||||
var style, i;
|
|
||||||
|
|
||||||
i = styles.length;
|
|
||||||
while ( i-- ) {
|
|
||||||
style = styles[i];
|
style = styles[i];
|
||||||
selectors.push(style.textContent.replace(reProperties, ''));
|
|
||||||
if ( style.sheet !== null ) {
|
if ( style.sheet !== null ) {
|
||||||
style.sheet.disabled = false;
|
style.sheet.disabled = false;
|
||||||
style[vAPI.sessionId] = undefined;
|
style[vAPI.sessionId] = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( selectors.length === 0 ) {
|
var elems = [];
|
||||||
return;
|
try {
|
||||||
}
|
elems = document.querySelectorAll('[' + vAPI.domFilterer.hiddenId + ']');
|
||||||
|
} catch (e) {
|
||||||
var elems = [];
|
}
|
||||||
try {
|
i = elems.length;
|
||||||
elems = document.querySelectorAll(selectors.join(','));
|
while ( i-- ) {
|
||||||
} catch (e) {
|
var elem = elems[i];
|
||||||
}
|
var shadow = elem.shadowRoot;
|
||||||
|
|
||||||
var elem, shadow;
|
|
||||||
i = elems.length;
|
|
||||||
while ( i-- ) {
|
|
||||||
elem = elems[i];
|
|
||||||
shadow = elem.shadowRoot;
|
|
||||||
if ( shadow === undefined ) {
|
if ( shadow === undefined ) {
|
||||||
style = elems[i].style;
|
style = elems[i].style;
|
||||||
if ( typeof style === 'object' || typeof style.removeProperty === 'function' ) {
|
if ( typeof style === 'object' || typeof style.removeProperty === 'function' ) {
|
||||||
|
@ -81,13 +56,14 @@ while ( i-- ) {
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ( shadow !== null && shadow.className === sessionId && shadow.firstElementChild !== null ) {
|
if (
|
||||||
|
shadow !== null &&
|
||||||
|
shadow.className === vAPI.domFilterer.shadowId &&
|
||||||
|
shadow.firstElementChild !== null
|
||||||
|
) {
|
||||||
shadow.removeChild(shadow.firstElementChild);
|
shadow.removeChild(shadow.firstElementChild);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
|
vAPI.domFilterer.toggleOn();
|
||||||
})();
|
})();
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
|
@ -19,51 +19,29 @@
|
||||||
Home: https://github.com/gorhill/uBlock
|
Home: https://github.com/gorhill/uBlock
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
if ( typeof vAPI !== 'object' ) {
|
(function() {
|
||||||
|
if ( typeof vAPI !== 'object' || typeof vAPI.domFilterer !== 'object' ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
var xpr = document.evaluate(
|
||||||
|
'count(//*[@' + vAPI.domFilterer.hiddenId + '])',
|
||||||
|
document,
|
||||||
|
null,
|
||||||
|
XPathResult.NUMBER_TYPE,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
// Insert all cosmetic filtering-related style tags in the DOM
|
vAPI.messaging.send(
|
||||||
|
|
||||||
var injectedSelectors = [];
|
|
||||||
var filteredElementCount = 0;
|
|
||||||
|
|
||||||
var reProperties = /\s*\{[^}]+\}\s*/;
|
|
||||||
var i;
|
|
||||||
|
|
||||||
var styles = vAPI.styles || [];
|
|
||||||
i = styles.length;
|
|
||||||
while ( i-- ) {
|
|
||||||
injectedSelectors = injectedSelectors.concat(styles[i].textContent.replace(reProperties, '').split(/\s*,\n\s*/));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( injectedSelectors.length !== 0 ) {
|
|
||||||
filteredElementCount = document.querySelectorAll(injectedSelectors.join(',')).length;
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
vAPI.messaging.send(
|
|
||||||
'scriptlets',
|
'scriptlets',
|
||||||
{
|
{
|
||||||
what: 'liveCosmeticFilteringData',
|
what: 'liveCosmeticFilteringData',
|
||||||
pageURL: window.location.href,
|
pageURL: window.location.href,
|
||||||
filteredElementCount: filteredElementCount
|
filteredElementCount: xpr && xpr.numberValue || 0
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
|
@ -28,13 +28,14 @@
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
if ( typeof vAPI !== 'object' ) {
|
if ( typeof vAPI !== 'object' || typeof vAPI.domFilterer !== 'object' ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
var sessionId = vAPI.sessionId;
|
var sessionId = vAPI.sessionId;
|
||||||
|
var shadowId = vAPI.domFilterer.shadowId;
|
||||||
|
|
||||||
if ( document.querySelector('iframe.dom-inspector.' + sessionId) !== null ) {
|
if ( document.querySelector('iframe.dom-inspector.' + sessionId) !== null ) {
|
||||||
return;
|
return;
|
||||||
|
@ -690,19 +691,20 @@ var cosmeticFilterMapper = (function() {
|
||||||
// Not all target nodes have necessarily been force-hidden,
|
// Not all target nodes have necessarily been force-hidden,
|
||||||
// do it now so that the inspector does not unhide these
|
// do it now so that the inspector does not unhide these
|
||||||
// nodes when disabling style tags.
|
// nodes when disabling style tags.
|
||||||
var nodesFromStyleTag = function(styleTag, rootNode) {
|
var nodesFromStyleTag = function(rootNode) {
|
||||||
var filterMap = nodeToCosmeticFilterMap;
|
var filterMap = nodeToCosmeticFilterMap,
|
||||||
var styleText = styleTag.textContent;
|
selectors, selector,
|
||||||
var selectors = styleText.slice(0, styleText.lastIndexOf('\n')).split(/,\n/);
|
nodes, node,
|
||||||
var i = selectors.length;
|
entries, entry,
|
||||||
var selector, nodes, j, node;
|
i, j;
|
||||||
|
|
||||||
|
// CSS-based selectors: simple one.
|
||||||
|
selectors = vAPI.domFilterer.simpleSelectors;
|
||||||
|
i = selectors.length;
|
||||||
while ( i-- ) {
|
while ( i-- ) {
|
||||||
// https://github.com/gorhill/uBlock/issues/1015
|
selector = selectors[i];
|
||||||
// Discard `:root ` prefix.
|
|
||||||
selector = selectors[i].slice(6);
|
|
||||||
if ( filterMap.has(rootNode) === false && rootNode[matchesFnName](selector) ) {
|
if ( filterMap.has(rootNode) === false && rootNode[matchesFnName](selector) ) {
|
||||||
filterMap.set(rootNode, selector);
|
filterMap.set(rootNode, selector);
|
||||||
hideNode(node);
|
|
||||||
}
|
}
|
||||||
nodes = rootNode.querySelectorAll(selector);
|
nodes = rootNode.querySelectorAll(selector);
|
||||||
j = nodes.length;
|
j = nodes.length;
|
||||||
|
@ -710,24 +712,106 @@ var cosmeticFilterMapper = (function() {
|
||||||
node = nodes[j];
|
node = nodes[j];
|
||||||
if ( filterMap.has(node) === false ) {
|
if ( filterMap.has(node) === false ) {
|
||||||
filterMap.set(node, selector);
|
filterMap.set(node, selector);
|
||||||
hideNode(node);
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CSS-based selectors: complex one (must query from doc root).
|
||||||
|
selectors = vAPI.domFilterer.complexSelectors;
|
||||||
|
i = selectors.length;
|
||||||
|
while ( i-- ) {
|
||||||
|
selector = selectors[i];
|
||||||
|
nodes = document.querySelectorAll(selector);
|
||||||
|
j = nodes.length;
|
||||||
|
while ( j-- ) {
|
||||||
|
node = nodes[j];
|
||||||
|
if ( filterMap.has(node) === false ) {
|
||||||
|
filterMap.set(node, selector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// `:has()`-based selectors: simple ones.
|
||||||
|
entries = vAPI.domFilterer.simpleHasSelectors;
|
||||||
|
i = entries.length;
|
||||||
|
while ( i-- ) {
|
||||||
|
entry = entries[i];
|
||||||
|
selector = entries.a + ':has(' + entries.b + ')';
|
||||||
|
if (
|
||||||
|
filterMap.has(rootNode) === false &&
|
||||||
|
rootNode[matchesFnName](entry.a) &&
|
||||||
|
rootNode.querySelector(entry.b) !== null
|
||||||
|
) {
|
||||||
|
filterMap.set(rootNode, selector);
|
||||||
|
}
|
||||||
|
nodes = rootNode.querySelectorAll(entries.a);
|
||||||
|
j = nodes.length;
|
||||||
|
while ( j-- ) {
|
||||||
|
node = nodes[j];
|
||||||
|
if (
|
||||||
|
filterMap.has(node) === false &&
|
||||||
|
node.querySelector(entry.b) !== null
|
||||||
|
) {
|
||||||
|
filterMap.set(node, selector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// `:has()`-based selectors: complex ones (must query from doc root).
|
||||||
|
entries = vAPI.domFilterer.complexHasSelectors;
|
||||||
|
i = entries.length;
|
||||||
|
while ( i-- ) {
|
||||||
|
entry = entries[i];
|
||||||
|
selector = entries.a + ':has(' + entries.b + ')';
|
||||||
|
nodes = document.querySelectorAll(entries.a);
|
||||||
|
j = nodes.length;
|
||||||
|
while ( j-- ) {
|
||||||
|
node = nodes[j];
|
||||||
|
if (
|
||||||
|
filterMap.has(node) === false &&
|
||||||
|
node.querySelector(entry.b) !== null
|
||||||
|
) {
|
||||||
|
filterMap.set(node, selector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// `:xpath()`-based selectors.
|
||||||
|
var xpr;
|
||||||
|
entries = vAPI.domFilterer.xpathSelectors;
|
||||||
|
i = entries.length;
|
||||||
|
while ( i-- ) {
|
||||||
|
entry = entries[i];
|
||||||
|
selector = ':xpath(' + entry + ')';
|
||||||
|
xpr = document.evaluate(
|
||||||
|
entry,
|
||||||
|
document,
|
||||||
|
null,
|
||||||
|
XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
|
||||||
|
xpr
|
||||||
|
);
|
||||||
|
j = xpr.snapshotLength;
|
||||||
|
while ( j-- ) {
|
||||||
|
node = xpr.snapshotItem(j);
|
||||||
|
if ( filterMap.has(node) === false ) {
|
||||||
|
filterMap.set(node, selector);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var incremental = function(rootNode) {
|
var incremental = function(rootNode) {
|
||||||
var styleTags = vAPI.styles || [];
|
var styleTags = vAPI.domFilterer.styleTags || [];
|
||||||
var styleTag;
|
var styleTag;
|
||||||
var i = styleTags.length;
|
var i = styleTags.length;
|
||||||
while ( i-- ) {
|
while ( i-- ) {
|
||||||
styleTag = styleTags[i];
|
styleTag = styleTags[i];
|
||||||
nodesFromStyleTag(styleTag, rootNode);
|
|
||||||
if ( styleTag.sheet !== null ) {
|
if ( styleTag.sheet !== null ) {
|
||||||
styleTag.sheet.disabled = true;
|
styleTag.sheet.disabled = true;
|
||||||
styleTag[vAPI.sessionId] = true;
|
styleTag[vAPI.sessionId] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
nodesFromStyleTag(rootNode);
|
||||||
};
|
};
|
||||||
|
|
||||||
var reset = function() {
|
var reset = function() {
|
||||||
|
@ -736,7 +820,7 @@ var cosmeticFilterMapper = (function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
var shutdown = function() {
|
var shutdown = function() {
|
||||||
var styleTags = vAPI.styles || [];
|
var styleTags = vAPI.domFilterer.styleTags || [];
|
||||||
var styleTag;
|
var styleTag;
|
||||||
var i = styleTags.length;
|
var i = styleTags.length;
|
||||||
while ( i-- ) {
|
while ( i-- ) {
|
||||||
|
@ -761,12 +845,51 @@ var elementsFromSelector = function(selector, context) {
|
||||||
if ( !context ) {
|
if ( !context ) {
|
||||||
context = document;
|
context = document;
|
||||||
}
|
}
|
||||||
var out = [];
|
var out;
|
||||||
|
if ( selector.indexOf(':') !== -1 ) {
|
||||||
|
out = elementsFromSpecialSelector(selector);
|
||||||
|
if ( out !== undefined ) {
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// plain CSS selector
|
||||||
try {
|
try {
|
||||||
out = context.querySelectorAll(selector);
|
out = context.querySelectorAll(selector);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
}
|
}
|
||||||
|
return out || [];
|
||||||
|
};
|
||||||
|
|
||||||
|
var elementsFromSpecialSelector = function(selector) {
|
||||||
|
var out = [], i;
|
||||||
|
var matches = /^(.+?):has\((.+?)\)$/.exec(selector);
|
||||||
|
if ( matches !== null ) {
|
||||||
|
var nodes = document.querySelector(matches[1]);
|
||||||
|
i = nodes.length;
|
||||||
|
while ( i-- ) {
|
||||||
|
var node = nodes[i];
|
||||||
|
if ( node.querySelector(matches[2]) !== null ) {
|
||||||
|
out.push(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
return out;
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
matches = /^:xpath\((.+?)\)$/.exec(selector);
|
||||||
|
if ( matches !== null ) {
|
||||||
|
var xpr = document.evaluate(
|
||||||
|
matches[1],
|
||||||
|
document,
|
||||||
|
null,
|
||||||
|
XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
i = xpr.snapshotLength;
|
||||||
|
while ( i-- ) {
|
||||||
|
out.push(xpr.snapshotItem(i));
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
@ -970,7 +1093,7 @@ var showNode = function(node, v1, v2) {
|
||||||
} else {
|
} else {
|
||||||
node.style.setProperty('display', v1, v2);
|
node.style.setProperty('display', v1, v2);
|
||||||
}
|
}
|
||||||
} else if ( shadow !== null && shadow.className === sessionId && shadow.firstElementChild === null ) {
|
} else if ( shadow !== null && shadow.className === shadowId && shadow.firstElementChild === null ) {
|
||||||
shadow.appendChild(document.createElement('content'));
|
shadow.appendChild(document.createElement('content'));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -983,7 +1106,7 @@ var hideNode = function(node) {
|
||||||
node.style.setProperty('display', 'none', 'important');
|
node.style.setProperty('display', 'none', 'important');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ( shadow !== null && shadow.className === sessionId ) {
|
if ( shadow !== null && shadow.className === shadowId ) {
|
||||||
if ( shadow.firstElementChild !== null ) {
|
if ( shadow.firstElementChild !== null ) {
|
||||||
shadow.removeChild(shadow.firstElementChild);
|
shadow.removeChild(shadow.firstElementChild);
|
||||||
}
|
}
|
||||||
|
@ -995,7 +1118,7 @@ var hideNode = function(node) {
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
shadow.className = sessionId;
|
shadow.className = shadowId;
|
||||||
};
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
@ -1052,6 +1175,12 @@ var onMessage = function(request) {
|
||||||
highlightElements();
|
highlightElements();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'toggleFilter':
|
||||||
|
highlightedElementLists[0] = selectNodes(request.filter, request.nid);
|
||||||
|
toggleNodes(highlightedElementLists[0], request.original, request.target);
|
||||||
|
highlightElements(true);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'toggleNodes':
|
case 'toggleNodes':
|
||||||
highlightedElementLists[0] = selectNodes(request.selector, request.nid);
|
highlightedElementLists[0] = selectNodes(request.selector, request.nid);
|
||||||
toggleNodes(highlightedElementLists[0], request.original, request.target);
|
toggleNodes(highlightedElementLists[0], request.original, request.target);
|
||||||
|
|
Loading…
Reference in New Issue