UNPKG

@qooxdoo/framework

Version:

The JS Framework for Coders

286 lines (248 loc) 7.77 kB
/* ************************************************************************ qooxdoo - the new era of web development http://qooxdoo.org Copyright: 2016 Visionet GmbH, http://www.visionet.de 2016 OETIKER+PARTNER AG, https://www.oetiker.ch License: MIT: https://opensource.org/licenses/MIT See the LICENSE file in the project's top-level directory for details. Authors: * Dietrich Streifert (level420) * Tobias Oetiker (oetiker) ************************************************************************ */ /** * Dynamically load non qx scripts. This class is aware of all scripts that have * been loaded using its instances, so if two instances load jquery, it will only * be loaded once, and the second instance will wait for the jquery to be loaded * before continuing to load additional scripts. * * Usage example: * * <pre> * ... assets ... * /** * * @asset(myapp/jquery/*) * * @asset(myapp/highcharts/*) * * * * @ignore(jQuery.*) * * @ignore(Highcharts.*) * ... * * * // in debug mode load the uncompressed unobfuscated scripts * var src = ''; * var min = '.min'; * if (qx.core.Environment.get("qx.debug")) { * src = '.src'; * min = ''; * } * * // initialize the script loading * var dynLoader = new qx.util.DynamicScriptLoader([ * "myapp/jquery/jquery"+min+".js", * "myapp/highcharts/highcharts"+src+".js", * "myapp/highcharts/highcharts-more"+src+".js", * "myapp/highcharts/highcharts-modifications.js" * ]); * * * dynLoader.addListenerOnce('ready',function(e){ * console.log("all scripts have been loaded!"); * }); * * dynLoader.addListener('failed',function(e){ * var data = e.getData(); * console.log("failed to load "+data.script); * }); * * dynLoader.start(); * * </pre> */ qx.Class.define("qx.util.DynamicScriptLoader", { extend: qx.core.Object, /** * Create a loader for the given scripts. * * @param scriptArr {Array|String} the uri name(s) of the script(s) to load */ construct: function (scriptArr) { this.base(arguments); this.__started = false; this.__QUEUE = (qx.lang.Type.isString(scriptArr) ? [ scriptArr ] : qx.lang.Array.clone(scriptArr)); }, /* ***************************************************************************** EVENTS ***************************************************************************** */ events: { /** * fired when a script is loaded successfully. The data contains 'script' and 'status' keys. */ loaded: 'qx.event.type.Data', /** * fired when a specific script fails loading. The data contains 'script' and 'status' keys. */ failed: 'qx.event.type.Data', /** * fired when all given scripts are loaded, each time loadScriptsDynamic is called. */ ready: 'qx.event.type.Event' }, statics: { /** * Map of scripts being added at the present time. Key is script name; value is instance of this class which * is loading it. */ __IN_PROGRESS: {}, /** * Map of scripts that have fully loaded. Key is script name; value is true */ __LOADED: {} }, /* ***************************************************************************** MEMBERS ***************************************************************************** */ members: { /** * Array of the scripts to be loaded */ __QUEUE: null, /** * True if start has been called. */ __started: null, /** * Start loading scripts. This may only be called once! * @return {Promise?} a promise which will be resolved after load of all scripts if promise support is enabled; nothing (undefined) if promises are not enabled. */ start: qx.core.Environment.select('qx.promise', { "true": function() { return new qx.Promise(function (resolve, reject) { this.addListenerOnce("ready", resolve, this); this.addListenerOnce("failed", function (e) { reject(new Error(e.getData())); }, this); if (this.isDisposed()) { reject(new Error('disposed')); } if (this.__started) { reject(new Error('you can only call start once per instance')); } this.__started = true; this.__loadScripts(); }, this); }, "false": function () { if (this.isDisposed()) { return; } if (this.__started) { throw new Error('you can only call start once per instance'); } this.__started = true; this.__loadScripts(); } }), /** * Chain loading scripts. * * Recursively called until the array of scripts is consumed * */ __loadScripts: function () { var DynamicScriptLoader = qx.util.DynamicScriptLoader; var script; var dynLoader; var id1, id2; var uri; var loader; script = this.__QUEUE.shift(); if (!script){ this.fireEvent("ready") return; } if (DynamicScriptLoader.__LOADED[script]){ this.fireDataEvent('loaded',{ script: script, status: 'preloaded' }); this.__loadScripts(); return; } dynLoader = DynamicScriptLoader.__IN_PROGRESS[script]; if (dynLoader){ id1 = dynLoader.addListener('loaded',function (e) { if (this.isDisposed()) { return; } var data = e.getData(); if (data.script === script){ dynLoader.removeListenerById(id2); dynLoader.removeListenerById(id1); this.fireDataEvent('loaded',data); this.__loadScripts(); } },this); id2 = dynLoader.addListener('failed',function (e) { if (this.isDisposed()) { return; } var data = e.getData(); dynLoader.removeListenerById(id1); dynLoader.removeListenerById(id2); this.fireDataEvent('failed',{ script: script, status: 'loading of ' + data.script + ' failed while waiting for ' + script }); },this); return; } uri = qx.util.ResourceManager.getInstance().toUri(script); loader = new qx.bom.request.Script(); loader.on("load", function(request) { if (this.isDisposed()) { return; } DynamicScriptLoader.__LOADED[script] = true; delete DynamicScriptLoader.__IN_PROGRESS[script]; this.fireDataEvent('loaded', { script: script, status: request.status }); this.__loadScripts(); },this); var onError = function(request) { if (this.isDisposed()) { return; } delete DynamicScriptLoader.__IN_PROGRESS[script]; this.fireDataEvent('failed', { script: script, status: request.status }); }; loader.on("error", onError,this); loader.on("timeout", onError,this); // this.debug("Loading " + script + " started"); loader.open("GET", uri); DynamicScriptLoader.__IN_PROGRESS[script] = this; loader.send(); } }, destruct : function() { var DynamicScriptLoader = qx.util.DynamicScriptLoader; for (var key in DynamicScriptLoader.__IN_PROGRESS){ if (DynamicScriptLoader.__IN_PROGRESS[key] === this) { delete DynamicScriptLoader.__IN_PROGRESS[key]; } } this.__QUEUE = undefined; } });