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
@@ -20,6 +20,11 @@ const { NO_EVENT, ON_OVER_COMPONENT } = env;
20
20
  * @property {boolean} [allowMultiple] - Whether to allow multiple file uploads.
21
21
  * @property {string} [acceptedFormats="audio/*"] - Accepted file formats (default is "audio/*").
22
22
  * @property {Object<string, string>} [audioTagAttributes] - Additional attributes to set on the audio tag.
23
+ * @property {__se__ComponentInsertBehaviorType} [insertBehavior] - Component insertion behavior for selection and cursor placement. [default: options.get('componentInsertBehavior')]
24
+ * - `auto`: Move cursor to the next line if possible, otherwise select the component.
25
+ * - `select`: Always select the inserted component.
26
+ * - `line`: Move cursor to the next line if possible, or create a new line and move there.
27
+ * - `none`: Do nothing.
23
28
  */
24
29
 
25
30
  /**
@@ -39,6 +44,11 @@ class Audio_ extends EditorInjector {
39
44
  return /^AUDIO$/i.test(node?.nodeName) ? node : null;
40
45
  }
41
46
 
47
+ #element;
48
+ #defaultWidth;
49
+ #defaultHeight;
50
+ #urlValue;
51
+
42
52
  /**
43
53
  * @constructor
44
54
  * @param {__se__EditorCore} editor - The root editor instance
@@ -62,7 +72,8 @@ class Audio_ extends EditorInjector {
62
72
  uploadSingleSizeLimit: numbers.get(pluginOptions.uploadSingleSizeLimit, 0),
63
73
  allowMultiple: !!pluginOptions.allowMultiple,
64
74
  acceptedFormats: typeof pluginOptions.acceptedFormats !== 'string' || pluginOptions.acceptedFormats.trim() === '*' ? 'audio/*' : pluginOptions.acceptedFormats.trim() || 'audio/*',
65
- audioTagAttributes: pluginOptions.audioTagAttributes || null
75
+ audioTagAttributes: pluginOptions.audioTagAttributes || null,
76
+ insertBehavior: pluginOptions.insertBehavior
66
77
  };
67
78
 
68
79
  // create HTML
@@ -89,12 +100,12 @@ class Audio_ extends EditorInjector {
89
100
  this.audioUrlFile = modalEl.querySelector('.se-input-url');
90
101
  /** @type {HTMLElement} */
91
102
  this.preview = modalEl.querySelector('.se-link-preview');
92
- /** @type {HTMLAudioElement} */
93
- this._element = null;
94
103
 
95
- this.defaultWidth = this.pluginOptions.defaultWidth;
96
- this.defaultHeight = this.pluginOptions.defaultHeight;
97
- this.urlValue = '';
104
+ /** @type {HTMLAudioElement} */
105
+ this.#element = null;
106
+ this.#defaultWidth = this.pluginOptions.defaultWidth;
107
+ this.#defaultHeight = this.pluginOptions.defaultHeight;
108
+ this.#urlValue = '';
98
109
 
99
110
  const galleryButton = modalEl.querySelector('.__se__gallery');
100
111
  if (galleryButton) this.eventManager.addEvent(galleryButton, 'click', this.#OpenGallery.bind(this));
@@ -127,8 +138,8 @@ class Audio_ extends EditorInjector {
127
138
  on(isUpdate) {
128
139
  if (!isUpdate) {
129
140
  if (this.audioInputFile && this.pluginOptions.allowMultiple) this.audioInputFile.setAttribute('multiple', 'multiple');
130
- } else if (this._element) {
131
- this.urlValue = this.preview.textContent = this.audioUrlFile.value = this._element.src;
141
+ } else if (this.#element) {
142
+ this.#urlValue = this.preview.textContent = this.audioUrlFile.value = this.#element.src;
132
143
  if (this.audioInputFile && this.pluginOptions.allowMultiple) this.audioInputFile.removeAttribute('multiple');
133
144
  } else {
134
145
  if (this.audioInputFile && this.pluginOptions.allowMultiple) this.audioInputFile.removeAttribute('multiple');
@@ -161,8 +172,8 @@ class Audio_ extends EditorInjector {
161
172
  async modalAction() {
162
173
  if (this.audioInputFile && this.audioInputFile?.files.length > 0) {
163
174
  return await this.submitFile(this.audioInputFile.files);
164
- } else if (this.audioUrlFile && this.urlValue.length > 0) {
165
- return await this.submitURL(this.urlValue);
175
+ } else if (this.audioUrlFile && this.#urlValue.length > 0) {
176
+ return await this.submitURL(this.#urlValue);
166
177
  }
167
178
  return false;
168
179
  }
@@ -174,7 +185,7 @@ class Audio_ extends EditorInjector {
174
185
  init() {
175
186
  Modal.OnChangeFile(this.fileModalWrapper, []);
176
187
  if (this.audioInputFile) this.audioInputFile.value = '';
177
- if (this.audioUrlFile) this.urlValue = this.preview.textContent = this.audioUrlFile.value = '';
188
+ if (this.audioUrlFile) this.#urlValue = this.preview.textContent = this.audioUrlFile.value = '';
178
189
  if (this.audioInputFile && this.audioUrlFile) {
179
190
  this.audioUrlFile.disabled = false;
180
191
  this.preview.style.textDecoration = '';
@@ -189,11 +200,11 @@ class Audio_ extends EditorInjector {
189
200
  controllerAction(target) {
190
201
  switch (target.getAttribute('data-command')) {
191
202
  case 'update':
192
- if (this.audioUrlFile) this.urlValue = this.preview.textContent = this.audioUrlFile.value = this._element.src;
203
+ if (this.audioUrlFile) this.#urlValue = this.preview.textContent = this.audioUrlFile.value = this.#element.src;
193
204
  this.open();
194
205
  break;
195
206
  case 'copy': {
196
- const figure = Figure.GetContainer(this._element);
207
+ const figure = Figure.GetContainer(this.#element);
197
208
  this.component.copy(figure.container);
198
209
  break;
199
210
  }
@@ -221,7 +232,7 @@ class Audio_ extends EditorInjector {
221
232
  const figureInfo = Figure.GetContainer(element);
222
233
  if (figureInfo && figureInfo.container && figureInfo.cover) return;
223
234
 
224
- this._setTagAttrs(element);
235
+ this.#setTagAttrs(element);
225
236
  const figure = Figure.CreateContainer(element.cloneNode(true), 'se-flex-component');
226
237
  this.figure.retainFigureFormat(figure.container, element, null, this.fileManager);
227
238
  }
@@ -234,21 +245,8 @@ class Audio_ extends EditorInjector {
234
245
  * @param {HTMLElement} target Target component element
235
246
  */
236
247
  select(target) {
237
- this.figure.open(target, { nonResizing: true, nonSizeInfo: true, nonBorder: true, figureTarget: true, __fileManagerInfo: false });
238
- this._ready(target);
239
- }
240
-
241
- /**
242
- * @private
243
- * @description Prepares the component for selection.
244
- * - Ensures that the controller is properly positioned and initialized.
245
- * - Prevents duplicate event handling if the component is already selected.
246
- * @param {HTMLElement} target - The selected element.
247
- */
248
- _ready(target) {
249
- if (_DragHandle.get('__overInfo') === ON_OVER_COMPONENT) return;
250
- this._element = /** @type {HTMLAudioElement} */ (target);
251
- this.controller.open(target, null, { isWWTarget: false, addOffset: null });
248
+ this.figure.open(target, { nonResizing: true, nonSizeInfo: true, nonBorder: true, figureTarget: true, infoOnly: false });
249
+ this.#ready(target);
252
250
  }
253
251
 
254
252
  /**
@@ -258,7 +256,7 @@ class Audio_ extends EditorInjector {
258
256
  * @returns {Promise<void>}
259
257
  */
260
258
  async destroy(target) {
261
- const element = target || this._element;
259
+ const element = target || this.#element;
262
260
  const figure = Figure.GetContainer(element);
263
261
  const container = figure.container || element;
264
262
  const focusEl = container.previousElementSibling || container.nextElementSibling;
@@ -271,7 +269,7 @@ class Audio_ extends EditorInjector {
271
269
  this.init();
272
270
  this.controller.close();
273
271
 
274
- if (emptyDiv !== this.editor.frameContext.get('wysiwyg')) {
272
+ if (emptyDiv !== this.frameContext.get('wysiwyg')) {
275
273
  this.nodeTransform.removeAllParents(
276
274
  emptyDiv,
277
275
  function (current) {
@@ -286,25 +284,6 @@ class Audio_ extends EditorInjector {
286
284
  this.history.push(false);
287
285
  }
288
286
 
289
- /**
290
- * @private
291
- * @description Registers uploaded audio files and creates the corresponding audio elements.
292
- * - Iterates through the uploaded files and inserts them into the editor.
293
- * @param {AudioInfo_audio} info - Upload metadata, including `isUpdate` flag and `element`.
294
- * @param {Object<string, *>} response - Server response containing uploaded file details.
295
- */
296
- _register(info, response) {
297
- const fileList = response.result;
298
-
299
- for (let i = 0, len = fileList.length, file, oAudio; i < len; i++) {
300
- if (info.isUpdate) oAudio = info.element;
301
- else oAudio = this._createAudioTag();
302
-
303
- file = { name: fileList[i].name, size: fileList[i].size };
304
- this._createComp(oAudio, fileList[i].url, file, info.isUpdate);
305
- }
306
- }
307
-
308
287
  /**
309
288
  * @description Create an "audio" component using the provided files.
310
289
  * @param {FileList|File[]} fileList File object list
@@ -321,7 +300,7 @@ class Audio_ extends EditorInjector {
321
300
  if (!/audio/i.test(f.type)) continue;
322
301
 
323
302
  s = f.size;
324
- if (slngleSizeLimit && slngleSizeLimit > s) {
303
+ if (slngleSizeLimit > 0 && s > slngleSizeLimit) {
325
304
  const err = '[SUNEDITOR.audioUpload.fail] Size of uploadable single file: ' + slngleSizeLimit / 1000 + 'KB';
326
305
  const message = await this.triggerEvent('onAudioUploadError', {
327
306
  error: err,
@@ -352,13 +331,13 @@ class Audio_ extends EditorInjector {
352
331
  const audioInfo = {
353
332
  files,
354
333
  isUpdate: this.modal.isUpdate,
355
- element: this._element
334
+ element: this.#element
356
335
  };
357
336
 
358
- const handler = function (newInfos, infos) {
337
+ const handler = function (uploadCallback, newInfos, infos) {
359
338
  infos = newInfos || infos;
360
- this._serverUpload(infos, infos.files);
361
- }.bind(this, audioInfo);
339
+ uploadCallback(infos, infos.files);
340
+ }.bind(this, this.#serverUpload.bind(this), audioInfo);
362
341
 
363
342
  const result = await this.triggerEvent('onAudioUploadBefore', {
364
343
  info: audioInfo,
@@ -387,13 +366,13 @@ class Audio_ extends EditorInjector {
387
366
  url,
388
367
  files: file,
389
368
  isUpdate: this.modal.isUpdate,
390
- element: this._createAudioTag()
369
+ element: this.#createAudioTag()
391
370
  };
392
371
 
393
- const handler = function (newInfos, infos) {
372
+ const handler = function (uploadCallback, newInfos, infos) {
394
373
  infos = newInfos || infos;
395
- this._createComp(infos.element, infos.url, infos.files, infos.isUpdate);
396
- }.bind(this, audioInfo);
374
+ uploadCallback(infos.element, infos.url, infos.files, infos.isUpdate, true);
375
+ }.bind(this, this.create.bind(this), audioInfo);
397
376
 
398
377
  const result = await this.triggerEvent('onAudioUploadBefore', {
399
378
  info: audioInfo,
@@ -410,7 +389,6 @@ class Audio_ extends EditorInjector {
410
389
  }
411
390
 
412
391
  /**
413
- * @private
414
392
  * @description Creates or updates an audio component within the editor.
415
393
  * - If `isUpdate` is `true`, updates the existing element's `src`.
416
394
  * - Otherwise, inserts a new audio component with the given file.
@@ -418,23 +396,24 @@ class Audio_ extends EditorInjector {
418
396
  * @param {string} src - The source URL of the audio file.
419
397
  * @param {{name: string, size: number}} file - The file metadata (name, size).
420
398
  * @param {boolean} isUpdate - Whether to update an existing element.
399
+ * @param {boolean} isLast - Indicates whether this is the last file in the batch (used for scroll and insert actions).
421
400
  */
422
- _createComp(element, src, file, isUpdate) {
401
+ create(element, src, file, isUpdate, isLast) {
423
402
  // create new tag
424
403
  if (!isUpdate) {
425
404
  this.fileManager.setFileData(element, file);
426
405
  element.src = src;
427
406
  const figure = Figure.CreateContainer(element, 'se-flex-component');
428
- if (!this.component.insert(figure.container, { skipCharCount: false, skipSelection: !this.options.get('componentAutoSelect'), skipHistory: false })) {
429
- this.editor.focus();
407
+ if (!this.component.insert(figure.container, { scrollTo: isLast ? true : false, insertBehavior: isLast ? this.pluginOptions.insertBehavior : 'line' })) {
408
+ if (isLast) this.editor.focus();
430
409
  return;
431
410
  }
432
- if (!this.options.get('componentAutoSelect')) {
411
+ if (!this.options.get('componentInsertBehavior')) {
433
412
  const line = this.format.addLine(figure.container, null);
434
413
  if (line) this.selection.setRange(line, 0, line, 0);
435
414
  }
436
415
  } else {
437
- if (this._element) element = this._element;
416
+ if (this.#element) element = this.#element;
438
417
  this.fileManager.setFileData(element, file);
439
418
  if (element && element.src !== src) {
440
419
  element.src = src;
@@ -449,27 +428,55 @@ class Audio_ extends EditorInjector {
449
428
  }
450
429
 
451
430
  /**
452
- * @private
431
+ * @description Prepares the component for selection.
432
+ * - Ensures that the controller is properly positioned and initialized.
433
+ * - Prevents duplicate event handling if the component is already selected.
434
+ * @param {HTMLElement} target - The selected element.
435
+ */
436
+ #ready(target) {
437
+ if (_DragHandle.get('__overInfo') === ON_OVER_COMPONENT) return;
438
+ this.#element = /** @type {HTMLAudioElement} */ (target);
439
+ this.controller.open(target, null, { isWWTarget: false, addOffset: null });
440
+ }
441
+
442
+ /**
443
+ * @description Registers uploaded audio files and creates the corresponding audio elements.
444
+ * - Iterates through the uploaded files and inserts them into the editor.
445
+ * @param {AudioInfo_audio} info - Upload metadata, including `isUpdate` flag and `element`.
446
+ * @param {Object<string, *>} response - Server response containing uploaded file details.
447
+ */
448
+ #register(info, response) {
449
+ const fileList = response.result;
450
+
451
+ for (let i = 0, len = fileList.length, file, oAudio; i < len; i++) {
452
+ if (info.isUpdate) oAudio = info.element;
453
+ else oAudio = this.#createAudioTag();
454
+
455
+ file = { name: fileList[i].name, size: fileList[i].size };
456
+ this.create(oAudio, fileList[i].url, file, info.isUpdate, i === len - 1);
457
+ }
458
+ }
459
+
460
+ /**
453
461
  * @description Creates a new `<audio>` element with default attributes.
454
462
  * - Applies width, height, and additional attributes from plugin options.
455
463
  * @returns {HTMLAudioElement} - The newly created `<audio>` element.
456
464
  */
457
- _createAudioTag() {
458
- const w = this.defaultWidth;
459
- const h = this.defaultHeight;
465
+ #createAudioTag() {
466
+ const w = this.#defaultWidth;
467
+ const h = this.#defaultHeight;
460
468
  /** @type {HTMLAudioElement} */
461
469
  const oAudio = dom.utils.createElement('AUDIO', { style: (w ? 'width:' + w + '; ' : '') + (h ? 'height:' + h + ';' : '') });
462
- this._setTagAttrs(oAudio);
470
+ this.#setTagAttrs(oAudio);
463
471
  return oAudio;
464
472
  }
465
473
 
466
474
  /**
467
- * @private
468
475
  * @description Sets attributes on an audio element based on plugin options.
469
476
  * - Adds the `controls` attribute and applies any custom attributes.
470
477
  * @param {HTMLElement} element - The `<audio>` element to modify.
471
478
  */
472
- _setTagAttrs(element) {
479
+ #setTagAttrs(element) {
473
480
  element.setAttribute('controls', 'true');
474
481
 
475
482
  const attrs = this.pluginOptions.audioTagAttributes;
@@ -481,21 +488,19 @@ class Audio_ extends EditorInjector {
481
488
  }
482
489
 
483
490
  /**
484
- * @private
485
491
  * @description Uploads audio files to the server.
486
492
  * - Sends a request to the configured upload URL and processes the response.
487
493
  * @param {AudioInfo_audio} info - Upload metadata, including `files` and `isUpdate`.
488
494
  * @param {FileList|File[]} files - The files to be uploaded.
489
495
  */
490
- _serverUpload(info, files) {
496
+ #serverUpload(info, files) {
491
497
  if (!files) return;
492
498
 
493
499
  const uploadFiles = this.modal.isUpdate ? [files[0]] : files;
494
- this.fileManager.upload(this.pluginOptions.uploadUrl, this.pluginOptions.uploadHeaders, uploadFiles, this.#UploadCallBack.bind(this, info), this._error.bind(this));
500
+ this.fileManager.upload(this.pluginOptions.uploadUrl, this.pluginOptions.uploadHeaders, uploadFiles, this.#UploadCallBack.bind(this, info), this.#error.bind(this));
495
501
  }
496
502
 
497
503
  /**
498
- * @private
499
504
  * @description Handles errors that occur during the audio upload process.
500
505
  * - Triggers the `onAudioUploadError` event to allow custom handling of errors.
501
506
  * - Displays an error message in the editor's UI.
@@ -503,7 +508,7 @@ class Audio_ extends EditorInjector {
503
508
  * @param {Object<string, *>} response - The error response object from the server or upload process.
504
509
  * @returns {Promise<void>}
505
510
  */
506
- async _error(response) {
511
+ async #error(response) {
507
512
  const message = await this.triggerEvent('onAudioUploadError', { error: response });
508
513
  const err = message === NO_EVENT ? response.errorMessage : message || response.errorMessage;
509
514
  this.ui.alertOpen(err, 'error');
@@ -521,9 +526,9 @@ class Audio_ extends EditorInjector {
521
526
  if ((await this.triggerEvent('audioUploadHandler', { xmlHttp, info })) === NO_EVENT) {
522
527
  const response = JSON.parse(xmlHttp.responseText);
523
528
  if (response.errorMessage) {
524
- this._error(response);
529
+ this.#error(response);
525
530
  } else {
526
- this._register(info, response);
531
+ this.#register(info, response);
527
532
  }
528
533
  }
529
534
  }
@@ -537,13 +542,13 @@ class Audio_ extends EditorInjector {
537
542
  /** @type {HTMLInputElement} */
538
543
  const target = dom.query.getEventTarget(e);
539
544
  const value = target.value.trim();
540
- this.urlValue = this.preview.textContent = !value
545
+ this.#urlValue = this.preview.textContent = !value
541
546
  ? ''
542
547
  : this.options.get('defaultUrlProtocol') && !value.includes('://') && value.indexOf('#') !== 0
543
- ? this.options.get('defaultUrlProtocol') + value
544
- : !value.includes('://')
545
- ? '/' + value
546
- : value;
548
+ ? this.options.get('defaultUrlProtocol') + value
549
+ : !value.includes('://')
550
+ ? '/' + value
551
+ : value;
547
552
  }
548
553
 
549
554
  /**
@@ -558,7 +563,7 @@ class Audio_ extends EditorInjector {
558
563
  * @param {HTMLInputElement} target - The target element.
559
564
  */
560
565
  #SetUrlInput(target) {
561
- this.urlValue = this.preview.textContent = this.audioUrlFile.value = target.getAttribute('data-command') || target.src;
566
+ this.#urlValue = this.preview.textContent = this.audioUrlFile.value = target.getAttribute('data-command') || target.src;
562
567
  this.audioUrlFile.focus();
563
568
  }
564
569