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,904 @@
1
+ import { dom, converter, keyCodeMap, env, numbers } from '../../../helper';
2
+ import { _DragHandle } from '../../../modules/ui';
3
+ import { COMMAND_BUTTONS } from './commandDispatcher';
4
+
5
+ const DISABLE_BUTTONS_CODEVIEW = `${COMMAND_BUTTONS}:not([class~="se-code-view-enabled"]):not([data-type="MORE"])`;
6
+ const DISABLE_BUTTONS_CONTROLLER = `${COMMAND_BUTTONS}:not([class~="se-component-enabled"]):not([data-type="MORE"])`;
7
+
8
+ const { _w } = env;
9
+
10
+ /**
11
+ * @description The UI class is a class that handles operations related to the user interface of SunEditor.
12
+ * - This class sets the editor's style, theme, editor mode, etc., and controls the state of various UI elements.
13
+ */
14
+ class UIManager {
15
+ #kernel;
16
+ #$;
17
+ #store;
18
+
19
+ #contextProvider;
20
+ #carrierWrapper;
21
+ #options;
22
+ #context;
23
+ #frameRoots;
24
+ #frameContext;
25
+ #eventManager;
26
+
27
+ #alertArea;
28
+ #alertInner;
29
+ #closeListener;
30
+ #closeSignal;
31
+ #backWrapper;
32
+
33
+ #controllerOnBtnDisabled = false;
34
+ #bindClose = null;
35
+ #toastToggle = null;
36
+
37
+ /**
38
+ * @description List of buttons that are disabled when `controller` is opened
39
+ * @type {Array<HTMLButtonElement|HTMLInputElement>}
40
+ */
41
+ #controllerOnDisabledButtons = [];
42
+
43
+ /**
44
+ * @description List of buttons that are disabled when `codeView` mode opened
45
+ * @type {Array<HTMLButtonElement|HTMLInputElement>}
46
+ */
47
+ #codeViewDisabledButtons = [];
48
+
49
+ /**
50
+ * @description Variable that controls the `blur` event in the editor of `inline` or `balloon` mode when the focus is moved to dropdown
51
+ * @type {boolean}
52
+ */
53
+ #notHideToolbar = false;
54
+
55
+ /**
56
+ * @description Line breaker (top)
57
+ * @type {HTMLElement}
58
+ */
59
+ #lineBreaker_t = null;
60
+
61
+ /**
62
+ * @description Line breaker (bottom)
63
+ * @type {HTMLElement}
64
+ */
65
+ #lineBreaker_b = null;
66
+
67
+ /**
68
+ * @constructor
69
+ * @param {SunEditor.Kernel} kernel
70
+ */
71
+ constructor(kernel) {
72
+ this.#kernel = kernel;
73
+ this.#$ = kernel.$;
74
+ this.#store = kernel.store;
75
+
76
+ this.#contextProvider = this.#$.contextProvider;
77
+ this.#carrierWrapper = this.#contextProvider.carrierWrapper;
78
+ this.#options = this.#$.options;
79
+ this.#context = this.#$.context;
80
+ this.#frameRoots = this.#$.frameRoots;
81
+ this.#frameContext = this.#$.frameContext;
82
+ this.#eventManager = this.#$.eventManager;
83
+
84
+ // alert
85
+ const alertModal = CreateAlertHTML(this.#contextProvider);
86
+ this.alertModal = alertModal;
87
+ this.alertMessage = alertModal.querySelector('span');
88
+
89
+ // toast
90
+ const toastPopup = CreateToastHTML();
91
+ this.toastPopup = toastPopup;
92
+ this.toastContainer = toastPopup.querySelector('.se-toast-container');
93
+ this.toastMessage = toastPopup.querySelector('span');
94
+ this.#carrierWrapper.appendChild(toastPopup);
95
+
96
+ // init
97
+ this.#alertArea = /** @type {HTMLElement} */ (this.#carrierWrapper.querySelector('.se-alert'));
98
+ this.#alertInner = /** @type {HTMLElement} */ (this.#carrierWrapper.querySelector('.se-alert .se-modal-inner'));
99
+ this.#alertInner.appendChild(alertModal);
100
+ this.#closeListener = [CloseListener.bind(this), OnClick_alert.bind(this)];
101
+ this.#closeSignal = false;
102
+ this.#backWrapper = /** @type {HTMLElement} */ (this.#carrierWrapper.querySelector('.se-back-wrapper'));
103
+
104
+ /**
105
+ * @description Whether `SelectMenu` is open
106
+ * @type {boolean}
107
+ */
108
+ this.selectMenuOn = false;
109
+
110
+ /**
111
+ * @description Currently open `Controller` info array
112
+ * @type {Array<SunEditor.Module.Controller.Info>}
113
+ */
114
+ this.opendControllers = [];
115
+
116
+ /**
117
+ * @description Controller target's frame div (`editor.frameContext.get('topArea')`)
118
+ * @type {?HTMLElement}
119
+ */
120
+ this.controllerTargetContext = null;
121
+
122
+ /**
123
+ * @internal
124
+ * @description Current Figure container.
125
+ * @type {?HTMLElement}
126
+ */
127
+ this._figureContainer = null;
128
+ }
129
+
130
+ /**
131
+ * @description Set editor frame styles.
132
+ * - Define the style of the edit area
133
+ * - It can also be defined with the `setOptions` method, but the `setEditorStyle` method does not render the editor again.
134
+ * @param {string} style Style string
135
+ * @param {?SunEditor.FrameContext} [fc] Frame context
136
+ */
137
+ setEditorStyle(style, fc) {
138
+ fc ||= this.#frameContext;
139
+
140
+ const fo = fc.get('options');
141
+ fo.set('editorStyle', style);
142
+
143
+ const newStyles = converter._setDefaultOptionStyle(fo, style);
144
+ fo.set('_defaultStyles', newStyles);
145
+
146
+ // top area
147
+ fc.get('topArea').style.cssText = newStyles.top;
148
+
149
+ // code view
150
+ const code = fc.get('code');
151
+ code.style.cssText = fo.get('_defaultStyles').frame;
152
+ code.style.display = 'none';
153
+
154
+ // wysiwyg frame
155
+ if (!fo.get('iframe')) {
156
+ fc.get('wysiwygFrame').style.cssText = newStyles.frame + newStyles.editor;
157
+ } else {
158
+ fc.get('wysiwygFrame').style.cssText = newStyles.frame;
159
+ fc.get('wysiwyg').style.cssText = newStyles.editor;
160
+ }
161
+ }
162
+
163
+ /**
164
+ * @description Set the theme to the editor
165
+ * @param {string} theme Theme name
166
+ */
167
+ setTheme(theme) {
168
+ if (typeof theme !== 'string') return;
169
+ const o = this.#options;
170
+ const prevTheme = o.get('_themeClass').trim();
171
+ o.set('theme', theme || '');
172
+ o.set('_themeClass', theme ? ` se-theme-${theme}` : '');
173
+ theme = o.get('_themeClass').trim();
174
+
175
+ const applyTheme = (target) => {
176
+ if (!target) return;
177
+ if (prevTheme) dom.utils.removeClass(target, prevTheme);
178
+ if (theme) dom.utils.addClass(target, theme);
179
+ };
180
+
181
+ applyTheme(this.#carrierWrapper);
182
+ this.#contextProvider.applyToRoots((e) => {
183
+ applyTheme(e.get('topArea'));
184
+ applyTheme(e.get('wysiwyg'));
185
+ });
186
+
187
+ applyTheme(this.#context.get('statusbar_wrapper'));
188
+ applyTheme(this.#context.get('toolbar_wrapper'));
189
+ }
190
+
191
+ /**
192
+ * @description Set direction to `rtl` or `ltr`.
193
+ * @param {string} dir `rtl` or `ltr`
194
+ */
195
+ setDir(dir) {
196
+ const rtl = dir === 'rtl';
197
+ if (this.#options.get('_rtl') === rtl) return;
198
+
199
+ try {
200
+ this.#options.set('_rtl', rtl);
201
+ this.offCurrentController();
202
+
203
+ const fc = this.#frameContext;
204
+ const plugins = this.#$.pluginManager.plugins;
205
+ for (const k in plugins) {
206
+ plugins[k].setDir?.(dir);
207
+ }
208
+
209
+ const toolbarWrapper = this.#context.get('toolbar_wrapper');
210
+ const statusbarWrapper = this.#context.get('statusbar_wrapper');
211
+ if (rtl) {
212
+ this.#contextProvider.applyToRoots((e) => {
213
+ dom.utils.addClass([e.get('topArea'), e.get('wysiwyg'), e.get('documentTypePageMirror')], 'se-rtl');
214
+ });
215
+ dom.utils.addClass([this.#carrierWrapper, toolbarWrapper, statusbarWrapper], 'se-rtl');
216
+ } else {
217
+ this.#contextProvider.applyToRoots((e) => {
218
+ dom.utils.removeClass([e.get('topArea'), e.get('wysiwyg'), e.get('documentTypePageMirror')], 'se-rtl');
219
+ });
220
+ dom.utils.removeClass([this.#carrierWrapper, toolbarWrapper, statusbarWrapper], 'se-rtl');
221
+ }
222
+
223
+ const lineNodes = dom.query.getListChildren(
224
+ fc.get('wysiwyg'),
225
+ (current) => {
226
+ return this.#$.format.isLine(current) && !!(current.style.marginRight || current.style.marginLeft || current.style.textAlign);
227
+ },
228
+ null,
229
+ );
230
+
231
+ for (let i = 0, n, l, r; (n = lineNodes[i]); i++) {
232
+ n = lineNodes[i];
233
+ // indent margin
234
+ r = n.style.marginRight;
235
+ l = n.style.marginLeft;
236
+ if (r || l) {
237
+ n.style.marginRight = l;
238
+ n.style.marginLeft = r;
239
+ }
240
+ // text align
241
+ r = n.style.textAlign;
242
+ if (r === 'left') n.style.textAlign = 'right';
243
+ else if (r === 'right') n.style.textAlign = 'left';
244
+ }
245
+
246
+ this.#activeDirBtn(rtl);
247
+
248
+ // document type
249
+ if (fc.has('documentType_use_header')) {
250
+ if (rtl) fc.get('wrapper').appendChild(fc.get('documentTypeInner'));
251
+ else fc.get('wrapper').insertBefore(fc.get('documentTypeInner'), fc.get('wysiwygFrame'));
252
+ }
253
+ if (fc.has('documentType_use_page')) {
254
+ if (rtl) fc.get('wrapper').insertBefore(fc.get('documentTypePage'), fc.get('wysiwygFrame'));
255
+ else fc.get('wrapper').appendChild(fc.get('documentTypePage'));
256
+ }
257
+
258
+ if (this.#store.mode.isBalloon) this.#$.toolbar._showBalloon();
259
+ else if (this.#store.mode.isSubBalloon) this.#$.subToolbar._showBalloon();
260
+ } catch (e) {
261
+ this.#options.set('_rtl', !rtl);
262
+ console.warn(`[SUNEDITOR.ui.setDir.fail] ${e.toString()}`);
263
+ }
264
+
265
+ this.#store.set('_lastSelectionNode', null);
266
+ this.#kernel._eventOrchestrator.applyTagEffect();
267
+ }
268
+
269
+ /**
270
+ * @description Switch to or off `ReadOnly` mode.
271
+ * @param {boolean} value `readOnly` boolean value.
272
+ * @param {string} [rootKey] Root key
273
+ */
274
+ readOnly(value, rootKey) {
275
+ const fc = rootKey ? this.#frameRoots.get(rootKey) : this.#frameContext;
276
+
277
+ fc.set('isReadOnly', !!value);
278
+
279
+ this._toggleControllerButtons(!!value);
280
+
281
+ if (value) {
282
+ this.offCurrentController();
283
+ this.offCurrentModal();
284
+
285
+ if (this.#$.toolbar?.currentMoreLayerActiveButton?.disabled) this.#$.toolbar._moreLayerOff();
286
+ if (this.#$.subToolbar?.currentMoreLayerActiveButton?.disabled) this.#$.subToolbar._moreLayerOff();
287
+ if (this.#$.menu?.currentDropdownActiveButton?.disabled) this.#$.menu.dropdownOff();
288
+ if (this.#$.menu?.currentContainerActiveButton?.disabled) this.#$.menu.containerOff();
289
+
290
+ fc.get('code').setAttribute('readOnly', 'true');
291
+ dom.utils.addClass(fc.get('wysiwyg'), 'se-read-only');
292
+ } else {
293
+ fc.get('code').removeAttribute('readOnly');
294
+ dom.utils.removeClass(fc.get('wysiwyg'), 'se-read-only');
295
+ }
296
+
297
+ if (this.#options.get('hasCodeMirror')) {
298
+ this.#$.viewer._codeMirrorEditor('readonly', !!value, rootKey);
299
+ }
300
+ }
301
+
302
+ /**
303
+ * @description Disables the editor.
304
+ * @param {string} [rootKey] Root key
305
+ */
306
+ disable(rootKey) {
307
+ const fc = rootKey ? this.#frameRoots.get(rootKey) : this.#frameContext;
308
+
309
+ this.#$.toolbar.disable();
310
+ this.offCurrentController();
311
+ this.offCurrentModal();
312
+
313
+ fc.get('wysiwyg').setAttribute('contenteditable', 'false');
314
+ fc.set('isDisabled', true);
315
+
316
+ if (this.#options.get('hasCodeMirror')) {
317
+ this.#$.viewer._codeMirrorEditor('readonly', true, rootKey);
318
+ } else {
319
+ fc.get('code').disabled = true;
320
+ }
321
+ }
322
+
323
+ /**
324
+ * @description Enables the editor.
325
+ * @param {string} [rootKey] Root key
326
+ */
327
+ enable(rootKey) {
328
+ const fc = rootKey ? this.#frameRoots.get(rootKey) : this.#frameContext;
329
+
330
+ this.#$.toolbar.enable();
331
+ fc.get('wysiwyg').setAttribute('contenteditable', 'true');
332
+ fc.set('isDisabled', false);
333
+
334
+ if (this.#options.get('hasCodeMirror')) {
335
+ this.#$.viewer._codeMirrorEditor('readonly', false, rootKey);
336
+ } else {
337
+ fc.get('code').disabled = false;
338
+ }
339
+ }
340
+
341
+ /**
342
+ * @description Shows the editor interface.
343
+ * @param {string} [rootKey] Root key
344
+ */
345
+ show(rootKey) {
346
+ const fc = rootKey ? this.#frameRoots.get(rootKey) : this.#frameContext;
347
+ const topAreaStyle = fc.get('topArea').style;
348
+ if (topAreaStyle.display === 'none') topAreaStyle.display = 'block';
349
+ }
350
+
351
+ /**
352
+ * @description Hides the editor interface.
353
+ * @param {string} [rootKey] Root key
354
+ */
355
+ hide(rootKey) {
356
+ const fc = rootKey ? this.#frameRoots.get(rootKey) : this.#frameContext;
357
+ fc.get('topArea').style.display = 'none';
358
+ }
359
+
360
+ /**
361
+ * @description Shows the loading spinner.
362
+ * @param {string} [rootKey] Root key
363
+ */
364
+ showLoading(rootKey) {
365
+ /** @type {HTMLElement} */ ((rootKey ? this.#frameRoots.get(rootKey).get('container') : this.#carrierWrapper).querySelector('.se-loading-box')).style.display = 'block';
366
+ }
367
+
368
+ /**
369
+ * @description Hides the loading spinner.
370
+ * @param {string} [rootKey] Root key
371
+ */
372
+ hideLoading(rootKey) {
373
+ /** @type {HTMLElement} */ ((rootKey ? this.#frameRoots.get(rootKey).get('container') : this.#carrierWrapper).querySelector('.se-loading-box')).style.display = 'none';
374
+ }
375
+
376
+ /**
377
+ * @description Open the alert panel
378
+ * @param {string} text alert message
379
+ * @param {""|"error"|"success"} type alert type
380
+ */
381
+ alertOpen(text, type) {
382
+ this.alertMessage.textContent = text;
383
+
384
+ dom.utils.removeClass(this.alertModal, 'se-alert-error|se-alert-success');
385
+ if (type) dom.utils.addClass(this.alertModal, `se-alert-${type}`);
386
+
387
+ if (this.#closeSignal) this.#alertInner.addEventListener('click', this.#closeListener[1]);
388
+ this.#bindClose &&= this.#eventManager.removeGlobalEvent(this.#bindClose);
389
+ this.#bindClose = this.#eventManager.addGlobalEvent('keydown', this.#closeListener[0]);
390
+
391
+ this.#alertArea.style.display = 'block';
392
+ dom.utils.addClass(this.alertModal, 'se-modal-show');
393
+ }
394
+
395
+ /**
396
+ * @description Close the alert panel
397
+ */
398
+ alertClose() {
399
+ dom.utils.removeClass(this.alertModal, 'se-modal-show');
400
+ dom.utils.removeClass(this.alertModal, 'se-alert-*');
401
+ this.#alertArea.style.display = 'none';
402
+ if (this.#closeSignal) this.#alertInner.removeEventListener('click', this.#closeListener[1]);
403
+ this.#bindClose &&= this.#eventManager.removeGlobalEvent(this.#bindClose);
404
+ }
405
+
406
+ /**
407
+ * @description Show toast
408
+ * @param {string} message toast message
409
+ * @param {number} [duration=1000] duration time(ms)
410
+ * @param {""|"error"|"success"} [type=""] duration time(ms)
411
+ */
412
+ showToast(message, duration = 1000, type) {
413
+ if (dom.utils.hasClass(this.toastContainer, 'se-toast-show')) {
414
+ this.closeToast();
415
+ }
416
+
417
+ dom.utils.removeClass(this.toastPopup, 'se-toast-error|se-toast-success');
418
+ if (type) dom.utils.addClass(this.toastPopup, `se-toast-${type}`);
419
+
420
+ this.toastPopup.style.display = 'block';
421
+ this.toastMessage.textContent = message;
422
+ dom.utils.addClass(this.toastContainer, 'se-toast-show');
423
+
424
+ // Auto-dismiss toast after display duration (cleared if toast is manually closed)
425
+ this.#toastToggle = _w.setTimeout(() => {
426
+ this.closeToast();
427
+ }, duration);
428
+ }
429
+
430
+ /**
431
+ * @description Close toast
432
+ */
433
+ closeToast() {
434
+ if (this.#toastToggle) _w.clearTimeout(this.#toastToggle);
435
+ this.#toastToggle = null;
436
+ dom.utils.removeClass(this.toastContainer, 'se-toast-show');
437
+ this.toastPopup.style.display = 'none';
438
+ }
439
+
440
+ /**
441
+ * @description This method disables or enables the toolbar buttons when the `controller` is activated or deactivated.
442
+ * - When the `controller` is activated, the toolbar buttons are disabled; when the `controller` is deactivated, the buttons are enabled.
443
+ * @param {boolean} active If `true`, the toolbar buttons will be disabled. If `false`, the toolbar buttons will be enabled.
444
+ * @returns {boolean} The current state of the controller on disabled buttons.
445
+ */
446
+ setControllerOnDisabledButtons(active) {
447
+ if (active && !this.#controllerOnBtnDisabled) {
448
+ this._toggleControllerButtons(true);
449
+ this.#controllerOnBtnDisabled = true;
450
+ } else if (!active && this.#controllerOnBtnDisabled) {
451
+ this._toggleControllerButtons(false);
452
+ this.#controllerOnBtnDisabled = false;
453
+ }
454
+ return this.#controllerOnBtnDisabled;
455
+ }
456
+
457
+ /**
458
+ * @description Set the controller target context to the current top area.
459
+ */
460
+ onControllerContext() {
461
+ this.controllerTargetContext = this.#frameContext.get('topArea');
462
+ }
463
+
464
+ /**
465
+ * @description Reset the controller target context.
466
+ */
467
+ offControllerContext() {
468
+ this.controllerTargetContext = null;
469
+ }
470
+
471
+ /**
472
+ * @description Activate the transparent background `div` so that other elements are not affected during resizing.
473
+ * @param {string} cursor cursor css property
474
+ */
475
+ enableBackWrapper(cursor) {
476
+ this.#backWrapper.style.cursor = cursor;
477
+ this.#backWrapper.style.display = 'block';
478
+ }
479
+
480
+ /**
481
+ * @description Disabled background `div`
482
+ */
483
+ disableBackWrapper() {
484
+ this.#backWrapper.style.display = 'none';
485
+ this.#backWrapper.style.cursor = 'default';
486
+ }
487
+
488
+ /**
489
+ * @description Closes the currently active controller by delegating to the component's deselect logic.
490
+ * Use this method to close a single active controller from external code.
491
+ * @see _offControllers - For closing all open controllers at once (internal use)
492
+ */
493
+ offCurrentController() {
494
+ this.#$.component.__deselect();
495
+ }
496
+
497
+ /**
498
+ * @description Closes the currently open modal dialog.
499
+ */
500
+ offCurrentModal() {
501
+ this.opendModal?.close();
502
+ }
503
+
504
+ /**
505
+ * @description Get the current figure container only if it is visible (active).
506
+ * @returns {?HTMLElement} The active figure element or null.
507
+ */
508
+ getVisibleFigure() {
509
+ return this._figureContainer?.style.display === 'block' ? this._figureContainer : null;
510
+ }
511
+
512
+ /**
513
+ * @description Set the active figure element (image, video) being resized.
514
+ * @param {?HTMLElement} figure
515
+ */
516
+ setFigureContainer(figure) {
517
+ this._figureContainer = figure;
518
+ }
519
+
520
+ preventToolbarHide(allow) {
521
+ this.#notHideToolbar = allow;
522
+ }
523
+
524
+ get isPreventToolbarHide() {
525
+ return this.#notHideToolbar;
526
+ }
527
+
528
+ /**
529
+ * @param {SunEditor.FrameContext} rt Root target[key] FrameContext
530
+ */
531
+ reset(rt) {
532
+ rt.set('_editorHeight', rt.get('wysiwygFrame').offsetHeight);
533
+ this.#lineBreaker_t = rt.get('lineBreaker_t');
534
+ this.#lineBreaker_b = rt.get('lineBreaker_b');
535
+ }
536
+
537
+ /**
538
+ * @internal
539
+ * @description Closes all open controllers except those marked as `fixed`.
540
+ * Iterates through `opendControllers`, calls `controllerClose` on each non-fixed controller,
541
+ * hides their forms, and resets the controller state.
542
+ * @see offCurrentController - Public method for closing a single controller via component deselect
543
+ */
544
+ _offControllers() {
545
+ const cont = this.opendControllers;
546
+ const fixedCont = [];
547
+ for (let i = 0, c; i < cont.length; i++) {
548
+ c = cont[i];
549
+ if (c.fixed) {
550
+ fixedCont.push(c);
551
+ continue;
552
+ }
553
+ c.inst.controllerClose?.();
554
+ if (c.form) c.form.style.display = 'none';
555
+ }
556
+ this.opendControllers = fixedCont;
557
+ this.currentControllerName = '';
558
+ this.#store.set('_preventBlur', false);
559
+ }
560
+
561
+ /**
562
+ * @internal
563
+ * @description Synchronizes floating UI element positions with the current scroll offset.
564
+ * Called by eventManager when the wysiwyg area is scrolled.
565
+ * - Adjusts balloon toolbar position based on scroll offset
566
+ * - Closes controllers if scroll target changes
567
+ * - Updates line breaker positions
568
+ * @param {SunEditor.EventWysiwyg} eventWysiwyg - The scroll event source (Window or element with scroll data)
569
+ */
570
+ _syncScrollPosition(eventWysiwyg) {
571
+ const y = eventWysiwyg.scrollTop || eventWysiwyg.scrollY || 0;
572
+ const x = eventWysiwyg.scrollLeft || eventWysiwyg.scrollX || 0;
573
+
574
+ if (this.#store.mode.isBalloon) {
575
+ this.#context.get('toolbar_main').style.top = this.#$.toolbar.balloonOffset.top - y + 'px';
576
+ this.#context.get('toolbar_main').style.left = this.#$.toolbar.balloonOffset.left - x + 'px';
577
+ } else if (this.#store.mode.isSubBalloon) {
578
+ this.#context.get('toolbar_sub_main').style.top = this.#$.subToolbar.balloonOffset.top - y + 'px';
579
+ this.#context.get('toolbar_sub_main').style.left = this.#$.subToolbar.balloonOffset.left - x + 'px';
580
+ }
581
+
582
+ if (this.controllerTargetContext !== this.#frameContext.get('topArea')) {
583
+ this.offCurrentController();
584
+ }
585
+
586
+ this.#resetLineBreaker(x, y);
587
+ }
588
+
589
+ /**
590
+ * @internal
591
+ * @description Repositions all currently open controllers after scroll.
592
+ * Called by eventManager during container scroll events.
593
+ * - Triggers drag handle repositioning if active
594
+ * - Calls _scrollReposition on each open controller
595
+ */
596
+ _repositionControllers() {
597
+ const openCont = this.opendControllers;
598
+ if (openCont.length === 0) return;
599
+
600
+ if (_DragHandle.get('__dragMove')) _DragHandle.get('__dragMove')();
601
+ for (let i = 0; i < openCont.length; i++) {
602
+ if (openCont[i].notInCarrier) continue;
603
+ openCont[i].inst?._scrollReposition();
604
+ }
605
+ }
606
+
607
+ /**
608
+ *
609
+ * @param {number} x
610
+ * @param {number} y
611
+ */
612
+ #resetLineBreaker(x, y) {
613
+ if (this.#lineBreaker_t) {
614
+ const t_style = this.#lineBreaker_t.style;
615
+ if (t_style.display !== 'none') {
616
+ const t_offset = (this.#lineBreaker_t.getAttribute('data-offset') || ',').split(',');
617
+ t_style.top = numbers.get(t_style.top, 0) - (y - numbers.get(t_offset[0], 0)) + 'px';
618
+ t_style.left = numbers.get(t_style.left, 0) - (x - numbers.get(t_offset[1], 0)) + 'px';
619
+ this.#lineBreaker_t.setAttribute('data-offset', y + ',' + x);
620
+ }
621
+ }
622
+
623
+ if (this.#lineBreaker_b) {
624
+ const b_style = this.#lineBreaker_b.style;
625
+ if (b_style.display !== 'none') {
626
+ const b_offset = (this.#lineBreaker_b.getAttribute('data-offset') || ',').split(',');
627
+ b_style.top = numbers.get(b_style.top, 0) - (y - numbers.get(b_offset[0], 0)) + 'px';
628
+ b_style[b_offset[1]] = numbers.get(b_style[b_offset[1]], 0) - (x - numbers.get(b_offset[2], 0)) + 'px';
629
+ this.#lineBreaker_b.setAttribute('data-offset', y + ',' + b_offset[1] + ',' + x);
630
+ }
631
+ }
632
+
633
+ const openCont = this.opendControllers;
634
+ for (let i = 0; i < openCont.length; i++) {
635
+ if (!openCont[i].notInCarrier) continue;
636
+ openCont[i].form.style.top = openCont[i].inst.__offset.top - y + 'px';
637
+ openCont[i].form.style.left = openCont[i].inst.__offset.left - x + 'px';
638
+ }
639
+ }
640
+
641
+ /**
642
+ * @internal
643
+ * @description Visible controllers
644
+ * @param {boolean} value hidden/show
645
+ * @param {?boolean} [lineBreakShow] Line break hidden/show (default: Follows the value `value`.)
646
+ */
647
+ _visibleControllers(value, lineBreakShow) {
648
+ const visible = value ? '' : 'hidden';
649
+ const breakerVisible = (lineBreakShow ?? visible) ? '' : 'hidden';
650
+
651
+ const cont = this.opendControllers;
652
+ for (let i = 0, c; i < cont.length; i++) {
653
+ c = cont[i];
654
+ if (c.form) c.form.style.visibility = visible;
655
+ }
656
+
657
+ this.#lineBreaker_t.style.visibility = breakerVisible;
658
+ this.#lineBreaker_b.style.visibility = breakerVisible;
659
+ }
660
+
661
+ setCurrentControllerContext;
662
+
663
+ /**
664
+ * @description Toggles direction button active state.
665
+ * @param {boolean} rtl - Whether the text direction is right-to-left.
666
+ */
667
+ #activeDirBtn(rtl) {
668
+ const icons = this.#contextProvider.icons;
669
+ const commandTargets = this.#$.commandDispatcher?.targets;
670
+ if (!commandTargets) return;
671
+ const shortcutsKeyMap = this.#$.shortcuts?.keyMap;
672
+
673
+ // change reverse shortcuts key
674
+ this.#$.shortcuts?.reverseKeys?.forEach((e) => {
675
+ const info = shortcutsKeyMap?.get(e);
676
+ if (!info) return;
677
+ [info.command, info.r] = [info.r, info.command];
678
+ });
679
+
680
+ // change dir buttons
681
+ this.#$.commandDispatcher.applyTargets('dir', (e) => {
682
+ dom.utils.changeTxt(e.querySelector('.se-tooltip-text'), this.#contextProvider.lang[rtl ? 'dir_ltr' : 'dir_rtl']);
683
+ dom.utils.changeElement(e.firstElementChild, icons[rtl ? 'dir_ltr' : 'dir_rtl']);
684
+ });
685
+
686
+ if (rtl) {
687
+ dom.utils.addClass(commandTargets.get('dir_rtl'), 'active');
688
+ dom.utils.removeClass(commandTargets.get('dir_ltr'), 'active');
689
+ } else {
690
+ dom.utils.addClass(commandTargets.get('dir_ltr'), 'active');
691
+ dom.utils.removeClass(commandTargets.get('dir_rtl'), 'active');
692
+ }
693
+ }
694
+
695
+ /**
696
+ * @internal
697
+ * @description Set the disabled button list
698
+ */
699
+ _initToggleButtons() {
700
+ const ctx = this.#context;
701
+
702
+ this.#codeViewDisabledButtons = converter.nodeListToArray(ctx.get('toolbar_buttonTray').querySelectorAll(DISABLE_BUTTONS_CODEVIEW));
703
+ this.#controllerOnDisabledButtons = converter.nodeListToArray(ctx.get('toolbar_buttonTray').querySelectorAll(DISABLE_BUTTONS_CONTROLLER));
704
+
705
+ if (this.#options.has('_subMode')) {
706
+ this.#codeViewDisabledButtons = this.#codeViewDisabledButtons.concat(converter.nodeListToArray(ctx.get('toolbar_sub_buttonTray').querySelectorAll(DISABLE_BUTTONS_CODEVIEW)));
707
+ this.#controllerOnDisabledButtons = this.#controllerOnDisabledButtons.concat(converter.nodeListToArray(ctx.get('toolbar_sub_buttonTray').querySelectorAll(DISABLE_BUTTONS_CONTROLLER)));
708
+ }
709
+ }
710
+
711
+ /**
712
+ * @internal
713
+ * @description Toggle the disabled state of buttons reserved for Code View.
714
+ * @param {boolean} isCodeView
715
+ */
716
+ _toggleCodeViewButtons(isCodeView) {
717
+ dom.utils.setDisabled(this.#codeViewDisabledButtons, isCodeView);
718
+ }
719
+ /**
720
+ * @internal
721
+ * @description Toggle the disabled state of buttons when a controller is active.
722
+ * @param {boolean} isOpen
723
+ */
724
+ _toggleControllerButtons(isOpen) {
725
+ dom.utils.setDisabled(this.#controllerOnDisabledButtons, isOpen);
726
+ }
727
+
728
+ /**
729
+ * @description Check if the button can be executed in the current state (ReadOnly, etc.)
730
+ * @param {Node} button
731
+ * @returns {boolean}
732
+ */
733
+ isButtonDisabled(button) {
734
+ if (this.#frameContext.get('isReadOnly') && dom.utils.arrayIncludes(this.#controllerOnDisabledButtons, button)) {
735
+ return true;
736
+ }
737
+ return false;
738
+ }
739
+
740
+ /**
741
+ * @internal
742
+ * @description Updates `placeholder` visibility based on editor state.
743
+ * Shows `placeholder` when editor is empty, hides it in code view or when content exists.
744
+ * @param {SunEditor.FrameContext} [fc] - Frame context (defaults to current frameContext)
745
+ */
746
+ _updatePlaceholder(fc) {
747
+ fc ||= this.#frameContext;
748
+ const placeholder = fc.get('placeholder');
749
+
750
+ if (placeholder) {
751
+ if (fc.get('isCodeView')) {
752
+ placeholder.style.display = 'none';
753
+ return;
754
+ }
755
+
756
+ if (this.#$.facade.isEmpty(fc)) {
757
+ placeholder.style.display = 'block';
758
+ } else {
759
+ placeholder.style.display = 'none';
760
+ }
761
+ }
762
+ }
763
+
764
+ /**
765
+ * @internal
766
+ * @description Synchronizes frame UI state after content changes.
767
+ * Coordinates `iframe` height adjustment, `placeholder` visibility, and document type page sync.
768
+ * @param {SunEditor.FrameContext} fc - Frame context to synchronize
769
+ */
770
+ _syncFrameState(fc) {
771
+ if (!fc) return;
772
+ this._iframeAutoHeight(fc);
773
+ this._updatePlaceholder(fc);
774
+ // document type page
775
+ if (fc.has('documentType_use_page')) {
776
+ fc.get('documentTypePageMirror').innerHTML = fc.get('wysiwyg').innerHTML;
777
+ fc.get('documentType').rePage(true);
778
+ }
779
+ }
780
+
781
+ /**
782
+ * @internal
783
+ * @description Adjusts `iframe` height to match content height.
784
+ * Handles `auto`-height `iframe`s and manages scrolling based on `maxHeight` option.
785
+ * @param {SunEditor.FrameContext} fc - Frame context containing the `iframe`
786
+ */
787
+ _iframeAutoHeight(fc) {
788
+ if (!fc) return;
789
+ const autoFrame = fc.get('_iframeAuto');
790
+
791
+ if (autoFrame) {
792
+ // Defer iframe height measurement — content must render/reflow before measuring offsetHeight
793
+ _w.setTimeout(() => {
794
+ const h = autoFrame.offsetHeight;
795
+ const wysiwygFrame = fc.get('wysiwygFrame');
796
+ if (!wysiwygFrame) return;
797
+ wysiwygFrame.style.height = h + 'px';
798
+
799
+ // maxHeight
800
+ const fo = fc.get('options');
801
+ if (fo?.get('iframe')) {
802
+ const maxHeight = fo.get('maxHeight');
803
+ if (maxHeight) {
804
+ wysiwygFrame.setAttribute('scrolling', h > numbers.get(maxHeight) ? 'auto' : 'no');
805
+ }
806
+ }
807
+
808
+ if (!env.isResizeObserverSupported) this._emitResizeEvent(fc, h, null);
809
+ }, 0);
810
+ } else if (!env.isResizeObserverSupported) {
811
+ const wysiwygFrame = fc.get('wysiwygFrame');
812
+ if (wysiwygFrame) {
813
+ this._emitResizeEvent(fc, wysiwygFrame.offsetHeight, null);
814
+ }
815
+ }
816
+ }
817
+
818
+ /**
819
+ * @internal
820
+ * @description Emits the `onResizeEditor` event when editor height changes.
821
+ * Calculates height from `ResizeObserverEntry` if not provided directly.
822
+ * @param {SunEditor.FrameContext} fc - Frame context
823
+ * @param {number} h - Height value (`-1` to calculate from `resizeObserverEntry`)
824
+ * @param {ResizeObserverEntry|null} resizeObserverEntry - `ResizeObserver` entry for height calculation
825
+ */
826
+ _emitResizeEvent(fc, h, resizeObserverEntry) {
827
+ h =
828
+ h === -1
829
+ ? resizeObserverEntry?.borderBoxSize && resizeObserverEntry.borderBoxSize[0]
830
+ ? resizeObserverEntry.borderBoxSize[0].blockSize
831
+ : resizeObserverEntry.contentRect.height + numbers.get(fc.get('wwComputedStyle').getPropertyValue('padding-left')) + numbers.get(fc.get('wwComputedStyle').getPropertyValue('padding-right'))
832
+ : h;
833
+ if (fc.get('_editorHeight') !== h) {
834
+ this.#eventManager.triggerEvent('onResizeEditor', { height: h, prevHeight: fc.get('_editorHeight'), frameContext: fc, observerEntry: resizeObserverEntry });
835
+ fc.set('_editorHeight', h);
836
+ }
837
+
838
+ // document type page
839
+ if (fc.has('documentType_use_page')) {
840
+ fc.get('documentType').resizePage();
841
+ }
842
+ }
843
+
844
+ init() {
845
+ this.#closeSignal = !this.#eventManager.addEvent(this.alertModal.querySelector('[data-command="close"]'), 'click', this.alertClose.bind(this));
846
+ this._initToggleButtons();
847
+ }
848
+
849
+ /**
850
+ * @internal
851
+ * @description Destroy the UI instance and release memory
852
+ */
853
+ _destroy() {
854
+ // Clear timer
855
+ if (this.#toastToggle) {
856
+ _w.clearTimeout(this.#toastToggle);
857
+ }
858
+
859
+ // Remove global event
860
+ this.#bindClose &&= this.#eventManager.removeGlobalEvent(this.#bindClose);
861
+
862
+ // Remove alert click event listener
863
+ if (this.#closeSignal && this.#alertInner) {
864
+ this.#alertInner.removeEventListener('click', this.#closeListener[1]);
865
+ }
866
+
867
+ this.opendModal = null;
868
+ this.opendBrowser = null;
869
+ this.#lineBreaker_t = null;
870
+ this.#lineBreaker_b = null;
871
+ this.#controllerOnDisabledButtons = null;
872
+ this.#codeViewDisabledButtons = null;
873
+ }
874
+ }
875
+
876
+ /**
877
+ * @param {MouseEvent} e - Event object
878
+ */
879
+ function OnClick_alert(e) {
880
+ const eventTarget = dom.query.getEventTarget(e);
881
+ if (/close/.test(eventTarget.getAttribute('data-command')) || eventTarget === this._alertInner) {
882
+ this.alertClose();
883
+ }
884
+ }
885
+
886
+ /**
887
+ * @param {KeyboardEvent} e - Event object
888
+ */
889
+ function CloseListener(e) {
890
+ if (!keyCodeMap.isEsc(e.code)) return;
891
+ this.alertClose();
892
+ }
893
+
894
+ function CreateAlertHTML({ lang, icons }) {
895
+ const html = '<div><button class="close" data-command="close" title="' + lang.close + '">' + icons.cancel + '</button></div><div><span></span></div>';
896
+ return dom.utils.createElement('DIV', { class: 'se-alert-content' }, html);
897
+ }
898
+
899
+ function CreateToastHTML() {
900
+ const html = '<div class="se-toast-container"><span></span></div>';
901
+ return dom.utils.createElement('DIV', { class: 'se-toast' }, html);
902
+ }
903
+
904
+ export default UIManager;