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:
parent
4593535a86
commit
1ca285f8bd
@ -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);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user