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