suneditor 3.0.0-beta.2 → 3.0.0-beta.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTING.md +186 -184
- package/LICENSE +21 -21
- package/README.md +157 -180
- package/dist/suneditor.min.css +1 -1
- package/dist/suneditor.min.js +1 -1
- package/package.json +126 -123
- package/src/assets/design/color.css +131 -121
- package/src/assets/design/index.css +3 -3
- package/src/assets/design/size.css +37 -35
- package/src/assets/design/typography.css +37 -37
- package/src/assets/icons/defaultIcons.js +247 -232
- package/src/assets/suneditor-contents.css +779 -778
- package/src/assets/suneditor.css +43 -35
- package/src/core/base/eventHandlers/handler_toolbar.js +135 -135
- package/src/core/base/eventHandlers/handler_ww_clipboard.js +56 -56
- package/src/core/base/eventHandlers/handler_ww_dragDrop.js +115 -113
- package/src/core/base/eventHandlers/handler_ww_key_input.js +1200 -1200
- package/src/core/base/eventHandlers/handler_ww_mouse.js +194 -194
- package/src/core/base/eventManager.js +1550 -1484
- package/src/core/base/history.js +355 -355
- package/src/core/class/char.js +163 -162
- package/src/core/class/component.js +856 -842
- package/src/core/class/format.js +3433 -3422
- package/src/core/class/html.js +1927 -1890
- package/src/core/class/menu.js +357 -346
- package/src/core/class/nodeTransform.js +424 -424
- package/src/core/class/offset.js +858 -891
- package/src/core/class/selection.js +710 -620
- package/src/core/class/shortcuts.js +98 -98
- package/src/core/class/toolbar.js +438 -430
- package/src/core/class/ui.js +424 -422
- package/src/core/class/viewer.js +750 -750
- package/src/core/editor.js +1810 -1708
- package/src/core/section/actives.js +268 -241
- package/src/core/section/constructor.js +1348 -1661
- package/src/core/section/context.js +102 -102
- package/src/core/section/documentType.js +582 -561
- package/src/core/section/options.js +367 -0
- package/src/core/util/instanceCheck.js +59 -0
- package/src/editorInjector/_classes.js +36 -36
- package/src/editorInjector/_core.js +92 -92
- package/src/editorInjector/index.js +75 -75
- package/src/events.js +634 -622
- package/src/helper/clipboard.js +59 -59
- package/src/helper/converter.js +586 -564
- package/src/helper/dom/domCheck.js +304 -304
- package/src/helper/dom/domQuery.js +677 -669
- package/src/helper/dom/domUtils.js +618 -557
- package/src/helper/dom/index.js +12 -12
- package/src/helper/env.js +249 -240
- package/src/helper/index.js +25 -25
- package/src/helper/keyCodeMap.js +183 -183
- package/src/helper/numbers.js +72 -72
- package/src/helper/unicode.js +47 -47
- package/src/langs/ckb.js +231 -231
- package/src/langs/cs.js +231 -231
- package/src/langs/da.js +231 -231
- package/src/langs/de.js +231 -231
- package/src/langs/en.js +230 -230
- package/src/langs/es.js +231 -231
- package/src/langs/fa.js +231 -231
- package/src/langs/fr.js +231 -231
- package/src/langs/he.js +231 -231
- package/src/langs/hu.js +230 -230
- package/src/langs/index.js +28 -28
- package/src/langs/it.js +231 -231
- package/src/langs/ja.js +230 -230
- package/src/langs/km.js +230 -230
- package/src/langs/ko.js +230 -230
- package/src/langs/lv.js +231 -231
- package/src/langs/nl.js +231 -231
- package/src/langs/pl.js +231 -231
- package/src/langs/pt_br.js +231 -231
- package/src/langs/ro.js +231 -231
- package/src/langs/ru.js +231 -231
- package/src/langs/se.js +231 -231
- package/src/langs/tr.js +231 -231
- package/src/langs/uk.js +231 -231
- package/src/langs/ur.js +231 -231
- package/src/langs/zh_cn.js +231 -231
- package/src/modules/ApiManager.js +191 -191
- package/src/modules/Browser.js +669 -667
- package/src/modules/ColorPicker.js +364 -362
- package/src/modules/Controller.js +474 -454
- package/src/modules/Figure.js +1620 -1617
- package/src/modules/FileManager.js +359 -359
- package/src/modules/HueSlider.js +577 -565
- package/src/modules/Modal.js +346 -346
- package/src/modules/ModalAnchorEditor.js +643 -643
- package/src/modules/SelectMenu.js +549 -549
- package/src/modules/_DragHandle.js +17 -17
- package/src/modules/index.js +14 -14
- package/src/plugins/browser/audioGallery.js +83 -83
- package/src/plugins/browser/fileBrowser.js +103 -103
- package/src/plugins/browser/fileGallery.js +83 -83
- package/src/plugins/browser/imageGallery.js +81 -81
- package/src/plugins/browser/videoGallery.js +103 -103
- package/src/plugins/command/blockquote.js +61 -60
- package/src/plugins/command/exportPDF.js +134 -134
- package/src/plugins/command/fileUpload.js +456 -456
- package/src/plugins/command/list_bulleted.js +149 -148
- package/src/plugins/command/list_numbered.js +152 -151
- package/src/plugins/dropdown/align.js +157 -155
- package/src/plugins/dropdown/backgroundColor.js +108 -104
- package/src/plugins/dropdown/font.js +141 -137
- package/src/plugins/dropdown/fontColor.js +109 -105
- package/src/plugins/dropdown/formatBlock.js +170 -178
- package/src/plugins/dropdown/hr.js +152 -152
- package/src/plugins/dropdown/layout.js +83 -83
- package/src/plugins/dropdown/lineHeight.js +131 -130
- package/src/plugins/dropdown/list.js +123 -122
- package/src/plugins/dropdown/paragraphStyle.js +138 -138
- package/src/plugins/dropdown/table.js +4110 -4000
- package/src/plugins/dropdown/template.js +83 -83
- package/src/plugins/dropdown/textStyle.js +149 -149
- package/src/plugins/field/mention.js +242 -242
- package/src/plugins/index.js +120 -120
- package/src/plugins/input/fontSize.js +414 -410
- package/src/plugins/input/pageNavigator.js +71 -70
- package/src/plugins/modal/audio.js +677 -677
- package/src/plugins/modal/drawing.js +537 -531
- package/src/plugins/modal/embed.js +886 -886
- package/src/plugins/modal/image.js +1377 -1376
- package/src/plugins/modal/link.js +248 -240
- package/src/plugins/modal/math.js +563 -563
- package/src/plugins/modal/video.js +1226 -1226
- package/src/plugins/popup/anchor.js +224 -222
- package/src/suneditor.js +114 -107
- package/src/themes/dark.css +132 -122
- package/src/typedef.js +132 -130
- package/types/assets/icons/defaultIcons.d.ts +8 -0
- package/types/core/base/eventManager.d.ts +29 -4
- package/types/core/class/char.d.ts +2 -1
- package/types/core/class/component.d.ts +1 -2
- package/types/core/class/format.d.ts +8 -1
- package/types/core/class/html.d.ts +8 -0
- package/types/core/class/menu.d.ts +8 -0
- package/types/core/class/offset.d.ts +24 -26
- package/types/core/class/selection.d.ts +2 -0
- package/types/core/class/toolbar.d.ts +6 -0
- package/types/core/class/ui.d.ts +1 -1
- package/types/core/editor.d.ts +34 -12
- package/types/core/section/constructor.d.ts +5 -638
- package/types/core/section/documentType.d.ts +12 -2
- package/types/core/section/options.d.ts +740 -0
- package/types/core/util/instanceCheck.d.ts +50 -0
- package/types/editorInjector/_core.d.ts +5 -5
- package/types/editorInjector/index.d.ts +2 -2
- package/types/events.d.ts +2 -0
- package/types/helper/converter.d.ts +9 -0
- package/types/helper/dom/domQuery.d.ts +5 -5
- package/types/helper/dom/domUtils.d.ts +8 -0
- package/types/helper/env.d.ts +6 -1
- package/types/helper/index.d.ts +4 -1
- package/types/index.d.ts +122 -120
- package/types/langs/_Lang.d.ts +194 -194
- package/types/modules/ColorPicker.d.ts +5 -1
- package/types/modules/Controller.d.ts +8 -4
- package/types/modules/Figure.d.ts +2 -1
- package/types/modules/HueSlider.d.ts +4 -1
- package/types/modules/SelectMenu.d.ts +1 -1
- package/types/plugins/command/blockquote.d.ts +1 -0
- package/types/plugins/command/list_bulleted.d.ts +1 -0
- package/types/plugins/command/list_numbered.d.ts +1 -0
- package/types/plugins/dropdown/align.d.ts +1 -0
- package/types/plugins/dropdown/backgroundColor.d.ts +1 -0
- package/types/plugins/dropdown/font.d.ts +1 -0
- package/types/plugins/dropdown/fontColor.d.ts +1 -0
- package/types/plugins/dropdown/formatBlock.d.ts +3 -2
- package/types/plugins/dropdown/lineHeight.d.ts +1 -0
- package/types/plugins/dropdown/list.d.ts +1 -0
- package/types/plugins/dropdown/table.d.ts +6 -0
- package/types/plugins/input/fontSize.d.ts +1 -0
- package/types/plugins/modal/drawing.d.ts +4 -0
- package/types/plugins/modal/link.d.ts +32 -15
- package/types/suneditor.d.ts +13 -9
- package/types/typedef.d.ts +8 -0
|
@@ -1,359 +1,359 @@
|
|
|
1
|
-
import CoreInjector from '../editorInjector/_core';
|
|
2
|
-
import ApiManager from './ApiManager';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @typedef {Object} FileStateInfo
|
|
6
|
-
* @property {string} src File source
|
|
7
|
-
* @property {number} index File index
|
|
8
|
-
* @property {string} name File name
|
|
9
|
-
* @property {number} size File size
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* @typedef {Object} FileStateParams
|
|
14
|
-
* @property {__se__EditorCore} editor - The root editor instance
|
|
15
|
-
* @property {Node} element File element
|
|
16
|
-
* @property {number} index File index
|
|
17
|
-
* @property {string} state File state ("create"|"update"|"delete")
|
|
18
|
-
* @property {FileStateInfo} info File information
|
|
19
|
-
* @property {number} remainingFilesCount Remaining file count
|
|
20
|
-
* @property {string} pluginName Plugin name
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* @typedef {Object} FileManagerParams
|
|
25
|
-
* @property {string} query The query selector used to find file elements in the editor
|
|
26
|
-
* @property {(params: Array<FileStateInfo>) => void=} loadHandler A function to handle the loaded file information
|
|
27
|
-
* @property {(info: FileStateParams) => void=} eventHandler A function to handle file-related events
|
|
28
|
-
*/
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* @class
|
|
32
|
-
* @description This module manages the file information of the editor.
|
|
33
|
-
*/
|
|
34
|
-
class FileManager extends CoreInjector {
|
|
35
|
-
/**
|
|
36
|
-
* @constructor
|
|
37
|
-
* @param {*} inst The instance object that called the constructor.
|
|
38
|
-
* @param {FileManagerParams} params FileManager options
|
|
39
|
-
*/
|
|
40
|
-
constructor(inst, params) {
|
|
41
|
-
super(inst.editor);
|
|
42
|
-
this.ui = this.editor.ui;
|
|
43
|
-
|
|
44
|
-
// members
|
|
45
|
-
inst.__fileManagement = this;
|
|
46
|
-
this.kind = inst.constructor.key || inst.constructor.name;
|
|
47
|
-
this.inst = inst;
|
|
48
|
-
this.component = inst.editor.component;
|
|
49
|
-
this.query = params.query;
|
|
50
|
-
this.loadHandler = params.loadHandler;
|
|
51
|
-
this.eventHandler = params.eventHandler;
|
|
52
|
-
this.infoList = [];
|
|
53
|
-
this.infoIndex = 0;
|
|
54
|
-
this.uploadFileLength = 0;
|
|
55
|
-
this.__updateTags = [];
|
|
56
|
-
// api manager
|
|
57
|
-
this.apiManager = new ApiManager(this, null);
|
|
58
|
-
|
|
59
|
-
// se-ts-ignore - call by editor
|
|
60
|
-
void this._resetInfo;
|
|
61
|
-
void this._checkInfo;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* @description Upload the file to the server.
|
|
66
|
-
* @param {string} uploadUrl Upload server url
|
|
67
|
-
* @param {?Object<string, string>} uploadHeader Request header
|
|
68
|
-
* @param {FileList|File[]|{formData: FormData, size: number}} data FormData in body or Files array
|
|
69
|
-
* @param {?(xmlHttp: XMLHttpRequest) => boolean=} callBack Success call back function
|
|
70
|
-
* @param {?(res: *, xmlHttp: XMLHttpRequest) => string=} errorCallBack Error call back function
|
|
71
|
-
*/
|
|
72
|
-
upload(uploadUrl, uploadHeader, data, callBack, errorCallBack) {
|
|
73
|
-
this.ui.showLoading();
|
|
74
|
-
|
|
75
|
-
let formData = null;
|
|
76
|
-
// create formData
|
|
77
|
-
if ('length' in data) {
|
|
78
|
-
formData = new FormData();
|
|
79
|
-
for (let i = 0, len = data.length; i < len; i++) {
|
|
80
|
-
formData.append('file-' + i, data[i]);
|
|
81
|
-
}
|
|
82
|
-
this.uploadFileLength = data.length;
|
|
83
|
-
} else {
|
|
84
|
-
formData = data.formData;
|
|
85
|
-
this.uploadFileLength = data.size;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
this.apiManager.call({ method: 'POST', url: uploadUrl, headers: uploadHeader, data: formData, callBack, errorCallBack });
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* @description Upload the file to the server.
|
|
93
|
-
* @param {string} uploadUrl Upload server url
|
|
94
|
-
* @param {?Object<string, string>} uploadHeader Request header
|
|
95
|
-
* @param {FileList|File[]|{formData: FormData, size: number}} data FormData in body or Files array
|
|
96
|
-
* @returns {Promise<XMLHttpRequest>}
|
|
97
|
-
*/
|
|
98
|
-
async asyncUpload(uploadUrl, uploadHeader, data) {
|
|
99
|
-
this.ui.showLoading();
|
|
100
|
-
|
|
101
|
-
let formData = null;
|
|
102
|
-
// create formData
|
|
103
|
-
if ('length' in data) {
|
|
104
|
-
formData = new FormData();
|
|
105
|
-
for (let i = 0, len = data.length; i < len; i++) {
|
|
106
|
-
formData.append('file-' + i, data[i]);
|
|
107
|
-
}
|
|
108
|
-
this.uploadFileLength = data.length;
|
|
109
|
-
} else {
|
|
110
|
-
formData = data.formData;
|
|
111
|
-
this.uploadFileLength = data.size;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return await this.apiManager.asyncCall({ method: 'POST', url: uploadUrl, headers: uploadHeader, data: formData });
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* @description Set the file information to the element.
|
|
119
|
-
* @param {Node} element File information element
|
|
120
|
-
* @param {Object} params
|
|
121
|
-
* @param {string} params.name File name
|
|
122
|
-
* @param {number} params.size File size
|
|
123
|
-
* @returns
|
|
124
|
-
*/
|
|
125
|
-
setFileData(element, { name, size }) {
|
|
126
|
-
if (!element) return;
|
|
127
|
-
/** @type {Element} */ (element).setAttribute('data-se-file-name', name);
|
|
128
|
-
/** @type {Element} */ (element).setAttribute('data-se-file-size', size + '');
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* @private
|
|
133
|
-
* @description Create info object of file and add it to "infoList"
|
|
134
|
-
* @param {HTMLMediaElement} element
|
|
135
|
-
* @param {{name: string, size: number}|null} file File information
|
|
136
|
-
*/
|
|
137
|
-
_setInfo(element, file) {
|
|
138
|
-
let dataIndex = Number(GetAttr(element, 'index'));
|
|
139
|
-
let info = null;
|
|
140
|
-
let state = '';
|
|
141
|
-
|
|
142
|
-
if (!file) {
|
|
143
|
-
file = {
|
|
144
|
-
name: GetAttr(element, 'file-name') || (typeof element.src === 'string' ? element.src.split('/').pop() : ''),
|
|
145
|
-
size: Number(GetAttr(element, 'file-size')) || 0
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// create
|
|
150
|
-
if (!dataIndex || this.editor._componentsInfoInit) {
|
|
151
|
-
state = 'create';
|
|
152
|
-
dataIndex = this.infoIndex++;
|
|
153
|
-
|
|
154
|
-
element.setAttribute('data-se-index', dataIndex + '');
|
|
155
|
-
element.setAttribute('data-se-file-name', file.name);
|
|
156
|
-
element.setAttribute('data-se-file-size', file.size + '');
|
|
157
|
-
|
|
158
|
-
info = {
|
|
159
|
-
src: element.src,
|
|
160
|
-
index: dataIndex,
|
|
161
|
-
name: file.name,
|
|
162
|
-
size: file.size
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
this.infoList.push(info);
|
|
166
|
-
} else {
|
|
167
|
-
// update
|
|
168
|
-
state = 'update';
|
|
169
|
-
dataIndex *= 1;
|
|
170
|
-
|
|
171
|
-
for (let i = 0, len = this.infoList.length; i < len; i++) {
|
|
172
|
-
if (dataIndex === this.infoList[i].index) {
|
|
173
|
-
info = this.infoList[i];
|
|
174
|
-
break;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
if (!info) {
|
|
179
|
-
dataIndex = this.infoIndex++;
|
|
180
|
-
info = {
|
|
181
|
-
index: dataIndex
|
|
182
|
-
};
|
|
183
|
-
this.infoList.push(info);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
info.src = element.src;
|
|
187
|
-
info.name = GetAttr(element, 'file-name');
|
|
188
|
-
info.size = Number(GetAttr(element, 'file-size'));
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// method bind
|
|
192
|
-
info.element = element;
|
|
193
|
-
|
|
194
|
-
info.delete = function (el) {
|
|
195
|
-
if (typeof this.inst.destroy === 'function') this.inst.destroy.call(this.inst, el);
|
|
196
|
-
this._deleteInfo(Number(GetAttr(el, 'index')));
|
|
197
|
-
}.bind(this, element);
|
|
198
|
-
// se-ts-ignore
|
|
199
|
-
void this._deleteInfo;
|
|
200
|
-
|
|
201
|
-
info.select = function (el) {
|
|
202
|
-
el.scrollIntoView(
|
|
203
|
-
const comp = this.component.get(el);
|
|
204
|
-
if (comp) {
|
|
205
|
-
this.component.select(comp.target, comp.pluginName);
|
|
206
|
-
} else if (typeof this.inst.select === 'function') {
|
|
207
|
-
this.inst.select(el);
|
|
208
|
-
}
|
|
209
|
-
}.bind(this, element);
|
|
210
|
-
|
|
211
|
-
const params = { editor: this.editor, element, index: dataIndex, state, info, remainingFilesCount: --this.uploadFileLength < 0 ? 0 : this.uploadFileLength, pluginName: this.kind };
|
|
212
|
-
if (typeof this.eventHandler === 'function') {
|
|
213
|
-
this.eventHandler(params);
|
|
214
|
-
}
|
|
215
|
-
this.triggerEvent('onFileManagerAction', { ...params, pluginName: this.kind });
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* @description Gets the sum of the sizes of the currently saved files.
|
|
220
|
-
* @returns {number} Size
|
|
221
|
-
*/
|
|
222
|
-
getSize() {
|
|
223
|
-
let size = 0;
|
|
224
|
-
for (let i = 0, len = this.infoList.length; i < len; i++) {
|
|
225
|
-
size += this.infoList[i].size * 1;
|
|
226
|
-
}
|
|
227
|
-
return size;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
/**
|
|
231
|
-
* @private
|
|
232
|
-
* @description Checke the file's information and modify the tag that does not fit the format.
|
|
233
|
-
* @param {boolean} loaded Whether the editor is loaded
|
|
234
|
-
*/
|
|
235
|
-
_checkInfo(loaded) {
|
|
236
|
-
const tags = [].slice.call(this.editor.frameContext.get('wysiwyg').querySelectorAll(this.query));
|
|
237
|
-
const infoList = this.infoList;
|
|
238
|
-
if (tags.length === infoList.length) {
|
|
239
|
-
// reset
|
|
240
|
-
if (this.editor._componentsInfoReset) {
|
|
241
|
-
for (let i = 0, len = tags.length; i < len; i++) {
|
|
242
|
-
this._setInfo(tags[i], null);
|
|
243
|
-
}
|
|
244
|
-
return;
|
|
245
|
-
} else {
|
|
246
|
-
let infoUpdate = false;
|
|
247
|
-
for (let i = 0, len = infoList.length, info; i < len; i++) {
|
|
248
|
-
info = infoList[i];
|
|
249
|
-
if (
|
|
250
|
-
tags.filter(function (t) {
|
|
251
|
-
return info.src === t.src && info.index.toString() === GetAttr(t, 'index');
|
|
252
|
-
}).length === 0
|
|
253
|
-
) {
|
|
254
|
-
infoUpdate = true;
|
|
255
|
-
break;
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
// pass
|
|
259
|
-
if (!infoUpdate) return;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// check
|
|
264
|
-
const currentTags = [];
|
|
265
|
-
const infoIndex = [];
|
|
266
|
-
for (let i = 0, len = infoList.length; i < len; i++) {
|
|
267
|
-
infoIndex[i] = infoList[i].index;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
this.__updateTags = tags;
|
|
271
|
-
|
|
272
|
-
while (tags.length > 0) {
|
|
273
|
-
const tag = tags.shift();
|
|
274
|
-
if (!GetAttr(tag, 'index') || !infoIndex.includes(Number(GetAttr(tag, 'index')))) {
|
|
275
|
-
currentTags.push(this.infoIndex);
|
|
276
|
-
tag.removeAttribute('data-se-index');
|
|
277
|
-
this._setInfo(tag, null);
|
|
278
|
-
} else {
|
|
279
|
-
currentTags.push(Number(GetAttr(tag, 'index')));
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
// editor load
|
|
284
|
-
if (loaded && typeof this.loadHandler === 'function') {
|
|
285
|
-
this.loadHandler(infoList);
|
|
286
|
-
return;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
for (let i = 0, dataIndex; i < infoList.length; i++) {
|
|
290
|
-
dataIndex = infoList[i].index;
|
|
291
|
-
if (currentTags.includes(dataIndex)) continue;
|
|
292
|
-
|
|
293
|
-
infoList.splice(i, 1);
|
|
294
|
-
|
|
295
|
-
const params = { editor: this.editor, element: null, index: dataIndex, state: 'delete', info: null, remainingFilesCount: 0, pluginName: this.kind };
|
|
296
|
-
if (typeof this.eventHandler === 'function') {
|
|
297
|
-
this.eventHandler(params);
|
|
298
|
-
}
|
|
299
|
-
this.triggerEvent('onFileManagerAction', { ...params, pluginName: this.kind });
|
|
300
|
-
|
|
301
|
-
i--;
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
/**
|
|
306
|
-
* @private
|
|
307
|
-
* @description Reset info object and "infoList = []", "infoIndex = 0"
|
|
308
|
-
*/
|
|
309
|
-
_resetInfo() {
|
|
310
|
-
const eh = typeof this.eventHandler === 'function';
|
|
311
|
-
const params = { editor: this.editor, element: null, state: 'delete', info: null, remainingFilesCount: 0, pluginName: this.kind };
|
|
312
|
-
for (let i = 0, len = this.infoList.length; i < len; i++) {
|
|
313
|
-
if (eh) this.eventHandler({ ...params, index: this.infoList[i].index, pluginName: this.kind });
|
|
314
|
-
this.triggerEvent('onFileManagerAction', { ...params, index: this.infoList[i].index, pluginName: this.kind });
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
this.infoList = [];
|
|
318
|
-
this.infoIndex = 0;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
/**
|
|
322
|
-
* @private
|
|
323
|
-
* @description Delete info object at "infoList"
|
|
324
|
-
* @param {number} index index of info object infoList[].index)
|
|
325
|
-
*/
|
|
326
|
-
_deleteInfo(index) {
|
|
327
|
-
if (index >= 0) {
|
|
328
|
-
for (let i = 0, len = this.infoList.length; i < len; i++) {
|
|
329
|
-
if (index === this.infoList[i].index) {
|
|
330
|
-
this.infoList.splice(i, 1);
|
|
331
|
-
if (typeof this.eventHandler === 'function') {
|
|
332
|
-
this.eventHandler({ editor: this.editor, element: null, index, state: 'delete', info: null, remainingFilesCount: 0, pluginName: this.kind });
|
|
333
|
-
}
|
|
334
|
-
return;
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
/**
|
|
342
|
-
* @private
|
|
343
|
-
* @param {Element} element - Element
|
|
344
|
-
* @param {string} name - Attribute name
|
|
345
|
-
* @returns {string|null}
|
|
346
|
-
*/
|
|
347
|
-
function GetAttr(element, name) {
|
|
348
|
-
const seAttr = element.getAttribute(`data-se-${name}`);
|
|
349
|
-
if (seAttr) return seAttr;
|
|
350
|
-
|
|
351
|
-
// v2-migration
|
|
352
|
-
const v2SeAttr = element.getAttribute(`data-${name}`);
|
|
353
|
-
if (!v2SeAttr) return null;
|
|
354
|
-
element.removeAttribute(`data-${name}`);
|
|
355
|
-
element.setAttribute(`data-se-${name}`, v2SeAttr);
|
|
356
|
-
return v2SeAttr;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
export default FileManager;
|
|
1
|
+
import CoreInjector from '../editorInjector/_core';
|
|
2
|
+
import ApiManager from './ApiManager';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {Object} FileStateInfo
|
|
6
|
+
* @property {string} src File source
|
|
7
|
+
* @property {number} index File index
|
|
8
|
+
* @property {string} name File name
|
|
9
|
+
* @property {number} size File size
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @typedef {Object} FileStateParams
|
|
14
|
+
* @property {__se__EditorCore} editor - The root editor instance
|
|
15
|
+
* @property {Node} element File element
|
|
16
|
+
* @property {number} index File index
|
|
17
|
+
* @property {string} state File state ("create"|"update"|"delete")
|
|
18
|
+
* @property {FileStateInfo} info File information
|
|
19
|
+
* @property {number} remainingFilesCount Remaining file count
|
|
20
|
+
* @property {string} pluginName Plugin name
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @typedef {Object} FileManagerParams
|
|
25
|
+
* @property {string} query The query selector used to find file elements in the editor
|
|
26
|
+
* @property {(params: Array<FileStateInfo>) => void=} loadHandler A function to handle the loaded file information
|
|
27
|
+
* @property {(info: FileStateParams) => void=} eventHandler A function to handle file-related events
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @class
|
|
32
|
+
* @description This module manages the file information of the editor.
|
|
33
|
+
*/
|
|
34
|
+
class FileManager extends CoreInjector {
|
|
35
|
+
/**
|
|
36
|
+
* @constructor
|
|
37
|
+
* @param {*} inst The instance object that called the constructor.
|
|
38
|
+
* @param {FileManagerParams} params FileManager options
|
|
39
|
+
*/
|
|
40
|
+
constructor(inst, params) {
|
|
41
|
+
super(inst.editor);
|
|
42
|
+
this.ui = this.editor.ui;
|
|
43
|
+
|
|
44
|
+
// members
|
|
45
|
+
inst.__fileManagement = this;
|
|
46
|
+
this.kind = inst.constructor.key || inst.constructor.name;
|
|
47
|
+
this.inst = inst;
|
|
48
|
+
this.component = inst.editor.component;
|
|
49
|
+
this.query = params.query;
|
|
50
|
+
this.loadHandler = params.loadHandler;
|
|
51
|
+
this.eventHandler = params.eventHandler;
|
|
52
|
+
this.infoList = [];
|
|
53
|
+
this.infoIndex = 0;
|
|
54
|
+
this.uploadFileLength = 0;
|
|
55
|
+
this.__updateTags = [];
|
|
56
|
+
// api manager
|
|
57
|
+
this.apiManager = new ApiManager(this, null);
|
|
58
|
+
|
|
59
|
+
// se-ts-ignore - call by editor
|
|
60
|
+
void this._resetInfo;
|
|
61
|
+
void this._checkInfo;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* @description Upload the file to the server.
|
|
66
|
+
* @param {string} uploadUrl Upload server url
|
|
67
|
+
* @param {?Object<string, string>} uploadHeader Request header
|
|
68
|
+
* @param {FileList|File[]|{formData: FormData, size: number}} data FormData in body or Files array
|
|
69
|
+
* @param {?(xmlHttp: XMLHttpRequest) => boolean=} callBack Success call back function
|
|
70
|
+
* @param {?(res: *, xmlHttp: XMLHttpRequest) => string=} errorCallBack Error call back function
|
|
71
|
+
*/
|
|
72
|
+
upload(uploadUrl, uploadHeader, data, callBack, errorCallBack) {
|
|
73
|
+
this.ui.showLoading();
|
|
74
|
+
|
|
75
|
+
let formData = null;
|
|
76
|
+
// create formData
|
|
77
|
+
if ('length' in data) {
|
|
78
|
+
formData = new FormData();
|
|
79
|
+
for (let i = 0, len = data.length; i < len; i++) {
|
|
80
|
+
formData.append('file-' + i, data[i]);
|
|
81
|
+
}
|
|
82
|
+
this.uploadFileLength = data.length;
|
|
83
|
+
} else {
|
|
84
|
+
formData = data.formData;
|
|
85
|
+
this.uploadFileLength = data.size;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
this.apiManager.call({ method: 'POST', url: uploadUrl, headers: uploadHeader, data: formData, callBack, errorCallBack });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @description Upload the file to the server.
|
|
93
|
+
* @param {string} uploadUrl Upload server url
|
|
94
|
+
* @param {?Object<string, string>} uploadHeader Request header
|
|
95
|
+
* @param {FileList|File[]|{formData: FormData, size: number}} data FormData in body or Files array
|
|
96
|
+
* @returns {Promise<XMLHttpRequest>}
|
|
97
|
+
*/
|
|
98
|
+
async asyncUpload(uploadUrl, uploadHeader, data) {
|
|
99
|
+
this.ui.showLoading();
|
|
100
|
+
|
|
101
|
+
let formData = null;
|
|
102
|
+
// create formData
|
|
103
|
+
if ('length' in data) {
|
|
104
|
+
formData = new FormData();
|
|
105
|
+
for (let i = 0, len = data.length; i < len; i++) {
|
|
106
|
+
formData.append('file-' + i, data[i]);
|
|
107
|
+
}
|
|
108
|
+
this.uploadFileLength = data.length;
|
|
109
|
+
} else {
|
|
110
|
+
formData = data.formData;
|
|
111
|
+
this.uploadFileLength = data.size;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return await this.apiManager.asyncCall({ method: 'POST', url: uploadUrl, headers: uploadHeader, data: formData });
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* @description Set the file information to the element.
|
|
119
|
+
* @param {Node} element File information element
|
|
120
|
+
* @param {Object} params
|
|
121
|
+
* @param {string} params.name File name
|
|
122
|
+
* @param {number} params.size File size
|
|
123
|
+
* @returns
|
|
124
|
+
*/
|
|
125
|
+
setFileData(element, { name, size }) {
|
|
126
|
+
if (!element) return;
|
|
127
|
+
/** @type {Element} */ (element).setAttribute('data-se-file-name', name);
|
|
128
|
+
/** @type {Element} */ (element).setAttribute('data-se-file-size', size + '');
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* @private
|
|
133
|
+
* @description Create info object of file and add it to "infoList"
|
|
134
|
+
* @param {HTMLMediaElement} element
|
|
135
|
+
* @param {{name: string, size: number}|null} file File information
|
|
136
|
+
*/
|
|
137
|
+
_setInfo(element, file) {
|
|
138
|
+
let dataIndex = Number(GetAttr(element, 'index'));
|
|
139
|
+
let info = null;
|
|
140
|
+
let state = '';
|
|
141
|
+
|
|
142
|
+
if (!file) {
|
|
143
|
+
file = {
|
|
144
|
+
name: GetAttr(element, 'file-name') || (typeof element.src === 'string' ? element.src.split('/').pop() : ''),
|
|
145
|
+
size: Number(GetAttr(element, 'file-size')) || 0
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// create
|
|
150
|
+
if (!dataIndex || this.editor._componentsInfoInit) {
|
|
151
|
+
state = 'create';
|
|
152
|
+
dataIndex = this.infoIndex++;
|
|
153
|
+
|
|
154
|
+
element.setAttribute('data-se-index', dataIndex + '');
|
|
155
|
+
element.setAttribute('data-se-file-name', file.name);
|
|
156
|
+
element.setAttribute('data-se-file-size', file.size + '');
|
|
157
|
+
|
|
158
|
+
info = {
|
|
159
|
+
src: element.src,
|
|
160
|
+
index: dataIndex,
|
|
161
|
+
name: file.name,
|
|
162
|
+
size: file.size
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
this.infoList.push(info);
|
|
166
|
+
} else {
|
|
167
|
+
// update
|
|
168
|
+
state = 'update';
|
|
169
|
+
dataIndex *= 1;
|
|
170
|
+
|
|
171
|
+
for (let i = 0, len = this.infoList.length; i < len; i++) {
|
|
172
|
+
if (dataIndex === this.infoList[i].index) {
|
|
173
|
+
info = this.infoList[i];
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (!info) {
|
|
179
|
+
dataIndex = this.infoIndex++;
|
|
180
|
+
info = {
|
|
181
|
+
index: dataIndex
|
|
182
|
+
};
|
|
183
|
+
this.infoList.push(info);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
info.src = element.src;
|
|
187
|
+
info.name = GetAttr(element, 'file-name');
|
|
188
|
+
info.size = Number(GetAttr(element, 'file-size'));
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// method bind
|
|
192
|
+
info.element = element;
|
|
193
|
+
|
|
194
|
+
info.delete = function (el) {
|
|
195
|
+
if (typeof this.inst.destroy === 'function') this.inst.destroy.call(this.inst, el);
|
|
196
|
+
this._deleteInfo(Number(GetAttr(el, 'index')));
|
|
197
|
+
}.bind(this, element);
|
|
198
|
+
// se-ts-ignore
|
|
199
|
+
void this._deleteInfo;
|
|
200
|
+
|
|
201
|
+
info.select = function (el) {
|
|
202
|
+
el.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'nearest' });
|
|
203
|
+
const comp = this.component.get(el);
|
|
204
|
+
if (comp) {
|
|
205
|
+
this.component.select(comp.target, comp.pluginName);
|
|
206
|
+
} else if (typeof this.inst.select === 'function') {
|
|
207
|
+
this.inst.select(el);
|
|
208
|
+
}
|
|
209
|
+
}.bind(this, element);
|
|
210
|
+
|
|
211
|
+
const params = { editor: this.editor, element, index: dataIndex, state, info, remainingFilesCount: --this.uploadFileLength < 0 ? 0 : this.uploadFileLength, pluginName: this.kind };
|
|
212
|
+
if (typeof this.eventHandler === 'function') {
|
|
213
|
+
this.eventHandler(params);
|
|
214
|
+
}
|
|
215
|
+
this.triggerEvent('onFileManagerAction', { ...params, pluginName: this.kind });
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* @description Gets the sum of the sizes of the currently saved files.
|
|
220
|
+
* @returns {number} Size
|
|
221
|
+
*/
|
|
222
|
+
getSize() {
|
|
223
|
+
let size = 0;
|
|
224
|
+
for (let i = 0, len = this.infoList.length; i < len; i++) {
|
|
225
|
+
size += this.infoList[i].size * 1;
|
|
226
|
+
}
|
|
227
|
+
return size;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* @private
|
|
232
|
+
* @description Checke the file's information and modify the tag that does not fit the format.
|
|
233
|
+
* @param {boolean} loaded Whether the editor is loaded
|
|
234
|
+
*/
|
|
235
|
+
_checkInfo(loaded) {
|
|
236
|
+
const tags = [].slice.call(this.editor.frameContext.get('wysiwyg').querySelectorAll(this.query));
|
|
237
|
+
const infoList = this.infoList;
|
|
238
|
+
if (tags.length === infoList.length) {
|
|
239
|
+
// reset
|
|
240
|
+
if (this.editor._componentsInfoReset) {
|
|
241
|
+
for (let i = 0, len = tags.length; i < len; i++) {
|
|
242
|
+
this._setInfo(tags[i], null);
|
|
243
|
+
}
|
|
244
|
+
return;
|
|
245
|
+
} else {
|
|
246
|
+
let infoUpdate = false;
|
|
247
|
+
for (let i = 0, len = infoList.length, info; i < len; i++) {
|
|
248
|
+
info = infoList[i];
|
|
249
|
+
if (
|
|
250
|
+
tags.filter(function (t) {
|
|
251
|
+
return info.src === t.src && info.index.toString() === GetAttr(t, 'index');
|
|
252
|
+
}).length === 0
|
|
253
|
+
) {
|
|
254
|
+
infoUpdate = true;
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
// pass
|
|
259
|
+
if (!infoUpdate) return;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// check
|
|
264
|
+
const currentTags = [];
|
|
265
|
+
const infoIndex = [];
|
|
266
|
+
for (let i = 0, len = infoList.length; i < len; i++) {
|
|
267
|
+
infoIndex[i] = infoList[i].index;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
this.__updateTags = tags;
|
|
271
|
+
|
|
272
|
+
while (tags.length > 0) {
|
|
273
|
+
const tag = tags.shift();
|
|
274
|
+
if (!GetAttr(tag, 'index') || !infoIndex.includes(Number(GetAttr(tag, 'index')))) {
|
|
275
|
+
currentTags.push(this.infoIndex);
|
|
276
|
+
tag.removeAttribute('data-se-index');
|
|
277
|
+
this._setInfo(tag, null);
|
|
278
|
+
} else {
|
|
279
|
+
currentTags.push(Number(GetAttr(tag, 'index')));
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// editor load
|
|
284
|
+
if (loaded && typeof this.loadHandler === 'function') {
|
|
285
|
+
this.loadHandler(infoList);
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
for (let i = 0, dataIndex; i < infoList.length; i++) {
|
|
290
|
+
dataIndex = infoList[i].index;
|
|
291
|
+
if (currentTags.includes(dataIndex)) continue;
|
|
292
|
+
|
|
293
|
+
infoList.splice(i, 1);
|
|
294
|
+
|
|
295
|
+
const params = { editor: this.editor, element: null, index: dataIndex, state: 'delete', info: null, remainingFilesCount: 0, pluginName: this.kind };
|
|
296
|
+
if (typeof this.eventHandler === 'function') {
|
|
297
|
+
this.eventHandler(params);
|
|
298
|
+
}
|
|
299
|
+
this.triggerEvent('onFileManagerAction', { ...params, pluginName: this.kind });
|
|
300
|
+
|
|
301
|
+
i--;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* @private
|
|
307
|
+
* @description Reset info object and "infoList = []", "infoIndex = 0"
|
|
308
|
+
*/
|
|
309
|
+
_resetInfo() {
|
|
310
|
+
const eh = typeof this.eventHandler === 'function';
|
|
311
|
+
const params = { editor: this.editor, element: null, state: 'delete', info: null, remainingFilesCount: 0, pluginName: this.kind };
|
|
312
|
+
for (let i = 0, len = this.infoList.length; i < len; i++) {
|
|
313
|
+
if (eh) this.eventHandler({ ...params, index: this.infoList[i].index, pluginName: this.kind });
|
|
314
|
+
this.triggerEvent('onFileManagerAction', { ...params, index: this.infoList[i].index, pluginName: this.kind });
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
this.infoList = [];
|
|
318
|
+
this.infoIndex = 0;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* @private
|
|
323
|
+
* @description Delete info object at "infoList"
|
|
324
|
+
* @param {number} index index of info object infoList[].index)
|
|
325
|
+
*/
|
|
326
|
+
_deleteInfo(index) {
|
|
327
|
+
if (index >= 0) {
|
|
328
|
+
for (let i = 0, len = this.infoList.length; i < len; i++) {
|
|
329
|
+
if (index === this.infoList[i].index) {
|
|
330
|
+
this.infoList.splice(i, 1);
|
|
331
|
+
if (typeof this.eventHandler === 'function') {
|
|
332
|
+
this.eventHandler({ editor: this.editor, element: null, index, state: 'delete', info: null, remainingFilesCount: 0, pluginName: this.kind });
|
|
333
|
+
}
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* @private
|
|
343
|
+
* @param {Element} element - Element
|
|
344
|
+
* @param {string} name - Attribute name
|
|
345
|
+
* @returns {string|null}
|
|
346
|
+
*/
|
|
347
|
+
function GetAttr(element, name) {
|
|
348
|
+
const seAttr = element.getAttribute(`data-se-${name}`);
|
|
349
|
+
if (seAttr) return seAttr;
|
|
350
|
+
|
|
351
|
+
// v2-migration
|
|
352
|
+
const v2SeAttr = element.getAttribute(`data-${name}`);
|
|
353
|
+
if (!v2SeAttr) return null;
|
|
354
|
+
element.removeAttribute(`data-${name}`);
|
|
355
|
+
element.setAttribute(`data-se-${name}`, v2SeAttr);
|
|
356
|
+
return v2SeAttr;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
export default FileManager;
|