Skip to content

Instantly share code, notes, and snippets.

@martijnthe
Created January 23, 2012 08:21
Show Gist options
  • Save martijnthe/1661717 to your computer and use it in GitHub Desktop.
Save martijnthe/1661717 to your computer and use it in GitHub Desktop.
FancyLoader
// Example use:
// See below for FancyLoader.src.js source
var loader = FancyLoader();
var defs = {
scripts: {
j: {
src: 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js',
doesExist: loader.doesJQueryExist,
dependencies: []
},
v: {
src: 'http://ajax.aspnetcdn.com/ajax/jquery.validate/1.9/jquery.validate.min.js',
doesExist: function() {
try {
var validatorLoaded = jQuery("#f_o_r_m").validate({});
return true;
} catch(err) {
return false;
}
},
dependencies: ['j']
}
},
callbacks: {
jd: {
dependencies: ['j'],
done: function() {
// do stuff when scripts 'j' is loaded
} // end done: function()
}, // end jd
d: {
dependencies: ['j', 'v'],
done: function() {
// do stuff when scripts 'j' and 'v' are loaded
} // end done: function()
} // end d
} // end callbacks
}; // end var defs
loader.load(defs);
function FancyLoader() {
// Privates:
var _configuration = { scripts:{}, callbacks:{} };
var _waitTime = 100;
function _loadScript(url, callback) {
// Thanks to Hay Kranen :)
// Callback is not required
callback = callback || function(){};
var script = document.createElement("script")
script.type = "text/javascript";
if (script.readyState) { // IE
script.onreadystatechange = function() {
// IE sometimes gives back the one state, and sometimes the
// other, so we need to check for both
if (script.readyState === "loaded" ||
script.readyState === "complete") {
script.onreadystatechange = null;
callback();
}
};
} else { // Others
script.onload = function() {
callback();
};
}
script.src = url;
// Adding to the <head> is safer than the end of the <body>
document.getElementsByTagName("head")[0].appendChild(script);
}
function _areDependenciesLoaded(dependee) {
if (dependee.dependencies === undefined) {
return true;
} else {
for (var i in dependee.dependencies) {
var k = dependee.dependencies[i];
try {
var d = _configuration.scripts[k];
if (d.state !== 'done') {
return false;
}
} catch(err) {
/* console.log('Missing dependent script "' + k +'" on which "' + dependee + '" depends.');*/
return false;
}
}
return true;
}
};
function _loadNext() {
// Start processing the scripts:
var _scripts = _configuration.scripts;
var _head = document.getElementsByTagName('head')[0];
for (var k in _scripts) {
var scriptConf = _scripts[k];
switch (scriptConf.state) {
case 'done':
case 'error':
continue;
case 'loading':
continue;
default: {
// Let's test if the script is loaded
var doesExist = false;
try {
doesExist = scriptConf.doesExist();
} catch(err) {
/* console.log('Missing "doesExist" function on "' + k + '"');*/
}
if (doesExist) {
// If it's already loaded...
if (_areDependenciesLoaded(scriptConf)) {
// Mark it as 'done'
scriptConf.state = 'done';
if (scriptConf.elem !== undefined) {
scriptConf.elem.onload = scriptConf.elem.onreadystatechange = null;
}
// console.log('Marked ' + k + ' as "done"');
} else {
// Waiting for the dependencies to load, before we can call the ready handler and be done:
scriptConf.state = 'waiting';
// console.log('Marked ' + k + ' as "waiting" but was loaded already.');
}
} else if (scriptConf.state != 'loading') {
// Else if it's not loaded...
// Check if the dependencies are loaded
if (_areDependenciesLoaded(scriptConf)) {
// If so, start loading
if (scriptConf.src !== undefined) {
scriptConf.state = 'loading';
console.log('Marked ' + k + ' as "loading"');
/* $LAB.script(scriptConf.src).wait(function(){
setTimeout(function() {
scriptConf.state = 'done';
_loadNext();
}, _waitTime);
}); */
//var kk = k;
var _capturedConf = scriptConf;
_loadScript(_capturedConf.src, function(){
setTimeout(function() {
//console.log('Marked ' + kk + ' as "done"');
_capturedConf.state = 'done';
_loadNext();
}, _waitTime);
});
} else {
scriptConf.state = 'error';
/* console.log('Missing script "src" in configuration.');*/
}
} else {
// If not, we'll only mark the state 'wait'
scriptConf.state = 'waiting';
// console.log('Marked ' + k + ' as "waiting"');
}
}
}
}
}
// Start processing the callbacks:
var _callbacks = _configuration.callbacks;
var _areAllCallbacksDone = true;
for (var k in _callbacks) {
var _cb = _callbacks[k];
if (_cb.state === 'done') {
continue; // Callback already called before.
} else {
// Are if the callback's dependencies fulfilled?
if (_areDependenciesLoaded(_cb)) {
// Call the callback
try {
_cb.done();
} catch(err) {
/* console.log('Exception: ' + err + ' while calling callback ' + _cb);*/
}
_cb.state = 'done';
// console.log('Marked ' + _cb + ' as "done"');
} else {
// Just wait for now...
_cb.state = 'waiting';
_areAllCallbacksDone = false;
// console.log('Marked ' + _cb + ' as "waiting"');
}
}
}
// Schedule the next processing round if not all callbacks are done.
if (_areAllCallbacksDone === false) {
// console.log('Scheduling...');
setTimeout(_loadNext, _waitTime);
};
};
// Convenience methods for testing existence of popular frameworks / libs:
function _doesJQueryExist() {
// Test existence of jQuery global
try {
var jQueryLoaded = jQuery;
return true;
} catch(err) {
return false;
}
};
/*
... support for other frameworks to come ...
*/
return {
load: function(configuration, waitTime) {
if (configuration.scripts === undefined) {
/* console.log('Incomplete configuration: "scripts" missing.');*/
return;
}
if (configuration.callbacks === undefined) {
/* console.log('Incomplete configuration: "callbacks" missing.');*/
return;
}
_configuration = configuration;
if (waitTime !== undefined) {
_waitTime = waitTime;
}
setTimeout(_loadNext, _waitTime);
},
// Public convenience methods to test existence of popular libraries:
doesJQueryExist: _doesJQueryExist
};
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment