Run my script on each page load, *including* AJAX

2019-05-29 20:48发布

问题:

I want to delay the page-load time for a specific web page - in this case, Google - so that users can't see the web page until a count-down timer has completed.

This question was inspired xkcd, and a similar question is "Javascript page load delay of specific set of pages".

I've tried a modified version of Jonathan's Greasemonkey script (see below), but this script only delays the Google page load the first time Google is used in a particular tab.

If Google is opened in a new tab, or the user follows a link from Google then returns, the script kicks in again. But, if the user doesn't ever navigate away from Google (say, they find the answer they were looking for in the brief abstract under each search result, then just search for something else), they can search without any delay.

Is there a way to force the delay screen to appear after each search (as opposed to after each time the page is visited)? -- preferably using either Greasemonkey or a Chrome plug-in?

Script currently used:
(first sets blocked addresses to a value of "1" and all other addresses to a value of "0," then, if block>0, the script kicks in...)

(function(){
    // Note: This doesn't actually stop the page from loading, but hides it, so you know its 
    // there, waiting; The dopamine of internet candy becomes a torture.  Better to clean 
    // your room or open an irb prompt instead.
    window.seconds = 30;

    function resetCountDown()
    {
        seconds = 30;
    }

    // You can has cybersauce
    window.clearDelay = function()
    {
        document.getElementById('eightSixTwoDelay').style.display = 'none';
    }

    var overlay = document.createElement('div');
    overlay.id = 'eightSixTwoDelay';
    overlay.style.backgroundColor = '#000';
    overlay.style.color = '#FFF';
    overlay.style.fontSize = '56px';
    overlay.style.fontFamily = 'Helvetica, Arial, Sans';
    overlay.style.fontWeight = 'bold';
    overlay.style.textDecoration = 'none';
    overlay.style.position = 'absolute';
    overlay.style.top = '0px';
    overlay.style.left = '0px';
    overlay.style.width = '100%';
    // clientHeight changes as content loads, and JS, like the PHX Valley Metro system, does not wait for you to run.
    overlay.style.height = document.body.clientHeight + 'px'; //'100%'; 
    overlay.style.paddingTop = '10px';
    overlay.style.paddingLeft = '10px';
    overlay.style.textAlign = 'left';
    overlay.style.zIndex = '10000'; // OVER 9000

    overlay.addEventListener("click", resetCountDown, true); // THERE IS NO ESCAPE

    document.getElementsByTagName('body')[0].appendChild(overlay);

    window.displayDelay = function()
    {
        if (seconds > -1)
        {
            document.getElementById('eightSixTwoDelay').innerHTML = 'Page ready in ' + seconds + ' seconds.';
            seconds -= 1;
            setTimeout(window.displayDelay, 1000);
        }
        else
        {
            clearDelay();
        }
    }


    window.onload = displayDelay();

})();
}

回答1:

When a new search is entered, Google politely changes the URL, as well as AJAXing-in the new page. So, listen for the hashchange event to determine when a new search was run.

Some random notes on that script:

  1. Use @run-at document-start so that the blanking starts as soon as possible.
  2. The overlay should be position: fixed;.
  3. Avoid setting global or window. scope variables, AMAP.

Here is a complete script that blanks the page on each new Google search:

// ==UserScript==
// @name        _Delay a page display, a la XKCD
// @namespace   _pc
// @match       http://*.google.com/*
// @run-at      document-start
// ==/UserScript==

/*--- Blank the screen as soon as the DOM is available, and also whenever
    the URL (hashtag) changes -- which happens when "new" pages are loaded
    via AJAX.
*/
window.addEventListener ("readystatechange",    FireWhenReady,          true);
window.addEventListener ("hashchange",          blankScreenForA_While,  true);

function FireWhenReady () {
    this.fired  = this.fired || false;

    if (    document.readyState != "uninitialized"
        &&  document.readyState != "loading"
        &&  ! this.fired
    ) {
        this.fired  = true;
        blankScreenForA_While ();
    }
}

function blankScreenForA_While () {
    /*  Note: This doesn't actually stop the page from loading, but hides it,
        so you know its there, waiting; The dopamine of internet candy becomes
        a torture.
        Better to clean your room or open an irb prompt instead.
    */
    //--- Settings:
    var pageDelaySeconds    = 5;
    var overlayID           = "gmEightSixTwoDelay"

    //--- One-time setup, for each new "page", START:
    function resetCountDown () {
        blankScreenForA_While.secondsRemaining  = pageDelaySeconds;
    }
    resetCountDown ();


    function createOverlay () {
        var overlay                 = document.getElementById (overlayID);
        if (overlay) {
            overlay.style.display   = 'block';  // Un-hide.
            return;
        }
        overlay                     = document.createElement ('div');
        overlay.id                  = overlayID;
        overlay.style.cssText       = "                                 \
            font:                   bold 56px Helvetica,Arial,Sans;     \
            text-decoration:        none;                               \
            position:               fixed;                              \
            top:                    0;                                  \
            left:                   0;                                  \
            width:                  100%;                               \
            height:                 100%;                               \
            z-index:                10000;  /* OVER 9000 */             \
            margin:                 0;                                  \
            overflow:               hidden;                             \
            color:                  pink;                               \
            background:             lime;                               \
            line-height:            1.5;                                \
            padding:                1em;                                \
            text-align:             center;                             \
        ";

        //--- Only use innerHTML the one time.
        overlay.innerHTML           = 'Go do something important!<br>'
                                    + 'Page ready in <span></span> seconds.'
                                    ;

        // THERE IS NO ESCAPE.
        overlay.addEventListener( "click", resetCountDown, true);

        document.body.appendChild (overlay);
    }
    createOverlay ();

    //--- One-time setup, for each new "page", :END


    // You can has cybersauce
    function clearDelay () {
        document.getElementById (overlayID).style.display = 'none';
    }


    function displayDelay () {
        if (blankScreenForA_While.secondsRemaining > -1) {
            var displaySpan         = document.querySelector (
                                        "#" + overlayID + " span"
                                    );
            displaySpan.textContent = blankScreenForA_While.secondsRemaining;

            blankScreenForA_While.secondsRemaining--;
            setTimeout (displayDelay, 1000);
        }
        else {
            clearDelay ();
        }
    }
    displayDelay ();

}//-- End of: blankScreenForA_While()