UNPKG

4.38 kBJavaScriptView Raw
1/**
2 * @license Copyright (c) 2003-2023, 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/* globals XMLHttpRequest, FormData */
6/**
7 * @module adapter-ckfinder/uploadadapter
8 */
9import { Plugin } from 'ckeditor5/src/core';
10import { FileRepository } from 'ckeditor5/src/upload';
11import { getCsrfToken } from './utils';
12/**
13 * A plugin that enables file uploads in CKEditor 5 using the CKFinder server–side connector.
14 *
15 * See the {@glink features/file-management/ckfinder "CKFinder file manager integration"} guide to learn how to configure
16 * and use this feature as well as find out more about the full integration with the file manager
17 * provided by the {@link module:ckfinder/ckfinder~CKFinder} plugin.
18 *
19 * Check out the {@glink features/images/image-upload/image-upload comprehensive "Image upload overview"} guide to learn
20 * about other ways to upload images into CKEditor 5.
21 */
22export default class CKFinderUploadAdapter extends Plugin {
23 /**
24 * @inheritDoc
25 */
26 static get requires() {
27 return [FileRepository];
28 }
29 /**
30 * @inheritDoc
31 */
32 static get pluginName() {
33 return 'CKFinderUploadAdapter';
34 }
35 /**
36 * @inheritDoc
37 */
38 init() {
39 const url = this.editor.config.get('ckfinder.uploadUrl');
40 if (!url) {
41 return;
42 }
43 // Register CKFinderAdapter
44 this.editor.plugins.get(FileRepository).createUploadAdapter = loader => new UploadAdapter(loader, url, this.editor.t);
45 }
46}
47/**
48 * Upload adapter for CKFinder.
49 */
50class UploadAdapter {
51 /**
52 * Creates a new adapter instance.
53 */
54 constructor(loader, url, t) {
55 this.loader = loader;
56 this.url = url;
57 this.t = t;
58 }
59 /**
60 * Starts the upload process.
61 *
62 * @see module:upload/filerepository~UploadAdapter#upload
63 */
64 upload() {
65 return this.loader.file.then(file => {
66 return new Promise((resolve, reject) => {
67 this._initRequest();
68 this._initListeners(resolve, reject, file);
69 this._sendRequest(file);
70 });
71 });
72 }
73 /**
74 * Aborts the upload process.
75 *
76 * @see module:upload/filerepository~UploadAdapter#abort
77 */
78 abort() {
79 if (this.xhr) {
80 this.xhr.abort();
81 }
82 }
83 /**
84 * Initializes the XMLHttpRequest object.
85 */
86 _initRequest() {
87 const xhr = this.xhr = new XMLHttpRequest();
88 xhr.open('POST', this.url, true);
89 xhr.responseType = 'json';
90 }
91 /**
92 * Initializes XMLHttpRequest listeners.
93 *
94 * @param resolve Callback function to be called when the request is successful.
95 * @param reject Callback function to be called when the request cannot be completed.
96 * @param file File instance to be uploaded.
97 */
98 _initListeners(resolve, reject, file) {
99 const xhr = this.xhr;
100 const loader = this.loader;
101 const t = this.t;
102 const genericError = t('Cannot upload file:') + ` ${file.name}.`;
103 xhr.addEventListener('error', () => reject(genericError));
104 xhr.addEventListener('abort', () => reject());
105 xhr.addEventListener('load', () => {
106 const response = xhr.response;
107 if (!response || !response.uploaded) {
108 return reject(response && response.error && response.error.message ? response.error.message : genericError);
109 }
110 resolve({
111 default: response.url
112 });
113 });
114 // Upload progress when it's supported.
115 /* istanbul ignore else -- @preserve */
116 if (xhr.upload) {
117 xhr.upload.addEventListener('progress', evt => {
118 if (evt.lengthComputable) {
119 loader.uploadTotal = evt.total;
120 loader.uploaded = evt.loaded;
121 }
122 });
123 }
124 }
125 /**
126 * Prepares the data and sends the request.
127 *
128 * @param file File instance to be uploaded.
129 */
130 _sendRequest(file) {
131 // Prepare form data.
132 const data = new FormData();
133 data.append('upload', file);
134 data.append('ckCsrfToken', getCsrfToken());
135 // Send request.
136 this.xhr.send(data);
137 }
138}