1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 | import { Plugin } from 'ckeditor5/src/core';
|
13 | import { FileRepository } from 'ckeditor5/src/upload';
|
14 |
|
15 | import '../../theme/imageuploadprogress.css';
|
16 | import '../../theme/imageuploadicon.css';
|
17 | import '../../theme/imageuploadloader.css';
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 | export default class ImageUploadProgress extends Plugin {
|
26 | |
27 |
|
28 |
|
29 | static get pluginName() {
|
30 | return 'ImageUploadProgress';
|
31 | }
|
32 |
|
33 | |
34 |
|
35 |
|
36 | constructor( editor ) {
|
37 | super( editor );
|
38 |
|
39 | |
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 | this.placeholder = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
|
48 | }
|
49 |
|
50 | |
51 |
|
52 |
|
53 | init() {
|
54 | const editor = this.editor;
|
55 |
|
56 |
|
57 | if ( editor.plugins.has( 'ImageBlockEditing' ) ) {
|
58 | editor.editing.downcastDispatcher.on( 'attribute:uploadStatus:imageBlock', ( ...args ) => this.uploadStatusChange( ...args ) );
|
59 | }
|
60 |
|
61 | if ( editor.plugins.has( 'ImageInlineEditing' ) ) {
|
62 | editor.editing.downcastDispatcher.on( 'attribute:uploadStatus:imageInline', ( ...args ) => this.uploadStatusChange( ...args ) );
|
63 | }
|
64 | }
|
65 |
|
66 | |
67 |
|
68 |
|
69 |
|
70 |
|
71 |
|
72 |
|
73 | uploadStatusChange( evt, data, conversionApi ) {
|
74 | const editor = this.editor;
|
75 | const modelImage = data.item;
|
76 | const uploadId = modelImage.getAttribute( 'uploadId' );
|
77 |
|
78 | if ( !conversionApi.consumable.consume( data.item, evt.name ) ) {
|
79 | return;
|
80 | }
|
81 |
|
82 | const imageUtils = editor.plugins.get( 'ImageUtils' );
|
83 | const fileRepository = editor.plugins.get( FileRepository );
|
84 | const status = uploadId ? data.attributeNewValue : null;
|
85 | const placeholder = this.placeholder;
|
86 | const viewFigure = editor.editing.mapper.toViewElement( modelImage );
|
87 | const viewWriter = conversionApi.writer;
|
88 |
|
89 | if ( status == 'reading' ) {
|
90 |
|
91 |
|
92 | _startAppearEffect( viewFigure, viewWriter );
|
93 | _showPlaceholder( imageUtils, placeholder, viewFigure, viewWriter );
|
94 |
|
95 | return;
|
96 | }
|
97 |
|
98 |
|
99 | if ( status == 'uploading' ) {
|
100 | const loader = fileRepository.loaders.get( uploadId );
|
101 |
|
102 |
|
103 | _startAppearEffect( viewFigure, viewWriter );
|
104 |
|
105 | if ( !loader ) {
|
106 |
|
107 |
|
108 |
|
109 | _showPlaceholder( imageUtils, placeholder, viewFigure, viewWriter );
|
110 | } else {
|
111 |
|
112 | _hidePlaceholder( viewFigure, viewWriter );
|
113 | _showProgressBar( viewFigure, viewWriter, loader, editor.editing.view );
|
114 | _displayLocalImage( imageUtils, viewFigure, viewWriter, loader );
|
115 | }
|
116 |
|
117 | return;
|
118 | }
|
119 |
|
120 | if ( status == 'complete' && fileRepository.loaders.get( uploadId ) ) {
|
121 | _showCompleteIcon( viewFigure, viewWriter, editor.editing.view );
|
122 | }
|
123 |
|
124 |
|
125 | _hideProgressBar( viewFigure, viewWriter );
|
126 | _hidePlaceholder( viewFigure, viewWriter );
|
127 | _stopAppearEffect( viewFigure, viewWriter );
|
128 | }
|
129 | }
|
130 |
|
131 |
|
132 |
|
133 |
|
134 |
|
135 | function _startAppearEffect( viewFigure, writer ) {
|
136 | if ( !viewFigure.hasClass( 'ck-appear' ) ) {
|
137 | writer.addClass( 'ck-appear', viewFigure );
|
138 | }
|
139 | }
|
140 |
|
141 |
|
142 |
|
143 |
|
144 |
|
145 | function _stopAppearEffect( viewFigure, writer ) {
|
146 | writer.removeClass( 'ck-appear', viewFigure );
|
147 | }
|
148 |
|
149 |
|
150 |
|
151 |
|
152 |
|
153 |
|
154 |
|
155 | function _showPlaceholder( imageUtils, placeholder, viewFigure, writer ) {
|
156 | if ( !viewFigure.hasClass( 'ck-image-upload-placeholder' ) ) {
|
157 | writer.addClass( 'ck-image-upload-placeholder', viewFigure );
|
158 | }
|
159 |
|
160 | const viewImg = imageUtils.findViewImgElement( viewFigure );
|
161 |
|
162 | if ( viewImg.getAttribute( 'src' ) !== placeholder ) {
|
163 | writer.setAttribute( 'src', placeholder, viewImg );
|
164 | }
|
165 |
|
166 | if ( !_getUIElement( viewFigure, 'placeholder' ) ) {
|
167 | writer.insert( writer.createPositionAfter( viewImg ), _createPlaceholder( writer ) );
|
168 | }
|
169 | }
|
170 |
|
171 |
|
172 |
|
173 |
|
174 |
|
175 | function _hidePlaceholder( viewFigure, writer ) {
|
176 | if ( viewFigure.hasClass( 'ck-image-upload-placeholder' ) ) {
|
177 | writer.removeClass( 'ck-image-upload-placeholder', viewFigure );
|
178 | }
|
179 |
|
180 | _removeUIElement( viewFigure, writer, 'placeholder' );
|
181 | }
|
182 |
|
183 |
|
184 |
|
185 |
|
186 |
|
187 |
|
188 |
|
189 |
|
190 | function _showProgressBar( viewFigure, writer, loader, view ) {
|
191 | const progressBar = _createProgressBar( writer );
|
192 | writer.insert( writer.createPositionAt( viewFigure, 'end' ), progressBar );
|
193 |
|
194 |
|
195 | loader.on( 'change:uploadedPercent', ( evt, name, value ) => {
|
196 | view.change( writer => {
|
197 | writer.setStyle( 'width', value + '%', progressBar );
|
198 | } );
|
199 | } );
|
200 | }
|
201 |
|
202 |
|
203 |
|
204 |
|
205 |
|
206 | function _hideProgressBar( viewFigure, writer ) {
|
207 | _removeUIElement( viewFigure, writer, 'progressBar' );
|
208 | }
|
209 |
|
210 |
|
211 |
|
212 |
|
213 |
|
214 |
|
215 | function _showCompleteIcon( viewFigure, writer, view ) {
|
216 | const completeIcon = writer.createUIElement( 'div', { class: 'ck-image-upload-complete-icon' } );
|
217 |
|
218 | writer.insert( writer.createPositionAt( viewFigure, 'end' ), completeIcon );
|
219 |
|
220 | setTimeout( () => {
|
221 | view.change( writer => writer.remove( writer.createRangeOn( completeIcon ) ) );
|
222 | }, 3000 );
|
223 | }
|
224 |
|
225 |
|
226 |
|
227 |
|
228 |
|
229 |
|
230 | function _createProgressBar( writer ) {
|
231 | const progressBar = writer.createUIElement( 'div', { class: 'ck-progress-bar' } );
|
232 |
|
233 | writer.setCustomProperty( 'progressBar', true, progressBar );
|
234 |
|
235 | return progressBar;
|
236 | }
|
237 |
|
238 |
|
239 |
|
240 |
|
241 |
|
242 |
|
243 | function _createPlaceholder( writer ) {
|
244 | const placeholder = writer.createUIElement( 'div', { class: 'ck-upload-placeholder-loader' } );
|
245 |
|
246 | writer.setCustomProperty( 'placeholder', true, placeholder );
|
247 |
|
248 | return placeholder;
|
249 | }
|
250 |
|
251 |
|
252 |
|
253 |
|
254 |
|
255 |
|
256 |
|
257 |
|
258 | function _getUIElement( imageFigure, uniqueProperty ) {
|
259 | for ( const child of imageFigure.getChildren() ) {
|
260 | if ( child.getCustomProperty( uniqueProperty ) ) {
|
261 | return child;
|
262 | }
|
263 | }
|
264 | }
|
265 |
|
266 |
|
267 |
|
268 |
|
269 |
|
270 |
|
271 |
|
272 | function _removeUIElement( viewFigure, writer, uniqueProperty ) {
|
273 | const element = _getUIElement( viewFigure, uniqueProperty );
|
274 |
|
275 | if ( element ) {
|
276 | writer.remove( writer.createRangeOn( element ) );
|
277 | }
|
278 | }
|
279 |
|
280 |
|
281 |
|
282 |
|
283 |
|
284 |
|
285 |
|
286 | function _displayLocalImage( imageUtils, viewFigure, writer, loader ) {
|
287 | if ( loader.data ) {
|
288 | const viewImg = imageUtils.findViewImgElement( viewFigure );
|
289 |
|
290 | writer.setAttribute( 'src', loader.data, viewImg );
|
291 | }
|
292 | }
|