plugin.js 17 KB

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