uploadadapter.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. /**
  2. * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. /* globals XMLHttpRequest, FormData */
  6. /**
  7. * @module adapter-ckfinder/uploadadapter
  8. */
  9. import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
  10. import FileRepository from '@ckeditor/ckeditor5-upload/src/filerepository';
  11. import { getCsrfToken } from './utils';
  12. /**
  13. * A plugin that enables CKFinder uploads in CKEditor 5.
  14. *
  15. * Configure the upload URL in
  16. * {@link module:adapter-ckfinder/uploadadapter~CKFinderAdapterConfig#uploadUrl `ckfinder.uploadUrl`}.
  17. *
  18. * @extends module:core/plugin~Plugin
  19. */
  20. export default class CKFinderUploadAdapter extends Plugin {
  21. /**
  22. * @inheritDoc
  23. */
  24. static get requires() {
  25. return [ FileRepository ];
  26. }
  27. /**
  28. * @inheritDoc
  29. */
  30. static get pluginName() {
  31. return 'CKFinderUploadAdapter';
  32. }
  33. /**
  34. * @inheritDoc
  35. */
  36. init() {
  37. const url = this.editor.config.get( 'ckfinder.uploadUrl' );
  38. if ( !url ) {
  39. return;
  40. }
  41. // Register CKFinderAdapter
  42. this.editor.plugins.get( FileRepository ).createUploadAdapter = loader => new UploadAdapter( loader, url, this.editor.t );
  43. }
  44. }
  45. /**
  46. * Upload adapter for CKFinder.
  47. *
  48. * @private
  49. * @implements module:upload/filerepository~UploadAdapter
  50. */
  51. class UploadAdapter {
  52. /**
  53. * Creates a new adapter instance.
  54. *
  55. * @param {module:upload/filerepository~FileLoader} loader
  56. * @param {String} url
  57. * @param {module:utils/locale~Locale#t} t
  58. */
  59. constructor( loader, url, t ) {
  60. /**
  61. * FileLoader instance to use during the upload.
  62. *
  63. * @member {module:upload/filerepository~FileLoader} #loader
  64. */
  65. this.loader = loader;
  66. /**
  67. * Upload URL.
  68. *
  69. * @member {String} #url
  70. */
  71. this.url = url;
  72. /**
  73. * Locale translation method.
  74. *
  75. * @member {module:utils/locale~Locale#t} #t
  76. */
  77. this.t = t;
  78. }
  79. /**
  80. * Starts the upload process.
  81. *
  82. * @see module:upload/filerepository~UploadAdapter#upload
  83. * @returns {Promise}
  84. */
  85. upload() {
  86. return new Promise( ( resolve, reject ) => {
  87. this._initRequest();
  88. this._initListeners( resolve, reject );
  89. this._sendRequest();
  90. } );
  91. }
  92. /**
  93. * Aborts the upload process.
  94. *
  95. * @see module:upload/filerepository~UploadAdapter#abort
  96. * @returns {Promise}
  97. */
  98. abort() {
  99. if ( this.xhr ) {
  100. this.xhr.abort();
  101. }
  102. }
  103. /**
  104. * Initializes the XMLHttpRequest object.
  105. *
  106. * @private
  107. */
  108. _initRequest() {
  109. const xhr = this.xhr = new XMLHttpRequest();
  110. xhr.open( 'POST', this.url, true );
  111. xhr.responseType = 'json';
  112. }
  113. /**
  114. * Initializes XMLHttpRequest listeners.
  115. *
  116. * @private
  117. * @param {Function} resolve Callback function to be called when the request is successful.
  118. * @param {Function} reject Callback function to be called when the request cannot be completed.
  119. */
  120. _initListeners( resolve, reject ) {
  121. const xhr = this.xhr;
  122. const loader = this.loader;
  123. const t = this.t;
  124. const genericError = t( 'Cannot upload file:' ) + ` ${ loader.file.name }.`;
  125. xhr.addEventListener( 'error', () => reject( genericError ) );
  126. xhr.addEventListener( 'abort', () => reject() );
  127. xhr.addEventListener( 'load', () => {
  128. const response = xhr.response;
  129. if ( !response || !response.uploaded ) {
  130. return reject( response && response.error && response.error.message ? response.error.message : genericError );
  131. }
  132. resolve( {
  133. default: response.url
  134. } );
  135. } );
  136. // Upload progress when it's supported.
  137. /* istanbul ignore else */
  138. if ( xhr.upload ) {
  139. xhr.upload.addEventListener( 'progress', evt => {
  140. if ( evt.lengthComputable ) {
  141. loader.uploadTotal = evt.total;
  142. loader.uploaded = evt.loaded;
  143. }
  144. } );
  145. }
  146. }
  147. /**
  148. * Prepares the data and sends the request.
  149. *
  150. * @private
  151. */
  152. _sendRequest() {
  153. // Prepare form data.
  154. const data = new FormData();
  155. data.append( 'upload', this.loader.file );
  156. data.append( 'ckCsrfToken', getCsrfToken() );
  157. // Send request.
  158. this.xhr.send( data );
  159. }
  160. }
  161. /**
  162. * The configuration of the {@link module:adapter-ckfinder/uploadadapter~CKFinderUploadAdapter CKFinder upload adapter}.
  163. *
  164. * Read more in {@link module:adapter-ckfinder/uploadadapter~CKFinderAdapterConfig}.
  165. *
  166. * @member {module:adapter-ckfinder/uploadadapter~CKFinderAdapterConfig} module:core/editor/editorconfig~EditorConfig#ckfinder
  167. */
  168. /**
  169. * The configuration of the {@link module:adapter-ckfinder/uploadadapter~CKFinderUploadAdapter CKFinder upload adapter}.
  170. *
  171. * ClassicEditor
  172. * .create( editorElement, {
  173. * ckfinder: {
  174. * uploadUrl: '/ckfinder/core/connector/php/connector.php?command=QuickUpload&type=Files&responseType=json'
  175. * }
  176. * } )
  177. * .then( ... )
  178. * .catch( ... );
  179. *
  180. * See {@link module:core/editor/editorconfig~EditorConfig all editor options}.
  181. *
  182. * @interface CKFinderAdapterConfig
  183. */
  184. /**
  185. * The URL to which files should be uploaded.
  186. *
  187. * @member {String} module:adapter-ckfinder/uploadadapter~CKFinderAdapterConfig#uploadUrl
  188. */