1
0
mirror of https://github.com/gorhill/uBlock.git synced 2024-11-06 19:02:30 +01:00

add new cosmetic operator csstext()

This commit is contained in:
gorhill 2016-08-03 08:06:51 -04:00
parent 4593535a86
commit 1ca285f8bd
2 changed files with 70 additions and 71 deletions

View File

@ -117,7 +117,7 @@ var jobQueue = [
{ t: 'css-csel', _0: [] } // to manually hide (not incremental) { t: 'css-csel', _0: [] } // to manually hide (not incremental)
]; ];
var reParserEx = /^(.*?(:has\(.+?\)|:xpath\(.+?\))?)(:style\(.+?\))?$/; var reParserEx = /:(?:csstext|has|style|xpath)\(.+?\)$/;
var allExceptions = Object.create(null); var allExceptions = Object.create(null);
var allSelectors = Object.create(null); var allSelectors = Object.create(null);
@ -172,58 +172,45 @@ var domFilterer = {
// 2 = simple css selectors/hide // 2 = simple css selectors/hide
// 3 = complex css selectors/hide // 3 = complex css selectors/hide
// Custom jobs: // Custom jobs:
// csstext/hide
// has/hide // has/hide
// xpath/hide // xpath/hide
// has/inline css declaration (not supported yet)
// xpath/inline css declaration (not supported yet)
addSelector: function(s) { addSelector: function(s) {
if ( allSelectors[s] || allExceptions[s] ) { if ( allSelectors[s] || allExceptions[s] ) {
return this; return this;
} }
allSelectors[s] = true; allSelectors[s] = true;
var parts = reParserEx.exec(s); var sel0 = s, sel1 = '';
if ( parts === null ) { return this; } if ( s.charCodeAt(s.length - 1) === 0x29 ) {
var sel0 = parts[1], sel1 = parts[2], style = parts[3]; var parts = reParserEx.exec(s);
if ( parts !== null ) {
// Hide sel1 = parts[0];
if ( style === undefined ) {
if ( sel1 === undefined ) {
this.job0._0.push(sel0);
if ( sel0.indexOf(' ') === -1 ) {
this.job2._0.push(sel0);
this.job2._1 = undefined;
} else {
this.job3._0.push(sel0);
this.job3._1 = undefined;
}
return this;
} }
if ( sel1.lastIndexOf(':has', 0) === 0 ) { }
this.jobQueue.push({ t: 'has-hide', raw: s, _0: sel0.slice(0, sel0.length - sel1.length), _1: sel1.slice(5, -1) }); if ( sel1 === '' ) {
return this; this.job0._0.push(sel0);
if ( sel0.indexOf(' ') === -1 ) {
this.job2._0.push(sel0);
this.job2._1 = undefined;
} else {
this.job3._0.push(sel0);
this.job3._1 = undefined;
} }
if ( sel1.lastIndexOf(':xpath',0) === 0 ) {
this.jobQueue.push({ t: 'xpath-hide', raw: s, _0: sel1.slice(7, -1) });
return this;
}
// ignore unknown selector
return this; return this;
} }
sel0 = sel0.slice(0, sel0.length - sel1.length);
// Modify style if ( sel1.lastIndexOf(':csstext', 0) === 0 ) {
if ( sel1 === undefined ) { this.jobQueue.push({ t: 'csstext-hide', raw: s, _0: sel0, _1: sel1.slice(9, -1) });
this.job1._0.push(sel0 + ' { ' + style.slice(7, -1) + ' }'); } else if ( sel1.lastIndexOf(':has', 0) === 0 ) {
this.jobQueue.push({ t: 'has-hide', raw: s, _0: sel0, _1: sel1.slice(5, -1) });
} else if ( sel1.lastIndexOf(':style',0) === 0 ) {
this.job1._0.push(sel0 + ' { ' + sel1.slice(7, -1) + ' }');
this.job1._1 = undefined; this.job1._1 = undefined;
return this; } else if ( sel1.lastIndexOf(':xpath',0) === 0 ) {
} this.jobQueue.push({ t: 'xpath-hide', raw: s, _0: sel1.slice(7, -1) });
if ( sel1.lastIndexOf(':has', 0) === 0 ) {
return this;
}
if ( sel1.lastIndexOf(':xpath',0) === 0 ) {
if ( sel0 !== sel1 ) { return this; }
return this;
} }
return this;
}, },
addSelectors: function(aa) { addSelectors: function(aa) {
@ -238,7 +225,7 @@ var domFilterer = {
head = doc.head, head = doc.head,
newParent = head || html; newParent = head || html;
if ( newParent === null ) { if ( newParent === null ) {
return; return false;
} }
var styles = this.styleTags, var styles = this.styleTags,
style, oldParent, style, oldParent,
@ -266,6 +253,7 @@ var domFilterer = {
if ( mustCommit && commitIfNeeded ) { if ( mustCommit && commitIfNeeded ) {
this.commit(); this.commit();
} }
return mustCommit;
}, },
commit_: function() { commit_: function() {
@ -375,9 +363,7 @@ var domFilterer = {
if ( display !== '' && display !== 'none' ) { if ( display !== '' && display !== 'none' ) {
var styleAttr = node.getAttribute('style') || ''; var styleAttr = node.getAttribute('style') || '';
node[this.hiddenId] = node.hasAttribute('style') && styleAttr; node[this.hiddenId] = node.hasAttribute('style') && styleAttr;
if ( styleAttr !== '' ) { if ( styleAttr !== '' ) { styleAttr += '; '; }
styleAttr += '; ';
}
node.setAttribute('style', styleAttr + 'display: none !important;'); node.setAttribute('style', styleAttr + 'display: none !important;');
} }
if ( shadowId === undefined ) { if ( shadowId === undefined ) {
@ -425,6 +411,21 @@ var domFilterer = {
} }
}, },
runCSSTextJob: function(job, fn) {
var nodes = document.querySelectorAll(job._0),
i = nodes.length, node;
if ( i === 0 ) { return; }
if ( typeof job._1 === 'string' ) {
job._1 = new RegExp(job._1.replace(/\s*\*\s*/g, '.*?'));
}
while ( i-- ) {
node = nodes[i];
if ( job._1.test(window.getComputedStyle(node).cssText) ) {
fn(node, job);
}
}
},
runHasJob: function(job, fn) { runHasJob: function(job, fn) {
var nodes = document.querySelectorAll(job._0), var nodes = document.querySelectorAll(job._0),
i = nodes.length, node; i = nodes.length, node;
@ -456,18 +457,15 @@ var domFilterer = {
runJob: function(job, fn) { runJob: function(job, fn) {
switch ( job.t ) { switch ( job.t ) {
case 'csstext-hide':
this.runCSSTextJob(job, fn);
break;
case 'has-hide': case 'has-hide':
this.runHasJob(job, fn); this.runHasJob(job, fn);
break; break;
case 'xpath-hide': case 'xpath-hide':
this.runXpathJob(job, fn); this.runXpathJob(job, fn);
break; break;
case 'has-style':
// not supported yet
break;
case 'xpath-style':
// not supported yet
break;
} }
}, },
@ -1291,20 +1289,16 @@ skip-survey=false: survey-phase-1 => survey-phase-2 => survey-phase-3 => commit
}; };
// Added node lists will be cumulated here before being processed // Added node lists will be cumulated here before being processed
var addedNodeLists = []; var addedNodeLists = [],
var addedNodeListsTimer = null; addedNodeListsTimer = null,
var addedNodeListsTimerDelay = 0; removedNodeListsTimer = null,
var removedNodeListsTimer = null; removedNodesHandlerMissCount = 0,
var removedNodeListsTimerDelay = 5; collapser = domCollapser;
var collapser = domCollapser;
var addedNodesHandler = function() { var addedNodesHandler = function() {
vAPI.executionCost.start(); vAPI.executionCost.start();
addedNodeListsTimer = null; addedNodeListsTimer = null;
if ( addedNodeListsTimerDelay < 100 ) {
addedNodeListsTimerDelay += 10;
}
var iNodeList = addedNodeLists.length, var iNodeList = addedNodeLists.length,
nodeList, iNode, node; nodeList, iNode, node;
while ( iNodeList-- ) { while ( iNodeList-- ) {
@ -1341,13 +1335,12 @@ skip-survey=false: survey-phase-1 => survey-phase-2 => survey-phase-3 => commit
// https://github.com/gorhill/uBlock/issues/873 // https://github.com/gorhill/uBlock/issues/873
// This will ensure our style elements will stay in the DOM. // This will ensure our style elements will stay in the DOM.
var removedNodesHandler = function() { var removedNodesHandler = function() {
removedNodeListsTimer = null; if ( domFilterer.checkStyleTags(true) === false ) {
removedNodeListsTimerDelay *= 2; removedNodesHandlerMissCount += 1;
// Stop watching style tags after a while. }
if ( removedNodeListsTimerDelay > 1000 ) { if ( removedNodesHandlerMissCount < 16 ) {
removedNodeListsTimerDelay = 0; removedNodeListsTimer = null;
} }
domFilterer.checkStyleTags(true);
}; };
// https://github.com/chrisaljoudi/uBlock/issues/205 // https://github.com/chrisaljoudi/uBlock/issues/205
@ -1372,10 +1365,10 @@ skip-survey=false: survey-phase-1 => survey-phase-2 => survey-phase-3 => commit
} }
} }
if ( addedNodeLists.length !== 0 && addedNodeListsTimer === null ) { if ( addedNodeLists.length !== 0 && addedNodeListsTimer === null ) {
addedNodeListsTimer = vAPI.setTimeout(addedNodesHandler, addedNodeListsTimerDelay); addedNodeListsTimer = window.requestAnimationFrame(addedNodesHandler);
} }
if ( removedNodeListsTimerDelay !== 0 && removedNodeLists && removedNodeListsTimer === null ) { if ( removedNodeLists && removedNodeListsTimer === null ) {
removedNodeListsTimer = vAPI.setTimeout(removedNodesHandler, removedNodeListsTimerDelay); removedNodeListsTimer = window.requestAnimationFrame(removedNodesHandler);
} }
vAPI.executionCost.stop('domIsLoaded/domLayoutChanged'); vAPI.executionCost.stop('domIsLoaded/domLayoutChanged');
@ -1394,10 +1387,10 @@ skip-survey=false: survey-phase-1 => survey-phase-2 => survey-phase-3 => commit
vAPI.shutdown.add(function() { vAPI.shutdown.add(function() {
domLayoutObserver.disconnect(); domLayoutObserver.disconnect();
if ( addedNodeListsTimer !== null ) { if ( addedNodeListsTimer !== null ) {
clearTimeout(addedNodeListsTimer); window.cancelAnimationFrame(addedNodeListsTimer);
} }
if ( removedNodeListsTimer !== null ) { if ( removedNodeListsTimer !== null ) {
clearTimeout(removedNodeListsTimer); window.cancelAnimationFrame(removedNodeListsTimer);
} }
}); });
})(); })();

View File

@ -247,7 +247,7 @@ 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)\(.+?\)$/; this.reNeedHostname = /^(?:.+?:csstext|.+?:has|:xpath)\(.+?\)$/;
}; };
/******************************************************************************/ /******************************************************************************/
@ -754,6 +754,7 @@ FilterContainer.prototype.isValidSelector = (function() {
}; };
} }
var reCSSTextSelector = /^(.+?):csstext\((.+?)\)$/;
var reHasSelector = /^(.+?):has\((.+?)\)$/; var reHasSelector = /^(.+?):has\((.+?)\)$/;
var reXpathSelector = /^:xpath\((.+?)\)$/; var reXpathSelector = /^:xpath\((.+?)\)$/;
var reStyleSelector = /^(.+?):style\((.+?)\)$/; var reStyleSelector = /^(.+?):style\((.+?)\)$/;
@ -776,11 +777,16 @@ FilterContainer.prototype.isValidSelector = (function() {
// We reach this point very rarely. // We reach this point very rarely.
var matches; var matches;
// Custom `:csstext`-based filter?
matches = reCSSTextSelector.exec(s);
if ( matches !== null ) {
return isValidCSSSelector(matches[1]);
}
// Future `:has`-based filter? If so, validate both parts of the whole // Future `:has`-based filter? If so, validate both parts of the whole
// selector. // selector.
matches = reHasSelector.exec(s); matches = reHasSelector.exec(s);
if ( matches !== null ) { if ( matches !== null ) {
return this.isValidSelector(matches[1]) && this.isValidSelector(matches[2]); return isValidCSSSelector(matches[1]) && isValidCSSSelector(matches[2]);
} }
// Custom `:xpath`-based filter? // Custom `:xpath`-based filter?
matches = reXpathSelector.exec(s); matches = reXpathSelector.exec(s);