1
0
mirror of https://github.com/gorhill/uBlock.git synced 2024-10-06 09:37:12 +02:00

this is for #84, #70, #53, #36

This commit is contained in:
gorhill 2014-07-20 15:00:26 -04:00
parent 8692621534
commit b82742d126
8 changed files with 333 additions and 167 deletions

View File

@ -47,7 +47,7 @@ google.*##.mw > #rcnt > #center_col > #taw > #tvcap > .c
# https://github.com/gorhill/uBlock/issues/70 # https://github.com/gorhill/uBlock/issues/70
# Workaround for issue 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 # Seen on mediafire.com
||torconpro.com^ ||torconpro.com^

View File

@ -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

View File

@ -122,7 +122,7 @@ var renderBlacklists = function() {
'<li class="listDetails">', '<li class="listDetails">',
'<input type="checkbox" {{checked}}>', '<input type="checkbox" {{checked}}>',
'&thinsp;', '&thinsp;',
'<a href="{{URL}}" type="text/plain">', '<a href="asset-viewer.html?url={{URL}}" type="text/plain">',
'{{name}}', '{{name}}',
'</a>', '</a>',
': ', ': ',

View File

@ -1008,25 +1008,41 @@ FilterBucket.prototype.match = function(url, tokenBeg) {
/******************************************************************************/ /******************************************************************************/
var FilterContainer = function() { var FilterContainer = function() {
this.categories = {}; this.reAnyToken = /[%0-9a-z]+/g;
this.duplicates = {}; this.buckets = new Array(8);
this.url = ''; this.blockedAnyPartyHostnames = new µBlock.LiquidDict();
this.tokenBeg = 0; this.blocked3rdPartyHostnames = new µBlock.LiquidDict();
this.tokenEnd = 0;
this.filterParser = new FilterParser(); 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.processedFilterCount = 0;
this.acceptedCount = 0; this.acceptedCount = 0;
this.allowFilterCount = 0; this.allowFilterCount = 0;
this.blockFilterCount = 0; this.blockFilterCount = 0;
this.duplicateCount = 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 FilterContainer.prototype.freeze = function() {
this.reAnyToken = /[%0-9a-z]+/g; //histogram('allFilters', this.categories);
this.buckets = new Array(8); 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.matchTokens = function(url) {
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;
var re = this.reAnyToken; var re = this.reAnyToken;
var matches, beg, token; var matches, beg, token;
var buckets = this.buckets; 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(); // adbProfiler.countUrl();
if ( this.frozen !== true ) {
return false;
}
// https://github.com/gorhill/httpswitchboard/issues/239 // https://github.com/gorhill/httpswitchboard/issues/239
// Convert url to lower case: // Convert url to lower case:
// `match-case` option not supported, but then, I saw only one // `match-case` option not supported, but then, I saw only one
// occurrence of it in all the supported lists (bulgaria list). // occurrence of it in all the supported lists (bulgaria list).
this.url = url.toLowerCase(); var url = requestURL.toLowerCase();
// The logic here is simple: // 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[5] = categories[this.makeCategoryKey(BlockAction | type | party)];
buckets[6] = categories[this.makeCategoryKey(BlockOneParty | type | domainParty)]; buckets[6] = categories[this.makeCategoryKey(BlockOneParty | type | domainParty)];
buckets[7] = categories[this.makeCategoryKey(BlockOtherParties | type)]; 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 // 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[5] = categories[this.makeCategoryKey(AllowAction | type | party)];
buckets[6] = categories[this.makeCategoryKey(AllowOneParty | type | domainParty)]; buckets[6] = categories[this.makeCategoryKey(AllowOneParty | type | domainParty)];
buckets[7] = categories[this.makeCategoryKey(AllowOtherParties | type | domainParty)]; buckets[7] = categories[this.makeCategoryKey(AllowOtherParties | type | domainParty)];
var ar = this.matchTokens(); var ar = this.matchTokens(url);
if ( ar !== false ) { if ( ar !== false ) {
return '@@' + ar; return '@@' + ar;
} }

View File

@ -272,6 +272,7 @@ var FilterContainer = function() {
FilterContainer.prototype.reset = function() { FilterContainer.prototype.reset = function() {
this.filterParser.reset(); this.filterParser.reset();
this.frozen = false;
this.acceptedCount = 0; this.acceptedCount = 0;
this.processedCount = 0; this.processedCount = 0;
this.genericFilters = {}; this.genericFilters = {};
@ -399,6 +400,7 @@ FilterContainer.prototype.freeze = function() {
// console.debug('Number of duplicate cosmetic filters skipped:', this.duplicateCount); // console.debug('Number of duplicate cosmetic filters skipped:', this.duplicateCount);
this.duplicates = {}; 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 accepted', this.acceptedCount);
//console.log('µBlock> adp-hide-filters.js: %d filters processed', this.processedCount); //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) { FilterContainer.prototype.retrieveGenericSelectors = function(tabHostname, request) {
if ( this.frozen !== true ) {
return;
}
if ( !tabHostname || µb.getCosmeticFilteringSwitch(tabHostname) !== true ) { if ( !tabHostname || µb.getCosmeticFilteringSwitch(tabHostname) !== true ) {
return; return;
} }
@ -669,6 +674,9 @@ FilterContainer.prototype.retrieveGenericSelectors = function(tabHostname, reque
/******************************************************************************/ /******************************************************************************/
FilterContainer.prototype.retrieveDomainSelectors = function(tabHostname, request) { FilterContainer.prototype.retrieveDomainSelectors = function(tabHostname, request) {
if ( this.frozen !== true ) {
return;
}
if ( !tabHostname || µb.getCosmeticFilteringSwitch(tabHostname) !== true ) { if ( !tabHostname || µb.getCosmeticFilteringSwitch(tabHostname) !== true ) {
return; return;
} }

View File

@ -62,8 +62,9 @@ File system structure:
var fileSystem; var fileSystem;
var fileSystemQuota = 40 * 1024 * 1024; var fileSystemQuota = 40 * 1024 * 1024;
var remoteRoot = µBlock.projectServerRoot; var repositoryRoot = µBlock.projectServerRoot;
var nullFunc = function() { }; var nullFunc = function() { };
var thirdpartyHomeURLs = null;
/******************************************************************************/ /******************************************************************************/
@ -71,6 +72,7 @@ var getTextFileFromURL = function(url, onLoad, onError) {
// console.log('µBlock> getTextFileFromURL("%s"):', url); // console.log('µBlock> getTextFileFromURL("%s"):', url);
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
xhr.responseType = 'text'; xhr.responseType = 'text';
xhr.timeout = 15000;
xhr.onload = onLoad; xhr.onload = onLoad;
xhr.onerror = onError; xhr.onerror = onError;
xhr.ontimeout = onError; xhr.ontimeout = onError;
@ -268,7 +270,7 @@ var readRemoteFile = function(path, callback) {
// 'ublock=...' is to skip browser cache // 'ublock=...' is to skip browser cache
getTextFileFromURL( getTextFileFromURL(
remoteRoot + path + '?ublock=' + Date.now(), repositoryRoot + path + '?ublock=' + Date.now(),
onRemoteFileLoaded, onRemoteFileLoaded,
onRemoteFileError onRemoteFileError
); );
@ -346,8 +348,10 @@ var writeLocalFile = function(path, content, callback) {
var updateFromRemote = function(details, callback) { var updateFromRemote = function(details, callback) {
// 'ublock=...' is to skip browser cache // 'ublock=...' is to skip browser cache
var remoteURL = remoteRoot + details.path + '?ublock=' + Date.now();
var targetPath = details.path; 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 targetMd5 = details.md5 || '';
var reportBackError = function() { var reportBackError = function() {
@ -360,30 +364,106 @@ var updateFromRemote = function(details, callback) {
var onRemoteFileLoaded = function() { var onRemoteFileLoaded = function() {
this.onload = this.onerror = null; this.onload = this.onerror = null;
if ( typeof this.responseText !== 'string' ) { if ( typeof this.responseText !== 'string' ) {
console.error('µBlock> updateFromRemote("%s") / onRemoteFileLoaded(): no response', remoteURL); console.error('µBlock> updateFromRemote("%s") / onRemoteFileLoaded(): no response', repositoryURL);
reportBackError(); reportBackError();
return; return;
} }
if ( YaMD5.hashStr(this.responseText) !== targetMd5 ) { if ( targetMd5 !== '' && YaMD5.hashStr(this.responseText) !== targetMd5 ) {
console.error('µBlock> updateFromRemote("%s") / onRemoteFileLoaded(): bad md5 checksum', remoteURL); console.error('µBlock> updateFromRemote("%s") / onRemoteFileLoaded(): bad md5 checksum', repositoryURL);
reportBackError(); reportBackError();
return; return;
} }
// console.debug('µBlock> updateFromRemote("%s") / onRemoteFileLoaded()', remoteURL); // console.debug('µBlock> updateFromRemote("%s") / onRemoteFileLoaded()', repositoryURL);
writeLocalFile(targetPath, this.responseText, callback); writeLocalFile(targetPath, this.responseText, callback);
}; };
var onRemoteFileError = function(ev) { var onRemoteFileError = function(ev) {
this.onload = this.onerror = null; this.onload = this.onerror = null;
console.error('µBlock> updateFromRemote() / onRemoteFileError("%s"):', remoteURL, this.statusText); console.error('µBlock> updateFromRemote() / onRemoteFileError("%s"):', repositoryURL, this.statusText);
reportBackError(); reportBackError();
}; };
getTextFileFromURL( var onHomeFileLoaded = function() {
remoteURL, this.onload = this.onerror = null;
onRemoteFileLoaded, if ( typeof this.responseText !== 'string' ) {
onRemoteFileError 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();
}
}; };
/******************************************************************************/ /******************************************************************************/

View File

@ -43,7 +43,7 @@ return {
allowedRequestCount: 0 allowedRequestCount: 0
}, },
updateAssetsEvery: 4 * 24 * 60 * 60 * 1000, updateAssetsEvery: 2 * 24 * 60 * 60 * 1000,
projectServerRoot: 'https://raw2.github.com/gorhill/ublock/master/', projectServerRoot: 'https://raw2.github.com/gorhill/ublock/master/',
userFiltersPath: 'assets/user/filters.txt', userFiltersPath: 'assets/user/filters.txt',

View File

@ -146,9 +146,8 @@ var cosmeticFiltering = (function() {
injectedSelectors[exceptions[i]] = true; injectedSelectors[exceptions[i]] = true;
} }
} }
idsFromNodeList(document.querySelectorAll('[id]'));
// TODO: evaluate merging into a single loop classesFromNodeList(document.querySelectorAll('[class]'));
selectorsFromNodeList(document.querySelectorAll('*[class],*[id]'));
retrieveGenericSelectors(); retrieveGenericSelectors();
}; };
@ -302,42 +301,47 @@ var cosmeticFiltering = (function() {
} }
}; };
// TODO: split back into to specialized functions as it was before. Too var idsFromNodeList = function(nodes) {
// many code paths creeped back, I thought I could get rid of most.
var selectorsFromNodeList = function(nodes) {
if ( !nodes || !nodes.length ) { if ( !nodes || !nodes.length ) {
return; return;
} }
if ( idSelectors === null ) { if ( idSelectors === null ) {
idSelectors = []; 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 ) { if ( classSelectors === null ) {
classSelectors = {}; classSelectors = {};
} }
var qq = queriedSelectors; var qq = queriedSelectors;
var cc = classSelectors; var cc = classSelectors;
var ii = idSelectors; var node, v, vv, j;
var node, v, classNames, j;
var i = nodes.length; var i = nodes.length;
while ( i-- ) { while ( i-- ) {
node = nodes[i]; node = nodes[i];
if ( node.nodeType !== 1 ) { if ( node.nodeType !== 1 ) { continue; }
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;
}
}
// class // class
v = nodes[i].className; v = nodes[i].className;
// it could be an SVGAnimatedString... // it could be an SVGAnimatedString...
@ -353,10 +357,10 @@ var cosmeticFiltering = (function() {
continue; continue;
} }
// many classes // many classes
classNames = v.trim().split(/\s+/); vv = v.trim().split(' ');
j = classNames.length; j = vv.length;
while ( j-- ) { while ( j-- ) {
v = classNames[j]; v = vv[j].trim();
if ( v === '' ) { continue; } if ( v === '' ) { continue; }
v = '.' + v; v = '.' + v;
if ( qq[v] ) { continue; } if ( qq[v] ) { continue; }
@ -371,12 +375,14 @@ var cosmeticFiltering = (function() {
var nodeList, j, node; var nodeList, j, node;
while ( i-- ) { while ( i-- ) {
nodeList = nodeLists[i]; nodeList = nodeLists[i];
selectorsFromNodeList(nodeList); idsFromNodeList(nodeList);
classesFromNodeList(nodeList);
j = nodeList.length; j = nodeList.length;
while ( j-- ) { while ( j-- ) {
node = nodeList[j]; node = nodeList[j];
if ( node.querySelectorAll ) { if ( typeof node.querySelectorAll === 'function' ) {
selectorsFromNodeList(node.querySelectorAll('*[id],*[class]')); idsFromNodeList(node.querySelectorAll('[id]'));
classesFromNodeList(node.querySelectorAll('[class]'));
} }
} }
} }
@ -394,7 +400,7 @@ var cosmeticFiltering = (function() {
// https://github.com/gorhill/uBlock/issues/7 // https://github.com/gorhill/uBlock/issues/7
var blockedElementHider = (function() { (function() {
var hideOne = function(elem, collapse) { var hideOne = function(elem, collapse) {
// If `!important` is not there, going back using history will likely // If `!important` is not there, going back using history will likely
// cause the hidden element to re-appear. // cause the hidden element to re-appear.
@ -404,21 +410,9 @@ var blockedElementHider = (function() {
} }
}; };
var observeOne = function(elem) { // First pass
var onComplete = function() { messaging.ask({ what: 'blockedRequests' }, function(details) {
var elem = this; var elems = document.querySelectorAll('img,iframe');
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) {
var blockedRequests = details.blockedRequests; var blockedRequests = details.blockedRequests;
var collapse = details.collapse; var collapse = details.collapse;
var i = elems.length; var i = elems.length;
@ -426,78 +420,41 @@ var blockedElementHider = (function() {
while ( i-- ) { while ( i-- ) {
elem = elems[i]; elem = elems[i];
src = elem.src; src = elem.src;
if ( typeof src !== 'string' ) { if ( typeof src !== 'string' || src === '' ) {
continue; continue;
} }
if ( src === '' ) { if ( blockedRequests[src] ) {
observeOne(elem);
} else if ( blockedRequests[src] ) {
hideOne(elem, collapse); hideOne(elem, collapse);
} }
} }
}; });
var processElements = function(elems) { // Listeners to mop up whatever is otherwise missed:
var blockedRequestsReceived = function(details) { // - Future requests not blocked yet
hideMany(elems, details); // - Elements dynamically added to the page
var i = elems.length; // - Elements which resource URL changes
while ( i-- ) { var onResourceLoaded = function(ev) {
hideMany(elems[i].querySelectorAll('img,iframe'), details); 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); messaging.ask({ what: 'blockedRequest', url: target.src }, onAnswerReceived);
};
// 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
}; };
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 // Observe changes in the DOM
var mutationObservedHandler = function(mutations) { var mutationObservedHandler = function(mutations) {
@ -511,7 +468,6 @@ var mutationObservedHandler = function(mutations) {
} }
if ( nodeLists.length ) { if ( nodeLists.length ) {
cosmeticFiltering.processNodeLists(nodeLists); cosmeticFiltering.processNodeLists(nodeLists);
blockedElementHider.addNodeLists(nodeLists);
} }
}; };