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