Skip to content

Instantly share code, notes, and snippets.

@mkkeck
Created May 25, 2019 09:19
Show Gist options
  • Save mkkeck/a1c58b979a616a6eddd7c29d7770b227 to your computer and use it in GitHub Desktop.
Save mkkeck/a1c58b979a616a6eddd7c29d7770b227 to your computer and use it in GitHub Desktop.
Function to queue jQuery in inline scripts, until jQuery is fully loaded async or via script injection.
/*!
* Queue jQuery function calls until jQuery is fully loaded.
*
* This avoids "jQuery / $ is undefined" errors in inline scripts
* if jQuery is loaded asynchron or via script injection
*
* Copyright 2019, Michael Keck <https://github.com/mkkeck>
* Released under the MIT license
*/
/*
* Example Usage:
*
* 1). Include this gist as an inline script in the <head> of your HTML document
*
* 2). Add follow script code for injecting jQuery (loading asynchron):
*
* // script injection
* !function(l, o, a, d, j, q) {
* j = o.createElement(a);
* j.src = d;
* j.async = true;
* // trigger on load
* j.onload = j.onerror = function() {
* j.onload = j.onerror = null;
*
* // the default name of the unqueue function is "$onLoaded"
* // check if the function window.$onLoaded is available
* if (/^f/.test(typeof l[ "$onLoaded" ])) {
* // call window.$onLoaded
* l[ "$onLoaded" ]();
* }
* };
* q = o.getElementsByTagName(a)[0];
* q.parentNode.insertBefore(j, q);
* }(window, document, "script", "path/to/jquery.min.js");
*
* 3.) Usage in inline scripts:
*
* // document.ready, prefered and best way
* jQuery(function( $ ) {
* // Your jQuery code here, using the $
* });
*
* // document.ready, alternative 1
* jQuery(document).ready(function( $ ) {
* // Your jQuery code here, using the $
* });
*
* // document.ready, alternative 2
* jQuery(document).on("ready", function( $ ) {
* // Your jQuery code here, using the $
* });
*
* // window.load
* jQuery(window).load(function( $ ) {
* // Your jQuery code here, using the $
* });
*
* // window.load; alternative 1
* jQuery(window).on("load", function( $ ) {
* // Your jQuery code here, using the $
* });
*
* 4). Notice:
* You can also use jQuery( window|document ).bind( ... ), but .bind() is
* deprecated since jQuery 3.0.
* See: https://api.jquery.com/category/deprecated/deprecated-3.0/
*/
/**
* @param {String} [$ready] Name of the function wich is applied to the global
* scope (window) for calling after jQuery is loaded;
* default: "$onLoaded"
* result: {Function} Window.$onLoaded();
*
* @param {String} [$sym] Set your own alias / shortcut for jQuery,
* espacially usefull for jQuery.noConflict;
* default: "$"
*
* @param {Window} [win] Global scope;
* default: Window
* @type {Function}
*/
(function($ready, $sym, win) {
/** @type {*|Window} */
win = win || window;
/**
* @type {String} $ready; default: "$onLoaded"
*/
$ready = $ready || "$onLoaded";
/**
* @type {String} $sym; default: "$"
*/
$sym = $sym || "$";
var
/**
* @type {Document|Window} element; Store the used element (Window | Document)
* @private
*/
element,
/**
* @type {Object} queueFn; Functions for the queue
* @private
*/
queueFn,
/**
* @type {Array} queue; The queue to store jQuery calls
* @private
*/
queue = [],
/**
* @type {Document} doc; jQuery needs a Document
* @private
*/
doc = win.document,
/**
* @type {String} jQuery; The name of the library
* @private
*/
jQuery = "jQuery",
/**
* @type {String} bind; Name for function "bind"
* @private
*/
bind = "bind",
/**
* @type {String} ready; Name for function "ready"
* @private
*/
ready = "ready",
/**
* boolean = is( string(value) [, RegExp(pattern) ] );
*
* Checking typeof's
*
* @private
* @param {String} value
* @param {RegExp} [typof]
* @return {boolean}
*/
is = function(value, typof) {
return !typof ? value !=="undefined" : typof.test(value);
};
// only do it, when Window.jQuery is typeof "undefined"
if ( !is(typeof win[ jQuery ] )) {
/** @type {{q: q, load: load, ready: ready, on: on}} */
queueFn = {
/**
* queueFn.p( function(handler), string(event), Window|Document);
*
* Push $.on(), $.bind(), $(document ...), $(window).load() to the queue
*
* @param {Function} handler
* @param {String} event
* @param {Window|Document} element
*/
q: function(handler, event, element) {
queue.push((!event || event === ready)
? handler
: { e: element === win ? win : doc, b: event, h: handler }
);
},
/**
* queueFn.on( string(event), function(handler) );
*
* @param {String} event
* @param {Function} handler
*/
on: function(event, handler) {
queueFn.q(handler, event, element);
},
/**
* queueFn.load( function(handler) );
*
* @param {Function} handler
*/
load: function(handler) {
queueFn.q(handler, "load", win);
},
/**
* queueFn.ready( function(handler) );
*
* @param {Function} handler
*/
ready: function(handler) {
queueFn.q(handler, ready, doc)
}
};
/** @type {queueFn.on} queueFn.bind; Alias of queueFn.on for older jQuery versions */
queueFn[bind] = queueFn.on;
/**
* Temporary Window.$ / Window.jQuery
*
* @type {Function}
*/
win[ $sym ] = win[ jQuery ] = function(handler) {
if ( is(typeof handler, /^f/) ) {
return queueFn[ ready ](handler);
}
element = handler === win ? win : doc;
return queueFn;
};
}
/**
* Callback function, when jQuery is fully loaded.
* Note: You have to call this function manually!
*
* @return {Window.$}
*/
win[ $ready ] = function() {
var entry, lib;
if ( is(typeof win[ jQuery ].fn) ) {
// Get a copy of Window.$ / Window.jQuery
lib = win[ $sym ] = win[ jQuery ];
bind = is(typeof lib.on) ? "on" : bind;
while( queue.length > 0) {
entry = queue.shift();
if ( is(typeof entry, /^f/) ) {
lib(entry( lib ) )
}
else {
(function(entry) {
if (entry.e && entry.b && entry.h) {
lib(entry.e)[ bind ](entry.b, function() {
entry.h( lib );
})
}
})(entry);
}
}
// Return Window.$ / Window.jQuery
win[ $sym ] = win[ jQuery ] = lib;
}
return win[ $sym ];
};
})( /*! "$onLoaded" */ );
/*!
* Queue jQuery function calls until jQuery is fully loaded.
*
* This avoids "jQuery / $ is undefined" errors in inline scripts
* if jQuery is loaded asynchron or via script injection
*
* Copyright 2019, Michael Keck <https://github.com/mkkeck>
* Released under the MIT license
*/
!function(n,f,t){t=t||window;n=n||"$onLoaded";f=f||"$";function e(n,o){return o?o.test(n):"undefined"!==n}var u,i,r=[],c=t.document,d="jQuery",y="bind",a="ready";if(!e(typeof t[d])){(i={q:function(n,o,f){r.push(o&&o!==a?{e:f===t?t:c,b:o,h:n}:n)},on:function(n,o){i.q(o,n,u)},load:function(n){i.q(n,"load",t)},ready:function(n){i.q(n,a,c)}})[y]=i.on;t[f]=t[d]=function(n){if(e(typeof n,/^f/))return i[a](n);u=n===t?t:c;return i}}t[n]=function(){var n,o;if(e(typeof t[d].fn)){o=t[f]=t[d];y=e(typeof o.on)?"on":y;for(;0<r.length;){n=r.shift();e(typeof n,/^f/)?o(n(o)):function(n){n.e&&n.b&&n.h&&o(n.e)[y](n.b,function(){n.h(o)})}(n)}t[f]=t[d]=o}return t[f]}}();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment