setMutationHandler

MutationObserver wrapper to wait for the specified CSS selector

< Feedback on setMutationHandler

Review: Good - script works

FFW
§
Posted: 2015-10-12

For pages that have many elements to be loaded dynamically..

and quickly, I noticed sometimes it would miss an element or two. Is that normal?

wOxxOmAuthor
§
Posted: 2015-10-12

Add the code you've used and the page url to test.

FFW
§
Posted: 2015-10-12

Never mind, it turned out that that page had all its elements inside it already. Just had to wait for it to get loaded. Solid script by the way, and I'm really glad I asked about such function back then!

wOxxOmAuthor
§
Posted: 2015-10-12
Edited: 2015-10-12

BTW sorry for the API change but I've just noticed the observer parameter was used only in 10% of my scripts so I removed it and now it is passed implicitly as this:

setMutationHandler(document, '.container p.some-child', function(nodes) {
    nodes.forEach(function(node) {
        node.style.display = 'none';
    });
    this.disconnect();
    return true; // continue enumerating current batch of mutations
}, {subtree: true, attributes: true, attributeFilter: ['style']});

Also notice the nodes parameter is now passed as an array so you can call all the usual array methods on it directly.

And finally you can pass the fourth parameter options to override the default {subtree:true, childList:true}.

FFW
§
Posted: 2015-10-12
Edited: 2015-10-12

While we at it, selecting a container for baseNode other than document never worked for me

Here is a quick example.. https://www.reddit.com/r/firefox

// ==UserScript==
// @name        Test!
// @namespace   1081920433
// @include     https://www.reddit.com/*
// @version     0.1
// @grant       none
// @run-at      document-start
// ==/UserScript==

setMutationHandler(document.querySelector('#siteTable'), '.may-blank.title', function(nodes) {
    [].forEach.call(nodes, function(n) {
        n.href = 'breakit';
    });
    return true;
});

function setMutationHandler(baseNode, selector, cb, options) {
    var ob = new MutationObserver(function(mutations) {
        for (var i=0, ml=mutations.length, m; (i<ml) && (m=mutations[i]); i++)
            for (var j=0, nodes=m.addedNodes, nl=nodes.length, n; (j<nl) && (n=nodes[j]); j++)
                if (n.nodeType == 1) 
                    if ((n = n.matches(selector) ? [n] : n.querySelectorAll(selector)) && n.length)
                        if (!cb.call(ob, Array.prototype.slice.call(n)))
                            return;
    });
    ob.observe(baseNode, options || {subtree:true, childList:true}); 
    return ob;
}
wOxxOmAuthor
§
Posted: 2015-10-12
Edited: 2015-10-12

That's because at document-start the document is usually empty, occasionally even <head> may not be present entirely, often no <body> element.

FFW
§
Posted: 2015-10-12

I kind of guessed that. Great, and thank you for the update!

§
Posted: 2019-02-17
Edited: 2019-02-17

Just recently, I start having an issue with the script missing elements as well, while I have a separate script that expands the urls of the posts alongside timestamps (That script included below in the function ExpandPostIDs works fine, it never missed a node, I noticed that sometimes timestamps are being skipped and missed out.

I'm not sure what the issue is.. any help?

https://greasyfork.org/en/scripts/371113-fb-full-timestamps-2019/code

EDIT: So the problem was that the elements that were being missed weren't abbr elements and didn't have a data-utime attribute either.

Adding

setMutationHandler(document, 'abbr[data-utime]', expandDates);
+setMutationHandler(document, '.h_1zif-zjsf.q_1zif-zjsq', expandDatesT);

Did yield a result, but I'm still trying to figure out how to get it to work the original data-utime because just doing that only assigns it an invalid data since the lack of a data-utime attribute

wOxxOmAuthor
§
Posted: 2019-02-17

@JZersche, sounds like a different issue. Try to find what's different about those elements in devtools.

§
Posted: 2019-02-17
Edited: 2019-02-17

Well, the tittle attribute, doesn't show up until you actually hover on the element, so this one is tricky..

Any ideas?

§
Posted: 2019-02-17
Edited: 2019-02-17

They removed the abbr attribute which contained the actual time a post was made from recent posts and instead put the time in there dynamically through XHR, so when you hover over something like '10 mins' the time pops up and the title attribute is added. Since it's added after hovering, I don't believe there's a way or at least that I know of to process it because it's not present until it's requested form the server. So, what I did was used moment.js to get the current time, and add that to the class for recently posted statuses, now I made it work only if the innerText of the class contains 'mins' using RegEX, From there I was able to extract the amount of minutes or hours that have passed since the status was made. So my next step is to take that number, and subtract it form the current time. :)

(Sorry for all the comments)

§
Posted: 2019-02-17
Edited: 2019-02-17

I got it working, I'll also be able to use

abbr.getElementsByClassName("_5pb8 o_1zif-v9x6 _8o _8s lfloat _ohe").getAttribute("href") 

to get the post url's. Might need some tweaking. I'll see.

Post reply

Sign in to post a reply.