/** * $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 * * if (!(window.ScriptQueueIncludes instanceof Array)) window.ScriptQueueIncludes = [] * window.ScriptQueueIncludes = window.ScriptQueueIncludes.concat(scriptsarray); * * ScriptQueue loads all the scripts, queued before its' load in the ScriptQueueIncludes ********** * * @author Ilya Lebedev * @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(""); /* * 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