From 2de24a11843df653173e50b9e952052361c64147 Mon Sep 17 00:00:00 2001 From: Raymond Hill Date: Sun, 6 Jun 2021 08:58:40 -0400 Subject: [PATCH] Add ability to linger for `remove-class` scriptlet Similar to related change for the `remove-attr` scriptlet: - https://github.com/gorhill/uBlock/commit/0f330c7359567587df6c35e9108b75c339533a56 Related feedback: - https://www.reddit.com/r/uBlockOrigin/comments/nsroaw/some_elements_isare_not_removed_after_the_cookie/ --- assets/resources/scriptlets.js | 42 ++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/assets/resources/scriptlets.js b/assets/resources/scriptlets.js index 01e163b8c..df51b0d72 100644 --- a/assets/resources/scriptlets.js +++ b/assets/resources/scriptlets.js @@ -764,7 +764,10 @@ if ( selector === '' || selector === '{{2}}' ) { selector = '.' + tokens.map(a => CSS.escape(a)).join(',.'); } + let behavior = '{{3}}'; + let timer; const rmclass = function() { + timer = undefined; try { const nodes = document.querySelectorAll(selector); for ( const node of nodes ) { @@ -773,14 +776,39 @@ } catch(ex) { } }; - if ( document.readyState === 'loading' ) { - window.addEventListener( - 'DOMContentLoaded', - rmclass, - { capture: true, 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(rmclass, { timeout: 67 }); + }; + const start = ( ) => { rmclass(); + if ( /\bstay\b/.test(behavior) === false ) { return; } + const observer = new MutationObserver(mutationHandler); + observer.observe(document.documentElement, { + attributes: true, + attributeFilter: [ 'class' ], + childList: true, + subtree: true, + }); + }; + if ( document.readyState !== 'complete' && /\bcomplete\b/.test(behavior) ) { + self.addEventListener('load', start, { once: true }); + } else if ( document.readyState === 'loading' ) { + self.addEventListener('DOMContentLoaded', start, { once: true }); + } else { + start(); } })();