Plugin Directory

Changeset 856065


Ignore:
Timestamp:
02/12/2014 04:02:55 AM (12 years ago)
Author:
kylereicks
Message:

Version 2.0.0, a rewrite

Location:
headwp/trunk
Files:
17 added
3 edited

Legend:

Unmodified
Added
Removed
  • headwp/trunk/head-js-wp.php

    r701136 r856065  
    55Description: A plugin to load footer scripts with head.js
    66Author: Kyle Reicks
    7 Version: 1.0
     7Version: 2.0.0
    88Author URI: http://github.com/kylereicks/
    99*/
    1010
    11 if(!class_exists('Head_js_wp')){
    12   class Head_js_wp{
     11define('HEAD_JS_WP_PATH', plugin_dir_path(__FILE__));
     12define('HEAD_JS_WP_URL', plugins_url('/', __FILE__));
     13define('HEAD_JS_WP_VERSION', '2.0.0');
     14define('HEAD_JS_VERSION', '1.0.3');
    1315
    14     function __construct(){
    15       if(!is_admin()){
    16         add_action('wp_enqueue_scripts', array($this, 'add_header_js_to_head'));
    17         remove_action('wp_print_footer_scripts', '_wp_footer_scripts');
    18         add_action('wp_print_footer_scripts', array($this, 'print_scripts_with_header_js'));
    19       }
    20     }
     16require_once(HEAD_JS_WP_PATH . 'inc/class-head-js-wp.php');
    2117
    22     function add_header_js_to_head(){
    23       if(!wp_script_is('head-js')){
    24         wp_register_script('head-js', plugins_url('/js/libs/head.load.js', __FILE__));
    25       }
    26     }
     18register_deactivation_hook(__FILE__, array('Head_js_wp', 'deactivate'));
    2719
    28     function print_scripts_with_header_js(){
    29       global $wp_scripts;
    30 
    31       print_late_styles();
    32 
    33       if(!empty($wp_scripts->queue)){
    34         $wp_scripts->all_deps($wp_scripts->queue);
    35       }
    36 
    37       if(!empty($wp_scripts->to_do)){
    38         $wp_scripts->do_item('head-js');
    39 
    40         foreach($wp_scripts->to_do as $handle){
    41           $wp_scripts->print_extra_script($handle);
    42         }
    43 
    44         $script_queues = $this->queue_scripts($wp_scripts);
    45 
    46         echo '<script>' . "\n" . 'head';
    47         foreach($script_queues as $queue){
    48           echo "\n" . '.js({';
    49           foreach($queue as $number => $script){
    50             $ending = (count($queue) === $number + 1) ? '})' : "},\n{";
    51             $version = ($wp_scripts->registered[$script]->ver) ? '?ver=' . $wp_scripts->registered[$script]->ver : "";
    52             $base_url = (preg_match('/^\//', $wp_scripts->registered[$script]->src)) ? $wp_scripts->base_url : '';
    53             echo str_replace('-', '_', $script) . " : '" . $base_url . $wp_scripts->registered[$script]->src . $version . "'" . $ending;
    54             $wp_scripts->done[] = $script;
    55             $wp_scripts->to_do = array_merge(array_diff($wp_scripts->to_do, array($script)));
    56           }
    57         }
    58         echo ';' . "\n" . '</script>' . "\n";
    59         return true;
    60       }else{
    61         return false;
    62       }
    63     }
    64 
    65     private function queue_scripts($wp_scripts){
    66       $script_queues = array();
    67 
    68       foreach($wp_scripts->to_do as $script){
    69         if(empty($wp_scripts->registered[$script]->deps)){
    70           $script_queues[] = array(
    71             $script
    72           );
    73         }else{
    74           foreach($script_queues as $number => $queue){
    75             foreach($queue as $queue_script){
    76               if(in_array($queue_script, $wp_scripts->registered[$script]->deps) && !in_array($script, $script_queues[$number])){
    77                 $script_queues[$number][] = $script;
    78               }
    79             }
    80           }
    81         }
    82       }
    83 
    84       foreach($script_queues as  $number => $queue){
    85         foreach($script_queues as $number_check => $queue_check){
    86           if($number > $number_check){
    87             $intersect = array_intersect($script_queues[$number], $script_queues[$number_check]);
    88             if(!empty($intersect)){
    89               $script_queues[$number] = array_diff($script_queues[$number], $intersect);
    90               $script_queues[$number] = array_merge($script_queues[$number], $script_queues[$number_check]);
    91               unset($script_queues[$number_check]);
    92             }
    93           }
    94         }
    95       }
    96       return $script_queues;
    97     }
    98   }/* End class Head_js_wp */
    99   $head_js_wp = new Head_js_wp();
    100 }
    101 /* End file head-js-wp.php */
     20Head_js_wp::get_instance();
  • headwp/trunk/js/libs/head.load.js

    r701136 r856065  
    1 (function(f,w){function m(){}function g(a,b){if(a){"object"===typeof a&&(a=[].slice.call(a));for(var c=0,d=a.length;c<d;c++)b.call(a,a[c],c)}}function v(a,b){var c=Object.prototype.toString.call(b).slice(8,-1);return b!==w&&null!==b&&c===a}function k(a){return v("Function",a)}function h(a){a=a||m;a._done||(a(),a._done=1)}function n(a){var b={};if("object"===typeof a)for(var c in a)a[c]&&(b={name:c,url:a[c]});else b=a.split("/"),b=b[b.length-1],c=b.indexOf("?"),b={name:-1!==c?b.substring(0,c):b,url:a};
    2 return(a=p[b.name])&&a.url===b.url?a:p[b.name]=b}function q(a){var a=a||p,b;for(b in a)if(a.hasOwnProperty(b)&&a[b].state!==r)return!1;return!0}function s(a,b){b=b||m;a.state===r?b():a.state===x?d.ready(a.name,b):a.state===y?a.onpreload.push(function(){s(a,b)}):(a.state=x,z(a,function(){a.state=r;b();g(l[a.name],function(a){h(a)});j&&q()&&g(l.ALL,function(a){h(a)})}))}function z(a,b){var b=b||m,c;/\.css[^\.]*$/.test(a.url)?(c=e.createElement("link"),c.type="text/"+(a.type||"css"),c.rel="stylesheet",
    3 c.href=a.url):(c=e.createElement("script"),c.type="text/"+(a.type||"javascript"),c.src=a.url);c.onload=c.onreadystatechange=function(a){a=a||f.event;if("load"===a.type||/loaded|complete/.test(c.readyState)&&(!e.documentMode||9>e.documentMode))c.onload=c.onreadystatechange=c.onerror=null,b()};c.onerror=function(){c.onload=c.onreadystatechange=c.onerror=null;b()};c.async=!1;c.defer=!1;var d=e.head||e.getElementsByTagName("head")[0];d.insertBefore(c,d.lastChild)}function i(){e.body?j||(j=!0,g(A,function(a){h(a)})):
    4 (f.clearTimeout(d.readyTimeout),d.readyTimeout=f.setTimeout(i,50))}function t(){e.addEventListener?(e.removeEventListener("DOMContentLoaded",t,!1),i()):"complete"===e.readyState&&(e.detachEvent("onreadystatechange",t),i())}var e=f.document,A=[],B=[],l={},p={},E="async"in e.createElement("script")||"MozAppearance"in e.documentElement.style||f.opera,C,j,D=f.head_conf&&f.head_conf.head||"head",d=f[D]=f[D]||function(){d.ready.apply(null,arguments)},y=1,x=3,r=4;d.load=E?function(){var a=arguments,b=a[a.length-
    5 1],c={};k(b)||(b=null);g(a,function(d,e){d!==b&&(d=n(d),c[d.name]=d,s(d,b&&e===a.length-2?function(){q(c)&&h(b)}:null))});return d}:function(){var a=arguments,b=[].slice.call(a,1),c=b[0];if(!C)return B.push(function(){d.load.apply(null,a)}),d;c?(g(b,function(a){if(!k(a)){var b=n(a);b.state===w&&(b.state=y,b.onpreload=[],z({url:b.url,type:"cache"},function(){b.state=2;g(b.onpreload,function(a){a.call()})}))}}),s(n(a[0]),k(c)?c:function(){d.load.apply(null,b)})):s(n(a[0]));return d};d.js=d.load;d.test=
    6 function(a,b,c,e){a="object"===typeof a?a:{test:a,success:b?v("Array",b)?b:[b]:!1,failure:c?v("Array",c)?c:[c]:!1,callback:e||m};(b=!!a.test)&&a.success?(a.success.push(a.callback),d.load.apply(null,a.success)):!b&&a.failure?(a.failure.push(a.callback),d.load.apply(null,a.failure)):e();return d};d.ready=function(a,b){if(a===e)return j?h(b):A.push(b),d;k(a)&&(b=a,a="ALL");if("string"!==typeof a||!k(b))return d;var c=p[a];if(c&&c.state===r||"ALL"===a&&q()&&j)return h(b),d;(c=l[a])?c.push(b):l[a]=[b];
    7 return d};d.ready(e,function(){q()&&g(l.ALL,function(a){h(a)});d.feature&&d.feature("domloaded",!0)});if("complete"===e.readyState)i();else if(e.addEventListener)e.addEventListener("DOMContentLoaded",t,!1),f.addEventListener("load",i,!1);else{e.attachEvent("onreadystatechange",t);f.attachEvent("onload",i);var u=!1;try{u=null==f.frameElement&&e.documentElement}catch(F){}u&&u.doScroll&&function b(){if(!j){try{u.doScroll("left")}catch(c){f.clearTimeout(d.readyTimeout);d.readyTimeout=f.setTimeout(b,50);
    8 return}i()}}()}setTimeout(function(){C=!0;g(B,function(b){b()})},300)})(window);
     1///#source 1 1 /src/1.0.0/load.js
     2/*! head.load - v1.0.3 */
     3/*
     4 * HeadJS     The only script in your <HEAD>
     5 * Author     Tero Piirainen  (tipiirai)
     6 * Maintainer Robert Hoffmann (itechnology)
     7 * License    MIT / http://bit.ly/mit-license
     8 * WebSite    http://headjs.com
     9 */
     10(function (win, undefined) {
     11    "use strict";
     12
     13    //#region variables
     14    var doc        = win.document,
     15        domWaiters = [],
     16        handlers   = {}, // user functions waiting for events
     17        assets     = {}, // loadable items in various states
     18        isAsync    = "async" in doc.createElement("script") || "MozAppearance" in doc.documentElement.style || win.opera,
     19        isDomReady,
     20
     21        /*** public API ***/
     22        headVar = win.head_conf && win.head_conf.head || "head",
     23        api     = win[headVar] = (win[headVar] || function () { api.ready.apply(null, arguments); }),
     24
     25        // states
     26        PRELOADING = 1,
     27        PRELOADED  = 2,
     28        LOADING    = 3,
     29        LOADED     = 4;
     30    //#endregion
     31
     32    //#region PRIVATE functions
     33
     34    //#region Helper functions
     35    function noop() {
     36        // does nothing
     37    }
     38
     39    function each(arr, callback) {
     40        if (!arr) {
     41            return;
     42        }
     43
     44        // arguments special type
     45        if (typeof arr === "object") {
     46            arr = [].slice.call(arr);
     47        }
     48
     49        // do the job
     50        for (var i = 0, l = arr.length; i < l; i++) {
     51            callback.call(arr, arr[i], i);
     52        }
     53    }
     54
     55    /* A must read: http://bonsaiden.github.com/JavaScript-Garden
     56     ************************************************************/
     57    function is(type, obj) {
     58        var clas = Object.prototype.toString.call(obj).slice(8, -1);
     59        return obj !== undefined && obj !== null && clas === type;
     60    }
     61
     62    function isFunction(item) {
     63        return is("Function", item);
     64    }
     65
     66    function isArray(item) {
     67        return is("Array", item);
     68    }
     69
     70    function toLabel(url) {
     71        ///<summary>Converts a url to a file label</summary>
     72        var items = url.split("/"),
     73             name = items[items.length - 1],
     74             i    = name.indexOf("?");
     75
     76        return i !== -1 ? name.substring(0, i) : name;
     77    }
     78
     79    // INFO: this look like a "im triggering callbacks all over the place, but only wanna run it one time function" ..should try to make everything work without it if possible
     80    // INFO: Even better. Look into promises/defered's like jQuery is doing
     81    function one(callback) {
     82        ///<summary>Execute a callback only once</summary>
     83        callback = callback || noop;
     84
     85        if (callback._done) {
     86            return;
     87        }
     88
     89        callback();
     90        callback._done = 1;
     91    }
     92    //#endregion
     93
     94    function conditional(test, success, failure, callback) {
     95        ///<summary>
     96        /// INFO: use cases:
     97        ///    head.test(condition, null       , "file.NOk" , callback);
     98        ///    head.test(condition, "fileOk.js", null       , callback);
     99        ///    head.test(condition, "fileOk.js", "file.NOk" , callback);
     100        ///    head.test(condition, "fileOk.js", ["file.NOk", "file.NOk"], callback);
     101        ///    head.test({
     102        ///               test    : condition,
     103        ///               success : [{ label1: "file1Ok.js"  }, { label2: "file2Ok.js" }],
     104        ///               failure : [{ label1: "file1NOk.js" }, { label2: "file2NOk.js" }],
     105        ///               callback: callback
     106        ///    );
     107        ///    head.test({
     108        ///               test    : condition,
     109        ///               success : ["file1Ok.js" , "file2Ok.js"],
     110        ///               failure : ["file1NOk.js", "file2NOk.js"],
     111        ///               callback: callback
     112        ///    );
     113        ///</summary>
     114        var obj = (typeof test === "object") ? test : {
     115            test: test,
     116            success: !!success ? isArray(success) ? success : [success] : false,
     117            failure: !!failure ? isArray(failure) ? failure : [failure] : false,
     118            callback: callback || noop
     119        };
     120
     121        // Test Passed ?
     122        var passed = !!obj.test;
     123
     124        // Do we have a success case
     125        if (passed && !!obj.success) {
     126            obj.success.push(obj.callback);
     127            api.load.apply(null, obj.success);
     128        }
     129        // Do we have a fail case
     130        else if (!passed && !!obj.failure) {
     131            obj.failure.push(obj.callback);
     132            api.load.apply(null, obj.failure);
     133        }
     134        else {
     135            callback();
     136        }
     137
     138        return api;
     139    }
     140
     141    function getAsset(item) {
     142        ///<summary>
     143        /// Assets are in the form of
     144        /// {
     145        ///     name : label,
     146        ///     url  : url,
     147        ///     state: state
     148        /// }
     149        ///</summary>
     150        var asset = {};
     151
     152        if (typeof item === "object") {
     153            for (var label in item) {
     154                if (!!item[label]) {
     155                    asset = {
     156                        name: label,
     157                        url : item[label]
     158                    };
     159                }
     160            }
     161        }
     162        else {
     163            asset = {
     164                name: toLabel(item),
     165                url : item
     166            };
     167        }
     168
     169        // is the item already existant
     170        var existing = assets[asset.name];
     171        if (existing && existing.url === asset.url) {
     172            return existing;
     173        }
     174
     175        assets[asset.name] = asset;
     176        return asset;
     177    }
     178
     179    function allLoaded(items) {
     180        items = items || assets;
     181
     182        for (var name in items) {
     183            if (items.hasOwnProperty(name) && items[name].state !== LOADED) {
     184                return false;
     185            }
     186        }
     187
     188        return true;
     189    }
     190
     191    function onPreload(asset) {
     192        asset.state = PRELOADED;
     193
     194        each(asset.onpreload, function (afterPreload) {
     195            afterPreload.call();
     196        });
     197    }
     198
     199    function preLoad(asset, callback) {
     200        if (asset.state === undefined) {
     201
     202            asset.state     = PRELOADING;
     203            asset.onpreload = [];
     204
     205            loadAsset({ url: asset.url, type: "cache" }, function () {
     206                onPreload(asset);
     207            });
     208        }
     209    }
     210
     211    function apiLoadHack() {
     212        /// <summary>preload with text/cache hack
     213        ///
     214        /// head.load("http://domain.com/file.js","http://domain.com/file.js", callBack)
     215        /// head.load(["http://domain.com/file.js","http://domain.com/file.js"], callBack)
     216        /// head.load({ label1: "http://domain.com/file.js" }, { label2: "http://domain.com/file.js" }, callBack)
     217        /// head.load([{ label1: "http://domain.com/file.js" }, { label2: "http://domain.com/file.js" }], callBack)
     218        /// </summary>
     219        var args     = arguments,
     220            callback = args[args.length - 1],
     221            rest     = [].slice.call(args, 1),
     222            next     = rest[0];
     223
     224        if (!isFunction(callback)) {
     225            callback = null;
     226        }
     227
     228        // if array, repush as args
     229        if (isArray(args[0])) {
     230            args[0].push(callback);
     231            api.load.apply(null, args[0]);
     232
     233            return api;
     234        }
     235
     236        // multiple arguments
     237        if (!!next) {
     238            /* Preload with text/cache hack (not good!)
     239             * http://blog.getify.com/on-script-loaders/
     240             * http://www.nczonline.net/blog/2010/12/21/thoughts-on-script-loaders/
     241             * If caching is not configured correctly on the server, then items could load twice !
     242             *************************************************************************************/
     243            each(rest, function (item) {
     244                // item is not a callback or empty string
     245                if (!isFunction(item) && !!item) {
     246                    preLoad(getAsset(item));
     247                }
     248            });
     249
     250            // execute
     251            load(getAsset(args[0]), isFunction(next) ? next : function () {
     252                api.load.apply(null, rest);
     253            });
     254        }
     255        else {
     256            // single item
     257            load(getAsset(args[0]));
     258        }
     259
     260        return api;
     261    }
     262
     263    function apiLoadAsync() {
     264        ///<summary>
     265        /// simply load and let browser take care of ordering
     266        ///
     267        /// head.load("http://domain.com/file.js","http://domain.com/file.js", callBack)
     268        /// head.load(["http://domain.com/file.js","http://domain.com/file.js"], callBack)
     269        /// head.load({ label1: "http://domain.com/file.js" }, { label2: "http://domain.com/file.js" }, callBack)
     270        /// head.load([{ label1: "http://domain.com/file.js" }, { label2: "http://domain.com/file.js" }], callBack)
     271        ///</summary>
     272        var args     = arguments,
     273            callback = args[args.length - 1],
     274            items    = {};
     275
     276        if (!isFunction(callback)) {
     277            callback = null;
     278        }
     279
     280        // if array, repush as args
     281        if (isArray(args[0])) {
     282            args[0].push(callback);
     283            api.load.apply(null, args[0]);
     284
     285            return api;
     286        }
     287
     288        // JRH 262#issuecomment-26288601
     289        // First populate the items array.
     290        // When allLoaded is called, all items will be populated.
     291        // Issue when lazy loaded, the callback can execute early.
     292        each(args, function (item, i) {
     293            if (item !== callback) {
     294                item             = getAsset(item);
     295                items[item.name] = item;
     296            }
     297        });
     298
     299        each(args, function (item, i) {
     300            if (item !== callback) {
     301                item = getAsset(item);
     302
     303                load(item, function () {
     304                    if (allLoaded(items)) {
     305                        one(callback);
     306                    }
     307                });
     308            }
     309        });
     310
     311        return api;
     312    }
     313
     314    function load(asset, callback) {
     315        ///<summary>Used with normal loading logic</summary>
     316        callback = callback || noop;
     317
     318        if (asset.state === LOADED) {
     319            callback();
     320            return;
     321        }
     322
     323        // INFO: why would we trigger a ready event when its not really loaded yet ?
     324        if (asset.state === LOADING) {
     325            api.ready(asset.name, callback);
     326            return;
     327        }
     328
     329        if (asset.state === PRELOADING) {
     330            asset.onpreload.push(function () {
     331                load(asset, callback);
     332            });
     333            return;
     334        }
     335
     336        asset.state = LOADING;
     337
     338        loadAsset(asset, function () {
     339            asset.state = LOADED;
     340
     341            callback();
     342
     343            // handlers for this asset
     344            each(handlers[asset.name], function (fn) {
     345                one(fn);
     346            });
     347
     348            // dom is ready & no assets are queued for loading
     349            // INFO: shouldn't we be doing the same test above ?
     350            if (isDomReady && allLoaded()) {
     351                each(handlers.ALL, function (fn) {
     352                    one(fn);
     353                });
     354            }
     355        });
     356    }
     357
     358    function getExtension(url) {
     359        url = url || "";
     360
     361        var items = url.split("?")[0].split(".");
     362        return items[items.length-1].toLowerCase();
     363    }
     364
     365    /* Parts inspired from: https://github.com/cujojs/curl
     366    ******************************************************/
     367    function loadAsset(asset, callback) {
     368        callback = callback || noop;
     369
     370        function error(event) {
     371            event = event || win.event;
     372
     373            // release event listeners
     374            ele.onload = ele.onreadystatechange = ele.onerror = null;
     375
     376            // do callback
     377            callback();
     378
     379            // need some more detailed error handling here
     380        }
     381
     382        function process(event) {
     383            event = event || win.event;
     384
     385            // IE 7/8 (2 events on 1st load)
     386            // 1) event.type = readystatechange, s.readyState = loading
     387            // 2) event.type = readystatechange, s.readyState = loaded
     388
     389            // IE 7/8 (1 event on reload)
     390            // 1) event.type = readystatechange, s.readyState = complete
     391
     392            // event.type === 'readystatechange' && /loaded|complete/.test(s.readyState)
     393
     394            // IE 9 (3 events on 1st load)
     395            // 1) event.type = readystatechange, s.readyState = loading
     396            // 2) event.type = readystatechange, s.readyState = loaded
     397            // 3) event.type = load            , s.readyState = loaded
     398
     399            // IE 9 (2 events on reload)
     400            // 1) event.type = readystatechange, s.readyState = complete
     401            // 2) event.type = load            , s.readyState = complete
     402
     403            // event.type === 'load'             && /loaded|complete/.test(s.readyState)
     404            // event.type === 'readystatechange' && /loaded|complete/.test(s.readyState)
     405
     406            // IE 10 (3 events on 1st load)
     407            // 1) event.type = readystatechange, s.readyState = loading
     408            // 2) event.type = load            , s.readyState = complete
     409            // 3) event.type = readystatechange, s.readyState = loaded
     410
     411            // IE 10 (3 events on reload)
     412            // 1) event.type = readystatechange, s.readyState = loaded
     413            // 2) event.type = load            , s.readyState = complete
     414            // 3) event.type = readystatechange, s.readyState = complete
     415
     416            // event.type === 'load'             && /loaded|complete/.test(s.readyState)
     417            // event.type === 'readystatechange' && /complete/.test(s.readyState)
     418
     419            // Other Browsers (1 event on 1st load)
     420            // 1) event.type = load, s.readyState = undefined
     421
     422            // Other Browsers (1 event on reload)
     423            // 1) event.type = load, s.readyState = undefined
     424
     425            // event.type == 'load' && s.readyState = undefined
     426
     427            // !doc.documentMode is for IE6/7, IE8+ have documentMode
     428            if (event.type === "load" || (/loaded|complete/.test(ele.readyState) && (!doc.documentMode || doc.documentMode < 9))) {
     429                // remove timeouts
     430                win.clearTimeout(asset.errorTimeout);
     431                win.clearTimeout(asset.cssTimeout);
     432
     433                // release event listeners
     434                ele.onload = ele.onreadystatechange = ele.onerror = null;
     435
     436                // do callback   
     437                callback();
     438            }
     439        }
     440
     441        function isCssLoaded() {
     442            // should we test again ? 20 retries = 5secs ..after that, the callback will be triggered by the error handler at 7secs
     443            if (asset.state !== LOADED && asset.cssRetries <= 20) {
     444
     445                // loop through stylesheets
     446                for (var i = 0, l = doc.styleSheets.length; i < l; i++) {
     447                    // do we have a match ?
     448                    // we need to tests agains ele.href and not asset.url, because a local file will be assigned the full http path on a link element
     449                    if (doc.styleSheets[i].href === ele.href) {
     450                        process({ "type": "load" });
     451                        return;
     452                    }
     453                }
     454
     455                // increment & try again
     456                asset.cssRetries++;
     457                asset.cssTimeout = win.setTimeout(isCssLoaded, 250);
     458            }
     459        }
     460
     461        var ele;
     462        var ext = getExtension(asset.url);
     463
     464        if (ext === "css") {
     465            ele      = doc.createElement("link");
     466            ele.type = "text/" + (asset.type || "css");
     467            ele.rel  = "stylesheet";
     468            ele.href = asset.url;
     469
     470            /* onload supported for CSS on unsupported browsers
     471             * Safari windows 5.1.7, FF < 10
     472             */
     473
     474            // Set counter to zero
     475            asset.cssRetries = 0;
     476            asset.cssTimeout = win.setTimeout(isCssLoaded, 500);         
     477        }
     478        else {
     479            ele      = doc.createElement("script");
     480            ele.type = "text/" + (asset.type || "javascript");
     481            ele.src = asset.url;
     482        }
     483
     484        ele.onload  = ele.onreadystatechange = process;
     485        ele.onerror = error;
     486
     487        /* Good read, but doesn't give much hope !
     488         * http://blog.getify.com/on-script-loaders/
     489         * http://www.nczonline.net/blog/2010/12/21/thoughts-on-script-loaders/
     490         * https://hacks.mozilla.org/2009/06/defer/
     491         */
     492
     493        // ASYNC: load in parallel and execute as soon as possible
     494        ele.async = false;
     495        // DEFER: load in parallel but maintain execution order
     496        ele.defer = false;
     497
     498        // timout for asset loading
     499        asset.errorTimeout = win.setTimeout(function () {
     500            error({ type: "timeout" });
     501        }, 7e3);
     502
     503        // use insertBefore to keep IE from throwing Operation Aborted (thx Bryan Forbes!)
     504        var head = doc.head || doc.getElementsByTagName("head")[0];
     505
     506        // but insert at end of head, because otherwise if it is a stylesheet, it will not override values     
     507        head.insertBefore(ele, head.lastChild);
     508    }
     509
     510    /* Parts inspired from: https://github.com/jrburke/requirejs
     511    ************************************************************/
     512    function init() {
     513        var items = doc.getElementsByTagName("script");
     514
     515        // look for a script with a data-head-init attribute
     516        for (var i = 0, l = items.length; i < l; i++) {
     517            var dataMain = items[i].getAttribute("data-headjs-load");
     518            if (!!dataMain) {
     519                api.load(dataMain);
     520                return;
     521            }
     522        }
     523    }
     524
     525    function ready(key, callback) {
     526        ///<summary>
     527        /// INFO: use cases:
     528        ///    head.ready(callBack);
     529        ///    head.ready(document , callBack);
     530        ///    head.ready("file.js", callBack);
     531        ///    head.ready("label"  , callBack);
     532        ///    head.ready(["label1", "label2"], callback);
     533        ///</summary>
     534
     535        // DOM ready check: head.ready(document, function() { });
     536        if (key === doc) {
     537            if (isDomReady) {
     538                one(callback);
     539            }
     540            else {
     541                domWaiters.push(callback);
     542            }
     543
     544            return api;
     545        }
     546
     547        // shift arguments
     548        if (isFunction(key)) {
     549            callback = key;
     550            key      = "ALL"; // holds all callbacks that where added without labels: ready(callBack)
     551        }
     552
     553        // queue all items from key and return. The callback will be executed if all items from key are already loaded.
     554        if (isArray(key)) {
     555            var items = {};
     556
     557            each(key, function (item) {
     558                items[item] = assets[item];
     559
     560                api.ready(item, function() {
     561                    if (allLoaded(items)) {
     562                        one(callback);
     563                    }
     564                });
     565            });
     566
     567            return api;
     568        }
     569
     570        // make sure arguments are sane
     571        if (typeof key !== "string" || !isFunction(callback)) {
     572            return api;
     573        }
     574
     575        // this can also be called when we trigger events based on filenames & labels
     576        var asset = assets[key];
     577
     578        // item already loaded --> execute and return
     579        if (asset && asset.state === LOADED || key === "ALL" && allLoaded() && isDomReady) {
     580            one(callback);
     581            return api;
     582        }
     583
     584        var arr = handlers[key];
     585        if (!arr) {
     586            arr = handlers[key] = [callback];
     587        }
     588        else {
     589            arr.push(callback);
     590        }
     591
     592        return api;
     593    }
     594
     595    /* Mix of stuff from jQuery & IEContentLoaded
     596     * http://dev.w3.org/html5/spec/the-end.html#the-end
     597     ***************************************************/
     598    function domReady() {
     599        // Make sure body exists, at least, in case IE gets a little overzealous (jQuery ticket #5443).
     600        if (!doc.body) {
     601            // let's not get nasty by setting a timeout too small.. (loop mania guaranteed if assets are queued)
     602            win.clearTimeout(api.readyTimeout);
     603            api.readyTimeout = win.setTimeout(domReady, 50);
     604            return;
     605        }
     606
     607        if (!isDomReady) {
     608            isDomReady = true;
     609
     610            init();
     611            each(domWaiters, function (fn) {
     612                one(fn);
     613            });
     614        }
     615    }
     616
     617    function domContentLoaded() {
     618        // W3C
     619        if (doc.addEventListener) {
     620            doc.removeEventListener("DOMContentLoaded", domContentLoaded, false);
     621            domReady();
     622        }
     623
     624        // IE
     625        else if (doc.readyState === "complete") {
     626            // we're here because readyState === "complete" in oldIE
     627            // which is good enough for us to call the dom ready!
     628            doc.detachEvent("onreadystatechange", domContentLoaded);
     629            domReady();
     630        }
     631    }
     632
     633    // Catch cases where ready() is called after the browser event has already occurred.
     634    // we once tried to use readyState "interactive" here, but it caused issues like the one
     635    // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
     636    if (doc.readyState === "complete") {
     637        domReady();
     638    }
     639
     640    // W3C
     641    else if (doc.addEventListener) {
     642        doc.addEventListener("DOMContentLoaded", domContentLoaded, false);
     643
     644        // A fallback to window.onload, that will always work
     645        win.addEventListener("load", domReady, false);
     646    }
     647
     648    // IE
     649    else {
     650        // Ensure firing before onload, maybe late but safe also for iframes
     651        doc.attachEvent("onreadystatechange", domContentLoaded);
     652
     653        // A fallback to window.onload, that will always work
     654        win.attachEvent("onload", domReady);
     655
     656        // If IE and not a frame
     657        // continually check to see if the document is ready
     658        var top = false;
     659
     660        try {
     661            top = !win.frameElement && doc.documentElement;
     662        } catch (e) { }
     663
     664        if (top && top.doScroll) {
     665            (function doScrollCheck() {
     666                if (!isDomReady) {
     667                    try {
     668                        // Use the trick by Diego Perini
     669                        // http://javascript.nwbox.com/IEContentLoaded/
     670                        top.doScroll("left");
     671                    } catch (error) {
     672                        // let's not get nasty by setting a timeout too small.. (loop mania guaranteed if assets are queued)
     673                        win.clearTimeout(api.readyTimeout);
     674                        api.readyTimeout = win.setTimeout(doScrollCheck, 50);
     675                        return;
     676                    }
     677
     678                    // and execute any waiting functions
     679                    domReady();
     680                }
     681            }());
     682        }
     683    }
     684    //#endregion
     685
     686    //#region Public Exports
     687    // INFO: determine which method to use for loading
     688    api.load  = api.js = isAsync ? apiLoadAsync : apiLoadHack;
     689    api.test  = conditional;
     690    api.ready = ready;
     691    //#endregion
     692
     693    //#region INIT
     694    // perform this when DOM is ready
     695    api.ready(doc, function () {
     696        if (allLoaded()) {
     697            each(handlers.ALL, function (callback) {
     698                one(callback);
     699            });
     700        }
     701
     702        if (api.feature) {
     703            api.feature("domloaded", true);
     704        }
     705    });
     706    //#endregion
     707}(window));
  • headwp/trunk/readme.txt

    r701136 r856065  
    44Tags: script loading, asynchronous, javascript, async, headJS, head.js, enqueue, wp_enqueue_script
    55Requires at least: 3.2
    6 Tested up to: 3.5.1
    7 Stable tag: 1.0
     6Tested up to: 3.8.1
     7Stable tag: 2.0.0
    88License: GPLv2 or later
    99License URI: http://www.gnu.org/licenses/gpl-2.0.html
    1010
    11 A plugin to load all footer scripts with [head.js](https://github.com/headjs/headjs).
     11A plugin to load all footer scripts and styles with [head.js](https://github.com/headjs/headjs).
    1212
    1313== Description ==
    1414
    15 Head.js is a script to asynchronously load and optionally asynchronously execute javascript assets.
     15Head.js is a script to asynchronously load and manage dependencies of javascript and CSS assets.
    1616
    17 This plugin loads the scripts enqueued in footer with the head.js loader. All of the footer scripts are loaded asynchronously and any scripts that do not share dependencies are executed asynchronously while scripts that share dependencies are executed in order.
     17This plugin loads the scripts and styles enqueued in footer with the head.js loader. It does not include head.js' feature detection.
    1818
    19 Head.WP assumes that scripts are loaded via `wp_enqueue_script()` and that any script enqueued in the `<head>` intends to be loaded before the rest of the page.
     19Head.js.wp assumes that scripts are loaded via `wp_enqueue_script()` and that any script enqueued in the `<head>` intends to be loaded before the rest of the page.
    2020
    2121== Installation ==
     
    4848== Changelog ==
    4949
     50= 2.0.0 =
     51* A complete rewrite. It really is much nicer now.
     52* Update to head.js version 1.0.3
     53
    5054= 1.0 =
    5155* Release 1.0.
     
    5357== Upgrade Notice ==
    5458
    55 = 1.0 =
    56 This is the initial public release.
     59= 2.0 =
     60This is a complete rewrite of the 1.0 release. I don't forsee any upgrading problems, but if you have made any customizations to the plugin or it's functionality, please test before updating a live site.
Note: See TracChangeset for help on using the changeset viewer.