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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (380) hide show
  1. package/README.md +65 -57
  2. package/dist/suneditor-contents.min.css +1 -0
  3. package/dist/suneditor.min.css +1 -1
  4. package/dist/suneditor.min.js +1 -1
  5. package/package.json +110 -61
  6. package/src/assets/design/color.css +36 -17
  7. package/src/assets/design/size.css +2 -0
  8. package/src/assets/icons/defaultIcons.js +17 -2
  9. package/src/assets/suneditor-contents.css +51 -16
  10. package/src/assets/suneditor.css +116 -43
  11. package/src/core/config/contextProvider.js +288 -0
  12. package/src/core/config/eventManager.js +188 -0
  13. package/src/core/config/instanceCheck.js +59 -0
  14. package/src/core/config/optionProvider.js +452 -0
  15. package/src/core/editor.js +166 -1637
  16. package/src/core/event/actions/index.js +229 -0
  17. package/src/core/event/effects/common.registry.js +74 -0
  18. package/src/core/event/effects/keydown.registry.js +573 -0
  19. package/src/core/event/effects/ruleHelpers.js +148 -0
  20. package/src/core/event/eventOrchestrator.js +944 -0
  21. package/src/core/event/executor.js +27 -0
  22. package/src/core/{base/eventHandlers → event/handlers}/handler_toolbar.js +27 -28
  23. package/src/core/{base/eventHandlers → event/handlers}/handler_ww_clipboard.js +10 -8
  24. package/src/core/{base/eventHandlers → event/handlers}/handler_ww_dragDrop.js +22 -23
  25. package/src/core/event/handlers/handler_ww_input.js +75 -0
  26. package/src/core/event/handlers/handler_ww_key.js +228 -0
  27. package/src/core/event/handlers/handler_ww_mouse.js +166 -0
  28. package/src/core/event/ports.js +211 -0
  29. package/src/core/event/reducers/keydown.reducer.js +97 -0
  30. package/src/core/event/rules/keydown.rule.arrow.js +63 -0
  31. package/src/core/event/rules/keydown.rule.backspace.js +208 -0
  32. package/src/core/event/rules/keydown.rule.delete.js +132 -0
  33. package/src/core/event/rules/keydown.rule.enter.js +150 -0
  34. package/src/core/event/rules/keydown.rule.tab.js +35 -0
  35. package/src/core/event/support/defaultLineManager.js +136 -0
  36. package/src/core/event/support/selectionState.js +204 -0
  37. package/src/core/kernel/coreKernel.js +320 -0
  38. package/src/core/kernel/kernelInjector.js +19 -0
  39. package/src/core/kernel/store.js +173 -0
  40. package/src/core/{class → logic/dom}/char.js +42 -45
  41. package/src/core/logic/dom/format.js +1075 -0
  42. package/src/core/{class → logic/dom}/html.js +743 -624
  43. package/src/core/logic/dom/inline.js +1847 -0
  44. package/src/core/logic/dom/listFormat.js +601 -0
  45. package/src/core/{class → logic/dom}/nodeTransform.js +92 -72
  46. package/src/core/{class → logic/dom}/offset.js +254 -317
  47. package/src/core/logic/dom/selection.js +754 -0
  48. package/src/core/logic/panel/menu.js +389 -0
  49. package/src/core/logic/panel/toolbar.js +449 -0
  50. package/src/core/logic/panel/viewer.js +761 -0
  51. package/src/core/logic/shell/_commandExecutor.js +380 -0
  52. package/src/core/logic/shell/commandDispatcher.js +241 -0
  53. package/src/core/logic/shell/component.js +970 -0
  54. package/src/core/logic/shell/focusManager.js +110 -0
  55. package/src/core/{base → logic/shell}/history.js +110 -60
  56. package/src/core/logic/shell/pluginManager.js +363 -0
  57. package/src/core/logic/shell/shortcuts.js +130 -0
  58. package/src/core/logic/shell/ui.js +904 -0
  59. package/src/core/schema/context.js +66 -0
  60. package/src/core/schema/frameContext.js +160 -0
  61. package/src/core/schema/options.js +628 -0
  62. package/src/core/section/constructor.js +194 -500
  63. package/src/core/section/documentType.js +297 -222
  64. package/src/events.js +808 -543
  65. package/src/helper/clipboard.js +27 -16
  66. package/src/helper/converter.js +100 -78
  67. package/src/helper/dom/domCheck.js +56 -30
  68. package/src/helper/dom/domQuery.js +159 -89
  69. package/src/helper/dom/domUtils.js +114 -49
  70. package/src/helper/dom/index.js +5 -1
  71. package/src/helper/env.js +26 -26
  72. package/src/helper/index.js +1 -1
  73. package/src/helper/keyCodeMap.js +25 -28
  74. package/src/helper/numbers.js +4 -8
  75. package/src/helper/unicode.js +4 -8
  76. package/src/hooks/base.js +307 -0
  77. package/src/hooks/params.js +130 -0
  78. package/src/interfaces/contracts.js +227 -0
  79. package/src/interfaces/index.js +7 -0
  80. package/src/interfaces/plugins.js +239 -0
  81. package/src/langs/ckb.js +4 -4
  82. package/src/langs/cs.js +4 -4
  83. package/src/langs/da.js +4 -4
  84. package/src/langs/de.js +4 -4
  85. package/src/langs/en.js +4 -4
  86. package/src/langs/es.js +4 -4
  87. package/src/langs/fa.js +4 -4
  88. package/src/langs/fr.js +4 -4
  89. package/src/langs/he.js +4 -4
  90. package/src/langs/hu.js +4 -4
  91. package/src/langs/it.js +4 -4
  92. package/src/langs/ja.js +4 -4
  93. package/src/langs/km.js +4 -4
  94. package/src/langs/ko.js +4 -4
  95. package/src/langs/lv.js +4 -4
  96. package/src/langs/nl.js +4 -4
  97. package/src/langs/pl.js +4 -4
  98. package/src/langs/pt_br.js +13 -13
  99. package/src/langs/ro.js +4 -4
  100. package/src/langs/ru.js +4 -4
  101. package/src/langs/se.js +4 -4
  102. package/src/langs/tr.js +4 -4
  103. package/src/langs/uk.js +4 -4
  104. package/src/langs/ur.js +4 -4
  105. package/src/langs/zh_cn.js +4 -4
  106. package/src/modules/{Browser.js → contract/Browser.js} +119 -128
  107. package/src/modules/{ColorPicker.js → contract/ColorPicker.js} +132 -142
  108. package/src/modules/contract/Controller.js +589 -0
  109. package/src/modules/{Figure.js → contract/Figure.js} +591 -411
  110. package/src/modules/{HueSlider.js → contract/HueSlider.js} +125 -86
  111. package/src/modules/contract/Modal.js +357 -0
  112. package/src/modules/contract/index.js +9 -0
  113. package/src/modules/manager/ApiManager.js +197 -0
  114. package/src/modules/{FileManager.js → manager/FileManager.js} +128 -160
  115. package/src/modules/manager/index.js +5 -0
  116. package/src/modules/{ModalAnchorEditor.js → ui/ModalAnchorEditor.js} +108 -138
  117. package/src/modules/{SelectMenu.js → ui/SelectMenu.js} +119 -120
  118. package/src/modules/{_DragHandle.js → ui/_DragHandle.js} +1 -1
  119. package/src/modules/ui/index.js +6 -0
  120. package/src/plugins/browser/audioGallery.js +23 -26
  121. package/src/plugins/browser/fileBrowser.js +25 -28
  122. package/src/plugins/browser/fileGallery.js +20 -23
  123. package/src/plugins/browser/imageGallery.js +24 -23
  124. package/src/plugins/browser/videoGallery.js +27 -29
  125. package/src/plugins/command/blockquote.js +11 -17
  126. package/src/plugins/command/exportPDF.js +26 -26
  127. package/src/plugins/command/fileUpload.js +138 -133
  128. package/src/plugins/command/list_bulleted.js +48 -44
  129. package/src/plugins/command/list_numbered.js +48 -44
  130. package/src/plugins/dropdown/align.js +64 -50
  131. package/src/plugins/dropdown/backgroundColor.js +34 -35
  132. package/src/plugins/dropdown/{formatBlock.js → blockStyle.js} +43 -37
  133. package/src/plugins/dropdown/font.js +50 -36
  134. package/src/plugins/dropdown/fontColor.js +34 -35
  135. package/src/plugins/dropdown/hr.js +55 -50
  136. package/src/plugins/dropdown/layout.js +20 -15
  137. package/src/plugins/dropdown/lineHeight.js +46 -30
  138. package/src/plugins/dropdown/list.js +32 -33
  139. package/src/plugins/dropdown/paragraphStyle.js +40 -34
  140. package/src/plugins/dropdown/table/index.js +915 -0
  141. package/src/plugins/dropdown/table/render/table.html.js +308 -0
  142. package/src/plugins/dropdown/table/render/table.menu.js +121 -0
  143. package/src/plugins/dropdown/table/services/table.cell.js +465 -0
  144. package/src/plugins/dropdown/table/services/table.clipboard.js +414 -0
  145. package/src/plugins/dropdown/table/services/table.grid.js +504 -0
  146. package/src/plugins/dropdown/table/services/table.resize.js +463 -0
  147. package/src/plugins/dropdown/table/services/table.selection.js +466 -0
  148. package/src/plugins/dropdown/table/services/table.style.js +844 -0
  149. package/src/plugins/dropdown/table/shared/table.constants.js +109 -0
  150. package/src/plugins/dropdown/table/shared/table.utils.js +219 -0
  151. package/src/plugins/dropdown/template.js +20 -15
  152. package/src/plugins/dropdown/textStyle.js +28 -22
  153. package/src/plugins/field/mention.js +54 -49
  154. package/src/plugins/index.js +5 -5
  155. package/src/plugins/input/fontSize.js +100 -97
  156. package/src/plugins/input/pageNavigator.js +13 -10
  157. package/src/plugins/modal/audio.js +208 -219
  158. package/src/plugins/modal/drawing.js +99 -104
  159. package/src/plugins/modal/embed.js +323 -312
  160. package/src/plugins/modal/image/index.js +942 -0
  161. package/src/plugins/modal/image/render/image.html.js +150 -0
  162. package/src/plugins/modal/image/services/image.size.js +198 -0
  163. package/src/plugins/modal/image/services/image.upload.js +216 -0
  164. package/src/plugins/modal/image/shared/image.constants.js +20 -0
  165. package/src/plugins/modal/link.js +74 -54
  166. package/src/plugins/modal/math.js +126 -119
  167. package/src/plugins/modal/video/index.js +858 -0
  168. package/src/plugins/modal/video/render/video.html.js +131 -0
  169. package/src/plugins/modal/video/services/video.size.js +281 -0
  170. package/src/plugins/modal/video/services/video.upload.js +92 -0
  171. package/src/plugins/popup/anchor.js +57 -49
  172. package/src/suneditor.js +73 -61
  173. package/src/themes/cobalt.css +155 -0
  174. package/src/themes/dark.css +143 -120
  175. package/src/typedef.js +214 -63
  176. package/types/assets/icons/defaultIcons.d.ts +8 -0
  177. package/types/assets/suneditor-contents.css.d.ts +1 -0
  178. package/types/assets/suneditor.css.d.ts +1 -0
  179. package/types/core/config/contextProvider.d.ts +148 -0
  180. package/types/core/config/eventManager.d.ts +68 -0
  181. package/types/core/config/instanceCheck.d.ts +33 -0
  182. package/types/core/config/optionProvider.d.ts +147 -0
  183. package/types/core/editor.d.ts +27 -586
  184. package/types/core/event/actions/index.d.ts +50 -0
  185. package/types/core/event/effects/common.registry.d.ts +56 -0
  186. package/types/core/event/effects/keydown.registry.d.ts +80 -0
  187. package/types/core/event/effects/ruleHelpers.d.ts +36 -0
  188. package/types/core/event/eventOrchestrator.d.ts +191 -0
  189. package/types/core/event/executor.d.ts +13 -0
  190. package/types/core/event/handlers/handler_toolbar.d.ts +38 -0
  191. package/types/core/event/handlers/handler_ww_clipboard.d.ts +36 -0
  192. package/types/core/event/handlers/handler_ww_dragDrop.d.ts +26 -0
  193. package/types/core/event/handlers/handler_ww_input.d.ts +38 -0
  194. package/types/core/event/handlers/handler_ww_key.d.ts +40 -0
  195. package/types/core/event/handlers/handler_ww_mouse.d.ts +47 -0
  196. package/types/core/event/ports.d.ts +256 -0
  197. package/types/core/event/reducers/keydown.reducer.d.ts +84 -0
  198. package/types/core/event/rules/keydown.rule.arrow.d.ts +19 -0
  199. package/types/core/event/rules/keydown.rule.backspace.d.ts +18 -0
  200. package/types/core/event/rules/keydown.rule.delete.d.ts +18 -0
  201. package/types/core/event/rules/keydown.rule.enter.d.ts +18 -0
  202. package/types/core/event/rules/keydown.rule.tab.d.ts +18 -0
  203. package/types/core/event/support/defaultLineManager.d.ts +22 -0
  204. package/types/core/event/support/selectionState.d.ts +29 -0
  205. package/types/core/kernel/coreKernel.d.ts +219 -0
  206. package/types/core/kernel/kernelInjector.d.ts +16 -0
  207. package/types/core/kernel/store.d.ts +170 -0
  208. package/types/core/logic/dom/char.d.ts +46 -0
  209. package/types/core/logic/dom/format.d.ts +234 -0
  210. package/types/core/logic/dom/html.d.ts +290 -0
  211. package/types/core/logic/dom/inline.d.ts +93 -0
  212. package/types/core/logic/dom/listFormat.d.ts +101 -0
  213. package/types/core/logic/dom/nodeTransform.d.ts +110 -0
  214. package/types/core/logic/dom/offset.d.ts +335 -0
  215. package/types/core/logic/dom/selection.d.ts +165 -0
  216. package/types/core/logic/panel/menu.d.ts +93 -0
  217. package/types/core/logic/panel/toolbar.d.ts +128 -0
  218. package/types/core/logic/panel/viewer.d.ts +89 -0
  219. package/types/core/logic/shell/_commandExecutor.d.ts +18 -0
  220. package/types/core/logic/shell/commandDispatcher.d.ts +65 -0
  221. package/types/core/logic/shell/component.d.ts +182 -0
  222. package/types/core/logic/shell/focusManager.d.ts +31 -0
  223. package/types/core/{base → logic/shell}/history.d.ts +13 -12
  224. package/types/core/logic/shell/pluginManager.d.ts +115 -0
  225. package/types/core/logic/shell/shortcuts.d.ts +131 -0
  226. package/types/core/logic/shell/ui.d.ts +261 -0
  227. package/types/core/schema/context.d.ts +104 -0
  228. package/types/core/schema/frameContext.d.ts +320 -0
  229. package/types/core/schema/options.d.ts +1241 -0
  230. package/types/core/section/constructor.d.ts +117 -652
  231. package/types/core/section/documentType.d.ts +43 -61
  232. package/types/events.d.ts +796 -65
  233. package/types/helper/clipboard.d.ts +5 -4
  234. package/types/helper/converter.d.ts +55 -43
  235. package/types/helper/dom/domCheck.d.ts +27 -19
  236. package/types/helper/dom/domQuery.d.ts +76 -57
  237. package/types/helper/dom/domUtils.d.ts +62 -39
  238. package/types/helper/dom/index.d.ts +87 -1
  239. package/types/helper/env.d.ts +16 -13
  240. package/types/helper/index.d.ts +8 -2
  241. package/types/helper/keyCodeMap.d.ts +24 -23
  242. package/types/helper/numbers.d.ts +4 -6
  243. package/types/helper/unicode.d.ts +4 -3
  244. package/types/hooks/base.d.ts +239 -0
  245. package/types/hooks/params.d.ts +65 -0
  246. package/types/index.d.ts +20 -117
  247. package/types/interfaces/contracts.d.ts +183 -0
  248. package/types/interfaces/index.d.ts +3 -0
  249. package/types/interfaces/plugins.d.ts +168 -0
  250. package/types/langs/_Lang.d.ts +2 -2
  251. package/types/langs/index.d.ts +2 -2
  252. package/types/modules/contract/Browser.d.ts +262 -0
  253. package/types/modules/contract/ColorPicker.d.ts +99 -0
  254. package/types/modules/contract/Controller.d.ts +204 -0
  255. package/types/modules/contract/Figure.d.ts +529 -0
  256. package/types/modules/{HueSlider.d.ts → contract/HueSlider.d.ts} +39 -28
  257. package/types/modules/contract/Modal.d.ts +62 -0
  258. package/types/modules/contract/index.d.ts +7 -0
  259. package/types/modules/manager/ApiManager.d.ts +106 -0
  260. package/types/modules/manager/FileManager.d.ts +124 -0
  261. package/types/modules/manager/index.d.ts +3 -0
  262. package/types/modules/ui/ModalAnchorEditor.d.ts +152 -0
  263. package/types/modules/ui/SelectMenu.d.ts +107 -0
  264. package/types/modules/{_DragHandle.d.ts → ui/_DragHandle.d.ts} +1 -0
  265. package/types/modules/ui/index.d.ts +4 -0
  266. package/types/plugins/browser/audioGallery.d.ts +33 -41
  267. package/types/plugins/browser/fileBrowser.d.ts +42 -50
  268. package/types/plugins/browser/fileGallery.d.ts +33 -41
  269. package/types/plugins/browser/imageGallery.d.ts +30 -37
  270. package/types/plugins/browser/videoGallery.d.ts +33 -41
  271. package/types/plugins/command/blockquote.d.ts +4 -21
  272. package/types/plugins/command/exportPDF.d.ts +23 -33
  273. package/types/plugins/command/fileUpload.d.ts +80 -100
  274. package/types/plugins/command/list_bulleted.d.ts +9 -35
  275. package/types/plugins/command/list_numbered.d.ts +9 -35
  276. package/types/plugins/dropdown/align.d.ts +23 -46
  277. package/types/plugins/dropdown/backgroundColor.d.ts +35 -53
  278. package/types/plugins/dropdown/blockStyle.d.ts +45 -0
  279. package/types/plugins/dropdown/font.d.ts +18 -41
  280. package/types/plugins/dropdown/fontColor.d.ts +35 -53
  281. package/types/plugins/dropdown/hr.d.ts +26 -52
  282. package/types/plugins/dropdown/layout.d.ts +19 -25
  283. package/types/plugins/dropdown/lineHeight.d.ts +21 -39
  284. package/types/plugins/dropdown/list.d.ts +6 -34
  285. package/types/plugins/dropdown/paragraphStyle.d.ts +34 -45
  286. package/types/plugins/dropdown/table/index.d.ts +158 -0
  287. package/types/plugins/dropdown/table/render/table.html.d.ts +71 -0
  288. package/types/plugins/dropdown/table/render/table.menu.d.ts +59 -0
  289. package/types/plugins/dropdown/table/services/table.cell.d.ts +76 -0
  290. package/types/plugins/dropdown/table/services/table.clipboard.d.ts +26 -0
  291. package/types/plugins/dropdown/table/services/table.grid.d.ts +77 -0
  292. package/types/plugins/dropdown/table/services/table.resize.d.ts +72 -0
  293. package/types/plugins/dropdown/table/services/table.selection.d.ts +59 -0
  294. package/types/plugins/dropdown/table/services/table.style.d.ts +162 -0
  295. package/types/plugins/dropdown/table/shared/table.constants.d.ts +134 -0
  296. package/types/plugins/dropdown/table/shared/table.utils.d.ts +91 -0
  297. package/types/plugins/dropdown/template.d.ts +19 -25
  298. package/types/plugins/dropdown/textStyle.d.ts +23 -30
  299. package/types/plugins/field/mention.d.ts +66 -72
  300. package/types/plugins/index.d.ts +41 -40
  301. package/types/plugins/input/fontSize.d.ts +57 -96
  302. package/types/plugins/input/pageNavigator.d.ts +5 -8
  303. package/types/plugins/modal/audio.d.ts +60 -153
  304. package/types/plugins/modal/drawing.d.ts +16 -118
  305. package/types/plugins/modal/embed.d.ts +46 -166
  306. package/types/plugins/modal/image/index.d.ts +281 -0
  307. package/types/plugins/modal/image/render/image.html.d.ts +45 -0
  308. package/types/plugins/modal/image/services/image.size.d.ts +55 -0
  309. package/types/plugins/modal/image/services/image.upload.d.ts +24 -0
  310. package/types/plugins/modal/image/shared/image.constants.d.ts +17 -0
  311. package/types/plugins/modal/link.d.ts +46 -66
  312. package/types/plugins/modal/math.d.ts +17 -86
  313. package/types/plugins/modal/{video.d.ts → video/index.d.ts} +89 -221
  314. package/types/plugins/modal/video/render/video.html.d.ts +37 -0
  315. package/types/plugins/modal/video/services/video.size.d.ts +74 -0
  316. package/types/plugins/modal/video/services/video.upload.d.ts +19 -0
  317. package/types/plugins/popup/anchor.d.ts +8 -38
  318. package/types/suneditor.d.ts +55 -24
  319. package/types/typedef.d.ts +344 -228
  320. package/CONTRIBUTING.md +0 -186
  321. package/src/core/base/eventHandlers/handler_ww_key_input.js +0 -1200
  322. package/src/core/base/eventHandlers/handler_ww_mouse.js +0 -194
  323. package/src/core/base/eventManager.js +0 -1523
  324. package/src/core/class/component.js +0 -856
  325. package/src/core/class/format.js +0 -3433
  326. package/src/core/class/menu.js +0 -346
  327. package/src/core/class/selection.js +0 -610
  328. package/src/core/class/shortcuts.js +0 -98
  329. package/src/core/class/toolbar.js +0 -431
  330. package/src/core/class/ui.js +0 -424
  331. package/src/core/class/viewer.js +0 -750
  332. package/src/core/section/actives.js +0 -266
  333. package/src/core/section/context.js +0 -102
  334. package/src/editorInjector/_classes.js +0 -36
  335. package/src/editorInjector/_core.js +0 -87
  336. package/src/editorInjector/index.js +0 -73
  337. package/src/modules/ApiManager.js +0 -191
  338. package/src/modules/Controller.js +0 -474
  339. package/src/modules/Modal.js +0 -346
  340. package/src/modules/index.js +0 -14
  341. package/src/plugins/dropdown/table.js +0 -4034
  342. package/src/plugins/modal/image.js +0 -1376
  343. package/src/plugins/modal/video.js +0 -1226
  344. package/types/core/base/eventHandlers/handler_toolbar.d.ts +0 -41
  345. package/types/core/base/eventHandlers/handler_ww_clipboard.d.ts +0 -40
  346. package/types/core/base/eventHandlers/handler_ww_dragDrop.d.ts +0 -35
  347. package/types/core/base/eventHandlers/handler_ww_key_input.d.ts +0 -45
  348. package/types/core/base/eventHandlers/handler_ww_mouse.d.ts +0 -39
  349. package/types/core/base/eventManager.d.ts +0 -401
  350. package/types/core/class/char.d.ts +0 -61
  351. package/types/core/class/component.d.ts +0 -213
  352. package/types/core/class/format.d.ts +0 -623
  353. package/types/core/class/html.d.ts +0 -430
  354. package/types/core/class/menu.d.ts +0 -126
  355. package/types/core/class/nodeTransform.d.ts +0 -93
  356. package/types/core/class/offset.d.ts +0 -522
  357. package/types/core/class/selection.d.ts +0 -188
  358. package/types/core/class/shortcuts.d.ts +0 -142
  359. package/types/core/class/toolbar.d.ts +0 -189
  360. package/types/core/class/ui.d.ts +0 -164
  361. package/types/core/class/viewer.d.ts +0 -140
  362. package/types/core/section/actives.d.ts +0 -46
  363. package/types/core/section/context.d.ts +0 -45
  364. package/types/editorInjector/_classes.d.ts +0 -41
  365. package/types/editorInjector/_core.d.ts +0 -87
  366. package/types/editorInjector/index.d.ts +0 -69
  367. package/types/modules/ApiManager.d.ts +0 -125
  368. package/types/modules/Browser.d.ts +0 -326
  369. package/types/modules/ColorPicker.d.ts +0 -135
  370. package/types/modules/Controller.d.ts +0 -251
  371. package/types/modules/Figure.d.ts +0 -517
  372. package/types/modules/FileManager.d.ts +0 -202
  373. package/types/modules/Modal.d.ts +0 -111
  374. package/types/modules/ModalAnchorEditor.d.ts +0 -236
  375. package/types/modules/SelectMenu.d.ts +0 -194
  376. package/types/modules/index.d.ts +0 -26
  377. package/types/plugins/dropdown/formatBlock.d.ts +0 -55
  378. package/types/plugins/dropdown/table.d.ts +0 -627
  379. package/types/plugins/modal/image.d.ts +0 -451
  380. /package/{LICENSE → LICENSE.txt} +0 -0
@@ -1,1692 +1,264 @@
1
- import { env, converter, dom, numbers } from '../helper';
2
- import Constructor, { InitOptions, UpdateButton, CreateShortcuts, CreateStatusbar, OPTION_FRAME_FIXED_FLAG, OPTION_FIXED_FLAG } from './section/constructor';
3
- import { UpdateStatusbarContext } from './section/context';
4
- import { BASIC_COMMANDS, ACTIVE_EVENT_COMMANDS, SELECT_ALL, DIR_BTN_ACTIVE, SAVE, COPY_FORMAT, FONT_STYLE, PAGE_BREAK } from './section/actives';
5
- import History from './base/history';
6
- import EventManager from './base/eventManager';
7
- import Events from '../events';
8
- import DocumentType from './section/documentType';
9
-
10
- // class injector
11
- import ClassInjector from '../editorInjector/_classes';
12
-
13
- // classes
14
- import Char from './class/char';
15
- import Component from './class/component';
16
- import Format from './class/format';
17
- import HTML from './class/html';
18
- import Menu from './class/menu';
19
- import NodeTransform from './class/nodeTransform';
20
- import Offset from './class/offset';
21
- import Selection_ from './class/selection';
22
- import Shortcuts from './class/shortcuts';
23
- import Toolbar from './class/toolbar';
24
- import UI from './class/ui';
25
- import Viewer from './class/viewer';
26
-
27
- const COMMAND_BUTTONS = '.se-menu-list .se-toolbar-btn[data-command]';
28
- const DISABLE_BUTTONS_CODEVIEW = `${COMMAND_BUTTONS}:not([class~="se-code-view-enabled"]):not([data-type="MORE"])`;
29
- const DISABLE_BUTTONS_CONTROLLER = `${COMMAND_BUTTONS}:not([class~="se-component-enabled"]):not([data-type="MORE"])`;
1
+ import { env, converter, dom } from '../helper';
2
+ import Constructor from './section/constructor';
30
3
 
31
- /**
32
- * @typedef {import('./section/constructor').EditorInitOptions} EditorInitOptions_editor
33
- */
34
-
35
- /**
36
- * @typedef {import('./section/constructor').EditorFrameOptions} EditorFrameOptions_editor
37
- */
4
+ // type
5
+ import DocumentType from './section/documentType';
38
6
 
39
- /**
40
- * @typedef {import('../modules/Controller').ControllerInfo} ControllerInfo_editor
41
- */
7
+ // kernel
8
+ import CoreKernel from './kernel/coreKernel';
42
9
 
43
10
  /**
44
- * @constructor
45
- * @description SunEditor constructor function.
46
- * @param {Array<{target: Element, key: *, options: EditorFrameOptions_editor}>} multiTargets Target element
47
- * @param {EditorInitOptions_editor} options options
11
+ * @description SunEditor class.
48
12
  */
49
- function Editor(multiTargets, options) {
50
- const _d = multiTargets[0].target.ownerDocument || env._d;
51
- const _w = _d.defaultView || env._w;
52
- const product = Constructor(multiTargets, options);
53
-
54
- /**
55
- * @description Frame root key array
56
- * @type {Array<*>}
57
- */
58
- this.rootKeys = product.rootKeys;
59
-
60
- /**
61
- * @description Frame root map
62
- * @type {Map<*, __se__FrameContext>}
63
- */
64
- this.frameRoots = product.frameRoots;
65
-
66
- /**
67
- * @description Editor context object
68
- * @type {__se__Context}
69
- */
70
- this.context = product.context;
71
-
72
- /**
73
- * @description Current focusing frame context
74
- * @type {__se__FrameContext}
75
- */
76
- this.frameContext = new Map();
77
-
78
- /**
79
- * @description Current focusing frame context options
80
- * @type {__se__FrameOptions}
81
- */
82
- this.frameOptions = new Map();
83
-
84
- /**
85
- * @description Document object
86
- * @type {Document}
87
- */
88
- this._d = _d;
89
-
90
- /**
91
- * @description Window object
92
- * @type {Window}
93
- */
94
- this._w = _w;
95
-
96
- /**
97
- * @description Controllers carrier
98
- * @type {HTMLElement}
99
- */
100
- this.carrierWrapper = product.carrierWrapper;
101
-
102
- /**
103
- * @description Editor options
104
- * @type {Map<string, *>}
105
- */
106
- this.options = product.options;
107
-
108
- /**
109
- * @description Plugins
110
- * @type {Object<string, *>}
111
- */
112
- this.plugins = product.plugins || {};
113
-
114
- /**
115
- * @description Events object, call by triggerEvent function
116
- * @type {Object<string, *>}
117
- */
118
- this.events = null;
119
-
120
- /**
121
- * @description Call the event function by injecting self: this.
122
- * @type {(eventName: string, ...args: *) => Promise<*>}
123
- */
124
- this.triggerEvent = null;
125
-
126
- /**
127
- * @description Default icons object
128
- * @type {Object<string, string>}
129
- */
130
- this.icons = product.icons;
131
-
132
- /**
133
- * @description loaded language
134
- * @type {Object<string, *>}
135
- */
136
- this.lang = product.lang;
137
-
138
- /**
139
- * @description Variables used internally in editor operation
140
- * @type {__se__EditorStatus}
141
- */
142
- this.status = {
143
- hasFocus: false,
144
- tabSize: 4,
145
- indentSize: 25,
146
- codeIndentSize: 2,
147
- currentNodes: [],
148
- currentNodesMap: [],
149
- onSelected: false,
150
- rootKey: product.rootId,
151
- _range: null,
152
- _onMousedown: false
153
- };
154
-
155
- /**
156
- * @description Is classic mode?
157
- * @type {boolean}
158
- */
159
- this.isClassic = false;
160
-
161
- /**
162
- * @description Is inline mode?
163
- * @type {boolean}
164
- */
165
- this.isInline = false;
166
-
167
- /**
168
- * @description Is balloon|balloon-always mode?
169
- * @type {boolean}
170
- */
171
- this.isBalloon = false;
172
-
173
- /**
174
- * @description Is balloon-always mode?
175
- * @type {boolean}
176
- */
177
- this.isBalloonAlways = false;
178
-
179
- /**
180
- * @description Is subToolbar balloon|balloon-always mode?
181
- * @type {boolean}
182
- */
183
- this.isSubBalloon = false;
184
-
185
- /**
186
- * @description Is subToolbar balloon-always mode?
187
- * @type {boolean}
188
- */
189
- this.isSubBalloonAlways = false;
190
-
191
- /**
192
- * @description All command buttons map
193
- * @type {Map<string, HTMLElement>}
194
- */
195
- this.allCommandButtons = new Map();
196
-
197
- /**
198
- * @description All command buttons map
199
- * @type {Map<string, HTMLElement>}
200
- */
201
- this.subAllCommandButtons = new Map();
202
-
203
- /**
204
- * @description Shoutcuts key map
205
- * @type {Map<string, *>}
206
- */
207
- this.shortcutsKeyMap = new Map();
208
-
209
- /**
210
- * @description Shoutcuts reverse key array
211
- * - An array of key codes generated with the reverseButtons option, used to reverse the action for a specific key combination.
212
- * @type {Array<string>}
213
- */
214
- this.reverseKeys = [];
215
-
216
- /**
217
- * @description A map with the plugin's buttons having an "active" method and the default command buttons with an "active" action.
218
- * - Each button is contained in an array.
219
- * @type {Map<string, Array<HTMLButtonElement>>}
220
- */
221
- this.commandTargets = new Map();
222
-
223
- /**
224
- * @description Plugins array with "active" method.
225
- * - "activeCommands" runs the "add" method when creating the editor.
226
- * @type {Array<string>}
227
- */
228
- this.activeCommands = null;
229
-
230
- /**
231
- * @description The selection node (selection.getNode()) to which the effect was last applied
232
- * @type {Node|null}
233
- */
234
- this.effectNode = null;
235
-
236
- /**
237
- * @description Currently open "Modal" instance
238
- * @type {*}
239
- */
240
- this.opendModal = null;
241
-
242
- /**
243
- * @description Currently open "Controller" info array
244
- * @type {Array<ControllerInfo_editor>}
245
- */
246
- this.opendControllers = [];
247
-
248
- /**
249
- * @description Currently open "Controller" caller plugin name
250
- */
251
- this.currentControllerName = '';
252
-
253
- /**
254
- * @description Currently open "Browser" instance
255
- * @type {*}
256
- */
257
- this.opendBrowser = null;
258
-
259
- /**
260
- * @description Whether "SelectMenu" is open
261
- * @type {boolean}
262
- */
263
- this.selectMenuOn = false;
264
-
265
- // ------ base ------
266
- /** @description History class instance @type {ReturnType<typeof import('./base/history').default>} */
267
- this.history = null;
268
- /** @description EventManager class instance @type {import('./base/eventManager').default} */
269
- this.eventManager = null;
270
-
271
- // ------ class ------
272
- /** @description Toolbar class instance @type {import('./class/toolbar').default} */
273
- this.toolbar = null;
274
- /** @description Sub-Toolbar class instance @type {import('./class/toolbar').default|null} */
275
- this.subToolbar = null;
276
- /** @description Char class instance @type {import('./class/char').default} */
277
- this.char = null;
278
- /** @description Component class instance @type {import('./class/component').default} */
279
- this.component = null;
280
- /** @description Format class instance @type {import('./class/format').default} */
281
- this.format = null;
282
- /** @description HTML class instance @type {import('./class/html').default} */
283
- this.html = null;
284
- /** @description Menu class instance @type {import('./class/menu').default} */
285
- this.menu = null;
286
- /** @description NodeTransform class instance @type {import('./class/nodeTransform').default} */
287
- this.nodeTransform = null;
288
- /** @description Offset class instance @type {import('./class/offset').default} */
289
- this.offset = null;
290
- /** @description Selection class instance @type {import('./class/selection').default} */
291
- this.selection = null;
292
- /** @description Shortcuts class instance @type {import('./class/shortcuts').default} */
293
- this.shortcuts = null;
294
- /** @description UI class instance @type {import('./class/ui').default} */
295
- this.ui = null;
296
- /** @description Viewer class instance @type {import('./class/viewer').default} */
297
- this.viewer = null;
298
-
299
- // ------------------------------------------------------- private properties -------------------------------------------------------
300
- /**
301
- * @description Line breaker (top)
302
- * @type {HTMLElement}
303
- */
304
- this._lineBreaker_t = null;
305
-
306
- /**
307
- * @description Line breaker (bottom)
308
- * @type {HTMLElement}
309
- */
310
- this._lineBreaker_b = null;
311
-
312
- /**
313
- * @description Closest ShadowRoot to editor if found
314
- * @type {ShadowRoot & { getSelection?: () => Selection }} - Chromium-based browsers (Chrome, Edge, etc.) has a getSelection method on the ShadowRoot
315
- */
316
- this._shadowRoot = null;
317
-
318
- /**
319
- * @description Plugin call event map
320
- * @type {Map<string, Array<((...args: *) => *) & { index: number }>>}
321
- */
322
- this._onPluginEvents = null;
323
-
324
- /**
325
- * @description Copy format info
326
- * - eventManager.__cacheStyleNodes copied
327
- * @type {Array<Node>|null}
328
- */
329
- this._onCopyFormatInfo = null;
330
-
331
- /**
332
- * @description Copy format init method
333
- * @type {(...args: *) => *|null}
334
- */
335
- this._onCopyFormatInitMethod = null;
336
-
337
- /**
338
- * @description Controller target's frame div (editor.frameContext.get('topArea'))
339
- * @type {HTMLElement|null}
340
- */
341
- this._controllerTargetContext = null;
342
-
343
- /**
344
- * @description List of buttons that are disabled when "controller" is opened
345
- * @type {Array<HTMLButtonElement|HTMLInputElement>}
346
- */
347
- this._controllerOnDisabledButtons = [];
348
-
349
- /**
350
- * @description List of buttons that are disabled when "codeView" mode opened
351
- * @type {Array<HTMLButtonElement|HTMLInputElement>}
352
- */
353
- this._codeViewDisabledButtons = [];
354
-
355
- /**
356
- * @description List of buttons to run plugins in the toolbar
357
- * @type {Array<HTMLElement>}
358
- */
359
- this._pluginCallButtons = product.pluginCallButtons;
360
-
361
- /**
362
- * @description List of buttons to run plugins in the Sub-Toolbar
363
- * @type {Array<HTMLElement>}
364
- */
365
- this._pluginCallButtons_sub = product.pluginCallButtons_sub;
366
-
367
- /**
368
- * @description Responsive Toolbar Button Structure array
369
- * @type {Array<*>}
370
- */
371
- this._responsiveButtons = product.responsiveButtons;
372
-
373
- /**
374
- * @description Responsive Sub-Toolbar Button Structure array
375
- * @type {Array<*>}
376
- */
377
- this._responsiveButtons_sub = product.responsiveButtons_sub;
378
-
379
- /**
380
- * @description Variable that controls the "blur" event in the editor of inline or balloon mode when the focus is moved to dropdown
381
- * @type {boolean}
382
- */
383
- this._notHideToolbar = false;
384
-
385
- /**
386
- * @description Variables for controlling blur events
387
- * @type {boolean}
388
- */
389
- this._preventBlur = false;
390
-
391
- /**
392
- * @description Variables for controlling focus events
393
- * @type {boolean}
394
- */
395
- this._preventFocus = false;
396
-
397
- /**
398
- * @description Variables for controlling selection change events
399
- */
400
- this._preventSelection = false;
401
-
402
- /**
403
- * @description If true, initialize all indexes of image, video information
404
- * @type {boolean}
405
- */
406
- this._componentsInfoInit = true;
407
-
408
- /**
409
- * @description If true, reset all indexes of image, video information
410
- * @type {boolean}
411
- */
412
- this._componentsInfoReset = false;
413
-
414
- /**
415
- * @description plugin retainFormat info Map()
416
- * @type {Map<string, ((...args: *) => *)>}
417
- */
418
- this._MELInfo = null;
419
-
420
- /**
421
- * @description Properties for managing files in the "FileManager" module
422
- * @type {Array<*>}
423
- */
424
- this._fileInfoPluginsCheck = null;
425
-
426
- /**
427
- * @description Properties for managing files in the "FileManager" module
428
- * @type {Array<*>}
429
- */
430
- this._fileInfoPluginsReset = null;
431
-
432
- /**
433
- * @description Variables for file component management
434
- * @type {Object<string, *>}
435
- */
436
- this._fileManager = {
437
- tags: null,
438
- regExp: null,
439
- pluginRegExp: null,
440
- pluginMap: null
441
- };
442
-
443
- /**
444
- * @description Variables for managing the components
445
- * @type {Array<*>}
446
- */
447
- this._componentManager = [];
448
-
449
- /**
450
- * @description Current Figure container.
451
- * @type {HTMLElement|null}
452
- */
453
- this._figureContainer = null;
454
-
455
- /**
456
- * @description Origin options
457
- * @type {EditorInitOptions_editor}
458
- */
459
- this._originOptions = options;
460
-
461
- /** ----- Create editor ------------------------------------------------------------ */
462
- this.__Create(options);
463
- }
464
-
465
- Editor.prototype = {
466
- /**
467
- * @description If the plugin is not added, add the plugin and call the 'add' function.
468
- * - If the plugin is added call callBack function.
469
- * @param {string} pluginName The name of the plugin to call
470
- * @param {?Array<HTMLElement>} targets Plugin target button (This is not necessary if you have a button list when creating the editor)
471
- * @param {?Object<string, *>} pluginOptions Plugin's options
472
- */
473
- registerPlugin(pluginName, targets, pluginOptions) {
474
- let plugin = this.plugins[pluginName];
475
- if (!plugin) {
476
- throw Error(`[SUNEDITOR.registerPlugin.fail] The called plugin does not exist or is in an invalid format. (pluginName: "${pluginName}")`);
477
- } else if (typeof this.plugins[pluginName] === 'function') {
478
- plugin = this.plugins[pluginName] = new this.plugins[pluginName](this, pluginOptions || {});
479
- if (typeof plugin.init === 'function') plugin.init();
480
- }
13
+ class Editor {
14
+ #kernel;
481
15
 
482
- if (targets) {
483
- for (let i = 0, len = targets.length; i < len; i++) {
484
- UpdateButton(targets[i], plugin, this.icons, this.lang);
485
- }
486
-
487
- if (!this.activeCommands.includes(pluginName) && typeof this.plugins[pluginName].active === 'function') {
488
- this.activeCommands.push(pluginName);
489
- }
490
- }
491
- },
16
+ /** @type {SunEditor.Deps} */
17
+ $;
492
18
 
493
19
  /**
494
- * @description Run plugin calls and basic commands.
495
- * @param {string} command Command string
496
- * @param {string} type Display type string ('command', 'dropdown', 'modal', 'container')
497
- * @param {?Node=} button The element of command button
20
+ * @constructor
21
+ * @description SunEditor constructor function.
22
+ * @param {Array<{target: Element, key: *, options: SunEditor.InitFrameOptions}>} multiTargets Target element
23
+ * @param {SunEditor.InitOptions} options options
498
24
  */
499
- run(command, type, button) {
500
- if (type) {
501
- if (/more/i.test(type)) {
502
- const toolbar = dom.query.getParentElement(button, '.se-toolbar');
503
- const toolInst = dom.utils.hasClass(toolbar, 'se-toolbar-sub') ? this.subToolbar : this.toolbar;
504
- if (button !== toolInst.currentMoreLayerActiveButton) {
505
- const layer = toolbar.querySelector('.' + command);
506
- if (layer) {
507
- toolInst._moreLayerOn(button, layer);
508
- toolInst._showBalloon();
509
- toolInst._showInline();
510
- }
511
- dom.utils.addClass(button, 'on');
512
- } else if (toolInst.currentMoreLayerActiveButton) {
513
- toolInst._moreLayerOff();
514
- toolInst._showBalloon();
515
- toolInst._showInline();
516
- }
25
+ constructor(multiTargets, options) {
26
+ const product = Constructor(multiTargets, options);
517
27
 
518
- this.viewer._resetFullScreenHeight();
519
- return;
520
- }
28
+ // CoreKernel
29
+ const kernel = new CoreKernel(this, { product, options });
30
+ this.#kernel = kernel;
521
31
 
522
- if (/container/.test(type) && (this.menu.targetMap[command] === null || button !== this.menu.currentContainerActiveButton)) {
523
- this.menu.containerOn(button);
524
- return;
525
- }
32
+ this.$ = kernel.$;
526
33
 
527
- if (this.frameContext.get('isReadOnly') && dom.utils.arrayIncludes(this._controllerOnDisabledButtons, button)) return;
528
- if (/dropdown/.test(type) && (this.menu.targetMap[command] === null || button !== this.menu.currentDropdownActiveButton)) {
529
- this.menu.dropdownOn(button);
530
- return;
531
- } else if (/modal/.test(type)) {
532
- this.plugins[command].open(button);
533
- return;
534
- } else if (/command/.test(type)) {
535
- this.plugins[command].action(button);
536
- } else if (/browser/.test(type)) {
537
- this.plugins[command].open(null);
538
- } else if (/popup/.test(type)) {
539
- this.plugins[command].show();
540
- }
541
- } else if (command) {
542
- this.commandHandler(command, button);
543
- }
544
-
545
- if (/dropdown/.test(type)) {
546
- this.menu.dropdownOff();
547
- } else if (!/command/.test(type)) {
548
- this.menu.dropdownOff();
549
- this.menu.containerOff();
550
- }
551
- },
552
-
553
- /**
554
- * @description Execute default command of command button
555
- * - (selectAll, codeView, fullScreen, indent, outdent, undo, redo, removeFormat, print, preview, showBlocks, save, bold, underline, italic, strike, subscript, superscript, copy, cut, paste)
556
- * @param {string} command Property of command button (data-value)
557
- * @param {?Node=} button Command button
558
- * @returns {Promise<void>}
559
- */
560
- async commandHandler(command, button) {
561
- if (this.frameContext.get('isReadOnly') && !/copy|cut|selectAll|codeView|fullScreen|print|preview|showBlocks/.test(command)) return;
562
-
563
- switch (command) {
564
- case 'selectAll':
565
- SELECT_ALL(this);
566
- break;
567
- case 'copy': {
568
- const range = this.selection.getRange();
569
- if (range.collapsed) break;
570
-
571
- const container = dom.utils.createElement('div', null, range.cloneContents());
572
- await this.html.copy(container.innerHTML);
573
-
574
- break;
575
- }
576
- case 'newDocument':
577
- this.html.set(`<${this.options.get('defaultLine')}><br></${this.options.get('defaultLine')}>`);
578
- this.focus();
579
- this.history.push(false);
580
- break;
581
- case 'codeView':
582
- this.viewer.codeView(!this.frameContext.get('isCodeView'));
583
- break;
584
- case 'fullScreen':
585
- this.viewer.fullScreen(!this.frameContext.get('isFullScreen'));
586
- break;
587
- case 'indent':
588
- this.format.indent();
589
- break;
590
- case 'outdent':
591
- this.format.outdent();
592
- break;
593
- case 'undo':
594
- this.history.undo();
595
- break;
596
- case 'redo':
597
- this.history.redo();
598
- break;
599
- case 'removeFormat':
600
- this.format.removeInlineElement();
601
- this.focus();
602
- break;
603
- case 'print':
604
- this.viewer.print();
605
- break;
606
- case 'preview':
607
- this.viewer.preview();
608
- break;
609
- case 'showBlocks':
610
- this.viewer.showBlocks(!this.frameContext.get('isShowBlocks'));
611
- break;
612
- case 'dir':
613
- this.setDir(this.options.get('_rtl') ? 'ltr' : 'rtl');
614
- break;
615
- case 'dir_ltr':
616
- this.setDir('ltr');
617
- break;
618
- case 'dir_rtl':
619
- this.setDir('rtl');
620
- break;
621
- case 'save':
622
- await SAVE(this);
623
- break;
624
- case 'copyFormat':
625
- COPY_FORMAT(this, button);
626
- break;
627
- case 'pageBreak':
628
- PAGE_BREAK(this);
629
- break;
630
- case 'pageUp':
631
- this.frameContext.get('documentType').pageUp();
632
- break;
633
- case 'pageDown':
634
- this.frameContext.get('documentType').pageDown();
635
- break;
636
- default:
637
- FONT_STYLE(this, command);
638
- }
639
- },
640
-
641
- /**
642
- * @description Execute "editor.run" with command button.
643
- * @param {Node} target Command target
644
- */
645
- runFromTarget(target) {
646
- if (dom.check.isInputElement(target)) return;
647
-
648
- const targetBtn = /** @type {HTMLButtonElement} */ (dom.query.getCommandTarget(target));
649
- if (!targetBtn) return;
650
-
651
- const command = targetBtn.getAttribute('data-command');
652
- const type = targetBtn.getAttribute('data-type');
653
-
654
- if (!command && !type) return;
655
- if (targetBtn.disabled) return;
656
-
657
- this.run(command, type, target);
658
- },
659
-
660
- /**
661
- * @description It is executed by inserting the button of commandTargets as the argument value of the "f" function.
662
- * - "func" is called as long as the button array's length.
663
- * @param {string} cmd data-command
664
- * @param {(...args: *) => *} func Function.
665
- */
666
- applyCommandTargets(cmd, func) {
667
- if (this.commandTargets.has(cmd)) {
668
- this.commandTargets.get(cmd).forEach(func);
669
- }
670
- },
671
-
672
- /**
673
- * @description Execute a function by traversing all root targets.
674
- * @param {(...args: *) => *} f Function
675
- */
676
- applyFrameRoots(f) {
677
- this.frameRoots.forEach(f);
678
- },
34
+ this.#Create(options).catch((e) => {
35
+ console.error('[SUNEDITOR:E_CREATE_FAIL] Failed to create editor instance.', e);
36
+ });
37
+ }
679
38
 
680
39
  /**
681
40
  * @description Checks if the content of the editor is empty.
682
41
  * - Display criteria for "placeholder".
683
- * @param {?__se__FrameContext=} fc Frame context, if not present, currently selected frame context.
42
+ * @param {?SunEditor.FrameContext} [fc] Frame context, if not present, currently selected frame context.
684
43
  * @returns {boolean}
685
44
  */
686
45
  isEmpty(fc) {
687
- fc = fc || this.frameContext;
688
- const wysiwyg = fc.get('wysiwyg');
689
- return dom.check.isZeroWidth(wysiwyg.textContent) && !wysiwyg.querySelector(this.options.get('allowedEmptyTags')) && (wysiwyg.innerText.match(/\n/g) || '').length <= 1;
690
- },
691
-
692
- /**
693
- * @description Set direction to "rtl" or "ltr".
694
- * @param {string} dir "rtl" or "ltr"
695
- */
696
- setDir(dir) {
697
- const rtl = dir === 'rtl';
698
- if (this.options.get('_rtl') === rtl) return;
699
-
700
- try {
701
- this.options.set('_rtl', rtl);
702
- this.ui._offCurrentController();
703
-
704
- const fc = this.frameContext;
705
- const plugins = this.plugins;
706
- for (const k in plugins) {
707
- if (typeof plugins[k].setDir === 'function') plugins[k].setDir(dir);
708
- }
709
-
710
- const toolbarWrapper = this.context.get('toolbar._wrapper');
711
- const statusbarWrapper = this.context.get('statusbar._wrapper');
712
- if (rtl) {
713
- this.applyFrameRoots((e) => {
714
- dom.utils.addClass([e.get('topArea'), e.get('wysiwyg'), e.get('documentTypePageMirror')], 'se-rtl');
715
- });
716
- dom.utils.addClass([this.carrierWrapper, toolbarWrapper, statusbarWrapper], 'se-rtl');
717
- } else {
718
- this.applyFrameRoots((e) => {
719
- dom.utils.removeClass([e.get('topArea'), e.get('wysiwyg'), e.get('documentTypePageMirror')], 'se-rtl');
720
- });
721
- dom.utils.removeClass([this.carrierWrapper, toolbarWrapper, statusbarWrapper], 'se-rtl');
722
- }
723
-
724
- const lineNodes = dom.query.getListChildren(fc.get('wysiwyg'), (current) => {
725
- return this.format.isLine(current) && !!(current.style.marginRight || current.style.marginLeft || current.style.textAlign);
726
- });
727
-
728
- for (let i = 0, n, l, r; (n = lineNodes[i]); i++) {
729
- n = lineNodes[i];
730
- // indent margin
731
- r = n.style.marginRight;
732
- l = n.style.marginLeft;
733
- if (r || l) {
734
- n.style.marginRight = l;
735
- n.style.marginLeft = r;
736
- }
737
- // text align
738
- r = n.style.textAlign;
739
- if (r === 'left') n.style.textAlign = 'right';
740
- else if (r === 'right') n.style.textAlign = 'left';
741
- }
742
-
743
- DIR_BTN_ACTIVE(this, rtl);
744
-
745
- // document type
746
- if (fc.has('documentType-use-header')) {
747
- if (rtl) fc.get('wrapper').appendChild(fc.get('documentTypeInner'));
748
- else fc.get('wrapper').insertBefore(fc.get('documentTypeInner'), fc.get('wysiwygFrame'));
749
- }
750
- if (fc.has('documentType-use-page')) {
751
- if (rtl) fc.get('wrapper').insertBefore(fc.get('documentTypePage'), fc.get('wysiwygFrame'));
752
- else fc.get('wrapper').appendChild(fc.get('documentTypePage'));
753
- }
754
-
755
- if (this.isBalloon) this.toolbar._showBalloon();
756
- else if (this.isSubBalloon) this.subToolbar._showBalloon();
757
- } catch (e) {
758
- this.options.set('_rtl', !rtl);
759
- console.warn(`[SUNEDITOR.setDir.fail] ${e.toString()}`);
760
- }
761
-
762
- this.effectNode = null;
763
- this.eventManager.applyTagEffect();
764
- },
46
+ const wysiwyg = (fc || this.$.frameContext).get('wysiwyg');
47
+ return dom.check.isZeroWidth(wysiwyg.textContent) && !wysiwyg.querySelector(this.$.options.get('allowedEmptyTags')) && (wysiwyg.innerText.match(/\n/g) || '').length <= 1;
48
+ }
765
49
 
766
50
  /**
767
51
  * @description Add or reset option property (Editor is reloaded)
768
- * @param {EditorInitOptions_editor} newOptions Options
52
+ * @example
53
+ * // Change toolbar buttons and height
54
+ * editor.resetOptions({
55
+ * buttonList: [['bold', 'italic'], ['image']],
56
+ * height: '500px',
57
+ * });
58
+ * @param {SunEditor.InitOptions} newOptions Options
769
59
  */
770
60
  resetOptions(newOptions) {
771
- this.viewer.codeView(false);
772
- this.viewer.showBlocks(false);
61
+ this.$.optionProvider.reset(newOptions);
773
62
 
774
- const rootDiff = new Map();
775
- const frameRoots = this.frameRoots;
776
- const newRoots = [];
777
- const newRootKeys = new Map();
63
+ this.$.store.set('_lastSelectionNode', null);
64
+ this.#setFrameInfo(this.$.frameRoots.get(this.$.store.get('rootKey')));
778
65
 
779
- // frame roots
780
- const nRoot = {};
781
- for (const k in newOptions) {
782
- if (OPTION_FRAME_FIXED_FLAG[k] === undefined) continue;
783
- nRoot[k] = newOptions[k];
784
- delete newOptions[k];
66
+ // plugin hook
67
+ for (const plugin of Object.values(this.$.plugins)) {
68
+ plugin.init?.();
785
69
  }
786
- for (const rootKey of frameRoots.keys()) {
787
- newOptions[rootKey || ''] = { ...nRoot, ...newOptions[rootKey || ''] };
788
- }
789
-
790
- // check reoption validation
791
- const newOptionKeys = Object.keys(newOptions);
792
- CheckResetKeys(newOptionKeys, this.plugins, '');
793
- if (newOptionKeys.length === 0) return;
794
-
795
- if (frameRoots.size === 1) {
796
- newOptionKeys.unshift(null);
797
- }
798
-
799
- // option merge
800
- const _originOptions = [this._originOptions, newOptions].reduce((init, option) => {
801
- for (const key in option) {
802
- if (frameRoots.has(key || null)) {
803
- RestoreFrameOptions(key, option, frameRoots, rootDiff, newRootKeys, newRoots);
804
- } else {
805
- init[key] = option[key];
806
- }
807
- }
808
- return init;
809
- }, {});
810
-
811
- // init options
812
- const options = this.options;
813
- const newO = InitOptions(_originOptions, newRoots, this.plugins);
814
- const newOptionMap = newO.o;
815
- const newFrameMap = newO.frameMap;
816
- /** --------- [root start] --------- */
817
- for (let i = 0, len = newOptionKeys.length, k; i < len; i++) {
818
- k = newOptionKeys[i] || null;
819
-
820
- if (newRootKeys.has(k)) {
821
- const diff = rootDiff.get(k);
822
- const fc = frameRoots.get(k);
823
- const originOptions = fc.get('options');
824
- const newRootOptions = newFrameMap.get(k);
825
-
826
- // --- set options : fc ---
827
- fc.set('options', newRootOptions);
828
-
829
- // statusbar-changed
830
- if (diff.has('statusbar-changed')) {
831
- // statusbar
832
- dom.utils.removeItem(fc.get('statusbar'));
833
- if (newRootOptions.get('statusbar')) {
834
- const statusbar = CreateStatusbar(newRootOptions, null).statusbar;
835
- fc.get('container').appendChild(statusbar);
836
- UpdateStatusbarContext(statusbar, fc);
837
- this.eventManager.__addStatusbarEvent(fc, newRootOptions);
838
- } else {
839
- this.eventManager.removeEvent(originOptions.get('__statusbarEvent'));
840
- newRootOptions.set('__statusbarEvent', null);
841
- UpdateStatusbarContext(null, fc);
842
- }
843
- // charCounter
844
- if (fc.get('statusbar')) {
845
- this.char.display(fc);
846
- }
847
- }
848
-
849
- // iframe's options
850
- if (diff.has('iframe_attributes')) {
851
- const frame = fc.get('wysiwygFrame');
852
- const originAttr = originOptions.get('iframe_attributes');
853
- const newAttr = newRootOptions.get('iframe_attributes');
854
- for (const origin_k in originAttr) frame.removeAttribute(origin_k, originAttr[origin_k]);
855
- for (const new_k in newAttr) frame.setAttribute(new_k, newAttr[new_k]);
856
- }
857
-
858
- if (diff.has('iframe_cssFileName')) {
859
- const docHead = fc.get('_wd').head;
860
- const links = docHead.getElementsByTagName('link');
861
- while (links[0]) docHead.removeChild(links[0]);
862
- const parseDocument = new DOMParser().parseFromString(converter._setIframeStyleLinks(newRootOptions.get('iframe_cssFileName')), 'text/html');
863
- const newLinks = parseDocument.head.children;
864
- const sTag = docHead.querySelector('style');
865
- while (newLinks[0]) docHead.insertBefore(newLinks[0], sTag);
866
- }
867
-
868
- if (diff.has('placeholder')) {
869
- fc.get('placeholder').textContent = newRootOptions.get('placeholder');
870
- }
871
-
872
- // frame styles
873
- this.ui.setEditorStyle(newRootOptions.get('editorStyle'), fc);
874
-
875
- // frame attributes
876
- const frame = fc.get('wysiwyg');
877
- const originAttr = originOptions.get('editableFrameAttributes');
878
- const newAttr = newRootOptions.get('editableFrameAttributes');
879
- for (const origin_k in originAttr) frame.removeAttribute(origin_k, originAttr[origin_k]);
880
- for (const new_k in newAttr) frame.setAttribute(new_k, newAttr[new_k]);
881
-
882
- continue;
883
- }
884
- /** --------- [root end] --------- */
885
-
886
- // --- set options ---
887
- options.set(k, newOptionMap.get(k));
888
-
889
- /** Options that require a function call */
890
- switch (k) {
891
- case 'theme': {
892
- this.ui.setTheme(options.get('theme'));
893
- break;
894
- }
895
- case 'events': {
896
- const events = options.get('events');
897
- for (const name in events) {
898
- this.events[name] = events[name];
899
- }
900
- break;
901
- }
902
- case 'autoStyleify': {
903
- this.html.__resetAutoStyleify(options.get('autoStyleify'));
904
- break;
905
- }
906
- case 'textDirection': {
907
- this.setDir(options.get('_rtl') ? 'ltr' : 'rtl');
908
- break;
909
- }
910
- case 'historyStackDelayTime': {
911
- this.history.resetDelayTime(options.get('historyStackDelayTime'));
912
- break;
913
- }
914
- case 'defaultLineBreakFormat': {
915
- this.format.__resetBrLineBreak(options.get('defaultLineBreakFormat'));
916
- }
917
- }
918
- }
919
-
920
- /** apply options */
921
- // _origin
922
- this._originOptions = _originOptions;
923
-
924
- // --- [toolbar] ---
925
- const toolbar = this.context.get('toolbar.main');
926
- // width
927
- if (/inline|balloon/i.test(options.get('mode')) && newOptionKeys.includes('toolbar_width')) {
928
- toolbar.style.width = options.get('toolbar_width');
929
- }
930
- // hide
931
- if (options.get('toolbar_hide')) {
932
- toolbar.style.display = 'none';
933
- } else {
934
- toolbar.style.display = '';
935
- }
936
- // shortcuts hint
937
- if (options.get('shortcutsHint')) {
938
- dom.utils.removeClass(toolbar, 'se-shortcut-hide');
939
- } else {
940
- dom.utils.addClass(toolbar, 'se-shortcut-hide');
941
- }
942
-
943
- this.effectNode = null;
944
- this._setFrameInfo(this.frameRoots.get(this.status.rootKey));
945
- },
70
+ }
946
71
 
947
72
  /**
948
73
  * @description Change the current root index.
949
- * @param {*} rootKey
74
+ * @example
75
+ * // Switch to the 'body' frame in a multi-root editor
76
+ * editor.changeFrameContext('body');
77
+ *
78
+ * // Switch back to the 'header' frame
79
+ * editor.changeFrameContext('header');
80
+ * @param {*} rootKey Root frame key.
950
81
  */
951
82
  changeFrameContext(rootKey) {
952
- if (rootKey === this.status.rootKey) return;
83
+ if (rootKey === this.$.store.get('rootKey')) return;
953
84
 
954
- this.status.rootKey = rootKey;
955
- this._setFrameInfo(this.frameRoots.get(rootKey));
956
- this.toolbar._resetSticky();
957
- },
85
+ this.$.store.set('rootKey', rootKey);
86
+ this.#setFrameInfo(this.$.frameRoots.get(rootKey));
87
+ this.$.toolbar._resetSticky();
88
+ }
958
89
 
959
90
  /**
960
- * @description javascript execCommand
961
- * @param {string} command javascript execCommand function property
962
- * @param {boolean=} showDefaultUI javascript execCommand function property
963
- * @param {string=} value javascript execCommand function property
91
+ * @description Destroy the suneditor
964
92
  */
965
- execCommand(command, showDefaultUI, value) {
966
- this.frameContext.get('_wd').execCommand(command, showDefaultUI, command === 'formatBlock' ? '<' + value + '>' : value);
967
- this.history.push(true);
968
- },
93
+ destroy() {
94
+ /** destroy external library */
95
+ if (this.$.options.get('hasCodeMirror')) {
96
+ this.$.contextProvider.applyToRoots((e) => {
97
+ const opts = e.get('options');
98
+ const cm6 = opts.get('codeMirror6Editor');
99
+ const cm5 = opts.get('codeMirror5Editor');
100
+ if (cm6) cm6.destroy();
101
+ else if (cm5) cm5.toTextArea();
102
+ });
103
+ }
969
104
 
970
- /**
971
- * @description Focus to wysiwyg area
972
- * @param {*} rootKey Root index
973
- */
974
- focus(rootKey) {
975
- if (rootKey) this.changeFrameContext(rootKey);
976
- if (this.frameContext.get('wysiwygFrame').style.display === 'none') return;
977
- this._preventBlur = false;
105
+ /** remove DOM elements */
106
+ dom.utils.removeItem(this.$.context.get('toolbar_wrapper'));
107
+ dom.utils.removeItem(this.$.context.get('toolbar_sub_wrapper'));
108
+ dom.utils.removeItem(this.$.context.get('statusbar_wrapper'));
978
109
 
979
- if (this.frameOptions.get('iframe') || !this.frameContext.get('wysiwyg').contains(this.selection.getNode())) {
980
- this._nativeFocus();
981
- } else {
982
- try {
983
- const range = this.selection.getRange();
984
- if (range.startContainer === range.endContainer && dom.check.isWysiwygFrame(range.startContainer)) {
985
- const currentNode = /** @type {HTMLElement} */ (range.commonAncestorContainer).children[range.startOffset];
986
- if (!this.format.isLine(currentNode) && !this.component.is(currentNode)) {
987
- const br = dom.utils.createElement('BR');
988
- const format = dom.utils.createElement(this.options.get('defaultLine'), null, br);
989
- this.frameContext.get('wysiwyg').insertBefore(format, currentNode);
990
- this.selection.setRange(br, 0, br, 0);
991
- return;
992
- }
993
- }
994
- this.selection.setRange(range.startContainer, range.startOffset, range.endContainer, range.endOffset);
995
- } catch (e) {
996
- console.warn('[SUNEDITOR.focus.warn] ', e);
997
- this._nativeFocus();
998
- }
110
+ /** clear events */
111
+ for (const k in this.events) {
112
+ this.events[k] = null;
999
113
  }
114
+ this.events = null;
1000
115
 
1001
- if (this.isBalloon) this.eventManager._toggleToolbarBalloon();
1002
- },
1003
-
1004
- /**
1005
- * @description If "focusEl" is a component, then that component is selected; if it is a format element, the last text is selected
1006
- * - If "focusEdge" is null, then selected last element
1007
- * @param {?Node=} focusEl Focus element
1008
- */
1009
- focusEdge(focusEl) {
1010
- this._preventBlur = false;
1011
- if (!focusEl) focusEl = this.frameContext.get('wysiwyg').lastElementChild;
116
+ /** destroy kernel (handles all internal cleanup) */
117
+ this.#kernel._destroy();
1012
118
 
1013
- const fileComponentInfo = this.component.get(focusEl);
1014
- if (fileComponentInfo) {
1015
- this.component.select(fileComponentInfo.target, fileComponentInfo.pluginName);
1016
- } else if (focusEl) {
1017
- if (focusEl.nodeType !== 3) {
1018
- focusEl = dom.query.getEdgeChild(
1019
- focusEl,
1020
- function (current) {
1021
- return current.childNodes.length === 0 || current.nodeType === 3;
1022
- },
1023
- true
1024
- );
1025
- }
1026
- if (!focusEl) this._nativeFocus();
1027
- else this.selection.setRange(focusEl, focusEl.textContent.length, focusEl, focusEl.textContent.length);
1028
- } else {
1029
- this.focus();
1030
- }
1031
- },
119
+ return null;
120
+ }
1032
121
 
1033
122
  /**
1034
- * @description Focusout to wysiwyg area (.blur())
123
+ * @description Set frameContext, frameOptions
124
+ * @param {SunEditor.FrameContext} rt Root target[key] FrameContext
1035
125
  */
1036
- blur() {
1037
- if (this.frameOptions.get('iframe')) {
1038
- this.frameContext.get('wysiwygFrame').blur();
1039
- } else {
1040
- this.frameContext.get('wysiwyg').blur();
1041
- }
1042
- },
126
+ #setFrameInfo(rt) {
127
+ this.$.contextProvider.reset(rt);
128
+ this.$.optionProvider.resetFrame(rt.get('options'));
129
+ this.$.ui.reset(rt);
130
+ }
1043
131
 
1044
132
  /**
1045
- * @description Destroy the suneditor
133
+ * @description Initializ editor
134
+ * @param {SunEditor.InitOptions} options Options
1046
135
  */
1047
- destroy() {
1048
- /** remove history */
1049
- this.history.destroy();
1050
-
1051
- /** remove event listeners */
1052
- this.eventManager._removeAllEvents();
136
+ #editorInit(options) {
137
+ this.$.store.set('initViewportHeight', env._w.visualViewport.height);
138
+ this.#kernel._eventOrchestrator.__setViewportSize();
1053
139
 
1054
- /** destroy external library */
1055
- if (this.options.get('codeMirror6Editor')) {
1056
- this.options.get('codeMirror6Editor').destroy();
1057
- }
140
+ this.$.contextProvider.init();
1058
141
 
1059
- /** remove element */
1060
- dom.utils.removeItem(this.carrierWrapper);
1061
- dom.utils.removeItem(this.context.get('toolbar._wrapper'));
1062
- dom.utils.removeItem(this.context.get('toolbar.sub._wrapper'));
1063
- dom.utils.removeItem(this.context.get('statusbar._wrapper'));
1064
- this.applyFrameRoots((e) => {
1065
- dom.utils.removeItem(e.get('topArea'));
1066
- e.get('options').clear();
1067
- e.clear();
142
+ // initialize core and add event listeners
143
+ this.#setFrameInfo(this.$.frameRoots.get(this.$.store.get('rootKey')));
144
+ this.#init(options);
145
+
146
+ this.$.contextProvider.applyToRoots((e) => {
147
+ this.#kernel._eventOrchestrator._addFrameEvents(e);
148
+ this.#initWysiwygArea(e, e.get('options').get('value'));
149
+ if (e.get('options').get('iframe') && e.get('options').get('height') === 'auto') {
150
+ this.$.ui._emitResizeEvent(e, e.get('wysiwygFrame').offsetHeight, null);
151
+ }
1068
152
  });
1069
153
 
1070
- /** remove object reference */
1071
- this.options.clear();
1072
- this.context.clear();
154
+ this.#kernel._eventOrchestrator.__eventDoc = null;
155
+ this.$.store._editorInitFinished = true;
156
+ this.$.pluginManager.checkFileInfo(true);
1073
157
 
1074
- let obj = this.plugins;
1075
- for (const k in obj) {
1076
- const p = obj[k];
1077
- if (typeof p._destroy === 'function') p._destroy();
1078
- for (const pk in p) {
1079
- delete p[pk];
1080
- }
1081
- delete obj[k];
1082
- }
1083
- obj = this.events;
1084
- for (const k in obj) {
1085
- delete obj[k];
1086
- }
158
+ // history reset
159
+ this.$.history.reset();
1087
160
 
1088
- obj = ['eventManager', 'char', 'component', 'format', 'html', 'menu', 'nodeTransform', 'offset', 'selection', 'shortcuts', 'toolbar', 'ui', 'viewer'];
1089
- for (let i = 0, len = obj.length, c; i < len; i++) {
1090
- c = this[obj[i]];
1091
- for (const k in c) {
1092
- delete c[k];
1093
- }
1094
- }
1095
- obj = this.subToolbar;
1096
- if (obj) {
1097
- for (const k in obj) {
1098
- delete obj[k];
161
+ // Defer post-init tasks (observers, history reset, plugin init, onload) to allow DOM to settle after iframe/wysiwyg insertion
162
+ env._w.setTimeout(() => {
163
+ // Check if instance was destroyed (e.g., in SSR with dynamic imports mistake)
164
+ if (!this.$.context?.size) {
165
+ console.warn('[SUNEDITOR:E_INIT_FAIL] Editor instance was destroyed before initialization completed. Check if destroy() was called.');
166
+ return;
1099
167
  }
1100
- }
1101
-
1102
- obj = null;
1103
- for (const k in this) {
1104
- delete this[k];
1105
- }
1106
-
1107
- return null;
1108
- },
1109
168
 
1110
- /** ----- private methods ----------------------------------------------------------------------------------------------------------------------------- */
1111
- /**
1112
- * @private
1113
- * @description Set frameContext, frameOptions
1114
- * @param {__se__FrameContext} rt Root target[key] FrameContext
1115
- */
1116
- _setFrameInfo(rt) {
1117
- this.frameContext = rt;
1118
- this.frameOptions = rt.get('options');
1119
- rt.set('_editorHeight', rt.get('wysiwygFrame').offsetHeight);
1120
- this._lineBreaker_t = rt.get('lineBreaker_t');
1121
- this._lineBreaker_b = rt.get('lineBreaker_b');
1122
- },
1123
-
1124
- /**
1125
- * @private
1126
- * @description Focus to wysiwyg area using "native focus function"
1127
- */
1128
- _nativeFocus() {
1129
- this.selection.__focus();
1130
- this.selection._init();
1131
- },
169
+ // toolbar visibility
170
+ this.$.context.get('toolbar_main').style.visibility = '';
171
+ // roots
172
+ this.$.contextProvider.applyToRoots((e) => {
173
+ // observer
174
+ if (this.#kernel._eventOrchestrator._wwFrameObserver) this.#kernel._eventOrchestrator._wwFrameObserver.observe(e.get('wysiwygFrame'));
175
+ if (this.#kernel._eventOrchestrator._toolbarObserver) this.#kernel._eventOrchestrator._toolbarObserver.observe(e.get('_toolbarShadow'));
176
+ // resource state
177
+ this.$.ui._syncFrameState(e);
178
+ });
1132
179
 
1133
- /**
1134
- * @private
1135
- * @description Check the components such as image and video and modify them according to the format.
1136
- * @param {boolean} loaded If true, the component is loaded.
1137
- */
1138
- _checkComponents(loaded) {
1139
- for (let i = 0, len = this._fileInfoPluginsCheck.length; i < len; i++) {
1140
- this._fileInfoPluginsCheck[i](loaded);
1141
- }
1142
- },
180
+ // plugin hook
181
+ for (const plugin of Object.values(this.$.plugins)) {
182
+ plugin.init?.();
183
+ }
184
+ // class init
185
+ this.$.selection.__init();
1143
186
 
1144
- /**
1145
- * @private
1146
- * @description Initialize the information of the components.
1147
- */
1148
- _resetComponents() {
1149
- for (let i = 0, len = this._fileInfoPluginsReset.length; i < len; i++) {
1150
- this._fileInfoPluginsReset[i]();
1151
- }
1152
- },
187
+ // user event
188
+ this.$.eventManager.triggerEvent('onload', {});
189
+ }, 0);
190
+ }
1153
191
 
1154
192
  /**
1155
- * @private
1156
193
  * @description Initializ wysiwyg area (Only called from core._init)
1157
- * @param {__se__FrameContext} e frameContext
194
+ * @param {SunEditor.FrameContext} e frameContext
1158
195
  * @param {string} value initial html string
1159
196
  */
1160
- _initWysiwygArea(e, value) {
197
+ #initWysiwygArea(e, value) {
1161
198
  // set content
1162
199
  e.get('wysiwyg').innerHTML =
1163
- this.html.clean(typeof value === 'string' ? value : (/^TEXTAREA$/i.test(e.get('originElement').nodeName) ? e.get('originElement').value : e.get('originElement').innerHTML) || '', {
200
+ this.$.html.clean(typeof value === 'string' ? value : (/^TEXTAREA$/i.test(e.get('originElement').nodeName) ? e.get('originElement').value : e.get('originElement').innerHTML) || '', {
1164
201
  forceFormat: true,
1165
202
  whitelist: null,
1166
203
  blacklist: null,
1167
- _freeCodeViewMode: this.options.get('freeCodeViewMode')
1168
- }) || '<' + this.options.get('defaultLine') + '><br></' + this.options.get('defaultLine') + '>';
204
+ _freeCodeViewMode: this.$.options.get('freeCodeViewMode'),
205
+ }) || '<' + this.$.options.get('defaultLine') + '><br></' + this.$.options.get('defaultLine') + '>';
1169
206
 
1170
207
  // char counter
1171
- if (e.has('charCounter')) e.get('charCounter').textContent = this.char.getLength();
208
+ if (e.has('charCounter')) e.get('charCounter').textContent = String(this.$.char.getLength());
1172
209
 
1173
210
  // document type init
1174
- if (this.options.get('type') === 'document') {
1175
- e.set('documentType', new DocumentType(this, e));
211
+ if (this.$.options.get('type') === 'document') {
212
+ e.set('documentType', new DocumentType(this.#kernel, e));
1176
213
  if (e.get('documentType').useHeader) {
1177
- e.set('documentType-use-header', true);
214
+ e.set('documentType_use_header', true);
1178
215
  }
1179
216
  if (e.get('documentType').usePage) {
1180
- e.set('documentType-use-page', true);
217
+ e.set('documentType_use_page', true);
1181
218
  e.get('documentTypePageMirror').innerHTML = e.get('wysiwyg').innerHTML;
1182
219
  }
1183
220
  }
1184
- },
1185
-
1186
- /**
1187
- * @private
1188
- * @description Called when there are changes to tags in the wysiwyg region.
1189
- * @param {__se__FrameContext} fc - Frame context object
1190
- */
1191
- _resourcesStateChange(fc) {
1192
- this._iframeAutoHeight(fc);
1193
- this._checkPlaceholder(fc);
1194
- if (this.options.get('type') === 'document' && fc.get('documentType').usePage) {
1195
- fc.get('documentTypePageMirror').innerHTML = fc.get('wysiwyg').innerHTML;
1196
- }
1197
- },
1198
-
1199
- /**
1200
- * @private
1201
- * @description Modify the height value of the iframe when the height of the iframe is automatic.
1202
- * @param {__se__FrameContext} fc - Frame context object
1203
- */
1204
- _iframeAutoHeight(fc) {
1205
- const autoFrame = fc.get('_iframeAuto');
1206
-
1207
- if (autoFrame) {
1208
- this._w.setTimeout(() => {
1209
- const h = autoFrame.offsetHeight;
1210
- fc.get('wysiwygFrame').style.height = h + 'px';
1211
- if (!env.isResizeObserverSupported) this.__callResizeFunction(fc, h, null);
1212
- }, 0);
1213
- } else if (!env.isResizeObserverSupported) {
1214
- this.__callResizeFunction(fc, fc.get('wysiwygFrame').offsetHeight, null);
1215
- }
1216
- },
1217
-
1218
- /**
1219
- * @private
1220
- * @description Call the "onResizeEditor" event
1221
- * @param {__se__FrameContext} fc - Frame context object
1222
- * @param {number} h - Height value
1223
- * @param {ResizeObserverEntry} resizeObserverEntry - ResizeObserverEntry object
1224
- */
1225
- __callResizeFunction(fc, h, resizeObserverEntry) {
1226
- h =
1227
- h === -1
1228
- ? resizeObserverEntry?.borderBoxSize && resizeObserverEntry.borderBoxSize[0]
1229
- ? resizeObserverEntry.borderBoxSize[0].blockSize
1230
- : resizeObserverEntry.contentRect.height + numbers.get(fc.get('wwComputedStyle').getPropertyValue('padding-left')) + numbers.get(fc.get('wwComputedStyle').getPropertyValue('padding-right'))
1231
- : h;
1232
- if (fc.get('_editorHeight') !== h) {
1233
- this.triggerEvent('onResizeEditor', { height: h, prevHeight: fc.get('_editorHeight'), frameContext: fc, observerEntry: resizeObserverEntry });
1234
- fc.set('_editorHeight', h);
1235
- }
1236
-
1237
- // document type page
1238
- if (fc.has('documentType-use-page')) {
1239
- fc.get('documentType').resizePage();
1240
- }
1241
- },
1242
-
1243
- /**
1244
- * @private
1245
- * @description Set display property when there is placeholder.
1246
- * @param {?__se__FrameContext=} fc - Frame context object, If null fc is this.frameContext
1247
- */
1248
- _checkPlaceholder(fc) {
1249
- fc = fc || this.frameContext;
1250
- const placeholder = fc.get('placeholder');
1251
-
1252
- if (placeholder) {
1253
- if (fc.get('isCodeView')) {
1254
- placeholder.style.display = 'none';
1255
- return;
1256
- }
1257
-
1258
- if (this.isEmpty(fc)) {
1259
- placeholder.style.display = 'block';
1260
- } else {
1261
- placeholder.style.display = 'none';
1262
- }
1263
- }
1264
- },
1265
-
1266
- /**
1267
- * @private
1268
- * @description Initializ editor
1269
- * @param {EditorInitOptions_editor} options Options
1270
- */
1271
- __editorInit(options) {
1272
- this.applyFrameRoots((e) => {
1273
- this.__setEditorParams(e);
1274
- });
1275
-
1276
- // initialize core and add event listeners
1277
- this._setFrameInfo(this.frameRoots.get(this.status.rootKey));
1278
- this.__init(options);
1279
- for (const v of this._onPluginEvents.values()) {
1280
- v.sort((a, b) => a.index - b.index);
1281
- }
1282
-
1283
- this.applyFrameRoots((e) => {
1284
- this.eventManager._addFrameEvents(e);
1285
- this._initWysiwygArea(e, e.get('options').get('value'));
1286
- });
1287
-
1288
- this.eventManager.__eventDoc = null;
1289
- this._componentsInfoInit = false;
1290
- this._componentsInfoReset = false;
1291
- this._checkComponents(true);
1292
-
1293
- this._w.setTimeout(() => {
1294
- // toolbar visibility
1295
- this.context.get('toolbar.main').style.visibility = '';
1296
- // roots
1297
- this.applyFrameRoots((e) => {
1298
- if (typeof this._resourcesStateChange !== 'function') return;
1299
- // observer
1300
- if (this.eventManager._wwFrameObserver) this.eventManager._wwFrameObserver.observe(e.get('wysiwygFrame'));
1301
- if (this.eventManager._toolbarObserver) this.eventManager._toolbarObserver.observe(e.get('_toolbarShadow'));
1302
- // resource state
1303
- this._resourcesStateChange(e);
1304
- });
1305
- // history reset
1306
- this.history.reset();
1307
- // user event
1308
- this.triggerEvent('onload', {});
1309
- }, 0);
1310
- },
221
+ }
1311
222
 
1312
223
  /**
1313
- * @private
1314
224
  * @description Initializ core variable
1315
- * @param {EditorInitOptions_editor} options Options
225
+ * @param {SunEditor.InitOptions} options Options
1316
226
  */
1317
- __init(options) {
1318
- // file components
1319
- this._fileInfoPluginsCheck = [];
1320
- this._fileInfoPluginsReset = [];
1321
-
1322
- // text components
1323
- this._MELInfo = new Map();
1324
-
1325
- // Command and file plugins registration
1326
- this.activeCommands = ACTIVE_EVENT_COMMANDS;
1327
- this._onPluginEvents = new Map([
1328
- ['onMouseMove', []],
1329
- ['onMouseLeave', []],
1330
- ['onMouseDown', []],
1331
- ['onMouseUp', []],
1332
- ['onScroll', []],
1333
- ['onClick', []],
1334
- ['onInput', []],
1335
- ['onKeyDown', []],
1336
- ['onKeyUp', []],
1337
- ['onFocus', []],
1338
- ['onBlur', []],
1339
- ['onPaste', []],
1340
- ['onFilePasteAndDrop', []]
1341
- ]);
1342
- this._fileManager.tags = [];
1343
- this._fileManager.pluginMap = {};
1344
- this._fileManager.tagAttrs = {};
1345
-
1346
- const plugins = this.plugins;
1347
- const filePluginRegExp = [];
1348
- let plugin;
1349
- for (const key in plugins) {
1350
- this.registerPlugin(key, this._pluginCallButtons[key], options[key]);
1351
- this.registerPlugin(key, this._pluginCallButtons_sub[key], options[key]);
1352
- plugin = this.plugins[key];
1353
-
1354
- // Filemanager
1355
- if (typeof plugin.__fileManagement === 'object') {
1356
- const fm = plugin.__fileManagement;
1357
- this._fileInfoPluginsCheck.push(fm._checkInfo.bind(fm));
1358
- this._fileInfoPluginsReset.push(fm._resetInfo.bind(fm));
1359
- if (Array.isArray(fm.tagNames)) {
1360
- const tagNames = fm.tagNames;
1361
- this._fileManager.tags = this._fileManager.tags.concat(tagNames);
1362
- filePluginRegExp.push(key);
1363
- for (let tag = 0, tLen = tagNames.length, t; tag < tLen; tag++) {
1364
- t = tagNames[tag].toLowerCase();
1365
- this._fileManager.pluginMap[t] = key;
1366
- if (fm.tagAttrs) {
1367
- this._fileManager.tagAttrs[t] = fm.tagAttrs;
1368
- }
1369
- }
1370
- }
1371
- }
1372
-
1373
- // Not file component
1374
- if (typeof plugin.constructor.component === 'function') {
1375
- this._componentManager.push(
1376
- function (launcher, element) {
1377
- if (!element || !(element = launcher.component?.call(this, element))) return null;
1378
- return {
1379
- target: element,
1380
- pluginName: launcher.key,
1381
- options: launcher.options
1382
- };
1383
- }.bind(plugin, plugin.constructor)
1384
- );
1385
- }
1386
-
1387
- // plugin event
1388
- const pluginOptions = plugin.constructor.options || {};
1389
- this._onPluginEvents.forEach((v, k) => {
1390
- if (typeof plugin[k] === 'function') {
1391
- const f = plugin[k].bind(plugin);
1392
- f.index = pluginOptions[`eventIndex_${k}`] || pluginOptions.eventIndex || 0;
1393
- v.push(f);
1394
- }
1395
- });
1396
-
1397
- // plugin maintain
1398
- if (plugin.retainFormat) {
1399
- const info = plugin.retainFormat();
1400
- this._MELInfo.set(info.query, info.method);
1401
- }
1402
- }
1403
-
1404
- if (this.options.get('buttons').has('pageBreak') || this.options.get('buttons_sub')?.has('pageBreak')) {
1405
- this._componentManager.push((element) => {
1406
- if (!element || !dom.utils.hasClass(element, 'se-page-break')) return null;
1407
- return {
1408
- target: element,
1409
- launcher: {
1410
- destroy: (target) => {
1411
- const focusEl = target.previousElementSibling || target.nextElementSibling;
1412
- dom.utils.removeItem(target);
1413
- // focus
1414
- this.focusEdge(focusEl);
1415
- this.history.push(false);
1416
- }
1417
- }
1418
- };
1419
- });
1420
- }
1421
-
1422
- this._fileManager.regExp = new RegExp(`^(${this._fileManager.tags.join('|') || '\\^'})$`, 'i');
1423
- this._fileManager.pluginRegExp = new RegExp(`^(${filePluginRegExp.length === 0 ? '\\^' : filePluginRegExp.join('|')})$`, 'i');
1424
-
1425
- delete this._pluginCallButtons;
1426
- delete this._pluginCallButtons_sub;
1427
-
1428
- this.__cachingButtons();
1429
- this.__cachingShortcuts();
1430
- },
1431
-
1432
- /**
1433
- * @private
1434
- * @description Caching basic buttons to use
1435
- */
1436
- __cachingButtons() {
1437
- const ctx = this.context;
1438
- this.__setDisabledButtons();
1439
- this.__saveCommandButtons(this.allCommandButtons, ctx.get('toolbar.buttonTray'));
1440
- if (this.options.has('_subMode')) {
1441
- this.__saveCommandButtons(this.subAllCommandButtons, ctx.get('toolbar.sub.buttonTray'));
1442
- }
1443
- },
1444
-
1445
- /**
1446
- * @private
1447
- * @description Set the disabled button list
1448
- * - this._codeViewDisabledButtons, this._controllerOnDisabledButtons
1449
- */
1450
- __setDisabledButtons() {
1451
- const ctx = this.context;
1452
-
1453
- this._codeViewDisabledButtons = converter.nodeListToArray(ctx.get('toolbar.buttonTray').querySelectorAll(DISABLE_BUTTONS_CODEVIEW));
1454
- this._controllerOnDisabledButtons = converter.nodeListToArray(ctx.get('toolbar.buttonTray').querySelectorAll(DISABLE_BUTTONS_CONTROLLER));
1455
-
1456
- if (this.options.has('_subMode')) {
1457
- this._codeViewDisabledButtons = this._codeViewDisabledButtons.concat(converter.nodeListToArray(ctx.get('toolbar.sub.buttonTray').querySelectorAll(DISABLE_BUTTONS_CODEVIEW)));
1458
- this._controllerOnDisabledButtons = this._controllerOnDisabledButtons.concat(converter.nodeListToArray(ctx.get('toolbar.sub.buttonTray').querySelectorAll(DISABLE_BUTTONS_CONTROLLER)));
1459
- }
1460
- },
1461
-
1462
- /**
1463
- * @private
1464
- * @description Save the current buttons
1465
- * @param {Map<string, Element>} cmdButtons Command button map
1466
- * @param {Element} tray Button tray
1467
- */
1468
- __saveCommandButtons(cmdButtons, tray) {
1469
- const currentButtons = tray.querySelectorAll(COMMAND_BUTTONS);
1470
- const shortcuts = this.options.get('shortcuts');
1471
- const reverseCommandArray = this.options.get('_reverseCommandArray');
1472
- const keyMap = this.shortcutsKeyMap;
1473
- const reverseKeys = this.reverseKeys;
1474
-
1475
- for (let i = 0, len = currentButtons.length, e, c; i < len; i++) {
1476
- e = /** @type {HTMLButtonElement} */ (currentButtons[i]);
1477
- c = e.getAttribute('data-command');
1478
- // command set
1479
- cmdButtons.set(c, e);
1480
- this.__setCommandTargets(c, e);
1481
- // shortcuts
1482
- CreateShortcuts(c, e, shortcuts[c], keyMap, reverseCommandArray, reverseKeys);
1483
- }
1484
- },
1485
-
1486
- /**
1487
- * @private
1488
- * @description Caches custom(starts with "_") shortcut keys for commands.
1489
- */
1490
- __cachingShortcuts() {
1491
- const shortcuts = this.options.get('shortcuts');
1492
- const reverseCommandArray = this.options.get('_reverseCommandArray');
1493
- const keyMap = this.shortcutsKeyMap;
1494
- const reverseKeys = this.reverseKeys;
1495
- for (const key of Object.keys(shortcuts)) {
1496
- if (!key.startsWith('_')) continue;
1497
- CreateShortcuts('', null, shortcuts[key], keyMap, reverseCommandArray, reverseKeys);
1498
- }
1499
- },
1500
-
1501
- /**
1502
- * @private
1503
- * @description Sets command target elements.
1504
- * @param {string} cmd - The command identifier.
1505
- * @param {HTMLButtonElement} target - The associated command button.
1506
- */
1507
- __setCommandTargets(cmd, target) {
1508
- if (!cmd || !target) return;
1509
-
1510
- const isBasicCmd = BASIC_COMMANDS.includes(cmd);
1511
- if (!isBasicCmd && !this.plugins[cmd]) return;
1512
-
1513
- if (!this.commandTargets.get(cmd)) {
1514
- this.commandTargets.set(cmd, [target]);
1515
- } else if (!this.commandTargets.get(cmd).includes(target)) {
1516
- this.commandTargets.get(cmd).push(target);
1517
- }
1518
- },
227
+ #init(options) {
228
+ this.$.pluginManager.init(options);
229
+ this.$.shortcuts._registerCustomShortcuts();
230
+ this.$.commandDispatcher._initCommandButtons();
231
+ this.$.ui.init();
232
+ }
1519
233
 
1520
234
  /**
1521
- * @private
1522
235
  * @description Configures the document properties of an iframe editor.
1523
236
  * @param {HTMLIFrameElement} frame - The editor iframe.
1524
- * @param {Map<string, *>} originOptions - The original options.
1525
- * @param {__se__FrameOptions} targetOptions - The new options.
237
+ * @param {SunEditor.Options} originOptions - The original options.
238
+ * @param {SunEditor.FrameOptions} targetOptions - The new options.
1526
239
  */
1527
- __setIframeDocument(frame, originOptions, targetOptions) {
1528
- frame.setAttribute('scrolling', 'auto');
240
+ #setIframeDocument(frame, originOptions, targetOptions) {
241
+ frame.contentDocument.documentElement.className = 'sun-editor';
1529
242
  frame.contentDocument.head.innerHTML =
1530
243
  '<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">' +
1531
244
  converter._setIframeStyleLinks(targetOptions.get('iframe_cssFileName')) +
1532
245
  converter._setAutoHeightStyle(targetOptions.get('height'));
1533
246
  frame.contentDocument.body.className = originOptions.get('_editableClass');
1534
247
  frame.contentDocument.body.setAttribute('contenteditable', 'true');
1535
- },
1536
-
1537
- /**
1538
- * @private
1539
- * @description Set the FrameContext parameters and options
1540
- * @param {__se__FrameContext} e - Frame context object
1541
- */
1542
- __setEditorParams(e) {
1543
- const frameOptions = e.get('options');
1544
- const _w = this._w;
1545
-
1546
- e.set('wwComputedStyle', _w.getComputedStyle(e.get('wysiwyg')));
1547
-
1548
- if (!frameOptions.get('iframe') && typeof ShadowRoot === 'function') {
1549
- let child = e.get('wysiwygFrame');
1550
- while (child) {
1551
- if (child.shadowRoot) {
1552
- this._shadowRoot = child.shadowRoot;
1553
- break;
1554
- } else if (child instanceof ShadowRoot) {
1555
- this._shadowRoot = child;
1556
- break;
1557
- }
1558
- child = child.parentNode;
1559
- }
1560
- }
1561
-
1562
- // wisywig attributes
1563
- const attr = frameOptions.get('editableFrameAttributes');
1564
- for (const k in attr) {
1565
- e.get('wysiwyg').setAttribute(k, attr[k]);
1566
- }
1567
-
1568
- // init, validate
1569
- if (frameOptions.get('iframe')) {
1570
- e.set('_ww', e.get('wysiwygFrame').contentWindow);
1571
- e.set('_wd', e.get('wysiwygFrame').contentDocument);
1572
- e.set('wysiwyg', e.get('_wd').body);
1573
- // e.get('wysiwyg').className += ' ' + options.get('_editableClass');
1574
- if (frameOptions.get('_defaultStyles').editor) e.get('wysiwyg').style.cssText = frameOptions.get('_defaultStyles').editor;
1575
- if (frameOptions.get('height') === 'auto') e.set('_iframeAuto', e.get('_wd').body);
1576
- } else {
1577
- e.set('_ww', _w);
1578
- e.set('_wd', this._d);
1579
- }
1580
- },
1581
-
1582
- /**
1583
- * @private
1584
- * @description Registers and initializes editor classes.
1585
- */
1586
- __registerClass() {
1587
- // use events
1588
- this.events = { ...Events, ...this.options.get('events') };
1589
- this.triggerEvent = async (eventName, eventData) => {
1590
- // [iframe] wysiwyg is disabled, the event is not called.
1591
- if (eventData?.frameContext?.get('wysiwyg').getAttribute('contenteditable') === 'false') return false;
1592
- const eventHandler = this.events[eventName];
1593
- if (typeof eventHandler === 'function') {
1594
- return await eventHandler({ editor: this, ...eventData });
1595
- }
1596
- return env.NO_EVENT;
1597
- };
1598
-
1599
- // history function
1600
- this.history = History(this);
1601
-
1602
- // eventManager
1603
- this.eventManager = new EventManager(this);
1604
-
1605
- // util classes
1606
- this.offset = new Offset(this);
1607
- this.shortcuts = new Shortcuts(this);
1608
- // main classes
1609
- this.toolbar = new Toolbar(this, { keyName: 'toolbar', balloon: this.isBalloon, balloonAlways: this.isBalloonAlways, inline: this.isInline, res: this._responsiveButtons });
1610
- if (this.options.has('_subMode')) {
1611
- this.subToolbar = new Toolbar(this, {
1612
- keyName: 'toolbar.sub',
1613
- balloon: this.isSubBalloon,
1614
- balloonAlways: this.isSubBalloonAlways,
1615
- inline: false,
1616
- res: this._responsiveButtons_sub
1617
- });
1618
- }
1619
- this.selection = new Selection_(this);
1620
- this.html = new HTML(this);
1621
- this.nodeTransform = new NodeTransform(this);
1622
- this.component = new Component(this);
1623
- this.format = new Format(this);
1624
- this.menu = new Menu(this);
1625
- this.char = new Char(this);
1626
- this.ui = new UI(this);
1627
- this.viewer = new Viewer(this);
1628
-
1629
- // register classes to the eventManager
1630
- ClassInjector.call(this.eventManager, this);
1631
- // register main classes
1632
- ClassInjector.call(this.char, this);
1633
- ClassInjector.call(this.component, this);
1634
- ClassInjector.call(this.format, this);
1635
- ClassInjector.call(this.html, this);
1636
- ClassInjector.call(this.menu, this);
1637
- ClassInjector.call(this.nodeTransform, this);
1638
- ClassInjector.call(this.offset, this);
1639
- ClassInjector.call(this.selection, this);
1640
- ClassInjector.call(this.shortcuts, this);
1641
- ClassInjector.call(this.toolbar, this);
1642
- ClassInjector.call(this.ui, this);
1643
- ClassInjector.call(this.viewer, this);
1644
- if (this.options.has('_subMode')) ClassInjector.call(this.subToolbar, this);
1645
-
1646
- // delete self reference
1647
- delete this.eventManager['eventManager'];
1648
- delete this.char['char'];
1649
- delete this.component['component'];
1650
- delete this.format['format'];
1651
- delete this.html['html'];
1652
- delete this.menu['menu'];
1653
- delete this.nodeTransform['nodeTransform'];
1654
- delete this.offset['offset'];
1655
- delete this.selection['selection'];
1656
- delete this.shortcuts['shortcuts'];
1657
- delete this.toolbar['toolbar'];
1658
- delete this.ui['ui'];
1659
- delete this.viewer['viewer'];
1660
- if (this.subToolbar) delete this.subToolbar['subToolbar'];
1661
-
1662
- this._responsiveButtons = this._responsiveButtons_sub = null;
1663
- },
248
+ }
1664
249
 
1665
250
  /**
1666
- * @private
1667
251
  * @description Creates the editor instance and initializes components.
1668
- * @param {EditorInitOptions_editor} originOptions - The initial editor options.
252
+ * @param {SunEditor.InitOptions} originOptions - The initial editor options.
1669
253
  * @returns {Promise<void>}
1670
254
  */
1671
- async __Create(originOptions) {
1672
- // set modes
1673
- this.isInline = /inline/i.test(this.options.get('mode'));
1674
- this.isBalloon = /balloon/i.test(this.options.get('mode'));
1675
- this.isBalloonAlways = /balloon-always/i.test(this.options.get('mode'));
1676
- this.isClassic = /classic/i.test(this.options.get('mode'));
1677
- // set subToolbar modes
1678
- this.isSubBalloon = /balloon/i.test(this.options.get('_subMode'));
1679
- this.isSubBalloonAlways = /balloon-always/i.test(this.options.get('_subMode'));
1680
-
1681
- // register class
1682
- this.__registerClass();
1683
-
255
+ async #Create(originOptions) {
1684
256
  // common events
1685
- this.eventManager._addCommonEvents();
257
+ this.#kernel._eventOrchestrator._addCommonEvents();
1686
258
 
1687
259
  // init
1688
260
  const iframePromises = [];
1689
- this.applyFrameRoots((e) => {
261
+ this.$.contextProvider.applyToRoots((e) => {
1690
262
  const o = e.get('originElement');
1691
263
  const t = e.get('topArea');
1692
264
  o.style.display = 'none';
@@ -1695,8 +267,8 @@ Editor.prototype = {
1695
267
 
1696
268
  if (e.get('options').get('iframe')) {
1697
269
  const iframeLoaded = new Promise((resolve) => {
1698
- this.eventManager.addEvent(e.get('wysiwygFrame'), 'load', ({ target }) => {
1699
- this.__setIframeDocument(target, this.options, e.get('options'));
270
+ this.$.eventManager.addEvent(e.get('wysiwygFrame'), 'load', ({ target }) => {
271
+ this.#setIframeDocument(/** @type{HTMLIFrameElement} */ (target), this.$.optionProvider.options, e.get('options'));
1700
272
  resolve();
1701
273
  });
1702
274
  });
@@ -1704,16 +276,16 @@ Editor.prototype = {
1704
276
  }
1705
277
  });
1706
278
 
1707
- this.applyFrameRoots((e) => {
279
+ this.$.contextProvider.applyToRoots((e) => {
1708
280
  e.get('wrapper').appendChild(e.get('wysiwygFrame'));
1709
281
 
1710
282
  // document type
1711
283
  if (e.get('documentTypeInner')) {
1712
- if (this.options.get('_rtl')) e.get('wrapper').appendChild(e.get('documentTypeInner'));
284
+ if (this.$.options.get('_rtl')) e.get('wrapper').appendChild(e.get('documentTypeInner'));
1713
285
  else e.get('wrapper').insertBefore(e.get('documentTypeInner'), e.get('wysiwygFrame'));
1714
286
  }
1715
287
  if (e.get('documentTypePage')) {
1716
- if (this.options.get('_rtl')) e.get('wrapper').insertBefore(e.get('documentTypePage'), e.get('wysiwygFrame'));
288
+ if (this.$.options.get('_rtl')) e.get('wrapper').insertBefore(e.get('documentTypePage'), e.get('wysiwygFrame'));
1717
289
  else e.get('wrapper').appendChild(e.get('documentTypePage'));
1718
290
  // page mirror
1719
291
  e.get('wrapper').appendChild(e.get('documentTypePageMirror'));
@@ -1724,50 +296,7 @@ Editor.prototype = {
1724
296
  await Promise.all(iframePromises);
1725
297
  }
1726
298
 
1727
- this.__editorInit(originOptions);
1728
- },
1729
-
1730
- Constructor: Editor
1731
- };
1732
-
1733
- function RestoreFrameOptions(key, option, frameRoots, rootDiff, newRootKeys, newRoots) {
1734
- const nro = option[key];
1735
- const newKeys = Object.keys(nro);
1736
- CheckResetKeys(newKeys, null, key + '.');
1737
- if (newKeys.length === 0) return false;
1738
-
1739
- const rootKey = key || null;
1740
- rootDiff.set(rootKey, new Map());
1741
-
1742
- const o = frameRoots.get(rootKey).get('options').get('_origin');
1743
- const no = {};
1744
- const hasOwn = Object.prototype.hasOwnProperty;
1745
- for (const rk in nro) {
1746
- if (!hasOwn.call(OPTION_FRAME_FIXED_FLAG, rk)) continue;
1747
- const roV = nro[rk];
1748
- if (!newKeys.includes(rk) || o[rk] === roV) continue;
1749
- rootDiff.get(rootKey).set(GetResetDiffKey(rk), true);
1750
- no[rk] = roV;
1751
- }
1752
-
1753
- const newO = { ...o, ...no };
1754
- newRootKeys.set(rootKey, new Map(Object.entries(newO)));
1755
- newRoots.push({ key: rootKey, options: newO });
1756
- }
1757
-
1758
- function GetResetDiffKey(key) {
1759
- if (/^statusbar|^charCounter/.test(key)) return 'statusbar-changed';
1760
- return key;
1761
- }
1762
-
1763
- function CheckResetKeys(keys, plugins, root) {
1764
- for (let i = 0, len = keys.length, k; i < len; i++) {
1765
- k = keys[i];
1766
- if (OPTION_FIXED_FLAG[k] === 'fixed' || OPTION_FRAME_FIXED_FLAG[k] === 'fixed' || (plugins && plugins[k])) {
1767
- console.warn(`[SUNEDITOR.warn.resetOptions] The "[${root + k}]" option cannot be changed after the editor is created.`);
1768
- keys.splice(i--, 1);
1769
- len--;
1770
- }
299
+ this.#editorInit(originOptions);
1771
300
  }
1772
301
  }
1773
302