Search code examples
javascriptjquerygithubgreasemonkeyuserscripts

Listening for github.com PJAX events in Greasemonkey user script


A user script I'm working on successfully works on initially loaded GitHub page. Though it needs to be re-applied when GitHub is navigated with PJAX.

So I have to set up a listener for PJAX changes somehow and run initialize function again.

Patching unsafeWindow.history.pushState won't work because of Greasemonkey/Firefox security policy, it will throw

Error: Permission denied to access object

I've tried to examine page scripts and hook to ajaxComplete event of unsafeWindow.require('jquery'), but the listener wasn't triggered (possibly because of the same security policy, but error console was empty).

Is there a better solution than MutationObserver/DOMSubtreeModified on PJAX container element?

The script is targeted at Firefox/Greasemonkey, but if it will be workable for Chrome/Tampermonkey, this won't hurt.


Solution

  • Add a listener for "pjax:end" event on document:

    $(document).on('pjax:end', ...)
    

    FWIW a working example in vanilla js. As you can see a MutationObserver is also used because the site script updates the dynamic container sometimes twice (discarding the first one completely), so, after the pjax:end handler completes, a MutationObserver handler is attached to detect removal of the file wrapper, in which case the processing is repeated:

    document.addEventListener('pjax:end', pageChangedHandler);
    
    function pageChangedHandler() {
    
        .......................
    
        var ovr = document.querySelector('include-fragment.file-wrap');
        if (ovr) {
            new MutationObserver(function(mutations) {
                mutations.forEach(m => {
                    var removed = m.removedNodes[0];
                    if (removed && removed.matches('.file-wrap')) {
                        this.disconnect();
                        pageChangedHandler();
                    }
                });
            }).observe(ovr.parentNode, {childList:true});
        }
    }