--- /dev/null
+/*\r
+Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.\r
+For licensing, see LICENSE.html or http://ckeditor.com/license\r
+*/\r
+\r
+/**\r
+ * @fileOverview Defines the {@link CKEDITOR.scriptLoader} object, used to load scripts\r
+ * asynchronously.\r
+ */\r
+\r
+/**\r
+ * Load scripts asynchronously.\r
+ * @namespace\r
+ * @example\r
+ */\r
+CKEDITOR.scriptLoader = (function()\r
+{\r
+ var uniqueScripts = {},\r
+ waitingList = {};\r
+\r
+ return /** @lends CKEDITOR.scriptLoader */ {\r
+ /**\r
+ * Loads one or more external script checking if not already loaded\r
+ * previously by this function.\r
+ * @param {String|Array} scriptUrl One or more URLs pointing to the\r
+ * scripts to be loaded.\r
+ * @param {Function} [callback] A function to be called when the script\r
+ * is loaded and executed. If a string is passed to "scriptUrl", a\r
+ * boolean parameter is passed to the callback, indicating the\r
+ * success of the load. If an array is passed instead, two array\r
+ * parameters are passed to the callback; the first contains the\r
+ * URLs that have been properly loaded, and the second the failed\r
+ * ones.\r
+ * @param {Object} [scope] The scope ("this" reference) to be used for\r
+ * the callback call. Default to {@link CKEDITOR}.\r
+ * @param {Boolean} [showBusy] Changes the cursor of the document while\r
++ * the script is loaded.\r
+ * @example\r
+ * CKEDITOR.scriptLoader.load( '/myscript.js' );\r
+ * @example\r
+ * CKEDITOR.scriptLoader.load( '/myscript.js', function( success )\r
+ * {\r
+ * // Alerts "true" if the script has been properly loaded.\r
+ * // HTTP error 404 should return "false".\r
+ * alert( success );\r
+ * });\r
+ * @example\r
+ * CKEDITOR.scriptLoader.load( [ '/myscript1.js', '/myscript2.js' ], function( completed, failed )\r
+ * {\r
+ * alert( 'Number of scripts loaded: ' + completed.length );\r
+ * alert( 'Number of failures: ' + failed.length );\r
+ * });\r
+ */\r
+ load : function( scriptUrl, callback, scope, showBusy )\r
+ {\r
+ var isString = ( typeof scriptUrl == 'string' );\r
+\r
+ if ( isString )\r
+ scriptUrl = [ scriptUrl ];\r
+\r
+ if ( !scope )\r
+ scope = CKEDITOR;\r
+\r
+ var scriptCount = scriptUrl.length,\r
+ completed = [],\r
+ failed = [];\r
+\r
+ var doCallback = function( success )\r
+ {\r
+ if ( callback )\r
+ {\r
+ if ( isString )\r
+ callback.call( scope, success );\r
+ else\r
+ callback.call( scope, completed, failed );\r
+ }\r
+ };\r
+\r
+ if ( scriptCount === 0 )\r
+ {\r
+ doCallback( true );\r
+ return;\r
+ }\r
+\r
+ var checkLoaded = function( url, success )\r
+ {\r
+ ( success ? completed : failed ).push( url );\r
+\r
+ if ( --scriptCount <= 0 )\r
+ {\r
+ showBusy && CKEDITOR.document.getDocumentElement().removeStyle( 'cursor' );\r
+ doCallback( success );\r
+ }\r
+ };\r
+\r
+ var onLoad = function( url, success )\r
+ {\r
+ // Mark this script as loaded.\r
+ uniqueScripts[ url ] = 1;\r
+\r
+ // Get the list of callback checks waiting for this file.\r
+ var waitingInfo = waitingList[ url ];\r
+ delete waitingList[ url ];\r
+\r
+ // Check all callbacks waiting for this file.\r
+ for ( var i = 0 ; i < waitingInfo.length ; i++ )\r
+ waitingInfo[ i ]( url, success );\r
+ };\r
+\r
+ var loadScript = function( url )\r
+ {\r
+ if ( uniqueScripts[ url ] )\r
+ {\r
+ checkLoaded( url, true );\r
+ return;\r
+ }\r
+\r
+ var waitingInfo = waitingList[ url ] || ( waitingList[ url ] = [] );\r
+ waitingInfo.push( checkLoaded );\r
+\r
+ // Load it only for the first request.\r
+ if ( waitingInfo.length > 1 )\r
+ return;\r
+\r
+ // Create the <script> element.\r
+ var script = new CKEDITOR.dom.element( 'script' );\r
+ script.setAttributes( {\r
+ type : 'text/javascript',\r
+ src : url } );\r
+\r
+ if ( callback )\r
+ {\r
+ if ( CKEDITOR.env.ie )\r
+ {\r
+ // FIXME: For IE, we are not able to return false on error (like 404).\r
+\r
+ /** @ignore */\r
+ script.$.onreadystatechange = function ()\r
+ {\r
+ if ( script.$.readyState == 'loaded' || script.$.readyState == 'complete' )\r
+ {\r
+ script.$.onreadystatechange = null;\r
+ onLoad( url, true );\r
+ }\r
+ };\r
+ }\r
+ else\r
+ {\r
+ /** @ignore */\r
+ script.$.onload = function()\r
+ {\r
+ // Some browsers, such as Safari, may call the onLoad function\r
+ // immediately. Which will break the loading sequence. (#3661)\r
+ setTimeout( function() { onLoad( url, true ); }, 0 );\r
+ };\r
+\r
+ // FIXME: Opera and Safari will not fire onerror.\r
+\r
+ /** @ignore */\r
+ script.$.onerror = function()\r
+ {\r
+ onLoad( url, false );\r
+ };\r
+ }\r
+ }\r
+\r
+ // Append it to <head>.\r
+ script.appendTo( CKEDITOR.document.getHead() );\r
+\r
+ CKEDITOR.fire( 'download', url ); // @Packager.RemoveLine\r
+ };\r
+\r
+ showBusy && CKEDITOR.document.getDocumentElement().setStyle( 'cursor', 'wait' );\r
+ for ( var i = 0 ; i < scriptCount ; i++ )\r
+ {\r
+ loadScript( scriptUrl[ i ] );\r
+ }\r
+ }\r
+ };\r
+})();\r