1 /* 2 * CKEditor - The text editor for Internet - http://ckeditor.com 3 * Copyright (C) 2003-2008 Frederico Caldeira Knabben 4 * 5 * == BEGIN LICENSE == 6 * 7 * Licensed under the terms of any of the following licenses at your 8 * choice: 9 * 10 * - GNU General Public License Version 2 or later (the "GPL") 11 * http://www.gnu.org/licenses/gpl.html 12 * 13 * - GNU Lesser General Public License Version 2.1 or later (the "LGPL") 14 * http://www.gnu.org/licenses/lgpl.html 15 * 16 * - Mozilla Public License Version 1.1 or later (the "MPL") 17 * http://www.mozilla.org/MPL/MPL-1.1.html 18 * 19 * == END LICENSE == 20 */ 21 22 /** 23 * @fileOverview Defines the {@link CKEDITOR.resourceManager} class, which is 24 * the base for resource managers, like plugins and themes. 25 */ 26 27 /** 28 * Base class for resource managers, like plugins and themes. This class is not 29 * intended to be used out of the CKEditor core code. 30 * @param {String} basePath The path for the resources folder. 31 * @param {String} fileName The name used for resource files. 32 * @namespace 33 * @example 34 */ 35 CKEDITOR.resourceManager = function( basePath, fileName ) 36 { 37 /** 38 * The base directory containing all resources. 39 * @name CKEDITOR.resourceManager.prototype.basePath 40 * @type String 41 * @example 42 */ 43 this.basePath = basePath; 44 45 /** 46 * The name used for resource files. 47 * @name CKEDITOR.resourceManager.prototype.fileName 48 * @type String 49 * @example 50 */ 51 this.fileName = fileName; 52 53 /** 54 * Contains references to all resources that have already been registered 55 * with {@link #add}. 56 * @name CKEDITOR.resourceManager.prototype.registered 57 * @type Object 58 * @example 59 */ 60 this.registered = {}; 61 62 /** 63 * Contains references to all resources that have already been loaded 64 * with {@link #load}. 65 * @name CKEDITOR.resourceManager.prototype.loaded 66 * @type Object 67 * @example 68 */ 69 this.loaded = {}; 70 71 /** 72 * Contains references to all resources that have already been registered 73 * with {@link #addExternal}. 74 * @name CKEDITOR.resourceManager.prototype.externals 75 * @type Object 76 * @example 77 */ 78 this.externals = {}; 79 80 /** 81 * @private 82 */ 83 this._ = 84 { 85 // List of callbacks waiting for plugins to be loaded. 86 waitingList : {} 87 }; 88 }; 89 90 CKEDITOR.resourceManager.prototype = 91 { 92 /** 93 * Registers a resource. 94 * @param {String} name The resource name. 95 * @param {Object} [definition] The resource definition. 96 * @example 97 * CKEDITOR.plugins.add( 'sample', { ... plugin definition ... } ); 98 * @see CKEDITOR.pluginDefinition 99 */ 100 add : function( name, definition ) 101 { 102 if ( this.registered[ name ] ) 103 throw '[CKEDITOR.resourceManager.add] The resource name "' + name + '" is already registered.'; 104 105 this.registered[ name ] = definition || {}; 106 }, 107 108 /** 109 * Gets the definition of a specific resource. 110 * @param {String} name The resource name. 111 * @type Object 112 * @example 113 * var definition = <b>CKEDITOR.plugins.get( 'sample' )</b>; 114 */ 115 get : function( name ) 116 { 117 return this.registered[ name ] || null; 118 }, 119 120 /** 121 * Get the full path for a specific loaded resource. 122 * @param {String} name The resource name. 123 * @type String 124 * @example 125 * alert( <b>CKEDITOR.plugins.getPath( 'sample' )</b> ); // "<editor path>/plugins/sample/" 126 */ 127 getPath : function( name ) 128 { 129 return this.loaded[ name ] || null; 130 }, 131 132 /** 133 * Registers a resource to be loaded from an external path instead of the core base path. 134 * @param {String} name The resource name. 135 * @param {String} path The resource external path. 136 * @example 137 * // Loads a plugin from '/myplugin/samples/plugin.js'. 138 * CKEDITOR.plugins.addExternal( 'sample', '/myplugins/sample/' ); 139 */ 140 addExternal : function( name, path ) 141 { 142 if ( this.registered[ name ] || this.externals[ name ] ) 143 throw '[CKEDITOR.resourceManager.import] The resource name "' + name + '" is already registered or imported.'; 144 145 this.externals[ name ] = path; 146 }, 147 148 /** 149 * Loads one or more resources. 150 * @param {String|Array} name The name of the resource to load. It may be a 151 * string with a single resource name, or an array with several names. 152 * @param {Function} callback A function to be called when all resources 153 * are loaded. The callback will receive an array containing all 154 * loaded names. 155 * @param {Object} [scope] The scope object to be used for the callback 156 * call. 157 * @example 158 * <b>CKEDITOR.plugins.load</b>( 'myplugin', function( plugins ) 159 * { 160 * alert( plugins[0] ); // "myplugin" 161 * }); 162 */ 163 load : function( name, callback, scope ) 164 { 165 // Ensure that we have an Array of names. 166 var names = CKEDITOR.tools.isArray( name ) ? name : [ name ]; 167 var total = names.length; 168 169 // Nothing to load, just call the callback. 170 if ( !total ) 171 { 172 callback.call( scope || window, names ); 173 return; 174 } 175 176 // This function is used to count the loaded plugins and call the 177 // callback when finished loading. 178 callback._loaded = 0; 179 callback._total = total; 180 var loadCheck = function( callback ) 181 { 182 if ( ++callback._loaded == callback._total ) 183 callback.call( scope || window, names ); 184 }; 185 186 var loaded = this.loaded, 187 waitingList = this._.waitingList; 188 189 var loadPlugin = function( name ) 190 { 191 // Calculate the plugin script path. 192 var path = this.externals[ name ] || ( this.basePath + name + '/' ); 193 var filePath = CKEDITOR.getUrl( path + this.fileName + '.js' ); 194 195 // Load the plugin script. 196 CKEDITOR.scriptLoader.load( filePath, function( success ) 197 { 198 if ( !success ) 199 throw '[CKEDITOR.resourceManager.load] Resource name "' + name + '" was not found at "' + filePath + '".'; 200 201 loaded[ name ] = path; 202 203 // Check all callbacks that were waiting for this 204 // resource. 205 for ( var j = 0 ; j < waitingInfo.length ; j++ ) 206 loadCheck( waitingInfo[ j ] ); 207 208 delete waitingList[ name ]; 209 }); 210 }; 211 212 // Loop through all names. 213 for ( var i = 0 ; i < names.length ; i++ ) 214 { 215 name = names[ i ]; 216 217 // If not loaded already. 218 if ( name && !loaded[ name ] && !this.registered[ name ] ) 219 { 220 var waitingInfo = waitingList[ name ] || ( waitingList[ name ] = [] ); 221 waitingInfo.push( callback ); 222 223 // If this is the first call for it, go ahead loading. 224 if ( waitingInfo.length == 1 ) 225 loadPlugin.call( this, name ); 226 } 227 else 228 loadCheck( callback ); 229 } 230 } 231 }; 232