JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
vanilla ckeditor-3.6.2
[ckeditor.git] / _source / plugins / filebrowser / plugin.js
1 /*\r
2 Copyright (c) 2003-2011, 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' )\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                 url = url.replace( /#/g, '%23' );\r
325 \r
326                 // If there is a reference to targetElement, update it.\r
327                 if ( targetElement )\r
328                 {\r
329                         var target = targetElement.split( ':' );\r
330                         var element = dialog.getContentElement( target[ 0 ], target[ 1 ] );\r
331                         if ( element )\r
332                         {\r
333                                 element.setValue( url );\r
334                                 dialog.selectPage( target[ 0 ] );\r
335                         }\r
336                 }\r
337         }\r
338 \r
339         /*\r
340          * Returns true if filebrowser is configured in one of the elements.\r
341          *\r
342          * @param {CKEDITOR.dialog.definitionObject}\r
343          *            definition Dialog definition.\r
344          * @param String\r
345          *            tabId The tab id where element(s) can be found.\r
346          * @param String\r
347          *            elementId The element id (or ids, separated with a semicolon) to check.\r
348          */\r
349         function isConfigured( definition, tabId, elementId )\r
350         {\r
351                 if ( elementId.indexOf( ";" ) !== -1 )\r
352                 {\r
353                         var ids = elementId.split( ";" );\r
354                         for ( var i = 0 ; i < ids.length ; i++ )\r
355                         {\r
356                                 if ( isConfigured( definition, tabId, ids[i] ) )\r
357                                         return true;\r
358                         }\r
359                         return false;\r
360                 }\r
361 \r
362                 var elementFileBrowser = definition.getContents( tabId ).get( elementId ).filebrowser;\r
363                 return ( elementFileBrowser && elementFileBrowser.url );\r
364         }\r
365 \r
366         function setUrl( fileUrl, data )\r
367         {\r
368                 var dialog = this._.filebrowserSe.getDialog(),\r
369                         targetInput = this._.filebrowserSe[ 'for' ],\r
370                         onSelect = this._.filebrowserSe.filebrowser.onSelect;\r
371 \r
372                 if ( targetInput )\r
373                         dialog.getContentElement( targetInput[ 0 ], targetInput[ 1 ] ).reset();\r
374 \r
375                 if ( typeof data == 'function' && data.call( this._.filebrowserSe ) === false )\r
376                         return;\r
377 \r
378                 if ( onSelect && onSelect.call( this._.filebrowserSe, fileUrl, data ) === false )\r
379                         return;\r
380 \r
381                 // The "data" argument may be used to pass the error message to the editor.\r
382                 if ( typeof data == 'string' && data )\r
383                         alert( data );\r
384 \r
385                 if ( fileUrl )\r
386                         updateTargetElement( fileUrl, this._.filebrowserSe );\r
387         }\r
388 \r
389         CKEDITOR.plugins.add( 'filebrowser',\r
390         {\r
391                 init : function( editor, pluginPath )\r
392                 {\r
393                         editor._.filebrowserFn = CKEDITOR.tools.addFunction( setUrl, editor );\r
394                         editor.on( 'destroy', function () { CKEDITOR.tools.removeFunction( this._.filebrowserFn ); } );\r
395                 }\r
396         } );\r
397 \r
398         CKEDITOR.on( 'dialogDefinition', function( evt )\r
399         {\r
400                 var definition = evt.data.definition,\r
401                         element;\r
402                 // Associate filebrowser to elements with 'filebrowser' attribute.\r
403                 for ( var i in definition.contents )\r
404                 {\r
405                         if ( ( element = definition.contents[ i ] ) )\r
406                         {\r
407                                 attachFileBrowser( evt.editor, evt.data.name, definition, element.elements );\r
408                                 if ( element.hidden && element.filebrowser )\r
409                                 {\r
410                                         element.hidden = !isConfigured( definition, element[ 'id' ], element.filebrowser );\r
411                                 }\r
412                         }\r
413                 }\r
414         } );\r
415 \r
416 } )();\r
417 \r
418 /**\r
419  * The location of an external file browser that should be launched when the <strong>Browse Server</strong>\r
420  * button is pressed. If configured, the <strong>Browse Server</strong> button will appear in the\r
421  * <strong>Link</strong>, <strong>Image</strong>, and <strong>Flash</strong> dialog windows.\r
422  * @see The <a href="http://docs.cksource.com/CKEditor_3.x/Developers_Guide/File_Browser_(Uploader)">File Browser/Uploader</a> documentation.\r
423  * @name CKEDITOR.config.filebrowserBrowseUrl\r
424  * @since 3.0\r
425  * @type String\r
426  * @default <code>''</code> (empty string = disabled)\r
427  * @example\r
428  * config.filebrowserBrowseUrl = '/browser/browse.php';\r
429  */\r
430 \r
431 /**\r
432  * The location of the script that handles file uploads.\r
433  * If set, the <strong>Upload</strong> tab will appear in the <strong>Link</strong>, <strong>Image</strong>,\r
434  * and <strong>Flash</strong> dialog windows.\r
435  * @name CKEDITOR.config.filebrowserUploadUrl\r
436  * @see The <a href="http://docs.cksource.com/CKEditor_3.x/Developers_Guide/File_Browser_(Uploader)">File Browser/Uploader</a> documentation.\r
437  * @since 3.0\r
438  * @type String\r
439  * @default <code>''</code> (empty string = disabled)\r
440  * @example\r
441  * config.filebrowserUploadUrl = '/uploader/upload.php';\r
442  */\r
443 \r
444 /**\r
445  * The location of an external file browser that should be launched when the <strong>Browse Server</strong>\r
446  * button is pressed in the <strong>Image</strong> dialog window.\r
447  * If not set, CKEditor will use <code>{@link CKEDITOR.config.filebrowserBrowseUrl}</code>.\r
448  * @name CKEDITOR.config.filebrowserImageBrowseUrl\r
449  * @since 3.0\r
450  * @type String\r
451  * @default <code>''</code> (empty string = disabled)\r
452  * @example\r
453  * config.filebrowserImageBrowseUrl = '/browser/browse.php?type=Images';\r
454  */\r
455 \r
456 /**\r
457  * The location of an external file browser that should be launched when the <strong>Browse Server</strong>\r
458  * button is pressed in the <strong>Flash</strong> dialog window.\r
459  * If not set, CKEditor will use <code>{@link CKEDITOR.config.filebrowserBrowseUrl}</code>.\r
460  * @name CKEDITOR.config.filebrowserFlashBrowseUrl\r
461  * @since 3.0\r
462  * @type String\r
463  * @default <code>''</code> (empty string = disabled)\r
464  * @example\r
465  * config.filebrowserFlashBrowseUrl = '/browser/browse.php?type=Flash';\r
466  */\r
467 \r
468 /**\r
469  * The location of the script that handles file uploads in the <strong>Image</strong> dialog window.\r
470  * If not set, CKEditor will use <code>{@link CKEDITOR.config.filebrowserUploadUrl}</code>.\r
471  * @name CKEDITOR.config.filebrowserImageUploadUrl\r
472  * @since 3.0\r
473  * @type String\r
474  * @default <code>''</code> (empty string = disabled)\r
475  * @example\r
476  * config.filebrowserImageUploadUrl = '/uploader/upload.php?type=Images';\r
477  */\r
478 \r
479 /**\r
480  * The location of the script that handles file uploads in the <strong>Flash</strong> dialog window.\r
481  * If not set, CKEditor will use <code>{@link CKEDITOR.config.filebrowserUploadUrl}</code>.\r
482  * @name CKEDITOR.config.filebrowserFlashUploadUrl\r
483  * @since 3.0\r
484  * @type String\r
485  * @default <code>''</code> (empty string = disabled)\r
486  * @example\r
487  * config.filebrowserFlashUploadUrl = '/uploader/upload.php?type=Flash';\r
488  */\r
489 \r
490 /**\r
491  * The location of an external file browser that should be launched when the <strong>Browse Server</strong>\r
492  * button is pressed in the <strong>Link</strong> tab of the <strong>Image</strong> dialog window.\r
493  * If not set, CKEditor will use <code>{@link CKEDITOR.config.filebrowserBrowseUrl}</code>.\r
494  * @name CKEDITOR.config.filebrowserImageBrowseLinkUrl\r
495  * @since 3.2\r
496  * @type String\r
497  * @default <code>''</code> (empty string = disabled)\r
498  * @example\r
499  * config.filebrowserImageBrowseLinkUrl = '/browser/browse.php';\r
500  */\r
501 \r
502 /**\r
503  * The features to use in the file browser popup window.\r
504  * @name CKEDITOR.config.filebrowserWindowFeatures\r
505  * @since 3.4.1\r
506  * @type String\r
507  * @default <code>'location=no,menubar=no,toolbar=no,dependent=yes,minimizable=no,modal=yes,alwaysRaised=yes,resizable=yes,scrollbars=yes'</code>\r
508  * @example\r
509  * config.filebrowserWindowFeatures = 'resizable=yes,scrollbars=no';\r
510  */\r
511 \r
512 /**\r
513  * The width of the file browser popup window. It can be a number denoting a value in\r
514  * pixels or a percent string.\r
515  * @name CKEDITOR.config.filebrowserWindowWidth\r
516  * @type Number|String\r
517  * @default <code>'80%'</code>\r
518  * @example\r
519  * config.filebrowserWindowWidth = 750;\r
520  * @example\r
521  * config.filebrowserWindowWidth = '50%';\r
522  */\r
523 \r
524 /**\r
525  * The height of the file browser popup window. It can be a number denoting a value in\r
526  * pixels or a percent string.\r
527  * @name CKEDITOR.config.filebrowserWindowHeight\r
528  * @type Number|String\r
529  * @default <code>'70%'</code>\r
530  * @example\r
531  * config.filebrowserWindowHeight = 580;\r
532  * @example\r
533  * config.filebrowserWindowHeight = '50%';\r
534  */\r