diff --git a/assets/ublock/filters.txt b/assets/ublock/filters.txt
index b8c06a77e..3d0ead71c 100644
--- a/assets/ublock/filters.txt
+++ b/assets/ublock/filters.txt
@@ -47,7 +47,7 @@ google.*##.mw > #rcnt > #center_col > #taw > #tvcap > .c
# https://github.com/gorhill/uBlock/issues/70
# Workaround for issue 70.
-deviantart.com##.dp-ad-target.atf-right-300x250
+#deviantart.com##.dp-ad-target.atf-right-300x250
# Seen on mediafire.com
||torconpro.com^
diff --git a/assets/ublock/thirdparty-lists.txt b/assets/ublock/thirdparty-lists.txt
new file mode 100644
index 000000000..7745e9485
--- /dev/null
+++ b/assets/ublock/thirdparty-lists.txt
@@ -0,0 +1,131 @@
+mirror1.malwaredomains.com/files/immortal_domains.txt
+http://mirror1.malwaredomains.com/files/immortal_domains.txt
+
+mirror1.malwaredomains.com/files/justdomains
+http://mirror1.malwaredomains.com/files/justdomains
+
+pgl.yoyo.org/as/serverlist
+http://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&showintro=1&mimetype=plaintext
+
+www.malwaredomainlist.com/hostslist/hosts.txt
+http://www.malwaredomainlist.com/hostslist/hosts.txt
+
+hosts-file.net/ad-servers
+http://hosts-file.net/.%5Cad_servers.txt
+
+someonewhocares.org/hosts/hosts
+http://someonewhocares.org/hosts/hosts
+
+winhelp2002.mvps.org/hosts.txt
+http://winhelp2002.mvps.org/hosts.txt
+
+spam404bl.com/spam404scamlist.txt
+http://spam404bl.com/spam404scamlist.txt
+
+easylist-downloads.adblockplus.org/easylist.txt
+https://easylist-downloads.adblockplus.org/easylist.txt
+
+easylist-downloads.adblockplus.org/easylist_noelemhide.txt
+https://easylist-downloads.adblockplus.org/easylist_noelemhide.txt
+
+easylist-downloads.adblockplus.org/easyprivacy.txt
+https://easylist-downloads.adblockplus.org/easyprivacy.txt
+
+easylist-downloads.adblockplus.org/fanboy-annoyance.txt
+https://easylist-downloads.adblockplus.org/fanboy-annoyance.txt
+
+easylist-downloads.adblockplus.org/fanboy-social.txt
+https://easylist-downloads.adblockplus.org/fanboy-social.txt
+
+www.fanboy.co.nz/r/fanboy-ultimate.txt
+https://www.fanboy.co.nz/r/fanboy-ultimate.txt
+
+www.fanboy.co.nz/enhancedstats.txt
+https://www.fanboy.co.nz/enhancedstats.txt
+
+www.fanboy.co.nz/fanboy-antifacebook.txt
+https://www.fanboy.co.nz/fanboy-antifacebook.txt
+
+raw.githubusercontent.com/reek/anti-adblock-killer/master/anti-adblock-killer-filters.txt
+https://raw.githubusercontent.com/reek/anti-adblock-killer/master/anti-adblock-killer-filters.txt
+
+easylist-downloads.adblockplus.org/easylistgermany.txt
+https://easylist-downloads.adblockplus.org/easylistgermany.txt
+
+www.hufilter.hu/hufilter.txt
+http://www.hufilter.hu/hufilter.txt
+
+easylist-downloads.adblockplus.org/easylistitaly.txt
+https://easylist-downloads.adblockplus.org/easylistitaly.txt
+
+dl.dropboxusercontent.com/u/1289327/abpxfiles/filtri.txt
+https://dl.dropboxusercontent.com/u/1289327/abpxfiles/filtri.txt
+
+easylist-downloads.adblockplus.org/easylistdutch.txt
+https://easylist-downloads.adblockplus.org/easylistdutch.txt
+
+easylist-downloads.adblockplus.org/liste_fr.txt
+https://easylist-downloads.adblockplus.org/liste_fr.txt
+
+easylist-downloads.adblockplus.org/advblock.txt
+https://easylist-downloads.adblockplus.org/advblock.txt
+
+easylist-downloads.adblockplus.org/bitblock.txt
+https://easylist-downloads.adblockplus.org/bitblock.txt
+
+easylist-downloads.adblockplus.org/easylistchina.txt
+https://easylist-downloads.adblockplus.org/easylistchina.txt
+
+cjxlist1.googlecode.com/svn/cjxlist.txt
+https://cjxlist1.googlecode.com/svn/cjxlist.txt
+
+adblock-chinalist.googlecode.com/svn/trunk/adblock.txt
+http://adblock-chinalist.googlecode.com/svn/trunk/adblock.txt
+
+adblock-plus-japanese-filter.googlecode.com/hg/abp_jp.txt
+https://adblock-plus-japanese-filter.googlecode.com/hg/abp_jp.txt
+
+margevicius.lt/AdBlockPlusLithuania.txt
+http://margevicius.lt/AdBlockPlusLithuania.txt
+
+stanev.org/abp/adblock_bg.txt
+http://stanev.org/abp/adblock_bg.txt
+
+indonesianadblockrules.googlecode.com/hg/subscriptions/abpindo.txt
+https://indonesianadblockrules.googlecode.com/hg/subscriptions/abpindo.txt
+
+liste-ar-adblock.googlecode.com/hg/Liste_AR.txt
+https://liste-ar-adblock.googlecode.com/hg/Liste_AR.txt
+
+raw.githubusercontent.com/tomasko126/easylistczechandslovak/master/filters.txt
+https://raw.githubusercontent.com/tomasko126/easylistczechandslovak/master/filters.txt
+
+raw.githubusercontent.com/adblockpolska/Adblock_PL_List/master/adblock_polska.txt
+https://raw.githubusercontent.com/adblockpolska/Adblock_PL_List/master/adblock_polska.txt
+
+raw.githubusercontent.com/AdBlockPlusIsrael/EasyListHebrew/master/EasyListHebrew.txt
+https://raw.githubusercontent.com/AdBlockPlusIsrael/EasyListHebrew/master/EasyListHebrew.txt
+
+raw.githubusercontent.com/wiltteri/wiltteri.txt/master/wiltteri.txt
+http://raw.githubusercontent.com/wiltteri/wiltteri.txt/master/wiltteri.txt
+
+home.fredfiber.no/langsholt/adblock.txt
+http://home.fredfiber.no/langsholt/adblock.txt
+
+www.fanboy.co.nz/fanboy-swedish.txt
+https://www.fanboy.co.nz/fanboy-swedish.txt
+
+adblock.schack.dk/block.txt
+http://adblock.schack.dk/block.txt
+
+adblock.gardar.net/is.abp.txt
+http://adblock.gardar.net/is.abp.txt
+
+www.void.gr/kargig/void-gr-filters.txt
+https://www.void.gr/kargig/void-gr-filters.txt
+
+abp.mozilla-hispano.org/nauscopio/filtros.txt
+http://abp.mozilla-hispano.org/nauscopio/filtros.txt
+
+gitorious.org/adblock-latvian/adblock-latvian/raw/master_lists/latvian-list.txt
+https://gitorious.org/adblock-latvian/adblock-latvian/raw/master%3Alists/latvian-list.txt
\ No newline at end of file
diff --git a/js/3p-filters.js b/js/3p-filters.js
index 11ba4d3e2..31cbacb8c 100644
--- a/js/3p-filters.js
+++ b/js/3p-filters.js
@@ -122,7 +122,7 @@ var renderBlacklists = function() {
'
',
'',
' ',
- '',
+ '',
'{{name}}',
'',
': ',
diff --git a/js/abp-filters.js b/js/abp-filters.js
index 9effda05b..92c6e1b4d 100644
--- a/js/abp-filters.js
+++ b/js/abp-filters.js
@@ -1008,25 +1008,41 @@ FilterBucket.prototype.match = function(url, tokenBeg) {
/******************************************************************************/
var FilterContainer = function() {
- this.categories = {};
- this.duplicates = {};
- this.url = '';
- this.tokenBeg = 0;
- this.tokenEnd = 0;
+ this.reAnyToken = /[%0-9a-z]+/g;
+ this.buckets = new Array(8);
+ this.blockedAnyPartyHostnames = new µBlock.LiquidDict();
+ this.blocked3rdPartyHostnames = new µBlock.LiquidDict();
this.filterParser = new FilterParser();
+ this.reset();
+};
+
+/******************************************************************************/
+
+// Reset all, thus reducing to a minimum memory footprint of the context.
+
+FilterContainer.prototype.reset = function() {
+ this.frozen = false;
this.processedFilterCount = 0;
this.acceptedCount = 0;
this.allowFilterCount = 0;
this.blockFilterCount = 0;
this.duplicateCount = 0;
+ this.categories = {};
+ this.duplicates = {};
+ this.blockedAnyPartyHostnames.reset();
+ this.blocked3rdPartyHostnames.reset();
+ this.filterParser.reset();
+};
- // This is for hostname-based-any-request filters
- this.blockedAnyPartyHostnames = new µBlock.LiquidDict();
- this.blocked3rdPartyHostnames = new µBlock.LiquidDict();
+/******************************************************************************/
- // Used during URL matching
- this.reAnyToken = /[%0-9a-z]+/g;
- this.buckets = new Array(8);
+FilterContainer.prototype.freeze = function() {
+ //histogram('allFilters', this.categories);
+ this.blockedAnyPartyHostnames.freeze();
+ this.blocked3rdPartyHostnames.freeze();
+ this.duplicates = {};
+ this.filterParser.reset();
+ this.frozen = true;
};
/******************************************************************************/
@@ -1233,35 +1249,7 @@ FilterContainer.prototype.addToCategory = function(category, tokenKey, filter) {
/******************************************************************************/
-// Reset all, thus reducing to a minimum memory footprint of the context.
-
-FilterContainer.prototype.reset = function() {
- this.processedFilterCount = 0;
- this.acceptedCount = 0;
- this.allowFilterCount = 0;
- this.blockFilterCount = 0;
- this.duplicateCount = 0;
- this.categories = {};
- this.blockedAnyPartyHostnames.reset();
- this.blocked3rdPartyHostnames.reset();
- this.duplicates = {};
- this.filterParser.reset();
-};
-
-/******************************************************************************/
-
-FilterContainer.prototype.freeze = function() {
- //histogram('allFilters', this.categories);
- this.blockedAnyPartyHostnames.freeze();
- this.blocked3rdPartyHostnames.freeze();
- this.duplicates = {};
- this.filterParser.reset();
-};
-
-/******************************************************************************/
-
-FilterContainer.prototype.matchTokens = function() {
- var url = this.url;
+FilterContainer.prototype.matchTokens = function(url) {
var re = this.reAnyToken;
var matches, beg, token;
var buckets = this.buckets;
@@ -1383,14 +1371,17 @@ FilterContainer.prototype.match3rdPartyHostname = function(requestHostname) {
/******************************************************************************/
-FilterContainer.prototype.matchString = function(pageDetails, url, requestType, requestHostname) {
+FilterContainer.prototype.matchString = function(pageDetails, requestURL, requestType, requestHostname) {
// adbProfiler.countUrl();
+ if ( this.frozen !== true ) {
+ return false;
+ }
// https://github.com/gorhill/httpswitchboard/issues/239
// Convert url to lower case:
// `match-case` option not supported, but then, I saw only one
// occurrence of it in all the supported lists (bulgaria list).
- this.url = url.toLowerCase();
+ var url = requestURL.toLowerCase();
// The logic here is simple:
//
@@ -1442,7 +1433,7 @@ FilterContainer.prototype.matchString = function(pageDetails, url, requestType,
buckets[5] = categories[this.makeCategoryKey(BlockAction | type | party)];
buckets[6] = categories[this.makeCategoryKey(BlockOneParty | type | domainParty)];
buckets[7] = categories[this.makeCategoryKey(BlockOtherParties | type)];
- br = this.matchTokens();
+ br = this.matchTokens(url);
}
// If there is no block filter, no need to test against allow filters
@@ -1459,7 +1450,7 @@ FilterContainer.prototype.matchString = function(pageDetails, url, requestType,
buckets[5] = categories[this.makeCategoryKey(AllowAction | type | party)];
buckets[6] = categories[this.makeCategoryKey(AllowOneParty | type | domainParty)];
buckets[7] = categories[this.makeCategoryKey(AllowOtherParties | type | domainParty)];
- var ar = this.matchTokens();
+ var ar = this.matchTokens(url);
if ( ar !== false ) {
return '@@' + ar;
}
diff --git a/js/abp-hide-filters.js b/js/abp-hide-filters.js
index 4dfd82762..6a15042bb 100644
--- a/js/abp-hide-filters.js
+++ b/js/abp-hide-filters.js
@@ -272,6 +272,7 @@ var FilterContainer = function() {
FilterContainer.prototype.reset = function() {
this.filterParser.reset();
+ this.frozen = false;
this.acceptedCount = 0;
this.processedCount = 0;
this.genericFilters = {};
@@ -399,6 +400,7 @@ FilterContainer.prototype.freeze = function() {
// console.debug('Number of duplicate cosmetic filters skipped:', this.duplicateCount);
this.duplicates = {};
+ this.frozen = true;
//console.log('µBlock> adp-hide-filters.js: %d filters accepted', this.acceptedCount);
//console.log('µBlock> adp-hide-filters.js: %d filters processed', this.processedCount);
@@ -611,6 +613,9 @@ FilterContainer.prototype.addFilterEntry = function(filterDict, hash, f) {
/******************************************************************************/
FilterContainer.prototype.retrieveGenericSelectors = function(tabHostname, request) {
+ if ( this.frozen !== true ) {
+ return;
+ }
if ( !tabHostname || µb.getCosmeticFilteringSwitch(tabHostname) !== true ) {
return;
}
@@ -669,6 +674,9 @@ FilterContainer.prototype.retrieveGenericSelectors = function(tabHostname, reque
/******************************************************************************/
FilterContainer.prototype.retrieveDomainSelectors = function(tabHostname, request) {
+ if ( this.frozen !== true ) {
+ return;
+ }
if ( !tabHostname || µb.getCosmeticFilteringSwitch(tabHostname) !== true ) {
return;
}
diff --git a/js/assets.js b/js/assets.js
index 9d48c13ad..70e02d688 100644
--- a/js/assets.js
+++ b/js/assets.js
@@ -62,8 +62,9 @@ File system structure:
var fileSystem;
var fileSystemQuota = 40 * 1024 * 1024;
-var remoteRoot = µBlock.projectServerRoot;
+var repositoryRoot = µBlock.projectServerRoot;
var nullFunc = function() { };
+var thirdpartyHomeURLs = null;
/******************************************************************************/
@@ -71,6 +72,7 @@ var getTextFileFromURL = function(url, onLoad, onError) {
// console.log('µBlock> getTextFileFromURL("%s"):', url);
var xhr = new XMLHttpRequest();
xhr.responseType = 'text';
+ xhr.timeout = 15000;
xhr.onload = onLoad;
xhr.onerror = onError;
xhr.ontimeout = onError;
@@ -268,7 +270,7 @@ var readRemoteFile = function(path, callback) {
// 'ublock=...' is to skip browser cache
getTextFileFromURL(
- remoteRoot + path + '?ublock=' + Date.now(),
+ repositoryRoot + path + '?ublock=' + Date.now(),
onRemoteFileLoaded,
onRemoteFileError
);
@@ -346,8 +348,10 @@ var writeLocalFile = function(path, content, callback) {
var updateFromRemote = function(details, callback) {
// 'ublock=...' is to skip browser cache
- var remoteURL = remoteRoot + details.path + '?ublock=' + Date.now();
var targetPath = details.path;
+ // https://github.com/gorhill/uBlock/issues/84
+ var homeURL = '';
+ var repositoryURL = repositoryRoot + targetPath + '?ublock=' + Date.now();
var targetMd5 = details.md5 || '';
var reportBackError = function() {
@@ -360,30 +364,106 @@ var updateFromRemote = function(details, callback) {
var onRemoteFileLoaded = function() {
this.onload = this.onerror = null;
if ( typeof this.responseText !== 'string' ) {
- console.error('µBlock> updateFromRemote("%s") / onRemoteFileLoaded(): no response', remoteURL);
+ console.error('µBlock> updateFromRemote("%s") / onRemoteFileLoaded(): no response', repositoryURL);
reportBackError();
return;
}
- if ( YaMD5.hashStr(this.responseText) !== targetMd5 ) {
- console.error('µBlock> updateFromRemote("%s") / onRemoteFileLoaded(): bad md5 checksum', remoteURL);
+ if ( targetMd5 !== '' && YaMD5.hashStr(this.responseText) !== targetMd5 ) {
+ console.error('µBlock> updateFromRemote("%s") / onRemoteFileLoaded(): bad md5 checksum', repositoryURL);
reportBackError();
return;
}
- // console.debug('µBlock> updateFromRemote("%s") / onRemoteFileLoaded()', remoteURL);
+ // console.debug('µBlock> updateFromRemote("%s") / onRemoteFileLoaded()', repositoryURL);
writeLocalFile(targetPath, this.responseText, callback);
};
var onRemoteFileError = function(ev) {
this.onload = this.onerror = null;
- console.error('µBlock> updateFromRemote() / onRemoteFileError("%s"):', remoteURL, this.statusText);
+ console.error('µBlock> updateFromRemote() / onRemoteFileError("%s"):', repositoryURL, this.statusText);
reportBackError();
};
- getTextFileFromURL(
- remoteURL,
- onRemoteFileLoaded,
- onRemoteFileError
- );
+ var onHomeFileLoaded = function() {
+ this.onload = this.onerror = null;
+ if ( typeof this.responseText !== 'string' ) {
+ console.error('µBlock> updateFromRemote("%s") / onHomeFileLoaded(): no response', homeURL);
+ getTextFileFromURL(repositoryURL, onRemoteFileLoaded, onRemoteFileError);
+ return;
+ }
+ if ( targetMd5 !== '' && YaMD5.hashStr(this.responseText) !== targetMd5 ) {
+ console.error('µBlock> updateFromRemote("%s") / onHomeFileLoaded(): bad md5 checksum', homeURL);
+ getTextFileFromURL(repositoryURL, onRemoteFileLoaded, onRemoteFileError);
+ return;
+ }
+ // console.debug('µBlock> updateFromRemote("%s") / onHomeFileLoaded()', homeURL);
+ writeLocalFile(targetPath, this.responseText, callback);
+ };
+
+ var onHomeFileError = function(ev) {
+ this.onload = this.onerror = null;
+ console.error('µBlock> updateFromRemote() / onHomeFileError("%s"):', homeURL, this.statusText);
+ getTextFileFromURL(repositoryURL, onRemoteFileLoaded, onRemoteFileError);
+ };
+
+ // https://github.com/gorhill/uBlock/issues/84
+ // Create a URL from where the asset needs to be downloaded. It can be:
+ // - a home server URL
+ // - a github repo URL
+ var getThirdpartyHomeURL = function() {
+ // If it is a 3rd-party, look-up home server URL, if any.
+ if ( targetPath.indexOf('assets/thirdparties/') === 0 ) {
+ homeURL = targetPath.replace('assets/thirdparties/', '');
+ if ( thirdpartyHomeURLs && thirdpartyHomeURLs[homeURL] ) {
+ homeURL = thirdpartyHomeURLs[homeURL];
+ } else {
+ homeURL = 'http://' + homeURL;
+ }
+ }
+ // If there is a home server, disregard checksum: the file is assumed
+ // most up to date at the home server.
+ if ( homeURL !== '' ) {
+ targetMd5 = '';
+ getTextFileFromURL(homeURL, onHomeFileLoaded, onHomeFileError);
+ return;
+ }
+ // The resource will be pulled from Github repo. It's reserved for
+ // more important assets, so we keep and use the checksum.
+ getTextFileFromURL(repositoryURL, onRemoteFileLoaded, onRemoteFileError);
+ };
+
+ // https://github.com/gorhill/uBlock/issues/84
+ // First try to load from the actual home server of a third-party.
+ var onThirdpartyHomeURLsLoaded = function(details) {
+ thirdpartyHomeURLs = {};
+ if ( details.error ) {
+ getThirdpartyHomeURL();
+ return;
+ }
+ var urlPairs = details.content.split(/\n\n+/);
+ var i = urlPairs.length;
+ var pair, pos, k, v;
+ while ( i-- ) {
+ pair = urlPairs[i];
+ pos = pair.indexOf('\n');
+ if ( pos === -1 ) {
+ continue;
+ }
+ k = pair.slice(0, pos).trim();
+ v = pair.slice(pos).trim();
+ if ( k === '' || v === '' ) {
+ continue;
+ }
+ thirdpartyHomeURLs[k] = v;
+ }
+ getThirdpartyHomeURL();
+ };
+
+ // Get home servers if not done yet.
+ if ( thirdpartyHomeURLs === null ) {
+ readLocalFile('assets/ublock/thirdparty-lists.txt', onThirdpartyHomeURLsLoaded);
+ } else {
+ getThirdpartyHomeURL();
+ }
};
/******************************************************************************/
diff --git a/js/background.js b/js/background.js
index 392c3d7fa..e073a74ad 100644
--- a/js/background.js
+++ b/js/background.js
@@ -43,7 +43,7 @@ return {
allowedRequestCount: 0
},
- updateAssetsEvery: 4 * 24 * 60 * 60 * 1000,
+ updateAssetsEvery: 2 * 24 * 60 * 60 * 1000,
projectServerRoot: 'https://raw2.github.com/gorhill/ublock/master/',
userFiltersPath: 'assets/user/filters.txt',
diff --git a/js/contentscript-end.js b/js/contentscript-end.js
index e120fcb2b..9aff7ecb9 100644
--- a/js/contentscript-end.js
+++ b/js/contentscript-end.js
@@ -146,9 +146,8 @@ var cosmeticFiltering = (function() {
injectedSelectors[exceptions[i]] = true;
}
}
-
- // TODO: evaluate merging into a single loop
- selectorsFromNodeList(document.querySelectorAll('*[class],*[id]'));
+ idsFromNodeList(document.querySelectorAll('[id]'));
+ classesFromNodeList(document.querySelectorAll('[class]'));
retrieveGenericSelectors();
};
@@ -302,42 +301,47 @@ var cosmeticFiltering = (function() {
}
};
- // TODO: split back into to specialized functions as it was before. Too
- // many code paths creeped back, I thought I could get rid of most.
- var selectorsFromNodeList = function(nodes) {
+ var idsFromNodeList = function(nodes) {
if ( !nodes || !nodes.length ) {
return;
}
if ( idSelectors === null ) {
idSelectors = [];
}
+ var qq = queriedSelectors;
+ var ii = idSelectors;
+ var node, v;
+ var i = nodes.length;
+ while ( i-- ) {
+ node = nodes[i];
+ if ( node.nodeType !== 1 ) { continue; }
+ // id
+ v = nodes[i].id;
+ // quite unlikely, so no need to be fancy
+ if ( typeof v !== 'string' ) { continue; }
+ v = v.trim();
+ if ( v === '' ) { continue; }
+ v = '#' + v;
+ if ( qq[v] ) { continue; }
+ ii.push(v);
+ qq[v] = true;
+ }
+ };
+
+ var classesFromNodeList = function(nodes) {
+ if ( !nodes || !nodes.length ) {
+ return;
+ }
if ( classSelectors === null ) {
classSelectors = {};
}
var qq = queriedSelectors;
var cc = classSelectors;
- var ii = idSelectors;
- var node, v, classNames, j;
+ var node, v, vv, j;
var i = nodes.length;
while ( i-- ) {
node = nodes[i];
- if ( node.nodeType !== 1 ) {
- continue;
- }
- // id
- v = nodes[i].id;
- // quite unlikely, so no need to be fancy
- if ( typeof v !== 'string' ) {
- v = '';
- }
- v = v.trim();
- if ( v !== '' ) {
- v = '#' + v;
- if ( !qq[v] ) {
- ii.push(v);
- qq[v] = true;
- }
- }
+ if ( node.nodeType !== 1 ) { continue; }
// class
v = nodes[i].className;
// it could be an SVGAnimatedString...
@@ -353,10 +357,10 @@ var cosmeticFiltering = (function() {
continue;
}
// many classes
- classNames = v.trim().split(/\s+/);
- j = classNames.length;
+ vv = v.trim().split(' ');
+ j = vv.length;
while ( j-- ) {
- v = classNames[j];
+ v = vv[j].trim();
if ( v === '' ) { continue; }
v = '.' + v;
if ( qq[v] ) { continue; }
@@ -371,12 +375,14 @@ var cosmeticFiltering = (function() {
var nodeList, j, node;
while ( i-- ) {
nodeList = nodeLists[i];
- selectorsFromNodeList(nodeList);
+ idsFromNodeList(nodeList);
+ classesFromNodeList(nodeList);
j = nodeList.length;
while ( j-- ) {
node = nodeList[j];
- if ( node.querySelectorAll ) {
- selectorsFromNodeList(node.querySelectorAll('*[id],*[class]'));
+ if ( typeof node.querySelectorAll === 'function' ) {
+ idsFromNodeList(node.querySelectorAll('[id]'));
+ classesFromNodeList(node.querySelectorAll('[class]'));
}
}
}
@@ -394,7 +400,7 @@ var cosmeticFiltering = (function() {
// https://github.com/gorhill/uBlock/issues/7
-var blockedElementHider = (function() {
+(function() {
var hideOne = function(elem, collapse) {
// If `!important` is not there, going back using history will likely
// cause the hidden element to re-appear.
@@ -404,21 +410,9 @@ var blockedElementHider = (function() {
}
};
- var observeOne = function(elem) {
- var onComplete = function() {
- var elem = this;
- var onAnswerReceived = function(details) {
- if ( details.blocked ) {
- hideOne(elem, details.collapse);
- }
- };
- messaging.ask({ what: 'blockedRequest', url: this.src }, onAnswerReceived);
- this.removeEventListener('load', onComplete);
- };
- elem.addEventListener('load', onComplete);
- };
-
- var hideMany = function(elems, details) {
+ // First pass
+ messaging.ask({ what: 'blockedRequests' }, function(details) {
+ var elems = document.querySelectorAll('img,iframe');
var blockedRequests = details.blockedRequests;
var collapse = details.collapse;
var i = elems.length;
@@ -426,78 +420,41 @@ var blockedElementHider = (function() {
while ( i-- ) {
elem = elems[i];
src = elem.src;
- if ( typeof src !== 'string' ) {
+ if ( typeof src !== 'string' || src === '' ) {
continue;
}
- if ( src === '' ) {
- observeOne(elem);
- } else if ( blockedRequests[src] ) {
+ if ( blockedRequests[src] ) {
hideOne(elem, collapse);
}
}
- };
+ });
- var processElements = function(elems) {
- var blockedRequestsReceived = function(details) {
- hideMany(elems, details);
- var i = elems.length;
- while ( i-- ) {
- hideMany(elems[i].querySelectorAll('img,iframe'), details);
+ // Listeners to mop up whatever is otherwise missed:
+ // - Future requests not blocked yet
+ // - Elements dynamically added to the page
+ // - Elements which resource URL changes
+ var onResourceLoaded = function(ev) {
+ var target = ev.target;
+ if ( !target || !target.src ) {
+ return;
+ }
+ var tag = target.tagName.toLowerCase();
+ if ( tag !== 'img' && tag !== 'iframe' ) {
+ return;
+ }
+ var onAnswerReceived = function(details) {
+ if ( details.blocked ) {
+ hideOne(target, details.collapse);
}
};
- messaging.ask({ what: 'blockedRequests' }, blockedRequestsReceived);
- };
-
- // rhill 2014-07-01: Avoid useless work: only nodes which are element are
- // of interest at this point -- because it is common that a lot of plain
- // text nodes get added.
- var addNodeLists = function(nodeLists) {
- var elems = [];
- var i = nodeLists.length;
- var nodeList, j, node;
- while ( i-- ) {
- nodeList = nodeLists[i];
- j = nodeList.length;
- while ( j-- ) {
- node = nodeList[j];
- if ( node.querySelectorAll ) {
- elems.push(node);
- }
- }
- }
- if ( elems.length ) {
- processElements(elems);
- }
- };
-
- var onBlockedRequestsReceived = function(details) {
- hideMany(document.querySelectorAll('img,iframe'), details);
- };
- messaging.ask({ what: 'blockedRequests' }, onBlockedRequestsReceived);
-
- return {
- addNodeLists: addNodeLists
+ messaging.ask({ what: 'blockedRequest', url: target.src }, onAnswerReceived);
};
+ document.addEventListener('load', onResourceLoaded, true);
+ document.addEventListener('error', onResourceLoaded, true);
})();
/******************************************************************************/
-// rhill 2013-11-09: Weird... This code is executed from µBlock
-// context first time extension is launched. Avoid this.
-// TODO: Investigate if this was a fluke or if it can really happen.
-// I suspect this could only happen when I was using chrome.tabs.executeScript(),
-// because now a delarative content script is used, along with "http{s}" URL
-// pattern matching.
-
-// console.debug('µBlock> window.location.href = "%s"', window.location.href);
-
-if ( /^https?:\/\/./.test(window.location.href) === false ) {
- console.debug("Huh?");
- return;
-}
-
-/******************************************************************************/
-
// Observe changes in the DOM
var mutationObservedHandler = function(mutations) {
@@ -511,7 +468,6 @@ var mutationObservedHandler = function(mutations) {
}
if ( nodeLists.length ) {
cosmeticFiltering.processNodeLists(nodeLists);
- blockedElementHider.addNodeLists(nodeLists);
}
};