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,8 +1,9 @@
1
- import EditorInjector from '../editorInjector';
2
- import { Controller, SelectMenu, _DragHandle } from '../modules';
3
- import { dom, numbers, env, converter, keyCodeMap } from '../helper';
1
+ import Controller from './Controller';
2
+ import SelectMenu from '../ui/SelectMenu';
3
+ import { _DragHandle } from '../ui/_DragHandle';
4
+ import { dom, numbers, env, converter, keyCodeMap } from '../../helper';
4
5
 
5
- const { ON_OVER_COMPONENT } = env;
6
+ const { _w, ON_OVER_COMPONENT } = env;
6
7
  const DIRECTION_CURSOR_MAP = { tl: 'nwse-resize', tr: 'nesw-resize', bl: 'nesw-resize', br: 'nwse-resize', lw: 'ew-resize', th: 'ns-resize', rw: 'ew-resize', bh: 'ns-resize' };
7
8
  const DIR_DIAGONAL = 'tl|bl|tr|br';
8
9
  const DIR_W = 'lw|rw';
@@ -12,100 +13,171 @@ let __resizing_cw = 0;
12
13
  let __resizing_sw = 0;
13
14
 
14
15
  /**
15
- * @typedef {Object} FigureParams
16
- * @property {string} [sizeUnit="px"] Size unit
17
- * @property {{ current: string, default: string }} [autoRatio=null] Auto ratio { current: '00%', default: '00%' }
18
- */
19
-
20
- /**
16
+ * Figure information object
21
17
  * @typedef {Object} FigureInfo
22
- * @property {HTMLElement} target Target element (img, iframe, video, audio, table, etc.)
23
- * @property {HTMLElement} container Container element (div.se-component|span.se-component.se-inline-component)
24
- * @property {?HTMLElement} cover Cover element (FIGURE|null)
25
- * @property {?HTMLElement} inlineCover Inline cover element (span.se-inline-component)
26
- * @property {?HTMLElement} caption Caption element (FIGCAPTION)
18
+ * @property {HTMLElement} target - Target element (`img`, `iframe`, `video`, `audio`, `table`, etc.)
19
+ * @property {HTMLElement} container - Container element (`div.se-component`|`span.se-component.se-inline-component`)
20
+ * @property {?HTMLElement} cover - Cover element (`FIGURE`|`null`)
21
+ * @property {?HTMLElement} inlineCover - Inline cover element (`span.se-inline-component`)
22
+ * @property {?HTMLElement} caption - Caption element (`FIGCAPTION`)
23
+ * @property {boolean} isVertical - Whether to rotate vertically
27
24
  */
28
25
 
29
26
  /**
27
+ * Figure target information object (for resize/align operations)
30
28
  * @typedef {Object} FigureTargetInfo
31
- * @property {HTMLElement} container Container element (div.se-component|span.se-component.se-inline-component)
32
- * @property {?HTMLElement=} cover Cover element (FIGURE|null)
33
- * @property {?HTMLElement=} caption Caption element (FIGCAPTION)
29
+ * @property {HTMLElement} container - Container element (`div.se-component`|`span.se-component.se-inline-component`)
30
+ * @property {?HTMLElement} [cover] - Cover element (`FIGURE`|`null`)
31
+ * @property {?HTMLElement} [caption] - Caption element (`FIGCAPTION`)
34
32
  * @property {string} [align] - Alignment of the element.
35
33
  * @property {{w:number, h:number}} [ratio] - The aspect ratio of the element.
34
+ * @property {boolean} isVertical - Whether to rotate vertically
36
35
  * @property {string|number} [w] - Width of the element.
37
36
  * @property {string|number} [h] - Height of the element.
38
37
  * @property {number} [t] - Top position.
39
38
  * @property {number} [l] - Left position.
40
- * @property {string|number} width - Width, can be a number or 'auto'.
41
- * @property {string|number} height - Height, can be a number or 'auto'.
39
+ * @property {string|number} width - Width, can be a number or `auto`.
40
+ * @property {string|number} height - Height, can be a number or `auto`.
42
41
  * @property {number} [originWidth] - Original width from `naturalWidth` or `offsetWidth`.
43
42
  * @property {number} [originHeight] - Original height from `naturalHeight` or `offsetHeight`.
44
43
  */
45
44
 
46
45
  /**
47
- * @typedef {Array<Array<
48
- * string |
49
- * {
50
- * action: (element: Node, value: string, target: Node) => void,
51
- * command: string,
52
- * value: string,
53
- * title: string,
54
- * icon: string
55
- * }
56
- * >>} FigureControls
57
- * "mirror". "rotate", "caption", "revert", "edit", "copy", "remove", "as", "resize_auto,[number]"
46
+ * Figure control button type
47
+ * @typedef {"mirror_h" | "mirror_v" | "rotate_l" | "rotate_r" | "caption" | "revert" | "edit" | "copy" | "remove" | "as" | "align" | "onalign" | "onresize"} FigureControlButton
48
+ */
49
+
50
+ /**
51
+ * Figure control resize value type (auto, or percentage numbers)
52
+ * @typedef {`resize_auto,${number}` | `resize_auto,${number},${number}` | `resize_auto,${number},${number},${number}` | `resize_auto,${number},${number},${number},${number}`} FigureControlResize
53
+ */
54
+
55
+ /**
56
+ * Figure control custom action object
57
+ * @typedef {{
58
+ * action: (element: Node, value: string, target: Node) => void,
59
+ * command: string,
60
+ * value: string,
61
+ * title: string,
62
+ * icon: string
63
+ * }} ControlCustomAction
64
+ */
65
+
66
+ /**
67
+ * Figure controls configuration
68
+ * 2D array of control buttons for the figure component toolbar
69
+ *
70
+ * **Available control buttons**:
71
+ * - `"mirror_h"`: Mirror horizontally
72
+ * - `"mirror_v"`: Mirror vertically
73
+ * - `"rotate_l"`: Rotate left (-90°)
74
+ * - `"rotate_r"`: Rotate right (90°)
75
+ * - `"caption"`: Toggle caption (`FIGCAPTION`)
76
+ * - `"revert"`: Revert to original size
77
+ * - `"edit"`: Open edit modal
78
+ * - `"copy"`: Copy component
79
+ * - `"remove"`: Remove component
80
+ * - `"as"`: Format type (`block`/`inline`) - requires `useFormatType` option
81
+ * - `"align"`: Alignment (`none`/`left`/`center`/`right`)
82
+ * - `"onalign"`: Alignment button (opens alignment menu)
83
+ * - `"onresize"`: Resize button (opens resize menu)
84
+ * - `"resize_auto,50,75,100"`: Auto-resize with percentage values (e.g., `"resize_auto,100,75,50"`)
85
+ * - Custom action object with action, command, value, title, icon
86
+ *
87
+ * @example
88
+ * // Basic controls
89
+ * [['mirror_h', 'mirror_v', 'align', 'caption', 'edit', 'copy', 'remove']]
90
+ *
91
+ * @example
92
+ * // Multi-row controls with resize options
93
+ * [
94
+ * ['as', 'resize_auto,100,75,50', 'rotate_l', 'rotate_r', 'mirror_h', 'mirror_v'],
95
+ * ['edit', 'align', 'caption', 'revert', 'copy', 'remove']
96
+ * ]
97
+ *
98
+ * @typedef {Array<Array<FigureControlButton | FigureControlResize | ControlCustomAction | string>>} FigureControls
99
+ */
100
+
101
+ // -------------------------------------------------------------------------------------------------------------------------
102
+
103
+ /**
104
+ * @typedef {Object} FigureParams
105
+ * @property {string} [sizeUnit="px"] Size unit
106
+ * @property {{ current: string, default: string }} [autoRatio=null] Auto ratio `{ current: '00%', default: '00%' }`
58
107
  */
59
108
 
60
109
  /**
61
110
  * @class
62
- * @description Controller module class
111
+ * @description Figure module class for handling resizable/alignable components (images, videos, iframes, etc.)
112
+ * @see EditorComponent for `inst._element` requirement
63
113
  */
64
- class Figure extends EditorInjector {
114
+ class Figure {
115
+ #$;
116
+
117
+ #offContainer;
118
+ #containerResizingESC;
119
+
120
+ #width = '';
121
+ #height = '';
122
+ #resize_w = 0;
123
+ #resize_h = 0;
124
+ #element_w = 0;
125
+ #element_h = 0;
126
+ #floatClassStr = '__se__float-none|__se__float-left|__se__float-center|__se__float-right';
127
+ #preventSizechange = false;
128
+ #revertSize = { w: '', h: '' };
129
+ #onResizeESCEvent = null;
130
+
65
131
  /**
66
132
  * @constructor
67
133
  * @param {*} inst The instance object that called the constructor.
134
+ * @param {SunEditor.Deps} $ Kernel dependencies
68
135
  * @param {FigureControls} controls Controller button array
69
136
  * @param {FigureParams} params Figure options
70
137
  */
71
- constructor(inst, controls, params) {
72
- super(inst.editor);
138
+ constructor(inst, $, controls, params) {
139
+ this.#$ = $;
140
+
73
141
  this.kind = inst.constructor.key || inst.constructor.name;
74
142
  this._alignIcons = {
75
- none: this.icons.format_float_none,
76
- left: this.icons.format_float_left,
77
- right: this.icons.format_float_right,
78
- center: this.icons.format_float_center
143
+ none: this.#$.icons.format_float_none,
144
+ left: this.#$.icons.format_float_left,
145
+ right: this.#$.icons.format_float_right,
146
+ center: this.#$.icons.format_float_center,
79
147
  };
80
148
 
81
149
  // modules
82
150
  /** @type {Object<string, *>} */
83
151
  this._action = {};
84
- const controllerEl = CreateHTML_controller(this, controls || []);
85
- this.controller = new Controller(this, controllerEl, { position: 'bottom', disabled: true }, this.kind);
86
- // align selectmenu
87
- this.alignButton = controllerEl.querySelector('[data-command="onalign"]');
88
- const alignMenus = CreateAlign(this, this.alignButton);
89
- if (alignMenus) {
90
- this.selectMenu_align = new SelectMenu(this, { checkList: false, position: 'bottom-center' });
91
- this.selectMenu_align.on(this.alignButton, this.#SetMenuAlign.bind(this), { class: 'se-figure-select-list' });
92
- this.selectMenu_align.create(alignMenus.items, alignMenus.html);
93
- }
94
- // as [block, inline] selectmenu
95
- this.asButton = controllerEl.querySelector('[data-command="onas"]');
96
- const asMenus = CreateAs(this, this.asButton);
97
- if (asMenus) {
98
- this.selectMenu_as = new SelectMenu(this, { checkList: false, position: 'bottom-center' });
99
- this.selectMenu_as.on(this.asButton, this.#SetMenuAs.bind(this), { class: 'se-figure-select-list' });
100
- this.selectMenu_as.create(asMenus.items, asMenus.html);
101
- }
102
- // resize selectmenu
103
- this.resizeButton = controllerEl.querySelector('[data-command="onresize"]');
104
- const resizeMenus = CreateResize(this, this.resizeButton);
105
- if (resizeMenus) {
106
- this.selectMenu_resize = new SelectMenu(this, { checkList: false, position: 'bottom-left', dir: 'ltr' });
107
- this.selectMenu_resize.on(this.resizeButton, this.#SetResize.bind(this));
108
- this.selectMenu_resize.create(resizeMenus.items, resizeMenus.html);
152
+
153
+ const controllerEl = CreateHTML_controller(this, $, controls || []);
154
+ this.controller = controllerEl ? new Controller(this, $, controllerEl, { position: 'bottom', disabled: true }, this.kind) : null;
155
+
156
+ if (controllerEl) {
157
+ // align selectmenu
158
+ this.alignButton = controllerEl.querySelector('[data-command="onalign"]');
159
+ const alignMenus = CreateAlign(this, $, this.alignButton);
160
+ if (alignMenus) {
161
+ this.selectMenu_align = new SelectMenu($, { checkList: false, position: 'bottom-center' });
162
+ this.selectMenu_align.on(this.alignButton, this.#SetMenuAlign.bind(this), { class: 'se-figure-select-list' });
163
+ this.selectMenu_align.create(alignMenus.items, alignMenus.html);
164
+ }
165
+ // as [block, inline] selectmenu
166
+ this.asButton = controllerEl.querySelector('[data-command="onas"]');
167
+ const asMenus = CreateAs($, this.asButton);
168
+ if (asMenus) {
169
+ this.selectMenu_as = new SelectMenu($, { checkList: false, position: 'bottom-center' });
170
+ this.selectMenu_as.on(this.asButton, this.#SetMenuAs.bind(this), { class: 'se-figure-select-list' });
171
+ this.selectMenu_as.create(asMenus.items, asMenus.html);
172
+ }
173
+ // resize selectmenu
174
+ this.resizeButton = controllerEl.querySelector('[data-command="onresize"]');
175
+ const resizeMenus = CreateResize($, this.resizeButton);
176
+ if (resizeMenus) {
177
+ this.selectMenu_resize = new SelectMenu($, { checkList: false, position: 'bottom-left', dir: 'ltr' });
178
+ this.selectMenu_resize.on(this.resizeButton, this.#SetResize.bind(this));
179
+ this.selectMenu_resize.create(resizeMenus.items, resizeMenus.html);
180
+ }
109
181
  }
110
182
 
111
183
  // members
@@ -113,57 +185,45 @@ class Figure extends EditorInjector {
113
185
  this.sizeUnit = params.sizeUnit || 'px';
114
186
  this.autoRatio = params.autoRatio;
115
187
  this.isVertical = false;
116
- this.percentageButtons = controllerEl.querySelectorAll('[data-command="resize_percent"]');
117
- this.captionButton = controllerEl.querySelector('[data-command="caption"]');
188
+ this.percentageButtons = controllerEl?.querySelectorAll('[data-command="resize_percent"]') || [];
189
+ this.captionButton = controllerEl?.querySelector('[data-command="caption"]');
118
190
  this.align = 'none';
119
191
  this.as = 'block';
192
+ /** @type {{left?: number, top?: number}} */
193
+ this.__offset = {};
120
194
  this._element = null;
121
195
  this._cover = null;
122
196
  this._inlineCover = null;
123
197
  this._container = null;
124
198
  this._caption = null;
125
- this._width = '';
126
- this._height = '';
127
- this._resize_w = 0;
128
- this._resize_h = 0;
129
- this._element_w = 0;
130
- this._element_h = 0;
131
- this._element_l = 0;
132
- this._element_t = 0;
133
199
  this._resizeClientX = 0;
134
200
  this._resizeClientY = 0;
135
201
  this._resize_direction = '';
136
- this._floatClassStr = '__se__float-none|__se__float-left|__se__float-center|__se__float-right';
137
- this.__preventSizechange = false;
138
- this.__revertSize = { w: '', h: '' };
139
- /** @type {{left?: number, top?: number}} */
140
- this.__offset = {};
141
- this.__offContainer = this.#OffFigureContainer.bind(this);
142
- this.__containerResizing = this.#ContainerResizing.bind(this);
143
202
  this.__containerResizingOff = this.#ContainerResizingOff.bind(this);
144
- this.__containerResizingESC = this.#ContainerResizingESC.bind(this);
203
+ this.__containerResizing = this.#ContainerResizing.bind(this);
145
204
  this.__onContainerEvent = null;
146
205
  this.__offContainerEvent = null;
147
- this.__onResizeESCEvent = null;
148
- this.__fileManagerInfo = false;
206
+
207
+ this.#offContainer = this.#OffFigureContainer.bind(this);
208
+ this.#containerResizingESC = this.#ContainerResizingESC.bind(this);
149
209
 
150
210
  // init
151
- this.eventManager.addEvent(this.alignButton, 'click', this.#OnClick_alignButton.bind(this));
152
- this.eventManager.addEvent(this.asButton, 'click', this.#OnClick_asButton.bind(this));
153
- this.eventManager.addEvent(this.resizeButton, 'click', this.#OnClick_resizeButton.bind(this));
154
- this.editor.applyFrameRoots((e) => {
211
+ this.#$.eventManager.addEvent(this.alignButton, 'click', this.#OnClick_alignButton.bind(this));
212
+ this.#$.eventManager.addEvent(this.asButton, 'click', this.#OnClick_asButton.bind(this));
213
+ this.#$.eventManager.addEvent(this.resizeButton, 'click', this.#OnClick_resizeButton.bind(this));
214
+ this.#$.contextProvider.applyToRoots((e) => {
155
215
  if (!e.get('wrapper').querySelector('.se-controller.se-resizing-container')) {
156
216
  // resizing
157
217
  const main = CreateHTML_resizeDot();
158
218
  const handles = main.querySelectorAll('.se-resize-dot > span');
159
219
  e.set('_figure', {
160
220
  main: main,
161
- border: main.querySelector('.se-resize-dot'),
162
- display: main.querySelector('.se-resize-display'),
163
- handles: handles
221
+ border: /** @type {HTMLElement} */ (main.querySelector('.se-resize-dot')),
222
+ display: /** @type {HTMLElement} */ (main.querySelector('.se-resize-display')),
223
+ handles: /** @type {*} */ (handles),
164
224
  });
165
225
  e.get('wrapper').appendChild(main);
166
- this.eventManager.addEvent(handles, 'mousedown', this.#OnResizeContainer.bind(this));
226
+ this.#$.eventManager.addEvent(handles, 'mousedown', this.#OnResizeContainer.bind(this));
167
227
  }
168
228
  });
169
229
  }
@@ -171,7 +231,7 @@ class Figure extends EditorInjector {
171
231
  /**
172
232
  * @description Create a container for the resizing component and insert the element.
173
233
  * @param {Node} element Target element
174
- * @param {string=} className Class name of container (fixed: se-component)
234
+ * @param {string} [className] Class name of container (fixed: `se-component`)
175
235
  * @returns {FigureInfo} {target, container, cover, inlineCover, caption}
176
236
  */
177
237
  static CreateContainer(element, className) {
@@ -182,7 +242,7 @@ class Figure extends EditorInjector {
182
242
  /**
183
243
  * @description Create a container for the inline resizing component and insert the element.
184
244
  * @param {Node} element Target element
185
- * @param {string} [className] Class name of container (fixed: se-component se-inline-component)
245
+ * @param {string} [className] Class name of container (fixed: `se-component` `se-inline-component`)
186
246
  * @returns {FigureInfo} {target, container, cover, inlineCover, caption}
187
247
  */
188
248
  static CreateInlineContainer(element, className) {
@@ -191,8 +251,8 @@ class Figure extends EditorInjector {
191
251
  }
192
252
 
193
253
  /**
194
- * @description Return HTML string of caption(FIGCAPTION) element
195
- * @param {Node} cover Cover element(FIGURE). "CreateContainer().cover"
254
+ * @description Return HTML string of caption(`FIGCAPTION`) element
255
+ * @param {Node} cover Cover element(`FIGURE`). `CreateContainer().cover`
196
256
  * @returns {HTMLElement} caption element
197
257
  */
198
258
  static CreateCaption(cover, text) {
@@ -202,19 +262,23 @@ class Figure extends EditorInjector {
202
262
  }
203
263
 
204
264
  /**
205
- * @description Get the element's container(.se-component) info.
265
+ * @description Get the element's container(`.se-component`) info.
206
266
  * @param {Node} element Target element
207
267
  * @returns {FigureInfo} {target, container, cover, inlineCover, caption}
208
268
  */
209
269
  static GetContainer(element) {
210
270
  const cover = dom.query.getParentElement(element, 'FIGURE', 2);
211
271
  const inlineCover = dom.query.getParentElement(element, 'SPAN', 2);
272
+ const anyCover = cover || inlineCover;
273
+ const target = dom.query.getParentElement(element, (current) => current.parentElement === anyCover, 0) || /** @type {HTMLElement} */ (element);
274
+
212
275
  return {
213
- target: /** @type {HTMLElement} */ (element),
214
- container: /** @type {HTMLElement} */ (dom.query.getParentElement(element, Figure.is, 2) || cover),
215
- cover: /** @type {HTMLElement} */ (cover),
276
+ target,
277
+ container: dom.query.getParentElement(target, Figure.is, 3) || cover,
278
+ cover: cover,
216
279
  inlineCover: dom.utils.hasClass(inlineCover, 'se-inline-component') ? /** @type {HTMLElement} */ (inlineCover) : null,
217
- caption: /** @type {HTMLElement} */ (dom.query.getEdgeChild(element.parentElement, 'FIGCAPTION', false))
280
+ caption: dom.query.getEdgeChild(target.parentElement, 'FIGCAPTION', false),
281
+ isVertical: IsVertical(target),
218
282
  };
219
283
  }
220
284
 
@@ -222,12 +286,12 @@ class Figure extends EditorInjector {
222
286
  * @description Ratio calculation
223
287
  * @param {string|number} w Width size
224
288
  * @param {string|number} h Height size
225
- * @param {?string=} [defaultSizeUnit="px"] Default size unit (default: "px")
289
+ * @param {?string} [defaultSizeUnit="px"] Default size unit (default: `"px"`)
226
290
  * @return {{w: number, h: number}}
227
291
  */
228
292
  static GetRatio(w, h, defaultSizeUnit) {
229
- let rw = 1,
230
- rh = 1;
293
+ let rw = 0,
294
+ rh = 0;
231
295
  if (/\d+/.test(w + '') && /\d+/.test(h + '')) {
232
296
  const xUnit = (!numbers.is(w) && String(w).replace(/\d+|\./g, '')) || defaultSizeUnit || 'px';
233
297
  const yUnit = (!numbers.is(h) && String(h).replace(/\d+|\./g, '')) || defaultSizeUnit || 'px';
@@ -241,7 +305,7 @@ class Figure extends EditorInjector {
241
305
 
242
306
  return {
243
307
  w: numbers.get(rw, 4),
244
- h: numbers.get(rh, 4)
308
+ h: numbers.get(rh, 4),
245
309
  };
246
310
  }
247
311
 
@@ -249,12 +313,12 @@ class Figure extends EditorInjector {
249
313
  * @description Ratio calculation
250
314
  * @param {string|number} w Width size
251
315
  * @param {string|number} h Height size
252
- * @param {string} defaultSizeUnit Default size unit (default: "px")
253
- * @param {{w: number, h: number}} ratio Ratio size (Figure.GetRatio)
316
+ * @param {string} defaultSizeUnit Default size unit (default: `"px"`)
317
+ * @param {?{w: number, h: number}} [ratio] Ratio size (Figure.GetRatio)
254
318
  * @return {{w: string|number, h: string|number}}
255
319
  */
256
320
  static CalcRatio(w, h, defaultSizeUnit, ratio) {
257
- if (/\d+/.test(w + '') && /\d+/.test(h + '')) {
321
+ if (ratio?.w && ratio?.h && /\d+/.test(w + '') && /\d+/.test(h + '')) {
258
322
  const xUnit = (!numbers.is(w) && String(w).replace(/\d+|\./g, '')) || defaultSizeUnit || 'px';
259
323
  const yUnit = (!numbers.is(h) && String(h).replace(/\d+|\./g, '')) || defaultSizeUnit || 'px';
260
324
  if (xUnit === yUnit) {
@@ -268,27 +332,28 @@ class Figure extends EditorInjector {
268
332
 
269
333
  return {
270
334
  w: w,
271
- h: h
335
+ h: h,
272
336
  };
273
337
  }
274
338
 
275
339
  /**
276
- * @description It is judged whether it is the component[img, iframe, video, audio, table] cover(class="se-component") and table, hr
340
+ * @description It is judged whether it is the component[`img`, `iframe`, `video`, `audio`, `table`] cover(class=`"se-component"`) and `table`, `hr`
277
341
  * @param {Node} element Target element
278
342
  * @returns {boolean}
279
343
  */
280
344
  static is(element) {
281
- return dom.utils.hasClass(element, 'se-component') || /^(HR)$/.test(element?.nodeName);
345
+ return dom.check.isComponentContainer(element) || /^(HR)$/.test(element?.nodeName);
282
346
  }
283
347
 
284
348
  /**
285
349
  * @description Close the figure's controller
286
350
  */
287
351
  close() {
288
- this.editor._preventBlur = false;
352
+ this.#$.store.set('_preventBlur', false);
289
353
  dom.utils.removeClass(this._cover, 'se-figure-selected');
290
- this.controller.close();
291
- this.component._removeDragEvent();
354
+ this.#$.component.__removeDragEvent();
355
+ this.#removeGlobalEvents();
356
+ this.controller?.close();
292
357
  }
293
358
 
294
359
  /**
@@ -298,19 +363,17 @@ class Figure extends EditorInjector {
298
363
  * @param {boolean} [params.nonResizing=false] Do not display the resizing button
299
364
  * @param {boolean} [params.nonSizeInfo=false] Do not display the size information
300
365
  * @param {boolean} [params.nonBorder=false] Do not display the selected style line
301
- * @param {boolean} [params.figureTarget=false] If true, the target is a figure element
302
- * @param {boolean} [params.__fileManagerInfo=false] If true, the file manager is called
366
+ * @param {boolean} [params.figureTarget=false] If `true`, the target is a figure element
367
+ * @param {boolean} [params.infoOnly=false] If `true`, returns only the figure target info without opening the controller
303
368
  * @returns {FigureTargetInfo|undefined} figure target info
304
369
  */
305
- open(targetNode, { nonResizing, nonSizeInfo, nonBorder, figureTarget, __fileManagerInfo }) {
370
+ open(targetNode, { nonResizing, nonSizeInfo, nonBorder, figureTarget, infoOnly }) {
306
371
  if (!targetNode) {
307
372
  console.warn('[SUNEDITOR.modules.Figure.open] The "targetNode" is null.');
308
373
  return;
309
374
  }
310
375
 
311
- if (_DragHandle.get('__overInfo') !== ON_OVER_COMPONENT) {
312
- this.ui._offCurrentController();
313
- } else {
376
+ if (_DragHandle.get('__overInfo') === ON_OVER_COMPONENT) {
314
377
  nonBorder = true;
315
378
  }
316
379
 
@@ -318,7 +381,7 @@ class Figure extends EditorInjector {
318
381
  const target = figureInfo.target;
319
382
  let exceptionFormat = false;
320
383
  if (!figureInfo.container) {
321
- if (!this.options.get('strictMode').formatFilter) {
384
+ if (!this.#$.options.get('strictMode').formatFilter) {
322
385
  figureInfo.container = target;
323
386
  figureInfo.cover = target;
324
387
  exceptionFormat = true;
@@ -327,28 +390,35 @@ class Figure extends EditorInjector {
327
390
  container: null,
328
391
  cover: null,
329
392
  width: target.style.width || /** @type {HTMLImageElement} */ (target).width || '',
330
- height: target.style.height || /** @type {HTMLImageElement} */ (target).height || ''
393
+ height: target.style.height || /** @type {HTMLImageElement} */ (target).height || '',
394
+ isVertical: this.isVertical,
331
395
  };
332
396
  }
333
397
  }
334
398
 
335
399
  _DragHandle.set('__figureInst', this);
336
400
 
337
- this._setFigureInfo(figureInfo);
401
+ this.#setFigureInfo(figureInfo);
338
402
 
339
403
  const sizeTarget = /** @type {HTMLElement} */ (figureTarget ? this._cover || this._container || target : target);
340
404
  const w = sizeTarget.offsetWidth || null;
341
405
  const h = sizeTarget.offsetHeight || null;
342
- const { top, left, scrollX, scrollY } = this.offset.getLocal(sizeTarget);
406
+ const { top, left, scrollX, scrollY } = this.#$.offset.getLocal(sizeTarget);
343
407
 
344
408
  const dataSize = (target.getAttribute('data-se-size') || '').split(',');
345
- const ratio = Figure.GetRatio(dataSize[0] || numbers.get(target.style.width, 2) || w, dataSize[1] || numbers.get(target.style.height, 2) || h, this.sizeUnit);
409
+
410
+ let rw = numbers.get(target.style.width, 2) || w;
411
+ let rh = numbers.get(target.style.height, 2) || h;
412
+ if (this.isVertical) [rw, rh] = [rh, rw];
413
+ const ratio = Figure.GetRatio(rw, rh, this.sizeUnit);
414
+
346
415
  const targetInfo = {
347
416
  container: figureInfo.container,
348
417
  cover: figureInfo.cover,
349
418
  caption: figureInfo.caption,
350
419
  align: this.align,
351
420
  ratio: ratio,
421
+ isVertical: this.isVertical,
352
422
  w: w || '',
353
423
  h: h || '',
354
424
  t: top,
@@ -356,15 +426,17 @@ class Figure extends EditorInjector {
356
426
  width: dataSize[0] || 'auto',
357
427
  height: dataSize[1] || 'auto',
358
428
  originWidth: /** @type {HTMLImageElement} */ (target).naturalWidth || target.offsetWidth,
359
- originHeight: /** @type {HTMLImageElement} */ (target).naturalHeight || target.offsetHeight
429
+ originHeight: /** @type {HTMLImageElement} */ (target).naturalHeight || target.offsetHeight,
360
430
  };
361
431
 
362
- this._width = targetInfo.width;
363
- this._height = targetInfo.height;
364
- if (__fileManagerInfo || this.__fileManagerInfo) return targetInfo;
432
+ this.#width = targetInfo.width;
433
+ this.#height = targetInfo.height;
434
+ if (infoOnly) return targetInfo;
435
+
436
+ const _figure = this.#$.frameContext.get('_figure');
437
+ this.#$.ui.setFigureContainer(_figure.main);
438
+ this.#$.ui.opendControllers = this.#$.ui.opendControllers.filter((c) => c.form !== _figure.main);
365
439
 
366
- const _figure = this.editor.frameContext.get('_figure');
367
- this.editor._figureContainer = _figure.main;
368
440
  _figure.main.style.top = top + 'px';
369
441
  _figure.main.style.left = left + 'px';
370
442
  _figure.main.style.width = (this.isVertical ? h : w) + 'px';
@@ -375,12 +447,13 @@ class Figure extends EditorInjector {
375
447
  _figure.border.style.height = (this.isVertical ? w : h) + 'px';
376
448
 
377
449
  this.__offset = { left: left + scrollX, top: top + scrollY };
378
- this.editor.opendControllers.push({
450
+
451
+ this.#$.ui.opendControllers.push({
379
452
  position: 'none',
380
453
  form: _figure.main,
381
454
  target: sizeTarget,
382
455
  inst: this,
383
- notInCarrier: true
456
+ notInCarrier: true,
384
457
  });
385
458
 
386
459
  // percentage active
@@ -407,46 +480,55 @@ class Figure extends EditorInjector {
407
480
  _figure.main.style.display = 'block';
408
481
 
409
482
  if (_DragHandle.get('__overInfo') !== ON_OVER_COMPONENT) {
410
- // align button
411
- this._setAlignIcon();
412
- // as button
413
- this._setAsIcon();
414
- this.ui._visibleControllers(true, true);
415
- // size
416
- const size = this.getSize(target);
417
- dom.utils.changeTxt(_figure.display, this.lang[this.align === 'none' ? 'basic' : this.align] + ' (' + size.w + ', ' + size.h + ')');
418
- this._displayResizeHandles(!nonResizing);
419
- // rotate, aption, align, onresize - display;
420
- const transformButtons = this.controller.form.querySelectorAll(
421
- '[data-command="rotate"][data-value="90"], [data-command="rotate"][data-value="-90"], [data-command="caption"], [data-command="onalign"], [data-command="onresize"]'
422
- );
423
- const display = this._inlineCover || exceptionFormat ? 'none' : '';
424
- transformButtons.forEach((button) => {
425
- /** @type {HTMLButtonElement} */ (button).style.display = display;
426
- });
427
- // onas
428
- const onas = this.controller.form.querySelector('[data-command="onas"]');
429
- if (onas) {
430
- /** @type {HTMLButtonElement} */ (onas).style.display = exceptionFormat ? 'none' : '';
483
+ // resize handles
484
+ const displayType = nonResizing ? 'none' : 'flex';
485
+ const resizeHandles = _figure.handles;
486
+ for (let i = 0, len = resizeHandles.length; i < len; i++) {
487
+ resizeHandles[i].style.display = displayType;
431
488
  }
489
+
490
+ if (this.controller) {
491
+ // size display
492
+ const size = this.getSize(target);
493
+ dom.utils.changeTxt(_figure.display, this.#$.lang[this.align === 'none' ? 'basic' : this.align] + ' (' + size.dw + ', ' + size.dh + ')');
494
+
495
+ // align button
496
+ this.#setAlignIcon();
497
+ // as button
498
+ this.#setAsIcon();
499
+ this.#$.ui._visibleControllers(true, true);
500
+
501
+ // rotate, aption, align, onresize - display;
502
+ const transformButtons = this.controller.form.querySelectorAll(
503
+ '[data-command="rotate"][data-value="90"], [data-command="rotate"][data-value="-90"], [data-command="caption"], [data-command="onalign"], [data-command="onresize"]',
504
+ );
505
+ const display = this._inlineCover || exceptionFormat ? 'none' : '';
506
+ transformButtons?.forEach((button) => {
507
+ /** @type {HTMLButtonElement} */ (button).style.display = display;
508
+ });
509
+ // onas
510
+ const onas = this.controller.form.querySelector('[data-command="onas"]');
511
+ if (onas) {
512
+ /** @type {HTMLButtonElement} */ (onas).style.display = exceptionFormat ? 'none' : '';
513
+ }
514
+ }
515
+
432
516
  // selecte
433
517
  dom.utils.removeClass(this._cover, 'se-figure-over-selected');
434
- this.controller.open(_figure.main, null, { initMethod: this.__offContainer, isWWTarget: false, addOffset: null });
435
- this._w.setTimeout(() => _DragHandle.set('__overInfo', false), 0);
518
+ this.controller?.open(_figure.main, null, { initMethod: this.#offContainer, isWWTarget: false, addOffset: null });
519
+ _w.setTimeout(() => _DragHandle.set('__overInfo', false), 0);
436
520
  } else {
437
521
  dom.utils.addClass(this._cover, 'se-figure-over-selected');
438
522
  }
439
523
 
440
524
  // set members
441
525
  dom.utils.addClass(this._cover, 'se-figure-selected');
442
- this._element_w = this._resize_w = w;
443
- this._element_h = this._resize_h = h;
444
- this._element_l = left;
445
- this._element_t = top;
526
+ this.#element_w = this.#resize_w = w;
527
+ this.#element_h = this.#resize_h = h;
446
528
 
447
529
  // drag
448
530
  if (!this._inlineCover && (_DragHandle.get('__overInfo') !== ON_OVER_COMPONENT || dom.utils.hasClass(figureInfo.container, 'se-input-component'))) {
449
- this._setDragEvent(_figure.main);
531
+ this.#setDragEvent(_figure.main);
450
532
  }
451
533
 
452
534
  return targetInfo;
@@ -456,28 +538,28 @@ class Figure extends EditorInjector {
456
538
  * @description Hide the controller
457
539
  */
458
540
  controllerHide() {
459
- this.controller.hide();
541
+ this.controller?.hide();
460
542
  }
461
543
 
462
544
  /**
463
545
  * @description Hide the controller
464
546
  */
465
547
  controllerShow() {
466
- this.controller.show();
548
+ this.controller?.show();
467
549
  }
468
550
 
469
551
  /**
470
552
  * @description Open the figure's controller
471
553
  * @param {Node} target Target element
472
554
  * @param {Object} [params={}] params
473
- * @param {boolean=} params.isWWTarget If the controller is in the WYSIWYG area, set it to true.
474
- * @param {() => void=} params.initMethod Method to be called when the controller is closed.
475
- * @param {boolean=} params.disabled If true, the controller is disabled.
476
- * @param {{left: number, top: number}=} params.addOffset Additional offset values
555
+ * @param {boolean} [params.isWWTarget] If the controller is in the WYSIWYG area, set it to `true`.
556
+ * @param {() => void} [params.initMethod] Method to be called when the controller is closed.
557
+ * @param {boolean} [params.disabled] If `true`, the controller is disabled.
558
+ * @param {{left: number, top: number}} [params.addOffset] Additional offset values
477
559
  */
478
560
  controllerOpen(target, params) {
479
561
  this._element = /** @type {HTMLElement} */ (target);
480
- this.controller.open(target, null, params);
562
+ this.controller?.open(target, null, params);
481
563
  }
482
564
 
483
565
  /**
@@ -485,7 +567,7 @@ class Figure extends EditorInjector {
485
567
  * @param {string|number} w Width size
486
568
  * @param {string|number} h Height size
487
569
  */
488
- setSize(w, h) {
570
+ setFigureSize(w, h) {
489
571
  if (/%$/.test(w + '')) {
490
572
  this._setPercentSize(w, h);
491
573
  } else if ((!w || w === 'auto') && (!h || h === 'auto')) {
@@ -496,53 +578,78 @@ class Figure extends EditorInjector {
496
578
  }
497
579
  }
498
580
 
581
+ /**
582
+ * @description Set the element's container size from plugins input value
583
+ * @param {string|number} w Width size
584
+ * @param {string|number} h Height size
585
+ */
586
+ setSize(w, h) {
587
+ const v = this.isVertical;
588
+ if (v) [w, h] = [h, w];
589
+ this.setFigureSize(w, h);
590
+ if (v) this.setTransform(this._element, w, h, 0);
591
+ }
592
+
499
593
  /**
500
594
  * @description Gets the Figure size
501
- * @param {?Node=} targetNode Target element, default is the current element
502
- * @returns {{w: string, h: string}}
595
+ * @param {?Node} [targetNode] Target element, default is the current element
596
+ * @returns {{w: string, h: string, dw: string, dh: string}}
503
597
  */
504
598
  getSize(targetNode) {
505
- if (!targetNode) targetNode = this._element;
506
- if (!targetNode) return { w: '', h: '' };
599
+ targetNode ||= this._element;
600
+
601
+ const v = IsVertical(targetNode);
602
+ let w = '';
603
+ let h = '';
604
+ let dw = '';
605
+ let dh = '';
606
+
607
+ if (!targetNode) return { w, h, dw, dh };
507
608
 
508
609
  const figure = Figure.GetContainer(targetNode);
509
610
  const target = figure.target;
510
611
  if (!figure.container) {
511
612
  // exceptionFormat
512
- if (!this.options.get('strictMode').formatFilter) {
513
- return {
514
- w: target.style.width || 'auto',
515
- h: target.style.height || 'auto'
516
- };
613
+ if (!this.#$.options.get('strictMode').formatFilter) {
614
+ w = target.style.width || 'auto';
615
+ h = target.style.height || 'auto';
616
+ } else {
617
+ w = '';
618
+ h = target.style.height;
517
619
  }
518
- return {
519
- w: '',
520
- h: target.style.height
521
- };
620
+ } else {
621
+ w = !/%$/.test(target.style.width) ? target.style.width : ((figure.container && numbers.get(figure.container.style.width, 2)) || 100) + '%';
622
+ h = figure.inlineCover
623
+ ? figure.inlineCover.style.height || /** @type {HTMLElement} */ (targetNode).style.height || String(/** @type {HTMLImageElement} */ (targetNode).height || '')
624
+ : numbers.get(figure.cover?.style.paddingBottom, 0) > 0 && !v
625
+ ? figure.cover?.style.height
626
+ : !/%$/.test(target.style.height) || !/%$/.test(target.style.width)
627
+ ? target.style.height
628
+ : ((figure.container && numbers.get(figure.container.style.height, 2)) || 100) + '%';
629
+
630
+ w ||= 'auto';
631
+ h ||= 'auto';
522
632
  }
523
633
 
524
- const w = !/%$/.test(target.style.width) ? target.style.width : ((figure.container && numbers.get(figure.container.style.width, 2)) || 100) + '%';
525
- const h = figure.inlineCover
526
- ? figure.inlineCover.style.height
527
- : numbers.get(figure.cover.style.paddingBottom, 0) > 0 && !this.isVertical
528
- ? figure.cover.style.height
529
- : !/%$/.test(target.style.height) || !/%$/.test(target.style.width)
530
- ? target.style.height
531
- : ((figure.container && numbers.get(figure.container.style.height, 2)) || 100) + '%';
634
+ dw = v ? h : w;
635
+ dh = v ? w : h;
636
+
532
637
  return {
533
- w: w || 'auto',
534
- h: h || 'auto'
638
+ w,
639
+ h,
640
+ dw,
641
+ dh,
535
642
  };
536
643
  }
537
644
 
538
645
  /**
539
646
  * @description Align the container.
540
647
  * @param {?Node} targetNode Target element
541
- * @param {string} align "none"|"left"|"center"|"right"
648
+ * @param {string} align `"none"`|`"left"`|`"center"`|`"right"`
542
649
  */
543
650
  setAlign(targetNode, align) {
544
- if (!targetNode) targetNode = this._element;
545
- this.align = align = align || 'none';
651
+ targetNode ||= this._element;
652
+ this.align = align ||= 'none';
546
653
 
547
654
  const figure = Figure.GetContainer(targetNode);
548
655
  if (!figure.cover) return;
@@ -550,7 +657,7 @@ class Figure extends EditorInjector {
550
657
  const target = figure.target;
551
658
  const container = figure.container;
552
659
  const cover = figure.cover;
553
- if (/%$/.test(target.style.width) && align === 'center' && !this.component.isInline(container)) {
660
+ if (/%$/.test(target.style.width) && align === 'center' && !this.#$.component.isInline(container)) {
554
661
  container.style.minWidth = '100%';
555
662
  cover.style.width = container.style.width;
556
663
  } else {
@@ -559,7 +666,7 @@ class Figure extends EditorInjector {
559
666
  }
560
667
 
561
668
  if (!dom.utils.hasClass(container, '__se__float-' + align)) {
562
- dom.utils.removeClass(container, this._floatClassStr);
669
+ dom.utils.removeClass(container, this.#floatClassStr);
563
670
  dom.utils.addClass(container, '__se__float-' + align);
564
671
  }
565
672
 
@@ -568,44 +675,47 @@ class Figure extends EditorInjector {
568
675
  this.__setCoverPaddingBottom(w, h);
569
676
  }
570
677
 
571
- this._setAlignIcon();
678
+ this.#setAlignIcon();
572
679
  }
573
680
 
574
681
  /**
575
682
  * @description As style[block, inline] the component
576
683
  * @param {?Node} targetNode Target element
577
684
  * @param {"block"|"inline"} formatStyle Format style
685
+ * @returns {HTMLElement} New target element after conversion
578
686
  */
579
687
  convertAsFormat(targetNode, formatStyle) {
580
- if (!targetNode) targetNode = this._element;
688
+ targetNode ||= this._element;
581
689
  this.as = formatStyle || 'block';
582
690
  const { container, inlineCover, target } = Figure.GetContainer(targetNode);
583
691
  const { w, h } = this.getSize(target);
584
692
 
585
693
  const newTarget = /** @type {HTMLElement} */ (target.cloneNode(false));
694
+ newTarget.style.width = '';
695
+ newTarget.style.height = '';
696
+ newTarget.removeAttribute('width');
697
+ newTarget.removeAttribute('height');
586
698
 
587
699
  switch (formatStyle) {
588
700
  case 'inline': {
589
701
  if (inlineCover) break;
590
- this.component.deselect();
702
+ this.#$.component.deselect();
591
703
 
592
704
  const next = container.nextElementSibling;
593
705
  const parent = container.parentElement;
594
706
 
595
- newTarget.style.width = '';
596
- newTarget.style.height = '';
597
707
  const figure = Figure.CreateInlineContainer(newTarget);
598
708
  dom.utils.addClass(
599
709
  figure.container,
600
710
  container.className
601
711
  .split(' ')
602
712
  .filter((v) => v !== 'se-figure-selected' && v !== 'se-component-selected')
603
- .join('|')
713
+ .join('|'),
604
714
  );
605
715
 
606
- this._asFormatChange(figure, w, h);
716
+ this.#asFormatChange(figure, w, h);
607
717
 
608
- const line = dom.utils.createElement(this.options.get('defaultLine'), null, figure.container);
718
+ const line = dom.utils.createElement(this.#$.options.get('defaultLine'), null, figure.container);
609
719
  parent.insertBefore(line, next);
610
720
  dom.utils.removeItem(container);
611
721
 
@@ -613,61 +723,39 @@ class Figure extends EditorInjector {
613
723
  }
614
724
  case 'block': {
615
725
  if (!inlineCover) break;
616
- this.component.deselect();
726
+ this.#$.component.deselect();
617
727
 
618
- this.selection.setRange(container, 0, container, 1);
619
- const r = this.html.remove();
620
- const s = this.nodeTransform.split(r.container, r.offset, 0);
728
+ this.#$.selection.setRange(container, 0, container, 1);
729
+ const r = this.#$.html.remove();
730
+ const s = this.#$.nodeTransform.split(r.container, r.offset, 0);
621
731
 
622
732
  if (s?.previousElementSibling && dom.check.isZeroWidth(s.previousElementSibling)) {
623
733
  dom.utils.removeItem(s.previousElementSibling);
624
734
  }
625
735
 
626
- newTarget.style.width = '';
627
- newTarget.style.height = '';
628
736
  const figure = Figure.CreateContainer(newTarget);
629
737
  dom.utils.addClass(
630
738
  figure.container,
631
739
  container.className
632
740
  .split(' ')
633
741
  .filter((v) => v !== 'se-inline-component' && v !== 'se-figure-selected' && v !== 'se-component-selected')
634
- .join('|')
742
+ .join('|'),
635
743
  );
636
744
 
637
- this._asFormatChange(figure, w, h);
745
+ this.#asFormatChange(figure, w, h);
638
746
 
639
747
  (s || r.container).parentElement.insertBefore(figure.container, s);
640
748
 
641
749
  break;
642
750
  }
643
751
  }
644
- }
645
752
 
646
- /**
647
- * @private
648
- * @description Handles format conversion (block/inline) for the figure component and applies size changes.
649
- * @param {FigureInfo} figureinfo {target, container, cover, inlineCover, caption}
650
- * @param {string|number} w Width value.
651
- * @param {string|number} h Height value.
652
- */
653
- _asFormatChange(figureinfo, w, h) {
654
- const kind = this.kind;
655
- figureinfo.target.onload = () => this.component.select(figureinfo.target, kind);
656
-
657
- this._setFigureInfo(figureinfo);
658
-
659
- if (figureinfo.inlineCover) {
660
- this.setAlign(figureinfo.target, 'none');
661
- this.deleteTransform();
662
- }
663
-
664
- this.setSize(w, h);
753
+ return newTarget;
665
754
  }
666
755
 
667
756
  /**
668
- * @description Controller button action
669
- * @param {HTMLButtonElement} target Target button element
670
- * @returns
757
+ * @hook Module.Controller
758
+ * @type {SunEditor.Hook.Controller.Action}
671
759
  */
672
760
  controllerAction(target) {
673
761
  const command = target.getAttribute('data-command');
@@ -678,7 +766,7 @@ class Figure extends EditorInjector {
678
766
 
679
767
  switch (command) {
680
768
  case 'mirror': {
681
- const info = this.#GetRotateValue(element);
769
+ const info = GetRotateValue(element);
682
770
  let x = info.x;
683
771
  let y = info.y;
684
772
 
@@ -691,27 +779,29 @@ class Figure extends EditorInjector {
691
779
  this._setRotate(element, info.r, x, y);
692
780
  break;
693
781
  }
694
- case 'rotate':
695
- this.setTransform(element, null, null, value);
782
+ case 'rotate': {
783
+ this.setTransform(element, null, null, Number(value));
696
784
  break;
697
- case 'caption':
785
+ }
786
+ case 'caption': {
698
787
  if (!this._caption) {
699
- const caption = Figure.CreateCaption(this._cover, this.lang.caption);
788
+ const caption = Figure.CreateCaption(this._cover, this.#$.lang.caption);
700
789
  const captionText = dom.query.getEdgeChild(caption, (current) => current.nodeType === 3, false);
701
790
 
702
791
  if (!captionText) {
703
792
  caption.focus();
704
793
  } else {
705
- this.selection.setRange(captionText, 0, captionText, captionText.textContent.length);
794
+ this.#$.selection.setRange(captionText, 0, captionText, captionText.textContent.length);
706
795
  }
707
796
 
797
+ this._caption = caption;
708
798
  this.controller.close();
709
799
  } else {
710
800
  dom.utils.removeItem(this._caption);
711
- this._w.setTimeout(this.component.select.bind(this.component, element, this.kind), 0);
801
+ _w.setTimeout(this.#$.component.select.bind(this.#$.component, element, this.kind), 0);
802
+ this._caption = null;
712
803
  }
713
804
 
714
- this._caption = !this._caption;
715
805
  if (/\d+/.test(element.style.height) || (this.isVertical && this._caption)) {
716
806
  if (/%$/.test(element.style.width) || /auto/.test(element.style.height)) {
717
807
  this.deleteTransform();
@@ -720,20 +810,24 @@ class Figure extends EditorInjector {
720
810
  }
721
811
  }
722
812
  break;
723
- case 'revert':
813
+ }
814
+ case 'revert': {
724
815
  this._setRevert();
725
816
  break;
726
- case 'edit':
727
- this.inst.edit(element);
817
+ }
818
+ case 'edit': {
819
+ this.inst.componentEdit(element);
728
820
  break;
821
+ }
729
822
  case 'copy': {
730
- this.component.copy(this._container);
823
+ this.#$.component.copy(this._container);
731
824
  break;
732
825
  }
733
- case 'remove':
734
- this.inst.destroy(element);
826
+ case 'remove': {
827
+ this.inst.componentDestroy(element);
735
828
  this.controller.close();
736
829
  break;
830
+ }
737
831
  }
738
832
 
739
833
  if (/^__c__/.test(command)) {
@@ -741,11 +835,11 @@ class Figure extends EditorInjector {
741
835
  return;
742
836
  }
743
837
 
744
- if (/^edit$/.test(command)) return;
838
+ if (command === 'edit') return;
745
839
 
746
- this.history.push(false);
840
+ this.#$.history.push(false);
747
841
  if (!/^remove|caption$/.test(command)) {
748
- this.component.select(element, this.kind);
842
+ this.#$.component.select(element, this.kind);
749
843
  }
750
844
  }
751
845
 
@@ -754,31 +848,32 @@ class Figure extends EditorInjector {
754
848
  * @param {Node} container - The container element of the figure component.
755
849
  * @param {Node} originEl - The original element of the figure component.
756
850
  * @param {Node} anchorCover - The anchor cover element of the figure component.
757
- * @param {import('./FileManager').default} [fileManagerInst=null] - FileManager module instance, if used.
851
+ * @param {import('../manager/FileManager').default} [fileManagerInst=null] - FileManager module instance, if used.
758
852
  */
759
853
  retainFigureFormat(container, originEl, anchorCover, fileManagerInst) {
760
- const isInline = this.component.isInline(container);
761
- let existElement = this.format.isBlock(originEl.parentNode) || dom.check.isWysiwygFrame(originEl.parentNode) ? originEl : dom.check.isAnchor(originEl.parentNode) ? originEl.parentNode : this.format.getLine(originEl) || originEl;
854
+ const isInline = this.#$.component.isInline(container);
855
+ const originParent = originEl.parentNode;
856
+ let existElement = this.#$.format.isBlock(originParent) || dom.check.isWysiwygFrame(originParent) ? originEl : Figure.GetContainer(originEl)?.container || originParent || originEl;
762
857
 
763
858
  if (dom.query.getParentElement(originEl, dom.check.isExcludeFormat)) {
764
859
  existElement = anchorCover && anchorCover !== originEl ? anchorCover : originEl;
765
860
  existElement.parentNode.replaceChild(container, existElement);
766
- } else if (isInline && this.format.isLine(existElement)) {
861
+ } else if (isInline && this.#$.format.isLine(existElement)) {
767
862
  const refer = isInline && /^SPAN$/i.test(originEl.parentElement.nodeName) ? originEl.parentElement : originEl;
768
863
  refer.parentElement.replaceChild(container, refer);
769
864
  } else if (dom.check.isListCell(existElement)) {
770
865
  const refer = dom.query.getParentElement(originEl, (current) => current.parentNode === existElement);
771
866
  existElement.insertBefore(container, refer);
772
867
  dom.utils.removeItem(originEl);
773
- this.nodeTransform.removeEmptyNode(refer, null, true);
774
- } else if (this.format.isLine(existElement)) {
868
+ this.#$.nodeTransform.removeEmptyNode(refer, null, true);
869
+ } else if (this.#$.format.isLine(existElement)) {
775
870
  const refer = dom.query.getParentElement(originEl, (current) => current.parentNode === existElement);
776
- existElement = this.nodeTransform.split(existElement, refer);
871
+ existElement = this.#$.nodeTransform.split(existElement, refer);
777
872
  existElement.parentNode.insertBefore(container, existElement);
778
873
  dom.utils.removeItem(originEl);
779
- this.nodeTransform.removeEmptyNode(existElement, null, true);
874
+ this.#$.nodeTransform.removeEmptyNode(existElement, null, true);
780
875
  } else {
781
- if (this.format.isLine(existElement.parentNode)) {
876
+ if (this.#$.format.isLine(existElement.parentNode)) {
782
877
  const formats = existElement.parentNode;
783
878
  formats.parentNode.insertBefore(container, existElement.previousSibling ? formats.nextElementSibling : formats);
784
879
  if (fileManagerInst?.__updateTags.map((current) => existElement.contains(current)).length === 0) dom.utils.removeItem(existElement);
@@ -792,10 +887,10 @@ class Figure extends EditorInjector {
792
887
 
793
888
  /**
794
889
  * @description Initialize the transform style (rotation) of the element.
795
- * @param {?Node=} node Target element, default is the current element
890
+ * @param {?Node} [node] Target element, default is the current element
796
891
  */
797
892
  deleteTransform(node) {
798
- if (!node) node = this._element;
893
+ node ||= this._element;
799
894
 
800
895
  const element = /** @type {HTMLElement} */ (node);
801
896
  const size = (element.getAttribute('data-se-size') || '').split(',');
@@ -805,7 +900,7 @@ class Figure extends EditorInjector {
805
900
  element.style.transform = '';
806
901
  element.style.transformOrigin = '';
807
902
 
808
- this._deleteCaptionPosition(element);
903
+ this.#deleteCaptionPosition(element);
809
904
  this._applySize(size[0] || 'auto', size[1] || '', '');
810
905
  }
811
906
 
@@ -814,20 +909,23 @@ class Figure extends EditorInjector {
814
909
  * @param {Node} node Target element
815
910
  * @param {?string|number} width Element's width size
816
911
  * @param {?string|number} height Element's height size
912
+ * @param {?number} deg rotate value
817
913
  */
818
914
  setTransform(node, width, height, deg) {
819
915
  try {
820
- this.__preventSizechange = true;
821
- const info = this.#GetRotateValue(node);
916
+ this.#preventSizechange = true;
917
+ const info = GetRotateValue(node);
822
918
  const slope = info.r + (deg || 0) * 1;
823
919
  deg = Math.abs(slope) >= 360 ? 0 : slope;
824
- const isVertical = (this.isVertical = /^(90|270)$/.test(Math.abs(deg).toString()));
920
+ const isVertical = (this.isVertical = IsVertical(deg));
825
921
 
826
922
  width = numbers.get(width, 0);
827
923
  height = numbers.get(height, 0);
828
924
 
829
925
  const element = /** @type {HTMLElement} */ (node);
830
926
  const dataSize = (element.getAttribute('data-se-size') || 'auto,auto').split(',');
927
+ if (isVertical) this._setRotate(element, deg, info.x, info.y);
928
+
831
929
  let transOrigin = '';
832
930
  if (/auto|%$/.test(dataSize[0]) && !isVertical) {
833
931
  if (dataSize[0] === 'auto' && dataSize[1] === 'auto') {
@@ -843,11 +941,13 @@ class Figure extends EditorInjector {
843
941
  const w = (isVertical ? offsetH : offsetW) + 'px';
844
942
  const h = (isVertical ? offsetW : offsetH) + 'px';
845
943
 
846
- this._deletePercentSize();
944
+ this.#deletePercentSize();
847
945
  this._applySize(offsetW + 'px', offsetH + 'px', '');
848
946
 
849
- cover.style.width = w;
850
- cover.style.height = figureInfo.caption || figureInfo.inlineCover ? '' : h;
947
+ if (cover) {
948
+ cover.style.width = w;
949
+ cover.style.height = figureInfo.caption || figureInfo.inlineCover ? '' : h;
950
+ }
851
951
 
852
952
  if (isVertical) {
853
953
  const transW = offsetW / 2 + 'px ' + offsetW / 2 + 'px 0';
@@ -857,23 +957,65 @@ class Figure extends EditorInjector {
857
957
  }
858
958
 
859
959
  element.style.transformOrigin = transOrigin;
860
- this._setRotate(element, deg, info.x, info.y);
960
+ if (!isVertical) this._setRotate(element, deg, info.x, info.y);
861
961
 
862
962
  if (isVertical) element.style.maxWidth = 'none';
863
963
  else element.style.maxWidth = '';
864
964
 
865
- this._setCaptionPosition(element);
965
+ this.#setCaptionPosition(element);
866
966
  } finally {
867
- this.__preventSizechange = false;
967
+ this.#preventSizechange = false;
968
+ }
969
+ }
970
+
971
+ /**
972
+ * @internal
973
+ * @description Displays or hides the resize handles of the figure component.
974
+ * @param {boolean} display Whether to display resize handles.
975
+ */
976
+ _displayResizeHandles(display) {
977
+ const type = !display ? 'none' : 'flex';
978
+ if (this.controller) this.controller.form.style.display = type;
979
+
980
+ const _figure = this.#$.frameContext.get('_figure');
981
+ const resizeHandles = _figure.handles;
982
+ for (let i = 0, len = resizeHandles.length; i < len; i++) {
983
+ resizeHandles[i].style.display = type;
984
+ }
985
+
986
+ if (type === 'none') {
987
+ dom.utils.addClass(_figure.main, 'se-resize-ing');
988
+ this.#onResizeESCEvent = this.#$.eventManager.addGlobalEvent('keydown', this.#containerResizingESC);
989
+ } else {
990
+ dom.utils.removeClass(_figure.main, 'se-resize-ing');
991
+ }
992
+ }
993
+
994
+ /**
995
+ * @description Handles format conversion (`block`/`inline`) for the figure component and applies size changes.
996
+ * @param {FigureInfo} figureinfo `{target, container, cover, inlineCover, caption}`
997
+ * @param {string|number} w Width value.
998
+ * @param {string|number} h Height value.
999
+ */
1000
+ #asFormatChange(figureinfo, w, h) {
1001
+ const kind = this.kind;
1002
+ figureinfo.target.onload = () => this.#$.component.select(figureinfo.target, kind);
1003
+
1004
+ this.#setFigureInfo(figureinfo);
1005
+
1006
+ if (figureinfo.inlineCover) {
1007
+ this.setAlign(figureinfo.target, 'none');
1008
+ this.deleteTransform();
868
1009
  }
1010
+
1011
+ this.setFigureSize(w, h);
869
1012
  }
870
1013
 
871
1014
  /**
872
- * @private
873
1015
  * @description Sets figure component properties such as cover, container, caption, and alignment.
874
- * @param {FigureInfo} figureInfo - {target, container, cover, inlineCover, caption}
1016
+ * @param {FigureInfo} figureInfo - `{target, container, cover, inlineCover, caption, isVertical}`
875
1017
  */
876
- _setFigureInfo(figureInfo) {
1018
+ #setFigureInfo(figureInfo) {
877
1019
  this._inlineCover = figureInfo.inlineCover;
878
1020
  this._cover = figureInfo.cover || this._inlineCover;
879
1021
  this._container = figureInfo.container;
@@ -881,11 +1023,11 @@ class Figure extends EditorInjector {
881
1023
  this._element = figureInfo.target;
882
1024
  this.align = (this._container.className.match(/(?:^|\s)__se__float-(none|left|center|right)(?:$|\s)/) || [])[1] || figureInfo.target.style.float || 'none';
883
1025
  this.as = this._inlineCover ? 'inline' : 'block';
884
- this.isVertical = /^(90|270)$/.test(Math.abs(this.#GetRotateValue(figureInfo.target).r).toString());
1026
+ this.isVertical = IsVertical(figureInfo.target);
885
1027
  }
886
1028
 
887
1029
  /**
888
- * @private
1030
+ * @internal
889
1031
  * @description Applies rotation transformation to the target element.
890
1032
  * @param {HTMLElement} element Target element.
891
1033
  * @param {number} r Rotation degree.
@@ -927,7 +1069,7 @@ class Figure extends EditorInjector {
927
1069
  }
928
1070
 
929
1071
  /**
930
- * @private
1072
+ * @internal
931
1073
  * @description Applies size adjustments to the figure element.
932
1074
  * @param {string|number} w Width value.
933
1075
  * @param {string|number} h Height value.
@@ -939,18 +1081,18 @@ class Figure extends EditorInjector {
939
1081
  h = /** @type {string} */ (h || (this.autoRatio ? this.autoRatio.current || this.autoRatio.default : h));
940
1082
  w = /** @type {string} */ (numbers.is(w) ? w + this.sizeUnit : w);
941
1083
 
942
- if (!/%$/.test(w) && !/%$/.test(h) && !onlyW && !onlyH) this._deletePercentSize();
1084
+ if (!/%$/.test(w) && !/%$/.test(h) && !onlyW && !onlyH) this.#deletePercentSize();
943
1085
 
944
1086
  const sizeTarget = this._cover || this._element;
945
1087
 
946
- if (this.autoRatio) this._cover.style.width = w;
1088
+ if (this.autoRatio && this._cover) this._cover.style.width = w;
947
1089
  if (!onlyH) {
948
1090
  sizeTarget.style.width = this._element.style.width = w;
949
1091
  }
950
1092
  if (!onlyW) {
951
1093
  h = numbers.is(h) ? h + this.sizeUnit : h;
952
1094
  sizeTarget.style.height = this._element.style.height = this.autoRatio && !this.isVertical ? '100%' : h;
953
- if (this.autoRatio) {
1095
+ if (this.autoRatio && this._cover) {
954
1096
  this._cover.style.height = h;
955
1097
  this.__setCoverPaddingBottom(w, h);
956
1098
  }
@@ -959,11 +1101,11 @@ class Figure extends EditorInjector {
959
1101
  if (this.align === 'center') this.setAlign(this._element, this.align);
960
1102
 
961
1103
  // save current size
962
- this._saveCurrentSize();
1104
+ this.#saveCurrentSize();
963
1105
  }
964
1106
 
965
1107
  /**
966
- * @private
1108
+ * @internal
967
1109
  * @description Sets padding-bottom for cover elements based on width and height.
968
1110
  * @param {string} w Width value.
969
1111
  * @param {string} h Height value.
@@ -971,6 +1113,10 @@ class Figure extends EditorInjector {
971
1113
  __setCoverPaddingBottom(w, h) {
972
1114
  if (this._inlineCover === this._cover) return;
973
1115
 
1116
+ if (this.isVertical) {
1117
+ [w, h] = [h, w];
1118
+ }
1119
+
974
1120
  this._cover.style.height = h;
975
1121
  if (/%$/.test(w) && this.align === 'center') {
976
1122
  this._cover.style.paddingBottom = !/%$/.test(h) ? h : numbers.get((numbers.get(h, 2) / 100) * numbers.get(w, 2), 2) + '%';
@@ -980,13 +1126,13 @@ class Figure extends EditorInjector {
980
1126
  }
981
1127
 
982
1128
  /**
983
- * @private
1129
+ * @internal
984
1130
  * @description Sets the figure element to its auto size.
985
1131
  */
986
1132
  _setAutoSize() {
987
1133
  if (this._caption) this._caption.style.marginTop = '';
988
1134
  this.deleteTransform();
989
- this._deletePercentSize();
1135
+ this.#deletePercentSize();
990
1136
 
991
1137
  if (this.autoRatio) {
992
1138
  this._setPercentSize('100%', this.autoRatio.current || this.autoRatio.default);
@@ -994,24 +1140,26 @@ class Figure extends EditorInjector {
994
1140
  this._element.style.maxWidth = '';
995
1141
  this._element.style.width = '';
996
1142
  this._element.style.height = '';
997
- this._cover.style.width = '';
998
- this._cover.style.height = '';
1143
+ if (this._cover) {
1144
+ this._cover.style.width = '';
1145
+ this._cover.style.height = '';
1146
+ }
999
1147
  }
1000
1148
 
1001
1149
  this.setAlign(this._element, this.align);
1002
1150
 
1003
1151
  // save current size
1004
- this._saveCurrentSize();
1152
+ this.#saveCurrentSize();
1005
1153
  }
1006
1154
 
1007
1155
  /**
1008
- * @private
1156
+ * @internal
1009
1157
  * @description Sets the figure element's size in percentage.
1010
1158
  * @param {string|number} w Width percentage.
1011
1159
  * @param {string|number} h Height percentage.
1012
1160
  */
1013
1161
  _setPercentSize(w, h) {
1014
- if (!h) h = this.autoRatio ? (/%$/.test(this.autoRatio.current) ? this.autoRatio.current : this.autoRatio.default) : h;
1162
+ h ||= this.autoRatio ? (/%$/.test(this.autoRatio.current) ? this.autoRatio.current : this.autoRatio.default) : h;
1015
1163
  h = h && !/%$/.test(h + '') && !numbers.get(h, 0) ? (numbers.is(h) ? h + '%' : h) : numbers.is(h) ? h + this.sizeUnit : h || (this.autoRatio ? this.autoRatio.default : '');
1016
1164
 
1017
1165
  const heightPercentage = /%$/.test(h + '');
@@ -1019,15 +1167,16 @@ class Figure extends EditorInjector {
1019
1167
  this._container.style.height = '';
1020
1168
 
1021
1169
  // exceptionFormat
1022
- if (this._element === this._cover && !this.options.get('strictMode').formatFilter) {
1023
- this._saveCurrentSize();
1170
+ if (this._element === this._cover && !this.#$.options.get('strictMode').formatFilter) {
1171
+ this.#saveCurrentSize();
1024
1172
  return;
1025
1173
  }
1026
1174
 
1027
- if (this._inlineCover !== this._cover) {
1175
+ if (this._inlineCover !== this._cover && this._cover) {
1028
1176
  this._cover.style.width = '100%';
1029
1177
  this._cover.style.height = String(h);
1030
1178
  }
1179
+
1031
1180
  this._element.style.width = '100%';
1032
1181
  this._element.style.maxWidth = '';
1033
1182
  this._element.style.height = String(this.autoRatio ? '100%' : heightPercentage ? '' : h);
@@ -1037,64 +1186,63 @@ class Figure extends EditorInjector {
1037
1186
  this.__setCoverPaddingBottom(String(w), String(h));
1038
1187
  }
1039
1188
 
1040
- this._setCaptionPosition(this._element);
1189
+ this.#setCaptionPosition(this._element);
1041
1190
 
1042
1191
  // save current size
1043
- this._saveCurrentSize();
1192
+ this.#saveCurrentSize();
1044
1193
  }
1045
1194
 
1046
1195
  /**
1047
- * @private
1048
1196
  * @description Deletes percentage-based sizing from the figure element.
1049
1197
  */
1050
- _deletePercentSize() {
1051
- this._cover.style.width = '';
1052
- this._cover.style.height = '';
1198
+ #deletePercentSize() {
1199
+ if (this._cover) {
1200
+ this._cover.style.width = '';
1201
+ this._cover.style.height = '';
1202
+ }
1203
+
1053
1204
  this._container.style.width = '';
1054
1205
  this._container.style.height = '';
1055
1206
 
1056
- dom.utils.removeClass(this._container, this._floatClassStr);
1207
+ dom.utils.removeClass(this._container, this.#floatClassStr);
1057
1208
  dom.utils.addClass(this._container, '__se__float-' + this.align);
1058
1209
 
1059
1210
  if (this.align === 'center') this.setAlign(this._element, this.align);
1060
1211
  }
1061
1212
 
1062
1213
  /**
1063
- * @private
1214
+ * @internal
1064
1215
  * @description Reverts the figure element to its previously saved size.
1065
1216
  */
1066
1217
  _setRevert() {
1067
- this.setSize(this.__revertSize.w, this.__revertSize.h);
1218
+ this.setFigureSize(this.#revertSize.w, this.#revertSize.h);
1068
1219
  }
1069
1220
 
1070
1221
  /**
1071
- * @private
1072
1222
  * @description Updates the figure's alignment icon.
1073
1223
  */
1074
- _setAlignIcon() {
1224
+ #setAlignIcon() {
1075
1225
  if (!this.alignButton) return;
1076
1226
  dom.utils.changeElement(this.alignButton.firstElementChild, this._alignIcons[this.align]);
1077
1227
  }
1078
1228
 
1079
1229
  /**
1080
- * @private
1081
1230
  * @description Updates the figure's block/inline format icon.
1082
1231
  */
1083
- _setAsIcon() {
1232
+ #setAsIcon() {
1084
1233
  if (!this.asButton) return;
1085
- dom.utils.changeElement(this.asButton.firstElementChild, this.icons[`as_${this.as}`]);
1234
+ dom.utils.changeElement(this.asButton.firstElementChild, this.#$.icons[`as_${this.as}`]);
1086
1235
  }
1087
1236
 
1088
1237
  /**
1089
- * @private
1090
1238
  * @description Saves the current size of the figure component.
1091
1239
  */
1092
- _saveCurrentSize() {
1093
- if (this.__preventSizechange) return;
1240
+ #saveCurrentSize() {
1241
+ if (this.#preventSizechange) return;
1094
1242
 
1095
1243
  const dataSize = (this._element.getAttribute('data-se-size') || ',').split(',');
1096
- this.__revertSize.w = dataSize[0];
1097
- this.__revertSize.h = dataSize[1];
1244
+ this.#revertSize.w = dataSize[0];
1245
+ this.#revertSize.h = dataSize[1];
1098
1246
 
1099
1247
  const size = this.getSize(this._element);
1100
1248
  // add too width, height attribute
@@ -1107,23 +1255,26 @@ class Figure extends EditorInjector {
1107
1255
  }
1108
1256
 
1109
1257
  /**
1110
- * @private
1111
1258
  * @description Adjusts the position of the caption within the figure.
1112
1259
  * @param {HTMLElement} element Target element.
1113
1260
  */
1114
- _setCaptionPosition(element) {
1261
+ #setCaptionPosition(element) {
1115
1262
  const figcaption = /** @type {HTMLElement} */ (dom.query.getEdgeChild(dom.query.getParentElement(element, 'FIGURE'), 'FIGCAPTION', false));
1116
1263
  if (figcaption) {
1117
- figcaption.style.marginTop = (this.isVertical ? element.offsetWidth - element.offsetHeight : 0) + 'px';
1264
+ figcaption.style.marginTop = (this.isVertical && !this.autoRatio ? element.offsetWidth - element.offsetHeight : 0) + 'px';
1265
+ if (this.isVertical && this.autoRatio) {
1266
+ element.style.marginTop = figcaption.offsetHeight + 'px';
1267
+ } else {
1268
+ element.style.marginTop = '';
1269
+ }
1118
1270
  }
1119
1271
  }
1120
1272
 
1121
1273
  /**
1122
- * @private
1123
1274
  * @description Removes the margin top property from the figure caption.
1124
1275
  * @param {HTMLElement} element Target element.
1125
1276
  */
1126
- _deleteCaptionPosition(element) {
1277
+ #deleteCaptionPosition(element) {
1127
1278
  const figcaption = /** @type {HTMLElement} */ (dom.query.getEdgeChild(dom.query.getParentElement(element, 'FIGURE'), 'FIGCAPTION', false));
1128
1279
  if (figcaption) {
1129
1280
  figcaption.style.marginTop = '';
@@ -1131,50 +1282,32 @@ class Figure extends EditorInjector {
1131
1282
  }
1132
1283
 
1133
1284
  /**
1134
- * @private
1135
- * @description Displays or hides the resize handles of the figure component.
1136
- * @param {boolean} display Whether to display resize handles.
1285
+ * @description Removes the resize event listeners.
1137
1286
  */
1138
- _displayResizeHandles(display) {
1139
- const type = !display ? 'none' : 'flex';
1140
- this.controller.form.style.display = type;
1287
+ #offResizeEvent() {
1288
+ this.#$.component.__removeDragEvent();
1289
+ this.#removeGlobalEvents();
1141
1290
 
1142
- const _figure = this.editor.frameContext.get('_figure');
1143
- const resizeHandles = _figure.handles;
1144
- for (let i = 0, len = resizeHandles.length; i < len; i++) {
1145
- resizeHandles[i].style.display = type;
1146
- }
1147
-
1148
- if (type === 'none') {
1149
- dom.utils.addClass(_figure.main, 'se-resize-ing');
1150
- this.__onResizeESCEvent = this.eventManager.addGlobalEvent('keydown', this.__containerResizingESC);
1151
- } else {
1152
- dom.utils.removeClass(_figure.main, 'se-resize-ing');
1153
- }
1291
+ this._displayResizeHandles(true);
1292
+ this.#$.ui.offCurrentController();
1293
+ this.#$.ui.disableBackWrapper();
1154
1294
  }
1155
1295
 
1156
1296
  /**
1157
- * @private
1158
- * @description Removes the resize event listeners.
1297
+ * @description Removes global event listeners related to resizing.
1159
1298
  */
1160
- _offResizeEvent() {
1161
- this.component._removeDragEvent();
1162
- this.eventManager.removeGlobalEvent(this.__onContainerEvent);
1163
- this.eventManager.removeGlobalEvent(this.__offContainerEvent);
1164
- this.eventManager.removeGlobalEvent(this.__onResizeESCEvent);
1165
-
1166
- this._displayResizeHandles(true);
1167
- this.ui._offCurrentController();
1168
- this.ui.disableBackWrapper();
1299
+ #removeGlobalEvents() {
1300
+ this.#$.eventManager.removeGlobalEvent(this.__onContainerEvent);
1301
+ this.#$.eventManager.removeGlobalEvent(this.__offContainerEvent);
1302
+ this.#$.eventManager.removeGlobalEvent(this.#onResizeESCEvent);
1169
1303
  }
1170
1304
 
1171
1305
  /**
1172
- * @private
1173
1306
  * @description Sets up drag event handling for the figure component.
1174
1307
  * @param {Node} figureMain The main figure container element.
1175
1308
  */
1176
- _setDragEvent(figureMain) {
1177
- const dragHandle = this.editor.frameContext.get('wrapper').querySelector('.se-drag-handle');
1309
+ #setDragEvent(figureMain) {
1310
+ const dragHandle = /** @type {HTMLElement} */ (this.#$.frameContext.get('wrapper').querySelector('.se-drag-handle'));
1178
1311
  dom.utils.removeClass(dragHandle, 'se-drag-handle-full');
1179
1312
 
1180
1313
  dragHandle.style.opacity = '';
@@ -1197,8 +1330,8 @@ class Figure extends EditorInjector {
1197
1330
  */
1198
1331
  #OnScrollDragHandler(dragHandle, figureMain) {
1199
1332
  dragHandle.style.display = 'block';
1200
- dragHandle.style.left = figureMain.offsetLeft + (this.options.get('_rtl') ? dragHandle.offsetWidth : figureMain.offsetWidth - dragHandle.offsetWidth * 1.5) + 'px';
1201
- dragHandle.style.top = figureMain.offsetTop - dragHandle.offsetHeight + 'px';
1333
+ dragHandle.style.left = figureMain.offsetLeft + (this.#$.options.get('_rtl') ? dragHandle.offsetWidth : figureMain.offsetWidth - dragHandle.offsetWidth * 1.5) + 'px';
1334
+ dragHandle.style.top = figureMain.offsetTop - dragHandle.offsetHeight + 0.5 + 'px';
1202
1335
  }
1203
1336
 
1204
1337
  /**
@@ -1208,15 +1341,17 @@ class Figure extends EditorInjector {
1208
1341
  e.stopPropagation();
1209
1342
  e.preventDefault();
1210
1343
 
1211
- const eventTarget = dom.query.getEventTarget(e);
1212
1344
  const inst = _DragHandle.get('__figureInst');
1345
+ if (!inst) return;
1346
+
1347
+ const eventTarget = dom.query.getEventTarget(e);
1213
1348
  const direction = (inst._resize_direction = eventTarget.classList[0]);
1214
1349
  inst._resizeClientX = e.clientX;
1215
1350
  inst._resizeClientY = e.clientY;
1216
- inst.editor.frameContext.get('_figure').main.style.float = /l/.test(direction) ? 'right' : /r/.test(direction) ? 'left' : 'none';
1217
- this.ui.enableBackWrapper(DIRECTION_CURSOR_MAP[direction]);
1351
+ this.#$.frameContext.get('_figure').main.style.float = /l/.test(direction) ? 'right' : /r/.test(direction) ? 'left' : 'none';
1352
+ this.#$.ui.enableBackWrapper(DIRECTION_CURSOR_MAP[direction]);
1218
1353
 
1219
- const { w, h } = this.getSize(inst._element);
1354
+ const { w, h, dw, dh } = this.getSize(inst._element);
1220
1355
  __resizing_p_wh = __resizing_p_ow = false;
1221
1356
  __resizing_cw = __resizing_sw = 0;
1222
1357
  if (!this.isVertical) {
@@ -1231,17 +1366,17 @@ class Figure extends EditorInjector {
1231
1366
  if (__resizing_p_wh || __resizing_p_ow) {
1232
1367
  const sizeTarget = inst._cover || inst._element;
1233
1368
  __resizing_sw = sizeTarget.offsetWidth;
1234
- __resizing_cw = converter.getWidthInPercentage(sizeTarget, this.editor.frameContext.get('wysiwygFrame')) / 100;
1369
+ __resizing_cw = converter.getWidthInPercentage(sizeTarget, this.#$.frameContext.get('wysiwygFrame')) / 100;
1235
1370
  }
1236
1371
  }
1237
1372
 
1238
- inst.__onContainerEvent = inst.eventManager.addGlobalEvent('mousemove', inst.__containerResizing);
1239
- inst.__offContainerEvent = inst.eventManager.addGlobalEvent('mouseup', inst.__containerResizingOff);
1373
+ inst.__onContainerEvent = this.#$.eventManager.addGlobalEvent('mousemove', inst.__containerResizing);
1374
+ inst.__offContainerEvent = this.#$.eventManager.addGlobalEvent('mouseup', inst.__containerResizingOff);
1240
1375
  inst._displayResizeHandles(false);
1241
1376
 
1242
- const _display = this.editor.frameContext.get('_figure').display;
1377
+ const _display = this.#$.frameContext.get('_figure').display;
1243
1378
  _display.style.display = 'block';
1244
- dom.utils.changeTxt(_display, w + ' x ' + h);
1379
+ dom.utils.changeTxt(_display, dw + ' * ' + dh);
1245
1380
  }
1246
1381
 
1247
1382
  /**
@@ -1252,14 +1387,15 @@ class Figure extends EditorInjector {
1252
1387
  const direction = this._resize_direction;
1253
1388
  const clientX = e.clientX;
1254
1389
  const clientY = e.clientY;
1390
+ const v = this.isVertical;
1255
1391
 
1256
- let resultW = this._element_w;
1257
- let resultH = this._element_h;
1392
+ let resultW = v ? this.#element_h : this.#element_w;
1393
+ let resultH = v ? this.#element_w : this.#element_h;
1258
1394
 
1259
1395
  const w = resultW + (/r/.test(direction) ? clientX - this._resizeClientX : this._resizeClientX - clientX);
1260
1396
  const h = resultH + (/b/.test(direction) ? clientY - this._resizeClientY : this._resizeClientY - clientY);
1261
1397
  const wh = (resultH / resultW) * w;
1262
- const resizeBorder = this.editor.frameContext.get('_figure').border;
1398
+ const resizeBorder = this.#$.frameContext.get('_figure').border;
1263
1399
 
1264
1400
  if (/t/.test(direction)) resizeBorder.style.top = resultH - (/h/.test(direction) ? h : wh) + 'px';
1265
1401
  if (/l/.test(direction)) resizeBorder.style.left = resultW - w + 'px';
@@ -1277,29 +1413,32 @@ class Figure extends EditorInjector {
1277
1413
  resultH = h;
1278
1414
  }
1279
1415
 
1280
- this._resize_w = /** @type {number} */ (/h$/.test(direction) ? this._width : Math.round(resultW));
1281
- this._resize_h = /** @type {number} */ (/w$/.test(direction) ? this._height : Math.round(resultH));
1282
- const rw = __resizing_cw ? (this._resize_w / __resizing_sw) * __resizing_cw * 100 : this._resize_w;
1283
- dom.utils.changeTxt(this.editor.frameContext.get('_figure').display, __resizing_cw ? numbers.get(rw > 100 ? 100 : rw, 2).toFixed(2) + '%' : rw + ' x ' + this._resize_h);
1416
+ const resize_w = /** @type {number} */ (!v && /h$/.test(direction) ? this.#width : Math.round(resultW));
1417
+ const resize_h = /** @type {number} */ (!v && /w$/.test(direction) ? this.#height : Math.round(resultH));
1418
+ const rw = __resizing_cw ? (resize_w / __resizing_sw) * __resizing_cw * 100 : resize_w;
1419
+ dom.utils.changeTxt(this.#$.frameContext.get('_figure').display, __resizing_cw ? numbers.get(rw > 100 ? 100 : rw, 2).toFixed(2) + '%' : rw + ' * ' + resize_h);
1420
+
1421
+ this.#resize_w = resize_w;
1422
+ this.#resize_h = resize_h;
1284
1423
  }
1285
1424
 
1286
1425
  /**
1287
1426
  * @description Finalizes the resizing process of the figure container.
1288
1427
  */
1289
1428
  #ContainerResizingOff() {
1290
- this._offResizeEvent();
1429
+ this.#offResizeEvent();
1291
1430
 
1292
1431
  // set size
1293
- let w = this.isVertical ? this._resize_h : this._resize_w;
1294
- let h = this.isVertical ? this._resize_w : this._resize_h;
1432
+ let w = this.isVertical ? this.#resize_h : this.#resize_w;
1433
+ let h = this.isVertical ? this.#resize_w : this.#resize_h;
1295
1434
  w = Math.round(w) || w;
1296
1435
  h = Math.round(h) || h;
1297
1436
 
1298
1437
  if (!this.isVertical && !/%$/.test(w + '')) {
1299
1438
  const limit =
1300
- this.editor.frameContext.get('wysiwygFrame').clientWidth -
1301
- numbers.get(this.editor.frameContext.get('wwComputedStyle').getPropertyValue('padding-left')) +
1302
- numbers.get(this.editor.frameContext.get('wwComputedStyle').getPropertyValue('padding-right')) -
1439
+ this.#$.frameContext.get('wysiwygFrame').clientWidth -
1440
+ numbers.get(this.#$.frameContext.get('wwComputedStyle').getPropertyValue('padding-left')) +
1441
+ numbers.get(this.#$.frameContext.get('wwComputedStyle').getPropertyValue('padding-right')) -
1303
1442
  2;
1304
1443
  if (numbers.get(w, 0) > limit) {
1305
1444
  h = Math.round((h / w) * limit);
@@ -1317,8 +1456,8 @@ class Figure extends EditorInjector {
1317
1456
  if (this.isVertical) this.setTransform(this._element, w, h, 0);
1318
1457
  }
1319
1458
 
1320
- this.history.push(false);
1321
- this.component.select(this._element, this.kind);
1459
+ this.#$.history.push(false);
1460
+ this.#$.component.select(this._element, this.kind);
1322
1461
  }
1323
1462
 
1324
1463
  /**
@@ -1327,8 +1466,8 @@ class Figure extends EditorInjector {
1327
1466
  */
1328
1467
  #ContainerResizingESC(e) {
1329
1468
  if (!keyCodeMap.isEsc(e.code)) return;
1330
- this._offResizeEvent();
1331
- this.component.select(this._element, this.kind);
1469
+ this.#offResizeEvent();
1470
+ this.#$.component.select(this._element, this.kind);
1332
1471
  }
1333
1472
 
1334
1473
  /**
@@ -1337,7 +1476,7 @@ class Figure extends EditorInjector {
1337
1476
  #SetMenuAlign(value) {
1338
1477
  this.setAlign(this._element, value);
1339
1478
  this.selectMenu_align.close();
1340
- this.component.select(this._element, this.kind);
1479
+ this.#$.component.select(this._element, this.kind);
1341
1480
  }
1342
1481
 
1343
1482
  /**
@@ -1367,12 +1506,14 @@ class Figure extends EditorInjector {
1367
1506
  }
1368
1507
 
1369
1508
  this.selectMenu_resize.close();
1370
- this.component.select(this._element, this.kind);
1509
+ this.#$.component.select(this._element, this.kind);
1371
1510
  }
1372
1511
 
1373
1512
  #OffFigureContainer() {
1374
- this.editor.frameContext.get('_figure').main.style.display = 'none';
1375
- this.editor._figureContainer = null;
1513
+ const _figure = this.#$.frameContext.get('_figure');
1514
+ _figure.main.style.display = 'none';
1515
+ this.#$.ui.setFigureContainer(null);
1516
+ this.#$.ui.opendControllers = this.#$.ui.opendControllers.filter((c) => c.form !== _figure.main);
1376
1517
  }
1377
1518
 
1378
1519
  #OnClick_alignButton() {
@@ -1404,27 +1545,41 @@ class Figure extends EditorInjector {
1404
1545
 
1405
1546
  this.selectMenu_resize.open('', '[data-command="' + command + '"]');
1406
1547
  }
1548
+ }
1407
1549
 
1408
- /**
1409
- * @param {Node} element Target element
1410
- * @returns {{ r: *, x: *, y: * }} Rotation value
1411
- */
1412
- #GetRotateValue(element) {
1413
- const transform = /** @type {HTMLElement} */ (element).style.transform;
1414
- if (!transform) return { r: 0, x: '', y: '' };
1415
- return {
1416
- r: Number((transform.match(/rotate\(([-0-9]+)deg\)/) || [])[1] || 0),
1417
- x: (transform.match(/rotateX\(([-0-9]+)deg\)/) || [])[1] || '',
1418
- y: (transform.match(/rotateY\(([-0-9]+)deg\)/) || [])[1] || ''
1419
- };
1420
- }
1550
+ /**
1551
+ * @param {Node} element Target element
1552
+ * @returns {{ r: *, x: *, y: * }} Rotation value
1553
+ */
1554
+ function GetRotateValue(element) {
1555
+ const transform = /** @type {HTMLElement} */ (element).style.transform;
1556
+ if (!transform) return { r: 0, x: '', y: '' };
1557
+ return {
1558
+ r: Number((transform.match(/rotate\(([-0-9]+)deg\)/) || [])[1] || 0),
1559
+ x: (transform.match(/rotateX\(([-0-9]+)deg\)/) || [])[1] || '',
1560
+ y: (transform.match(/rotateY\(([-0-9]+)deg\)/) || [])[1] || '',
1561
+ };
1421
1562
  }
1422
1563
 
1423
- function CreateAlign(inst, button) {
1564
+ /**
1565
+ * @param {Node|number} elementOrDeg Target element
1566
+ * @returns {boolean} Whether to rotate vertically
1567
+ */
1568
+ function IsVertical(elementOrDeg) {
1569
+ return /^(90|270)$/.test(Math.abs(numbers.is(elementOrDeg) ? elementOrDeg : GetRotateValue(/** @type{Node} */ (elementOrDeg)).r).toString());
1570
+ }
1571
+
1572
+ /**
1573
+ * @param {Figure} inst - Figure instance
1574
+ * @param {SunEditor.Deps} $ - Kernel dependencies
1575
+ * @param {Element} button - Align button element
1576
+ * @returns {{html: string[], items: string[]}|null}
1577
+ */
1578
+ function CreateAlign(inst, $, button) {
1424
1579
  if (!button) return null;
1425
1580
 
1426
1581
  const icons = [inst._alignIcons.none, inst._alignIcons.left, inst._alignIcons.center, inst._alignIcons.right];
1427
- const langs = [inst.lang.basic, inst.lang.left, inst.lang.center, inst.lang.right];
1582
+ const langs = [$.lang.basic, $.lang.left, $.lang.center, $.lang.right];
1428
1583
  const commands = ['none', 'left', 'center', 'right'];
1429
1584
  const html = [];
1430
1585
  const items = [];
@@ -1442,11 +1597,16 @@ function CreateAlign(inst, button) {
1442
1597
  return { html: html, items: items };
1443
1598
  }
1444
1599
 
1445
- function CreateAs(inst, button) {
1600
+ /**
1601
+ * @param {SunEditor.Deps} $ - Kernel dependencies
1602
+ * @param {Element} button - As button element
1603
+ * @returns {{html: string[], items: string[]}|null}
1604
+ */
1605
+ function CreateAs($, button) {
1446
1606
  if (!button) return null;
1447
1607
 
1448
- const icons = [inst.icons.as_block, inst.icons.as_inline];
1449
- const langs = [inst.lang.asBlock, inst.lang.asInline];
1608
+ const icons = [$.icons.as_block, $.icons.as_inline];
1609
+ const langs = [$.lang.asBlock, $.lang.asInline];
1450
1610
  const commands = ['block', 'inline'];
1451
1611
  const html = [];
1452
1612
  const items = [];
@@ -1464,7 +1624,12 @@ function CreateAs(inst, button) {
1464
1624
  return { html: html, items: items };
1465
1625
  }
1466
1626
 
1467
- function CreateResize(editor, button) {
1627
+ /**
1628
+ * @param {SunEditor.Deps} $ - Kernel dependencies
1629
+ * @param {Element} button - Resize button element
1630
+ * @returns {{html: string[], items: string[]}|null}
1631
+ */
1632
+ function CreateResize($, button) {
1468
1633
  if (!button) return null;
1469
1634
 
1470
1635
  const items = button.getAttribute('data-value').split(',');
@@ -1473,13 +1638,16 @@ function CreateResize(editor, button) {
1473
1638
  v = items[i];
1474
1639
  n = numbers.is(v);
1475
1640
  c = n ? 'resize_percent' + v : 'auto';
1476
- l = n ? v + '%' : editor.lang.autoSize;
1641
+ l = n ? v + '%' : $.lang.autoSize;
1477
1642
  html.push('<button type="button" class="se-btn-list" data-command="' + c + '" data-value="' + v + '"><span>' + l + '</span></button>');
1478
1643
  }
1479
1644
 
1480
1645
  return { html: html, items: items };
1481
1646
  }
1482
1647
 
1648
+ /**
1649
+ * @returns {HTMLElement}
1650
+ */
1483
1651
  function CreateHTML_resizeDot() {
1484
1652
  const html = /*html*/ `
1485
1653
  <div class="se-resize-dot">
@@ -1497,6 +1665,10 @@ function CreateHTML_resizeDot() {
1497
1665
  return dom.utils.createElement('DIV', { class: 'se-controller se-resizing-container', style: 'display: none;' }, html);
1498
1666
  }
1499
1667
 
1668
+ /**
1669
+ * @param {string} group - Button group string (e.g. `"resize_100"`, `"rotate_l"`)
1670
+ * @returns {{c: string, v: *, l: string, t: *, i: string}|null}
1671
+ */
1500
1672
  function GET_CONTROLLER_BUTTONS(group) {
1501
1673
  const g = group.split('_');
1502
1674
  const command = g[0];
@@ -1571,15 +1743,21 @@ function GET_CONTROLLER_BUTTONS(group) {
1571
1743
  v: v,
1572
1744
  l: l,
1573
1745
  t: t,
1574
- i: i
1746
+ i: i,
1575
1747
  };
1576
1748
  }
1577
1749
 
1578
- function CreateHTML_controller(inst, controls) {
1750
+ /**
1751
+ * @param {Figure} inst - Figure instance
1752
+ * @param {SunEditor.Deps} $ - Kernel dependencies
1753
+ * @param {FigureControls} controls - Controller button array
1754
+ * @returns {HTMLElement|null}
1755
+ */
1756
+ function CreateHTML_controller(inst, $, controls) {
1579
1757
  let html = null;
1580
1758
 
1581
1759
  if (controls?.length > 0) {
1582
- const { lang, icons } = inst;
1760
+ const { lang, icons } = $;
1583
1761
  html = '<div class="se-arrow se-arrow-up"></div>';
1584
1762
  for (let i = 0, group; i < controls.length; i++) {
1585
1763
  group = controls[i];
@@ -1587,17 +1765,17 @@ function CreateHTML_controller(inst, controls) {
1587
1765
  for (let j = 0, len = group.length, m; j < len; j++) {
1588
1766
  m = group[j];
1589
1767
 
1590
- if (typeof m?.action === 'function') {
1591
- const g = m;
1768
+ if (typeof (/** @type {ControlCustomAction} */ (m)?.action) === 'function') {
1769
+ const g = /** @type {ControlCustomAction} */ (m);
1592
1770
  m = {
1593
1771
  c: `__c__${g.command}`,
1594
1772
  v: g.value || '',
1595
1773
  l: g.title,
1596
- i: g.icon
1774
+ i: g.icon,
1597
1775
  };
1598
1776
  inst._action[m.c] = g.action;
1599
1777
  } else {
1600
- m = GET_CONTROLLER_BUTTONS(m);
1778
+ m = GET_CONTROLLER_BUTTONS(/** @type {string} */ (m));
1601
1779
  if (!m) continue;
1602
1780
  }
1603
1781
 
@@ -1611,7 +1789,9 @@ function CreateHTML_controller(inst, controls) {
1611
1789
  }
1612
1790
  }
1613
1791
 
1614
- return dom.utils.createElement('DIV', { class: 'se-controller se-controller-resizing' + (!html ? ' se-empty-controller' : '') }, html);
1792
+ if (!html) return null;
1793
+
1794
+ return dom.utils.createElement('DIV', { class: 'se-controller se-controller-resizing' }, html);
1615
1795
  }
1616
1796
 
1617
1797
  export default Figure;