Greasy Fork is available in English.

DONE - Visual Sign Of A Loaded Page

Shows a big DONE sign when the page is fully loaded

// ==UserScript==
// @name          DONE - Visual Sign Of A Loaded Page
// @namespace     http://userscripts.org/users/23652
// @description   Shows a big DONE sign when the page is fully loaded
// @include       http://*.*/*
// @include       https://*.*/*
// @copyright     JoeSimmons
// @version       1.0.3
// @license       GPL version 3 or any later version; http://www.gnu.org/copyleft/gpl.html
// @grant         GM_addStyle
// ==/UserScript==

+function () {
    'use strict';

    // temporary fade function until I implement one in JSL
    function fade(dir, element) {
        var interval = 0.05,
            fps = Math.floor(1000 / 60),
            count, intv;

        function anim() {
            var curOpacity = parseFloat(element.style.opacity);

            if (dir === 'in') {
                if (curOpacity >= 1) {
                    count = 1;
                    element.style.opacity = '1';
                    window.clearInterval(intv);
                } else {
                    element.style.opacity = (count += interval);
                }
            } else if (dir === 'out') {
                if (curOpacity <= 0) {
                    count = 0;
                    element.style.opacity = '0';
                    element.style.display = 'none';
                    window.clearInterval(intv);
                } else {
                    element.style.opacity = (count -= interval);
                }
            }
        }

        if (typeof element === 'string') {
            element = document.getElementById(element);
        }

        if (dir === 'in') {
            element.style.opacity = '0';
            count = 0;

            if (element.style.display === 'none') {
                element.style.display = '';
            }
        } else if (dir === 'out') {
            element.style.opacity = '1';
            count = 1;
        } else {
            return;
        }

        intv = window.setInterval(anim, fps);
    }

    // runAfterPageIdle by JoeSimmons
    // supply it a function and it will run when the page stops mutating
    function runAfterPageIdle(fn) {
        var time = Date.now(),
            set = window.setInterval.bind(window),
            clear = window.clearInterval.bind(window),
            idleTime = 499, // adjustable -- the user's function runs after this idle length; in ms
            freezeCalled = false,
            listenIntv;

        function listen(a) {
            var now = Date.now(); // why call Date.now() twice? :)

            if (typeof a === 'undefined' && (now - time) > idleTime) {
                // clear if it's been idle for the set length of time
                checkFreezing();
            } else if (typeof a === 'object') {
                // reset if it hasn't been idle for the set length of time
                time = now;
            }
        }

        function checkFreezing() {
            var firstTime = Date.now(),
                lastTime = firstTime,
                endOnShortInterval = false,
                freezingIntv;

            // this script has the possibility of checking for freezing twice,
            // but we only want it to run once, regardless of which function calls it first
            if (freezeCalled === true) { return; }
            freezeCalled = true;

            function monitor() {
                var now = Date.now(),
                    diff = now - lastTime;

                if (diff < 41 && endOnShortInterval === true || (now - firstTime) > 499) {
                    clear(freezingIntv);
                    done();
                } else if (diff > 299) {
                    endOnShortInterval = true;
                }
            }

            freezingIntv = set(monitor, 20);
        }

        function done() {
            // clear the interval
            clear(listenIntv);

            // remove listeners
            document.removeEventListener('DOMSubtreeModified', listen, false);
            document.removeEventListener('DOMNodeInserted', listen, false);
            document.removeEventListener('DOMNodeRemoved', listen, false);

            // run user at next event loop slot
            window.setTimeout(fn, 0);
        }

        if (typeof JSL !== 'undefined' && typeof JSL.setInterval === 'function' && typeof JSL.clearInterval === 'function') {
            set = JSL.setInterval.bind(JSL);
            clear = JSL.clearInterval.bind(JSL);
        }

        if (typeof fn === 'function') {
            listenIntv = set(listen, 125); // check 8 times per second

            // set listeners
            document.addEventListener('DOMSubtreeModified', listen, false);
            document.addEventListener('DOMNodeInserted', listen, false);
            document.addEventListener('DOMNodeRemoved', listen, false);

            window.addEventListener('load', function () {
                window.setTimeout(checkFreezing, 0);
            }, false);
        }
    }

    function main() {
        var box = document.createElement('div'),
            boxWidth = Math.floor(window.innerWidth * 0.95),
            oldTitle;

        GM_addStyle('' +
            '#load_sign { ' +
                'background: #D7FFD7; ' +
                'border: 3px ridge #008000; ' +
                'color: #00C400; ' +
                'display: block; ' +
                'font-style: Arial; ' +
                'font-size: 24pt; ' +
                'height: 42px; ' +
                'left: ' + (window.innerWidth / 2 - boxWidth / 2) + 'px; ' + // division comes first here so it works
                'margin: 0 auto; ' +
                'min-height: 42px; ' +
                'padding: 4px 0; ' +
                'position: fixed; ' +
                'text-align: center; ' +
                'text-shadow: 2px 2px 4px #C7C7C7; ' +
                'top: 0; ' +
                'width: ' + boxWidth + 'px; ' +
                'z-index: 2100100100; ' +
            '}' +
        '');

        box.id = 'load_sign';
        box.appendChild( document.createTextNode('DONE') );
        document.body.appendChild(box);

        // add done to the title
        oldTitle = document.title;
        document.title = '[DONE] ' + oldTitle;

        window.setTimeout(function () {
            fade('out', 'load_sign');
            document.title = oldTitle;
        }, 750);
    }

    // make sure the page is not in a frame
    if (window.frameElement || window !== window.top) { return; }

    runAfterPageIdle(main);
}();