JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
a38433e86510887a161cecb5246692e1ac47e439
[ckeditor.git] / resourcemanager.js
1 /*\r
2 Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.\r
3 For licensing, see LICENSE.html or http://ckeditor.com/license\r
4 */\r
5 \r
6 /**\r
7  * @fileOverview Defines the {@link CKEDITOR.resourceManager} class, which is\r
8  *              the base for resource managers, like plugins and themes.\r
9  */\r
10 \r
11  /**\r
12  * Base class for resource managers, like plugins and themes. This class is not\r
13  * intended to be used out of the CKEditor core code.\r
14  * @param {String} basePath The path for the resources folder.\r
15  * @param {String} fileName The name used for resource files.\r
16  * @namespace\r
17  * @example\r
18  */\r
19 CKEDITOR.resourceManager = function( basePath, fileName )\r
20 {\r
21         /**\r
22          * The base directory containing all resources.\r
23          * @name CKEDITOR.resourceManager.prototype.basePath\r
24          * @type String\r
25          * @example\r
26          */\r
27         this.basePath = basePath;\r
28 \r
29         /**\r
30          * The name used for resource files.\r
31          * @name CKEDITOR.resourceManager.prototype.fileName\r
32          * @type String\r
33          * @example\r
34          */\r
35         this.fileName = fileName;\r
36 \r
37         /**\r
38          * Contains references to all resources that have already been registered\r
39          * with {@link #add}.\r
40          * @name CKEDITOR.resourceManager.prototype.registered\r
41          * @type Object\r
42          * @example\r
43          */\r
44         this.registered = {};\r
45 \r
46         /**\r
47          * Contains references to all resources that have already been loaded\r
48          * with {@link #load}.\r
49          * @name CKEDITOR.resourceManager.prototype.loaded\r
50          * @type Object\r
51          * @example\r
52          */\r
53         this.loaded = {};\r
54 \r
55         /**\r
56          * Contains references to all resources that have already been registered\r
57          * with {@link #addExternal}.\r
58          * @name CKEDITOR.resourceManager.prototype.externals\r
59          * @type Object\r
60          * @example\r
61          */\r
62         this.externals = {};\r
63 \r
64         /**\r
65          * @private\r
66          */\r
67         this._ =\r
68         {\r
69                 // List of callbacks waiting for plugins to be loaded.\r
70                 waitingList : {}\r
71         };\r
72 };\r
73 \r
74 CKEDITOR.resourceManager.prototype =\r
75 {\r
76         /**\r
77          * Registers a resource.\r
78          * @param {String} name The resource name.\r
79          * @param {Object} [definition] The resource definition.\r
80          * @example\r
81          * CKEDITOR.plugins.add( 'sample', { ... plugin definition ... } );\r
82          * @see CKEDITOR.pluginDefinition\r
83          */\r
84         add : function( name, definition )\r
85         {\r
86                 if ( this.registered[ name ] )\r
87                         throw '[CKEDITOR.resourceManager.add] The resource name "' + name + '" is already registered.';\r
88 \r
89                 CKEDITOR.fire( name + CKEDITOR.tools.capitalize( this.fileName ) + 'Ready',\r
90                                 this.registered[ name ] = definition || {} );\r
91         },\r
92 \r
93         /**\r
94          * Gets the definition of a specific resource.\r
95          * @param {String} name The resource name.\r
96          * @type Object\r
97          * @example\r
98          * var definition = <b>CKEDITOR.plugins.get( 'sample' )</b>;\r
99          */\r
100         get : function( name )\r
101         {\r
102                 return this.registered[ name ] || null;\r
103         },\r
104 \r
105         /**\r
106          * Get the folder path for a specific loaded resource.\r
107          * @param {String} name The resource name.\r
108          * @type String\r
109          * @example\r
110          * alert( <b>CKEDITOR.plugins.getPath( 'sample' )</b> );  // "&lt;editor path&gt;/plugins/sample/"\r
111          */\r
112         getPath : function( name )\r
113         {\r
114                 var external = this.externals[ name ];\r
115                 return CKEDITOR.getUrl( ( external && external.dir ) || this.basePath + name + '/' );\r
116         },\r
117 \r
118         /**\r
119          * Get the file path for a specific loaded resource.\r
120          * @param {String} name The resource name.\r
121          * @type String\r
122          * @example\r
123          * alert( <b>CKEDITOR.plugins.getFilePath( 'sample' )</b> );  // "&lt;editor path&gt;/plugins/sample/plugin.js"\r
124          */\r
125         getFilePath : function( name )\r
126         {\r
127                 var external = this.externals[ name ];\r
128                 return CKEDITOR.getUrl(\r
129                                 this.getPath( name ) +\r
130                                 ( ( external && ( typeof external.file == 'string' ) ) ? external.file : this.fileName + '.js' ) );\r
131         },\r
132 \r
133         /**\r
134          * Registers one or more resources to be loaded from an external path\r
135          * instead of the core base path.\r
136          * @param {String} names The resource names, separated by commas.\r
137          * @param {String} path The path of the folder containing the resource.\r
138          * @param {String} [fileName] The resource file name. If not provided, the\r
139          *              default name is used; If provided with a empty string, will implicitly indicates that {@param path}\r
140          *              is already the full path.\r
141          * @example\r
142          * // Loads a plugin from '/myplugin/samples/plugin.js'.\r
143          * CKEDITOR.plugins.addExternal( 'sample', '/myplugins/sample/' );\r
144          * @example\r
145          * // Loads a plugin from '/myplugin/samples/my_plugin.js'.\r
146          * CKEDITOR.plugins.addExternal( 'sample', '/myplugins/sample/', 'my_plugin.js' );\r
147          * @example\r
148          * // Loads a plugin from '/myplugin/samples/my_plugin.js'.\r
149          * CKEDITOR.plugins.addExternal( 'sample', '/myplugins/sample/my_plugin.js', '' );\r
150          */\r
151         addExternal : function( names, path, fileName )\r
152         {\r
153                 names = names.split( ',' );\r
154                 for ( var i = 0 ; i < names.length ; i++ )\r
155                 {\r
156                         var name = names[ i ];\r
157 \r
158                         this.externals[ name ] =\r
159                         {\r
160                                 dir : path,\r
161                                 file : fileName\r
162                         };\r
163                 }\r
164         },\r
165 \r
166         /**\r
167          * Loads one or more resources.\r
168          * @param {String|Array} name The name of the resource to load. It may be a\r
169          *              string with a single resource name, or an array with several names.\r
170          * @param {Function} callback A function to be called when all resources\r
171          *              are loaded. The callback will receive an array containing all\r
172          *              loaded names.\r
173          * @param {Object} [scope] The scope object to be used for the callback\r
174          *              call.\r
175          * @example\r
176          * <b>CKEDITOR.plugins.load</b>( 'myplugin', function( plugins )\r
177          *     {\r
178          *         alert( plugins['myplugin'] );  // "object"\r
179          *     });\r
180          */\r
181         load : function( names, callback, scope )\r
182         {\r
183                 // Ensure that we have an array of names.\r
184                 if ( !CKEDITOR.tools.isArray( names ) )\r
185                         names = names ? [ names ] : [];\r
186 \r
187                 var loaded = this.loaded,\r
188                         registered = this.registered,\r
189                         urls = [],\r
190                         urlsNames = {},\r
191                         resources = {};\r
192 \r
193                 // Loop through all names.\r
194                 for ( var i = 0 ; i < names.length ; i++ )\r
195                 {\r
196                         var name = names[ i ];\r
197 \r
198                         if ( !name )\r
199                                 continue;\r
200 \r
201                         // If not available yet.\r
202                         if ( !loaded[ name ] && !registered[ name ] )\r
203                         {\r
204                                 var url = this.getFilePath( name );\r
205                                 urls.push( url );\r
206                                 if ( !( url in urlsNames ) )\r
207                                         urlsNames[ url ] = [];\r
208                                 urlsNames[ url ].push( name );\r
209                         }\r
210                         else\r
211                                 resources[ name ] = this.get( name );\r
212                 }\r
213 \r
214                 CKEDITOR.scriptLoader.load( urls, function( completed, failed )\r
215                         {\r
216                                 if ( failed.length )\r
217                                 {\r
218                                         throw '[CKEDITOR.resourceManager.load] Resource name "' + urlsNames[ failed[ 0 ] ].join( ',' )\r
219                                                 + '" was not found at "' + failed[ 0 ] + '".';\r
220                                 }\r
221 \r
222                                 for ( var i = 0 ; i < completed.length ; i++ )\r
223                                 {\r
224                                         var nameList = urlsNames[ completed[ i ] ];\r
225                                         for ( var j = 0 ; j < nameList.length ; j++ )\r
226                                         {\r
227                                                 var name = nameList[ j ];\r
228                                                 resources[ name ] = this.get( name );\r
229 \r
230                                                 loaded[ name ] = 1;\r
231                                         }\r
232                                 }\r
233 \r
234                                 callback.call( scope, resources );\r
235                         }\r
236                         , this);\r
237         }\r
238 };\r