201 lines
6.4 KiB
JavaScript
201 lines
6.4 KiB
JavaScript
|
/**
|
||
|
* $Id: scriptqueue.js 351 2007-11-13 12:56:18Z wingedfox $
|
||
|
* $HeadURL: https://svn.debugger.ru/repos/jslibs/BrowserExtensions/tags/BrowserExtensions.018/scriptqueue.js $
|
||
|
*
|
||
|
* Dynamically load scripts and script queues (when load order is important)
|
||
|
*
|
||
|
**********NOTE********
|
||
|
* If you need to load any scripts before ScriptQueue exists, use the following snippet
|
||
|
* <code>
|
||
|
* if (!(window.ScriptQueueIncludes instanceof Array)) window.ScriptQueueIncludes = []
|
||
|
* window.ScriptQueueIncludes = window.ScriptQueueIncludes.concat(scriptsarray);
|
||
|
* </code>
|
||
|
* ScriptQueue loads all the scripts, queued before its' load in the ScriptQueueIncludes
|
||
|
**********
|
||
|
*
|
||
|
* @author Ilya Lebedev <ilya@lebedev.net>
|
||
|
* @modified $Date: 2007-11-13 15:56:18 +0300 (Втр, 13 Ноя 2007) $
|
||
|
* @version $Rev: 351 $
|
||
|
* @license LGPL 2.1 or later
|
||
|
*
|
||
|
* @class ScriptQueue
|
||
|
* @param {Function} optional callback function, called on each successful script load
|
||
|
* @scope public
|
||
|
*/
|
||
|
ScriptQueue = function (cbk) {
|
||
|
var self = this
|
||
|
,static = arguments.callee;
|
||
|
/*
|
||
|
* empty function is better than number of checks in the code...
|
||
|
*/
|
||
|
if ('function' != typeof cbk) cbk = function(){}
|
||
|
/**
|
||
|
* Queue for the current loader instance
|
||
|
*
|
||
|
* @type {Array}
|
||
|
* @scope private
|
||
|
*/
|
||
|
var queue = [];
|
||
|
//-------------------------------------------------------------------------
|
||
|
// PUBLIC
|
||
|
//-------------------------------------------------------------------------
|
||
|
/**
|
||
|
* Loads the single script, independent from any other
|
||
|
*
|
||
|
* @param {String} path path to the target script
|
||
|
* @return {Boolean} true when script is getting loaded, false otherwise
|
||
|
* @scope public
|
||
|
*/
|
||
|
self.load = function (path) {
|
||
|
load(path,cbk);
|
||
|
}
|
||
|
/**
|
||
|
* Builds a queue of scripts, when they should be loaded in the proper order
|
||
|
*
|
||
|
* @param {String} path script name to add to the queue
|
||
|
* @scope public
|
||
|
*/
|
||
|
self.queue = function (path) {
|
||
|
var f = queue.length;
|
||
|
queue[f] = path;
|
||
|
if (!f) load(path,queuemonitor);
|
||
|
}
|
||
|
//-------------------------------------------------------------------------
|
||
|
// PRIVATE
|
||
|
//-------------------------------------------------------------------------
|
||
|
/**
|
||
|
* Performs scripts existense check and loads it, if needed
|
||
|
*
|
||
|
* @param {String} path path to the script
|
||
|
* @param {Function} cbk callback
|
||
|
* @scope private
|
||
|
*/
|
||
|
var load = function (path, cbk) {
|
||
|
var sid
|
||
|
,scr = static.scripts;
|
||
|
if (sid = scr.hash[path]) { // in queue
|
||
|
scr = static.scripts[sid]
|
||
|
if (scr[2]) { // loaded
|
||
|
cbk(path,scr[2]);
|
||
|
} else {
|
||
|
scr[1].push(cbk);
|
||
|
}
|
||
|
} else {
|
||
|
sid = scr.length;
|
||
|
scr[sid] = [path,[cbk],false];
|
||
|
scr.hash[path] = sid;
|
||
|
ls(path);
|
||
|
}
|
||
|
}
|
||
|
/**
|
||
|
* Attaches script to the document
|
||
|
*
|
||
|
* @param {String} src path to script
|
||
|
* @scope private
|
||
|
*/
|
||
|
var ls = function (src) {
|
||
|
if (document.body) { // document is loaded, don't use document.write
|
||
|
var s = document.createElement('script')
|
||
|
,h = document.getElementsByTagName("head")[0];
|
||
|
s.type= "text/javascript";
|
||
|
s.charset="UTF-8";
|
||
|
s.src=src;
|
||
|
/*
|
||
|
* some browsers does change the src, store original one here
|
||
|
*/
|
||
|
s.rSrc=src;
|
||
|
s.onload = s.onreadystatechange = loadmonitor;
|
||
|
h.appendChild(s);
|
||
|
} else {
|
||
|
document.write("<scr"+"ipt onload=\"\" src=\""+src+"\" charset=\"UTF-8\"></scr"+"ipt>");
|
||
|
/*
|
||
|
* note, real onload handler is commented out, because IE calls it too late,
|
||
|
* which is not acceptable, because it breaks onload there
|
||
|
* assume, that scripts are loaded successfully
|
||
|
*/
|
||
|
// s.onload = s.onreadystatechange = loadmonitor;
|
||
|
loadmonitor.call({'rSrc':src},{'type':'load'});
|
||
|
}
|
||
|
}
|
||
|
//-------------------------------------------------------------------------
|
||
|
// PROTECTED
|
||
|
//-------------------------------------------------------------------------
|
||
|
/**
|
||
|
* Monitors queue load and runs next iteration, untill empties the queue
|
||
|
*
|
||
|
* @param {String} path loaded script
|
||
|
* @param {Boolean} s load completed status
|
||
|
* @scope protected
|
||
|
*/
|
||
|
var queuemonitor = function (path,s) {
|
||
|
/*
|
||
|
* execute the user callback
|
||
|
*/
|
||
|
cbk(path,s);
|
||
|
queue.splice(0,1);
|
||
|
/*
|
||
|
* next run
|
||
|
*/
|
||
|
if (queue.length && s)
|
||
|
load(queue[0],arguments.callee);
|
||
|
else
|
||
|
cbk(null,s)
|
||
|
}
|
||
|
/**
|
||
|
* Handles onload and onreadystatechange events
|
||
|
*
|
||
|
* @param {Event} e handled event object
|
||
|
* @scope protected
|
||
|
*/
|
||
|
var loadmonitor = function (e) {
|
||
|
var scr = static.scripts
|
||
|
,sid = scr.hash[this.rSrc]
|
||
|
,e = e||window.event
|
||
|
scr = scr[sid];
|
||
|
if (('load' == e.type || 'complete'==this.readyState)) {
|
||
|
if (!scr[2])
|
||
|
scr[2] = true;
|
||
|
else
|
||
|
return; // prevent duplicate calls from event handler
|
||
|
}
|
||
|
for (var i=0,cbk=scr[1],cL=cbk.length;i<cL;i++) {
|
||
|
cbk[i](scr[0],scr[2]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
/**
|
||
|
* Stores information about the loaded scripts
|
||
|
* Element structure:
|
||
|
* [0 : string script path
|
||
|
* 1 : [ array of callback functions ]
|
||
|
* 2 : boolean 'loaded' flag
|
||
|
* ]
|
||
|
* Array fields:
|
||
|
* .hash { maps script paths' to array ids }
|
||
|
*
|
||
|
* @type {Array}
|
||
|
* @scope protected
|
||
|
*/
|
||
|
ScriptQueue.scripts = [false];
|
||
|
ScriptQueue.scripts.hash = {};
|
||
|
/**
|
||
|
* Static method to load bunch of scripts at once
|
||
|
* note, there's no callback support
|
||
|
*
|
||
|
* @param {Array} arr list of scripts to execute
|
||
|
* @scope public
|
||
|
*/
|
||
|
ScriptQueue.queue = function(arr) {
|
||
|
if (!arr.length) return;
|
||
|
var q = new ScriptQueue;
|
||
|
for (var i=0,aL=arr.length;i<aL;i++) {
|
||
|
q.queue(arr[i]);
|
||
|
}
|
||
|
}
|
||
|
/*
|
||
|
* If any load requests does exists, serve them
|
||
|
*/
|
||
|
if (window.ScriptQueueIncludes instanceof Array) {
|
||
|
ScriptQueue.queue(window.ScriptQueueIncludes);
|
||
|
}
|