diff options
Diffstat (limited to 'sources/core/scriptloader.js')
-rw-r--r-- | sources/core/scriptloader.js | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/sources/core/scriptloader.js b/sources/core/scriptloader.js new file mode 100644 index 0000000..a2b9cca --- /dev/null +++ b/sources/core/scriptloader.js | |||
@@ -0,0 +1,202 @@ | |||
1 | /** | ||
2 | * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
3 | * For licensing, see LICENSE.md or http://ckeditor.com/license | ||
4 | */ | ||
5 | |||
6 | /** | ||
7 | * @fileOverview Defines the {@link CKEDITOR.scriptLoader} object, used to load scripts | ||
8 | * asynchronously. | ||
9 | */ | ||
10 | |||
11 | /** | ||
12 | * Load scripts asynchronously. | ||
13 | * | ||
14 | * @class | ||
15 | * @singleton | ||
16 | */ | ||
17 | CKEDITOR.scriptLoader = ( function() { | ||
18 | var uniqueScripts = {}, | ||
19 | waitingList = {}; | ||
20 | |||
21 | return { | ||
22 | /** | ||
23 | * Loads one or more external script checking if not already loaded | ||
24 | * previously by this function. | ||
25 | * | ||
26 | * CKEDITOR.scriptLoader.load( '/myscript.js' ); | ||
27 | * | ||
28 | * CKEDITOR.scriptLoader.load( '/myscript.js', function( success ) { | ||
29 | * // Alerts true if the script has been properly loaded. | ||
30 | * // HTTP error 404 should return false. | ||
31 | * alert( success ); | ||
32 | * } ); | ||
33 | * | ||
34 | * CKEDITOR.scriptLoader.load( [ '/myscript1.js', '/myscript2.js' ], function( completed, failed ) { | ||
35 | * alert( 'Number of scripts loaded: ' + completed.length ); | ||
36 | * alert( 'Number of failures: ' + failed.length ); | ||
37 | * } ); | ||
38 | * | ||
39 | * @param {String/Array} scriptUrl One or more URLs pointing to the | ||
40 | * scripts to be loaded. | ||
41 | * @param {Function} [callback] A function to be called when the script | ||
42 | * is loaded and executed. If a string is passed to `scriptUrl`, a | ||
43 | * boolean parameter is passed to the callback, indicating the | ||
44 | * success of the load. If an array is passed instead, two arrays | ||
45 | * parameters are passed to the callback - the first contains the | ||
46 | * URLs that have been properly loaded and the second the failed ones. | ||
47 | * @param {Object} [scope] The scope (`this` reference) to be used for | ||
48 | * the callback call. Defaults to {@link CKEDITOR}. | ||
49 | * @param {Boolean} [showBusy] Changes the cursor of the document while | ||
50 | * the script is loaded. | ||
51 | */ | ||
52 | load: function( scriptUrl, callback, scope, showBusy ) { | ||
53 | var isString = ( typeof scriptUrl == 'string' ); | ||
54 | |||
55 | if ( isString ) | ||
56 | scriptUrl = [ scriptUrl ]; | ||
57 | |||
58 | if ( !scope ) | ||
59 | scope = CKEDITOR; | ||
60 | |||
61 | var scriptCount = scriptUrl.length, | ||
62 | completed = [], | ||
63 | failed = []; | ||
64 | |||
65 | var doCallback = function( success ) { | ||
66 | if ( callback ) { | ||
67 | if ( isString ) | ||
68 | callback.call( scope, success ); | ||
69 | else | ||
70 | callback.call( scope, completed, failed ); | ||
71 | } | ||
72 | }; | ||
73 | |||
74 | if ( scriptCount === 0 ) { | ||
75 | doCallback( true ); | ||
76 | return; | ||
77 | } | ||
78 | |||
79 | var checkLoaded = function( url, success ) { | ||
80 | ( success ? completed : failed ).push( url ); | ||
81 | |||
82 | if ( --scriptCount <= 0 ) { | ||
83 | showBusy && CKEDITOR.document.getDocumentElement().removeStyle( 'cursor' ); | ||
84 | doCallback( success ); | ||
85 | } | ||
86 | }; | ||
87 | |||
88 | var onLoad = function( url, success ) { | ||
89 | // Mark this script as loaded. | ||
90 | uniqueScripts[ url ] = 1; | ||
91 | |||
92 | // Get the list of callback checks waiting for this file. | ||
93 | var waitingInfo = waitingList[ url ]; | ||
94 | delete waitingList[ url ]; | ||
95 | |||
96 | // Check all callbacks waiting for this file. | ||
97 | for ( var i = 0; i < waitingInfo.length; i++ ) | ||
98 | waitingInfo[ i ]( url, success ); | ||
99 | }; | ||
100 | |||
101 | var loadScript = function( url ) { | ||
102 | if ( uniqueScripts[ url ] ) { | ||
103 | checkLoaded( url, true ); | ||
104 | return; | ||
105 | } | ||
106 | |||
107 | var waitingInfo = waitingList[ url ] || ( waitingList[ url ] = [] ); | ||
108 | waitingInfo.push( checkLoaded ); | ||
109 | |||
110 | // Load it only for the first request. | ||
111 | if ( waitingInfo.length > 1 ) | ||
112 | return; | ||
113 | |||
114 | // Create the <script> element. | ||
115 | var script = new CKEDITOR.dom.element( 'script' ); | ||
116 | script.setAttributes( { | ||
117 | type: 'text/javascript', | ||
118 | src: url | ||
119 | } ); | ||
120 | |||
121 | if ( callback ) { | ||
122 | // The onload or onerror event does not fire in IE8 and IE9 Quirks Mode (#14849). | ||
123 | if ( CKEDITOR.env.ie && ( CKEDITOR.env.version <= 8 || CKEDITOR.env.ie9Compat ) ) { | ||
124 | script.$.onreadystatechange = function() { | ||
125 | if ( script.$.readyState == 'loaded' || script.$.readyState == 'complete' ) { | ||
126 | script.$.onreadystatechange = null; | ||
127 | onLoad( url, true ); | ||
128 | } | ||
129 | }; | ||
130 | } else { | ||
131 | script.$.onload = function() { | ||
132 | // Some browsers, such as Safari, may call the onLoad function | ||
133 | // immediately. Which will break the loading sequence. (#3661) | ||
134 | setTimeout( function() { | ||
135 | onLoad( url, true ); | ||
136 | }, 0 ); | ||
137 | }; | ||
138 | |||
139 | script.$.onerror = function() { | ||
140 | onLoad( url, false ); | ||
141 | }; | ||
142 | } | ||
143 | } | ||
144 | |||
145 | // Append it to <head>. | ||
146 | script.appendTo( CKEDITOR.document.getHead() ); | ||
147 | |||
148 | CKEDITOR.fire( 'download', url ); // %REMOVE_LINE% | ||
149 | }; | ||
150 | |||
151 | showBusy && CKEDITOR.document.getDocumentElement().setStyle( 'cursor', 'wait' ); | ||
152 | for ( var i = 0; i < scriptCount; i++ ) { | ||
153 | loadScript( scriptUrl[ i ] ); | ||
154 | } | ||
155 | }, | ||
156 | |||
157 | /** | ||
158 | * Loads a script in a queue, so only one is loaded at the same time. | ||
159 | * | ||
160 | * @since 4.1.2 | ||
161 | * @param {String} scriptUrl URL pointing to the script to be loaded. | ||
162 | * @param {Function} [callback] A function to be called when the script | ||
163 | * is loaded and executed. A boolean parameter is passed to the callback, | ||
164 | * indicating the success of the load. | ||
165 | * | ||
166 | * @see CKEDITOR.scriptLoader#load | ||
167 | */ | ||
168 | queue: ( function() { | ||
169 | var pending = []; | ||
170 | |||
171 | // Loads the very first script from queue and removes it. | ||
172 | function loadNext() { | ||
173 | var script; | ||
174 | |||
175 | if ( ( script = pending[ 0 ] ) ) | ||
176 | this.load( script.scriptUrl, script.callback, CKEDITOR, 0 ); | ||
177 | } | ||
178 | |||
179 | return function( scriptUrl, callback ) { | ||
180 | var that = this; | ||
181 | |||
182 | // This callback calls the standard callback for the script | ||
183 | // and loads the very next script from pending list. | ||
184 | function callbackWrapper() { | ||
185 | callback && callback.apply( this, arguments ); | ||
186 | |||
187 | // Removed the just loaded script from the queue. | ||
188 | pending.shift(); | ||
189 | |||
190 | loadNext.call( that ); | ||
191 | } | ||
192 | |||
193 | // Let's add this script to the queue | ||
194 | pending.push( { scriptUrl: scriptUrl, callback: callbackWrapper } ); | ||
195 | |||
196 | // If the queue was empty, then start loading. | ||
197 | if ( pending.length == 1 ) | ||
198 | loadNext.call( this ); | ||
199 | }; | ||
200 | } )() | ||
201 | }; | ||
202 | } )(); | ||