UNPKG

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