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 | */
|
9 | import { Plugin } from 'ckeditor5/src/core';
|
10 | import { FileRepository } from 'ckeditor5/src/upload';
|
11 | import { 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 | */
|
22 | export 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 | */
|
50 | class 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 | }
|