Keep track of creating elements in a greasemonkey script?

I need to be notified when an element with the class "nav" is created when the document is loaded. Googling I found MutationObservers and thought they would be perfect, but I can't get it to work.

// ==UserScript== // @name ii-shortcuts // @namespace https://github.com/RedHatter // @include * // @version 1 // @run-at document-start // ==/UserScript== var observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { if (mutation.target.getAttribute('class') == 'nav') GM_log('nav creation'); }); }); observer.observe(document, {subtree: true, attributes: true, attributeFilter: ['class']}); 

I also tried.

 // ==UserScript== // @name ii-shortcuts // @namespace https://github.com/RedHatter // @include * // @version 1 // @run-at document-start // ==/UserScript== var observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { if (mutation.addedNodes[0].getAttribute('class') == 'nav') GM_log('nav creation'); }); }); observer.observe(document, {subtree: true, childList: true}); 

But in the latter case, "nav creation" was registered on the page load. What am I missing?

+8
source share
2 answers

A few questions (large to small):

  • When the document is first, it is statically loaded; events childList events, not attributes events.

    For instance,

     $("body").append ('<p id="foo" class="bar">Hiya!</p><p>blah</p>'); 

    generates one childList event, and the subsequent

     $("#foo").attr ("class", "bar2"); 

    generates an attributes event.

  • The mutation.addedNodes[0] that mutation.addedNodes[0] contains an element with class nav are practically zero. This is almost always node text.
    You need to check the whole array, PLUS target .

  • Do not use getAttribute('class') == 'nav' to test classes. This will throw exceptions for nodes without the getAttribute function and skip elements that have more than one class. EG: <p class="foo nav bar">...

    Use classList.contains() for the corresponding node types.

  • Use the @grant directive if you use any GM_ functions such as GM_log() . In any case, use the grant to make sure that the sandbox remains.

  • Avoid using // @include * . Especially with timers and watchers, this can lead to the loss of your browser and your machine.

  • This information is for Firefox. Chrome has big differences in how it implements Mutation observers. This code will not work in Chrome until the page loads.


Putting it all together, the script becomes:

 // ==UserScript== // @name _ii-shortcuts // @namespace https://github.com/RedHatter // @include http://YOUR_SERVER.COM/YOUR_PATH/* // @run-at document-start // @version 1 // @grant GM_log // ==/UserScript== /*- The @grant directive is needed to work around a design change introduced in GM 1.0. It restores the sandbox. */ var MutationObserver = window.MutationObserver; var myObserver = new MutationObserver (mutationHandler); var obsConfig = { childList: true, attributes: true, subtree: true, attributeFilter: ['class'] }; myObserver.observe (document, obsConfig); function mutationHandler (mutationRecords) { mutationRecords.forEach ( function (mutation) { if ( mutation.type == "childList" && typeof mutation.addedNodes == "object" && mutation.addedNodes.length ) { for (var J = 0, L = mutation.addedNodes.length; J < L; ++J) { checkForCSS_Class (mutation.addedNodes[J], "nav"); } } else if (mutation.type == "attributes") { checkForCSS_Class (mutation.target, "nav"); } } ); } function checkForCSS_Class (node, className) { //-- Only process element nodes if (node.nodeType === 1) { if (node.classList.contains (className) ) { console.log ( 'New node with class "' + className + '" = ', node ); // YOUR CODE HERE //GM_log ('nav creation'); } } } 
+8
source

MutationObservers are called for more things than just adding nodes, including changing attributes and deleting nodes.

So make sure mutation.addedNodes returns null - in this case this code will fail. Try:

 if (mutation.addedNodes && mutation.addedNodes[0].getAttribute('class') === 'nav') { ... 

The mutation object also has a 'type' attribute, which you can use to get more information; Have you read the API docs on MDN ? There are some good examples.

0
source

Source: https://habr.com/ru/post/949377/


All Articles