suneditor 3.0.0-alpha.2 → 3.0.0-alpha.20

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 (306) hide show
  1. package/.eslintrc.json +4 -3
  2. package/CONTRIBUTING.md +4 -2
  3. package/README.md +19 -11
  4. package/README_V3_TEMP.md +705 -0
  5. package/dist/suneditor.min.css +1 -0
  6. package/dist/suneditor.min.js +1 -0
  7. package/example.md +587 -0
  8. package/package.json +15 -9
  9. package/src/assets/icons/_default.js +166 -131
  10. package/src/assets/{suneditor-content.css → suneditor-contents.css} +182 -45
  11. package/src/assets/suneditor.css +1195 -556
  12. package/src/assets/variables.css +138 -0
  13. package/src/core/base/eventHandlers/handler_toolbar.js +35 -14
  14. package/src/core/base/eventHandlers/handler_ww_clipboard.js +29 -4
  15. package/src/core/base/eventHandlers/handler_ww_dragDrop.js +59 -15
  16. package/src/core/base/eventHandlers/handler_ww_key_input.js +426 -212
  17. package/src/core/base/eventHandlers/handler_ww_mouse.js +108 -32
  18. package/src/core/base/eventManager.js +540 -209
  19. package/src/core/base/events.js +616 -320
  20. package/src/core/base/history.js +93 -39
  21. package/src/core/class/char.js +29 -13
  22. package/src/core/class/component.js +332 -145
  23. package/src/core/class/format.js +671 -509
  24. package/src/core/class/html.js +504 -290
  25. package/src/core/class/menu.js +114 -47
  26. package/src/core/class/nodeTransform.js +111 -66
  27. package/src/core/class/offset.js +409 -105
  28. package/src/core/class/selection.js +220 -108
  29. package/src/core/class/shortcuts.js +68 -8
  30. package/src/core/class/toolbar.js +106 -116
  31. package/src/core/class/ui.js +330 -0
  32. package/src/core/class/viewer.js +178 -74
  33. package/src/core/editor.js +489 -384
  34. package/src/core/section/actives.js +118 -22
  35. package/src/core/section/constructor.js +504 -170
  36. package/src/core/section/context.js +28 -23
  37. package/src/core/section/documentType.js +561 -0
  38. package/src/editorInjector/_classes.js +19 -5
  39. package/src/editorInjector/_core.js +71 -7
  40. package/src/editorInjector/index.js +63 -1
  41. package/src/helper/converter.js +137 -19
  42. package/src/helper/dom/domCheck.js +294 -0
  43. package/src/helper/dom/domQuery.js +609 -0
  44. package/src/helper/dom/domUtils.js +533 -0
  45. package/src/helper/dom/index.js +12 -0
  46. package/src/helper/env.js +42 -19
  47. package/src/helper/index.js +7 -4
  48. package/src/helper/keyCodeMap.js +183 -0
  49. package/src/helper/numbers.js +8 -8
  50. package/src/helper/unicode.js +5 -5
  51. package/src/langs/ckb.js +69 -3
  52. package/src/langs/cs.js +67 -1
  53. package/src/langs/da.js +68 -2
  54. package/src/langs/de.js +68 -3
  55. package/src/langs/en.js +29 -1
  56. package/src/langs/es.js +68 -3
  57. package/src/langs/fa.js +70 -2
  58. package/src/langs/fr.js +68 -2
  59. package/src/langs/he.js +68 -3
  60. package/src/langs/hu.js +226 -0
  61. package/src/langs/index.js +3 -2
  62. package/src/langs/it.js +65 -0
  63. package/src/langs/ja.js +68 -3
  64. package/src/langs/ko.js +66 -1
  65. package/src/langs/lv.js +68 -3
  66. package/src/langs/nl.js +68 -3
  67. package/src/langs/pl.js +68 -3
  68. package/src/langs/pt_br.js +65 -0
  69. package/src/langs/ro.js +69 -4
  70. package/src/langs/ru.js +68 -3
  71. package/src/langs/se.js +68 -3
  72. package/src/langs/tr.js +68 -0
  73. package/src/langs/ua.js +68 -3
  74. package/src/langs/ur.js +71 -6
  75. package/src/langs/zh_cn.js +69 -4
  76. package/src/modules/ApiManager.js +77 -54
  77. package/src/modules/Browser.js +667 -0
  78. package/src/modules/ColorPicker.js +162 -102
  79. package/src/modules/Controller.js +233 -136
  80. package/src/modules/Figure.js +913 -489
  81. package/src/modules/FileManager.js +141 -72
  82. package/src/modules/HueSlider.js +113 -61
  83. package/src/modules/Modal.js +292 -113
  84. package/src/modules/ModalAnchorEditor.js +380 -230
  85. package/src/modules/SelectMenu.js +270 -168
  86. package/src/modules/_DragHandle.js +2 -1
  87. package/src/modules/index.js +3 -3
  88. package/src/plugins/browser/audioGallery.js +83 -0
  89. package/src/plugins/browser/fileBrowser.js +103 -0
  90. package/src/plugins/browser/fileGallery.js +83 -0
  91. package/src/plugins/browser/imageGallery.js +81 -0
  92. package/src/plugins/browser/videoGallery.js +103 -0
  93. package/src/plugins/command/blockquote.js +40 -27
  94. package/src/plugins/command/exportPDF.js +134 -0
  95. package/src/plugins/command/fileUpload.js +226 -158
  96. package/src/plugins/command/list_bulleted.js +93 -47
  97. package/src/plugins/command/list_numbered.js +93 -47
  98. package/src/plugins/dropdown/align.js +66 -54
  99. package/src/plugins/dropdown/backgroundColor.js +76 -45
  100. package/src/plugins/dropdown/font.js +71 -47
  101. package/src/plugins/dropdown/fontColor.js +78 -46
  102. package/src/plugins/dropdown/formatBlock.js +74 -33
  103. package/src/plugins/dropdown/hr.js +102 -51
  104. package/src/plugins/dropdown/layout.js +37 -26
  105. package/src/plugins/dropdown/lineHeight.js +54 -38
  106. package/src/plugins/dropdown/list.js +60 -45
  107. package/src/plugins/dropdown/paragraphStyle.js +51 -30
  108. package/src/plugins/dropdown/table.js +1269 -777
  109. package/src/plugins/dropdown/template.js +38 -26
  110. package/src/plugins/dropdown/textStyle.js +43 -31
  111. package/src/plugins/field/mention.js +144 -82
  112. package/src/plugins/index.js +32 -6
  113. package/src/plugins/input/fontSize.js +161 -108
  114. package/src/plugins/input/pageNavigator.js +70 -0
  115. package/src/plugins/modal/audio.js +341 -169
  116. package/src/plugins/modal/drawing.js +530 -0
  117. package/src/plugins/modal/embed.js +886 -0
  118. package/src/plugins/modal/image.js +673 -358
  119. package/src/plugins/modal/link.js +100 -71
  120. package/src/plugins/modal/math.js +384 -168
  121. package/src/plugins/modal/video.js +693 -336
  122. package/src/plugins/popup/anchor.js +222 -0
  123. package/src/suneditor.js +54 -12
  124. package/src/themes/dark.css +85 -0
  125. package/src/typedef.js +86 -0
  126. package/types/assets/icons/_default.d.ts +152 -0
  127. package/types/core/base/eventHandlers/handler_toolbar.d.ts +41 -0
  128. package/types/core/base/eventHandlers/handler_ww_clipboard.d.ts +40 -0
  129. package/types/core/base/eventHandlers/handler_ww_dragDrop.d.ts +35 -0
  130. package/types/core/base/eventHandlers/handler_ww_key_input.d.ts +45 -0
  131. package/types/core/base/eventHandlers/handler_ww_mouse.d.ts +39 -0
  132. package/types/core/base/eventManager.d.ts +377 -0
  133. package/types/core/base/events.d.ts +297 -0
  134. package/types/core/base/history.d.ts +81 -0
  135. package/types/core/class/char.d.ts +60 -0
  136. package/types/core/class/component.d.ts +259 -0
  137. package/types/core/class/format.d.ts +615 -0
  138. package/types/core/class/html.d.ts +377 -0
  139. package/types/core/class/menu.d.ts +118 -0
  140. package/types/core/class/nodeTransform.d.ts +93 -0
  141. package/types/core/class/offset.d.ts +512 -0
  142. package/types/core/class/selection.d.ts +188 -0
  143. package/types/core/class/shortcuts.d.ts +142 -0
  144. package/types/core/class/toolbar.d.ts +189 -0
  145. package/types/core/class/ui.d.ts +144 -0
  146. package/types/core/class/viewer.d.ts +140 -0
  147. package/types/core/editor.d.ts +606 -0
  148. package/types/core/section/actives.d.ts +46 -0
  149. package/types/core/section/constructor.d.ts +748 -0
  150. package/types/core/section/context.d.ts +45 -0
  151. package/types/core/section/documentType.d.ts +178 -0
  152. package/types/editorInjector/_classes.d.ts +41 -0
  153. package/types/editorInjector/_core.d.ts +92 -0
  154. package/types/editorInjector/index.d.ts +71 -0
  155. package/types/helper/converter.d.ts +150 -0
  156. package/types/helper/dom/domCheck.d.ts +182 -0
  157. package/types/helper/dom/domQuery.d.ts +214 -0
  158. package/types/helper/dom/domUtils.d.ts +211 -0
  159. package/types/helper/dom/index.d.ts +9 -0
  160. package/types/helper/env.d.ts +149 -0
  161. package/types/helper/index.d.ts +163 -0
  162. package/types/helper/keyCodeMap.d.ts +110 -0
  163. package/types/helper/numbers.d.ts +43 -0
  164. package/types/helper/unicode.d.ts +28 -0
  165. package/types/index.d.ts +0 -0
  166. package/{typings/Lang.d.ts → types/langs/_Lang.d.ts} +170 -103
  167. package/types/langs/ckb.d.ts +384 -0
  168. package/types/langs/cs.d.ts +384 -0
  169. package/types/langs/da.d.ts +384 -0
  170. package/types/langs/de.d.ts +384 -0
  171. package/types/langs/en.d.ts +384 -0
  172. package/types/langs/es.d.ts +384 -0
  173. package/types/langs/fa.d.ts +384 -0
  174. package/types/langs/fr.d.ts +384 -0
  175. package/types/langs/he.d.ts +384 -0
  176. package/types/langs/hu.d.ts +384 -0
  177. package/types/langs/index.d.ts +48 -0
  178. package/types/langs/it.d.ts +384 -0
  179. package/types/langs/ja.d.ts +384 -0
  180. package/types/langs/ko.d.ts +384 -0
  181. package/types/langs/lv.d.ts +384 -0
  182. package/types/langs/nl.d.ts +384 -0
  183. package/types/langs/pl.d.ts +384 -0
  184. package/types/langs/pt_br.d.ts +384 -0
  185. package/types/langs/ro.d.ts +384 -0
  186. package/types/langs/ru.d.ts +384 -0
  187. package/types/langs/se.d.ts +384 -0
  188. package/types/langs/tr.d.ts +384 -0
  189. package/types/langs/ua.d.ts +384 -0
  190. package/types/langs/ur.d.ts +384 -0
  191. package/types/langs/zh_cn.d.ts +384 -0
  192. package/types/modules/ApiManager.d.ts +125 -0
  193. package/types/modules/Browser.d.ts +326 -0
  194. package/types/modules/ColorPicker.d.ts +131 -0
  195. package/types/modules/Controller.d.ts +231 -0
  196. package/types/modules/Figure.d.ts +504 -0
  197. package/types/modules/FileManager.d.ts +202 -0
  198. package/types/modules/HueSlider.d.ts +136 -0
  199. package/types/modules/Modal.d.ts +117 -0
  200. package/types/modules/ModalAnchorEditor.d.ts +236 -0
  201. package/types/modules/SelectMenu.d.ts +194 -0
  202. package/types/modules/_DragHandle.d.ts +7 -0
  203. package/types/modules/index.d.ts +26 -0
  204. package/types/plugins/browser/audioGallery.d.ts +55 -0
  205. package/types/plugins/browser/fileBrowser.d.ts +64 -0
  206. package/types/plugins/browser/fileGallery.d.ts +55 -0
  207. package/types/plugins/browser/imageGallery.d.ts +51 -0
  208. package/types/plugins/browser/videoGallery.d.ts +57 -0
  209. package/types/plugins/command/blockquote.d.ts +28 -0
  210. package/types/plugins/command/exportPDF.d.ts +46 -0
  211. package/types/plugins/command/fileUpload.d.ts +156 -0
  212. package/types/plugins/command/list_bulleted.d.ts +56 -0
  213. package/types/plugins/command/list_numbered.d.ts +56 -0
  214. package/types/plugins/dropdown/align.d.ts +60 -0
  215. package/types/plugins/dropdown/backgroundColor.d.ts +63 -0
  216. package/types/plugins/dropdown/font.d.ts +54 -0
  217. package/types/plugins/dropdown/fontColor.d.ts +63 -0
  218. package/types/plugins/dropdown/formatBlock.d.ts +58 -0
  219. package/types/plugins/dropdown/hr.d.ts +81 -0
  220. package/types/plugins/dropdown/layout.d.ts +40 -0
  221. package/types/plugins/dropdown/lineHeight.d.ts +50 -0
  222. package/types/plugins/dropdown/list.d.ts +39 -0
  223. package/types/plugins/dropdown/paragraphStyle.d.ts +54 -0
  224. package/types/plugins/dropdown/table.d.ts +579 -0
  225. package/types/plugins/dropdown/template.d.ts +40 -0
  226. package/types/plugins/dropdown/textStyle.d.ts +41 -0
  227. package/types/plugins/field/mention.d.ts +102 -0
  228. package/types/plugins/index.d.ts +107 -0
  229. package/types/plugins/input/fontSize.d.ts +170 -0
  230. package/types/plugins/input/pageNavigator.d.ts +28 -0
  231. package/types/plugins/modal/audio.d.ts +269 -0
  232. package/types/plugins/modal/drawing.d.ts +246 -0
  233. package/types/plugins/modal/embed.d.ts +387 -0
  234. package/types/plugins/modal/image.d.ts +451 -0
  235. package/types/plugins/modal/link.d.ts +128 -0
  236. package/types/plugins/modal/math.d.ts +193 -0
  237. package/types/plugins/modal/video.d.ts +485 -0
  238. package/types/plugins/popup/anchor.d.ts +56 -0
  239. package/types/suneditor.d.ts +51 -0
  240. package/types/typedef-global.d.ts +144 -0
  241. package/src/core/class/notice.js +0 -42
  242. package/src/helper/domUtils.js +0 -1177
  243. package/src/modules/FileBrowser.js +0 -271
  244. package/src/plugins/command/exportPdf.js +0 -168
  245. package/src/plugins/fileBrowser/imageGallery.js +0 -81
  246. package/src/themes/test.css +0 -61
  247. package/typings/CommandPlugin.d.ts +0 -8
  248. package/typings/DialogPlugin.d.ts +0 -20
  249. package/typings/FileBrowserPlugin.d.ts +0 -30
  250. package/typings/Module.d.ts +0 -15
  251. package/typings/Plugin.d.ts +0 -42
  252. package/typings/SubmenuPlugin.d.ts +0 -8
  253. package/typings/_classes.d.ts +0 -17
  254. package/typings/_colorPicker.d.ts +0 -60
  255. package/typings/_core.d.ts +0 -55
  256. package/typings/align.d.ts +0 -5
  257. package/typings/audio.d.ts +0 -5
  258. package/typings/backgroundColor.d.ts +0 -5
  259. package/typings/blockquote.d.ts +0 -5
  260. package/typings/char.d.ts +0 -39
  261. package/typings/component.d.ts +0 -38
  262. package/typings/context.d.ts +0 -39
  263. package/typings/converter.d.ts +0 -33
  264. package/typings/dialog.d.ts +0 -28
  265. package/typings/domUtils.d.ts +0 -361
  266. package/typings/editor.d.ts +0 -7
  267. package/typings/editor.ts +0 -542
  268. package/typings/env.d.ts +0 -70
  269. package/typings/eventManager.d.ts +0 -37
  270. package/typings/events.d.ts +0 -262
  271. package/typings/fileBrowser.d.ts +0 -42
  272. package/typings/fileManager.d.ts +0 -67
  273. package/typings/font.d.ts +0 -5
  274. package/typings/fontColor.d.ts +0 -5
  275. package/typings/fontSize.d.ts +0 -5
  276. package/typings/format.d.ts +0 -191
  277. package/typings/formatBlock.d.ts +0 -5
  278. package/typings/history.d.ts +0 -48
  279. package/typings/horizontalRule.d.ts +0 -5
  280. package/typings/image.d.ts +0 -5
  281. package/typings/imageGallery.d.ts +0 -5
  282. package/typings/index.d.ts +0 -21
  283. package/typings/index.modules.d.ts +0 -11
  284. package/typings/index.plugins.d.ts +0 -58
  285. package/typings/lineHeight.d.ts +0 -5
  286. package/typings/link.d.ts +0 -5
  287. package/typings/list.d.ts +0 -5
  288. package/typings/math.d.ts +0 -5
  289. package/typings/mediaContainer.d.ts +0 -25
  290. package/typings/mention.d.ts +0 -5
  291. package/typings/node.d.ts +0 -57
  292. package/typings/notice.d.ts +0 -16
  293. package/typings/numbers.d.ts +0 -29
  294. package/typings/offset.d.ts +0 -24
  295. package/typings/options.d.ts +0 -589
  296. package/typings/paragraphStyle.d.ts +0 -5
  297. package/typings/resizing.d.ts +0 -141
  298. package/typings/selection.d.ts +0 -94
  299. package/typings/shortcuts.d.ts +0 -13
  300. package/typings/suneditor.d.ts +0 -9
  301. package/typings/table.d.ts +0 -5
  302. package/typings/template.d.ts +0 -5
  303. package/typings/textStyle.d.ts +0 -5
  304. package/typings/toolbar.d.ts +0 -32
  305. package/typings/unicode.d.ts +0 -25
  306. package/typings/video.d.ts +0 -5
@@ -1,17 +1,32 @@
1
1
  import _icons from '../../assets/icons/_default';
2
2
  import _defaultLang from '../../langs/en';
3
3
  import { CreateContext, CreateFrameContext } from './context';
4
- import { domUtils, numbers, converter, env } from '../../helper';
4
+ import { dom, numbers, converter, env } from '../../helper';
5
5
 
6
6
  const _d = env._d;
7
- const DEFAULT_BUTTON_LIST = [['undo', 'redo'], ['bold', 'underline', 'italic', 'strike', 'subscript', 'superscript'], ['removeFormat'], ['outdent', 'indent'], ['fullScreen', 'showBlocks', 'codeView'], ['preview', 'print']];
7
+ const DEFAULT_BUTTON_LIST = [
8
+ ['undo', 'redo'],
9
+ '|',
10
+ ['bold', 'underline', 'italic', 'strike', '|', 'subscript', 'superscript'],
11
+ '|',
12
+ ['removeFormat'],
13
+ '|',
14
+ ['outdent', 'indent'],
15
+ '|',
16
+ ['fullScreen', 'showBlocks', 'codeView'],
17
+ '|',
18
+ ['preview', 'print']
19
+ ];
8
20
 
9
21
  const REQUIRED_FORMAT_LINE = 'div';
10
22
  const REQUIRED_ELEMENT_WHITELIST = 'br|div';
11
23
  const DEFAULT_ELEMENT_WHITELIST =
12
24
  'p|pre|blockquote|h1|h2|h3|h4|h5|h6|ol|ul|li|hr|figure|figcaption|img|iframe|audio|video|source|table|thead|tbody|tr|th|td|caption|a|b|strong|var|i|em|u|ins|s|span|strike|del|sub|sup|code|svg|path|details|summary';
13
25
  const DEFAULT_TEXT_STYLE_TAGS = 'strong|span|font|b|var|i|em|u|ins|s|strike|del|sub|sup|mark|a|label|code|summary';
14
- const DEFAULT_ATTRIBUTE_WHITELIST = 'contenteditable|target|href|title|download|rel|src|alt|class|type|controls|colspan|rowspan';
26
+
27
+ const _video_audio_attr = '|controls|autoplay|loop|muted|poster|preload|playsinline|volume|crossorigin|disableRemotePlayback|controlsList';
28
+ const _iframe_attr = '|allowfullscreen|sandbox|loading|allow|referrerpolicy|frameborder|scrolling';
29
+ const DEFAULT_ATTRIBUTE_WHITELIST = 'contenteditable|target|href|title|download|rel|src|alt|class|type|colspan|rowspan' + _video_audio_attr + _iframe_attr;
15
30
 
16
31
  const DEFAULT_FORMAT_LINE = 'P|H[1-6]|LI|TH|TD|DETAILS';
17
32
  const DEFAULT_FORMAT_BR_LINE = 'PRE';
@@ -19,9 +34,12 @@ const DEFAULT_FORMAT_CLOSURE_BR_LINE = '';
19
34
  const DEFAULT_FORMAT_BLOCK = 'BLOCKQUOTE|OL|UL|FIGCAPTION|TABLE|THEAD|TBODY|TR|CAPTION|DETAILS';
20
35
  const DEFAULT_FORMAT_CLOSURE_BLOCK = 'TH|TD';
21
36
 
37
+ const DEFAULT_ALLOWED_EMPTY_NODE_LIST = '.se-component, pre, blockquote, hr, li, table, img, iframe, video, audio, canvas, details';
38
+
22
39
  const DEFAULT_SIZE_UNITS = ['px', 'pt', 'em', 'rem'];
23
40
 
24
- const DEFAULT_CLASS_NAME = '^__se__|^se-|^katex';
41
+ const DEFAULT_CLASS_NAME = '^__se__|^se-|^katex|^MathJax';
42
+ const DEFAULT_CLASS_MJX = 'mjx-container|mjx-math|mjx-mrow|mjx-mi|mjx-mo|mjx-mn|mjx-msup|mjx-mfrac|mjx-munderover';
25
43
  const DEFAULT_EXTRA_TAG_MAP = { script: false, style: false, meta: false, link: false, '[a-z]+:[a-z]+': false };
26
44
 
27
45
  const DEFAULT_TAG_STYLES = {
@@ -42,6 +60,7 @@ const DEFAULT_CONTENT_STYLES =
42
60
  'margin|margin-block-end|margin-block-start|margin-bottom|margin-inline-end|margin-inline-start|margin-left|margin-right|margin-top|max-width|min-width|' +
43
61
  'outline|overflow|' +
44
62
  'position|padding|padding-bottom|padding-inline-start|padding-left|padding-right|padding-top|' +
63
+ 'page-break-before|page-break-after|page-break-inside|' +
45
64
  'rotate|rotateX|rotateY|' +
46
65
  'table-layout|text-align|text-decoration|text-shadow|text-transform|top|' +
47
66
  'text-indent|text-rendering|' +
@@ -52,8 +71,8 @@ const RETAIN_STYLE_MODE = ['repeat', 'always', 'none'];
52
71
 
53
72
  export const RO_UNAVAILABD = [
54
73
  'mode',
74
+ 'type',
55
75
  'externalLibs',
56
- 'keepStyleOnDelete',
57
76
  'iframe',
58
77
  'convertTextTags',
59
78
  'textStyleTags',
@@ -87,23 +106,161 @@ export const RO_UNAVAILABD = [
87
106
  ];
88
107
 
89
108
  /**
90
- * @description document create
91
- * @param {Object} options Options
92
- * @param {Element|Array.<Element>} editorTargets Target textarea
93
- * @returns {Object}
109
+ * @typedef {Object} EditorFrameOptions
110
+ * @property {string} [value=""] - Initial value for the editor.
111
+ * @property {string} [placeholder=""] - Placeholder text.
112
+ * @property {Object<string, string>} [editableFrameAttributes={}] - Attributes for the editable frame[.sun-editor-editable]. (e.g. [key]: value)
113
+ * @property {string} [width="100%"] - Width for the editor.
114
+ * @property {string} [minWidth=""] - Min width for the editor.
115
+ * @property {string} [maxWidth=""] - Max width for the editor.
116
+ * @property {string} [height="auto"] - Height for the editor.
117
+ * @property {string} [minHeight=""] - Min height for the editor.
118
+ * @property {string} [maxHeight=""] - Max height for the editor.
119
+ * @property {string} [editorStyle=""] - Style string of the top frame of the editor. (e.g. "border: 1px solid #ccc;").
120
+ * @property {boolean} [iframe=false] - Content will be placed in an iframe and isolated from the rest of the page.
121
+ * @property {boolean} [iframe_fullPage=false] - Allows the usage of HTML, HEAD, BODY tags and DOCTYPE declaration on the "iframe".
122
+ * @property {Object<string, string>} [iframe_attributes={}] - Attributes of the "iframe". (e.g. {'scrolling': 'no'})
123
+ * @property {string} [iframe_cssFileName="suneditor"] - Name or Array of the CSS file to apply inside the iframe.
124
+ * - You can also use regular expressions.
125
+ * - Applied by searching by filename in the link tag of document,
126
+ * - or put the URL value (".css" can be omitted).
127
+ * @property {boolean} [statusbar=true] - Enables the status bar.
128
+ * @property {boolean} [statusbar_showPathLabel=true] - Displays the current node structure to status bar.
129
+ * @property {boolean} [statusbar_resizeEnable=true] - Enables resize function of bottom status bar
130
+ * @property {boolean} [charCounter=false] - Shows the number of characters in the editor.
131
+ * - If the maxCharCount option has a value, it becomes true.
132
+ * @property {number} [charCounter_max] - The maximum number of characters allowed to be inserted into the editor.
133
+ * @property {string} [charCounter_label] - Text to be displayed in the "charCounter" area of the bottom bar. (e.g. "Characters : 20/200")
134
+ * @property {"char"|"byte"|"byte-html"} [charCounter_type="char"] - Defines the calculation method of the "charCounter" option.
135
+ * - 'char': Characters length.
136
+ * - 'byte': Binary data size of characters.
137
+ * - 'byte-html': Binary data size of the full HTML string.
94
138
  */
95
- const Constructor = function (editorTargets, options) {
139
+
140
+ /**
141
+ * @typedef {Object} EditorBaseOptions
142
+ * @property {Object<string, *>|Array<Object<string, *>>} [plugins] - Plugin configuration.
143
+ * @property {Array<string>} [excludedPlugins] - Plugin configuration.
144
+ * @property {Array<string[]|string>} [buttonList] - List of toolbar buttons, grouped by sub-arrays.
145
+ * @property {boolean} [v2Migration=false] - Enables migration mode for SunEditor v2.
146
+ * @property {boolean|{tagFilter: boolean, formatFilter: boolean, classFilter: boolean, styleNodeFilter: boolean, attrFilter: boolean, styleFilter: boolean}} [strictMode=true] - Enables strict filtering of tags, attributes, and styles.
147
+ * @property {"classic"|"inline"|"balloon"|"balloon-always"} [mode="classic"] - Toolbar mode: "classic", "inline", "balloon", "balloon-always".
148
+ * @property {string} [type=""] - Editor type: "document:header,page".
149
+ * @property {string} [theme=""] - Editor theme.
150
+ * @property {Object<string, string>} [lang] - Language configuration.
151
+ * @property {Array<string>} [fontSizeUnits=["px", "pt", "em", "rem"]] - Allowed font size units.
152
+ * @property {string} [allowedClassName] - Allowed class names.
153
+ * @property {boolean} [closeModalOutsideClick=false] - Closes modals when clicking outside.
154
+ * @property {boolean} [copyFormatKeepOn=false] - Keeps the format of the copied content.
155
+ * @property {boolean} [syncTabIndent=true] - Synchronizes tab indent with spaces.
156
+ * @property {boolean} [tabDisable=false] - Disables tab key input.
157
+ * @property {boolean} [autoLinkify] - Automatically converts URLs into hyperlinks. ("Link" plugin required)
158
+ * @property {Array<string>} [autoStyleify=["bold", "underline", "italic", "strike"]] - Styles applied automatically on text input.
159
+ * @property {Object<string, string|number>} [scrollToOptions={behavior: "auto", block: "nearest"}] - Configuration for scroll behavior when navigating editor content.
160
+ * @property {Object<string, string|number>} [componentScrollToOptions={behavior: "smooth", block: "center"}] - Configuration for scroll behavior when navigating components.
161
+ * @property {"repeat"|"always"|"none"} [retainStyleMode="repeat"] - This option determines how inline elements (such as <span>, <strong>, etc.) are handled when deleting text.
162
+ * - "repeat": Inline styles are retained unless the backspace key is repeatedly pressed. If the user continuously presses backspace, the styles will eventually be removed.
163
+ * - "none": Inline styles are not retained at all. When deleting text, the associated inline elements are immediately removed along with it.
164
+ * - "always": Inline styles persist indefinitely unless explicitly removed. Even if all text inside an inline element is deleted, the element itself remains until manually removed.
165
+ * @property {Object<string, boolean>} [allowedExtraTags={script: false, style: false, meta: false, link: false, "[a-z]+:[a-z]+": false}] - Specifies extra allowed or disallowed tags.
166
+ * @property {Object<string, (...args: *) => *>} [events={}] - Custom event handlers.
167
+ * @property {string} [__textStyleTags="strong|span|font|b|var|i|em|u|ins|s|strike|del|sub|sup|mark|a|label|code|summary"] - The basic tags that serves as the base for "textStyleTags"
168
+ * @property {string} [textStyleTags="strong|span|font|b|var|i|em|u|ins|s|strike|del|sub|sup|mark|a|label|code|summary"] - Additional text style tags.
169
+ * @property {Object<string, string>} [convertTextTags={bold: "strong", underline: "u", italic: "em", strike: "del", subscript: "sub", superscript: "sup"}] - Maps text styles to specific HTML tags.
170
+ * @property {Object<string, string>} [__tagStyles={'table|th|td': 'border|border-[a-z]+|background-color|text-align|float|font-weight|text-decoration|font-style', 'ol|ul': 'list-style-type'}] - The basic tags that serves as the base for "tagStyles"
171
+ * @property {Object<string, string>} [tagStyles={}] - Specifies allowed styles for HTML tags.
172
+ * @property {string} [spanStyles="font-family|font-size|color|background-color"] - Specifies allowed styles for the "span" tag.
173
+ * @property {string} [lineStyles="text-align|margin-left|margin-right|line-height"] - Specifies allowed styles for the "line" element (p..).
174
+ * @property {string} [textDirection="ltr"] - Text direction: "ltr" or "rtl".
175
+ * @property {Array<string>} [reverseButtons=['indent-outdent']] - An array of command pairs whose shortcut icons should be opposite each other, depending on the "textDirection" mode.
176
+ * @property {number} [historyStackDelayTime=400] - Delay time for history stack updates (ms).
177
+ * @property {string} [lineAttrReset=""] - Line properties that should be reset when changing lines (e.g. "id|name").
178
+ * @property {string} [printClass=""] - Class name for printing.
179
+ * @property {string} [defaultLine="p"] - Default line element when inserting new lines.
180
+ * @property {string} [__defaultElementWhitelist="br|div"] - Default allowed HTML elements. The default values are maintained.
181
+ * @property {string} [elementWhitelist=""] - Allowed HTML elements. Delimiter: "|" (e.g. "p|div", "*").
182
+ * @property {string} [elementBlacklist=""] - Disallowed HTML elements. Delimiter: "|" (e.g. "script|style").
183
+ * @property {string} [__defaultAttributeWhitelist] - Allowed attributes. Delimiter: "|" (e.g. "href|target").
184
+ * @property {Object<string, string>} [attributeWhitelist=""] - Allowed attributes. (e.g. {a: "href|target", img: "src|alt"}).
185
+ * @property {Object<string, string>} [attributeBlacklist=""] - Disallowed attributes. (e.g. {a: "href|target", img: "src|alt"}).
186
+ * @property {string} [__defaultFormatLine="P|DIV|H[1-6]|LI|TH|TD|DETAILS"] - Overrides the editor's default "line" element.
187
+ * @property {string} [formatLine="P|DIV|H[1-6]|LI|TH|TD|DETAILS"] - Specifies the editor's "line" elements.
188
+ * - (P, DIV, H[1-6], PRE, LI | class="__se__format__line_xxx")
189
+ * - "line" element also contain "brLine" element
190
+ * @property {string} [__defaultFormatBrLine="PRE"] - Overrides the editor's default "brLine" element.
191
+ * @property {string} [formatBrLine="PRE"] - Specifies the editor's "brLine" elements. (e.g. "PRE").
192
+ * - (PRE | class="__se__format__br_line_xxx")
193
+ * - "brLine" elements is included in the "line" element.
194
+ * - "brLine" elements's line break is "BR" tag.
195
+ * ※ Entering the Enter key in the space on the last line ends "brLine" and appends "line".
196
+ * @property {string} [__defaultFormatClosureBrLine=""] - Overrides the editor's default "closureBrLine" element.
197
+ * @property {string} [formatClosureBrLine=""] - Specifies the editor's "closureBrLine" elements.
198
+ * - (class="__se__format__br_line__closure_xxx")
199
+ * - "closureBrLine" elements is included in the "brLine".
200
+ * - "closureBrLine" elements's line break is "BR" tag.
201
+ * - ※ You cannot exit this format with the Enter key or Backspace key.
202
+ * - ※ Use it only in special cases. ([ex] format of table cells)
203
+ * @property {string} [__defaultFormatBlock="BLOCKQUOTE|OL|UL|FIGCAPTION|TABLE|THEAD|TBODY|TR|CAPTION|DETAILS"] - Overrides the editor's default "block" element.
204
+ * @property {string} [formatBlock="BLOCKQUOTE|OL|UL|FIGCAPTION|TABLE|THEAD|TBODY|TR|CAPTION|DETAILS"] - Specifies the editor's "block" elements.
205
+ * - (BLOCKQUOTE, OL, UL, FIGCAPTION, TABLE, THEAD, TBODY, TR, TH, TD | class="__se__format__block_xxx")
206
+ * - "block" is wrap the "line" and "component"
207
+ * @property {string} [__defaultFormatClosureBlock="TH|TD"] - Overrides the editor's default "closureBlock" element.
208
+ * @property {string} [formatClosureBlock="TH|TD"] - Specifies the editor's "closureBlock" elements.
209
+ * - (TH, TD | class="__se__format__block_closure_xxx")
210
+ * - "closureBlock" elements is included in the "block".
211
+ * - "closureBlock" element is wrap the "line" and "component"
212
+ * - ※ You cannot exit this format with the Enter key or Backspace key.
213
+ * - ※ Use it only in special cases. ([ex] format of table cells)
214
+ * @property {string} [allowedEmptyTags=".se-component, pre, blockquote, hr, li, table, img, iframe, video, audio, canvas, details"] - Allowed empty tags.
215
+ * @property {number|string} [toolbar_width="auto"] - Toolbar width.
216
+ * @property {Element|string} [toolbar_container] - Container element for the toolbar.
217
+ * @property {number} [toolbar_sticky=0] - Enables sticky toolbar with optional offset.
218
+ * @property {boolean} [toolbar_hide=false] - Hides toolbar initially.
219
+ * @property {Object} [subToolbar] - Sub-toolbar configuration.
220
+ * @property {Array<Array<string>>} [subToolbar.buttonList] - List of Sub-toolbar buttons, grouped by sub-arrays.
221
+ * @property {"balloon"|"balloon-always"} [subToolbar.mode="balloon"] - Sub-toolbar mode: "balloon", "balloon-always".
222
+ * @property {number|string} [subToolbar.width="auto"] - Sub-toolbar width.
223
+ * @property {Element|string} [statusbar_container] - Container element for the status bar.
224
+ * @property {boolean} [shortcutsHint=true] - Displays shortcut hints in tooltips.
225
+ * @property {boolean} [shortcutsDisable=false] - Disables keyboard shortcuts.
226
+ * @property {Object<string, Array<string>>} [shortcuts] - Custom keyboard shortcuts.
227
+ * @property {number} [fullScreenOffset=0] - Offset applied when entering fullscreen mode.
228
+ * @property {string} [previewTemplate] - Custom template for preview mode.
229
+ * @property {string} [printTemplate] - Custom template for print mode.
230
+ * @property {boolean} [componentAutoSelect=false] - Enables automatic selection of inserted components.
231
+ * @property {string} [defaultUrlProtocol] - Default URL protocol for links.
232
+ * @property {string} [allUsedStyles] - Specifies additional styles to the list of allowed styles. Delimiter: "|" (e.g. "color|background-color").
233
+ * @property {Object<string, string>} [icons] - Overrides the default icons.
234
+ * @property {string} [freeCodeViewMode=false] - Enables free code view mode.
235
+ * @property {boolean} [__lineFormatFilter=true] - Line format filter configuration.
236
+ * @property {boolean} [__pluginRetainFilter=true] - Plugin retain filter configuration.
237
+ * @property {Array<string>} [__listCommonStyle=["fontSize", "color", "fontFamily", "fontWeight", "fontStyle"]] - Defines the list of styles that are applied directly to the `<li>` element
238
+ * - when a text style is applied to the entire list item.
239
+ * - For example, when changing the font size or color of a list item (`<li>`),
240
+ * - these styles will be applied to the `<li>` tag instead of wrapping the content inside additional tags.
241
+ * @property {Object<string, *>} [externalLibs] - External libraries like CodeMirror or MathJax.
242
+ * @property {Object<string, *>} [PluginOptions] - Dynamic plugin options, where the key is the plugin name and the value is its configuration.
243
+ */
244
+
245
+ /**
246
+ * @typedef {EditorBaseOptions & EditorFrameOptions} EditorInitOptions
247
+ */
248
+
249
+ /**
250
+ * @description Creates a new SunEditor instance with specified options.
251
+ * @param {Array<{target: Element, key: *, options: EditorFrameOptions}>} editorTargets - Target element or multi-root object.
252
+ * @param {EditorInitOptions} options - Configuration options for the editor.
253
+ * @returns {Object<string, *>} - SunEditor instance with context, options, and DOM elements.
254
+ */
255
+ function Constructor(editorTargets, options) {
96
256
  if (typeof options !== 'object') options = {};
97
257
 
98
258
  /** --- Plugins ------------------------------------------------------------------------------------------ */
99
259
  const plugins = {};
100
260
  if (options.plugins) {
261
+ const excludedPlugins = options.excludedPlugins || [];
101
262
  const originPlugins = options.plugins;
102
- const pluginsValues = Array.isArray(originPlugins.length)
103
- ? originPlugins
104
- : Object.keys(originPlugins).map(function (name) {
105
- return originPlugins[name];
106
- });
263
+ const pluginsValues = (Array.isArray(originPlugins) ? originPlugins : Object.keys(originPlugins)).filter((name) => !excludedPlugins.includes(name)).map((name) => originPlugins[name]);
107
264
 
108
265
  for (let i = 0, len = pluginsValues.length, p; i < len; i++) {
109
266
  p = pluginsValues[i].default || pluginsValues[i];
@@ -112,39 +269,41 @@ const Constructor = function (editorTargets, options) {
112
269
  }
113
270
 
114
271
  /** --- options --------------------------------------------------------------- */
115
- const optionMap = InitOptions(options, editorTargets);
272
+ const optionMap = InitOptions(options, editorTargets, plugins);
116
273
  const o = optionMap.o;
117
274
  const icons = optionMap.i;
118
275
  const lang = optionMap.l;
119
- const loadingBox = domUtils.createElement('DIV', { class: 'se-loading-box sun-editor-common' }, '<div class="se-loading-effect"></div>');
276
+ const loadingBox = dom.utils.createElement('DIV', { class: 'se-loading-box sun-editor-common' }, '<div class="se-loading-effect"></div>');
120
277
 
121
278
  /** --- carrier wrapper --------------------------------------------------------------- */
122
- const editor_carrier_wrapper = domUtils.createElement('DIV', { class: 'sun-editor sun-editor-carrier-wrapper sun-editor-common' + (o.get('_rtl') ? ' se-rtl' : '') });
279
+ const editor_carrier_wrapper = dom.utils.createElement('DIV', { class: 'sun-editor sun-editor-carrier-wrapper sun-editor-common' + o.get('_themeClass') + (o.get('_rtl') ? ' se-rtl' : '') });
123
280
  // menuTray
124
- const menuTray = domUtils.createElement('DIV', { class: 'se-menu-tray' });
281
+ const menuTray = dom.utils.createElement('DIV', { class: 'se-menu-tray' });
125
282
  editor_carrier_wrapper.appendChild(menuTray);
126
283
  // focus temp element
127
- const focusTemp = domUtils.createElement('INPUT', {
128
- class: '__se__focus__temp__',
129
- style: 'position: absolute !important; top: -10000px !important; display: block !important; width: 0 !important; height: 0 !important; margin: 0 !important; padding: 0 !important;'
130
- });
284
+ const focusTemp = /** @type {HTMLInputElement} */ (
285
+ dom.utils.createElement('INPUT', {
286
+ class: '__se__focus__temp__',
287
+ style: 'position: fixed !important; top: -10000px !important; left: -10000px !important; display: block !important; width: 0 !important; height: 0 !important; margin: 0 !important; padding: 0 !important;'
288
+ })
289
+ );
131
290
  focusTemp.tabIndex = 0;
132
291
  editor_carrier_wrapper.appendChild(focusTemp);
133
292
 
134
293
  // modal
135
- const modal = domUtils.createElement('DIV', { class: 'se-modal sun-editor-common' });
136
- const modal_back = domUtils.createElement('DIV', { class: 'se-modal-back', style: 'display: none;' });
137
- const modal_inner = domUtils.createElement('DIV', { class: 'se-modal-inner', style: 'display: none;' });
294
+ const modal = dom.utils.createElement('DIV', { class: 'se-modal sun-editor-common' });
295
+ const modal_back = dom.utils.createElement('DIV', { class: 'se-modal-back', style: 'display: none;' });
296
+ const modal_inner = dom.utils.createElement('DIV', { class: 'se-modal-inner', style: 'display: none;' });
138
297
  modal.appendChild(modal_back);
139
298
  modal.appendChild(modal_inner);
140
299
  editor_carrier_wrapper.appendChild(modal);
141
300
 
142
301
  // loding box, resizing back
143
- editor_carrier_wrapper.appendChild(domUtils.createElement('DIV', { class: 'se-back-wrapper' }));
302
+ editor_carrier_wrapper.appendChild(dom.utils.createElement('DIV', { class: 'se-back-wrapper' }));
144
303
  editor_carrier_wrapper.appendChild(loadingBox.cloneNode(true));
145
304
 
146
305
  // drag cursor
147
- const dragCursor = domUtils.createElement('DIV', { class: 'se-drag-cursor' });
306
+ const dragCursor = dom.utils.createElement('DIV', { class: 'se-drag-cursor' });
148
307
  editor_carrier_wrapper.appendChild(dragCursor);
149
308
 
150
309
  // set carrier wrapper
@@ -163,7 +322,7 @@ const Constructor = function (editorTargets, options) {
163
322
  } else if (/balloon/i.test(o.get('mode'))) {
164
323
  toolbar.className += ' se-toolbar-balloon';
165
324
  toolbar.style.width = o.get('toolbar_width');
166
- toolbar.appendChild(domUtils.createElement('DIV', { class: 'se-arrow' }));
325
+ toolbar.appendChild(dom.utils.createElement('DIV', { class: 'se-arrow' }));
167
326
  }
168
327
 
169
328
  /** --- subToolbar --------------------------------------------------------------- */
@@ -174,7 +333,7 @@ const Constructor = function (editorTargets, options) {
174
333
  // subbar mode must be balloon-*
175
334
  subbar.className += ' se-toolbar-balloon se-toolbar-sub';
176
335
  subbar.style.width = o.get('toolbar.sub_width');
177
- subbar.appendChild(domUtils.createElement('DIV', { class: 'se-arrow' }));
336
+ subbar.appendChild(dom.utils.createElement('DIV', { class: 'se-arrow' }));
178
337
  }
179
338
 
180
339
  /** frame - root set - start -------------------------------------------------------------- */
@@ -185,12 +344,12 @@ const Constructor = function (editorTargets, options) {
185
344
  let default_status_bar = null;
186
345
  for (let i = 0, len = editorTargets.length; i < len; i++) {
187
346
  const editTarget = editorTargets[i];
188
- const to = editTarget.options;
189
- const top_div = domUtils.createElement('DIV', { class: 'sun-editor' + (to.get('_rtl') ? ' se-rtl' : '') });
190
- const container = domUtils.createElement('DIV', { class: 'se-container' });
191
- const editor_div = domUtils.createElement('DIV', { class: 'se-wrapper' });
347
+ const to = optionMap.frameMap.get(editTarget.key);
348
+ const top_div = dom.utils.createElement('DIV', { class: 'sun-editor' + o.get('_themeClass') + (to.get('_rtl') ? ' se-rtl' : '') });
349
+ const container = dom.utils.createElement('DIV', { class: 'se-container' });
350
+ const editor_div = dom.utils.createElement('DIV', { class: 'se-wrapper' + (o.get('type') === 'document' ? ' se-type-document' : '') });
192
351
 
193
- container.appendChild(domUtils.createElement('DIV', { class: 'se-toolbar-shadow' }));
352
+ container.appendChild(dom.utils.createElement('DIV', { class: 'se-toolbar-shadow' }));
194
353
 
195
354
  // init element
196
355
  const initElements = _initTargetElements(editTarget.key, o, top_div, to);
@@ -201,22 +360,22 @@ const Constructor = function (editorTargets, options) {
201
360
  let textarea = initElements.codeView;
202
361
 
203
362
  // line breaker
204
- const line_breaker_t = domUtils.createElement('DIV', { class: 'se-line-breaker-component se-line-breaker-component-t', title: lang.insertLine }, icons.line_break);
205
- const line_breaker_b = domUtils.createElement('DIV', { class: 'se-line-breaker-component se-line-breaker-component-b', title: lang.insertLine }, icons.line_break);
363
+ const line_breaker_t = dom.utils.createElement('DIV', { class: 'se-line-breaker-component se-line-breaker-component-t', title: lang.insertLine }, icons.line_break);
364
+ const line_breaker_b = dom.utils.createElement('DIV', { class: 'se-line-breaker-component se-line-breaker-component-b', title: lang.insertLine }, icons.line_break);
206
365
 
207
366
  editor_div.appendChild(line_breaker_t);
208
367
  editor_div.appendChild(line_breaker_b);
209
368
 
210
369
  // append container
211
370
  if (placeholder_span) editor_div.appendChild(placeholder_span);
212
- container.appendChild(domUtils.createElement('DIV', { class: 'se-toolbar-sticky-dummy' }));
371
+ container.appendChild(dom.utils.createElement('DIV', { class: 'se-toolbar-sticky-dummy' }));
213
372
  container.appendChild(editor_div);
214
373
 
215
374
  // statusbar
216
375
  if (statusbar) {
217
376
  if (statusbarContainer) {
218
377
  if (!default_status_bar) {
219
- statusbarContainer.appendChild(domUtils.createElement('DIV', { class: 'sun-editor' }, statusbar));
378
+ statusbarContainer.appendChild(dom.utils.createElement('DIV', { class: 'sun-editor' + o.get('_themeClass') }, statusbar));
220
379
  default_status_bar = statusbar;
221
380
  }
222
381
  } else {
@@ -231,7 +390,7 @@ const Constructor = function (editorTargets, options) {
231
390
  const key = editTarget.key || null;
232
391
 
233
392
  // code view - wrapper
234
- const codeWrapper = domUtils.createElement('DIV', { class: 'se-code-wrapper' }, textarea);
393
+ const codeWrapper = dom.utils.createElement('DIV', { class: 'se-code-wrapper' }, textarea);
235
394
  codeWrapper.style.setProperty('display', 'none', 'important');
236
395
  editor_div.appendChild(codeWrapper);
237
396
 
@@ -240,29 +399,46 @@ const Constructor = function (editorTargets, options) {
240
399
  // not used code mirror
241
400
  if (textarea === codeMirrorEl) {
242
401
  // add line nubers
243
- const codeNumbers = domUtils.createElement('TEXTAREA', { class: 'se-code-view-line', readonly: 'true' }, null);
402
+ const codeNumbers = dom.utils.createElement('TEXTAREA', { class: 'se-code-view-line', readonly: 'true' }, null);
244
403
  codeWrapper.insertBefore(codeNumbers, textarea);
245
404
  } else {
246
405
  textarea = codeMirrorEl;
247
406
  }
248
407
 
408
+ // document type
409
+ const documentTypeInner = { inner: null, page: null, pageMirror: null };
410
+ if (o.get('type-options').includes('header')) {
411
+ documentTypeInner.inner = dom.utils.createElement('DIV', { class: 'se-document-lines', style: `height: ${to.get('height')};` }, '<div class="se-document-lines-inner"></div>');
412
+ }
413
+ if (o.get('type-options').includes('page')) {
414
+ documentTypeInner.page = dom.utils.createElement('DIV', { class: 'se-document-page' }, null);
415
+ documentTypeInner.pageMirror = dom.utils.createElement(
416
+ 'DIV',
417
+ {
418
+ class: 'sun-editor-editable se-document-page-mirror-a4',
419
+ style: `position: absolute; width: 21cm; columns: 21cm; border: 0; overflow: hidden; height: auto; top: -10000px; left: -10000px;`
420
+ },
421
+ null
422
+ );
423
+ }
424
+
249
425
  // set container
250
426
  top_div.appendChild(container);
251
427
  rootKeys.push(key);
252
- frameRoots.set(key, CreateFrameContext(editTarget, top_div, wysiwyg_div, codeWrapper, textarea, default_status_bar || statusbar, key));
428
+ frameRoots.set(key, CreateFrameContext({ target: editTarget.target, key: editTarget.key, options: to }, top_div, wysiwyg_div, codeWrapper, textarea, default_status_bar || statusbar, documentTypeInner, key));
253
429
  }
254
430
  /** frame - root set - end -------------------------------------------------------------- */
255
431
 
256
432
  // toolbar container
257
433
  const toolbar_container = o.get('toolbar_container');
258
434
  if (toolbar_container) {
259
- const top_div = domUtils.createElement('DIV', { class: 'sun-editor' + (o.get('_rtl') ? ' se-rtl' : '') });
260
- const container = domUtils.createElement('DIV', { class: 'se-container' });
435
+ const top_div = dom.utils.createElement('DIV', { class: 'sun-editor' + o.get('_themeClass') + (o.get('_rtl') ? ' se-rtl' : '') });
436
+ const container = dom.utils.createElement('DIV', { class: 'se-container' });
261
437
  container.appendChild(toolbar);
262
438
  if (subbar) container.appendChild(subbar);
263
439
  top_div.appendChild(container);
264
440
  toolbar_container.appendChild(top_div);
265
- toolbar_container.appendChild(domUtils.createElement('DIV', { class: 'se-toolbar-sticky-dummy' }));
441
+ toolbar_container.appendChild(dom.utils.createElement('DIV', { class: 'se-toolbar-sticky-dummy' }));
266
442
  } else {
267
443
  const rootContainer = frameRoots.get(rootId).get('container');
268
444
  rootContainer.insertBefore(toolbar, rootContainer.firstElementChild);
@@ -285,30 +461,74 @@ const Constructor = function (editorTargets, options) {
285
461
  pluginCallButtons_sub: sub_main ? sub_main.pluginCallButtons : [],
286
462
  responsiveButtons_sub: sub_main ? sub_main.responsiveButtons : []
287
463
  };
288
- };
464
+ }
289
465
 
290
466
  /**
291
467
  * @description Create shortcuts desc span.
292
468
  * @param {string} command Command string
293
- * @param {Array.<string>} values options.shortcuts[command]
294
- * @param {Element} button Command button element
295
- * @param {Map} keyMap Map to store shortcut key info
469
+ * @param {Array<string>} values options.shortcuts[command]
470
+ * @param {Element|null} button Command button element
471
+ * @param {Map<string, *>} keyMap Map to store shortcut key info
296
472
  * @param {Array} rc "_reverseCommandArray" option
297
473
  * @param {Array} reverseKeys Reverse key array
298
474
  */
299
475
  export function CreateShortcuts(command, button, values, keyMap, rc, reverseKeys) {
300
476
  if (!values || values.length < 2) return;
301
- const tooptip = button.querySelector('.se-tooltip-text');
477
+ const tooptip = button?.querySelector('.se-tooltip-text');
478
+
479
+ for (let i = 0, a, v, c, s, edge, space, enter, textTrigger, plugin, method, t, k, r, _i; i < values.length; i += 2 + _i) {
480
+ _i = 0;
481
+ a = values[i].split('+');
482
+
483
+ plugin = null;
484
+ method = a.at(-1).trim?.();
485
+ if (method.startsWith('~')) {
486
+ plugin = command;
487
+ method = a.pop().trim().substring(1);
488
+ } else if (method.startsWith('p~')) {
489
+ const a_ = a.pop().trim().substring(2).split('.');
490
+ plugin = a_[0];
491
+ method = a_[1];
492
+ } else if (method.startsWith('$')) {
493
+ _i = 1;
494
+ method = values[i + 2];
495
+ } else {
496
+ method = '';
497
+ }
498
+
499
+ c = s = edge = space = enter = textTrigger = v = null;
500
+ for (const a_ of a) {
501
+ switch (a_.trim()) {
502
+ case 'c':
503
+ c = true;
504
+ break;
505
+ case '!':
506
+ edge = true;
507
+ break;
508
+ case 's':
509
+ s = true;
510
+ break;
511
+ case '_':
512
+ space = true;
513
+ break;
514
+ case '=':
515
+ textTrigger = true;
516
+ break;
517
+ case '/':
518
+ enter = true;
519
+ break;
520
+ default:
521
+ v = a_;
522
+ }
523
+ }
302
524
 
303
- for (let i = 0, v, s, t, k, r; i < values.length; i += 2) {
304
- v = values[i];
305
- s = /^s/i.test(v);
306
- k = numbers.get(v) + (s ? 1000 : 0);
525
+ k = c ? v + (s ? '1000' : '') : v;
307
526
  if (!keyMap.has(k)) {
308
527
  r = rc.indexOf(command);
309
528
  r = r === -1 ? '' : numbers.isOdd(r) ? rc[r + 1] : rc[r - 1];
310
529
  if (r) reverseKeys.push(k);
311
- keyMap.set(k, { c: command, r: r, t: button.getAttribute('data-type'), e: button });
530
+
531
+ keyMap.set(k, { c, s, edge, space, enter, textTrigger, plugin, command, method, r, type: button?.getAttribute('data-type'), button, key: k });
312
532
  }
313
533
 
314
534
  if (!(t = values[i + 1])) continue;
@@ -317,13 +537,15 @@ export function CreateShortcuts(command, button, values, keyMap, rc, reverseKeys
317
537
  }
318
538
 
319
539
  function _addTooltip(tooptipBtn, shift, shortcut) {
320
- tooptipBtn.appendChild(domUtils.createElement('SPAN', { class: 'se-shortcut' }, env.cmdIcon + (shift ? env.shiftIcon : '') + '+<span class="se-shortcut-key">' + shortcut + '</span>'));
540
+ tooptipBtn.appendChild(dom.utils.createElement('SPAN', { class: 'se-shortcut' }, env.cmdIcon + (shift ? env.shiftIcon : '') + '+<span class="se-shortcut-key">' + shortcut + '</span>'));
321
541
  }
322
542
 
323
543
  /**
544
+ * @private
324
545
  * @description Returns a new object with merge "a" and "b"
325
- * @param {Object} obj object
326
- * @returns {Object}
546
+ * @param {Object<*, *>} a object
547
+ * @param {Object<*, *>} b object
548
+ * @returns {Object<*, *>} new object
327
549
  */
328
550
  function _mergeObject(a, b) {
329
551
  return [a, b].reduce((_default, _new) => {
@@ -336,11 +558,20 @@ function _mergeObject(a, b) {
336
558
 
337
559
  /**
338
560
  * @description Initialize options
339
- * @param {Object} options Options object
340
- * @param {Array.<Element>} editorTargets Target textarea
341
- * @returns {o:Map, p:Map} {{o: options map, p: plugins map}}
561
+ * @param {EditorInitOptions} options Configuration options for the editor.
562
+ * @param {Array<{target: Element, key: *, options: EditorFrameOptions}>} editorTargets Target textarea
563
+ * @param {Object<string, *>} plugins Plugins object
564
+ * @returns {{o: Map<string, *>, i: Object<string, string>, l: Object<string, string>, v: string, buttons: Array<string[]|string>, subButtons: Array<string[]|string>, statusbarContainer: Element|null, frameMap: Map<*, *>}}
565
+ * - o: options
566
+ * - i: icons
567
+ * - l: lang
568
+ * - v: value
569
+ * - buttons: Toolbar button list
570
+ * - subButtons: Sub-Toolbar button list
571
+ * - statusbarContainer: statusbar container
572
+ * - frameMap: converted options map
342
573
  */
343
- export function InitOptions(options, editorTargets) {
574
+ export function InitOptions(options, editorTargets, plugins) {
344
575
  const buttonList = options.buttonList || DEFAULT_BUTTON_LIST;
345
576
  const o = new Map();
346
577
 
@@ -349,7 +580,11 @@ export function InitOptions(options, editorTargets) {
349
580
  if (!options.toolbar_container && !/inline|balloon/i.test(options.mode)) throw Error('[SUNEDITOR.create.fail] In multi root, The "mode" option cannot be "classic" without using the "toolbar_container" option.');
350
581
  }
351
582
 
583
+ // migration data-.+
584
+ o.set('v2Migration', !!options.v2Migration);
585
+
352
586
  /** Base */
587
+ o.set('buttons', new Set(buttonList.toString().split(',')));
353
588
  const modeValue = options.strictMode !== false;
354
589
  o.set('strictMode', {
355
590
  tagFilter: modeValue,
@@ -358,13 +593,32 @@ export function InitOptions(options, editorTargets) {
358
593
  styleNodeFilter: modeValue,
359
594
  attrFilter: modeValue,
360
595
  styleFilter: modeValue,
361
- ...options.strictMode
596
+ ...(typeof options.strictMode === 'boolean' ? {} : options.strictMode)
362
597
  });
598
+ o.set('freeCodeViewMode', !!options.freeCodeViewMode);
599
+ o.set('__lineFormatFilter', options.__lineFormatFilter ?? true);
600
+ o.set('__pluginRetainFilter', options.__pluginRetainFilter ?? true);
363
601
  o.set('mode', options.mode || 'classic'); // classic, inline, balloon, balloon-always
602
+ o.set('type', options.type?.split(':')[0] || ''); // document:header,page
603
+ o.set('theme', options.theme || '');
604
+ o.set('_themeClass', options.theme ? ` se-theme-${options.theme}` : '');
605
+ o.set('type-options', options.type?.split(':')[1] || '');
364
606
  o.set('externalLibs', options.externalLibs || {});
365
- o.set('keepStyleOnDelete', !!options.keepStyleOnDelete);
366
607
  o.set('fontSizeUnits', Array.isArray(options.fontSizeUnits) && options.fontSizeUnits.length > 0 ? options.fontSizeUnits.map((v) => v.toLowerCase()) : DEFAULT_SIZE_UNITS);
367
608
  o.set('allowedClassName', new RegExp(`${options.allowedClassName && typeof options.allowedClassName === 'string' ? options.allowedClassName + '|' : ''}${DEFAULT_CLASS_NAME}`));
609
+ o.set('closeModalOutsideClick', !!options.closeModalOutsideClick);
610
+
611
+ // format
612
+ o.set('copyFormatKeepOn', !!options.copyFormatKeepOn);
613
+ o.set('syncTabIndent', options.syncTabIndent ?? true);
614
+
615
+ // auto convert on paste
616
+ o.set('autoLinkify', options.autoLinkify ?? !!plugins.link);
617
+ o.set('autoStyleify', Array.isArray(options.autoStyleify) ? options.autoStyleify : ['bold', 'underline', 'italic', 'strike']);
618
+
619
+ // scroll options
620
+ o.set('scrollToOptions', { behavior: 'auto', block: 'nearest', ...options.scrollToOptions });
621
+ o.set('componentScrollToOptions', { behavior: 'smooth', block: 'center', ...options.componentScrollToOptions });
368
622
 
369
623
  let retainStyleMode = options.retainStyleMode;
370
624
  if (typeof retainStyleMode === 'string' && !RETAIN_STYLE_MODE.includes(retainStyleMode)) {
@@ -448,6 +702,7 @@ export function InitOptions(options, editorTargets) {
448
702
  // text direction
449
703
  o.set('textDirection', typeof options.textDirection !== 'string' ? 'ltr' : options.textDirection);
450
704
  o.set('_rtl', o.get('textDirection') === 'rtl');
705
+ // An array of key codes generated with the reverseButtons option, used to reverse the action for a specific key combination.
451
706
  o.set('reverseCommands', ['indent-outdent'].concat(options.reverseButtons || []));
452
707
  o.set('_reverseCommandArray', ('-' + o.get('reverseCommands').join('-')).split('-'));
453
708
  if (numbers.isEven(o.get('_reverseCommandArray').length)) {
@@ -456,16 +711,17 @@ export function InitOptions(options, editorTargets) {
456
711
 
457
712
  // etc
458
713
  o.set('historyStackDelayTime', typeof options.historyStackDelayTime === 'number' ? options.historyStackDelayTime : 400);
459
- o.set('_editableClass', 'sun-editor-editable' + (o.get('_rtl') ? ' se-rtl' : ''));
714
+ o.set('_editableClass', 'sun-editor-editable' + o.get('_themeClass') + (o.get('_rtl') ? ' se-rtl' : '') + (o.get('type') === 'document' ? ' se-type-document-editable' : ''));
460
715
  o.set('lineAttrReset', ['id'].concat(options.lineAttrReset && typeof options.lineAttrReset === 'string' ? options.lineAttrReset.toLowerCase().split('|') : []));
461
- o.set('printClass', typeof options.printClass === 'string' ? options.printClass : null);
716
+ o.set('printClass', typeof options.printClass === 'string' ? options.printClass + ' ' + o.get('_editableClass') : null);
462
717
 
463
718
  /** whitelist, blacklist */
464
719
  // default line
465
720
  o.set('defaultLine', typeof options.defaultLine === 'string' && options.defaultLine.length > 0 ? options.defaultLine : 'p');
466
721
  // element
467
722
  const elw = (typeof options.elementWhitelist === 'string' ? options.elementWhitelist : '').toLowerCase();
468
- o.set('elementWhitelist', elw + (elw ? '|' : '') + o.get('_allowedExtraTag'));
723
+ const mjxEls = o.get('externalLibs').mathjax ? DEFAULT_CLASS_MJX + '|' : '';
724
+ o.set('elementWhitelist', elw + (elw ? '|' : '') + mjxEls + o.get('_allowedExtraTag'));
469
725
  const elb = _createBlacklist((typeof options.elementBlacklist === 'string' ? options.elementBlacklist : '').toLowerCase(), o.get('defaultLine'));
470
726
  o.set('elementBlacklist', elb + (elb ? '|' : '') + o.get('_disallowedExtraTag'));
471
727
  // attribute
@@ -519,6 +775,8 @@ export function InitOptions(options, editorTargets) {
519
775
  )
520
776
  );
521
777
 
778
+ o.set('allowedEmptyTags', DEFAULT_ALLOWED_EMPTY_NODE_LIST + (options.allowedEmptyTags ? ', ' + options.allowedEmptyTags : ''));
779
+
522
780
  /** __defaults */
523
781
  o.set('__defaultElementWhitelist', REQUIRED_ELEMENT_WHITELIST + '|' + (typeof options.__defaultElementWhitelist === 'string' ? options.__defaultElementWhitelist : DEFAULT_ELEMENT_WHITELIST).toLowerCase());
524
782
  o.set('__defaultAttributeWhitelist', (typeof options.__defaultAttributeWhitelist === 'string' ? options.__defaultAttributeWhitelist : DEFAULT_ATTRIBUTE_WHITELIST).toLowerCase());
@@ -528,7 +786,7 @@ export function InitOptions(options, editorTargets) {
528
786
  /** Toolbar */
529
787
  o.set('toolbar_width', options.toolbar_width ? (numbers.is(options.toolbar_width) ? options.toolbar_width + 'px' : options.toolbar_width) : 'auto');
530
788
  o.set('toolbar_container', options.toolbar_container && !/inline/i.test(o.get('mode')) ? (typeof options.toolbar_container === 'string' ? _d.querySelector(options.toolbar_container) : options.toolbar_container) : null);
531
- o.set('toolbar_sticky', /balloon/i.test(o.get('mode')) ? -1 : options.toolbar_sticky === undefined ? 0 : /^\d+/.test(options.toolbar_sticky) ? numbers.get(options.toolbar_sticky, 0) : -1);
789
+ o.set('toolbar_sticky', /balloon/i.test(o.get('mode')) ? -1 : options.toolbar_sticky === undefined ? 0 : numbers.is(options.toolbar_sticky) ? numbers.get(options.toolbar_sticky, 0) : -1);
532
790
  o.set('toolbar_hide', !!options.toolbar_hide);
533
791
 
534
792
  /** subToolbar */
@@ -541,12 +799,14 @@ export function InitOptions(options, editorTargets) {
541
799
  o.set('_subMode', subbar.mode || 'balloon');
542
800
  o.set('toolbar.sub_width', subbar.width ? (numbers.is(subbar.width) ? subbar.width + 'px' : subbar.width) : 'auto');
543
801
  subButtons = o.get('_rtl') ? subbar.buttonList.reverse() : subbar.buttonList;
802
+ o.set('buttons_sub', new Set(subButtons.toString().split(',')));
544
803
  }
545
804
  }
546
805
 
547
806
  /** root options */
807
+ const frameMap = new Map();
548
808
  for (let i = 0, len = editorTargets.length; i < len; i++) {
549
- InitFrameOptions(editorTargets[i].options || {}, options, (editorTargets[i].options = new Map()));
809
+ frameMap.set(editorTargets[i].key, InitFrameOptions(editorTargets[i].options || {}, options));
550
810
  }
551
811
 
552
812
  /** Key actions */
@@ -557,20 +817,25 @@ export function InitOptions(options, editorTargets) {
557
817
  : [
558
818
  {
559
819
  // default command
560
- selectAll: ['65', 'A'],
561
- bold: ['66', 'B'],
562
- strike: ['s83', 'S'],
563
- underline: ['85', 'U'],
564
- italic: ['73', 'I'],
565
- redo: ['89', 'Y', 's90', 'Z'],
566
- undo: ['90', 'Z'],
567
- indent: ['221', ']'],
568
- outdent: ['219', '['],
569
- sup: ['187', '='],
570
- sub: ['s187', '='],
571
- save: ['83', 'S'],
820
+ selectAll: ['c+KeyA', 'A'],
821
+ bold: ['c+KeyB', 'B'],
822
+ strike: ['c+s+KeyS', 'S'],
823
+ underline: ['c+KeyU', 'U'],
824
+ italic: ['c+KeyI', 'I'],
825
+ redo: ['c+KeyY', 'Y', 'c+s+KeyZ', 'Z'],
826
+ undo: ['c+KeyZ', 'Z'],
827
+ indent: ['c+BracketRight', ']'],
828
+ outdent: ['c+BracketLeft', '['],
829
+ save: ['c+KeyS', 'S'],
572
830
  // plugins
573
- link: ['75', 'K']
831
+ link: ['c+KeyK', 'K'],
832
+ hr: ['!+---+=+~shortcut', ''],
833
+ list_numbered: ['!+1.+_+~shortcut', ''],
834
+ list_bulleted: ['!+*.+_+~shortcut', ''],
835
+ // custom
836
+ _h1: ['c+s+Digit1+p~formatBlock.createHeader', ''],
837
+ _h2: ['c+s+Digit2+p~formatBlock.createHeader', ''],
838
+ _h3: ['c+s+Digit3+p~formatBlock.createHeader', '']
574
839
  },
575
840
  options.shortcuts || {}
576
841
  ].reduce((_default, _new) => {
@@ -582,12 +847,12 @@ export function InitOptions(options, editorTargets) {
582
847
  o.set('shortcuts', shortcuts);
583
848
 
584
849
  /** View */
585
- o.set('fullScreenOffset', options.fullScreenOffset === undefined ? 0 : /^\d+/.test(options.fullScreenOffset) ? numbers.get(options.fullScreenOffset, 0) : 0);
850
+ o.set('fullScreenOffset', options.fullScreenOffset === undefined ? 0 : numbers.is(options.fullScreenOffset) ? numbers.get(options.fullScreenOffset, 0) : 0);
586
851
  o.set('previewTemplate', typeof options.previewTemplate === 'string' ? options.previewTemplate : null);
587
852
  o.set('printTemplate', typeof options.printTemplate === 'string' ? options.printTemplate : null);
588
853
 
589
854
  /** --- Media select */
590
- o.set('mediaAutoSelect', options.mediaAutoSelect === undefined ? true : !!options.mediaAutoSelect);
855
+ o.set('componentAutoSelect', options.componentAutoSelect === undefined ? false : !!options.componentAutoSelect);
591
856
 
592
857
  /** --- Url input protocol */
593
858
  o.set('defaultUrlProtocol', typeof options.defaultUrlProtocol === 'string' ? options.defaultUrlProtocol : null);
@@ -651,42 +916,49 @@ export function InitOptions(options, editorTargets) {
651
916
  return {
652
917
  o: o,
653
918
  i: icons,
654
- l: options.lang || _defaultLang,
919
+ l: /** @type {Object<string, string>} */ (options.lang || _defaultLang),
655
920
  v: (options.value = typeof options.value === 'string' ? options.value : null),
656
921
  buttons: o.get('_rtl') ? buttonList.reverse() : buttonList,
657
922
  subButtons: subButtons,
658
- statusbarContainer: typeof options.statusbar_container === 'string' ? _d.querySelector(options.statusbar_container) : options.statusbar_container
923
+ statusbarContainer: typeof options.statusbar_container === 'string' ? _d.querySelector(options.statusbar_container) : options.statusbar_container,
924
+ frameMap: frameMap
659
925
  };
660
926
  }
661
927
 
928
+ /**
929
+ * @description Create a context object for the editor frame.
930
+ * @param {Map<string, *>} targetOptions - editor.frameOptions
931
+ * @param {HTMLElement} statusbar - statusbar element
932
+ * @returns {{statusbar: HTMLElement, navigation: HTMLElement, charWrapper: HTMLElement, charCounter: HTMLElement}}
933
+ */
662
934
  export function CreateStatusbar(targetOptions, statusbar) {
663
935
  let navigation = null;
664
936
  let charWrapper = null;
665
937
  let charCounter = null;
666
938
 
667
939
  if (targetOptions.get('statusbar')) {
668
- statusbar = statusbar || domUtils.createElement('DIV', { class: 'se-status-bar sun-editor-common' });
940
+ statusbar = statusbar || dom.utils.createElement('DIV', { class: 'se-status-bar sun-editor-common' });
669
941
 
670
942
  /** navigation */
671
- navigation = statusbar.querySelector('.se-navigation') || domUtils.createElement('DIV', { class: 'se-navigation sun-editor-common' });
943
+ navigation = statusbar.querySelector('.se-navigation') || dom.utils.createElement('DIV', { class: 'se-navigation sun-editor-common' });
672
944
  statusbar.appendChild(navigation);
673
945
 
674
946
  /** char counter */
675
947
  if (targetOptions.get('charCounter')) {
676
- charWrapper = statusbar.querySelector('.se-char-counter-wrapper') || domUtils.createElement('DIV', { class: 'se-char-counter-wrapper' });
948
+ charWrapper = statusbar.querySelector('.se-char-counter-wrapper') || dom.utils.createElement('DIV', { class: 'se-char-counter-wrapper' });
677
949
 
678
950
  if (targetOptions.get('charCounter_label')) {
679
- const charLabel = charWrapper.querySelector('.se-char-label') || domUtils.createElement('SPAN', { class: 'se-char-label' });
951
+ const charLabel = charWrapper.querySelector('.se-char-label') || dom.utils.createElement('SPAN', { class: 'se-char-label' });
680
952
  charLabel.textContent = targetOptions.get('charCounter_label');
681
953
  charWrapper.appendChild(charLabel);
682
954
  }
683
955
 
684
- charCounter = charWrapper.querySelector('.se-char-counter') || domUtils.createElement('SPAN', { class: 'se-char-counter' });
956
+ charCounter = charWrapper.querySelector('.se-char-counter') || dom.utils.createElement('SPAN', { class: 'se-char-counter' });
685
957
  charCounter.textContent = '0';
686
958
  charWrapper.appendChild(charCounter);
687
959
 
688
960
  if (targetOptions.get('charCounter_max') > 0) {
689
- const char_max = charWrapper.querySelector('.se-char-max') || domUtils.createElement('SPAN', { class: 'se-char-max' });
961
+ const char_max = charWrapper.querySelector('.se-char-max') || dom.utils.createElement('SPAN', { class: 'se-char-max' });
690
962
  char_max.textContent = ' / ' + targetOptions.get('charCounter_max');
691
963
  charWrapper.appendChild(char_max);
692
964
  }
@@ -697,13 +969,21 @@ export function CreateStatusbar(targetOptions, statusbar) {
697
969
 
698
970
  return {
699
971
  statusbar: statusbar,
700
- navigation: navigation,
701
- charWrapper: charWrapper,
702
- charCounter: charCounter
972
+ navigation: /** @type {HTMLElement} */ (navigation),
973
+ charWrapper: /** @type {HTMLElement} */ (charWrapper),
974
+ charCounter: /** @type {HTMLElement} */ (charCounter)
703
975
  };
704
976
  }
705
977
 
706
- function InitFrameOptions(o, origin, fo) {
978
+ /**
979
+ * @description Initialize options.
980
+ * @param {EditorFrameOptions} o - Target options
981
+ * @param {EditorInitOptions} origin - Full options
982
+ * @returns {Map<string, *>}
983
+ */
984
+ function InitFrameOptions(o, origin) {
985
+ const fo = new Map();
986
+
707
987
  fo.set('_origin', o);
708
988
  const barContainer = origin.statusbar_container;
709
989
 
@@ -757,14 +1037,18 @@ function InitFrameOptions(o, origin, fo) {
757
1037
  fo.set('charCounter_max', numbers.is(charCounter_max) && charCounter_max > -1 ? charCounter_max * 1 : null);
758
1038
  fo.set('charCounter_label', typeof charCounter_label === 'string' ? charCounter_label.trim() : null);
759
1039
  fo.set('charCounter_type', typeof charCounter_type === 'string' ? charCounter_type : 'char');
1040
+
1041
+ return fo;
760
1042
  }
761
1043
 
762
1044
  /**
1045
+ * @private
763
1046
  * @description Initialize property of suneditor elements
764
- * @param {string} key Key
765
- * @param {Object} options Options
766
- * @param {Element} topDiv Suneditor top div
767
- * @returns {Object} Bottom bar elements (statusbar, navigation, charWrapper, charCounter)
1047
+ * @param {string} key - The key of the editor frame
1048
+ * @param {Map<string, *>} options - options
1049
+ * @param {HTMLElement} topDiv - top div
1050
+ * @param {Map<string, *>} targetOptions - editor.frameOptions
1051
+ * @returns {{bottomBar: ReturnType<CreateStatusbar>, wysiwygFrame: HTMLElement, codeView: HTMLElement, placeholder: HTMLElement}}
768
1052
  */
769
1053
  function _initTargetElements(key, options, topDiv, targetOptions) {
770
1054
  const editorStyles = targetOptions.get('_defaultStyles');
@@ -773,13 +1057,13 @@ function _initTargetElements(key, options, topDiv, targetOptions) {
773
1057
 
774
1058
  /** editor */
775
1059
  // wysiwyg div or iframe
776
- const wysiwygDiv = domUtils.createElement(!targetOptions.get('iframe') ? 'DIV' : 'IFRAME', {
1060
+ const wysiwygDiv = dom.utils.createElement(!targetOptions.get('iframe') ? 'DIV' : 'IFRAME', {
777
1061
  class: 'se-wrapper-inner se-wrapper-wysiwyg',
778
1062
  'data-root-key': key
779
1063
  });
780
1064
 
781
1065
  if (!targetOptions.get('iframe')) {
782
- wysiwygDiv.setAttribute('contenteditable', true);
1066
+ wysiwygDiv.setAttribute('contenteditable', 'true');
783
1067
  wysiwygDiv.setAttribute('scrolling', 'auto');
784
1068
  wysiwygDiv.className += ' ' + options.get('_editableClass');
785
1069
  wysiwygDiv.style.cssText = editorStyles.frame + editorStyles.editor;
@@ -788,17 +1072,19 @@ function _initTargetElements(key, options, topDiv, targetOptions) {
788
1072
  for (const frameKey in frameAttrs) {
789
1073
  wysiwygDiv.setAttribute(frameKey, frameAttrs[frameKey]);
790
1074
  }
791
- wysiwygDiv.allowFullscreen = true;
792
- wysiwygDiv.frameBorder = 0;
793
- wysiwygDiv.style.cssText = editorStyles.frame;
1075
+
1076
+ const iframeWW = /** @type {HTMLIFrameElement} */ (wysiwygDiv);
1077
+ iframeWW.allowFullscreen = true;
1078
+ iframeWW.frameBorder = '0';
1079
+ iframeWW.style.cssText = editorStyles.frame;
794
1080
  }
795
1081
 
796
1082
  // textarea for code view
797
- const textarea = domUtils.createElement('TEXTAREA', { class: 'se-wrapper-inner se-code-viewer', style: editorStyles.frame });
1083
+ const textarea = dom.utils.createElement('TEXTAREA', { class: 'se-wrapper-inner se-code-viewer', style: editorStyles.frame });
798
1084
  let placeholder = null;
799
1085
  if (targetOptions.get('placeholder')) {
800
- placeholder = domUtils.createElement('SPAN', { class: 'se-placeholder' });
801
- placeholder.innerText = targetOptions.get('placeholder');
1086
+ placeholder = dom.utils.createElement('SPAN', { class: 'se-placeholder' });
1087
+ placeholder.textContent = targetOptions.get('placeholder');
802
1088
  }
803
1089
 
804
1090
  return {
@@ -810,9 +1096,10 @@ function _initTargetElements(key, options, topDiv, targetOptions) {
810
1096
  }
811
1097
 
812
1098
  /**
1099
+ * @private
813
1100
  * @description Check the CodeMirror option to apply the CodeMirror and return the CodeMirror element.
814
- * @param {Object} options options
815
- * @param {Element} textarea textarea element
1101
+ * @param {Map<string, *>} options options
1102
+ * @param {HTMLElement} textarea textarea element
816
1103
  */
817
1104
  function _checkCodeMirror(options, targetOptions, textarea) {
818
1105
  let cmeditor = null;
@@ -863,7 +1150,7 @@ function _checkCodeMirror(options, targetOptions, textarea) {
863
1150
 
864
1151
  options.set('hasCodeMirror', hasCodeMirror);
865
1152
  if (cmeditor) {
866
- domUtils.removeItem(textarea);
1153
+ dom.utils.removeItem(textarea);
867
1154
  cmeditor.className += ' se-code-viewer-mirror';
868
1155
  return cmeditor;
869
1156
  }
@@ -872,6 +1159,7 @@ function _checkCodeMirror(options, targetOptions, textarea) {
872
1159
  }
873
1160
 
874
1161
  /**
1162
+ * @private
875
1163
  * @description create blacklist
876
1164
  * @param {string} blacklist blacklist
877
1165
  * @param {string} defaultLine options.get('defaultLine')
@@ -893,6 +1181,7 @@ function _createBlacklist(blacklist, defaultLine) {
893
1181
  }
894
1182
 
895
1183
  /**
1184
+ * @private
896
1185
  * @description create formats regexp object.
897
1186
  * @param {string} value value
898
1187
  * @param {string} defaultValue default value
@@ -913,8 +1202,9 @@ function _createFormatInfo(value, defaultValue, blacklist) {
913
1202
  }
914
1203
 
915
1204
  /**
1205
+ * @private
916
1206
  * @description create whitelist or blacklist.
917
- * @param {Object} o options
1207
+ * @param {Map<string, *>} o options
918
1208
  * @returns {string} whitelist
919
1209
  */
920
1210
  function _createWhitelist(o) {
@@ -928,8 +1218,9 @@ function _createWhitelist(o) {
928
1218
  }
929
1219
 
930
1220
  /**
1221
+ * @private
931
1222
  * @description Suneditor's Default button list
932
- * @param {Object} options options
1223
+ * @param {Map<string, *>} options options
933
1224
  */
934
1225
  function _defaultButtons(options, icons, lang) {
935
1226
  const isRTL = options.get('_rtl');
@@ -941,6 +1232,7 @@ function _defaultButtons(options, icons, lang) {
941
1232
  subscript: ['', lang.subscript, 'subscript', '', icons.subscript],
942
1233
  superscript: ['', lang.superscript, 'superscript', '', icons.superscript],
943
1234
  removeFormat: ['', lang.removeFormat, 'removeFormat', '', icons.remove_format],
1235
+ copyFormat: ['', lang.copyFormat, 'copyFormat', '', icons.format_paint],
944
1236
  indent: ['se-icon-flip-rtl', lang.indent, 'indent', '', isRTL ? icons.outdent : icons.indent],
945
1237
  outdent: ['se-icon-flip-rtl', lang.outdent, 'outdent', '', isRTL ? icons.indent : icons.outdent],
946
1238
  fullScreen: ['se-code-view-enabled se-component-enabled', lang.fullScreen, 'fullScreen', '', icons.expansion],
@@ -955,17 +1247,23 @@ function _defaultButtons(options, icons, lang) {
955
1247
  dir_rtl: ['', lang.dir_rtl, 'dir_rtl', '', icons.dir_rtl],
956
1248
  save: ['se-component-enabled', lang.save, 'save', '', icons.save],
957
1249
  newDocument: ['se-component-enabled', lang.newDocument, 'newDocument', '', icons.new_document],
958
- selectAll: ['se-component-enabled', lang.selectAll, 'selectAll', '', icons.select_all]
1250
+ selectAll: ['se-component-enabled', lang.selectAll, 'selectAll', '', icons.select_all],
1251
+ pageBreak: ['se-component-enabled', lang.pageBreak, 'pageBreak', '', icons.page_break],
1252
+ // document type buttons
1253
+ pageUp: ['se-component-enabled', lang.pageUp, 'pageUp', '', icons.page_up],
1254
+ pageDown: ['se-component-enabled', lang.pageDown, 'pageDown', '', icons.page_down],
1255
+ pageNavigator: ['se-component-enabled', '', 'pageNavigator', 'input', '']
959
1256
  };
960
1257
  }
961
1258
 
962
1259
  /**
1260
+ * @private
963
1261
  * @description Create a group div containing each module
964
- * @returns {Object}
1262
+ * @returns {{div: Element, ul: Element}}
965
1263
  */
966
1264
  function _createModuleGroup() {
967
- const oUl = domUtils.createElement('UL', { class: 'se-menu-list' });
968
- const oDiv = domUtils.createElement('DIV', { class: 'se-btn-module se-btn-module-border' }, oUl);
1265
+ const oUl = dom.utils.createElement('UL', { class: 'se-menu-list' });
1266
+ const oDiv = dom.utils.createElement('DIV', { class: 'se-btn-module se-btn-module-border' }, oUl);
969
1267
 
970
1268
  return {
971
1269
  div: oDiv,
@@ -974,27 +1272,38 @@ function _createModuleGroup() {
974
1272
  }
975
1273
 
976
1274
  /**
1275
+ * @private
977
1276
  * @description Create a button element
978
1277
  * @param {string} className className in button
979
1278
  * @param {string} title Title in button
980
1279
  * @param {string} dataCommand The data-command property of the button
981
- * @param {string} dataType The data-type property of the button ('modal', 'dropdown', 'command', 'container')
1280
+ * @param {"command"|"dropdown"|"field"|"browser"|"input"|"modal"|"popup"} dataType The data-type property of the button
982
1281
  * @param {string} innerHTML Html in button
983
1282
  * @param {string} _disabled Button disabled
984
- * @param {Object} icons Icons
985
- * @returns {Object}
1283
+ * @param {Object<string, string>} icons Icons
1284
+ * @returns {{li: HTMLElement, button: HTMLElement}}
986
1285
  */
987
1286
  function _createButton(className, title, dataCommand, dataType, innerHTML, _disabled, icons) {
988
- const oLi = domUtils.createElement('LI');
1287
+ if (!innerHTML) innerHTML = '';
1288
+
1289
+ const oLi = dom.utils.createElement('LI');
989
1290
  const label = title || '';
990
- const oButton = domUtils.createElement(/^INPUT|FIELD$/i.test(dataType) ? 'DIV' : 'BUTTON', {
991
- type: 'button',
992
- class: 'se-toolbar-btn se-btn se-tooltip' + (className ? ' ' + className : ''),
993
- 'data-command': dataCommand,
994
- 'data-type': dataType,
995
- 'aria-label': label.replace(/<span .+<\/span>/, ''),
996
- tabindex: '-1'
997
- });
1291
+ const isDiv = /^INPUT|FIELD$/i.test(dataType);
1292
+ const oButton = /** @type {HTMLButtonElement} */ (
1293
+ 'se-toolbar-separator-vertical' === className
1294
+ ? dom.utils.createElement('DIV', { class: className, tabindex: '-1' }, null)
1295
+ : dom.utils.createElement(isDiv ? 'DIV' : 'BUTTON', {
1296
+ class: 'se-toolbar-btn se-btn se-tooltip' + (className ? ' ' + className : ''),
1297
+ 'data-command': dataCommand,
1298
+ 'data-type': dataType,
1299
+ 'aria-label': label.replace(/<span .+<\/span>/, ''),
1300
+ tabindex: '-1'
1301
+ })
1302
+ );
1303
+
1304
+ if (!isDiv) {
1305
+ oButton.setAttribute('type', 'button');
1306
+ }
998
1307
 
999
1308
  if (/^default\./i.test(innerHTML)) {
1000
1309
  innerHTML = icons[innerHTML.replace(/^default\./i, '')];
@@ -1004,9 +1313,9 @@ function _createButton(className, title, dataCommand, dataType, innerHTML, _disa
1004
1313
  oButton.className += ' se-btn-more-text';
1005
1314
  }
1006
1315
 
1007
- if (_disabled) oButton.setAttribute('disabled', true);
1316
+ if (_disabled) oButton.disabled = true;
1008
1317
 
1009
- if (/^FIELD$/i.test(dataType)) domUtils.addClass(oLi, 'se-toolbar-hidden-btn');
1318
+ if (/^FIELD$/i.test(dataType)) dom.utils.addClass(oLi, 'se-toolbar-hidden-btn');
1010
1319
 
1011
1320
  if (label) innerHTML += CreateTooltipInner(label);
1012
1321
  if (innerHTML) oButton.innerHTML = innerHTML;
@@ -1019,18 +1328,34 @@ function _createButton(className, title, dataCommand, dataType, innerHTML, _disa
1019
1328
  };
1020
1329
  }
1021
1330
 
1331
+ /**
1332
+ * @description Create tooltip HTML
1333
+ * @param {string} text Tooltip text
1334
+ * @returns {string} Tooltip HTML
1335
+ */
1022
1336
  export function CreateTooltipInner(text) {
1023
1337
  return `<span class="se-tooltip-inner"><span class="se-tooltip-text">${text}</span></span>`;
1024
1338
  }
1025
1339
 
1340
+ /**
1341
+ * @description Update a button state, attributes, and icons
1342
+ * @param {HTMLElement|null} element Button element
1343
+ * @param {Object<string, *>} plugin Plugin
1344
+ * @param {Object<string, string>} icons Icons
1345
+ * @param {Object<string, string>} lang lang
1346
+ */
1026
1347
  export function UpdateButton(element, plugin, icons, lang) {
1027
1348
  if (!element) return;
1028
1349
 
1029
1350
  const noneInner = plugin.inner === false;
1030
1351
 
1031
- element.innerHTML = noneInner
1032
- ? ''
1033
- : (plugin.inner || icons[plugin.icon] || plugin.icon || '<span class="se-icon-text">!</span>') + '<span class="se-tooltip-inner"><span class="se-tooltip-text">' + (lang[plugin.title] || plugin.title) + '</span></span>';
1352
+ if (plugin.inner?.nodeType === 1) {
1353
+ element.appendChild(plugin.inner);
1354
+ } else {
1355
+ element.innerHTML = noneInner
1356
+ ? ''
1357
+ : (plugin.inner || icons[plugin.icon] || plugin.icon || '<span class="se-icon-text">!</span>') + '<span class="se-tooltip-inner"><span class="se-tooltip-text">' + (lang[plugin.title] || plugin.title) + '</span></span>';
1358
+ }
1034
1359
 
1035
1360
  element.setAttribute('aria-label', plugin.title);
1036
1361
 
@@ -1043,24 +1368,24 @@ export function UpdateButton(element, plugin, icons, lang) {
1043
1368
  }
1044
1369
 
1045
1370
  // side, replace button
1046
- if (plugin.afterButton) {
1047
- domUtils.addClass(plugin.afterButton, 'se-toolbar-btn');
1048
- element.parentElement.appendChild(plugin.afterButton);
1371
+ if (plugin.afterItem) {
1372
+ dom.utils.addClass(plugin.afterItem, 'se-toolbar-btn');
1373
+ element.parentElement.appendChild(plugin.afterItem);
1049
1374
 
1050
- domUtils.addClass(element, 'se-side-btn-a');
1051
- domUtils.addClass(plugin.afterButton, 'se-side-btn-after');
1375
+ dom.utils.addClass(element, 'se-side-btn-a');
1376
+ dom.utils.addClass(plugin.afterItem, 'se-side-btn-after');
1052
1377
  }
1053
- if (plugin.beforeButton) {
1054
- domUtils.addClass(plugin.beforeButton, 'se-toolbar-btn');
1055
- element.parentElement.insertBefore(plugin.beforeButton, element);
1378
+ if (plugin.beforeItem) {
1379
+ dom.utils.addClass(plugin.beforeItem, 'se-toolbar-btn');
1380
+ element.parentElement.insertBefore(plugin.beforeItem, element);
1056
1381
 
1057
- if (plugin.afterButton) {
1058
- domUtils.addClass(element, 'se-side-btn');
1059
- domUtils.removeClass(element, 'se-side-btn-a');
1382
+ if (plugin.afterItem) {
1383
+ dom.utils.addClass(element, 'se-side-btn');
1384
+ dom.utils.removeClass(element, 'se-side-btn-a');
1060
1385
  } else {
1061
- domUtils.addClass(element, 'se-side-btn-b');
1386
+ dom.utils.addClass(element, 'se-side-btn-b');
1062
1387
  }
1063
- domUtils.addClass(plugin.beforeButton, 'se-side-btn-before');
1388
+ dom.utils.addClass(plugin.beforeItem, 'se-side-btn-before');
1064
1389
  }
1065
1390
  if (plugin.replaceButton) {
1066
1391
  element.parentElement.appendChild(plugin.replaceButton);
@@ -1070,10 +1395,10 @@ export function UpdateButton(element, plugin, icons, lang) {
1070
1395
  if (!plugin.replaceButton && /^INPUT$/i.test(element.getAttribute('data-type'))) {
1071
1396
  const inputTarget = element.querySelector('input');
1072
1397
  if (inputTarget) {
1073
- domUtils.addClass(inputTarget, 'se-toolbar-btn');
1398
+ dom.utils.addClass(inputTarget, 'se-toolbar-btn');
1074
1399
  inputTarget.setAttribute('data-command', element.getAttribute('data-command'));
1075
1400
  inputTarget.setAttribute('data-type', element.getAttribute('data-type'));
1076
- if (element.hasAttribute('disabled')) inputTarget.setAttribute('disabled', true);
1401
+ if (element.hasAttribute('disabled')) inputTarget.disabled = true;
1077
1402
  }
1078
1403
  }
1079
1404
  }
@@ -1081,17 +1406,18 @@ export function UpdateButton(element, plugin, icons, lang) {
1081
1406
  /**
1082
1407
  * @description Create editor HTML
1083
1408
  * @param {Array} buttonList option.buttonList
1084
- * @param {Object|null} plugins Plugins
1085
- * @param {Array} options options
1086
- * @param {Object} icons icons
1087
- * @param {Object} lang lang
1409
+ * @param {?Object<string, *>} plugins Plugins
1410
+ * @param {Map<string, *>} options options
1411
+ * @param {Object<string, string>} icons icons
1412
+ * @param {Object<string, string>} lang lang
1088
1413
  * @param {boolean} isUpdate Is update
1089
- * @returns {Object} { element: (Element) Toolbar element, plugins: (Array|null) Plugins Array, pluginCallButtons: (Object), responsiveButtons: (Array) }
1414
+ * @returns {{element: HTMLElement, pluginCallButtons: Object<string, Array<HTMLElement>>, responsiveButtons: Array<HTMLElement>, buttonTray: HTMLElement, updateButtons: Array<{button: HTMLElement, plugin: *, key: string}>}}}
1090
1415
  */
1091
1416
  export function CreateToolBar(buttonList, plugins, options, icons, lang, isUpdate) {
1092
1417
  /** create button list */
1093
1418
  buttonList = JSON.parse(JSON.stringify(buttonList));
1094
1419
  const defaultButtonList = _defaultButtons(options, icons, lang);
1420
+ /** @type {Object<string, Array<HTMLElement>>} */
1095
1421
  const pluginCallButtons = {};
1096
1422
  const responsiveButtons = [];
1097
1423
  const updateButtons = [];
@@ -1101,10 +1427,10 @@ export function CreateToolBar(buttonList, plugins, options, icons, lang, isUpdat
1101
1427
  let plugin = null;
1102
1428
  let moduleElement = null;
1103
1429
  let buttonElement = null;
1104
- let vertical = false;
1105
- const moreLayer = domUtils.createElement('DIV', { class: 'se-toolbar-more-layer' });
1106
- const buttonTray = domUtils.createElement('DIV', { class: 'se-btn-tray' });
1107
- const separator_vertical = domUtils.createElement('DIV', { class: 'se-toolbar-separator-vertical' });
1430
+ // let vertical = false;
1431
+ const moreLayer = dom.utils.createElement('DIV', { class: 'se-toolbar-more-layer' });
1432
+ const buttonTray = dom.utils.createElement('DIV', { class: 'se-btn-tray' });
1433
+ const separator_vertical = dom.utils.createElement('DIV', { class: 'se-toolbar-separator-vertical' });
1108
1434
 
1109
1435
  buttonGroupLoop: for (let i = 0, more, moreContainer, moreCommand, buttonGroup, align; i < buttonList.length; i++) {
1110
1436
  more = false;
@@ -1134,14 +1460,14 @@ export function CreateToolBar(buttonList, plugins, options, icons, lang, isUpdat
1134
1460
  } else {
1135
1461
  // align
1136
1462
  if (/^-/.test(button)) {
1137
- align = button.substr(1);
1463
+ align = button.substring(1);
1138
1464
  moduleElement.div.className += ' module-float-' + align;
1139
1465
  continue;
1140
1466
  }
1141
1467
 
1142
1468
  // rtl fix
1143
1469
  if (/^#/.test(button)) {
1144
- const option = button.substr(1);
1470
+ const option = button.substring(1);
1145
1471
  if (option === 'fix') moduleElement.ul.className += ' se-menu-dir-fix';
1146
1472
  continue;
1147
1473
  }
@@ -1154,6 +1480,9 @@ export function CreateToolBar(buttonList, plugins, options, icons, lang, isUpdat
1154
1480
  const title = matched[1].trim();
1155
1481
  const innerHTML = matched[2].trim();
1156
1482
  modules = ['se-btn-more', /^lang\./i.test(title) ? lang[title.replace(/^lang\./i, '')] : title, moreCommand, 'MORE', innerHTML];
1483
+ } else if (button === '|') {
1484
+ // separator vertical
1485
+ modules = ['se-toolbar-separator-vertical', '', '', 'separator', ''];
1157
1486
  } else {
1158
1487
  // default command
1159
1488
  modules = defaultButtonList[button];
@@ -1184,7 +1513,7 @@ export function CreateToolBar(buttonList, plugins, options, icons, lang, isUpdat
1184
1513
  // more button
1185
1514
  if (moreButton) {
1186
1515
  more = true;
1187
- moreContainer = domUtils.createElement('DIV');
1516
+ moreContainer = dom.utils.createElement('DIV');
1188
1517
  moreContainer.className = 'se-more-layer ' + moreCommand;
1189
1518
  moreContainer.setAttribute('data-ref', moreCommand);
1190
1519
  moreContainer.innerHTML = '<div class="se-more-form"><ul class="se-menu-list"' + (align ? ' style="float: ' + align + ';"' : '') + '></ul></div>';
@@ -1193,18 +1522,23 @@ export function CreateToolBar(buttonList, plugins, options, icons, lang, isUpdat
1193
1522
  }
1194
1523
  }
1195
1524
 
1196
- if (vertical) {
1197
- const sv = separator_vertical.cloneNode(false);
1198
- buttonTray.appendChild(sv);
1199
- }
1525
+ // if (vertical) {
1526
+ // const sv = separator_vertical.cloneNode(false);
1527
+ // buttonTray.appendChild(sv);
1528
+ // }
1200
1529
 
1201
1530
  buttonTray.appendChild(moduleElement.div);
1202
- vertical = true;
1531
+ // vertical = true;
1532
+ } else if (buttonGroup === '|') {
1533
+ // // separator vertical
1534
+ const sv = separator_vertical.cloneNode(false);
1535
+ buttonTray.appendChild(sv);
1536
+ continue;
1203
1537
  } else if (/^\/$/.test(buttonGroup)) {
1204
1538
  /** line break */
1205
- const enterDiv = domUtils.createElement('DIV', { class: 'se-btn-module-enter' });
1539
+ const enterDiv = dom.utils.createElement('DIV', { class: 'se-btn-module-enter' });
1206
1540
  buttonTray.appendChild(enterDiv);
1207
- vertical = false;
1541
+ // vertical = false;
1208
1542
  }
1209
1543
  }
1210
1544
 
@@ -1213,7 +1547,7 @@ export function CreateToolBar(buttonList, plugins, options, icons, lang, isUpdat
1213
1547
  buttonTray.style.display = 'none';
1214
1548
  break;
1215
1549
  case 1:
1216
- domUtils.removeClass(buttonTray.firstElementChild, 'se-btn-module-border');
1550
+ dom.utils.removeClass(buttonTray.firstElementChild, 'se-btn-module-border');
1217
1551
  break;
1218
1552
  }
1219
1553
 
@@ -1221,7 +1555,7 @@ export function CreateToolBar(buttonList, plugins, options, icons, lang, isUpdat
1221
1555
  if (responsiveButtons.length > 0) responsiveButtons.unshift(buttonList);
1222
1556
 
1223
1557
  // rendering toolbar
1224
- const tool_bar = domUtils.createElement('DIV', { class: 'se-toolbar sun-editor-common' + (!options.get('shortcutsHint') ? ' se-shortcut-hide' : '') }, buttonTray);
1558
+ const tool_bar = dom.utils.createElement('DIV', { class: 'se-toolbar sun-editor-common' + (!options.get('shortcutsHint') ? ' se-shortcut-hide' : '') }, buttonTray);
1225
1559
 
1226
1560
  if (options.get('toolbar_hide')) tool_bar.style.display = 'none';
1227
1561