JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
176ce05a1591f609b7c9b97a14c26bed9a413f11
[ckeditor.git] / _source / plugins / filebrowser / plugin.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 The "filebrowser" plugin, it adds support for file uploads and\r
8  *               browsing.\r
9  *\r
10  * When file is selected inside of the file browser or uploaded, its url is\r
11  * inserted automatically to a field, which is described in the 'filebrowser'\r
12  * attribute. To specify field that should be updated, pass the tab id and\r
13  * element id, separated with a colon.\r
14  *\r
15  * Example 1: (Browse)\r
16  *\r
17  * <pre>\r
18  * {\r
19  *      type : 'button',\r
20  *      id : 'browse',\r
21  *      filebrowser : 'tabId:elementId',\r
22  *      label : editor.lang.common.browseServer\r
23  * }\r
24  * </pre>\r
25  *\r
26  * If you set the 'filebrowser' attribute on any element other than\r
27  * 'fileButton', the 'Browse' action will be triggered.\r
28  *\r
29  * Example 2: (Quick Upload)\r
30  *\r
31  * <pre>\r
32  * {\r
33  *      type : 'fileButton',\r
34  *      id : 'uploadButton',\r
35  *      filebrowser : 'tabId:elementId',\r
36  *      label : editor.lang.common.uploadSubmit,\r
37  *      'for' : [ 'upload', 'upload' ]\r
38  * }\r
39  * </pre>\r
40  *\r
41  * If you set the 'filebrowser' attribute on a fileButton element, the\r
42  * 'QuickUpload' action will be executed.\r
43  *\r
44  * Filebrowser plugin also supports more advanced configuration (through\r
45  * javascript object).\r
46  *\r
47  * The following settings are supported:\r
48  *\r
49  * <pre>\r
50  *  [action] - Browse or QuickUpload\r
51  *  [target] - field to update, tabId:elementId\r
52  *  [params] - additional arguments to be passed to the server connector (optional)\r
53  *  [onSelect] - function to execute when file is selected/uploaded (optional)\r
54  *  [url] - the URL to be called (optional)\r
55  * </pre>\r
56  *\r
57  * Example 3: (Quick Upload)\r
58  *\r
59  * <pre>\r
60  * {\r
61  *      type : 'fileButton',\r
62  *      label : editor.lang.common.uploadSubmit,\r
63  *      id : 'buttonId',\r
64  *      filebrowser :\r
65  *      {\r
66  *              action : 'QuickUpload', //required\r
67  *              target : 'tab1:elementId', //required\r
68  *              params : //optional\r
69  *              {\r
70  *                      type : 'Files',\r
71  *                      currentFolder : '/folder/'\r
72  *              },\r
73  *              onSelect : function( fileUrl, errorMessage ) //optional\r
74  *              {\r
75  *                      // Do not call the built-in selectFuntion\r
76  *                      // return false;\r
77  *              }\r
78  *      },\r
79  *      'for' : [ 'tab1', 'myFile' ]\r
80  * }\r
81  * </pre>\r
82  *\r
83  * Suppose we have a file element with id 'myFile', text field with id\r
84  * 'elementId' and a fileButton. If filebowser.url is not specified explicitly,\r
85  * form action will be set to 'filebrowser[DialogName]UploadUrl' or, if not\r
86  * specified, to 'filebrowserUploadUrl'. Additional parameters from 'params'\r
87  * object will be added to the query string. It is possible to create your own\r
88  * uploadHandler and cancel the built-in updateTargetElement command.\r
89  *\r
90  * Example 4: (Browse)\r
91  *\r
92  * <pre>\r
93  * {\r
94  *      type : 'button',\r
95  *      id : 'buttonId',\r
96  *      label : editor.lang.common.browseServer,\r
97  *      filebrowser :\r
98  *      {\r
99  *              action : 'Browse',\r
100  *              url : '/ckfinder/ckfinder.html&amp;type=Images',\r
101  *              target : 'tab1:elementId'\r
102  *      }\r
103  * }\r
104  * </pre>\r
105  *\r
106  * In this example, after pressing a button, file browser will be opened in a\r
107  * popup. If we don't specify filebrowser.url attribute,\r
108  * 'filebrowser[DialogName]BrowseUrl' or 'filebrowserBrowseUrl' will be used.\r
109  * After selecting a file in a file browser, an element with id 'elementId' will\r
110  * be updated. Just like in the third example, a custom 'onSelect' function may be\r
111  * defined.\r
112  */\r
113 ( function()\r
114 {\r
115         /**\r
116          * Adds (additional) arguments to given url.\r
117          *\r
118          * @param {String}\r
119          *            url The url.\r
120          * @param {Object}\r
121          *            params Additional parameters.\r
122          */\r
123         function addQueryString( url, params )\r
124         {\r
125                 var queryString = [];\r
126 \r
127                 if ( !params )\r
128                         return url;\r
129                 else\r
130                 {\r
131                         for ( var i in params )\r
132                                 queryString.push( i + "=" + encodeURIComponent( params[ i ] ) );\r
133                 }\r
134 \r
135                 return url + ( ( url.indexOf( "?" ) != -1 ) ? "&" : "?" ) + queryString.join( "&" );\r
136         }\r
137 \r
138         /**\r
139          * Make a string's first character uppercase.\r
140          *\r
141          * @param {String}\r
142          *            str String.\r
143          */\r
144         function ucFirst( str )\r
145         {\r
146                 str += '';\r
147                 var f = str.charAt( 0 ).toUpperCase();\r
148                 return f + str.substr( 1 );\r
149         }\r
150 \r
151         /**\r
152          * The onlick function assigned to the 'Browse Server' button. Opens the\r
153          * file browser and updates target field when file is selected.\r
154          *\r
155          * @param {CKEDITOR.event}\r
156          *            evt The event object.\r
157          */\r
158         function browseServer( evt )\r
159         {\r
160                 var dialog = this.getDialog();\r
161                 var editor = dialog.getParentEditor();\r
162 \r
163                 editor._.filebrowserSe = this;\r
164 \r
165                 var width = editor.config[ 'filebrowser' + ucFirst( dialog.getName() ) + 'WindowWidth' ]\r
166                                 || editor.config.filebrowserWindowWidth || '80%';\r
167                 var height = editor.config[ 'filebrowser' + ucFirst( dialog.getName() ) + 'WindowHeight' ]\r
168                                 || editor.config.filebrowserWindowHeight || '70%';\r
169 \r
170                 var params = this.filebrowser.params || {};\r
171                 params.CKEditor = editor.name;\r
172                 params.CKEditorFuncNum = editor._.filebrowserFn;\r
173                 if ( !params.langCode )\r
174                         params.langCode = editor.langCode;\r
175 \r
176                 var url = addQueryString( this.filebrowser.url, params );\r
177                 editor.popup( url, width, height, editor.config.fileBrowserWindowFeatures );\r
178         }\r
179 \r
180         /**\r
181          * The onlick function assigned to the 'Upload' button. Makes the final\r
182          * decision whether form is really submitted and updates target field when\r
183          * file is uploaded.\r
184          *\r
185          * @param {CKEDITOR.event}\r
186          *            evt The event object.\r
187          */\r
188         function uploadFile( evt )\r
189         {\r
190                 var dialog = this.getDialog();\r
191                 var editor = dialog.getParentEditor();\r
192 \r
193                 editor._.filebrowserSe = this;\r
194 \r
195                 // If user didn't select the file, stop the upload.\r
196                 if ( !dialog.getContentElement( this[ 'for' ][ 0 ], this[ 'for' ][ 1 ] ).getInputElement().$.value )\r
197                         return false;\r
198 \r
199                 if ( !dialog.getContentElement( this[ 'for' ][ 0 ], this[ 'for' ][ 1 ] ).getAction() )\r
200                         return false;\r
201 \r
202                 return true;\r
203         }\r
204 \r
205         /**\r
206          * Setups the file element.\r
207          *\r
208          * @param {CKEDITOR.ui.dialog.file}\r
209          *            fileInput The file element used during file upload.\r
210          * @param {Object}\r
211          *            filebrowser Object containing filebrowser settings assigned to\r
212          *            the fileButton associated with this file element.\r
213          */\r
214         function setupFileElement( editor, fileInput, filebrowser )\r
215         {\r
216                 var params = filebrowser.params || {};\r
217                 params.CKEditor = editor.name;\r
218                 params.CKEditorFuncNum = editor._.filebrowserFn;\r
219                 if ( !params.langCode )\r
220                         params.langCode = editor.langCode;\r
221 \r
222                 fileInput.action = addQueryString( filebrowser.url, params );\r
223                 fileInput.filebrowser = filebrowser;\r
224         }\r
225 \r
226         /**\r
227          * Traverse through the content definition and attach filebrowser to\r
228          * elements with 'filebrowser' attribute.\r
229          *\r
230          * @param String\r
231          *            dialogName Dialog name.\r
232          * @param {CKEDITOR.dialog.dialogDefinitionObject}\r
233          *            definition Dialog definition.\r
234          * @param {Array}\r
235          *            elements Array of {@link CKEDITOR.dialog.contentDefinition}\r
236          *            objects.\r
237          */\r
238         function attachFileBrowser( editor, dialogName, definition, elements )\r
239         {\r
240                 var element, fileInput;\r
241 \r
242                 for ( var i in elements )\r
243                 {\r
244                         element = elements[ i ];\r
245 \r
246                         if ( element.type == 'hbox' || element.type == 'vbox' )\r
247                                 attachFileBrowser( editor, dialogName, definition, element.children );\r
248 \r
249                         if ( !element.filebrowser )\r
250                                 continue;\r
251 \r
252                         if ( typeof element.filebrowser == 'string' )\r
253                         {\r
254                                 var fb =\r
255                                 {\r
256                                         action : ( element.type == 'fileButton' ) ? 'QuickUpload' : 'Browse',\r
257                                         target : element.filebrowser\r
258                                 };\r
259                                 element.filebrowser = fb;\r
260                         }\r
261 \r
262                         if ( element.filebrowser.action == 'Browse' )\r
263                         {\r
264                                 var url = element.filebrowser.url || editor.config[ 'filebrowser' + ucFirst( dialogName ) + 'BrowseUrl' ]\r
265                                                         || editor.config.filebrowserBrowseUrl;\r
266 \r
267                                 if ( url )\r
268                                 {\r
269                                         element.onClick = browseServer;\r
270                                         element.filebrowser.url = url;\r
271                                         element.hidden = false;\r
272                                 }\r
273                         }\r
274                         else if ( element.filebrowser.action == 'QuickUpload' && element[ 'for' ] )\r
275                         {\r
276                                 url =  element.filebrowser.url || editor.config[ 'filebrowser' + ucFirst( dialogName ) + 'UploadUrl' ]\r
277                                                         || editor.config.filebrowserUploadUrl;\r
278 \r
279                                 if ( url )\r
280                                 {\r
281                                         var onClick = element.onClick;\r
282                                         element.onClick = function( evt )\r
283                                         {\r
284                                                 // "element" here means the definition object, so we need to find the correct\r
285                                                 // button to scope the event call\r
286                                                 var sender = evt.sender;\r
287                                                 if ( onClick && onClick.call( sender, evt ) === false )\r
288                                                         return false;\r
289 \r
290                                                 return uploadFile.call( sender, evt );\r
291                                         };\r
292 \r
293                                         element.filebrowser.url = url;\r
294                                         element.hidden = false;\r
295                                         setupFileElement( editor, definition.getContents( element[ 'for' ][ 0 ] ).get( element[ 'for' ][ 1 ] ), element.filebrowser );\r
296                                 }\r
297                         }\r
298                 }\r
299         }\r
300 \r
301         /**\r
302          * Updates the target element with the url of uploaded/selected file.\r
303          *\r
304          * @param {String}\r
305          *            url The url of a file.\r
306          */\r
307         function updateTargetElement( url, sourceElement )\r
308         {\r
309                 var dialog = sourceElement.getDialog();\r
310                 var targetElement = sourceElement.filebrowser.target || null;\r
311                 url = url.replace( /#/g, '%23' );\r
312 \r
313                 // If there is a reference to targetElement, update it.\r
314                 if ( targetElement )\r
315                 {\r
316                         var target = targetElement.split( ':' );\r
317                         var element = dialog.getContentElement( target[ 0 ], target[ 1 ] );\r
318                         if ( element )\r
319                         {\r
320                                 element.setValue( url );\r
321                                 dialog.selectPage( target[ 0 ] );\r
322                         }\r
323                 }\r
324         }\r
325 \r
326         /**\r
327          * Returns true if filebrowser is configured in one of the elements.\r
328          *\r
329          * @param {CKEDITOR.dialog.dialogDefinitionObject}\r
330          *            definition Dialog definition.\r
331          * @param String\r
332          *            tabId The tab id where element(s) can be found.\r
333          * @param String\r
334          *            elementId The element id (or ids, separated with a semicolon) to check.\r
335          */\r
336         function isConfigured( definition, tabId, elementId )\r
337         {\r
338                 if ( elementId.indexOf( ";" ) !== -1 )\r
339                 {\r
340                         var ids = elementId.split( ";" );\r
341                         for ( var i = 0 ; i < ids.length ; i++ )\r
342                         {\r
343                                 if ( isConfigured( definition, tabId, ids[i]) )\r
344                                         return true;\r
345                         }\r
346                         return false;\r
347                 }\r
348 \r
349                 var elementFileBrowser = definition.getContents( tabId ).get( elementId ).filebrowser;\r
350                 return ( elementFileBrowser && elementFileBrowser.url );\r
351         }\r
352 \r
353         function setUrl( fileUrl, data )\r
354         {\r
355                 var dialog = this._.filebrowserSe.getDialog(),\r
356                         targetInput = this._.filebrowserSe[ 'for' ],\r
357                         onSelect = this._.filebrowserSe.filebrowser.onSelect;\r
358 \r
359                 if ( targetInput )\r
360                         dialog.getContentElement( targetInput[ 0 ], targetInput[ 1 ] ).reset();\r
361 \r
362                 if ( typeof data == 'function' && data.call( this._.filebrowserSe ) === false )\r
363                         return;\r
364 \r
365                 if ( onSelect && onSelect.call( this._.filebrowserSe, fileUrl, data ) === false )\r
366                         return;\r
367 \r
368                 // The "data" argument may be used to pass the error message to the editor.\r
369                 if ( typeof data == 'string' && data )\r
370                         alert( data );\r
371 \r
372                 if ( fileUrl )\r
373                         updateTargetElement( fileUrl, this._.filebrowserSe );\r
374         }\r
375 \r
376         CKEDITOR.plugins.add( 'filebrowser',\r
377         {\r
378                 init : function( editor, pluginPath )\r
379                 {\r
380                         editor._.filebrowserFn = CKEDITOR.tools.addFunction( setUrl, editor );\r
381                 }\r
382         } );\r
383 \r
384         CKEDITOR.on( 'dialogDefinition', function( evt )\r
385         {\r
386                 var definition = evt.data.definition,\r
387                         element;\r
388                 // Associate filebrowser to elements with 'filebrowser' attribute.\r
389                 for ( var i in definition.contents )\r
390                 {\r
391                         if ( ( element = definition.contents[ i ] ) )\r
392                         {\r
393                                 attachFileBrowser( evt.editor, evt.data.name, definition, element.elements );\r
394                                 if ( element.hidden && element.filebrowser )\r
395                                 {\r
396                                         element.hidden = !isConfigured( definition, element[ 'id' ], element.filebrowser );\r
397                                 }\r
398                         }\r
399                 }\r
400         } );\r
401 \r
402 } )();\r
403 \r
404 /**\r
405  * The location of an external file browser, that should be launched when "Browse Server" button is pressed.\r
406  * If configured, the "Browse Server" button will appear in Link, Image and Flash dialogs.\r
407  * @see The <a href="http://docs.cksource.com/CKEditor_3.x/Developers_Guide/File_Browser_(Uploader)">File Browser/Uploader</a> documentation.\r
408  * @name CKEDITOR.config.filebrowserBrowseUrl\r
409  * @since 3.0\r
410  * @type String\r
411  * @default '' (empty string = disabled)\r
412  * @example\r
413  * config.filebrowserBrowseUrl = '/browser/browse.php';\r
414  */\r
415 \r
416 /**\r
417  * The location of a script that handles file uploads.\r
418  * If set, the "Upload" tab will appear in "Link", "Image" and "Flash" dialogs.\r
419  * @name CKEDITOR.config.filebrowserUploadUrl\r
420  * @see The <a href="http://docs.cksource.com/CKEditor_3.x/Developers_Guide/File_Browser_(Uploader)">File Browser/Uploader</a> documentation.\r
421  * @since 3.0\r
422  * @type String\r
423  * @default '' (empty string = disabled)\r
424  * @example\r
425  * config.filebrowserUploadUrl = '/uploader/upload.php';\r
426  */\r
427 \r
428 /**\r
429  * The location of an external file browser, that should be launched when "Browse Server" button is pressed in the Image dialog.\r
430  * If not set, CKEditor will use {@link CKEDITOR.config.filebrowserBrowseUrl}.\r
431  * @name CKEDITOR.config.filebrowserImageBrowseUrl\r
432  * @since 3.0\r
433  * @type String\r
434  * @default '' (empty string = disabled)\r
435  * @example\r
436  * config.filebrowserImageBrowseUrl = '/browser/browse.php?type=Images';\r
437  */\r
438 \r
439 /**\r
440  * The location of an external file browser, that should be launched when "Browse Server" button is pressed in the Flash dialog.\r
441  * If not set, CKEditor will use {@link CKEDITOR.config.filebrowserBrowseUrl}.\r
442  * @name CKEDITOR.config.filebrowserFlashBrowseUrl\r
443  * @since 3.0\r
444  * @type String\r
445  * @default '' (empty string = disabled)\r
446  * @example\r
447  * config.filebrowserFlashBrowseUrl = '/browser/browse.php?type=Flash';\r
448  */\r
449 \r
450 /**\r
451  * The location of a script that handles file uploads in the Image dialog.\r
452  * If not set, CKEditor will use {@link CKEDITOR.config.filebrowserUploadUrl}.\r
453  * @name CKEDITOR.config.filebrowserImageUploadUrl\r
454  * @since 3.0\r
455  * @type String\r
456  * @default '' (empty string = disabled)\r
457  * @example\r
458  * config.filebrowserImageUploadUrl = '/uploader/upload.php?type=Images';\r
459  */\r
460 \r
461 /**\r
462  * The location of a script that handles file uploads in the Flash dialog.\r
463  * If not set, CKEditor will use {@link CKEDITOR.config.filebrowserUploadUrl}.\r
464  * @name CKEDITOR.config.filebrowserFlashUploadUrl\r
465  * @since 3.0\r
466  * @type String\r
467  * @default '' (empty string = disabled)\r
468  * @example\r
469  * config.filebrowserFlashUploadUrl = '/uploader/upload.php?type=Flash';\r
470  */\r
471 \r
472 /**\r
473  * The location of an external file browser, that should be launched when "Browse Server" button is pressed in the Link tab of Image dialog.\r
474  * If not set, CKEditor will use {@link CKEDITOR.config.filebrowserBrowseUrl}.\r
475  * @name CKEDITOR.config.filebrowserImageBrowseLinkUrl\r
476  * @since 3.2\r
477  * @type String\r
478  * @default '' (empty string = disabled)\r
479  * @example\r
480  * config.filebrowserImageBrowseLinkUrl = '/browser/browse.php';\r
481  */\r
482 \r
483 /**\r
484  * The "features" to use in the file browser popup window.\r
485  * @name CKEDITOR.config.filebrowserWindowFeatures\r
486  * @since 3.4.1\r
487  * @type String\r
488  * @default 'location=no,menubar=no,toolbar=no,dependent=yes,minimizable=no,modal=yes,alwaysRaised=yes,resizable=yes,scrollbars=yes'\r
489  * @example\r
490  * config.filebrowserWindowFeatures = 'resizable=yes,scrollbars=no';\r
491  */\r