]>
Commit | Line | Data |
---|---|---|
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.loader} objects, which is used to | |
8 | * load core scripts and their dependencies from _source. | |
9 | */ | |
10 | ||
11 | if ( typeof CKEDITOR == 'undefined' ) | |
12 | CKEDITOR = {}; // jshint ignore:line | |
13 | ||
14 | if ( !CKEDITOR.loader ) { | |
15 | /** | |
16 | * Load core scripts and their dependencies from _source. | |
17 | * | |
18 | * @class | |
19 | * @singleton | |
20 | */ | |
21 | CKEDITOR.loader = ( function() { | |
22 | // Table of script names and their dependencies. | |
23 | var scripts = { | |
24 | '_bootstrap': [ | |
25 | 'config', 'creators/inline', 'creators/themedui', 'editable', 'ckeditor', 'plugins', | |
26 | 'scriptloader', 'style', 'tools', | |
27 | // The following are entries that we want to force loading at the end to avoid dependence recursion. | |
28 | 'dom/comment', 'dom/elementpath', 'dom/text', 'dom/rangelist', 'skin' | |
29 | ], | |
30 | 'ckeditor': [ | |
31 | 'ckeditor_basic', 'log', 'dom', 'dtd', 'dom/document', 'dom/element', 'dom/iterator', 'editor', 'event', | |
32 | 'htmldataprocessor', 'htmlparser', 'htmlparser/element', 'htmlparser/fragment', 'htmlparser/filter', | |
33 | 'htmlparser/basicwriter', 'template', 'tools' | |
34 | ], | |
35 | 'ckeditor_base': [], | |
36 | 'ckeditor_basic': [ 'editor_basic', 'env', 'event' ], | |
37 | 'command': [], | |
38 | 'config': [ 'ckeditor_base' ], | |
39 | 'dom': [], | |
40 | 'dom/comment': [ 'dom/node' ], | |
41 | 'dom/document': [ 'dom/node', 'dom/window' ], | |
42 | 'dom/documentfragment': [ 'dom/element' ], | |
43 | 'dom/element': [ 'dom', 'dom/document', 'dom/domobject', 'dom/node', 'dom/nodelist', 'tools' ], | |
44 | 'dom/elementpath': [ 'dom/element' ], | |
45 | 'dom/event': [], | |
46 | 'dom/iterator': [ 'dom/range' ], | |
47 | 'dom/node': [ 'dom/domobject', 'tools' ], | |
48 | 'dom/nodelist': [ 'dom/node' ], | |
49 | 'dom/domobject': [ 'dom/event' ], | |
50 | 'dom/range': [ 'dom/document', 'dom/documentfragment', 'dom/element', 'dom/walker' ], | |
51 | 'dom/rangelist': [ 'dom/range' ], | |
52 | 'dom/text': [ 'dom/node', 'dom/domobject' ], | |
53 | 'dom/walker': [ 'dom/node' ], | |
54 | 'dom/window': [ 'dom/domobject' ], | |
55 | 'dtd': [ 'tools' ], | |
56 | 'editable': [ 'editor', 'tools' ], | |
57 | 'editor': [ | |
58 | 'command', 'config', 'editor_basic', 'filter', 'focusmanager', 'keystrokehandler', 'lang', | |
59 | 'plugins', 'tools', 'ui' | |
60 | ], | |
61 | 'editor_basic': [ 'event' ], | |
62 | 'env': [], | |
63 | 'event': [], | |
64 | 'filter': [ 'dtd', 'tools' ], | |
65 | 'focusmanager': [], | |
66 | 'htmldataprocessor': [ 'htmlparser', 'htmlparser/basicwriter', 'htmlparser/fragment', 'htmlparser/filter' ], | |
67 | 'htmlparser': [], | |
68 | 'htmlparser/comment': [ 'htmlparser', 'htmlparser/node' ], | |
69 | 'htmlparser/element': [ 'htmlparser', 'htmlparser/fragment', 'htmlparser/node' ], | |
70 | 'htmlparser/fragment': [ 'htmlparser', 'htmlparser/comment', 'htmlparser/text', 'htmlparser/cdata' ], | |
71 | 'htmlparser/text': [ 'htmlparser', 'htmlparser/node' ], | |
72 | 'htmlparser/cdata': [ 'htmlparser', 'htmlparser/node' ], | |
73 | 'htmlparser/filter': [ 'htmlparser' ], | |
74 | 'htmlparser/basicwriter': [ 'htmlparser' ], | |
75 | 'htmlparser/node': [ 'htmlparser' ], | |
76 | 'keystrokehandler': [ 'event' ], | |
77 | 'lang': [], | |
78 | 'log': [ 'ckeditor_basic' ], | |
79 | 'plugins': [ 'resourcemanager' ], | |
80 | 'resourcemanager': [ 'scriptloader', 'tools' ], | |
81 | 'scriptloader': [ 'dom/element', 'env' ], | |
82 | 'selection': [ 'dom/range', 'dom/walker' ], | |
83 | 'skin': [], | |
84 | 'style': [ 'selection' ], | |
85 | 'template': [], | |
86 | 'tools': [ 'env' ], | |
87 | 'ui': [], | |
88 | 'creators/themedui': [], | |
89 | 'creators/inline': [] | |
90 | }; | |
91 | ||
92 | // The production implementation contains a fixed timestamp generated by the releaser. | |
93 | var timestamp = '%TIMESTAMP%'; | |
94 | // The development implementation contains a current timestamp. // %REMOVE_LINE% | |
95 | timestamp = ( CKEDITOR && CKEDITOR.timestamp ) || ( new Date() ).valueOf(); // %REMOVE_LINE% | |
96 | ||
97 | var getUrl = function( resource ) { | |
98 | if ( CKEDITOR && CKEDITOR.getUrl ) | |
99 | return CKEDITOR.getUrl( resource ); | |
100 | ||
101 | return CKEDITOR.basePath + resource + ( resource.indexOf( '?' ) >= 0 ? '&' : '?' ) + 't=' + timestamp; | |
102 | }; | |
103 | ||
104 | var pendingLoad = []; | |
105 | ||
106 | return { | |
107 | /** | |
108 | * The list of loaded scripts in their loading order. | |
109 | * | |
110 | * // Alert the loaded script names. | |
111 | * alert( CKEDITOR.loader.loadedScripts ); | |
112 | */ | |
113 | loadedScripts: [], | |
114 | /** | |
115 | * Table of script names and their dependencies. | |
116 | * | |
117 | * @property {Array} | |
118 | */ | |
119 | scripts: scripts, | |
120 | ||
121 | /** | |
122 | * @todo | |
123 | */ | |
124 | loadPending: function() { | |
125 | var scriptName = pendingLoad.shift(); | |
126 | ||
127 | if ( !scriptName ) | |
128 | return; | |
129 | ||
130 | var scriptSrc = getUrl( 'core/' + scriptName + '.js' ); | |
131 | ||
132 | var script = document.createElement( 'script' ); | |
133 | script.type = 'text/javascript'; | |
134 | script.src = scriptSrc; | |
135 | ||
136 | function onScriptLoaded() { | |
137 | // Append this script to the list of loaded scripts. | |
138 | CKEDITOR.loader.loadedScripts.push( scriptName ); | |
139 | ||
140 | // Load the next. | |
141 | CKEDITOR.loader.loadPending(); | |
142 | } | |
143 | ||
144 | // We must guarantee the execution order of the scripts, so we | |
145 | // need to load them one by one. (http://dev.ckeditor.com/ticket/4145) | |
146 | // The following if/else block has been taken from the scriptloader core code. | |
147 | if ( typeof script.onreadystatechange !== 'undefined' ) { | |
148 | /** @ignore */ | |
149 | script.onreadystatechange = function() { | |
150 | if ( script.readyState == 'loaded' || script.readyState == 'complete' ) { | |
151 | script.onreadystatechange = null; | |
152 | onScriptLoaded(); | |
153 | } | |
154 | }; | |
155 | } else { | |
156 | /** @ignore */ | |
157 | script.onload = function() { | |
158 | // Some browsers, such as Safari, may call the onLoad function | |
159 | // immediately. Which will break the loading sequence. (http://dev.ckeditor.com/ticket/3661) | |
160 | setTimeout( function() { | |
161 | onScriptLoaded( scriptName ); | |
162 | }, 0 ); | |
163 | }; | |
164 | } | |
165 | ||
166 | document.body.appendChild( script ); | |
167 | }, | |
168 | ||
169 | /** | |
170 | * Loads a specific script, including its dependencies. This is not a | |
171 | * synchronous loading, which means that the code to be loaded will | |
172 | * not necessarily be available after this call. | |
173 | * | |
174 | * CKEDITOR.loader.load( 'dom/element' ); | |
175 | * | |
176 | * @param {String} scriptName | |
177 | * @param {Boolean} [defer=false] | |
178 | * @todo params | |
179 | */ | |
180 | load: function( scriptName, defer ) { | |
181 | // Check if the script has already been loaded. | |
182 | if ( ( 's:' + scriptName ) in this.loadedScripts ) | |
183 | return; | |
184 | ||
185 | // Get the script dependencies list. | |
186 | var dependencies = scripts[ scriptName ]; | |
187 | if ( !dependencies ) | |
188 | throw 'The script name"' + scriptName + '" is not defined.'; | |
189 | ||
190 | // Mark the script as loaded, even before really loading it, to | |
191 | // avoid cross references recursion. | |
192 | // Prepend script name with 's:' to avoid conflict with Array's methods. | |
193 | this.loadedScripts[ 's:' + scriptName ] = true; | |
194 | ||
195 | // Load all dependencies first. | |
196 | for ( var i = 0; i < dependencies.length; i++ ) | |
197 | this.load( dependencies[ i ], true ); | |
198 | ||
199 | var scriptSrc = getUrl( 'core/' + scriptName + '.js' ); | |
200 | ||
201 | // Append the <script> element to the DOM. | |
202 | // If the page is fully loaded, we can't use document.write | |
203 | // but if the script is run while the body is loading then it's safe to use it | |
204 | // Unfortunately, Firefox <3.6 doesn't support document.readyState, so it won't get this improvement | |
205 | if ( document.body && ( !document.readyState || document.readyState == 'complete' ) ) { | |
206 | pendingLoad.push( scriptName ); | |
207 | ||
208 | if ( !defer ) | |
209 | this.loadPending(); | |
210 | } else { | |
211 | // Append this script to the list of loaded scripts. | |
212 | this.loadedScripts.push( scriptName ); | |
213 | ||
214 | document.write( '<script src="' + scriptSrc + '" type="text/javascript"><\/script>' ); | |
215 | } | |
216 | } | |
217 | }; | |
218 | } )(); | |
219 | } | |
220 | ||
221 | // Check if any script has been defined for autoload. | |
222 | if ( CKEDITOR._autoLoad ) { | |
223 | CKEDITOR.loader.load( CKEDITOR._autoLoad ); | |
224 | delete CKEDITOR._autoLoad; | |
225 | } |