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,10 +1,11 @@
1
- import { env, converter, domUtils, numbers } from '../helper';
1
+ import { env, converter, dom, numbers } from '../helper';
2
2
  import Constructor, { InitOptions, UpdateButton, CreateShortcuts, CreateStatusbar, RO_UNAVAILABD } from './section/constructor';
3
3
  import { UpdateStatusbarContext } from './section/context';
4
- import { BASIC_COMMANDS, ACTIVE_EVENT_COMMANDS, SELECT_ALL, DIR_BTN_ACTIVE, SAVE, FONT_STYLE } from './section/actives';
4
+ import { BASIC_COMMANDS, ACTIVE_EVENT_COMMANDS, SELECT_ALL, DIR_BTN_ACTIVE, SAVE, COPY_FORMAT, FONT_STYLE, PAGE_BREAK } from './section/actives';
5
5
  import History from './base/history';
6
6
  import EventManager from './base/eventManager';
7
7
  import Events from './base/events';
8
+ import DocumentType from './section/documentType';
8
9
 
9
10
  // class injector
10
11
  import ClassInjector from '../editorInjector/_classes';
@@ -16,11 +17,11 @@ import Format from './class/format';
16
17
  import HTML from './class/html';
17
18
  import Menu from './class/menu';
18
19
  import NodeTransform from './class/nodeTransform';
19
- import Notice from './class/notice';
20
20
  import Offset from './class/offset';
21
- import Selection from './class/selection';
21
+ import Selection_ from './class/selection';
22
22
  import Shortcuts from './class/shortcuts';
23
23
  import Toolbar from './class/toolbar';
24
+ import UI from './class/ui';
24
25
  import Viewer from './class/viewer';
25
26
 
26
27
  const COMMAND_BUTTONS = '.se-menu-list .se-toolbar-btn[data-command]';
@@ -28,24 +29,57 @@ const DISABLE_BUTTONS_CODEVIEW = `${COMMAND_BUTTONS}:not([class~="se-code-view-e
28
29
  const DISABLE_BUTTONS_CONTROLLER = `${COMMAND_BUTTONS}:not([class~="se-component-enabled"]):not([data-type="MORE"])`;
29
30
 
30
31
  /**
32
+ * @typedef {import('./section/constructor').EditorInitOptions} EditorInitOptions
33
+ */
34
+
35
+ /**
36
+ * @typedef {import('./section/constructor').EditorFrameOptions} EditorFrameOptions
37
+ */
38
+
39
+ /**
40
+ * @typedef {import('../modules/Controller').ControllerInfo} ControllerInfo
41
+ */
42
+
43
+ /**
44
+ * @constructor
31
45
  * @description SunEditor constructor function.
32
- * @param {Array.<Element>} multiTargets Target textarea
33
- * @param {Object} options options
34
- * @returns {Object}
46
+ * @param {Array<{target: Element, key: *, options: EditorFrameOptions}>} multiTargets Target element
47
+ * @param {EditorInitOptions} options options
35
48
  */
36
- const Editor = function (multiTargets, options) {
49
+ function Editor(multiTargets, options) {
37
50
  const _d = multiTargets[0].target.ownerDocument || env._d;
38
51
  const _w = _d.defaultView || env._w;
39
52
  const product = Constructor(multiTargets, options);
40
53
 
41
- // properties
54
+ /**
55
+ * @description Frame root key array
56
+ * @type {Array<*>}
57
+ */
42
58
  this.rootKeys = product.rootKeys;
59
+
60
+ /**
61
+ * @description Frame root map
62
+ * @type {Map<*, __se__FrameContext>}
63
+ */
43
64
  this.frameRoots = product.frameRoots;
65
+
66
+ /**
67
+ * @description Editor context object
68
+ * @type {__se__Context}
69
+ */
44
70
  this.context = product.context;
71
+
72
+ /**
73
+ * @description Current focusing frame context
74
+ * @type {__se__FrameContext}
75
+ */
45
76
  this.frameContext = new Map();
77
+
78
+ /**
79
+ * @description Current focusing frame context options
80
+ * @type {__se__FrameOptions}
81
+ */
46
82
  this.frameOptions = new Map();
47
- this._lineBreaker_t = null;
48
- this._lineBreaker_b = null;
49
83
 
50
84
  /**
51
85
  * @description Document object
@@ -61,54 +95,49 @@ const Editor = function (multiTargets, options) {
61
95
 
62
96
  /**
63
97
  * @description Controllers carrier
98
+ * @type {HTMLElement}
64
99
  */
65
100
  this.carrierWrapper = product.carrierWrapper;
66
101
 
67
102
  /**
68
103
  * @description Editor options
69
- * @type {Object.<string, any>}
104
+ * @type {Map<string, *>}
70
105
  */
71
106
  this.options = product.options;
72
107
 
73
108
  /**
74
109
  * @description Plugins
75
- * @type {Object.<string, any>}
110
+ * @type {Object<string, *>}
76
111
  */
77
112
  this.plugins = product.plugins || {};
78
113
 
79
114
  /**
80
115
  * @description Events object, call by triggerEvent function
81
- * @type {Object.<string, any>}
116
+ * @type {Object<string, *>}
82
117
  */
83
118
  this.events = null;
84
119
 
85
120
  /**
86
121
  * @description Call the event function by injecting self: this.
87
- * @type {Function}
122
+ * @type {(eventName: string, ...args: *) => Promise<*>}
88
123
  */
89
124
  this.triggerEvent = null;
90
125
 
91
126
  /**
92
127
  * @description Default icons object
93
- * @type {Object.<string, string>}
128
+ * @type {Object<string, string>}
94
129
  */
95
130
  this.icons = product.icons;
96
131
 
97
132
  /**
98
133
  * @description loaded language
99
- * @type {Object.<string, any>}
134
+ * @type {Object<string, *>}
100
135
  */
101
136
  this.lang = product.lang;
102
137
 
103
138
  /**
104
139
  * @description Variables used internally in editor operation
105
- * @property {boolean} hasFocus Boolean value of whether the editor has focus
106
- * @property {number} tabSize Indent size of tab (4)
107
- * @property {number} indentSize Indent size (25)px
108
- * @property {number} codeIndentSize Indent size of Code view mode (2)
109
- * @property {Array} currentNodes An element array of the current cursor's node structure
110
- * @property {Array} currentNodesMap An element name array of the current cursor's node structure
111
- * @property {number} rootKey Current root key
140
+ * @type {__se__EditorStatus}
112
141
  */
113
142
  this.status = {
114
143
  hasFocus: false,
@@ -117,147 +146,281 @@ const Editor = function (multiTargets, options) {
117
146
  codeIndentSize: 2,
118
147
  currentNodes: [],
119
148
  currentNodesMap: [],
149
+ onSelected: false,
120
150
  rootKey: product.rootId,
121
- _range: null
151
+ _range: null,
152
+ _onMousedown: false
122
153
  };
123
154
 
124
155
  /**
125
156
  * @description Is classic mode?
157
+ * @type {boolean}
126
158
  */
127
- this.isClassic = null;
159
+ this.isClassic = false;
128
160
 
129
161
  /**
130
162
  * @description Is inline mode?
163
+ * @type {boolean}
131
164
  */
132
- this.isInline = null;
165
+ this.isInline = false;
133
166
 
134
167
  /**
135
168
  * @description Is balloon|balloon-always mode?
169
+ * @type {boolean}
136
170
  */
137
- this.isBalloon = null;
171
+ this.isBalloon = false;
138
172
 
139
173
  /**
140
174
  * @description Is balloon-always mode?
175
+ * @type {boolean}
141
176
  */
142
- this.isBalloonAlways = null;
177
+ this.isBalloonAlways = false;
143
178
 
144
179
  /**
145
180
  * @description Is subToolbar balloon|balloon-always mode?
181
+ * @type {boolean}
146
182
  */
147
- this.isSubBalloon = null;
183
+ this.isSubBalloon = false;
148
184
 
149
185
  /**
150
186
  * @description Is subToolbar balloon-always mode?
187
+ * @type {boolean}
151
188
  */
152
- this.isSubBalloonAlways = null;
189
+ this.isSubBalloonAlways = false;
153
190
 
154
- // ----- Properties not shared with _core -----
155
191
  /**
156
192
  * @description All command buttons map
193
+ * @type {Map<string, HTMLElement>}
157
194
  */
158
195
  this.allCommandButtons = new Map();
196
+
197
+ /**
198
+ * @description All command buttons map
199
+ * @type {Map<string, HTMLElement>}
200
+ */
159
201
  this.subAllCommandButtons = new Map();
160
202
 
161
203
  /**
162
204
  * @description Shoutcuts key map
205
+ * @type {Map<string, *>}
163
206
  */
164
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
+ */
165
214
  this.reverseKeys = [];
166
215
 
167
216
  /**
168
217
  * @description A map with the plugin's buttons having an "active" method and the default command buttons with an "active" action.
169
- * Each button is contained in an array.
218
+ * - Each button is contained in an array.
219
+ * @type {Map<string, Array<HTMLButtonElement>>}
170
220
  */
171
221
  this.commandTargets = new Map();
172
222
 
173
223
  /**
174
224
  * @description Plugins array with "active" method.
175
- * "activeCommands" runs the "add" method when creating the editor.
225
+ * - "activeCommands" runs the "add" method when creating the editor.
226
+ * @type {Array<string>}
176
227
  */
177
228
  this.activeCommands = null;
178
229
 
179
230
  /**
180
231
  * @description The selection node (selection.getNode()) to which the effect was last applied
232
+ * @type {Node|null}
181
233
  */
182
234
  this.effectNode = null;
183
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>}
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
+
184
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
+
185
312
  /**
186
313
  * @description Closest ShadowRoot to editor if found
187
314
  * @type {ShadowRoot}
188
- * @private
189
315
  */
190
316
  this._shadowRoot = null;
191
317
 
192
318
  /**
193
319
  * @description Plugin call event map
194
- * @private
320
+ * @type {Map<string, Array<((...args: *) => *) & { index: number }>>}
195
321
  */
196
322
  this._onPluginEvents = null;
197
323
 
198
324
  /**
199
- * @description Controller, modal relative
200
- * @private
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}
201
340
  */
202
- this.opendModal = null;
203
- this.opendControllers = [];
204
- this.currentControllerName = '';
205
341
  this._controllerTargetContext = null;
206
- this.selectMenuOn = false;
207
- this._backWrapper = product.carrierWrapper.querySelector('.se-back-wrapper');
208
342
 
343
+ /**
344
+ * @description List of buttons that are disabled when "controller" is opened
345
+ * @type {Array<HTMLButtonElement|HTMLInputElement>}
346
+ */
209
347
  this._controllerOnDisabledButtons = [];
348
+
349
+ /**
350
+ * @description List of buttons that are disabled when "codeView" mode opened
351
+ * @type {Array<HTMLButtonElement|HTMLInputElement>}
352
+ */
210
353
  this._codeViewDisabledButtons = [];
211
354
 
212
355
  /**
213
- * @description Button List in Responsive Toolbar.
214
- * @private
356
+ * @description List of buttons to run plugins in the toolbar
357
+ * @type {Array<HTMLElement>}
215
358
  */
216
359
  this._pluginCallButtons = product.pluginCallButtons;
360
+
361
+ /**
362
+ * @description List of buttons to run plugins in the Sub-Toolbar
363
+ * @type {Array<HTMLElement>}
364
+ */
217
365
  this._pluginCallButtons_sub = product.pluginCallButtons_sub;
366
+
367
+ /**
368
+ * @description Responsive Toolbar Button Structure array
369
+ * @type {Array<*>}
370
+ */
218
371
  this._responsiveButtons = product.responsiveButtons;
372
+
373
+ /**
374
+ * @description Responsive Sub-Toolbar Button Structure array
375
+ * @type {Array<*>}
376
+ */
219
377
  this._responsiveButtons_sub = product.responsiveButtons_sub;
220
378
 
221
379
  /**
222
380
  * @description Variable that controls the "blur" event in the editor of inline or balloon mode when the focus is moved to dropdown
223
- * @private
381
+ * @type {boolean}
224
382
  */
225
383
  this._notHideToolbar = false;
226
384
 
227
385
  /**
228
386
  * @description Variables for controlling focus and blur events
229
- * @private
387
+ * @type {boolean}
230
388
  */
231
- this._antiBlur = false;
389
+ this._preventBlur = false;
232
390
 
233
391
  /**
234
- * @description If true, (initialize, reset) all indexes of image, video information
235
- * @private
392
+ * @description If true, initialize all indexes of image, video information
393
+ * @type {boolean}
236
394
  */
237
395
  this._componentsInfoInit = true;
396
+
397
+ /**
398
+ * @description If true, reset all indexes of image, video information
399
+ * @type {boolean}
400
+ */
238
401
  this._componentsInfoReset = false;
239
402
 
240
403
  /**
241
404
  * @description plugin retainFormat info Map()
242
- * @private
405
+ * @type {Map<string, ((...args: *) => *)>}
243
406
  */
244
407
  this._MELInfo = null;
245
408
 
246
409
  /**
247
410
  * @description Properties for managing files in the "FileManager" module
248
- * @private
411
+ * @type {Array<*>}
249
412
  */
250
413
  this._fileInfoPluginsCheck = null;
251
414
 
252
415
  /**
253
416
  * @description Properties for managing files in the "FileManager" module
254
- * @private
417
+ * @type {Array<*>}
255
418
  */
256
419
  this._fileInfoPluginsReset = null;
257
420
 
258
421
  /**
259
422
  * @description Variables for file component management
260
- * @private
423
+ * @type {Object<string, *>}
261
424
  */
262
425
  this._fileManager = {
263
426
  tags: null,
@@ -265,34 +428,38 @@ const Editor = function (multiTargets, options) {
265
428
  pluginRegExp: null,
266
429
  pluginMap: null
267
430
  };
431
+
432
+ /**
433
+ * @description Variables for managing the components
434
+ * @type {Array<*>}
435
+ */
268
436
  this._componentManager = [];
269
437
 
270
438
  /**
271
439
  * @description Current Figure container.
272
- * @private
440
+ * @type {HTMLElement|null}
273
441
  */
274
442
  this._figureContainer = null;
275
443
 
276
444
  /**
277
445
  * @description Origin options
278
- * @private
446
+ * @type {EditorInitOptions}
279
447
  */
280
448
  this._originOptions = options;
281
449
 
282
450
  /** ----- Create editor ------------------------------------------------------------ */
283
451
  this.__Create(options);
284
- };
452
+ }
285
453
 
286
454
  Editor.prototype = {
287
455
  /**
288
456
  * @description If the plugin is not added, add the plugin and call the 'add' function.
289
- * If the plugin is added call callBack function.
457
+ * - If the plugin is added call callBack function.
290
458
  * @param {string} pluginName The name of the plugin to call
291
- * @param {Array.<Element>|null} targets Plugin target button (This is not necessary if you have a button list when creating the editor)
292
- * @param {object|null} pluginOptions Plugin's options
293
- * @param {object} shortcuts this.options.get('shortcuts')
459
+ * @param {?Array<HTMLElement>} targets Plugin target button (This is not necessary if you have a button list when creating the editor)
460
+ * @param {?Object<string, *>} pluginOptions Plugin's options
294
461
  */
295
- registerPlugin(pluginName, targets, pluginOptions, shortcuts) {
462
+ registerPlugin(pluginName, targets, pluginOptions) {
296
463
  let plugin = this.plugins[pluginName];
297
464
  if (!plugin) {
298
465
  throw Error(`[SUNEDITOR.registerPlugin.fail] The called plugin does not exist or is in an invalid format. (pluginName: "${pluginName}")`);
@@ -303,7 +470,7 @@ Editor.prototype = {
303
470
 
304
471
  if (targets) {
305
472
  for (let i = 0, len = targets.length; i < len; i++) {
306
- UpdateButton(targets[i], plugin, this.icons, this.lang, shortcuts);
473
+ UpdateButton(targets[i], plugin, this.icons, this.lang);
307
474
  }
308
475
 
309
476
  if (!this.activeCommands.includes(pluginName) && typeof this.plugins[pluginName].active === 'function') {
@@ -316,13 +483,13 @@ Editor.prototype = {
316
483
  * @description Run plugin calls and basic commands.
317
484
  * @param {string} command Command string
318
485
  * @param {string} type Display type string ('command', 'dropdown', 'modal', 'container')
319
- * @param {Element|null} button The element of command button
486
+ * @param {?Node=} button The element of command button
320
487
  */
321
488
  run(command, type, button) {
322
489
  if (type) {
323
490
  if (/more/i.test(type)) {
324
- const toolbar = domUtils.getParentElement(button, '.se-toolbar');
325
- const toolInst = domUtils.hasClass(toolbar, 'se-toolbar-sub') ? this.subToolbar : this.toolbar;
491
+ const toolbar = dom.query.getParentElement(button, '.se-toolbar');
492
+ const toolInst = dom.utils.hasClass(toolbar, 'se-toolbar-sub') ? this.subToolbar : this.toolbar;
326
493
  if (button !== toolInst.currentMoreLayerActiveButton) {
327
494
  const layer = toolbar.querySelector('.' + command);
328
495
  if (layer) {
@@ -330,7 +497,7 @@ Editor.prototype = {
330
497
  toolInst._showBalloon();
331
498
  toolInst._showInline();
332
499
  }
333
- domUtils.addClass(button, 'on');
500
+ dom.utils.addClass(button, 'on');
334
501
  } else if (toolInst.currentMoreLayerActiveButton) {
335
502
  toolInst._moreLayerOff();
336
503
  toolInst._showBalloon();
@@ -346,7 +513,7 @@ Editor.prototype = {
346
513
  return;
347
514
  }
348
515
 
349
- if (this.frameContext.get('isReadOnly') && domUtils.arrayIncludes(this._controllerOnDisabledButtons, button)) return;
516
+ if (this.frameContext.get('isReadOnly') && dom.utils.arrayIncludes(this._controllerOnDisabledButtons, button)) return;
350
517
  if (/dropdown/.test(type) && (this.menu.targetMap[command] === null || button !== this.menu.currentDropdownActiveButton)) {
351
518
  this.menu.dropdownOn(button);
352
519
  return;
@@ -355,11 +522,13 @@ Editor.prototype = {
355
522
  return;
356
523
  } else if (/command/.test(type)) {
357
524
  this.plugins[command].action(button);
358
- } else if (/fileBrowser/.test(type)) {
525
+ } else if (/browser/.test(type)) {
359
526
  this.plugins[command].open(null);
527
+ } else if (/popup/.test(type)) {
528
+ this.plugins[command].show();
360
529
  }
361
530
  } else if (command) {
362
- this.commandHandler(command);
531
+ this.commandHandler(command, button);
363
532
  }
364
533
 
365
534
  if (/dropdown/.test(type)) {
@@ -372,20 +541,15 @@ Editor.prototype = {
372
541
 
373
542
  /**
374
543
  * @description Execute default command of command button
375
- * (selectAll, codeView, fullScreen, indent, outdent, undo, redo, removeFormat, print, preview, showBlocks, save, bold, underline, italic, strike, subscript, superscript, copy, cut, paste)
544
+ * - (selectAll, codeView, fullScreen, indent, outdent, undo, redo, removeFormat, print, preview, showBlocks, save, bold, underline, italic, strike, subscript, superscript, copy, cut, paste)
376
545
  * @param {string} command Property of command button (data-value)
546
+ * @param {Node} button Command button
547
+ * @returns {Promise<void>}
377
548
  */
378
- async commandHandler(command) {
549
+ async commandHandler(command, button) {
379
550
  if (this.frameContext.get('isReadOnly') && !/copy|cut|selectAll|codeView|fullScreen|print|preview|showBlocks/.test(command)) return;
380
551
 
381
552
  switch (command) {
382
- case 'copy':
383
- case 'cut':
384
- this.execCommand(command);
385
- break;
386
- case 'paste':
387
- // @todo
388
- break;
389
553
  case 'selectAll':
390
554
  SELECT_ALL(this);
391
555
  break;
@@ -413,7 +577,7 @@ Editor.prototype = {
413
577
  this.history.redo();
414
578
  break;
415
579
  case 'removeFormat':
416
- this.format.removeTextStyle();
580
+ this.format.removeInlineElement();
417
581
  this.focus();
418
582
  break;
419
583
  case 'print':
@@ -437,6 +601,18 @@ Editor.prototype = {
437
601
  case 'save':
438
602
  await SAVE(this);
439
603
  break;
604
+ case 'copyFormat':
605
+ COPY_FORMAT(this, button);
606
+ break;
607
+ case 'pageBreak':
608
+ PAGE_BREAK(this);
609
+ break;
610
+ case 'pageUp':
611
+ this.frameContext.get('documentType').pageUp();
612
+ break;
613
+ case 'pageDown':
614
+ this.frameContext.get('documentType').pageDown();
615
+ break;
440
616
  default:
441
617
  FONT_STYLE(this, command);
442
618
  }
@@ -444,36 +620,38 @@ Editor.prototype = {
444
620
 
445
621
  /**
446
622
  * @description Execute "editor.run" with command button.
447
- * @param {Element} target Command target
623
+ * @param {Node} target Command target
448
624
  */
449
625
  runFromTarget(target) {
450
- const isInput = domUtils.isInputElement(target);
451
- if (isInput || !(target = domUtils.getCommandTarget(target))) return;
626
+ if (dom.check.isInputElement(target)) return;
627
+
628
+ const targetBtn = /** @type {HTMLButtonElement} */ (dom.query.getCommandTarget(target));
629
+ if (!targetBtn) return;
452
630
 
453
- const command = target.getAttribute('data-command');
454
- const type = target.getAttribute('data-type');
631
+ const command = targetBtn.getAttribute('data-command');
632
+ const type = targetBtn.getAttribute('data-type');
455
633
 
456
634
  if (!command && !type) return;
457
- if (target.disabled) return;
635
+ if (targetBtn.disabled) return;
458
636
 
459
637
  this.run(command, type, target);
460
638
  },
461
639
 
462
640
  /**
463
641
  * @description It is executed by inserting the button of commandTargets as the argument value of the "f" function.
464
- * "f" is called as long as the button array's length.
642
+ * - "func" is called as long as the button array's length.
465
643
  * @param {string} cmd data-command
466
- * @param {Function} f Function.
644
+ * @param {(...args: *) => *} func Function.
467
645
  */
468
- applyCommandTargets(cmd, f) {
646
+ applyCommandTargets(cmd, func) {
469
647
  if (this.commandTargets.has(cmd)) {
470
- this.commandTargets.get(cmd).forEach(f);
648
+ this.commandTargets.get(cmd).forEach(func);
471
649
  }
472
650
  },
473
651
 
474
652
  /**
475
- * @description Executes a function by traversing all root targets.
476
- * @param {Function} f Function
653
+ * @description Execute a function by traversing all root targets.
654
+ * @param {(...args: *) => *} f Function
477
655
  */
478
656
  applyFrameRoots(f) {
479
657
  this.frameRoots.forEach(f);
@@ -481,14 +659,14 @@ Editor.prototype = {
481
659
 
482
660
  /**
483
661
  * @description Checks if the content of the editor is empty.
484
- * Display criteria for "placeholder".
485
- * @param {frameContext|null} fc Frame context, if not present, currently selected frame context.
662
+ * - Display criteria for "placeholder".
663
+ * @param {?__se__FrameContext=} fc Frame context, if not present, currently selected frame context.
486
664
  * @returns {boolean}
487
665
  */
488
666
  isEmpty(fc) {
489
667
  fc = fc || this.frameContext;
490
668
  const wysiwyg = fc.get('wysiwyg');
491
- return domUtils.isZeroWith(wysiwyg.textContent) && !wysiwyg.querySelector(env._allowedEmptyNodeList) && (wysiwyg.innerText.match(/\n/g) || '').length <= 1;
669
+ return dom.check.isZeroWidth(wysiwyg.textContent) && !wysiwyg.querySelector(this.options.get('allowedEmptyTags')) && (wysiwyg.innerText.match(/\n/g) || '').length <= 1;
492
670
  },
493
671
 
494
672
  /**
@@ -501,7 +679,7 @@ Editor.prototype = {
501
679
 
502
680
  try {
503
681
  this.options.set('_rtl', rtl);
504
- this._offCurrentController();
682
+ this.ui._offCurrentController();
505
683
 
506
684
  const fc = this.frameContext;
507
685
  const plugins = this.plugins;
@@ -513,18 +691,18 @@ Editor.prototype = {
513
691
  const statusbarWrapper = this.context.get('statusbar._wrapper');
514
692
  if (rtl) {
515
693
  this.applyFrameRoots((e) => {
516
- domUtils.addClass([e.get('topArea'), e.get('wysiwyg')], 'se-rtl');
694
+ dom.utils.addClass([e.get('topArea'), e.get('wysiwyg'), e.get('documentTypePageMirror')], 'se-rtl');
517
695
  });
518
- domUtils.addClass([this.carrierWrapper, toolbarWrapper, statusbarWrapper], 'se-rtl');
696
+ dom.utils.addClass([this.carrierWrapper, toolbarWrapper, statusbarWrapper], 'se-rtl');
519
697
  } else {
520
698
  this.applyFrameRoots((e) => {
521
- domUtils.removeClass([e.get('topArea'), e.get('wysiwyg')], 'se-rtl');
699
+ dom.utils.removeClass([e.get('topArea'), e.get('wysiwyg'), e.get('documentTypePageMirror')], 'se-rtl');
522
700
  });
523
- domUtils.removeClass([this.carrierWrapper, toolbarWrapper, statusbarWrapper], 'se-rtl');
701
+ dom.utils.removeClass([this.carrierWrapper, toolbarWrapper, statusbarWrapper], 'se-rtl');
524
702
  }
525
703
 
526
- const lineNodes = domUtils.getListChildren(fc.wysiwyg, (current) => {
527
- return this.format.isLine(current) && (current.style.marginRight || current.style.marginLeft || current.style.textAlign);
704
+ const lineNodes = dom.query.getListChildren(fc.get('wysiwyg'), (current) => {
705
+ return this.format.isLine(current) && !!(current.style.marginRight || current.style.marginLeft || current.style.textAlign);
528
706
  });
529
707
 
530
708
  for (let i = 0, n, l, r; (n = lineNodes[i]); i++) {
@@ -544,6 +722,16 @@ Editor.prototype = {
544
722
 
545
723
  DIR_BTN_ACTIVE(this, rtl);
546
724
 
725
+ // document type
726
+ if (fc.has('documentType-use-header')) {
727
+ if (rtl) fc.get('wrapper').appendChild(fc.get('documentTypeInner'));
728
+ else fc.get('wrapper').insertBefore(fc.get('documentTypeInner'), fc.get('wysiwygFrame'));
729
+ }
730
+ if (fc.has('documentType-use-page')) {
731
+ if (rtl) fc.get('wrapper').insertBefore(fc.get('documentTypePage'), fc.get('wysiwygFrame'));
732
+ else fc.get('wrapper').appendChild(fc.get('documentTypePage'));
733
+ }
734
+
547
735
  if (this.isBalloon) this.toolbar._showBalloon();
548
736
  else if (this.isSubBalloon) this.subToolbar._showBalloon();
549
737
  } catch (e) {
@@ -557,7 +745,7 @@ Editor.prototype = {
557
745
 
558
746
  /**
559
747
  * @description Add or reset option property (Editor is reloaded)
560
- * @param {Object} newOptions Options
748
+ * @param {EditorInitOptions} newOptions Options
561
749
  */
562
750
  resetOptions(newOptions) {
563
751
  const _keys = Object.keys;
@@ -600,7 +788,7 @@ Editor.prototype = {
600
788
 
601
789
  // init options
602
790
  const options = this.options;
603
- const newMap = InitOptions(this._originOptions, newRoots).o;
791
+ const newMap = InitOptions(this._originOptions, newRoots, this.plugins).o;
604
792
  /** --------- root start --------- */
605
793
  for (let i = 0, k; (k = newOptionKeys[i]); i++) {
606
794
  if (newRootKeys[k]) {
@@ -611,7 +799,7 @@ Editor.prototype = {
611
799
 
612
800
  // statusbar
613
801
  if (diff.has('statusbar')) {
614
- domUtils.removeItem(fc.get('statusbar'));
802
+ dom.utils.removeItem(fc.get('statusbar'));
615
803
  if (newRootOptions.get('statusbar')) {
616
804
  const statusbar = CreateStatusbar(newRootOptions, null).statusbar;
617
805
  fc.get('container').appendChild(statusbar);
@@ -646,7 +834,7 @@ Editor.prototype = {
646
834
  fc.set('options', newRootOptions);
647
835
 
648
836
  // frame styles
649
- this.setEditorStyle(newRootOptions.get('_defaultStyles'), fc);
837
+ this.ui.setEditorStyle(newRootOptions.get('_defaultStyles'), fc);
650
838
 
651
839
  // frame attributes
652
840
  const frame = fc.get('wysiwyg');
@@ -687,9 +875,14 @@ Editor.prototype = {
687
875
  }
688
876
  // shortcuts hint
689
877
  if (options.get('shortcutsHint')) {
690
- domUtils.removeClass(toolbar, 'se-shortcut-hide');
878
+ dom.utils.removeClass(toolbar, 'se-shortcut-hide');
691
879
  } else {
692
- domUtils.addClass(toolbar, 'se-shortcut-hide');
880
+ dom.utils.addClass(toolbar, 'se-shortcut-hide');
881
+ }
882
+
883
+ // theme
884
+ if (this._originOptions.theme !== (newOptions.theme ?? this._originOptions.theme)) {
885
+ this.ui.setTheme(newOptions.theme);
693
886
  }
694
887
 
695
888
  this.effectNode = null;
@@ -698,7 +891,7 @@ Editor.prototype = {
698
891
 
699
892
  /**
700
893
  * @description Change the current root index.
701
- * @param {number} rootKey
894
+ * @param {*} rootKey
702
895
  */
703
896
  changeFrameContext(rootKey) {
704
897
  if (rootKey === this.status.rootKey) return;
@@ -711,8 +904,8 @@ Editor.prototype = {
711
904
  /**
712
905
  * @description javascript execCommand
713
906
  * @param {string} command javascript execCommand function property
714
- * @param {Boolean|undefined} showDefaultUI javascript execCommand function property
715
- * @param {string|undefined} value javascript execCommand function property
907
+ * @param {boolean=} showDefaultUI javascript execCommand function property
908
+ * @param {string=} value javascript execCommand function property
716
909
  */
717
910
  execCommand(command, showDefaultUI, value) {
718
911
  this.frameContext.get('_wd').execCommand(command, showDefaultUI, command === 'formatBlock' ? '<' + value + '>' : value);
@@ -721,23 +914,23 @@ Editor.prototype = {
721
914
 
722
915
  /**
723
916
  * @description Focus to wysiwyg area
724
- * @param {number|undefined} rootKey Root index
917
+ * @param {*} rootKey Root index
725
918
  */
726
919
  focus(rootKey) {
727
920
  if (rootKey) this.changeFrameContext(rootKey);
728
921
  if (this.frameContext.get('wysiwygFrame').style.display === 'none') return;
729
- this._antiBlur = false;
922
+ this._preventBlur = false;
730
923
 
731
924
  if (this.frameOptions.get('iframe') || !this.frameContext.get('wysiwyg').contains(this.selection.getNode())) {
732
925
  this._nativeFocus();
733
926
  } else {
734
927
  try {
735
928
  const range = this.selection.getRange();
736
- if (range.startContainer === range.endContainer && domUtils.isWysiwygFrame(range.startContainer)) {
737
- const currentNode = range.commonAncestorContainer.children[range.startOffset];
929
+ if (range.startContainer === range.endContainer && dom.check.isWysiwygFrame(range.startContainer)) {
930
+ const currentNode = /** @type {HTMLElement} */ (range.commonAncestorContainer).children[range.startOffset];
738
931
  if (!this.format.isLine(currentNode) && !this.component.is(currentNode)) {
739
- const br = domUtils.createElement('BR');
740
- const format = domUtils.createElement(this.options.get('defaultLine'), null, br);
932
+ const br = dom.utils.createElement('BR');
933
+ const format = dom.utils.createElement(this.options.get('defaultLine'), null, br);
741
934
  this.frameContext.get('wysiwyg').insertBefore(format, currentNode);
742
935
  this.selection.setRange(br, 0, br, 0);
743
936
  return;
@@ -755,11 +948,11 @@ Editor.prototype = {
755
948
 
756
949
  /**
757
950
  * @description If "focusEl" is a component, then that component is selected; if it is a format element, the last text is selected
758
- * If "focusEdge" is null, then selected last element
759
- * @param {Element|null} focusEl Focus element
951
+ * - If "focusEdge" is null, then selected last element
952
+ * @param {?Node=} focusEl Focus element
760
953
  */
761
954
  focusEdge(focusEl) {
762
- this._antiBlur = false;
955
+ this._preventBlur = false;
763
956
  if (!focusEl) focusEl = this.frameContext.get('wysiwyg').lastElementChild;
764
957
 
765
958
  const fileComponentInfo = this.component.get(focusEl);
@@ -767,7 +960,7 @@ Editor.prototype = {
767
960
  this.component.select(fileComponentInfo.target, fileComponentInfo.pluginName, false);
768
961
  } else if (focusEl) {
769
962
  if (focusEl.nodeType !== 3) {
770
- focusEl = domUtils.getEdgeChild(
963
+ focusEl = dom.query.getEdgeChild(
771
964
  focusEl,
772
965
  function (current) {
773
966
  return current.childNodes.length === 0 || current.nodeType === 3;
@@ -793,163 +986,6 @@ Editor.prototype = {
793
986
  }
794
987
  },
795
988
 
796
- /**
797
- * @description Set "options.get('editorStyle')" style.
798
- * Define the style of the edit area
799
- * It can also be defined with the "setOptions" method, but the "setEditorStyle" method does not render the editor again.
800
- * @param {string} style Style string
801
- * @param {FrameContext|null} fc Frame context
802
- */
803
- setEditorStyle(style, fc) {
804
- fc = fc || this.frameContext;
805
- const fo = fc.get('options');
806
-
807
- const newStyles = converter._setDefaultOptionStyle(fo, style);
808
- fo.set('_defaultStyles', newStyles);
809
-
810
- // top area
811
- fc.get('topArea').style.cssText = newStyles.top;
812
-
813
- // code view
814
- const code = fc.get('code');
815
- code.style.cssText = fo.get('_defaultStyles').frame;
816
- code.style.display = 'none';
817
-
818
- // wysiwyg frame
819
- if (!fo.get('iframe')) {
820
- fc.get('wysiwygFrame').style.cssText = newStyles.frame + newStyles.editor;
821
- } else {
822
- fc.get('wysiwygFrame').style.cssText = newStyles.frame;
823
- fc.get('wysiwyg').style.cssText = newStyles.editor;
824
- }
825
- },
826
-
827
- /**
828
- * @description Switch to or off "ReadOnly" mode.
829
- * @param {boolean} value "readOnly" boolean value.
830
- * @param {string|undefined} rootKey Root key
831
- */
832
- readOnly(value, rootKey) {
833
- const fc = rootKey ? this.frameRoots.get(rootKey) : this.frameContext;
834
-
835
- fc.set('isReadOnly', !!value);
836
- domUtils.setDisabled(this._controllerOnDisabledButtons, !!value);
837
-
838
- if (value) {
839
- this._offCurrentController();
840
- this._offCurrentModal();
841
-
842
- if (this.toolbar?.currentMoreLayerActiveButton?.disabled) this.toolbar.moreLayerOff();
843
- if (this.subToolbar?.currentMoreLayerActiveButton?.disabled) this.subToolbar.moreLayerOff();
844
- if (this.menu?.currentDropdownActiveButton?.disabled) this.menu.dropdownOff();
845
- if (this.menu?.currentContainerActiveButton?.disabled) this.menu.containerOff();
846
- if (this.modalForm) this.plugins.modal.close.call(this);
847
-
848
- fc.get('code').setAttribute('readOnly', 'true');
849
- domUtils.addClass(fc.get('wysiwygFrame'), 'se-read-only');
850
- } else {
851
- fc.get('code').removeAttribute('readOnly');
852
- domUtils.removeClass(fc.get('wysiwygFrame'), 'se-read-only');
853
- }
854
-
855
- if (this.options.get('hasCodeMirror')) {
856
- this.viewer._codeMirrorEditor('readonly', !!value, rootKey);
857
- }
858
- },
859
-
860
- /**
861
- * @description Disable the suneditor
862
- * @param {string|undefined} rootKey Root key
863
- */
864
- disable(rootKey) {
865
- const fc = rootKey ? this.frameRoots.get(rootKey) : this.frameContext;
866
-
867
- this.toolbar.disable();
868
- this._offCurrentController();
869
- this._offCurrentModal();
870
-
871
- if (this.modalForm) this.plugins.modal.close.call(this);
872
-
873
- fc.get('wysiwyg').setAttribute('contenteditable', false);
874
- fc.set('isDisabled', true);
875
-
876
- if (this.options.get('hasCodeMirror')) {
877
- this.viewer._codeMirrorEditor('readonly', true, rootKey);
878
- } else {
879
- fc.get('code').setAttribute('disabled', true);
880
- }
881
- },
882
-
883
- /**
884
- * @description Enable the suneditor
885
- * @param {string|undefined} rootKey Root key
886
- */
887
- enable(rootKey) {
888
- const fc = rootKey ? this.frameRoots.get(rootKey) : this.frameContext;
889
-
890
- this.toolbar.enable();
891
- fc.get('wysiwyg').setAttribute('contenteditable', true);
892
- fc.set('isDisabled', false);
893
-
894
- if (this.options.get('hasCodeMirror')) {
895
- this.viewer._codeMirrorEditor('readonly', false, rootKey);
896
- } else {
897
- fc.get('code').removeAttribute('disabled');
898
- }
899
- },
900
-
901
- /**
902
- * @description Show the suneditor
903
- * @param {string|undefined} rootKey Root key
904
- */
905
- show(rootKey) {
906
- const fc = rootKey ? this.frameRoots.get(rootKey) : this.frameContext;
907
- const topAreaStyle = fc.get('topArea').style;
908
- if (topAreaStyle.display === 'none') topAreaStyle.display = 'block';
909
- },
910
-
911
- /**
912
- * @description Hide the suneditor
913
- * @param {string|undefined} rootKey Root key
914
- */
915
- hide(rootKey) {
916
- const fc = rootKey ? this.frameRoots.get(rootKey) : this.frameContext;
917
- fc.get('topArea').style.display = 'none';
918
- },
919
-
920
- /**
921
- * @description Show loading box
922
- * @param {string|undefined} rootKey Root key
923
- */
924
- showLoading(rootKey) {
925
- (rootKey ? this.frameRoots.get(rootKey).get('container') : this.carrierWrapper).querySelector('.se-loading-box').style.display = 'block';
926
- },
927
-
928
- /**
929
- * @description Hide loading box
930
- * @param {string|undefined} rootKey Root key
931
- */
932
- hideLoading(rootKey) {
933
- (rootKey ? this.frameRoots.get(rootKey).get('container') : this.carrierWrapper).querySelector('.se-loading-box').style.display = 'none';
934
- },
935
-
936
- /**
937
- * @description Activate the transparent background "div" so that other elements are not affected during resizing.
938
- * @param {cursor} cursor cursor css property
939
- */
940
- enableBackWrapper(cursor) {
941
- this._backWrapper.style.cursor = cursor;
942
- this._backWrapper.style.display = 'block';
943
- },
944
-
945
- /**
946
- * @description Disabled background "div"
947
- */
948
- disableBackWrapper() {
949
- this._backWrapper.style.display = 'none';
950
- this._backWrapper.style.cursor = 'default';
951
- },
952
-
953
989
  /**
954
990
  * @description Destroy the suneditor
955
991
  */
@@ -966,12 +1002,12 @@ Editor.prototype = {
966
1002
  }
967
1003
 
968
1004
  /** remove element */
969
- domUtils.removeItem(this.carrierWrapper);
970
- domUtils.removeItem(this.context.get('toolbar._wrapper'));
971
- domUtils.removeItem(this.context.get('toolbar.sub._wrapper'));
972
- domUtils.removeItem(this.context.get('statusbar._wrapper'));
1005
+ dom.utils.removeItem(this.carrierWrapper);
1006
+ dom.utils.removeItem(this.context.get('toolbar._wrapper'));
1007
+ dom.utils.removeItem(this.context.get('toolbar.sub._wrapper'));
1008
+ dom.utils.removeItem(this.context.get('statusbar._wrapper'));
973
1009
  this.applyFrameRoots((e) => {
974
- domUtils.removeItem(e.get('topArea'));
1010
+ dom.utils.removeItem(e.get('topArea'));
975
1011
  e.get('options').clear();
976
1012
  e.clear();
977
1013
  });
@@ -994,7 +1030,7 @@ Editor.prototype = {
994
1030
  delete obj[k];
995
1031
  }
996
1032
 
997
- obj = ['eventManager', 'char', 'component', 'format', 'html', 'menu', 'nodeTransform', 'notice', 'offset', 'selection', 'shortcuts', 'toolbar', 'viewer'];
1033
+ obj = ['eventManager', 'char', 'component', 'format', 'html', 'menu', 'nodeTransform', 'offset', 'selection', 'shortcuts', 'toolbar', 'ui', 'viewer'];
998
1034
  for (let i = 0, len = obj.length, c; i < len; i++) {
999
1035
  c = this[obj[i]];
1000
1036
  for (const k in c) {
@@ -1018,8 +1054,9 @@ Editor.prototype = {
1018
1054
 
1019
1055
  /** ----- private methods ----------------------------------------------------------------------------------------------------------------------------- */
1020
1056
  /**
1057
+ * @private
1021
1058
  * @description Set frameContext, frameOptions
1022
- * @param {rootTarget} rt Root target
1059
+ * @param {__se__FrameContext} rt Root target[key] FrameContext
1023
1060
  */
1024
1061
  _setFrameInfo(rt) {
1025
1062
  this.frameContext = rt;
@@ -1030,68 +1067,8 @@ Editor.prototype = {
1030
1067
  },
1031
1068
 
1032
1069
  /**
1033
- * @description visible controllers
1034
- * @param {boolean} value hidden/show
1035
- * @param {boolean?} lineBreakShow Line break hidden/show (default: Follows the value "value".)
1036
- * @private
1037
- */
1038
- _visibleControllers(value, lineBreakShow) {
1039
- const visible = value ? '' : 'hidden';
1040
- const breakerVisible = lineBreakShow ?? visible ? '' : 'hidden';
1041
-
1042
- const cont = this.opendControllers;
1043
- for (let i = 0, c; i < cont.length; i++) {
1044
- c = cont[i];
1045
- if (c.form) c.form.style.visibility = visible;
1046
- }
1047
-
1048
- this._lineBreaker_t.style.visibility = breakerVisible;
1049
- this._lineBreaker_b.style.visibility = breakerVisible;
1050
- },
1051
-
1052
- /**
1053
- * @description Off current controllers
1054
1070
  * @private
1055
- */
1056
- _offCurrentController() {
1057
- this.__offControllers();
1058
- this.component.deselect();
1059
- },
1060
-
1061
- /**
1062
- * @description Off controllers
1063
- * @private
1064
- */
1065
- __offControllers() {
1066
- const cont = this.opendControllers;
1067
- const fixedCont = [];
1068
- for (let i = 0, c; i < cont.length; i++) {
1069
- c = cont[i];
1070
- if (c.fixed) {
1071
- fixedCont.push(c);
1072
- continue;
1073
- }
1074
- if (typeof c.inst.close === 'function') c.inst.close();
1075
- if (c.form) c.form.style.display = 'none';
1076
- }
1077
- this.opendControllers = fixedCont;
1078
- this.currentControllerName = '';
1079
- this._antiBlur = false;
1080
- },
1081
-
1082
- /**
1083
- * @description Off current modal
1084
- * @private
1085
- */
1086
- _offCurrentModal() {
1087
- if (this.opendModal) {
1088
- this.opendModal.close();
1089
- }
1090
- },
1091
-
1092
- /**
1093
1071
  * @description Focus to wysiwyg area using "native focus function"
1094
- * @private
1095
1072
  */
1096
1073
  _nativeFocus() {
1097
1074
  this.selection.__focus();
@@ -1099,8 +1076,9 @@ Editor.prototype = {
1099
1076
  },
1100
1077
 
1101
1078
  /**
1102
- * @description Check the components such as image and video and modify them according to the format.
1103
1079
  * @private
1080
+ * @description Check the components such as image and video and modify them according to the format.
1081
+ * @param {boolean} loaded If true, the component is loaded.
1104
1082
  */
1105
1083
  _checkComponents(loaded) {
1106
1084
  for (let i = 0, len = this._fileInfoPluginsCheck.length; i < len; i++) {
@@ -1109,8 +1087,8 @@ Editor.prototype = {
1109
1087
  },
1110
1088
 
1111
1089
  /**
1112
- * @description Initialize the information of the components.
1113
1090
  * @private
1091
+ * @description Initialize the information of the components.
1114
1092
  */
1115
1093
  _resetComponents() {
1116
1094
  for (let i = 0, len = this._fileInfoPluginsReset.length; i < len; i++) {
@@ -1119,31 +1097,54 @@ Editor.prototype = {
1119
1097
  },
1120
1098
 
1121
1099
  /**
1100
+ * @private
1122
1101
  * @description Initializ wysiwyg area (Only called from core._init)
1123
- * @param {Map} e frameContext
1102
+ * @param {__se__FrameContext} e frameContext
1124
1103
  * @param {string} value initial html string
1125
- * @private
1126
1104
  */
1127
1105
  _initWysiwygArea(e, value) {
1106
+ // set content
1128
1107
  e.get('wysiwyg').innerHTML =
1129
- this.html.clean(typeof value === 'string' ? value : (/^TEXTAREA$/i.test(e.get('originElement').nodeName) ? e.get('originElement').value : e.get('originElement').innerHTML) || '', true, null, null) ||
1130
- '<' + this.options.get('defaultLine') + '><br></' + this.options.get('defaultLine') + '>';
1131
-
1108
+ this.html.clean(typeof value === 'string' ? value : (/^TEXTAREA$/i.test(e.get('originElement').nodeName) ? e.get('originElement').value : e.get('originElement').innerHTML) || '', {
1109
+ forceFormat: true,
1110
+ whitelist: null,
1111
+ blacklist: null,
1112
+ _freeCodeViewMode: this.options.get('freeCodeViewMode')
1113
+ }) || '<' + this.options.get('defaultLine') + '><br></' + this.options.get('defaultLine') + '>';
1114
+
1115
+ // char counter
1132
1116
  if (e.has('charCounter')) e.get('charCounter').textContent = this.char.getLength();
1117
+
1118
+ // document type init
1119
+ if (this.options.get('type') === 'document') {
1120
+ e.set('documentType', new DocumentType(this, e));
1121
+ if (e.get('documentType').useHeader) {
1122
+ e.set('documentType-use-header', true);
1123
+ }
1124
+ if (e.get('documentType').usePage) {
1125
+ e.set('documentType-use-page', true);
1126
+ e.get('documentTypePageMirror').innerHTML = e.get('wysiwyg').innerHTML;
1127
+ }
1128
+ }
1133
1129
  },
1134
1130
 
1135
1131
  /**
1136
- * @description Called when there are changes to tags in the wysiwyg region.
1137
1132
  * @private
1133
+ * @description Called when there are changes to tags in the wysiwyg region.
1134
+ * @param {__se__FrameContext} fc - Frame context object
1138
1135
  */
1139
1136
  _resourcesStateChange(fc) {
1140
1137
  this._iframeAutoHeight(fc);
1141
1138
  this._checkPlaceholder(fc);
1139
+ if (this.options.get('type') === 'document' && fc.get('documentType').usePage) {
1140
+ fc.get('documentTypePageMirror').innerHTML = fc.get('wysiwyg').innerHTML;
1141
+ }
1142
1142
  },
1143
1143
 
1144
1144
  /**
1145
- * @description Modify the height value of the iframe when the height of the iframe is automatic.
1146
1145
  * @private
1146
+ * @description Modify the height value of the iframe when the height of the iframe is automatic.
1147
+ * @param {__se__FrameContext} fc - Frame context object
1147
1148
  */
1148
1149
  _iframeAutoHeight(fc) {
1149
1150
  const autoFrame = fc.get('_iframeAuto');
@@ -1159,6 +1160,13 @@ Editor.prototype = {
1159
1160
  }
1160
1161
  },
1161
1162
 
1163
+ /**
1164
+ * @private
1165
+ * @description Call the "onResizeEditor" event
1166
+ * @param {__se__FrameContext} fc - Frame context object
1167
+ * @param {number} h - Height value
1168
+ * @param {ResizeObserverEntry} resizeObserverEntry - ResizeObserverEntry object
1169
+ */
1162
1170
  __callResizeFunction(fc, h, resizeObserverEntry) {
1163
1171
  h =
1164
1172
  h === -1
@@ -1170,11 +1178,17 @@ Editor.prototype = {
1170
1178
  this.triggerEvent('onResizeEditor', { height: h, prevHeight: fc.get('_editorHeight'), frameContext: fc, observerEntry: resizeObserverEntry });
1171
1179
  fc.set('_editorHeight', h);
1172
1180
  }
1181
+
1182
+ // document type page
1183
+ if (fc.has('documentType-use-page')) {
1184
+ fc.get('documentType').resizePage();
1185
+ }
1173
1186
  },
1174
1187
 
1175
1188
  /**
1176
- * @description Set display property when there is placeholder.
1177
1189
  * @private
1190
+ * @description Set display property when there is placeholder.
1191
+ * @param {?__se__FrameContext=} fc - Frame context object, If null fc is this.frameContext
1178
1192
  */
1179
1193
  _checkPlaceholder(fc) {
1180
1194
  fc = fc || this.frameContext;
@@ -1195,8 +1209,9 @@ Editor.prototype = {
1195
1209
  },
1196
1210
 
1197
1211
  /**
1198
- * @description Initializ editor
1199
1212
  * @private
1213
+ * @description Initializ editor
1214
+ * @param {EditorInitOptions} options Options
1200
1215
  */
1201
1216
  __editorInit(options) {
1202
1217
  this.applyFrameRoots((e) => {
@@ -1240,8 +1255,9 @@ Editor.prototype = {
1240
1255
  },
1241
1256
 
1242
1257
  /**
1243
- * @description Initializ core variable
1244
1258
  * @private
1259
+ * @description Initializ core variable
1260
+ * @param {EditorInitOptions} options Options
1245
1261
  */
1246
1262
  __init(options) {
1247
1263
  // file components
@@ -1272,13 +1288,11 @@ Editor.prototype = {
1272
1288
  this._fileManager.tagAttrs = {};
1273
1289
 
1274
1290
  const plugins = this.plugins;
1275
- const isArray = Array.isArray;
1276
- const shortcuts = this.options.get('shortcuts');
1277
1291
  const filePluginRegExp = [];
1278
1292
  let plugin;
1279
1293
  for (const key in plugins) {
1280
- this.registerPlugin(key, this._pluginCallButtons[key], options[key], shortcuts[key]);
1281
- this.registerPlugin(key, this._pluginCallButtons_sub[key], options[key], shortcuts[key]);
1294
+ this.registerPlugin(key, this._pluginCallButtons[key], options[key]);
1295
+ this.registerPlugin(key, this._pluginCallButtons_sub[key], options[key]);
1282
1296
  plugin = this.plugins[key];
1283
1297
 
1284
1298
  // Filemanager
@@ -1286,7 +1300,7 @@ Editor.prototype = {
1286
1300
  const fm = plugin.__fileManagement;
1287
1301
  this._fileInfoPluginsCheck.push(fm._checkInfo.bind(fm));
1288
1302
  this._fileInfoPluginsReset.push(fm._resetInfo.bind(fm));
1289
- if (isArray(fm.tagNames)) {
1303
+ if (Array.isArray(fm.tagNames)) {
1290
1304
  const tagNames = fm.tagNames;
1291
1305
  this._fileManager.tags = this._fileManager.tags.concat(tagNames);
1292
1306
  filePluginRegExp.push(key);
@@ -1304,7 +1318,7 @@ Editor.prototype = {
1304
1318
  if (typeof plugin.constructor.component === 'function') {
1305
1319
  this._componentManager.push(
1306
1320
  function (launcher, element) {
1307
- if (!(element = launcher.component?.call(this, element))) return null;
1321
+ if (!element || !(element = launcher.component?.call(this, element))) return null;
1308
1322
  return {
1309
1323
  target: element,
1310
1324
  pluginName: launcher.key,
@@ -1331,6 +1345,24 @@ Editor.prototype = {
1331
1345
  }
1332
1346
  }
1333
1347
 
1348
+ if (this.options.get('buttons').has('pageBreak') || this.options.get('buttons_sub')?.has('pageBreak')) {
1349
+ this._componentManager.push((element) => {
1350
+ if (!element || !dom.utils.hasClass(element, 'se-page-break')) return null;
1351
+ return {
1352
+ target: element,
1353
+ launcher: {
1354
+ destroy: (target) => {
1355
+ const focusEl = target.previousElementSibling || target.nextElementSibling;
1356
+ dom.utils.removeItem(target);
1357
+ // focus
1358
+ this.focusEdge(focusEl);
1359
+ this.history.push(false);
1360
+ }
1361
+ }
1362
+ };
1363
+ });
1364
+ }
1365
+
1334
1366
  this._fileManager.regExp = new RegExp(`^(${this._fileManager.tags.join('|') || '\\^'})$`, 'i');
1335
1367
  this._fileManager.pluginRegExp = new RegExp(`^(${filePluginRegExp.length === 0 ? '\\^' : filePluginRegExp.join('|')})$`, 'i');
1336
1368
 
@@ -1338,11 +1370,12 @@ Editor.prototype = {
1338
1370
  delete this._pluginCallButtons_sub;
1339
1371
 
1340
1372
  this.__cachingButtons();
1373
+ this.__cachingShortcuts();
1341
1374
  },
1342
1375
 
1343
1376
  /**
1344
- * @description Caching basic buttons to use
1345
1377
  * @private
1378
+ * @description Caching basic buttons to use
1346
1379
  */
1347
1380
  __cachingButtons() {
1348
1381
  const ctx = this.context;
@@ -1353,6 +1386,11 @@ Editor.prototype = {
1353
1386
  }
1354
1387
  },
1355
1388
 
1389
+ /**
1390
+ * @private
1391
+ * @description Set the disabled button list
1392
+ * - this._codeViewDisabledButtons, this._controllerOnDisabledButtons
1393
+ */
1356
1394
  __setDisabledButtons() {
1357
1395
  const ctx = this.context;
1358
1396
 
@@ -1366,8 +1404,10 @@ Editor.prototype = {
1366
1404
  },
1367
1405
 
1368
1406
  /**
1369
- * @description Save the current buttons
1370
1407
  * @private
1408
+ * @description Save the current buttons
1409
+ * @param {Map<string, Element>} cmdButtons Command button map
1410
+ * @param {Element} tray Button tray
1371
1411
  */
1372
1412
  __saveCommandButtons(cmdButtons, tray) {
1373
1413
  const currentButtons = tray.querySelectorAll(COMMAND_BUTTONS);
@@ -1377,7 +1417,7 @@ Editor.prototype = {
1377
1417
  const reverseKeys = this.reverseKeys;
1378
1418
 
1379
1419
  for (let i = 0, len = currentButtons.length, e, c; i < len; i++) {
1380
- e = currentButtons[i];
1420
+ e = /** @type {HTMLButtonElement} */ (currentButtons[i]);
1381
1421
  c = e.getAttribute('data-command');
1382
1422
  // command set
1383
1423
  cmdButtons.set(c, e);
@@ -1387,6 +1427,27 @@ Editor.prototype = {
1387
1427
  }
1388
1428
  },
1389
1429
 
1430
+ /**
1431
+ * @private
1432
+ * @description Caches shortcut keys for commands.
1433
+ */
1434
+ __cachingShortcuts() {
1435
+ const shortcuts = this.options.get('shortcuts');
1436
+ const reverseCommandArray = this.options.get('_reverseCommandArray');
1437
+ const keyMap = this.shortcutsKeyMap;
1438
+ const reverseKeys = this.reverseKeys;
1439
+ for (const key of Object.keys(shortcuts)) {
1440
+ if (!key.startsWith('_')) continue;
1441
+ CreateShortcuts('', null, shortcuts[key], keyMap, reverseCommandArray, reverseKeys);
1442
+ }
1443
+ },
1444
+
1445
+ /**
1446
+ * @private
1447
+ * @description Sets command target elements.
1448
+ * @param {string} cmd - The command identifier.
1449
+ * @param {HTMLButtonElement} target - The associated command button.
1450
+ */
1390
1451
  __setCommandTargets(cmd, target) {
1391
1452
  if (!cmd || !target) return;
1392
1453
 
@@ -1400,6 +1461,13 @@ Editor.prototype = {
1400
1461
  }
1401
1462
  },
1402
1463
 
1464
+ /**
1465
+ * @private
1466
+ * @description Configures the document properties of an iframe editor.
1467
+ * @param {HTMLIFrameElement} frame - The editor iframe.
1468
+ * @param {Map<string, *>} originOptions - The original options.
1469
+ * @param {__se__FrameOptions} targetOptions - The new options.
1470
+ */
1403
1471
  __setIframeDocument(frame, originOptions, targetOptions) {
1404
1472
  frame.setAttribute('scrolling', 'auto');
1405
1473
  frame.contentDocument.head.innerHTML =
@@ -1407,9 +1475,14 @@ Editor.prototype = {
1407
1475
  converter._setIframeStyleLinks(targetOptions.get('iframe_cssFileName')) +
1408
1476
  converter._setAutoHeightStyle(targetOptions.get('height'));
1409
1477
  frame.contentDocument.body.className = originOptions.get('_editableClass');
1410
- frame.contentDocument.body.setAttribute('contenteditable', true);
1478
+ frame.contentDocument.body.setAttribute('contenteditable', 'true');
1411
1479
  },
1412
1480
 
1481
+ /**
1482
+ * @private
1483
+ * @description Set the FrameContext parameters and options
1484
+ * @param {__se__FrameContext} e - Frame context object
1485
+ */
1413
1486
  __setEditorParams(e) {
1414
1487
  const frameOptions = e.get('options');
1415
1488
  const _w = this._w;
@@ -1450,10 +1523,16 @@ Editor.prototype = {
1450
1523
  }
1451
1524
  },
1452
1525
 
1526
+ /**
1527
+ * @private
1528
+ * @description Registers and initializes editor classes.
1529
+ */
1453
1530
  __registerClass() {
1454
1531
  // use events
1455
- this.events = { ...Events(), ...this.options.get('events') };
1532
+ this.events = { ...Events, ...this.options.get('events') };
1456
1533
  this.triggerEvent = async (eventName, eventData) => {
1534
+ // [iframe] wysiwyg is disabled, the event is not called.
1535
+ if (eventData?.frameContext?.get('wysiwyg').getAttribute('contenteditable') === 'false') return false;
1457
1536
  const eventHandler = this.events[eventName];
1458
1537
  if (typeof eventHandler === 'function') {
1459
1538
  return await eventHandler({ editor: this, ...eventData });
@@ -1470,10 +1549,9 @@ Editor.prototype = {
1470
1549
  // util classes
1471
1550
  this.offset = new Offset(this);
1472
1551
  this.shortcuts = new Shortcuts(this);
1473
- this.notice = new Notice(this);
1474
1552
  // main classes
1475
1553
  this.toolbar = new Toolbar(this, { keyName: 'toolbar', balloon: this.isBalloon, balloonAlways: this.isBalloonAlways, inline: this.isInline, res: this._responsiveButtons });
1476
- if (this.options.has('_subMode'))
1554
+ if (this.options.has('_subMode')) {
1477
1555
  this.subToolbar = new Toolbar(this, {
1478
1556
  keyName: 'toolbar.sub',
1479
1557
  balloon: this.isSubBalloon,
@@ -1481,13 +1559,15 @@ Editor.prototype = {
1481
1559
  inline: false,
1482
1560
  res: this._responsiveButtons_sub
1483
1561
  });
1484
- this.selection = new Selection(this);
1562
+ }
1563
+ this.selection = new Selection_(this);
1485
1564
  this.html = new HTML(this);
1486
1565
  this.nodeTransform = new NodeTransform(this);
1487
1566
  this.component = new Component(this);
1488
1567
  this.format = new Format(this);
1489
1568
  this.menu = new Menu(this);
1490
1569
  this.char = new Char(this);
1570
+ this.ui = new UI(this);
1491
1571
  this.viewer = new Viewer(this);
1492
1572
 
1493
1573
  // register classes to the eventManager
@@ -1499,26 +1579,39 @@ Editor.prototype = {
1499
1579
  ClassInjector.call(this.html, this);
1500
1580
  ClassInjector.call(this.menu, this);
1501
1581
  ClassInjector.call(this.nodeTransform, this);
1582
+ ClassInjector.call(this.offset, this);
1502
1583
  ClassInjector.call(this.selection, this);
1584
+ ClassInjector.call(this.shortcuts, this);
1503
1585
  ClassInjector.call(this.toolbar, this);
1586
+ ClassInjector.call(this.ui, this);
1504
1587
  ClassInjector.call(this.viewer, this);
1505
1588
  if (this.options.has('_subMode')) ClassInjector.call(this.subToolbar, this);
1506
1589
 
1507
1590
  // delete self reference
1508
- delete this.char.char;
1509
- delete this.component.component;
1510
- delete this.format.format;
1511
- delete this.html.html;
1512
- delete this.menu.menu;
1513
- delete this.nodeTransform.nodeTransform;
1514
- delete this.selection.selection;
1515
- delete this.toolbar.toolbar;
1516
- delete this.viewer.viewer;
1517
- if (this.subToolbar) delete this.subToolbar.subToolbar;
1518
-
1519
- this._responsiveButtons = this._responsiveButtons_res = null;
1591
+ delete this.eventManager['eventManager'];
1592
+ delete this.char['char'];
1593
+ delete this.component['component'];
1594
+ delete this.format['format'];
1595
+ delete this.html['html'];
1596
+ delete this.menu['menu'];
1597
+ delete this.nodeTransform['nodeTransform'];
1598
+ delete this.offset['offset'];
1599
+ delete this.selection['selection'];
1600
+ delete this.shortcuts['shortcuts'];
1601
+ delete this.toolbar['toolbar'];
1602
+ delete this.ui['ui'];
1603
+ delete this.viewer['viewer'];
1604
+ if (this.subToolbar) delete this.subToolbar['subToolbar'];
1605
+
1606
+ this._responsiveButtons = this._responsiveButtons_sub = null;
1520
1607
  },
1521
1608
 
1609
+ /**
1610
+ * @private
1611
+ * @description Creates the editor instance and initializes components.
1612
+ * @param {EditorInitOptions} originOptions - The initial editor options.
1613
+ * @returns {Promise<void>}
1614
+ */
1522
1615
  async __Create(originOptions) {
1523
1616
  // set modes
1524
1617
  this.isInline = /inline/i.test(this.options.get('mode'));
@@ -1546,7 +1639,7 @@ Editor.prototype = {
1546
1639
 
1547
1640
  if (e.get('options').get('iframe')) {
1548
1641
  const iframeLoaded = new Promise((resolve) => {
1549
- e.get('wysiwygFrame').addEventListener('load', ({ target }) => {
1642
+ this.eventManager.addEvent(e.get('wysiwygFrame'), 'load', ({ target }) => {
1550
1643
  this.__setIframeDocument(target, this.options, e.get('options'));
1551
1644
  resolve();
1552
1645
  });
@@ -1557,6 +1650,18 @@ Editor.prototype = {
1557
1650
 
1558
1651
  this.applyFrameRoots((e) => {
1559
1652
  e.get('wrapper').appendChild(e.get('wysiwygFrame'));
1653
+
1654
+ // document type
1655
+ if (e.get('documentTypeInner')) {
1656
+ if (this.options.get('_rtl')) e.get('wrapper').appendChild(e.get('documentTypeInner'));
1657
+ else e.get('wrapper').insertBefore(e.get('documentTypeInner'), e.get('wysiwygFrame'));
1658
+ }
1659
+ if (e.get('documentTypePage')) {
1660
+ if (this.options.get('_rtl')) e.get('wrapper').insertBefore(e.get('documentTypePage'), e.get('wysiwygFrame'));
1661
+ else e.get('wrapper').appendChild(e.get('documentTypePage'));
1662
+ // page mirror
1663
+ e.get('wrapper').appendChild(e.get('documentTypePageMirror'));
1664
+ }
1560
1665
  });
1561
1666
 
1562
1667
  if (iframePromises.length > 0) {