Wednesday, July 8, 2015

Perfect way to detect page is ready without jQuery (document.ready without jQuery)

If you find yourself without jQuery and you need to detect if your page is ready, feel free to use this plain JavaScript implementation I've extracted from jQuery 1.11.3 (the latest of the 1.x.x branch at the time of writing). JSFiddle link below.


// bindReady source

/*!
 * jQuery JavaScript Library v1.11.3
 * http://jquery.com/
 *
 * Includes Sizzle.js
 * http://sizzlejs.com/
 *
 * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors
 * Released under the MIT license
 * http://jquery.org/license
 *
 * Date: 2015-04-28T16:19Z
 */
var readyFired = false;

function bindReady(readyCallback) {
    /**
     * Clean-up method for dom ready events
     */
    function detach() {
        if (document.addEventListener) {
            document.removeEventListener("DOMContentLoaded", completed, false);
            window.removeEventListener("load", completed, false);
        } else {
            document.detachEvent("onreadystatechange", completed);
            window.detachEvent("onload", completed);
        }
    }
    // Handle when the DOM is ready
    function ready() {
        if (!readyFired) {
            // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
            if (!document.body) {
                setTimeout(ready, 1);
            }
            // Remember that the DOM is ready
            readyFired = true;
            // Time to call back
            if (readyCallback && typeof (readyCallback) === "function") {
                readyCallback.apply();
            }
        }
    }
    /**
     * The ready event handler and self cleanup method
     */
    function completed() {
        // readyState === "complete" is good enough for us to call the dom ready in oldIE
        if (document.addEventListener || event.type === "load" || document.readyState === "complete") {
            detach();
            ready();
        }
    }
    // Catch cases where $(document).ready() is called after the browser event has already occurred.
    // we once tried to use readyState "interactive" here, but it caused issues like the one
    // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
    if (document.readyState === "complete") {
        // Handle it asynchronously to allow scripts the opportunity to delay ready
        setTimeout(ready);
        // Standards-based browsers support DOMContentLoaded
    } else if (document.addEventListener) {
        // Use the handy event callback
        document.addEventListener("DOMContentLoaded", completed, false);
        // A fallback to window.onload, that will always work
        window.addEventListener("load", completed, false);
        // If IE event model is used
    } else {
        // Ensure firing before onload, maybe late but safe also for iframes
        document.attachEvent("onreadystatechange", completed);
        // A fallback to window.onload, that will always work
        window.attachEvent("onload", completed);
        // If IE and not a frame
        // continually check to see if the document is ready
        var top = false;
        try {
            top = window.frameElement == null && document.documentElement;
        } catch (e) {}
        if (top && top.doScroll) {
            (function doScrollCheck() {
                if (!readyFired) {
                    try {
                        // Use the trick by Diego Perini
                        // http://javascript.nwbox.com/IEContentLoaded/
                        top.doScroll("left");
                    } catch (e) {
                        return setTimeout(doScrollCheck, 50);
                    }
                    // detach all dom ready events
                    detach();
                    // and execute any waiting functions
                    ready();
                }
            })();
        }
    }
}
// end bindReady