• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ckeditor / ckeditor5 / 807a1e87-d3b1-42e0-818f-814095f68d29

08 Sep 2023 12:24PM UTC coverage: 100.0%. Remained the same
807a1e87-d3b1-42e0-818f-814095f68d29

push

circleci

illia-stv
Fix (ckbox): remove focus helper

12401 of 12401 branches covered (100.0%)

Branch coverage included in aggregate %.

32590 of 32590 relevant lines covered (100.0%)

11872.08 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

100.0
/packages/ckeditor5-adapter-ckfinder/src/uploadadapter.ts
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

6
/* globals XMLHttpRequest, FormData */
7

8
/**
9
 * @module adapter-ckfinder/uploadadapter
10
 */
11

12
import { Plugin } from 'ckeditor5/src/core';
13
import {
14
        FileRepository,
15
        type UploadAdapter as UploadAdapterInterface,
16
        type FileLoader,
17
        type UploadResponse
18
} from 'ckeditor5/src/upload';
19
import type { LocaleTranslate } from 'ckeditor5/src/utils';
20

21
import { getCsrfToken } from './utils';
22

23
/**
24
 * A plugin that enables file uploads in CKEditor 5 using the CKFinder server–side connector.
25
 *
26
 * See the {@glink features/file-management/ckfinder "CKFinder file manager integration"} guide to learn how to configure
27
 * and use this feature as well as find out more about the full integration with the file manager
28
 * provided by the {@link module:ckfinder/ckfinder~CKFinder} plugin.
29
 *
30
 * Check out the {@glink features/images/image-upload/image-upload comprehensive "Image upload overview"} guide to learn
31
 * about other ways to upload images into CKEditor 5.
32
 */
33
export default class CKFinderUploadAdapter extends Plugin {
34
        /**
35
         * @inheritDoc
36
         */
37
        public static get requires() {
38
                return [ FileRepository ] as const;
60✔
39
        }
40

41
        /**
42
         * @inheritDoc
43
         */
44
        public static get pluginName() {
45
                return 'CKFinderUploadAdapter' as const;
48✔
46
        }
47

48
        /**
49
         * @inheritDoc
50
         */
51
        public init(): void {
52
                const url = this.editor.config.get( 'ckfinder.uploadUrl' )! as string;
12✔
53

54
                if ( !url ) {
12✔
55
                        return;
1✔
56
                }
57

58
                // Register CKFinderAdapter
59
                this.editor.plugins.get( FileRepository ).createUploadAdapter = loader => new UploadAdapter( loader, url, this.editor.t );
20✔
60
        }
61
}
62

63
/**
64
 * Upload adapter for CKFinder.
65
 */
66
class UploadAdapter implements UploadAdapterInterface {
67
        /**
68
         * FileLoader instance to use during the upload.
69
         */
70
        public loader: FileLoader;
71

72
        /**
73
         * Upload URL.
74
         */
75
        public url: string;
76

77
        /**
78
         * Locale translation method.
79
         */
80
        public t: LocaleTranslate;
81

82
        private xhr?: XMLHttpRequest;
83

84
        /**
85
         * Creates a new adapter instance.
86
         */
87
        constructor( loader: FileLoader, url: string, t: LocaleTranslate ) {
88
                this.loader = loader;
20✔
89
                this.url = url;
20✔
90
                this.t = t;
20✔
91
        }
92

93
        /**
94
         * Starts the upload process.
95
         *
96
         * @see module:upload/filerepository~UploadAdapter#upload
97
         */
98
        public upload() {
99
                return this.loader.file.then( file => {
7✔
100
                        return new Promise<UploadResponse>( ( resolve, reject ) => {
7✔
101
                                this._initRequest();
7✔
102
                                this._initListeners( resolve, reject, file! );
7✔
103
                                this._sendRequest( file! );
7✔
104
                        } );
105
                } );
106
        }
107

108
        /**
109
         * Aborts the upload process.
110
         *
111
         * @see module:upload/filerepository~UploadAdapter#abort
112
         */
113
        public abort() {
114
                if ( this.xhr ) {
2✔
115
                        this.xhr.abort();
1✔
116
                }
117
        }
118

119
        /**
120
         * Initializes the XMLHttpRequest object.
121
         */
122
        private _initRequest() {
123
                const xhr = this.xhr = new XMLHttpRequest();
7✔
124

125
                xhr.open( 'POST', this.url, true );
7✔
126
                xhr.responseType = 'json';
7✔
127
        }
128

129
        /**
130
         * Initializes XMLHttpRequest listeners.
131
         *
132
         * @param resolve Callback function to be called when the request is successful.
133
         * @param reject Callback function to be called when the request cannot be completed.
134
         * @param file File instance to be uploaded.
135
         */
136
        private _initListeners(
137
                resolve: ( value: UploadResponse ) => void,
138
                reject: ( reason?: unknown ) => void,
139
                file: File
140
        ) {
141
                const xhr = this.xhr!;
7✔
142
                const loader = this.loader;
7✔
143
                const t = this.t;
7✔
144
                const genericError = t( 'Cannot upload file:' ) + ` ${ file.name }.`;
7✔
145

146
                xhr.addEventListener( 'error', () => reject( genericError ) );
7✔
147
                xhr.addEventListener( 'abort', () => reject() );
7✔
148
                xhr.addEventListener( 'load', () => {
7✔
149
                        const response = xhr.response;
3✔
150

151
                        if ( !response || !response.uploaded ) {
3✔
152
                                return reject( response && response.error && response.error.message ? response.error.message : genericError );
2✔
153
                        }
154

155
                        resolve( {
1✔
156
                                default: response.url
157
                        } );
158
                } );
159

160
                // Upload progress when it's supported.
161
                /* istanbul ignore else -- @preserve */
162
                if ( xhr.upload ) {
7✔
163
                        xhr.upload.addEventListener( 'progress', evt => {
7✔
164
                                if ( evt.lengthComputable ) {
6✔
165
                                        loader.uploadTotal = evt.total;
4✔
166
                                        loader.uploaded = evt.loaded;
4✔
167
                                }
168
                        } );
169
                }
170
        }
171

172
        /**
173
         * Prepares the data and sends the request.
174
         *
175
         * @param file File instance to be uploaded.
176
         */
177
        private _sendRequest( file: File ) {
178
                // Prepare form data.
179
                const data = new FormData();
7✔
180
                data.append( 'upload', file );
7✔
181
                data.append( 'ckCsrfToken', getCsrfToken() );
7✔
182

183
                // Send request.
184
                this.xhr!.send( data );
7✔
185
        }
186
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc