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.
Files changed (177) hide show
  1. package/CONTRIBUTING.md +186 -184
  2. package/LICENSE +21 -21
  3. package/README.md +157 -180
  4. package/dist/suneditor.min.css +1 -1
  5. package/dist/suneditor.min.js +1 -1
  6. package/package.json +126 -123
  7. package/src/assets/design/color.css +131 -121
  8. package/src/assets/design/index.css +3 -3
  9. package/src/assets/design/size.css +37 -35
  10. package/src/assets/design/typography.css +37 -37
  11. package/src/assets/icons/defaultIcons.js +247 -232
  12. package/src/assets/suneditor-contents.css +779 -778
  13. package/src/assets/suneditor.css +43 -35
  14. package/src/core/base/eventHandlers/handler_toolbar.js +135 -135
  15. package/src/core/base/eventHandlers/handler_ww_clipboard.js +56 -56
  16. package/src/core/base/eventHandlers/handler_ww_dragDrop.js +115 -113
  17. package/src/core/base/eventHandlers/handler_ww_key_input.js +1200 -1200
  18. package/src/core/base/eventHandlers/handler_ww_mouse.js +194 -194
  19. package/src/core/base/eventManager.js +1550 -1484
  20. package/src/core/base/history.js +355 -355
  21. package/src/core/class/char.js +163 -162
  22. package/src/core/class/component.js +856 -842
  23. package/src/core/class/format.js +3433 -3422
  24. package/src/core/class/html.js +1927 -1890
  25. package/src/core/class/menu.js +357 -346
  26. package/src/core/class/nodeTransform.js +424 -424
  27. package/src/core/class/offset.js +858 -891
  28. package/src/core/class/selection.js +710 -620
  29. package/src/core/class/shortcuts.js +98 -98
  30. package/src/core/class/toolbar.js +438 -430
  31. package/src/core/class/ui.js +424 -422
  32. package/src/core/class/viewer.js +750 -750
  33. package/src/core/editor.js +1810 -1708
  34. package/src/core/section/actives.js +268 -241
  35. package/src/core/section/constructor.js +1348 -1661
  36. package/src/core/section/context.js +102 -102
  37. package/src/core/section/documentType.js +582 -561
  38. package/src/core/section/options.js +367 -0
  39. package/src/core/util/instanceCheck.js +59 -0
  40. package/src/editorInjector/_classes.js +36 -36
  41. package/src/editorInjector/_core.js +92 -92
  42. package/src/editorInjector/index.js +75 -75
  43. package/src/events.js +634 -622
  44. package/src/helper/clipboard.js +59 -59
  45. package/src/helper/converter.js +586 -564
  46. package/src/helper/dom/domCheck.js +304 -304
  47. package/src/helper/dom/domQuery.js +677 -669
  48. package/src/helper/dom/domUtils.js +618 -557
  49. package/src/helper/dom/index.js +12 -12
  50. package/src/helper/env.js +249 -240
  51. package/src/helper/index.js +25 -25
  52. package/src/helper/keyCodeMap.js +183 -183
  53. package/src/helper/numbers.js +72 -72
  54. package/src/helper/unicode.js +47 -47
  55. package/src/langs/ckb.js +231 -231
  56. package/src/langs/cs.js +231 -231
  57. package/src/langs/da.js +231 -231
  58. package/src/langs/de.js +231 -231
  59. package/src/langs/en.js +230 -230
  60. package/src/langs/es.js +231 -231
  61. package/src/langs/fa.js +231 -231
  62. package/src/langs/fr.js +231 -231
  63. package/src/langs/he.js +231 -231
  64. package/src/langs/hu.js +230 -230
  65. package/src/langs/index.js +28 -28
  66. package/src/langs/it.js +231 -231
  67. package/src/langs/ja.js +230 -230
  68. package/src/langs/km.js +230 -230
  69. package/src/langs/ko.js +230 -230
  70. package/src/langs/lv.js +231 -231
  71. package/src/langs/nl.js +231 -231
  72. package/src/langs/pl.js +231 -231
  73. package/src/langs/pt_br.js +231 -231
  74. package/src/langs/ro.js +231 -231
  75. package/src/langs/ru.js +231 -231
  76. package/src/langs/se.js +231 -231
  77. package/src/langs/tr.js +231 -231
  78. package/src/langs/uk.js +231 -231
  79. package/src/langs/ur.js +231 -231
  80. package/src/langs/zh_cn.js +231 -231
  81. package/src/modules/ApiManager.js +191 -191
  82. package/src/modules/Browser.js +669 -667
  83. package/src/modules/ColorPicker.js +364 -362
  84. package/src/modules/Controller.js +474 -454
  85. package/src/modules/Figure.js +1620 -1617
  86. package/src/modules/FileManager.js +359 -359
  87. package/src/modules/HueSlider.js +577 -565
  88. package/src/modules/Modal.js +346 -346
  89. package/src/modules/ModalAnchorEditor.js +643 -643
  90. package/src/modules/SelectMenu.js +549 -549
  91. package/src/modules/_DragHandle.js +17 -17
  92. package/src/modules/index.js +14 -14
  93. package/src/plugins/browser/audioGallery.js +83 -83
  94. package/src/plugins/browser/fileBrowser.js +103 -103
  95. package/src/plugins/browser/fileGallery.js +83 -83
  96. package/src/plugins/browser/imageGallery.js +81 -81
  97. package/src/plugins/browser/videoGallery.js +103 -103
  98. package/src/plugins/command/blockquote.js +61 -60
  99. package/src/plugins/command/exportPDF.js +134 -134
  100. package/src/plugins/command/fileUpload.js +456 -456
  101. package/src/plugins/command/list_bulleted.js +149 -148
  102. package/src/plugins/command/list_numbered.js +152 -151
  103. package/src/plugins/dropdown/align.js +157 -155
  104. package/src/plugins/dropdown/backgroundColor.js +108 -104
  105. package/src/plugins/dropdown/font.js +141 -137
  106. package/src/plugins/dropdown/fontColor.js +109 -105
  107. package/src/plugins/dropdown/formatBlock.js +170 -178
  108. package/src/plugins/dropdown/hr.js +152 -152
  109. package/src/plugins/dropdown/layout.js +83 -83
  110. package/src/plugins/dropdown/lineHeight.js +131 -130
  111. package/src/plugins/dropdown/list.js +123 -122
  112. package/src/plugins/dropdown/paragraphStyle.js +138 -138
  113. package/src/plugins/dropdown/table.js +4110 -4000
  114. package/src/plugins/dropdown/template.js +83 -83
  115. package/src/plugins/dropdown/textStyle.js +149 -149
  116. package/src/plugins/field/mention.js +242 -242
  117. package/src/plugins/index.js +120 -120
  118. package/src/plugins/input/fontSize.js +414 -410
  119. package/src/plugins/input/pageNavigator.js +71 -70
  120. package/src/plugins/modal/audio.js +677 -677
  121. package/src/plugins/modal/drawing.js +537 -531
  122. package/src/plugins/modal/embed.js +886 -886
  123. package/src/plugins/modal/image.js +1377 -1376
  124. package/src/plugins/modal/link.js +248 -240
  125. package/src/plugins/modal/math.js +563 -563
  126. package/src/plugins/modal/video.js +1226 -1226
  127. package/src/plugins/popup/anchor.js +224 -222
  128. package/src/suneditor.js +114 -107
  129. package/src/themes/dark.css +132 -122
  130. package/src/typedef.js +132 -130
  131. package/types/assets/icons/defaultIcons.d.ts +8 -0
  132. package/types/core/base/eventManager.d.ts +29 -4
  133. package/types/core/class/char.d.ts +2 -1
  134. package/types/core/class/component.d.ts +1 -2
  135. package/types/core/class/format.d.ts +8 -1
  136. package/types/core/class/html.d.ts +8 -0
  137. package/types/core/class/menu.d.ts +8 -0
  138. package/types/core/class/offset.d.ts +24 -26
  139. package/types/core/class/selection.d.ts +2 -0
  140. package/types/core/class/toolbar.d.ts +6 -0
  141. package/types/core/class/ui.d.ts +1 -1
  142. package/types/core/editor.d.ts +34 -12
  143. package/types/core/section/constructor.d.ts +5 -638
  144. package/types/core/section/documentType.d.ts +12 -2
  145. package/types/core/section/options.d.ts +740 -0
  146. package/types/core/util/instanceCheck.d.ts +50 -0
  147. package/types/editorInjector/_core.d.ts +5 -5
  148. package/types/editorInjector/index.d.ts +2 -2
  149. package/types/events.d.ts +2 -0
  150. package/types/helper/converter.d.ts +9 -0
  151. package/types/helper/dom/domQuery.d.ts +5 -5
  152. package/types/helper/dom/domUtils.d.ts +8 -0
  153. package/types/helper/env.d.ts +6 -1
  154. package/types/helper/index.d.ts +4 -1
  155. package/types/index.d.ts +122 -120
  156. package/types/langs/_Lang.d.ts +194 -194
  157. package/types/modules/ColorPicker.d.ts +5 -1
  158. package/types/modules/Controller.d.ts +8 -4
  159. package/types/modules/Figure.d.ts +2 -1
  160. package/types/modules/HueSlider.d.ts +4 -1
  161. package/types/modules/SelectMenu.d.ts +1 -1
  162. package/types/plugins/command/blockquote.d.ts +1 -0
  163. package/types/plugins/command/list_bulleted.d.ts +1 -0
  164. package/types/plugins/command/list_numbered.d.ts +1 -0
  165. package/types/plugins/dropdown/align.d.ts +1 -0
  166. package/types/plugins/dropdown/backgroundColor.d.ts +1 -0
  167. package/types/plugins/dropdown/font.d.ts +1 -0
  168. package/types/plugins/dropdown/fontColor.d.ts +1 -0
  169. package/types/plugins/dropdown/formatBlock.d.ts +3 -2
  170. package/types/plugins/dropdown/lineHeight.d.ts +1 -0
  171. package/types/plugins/dropdown/list.d.ts +1 -0
  172. package/types/plugins/dropdown/table.d.ts +6 -0
  173. package/types/plugins/input/fontSize.d.ts +1 -0
  174. package/types/plugins/modal/drawing.d.ts +4 -0
  175. package/types/plugins/modal/link.d.ts +32 -15
  176. package/types/suneditor.d.ts +13 -9
  177. 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(this.options.get('componentScrollToOptions'));
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;