mirror of
https://github.com/gorhill/uBlock.git
synced 2024-11-10 01:02:08 +01:00
Fix use of sibling-related CSS syntax at prefix position
Related discussion: - https://www.reddit.com/r/uBlockOrigin/comments/c6iem5/
This commit is contained in:
parent
3a8608b49a
commit
c1bdc123f2
5 changed files with 43 additions and 31 deletions
|
@ -163,8 +163,8 @@
|
|||
</div>
|
||||
|
||||
<div id="a17" class="tile">
|
||||
<div class="pass"><div class="fail"></div><a></a><b></b></div>
|
||||
<code>#pcf #a17 .fail:has(~ b)</code>
|
||||
<div class="pass"><div class="fail"></div><a><b></b></a></div>
|
||||
<code>#pcf #a17 .fail:has(~ a:has(b))</code>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
|
|
@ -128,18 +128,18 @@
|
|||
<code>^#phf #a11 .pass > a:has(b) + .fail:has(b)</code>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="a12" class="tile">
|
||||
<div class="pass"><div class="fail"></div><a></a><b></b></div>
|
||||
<code>^#phf #a12 .fail:has(+ a)</code>
|
||||
</div>
|
||||
|
||||
<div id="a13" class="tile">
|
||||
<div class="pass"><div class="fail"></div><a></a><b></b></div>
|
||||
<code>^#phf #a13 .fail:has(~ b)</code>
|
||||
<div class="pass"><div class="fail"></div><a><b></b></a></div>
|
||||
<code>^#phf #a13 .fail:has(~ a:has(b))</code>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const hostname = self.location.hostname;
|
||||
const filters = [];
|
||||
|
|
|
@ -660,10 +660,8 @@ vAPI.DOMFilterer = (function() {
|
|||
}
|
||||
prime(input) {
|
||||
const root = input || document;
|
||||
if ( this.selector !== '' ) {
|
||||
return root.querySelectorAll(this.selector);
|
||||
}
|
||||
return [ root ];
|
||||
if ( this.selector === '' ) { return [ root ]; }
|
||||
return root.querySelectorAll(this.selector);
|
||||
}
|
||||
exec(input) {
|
||||
let nodes = this.prime(input);
|
||||
|
|
|
@ -169,10 +169,8 @@
|
|||
}
|
||||
prime(input) {
|
||||
const root = input || docRegister;
|
||||
if ( this.selector !== '' ) {
|
||||
return root.querySelectorAll(this.selector);
|
||||
}
|
||||
return [ root ];
|
||||
if ( this.selector === '' ) { return [ root ]; }
|
||||
return root.querySelectorAll(this.selector);
|
||||
}
|
||||
exec(input) {
|
||||
if ( this.invalid ) { return []; }
|
||||
|
|
|
@ -68,9 +68,9 @@
|
|||
parsed.suffix = '';
|
||||
};
|
||||
|
||||
const isValidCSSSelector = (function() {
|
||||
var div = document.createElement('div'),
|
||||
matchesFn;
|
||||
const isValidCSSSelector = (( ) => {
|
||||
const div = document.createElement('div');
|
||||
let matchesFn;
|
||||
// Keep in mind:
|
||||
// https://github.com/gorhill/uBlock/issues/693
|
||||
// https://github.com/gorhill/uBlock/issues/1955
|
||||
|
@ -95,11 +95,11 @@
|
|||
}
|
||||
// Quick regex-based validation -- most cosmetic filters are of the
|
||||
// simple form and in such case a regex is much faster.
|
||||
var reSimple = /^[#.][\w-]+$/;
|
||||
return function(s) {
|
||||
const reSimple = /^[#.][\w-]+$/;
|
||||
return s => {
|
||||
if ( reSimple.test(s) ) { return true; }
|
||||
try {
|
||||
matchesFn(s + ', ' + s + ':not(#foo)');
|
||||
matchesFn(`${s}, ${s}:not(#foo)`);
|
||||
} catch (ex) {
|
||||
return false;
|
||||
}
|
||||
|
@ -152,7 +152,7 @@
|
|||
return hostnames;
|
||||
};
|
||||
|
||||
const compileProceduralSelector = (function() {
|
||||
const compileProceduralSelector = (( ) => {
|
||||
const reProceduralOperator = new RegExp([
|
||||
'^(?:',
|
||||
[
|
||||
|
@ -178,8 +178,9 @@
|
|||
|
||||
const reEatBackslashes = /\\([()])/g;
|
||||
const reEscapeRegex = /[.*+?^${}()|[\]\\]/g;
|
||||
const reNeedScope = /^\s*[+>~]/;
|
||||
const reIsDanglingSelector = /(?:[+>~]\s*|\s+)$/;
|
||||
const reNeedScope = /^\s*>/;
|
||||
const reIsDanglingSelector = /[+>~\s]\s*$/;
|
||||
const reIsSiblingSelector = /^\s*[+~]/;
|
||||
|
||||
const regexToRawValue = new Map();
|
||||
let lastProceduralSelector = '',
|
||||
|
@ -226,9 +227,9 @@
|
|||
|
||||
const compileConditionalSelector = function(s) {
|
||||
// https://github.com/AdguardTeam/ExtendedCss/issues/31#issuecomment-302391277
|
||||
// Prepend `:scope ` if needed.
|
||||
// Prepend `:scope ` if needed.
|
||||
if ( reNeedScope.test(s) ) {
|
||||
s = ':scope ' + s;
|
||||
s = `:scope ${s}`;
|
||||
}
|
||||
return compile(s);
|
||||
};
|
||||
|
@ -367,7 +368,7 @@
|
|||
return raw.join('');
|
||||
};
|
||||
|
||||
const compile = function(raw) {
|
||||
const compile = function(raw, root = false) {
|
||||
if ( raw === '' ) { return; }
|
||||
let prefix = '',
|
||||
tasks = [];
|
||||
|
@ -436,16 +437,31 @@
|
|||
// At least one task found: nothing should be left to parse.
|
||||
if ( tasks.length === 0 ) {
|
||||
prefix = raw;
|
||||
tasks = undefined;
|
||||
} else if ( opPrefixBeg < n ) {
|
||||
const spath = compileSpathExpression(raw.slice(opPrefixBeg));
|
||||
if ( spath === undefined ) { return; }
|
||||
tasks.push([ ':spath', spath ]);
|
||||
}
|
||||
// https://github.com/NanoAdblocker/NanoCore/issues/1#issuecomment-354394894
|
||||
// https://www.reddit.com/r/uBlockOrigin/comments/c6iem5/
|
||||
// Convert sibling-selector prefix into :spath operator, but
|
||||
// only if context is not the root.
|
||||
if ( prefix !== '' ) {
|
||||
if ( reIsDanglingSelector.test(prefix) ) { prefix += '*'; }
|
||||
if ( isValidCSSSelector(prefix) === false ) { return; }
|
||||
if ( isValidCSSSelector(prefix) === false ) {
|
||||
if (
|
||||
root ||
|
||||
reIsSiblingSelector.test(prefix) === false ||
|
||||
compileSpathExpression(prefix) === undefined
|
||||
) {
|
||||
return;
|
||||
}
|
||||
tasks.unshift([ ':spath', prefix ]);
|
||||
prefix = '';
|
||||
}
|
||||
}
|
||||
if ( tasks.length === 0 ) {
|
||||
tasks = undefined;
|
||||
}
|
||||
return { selector: prefix, tasks: tasks };
|
||||
};
|
||||
|
@ -455,7 +471,7 @@
|
|||
return lastProceduralSelectorCompiled;
|
||||
}
|
||||
lastProceduralSelector = raw;
|
||||
let compiled = compile(raw);
|
||||
let compiled = compile(raw, true);
|
||||
if ( compiled !== undefined ) {
|
||||
compiled.raw = decompile(compiled);
|
||||
compiled = JSON.stringify(compiled);
|
||||
|
@ -717,8 +733,8 @@
|
|||
}
|
||||
|
||||
// Procedural selector?
|
||||
let compiled;
|
||||
if ( (compiled = compileProceduralSelector(raw)) ) {
|
||||
const compiled = compileProceduralSelector(raw);
|
||||
if ( compiled !== undefined ) {
|
||||
return compiled;
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue