From 9dece3bd30bfa6ef35a6e58c37740adbd8482ab9 Mon Sep 17 00:00:00 2001 From: Raymond Hill Date: Sat, 21 Aug 2021 09:41:48 -0400 Subject: [PATCH] Add new procedural cosmetic operator: `:matches-path(...)` Related issue: - https://github.com/uBlockOrigin/uBlock-issues/issues/1690 New procedural operator: `:matches-path(...)` Description: this is a all-or-nothing passthrough operator, which on/off behavior is dictated by whether the argument match the path of the current location. The argument can be either plain text to be found at any position in the path, or a literal regex against which the path is tested. Whereas cosmetic filters can be made specific to whole domain, the new `:matches-path()` operator allows to further narrow the specificity according to the path of the current document lcoation. Typically this procedural operator is used as first operator in a procedural cosmetic filter, so as to ensure that no further matching work is performed should there be no match against the current path of the current document location. Example of usage: example.com##:matches-path(/shop) p Will hide all `p` elements when visiting `https://example.com/shop/stuff`, but not when visiting `https://example.com/` or any other page on `example.com` which has no instance of `/shop` in the path part of the URL. --- src/js/codemirror/ubo-static-filtering.js | 5 ++--- src/js/contentscript-extra.js | 16 ++++++++++++++++ src/js/static-filtering-parser.js | 4 ++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/js/codemirror/ubo-static-filtering.js b/src/js/codemirror/ubo-static-filtering.js index 70be0dc7f..d7a0e570a 100644 --- a/src/js/codemirror/ubo-static-filtering.js +++ b/src/js/codemirror/ubo-static-filtering.js @@ -417,9 +417,8 @@ const initHints = function() { const parser = new StaticFilteringParser(); const proceduralOperatorNames = new Map( - Array.from(parser.proceduralOperatorTokens).filter(item => { - return (item[1] & 0b01) !== 0; - }) + Array.from(parser.proceduralOperatorTokens) + .filter(item => (item[1] & 0b01) !== 0) ); const excludedHints = new Set([ 'genericblock', diff --git a/src/js/contentscript-extra.js b/src/js/contentscript-extra.js index 88afab0fc..22721cd54 100644 --- a/src/js/contentscript-extra.js +++ b/src/js/contentscript-extra.js @@ -102,6 +102,21 @@ const PSelectorMinTextLengthTask = class { } }; +const PSelectorMatchesPathTask = class { + constructor(task) { + let arg0 = task[1], arg1; + if ( Array.isArray(task[1]) ) { + arg1 = arg0[1]; arg0 = arg0[0]; + } + this.needle = new RegExp(arg0, arg1); + } + transpose(node, output) { + if ( this.needle.test(self.location.pathname) ) { + output.push(node); + } + } +}; + // https://github.com/AdguardTeam/ExtendedCss/issues/31#issuecomment-302391277 // Prepend `:scope ` if needed. const PSelectorSpathTask = class { @@ -232,6 +247,7 @@ const PSelector = class { [ ':matches-css', PSelectorMatchesCSSTask ], [ ':matches-css-after', PSelectorMatchesCSSAfterTask ], [ ':matches-css-before', PSelectorMatchesCSSBeforeTask ], + [ ':matches-path', PSelectorMatchesPathTask ], [ ':min-text-length', PSelectorMinTextLengthTask ], [ ':not', PSelectorIfNotTask ], [ ':nth-ancestor', PSelectorUpwardTask ], diff --git a/src/js/static-filtering-parser.js b/src/js/static-filtering-parser.js index 933567fe2..8722a299e 100644 --- a/src/js/static-filtering-parser.js +++ b/src/js/static-filtering-parser.js @@ -1618,6 +1618,7 @@ Parser.prototype.SelectorCompiler = class { case ':spath': raw.push(task[1]); break; + case ':matches-path': case ':min-text-length': case ':upward': case ':watch-attr': @@ -1793,6 +1794,8 @@ Parser.prototype.SelectorCompiler = class { return this.compileCSSDeclaration(args); case ':matches-css-before': return this.compileCSSDeclaration(args); + case ':matches-path': + return this.compileText(args); case ':min-text-length': return this.compileInteger(args); case ':not': @@ -1826,6 +1829,7 @@ Parser.prototype.proceduralOperatorTokens = new Map([ [ 'matches-css', 0b11 ], [ 'matches-css-after', 0b11 ], [ 'matches-css-before', 0b11 ], + [ 'matches-path', 0b01 ], [ 'min-text-length', 0b01 ], [ 'not', 0b01 ], [ 'nth-ancestor', 0b00 ],