suneditor 3.0.0-beta.9 → 3.0.0-rc.2

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 (380) hide show
  1. package/README.md +65 -57
  2. package/dist/suneditor-contents.min.css +1 -0
  3. package/dist/suneditor.min.css +1 -1
  4. package/dist/suneditor.min.js +1 -1
  5. package/package.json +110 -61
  6. package/src/assets/design/color.css +36 -17
  7. package/src/assets/design/size.css +2 -0
  8. package/src/assets/icons/defaultIcons.js +17 -2
  9. package/src/assets/suneditor-contents.css +51 -16
  10. package/src/assets/suneditor.css +116 -43
  11. package/src/core/config/contextProvider.js +288 -0
  12. package/src/core/config/eventManager.js +188 -0
  13. package/src/core/config/instanceCheck.js +59 -0
  14. package/src/core/config/optionProvider.js +452 -0
  15. package/src/core/editor.js +166 -1637
  16. package/src/core/event/actions/index.js +229 -0
  17. package/src/core/event/effects/common.registry.js +74 -0
  18. package/src/core/event/effects/keydown.registry.js +573 -0
  19. package/src/core/event/effects/ruleHelpers.js +148 -0
  20. package/src/core/event/eventOrchestrator.js +944 -0
  21. package/src/core/event/executor.js +27 -0
  22. package/src/core/{base/eventHandlers → event/handlers}/handler_toolbar.js +27 -28
  23. package/src/core/{base/eventHandlers → event/handlers}/handler_ww_clipboard.js +10 -8
  24. package/src/core/{base/eventHandlers → event/handlers}/handler_ww_dragDrop.js +22 -23
  25. package/src/core/event/handlers/handler_ww_input.js +75 -0
  26. package/src/core/event/handlers/handler_ww_key.js +228 -0
  27. package/src/core/event/handlers/handler_ww_mouse.js +166 -0
  28. package/src/core/event/ports.js +211 -0
  29. package/src/core/event/reducers/keydown.reducer.js +97 -0
  30. package/src/core/event/rules/keydown.rule.arrow.js +63 -0
  31. package/src/core/event/rules/keydown.rule.backspace.js +208 -0
  32. package/src/core/event/rules/keydown.rule.delete.js +132 -0
  33. package/src/core/event/rules/keydown.rule.enter.js +150 -0
  34. package/src/core/event/rules/keydown.rule.tab.js +35 -0
  35. package/src/core/event/support/defaultLineManager.js +136 -0
  36. package/src/core/event/support/selectionState.js +204 -0
  37. package/src/core/kernel/coreKernel.js +320 -0
  38. package/src/core/kernel/kernelInjector.js +19 -0
  39. package/src/core/kernel/store.js +173 -0
  40. package/src/core/{class → logic/dom}/char.js +42 -45
  41. package/src/core/logic/dom/format.js +1075 -0
  42. package/src/core/{class → logic/dom}/html.js +743 -624
  43. package/src/core/logic/dom/inline.js +1847 -0
  44. package/src/core/logic/dom/listFormat.js +601 -0
  45. package/src/core/{class → logic/dom}/nodeTransform.js +92 -72
  46. package/src/core/{class → logic/dom}/offset.js +254 -317
  47. package/src/core/logic/dom/selection.js +754 -0
  48. package/src/core/logic/panel/menu.js +389 -0
  49. package/src/core/logic/panel/toolbar.js +449 -0
  50. package/src/core/logic/panel/viewer.js +761 -0
  51. package/src/core/logic/shell/_commandExecutor.js +380 -0
  52. package/src/core/logic/shell/commandDispatcher.js +241 -0
  53. package/src/core/logic/shell/component.js +970 -0
  54. package/src/core/logic/shell/focusManager.js +110 -0
  55. package/src/core/{base → logic/shell}/history.js +110 -60
  56. package/src/core/logic/shell/pluginManager.js +363 -0
  57. package/src/core/logic/shell/shortcuts.js +130 -0
  58. package/src/core/logic/shell/ui.js +904 -0
  59. package/src/core/schema/context.js +66 -0
  60. package/src/core/schema/frameContext.js +160 -0
  61. package/src/core/schema/options.js +628 -0
  62. package/src/core/section/constructor.js +194 -500
  63. package/src/core/section/documentType.js +297 -222
  64. package/src/events.js +808 -543
  65. package/src/helper/clipboard.js +27 -16
  66. package/src/helper/converter.js +100 -78
  67. package/src/helper/dom/domCheck.js +56 -30
  68. package/src/helper/dom/domQuery.js +159 -89
  69. package/src/helper/dom/domUtils.js +114 -49
  70. package/src/helper/dom/index.js +5 -1
  71. package/src/helper/env.js +26 -26
  72. package/src/helper/index.js +1 -1
  73. package/src/helper/keyCodeMap.js +25 -28
  74. package/src/helper/numbers.js +4 -8
  75. package/src/helper/unicode.js +4 -8
  76. package/src/hooks/base.js +307 -0
  77. package/src/hooks/params.js +130 -0
  78. package/src/interfaces/contracts.js +227 -0
  79. package/src/interfaces/index.js +7 -0
  80. package/src/interfaces/plugins.js +239 -0
  81. package/src/langs/ckb.js +4 -4
  82. package/src/langs/cs.js +4 -4
  83. package/src/langs/da.js +4 -4
  84. package/src/langs/de.js +4 -4
  85. package/src/langs/en.js +4 -4
  86. package/src/langs/es.js +4 -4
  87. package/src/langs/fa.js +4 -4
  88. package/src/langs/fr.js +4 -4
  89. package/src/langs/he.js +4 -4
  90. package/src/langs/hu.js +4 -4
  91. package/src/langs/it.js +4 -4
  92. package/src/langs/ja.js +4 -4
  93. package/src/langs/km.js +4 -4
  94. package/src/langs/ko.js +4 -4
  95. package/src/langs/lv.js +4 -4
  96. package/src/langs/nl.js +4 -4
  97. package/src/langs/pl.js +4 -4
  98. package/src/langs/pt_br.js +13 -13
  99. package/src/langs/ro.js +4 -4
  100. package/src/langs/ru.js +4 -4
  101. package/src/langs/se.js +4 -4
  102. package/src/langs/tr.js +4 -4
  103. package/src/langs/uk.js +4 -4
  104. package/src/langs/ur.js +4 -4
  105. package/src/langs/zh_cn.js +4 -4
  106. package/src/modules/{Browser.js → contract/Browser.js} +119 -128
  107. package/src/modules/{ColorPicker.js → contract/ColorPicker.js} +132 -142
  108. package/src/modules/contract/Controller.js +589 -0
  109. package/src/modules/{Figure.js → contract/Figure.js} +591 -411
  110. package/src/modules/{HueSlider.js → contract/HueSlider.js} +125 -86
  111. package/src/modules/contract/Modal.js +357 -0
  112. package/src/modules/contract/index.js +9 -0
  113. package/src/modules/manager/ApiManager.js +197 -0
  114. package/src/modules/{FileManager.js → manager/FileManager.js} +128 -160
  115. package/src/modules/manager/index.js +5 -0
  116. package/src/modules/{ModalAnchorEditor.js → ui/ModalAnchorEditor.js} +108 -138
  117. package/src/modules/{SelectMenu.js → ui/SelectMenu.js} +119 -120
  118. package/src/modules/{_DragHandle.js → ui/_DragHandle.js} +1 -1
  119. package/src/modules/ui/index.js +6 -0
  120. package/src/plugins/browser/audioGallery.js +23 -26
  121. package/src/plugins/browser/fileBrowser.js +25 -28
  122. package/src/plugins/browser/fileGallery.js +20 -23
  123. package/src/plugins/browser/imageGallery.js +24 -23
  124. package/src/plugins/browser/videoGallery.js +27 -29
  125. package/src/plugins/command/blockquote.js +11 -17
  126. package/src/plugins/command/exportPDF.js +26 -26
  127. package/src/plugins/command/fileUpload.js +138 -133
  128. package/src/plugins/command/list_bulleted.js +48 -44
  129. package/src/plugins/command/list_numbered.js +48 -44
  130. package/src/plugins/dropdown/align.js +64 -50
  131. package/src/plugins/dropdown/backgroundColor.js +34 -35
  132. package/src/plugins/dropdown/{formatBlock.js → blockStyle.js} +43 -37
  133. package/src/plugins/dropdown/font.js +50 -36
  134. package/src/plugins/dropdown/fontColor.js +34 -35
  135. package/src/plugins/dropdown/hr.js +55 -50
  136. package/src/plugins/dropdown/layout.js +20 -15
  137. package/src/plugins/dropdown/lineHeight.js +46 -30
  138. package/src/plugins/dropdown/list.js +32 -33
  139. package/src/plugins/dropdown/paragraphStyle.js +40 -34
  140. package/src/plugins/dropdown/table/index.js +915 -0
  141. package/src/plugins/dropdown/table/render/table.html.js +308 -0
  142. package/src/plugins/dropdown/table/render/table.menu.js +121 -0
  143. package/src/plugins/dropdown/table/services/table.cell.js +465 -0
  144. package/src/plugins/dropdown/table/services/table.clipboard.js +414 -0
  145. package/src/plugins/dropdown/table/services/table.grid.js +504 -0
  146. package/src/plugins/dropdown/table/services/table.resize.js +463 -0
  147. package/src/plugins/dropdown/table/services/table.selection.js +466 -0
  148. package/src/plugins/dropdown/table/services/table.style.js +844 -0
  149. package/src/plugins/dropdown/table/shared/table.constants.js +109 -0
  150. package/src/plugins/dropdown/table/shared/table.utils.js +219 -0
  151. package/src/plugins/dropdown/template.js +20 -15
  152. package/src/plugins/dropdown/textStyle.js +28 -22
  153. package/src/plugins/field/mention.js +54 -49
  154. package/src/plugins/index.js +5 -5
  155. package/src/plugins/input/fontSize.js +100 -97
  156. package/src/plugins/input/pageNavigator.js +13 -10
  157. package/src/plugins/modal/audio.js +208 -219
  158. package/src/plugins/modal/drawing.js +99 -104
  159. package/src/plugins/modal/embed.js +323 -312
  160. package/src/plugins/modal/image/index.js +942 -0
  161. package/src/plugins/modal/image/render/image.html.js +150 -0
  162. package/src/plugins/modal/image/services/image.size.js +198 -0
  163. package/src/plugins/modal/image/services/image.upload.js +216 -0
  164. package/src/plugins/modal/image/shared/image.constants.js +20 -0
  165. package/src/plugins/modal/link.js +74 -54
  166. package/src/plugins/modal/math.js +126 -119
  167. package/src/plugins/modal/video/index.js +858 -0
  168. package/src/plugins/modal/video/render/video.html.js +131 -0
  169. package/src/plugins/modal/video/services/video.size.js +281 -0
  170. package/src/plugins/modal/video/services/video.upload.js +92 -0
  171. package/src/plugins/popup/anchor.js +57 -49
  172. package/src/suneditor.js +73 -61
  173. package/src/themes/cobalt.css +155 -0
  174. package/src/themes/dark.css +143 -120
  175. package/src/typedef.js +214 -63
  176. package/types/assets/icons/defaultIcons.d.ts +8 -0
  177. package/types/assets/suneditor-contents.css.d.ts +1 -0
  178. package/types/assets/suneditor.css.d.ts +1 -0
  179. package/types/core/config/contextProvider.d.ts +148 -0
  180. package/types/core/config/eventManager.d.ts +68 -0
  181. package/types/core/config/instanceCheck.d.ts +33 -0
  182. package/types/core/config/optionProvider.d.ts +147 -0
  183. package/types/core/editor.d.ts +27 -586
  184. package/types/core/event/actions/index.d.ts +50 -0
  185. package/types/core/event/effects/common.registry.d.ts +56 -0
  186. package/types/core/event/effects/keydown.registry.d.ts +80 -0
  187. package/types/core/event/effects/ruleHelpers.d.ts +36 -0
  188. package/types/core/event/eventOrchestrator.d.ts +191 -0
  189. package/types/core/event/executor.d.ts +13 -0
  190. package/types/core/event/handlers/handler_toolbar.d.ts +38 -0
  191. package/types/core/event/handlers/handler_ww_clipboard.d.ts +36 -0
  192. package/types/core/event/handlers/handler_ww_dragDrop.d.ts +26 -0
  193. package/types/core/event/handlers/handler_ww_input.d.ts +38 -0
  194. package/types/core/event/handlers/handler_ww_key.d.ts +40 -0
  195. package/types/core/event/handlers/handler_ww_mouse.d.ts +47 -0
  196. package/types/core/event/ports.d.ts +256 -0
  197. package/types/core/event/reducers/keydown.reducer.d.ts +84 -0
  198. package/types/core/event/rules/keydown.rule.arrow.d.ts +19 -0
  199. package/types/core/event/rules/keydown.rule.backspace.d.ts +18 -0
  200. package/types/core/event/rules/keydown.rule.delete.d.ts +18 -0
  201. package/types/core/event/rules/keydown.rule.enter.d.ts +18 -0
  202. package/types/core/event/rules/keydown.rule.tab.d.ts +18 -0
  203. package/types/core/event/support/defaultLineManager.d.ts +22 -0
  204. package/types/core/event/support/selectionState.d.ts +29 -0
  205. package/types/core/kernel/coreKernel.d.ts +219 -0
  206. package/types/core/kernel/kernelInjector.d.ts +16 -0
  207. package/types/core/kernel/store.d.ts +170 -0
  208. package/types/core/logic/dom/char.d.ts +46 -0
  209. package/types/core/logic/dom/format.d.ts +234 -0
  210. package/types/core/logic/dom/html.d.ts +290 -0
  211. package/types/core/logic/dom/inline.d.ts +93 -0
  212. package/types/core/logic/dom/listFormat.d.ts +101 -0
  213. package/types/core/logic/dom/nodeTransform.d.ts +110 -0
  214. package/types/core/logic/dom/offset.d.ts +335 -0
  215. package/types/core/logic/dom/selection.d.ts +165 -0
  216. package/types/core/logic/panel/menu.d.ts +93 -0
  217. package/types/core/logic/panel/toolbar.d.ts +128 -0
  218. package/types/core/logic/panel/viewer.d.ts +89 -0
  219. package/types/core/logic/shell/_commandExecutor.d.ts +18 -0
  220. package/types/core/logic/shell/commandDispatcher.d.ts +65 -0
  221. package/types/core/logic/shell/component.d.ts +182 -0
  222. package/types/core/logic/shell/focusManager.d.ts +31 -0
  223. package/types/core/{base → logic/shell}/history.d.ts +13 -12
  224. package/types/core/logic/shell/pluginManager.d.ts +115 -0
  225. package/types/core/logic/shell/shortcuts.d.ts +131 -0
  226. package/types/core/logic/shell/ui.d.ts +261 -0
  227. package/types/core/schema/context.d.ts +104 -0
  228. package/types/core/schema/frameContext.d.ts +320 -0
  229. package/types/core/schema/options.d.ts +1241 -0
  230. package/types/core/section/constructor.d.ts +117 -652
  231. package/types/core/section/documentType.d.ts +43 -61
  232. package/types/events.d.ts +796 -65
  233. package/types/helper/clipboard.d.ts +5 -4
  234. package/types/helper/converter.d.ts +55 -43
  235. package/types/helper/dom/domCheck.d.ts +27 -19
  236. package/types/helper/dom/domQuery.d.ts +76 -57
  237. package/types/helper/dom/domUtils.d.ts +62 -39
  238. package/types/helper/dom/index.d.ts +87 -1
  239. package/types/helper/env.d.ts +16 -13
  240. package/types/helper/index.d.ts +8 -2
  241. package/types/helper/keyCodeMap.d.ts +24 -23
  242. package/types/helper/numbers.d.ts +4 -6
  243. package/types/helper/unicode.d.ts +4 -3
  244. package/types/hooks/base.d.ts +239 -0
  245. package/types/hooks/params.d.ts +65 -0
  246. package/types/index.d.ts +20 -117
  247. package/types/interfaces/contracts.d.ts +183 -0
  248. package/types/interfaces/index.d.ts +3 -0
  249. package/types/interfaces/plugins.d.ts +168 -0
  250. package/types/langs/_Lang.d.ts +2 -2
  251. package/types/langs/index.d.ts +2 -2
  252. package/types/modules/contract/Browser.d.ts +262 -0
  253. package/types/modules/contract/ColorPicker.d.ts +99 -0
  254. package/types/modules/contract/Controller.d.ts +204 -0
  255. package/types/modules/contract/Figure.d.ts +529 -0
  256. package/types/modules/{HueSlider.d.ts → contract/HueSlider.d.ts} +39 -28
  257. package/types/modules/contract/Modal.d.ts +62 -0
  258. package/types/modules/contract/index.d.ts +7 -0
  259. package/types/modules/manager/ApiManager.d.ts +106 -0
  260. package/types/modules/manager/FileManager.d.ts +124 -0
  261. package/types/modules/manager/index.d.ts +3 -0
  262. package/types/modules/ui/ModalAnchorEditor.d.ts +152 -0
  263. package/types/modules/ui/SelectMenu.d.ts +107 -0
  264. package/types/modules/{_DragHandle.d.ts → ui/_DragHandle.d.ts} +1 -0
  265. package/types/modules/ui/index.d.ts +4 -0
  266. package/types/plugins/browser/audioGallery.d.ts +33 -41
  267. package/types/plugins/browser/fileBrowser.d.ts +42 -50
  268. package/types/plugins/browser/fileGallery.d.ts +33 -41
  269. package/types/plugins/browser/imageGallery.d.ts +30 -37
  270. package/types/plugins/browser/videoGallery.d.ts +33 -41
  271. package/types/plugins/command/blockquote.d.ts +4 -21
  272. package/types/plugins/command/exportPDF.d.ts +23 -33
  273. package/types/plugins/command/fileUpload.d.ts +80 -100
  274. package/types/plugins/command/list_bulleted.d.ts +9 -35
  275. package/types/plugins/command/list_numbered.d.ts +9 -35
  276. package/types/plugins/dropdown/align.d.ts +23 -46
  277. package/types/plugins/dropdown/backgroundColor.d.ts +35 -53
  278. package/types/plugins/dropdown/blockStyle.d.ts +45 -0
  279. package/types/plugins/dropdown/font.d.ts +18 -41
  280. package/types/plugins/dropdown/fontColor.d.ts +35 -53
  281. package/types/plugins/dropdown/hr.d.ts +26 -52
  282. package/types/plugins/dropdown/layout.d.ts +19 -25
  283. package/types/plugins/dropdown/lineHeight.d.ts +21 -39
  284. package/types/plugins/dropdown/list.d.ts +6 -34
  285. package/types/plugins/dropdown/paragraphStyle.d.ts +34 -45
  286. package/types/plugins/dropdown/table/index.d.ts +158 -0
  287. package/types/plugins/dropdown/table/render/table.html.d.ts +71 -0
  288. package/types/plugins/dropdown/table/render/table.menu.d.ts +59 -0
  289. package/types/plugins/dropdown/table/services/table.cell.d.ts +76 -0
  290. package/types/plugins/dropdown/table/services/table.clipboard.d.ts +26 -0
  291. package/types/plugins/dropdown/table/services/table.grid.d.ts +77 -0
  292. package/types/plugins/dropdown/table/services/table.resize.d.ts +72 -0
  293. package/types/plugins/dropdown/table/services/table.selection.d.ts +59 -0
  294. package/types/plugins/dropdown/table/services/table.style.d.ts +162 -0
  295. package/types/plugins/dropdown/table/shared/table.constants.d.ts +134 -0
  296. package/types/plugins/dropdown/table/shared/table.utils.d.ts +91 -0
  297. package/types/plugins/dropdown/template.d.ts +19 -25
  298. package/types/plugins/dropdown/textStyle.d.ts +23 -30
  299. package/types/plugins/field/mention.d.ts +66 -72
  300. package/types/plugins/index.d.ts +41 -40
  301. package/types/plugins/input/fontSize.d.ts +57 -96
  302. package/types/plugins/input/pageNavigator.d.ts +5 -8
  303. package/types/plugins/modal/audio.d.ts +60 -153
  304. package/types/plugins/modal/drawing.d.ts +16 -118
  305. package/types/plugins/modal/embed.d.ts +46 -166
  306. package/types/plugins/modal/image/index.d.ts +281 -0
  307. package/types/plugins/modal/image/render/image.html.d.ts +45 -0
  308. package/types/plugins/modal/image/services/image.size.d.ts +55 -0
  309. package/types/plugins/modal/image/services/image.upload.d.ts +24 -0
  310. package/types/plugins/modal/image/shared/image.constants.d.ts +17 -0
  311. package/types/plugins/modal/link.d.ts +46 -66
  312. package/types/plugins/modal/math.d.ts +17 -86
  313. package/types/plugins/modal/{video.d.ts → video/index.d.ts} +89 -221
  314. package/types/plugins/modal/video/render/video.html.d.ts +37 -0
  315. package/types/plugins/modal/video/services/video.size.d.ts +74 -0
  316. package/types/plugins/modal/video/services/video.upload.d.ts +19 -0
  317. package/types/plugins/popup/anchor.d.ts +8 -38
  318. package/types/suneditor.d.ts +55 -24
  319. package/types/typedef.d.ts +344 -228
  320. package/CONTRIBUTING.md +0 -186
  321. package/src/core/base/eventHandlers/handler_ww_key_input.js +0 -1200
  322. package/src/core/base/eventHandlers/handler_ww_mouse.js +0 -194
  323. package/src/core/base/eventManager.js +0 -1523
  324. package/src/core/class/component.js +0 -856
  325. package/src/core/class/format.js +0 -3433
  326. package/src/core/class/menu.js +0 -346
  327. package/src/core/class/selection.js +0 -610
  328. package/src/core/class/shortcuts.js +0 -98
  329. package/src/core/class/toolbar.js +0 -431
  330. package/src/core/class/ui.js +0 -424
  331. package/src/core/class/viewer.js +0 -750
  332. package/src/core/section/actives.js +0 -266
  333. package/src/core/section/context.js +0 -102
  334. package/src/editorInjector/_classes.js +0 -36
  335. package/src/editorInjector/_core.js +0 -87
  336. package/src/editorInjector/index.js +0 -73
  337. package/src/modules/ApiManager.js +0 -191
  338. package/src/modules/Controller.js +0 -474
  339. package/src/modules/Modal.js +0 -346
  340. package/src/modules/index.js +0 -14
  341. package/src/plugins/dropdown/table.js +0 -4034
  342. package/src/plugins/modal/image.js +0 -1376
  343. package/src/plugins/modal/video.js +0 -1226
  344. package/types/core/base/eventHandlers/handler_toolbar.d.ts +0 -41
  345. package/types/core/base/eventHandlers/handler_ww_clipboard.d.ts +0 -40
  346. package/types/core/base/eventHandlers/handler_ww_dragDrop.d.ts +0 -35
  347. package/types/core/base/eventHandlers/handler_ww_key_input.d.ts +0 -45
  348. package/types/core/base/eventHandlers/handler_ww_mouse.d.ts +0 -39
  349. package/types/core/base/eventManager.d.ts +0 -401
  350. package/types/core/class/char.d.ts +0 -61
  351. package/types/core/class/component.d.ts +0 -213
  352. package/types/core/class/format.d.ts +0 -623
  353. package/types/core/class/html.d.ts +0 -430
  354. package/types/core/class/menu.d.ts +0 -126
  355. package/types/core/class/nodeTransform.d.ts +0 -93
  356. package/types/core/class/offset.d.ts +0 -522
  357. package/types/core/class/selection.d.ts +0 -188
  358. package/types/core/class/shortcuts.d.ts +0 -142
  359. package/types/core/class/toolbar.d.ts +0 -189
  360. package/types/core/class/ui.d.ts +0 -164
  361. package/types/core/class/viewer.d.ts +0 -140
  362. package/types/core/section/actives.d.ts +0 -46
  363. package/types/core/section/context.d.ts +0 -45
  364. package/types/editorInjector/_classes.d.ts +0 -41
  365. package/types/editorInjector/_core.d.ts +0 -87
  366. package/types/editorInjector/index.d.ts +0 -69
  367. package/types/modules/ApiManager.d.ts +0 -125
  368. package/types/modules/Browser.d.ts +0 -326
  369. package/types/modules/ColorPicker.d.ts +0 -135
  370. package/types/modules/Controller.d.ts +0 -251
  371. package/types/modules/Figure.d.ts +0 -517
  372. package/types/modules/FileManager.d.ts +0 -202
  373. package/types/modules/Modal.d.ts +0 -111
  374. package/types/modules/ModalAnchorEditor.d.ts +0 -236
  375. package/types/modules/SelectMenu.d.ts +0 -194
  376. package/types/modules/index.d.ts +0 -26
  377. package/types/plugins/dropdown/formatBlock.d.ts +0 -55
  378. package/types/plugins/dropdown/table.d.ts +0 -627
  379. package/types/plugins/modal/image.d.ts +0 -451
  380. /package/{LICENSE → LICENSE.txt} +0 -0
@@ -1,37 +1,39 @@
1
- import EditorInjector from '../../editorInjector';
2
- import { Modal, Controller, FileManager, Figure, _DragHandle } from '../../modules';
1
+ import { PluginModal } from '../../interfaces';
2
+ import { Modal, Controller, Figure } from '../../modules/contract';
3
+ import { FileManager } from '../../modules/manager';
4
+ import { _DragHandle } from '../../modules/ui';
3
5
  import { dom, numbers, env } from '../../helper';
4
6
  const { NO_EVENT, ON_OVER_COMPONENT } = env;
5
7
 
6
- /**
7
- * @typedef {import('../../events').AudioInfo} AudioInfo_audio
8
- */
9
-
10
8
  /**
11
9
  * @typedef {Object} AudioPluginOptions
12
- * @property {string} [defaultWidth="300px"] - The default width of the audio tag (e.g., "300px").
13
- * @property {string} [defaultHeight="150px"] - The default height of the audio tag (e.g., "150px").
10
+ * @property {string} [defaultWidth="300px"] - The default width of the `AUDIO` tag (e.g., `"300px"`).
11
+ * @property {string} [defaultHeight="150px"] - The default height of the `AUDIO` tag (e.g., `"150px"`).
14
12
  * @property {boolean} [createFileInput] - Whether to create a file input element.
15
- * @property {boolean} [createUrlInput] - Whether to create a URL input element (default is true if file input is not created).
13
+ * @property {boolean} [createUrlInput] - Whether to create a URL input element (default is `true` if file input is not created).
16
14
  * @property {string} [uploadUrl] - The URL to which files will be uploaded.
17
15
  * @property {Object<string, string>} [uploadHeaders] - Headers to include in the file upload request.
18
16
  * @property {number} [uploadSizeLimit] - The total upload size limit in bytes.
19
17
  * @property {number} [uploadSingleSizeLimit] - The single file size limit in bytes.
20
18
  * @property {boolean} [allowMultiple] - Whether to allow multiple file uploads.
21
- * @property {string} [acceptedFormats="audio/*"] - Accepted file formats (default is "audio/*").
22
- * @property {Object<string, string>} [audioTagAttributes] - Additional attributes to set on the audio tag.
19
+ * @property {string} [acceptedFormats="audio/*"] - Accepted file formats (default is `"audio/*"`).
20
+ * @property {Object<string, string>} [audioTagAttributes] - Additional attributes to set on the `AUDIO` tag.
21
+ * @property {SunEditor.ComponentInsertType} [insertBehavior] - Component insertion behavior for selection and cursor placement. [default: `options.get('componentInsertBehavior')`]
22
+ * - `auto`: Move cursor to the next line if possible, otherwise select the component.
23
+ * - `select`: Always select the inserted component.
24
+ * - `line`: Move cursor to the next line if possible, or create a new line and move there.
25
+ * - `none`: Do nothing.
23
26
  */
24
27
 
25
28
  /**
26
29
  * @class
27
30
  * @description Audio modal plugin.
28
31
  */
29
- class Audio_ extends EditorInjector {
32
+ class Audio_ extends PluginModal {
30
33
  static key = 'audio';
31
- static type = 'modal';
32
34
  static className = '';
35
+
33
36
  /**
34
- * @this {Audio_}
35
37
  * @param {HTMLElement} node - The node to check.
36
38
  * @returns {HTMLElement|null} Returns a node if the node is a valid component.
37
39
  */
@@ -39,15 +41,20 @@ class Audio_ extends EditorInjector {
39
41
  return /^AUDIO$/i.test(node?.nodeName) ? node : null;
40
42
  }
41
43
 
44
+ #defaultWidth;
45
+ #defaultHeight;
46
+ #urlValue = '';
47
+ #element = null;
48
+
42
49
  /**
43
50
  * @constructor
44
- * @param {__se__EditorCore} editor - The root editor instance
51
+ * @param {SunEditor.Kernel} editor - The core kernel
45
52
  * @param {AudioPluginOptions} pluginOptions
46
53
  */
47
54
  constructor(editor, pluginOptions) {
48
- // plugin bisic properties
55
+ // plugin basic properties
49
56
  super(editor);
50
- this.title = this.lang.audio;
57
+ this.title = this.$.lang.audio;
51
58
  this.icon = 'audio';
52
59
 
53
60
  // define plugin options
@@ -62,24 +69,25 @@ class Audio_ extends EditorInjector {
62
69
  uploadSingleSizeLimit: numbers.get(pluginOptions.uploadSingleSizeLimit, 0),
63
70
  allowMultiple: !!pluginOptions.allowMultiple,
64
71
  acceptedFormats: typeof pluginOptions.acceptedFormats !== 'string' || pluginOptions.acceptedFormats.trim() === '*' ? 'audio/*' : pluginOptions.acceptedFormats.trim() || 'audio/*',
65
- audioTagAttributes: pluginOptions.audioTagAttributes || null
72
+ audioTagAttributes: pluginOptions.audioTagAttributes || null,
73
+ insertBehavior: pluginOptions.insertBehavior,
66
74
  };
67
75
 
68
76
  // create HTML
69
- const modalEl = CreateHTML_modal(editor, this.pluginOptions);
70
- const controllerEl = CreateHTML_controller(editor);
77
+ const modalEl = CreateHTML_modal(this.$, this.pluginOptions);
78
+ const controllerEl = CreateHTML_controller(this.$);
71
79
 
72
80
  // modules
73
- this.modal = new Modal(this, modalEl);
74
- this.controller = new Controller(this, controllerEl, { position: 'bottom', disabled: true });
75
- this.fileManager = new FileManager(this, {
81
+ this.modal = new Modal(this, this.$, modalEl);
82
+ this.controller = new Controller(this, this.$, controllerEl, { position: 'bottom', disabled: true });
83
+ this.fileManager = new FileManager(this, this.$, {
76
84
  query: 'audio',
77
- loadHandler: this.events.onAudioLoad,
78
- eventHandler: this.events.onAudioAction
85
+ loadEventName: 'onAudioLoad',
86
+ actionEventName: 'onAudioAction',
79
87
  });
80
88
 
81
89
  // members
82
- this.figure = new Figure(this, null, {});
90
+ this.figure = new Figure(this, this.$, null, {});
83
91
 
84
92
  /** @type {HTMLElement} */
85
93
  this.fileModalWrapper = modalEl.querySelector('.se-flex-input-wrapper');
@@ -89,92 +97,99 @@ class Audio_ extends EditorInjector {
89
97
  this.audioUrlFile = modalEl.querySelector('.se-input-url');
90
98
  /** @type {HTMLElement} */
91
99
  this.preview = modalEl.querySelector('.se-link-preview');
92
- /** @type {HTMLAudioElement} */
93
- this._element = null;
94
100
 
95
- this.defaultWidth = this.pluginOptions.defaultWidth;
96
- this.defaultHeight = this.pluginOptions.defaultHeight;
97
- this.urlValue = '';
101
+ /** @type {HTMLAudioElement} */
102
+ this.#defaultWidth = this.pluginOptions.defaultWidth;
103
+ this.#defaultHeight = this.pluginOptions.defaultHeight;
98
104
 
99
105
  const galleryButton = modalEl.querySelector('.__se__gallery');
100
- if (galleryButton) this.eventManager.addEvent(galleryButton, 'click', this.#OpenGallery.bind(this));
106
+ if (galleryButton) this.$.eventManager.addEvent(galleryButton, 'click', this.#OpenGallery.bind(this));
101
107
 
102
108
  // init
103
109
  if (this.audioInputFile) {
104
- this.eventManager.addEvent(modalEl.querySelector('.se-modal-files-edge-button'), 'click', this.#RemoveSelectedFiles.bind(this, this.audioUrlFile, this.preview));
110
+ this.$.eventManager.addEvent(modalEl.querySelector('.se-modal-files-edge-button'), 'click', this.#RemoveSelectedFiles.bind(this, this.audioUrlFile, this.preview));
105
111
  if (this.audioUrlFile) {
106
- this.eventManager.addEvent(this.audioInputFile, 'change', this.#FileInputChange.bind(this));
112
+ this.$.eventManager.addEvent(this.audioInputFile, 'change', this.#FileInputChange.bind(this));
107
113
  }
108
114
  }
109
115
  if (this.audioUrlFile) {
110
- this.eventManager.addEvent(this.audioUrlFile, 'input', this.#OnLinkPreview.bind(this));
116
+ this.$.eventManager.addEvent(this.audioUrlFile, 'input', this.#OnLinkPreview.bind(this));
111
117
  }
112
118
  }
113
119
 
114
120
  /**
115
- * @editorMethod Modules.Modal
116
- * @description Executes the method that is called when a "Modal" module's is opened.
121
+ * @override
122
+ * @type {PluginModal['open']}
117
123
  */
118
124
  open() {
119
125
  this.modal.open();
120
126
  }
121
127
 
122
128
  /**
123
- * @editorMethod Modules.Modal
124
- * @description Executes the method that is called when a plugin's modal is opened.
125
- * @param {boolean} isUpdate "Indicates whether the modal is for editing an existing component (true) or registering a new one (false)."
129
+ * @hook Editor.core
130
+ * @type {SunEditor.Hook.Core.RetainFormat}
126
131
  */
127
- on(isUpdate) {
128
- if (!isUpdate) {
129
- 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;
132
- if (this.audioInputFile && this.pluginOptions.allowMultiple) this.audioInputFile.removeAttribute('multiple');
133
- } else {
134
- if (this.audioInputFile && this.pluginOptions.allowMultiple) this.audioInputFile.removeAttribute('multiple');
135
- }
132
+ retainFormat() {
133
+ return {
134
+ query: 'audio',
135
+ method: (element) => {
136
+ const figureInfo = Figure.GetContainer(element);
137
+ if (figureInfo && figureInfo.container && figureInfo.cover) return;
138
+
139
+ this.#setTagAttrs(element);
140
+ const figure = Figure.CreateContainer(element.cloneNode(true), 'se-flex-component');
141
+ this.figure.retainFigureFormat(figure.container, element, null, this.fileManager);
142
+ },
143
+ };
136
144
  }
137
145
 
138
146
  /**
139
- * @editorMethod Editor.EventManager
140
- * @description Executes the event function of "paste" or "drop".
141
- * @param {Object} params { frameContext, event, file }
142
- * @param {__se__FrameContext} params.frameContext Frame context
143
- * @param {ClipboardEvent} params.event Event object
144
- * @param {File} params.file File object
145
- * @returns {boolean} - If return false, the file upload will be canceled
147
+ * @hook Editor.EventManager
148
+ * @type {SunEditor.Hook.Event.OnFilePasteAndDrop}
146
149
  */
147
150
  onFilePasteAndDrop({ file }) {
148
151
  if (!/^audio/.test(file.type)) return;
149
152
 
150
153
  this.submitFile([file]);
151
- this.editor.focus();
154
+ this.$.focusManager.focus();
155
+ }
152
156
 
153
- return false;
157
+ /**
158
+ * @hook Modules.Modal
159
+ * @type {SunEditor.Hook.Modal.On}
160
+ */
161
+ modalOn(isUpdate) {
162
+ if (!isUpdate) {
163
+ if (this.audioInputFile && this.pluginOptions.allowMultiple) this.audioInputFile.setAttribute('multiple', 'multiple');
164
+ } else if (this.#element) {
165
+ this.#urlValue = this.preview.textContent = this.audioUrlFile.value = this.#element.src;
166
+ if (this.audioInputFile && this.pluginOptions.allowMultiple) this.audioInputFile.removeAttribute('multiple');
167
+ } else {
168
+ if (this.audioInputFile && this.pluginOptions.allowMultiple) this.audioInputFile.removeAttribute('multiple');
169
+ }
154
170
  }
155
171
 
156
172
  /**
157
- * @editorMethod Modules.Modal
158
- * @description This function is called when a form within a modal window is "submit".
159
- * @returns {Promise<boolean>} Success or failure
173
+ * @hook Modules.Modal
174
+ * @type {SunEditor.Hook.Modal.Action}
160
175
  */
161
176
  async modalAction() {
162
177
  if (this.audioInputFile && this.audioInputFile?.files.length > 0) {
163
178
  return await this.submitFile(this.audioInputFile.files);
164
- } else if (this.audioUrlFile && this.urlValue.length > 0) {
165
- return await this.submitURL(this.urlValue);
179
+ } else if (this.audioUrlFile && this.#urlValue.length > 0) {
180
+ return await this.submitURL(this.#urlValue);
166
181
  }
167
182
  return false;
168
183
  }
169
184
 
170
185
  /**
171
- * @editorMethod Modules.Modal
172
- * @description This function is called before the modal window is opened, but before it is closed.
186
+ * @hook Modules.Modal
187
+ * @type {SunEditor.Hook.Modal.Init}
173
188
  */
174
- init() {
189
+ modalInit() {
175
190
  Modal.OnChangeFile(this.fileModalWrapper, []);
176
191
  if (this.audioInputFile) this.audioInputFile.value = '';
177
- if (this.audioUrlFile) this.urlValue = this.preview.textContent = this.audioUrlFile.value = '';
192
+ if (this.audioUrlFile) this.#urlValue = this.preview.textContent = this.audioUrlFile.value = '';
178
193
  if (this.audioInputFile && this.audioUrlFile) {
179
194
  this.audioUrlFile.disabled = false;
180
195
  this.preview.style.textDecoration = '';
@@ -182,155 +197,94 @@ class Audio_ extends EditorInjector {
182
197
  }
183
198
 
184
199
  /**
185
- * @editorMethod Modules.Controller
186
- * @description Executes the method that is called when a button is clicked in the "controller".
187
- * @param {HTMLButtonElement} target Target button element
200
+ * @hook Modules.Controller
201
+ * @type {SunEditor.Hook.Controller.Action}
188
202
  */
189
203
  controllerAction(target) {
190
204
  switch (target.getAttribute('data-command')) {
191
205
  case 'update':
192
- if (this.audioUrlFile) this.urlValue = this.preview.textContent = this.audioUrlFile.value = this._element.src;
206
+ if (this.audioUrlFile) this.#urlValue = this.preview.textContent = this.audioUrlFile.value = this.#element.src;
193
207
  this.open();
194
208
  break;
195
209
  case 'copy': {
196
- const figure = Figure.GetContainer(this._element);
197
- this.component.copy(figure.container);
210
+ const figure = Figure.GetContainer(this.#element);
211
+ this.$.component.copy(figure.container);
198
212
  break;
199
213
  }
200
214
  case 'delete':
201
- this.destroy();
215
+ this.componentDestroy(null);
202
216
  break;
203
217
  }
204
218
  }
205
219
 
206
220
  /**
207
- * @editorMethod Editor.core
208
- * @description This method is used to validate and preserve the format of the component within the editor.
209
- * - It ensures that the structure and attributes of the element are maintained and secure.
210
- * - The method checks if the element is already wrapped in a valid container and updates its attributes if necessary.
211
- * - If the element isn't properly contained, a new container is created to retain the format.
212
- * @returns {{query: string, method: (element: HTMLAudioElement) => void}} The format retention object containing the query and method to process the element.
213
- * - query: The selector query to identify the relevant elements (in this case, 'audio').
214
- * - method:The function to execute on the element to validate and preserve its format.
215
- * - The function takes the element as an argument, checks if it is contained correctly, and applies necessary adjustments.
221
+ * @hook Editor.Component
222
+ * @type {SunEditor.Hook.Component.Select}
216
223
  */
217
- retainFormat() {
218
- return {
219
- query: 'audio',
220
- method: (element) => {
221
- const figureInfo = Figure.GetContainer(element);
222
- if (figureInfo && figureInfo.container && figureInfo.cover) return;
223
-
224
- this._setTagAttrs(element);
225
- const figure = Figure.CreateContainer(element.cloneNode(true), 'se-flex-component');
226
- this.figure.retainFigureFormat(figure.container, element, null, this.fileManager);
227
- }
228
- };
224
+ componentSelect(target) {
225
+ this.figure.open(target, { nonResizing: true, nonSizeInfo: true, nonBorder: true, figureTarget: true, infoOnly: false });
226
+ this.#ready(target);
229
227
  }
230
228
 
231
229
  /**
232
- * @editorMethod Editor.Component
233
- * @description Executes the method that is called when a component of a plugin is selected.
234
- * @param {HTMLElement} target Target component element
230
+ * @hook Editor.Component
231
+ * @type {SunEditor.Hook.Component.Destroy}
235
232
  */
236
- 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 });
252
- }
253
-
254
- /**
255
- * @editorMethod Editor.Component
256
- * @description Method to delete a component of a plugin, called by the "FileManager", "Controller" module.
257
- * @param {HTMLElement=} target Target element, if null current selected element
258
- * @returns {Promise<void>}
259
- */
260
- async destroy(target) {
261
- const element = target || this._element;
233
+ async componentDestroy(target) {
234
+ const element = target || this.#element;
262
235
  const figure = Figure.GetContainer(element);
263
236
  const container = figure.container || element;
264
237
  const focusEl = container.previousElementSibling || container.nextElementSibling;
265
238
 
266
- const message = await this.triggerEvent('onAudioDeleteBefore', { element: element, container: figure, url: element.getAttribute('src') });
239
+ const message = await this.$.eventManager.triggerEvent('onAudioDeleteBefore', { element: element, container: figure, url: element.getAttribute('src') });
267
240
  if (message === false) return;
268
241
 
269
242
  const emptyDiv = container.parentNode;
270
243
  dom.utils.removeItem(container);
271
- this.init();
244
+ this.modalInit();
272
245
  this.controller.close();
273
246
 
274
- if (emptyDiv !== this.editor.frameContext.get('wysiwyg')) {
275
- this.nodeTransform.removeAllParents(
247
+ if (emptyDiv !== this.$.frameContext.get('wysiwyg')) {
248
+ this.$.nodeTransform.removeAllParents(
276
249
  emptyDiv,
277
250
  function (current) {
278
251
  return current.childNodes.length === 0;
279
252
  },
280
- null
253
+ null,
281
254
  );
282
255
  }
283
256
 
284
257
  // focus
285
- this.editor.focusEdge(focusEl);
286
- this.history.push(false);
258
+ this.$.focusManager.focusEdge(focusEl);
259
+ this.$.history.push(false);
287
260
  }
288
261
 
289
262
  /**
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
- /**
309
- * @description Create an "audio" component using the provided files.
263
+ * @description Create an `audio` component using the provided files.
310
264
  * @param {FileList|File[]} fileList File object list
311
- * @returns {Promise<boolean>} If return false, the file upload will be canceled
265
+ * @returns {Promise<boolean>} If return `false`, the file upload will be canceled
312
266
  */
313
267
  async submitFile(fileList) {
314
268
  if (fileList.length === 0) return false;
315
269
 
316
270
  let fileSize = 0;
317
271
  const files = [];
318
- const slngleSizeLimit = this.pluginOptions.uploadSingleSizeLimit;
272
+ const singleSizeLimit = this.pluginOptions.uploadSingleSizeLimit;
319
273
  for (let i = 0, len = fileList.length, f, s; i < len; i++) {
320
274
  f = fileList[i];
321
275
  if (!/audio/i.test(f.type)) continue;
322
276
 
323
277
  s = f.size;
324
- if (slngleSizeLimit && slngleSizeLimit > s) {
325
- const err = '[SUNEDITOR.audioUpload.fail] Size of uploadable single file: ' + slngleSizeLimit / 1000 + 'KB';
326
- const message = await this.triggerEvent('onAudioUploadError', {
278
+ if (singleSizeLimit > 0 && s > singleSizeLimit) {
279
+ const err = '[SUNEDITOR.audioUpload.fail] Size of uploadable single file: ' + singleSizeLimit / 1000 + 'KB';
280
+ const message = await this.$.eventManager.triggerEvent('onAudioUploadError', {
327
281
  error: err,
328
- limitSize: slngleSizeLimit,
282
+ limitSize: singleSizeLimit,
329
283
  uploadSize: s,
330
- file: f
284
+ file: f,
331
285
  });
332
286
 
333
- this.ui.alertOpen(message === NO_EVENT ? err : message || err, 'error');
287
+ this.$.ui.alertOpen(message === NO_EVENT ? err : message || err, 'error');
334
288
 
335
289
  return false;
336
290
  }
@@ -342,9 +296,9 @@ class Audio_ extends EditorInjector {
342
296
  const limitSize = this.pluginOptions.uploadSizeLimit;
343
297
  if (limitSize > 0 && fileSize + this.fileManager.getSize() > limitSize) {
344
298
  const err = '[SUNEDITOR.audioUpload.fail] Size of uploadable total audios: ' + limitSize / 1000 + 'KB';
345
- const message = await this.triggerEvent('onAudioUploadError', { error: err, limitSize, currentSize: this.fileManager.getSize(), uploadSize: fileSize });
299
+ const message = await this.$.eventManager.triggerEvent('onAudioUploadError', { error: err, limitSize, currentSize: this.fileManager.getSize(), uploadSize: fileSize });
346
300
 
347
- this.ui.alertOpen(message === NO_EVENT ? err : message || err, 'error');
301
+ this.$.ui.alertOpen(message === NO_EVENT ? err : message || err, 'error');
348
302
 
349
303
  return false;
350
304
  }
@@ -352,17 +306,17 @@ class Audio_ extends EditorInjector {
352
306
  const audioInfo = {
353
307
  files,
354
308
  isUpdate: this.modal.isUpdate,
355
- element: this._element
309
+ element: this.#element,
356
310
  };
357
311
 
358
- const handler = function (newInfos, infos) {
312
+ const handler = function (uploadCallback, newInfos, infos) {
359
313
  infos = newInfos || infos;
360
- this._serverUpload(infos, infos.files);
361
- }.bind(this, audioInfo);
314
+ uploadCallback(infos, infos.files);
315
+ }.bind(this, this.#serverUpload.bind(this), audioInfo);
362
316
 
363
- const result = await this.triggerEvent('onAudioUploadBefore', {
317
+ const result = await this.$.eventManager.triggerEvent('onAudioUploadBefore', {
364
318
  info: audioInfo,
365
- handler
319
+ handler,
366
320
  });
367
321
 
368
322
  if (typeof result === 'undefined') return true;
@@ -375,7 +329,7 @@ class Audio_ extends EditorInjector {
375
329
  }
376
330
 
377
331
  /**
378
- * @description Create an "audio" component using the provided url.
332
+ * @description Create an `audio` component using the provided url.
379
333
  * @param {string} url File url
380
334
  * @returns {Promise<boolean>}
381
335
  */
@@ -387,17 +341,17 @@ class Audio_ extends EditorInjector {
387
341
  url,
388
342
  files: file,
389
343
  isUpdate: this.modal.isUpdate,
390
- element: this._createAudioTag()
344
+ element: this.#createAudioTag(),
391
345
  };
392
346
 
393
- const handler = function (newInfos, infos) {
347
+ const handler = function (uploadCallback, newInfos, infos) {
394
348
  infos = newInfos || infos;
395
- this._createComp(infos.element, infos.url, infos.files, infos.isUpdate);
396
- }.bind(this, audioInfo);
349
+ uploadCallback(infos.element, infos.url, infos.files, infos.isUpdate, true);
350
+ }.bind(this, this.create.bind(this), audioInfo);
397
351
 
398
- const result = await this.triggerEvent('onAudioUploadBefore', {
352
+ const result = await this.$.eventManager.triggerEvent('onAudioUploadBefore', {
399
353
  info: audioInfo,
400
- handler
354
+ handler,
401
355
  });
402
356
 
403
357
  if (typeof result === 'undefined') return true;
@@ -410,66 +364,94 @@ class Audio_ extends EditorInjector {
410
364
  }
411
365
 
412
366
  /**
413
- * @private
414
- * @description Creates or updates an audio component within the editor.
367
+ * @description Creates or updates an `audio` component within the editor.
415
368
  * - If `isUpdate` is `true`, updates the existing element's `src`.
416
- * - Otherwise, inserts a new audio component with the given file.
417
- * @param {HTMLAudioElement} element - The target audio element.
369
+ * - Otherwise, inserts a new `audio` component with the given file.
370
+ * @param {HTMLAudioElement} element - The target `AUDIO` element.
418
371
  * @param {string} src - The source URL of the audio file.
419
372
  * @param {{name: string, size: number}} file - The file metadata (name, size).
420
373
  * @param {boolean} isUpdate - Whether to update an existing element.
374
+ * @param {boolean} isLast - Indicates whether this is the last file in the batch (used for scroll and insert actions).
421
375
  */
422
- _createComp(element, src, file, isUpdate) {
376
+ create(element, src, file, isUpdate, isLast) {
423
377
  // create new tag
424
378
  if (!isUpdate) {
425
379
  this.fileManager.setFileData(element, file);
426
380
  element.src = src;
427
381
  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();
382
+ if (!this.$.component.insert(figure.container, { scrollTo: isLast ? true : false, insertBehavior: isLast ? this.pluginOptions.insertBehavior : 'line' })) {
383
+ if (isLast) this.$.focusManager.focus();
430
384
  return;
431
385
  }
432
- if (!this.options.get('componentAutoSelect')) {
433
- const line = this.format.addLine(figure.container, null);
434
- if (line) this.selection.setRange(line, 0, line, 0);
386
+ if (!this.$.options.get('componentInsertBehavior')) {
387
+ const line = this.$.format.addLine(figure.container, null);
388
+ if (line) this.$.selection.setRange(line, 0, line, 0);
435
389
  }
436
390
  } else {
437
- if (this._element) element = this._element;
391
+ if (this.#element) element = this.#element;
438
392
  this.fileManager.setFileData(element, file);
439
393
  if (element && element.src !== src) {
440
394
  element.src = src;
441
- this.component.select(element, Audio_.key);
395
+ this.$.component.select(element, Audio_.key);
442
396
  } else {
443
- this.component.select(element, Audio_.key);
397
+ this.$.component.select(element, Audio_.key);
444
398
  return;
445
399
  }
446
400
  }
447
401
 
448
- if (isUpdate) this.history.push(false);
402
+ if (isUpdate) this.$.history.push(false);
403
+ }
404
+
405
+ /**
406
+ * @description Prepares the component for selection.
407
+ * - Ensures that the controller is properly positioned and initialized.
408
+ * - Prevents duplicate event handling if the component is already selected.
409
+ * @param {HTMLElement} target - The selected element.
410
+ */
411
+ #ready(target) {
412
+ if (_DragHandle.get('__overInfo') === ON_OVER_COMPONENT) return;
413
+ this.#element = /** @type {HTMLAudioElement} */ (target);
414
+ this.controller.open(target, null, { isWWTarget: false, addOffset: null });
415
+ }
416
+
417
+ /**
418
+ * @description Registers uploaded audio files and creates the corresponding audio elements.
419
+ * - Iterates through the uploaded files and inserts them into the editor.
420
+ * @param {SunEditor.EventParams.AudioInfo} info - Upload metadata, including `isUpdate` flag and `element`.
421
+ * @param {Object<string, *>} response - Server response containing uploaded file details.
422
+ */
423
+ #register(info, response) {
424
+ const fileList = response.result;
425
+
426
+ for (let i = 0, len = fileList.length, file, oAudio; i < len; i++) {
427
+ if (info.isUpdate) oAudio = info.element;
428
+ else oAudio = this.#createAudioTag();
429
+
430
+ file = { name: fileList[i].name, size: fileList[i].size };
431
+ this.create(oAudio, fileList[i].url, file, info.isUpdate, i === len - 1);
432
+ }
449
433
  }
450
434
 
451
435
  /**
452
- * @private
453
- * @description Creates a new `<audio>` element with default attributes.
436
+ * @description Creates a new `AUDIO` element with default attributes.
454
437
  * - Applies width, height, and additional attributes from plugin options.
455
- * @returns {HTMLAudioElement} - The newly created `<audio>` element.
438
+ * @returns {HTMLAudioElement} - The newly created `AUDIO` element.
456
439
  */
457
- _createAudioTag() {
458
- const w = this.defaultWidth;
459
- const h = this.defaultHeight;
440
+ #createAudioTag() {
441
+ const w = this.#defaultWidth;
442
+ const h = this.#defaultHeight;
460
443
  /** @type {HTMLAudioElement} */
461
444
  const oAudio = dom.utils.createElement('AUDIO', { style: (w ? 'width:' + w + '; ' : '') + (h ? 'height:' + h + ';' : '') });
462
- this._setTagAttrs(oAudio);
445
+ this.#setTagAttrs(oAudio);
463
446
  return oAudio;
464
447
  }
465
448
 
466
449
  /**
467
- * @private
468
- * @description Sets attributes on an audio element based on plugin options.
450
+ * @description Sets attributes on an `AUDIO` element based on plugin options.
469
451
  * - Adds the `controls` attribute and applies any custom attributes.
470
- * @param {HTMLElement} element - The `<audio>` element to modify.
452
+ * @param {HTMLElement} element - The `AUDIO` element to modify.
471
453
  */
472
- _setTagAttrs(element) {
454
+ #setTagAttrs(element) {
473
455
  element.setAttribute('controls', 'true');
474
456
 
475
457
  const attrs = this.pluginOptions.audioTagAttributes;
@@ -481,21 +463,19 @@ class Audio_ extends EditorInjector {
481
463
  }
482
464
 
483
465
  /**
484
- * @private
485
466
  * @description Uploads audio files to the server.
486
467
  * - Sends a request to the configured upload URL and processes the response.
487
- * @param {AudioInfo_audio} info - Upload metadata, including `files` and `isUpdate`.
468
+ * @param {SunEditor.EventParams.AudioInfo} info - Upload metadata, including `files` and `isUpdate`.
488
469
  * @param {FileList|File[]} files - The files to be uploaded.
489
470
  */
490
- _serverUpload(info, files) {
471
+ #serverUpload(info, files) {
491
472
  if (!files) return;
492
473
 
493
474
  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));
475
+ this.fileManager.upload(this.pluginOptions.uploadUrl, this.pluginOptions.uploadHeaders, uploadFiles, this.#UploadCallBack.bind(this, info), this.#error.bind(this));
495
476
  }
496
477
 
497
478
  /**
498
- * @private
499
479
  * @description Handles errors that occur during the audio upload process.
500
480
  * - Triggers the `onAudioUploadError` event to allow custom handling of errors.
501
481
  * - Displays an error message in the editor's UI.
@@ -503,10 +483,10 @@ class Audio_ extends EditorInjector {
503
483
  * @param {Object<string, *>} response - The error response object from the server or upload process.
504
484
  * @returns {Promise<void>}
505
485
  */
506
- async _error(response) {
507
- const message = await this.triggerEvent('onAudioUploadError', { error: response });
486
+ async #error(response) {
487
+ const message = await this.$.eventManager.triggerEvent('onAudioUploadError', { error: response });
508
488
  const err = message === NO_EVENT ? response.errorMessage : message || response.errorMessage;
509
- this.ui.alertOpen(err, 'error');
489
+ this.$.ui.alertOpen(err, 'error');
510
490
  console.error('[SUNEDITOR.plugin.audio.error]', err);
511
491
  }
512
492
 
@@ -514,16 +494,16 @@ class Audio_ extends EditorInjector {
514
494
  * @description Handles the server response after a file upload.
515
495
  * - If the upload is successful, registers the uploaded audio.
516
496
  * - If an error occurs, triggers an error event.
517
- * @param {AudioInfo_audio} info - Upload metadata.
497
+ * @param {SunEditor.EventParams.AudioInfo} info - Upload metadata.
518
498
  * @param {XMLHttpRequest} xmlHttp - The completed XHR request.
519
499
  */
520
500
  async #UploadCallBack(info, xmlHttp) {
521
- if ((await this.triggerEvent('audioUploadHandler', { xmlHttp, info })) === NO_EVENT) {
501
+ if ((await this.$.eventManager.triggerEvent('audioUploadHandler', { xmlHttp, info })) === NO_EVENT) {
522
502
  const response = JSON.parse(xmlHttp.responseText);
523
503
  if (response.errorMessage) {
524
- this._error(response);
504
+ this.#error(response);
525
505
  } else {
526
- this._register(info, response);
506
+ this.#register(info, response);
527
507
  }
528
508
  }
529
509
  }
@@ -537,13 +517,13 @@ class Audio_ extends EditorInjector {
537
517
  /** @type {HTMLInputElement} */
538
518
  const target = dom.query.getEventTarget(e);
539
519
  const value = target.value.trim();
540
- this.urlValue = this.preview.textContent = !value
520
+ this.#urlValue = this.preview.textContent = !value
541
521
  ? ''
542
- : this.options.get('defaultUrlProtocol') && !value.includes('://') && value.indexOf('#') !== 0
543
- ? this.options.get('defaultUrlProtocol') + value
544
- : !value.includes('://')
545
- ? '/' + value
546
- : value;
522
+ : this.$.options.get('defaultUrlProtocol') && !value.includes('://') && value.indexOf('#') !== 0
523
+ ? this.$.options.get('defaultUrlProtocol') + value
524
+ : !value.includes('://')
525
+ ? '/' + value
526
+ : value;
547
527
  }
548
528
 
549
529
  /**
@@ -551,14 +531,14 @@ class Audio_ extends EditorInjector {
551
531
  * - Calls a function to populate the URL input with the selected audio file.
552
532
  */
553
533
  #OpenGallery() {
554
- this.plugins.audioGallery.open(this.#SetUrlInput.bind(this));
534
+ this.$.plugins.audioGallery.open(this.#SetUrlInput.bind(this));
555
535
  }
556
536
 
557
537
  /**
558
538
  * @param {HTMLInputElement} target - The target element.
559
539
  */
560
540
  #SetUrlInput(target) {
561
- this.urlValue = this.preview.textContent = this.audioUrlFile.value = target.getAttribute('data-command') || target.src;
541
+ this.#urlValue = this.preview.textContent = this.audioUrlFile.value = target.getAttribute('data-command') || target.src;
562
542
  this.audioUrlFile.focus();
563
543
  }
564
544
 
@@ -598,6 +578,11 @@ class Audio_ extends EditorInjector {
598
578
  }
599
579
  }
600
580
 
581
+ /**
582
+ * @param {SunEditor.Deps} $ - Kernel dependencies
583
+ * @param {import('./audio').AudioPluginOptions} pluginOptions - Audio plugin options
584
+ * @returns {HTMLElement}
585
+ */
601
586
  function CreateHTML_modal({ lang, icons, plugins }, pluginOptions) {
602
587
  let html = /*html*/ `
603
588
  <form method="post" enctype="multipart/form-data">
@@ -645,6 +630,10 @@ function CreateHTML_modal({ lang, icons, plugins }, pluginOptions) {
645
630
  return dom.utils.createElement('DIV', { class: 'se-modal-content' }, html);
646
631
  }
647
632
 
633
+ /**
634
+ * @param {SunEditor.Deps} $ - Kernel dependencies
635
+ * @returns {HTMLElement}
636
+ */
648
637
  function CreateHTML_controller({ lang, icons }) {
649
638
  const html = /*html*/ `
650
639
  <div class="se-arrow se-arrow-up"></div>