mirror of
https://github.com/gorhill/uBlock.git
synced 2024-11-10 01:02:08 +01:00
Add procedural operator :shadow()
-- status is experimental
For internal use by filter list maintainers, do not open issues about this. Left undocumented on purpose. This new procedural operator allows to target elements in the shadow root of an element. subject:shadow(arg) - Description: Look-up matching elements inside the shadow root (if present) of _subject_. - Chainable: Yes - _subject_: Can be a plain or procedural selector. - _arg_: A plain or a procedural selector for the elements to target inside the shadowroot. Example: ..##body > div:not([class]):shadow(div[style]):has(:shadow([data-i18n^="#ad"]))
This commit is contained in:
parent
6f54317bdf
commit
52b46eb98b
3 changed files with 71 additions and 2 deletions
|
@ -341,6 +341,38 @@ class PSelectorOthersTask extends PSelectorTask {
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
class PSelectorShadowTask extends PSelectorTask {
|
||||
constructor(task) {
|
||||
super();
|
||||
this.selector = task[1];
|
||||
}
|
||||
transpose(node, output) {
|
||||
const root = this.openOrClosedShadowRoot(node);
|
||||
if ( root === null ) { return; }
|
||||
const nodes = root.querySelectorAll(this.selector);
|
||||
output.push(...nodes);
|
||||
}
|
||||
get openOrClosedShadowRoot() {
|
||||
if ( PSelectorShadowTask.openOrClosedShadowRoot !== undefined ) {
|
||||
return PSelectorShadowTask.openOrClosedShadowRoot;
|
||||
}
|
||||
if ( typeof chrome === 'object' && chrome !== null ) {
|
||||
if ( chrome.dom instanceof Object ) {
|
||||
if ( typeof chrome.dom.openOrClosedShadowRoot === 'function' ) {
|
||||
PSelectorShadowTask.openOrClosedShadowRoot =
|
||||
chrome.dom.openOrClosedShadowRoot;
|
||||
return PSelectorShadowTask.openOrClosedShadowRoot;
|
||||
}
|
||||
}
|
||||
}
|
||||
PSelectorShadowTask.openOrClosedShadowRoot = node =>
|
||||
node.openOrClosedShadowRoot || null;
|
||||
return PSelectorShadowTask.openOrClosedShadowRoot;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// https://github.com/AdguardTeam/ExtendedCss/issues/31#issuecomment-302391277
|
||||
// Prepend `:scope ` if needed.
|
||||
class PSelectorSpathTask extends PSelectorTask {
|
||||
|
@ -471,7 +503,6 @@ class PSelectorXpathTask extends PSelectorTask {
|
|||
|
||||
class PSelector {
|
||||
constructor(o) {
|
||||
this.raw = o.raw;
|
||||
this.selector = o.selector;
|
||||
this.tasks = [];
|
||||
const tasks = [];
|
||||
|
@ -542,6 +573,7 @@ PSelector.prototype.operatorToTaskMap = new Map([
|
|||
[ 'min-text-length', PSelectorMinTextLengthTask ],
|
||||
[ 'not', PSelectorIfNotTask ],
|
||||
[ 'others', PSelectorOthersTask ],
|
||||
[ 'shadow', PSelectorShadowTask ],
|
||||
[ 'spath', PSelectorSpathTask ],
|
||||
[ 'upward', PSelectorUpwardTask ],
|
||||
[ 'watch-attr', PSelectorWatchAttrs ],
|
||||
|
|
|
@ -242,6 +242,36 @@ class PSelectorOthersTask extends PSelectorTask {
|
|||
}
|
||||
}
|
||||
|
||||
class PSelectorShadowTask extends PSelectorTask {
|
||||
constructor(task) {
|
||||
super();
|
||||
this.selector = task[1];
|
||||
}
|
||||
transpose(node, output) {
|
||||
const root = this.openOrClosedShadowRoot(node);
|
||||
if ( root === null ) { return; }
|
||||
const nodes = root.querySelectorAll(this.selector);
|
||||
output.push(...nodes);
|
||||
}
|
||||
get openOrClosedShadowRoot() {
|
||||
if ( PSelectorShadowTask.openOrClosedShadowRoot !== undefined ) {
|
||||
return PSelectorShadowTask.openOrClosedShadowRoot;
|
||||
}
|
||||
if ( typeof chrome === 'object' && chrome !== null ) {
|
||||
if ( chrome.dom instanceof Object ) {
|
||||
if ( typeof chrome.dom.openOrClosedShadowRoot === 'function' ) {
|
||||
PSelectorShadowTask.openOrClosedShadowRoot =
|
||||
chrome.dom.openOrClosedShadowRoot;
|
||||
return PSelectorShadowTask.openOrClosedShadowRoot;
|
||||
}
|
||||
}
|
||||
}
|
||||
PSelectorShadowTask.openOrClosedShadowRoot = node =>
|
||||
node.openOrClosedShadowRoot || null;
|
||||
return PSelectorShadowTask.openOrClosedShadowRoot;
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/AdguardTeam/ExtendedCss/issues/31#issuecomment-302391277
|
||||
// Prepend `:scope ` if needed.
|
||||
class PSelectorSpathTask extends PSelectorTask {
|
||||
|
@ -366,7 +396,6 @@ class PSelectorXpathTask extends PSelectorTask {
|
|||
|
||||
class PSelector {
|
||||
constructor(o) {
|
||||
this.raw = o.raw;
|
||||
this.selector = o.selector;
|
||||
this.tasks = [];
|
||||
const tasks = [];
|
||||
|
@ -437,6 +466,7 @@ PSelector.prototype.operatorToTaskMap = new Map([
|
|||
[ 'min-text-length', PSelectorMinTextLengthTask ],
|
||||
[ 'not', PSelectorIfNotTask ],
|
||||
[ 'others', PSelectorOthersTask ],
|
||||
[ 'shadow', PSelectorShadowTask ],
|
||||
[ 'spath', PSelectorSpathTask ],
|
||||
[ 'upward', PSelectorUpwardTask ],
|
||||
[ 'watch-attr', PSelectorWatchAttrs ],
|
||||
|
|
|
@ -3208,6 +3208,7 @@ class ExtSelectorCompiler {
|
|||
'matches-path',
|
||||
'min-text-length',
|
||||
'others',
|
||||
'shadow',
|
||||
'upward',
|
||||
'watch-attr',
|
||||
'xpath',
|
||||
|
@ -3862,6 +3863,8 @@ class ExtSelectorCompiler {
|
|||
return this.compileText(arg);
|
||||
case 'remove-class':
|
||||
return this.compileText(arg);
|
||||
case 'shadow':
|
||||
return this.compileSelector(arg);
|
||||
case 'style':
|
||||
return this.compileStyleProperties(arg);
|
||||
case 'upward':
|
||||
|
@ -3999,6 +4002,10 @@ class ExtSelectorCompiler {
|
|||
compileUpwardArgument(s) {
|
||||
const i = this.compileInteger(s, 1, 256);
|
||||
if ( i !== undefined ) { return i; }
|
||||
return this.compilePlainSelector(s);
|
||||
}
|
||||
|
||||
compilePlainSelector(s) {
|
||||
const parts = this.astFromRaw(s, 'selectorList' );
|
||||
if ( this.astIsValidSelectorList(parts) !== true ) { return; }
|
||||
if ( this.astHasType(parts, 'ProceduralSelector') ) { return; }
|
||||
|
|
Loading…
Reference in a new issue