Skip to content

Commit

Permalink
Add procedural cosmetic operators remove() and upward()
Browse files Browse the repository at this point in the history
***

New procedural cosmetic operator: `:remove()`

Related issue:
- gorhill#2252

The purpose is to outright remove elements from the
DOM tree. Since `:remove()` is an "action" operator,
it must only be used as a trailing operator (just
like the `:style()` operator).

AdGuard's cosmetic filter syntax `{ remove: true; }`
will be converted to uBO's `:remove()` operator
internally.

***

New procedural cosmetic operator: `:upward(...)`

The purpose is to lookup an ancestor element.

When used with an integer argument, it is synonym of
`:nth-ancestor()`, which will be deprecated and which
will no longer be supported once no longer used in
mainstream filter lists.

Filter lists maintainers must only use `:upward(int)`
instead of `:nth-ancestor(int)` once the new operator
become available in all stable releases of uBO.

`:upward()` can also accept a CSS selector as argument,
in which case the nearest ancestor which matches the
CSS selector will be selected.
  • Loading branch information
gorhill committed Mar 7, 2020
1 parent 14ebfbe commit 72bb700
Show file tree
Hide file tree
Showing 11 changed files with 436 additions and 183 deletions.
150 changes: 150 additions & 0 deletions docs/tests/css-selector-based-cosmetic-filters.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>CSS selector-based cosmetic filters</title>
<style>
.filters {
font-family: monospace;
white-space: pre;
}
.tests {
align-items: flex-start;
display: flex;
flex-wrap: wrap;
}
.tile {
display: inline-flex;
flex-direction: column;
margin: 0 20px 10px 0;
min-width: 200px;
}
.tile div {
align-items: center;
color: white;
display: flex;
justify-content: center;
}
.tile > div {
height: 50px;
position: relative;
}
.tile > div > div {
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
}
.tile > code {
align-self: center;
}
.pass {
background-color: green;
}
.pass::before {
content: 'pass';
}
.fail {
background-color: red;
}
.fail::before {
content: 'fail';
}
.tests a, .tests b {
display: none;
}
.tests a::before {
opacity: 0;
}
.tests b::after {
opacity: 0;
}
.fail-pseudo::before {
align-items: center;
background-color: red;
content: 'fail';
display: flex;
height: 100%;
justify-content: center;
left: 0;
position: absolute;
top: 0;
width: 100%;
}
</style>
</head>
<body>
<h1>CSS selector-based cosmetic filters</h1>
<p><a href="./.">Back</a>
<br><br></p>
<h3>Filters</h3>
<div class="filters"><noscript>Enable JavaScript to see needed filters</noscript></div>

<h3>Tests</h3>
<div id="ccf" class="tests">

<div id="a1" class="tile">
<div class="pass"><div class="fail"><a><b></b></a></div></div>
<code class="generic">#ccf #a1 .fail</code>
</div>

<div id="a2" class="tile">
<div class="pass"><div class="fail"><a><b></b></a></div></div>
<code class="generic">#ccf #a2 .fail:not(.a2)</code>
</div>

<div id="a3" class="tile">
<div class="pass"><div class="fail"><a><b></b></a></div></div>
<code>#ccf #a3 .fail</code>
</div>

<div id="a4" class="tile">
<div class="pass"><div class="fail"><a><b></b></a></div></div>
<code>#ccf #a4 .fail:not(.a4)</code>
</div>

<div id="a5" class="tile">
<div class="pass"><div class="fail"><a><b></b></a></div></div>
<code>#ccf #a5 .fail:style(visibility: hidden)</code>
</div>

<div id="a6" class="tile">
<div class="pass"><div class="fail-pseudo"><a><b></b></a></div></div>
<code class="generic">#ccf #a6 .fail-pseudo::before</code>
</div>

<div id="a7" class="tile">
<div class="pass"><div class="fail-pseudo"><a><b></b></a></div></div>
<code>#ccf #a7 .fail-pseudo::before</code>
</div>

<div id="a8" class="tile">
<div class="pass"><div class="fail-pseudo"><a><b></b></a></div></div>
<code>#ccf #a8 .fail-pseudo::before:style(visibility: hidden)</code>
</div>

</div>

<script>
const hostname = self.location.hostname;
const filters = [];
const fragment = document.createDocumentFragment();
for ( const node of document.querySelectorAll('code') ) {
const div = document.createElement('div');
let text = '##' + node.textContent;
if ( node.classList.contains('generic') === false ) {
text = hostname + text;
}
div.textContent = text;
fragment.appendChild(div);
}
const parent = document.querySelector('.filters');
while ( parent.lastElementChild !== null ) {
parent.removeChild(parent.lastElementChild);
}
parent.appendChild(fragment);
</script>
</body>
</html>
8 changes: 5 additions & 3 deletions docs/tests/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@
<h1>uBlock Origin tests</h1>
<p>Some of the pages below are hosted on <a href="raw.githack.com">raw.githack.com</a> in order to ensure some of the secondary resources can be properly loaded (specifically, the WebAssembly modules, as they <a href="https://github.com/WebAssembly/design/blob/master/Web.md#webassemblyinstantiatestreaming">require to be loaded using same-origin policy</a>).</p>
<ul>
<li><a href="https://raw.githack.com/gorhill/uBlock/master/docs/tests/hntrie-test.html">HNTrie: tests</a>
<li><a href="https://raw.githack.com/gorhill/uBlock/master/docs/tests/hnset-benchmark.html">HNTrie, small (2) to medium (~1000) set: benchmarks</a>
<li><a href="https://raw.githack.com/gorhill/uBlock/master/docs/tests/hnbigset-benchmark.html">HNTrie, small (2) to large (40,000+) set: benchmarks</a>
<li><a href="css-selector-based-cosmetic-filters.html">CSS selector-based cosmetic filters</a>
<li><a href="procedural-cosmetic-filters.html">Procedural cosmetic filters</a>
<li><a href="procedural-html-filters.html">Procedural HTML filters</a>
<li><a href="scriptlet-injection-filters-1.html">Scriptlet injection filters / no-setTimeout-if</a>
<li>&nbsp;
<li><a href="https://raw.githack.com/gorhill/uBlock/master/docs/tests/hntrie-test.html">HNTrie: tests</a>
<li><a href="https://raw.githack.com/gorhill/uBlock/master/docs/tests/hnset-benchmark.html">HNTrie, small (2) to medium (~1000) set: benchmarks</a>
<li><a href="https://raw.githack.com/gorhill/uBlock/master/docs/tests/hnbigset-benchmark.html">HNTrie, small (2) to large (40,000+) set: benchmarks</a>
</ul>
</body>
</html>
15 changes: 15 additions & 0 deletions docs/tests/procedural-cosmetic-filters.html
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,21 @@ <h3>Tests</h3>
<code>#pcf #a17 .fail:has(~ a:has(b))</code>
</div>

<div id="a18" class="tile">
<div class="pass"><div class="fail"></div><a><b></b></a></div>
<code>#pcf #a18 .fail:remove()</code>
</div>

<div id="a19" class="tile">
<div class="pass"><div class="fail"><a><b></b></a></div></div>
<code>#pcf #a19 b:upward(2)</code>
</div>

<div id="a20" class="tile">
<div class="pass"><div class="fail"><a><b></b></a></div></div>
<code>#pcf #a20 b:upward(.fail)</code>
</div>

</div>

<script>
Expand Down
10 changes: 10 additions & 0 deletions docs/tests/procedural-html-filters.html
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,16 @@ <h3>Tests</h3>
<code>^#phf #a13 .fail:has(~ a:has(b))</code>
</div>

<div id="a14" class="tile">
<div class="pass"><div class="fail"><a><b></b></a></div></div>
<code>^#phf #a14 b:upward(2)</code>
</div>

<div id="a15" class="tile">
<div class="pass"><div class="fail"><a><b></b></a></div></div>
<code>^#phf #a15 b:upward(.fail)</code>
</div>

</div>

<script>
Expand Down
2 changes: 1 addition & 1 deletion platform/chromium/vapi-usercss.pseudo.js
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ vAPI.DOMFilterer = class {
Array.from(this.specificSimpleHide).join(',\n');
}
for ( const node of this.addedNodes ) {
if ( node[vAPI.matchesProp](this.specificSimpleHideAggregated) ) {
if ( node.matches(this.specificSimpleHideAggregated) ) {
this.hideNode(node);
}
const nodes = node.querySelectorAll(this.specificSimpleHideAggregated);
Expand Down
Loading

0 comments on commit 72bb700

Please sign in to comment.