From d043f54a32ad646cc2c17afc81d1034d6962c674 Mon Sep 17 00:00:00 2001 From: gorhill Date: Fri, 4 Jul 2014 16:47:34 -0400 Subject: [PATCH] this fixes #41 --- js/abp-hide-filters.js | 50 ++++++++++++++++++++++++++---- js/contentscript-end.js | 68 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 105 insertions(+), 13 deletions(-) diff --git a/js/abp-hide-filters.js b/js/abp-hide-filters.js index d4615f2f8..339ac3be4 100644 --- a/js/abp-hide-filters.js +++ b/js/abp-hide-filters.js @@ -251,7 +251,11 @@ var FilterContainer = function() { this.processedCount = 0; this.filters = {}; this.hideUnfiltered = []; + this.hideLowGenerics = {}; + this.hideHighGenerics = []; this.donthideUnfiltered = []; + this.donthideLowGenerics = {}; + this.donthideHighGenerics = []; this.rejected = []; }; @@ -265,7 +269,11 @@ FilterContainer.prototype.reset = function() { this.processedCount = 0; this.filters = {}; this.hideUnfiltered = []; + this.hideLowGenerics = {}; + this.hideHighGenerics = []; this.donthideUnfiltered = []; + this.donthideLowGenerics = {}; + this.donthideHighGenerics = []; this.rejected = []; }; @@ -316,7 +324,29 @@ FilterContainer.prototype.add = function(s) { /******************************************************************************/ -FilterContainer.prototype.chunkify = function(selectors) { +FilterContainer.prototype.freezeGenerics = function(what) { + var selectors = this[what + 'Unfiltered']; + //console.log('%d highly generic selectors:\n', selectors.length, selectors.sort().join('\n')); + + // ["title"] and ["alt"] will be sorted out manually, these are the most + // common generic selectors, aka "low generics". The rest will be put in + // the high genericity bin. + var lowGenerics = {}; + var lowGenericCount = 0; + var re = /^(([a-z]*)\[(alt|title)="([^"]+)"\])$/; + var i = selectors.length; + var selector, matches; + while ( i-- ) { + selector = selectors[i]; + matches = re.exec(selector); + if ( !matches ) { + continue; + } + lowGenerics[matches[1]] = true; + lowGenericCount++; + selectors.splice(i, 1); + } + // Chunksize is a compromise between number of selectors per chunk (the // number of selectors querySelector() will have to deal with), and the // number of chunks (the number of times querySelector() will have to @@ -334,14 +364,18 @@ FilterContainer.prototype.chunkify = function(selectors) { } chunkified.push(chunk.join(',')); } - return chunkified; + + this[what + 'LowGenerics'] = lowGenerics; + this[what + 'LowGenericCount'] = lowGenericCount; + this[what + 'HighGenerics'] = chunkified; + this[what + 'Unfiltered'] = []; }; /******************************************************************************/ FilterContainer.prototype.freeze = function() { - this.hideUnfiltered = this.chunkify(this.hideUnfiltered); - this.donthideUnfiltered = this.chunkify(this.donthideUnfiltered); + this.freezeGenerics('hide'); + this.freezeGenerics('donthide'); this.filterParser.reset(); @@ -582,8 +616,12 @@ FilterContainer.prototype.retrieveGenericSelectors = function(tabHostname, reque var r = { hide: [], donthide: [], - hideUnfiltered: this.hideUnfiltered, - donthideUnfiltered: this.donthideUnfiltered + hideLowGenerics: this.hideLowGenerics, + hideLowGenericCount: this.hideLowGenericCount, + hideHighGenerics: this.hideHighGenerics, + donthideLowGenerics: this.donthideLowGenerics, + donthideLowGenericCount: this.donthideLowGenericCount, + donthideHighGenerics: this.donthideHighGenerics }; var hash, bucket; diff --git a/js/contentscript-end.js b/js/contentscript-end.js index 726c8e7db..d92d33434 100644 --- a/js/contentscript-end.js +++ b/js/contentscript-end.js @@ -177,7 +177,8 @@ var cosmeticFiltering = (function() { return; } var styleText = []; - filterUnfiltered(selectors.hideUnfiltered, selectors.hide); + filterLowGenerics(selectors, 'hide'); + filterHighGenerics(selectors, 'hide'); reduce(selectors.hide, injectedSelectors); if ( selectors.hide.length ) { var hideStyleText = '{{hideSelectors}} {display:none !important;}' @@ -186,7 +187,8 @@ var cosmeticFiltering = (function() { applyCSS(selectors.hide, 'display', 'none'); //console.debug('µBlock> generic cosmetic filters: injecting %d CSS rules:', selectors.hide.length, hideStyleText); } - filterUnfiltered(selectors.donthideUnfiltered, selectors.donthide); + filterLowGenerics(selectors, 'donthide'); + filterHighGenerics(selectors, 'donthide'); reduce(selectors.donthide, injectedSelectors); if ( selectors.donthide.length ) { var dontHideStyleText = '{{donthideSelectors}} {display:initial !important;}' @@ -216,16 +218,68 @@ var cosmeticFiltering = (function() { } }; - var filterUnfiltered = function(inSelectors, outSelectors) { - var i = inSelectors.length; + var filterTitleGeneric = function(generics, root, out) { + if ( !root.title.length ) { + return; + } + var selector = '[title="' + root.title + '"]'; + if ( generics[selector] && !injectedSelectors[selector] ) { + out.push(selector); + } + selector = root.tagName + selector; + if ( generics[selector] && !injectedSelectors[selector] ) { + out.push(selector); + } + }; + + var filterAltGeneric = function(generics, root, out) { + var alt = root.getAttribute('alt'); + if ( !alt || !alt.length ) { + return; + } + var selector = '[alt="' + root.title + '"]'; + if ( generics[selector] && !injectedSelectors[selector] ) { + out.push(selector); + } + selector = root.tagName + selector; + if ( generics[selector] && !injectedSelectors[selector] ) { + out.push(selector); + } + }; + + var filterLowGenerics = function(selectors, what) { + if ( selectors[what + 'LowGenericCount'] === 0 ) { + return; + } + var out = selectors[what]; + var generics = selectors[what + 'LowGenerics']; + var nodeList, iNode; + // Low generics: ["title"] + nodeList = document.querySelectorAll('[title]'); + iNode = nodeList.length; + while ( iNode-- ) { + filterTitleGeneric(generics, nodeList[iNode], out); + } + // Low generics: ["alt"] + nodeList = document.querySelectorAll('[alt]'); + iNode = nodeList.length; + while ( iNode-- ) { + filterAltGeneric(generics, nodeList[iNode], out); + } + }; + + var filterHighGenerics = function(selectors, what) { + var out = selectors[what]; + var generics = selectors[what + 'HighGenerics']; + var iGeneric = generics.length; var selector; - while ( i-- ) { - selector = inSelectors[i]; + while ( iGeneric-- ) { + selector = generics[iGeneric]; if ( injectedSelectors[selector] ) { continue; } if ( document.querySelector(selector) !== null ) { - outSelectors.push(selector); + out.push(selector); } } };