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