suneditor 3.0.0-beta.3 → 3.0.0-beta.30

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 (241) hide show
  1. package/CONTRIBUTING.md +8 -8
  2. package/README.md +44 -49
  3. package/dist/suneditor.min.css +1 -1
  4. package/dist/suneditor.min.js +1 -1
  5. package/package.json +95 -53
  6. package/src/assets/design/color.css +2 -2
  7. package/src/assets/design/size.css +2 -0
  8. package/src/assets/icons/defaultIcons.js +16 -1
  9. package/src/assets/suneditor-contents.css +9 -8
  10. package/src/assets/suneditor.css +29 -26
  11. package/src/core/{section → base}/actives.js +20 -12
  12. package/src/core/base/history.js +4 -4
  13. package/src/core/class/char.js +10 -10
  14. package/src/core/class/component.js +146 -57
  15. package/src/core/class/format.js +94 -2458
  16. package/src/core/class/html.js +187 -129
  17. package/src/core/class/inline.js +1853 -0
  18. package/src/core/class/listFormat.js +582 -0
  19. package/src/core/class/menu.js +14 -3
  20. package/src/core/class/nodeTransform.js +9 -14
  21. package/src/core/class/offset.js +162 -197
  22. package/src/core/class/selection.js +137 -34
  23. package/src/core/class/toolbar.js +73 -52
  24. package/src/core/class/ui.js +11 -11
  25. package/src/core/class/viewer.js +56 -55
  26. package/src/core/config/context.js +122 -0
  27. package/src/core/config/frameContext.js +204 -0
  28. package/src/core/config/options.js +639 -0
  29. package/src/core/editor.js +181 -108
  30. package/src/core/event/actions/index.js +229 -0
  31. package/src/core/event/effects/common.registry.js +60 -0
  32. package/src/core/event/effects/keydown.registry.js +551 -0
  33. package/src/core/event/effects/ruleHelpers.js +145 -0
  34. package/src/core/{base → event}/eventManager.js +119 -201
  35. package/src/core/event/executor.js +21 -0
  36. package/src/core/{base/eventHandlers → event/handlers}/handler_toolbar.js +4 -4
  37. package/src/core/{base/eventHandlers → event/handlers}/handler_ww_dragDrop.js +2 -2
  38. package/src/core/event/handlers/handler_ww_input.js +77 -0
  39. package/src/core/event/handlers/handler_ww_key.js +228 -0
  40. package/src/core/{base/eventHandlers → event/handlers}/handler_ww_mouse.js +3 -3
  41. package/src/core/event/ports.js +211 -0
  42. package/src/core/event/reducers/keydown.reducer.js +89 -0
  43. package/src/core/event/rules/keydown.rule.arrow.js +54 -0
  44. package/src/core/event/rules/keydown.rule.backspace.js +202 -0
  45. package/src/core/event/rules/keydown.rule.delete.js +126 -0
  46. package/src/core/event/rules/keydown.rule.enter.js +144 -0
  47. package/src/core/event/rules/keydown.rule.tab.js +29 -0
  48. package/src/core/section/constructor.js +79 -388
  49. package/src/core/section/documentType.js +47 -26
  50. package/src/core/util/instanceCheck.js +59 -0
  51. package/src/editorInjector/_classes.js +4 -0
  52. package/src/editorInjector/_core.js +17 -7
  53. package/src/editorInjector/index.js +10 -2
  54. package/src/events.js +6 -0
  55. package/src/helper/clipboard.js +24 -10
  56. package/src/helper/converter.js +17 -12
  57. package/src/helper/dom/domCheck.js +22 -3
  58. package/src/helper/dom/domQuery.js +91 -45
  59. package/src/helper/dom/domUtils.js +93 -19
  60. package/src/helper/dom/index.js +4 -0
  61. package/src/helper/env.js +11 -7
  62. package/src/helper/keyCodeMap.js +4 -3
  63. package/src/langs/ckb.js +1 -1
  64. package/src/langs/cs.js +1 -1
  65. package/src/langs/da.js +1 -1
  66. package/src/langs/de.js +1 -1
  67. package/src/langs/en.js +1 -1
  68. package/src/langs/es.js +1 -1
  69. package/src/langs/fa.js +1 -1
  70. package/src/langs/fr.js +1 -1
  71. package/src/langs/he.js +1 -1
  72. package/src/langs/hu.js +1 -1
  73. package/src/langs/it.js +1 -1
  74. package/src/langs/ja.js +1 -1
  75. package/src/langs/km.js +1 -1
  76. package/src/langs/ko.js +1 -1
  77. package/src/langs/lv.js +1 -1
  78. package/src/langs/nl.js +1 -1
  79. package/src/langs/pl.js +1 -1
  80. package/src/langs/pt_br.js +10 -10
  81. package/src/langs/ro.js +1 -1
  82. package/src/langs/ru.js +1 -1
  83. package/src/langs/se.js +1 -1
  84. package/src/langs/tr.js +1 -1
  85. package/src/langs/uk.js +1 -1
  86. package/src/langs/ur.js +1 -1
  87. package/src/langs/zh_cn.js +1 -1
  88. package/src/modules/ApiManager.js +25 -18
  89. package/src/modules/Browser.js +52 -61
  90. package/src/modules/ColorPicker.js +37 -38
  91. package/src/modules/Controller.js +85 -79
  92. package/src/modules/Figure.js +275 -187
  93. package/src/modules/FileManager.js +86 -92
  94. package/src/modules/HueSlider.js +67 -35
  95. package/src/modules/Modal.js +84 -77
  96. package/src/modules/ModalAnchorEditor.js +62 -79
  97. package/src/modules/SelectMenu.js +89 -86
  98. package/src/plugins/browser/audioGallery.js +9 -5
  99. package/src/plugins/browser/fileBrowser.js +10 -6
  100. package/src/plugins/browser/fileGallery.js +9 -5
  101. package/src/plugins/browser/imageGallery.js +9 -5
  102. package/src/plugins/browser/videoGallery.js +11 -6
  103. package/src/plugins/command/blockquote.js +1 -0
  104. package/src/plugins/command/exportPDF.js +11 -8
  105. package/src/plugins/command/fileUpload.js +41 -29
  106. package/src/plugins/command/list_bulleted.js +2 -1
  107. package/src/plugins/command/list_numbered.js +2 -1
  108. package/src/plugins/dropdown/align.js +8 -2
  109. package/src/plugins/dropdown/backgroundColor.js +19 -11
  110. package/src/plugins/dropdown/font.js +15 -9
  111. package/src/plugins/dropdown/fontColor.js +19 -11
  112. package/src/plugins/dropdown/formatBlock.js +7 -2
  113. package/src/plugins/dropdown/hr.js +7 -3
  114. package/src/plugins/dropdown/layout.js +6 -2
  115. package/src/plugins/dropdown/lineHeight.js +8 -3
  116. package/src/plugins/dropdown/list.js +2 -1
  117. package/src/plugins/dropdown/paragraphStyle.js +15 -11
  118. package/src/plugins/dropdown/{table.js → table/index.js} +514 -362
  119. package/src/plugins/dropdown/template.js +6 -2
  120. package/src/plugins/dropdown/textStyle.js +7 -3
  121. package/src/plugins/field/mention.js +33 -27
  122. package/src/plugins/input/fontSize.js +44 -37
  123. package/src/plugins/input/pageNavigator.js +3 -2
  124. package/src/plugins/modal/audio.js +90 -85
  125. package/src/plugins/modal/drawing.js +58 -66
  126. package/src/plugins/modal/embed.js +193 -180
  127. package/src/plugins/modal/image.js +441 -439
  128. package/src/plugins/modal/link.js +31 -8
  129. package/src/plugins/modal/math.js +23 -22
  130. package/src/plugins/modal/video.js +233 -230
  131. package/src/plugins/popup/anchor.js +24 -18
  132. package/src/suneditor.js +69 -24
  133. package/src/typedef.js +42 -19
  134. package/types/assets/icons/defaultIcons.d.ts +8 -0
  135. package/types/core/class/char.d.ts +1 -1
  136. package/types/core/class/component.d.ts +29 -7
  137. package/types/core/class/format.d.ts +4 -354
  138. package/types/core/class/html.d.ts +13 -4
  139. package/types/core/class/inline.d.ts +263 -0
  140. package/types/core/class/listFormat.d.ts +135 -0
  141. package/types/core/class/menu.d.ts +10 -2
  142. package/types/core/class/offset.d.ts +24 -26
  143. package/types/core/class/selection.d.ts +2 -0
  144. package/types/core/class/toolbar.d.ts +24 -11
  145. package/types/core/class/ui.d.ts +1 -1
  146. package/types/core/class/viewer.d.ts +1 -1
  147. package/types/core/config/context.d.ts +157 -0
  148. package/types/core/config/frameContext.d.ts +367 -0
  149. package/types/core/config/options.d.ts +1119 -0
  150. package/types/core/editor.d.ts +101 -66
  151. package/types/core/event/actions/index.d.ts +47 -0
  152. package/types/core/event/effects/common.registry.d.ts +50 -0
  153. package/types/core/event/effects/keydown.registry.d.ts +73 -0
  154. package/types/core/event/effects/ruleHelpers.d.ts +31 -0
  155. package/types/core/{base → event}/eventManager.d.ts +15 -46
  156. package/types/core/event/executor.d.ts +6 -0
  157. package/types/core/event/handlers/handler_ww_input.d.ts +41 -0
  158. package/types/core/{base/eventHandlers/handler_ww_key_input.d.ts → event/handlers/handler_ww_key.d.ts} +4 -6
  159. package/types/core/event/ports.d.ts +255 -0
  160. package/types/core/event/reducers/keydown.reducer.d.ts +75 -0
  161. package/types/core/event/rules/keydown.rule.arrow.d.ts +8 -0
  162. package/types/core/event/rules/keydown.rule.backspace.d.ts +9 -0
  163. package/types/core/event/rules/keydown.rule.delete.d.ts +9 -0
  164. package/types/core/event/rules/keydown.rule.enter.d.ts +9 -0
  165. package/types/core/event/rules/keydown.rule.tab.d.ts +9 -0
  166. package/types/core/section/constructor.d.ts +101 -631
  167. package/types/core/section/documentType.d.ts +14 -4
  168. package/types/core/util/instanceCheck.d.ts +50 -0
  169. package/types/editorInjector/_classes.d.ts +4 -0
  170. package/types/editorInjector/_core.d.ts +17 -7
  171. package/types/editorInjector/index.d.ts +10 -2
  172. package/types/events.d.ts +1 -0
  173. package/types/helper/clipboard.d.ts +2 -2
  174. package/types/helper/converter.d.ts +6 -9
  175. package/types/helper/dom/domCheck.d.ts +7 -0
  176. package/types/helper/dom/domQuery.d.ts +19 -8
  177. package/types/helper/dom/domUtils.d.ts +24 -2
  178. package/types/helper/dom/index.d.ts +86 -1
  179. package/types/helper/env.d.ts +6 -1
  180. package/types/helper/index.d.ts +7 -1
  181. package/types/helper/keyCodeMap.d.ts +3 -3
  182. package/types/index.d.ts +23 -117
  183. package/types/langs/index.d.ts +2 -2
  184. package/types/modules/ApiManager.d.ts +1 -8
  185. package/types/modules/Browser.d.ts +4 -62
  186. package/types/modules/ColorPicker.d.ts +4 -21
  187. package/types/modules/Controller.d.ts +8 -64
  188. package/types/modules/Figure.d.ts +54 -50
  189. package/types/modules/FileManager.d.ts +1 -13
  190. package/types/modules/HueSlider.d.ts +13 -3
  191. package/types/modules/Modal.d.ts +0 -43
  192. package/types/modules/ModalAnchorEditor.d.ts +0 -73
  193. package/types/modules/SelectMenu.d.ts +0 -85
  194. package/types/modules/index.d.ts +3 -3
  195. package/types/plugins/browser/audioGallery.d.ts +29 -18
  196. package/types/plugins/browser/fileBrowser.d.ts +38 -27
  197. package/types/plugins/browser/fileGallery.d.ts +29 -18
  198. package/types/plugins/browser/imageGallery.d.ts +24 -16
  199. package/types/plugins/browser/videoGallery.d.ts +29 -18
  200. package/types/plugins/command/blockquote.d.ts +1 -0
  201. package/types/plugins/command/exportPDF.d.ts +18 -18
  202. package/types/plugins/command/fileUpload.d.ts +65 -45
  203. package/types/plugins/command/list_bulleted.d.ts +1 -0
  204. package/types/plugins/command/list_numbered.d.ts +1 -0
  205. package/types/plugins/dropdown/align.d.ts +13 -8
  206. package/types/plugins/dropdown/backgroundColor.d.ts +30 -19
  207. package/types/plugins/dropdown/font.d.ts +13 -12
  208. package/types/plugins/dropdown/fontColor.d.ts +30 -19
  209. package/types/plugins/dropdown/formatBlock.d.ts +13 -8
  210. package/types/plugins/dropdown/hr.d.ts +15 -11
  211. package/types/plugins/dropdown/layout.d.ts +15 -11
  212. package/types/plugins/dropdown/lineHeight.d.ts +16 -11
  213. package/types/plugins/dropdown/list.d.ts +1 -0
  214. package/types/plugins/dropdown/paragraphStyle.d.ts +31 -27
  215. package/types/plugins/dropdown/table/index.d.ts +582 -0
  216. package/types/plugins/dropdown/table.d.ts +41 -86
  217. package/types/plugins/dropdown/template.d.ts +15 -11
  218. package/types/plugins/dropdown/textStyle.d.ts +19 -11
  219. package/types/plugins/field/mention.d.ts +58 -56
  220. package/types/plugins/index.d.ts +38 -38
  221. package/types/plugins/input/fontSize.d.ts +46 -50
  222. package/types/plugins/modal/audio.d.ts +26 -56
  223. package/types/plugins/modal/drawing.d.ts +0 -85
  224. package/types/plugins/modal/embed.d.ts +15 -79
  225. package/types/plugins/modal/image.d.ts +24 -136
  226. package/types/plugins/modal/link.d.ts +34 -15
  227. package/types/plugins/modal/math.d.ts +0 -16
  228. package/types/plugins/modal/video.d.ts +17 -86
  229. package/types/plugins/popup/anchor.d.ts +1 -8
  230. package/types/suneditor.d.ts +70 -19
  231. package/types/typedef.d.ts +60 -46
  232. package/src/core/base/eventHandlers/handler_ww_key_input.js +0 -1200
  233. package/src/core/section/context.js +0 -102
  234. package/types/core/section/context.d.ts +0 -45
  235. package/types/langs/_Lang.d.ts +0 -194
  236. /package/src/core/{base/eventHandlers → event/handlers}/handler_ww_clipboard.js +0 -0
  237. /package/types/core/{section → base}/actives.d.ts +0 -0
  238. /package/types/core/{base/eventHandlers → event/handlers}/handler_toolbar.d.ts +0 -0
  239. /package/types/core/{base/eventHandlers → event/handlers}/handler_ww_clipboard.d.ts +0 -0
  240. /package/types/core/{base/eventHandlers → event/handlers}/handler_ww_dragDrop.d.ts +0 -0
  241. /package/types/core/{base/eventHandlers → event/handlers}/handler_ww_mouse.d.ts +0 -0
@@ -4,6 +4,23 @@ import { FileManager, Figure, Controller } from '../../modules';
4
4
 
5
5
  const { NO_EVENT } = env;
6
6
 
7
+ /**
8
+ * @typedef FileUploadPluginOptions
9
+ * @property {string} uploadUrl - Server request URL for file upload
10
+ * @property {Object<string, string>} [uploadHeaders] - Server request headers
11
+ * @property {string} [uploadSizeLimit] - Total upload size limit in bytes
12
+ * @property {string} [uploadSingleSizeLimit] - Single file size limit in bytes
13
+ * @property {boolean} [allowMultiple=false] - Allow multiple file uploads
14
+ * @property {string} [acceptedFormats="*"] - Accepted file formats (e.g., 'image/*, .pdf')
15
+ * @property {string} [as="box"] - Specify the default form of the file component as 'box' or 'link'
16
+ * @property {Array<string>} [controls] - Additional controls to be added to the figure
17
+ * @property {__se__ComponentInsertBehaviorType} [insertBehavior] - Component insertion behavior for selection and cursor placement. [default: options.get('componentInsertBehavior')]
18
+ * - `auto`: Move cursor to the next line if possible, otherwise select the component.
19
+ * - `select`: Always select the inserted component.
20
+ * - `line`: Move cursor to the next line if possible, or create a new line and move there.
21
+ * - `none`: Do nothing.
22
+ */
23
+
7
24
  /**
8
25
  * @class
9
26
  * @description File upload plugin
@@ -22,18 +39,13 @@ class FileUpload extends EditorInjector {
22
39
  return dom.check.isAnchor(node) && node.hasAttribute('data-se-file-download') ? node : null;
23
40
  }
24
41
 
42
+ #acceptedCheck;
43
+ #element;
44
+
25
45
  /**
26
46
  * @constructor
27
47
  * @param {__se__EditorCore} editor - The root editor instance
28
- * @param {Object} pluginOptions - plugin options
29
- * @param {string} pluginOptions.uploadUrl - server request url
30
- * @param {Object<string, string>=} pluginOptions.uploadHeaders - server request headers
31
- * @param {string=} pluginOptions.uploadSizeLimit - upload size limit
32
- * @param {string=} pluginOptions.uploadSingleSizeLimit - upload single size limit
33
- * @param {boolean=} pluginOptions.allowMultiple - allow multiple files
34
- * @param {string=} pluginOptions.acceptedFormats - accepted formats
35
- * @param {string=} pluginOptions.as - Whether to use the 'Box' or 'Link' conversion button
36
- * @param {Array<string>} pluginOptions.controls - Additional controls to be added to the figure
48
+ * @param {FileUploadPluginOptions} pluginOptions - plugin options
37
49
  */
38
50
  constructor(editor, pluginOptions) {
39
51
  super(editor);
@@ -50,13 +62,15 @@ class FileUpload extends EditorInjector {
50
62
  this.uploadSingleSizeLimit = numbers.get(pluginOptions.uploadSingleSizeLimit, 0);
51
63
  this.allowMultiple = !!pluginOptions.allowMultiple;
52
64
  this.acceptedFormats = typeof pluginOptions.acceptedFormats !== 'string' ? '*' : pluginOptions.acceptedFormats.trim() || '*';
53
- this._acceptedCheck = this.acceptedFormats.split(', ');
54
65
  this.as = pluginOptions.as || 'box';
66
+ this.insertBehavior = pluginOptions.insertBehavior;
55
67
  this.input = dom.utils.createElement('input', { type: 'file', accept: this.acceptedFormats });
56
68
  if (this.allowMultiple) {
57
69
  this.input.setAttribute('multiple', 'multiple');
58
70
  }
59
- this._element = null;
71
+
72
+ this.#acceptedCheck = this.acceptedFormats.split(', ');
73
+ this.#element = null;
60
74
 
61
75
  // figure
62
76
  const customItems = {
@@ -117,12 +131,12 @@ class FileUpload extends EditorInjector {
117
131
  * @param {HTMLElement} target Target component element
118
132
  */
119
133
  select(target) {
120
- this._element = target;
134
+ this.#element = target;
121
135
  const asBtn = this.figure.controller.form.querySelector('[data-command="__c__as"]');
122
136
  if (dom.check.isFigure(target.parentElement)) {
123
137
  asBtn.innerHTML = this.icons.reduction + dom.utils.createTooltipInner(this.lang.asLink);
124
138
  asBtn.setAttribute('data-value', 'link');
125
- this.figure.open(target, { nonResizing: true, nonSizeInfo: true, nonBorder: true, figureTarget: true, __fileManagerInfo: false });
139
+ this.figure.open(target, { nonResizing: true, nonSizeInfo: true, nonBorder: true, figureTarget: true, infoOnly: false });
126
140
  } else {
127
141
  asBtn.innerHTML = this.icons.expansion + dom.utils.createTooltipInner(this.lang.asBlock);
128
142
  asBtn.setAttribute('data-value', 'box');
@@ -143,7 +157,7 @@ class FileUpload extends EditorInjector {
143
157
  onFilePasteAndDrop({ file }) {
144
158
  const fileType = file.type;
145
159
  if (
146
- !this._acceptedCheck.some((format) => {
160
+ !this.#acceptedCheck.some((format) => {
147
161
  if (format.startsWith('*')) return true;
148
162
  if (format.startsWith(fileType)) return true;
149
163
  })
@@ -180,11 +194,11 @@ class FileUpload extends EditorInjector {
180
194
 
181
195
  if (command === 'edit') {
182
196
  if (this.editInput.value.trim().length === 0) return;
183
- this._element.textContent = this.editInput.value;
197
+ this.#element.textContent = this.editInput.value;
184
198
  }
185
199
 
186
200
  this.controller.close();
187
- this.component.select(this._element, FileUpload.key);
201
+ this.component.select(this.#element, FileUpload.key);
188
202
  }
189
203
 
190
204
  /**
@@ -225,7 +239,7 @@ class FileUpload extends EditorInjector {
225
239
  for (let i = 0, len = fileList.length, f, s; i < len; i++) {
226
240
  f = fileList[i];
227
241
  s = f.size;
228
- if (slngleSizeLimit && slngleSizeLimit > s) {
242
+ if (slngleSizeLimit > 0 && s > slngleSizeLimit) {
229
243
  const err = '[SUNEDITOR.fileUpload.fail] Size of uploadable single file: ' + slngleSizeLimit / 1000 + 'KB';
230
244
  const message = await this.triggerEvent('onFileUploadError', {
231
245
  error: err,
@@ -269,7 +283,7 @@ class FileUpload extends EditorInjector {
269
283
  infos = newInfos || infos;
270
284
  const xmlHttp = await this.fileManager.asyncUpload(infos.url, infos.uploadHeaders, infos.files);
271
285
  uploadCallback(xmlHttp);
272
- }.bind(this, this.#_uploadCallBack.bind(this), fileInfo);
286
+ }.bind(this, this.#uploadCallBack.bind(this), fileInfo);
273
287
 
274
288
  const result = await this.triggerEvent('onFileUploadBefore', {
275
289
  info: fileInfo,
@@ -328,7 +342,7 @@ class FileUpload extends EditorInjector {
328
342
  * @description Create file element
329
343
  * @param {string} url File URL
330
344
  * @param {File|{name: string, size: number}} file File object
331
- * @param {boolean} isLast Is last file
345
+ * @param {boolean} isLast Indicates whether this is the last file in the batch (used for scroll and insert actions).
332
346
  */
333
347
  create(url, file, isLast) {
334
348
  const name = file.name || url;
@@ -350,21 +364,21 @@ class FileUpload extends EditorInjector {
350
364
 
351
365
  if (this.as === 'link') {
352
366
  a.className = 'se-component se-inline-component';
353
- this.component.insert(a, { skipCharCount: false, skipSelection: false, skipHistory: false });
367
+ this.component.insert(a, { scrollTo: isLast ? true : false, insertBehavior: isLast ? this.insertBehavior : null });
354
368
  return;
355
369
  }
356
370
 
357
371
  const figure = Figure.CreateContainer(a);
358
372
  dom.utils.addClass(figure.container, 'se-file-figure|se-flex-component');
359
373
 
360
- if (!this.component.insert(figure.container, { skipCharCount: false, skipSelection: isLast ? !this.options.get('componentAutoSelect') : true, skipHistory: false })) {
374
+ if (!this.component.insert(figure.container, { scrollTo: isLast ? true : false, insertBehavior: isLast ? this.insertBehavior : null })) {
361
375
  this.editor.focus();
362
376
  return;
363
377
  }
364
378
 
365
379
  if (!isLast) return;
366
380
 
367
- if (!this.options.get('componentAutoSelect')) {
381
+ if (!this.options.get('componentInsertBehavior')) {
368
382
  const line = this.format.addLine(figure.container, null);
369
383
  if (line) this.selection.setRange(line, 0, line, 0);
370
384
  } else {
@@ -373,12 +387,11 @@ class FileUpload extends EditorInjector {
373
387
  }
374
388
 
375
389
  /**
376
- * @private
377
390
  * @description Processes the server response after file upload.
378
391
  * - Registers the uploaded files in the editor.
379
392
  * @param {Object<string, *>} response - The response object from the server.
380
393
  */
381
- _register(response) {
394
+ #register(response) {
382
395
  response.result.forEach((file, i, a) => {
383
396
  this.create(
384
397
  file.url,
@@ -392,13 +405,12 @@ class FileUpload extends EditorInjector {
392
405
  }
393
406
 
394
407
  /**
395
- * @private
396
408
  * @description Handles file upload errors.
397
409
  * - Displays an error message if the upload fails.
398
410
  * @param {Object<string, *>} response - The error response from the server.
399
411
  * @returns {Promise<void>}
400
412
  */
401
- async _error(response) {
413
+ async #error(response) {
402
414
  const message = await this.triggerEvent('onFileUploadError', { error: response });
403
415
  if (message === false) return;
404
416
  const err = message === NO_EVENT ? response.errorMessage : message || response.errorMessage;
@@ -411,12 +423,12 @@ class FileUpload extends EditorInjector {
411
423
  * - Parses the response and registers the uploaded file.
412
424
  * @param {XMLHttpRequest} xmlHttp - The completed XHR request.
413
425
  */
414
- #_uploadCallBack(xmlHttp) {
426
+ #uploadCallBack(xmlHttp) {
415
427
  const response = JSON.parse(xmlHttp.responseText);
416
428
  if (response.errorMessage) {
417
- this._error(response);
429
+ this.#error(response);
418
430
  } else {
419
- this._register(response);
431
+ this.#register(response);
420
432
  }
421
433
  }
422
434
 
@@ -43,6 +43,7 @@ class List_bulleted extends EditorInjector {
43
43
  * @param {?HTMLElement=} element - Node element where the cursor is currently located
44
44
  * @param {?HTMLElement=} target - The plugin's toolbar button element
45
45
  * @returns {boolean} - Whether the plugin is active
46
+ * - If it returns "undefined", it will no longer be called in this scope.
46
47
  */
47
48
  active(element, target) {
48
49
  if (dom.check.isListCell(element) && /^UL$/i.test(element.parentElement.nodeName)) {
@@ -111,7 +112,7 @@ class List_bulleted extends EditorInjector {
111
112
  * @param {string} [type=""] List type
112
113
  */
113
114
  submit(type) {
114
- const range = this.format.applyList(`ul:${type || ''}`, null, false);
115
+ const range = this.listFormat.apply(`ul:${type || ''}`, null, false);
115
116
  if (range) this.selection.setRange(range.sc, range.so, range.ec, range.eo);
116
117
  this.editor.focus();
117
118
  this.history.push(false);
@@ -43,6 +43,7 @@ class List_numbered extends EditorInjector {
43
43
  * @param {?HTMLElement=} element - Node element where the cursor is currently located
44
44
  * @param {?HTMLElement=} target - The plugin's toolbar button element
45
45
  * @returns {boolean} - Whether the plugin is active
46
+ * - If it returns "undefined", it will no longer be called in this scope.
46
47
  */
47
48
  active(element, target) {
48
49
  if (dom.check.isListCell(element) && /^OL$/i.test(element.parentElement.nodeName)) {
@@ -111,7 +112,7 @@ class List_numbered extends EditorInjector {
111
112
  * @param {string} [type=""] List type
112
113
  */
113
114
  submit(type) {
114
- const range = this.format.applyList(`ol:${type || ''}`, null, false);
115
+ const range = this.listFormat.apply(`ol:${type || ''}`, null, false);
115
116
  if (range) this.selection.setRange(range.sc, range.so, range.ec, range.eo);
116
117
  this.editor.focus();
117
118
  this.history.push(false);
@@ -1,6 +1,11 @@
1
1
  import EditorInjector from '../../editorInjector';
2
2
  import { dom } from '../../helper';
3
3
 
4
+ /**
5
+ * @typedef {Object} AlignPluginOptions
6
+ * @property {Array.<"right"|"center"|"left"|"justify">} [items] - Align items
7
+ */
8
+
4
9
  /**
5
10
  * @class
6
11
  * @description Align plugin
@@ -12,8 +17,7 @@ class Align extends EditorInjector {
12
17
 
13
18
  /**
14
19
  * @param {__se__EditorCore} editor - The root editor instance
15
- * @param {Object} pluginOptions
16
- * @param {Array.<"right"|"center"|"left"|"justify">} pluginOptions.items - Align items
20
+ * @param {AlignPluginOptions} pluginOptions - Plugin options
17
21
  */
18
22
  constructor(editor, pluginOptions) {
19
23
  super(editor);
@@ -44,6 +48,7 @@ class Align extends EditorInjector {
44
48
  * @param {?HTMLElement=} element - Node element where the cursor is currently located
45
49
  * @param {?HTMLElement=} target - The plugin's toolbar button element
46
50
  * @returns {boolean} - Whether the plugin is active
51
+ * - If it returns "undefined", it will no longer be called in this scope.
47
52
  */
48
53
  active(element, target) {
49
54
  const targetChild = target.firstElementChild;
@@ -58,6 +63,7 @@ class Align extends EditorInjector {
58
63
  target.setAttribute('data-focus', textAlign);
59
64
  return true;
60
65
  }
66
+ return undefined;
61
67
  }
62
68
 
63
69
  return false;
@@ -2,6 +2,13 @@ import EditorInjector from '../../editorInjector';
2
2
  import ColorPicker from '../../modules/ColorPicker';
3
3
  import { dom } from '../../helper';
4
4
 
5
+ /**
6
+ * @typedef {Object} BackgroundColorPluginOptions
7
+ * @property {Array<string|{value: string, name: string}>} [items] - Color list
8
+ * @property {number} [splitNum] - Number of colors per line
9
+ * @property {boolean} [disableHEXInput] - Disable HEX input
10
+ */
11
+
5
12
  /**
6
13
  * @class
7
14
  * @description Text background color plugin
@@ -14,10 +21,7 @@ class BackgroundColor extends EditorInjector {
14
21
  /**
15
22
  * @constructor
16
23
  * @param {__se__EditorCore} editor - The root editor instance
17
- * @param {Object} pluginOptions
18
- * @param {Array<string|{value: string, name: string}>} pluginOptions.items - Color list
19
- * @param {number} pluginOptions.splitNum - Number of colors per line
20
- * @param {boolean} pluginOptions.disableHEXInput - Disable HEX input
24
+ * @param {BackgroundColorPluginOptions} pluginOptions - Plugin options
21
25
  */
22
26
  constructor(editor, pluginOptions) {
23
27
  super(editor);
@@ -47,15 +51,19 @@ class BackgroundColor extends EditorInjector {
47
51
  * @param {?HTMLElement=} element - Node element where the cursor is currently located
48
52
  * @param {?HTMLElement=} target - The plugin's toolbar button element
49
53
  * @returns {boolean} - Whether the plugin is active
54
+ * - If it returns "undefined", it will no longer be called in this scope.
50
55
  */
51
56
  active(element, target) {
52
57
  const colorHelper = /** @type {SVGPathElement} */ (target.querySelector('path.se-svg-color-helper'));
53
- if (!colorHelper) return false;
58
+ if (!colorHelper) return undefined;
54
59
 
60
+ let color = '';
55
61
  if (!element) {
56
- colorHelper.style.color = '';
57
- } else if (element.style.backgroundColor.length > 0) {
58
- colorHelper.style.color = element.style.backgroundColor;
62
+ colorHelper.style.color = color;
63
+ } else if (this.format.isLine(element)) {
64
+ return undefined;
65
+ } else if ((color = dom.utils.getStyle(element, 'backgroundColor'))) {
66
+ colorHelper.style.color = color;
59
67
  return true;
60
68
  }
61
69
 
@@ -68,7 +76,7 @@ class BackgroundColor extends EditorInjector {
68
76
  * @param {HTMLElement} target Line element at the current cursor position
69
77
  */
70
78
  on(target) {
71
- this.colorPicker.init(this.selection.getNode(), target);
79
+ this.colorPicker.init(this.selection.getNode(), target, (current) => this.format.isLine(current));
72
80
  }
73
81
 
74
82
  /**
@@ -88,9 +96,9 @@ class BackgroundColor extends EditorInjector {
88
96
  colorPickerAction(color) {
89
97
  if (color) {
90
98
  const newNode = dom.utils.createElement('SPAN', { style: 'background-color: ' + color + ';' });
91
- this.format.applyInlineElement(newNode, { stylesToModify: ['background-color'], nodesToRemove: null, strictRemove: null });
99
+ this.inline.apply(newNode, { stylesToModify: ['background-color'], nodesToRemove: null, strictRemove: null });
92
100
  } else {
93
- this.format.applyInlineElement(null, { stylesToModify: ['background-color'], nodesToRemove: ['span'], strictRemove: true });
101
+ this.inline.apply(null, { stylesToModify: ['background-color'], nodesToRemove: ['span'], strictRemove: true });
94
102
  }
95
103
 
96
104
  this.menu.dropdownOff();
@@ -1,6 +1,11 @@
1
1
  import EditorInjector from '../../editorInjector';
2
2
  import { dom } from '../../helper';
3
3
 
4
+ /**
5
+ * @typedef {Object} FontPluginOptions
6
+ * @property {Array<string>} [items] - Font list
7
+ */
8
+
4
9
  /**
5
10
  * @class
6
11
  * @description Text font plugin
@@ -13,10 +18,7 @@ class Font extends EditorInjector {
13
18
  /**
14
19
  * @constructor
15
20
  * @param {__se__EditorCore} editor - The root editor instance
16
- * @param {Object} pluginOptions
17
- * @param {Array<string>} pluginOptions.items - Font list
18
- * @param {number} pluginOptions.splitNum - Number of colors per line
19
- * @param {boolean} pluginOptions.disableHEXInput - Disable HEX input
21
+ * @param {FontPluginOptions} pluginOptions - plugin options
20
22
  */
21
23
  constructor(editor, pluginOptions) {
22
24
  super(editor);
@@ -43,17 +45,21 @@ class Font extends EditorInjector {
43
45
  * @param {?HTMLElement=} element - Node element where the cursor is currently located
44
46
  * @param {?HTMLElement=} target - The plugin's toolbar button element
45
47
  * @returns {boolean} - Whether the plugin is active
48
+ * - If it returns "undefined", it will no longer be called in this scope.
46
49
  */
47
50
  active(element, target) {
48
51
  const targetText = target.querySelector('.se-txt');
49
52
  const tooltip = target.parentNode.querySelector('.se-tooltip-text');
50
53
 
54
+ let fontFamily = '';
51
55
  if (!element) {
52
- const font = this.status.hasFocus ? this.editor.frameContext.get('wwComputedStyle').fontFamily : this.lang.font;
56
+ const font = this.status.hasFocus ? this.frameContext.get('wwComputedStyle').fontFamily : this.lang.font;
53
57
  dom.utils.changeTxt(targetText, font);
54
58
  dom.utils.changeTxt(tooltip, this.status.hasFocus ? this.lang.font + (font ? ' (' + font + ')' : '') : font);
55
- } else if (element?.style.fontFamily.length > 0) {
56
- const selectFont = element.style.fontFamily.replace(/["']/g, '');
59
+ } else if (this.format.isLine(element)) {
60
+ return undefined;
61
+ } else if ((fontFamily = dom.utils.getStyle(element, 'fontFamily'))) {
62
+ const selectFont = fontFamily.replace(/["']/g, '');
57
63
  dom.utils.changeTxt(targetText, selectFont);
58
64
  dom.utils.changeTxt(tooltip, this.lang.font + ' (' + selectFont + ')');
59
65
  return true;
@@ -102,9 +108,9 @@ class Font extends EditorInjector {
102
108
  if ((await this.triggerEvent('onFontActionBefore', { value })) === false) return;
103
109
 
104
110
  const newNode = dom.utils.createElement('SPAN', { style: 'font-family: ' + value + ';' });
105
- this.format.applyInlineElement(newNode, { stylesToModify: ['font-family'], nodesToRemove: null, strictRemove: null });
111
+ this.inline.apply(newNode, { stylesToModify: ['font-family'], nodesToRemove: null, strictRemove: null });
106
112
  } else {
107
- this.format.applyInlineElement(null, { stylesToModify: ['font-family'], nodesToRemove: ['span'], strictRemove: true });
113
+ this.inline.apply(null, { stylesToModify: ['font-family'], nodesToRemove: ['span'], strictRemove: true });
108
114
  }
109
115
 
110
116
  this.menu.dropdownOff();
@@ -2,6 +2,13 @@ import EditorInjector from '../../editorInjector';
2
2
  import ColorPicker from '../../modules/ColorPicker';
3
3
  import { dom } from '../../helper';
4
4
 
5
+ /**
6
+ * @typedef {Object} FontColorPluginOptions
7
+ * @property {Array<string|{value: string, name: string}>} [items] - Color list
8
+ * @property {number} [splitNum] - Number of colors per line
9
+ * @property {boolean} [disableHEXInput] - Disable HEX input
10
+ */
11
+
5
12
  /**
6
13
  * @class
7
14
  * @description Font color plugin
@@ -14,10 +21,7 @@ class FontColor extends EditorInjector {
14
21
  /**
15
22
  * @constructor
16
23
  * @param {__se__EditorCore} editor - The root editor instance
17
- * @param {Object} pluginOptions
18
- * @param {Array<string|{value: string, name: string}>} pluginOptions.items - Color list
19
- * @param {number} pluginOptions.splitNum - Number of colors per line
20
- * @param {boolean} pluginOptions.disableHEXInput - Disable HEX input
24
+ * @param {FontColorPluginOptions} pluginOptions - Plugin options
21
25
  */
22
26
  constructor(editor, pluginOptions) {
23
27
  super(editor);
@@ -47,16 +51,20 @@ class FontColor extends EditorInjector {
47
51
  * @param {?HTMLElement=} element - Node element where the cursor is currently located
48
52
  * @param {?HTMLElement=} target - The plugin's toolbar button element
49
53
  * @returns {boolean} - Whether the plugin is active
54
+ * - If it returns "undefined", it will no longer be called in this scope.
50
55
  */
51
56
  active(element, target) {
52
57
  /** @type {HTMLElement} */
53
58
  const colorHelper = target.querySelector('.se-svg-color-helper');
54
- if (!colorHelper) return false;
59
+ if (!colorHelper) return undefined;
55
60
 
61
+ let color = '';
56
62
  if (!element) {
57
- colorHelper.style.color = '';
58
- } else if (element?.style.color.length > 0) {
59
- colorHelper.style.color = element.style.color;
63
+ colorHelper.style.color = color;
64
+ } else if (this.format.isLine(element)) {
65
+ return undefined;
66
+ } else if ((color = dom.utils.getStyle(element, 'color'))) {
67
+ colorHelper.style.color = color;
60
68
  return true;
61
69
  }
62
70
 
@@ -69,7 +77,7 @@ class FontColor extends EditorInjector {
69
77
  * @param {HTMLElement} target Line element at the current cursor position
70
78
  */
71
79
  on(target) {
72
- this.colorPicker.init(this.selection.getNode(), target);
80
+ this.colorPicker.init(this.selection.getNode(), target, (current) => this.format.isLine(current));
73
81
  }
74
82
 
75
83
  /**
@@ -89,9 +97,9 @@ class FontColor extends EditorInjector {
89
97
  colorPickerAction(color) {
90
98
  if (color) {
91
99
  const newNode = dom.utils.createElement('SPAN', { style: 'color: ' + color + ';' });
92
- this.format.applyInlineElement(newNode, { stylesToModify: ['color'], nodesToRemove: null, strictRemove: null });
100
+ this.inline.apply(newNode, { stylesToModify: ['color'], nodesToRemove: null, strictRemove: null });
93
101
  } else {
94
- this.format.applyInlineElement(null, { stylesToModify: ['color'], nodesToRemove: ['span'], strictRemove: true });
102
+ this.inline.apply(null, { stylesToModify: ['color'], nodesToRemove: ['span'], strictRemove: true });
95
103
  }
96
104
 
97
105
  this.menu.dropdownOff();
@@ -1,6 +1,11 @@
1
1
  import EditorInjector from '../../editorInjector';
2
2
  import { dom } from '../../helper';
3
3
 
4
+ /**
5
+ * @typedef {Object} FormatBlockPluginOptions
6
+ * @property {Array<string>} [items] - Format list
7
+ */
8
+
4
9
  /**
5
10
  * @class
6
11
  * @description FormatBlock Plugin (P, BLOCKQUOTE, PRE, H1, H2...)
@@ -13,8 +18,7 @@ class FormatBlock extends EditorInjector {
13
18
  /**
14
19
  * @constructor
15
20
  * @param {__se__EditorCore} editor - The root editor instance
16
- * @param {Object} pluginOptions
17
- * @param {Array<string>} pluginOptions.items - Format list
21
+ * @param {FormatBlockPluginOptions} pluginOptions - Plugin options
18
22
  */
19
23
  constructor(editor, pluginOptions) {
20
24
  super(editor);
@@ -39,6 +43,7 @@ class FormatBlock extends EditorInjector {
39
43
  * @param {?HTMLElement=} element - Node element where the cursor is currently located
40
44
  * @param {?HTMLElement=} target - The plugin's toolbar button element
41
45
  * @returns {boolean} - Whether the plugin is active
46
+ * - If it returns "undefined", it will no longer be called in this scope.
42
47
  */
43
48
  active(element, target) {
44
49
  let formatTitle = this.lang.formats;
@@ -1,6 +1,11 @@
1
1
  import EditorInjector from '../../editorInjector';
2
2
  import { dom } from '../../helper';
3
3
 
4
+ /**
5
+ * @typedef {Object} HRPluginOptions
6
+ * @property {Array<{name: string, class: string}>} [items] - HR list
7
+ */
8
+
4
9
  /**
5
10
  * @class
6
11
  * @description HR Plugin
@@ -21,8 +26,7 @@ class HR extends EditorInjector {
21
26
  /**
22
27
  * @constructor
23
28
  * @param {__se__EditorCore} editor - The root editor instance
24
- * @param {Object} pluginOptions
25
- * @param {Array<{name: string, class: string}>} pluginOptions.items - HR list
29
+ * @param {HRPluginOptions} pluginOptions - Plugin options
26
30
  */
27
31
  constructor(editor, pluginOptions) {
28
32
  // plugin bisic properties
@@ -106,7 +110,7 @@ class HR extends EditorInjector {
106
110
  submit(className) {
107
111
  const hr = dom.utils.createElement('hr', { class: className });
108
112
  this.editor.focus();
109
- this.component.insert(hr, { skipCharCount: false, skipSelection: true, skipHistory: false });
113
+ this.component.insert(hr, { insertBehavior: 'line' });
110
114
  return hr;
111
115
  }
112
116
  }
@@ -1,6 +1,11 @@
1
1
  import EditorInjector from '../../editorInjector';
2
2
  import { dom } from '../../helper';
3
3
 
4
+ /**
5
+ * @typedef {Object} LayoutPluginOptions
6
+ * @property {Array<{name: string, html: string}>} [items] - Layout list
7
+ */
8
+
4
9
  /**
5
10
  * @class
6
11
  * @description Layout Plugin, Apply layout to the entire editor.
@@ -13,8 +18,7 @@ class Layout extends EditorInjector {
13
18
  /**
14
19
  * @constructor
15
20
  * @param {__se__EditorCore} editor - The root editor instance
16
- * @param {Object} pluginOptions
17
- * @param {Array<{name: string, html: string}>} pluginOptions.items - Layout list
21
+ * @param {LayoutPluginOptions} pluginOptions - Plugin options
18
22
  */
19
23
  constructor(editor, pluginOptions) {
20
24
  // plugin bisic properties
@@ -1,6 +1,11 @@
1
1
  import EditorInjector from '../../editorInjector';
2
2
  import { dom } from '../../helper';
3
3
 
4
+ /**
5
+ * @typedef {Object} LineHeightPluginOptions
6
+ * @property {Array<{text: string, value: number}>} [items] - Line height list
7
+ */
8
+
4
9
  /**
5
10
  * @class
6
11
  * @description Line height Plugin
@@ -13,8 +18,7 @@ class LineHeight extends EditorInjector {
13
18
  /**
14
19
  * @constructor
15
20
  * @param {__se__EditorCore} editor - The root editor instance
16
- * @param {Object} pluginOptions
17
- * @param {Array<{text: string, value: number}>} pluginOptions.items - Line height list
21
+ * @param {LineHeightPluginOptions} pluginOptions - Plugin options
18
22
  */
19
23
  constructor(editor, pluginOptions) {
20
24
  // plugin bisic properties
@@ -39,9 +43,10 @@ class LineHeight extends EditorInjector {
39
43
  * @param {?HTMLElement=} element - Node element where the cursor is currently located
40
44
  * @param {?HTMLElement=} target - The plugin's toolbar button element
41
45
  * @returns {boolean} - Whether the plugin is active
46
+ * - If it returns "undefined", it will no longer be called in this scope.
42
47
  */
43
48
  active(element, target) {
44
- if (element?.style?.lineHeight.length > 0) {
49
+ if (this.format.isLine(element) && element.style.lineHeight.length > 0) {
45
50
  dom.utils.addClass(target, 'active');
46
51
  return true;
47
52
  }
@@ -40,6 +40,7 @@ class List extends EditorInjector {
40
40
  * @param {?HTMLElement=} element - Node element where the cursor is currently located
41
41
  * @param {?HTMLElement=} target - The plugin's toolbar button element
42
42
  * @returns {boolean} - Whether the plugin is active
43
+ * - If it returns "undefined", it will no longer be called in this scope.
43
44
  */
44
45
  active(element, target) {
45
46
  const icon = target.firstElementChild;
@@ -91,7 +92,7 @@ class List extends EditorInjector {
91
92
  action(target) {
92
93
  const command = target.getAttribute('data-command');
93
94
  const type = target.getAttribute('data-value') || '';
94
- const range = this.format.applyList(`${command}:${type}`, null, false);
95
+ const range = this.listFormat.apply(`${command}:${type}`, null, false);
95
96
  if (range) this.selection.setRange(range.sc, range.so, range.ec, range.eo);
96
97
 
97
98
  this.menu.dropdownOff();
@@ -1,6 +1,20 @@
1
1
  import EditorInjector from '../../editorInjector';
2
2
  import { dom } from '../../helper';
3
3
 
4
+ /**
5
+ * @typedef {Object} ParagraphStylePluginOptions
6
+ * @property {Array<string|{name: string, class: string, _class: string}>} [items] - Paragraph item list
7
+ * @example
8
+ * use default paragraph styles
9
+ * ['spaced', 'bordered', 'neon']
10
+ * custom paragraph styles
11
+ * [
12
+ * { name: 'spaced', class: '__se__p-spaced', _class: '' },
13
+ * { name: 'bordered', class: '__se__p-bordered', _class: '' },
14
+ * { name: 'neon', class: '__se__p-neon', _class: '' }
15
+ * ]
16
+ */
17
+
4
18
  /**
5
19
  * @class
6
20
  * @description A plugin to style lines using classes.
@@ -13,17 +27,7 @@ class ParagraphStyle extends EditorInjector {
13
27
  /**
14
28
  * @constructor
15
29
  * @param {__se__EditorCore} editor - The root editor instance
16
- * @param {Object} pluginOptions
17
- * @param {Array<string|{name: string, class: string, _class: string}>} pluginOptions.items - Paragraph item list
18
- * @example
19
- * use default paragraph styles
20
- * ['spaced', 'bordered', 'neon']
21
- * custom paragraph styles
22
- [
23
- { name: 'spaced', class: '__se__p-spaced', _class: '' },
24
- { name: 'bordered', class: '__se__p-bordered', _class: '' },
25
- { name: 'neon', class: '__se__p-neon', _class: ''}
26
- ]
30
+ * @param {ParagraphStylePluginOptions} pluginOptions - Plugin options
27
31
  */
28
32
  constructor(editor, pluginOptions) {
29
33
  // plugin bisic properties