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)
  • Loading branch information
gorhill committed Jan 8, 2021
1 parent 0e3071d commit 0f330c7
Showing 1 changed file with 36 additions and 4 deletions.
40 changes: 36 additions & 4 deletions assets/resources/scriptlets.js
Original file line number Diff line number Diff line change
Expand Up @@ -665,7 +665,10 @@
if ( selector === '' || selector === '{{2}}' ) {
selector = `[${tokens.join('],[')}]`;
}
const rmattr = function() {
let behavior = '{{3}}';
let timer;
const rmattr = ( ) => {
timer = undefined;
try {
const nodes = document.querySelectorAll(selector);
for ( const node of nodes ) {
Expand All @@ -676,10 +679,39 @@
} catch(ex) {
}
};
if ( document.readyState === 'loading' ) {
window.addEventListener('DOMContentLoaded', rmattr, { once: 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; }
timer = self.requestIdleCallback(rmattr, { timeout: 67 });
};
const start = ( ) => {
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) ) {
document.addEventListener('load', start, { once: true });

This comment has been minimized.

Copy link
@gwarser

gwarser Jan 8, 2021

Contributor

Should not this be window load event instead of document?

This comment has been minimized.

Copy link
@gorhill

gorhill Jan 8, 2021

Author Owner

I thought this was the same, but apparently not: https://stackoverflow.com/a/38517365

} else if ( document.readyState === 'loading' ) {
document.addEventListener('DOMContentLoaded', start, { once: true });
} else {
start();
}
})();

Expand Down

0 comments on commit 0f330c7

Please sign in to comment.