Search code examples
javascriptgreasemonkeyuserscripts

How would I get a user script to load after php is executed?


I am writing a script that changes up the message system for a website I use a lot. It adds a button to the top of each message thread. When clicked, it automatically moves to the most recent message in the thread.

The issue I am having is that the messages are loaded by php and the script fires before the messages are loaded. The site also doesn't load all of the message threads at the same time. It will load 10 or so, and then as you scroll down it loads more. Is there a way to get the button to load for each of the message threads, or am I shooting for an unreachable goal?

// ==UserScript==
// @name          Imgur - Message Viewer
// @namespace     Basion
// @description   It skips to the bottom of the most recent message
// @author        Basion
// @include       http://imgur.com/*
// @include       https://imgur.com/*
// @include       http://*.imgur.com/*
// @include       https://*.imgur.com/*
// @run-at        document-end
// ==/UserScript==
var messages = document.getElementsByClassName("thread-wrapper");

var newA = document.createElement('a');

for (var i = 0; i < messages.length; i++) {
    newA.addEventListener("click", scrollToMessage(i), true);
    newA.innerText = "Go to Newest Message";
    messages[i].appendChild(newA);
}
function scrollToMessage(id) {
    var newMessages = document.getElementsByClassName('thread-wrapper');
    newMessages[id].scrollIntoView(false);
}

Solution

  • To handle elements added via AJAX, use jQuery and waitForKeyElements as shown in "Run Greasemonkey script on the same page, multiple times?".
    Here's a handy jQuery reference.

    Also, you can't send id's to event listeners that way.

    Here's a complete working, post-jump script, adapted to the question's code and the Imgur target page(s):

    // ==UserScript==
    // @name          Imgur - Message Viewer
    // @namespace     Basion
    // @description   It skips to the bottom of the most recent message
    // @author        Basion
    // @include       http://imgur.com/*
    // @include       https://imgur.com/*
    // @include       http://*.imgur.com/*
    // @include       https://*.imgur.com/*
    // @run-at        document-end
    // @require       http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js
    // @require       https://gist.github.com/raw/2625891/waitForKeyElements.js
    // @grant         GM_addStyle
    // ==/UserScript==
    /*- The @grant directive is needed to work around a design change
        introduced in GM 1.0.   It restores the sandbox.
    */
    
    waitForKeyElements ("div.thread-wrapper", addJumpButton);
    
    /*-- Prepend a button to the top of each thread.  Don't add in the header, to
        avoid conflicts with the open/close toggle.
    */
    function addJumpButton (jNode) {
        jNode.prepend (
            '<a href="#" class="gmThreadJmpBtn">Go to Newest Message in thread</a>'
        );
    }
    
    //-- Activate *all* the jump buttons with one jQuery function.
    $("div.notifications").on (
        "click", "div.thread-wrapper a.gmThreadJmpBtn", jumpToEndOfThread
    );
    
    function jumpToEndOfThread (zEvent) {
        //-- The last (newest) message will be just above the "reply bar".
        var thisThreadHdr   = $(zEvent.target);
        var targetDiv       = thisThreadHdr.nextAll ("div.reply.striped");
        targetDiv[0].scrollIntoView (false);
    
        //-- Block the page handlers from also firing for this link.
        zEvent.stopPropagation ();
        zEvent.preventDefault ();
    }