Skip to content

Commit

Permalink
Add ability to linger for remove-attr scriplet
Browse files Browse the repository at this point in the history
Related issue:
- uBlockOrigin/uBlock-issues#1445

A third (optional) argument has been added to `remove-attr`
scriptlet, which can be one or more space-separated tokens
dictating the behavior of the scriptlet:

`stay`: This tells the scriplet to stay and act on DOM
changes, whiĺe the default behavior is to act only once
when the document becomes interactive.

`complete`: This tells the scriplet to start acting only
when the document is complete, i.e. once all secondary
resources have been loaded, while the default is to start
acting when the document is interactive -- which is earlier
than when the document is complete.

Example:

    ...##+js(remove-attr, class, .j-mini-player, stay)

Related commits:
- gorhill/uBlock@0f330c7
- gorhill/uBlock@5fa8739

Co-authored-by: Raymond Hill <rhill@raymondhill.net>
  • Loading branch information
JustOff and gorhill committed Jan 25, 2021
1 parent 0043b4c commit bba2397
Showing 1 changed file with 51 additions and 14 deletions.
65 changes: 51 additions & 14 deletions assets/resources/resources.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2177,28 +2177,65 @@ no-fetch-if.js application/javascript

remove-attr.js application/javascript
(function() {
var attr = '{{1}}';
if ( attr === '' || attr === '{{1}}' ) { return; }
var attrs = attr.split(/\s*\|\s*/);
var selector = '{{2}}';
const token = '{{1}}';
if ( token === '' || token === '{{1}}' ) { return; }
const tokens = token.split(/\s*\|\s*/);
let selector = '{{2}}';
if ( selector === '' || selector === '{{2}}' ) {
selector = '[' + attrs.join('],[') + ']';
selector = `[${tokens.join('],[')}]`;
}
var rmattr = function(ev) {
if ( ev ) { window.removeEventListener(ev.type, rmattr, true); }
let behavior = '{{3}}';
let timer;
const rmattr = ( ) => {
timer = undefined;
try {
var nodes = document.querySelectorAll(selector), i = nodes.length;
while ( i-- ) {
var node = nodes[i], j = attrs.length;
while ( j-- ) { node.removeAttribute(attrs[j]); }
const nodes = document.querySelectorAll(selector);
for ( let node of nodes ) {
for ( let attr of tokens ) {
node.removeAttribute(attr);
}
}
} catch(ex) {
}
};
if ( document.readyState === 'loading' ) {
window.addEventListener('DOMContentLoaded', rmattr, true);
} else {
const mutationHandler = mutations => {
if ( timer !== undefined ) { return; }
let skip = true;
for ( let i = 0; i < mutations.length && skip; i++ ) {
const { type, addedNodes, removedNodes } = mutations[i];
if ( type === 'attributes' ) { skip = false; }
for ( let j = 0; j < addedNodes.length && skip; j++ ) {
if ( addedNodes[j].nodeType === 1 ) { skip = false; break; }
}
for ( let j = 0; j < removedNodes.length && skip; j++ ) {
if ( removedNodes[j].nodeType === 1 ) { skip = false; break; }
}
}
if ( skip ) { return; }
if ( 'requestIdleCallback' in self ) {
timer = self.requestIdleCallback(rmattr, { timeout: 67 });
} else {
timer = self.setTimeout(rmattr, 1);
}
};
const start = ( ev ) => {
if ( ev ) { self.removeEventListener(ev.type, rmattr, true); }
rmattr();
if ( /\bstay\b/.test(behavior) === false ) { return; }
const observer = new MutationObserver(mutationHandler);
observer.observe(document.documentElement, {
attributes: true,
attributeFilter: tokens,
childList: true,
subtree: true,
});
};
if ( document.readyState !== 'complete' && /\bcomplete\b/.test(behavior) ) {
self.addEventListener('load', start, true);
} else if ( document.readyState === 'loading' ) {
self.addEventListener('DOMContentLoaded', start, true);
} else {
start();
}
})();

Expand Down

0 comments on commit bba2397

Please sign in to comment.