1 /* 2 Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. 3 For licensing, see LICENSE.html 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 = {}; 13 14 if ( !CKEDITOR.loader ) 15 { 16 /** 17 * Load core scripts and their dependencies from _source. 18 * @namespace 19 * @example 20 */ 21 CKEDITOR.loader = (function() 22 { 23 // Table of script names and their dependencies. 24 var scripts = 25 { 26 'core/_bootstrap' : [ 'core/config', 'core/ckeditor', 'core/plugins', 'core/scriptloader', 'core/tools', /* The following are entries that we want to force loading at the end to avoid dependence recursion */ 'core/dom/comment', 'core/dom/elementpath', 'core/dom/text', 'core/dom/rangelist' ], 27 'core/ckeditor' : [ 'core/ckeditor_basic', 'core/dom', 'core/dtd', 'core/dom/document', 'core/dom/element', 'core/editor', 'core/event', 'core/htmlparser', 'core/htmlparser/element', 'core/htmlparser/fragment', 'core/htmlparser/filter', 'core/htmlparser/basicwriter', 'core/tools' ], 28 'core/ckeditor_base' : [], 29 'core/ckeditor_basic' : [ 'core/editor_basic', 'core/env', 'core/event' ], 30 'core/command' : [], 31 'core/config' : [ 'core/ckeditor_base' ], 32 'core/dom' : [], 33 'core/dom/comment' : [ 'core/dom/node' ], 34 'core/dom/document' : [ 'core/dom', 'core/dom/domobject', 'core/dom/window' ], 35 'core/dom/documentfragment' : [ 'core/dom/element' ], 36 'core/dom/element' : [ 'core/dom', 'core/dom/document', 'core/dom/domobject', 'core/dom/node', 'core/dom/nodelist', 'core/tools' ], 37 'core/dom/elementpath' : [ 'core/dom/element' ], 38 'core/dom/event' : [], 39 'core/dom/node' : [ 'core/dom/domobject', 'core/tools' ], 40 'core/dom/nodelist' : [ 'core/dom/node' ], 41 'core/dom/domobject' : [ 'core/dom/event' ], 42 'core/dom/range' : [ 'core/dom/document', 'core/dom/documentfragment', 'core/dom/element', 'core/dom/walker' ], 43 'core/dom/rangelist' : [ 'core/dom/range' ], 44 'core/dom/text' : [ 'core/dom/node', 'core/dom/domobject' ], 45 'core/dom/walker' : [ 'core/dom/node' ], 46 'core/dom/window' : [ 'core/dom/domobject' ], 47 'core/dtd' : [ 'core/tools' ], 48 'core/editor' : [ 'core/command', 'core/config', 'core/editor_basic', 'core/focusmanager', 'core/lang', 'core/plugins', 'core/skins', 'core/themes', 'core/tools', 'core/ui' ], 49 'core/editor_basic' : [ 'core/event' ], 50 'core/env' : [], 51 'core/event' : [], 52 'core/focusmanager' : [], 53 'core/htmlparser' : [], 54 'core/htmlparser/comment' : [ 'core/htmlparser' ], 55 'core/htmlparser/element' : [ 'core/htmlparser', 'core/htmlparser/fragment' ], 56 'core/htmlparser/fragment' : [ 'core/htmlparser', 'core/htmlparser/comment', 'core/htmlparser/text', 'core/htmlparser/cdata' ], 57 'core/htmlparser/text' : [ 'core/htmlparser' ], 58 'core/htmlparser/cdata' : [ 'core/htmlparser' ], 59 'core/htmlparser/filter' : [ 'core/htmlparser' ], 60 'core/htmlparser/basicwriter': [ 'core/htmlparser' ], 61 'core/lang' : [], 62 'core/plugins' : [ 'core/resourcemanager' ], 63 'core/resourcemanager' : [ 'core/scriptloader', 'core/tools' ], 64 'core/scriptloader' : [ 'core/dom/element', 'core/env' ], 65 'core/skins' : [ 'core/scriptloader' ], 66 'core/themes' : [ 'core/resourcemanager' ], 67 'core/tools' : [ 'core/env' ], 68 'core/ui' : [] 69 }; 70 71 var basePath = (function() 72 { 73 // This is a copy of CKEDITOR.basePath, but requires the script having 74 // "_source/core/loader.js". 75 if ( CKEDITOR && CKEDITOR.basePath ) 76 return CKEDITOR.basePath; 77 78 // Find out the editor directory path, based on its <script> tag. 79 var path = ''; 80 var scripts = document.getElementsByTagName( 'script' ); 81 82 for ( var i = 0 ; i < scripts.length ; i++ ) 83 { 84 var match = scripts[i].src.match( /(^|.*?[\\\/])(?:_source\/)?core\/loader.js(?:\?.*)?$/i ); 85 86 if ( match ) 87 { 88 path = match[1]; 89 break; 90 } 91 } 92 93 // In IE (only) the script.src string is the raw valued entered in the 94 // HTML. Other browsers return the full resolved URL instead. 95 if ( path.indexOf('://') == -1 ) 96 { 97 // Absolute path. 98 if ( path.indexOf( '/' ) === 0 ) 99 path = location.href.match( /^.*?:\/\/[^\/]*/ )[0] + path; 100 // Relative path. 101 else 102 path = location.href.match( /^[^\?]*\// )[0] + path; 103 } 104 105 return path; 106 })(); 107 108 var timestamp = ( CKEDITOR && CKEDITOR.timestamp ) || ( new Date() ).valueOf(); // %REMOVE_LINE% 109 /* // %REMOVE_LINE% 110 * The production implementation contains a fixed timestamp // %REMOVE_LINE% 111 * generated by the releaser // %REMOVE_LINE% 112 var timestamp = '%TIMESTAMP%'; 113 */ // %REMOVE_LINE% 114 115 var getUrl = function( resource ) 116 { 117 if ( CKEDITOR && CKEDITOR.getUrl ) 118 return CKEDITOR.getUrl( resource ); 119 120 return basePath + resource + 121 ( resource.indexOf( '?' ) >= 0 ? '&' : '?' ) + 122 't=' + timestamp; 123 }; 124 125 var pendingLoad = []; 126 127 /** @lends CKEDITOR.loader */ 128 return { 129 /** 130 * The list of loaded scripts in their loading order. 131 * @type Array 132 * @example 133 * // Alert the loaded script names. 134 * alert( <b>CKEDITOR.loader.loadedScripts</b> ); 135 */ 136 loadedScripts : [], 137 138 loadPending : function() 139 { 140 var scriptName = pendingLoad.shift(); 141 142 if ( !scriptName ) 143 return; 144 145 var scriptSrc = getUrl( '_source/' + scriptName + '.js' ); 146 147 var script = document.createElement( 'script' ); 148 script.type = 'text/javascript'; 149 script.src = scriptSrc; 150 151 function onScriptLoaded() 152 { 153 // Append this script to the list of loaded scripts. 154 CKEDITOR.loader.loadedScripts.push( scriptName ); 155 156 // Load the next. 157 CKEDITOR.loader.loadPending(); 158 } 159 160 // We must guarantee the execution order of the scripts, so we 161 // need to load them one by one. (#4145) 162 // The following if/else block has been taken from the scriptloader core code. 163 if ( typeof(script.onreadystatechange) !== "undefined" ) 164 { 165 /** @ignore */ 166 script.onreadystatechange = function() 167 { 168 if ( script.readyState == 'loaded' || script.readyState == 'complete' ) 169 { 170 script.onreadystatechange = null; 171 onScriptLoaded(); 172 } 173 }; 174 } 175 else 176 { 177 /** @ignore */ 178 script.onload = function() 179 { 180 // Some browsers, such as Safari, may call the onLoad function 181 // immediately. Which will break the loading sequence. (#3661) 182 setTimeout( function() { onScriptLoaded( scriptName ); }, 0 ); 183 }; 184 } 185 186 document.body.appendChild( script ); 187 }, 188 189 /** 190 * Loads a specific script, including its dependencies. This is not a 191 * synchronous loading, which means that the code to be loaded will 192 * not necessarily be available after this call. 193 * @example 194 * CKEDITOR.loader.load( 'core/dom/element' ); 195 */ 196 load : function( scriptName, defer ) 197 { 198 // Check if the script has already been loaded. 199 if ( scriptName in this.loadedScripts ) 200 return; 201 202 // Get the script dependencies list. 203 var dependencies = scripts[ scriptName ]; 204 if ( !dependencies ) 205 throw 'The script name"' + scriptName + '" is not defined.'; 206 207 // Mark the script as loaded, even before really loading it, to 208 // avoid cross references recursion. 209 this.loadedScripts[ scriptName ] = true; 210 211 // Load all dependencies first. 212 for ( var i = 0 ; i < dependencies.length ; i++ ) 213 this.load( dependencies[ i ], true ); 214 215 var scriptSrc = getUrl( '_source/' + scriptName + '.js' ); 216 217 // Append the <script> element to the DOM. 218 // If the page is fully loaded, we can't use document.write 219 // but if the script is run while the body is loading then it's safe to use it 220 // Unfortunately, Firefox <3.6 doesn't support document.readyState, so it won't get this improvement 221 if ( document.body && (!document.readyState || document.readyState == 'complete') ) 222 { 223 pendingLoad.push( scriptName ); 224 225 if ( !defer ) 226 this.loadPending(); 227 } 228 else 229 { 230 // Append this script to the list of loaded scripts. 231 this.loadedScripts.push( scriptName ); 232 233 document.write( '<script src="' + scriptSrc + '" type="text/javascript"><\/script>' ); 234 } 235 } 236 }; 237 })(); 238 } 239 240 // Check if any script has been defined for autoload. 241 if ( CKEDITOR._autoLoad ) 242 { 243 CKEDITOR.loader.load( CKEDITOR._autoLoad ); 244 delete CKEDITOR._autoLoad; 245 } 246