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
@@ -0,0 +1,970 @@
1
+ import { dom, env, numbers, unicode, keyCodeMap, converter } from '../../../helper';
2
+ import { Figure } from '../../../modules/contract';
3
+ import { _DragHandle } from '../../../modules/ui';
4
+
5
+ const { _w, ON_OVER_COMPONENT, isMobile } = env;
6
+ const DIR_KEYCODE = /^Arrow(Left|Up|Right|Down)$/;
7
+ const DIR_UP_KEYCODE = /^Arrow(Left|Up)$/;
8
+
9
+ /**
10
+ * @description Class for managing components such as images and tables that are not in `line` format
11
+ */
12
+ class Component {
13
+ #kernel;
14
+ #$;
15
+ #store;
16
+
17
+ #contextProvider;
18
+ #carrierWrapper;
19
+ #options;
20
+ #frameContext;
21
+ #eventManager;
22
+
23
+ /** @type {Object<string, (...args: *) => *>} */
24
+ #globalEvents;
25
+ /** @type {?SunEditor.Event.GlobalInfo} */
26
+ #bindClose_copy = null;
27
+ /** @type {?SunEditor.Event.GlobalInfo} */
28
+ #bindClose_cut = null;
29
+ /** @type {?SunEditor.Event.GlobalInfo} */
30
+ #bindClose_keydown = null;
31
+ /** @type {?SunEditor.Event.GlobalInfo} */
32
+ #bindClose_mousedown = null;
33
+
34
+ /**
35
+ * @constructor
36
+ * @param {SunEditor.Kernel} kernel
37
+ */
38
+ constructor(kernel) {
39
+ this.#kernel = kernel;
40
+ this.#$ = kernel.$;
41
+ this.#store = kernel.store;
42
+
43
+ this.#contextProvider = this.#$.contextProvider;
44
+ this.#carrierWrapper = this.#contextProvider.carrierWrapper;
45
+ this.#options = this.#$.options;
46
+ this.#frameContext = this.#$.frameContext;
47
+ this.#eventManager = this.#$.eventManager;
48
+
49
+ /**
50
+ * @description The current component information, used copy, cut, and keydown events
51
+ * @type {SunEditor.ComponentInfo}
52
+ */
53
+ this.info = null;
54
+
55
+ /**
56
+ * @description Component is selected
57
+ * @type {boolean}
58
+ */
59
+ this.isSelected = false;
60
+
61
+ /**
62
+ * @description Currently selected component target
63
+ * @type {?Node}
64
+ */
65
+ this.currentTarget = null;
66
+
67
+ /**
68
+ * @description Currently selected component plugin instance
69
+ * @type {*}
70
+ */
71
+ this.currentPlugin = null;
72
+
73
+ /**
74
+ * @description Currently selected component plugin name
75
+ * @type {*}
76
+ */
77
+ this.currentPluginName = '';
78
+
79
+ /**
80
+ * @description Currently selected component information
81
+ * @type {?SunEditor.ComponentInfo}
82
+ */
83
+ this.currentInfo = null;
84
+
85
+ this.#globalEvents = {
86
+ copy: this.#OnCopy_component.bind(this),
87
+ cut: this.#OnCut_component.bind(this),
88
+ keydown: this.#OnKeyDown_component.bind(this),
89
+ mousedown: this.#CloseListener_mousedown.bind(this),
90
+ };
91
+
92
+ /** @internal */
93
+ this.__selectionSelected = false;
94
+ /** @internal */
95
+ this.__prevent = false;
96
+ }
97
+
98
+ /**
99
+ * @description Initialize eventManager reference after EventManager is created.
100
+ */
101
+ _init() {
102
+ this.#contextProvider.applyToRoots((e) => {
103
+ // drag
104
+ const dragHandle = dom.utils.createElement('DIV', { class: 'se-drag-handle', draggable: 'true' }, this.#contextProvider.icons.selection);
105
+ e.get('wrapper').appendChild(dragHandle);
106
+ this.#eventManager.addEvent(dragHandle, 'mouseenter', this.#OnDragEnter.bind(this));
107
+ this.#eventManager.addEvent(dragHandle, 'mouseleave', this.#OnDragLeave.bind(this));
108
+ this.#eventManager.addEvent(dragHandle, 'dragstart', this.#OnDragStart.bind(this));
109
+ this.#eventManager.addEvent(dragHandle, 'dragend', this.#OnDragEnd.bind(this));
110
+ this.#eventManager.addEvent(dragHandle, 'click', this.#OnDragClick.bind(this));
111
+ });
112
+ }
113
+
114
+ /**
115
+ * @description Inserts an element and returns it. (Used for elements: table, hr, image, video)
116
+ * - If `element` is `HR`, inserts and returns the new line.
117
+ * @param {Node} element Element to be inserted
118
+ * @param {Object} [options] Options
119
+ * @param {boolean} [options.skipCharCount=false] If `true`, it will be inserted even if `frameOptions.get('charCounter_max')` is exceeded.
120
+ * @param {boolean} [options.skipHistory=false] If `true`, do not push to history.
121
+ * @param {boolean} [options.scrollTo=true] `true` : Scroll to the inserted element, `false` : Do not scroll.
122
+ * @param {SunEditor.ComponentInsertType} [options.insertBehavior] If `true`, do not automatically select the inserted component. [default: `options.get('componentInsertBehavior')`]
123
+ * - If `null`, no action is performed after insertion.
124
+ * @returns {HTMLElement} The inserted element or new line (for HR)
125
+ */
126
+ insert(element, { skipCharCount = false, skipHistory = false, scrollTo = true, insertBehavior } = {}) {
127
+ if (this.#frameContext.get('isReadOnly') || (!skipCharCount && !this.#$.char.check(element))) {
128
+ return null;
129
+ }
130
+
131
+ if (insertBehavior === undefined) insertBehavior = this.#options.get('componentInsertBehavior');
132
+
133
+ const r = this.#$.html.remove();
134
+ const isInline = this.isInline(element);
135
+ this.#$.selection.getRangeAndAddLine(this.#$.selection.getRange(), r.container);
136
+ const selectionNode = this.#$.selection.getNode();
137
+ let oNode = null;
138
+ let formatEl = this.#$.format.getLine(selectionNode, null);
139
+
140
+ try {
141
+ if (dom.check.isListCell(formatEl)) {
142
+ this.#$.html.insertNode(element, { afterNode: isInline ? null : !dom.check.isZeroWidth(selectionNode) ? null : (selectionNode || r.container || {}).nextSibling, skipCharCount: true });
143
+ if (!isInline && !element.nextSibling) element.parentNode.appendChild(dom.utils.createElement('BR'));
144
+ } else {
145
+ if (!isInline && this.#$.selection.getRange().collapsed && (r.container?.nodeType === 3 || dom.check.isBreak(r.container))) {
146
+ const depthFormat = dom.query.getParentElement(r.container, this.#$.format.isBlock.bind(this.#$.format));
147
+ oNode = this.#$.nodeTransform.split(r.container, r.offset, !depthFormat ? 0 : dom.query.getNodeDepth(depthFormat) + 1);
148
+ if (oNode) formatEl = /** @type {HTMLElement} */ (oNode.previousSibling);
149
+ }
150
+ this.#$.html.insertNode(element, { afterNode: isInline ? null : this.#$.format.isBlock(formatEl) ? null : formatEl, skipCharCount: true });
151
+ if (!isInline && formatEl && dom.check.isZeroWidth(formatEl)) dom.utils.removeItem(formatEl);
152
+ }
153
+
154
+ if (isInline) {
155
+ const empty = dom.utils.createTextNode(unicode.zeroWidthSpace);
156
+ element.parentNode.insertBefore(empty, element.nextSibling);
157
+ }
158
+ } catch (e) {
159
+ console.error('Component insert error:', e);
160
+ }
161
+
162
+ if (!skipHistory) this.#$.history.push(false);
163
+
164
+ // document type
165
+ if (this.#frameContext.has('documentType_use_header')) {
166
+ this.#frameContext.get('documentType').reHeader();
167
+ }
168
+
169
+ const targetElement = /** @type {HTMLElement} */ (oNode || element);
170
+
171
+ if (scrollTo) this.#$.selection.scrollTo(targetElement, { behavior: 'auto' });
172
+ if (insertBehavior !== null) this.applyInsertBehavior(element, oNode, insertBehavior);
173
+
174
+ return targetElement;
175
+ }
176
+
177
+ /**
178
+ * @description Handles post-insertion behavior for a newly created component based on the specified mode.
179
+ * @param {Node} container The inserted component element.
180
+ * @param {?Node} [oNode] Optional node to use for selection if the component cannot be selected.
181
+ * @param {SunEditor.ComponentInsertType} [insertBehavior] Behavior mode after component insertion.
182
+ */
183
+ applyInsertBehavior(container, oNode, insertBehavior) {
184
+ const cInfo = this.get(container);
185
+
186
+ if (this.isInline(container)) {
187
+ const nr = this.#$.selection.getNearRange(container);
188
+ if (nr) {
189
+ this.#$.selection.setRange(nr.container, nr.offset, nr.container, nr.offset);
190
+ } else {
191
+ this.select(cInfo.target, cInfo.pluginName);
192
+ }
193
+ return;
194
+ }
195
+
196
+ switch (insertBehavior) {
197
+ case 'auto': {
198
+ if (!this.#moveToNextLineOrAdd(container)) {
199
+ this.select(cInfo.target, cInfo.pluginName);
200
+ }
201
+
202
+ break;
203
+ }
204
+ case 'select': {
205
+ this.#$.selection.setRange(container, 0, container, 0);
206
+
207
+ if (cInfo) {
208
+ this.select(cInfo.target, cInfo.pluginName);
209
+ } else if (oNode) {
210
+ oNode = dom.query.getEdgeChildNodes(oNode, null).sc || oNode;
211
+ this.#$.selection.setRange(oNode, 0, oNode, 0);
212
+ }
213
+ break;
214
+ }
215
+ case 'line': {
216
+ if (!this.#moveToNextLineOrAdd(container)) {
217
+ const line = this.#$.format.addLine(container, null);
218
+ if (line) this.#$.selection.setRange(line, 0, line, 0);
219
+ }
220
+
221
+ break;
222
+ }
223
+ case 'none': {
224
+ // Do not select the component and remove the editor focus
225
+ break;
226
+ }
227
+ }
228
+ }
229
+
230
+ /**
231
+ * @description Gets the file component and that plugin name
232
+ * - return: {target, component, pluginName} | null
233
+ * @param {Node} element Target element (figure tag, component div, file tag)
234
+ * @returns {SunEditor.ComponentInfo|null}
235
+ */
236
+ get(element) {
237
+ if (!element) return null;
238
+
239
+ let target;
240
+ let pluginName = '';
241
+ let options = {};
242
+ let isFile = false;
243
+ let launcher = null;
244
+
245
+ if (this.is(element)) {
246
+ if (dom.check.isComponentContainer(element) && !dom.utils.hasClass(element, 'se-inline-component')) element = /** @type {HTMLElement} */ (element).firstElementChild || element;
247
+ if (/^FIGURE$/i.test(element.nodeName)) element = /** @type {HTMLElement} */ (element).firstElementChild;
248
+ if (!element) return null;
249
+
250
+ const comp = this.#$.pluginManager.findComponentInfo(element);
251
+ if (!comp) return null;
252
+ target = comp.target;
253
+ pluginName = comp.pluginName;
254
+ options = comp.options;
255
+ launcher = comp.launcher;
256
+ }
257
+
258
+ if (!target && element.nodeName) {
259
+ if (this.#isFiles(element)) {
260
+ isFile = true;
261
+ }
262
+ const comp = this.#$.pluginManager.findComponentInfo(element);
263
+ if (!comp) return null;
264
+ target = comp.target;
265
+ pluginName = comp.pluginName;
266
+ options = comp.options;
267
+ launcher = comp.launcher;
268
+ }
269
+
270
+ if (!target) {
271
+ return null;
272
+ }
273
+
274
+ const figureInfo = Figure.GetContainer(target);
275
+ const container = figureInfo.container || figureInfo.cover || target;
276
+ return (this.info = {
277
+ target: figureInfo.target,
278
+ pluginName,
279
+ options,
280
+ container: container,
281
+ cover: figureInfo.cover,
282
+ inlineCover: figureInfo.inlineCover,
283
+ caption: figureInfo.caption,
284
+ isFile,
285
+ launcher,
286
+ isInputType: dom.utils.hasClass(container, 'se-input-component'),
287
+ });
288
+ }
289
+
290
+ /**
291
+ * @description The component(media, file component, table, etc) is selected and the resizing module is called.
292
+ * @param {Node} element Target element
293
+ * @param {string} pluginName The plugin name for the selected target.
294
+ * @param {Object} [options] Options
295
+ * @param {boolean} [options.isInput=false] Whether the target is an input component (table).
296
+ */
297
+ select(element, pluginName, { isInput = false } = {}) {
298
+ const info = this.get(element);
299
+ if (!info || dom.check.isUneditable(dom.query.getParentElement(element, this.is.bind(this))) || dom.check.isUneditable(element)) return false;
300
+
301
+ const plugin = info.launcher || this.#$.plugins[pluginName];
302
+ if (!plugin) return;
303
+
304
+ const notOver = _DragHandle.get('__overInfo') !== ON_OVER_COMPONENT;
305
+ if (!isInput && notOver) {
306
+ if (this.#store.get('_mousedown')) return;
307
+
308
+ this.#store.set('_preventBlur', true);
309
+ this.__selectionSelected = true;
310
+ if (this.isInline(info.container)) {
311
+ this.#$.selection.setRange(info.container, 0, info.container, 0);
312
+ }
313
+ this.#$.focusManager.blur();
314
+ // Defer flag reset — blur event fires synchronously and checks __selectionSelected to distinguish component-initiated blur
315
+ _w.setTimeout(() => {
316
+ this.__selectionSelected = false;
317
+ });
318
+ }
319
+
320
+ this.isSelected = true;
321
+ this.__prevent = true;
322
+
323
+ let isNonFigureComponent;
324
+ if (typeof plugin.componentSelect === 'function') isNonFigureComponent = plugin.componentSelect(element);
325
+
326
+ const isBreakComponent = dom.utils.hasClass(info.target, 'se-component-line-break');
327
+ if (isBreakComponent || (!isNonFigureComponent && !dom.utils.hasClass(info.container, 'se-inline-component'))) this._setComponentLineBreaker(/** @type {HTMLElement} */ (info.container || info.cover || element));
328
+
329
+ this.currentTarget = element;
330
+ this.currentPlugin = plugin;
331
+ this.currentPluginName = pluginName;
332
+ this.currentInfo = info;
333
+
334
+ _DragHandle.set('__dragInst', this);
335
+
336
+ const __overInfo = _DragHandle.get('__overInfo');
337
+ // Defer drag handle setup — let the current click/mousedown event complete before attaching global listeners
338
+ _w.setTimeout(() => {
339
+ _DragHandle.set('__overInfo', __overInfo === ON_OVER_COMPONENT ? undefined : false);
340
+ if (__overInfo !== ON_OVER_COMPONENT) this.#addGlobalEvent();
341
+ if (!info.isFile) this.#addNotFileGlobalEvent();
342
+ }, 0);
343
+
344
+ converter.debounce(() => {
345
+ dom.utils.addClass(info.container, 'se-component-selected');
346
+ }, 0)();
347
+
348
+ if (notOver && !this.#store.get('hasFocus') && !this.#store.get('_preventFocus')) {
349
+ this.#kernel._eventOrchestrator.__postFocusEvent(this.#frameContext, null);
350
+ this.#store.set('_preventFocus', true);
351
+ }
352
+
353
+ if (!isBreakComponent && __overInfo !== ON_OVER_COMPONENT) {
354
+ // set zero width space
355
+ if (!this.isInline(info.container)) return;
356
+
357
+ const oNode = info.container;
358
+ let zeroWidth = null;
359
+ if (!oNode.previousSibling || dom.check.isBreak(oNode.previousSibling)) {
360
+ zeroWidth = dom.utils.createTextNode(unicode.zeroWidthSpace);
361
+ oNode.parentNode.insertBefore(zeroWidth, oNode);
362
+ }
363
+
364
+ if (!oNode.nextSibling || dom.check.isBreak(oNode.nextSibling)) {
365
+ zeroWidth = dom.utils.createTextNode(unicode.zeroWidthSpace);
366
+ oNode.parentNode.insertBefore(zeroWidth, oNode.nextSibling);
367
+ }
368
+
369
+ this.#store.set('controlActive', true);
370
+ } else if (isBreakComponent || !dom.utils.hasClass(info.container, 'se-input-component')) {
371
+ const dragHandle = /** @type {HTMLElement} */ (this.#frameContext.get('wrapper').querySelector('.se-drag-handle'));
372
+ dom.utils.addClass(dragHandle, 'se-drag-handle-full');
373
+ this.#$.ui._visibleControllers(false, false);
374
+
375
+ const sizeTarget = info.caption ? info.target : info.cover || info.container || info.target;
376
+ const w = sizeTarget.offsetWidth;
377
+ const h = sizeTarget.offsetHeight;
378
+ const { top, left } = this.#$.offset.getLocal(sizeTarget);
379
+
380
+ dragHandle.style.opacity = '0';
381
+ dragHandle.style.width = w + 'px';
382
+ dragHandle.style.height = h + 'px';
383
+ dragHandle.style.top = top + 'px';
384
+ dragHandle.style.left = left + 'px';
385
+
386
+ _DragHandle.set('__dragHandler', dragHandle);
387
+ _DragHandle.set('__dragContainer', info.container);
388
+ _DragHandle.set('__dragCover', info.cover);
389
+
390
+ dragHandle.style.display = 'block';
391
+ }
392
+ }
393
+
394
+ /**
395
+ * @description Deselects the selected component.
396
+ */
397
+ deselect() {
398
+ // Defer controlActive reset — synchronous blur handlers during deselect still need to see it as active
399
+ _w.setTimeout(() => {
400
+ this.#store.set('controlActive', false);
401
+ }, 0);
402
+ this.__deselect();
403
+ this.#$.ui.setControllerOnDisabledButtons(false);
404
+
405
+ if (this.#store.get('_preventFocus') && !this.#store.get('hasFocus') && !this.__prevent) {
406
+ this.#kernel._eventOrchestrator.__postBlurEvent(this.#frameContext, null);
407
+ this.#store.set('_preventFocus', false);
408
+ }
409
+ }
410
+
411
+ /**
412
+ * @description Determines if the specified node is a block component (e.g., img, iframe, video, audio, table) with the class `se-component`
413
+ * - or a direct `FIGURE` node. This function checks if the node itself is a component
414
+ * - or if it belongs to any components identified by the component manager.
415
+ * @param {Node} element The DOM node to check.
416
+ * @returns {boolean} True if the node is a block component or part of it, otherwise false.
417
+ */
418
+ is(element) {
419
+ if (!element) return false;
420
+
421
+ if (/^FIGURE$/i.test(element.nodeName) || dom.check.isComponentContainer(element)) return true;
422
+ if (this.#$.pluginManager.findComponentInfo(element)) return true;
423
+
424
+ return false;
425
+ }
426
+
427
+ /**
428
+ * @description Checks if the given node is an inline component (class `se-inline-component`).
429
+ * - If the node is a `FIGURE`, it checks the parent element instead.
430
+ * - It also verifies whether the node is part of an inline component recognized by the component manager.
431
+ * @param {Node} element The DOM node to check.
432
+ * @returns {boolean} True if the node is an inline component or part of it, otherwise false.
433
+ */
434
+ isInline(element) {
435
+ if (!element) return false;
436
+
437
+ if (/^FIGURE$/i.test(element.nodeName)) element = element.parentElement;
438
+ if (dom.utils.hasClass(element, 'se-inline-component')) return true;
439
+
440
+ const comp = this.#$.pluginManager.findComponentInfo(element);
441
+ if (comp && (dom.utils.hasClass(element, 'se-inline-component') || dom.utils.hasClass(element.parentElement, 'se-inline-component'))) return true;
442
+
443
+ return false;
444
+ }
445
+
446
+ /**
447
+ * @description Checks if the specified node qualifies as a basic component within the editor.
448
+ * - This function verifies whether the node is recognized as a component by the `is` function, while also ensuring that it is not an inline component as determined by the `isInline` function.
449
+ * - This is used to identify block-level elements or standalone components that are not part of the inline component classification.
450
+ * @param {Node} element The DOM node to check.
451
+ * @returns {boolean} True if the node is a basic (non-inline) component, otherwise false.
452
+ */
453
+ isBasic(element) {
454
+ return this.is(element) && !this.isInline(element);
455
+ }
456
+
457
+ /**
458
+ * @description Copies the specified component node to the clipboard.
459
+ * - This function is different from the one called when the user presses the `Ctrl + C` key combination.
460
+ * @param {Node} container The DOM node to check.
461
+ */
462
+ async copy(container) {
463
+ const cloneContainer = /** @type {HTMLElement} */ (dom.utils.clone(container, true));
464
+
465
+ RemoveSelectedClass(cloneContainer);
466
+
467
+ // copy to clipboard
468
+ if ((await this.#$.html.copy(cloneContainer)) === false) return;
469
+
470
+ // copy effect
471
+ dom.utils.flashClass(container, 'se-copy');
472
+ }
473
+
474
+ /**
475
+ * @description Temporarily selects a component without showing its controller.
476
+ * This is a lightweight selection mode used for:
477
+ * - Mouse hover: Shows visual selection while hovering, auto-deselects on mouse out
478
+ * - Table column/row resize: Maintains selection after resize without showing controller
479
+ *
480
+ * Key differences from `select()`:
481
+ * - Does NOT show the component's controller (resize handles, toolbar, etc.)
482
+ * - Sets `__overInfo` flag so selection is automatically cleared on mouse out
483
+ * - Calling `select()` afterward will upgrade to full selection with controller
484
+ *
485
+ * @param {Element} target The element to hover-select
486
+ */
487
+ hoverSelect(target) {
488
+ const figure = dom.query.getParentElement(target, dom.check.isFigure);
489
+ let info = this.get(target);
490
+ if (info || figure) {
491
+ info ||= this.get(figure);
492
+ if (info && !dom.utils.hasClass(info.container, 'se-component-selected')) {
493
+ this.#$.ui.offCurrentController();
494
+ _DragHandle.set('__overInfo', ON_OVER_COMPONENT);
495
+ this.select(info.target, info.pluginName);
496
+ }
497
+ } else if (_DragHandle.get('__overInfo') !== null && !dom.utils.hasClass(target, 'se-drag-handle')) {
498
+ this.__deselect();
499
+ _DragHandle.set('__overInfo', null);
500
+ }
501
+ }
502
+
503
+ /**
504
+ * @internal
505
+ * @description Deselects the currently selected component, removing any selection effects and associated event listeners.
506
+ * - This method resets the selection state and hides UI elements related to the component selection.
507
+ */
508
+ __deselect() {
509
+ this.#store.set('_preventBlur', false);
510
+ _DragHandle.set('__overInfo', null);
511
+ this.__removeDragEvent();
512
+
513
+ if (this.currentInfo) {
514
+ const infoContainer = this.currentInfo.container;
515
+ const infoCover = this.currentInfo.cover;
516
+ converter.debounce(() => {
517
+ RemoveSelectedClass(infoContainer);
518
+ dom.utils.removeClass(infoCover, 'se-figure-over-selected');
519
+ }, 0)();
520
+ }
521
+
522
+ if (this.#frameContext.get('lineBreaker_t')) {
523
+ this.#frameContext.get('lineBreaker_t').style.display = this.#frameContext.get('lineBreaker_b').style.display = 'none';
524
+ }
525
+
526
+ if (this.currentPlugin) {
527
+ this.currentPlugin.componentDeselect?.(this.currentTarget);
528
+ }
529
+
530
+ this.isSelected = false;
531
+ this.currentPlugin = null;
532
+ this.currentTarget = null;
533
+ this.currentPluginName = '';
534
+ this.currentInfo = null;
535
+ this.__removeGlobalEvent();
536
+ this.#$.ui._offControllers();
537
+ }
538
+
539
+ /**
540
+ * @internal
541
+ * @description Set line breaker of component
542
+ * @param {HTMLElement} element Element tag
543
+ */
544
+ _setComponentLineBreaker(element) {
545
+ const _overInfo = _DragHandle.get('__overInfo') === ON_OVER_COMPONENT;
546
+ this.#kernel._eventOrchestrator._lineBreakComp = null;
547
+ const info = this.get(element);
548
+ if (!info) return;
549
+
550
+ const fc = this.#frameContext;
551
+ const container = info.container;
552
+ const isNonSelected = dom.utils.hasClass(container, 'se-flex-component');
553
+ const lb_t = fc.get('lineBreaker_t');
554
+ const lb_b = fc.get('lineBreaker_b');
555
+ const t_style = lb_t.style;
556
+ const b_style = lb_b.style;
557
+ const offsetTarget = container.offsetWidth < element.offsetWidth ? container : element;
558
+ const target = this.#$.ui.getVisibleFigure() || offsetTarget;
559
+ const isList = dom.check.isListCell(container.parentNode);
560
+
561
+ // top
562
+ let componentTop, w;
563
+ const isRtl = this.#options.get('_rtl');
564
+ const dir = isRtl ? ['right', 'left'] : ['left', 'right'];
565
+ const { top, left, right, scrollX, scrollY } = this.#$.offset.getLocal(offsetTarget);
566
+ const sideOffset = isRtl ? right : left;
567
+
568
+ if (isList ? (!dom.check.isBreak(container.previousElementSibling) && !container.previousSibling?.textContent?.trim()) || this.is(container.previousElementSibling) : !this.#$.format.isLine(container.previousElementSibling)) {
569
+ const cStyle = _w.getComputedStyle(lb_t);
570
+ const cH = numbers.get(cStyle.height, 1);
571
+ const cW = numbers.get(cStyle.width, 1);
572
+
573
+ this.#kernel._eventOrchestrator._lineBreakComp = container;
574
+ componentTop = top;
575
+ w = target.offsetWidth / 2 / 2;
576
+
577
+ t_style.top = componentTop - cH / 2 + 'px';
578
+ t_style[dir[0]] = (isNonSelected ? sideOffset - cW / 2 : sideOffset + w) + 'px';
579
+ t_style[dir[1]] = '';
580
+
581
+ lb_t.setAttribute('data-offset', scrollY + ',' + scrollX);
582
+ if (_overInfo) dom.utils.removeClass(lb_t, 'se-on-selected');
583
+ else dom.utils.addClass(lb_t, 'se-on-selected');
584
+
585
+ t_style.display = 'block';
586
+ t_style.visibility = '';
587
+ } else {
588
+ t_style.display = 'none';
589
+ }
590
+
591
+ // bottom
592
+ if (isList ? (!dom.check.isBreak(container.nextElementSibling) && !container.nextSibling?.textContent?.trim()) || this.is(container.nextElementSibling) : !this.#$.format.isLine(container.nextElementSibling)) {
593
+ const cStyle = _w.getComputedStyle(lb_b);
594
+ const cH = numbers.get(cStyle.height, 1);
595
+ const cW = numbers.get(cStyle.width, 1);
596
+
597
+ if (!componentTop) {
598
+ this.#kernel._eventOrchestrator._lineBreakComp = container;
599
+ componentTop = top;
600
+ w = target.offsetWidth / 2 / 2;
601
+ }
602
+
603
+ b_style.top = componentTop + target.offsetHeight - cH / 2 + 'px';
604
+ b_style[dir[0]] = sideOffset + target.offsetWidth - (isNonSelected ? 0 : w) - (isNonSelected ? cW / 2 : cW) + 'px';
605
+ b_style[dir[1]] = '';
606
+
607
+ lb_b.setAttribute('data-offset', scrollY + ',' + dir[0] + ',' + scrollX);
608
+ if (_overInfo) dom.utils.removeClass(lb_b, 'se-on-selected');
609
+ else dom.utils.addClass(lb_b, 'se-on-selected');
610
+
611
+ b_style.display = 'block';
612
+ b_style.visibility = '';
613
+ } else {
614
+ b_style.display = 'none';
615
+ }
616
+ }
617
+
618
+ /**
619
+ * @internal
620
+ * @description Removes global event listeners that were previously added for component interactions.
621
+ */
622
+ __removeGlobalEvent() {
623
+ this.#removeNotFileGlobalEvent();
624
+ this.#bindClose_copy &&= this.#eventManager.removeGlobalEvent(this.#bindClose_copy);
625
+ this.#bindClose_cut &&= this.#eventManager.removeGlobalEvent(this.#bindClose_cut);
626
+ this.#bindClose_keydown &&= this.#eventManager.removeGlobalEvent(this.#bindClose_keydown);
627
+ }
628
+
629
+ /**
630
+ * @internal
631
+ * @description Removes drag-related events and resets drag-related states.
632
+ */
633
+ __removeDragEvent() {
634
+ /** @type {HTMLElement} */ (this.#carrierWrapper.querySelector('.se-drag-cursor')).style.left = '-10000px';
635
+ if (_DragHandle.get('__dragHandler')) _DragHandle.get('__dragHandler').style.display = 'none';
636
+
637
+ dom.utils.removeClass([_DragHandle.get('__dragHandler'), _DragHandle.get('__dragContainer')], 'se-dragging');
638
+ dom.utils.removeClass([_DragHandle.get('__dragCover'), _DragHandle.get('__dragContainer')], 'se-drag-over');
639
+
640
+ _DragHandle.set('__figureInst', null);
641
+ _DragHandle.set('__dragInst', null);
642
+ _DragHandle.set('__dragHandler', null);
643
+ _DragHandle.set('__dragContainer', null);
644
+ _DragHandle.set('__dragCover', null);
645
+ _DragHandle.set('__dragMove', null);
646
+ _DragHandle.set('__overInfo', null);
647
+ }
648
+
649
+ /**
650
+ * @description Adds global event listeners for component interactions such as copy, cut, and keydown events.
651
+ */
652
+ #addGlobalEvent() {
653
+ this.__removeGlobalEvent();
654
+ this.#bindClose_copy = this.#eventManager.addGlobalEvent('copy', this.#globalEvents.copy);
655
+ this.#bindClose_cut = this.#eventManager.addGlobalEvent('cut', this.#globalEvents.cut);
656
+ this.#bindClose_keydown = this.#eventManager.addGlobalEvent('keydown', this.#globalEvents.keydown);
657
+ }
658
+
659
+ /**
660
+ * @description Adds global event listeners for non-file-related interactions such as mouse and touch events.
661
+ */
662
+ #addNotFileGlobalEvent() {
663
+ this.#removeNotFileGlobalEvent();
664
+ this.#bindClose_mousedown = this.#eventManager.addGlobalEvent(isMobile ? 'click' : 'mousedown', this.#globalEvents.mousedown, true);
665
+ }
666
+
667
+ /**
668
+ * @internal
669
+ * @description Removes global event listeners related to non-file interactions.
670
+ */
671
+ #removeNotFileGlobalEvent() {
672
+ this.#bindClose_mousedown &&= this.#eventManager.removeGlobalEvent(this.#bindClose_mousedown);
673
+ }
674
+
675
+ /**
676
+ * @description
677
+ * Attempts to move the cursor to a valid line after the given container.
678
+ * - If a valid next sibling line exists, moves the selection there.
679
+ * - If no next sibling exists, creates a new line after the container and moves the selection there.
680
+ * - If the next sibling exists but is not a valid line element and cannot create a new line, returns false.
681
+ * @param {Node} container The component container element.
682
+ * @returns {boolean} Returns true if the selection moved to a line (existing or newly created), otherwise false.
683
+ */
684
+ #moveToNextLineOrAdd(container) {
685
+ const nextSibling = /** @type {Element} */ (container).nextElementSibling;
686
+ if (!nextSibling) {
687
+ const line = this.#$.format.addLine(container, null);
688
+ if (line) this.#$.selection.setRange(line, 0, line, 0);
689
+ return true;
690
+ } else if (this.#$.format.isLine(nextSibling)) {
691
+ this.#$.selection.setRange(nextSibling, 0, nextSibling, 0);
692
+ return true;
693
+ }
694
+
695
+ return false;
696
+ }
697
+
698
+ /**
699
+ * @description Checks if the given element is a file component by matching its tag name against the file manager's regular expressions.
700
+ * - It also verifies whether the element has the required attributes based on the tag type.
701
+ * @param {Node} element The element to check.
702
+ * @returns {boolean} Returns true if the element is a file component, otherwise false.
703
+ */
704
+ #isFiles(element) {
705
+ const nodeName = element.nodeName.toLowerCase();
706
+ return (
707
+ this.#$.pluginManager.fileInfo.regExp.test(nodeName) &&
708
+ (!this.#$.pluginManager.fileInfo.tagAttrs[nodeName] || this.#$.pluginManager.fileInfo.tagAttrs[nodeName]?.every((v) => /** @type {HTMLElement} */ (element).hasAttribute(v)))
709
+ );
710
+ }
711
+
712
+ #OnDragEnter() {
713
+ this.#store.set('_preventBlur', true);
714
+ this.#$.ui._visibleControllers(false, dom.utils.hasClass(_DragHandle.get('__dragHandler'), 'se-drag-handle-full'));
715
+ dom.utils.addClass(_DragHandle.get('__dragCover') || _DragHandle.get('__dragContainer'), 'se-drag-over');
716
+ }
717
+
718
+ #OnDragLeave() {
719
+ this.#store.set('_preventBlur', false);
720
+ if (!dom.utils.hasClass(_DragHandle.get('__dragHandler'), 'se-drag-handle-full')) this.#$.ui._visibleControllers(true, true);
721
+ dom.utils.removeClass([_DragHandle.get('__dragCover'), _DragHandle.get('__dragContainer')], 'se-drag-over');
722
+ }
723
+
724
+ /**
725
+ * @param {DragEvent} e - Drag event
726
+ */
727
+ #OnDragStart(e) {
728
+ const cover = _DragHandle.get('__dragCover') || _DragHandle.get('__dragContainer');
729
+
730
+ if (!cover) {
731
+ e.preventDefault();
732
+ return;
733
+ }
734
+
735
+ this.#store.set('_preventBlur', false);
736
+ dom.utils.addClass(_DragHandle.get('__dragHandler'), 'se-dragging');
737
+ dom.utils.addClass(_DragHandle.get('__dragContainer'), 'se-dragging');
738
+ e.dataTransfer.setDragImage(cover, this.#options.get('_rtl') ? cover.offsetWidth : -5, -5);
739
+ }
740
+
741
+ #OnDragEnd() {
742
+ this.#store.set('_preventBlur', false);
743
+ dom.utils.removeClass([_DragHandle.get('__dragHandler'), _DragHandle.get('__dragContainer')], 'se-dragging');
744
+ this.__removeDragEvent();
745
+ }
746
+
747
+ /**
748
+ * @param {MouseEvent} e - Mouse event
749
+ */
750
+ #OnDragClick(e) {
751
+ const target = dom.query.getEventTarget(e);
752
+ if (!dom.utils.hasClass(target, 'se-drag-handle-full')) return;
753
+
754
+ const dragInst = _DragHandle.get('__dragInst');
755
+ if (!dragInst) return;
756
+
757
+ this.__removeDragEvent();
758
+ this.select(dragInst.currentTarget, dragInst.currentPluginName);
759
+ }
760
+
761
+ /**
762
+ * @param {MouseEvent} e - Mouse event
763
+ */
764
+ #CloseListener_mousedown(e) {
765
+ const target = dom.query.getEventTarget(e);
766
+ if (
767
+ this.currentTarget?.contains(target) ||
768
+ dom.query.getParentElement(target, '.se-controller') ||
769
+ dom.utils.hasClass(target, 'se-drag-handle') ||
770
+ (this.currentPluginName === this.#$.ui.currentControllerName && this.#$.ui.opendControllers.some(({ form }) => form.contains(target)))
771
+ ) {
772
+ return;
773
+ }
774
+ this.deselect();
775
+ }
776
+
777
+ /**
778
+ * @param {ClipboardEvent} e - Event object
779
+ */
780
+ #OnCopy_component(e) {
781
+ const target = dom.query.getEventTarget(e);
782
+ if (dom.check.isInputElement(target) && dom.query.getParentElement(target, '.se-modal')) return;
783
+
784
+ const info = this.info;
785
+ if (!info) return;
786
+
787
+ const cloneContainer = info.container.cloneNode(true);
788
+ if (typeof this.#$.plugins[info.pluginName]?.componentCopy !== 'function' || this.#$.plugins[info.pluginName].componentCopy({ event: e, cloneContainer, info }) === false) {
789
+ SetClipboardComponent(e, cloneContainer, e.clipboardData);
790
+ }
791
+
792
+ // copy effect
793
+ dom.utils.flashClass(info.container, 'se-copy');
794
+ }
795
+
796
+ /**
797
+ * @param {ClipboardEvent} e - Event object
798
+ */
799
+ #OnCut_component(e) {
800
+ const info = this.info;
801
+ if (!info) return;
802
+
803
+ const cloneContainer = info.container.cloneNode(true);
804
+ dom.utils.removeClass(cloneContainer, 'se-component-selected');
805
+
806
+ SetClipboardComponent(e, cloneContainer, e.clipboardData);
807
+ this.deselect();
808
+ dom.utils.removeItem(info.container);
809
+ }
810
+
811
+ /**
812
+ * @param {KeyboardEvent} e - Event object
813
+ */
814
+ async #OnKeyDown_component(e) {
815
+ if (this.#$.ui.selectMenuOn) return;
816
+
817
+ const keyCode = e.code;
818
+ const ctrl = keyCodeMap.isCtrl(e);
819
+
820
+ // redo, undo
821
+ if (ctrl) {
822
+ if (keyCode !== 'ControlRight' && keyCode !== 'ControlLeft') {
823
+ const info = this.#$.shortcuts.keyMap.get(keyCode + (e.shiftKey ? '1000' : ''));
824
+ if (/^(redo|undo)$/.test(info?.command)) {
825
+ e.preventDefault();
826
+ e.stopPropagation();
827
+ this.#$.commandDispatcher.run(info.command, info.type, info.button);
828
+ }
829
+ }
830
+ return;
831
+ }
832
+
833
+ // backspace key, delete key
834
+ if (keyCodeMap.isRemoveKey(keyCode)) {
835
+ e.preventDefault();
836
+ e.stopPropagation();
837
+
838
+ if (typeof this.currentPlugin?.componentDestroy === 'function' && (!this.info.isInputType || !this.#store.get('hasFocus'))) {
839
+ const focusNode = this.info.container.previousSibling;
840
+ await this.currentPlugin.componentDestroy(this.currentTarget);
841
+ this.deselect();
842
+ if (focusNode) {
843
+ const offset = focusNode.nodeType === 3 ? focusNode.textContent.length : 1;
844
+ this.#$.selection.setRange(focusNode, offset, focusNode, offset);
845
+ } else {
846
+ this.#$.focusManager.focus();
847
+ }
848
+ return;
849
+ }
850
+ }
851
+
852
+ // enter key
853
+ if (keyCodeMap.isEnter(keyCode)) {
854
+ e.preventDefault();
855
+ const compContext = this.currentInfo || this.get(this.currentTarget);
856
+ const container = compContext.container || compContext.target;
857
+ const sibling = container.previousElementSibling || container.nextElementSibling;
858
+ let newEl = null;
859
+ if (dom.check.isListCell(container.parentNode)) {
860
+ newEl = dom.utils.createElement('BR');
861
+ } else {
862
+ newEl = dom.utils.createElement(this.#$.format.isLine(sibling) ? sibling.nodeName : this.#options.get('defaultLine'), null, '<br>');
863
+ }
864
+
865
+ const pluginName = this.currentPluginName;
866
+ this.deselect();
867
+ container.parentNode.insertBefore(newEl, container);
868
+ if (this.select(compContext.target, pluginName) === false) this.#$.focusManager.blur();
869
+ this.#$.history.push(false);
870
+
871
+ return;
872
+ }
873
+
874
+ // up down, left right
875
+ DIR_KEYCODE.lastIndex = 0;
876
+ if (DIR_KEYCODE.test(keyCode)) {
877
+ const { container } = this.get(this.currentTarget);
878
+ const isInline = this.isInline(container || this.currentTarget);
879
+
880
+ let el = null;
881
+ let offset = 1;
882
+ if (isInline) {
883
+ switch (keyCode) {
884
+ case 'ArrowLeft': // left
885
+ el = container.previousSibling;
886
+ offset = el?.nodeType === 3 ? el.textContent.length : 1;
887
+ break;
888
+ case 'ArrowRight': // right
889
+ el = container.nextSibling;
890
+ offset = 0;
891
+ break;
892
+ case 'ArrowUp': {
893
+ // up
894
+ const line = this.#$.format.getLine(container, null);
895
+ el = line?.previousElementSibling;
896
+ offset = 0;
897
+ break;
898
+ }
899
+ case 'ArrowDown': {
900
+ // down
901
+ const line = this.#$.format.getLine(container, null);
902
+ el = line?.nextElementSibling;
903
+ break;
904
+ }
905
+ }
906
+ } else {
907
+ DIR_UP_KEYCODE.lastIndex = 0;
908
+ if (DIR_UP_KEYCODE.test(keyCode)) {
909
+ el = container.previousElementSibling;
910
+ } else {
911
+ el = container.nextElementSibling;
912
+ offset = 0;
913
+ }
914
+ }
915
+
916
+ if (!el) return;
917
+
918
+ this.deselect();
919
+
920
+ const elComp = this.get(el);
921
+ if (elComp?.container) {
922
+ e.stopPropagation();
923
+ e.preventDefault();
924
+ this.select(elComp.target, elComp.pluginName);
925
+ } else {
926
+ try {
927
+ this.#store.set('_preventBlur', true);
928
+ e.stopPropagation();
929
+ e.preventDefault();
930
+ this.#$.selection.setRange(el, offset, el, offset);
931
+ } finally {
932
+ this.#store.set('_preventBlur', false);
933
+ }
934
+ }
935
+
936
+ return;
937
+ }
938
+
939
+ // ESC
940
+ if (keyCodeMap.isEsc(keyCode)) {
941
+ this.deselect();
942
+ return;
943
+ }
944
+ }
945
+
946
+ /**
947
+ * @internal
948
+ * @description Destroy the Component instance and release memory
949
+ */
950
+ _destroy() {
951
+ this.__removeGlobalEvent();
952
+ this.__removeDragEvent();
953
+ }
954
+ }
955
+
956
+ function SetClipboardComponent(e, container, clipboardData) {
957
+ e.preventDefault();
958
+ e.stopPropagation();
959
+ RemoveSelectedClass(container);
960
+ clipboardData.setData('text/html', container.outerHTML);
961
+ }
962
+
963
+ function RemoveSelectedClass(container) {
964
+ dom.utils.removeClass(container, 'se-component-selected');
965
+ dom.utils.removeClass(container.querySelectorAll('.se-figure-selected'), 'se-figure-selected');
966
+ dom.utils.removeClass(container.querySelectorAll('.se-selected-table-cell'), 'se-selected-table-cell');
967
+ dom.utils.removeClass(container.querySelector('.se-selected-cell-focus'), 'se-selected-cell-focus');
968
+ }
969
+
970
+ export default Component;