loader.js 7.5 KB

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