sebastian-software/core

View on GitHub
source/class/core/io/StyleSheet.js

Summary

Maintainability
B
4 hrs
Test Coverage
/*
==================================================================================================
  Core - JavaScript Foundation
  Copyright 2010-2012 Zynga Inc.
  Copyright 2012-2014 Sebastian Werner
--------------------------------------------------------------------------------------------------
  Inspired by: http://www.phpied.com/when-is-a-stylesheet-really-loaded/
==================================================================================================
*/

"use strict";

if (jasy.Env.isSet("runtime", "browser"))
{
    (function(global)
    {
        var doc = global.document;

        // Dynamic URI can be shared because we do not support reloading files
        var dynamicExtension = "?r=" + Date.now();


        /**
         * Stylesheet loader with support for load callback.
         */
        core.Module("core.io.StyleSheet",
        {
            /** Whether the loader supports parallel requests. Always true for stylesheets (order should, hopefully, not be important). */
            SUPPORTS_PARALLEL : true,


            /**
             * Loads a StyleSheet file from the given @uri {String} and fires a @callback {Function} (in @context {Object?}) when it was loaded.
             * Optionally appends an random `GET` parameter to omit caching when @nocache {Boolean?false} is enabled..
             */
            load: function(uri, callback, context, nocache)
            {
                if (jasy.Env.isSet("debug"))
                {
                    core.Assert.isType(uri, "String");

                    if (callback != null) {
                        core.Assert.isType(callback, "Function", "Invalid callback method!");
                    }

                    if (context != null) {
                        core.Assert.isType(context, "Object", "Invalid callback context!");
                    }

                    if (nocache != null) {
                        core.Assert.isType(nocache, "Boolean");
                    }
                }

                // Default nocache to true when debugging is enabled
                if (jasy.Env.isSet("debug") && nocache == null) {
                    nocache = true;
                }

                if (core.io.Util.isRelativeUrl(uri)) {
                    uri = jasy.Env.getValue("jasy.url") + uri;
                }

                var head = doc.head;

                if (!context) {
                    context = global;
                }

                // Use listener to stylesheet list and compare elements
                if (jasy.Env.isSet("engine", "webkit"))
                {
                    var link = doc.createElement('link');
                    var sheets = doc.styleSheets;

                    var handle = setInterval(function()
                    {
                        for (var i=0, l=sheets.length; i<l; i++)
                        {
                            // In Webkit browsers the sheets array is populated as soon
                            // as the stylesheet was loaded.
                            if (sheets[i].ownerNode === link)
                            {
                                clearInterval(handle);
                                if (callback) {
                                    callback.call(context, uri, false);
                                }
                            }
                        }
                    }, 50);

                    link.rel = "stylesheet";
                    link.type = "text/css";
                    link.href = uri + (nocache ? dynamicExtension : "");

                    head.appendChild(link);
                }

                // Use style import fallback for buggy GECKO
                else if (jasy.Env.isSet("engine", "gecko"))
                {
                    var style = doc.createElement("style");
                    style.textContent = "@import '" + uri + (nocache ? dynamicExtension : "") + "'";

                    var handle = setInterval(function()
                    {
                        try
                        {
                            // MAGIC: only populated when file is loaded
                            style.sheet.cssRules; // jshint ignore:line

                            clearInterval(handle);
                            if (callback) {
                                callback.call(context, uri, false);
                            }
                        } catch(e) {}
                    }, 50);

                    head.appendChild(style);
                }

                // Load event only supported by MSIE and OPERA
                else
                {
                    var link = doc.createElement("link");
                    link.onload = link.onerror = function(e)
                    {
                        link.onload = link.onerror = null;

                        if (callback) {
                            callback.call(context, uri, (e||global.event).type === "error");
                        }
                    };

                    link.rel = "stylesheet";
                    link.type = "text/css";
                    link.href = uri + (nocache ? dynamicExtension : "");

                    head.appendChild(link);
                }
            }
        });
    })(core.Main.getGlobal());
}