Skip to content
Permalink
Browse files
Add ability to linger for remove-attr scriplet
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 bba23972faebc3df43b07a942b4870749f7845aa
Showing with 51 additions and 14 deletions.
  1. +51 −14 assets/resources/resources.txt
@@ -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();
}
})();

0 comments on commit bba2397

Please sign in to comment.