mirror of
https://github.com/gorhill/uBlock.git
synced 2024-11-07 11:22:38 +01:00
Add new procedural cosmetic filter operator: :matches-media()
Related issue: - https://github.com/uBlockOrigin/uBlock-issues/issues/2185 The argument must be a valid media query as documented on MDN, i.e. what appears between the `@media` at-rule and the first opening curly bracket (including the parentheses when required): - https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries Best practice: Use `:matches-media()` after plain CSS selectors, if any. Good: example.com###target-1 > .target-2:matches-media((min-width: 800px)) Bad (though this will still work): example.com##:matches-media((min-width: 800px)) #target-1 > .target-2 The reason for this is to keep the door open for a future optimisation where uBO could convert `:matches-media()`-based filters into CSS media rules injected declaratively in a user stylesheet.
This commit is contained in:
parent
deb5fea0ba
commit
40c315a107
@ -104,15 +104,22 @@ class PSelectorMatchesCSSBeforeTask extends PSelectorMatchesCSSTask {
|
|||||||
}
|
}
|
||||||
PSelectorMatchesCSSBeforeTask.prototype.pseudo = ':before';
|
PSelectorMatchesCSSBeforeTask.prototype.pseudo = ':before';
|
||||||
|
|
||||||
class PSelectorMinTextLengthTask extends PSelectorTask {
|
class PSelectorMatchesMediaTask extends PSelectorTask {
|
||||||
constructor(task) {
|
constructor(task) {
|
||||||
super();
|
super();
|
||||||
this.min = task[1];
|
this.mql = window.matchMedia(task[1]);
|
||||||
|
if ( this.mql.media === 'not all' ) { return; }
|
||||||
|
this.mql.addEventListener('change', ( ) => {
|
||||||
|
if ( typeof vAPI !== 'object' ) { return; }
|
||||||
|
if ( vAPI === null ) { return; }
|
||||||
|
const filterer = vAPI.domFilterer && vAPI.domFilterer.proceduralFilterer;
|
||||||
|
if ( filterer instanceof Object === false ) { return; }
|
||||||
|
filterer.onDOMChanged([ null ]);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
transpose(node, output) {
|
transpose(node, output) {
|
||||||
if ( node.textContent.length >= this.min ) {
|
if ( this.mql.matches === false ) { return; }
|
||||||
output.push(node);
|
output.push(node);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,6 +139,18 @@ class PSelectorMatchesPathTask extends PSelectorTask {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class PSelectorMinTextLengthTask extends PSelectorTask {
|
||||||
|
constructor(task) {
|
||||||
|
super();
|
||||||
|
this.min = task[1];
|
||||||
|
}
|
||||||
|
transpose(node, output) {
|
||||||
|
if ( node.textContent.length >= this.min ) {
|
||||||
|
output.push(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class PSelectorOthersTask extends PSelectorTask {
|
class PSelectorOthersTask extends PSelectorTask {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
@ -322,6 +341,7 @@ class PSelector {
|
|||||||
[ ':matches-css', PSelectorMatchesCSSTask ],
|
[ ':matches-css', PSelectorMatchesCSSTask ],
|
||||||
[ ':matches-css-after', PSelectorMatchesCSSAfterTask ],
|
[ ':matches-css-after', PSelectorMatchesCSSAfterTask ],
|
||||||
[ ':matches-css-before', PSelectorMatchesCSSBeforeTask ],
|
[ ':matches-css-before', PSelectorMatchesCSSBeforeTask ],
|
||||||
|
[ ':matches-media', PSelectorMatchesMediaTask ],
|
||||||
[ ':matches-path', PSelectorMatchesPathTask ],
|
[ ':matches-path', PSelectorMatchesPathTask ],
|
||||||
[ ':min-text-length', PSelectorMinTextLengthTask ],
|
[ ':min-text-length', PSelectorMinTextLengthTask ],
|
||||||
[ ':not', PSelectorIfNotTask ],
|
[ ':not', PSelectorIfNotTask ],
|
||||||
|
@ -1581,6 +1581,18 @@ Parser.prototype.SelectorCompiler = class {
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
compileMediaQuery(s) {
|
||||||
|
if ( typeof self !== 'object' ) { return; }
|
||||||
|
if ( self === null ) { return; }
|
||||||
|
if ( typeof self.matchMedia !== 'function' ) { return; }
|
||||||
|
try {
|
||||||
|
const mql = self.matchMedia(s);
|
||||||
|
if ( mql instanceof self.MediaQueryList === false ) { return; }
|
||||||
|
if ( mql.media !== 'not all' ) { return s; }
|
||||||
|
} catch(ex) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/341#issuecomment-447603588
|
// https://github.com/uBlockOrigin/uBlock-issues/issues/341#issuecomment-447603588
|
||||||
// Reject instances of :not() filters for which the argument is
|
// Reject instances of :not() filters for which the argument is
|
||||||
// a valid CSS selector, otherwise we would be adversely changing the
|
// a valid CSS selector, otherwise we would be adversely changing the
|
||||||
@ -1702,6 +1714,7 @@ Parser.prototype.SelectorCompiler = class {
|
|||||||
case ':spath':
|
case ':spath':
|
||||||
raw.push(task[1]);
|
raw.push(task[1]);
|
||||||
break;
|
break;
|
||||||
|
case ':matches-media':
|
||||||
case ':min-text-length':
|
case ':min-text-length':
|
||||||
case ':others':
|
case ':others':
|
||||||
case ':upward':
|
case ':upward':
|
||||||
@ -1878,6 +1891,8 @@ Parser.prototype.SelectorCompiler = class {
|
|||||||
return this.compileCSSDeclaration(args);
|
return this.compileCSSDeclaration(args);
|
||||||
case ':matches-css-before':
|
case ':matches-css-before':
|
||||||
return this.compileCSSDeclaration(args);
|
return this.compileCSSDeclaration(args);
|
||||||
|
case ':matches-media':
|
||||||
|
return this.compileMediaQuery(args);
|
||||||
case ':matches-path':
|
case ':matches-path':
|
||||||
return this.compileText(args);
|
return this.compileText(args);
|
||||||
case ':min-text-length':
|
case ':min-text-length':
|
||||||
@ -1918,7 +1933,8 @@ Parser.prototype.proceduralOperatorTokens = new Map([
|
|||||||
[ 'matches-css', 0b11 ],
|
[ 'matches-css', 0b11 ],
|
||||||
[ 'matches-css-after', 0b11 ],
|
[ 'matches-css-after', 0b11 ],
|
||||||
[ 'matches-css-before', 0b11 ],
|
[ 'matches-css-before', 0b11 ],
|
||||||
[ 'matches-path', 0b01 ],
|
[ 'matches-media', 0b11 ],
|
||||||
|
[ 'matches-path', 0b11 ],
|
||||||
[ 'min-text-length', 0b01 ],
|
[ 'min-text-length', 0b01 ],
|
||||||
[ 'not', 0b01 ],
|
[ 'not', 0b01 ],
|
||||||
[ 'nth-ancestor', 0b00 ],
|
[ 'nth-ancestor', 0b00 ],
|
||||||
|
Loading…
Reference in New Issue
Block a user