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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (315) hide show
  1. package/CONTRIBUTING.md +170 -22
  2. package/{LICENSE.txt → LICENSE} +9 -9
  3. package/README.md +168 -30
  4. package/dist/suneditor.min.css +1 -1
  5. package/dist/suneditor.min.js +1 -1
  6. package/package.json +47 -21
  7. package/src/assets/design/color.css +121 -0
  8. package/src/assets/design/index.css +3 -0
  9. package/src/assets/design/size.css +35 -0
  10. package/src/assets/design/typography.css +37 -0
  11. package/src/assets/icons/defaultIcons.js +232 -0
  12. package/src/assets/suneditor-contents.css +181 -46
  13. package/src/assets/suneditor.css +1403 -650
  14. package/src/core/base/eventHandlers/handler_toolbar.js +35 -14
  15. package/src/core/base/eventHandlers/handler_ww_clipboard.js +23 -4
  16. package/src/core/base/eventHandlers/handler_ww_dragDrop.js +49 -10
  17. package/src/core/base/eventHandlers/handler_ww_key_input.js +422 -224
  18. package/src/core/base/eventHandlers/handler_ww_mouse.js +83 -36
  19. package/src/core/base/eventManager.js +520 -179
  20. package/src/core/base/history.js +95 -41
  21. package/src/core/class/char.js +26 -11
  22. package/src/core/class/component.js +345 -137
  23. package/src/core/class/format.js +683 -519
  24. package/src/core/class/html.js +485 -305
  25. package/src/core/class/menu.js +133 -47
  26. package/src/core/class/nodeTransform.js +90 -71
  27. package/src/core/class/offset.js +408 -92
  28. package/src/core/class/selection.js +216 -106
  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 +422 -0
  32. package/src/core/class/viewer.js +178 -74
  33. package/src/core/editor.js +496 -389
  34. package/src/core/section/actives.js +123 -27
  35. package/src/core/section/constructor.js +615 -206
  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/events.js +622 -0
  42. package/src/helper/clipboard.js +59 -0
  43. package/src/helper/converter.js +202 -26
  44. package/src/helper/dom/domCheck.js +304 -0
  45. package/src/helper/dom/domQuery.js +669 -0
  46. package/src/helper/dom/domUtils.js +557 -0
  47. package/src/helper/dom/index.js +12 -0
  48. package/src/helper/env.js +46 -56
  49. package/src/helper/index.js +10 -4
  50. package/src/helper/keyCodeMap.js +183 -0
  51. package/src/helper/numbers.js +12 -8
  52. package/src/helper/unicode.js +9 -5
  53. package/src/langs/ckb.js +74 -4
  54. package/src/langs/cs.js +72 -2
  55. package/src/langs/da.js +73 -3
  56. package/src/langs/de.js +73 -4
  57. package/src/langs/en.js +23 -3
  58. package/src/langs/es.js +73 -4
  59. package/src/langs/fa.js +75 -3
  60. package/src/langs/fr.js +73 -3
  61. package/src/langs/he.js +73 -4
  62. package/src/langs/hu.js +230 -0
  63. package/src/langs/index.js +7 -3
  64. package/src/langs/it.js +70 -1
  65. package/src/langs/ja.js +72 -4
  66. package/src/langs/km.js +230 -0
  67. package/src/langs/ko.js +22 -2
  68. package/src/langs/lv.js +74 -5
  69. package/src/langs/nl.js +73 -4
  70. package/src/langs/pl.js +73 -4
  71. package/src/langs/pt_br.js +70 -1
  72. package/src/langs/ro.js +74 -5
  73. package/src/langs/ru.js +73 -4
  74. package/src/langs/se.js +73 -4
  75. package/src/langs/tr.js +73 -1
  76. package/src/langs/{ua.js → uk.js} +75 -6
  77. package/src/langs/ur.js +77 -8
  78. package/src/langs/zh_cn.js +74 -5
  79. package/src/modules/ApiManager.js +77 -54
  80. package/src/modules/Browser.js +667 -0
  81. package/src/modules/ColorPicker.js +162 -102
  82. package/src/modules/Controller.js +273 -142
  83. package/src/modules/Figure.js +925 -484
  84. package/src/modules/FileManager.js +121 -69
  85. package/src/modules/HueSlider.js +113 -61
  86. package/src/modules/Modal.js +291 -122
  87. package/src/modules/ModalAnchorEditor.js +383 -234
  88. package/src/modules/SelectMenu.js +270 -168
  89. package/src/modules/_DragHandle.js +2 -1
  90. package/src/modules/index.js +3 -3
  91. package/src/plugins/browser/audioGallery.js +83 -0
  92. package/src/plugins/browser/fileBrowser.js +103 -0
  93. package/src/plugins/browser/fileGallery.js +83 -0
  94. package/src/plugins/browser/imageGallery.js +81 -0
  95. package/src/plugins/browser/videoGallery.js +103 -0
  96. package/src/plugins/command/blockquote.js +40 -27
  97. package/src/plugins/command/exportPDF.js +134 -0
  98. package/src/plugins/command/fileUpload.js +229 -162
  99. package/src/plugins/command/list_bulleted.js +83 -47
  100. package/src/plugins/command/list_numbered.js +83 -47
  101. package/src/plugins/dropdown/align.js +66 -54
  102. package/src/plugins/dropdown/backgroundColor.js +63 -49
  103. package/src/plugins/dropdown/font.js +71 -47
  104. package/src/plugins/dropdown/fontColor.js +63 -48
  105. package/src/plugins/dropdown/formatBlock.js +70 -33
  106. package/src/plugins/dropdown/hr.js +92 -51
  107. package/src/plugins/dropdown/layout.js +37 -26
  108. package/src/plugins/dropdown/lineHeight.js +54 -38
  109. package/src/plugins/dropdown/list.js +60 -45
  110. package/src/plugins/dropdown/paragraphStyle.js +51 -30
  111. package/src/plugins/dropdown/table.js +2003 -813
  112. package/src/plugins/dropdown/template.js +38 -26
  113. package/src/plugins/dropdown/textStyle.js +43 -31
  114. package/src/plugins/field/mention.js +147 -86
  115. package/src/plugins/index.js +32 -6
  116. package/src/plugins/input/fontSize.js +161 -108
  117. package/src/plugins/input/pageNavigator.js +70 -0
  118. package/src/plugins/modal/audio.js +358 -173
  119. package/src/plugins/modal/drawing.js +531 -0
  120. package/src/plugins/modal/embed.js +886 -0
  121. package/src/plugins/modal/image.js +674 -362
  122. package/src/plugins/modal/link.js +100 -71
  123. package/src/plugins/modal/math.js +367 -167
  124. package/src/plugins/modal/video.js +691 -335
  125. package/src/plugins/popup/anchor.js +222 -0
  126. package/src/suneditor.js +50 -13
  127. package/src/themes/dark.css +122 -0
  128. package/src/typedef.js +130 -0
  129. package/types/assets/icons/defaultIcons.d.ts +153 -0
  130. package/types/core/base/eventHandlers/handler_toolbar.d.ts +41 -0
  131. package/types/core/base/eventHandlers/handler_ww_clipboard.d.ts +40 -0
  132. package/types/core/base/eventHandlers/handler_ww_dragDrop.d.ts +35 -0
  133. package/types/core/base/eventHandlers/handler_ww_key_input.d.ts +45 -0
  134. package/types/core/base/eventHandlers/handler_ww_mouse.d.ts +39 -0
  135. package/types/core/base/eventManager.d.ts +385 -0
  136. package/types/core/base/history.d.ts +81 -0
  137. package/types/core/class/char.d.ts +60 -0
  138. package/types/core/class/component.d.ts +212 -0
  139. package/types/core/class/format.d.ts +616 -0
  140. package/types/core/class/html.d.ts +422 -0
  141. package/types/core/class/menu.d.ts +126 -0
  142. package/types/core/class/nodeTransform.d.ts +93 -0
  143. package/types/core/class/offset.d.ts +522 -0
  144. package/types/core/class/selection.d.ts +188 -0
  145. package/types/core/class/shortcuts.d.ts +142 -0
  146. package/types/core/class/toolbar.d.ts +189 -0
  147. package/types/core/class/ui.d.ts +164 -0
  148. package/types/core/class/viewer.d.ts +140 -0
  149. package/types/core/editor.d.ts +610 -0
  150. package/types/core/section/actives.d.ts +46 -0
  151. package/types/core/section/constructor.d.ts +777 -0
  152. package/types/core/section/context.d.ts +45 -0
  153. package/types/core/section/documentType.d.ts +178 -0
  154. package/types/editorInjector/_classes.d.ts +41 -0
  155. package/types/editorInjector/_core.d.ts +92 -0
  156. package/types/editorInjector/index.d.ts +71 -0
  157. package/types/events.d.ts +273 -0
  158. package/types/helper/clipboard.d.ts +12 -0
  159. package/types/helper/converter.d.ts +197 -0
  160. package/types/helper/dom/domCheck.d.ts +189 -0
  161. package/types/helper/dom/domQuery.d.ts +223 -0
  162. package/types/helper/dom/domUtils.d.ts +226 -0
  163. package/types/helper/dom/index.d.ts +9 -0
  164. package/types/helper/env.d.ts +132 -0
  165. package/types/helper/index.d.ts +174 -0
  166. package/types/helper/keyCodeMap.d.ts +110 -0
  167. package/types/helper/numbers.d.ts +46 -0
  168. package/types/helper/unicode.d.ts +28 -0
  169. package/types/index.d.ts +120 -0
  170. package/{typings/Lang.d.ts → types/langs/_Lang.d.ts} +173 -103
  171. package/types/langs/ckb.d.ts +3 -0
  172. package/types/langs/cs.d.ts +3 -0
  173. package/types/langs/da.d.ts +3 -0
  174. package/types/langs/de.d.ts +3 -0
  175. package/types/langs/en.d.ts +3 -0
  176. package/types/langs/es.d.ts +3 -0
  177. package/types/langs/fa.d.ts +3 -0
  178. package/types/langs/fr.d.ts +3 -0
  179. package/types/langs/he.d.ts +3 -0
  180. package/types/langs/hu.d.ts +3 -0
  181. package/types/langs/index.d.ts +54 -0
  182. package/types/langs/it.d.ts +3 -0
  183. package/types/langs/ja.d.ts +3 -0
  184. package/types/langs/km.d.ts +3 -0
  185. package/types/langs/ko.d.ts +3 -0
  186. package/types/langs/lv.d.ts +3 -0
  187. package/types/langs/nl.d.ts +3 -0
  188. package/types/langs/pl.d.ts +3 -0
  189. package/types/langs/pt_br.d.ts +3 -0
  190. package/types/langs/ro.d.ts +3 -0
  191. package/types/langs/ru.d.ts +3 -0
  192. package/types/langs/se.d.ts +3 -0
  193. package/types/langs/tr.d.ts +3 -0
  194. package/types/langs/uk.d.ts +3 -0
  195. package/types/langs/ur.d.ts +3 -0
  196. package/types/langs/zh_cn.d.ts +3 -0
  197. package/types/modules/ApiManager.d.ts +125 -0
  198. package/types/modules/Browser.d.ts +326 -0
  199. package/types/modules/ColorPicker.d.ts +131 -0
  200. package/types/modules/Controller.d.ts +251 -0
  201. package/types/modules/Figure.d.ts +517 -0
  202. package/types/modules/FileManager.d.ts +202 -0
  203. package/types/modules/HueSlider.d.ts +136 -0
  204. package/types/modules/Modal.d.ts +111 -0
  205. package/types/modules/ModalAnchorEditor.d.ts +236 -0
  206. package/types/modules/SelectMenu.d.ts +194 -0
  207. package/types/modules/_DragHandle.d.ts +7 -0
  208. package/types/modules/index.d.ts +26 -0
  209. package/types/plugins/browser/audioGallery.d.ts +55 -0
  210. package/types/plugins/browser/fileBrowser.d.ts +64 -0
  211. package/types/plugins/browser/fileGallery.d.ts +55 -0
  212. package/types/plugins/browser/imageGallery.d.ts +51 -0
  213. package/types/plugins/browser/videoGallery.d.ts +57 -0
  214. package/types/plugins/command/blockquote.d.ts +28 -0
  215. package/types/plugins/command/exportPDF.d.ts +46 -0
  216. package/types/plugins/command/fileUpload.d.ts +156 -0
  217. package/types/plugins/command/list_bulleted.d.ts +46 -0
  218. package/types/plugins/command/list_numbered.d.ts +46 -0
  219. package/types/plugins/dropdown/align.d.ts +60 -0
  220. package/types/plugins/dropdown/backgroundColor.d.ts +63 -0
  221. package/types/plugins/dropdown/font.d.ts +54 -0
  222. package/types/plugins/dropdown/fontColor.d.ts +63 -0
  223. package/types/plugins/dropdown/formatBlock.d.ts +54 -0
  224. package/types/plugins/dropdown/hr.d.ts +71 -0
  225. package/types/plugins/dropdown/layout.d.ts +40 -0
  226. package/types/plugins/dropdown/lineHeight.d.ts +50 -0
  227. package/types/plugins/dropdown/list.d.ts +39 -0
  228. package/types/plugins/dropdown/paragraphStyle.d.ts +54 -0
  229. package/types/plugins/dropdown/table.d.ts +627 -0
  230. package/types/plugins/dropdown/template.d.ts +40 -0
  231. package/types/plugins/dropdown/textStyle.d.ts +41 -0
  232. package/types/plugins/field/mention.d.ts +102 -0
  233. package/types/plugins/index.d.ts +107 -0
  234. package/types/plugins/input/fontSize.d.ts +170 -0
  235. package/types/plugins/input/pageNavigator.d.ts +28 -0
  236. package/types/plugins/modal/audio.d.ts +269 -0
  237. package/types/plugins/modal/drawing.d.ts +246 -0
  238. package/types/plugins/modal/embed.d.ts +387 -0
  239. package/types/plugins/modal/image.d.ts +451 -0
  240. package/types/plugins/modal/link.d.ts +128 -0
  241. package/types/plugins/modal/math.d.ts +193 -0
  242. package/types/plugins/modal/video.d.ts +485 -0
  243. package/types/plugins/popup/anchor.d.ts +56 -0
  244. package/types/suneditor.d.ts +51 -0
  245. package/types/typedef.d.ts +233 -0
  246. package/.eslintignore +0 -7
  247. package/.eslintrc.json +0 -64
  248. package/src/assets/icons/_default.js +0 -194
  249. package/src/core/base/events.js +0 -320
  250. package/src/core/class/notice.js +0 -42
  251. package/src/helper/domUtils.js +0 -1177
  252. package/src/modules/FileBrowser.js +0 -271
  253. package/src/plugins/command/exportPdf.js +0 -168
  254. package/src/plugins/fileBrowser/imageGallery.js +0 -81
  255. package/src/themes/test.css +0 -61
  256. package/typings/CommandPlugin.d.ts +0 -8
  257. package/typings/DialogPlugin.d.ts +0 -20
  258. package/typings/FileBrowserPlugin.d.ts +0 -30
  259. package/typings/Module.d.ts +0 -15
  260. package/typings/Plugin.d.ts +0 -42
  261. package/typings/SubmenuPlugin.d.ts +0 -8
  262. package/typings/_classes.d.ts +0 -17
  263. package/typings/_colorPicker.d.ts +0 -60
  264. package/typings/_core.d.ts +0 -55
  265. package/typings/align.d.ts +0 -5
  266. package/typings/audio.d.ts +0 -5
  267. package/typings/backgroundColor.d.ts +0 -5
  268. package/typings/blockquote.d.ts +0 -5
  269. package/typings/char.d.ts +0 -39
  270. package/typings/component.d.ts +0 -38
  271. package/typings/context.d.ts +0 -39
  272. package/typings/converter.d.ts +0 -33
  273. package/typings/dialog.d.ts +0 -28
  274. package/typings/domUtils.d.ts +0 -361
  275. package/typings/editor.d.ts +0 -7
  276. package/typings/editor.ts +0 -542
  277. package/typings/env.d.ts +0 -70
  278. package/typings/eventManager.d.ts +0 -37
  279. package/typings/events.d.ts +0 -262
  280. package/typings/fileBrowser.d.ts +0 -42
  281. package/typings/fileManager.d.ts +0 -67
  282. package/typings/font.d.ts +0 -5
  283. package/typings/fontColor.d.ts +0 -5
  284. package/typings/fontSize.d.ts +0 -5
  285. package/typings/format.d.ts +0 -191
  286. package/typings/formatBlock.d.ts +0 -5
  287. package/typings/history.d.ts +0 -48
  288. package/typings/horizontalRule.d.ts +0 -5
  289. package/typings/image.d.ts +0 -5
  290. package/typings/imageGallery.d.ts +0 -5
  291. package/typings/index.d.ts +0 -21
  292. package/typings/index.modules.d.ts +0 -11
  293. package/typings/index.plugins.d.ts +0 -58
  294. package/typings/lineHeight.d.ts +0 -5
  295. package/typings/link.d.ts +0 -5
  296. package/typings/list.d.ts +0 -5
  297. package/typings/math.d.ts +0 -5
  298. package/typings/mediaContainer.d.ts +0 -25
  299. package/typings/mention.d.ts +0 -5
  300. package/typings/node.d.ts +0 -57
  301. package/typings/notice.d.ts +0 -16
  302. package/typings/numbers.d.ts +0 -29
  303. package/typings/offset.d.ts +0 -24
  304. package/typings/options.d.ts +0 -589
  305. package/typings/paragraphStyle.d.ts +0 -5
  306. package/typings/resizing.d.ts +0 -141
  307. package/typings/selection.d.ts +0 -94
  308. package/typings/shortcuts.d.ts +0 -13
  309. package/typings/suneditor.d.ts +0 -9
  310. package/typings/table.d.ts +0 -5
  311. package/typings/template.d.ts +0 -5
  312. package/typings/textStyle.d.ts +0 -5
  313. package/typings/toolbar.d.ts +0 -32
  314. package/typings/unicode.d.ts +0 -25
  315. package/typings/video.d.ts +0 -5
@@ -1,10 +1,11 @@
1
- import { env, converter, domUtils, numbers } from '../helper';
2
- import Constructor, { InitOptions, UpdateButton, CreateShortcuts, CreateStatusbar, RO_UNAVAILABD } from './section/constructor';
1
+ import { env, converter, dom, numbers } from '../helper';
2
+ import Constructor, { InitOptions, UpdateButton, CreateShortcuts, CreateStatusbar, OPTION_FIXED_FLAG } from './section/constructor';
3
3
  import { UpdateStatusbarContext } from './section/context';
4
- import { BASIC_COMMANDS, ACTIVE_EVENT_COMMANDS, SELECT_ALL, DIR_BTN_ACTIVE, SAVE, COPY_FORMAT, 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
- import Events from './base/events';
7
+ import Events from '../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_editor
33
+ */
34
+
35
+ /**
36
+ * @typedef {import('./section/constructor').EditorFrameOptions} EditorFrameOptions_editor
37
+ */
38
+
39
+ /**
40
+ * @typedef {import('../modules/Controller').ControllerInfo} ControllerInfo_editor
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_editor}>} multiTargets Target element
47
+ * @param {EditorInitOptions_editor} 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,55 +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 {boolean} componentSelected Boolean value of whether component is selected
112
- * @property {number} rootKey Current root key
140
+ * @type {__se__EditorStatus}
113
141
  */
114
142
  this.status = {
115
143
  hasFocus: false,
@@ -118,155 +146,286 @@ const Editor = function (multiTargets, options) {
118
146
  codeIndentSize: 2,
119
147
  currentNodes: [],
120
148
  currentNodesMap: [],
121
- componentSelected: false,
149
+ onSelected: false,
122
150
  rootKey: product.rootId,
123
- _range: null
151
+ _range: null,
152
+ _onMousedown: false
124
153
  };
125
154
 
126
155
  /**
127
156
  * @description Is classic mode?
157
+ * @type {boolean}
128
158
  */
129
- this.isClassic = null;
159
+ this.isClassic = false;
130
160
 
131
161
  /**
132
162
  * @description Is inline mode?
163
+ * @type {boolean}
133
164
  */
134
- this.isInline = null;
165
+ this.isInline = false;
135
166
 
136
167
  /**
137
168
  * @description Is balloon|balloon-always mode?
169
+ * @type {boolean}
138
170
  */
139
- this.isBalloon = null;
171
+ this.isBalloon = false;
140
172
 
141
173
  /**
142
174
  * @description Is balloon-always mode?
175
+ * @type {boolean}
143
176
  */
144
- this.isBalloonAlways = null;
177
+ this.isBalloonAlways = false;
145
178
 
146
179
  /**
147
180
  * @description Is subToolbar balloon|balloon-always mode?
181
+ * @type {boolean}
148
182
  */
149
- this.isSubBalloon = null;
183
+ this.isSubBalloon = false;
150
184
 
151
185
  /**
152
186
  * @description Is subToolbar balloon-always mode?
187
+ * @type {boolean}
153
188
  */
154
- this.isSubBalloonAlways = null;
189
+ this.isSubBalloonAlways = false;
155
190
 
156
- // ----- Properties not shared with _core -----
157
191
  /**
158
192
  * @description All command buttons map
193
+ * @type {Map<string, HTMLElement>}
159
194
  */
160
195
  this.allCommandButtons = new Map();
196
+
197
+ /**
198
+ * @description All command buttons map
199
+ * @type {Map<string, HTMLElement>}
200
+ */
161
201
  this.subAllCommandButtons = new Map();
162
202
 
163
203
  /**
164
204
  * @description Shoutcuts key map
205
+ * @type {Map<string, *>}
165
206
  */
166
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
+ */
167
214
  this.reverseKeys = [];
168
215
 
169
216
  /**
170
217
  * @description A map with the plugin's buttons having an "active" method and the default command buttons with an "active" action.
171
- * Each button is contained in an array.
218
+ * - Each button is contained in an array.
219
+ * @type {Map<string, Array<HTMLButtonElement>>}
172
220
  */
173
221
  this.commandTargets = new Map();
174
222
 
175
223
  /**
176
224
  * @description Plugins array with "active" method.
177
- * "activeCommands" runs the "add" method when creating the editor.
225
+ * - "activeCommands" runs the "add" method when creating the editor.
226
+ * @type {Array<string>}
178
227
  */
179
228
  this.activeCommands = null;
180
229
 
181
230
  /**
182
231
  * @description The selection node (selection.getNode()) to which the effect was last applied
232
+ * @type {Node|null}
183
233
  */
184
234
  this.effectNode = null;
185
235
 
236
+ /**
237
+ * @description Currently open "Modal" instance
238
+ * @type {*}
239
+ */
240
+ this.opendModal = null;
241
+
242
+ /**
243
+ * @description Currently open "Controller" info array
244
+ * @type {Array<ControllerInfo_editor>}
245
+ */
246
+ this.opendControllers = [];
247
+
248
+ /**
249
+ * @description Currently open "Controller" caller plugin name
250
+ */
251
+ this.currentControllerName = '';
252
+
253
+ /**
254
+ * @description Currently open "Browser" instance
255
+ * @type {*}
256
+ */
257
+ this.opendBrowser = null;
258
+
259
+ /**
260
+ * @description Whether "SelectMenu" is open
261
+ * @type {boolean}
262
+ */
263
+ this.selectMenuOn = false;
264
+
265
+ // ------ base ------
266
+ /** @description History class instance @type {ReturnType<typeof import('./base/history').default>} */
267
+ this.history = null;
268
+ /** @description EventManager class instance @type {import('./base/eventManager').default} */
269
+ this.eventManager = null;
270
+
271
+ // ------ class ------
272
+ /** @description Toolbar class instance @type {import('./class/toolbar').default} */
273
+ this.toolbar = null;
274
+ /** @description Sub-Toolbar class instance @type {import('./class/toolbar').default|null} */
275
+ this.subToolbar = null;
276
+ /** @description Char class instance @type {import('./class/char').default} */
277
+ this.char = null;
278
+ /** @description Component class instance @type {import('./class/component').default} */
279
+ this.component = null;
280
+ /** @description Format class instance @type {import('./class/format').default} */
281
+ this.format = null;
282
+ /** @description HTML class instance @type {import('./class/html').default} */
283
+ this.html = null;
284
+ /** @description Menu class instance @type {import('./class/menu').default} */
285
+ this.menu = null;
286
+ /** @description NodeTransform class instance @type {import('./class/nodeTransform').default} */
287
+ this.nodeTransform = null;
288
+ /** @description Offset class instance @type {import('./class/offset').default} */
289
+ this.offset = null;
290
+ /** @description Selection class instance @type {import('./class/selection').default} */
291
+ this.selection = null;
292
+ /** @description Shortcuts class instance @type {import('./class/shortcuts').default} */
293
+ this.shortcuts = null;
294
+ /** @description UI class instance @type {import('./class/ui').default} */
295
+ this.ui = null;
296
+ /** @description Viewer class instance @type {import('./class/viewer').default} */
297
+ this.viewer = null;
298
+
186
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
+
187
312
  /**
188
313
  * @description Closest ShadowRoot to editor if found
189
314
  * @type {ShadowRoot}
190
- * @private
191
315
  */
192
316
  this._shadowRoot = null;
193
317
 
194
318
  /**
195
319
  * @description Plugin call event map
196
- * @private
320
+ * @type {Map<string, Array<((...args: *) => *) & { index: number }>>}
197
321
  */
198
322
  this._onPluginEvents = null;
199
323
 
200
324
  /**
201
325
  * @description Copy format info
202
- * @private
326
+ * - eventManager.__cacheStyleNodes copied
327
+ * @type {Array<Node>|null}
203
328
  */
204
329
  this._onCopyFormatInfo = null;
330
+
331
+ /**
332
+ * @description Copy format init method
333
+ * @type {(...args: *) => *|null}
334
+ */
205
335
  this._onCopyFormatInitMethod = null;
206
336
 
207
337
  /**
208
- * @description Controller, modal relative
209
- * @private
338
+ * @description Controller target's frame div (editor.frameContext.get('topArea'))
339
+ * @type {HTMLElement|null}
210
340
  */
211
- this.opendModal = null;
212
- this.opendControllers = [];
213
- this.currentControllerName = '';
214
341
  this._controllerTargetContext = null;
215
- this.selectMenuOn = false;
216
- this._backWrapper = product.carrierWrapper.querySelector('.se-back-wrapper');
217
342
 
343
+ /**
344
+ * @description List of buttons that are disabled when "controller" is opened
345
+ * @type {Array<HTMLButtonElement|HTMLInputElement>}
346
+ */
218
347
  this._controllerOnDisabledButtons = [];
348
+
349
+ /**
350
+ * @description List of buttons that are disabled when "codeView" mode opened
351
+ * @type {Array<HTMLButtonElement|HTMLInputElement>}
352
+ */
219
353
  this._codeViewDisabledButtons = [];
220
354
 
221
355
  /**
222
- * @description Button List in Responsive Toolbar.
223
- * @private
356
+ * @description List of buttons to run plugins in the toolbar
357
+ * @type {Array<HTMLElement>}
224
358
  */
225
359
  this._pluginCallButtons = product.pluginCallButtons;
360
+
361
+ /**
362
+ * @description List of buttons to run plugins in the Sub-Toolbar
363
+ * @type {Array<HTMLElement>}
364
+ */
226
365
  this._pluginCallButtons_sub = product.pluginCallButtons_sub;
366
+
367
+ /**
368
+ * @description Responsive Toolbar Button Structure array
369
+ * @type {Array<*>}
370
+ */
227
371
  this._responsiveButtons = product.responsiveButtons;
372
+
373
+ /**
374
+ * @description Responsive Sub-Toolbar Button Structure array
375
+ * @type {Array<*>}
376
+ */
228
377
  this._responsiveButtons_sub = product.responsiveButtons_sub;
229
378
 
230
379
  /**
231
380
  * @description Variable that controls the "blur" event in the editor of inline or balloon mode when the focus is moved to dropdown
232
- * @private
381
+ * @type {boolean}
233
382
  */
234
383
  this._notHideToolbar = false;
235
384
 
236
385
  /**
237
386
  * @description Variables for controlling focus and blur events
238
- * @private
387
+ * @type {boolean}
239
388
  */
240
- this._antiBlur = false;
389
+ this._preventBlur = false;
241
390
 
242
391
  /**
243
- * @description If true, (initialize, reset) all indexes of image, video information
244
- * @private
392
+ * @description Variables for controlling selection change events
393
+ */
394
+ this._preventSelection = false;
395
+
396
+ /**
397
+ * @description If true, initialize all indexes of image, video information
398
+ * @type {boolean}
245
399
  */
246
400
  this._componentsInfoInit = true;
401
+
402
+ /**
403
+ * @description If true, reset all indexes of image, video information
404
+ * @type {boolean}
405
+ */
247
406
  this._componentsInfoReset = false;
248
407
 
249
408
  /**
250
409
  * @description plugin retainFormat info Map()
251
- * @private
410
+ * @type {Map<string, ((...args: *) => *)>}
252
411
  */
253
412
  this._MELInfo = null;
254
413
 
255
414
  /**
256
415
  * @description Properties for managing files in the "FileManager" module
257
- * @private
416
+ * @type {Array<*>}
258
417
  */
259
418
  this._fileInfoPluginsCheck = null;
260
419
 
261
420
  /**
262
421
  * @description Properties for managing files in the "FileManager" module
263
- * @private
422
+ * @type {Array<*>}
264
423
  */
265
424
  this._fileInfoPluginsReset = null;
266
425
 
267
426
  /**
268
427
  * @description Variables for file component management
269
- * @private
428
+ * @type {Object<string, *>}
270
429
  */
271
430
  this._fileManager = {
272
431
  tags: null,
@@ -274,34 +433,38 @@ const Editor = function (multiTargets, options) {
274
433
  pluginRegExp: null,
275
434
  pluginMap: null
276
435
  };
436
+
437
+ /**
438
+ * @description Variables for managing the components
439
+ * @type {Array<*>}
440
+ */
277
441
  this._componentManager = [];
278
442
 
279
443
  /**
280
444
  * @description Current Figure container.
281
- * @private
445
+ * @type {HTMLElement|null}
282
446
  */
283
447
  this._figureContainer = null;
284
448
 
285
449
  /**
286
450
  * @description Origin options
287
- * @private
451
+ * @type {EditorInitOptions_editor}
288
452
  */
289
453
  this._originOptions = options;
290
454
 
291
455
  /** ----- Create editor ------------------------------------------------------------ */
292
456
  this.__Create(options);
293
- };
457
+ }
294
458
 
295
459
  Editor.prototype = {
296
460
  /**
297
461
  * @description If the plugin is not added, add the plugin and call the 'add' function.
298
- * If the plugin is added call callBack function.
462
+ * - If the plugin is added call callBack function.
299
463
  * @param {string} pluginName The name of the plugin to call
300
- * @param {Array.<Element>|null} targets Plugin target button (This is not necessary if you have a button list when creating the editor)
301
- * @param {object|null} pluginOptions Plugin's options
302
- * @param {object} shortcuts this.options.get('shortcuts')
464
+ * @param {?Array<HTMLElement>} targets Plugin target button (This is not necessary if you have a button list when creating the editor)
465
+ * @param {?Object<string, *>} pluginOptions Plugin's options
303
466
  */
304
- registerPlugin(pluginName, targets, pluginOptions, shortcuts) {
467
+ registerPlugin(pluginName, targets, pluginOptions) {
305
468
  let plugin = this.plugins[pluginName];
306
469
  if (!plugin) {
307
470
  throw Error(`[SUNEDITOR.registerPlugin.fail] The called plugin does not exist or is in an invalid format. (pluginName: "${pluginName}")`);
@@ -312,7 +475,7 @@ Editor.prototype = {
312
475
 
313
476
  if (targets) {
314
477
  for (let i = 0, len = targets.length; i < len; i++) {
315
- UpdateButton(targets[i], plugin, this.icons, this.lang, shortcuts);
478
+ UpdateButton(targets[i], plugin, this.icons, this.lang);
316
479
  }
317
480
 
318
481
  if (!this.activeCommands.includes(pluginName) && typeof this.plugins[pluginName].active === 'function') {
@@ -325,13 +488,13 @@ Editor.prototype = {
325
488
  * @description Run plugin calls and basic commands.
326
489
  * @param {string} command Command string
327
490
  * @param {string} type Display type string ('command', 'dropdown', 'modal', 'container')
328
- * @param {Element|null} button The element of command button
491
+ * @param {?Node=} button The element of command button
329
492
  */
330
493
  run(command, type, button) {
331
494
  if (type) {
332
495
  if (/more/i.test(type)) {
333
- const toolbar = domUtils.getParentElement(button, '.se-toolbar');
334
- const toolInst = domUtils.hasClass(toolbar, 'se-toolbar-sub') ? this.subToolbar : this.toolbar;
496
+ const toolbar = dom.query.getParentElement(button, '.se-toolbar');
497
+ const toolInst = dom.utils.hasClass(toolbar, 'se-toolbar-sub') ? this.subToolbar : this.toolbar;
335
498
  if (button !== toolInst.currentMoreLayerActiveButton) {
336
499
  const layer = toolbar.querySelector('.' + command);
337
500
  if (layer) {
@@ -339,7 +502,7 @@ Editor.prototype = {
339
502
  toolInst._showBalloon();
340
503
  toolInst._showInline();
341
504
  }
342
- domUtils.addClass(button, 'on');
505
+ dom.utils.addClass(button, 'on');
343
506
  } else if (toolInst.currentMoreLayerActiveButton) {
344
507
  toolInst._moreLayerOff();
345
508
  toolInst._showBalloon();
@@ -355,7 +518,7 @@ Editor.prototype = {
355
518
  return;
356
519
  }
357
520
 
358
- if (this.frameContext.get('isReadOnly') && domUtils.arrayIncludes(this._controllerOnDisabledButtons, button)) return;
521
+ if (this.frameContext.get('isReadOnly') && dom.utils.arrayIncludes(this._controllerOnDisabledButtons, button)) return;
359
522
  if (/dropdown/.test(type) && (this.menu.targetMap[command] === null || button !== this.menu.currentDropdownActiveButton)) {
360
523
  this.menu.dropdownOn(button);
361
524
  return;
@@ -364,8 +527,10 @@ Editor.prototype = {
364
527
  return;
365
528
  } else if (/command/.test(type)) {
366
529
  this.plugins[command].action(button);
367
- } else if (/fileBrowser/.test(type)) {
530
+ } else if (/browser/.test(type)) {
368
531
  this.plugins[command].open(null);
532
+ } else if (/popup/.test(type)) {
533
+ this.plugins[command].show();
369
534
  }
370
535
  } else if (command) {
371
536
  this.commandHandler(command, button);
@@ -381,24 +546,27 @@ Editor.prototype = {
381
546
 
382
547
  /**
383
548
  * @description Execute default command of command button
384
- * (selectAll, codeView, fullScreen, indent, outdent, undo, redo, removeFormat, print, preview, showBlocks, save, bold, underline, italic, strike, subscript, superscript, copy, cut, paste)
549
+ * - (selectAll, codeView, fullScreen, indent, outdent, undo, redo, removeFormat, print, preview, showBlocks, save, bold, underline, italic, strike, subscript, superscript, copy, cut, paste)
385
550
  * @param {string} command Property of command button (data-value)
386
- * @param {Element} button Command button
551
+ * @param {?Node=} button Command button
552
+ * @returns {Promise<void>}
387
553
  */
388
554
  async commandHandler(command, button) {
389
555
  if (this.frameContext.get('isReadOnly') && !/copy|cut|selectAll|codeView|fullScreen|print|preview|showBlocks/.test(command)) return;
390
556
 
391
557
  switch (command) {
392
- case 'copy':
393
- case 'cut':
394
- this.execCommand(command);
395
- break;
396
- case 'paste':
397
- // @todo
398
- break;
399
558
  case 'selectAll':
400
559
  SELECT_ALL(this);
401
560
  break;
561
+ case 'copy': {
562
+ const range = this.selection.getRange();
563
+ if (range.collapsed) break;
564
+
565
+ const container = dom.utils.createElement('div', null, range.cloneContents());
566
+ await this.html.copy(container.innerHTML);
567
+
568
+ break;
569
+ }
402
570
  case 'newDocument':
403
571
  this.html.set(`<${this.options.get('defaultLine')}><br></${this.options.get('defaultLine')}>`);
404
572
  this.focus();
@@ -423,7 +591,7 @@ Editor.prototype = {
423
591
  this.history.redo();
424
592
  break;
425
593
  case 'removeFormat':
426
- this.format.removeTextStyle();
594
+ this.format.removeInlineElement();
427
595
  this.focus();
428
596
  break;
429
597
  case 'print':
@@ -450,6 +618,15 @@ Editor.prototype = {
450
618
  case 'copyFormat':
451
619
  COPY_FORMAT(this, button);
452
620
  break;
621
+ case 'pageBreak':
622
+ PAGE_BREAK(this);
623
+ break;
624
+ case 'pageUp':
625
+ this.frameContext.get('documentType').pageUp();
626
+ break;
627
+ case 'pageDown':
628
+ this.frameContext.get('documentType').pageDown();
629
+ break;
453
630
  default:
454
631
  FONT_STYLE(this, command);
455
632
  }
@@ -457,36 +634,38 @@ Editor.prototype = {
457
634
 
458
635
  /**
459
636
  * @description Execute "editor.run" with command button.
460
- * @param {Element} target Command target
637
+ * @param {Node} target Command target
461
638
  */
462
639
  runFromTarget(target) {
463
- const isInput = domUtils.isInputElement(target);
464
- if (isInput || !(target = domUtils.getCommandTarget(target))) return;
640
+ if (dom.check.isInputElement(target)) return;
641
+
642
+ const targetBtn = /** @type {HTMLButtonElement} */ (dom.query.getCommandTarget(target));
643
+ if (!targetBtn) return;
465
644
 
466
- const command = target.getAttribute('data-command');
467
- const type = target.getAttribute('data-type');
645
+ const command = targetBtn.getAttribute('data-command');
646
+ const type = targetBtn.getAttribute('data-type');
468
647
 
469
648
  if (!command && !type) return;
470
- if (target.disabled) return;
649
+ if (targetBtn.disabled) return;
471
650
 
472
651
  this.run(command, type, target);
473
652
  },
474
653
 
475
654
  /**
476
655
  * @description It is executed by inserting the button of commandTargets as the argument value of the "f" function.
477
- * "f" is called as long as the button array's length.
656
+ * - "func" is called as long as the button array's length.
478
657
  * @param {string} cmd data-command
479
- * @param {Function} f Function.
658
+ * @param {(...args: *) => *} func Function.
480
659
  */
481
- applyCommandTargets(cmd, f) {
660
+ applyCommandTargets(cmd, func) {
482
661
  if (this.commandTargets.has(cmd)) {
483
- this.commandTargets.get(cmd).forEach(f);
662
+ this.commandTargets.get(cmd).forEach(func);
484
663
  }
485
664
  },
486
665
 
487
666
  /**
488
- * @description Executes a function by traversing all root targets.
489
- * @param {Function} f Function
667
+ * @description Execute a function by traversing all root targets.
668
+ * @param {(...args: *) => *} f Function
490
669
  */
491
670
  applyFrameRoots(f) {
492
671
  this.frameRoots.forEach(f);
@@ -494,14 +673,14 @@ Editor.prototype = {
494
673
 
495
674
  /**
496
675
  * @description Checks if the content of the editor is empty.
497
- * Display criteria for "placeholder".
498
- * @param {frameContext|null} fc Frame context, if not present, currently selected frame context.
676
+ * - Display criteria for "placeholder".
677
+ * @param {?__se__FrameContext=} fc Frame context, if not present, currently selected frame context.
499
678
  * @returns {boolean}
500
679
  */
501
680
  isEmpty(fc) {
502
681
  fc = fc || this.frameContext;
503
682
  const wysiwyg = fc.get('wysiwyg');
504
- return domUtils.isZeroWith(wysiwyg.textContent) && !wysiwyg.querySelector(env._allowedEmptyNodeList) && (wysiwyg.innerText.match(/\n/g) || '').length <= 1;
683
+ return dom.check.isZeroWidth(wysiwyg.textContent) && !wysiwyg.querySelector(this.options.get('allowedEmptyTags')) && (wysiwyg.innerText.match(/\n/g) || '').length <= 1;
505
684
  },
506
685
 
507
686
  /**
@@ -514,7 +693,7 @@ Editor.prototype = {
514
693
 
515
694
  try {
516
695
  this.options.set('_rtl', rtl);
517
- this._offCurrentController();
696
+ this.ui._offCurrentController();
518
697
 
519
698
  const fc = this.frameContext;
520
699
  const plugins = this.plugins;
@@ -526,18 +705,18 @@ Editor.prototype = {
526
705
  const statusbarWrapper = this.context.get('statusbar._wrapper');
527
706
  if (rtl) {
528
707
  this.applyFrameRoots((e) => {
529
- domUtils.addClass([e.get('topArea'), e.get('wysiwyg')], 'se-rtl');
708
+ dom.utils.addClass([e.get('topArea'), e.get('wysiwyg'), e.get('documentTypePageMirror')], 'se-rtl');
530
709
  });
531
- domUtils.addClass([this.carrierWrapper, toolbarWrapper, statusbarWrapper], 'se-rtl');
710
+ dom.utils.addClass([this.carrierWrapper, toolbarWrapper, statusbarWrapper], 'se-rtl');
532
711
  } else {
533
712
  this.applyFrameRoots((e) => {
534
- domUtils.removeClass([e.get('topArea'), e.get('wysiwyg')], 'se-rtl');
713
+ dom.utils.removeClass([e.get('topArea'), e.get('wysiwyg'), e.get('documentTypePageMirror')], 'se-rtl');
535
714
  });
536
- domUtils.removeClass([this.carrierWrapper, toolbarWrapper, statusbarWrapper], 'se-rtl');
715
+ dom.utils.removeClass([this.carrierWrapper, toolbarWrapper, statusbarWrapper], 'se-rtl');
537
716
  }
538
717
 
539
- const lineNodes = domUtils.getListChildren(fc.wysiwyg, (current) => {
540
- return this.format.isLine(current) && (current.style.marginRight || current.style.marginLeft || current.style.textAlign);
718
+ const lineNodes = dom.query.getListChildren(fc.get('wysiwyg'), (current) => {
719
+ return this.format.isLine(current) && !!(current.style.marginRight || current.style.marginLeft || current.style.textAlign);
541
720
  });
542
721
 
543
722
  for (let i = 0, n, l, r; (n = lineNodes[i]); i++) {
@@ -557,6 +736,16 @@ Editor.prototype = {
557
736
 
558
737
  DIR_BTN_ACTIVE(this, rtl);
559
738
 
739
+ // document type
740
+ if (fc.has('documentType-use-header')) {
741
+ if (rtl) fc.get('wrapper').appendChild(fc.get('documentTypeInner'));
742
+ else fc.get('wrapper').insertBefore(fc.get('documentTypeInner'), fc.get('wysiwygFrame'));
743
+ }
744
+ if (fc.has('documentType-use-page')) {
745
+ if (rtl) fc.get('wrapper').insertBefore(fc.get('documentTypePage'), fc.get('wysiwygFrame'));
746
+ else fc.get('wrapper').appendChild(fc.get('documentTypePage'));
747
+ }
748
+
560
749
  if (this.isBalloon) this.toolbar._showBalloon();
561
750
  else if (this.isSubBalloon) this.subToolbar._showBalloon();
562
751
  } catch (e) {
@@ -570,7 +759,7 @@ Editor.prototype = {
570
759
 
571
760
  /**
572
761
  * @description Add or reset option property (Editor is reloaded)
573
- * @param {Object} newOptions Options
762
+ * @param {EditorInitOptions_editor} newOptions Options
574
763
  */
575
764
  resetOptions(newOptions) {
576
765
  const _keys = Object.keys;
@@ -624,7 +813,7 @@ Editor.prototype = {
624
813
 
625
814
  // statusbar
626
815
  if (diff.has('statusbar')) {
627
- domUtils.removeItem(fc.get('statusbar'));
816
+ dom.utils.removeItem(fc.get('statusbar'));
628
817
  if (newRootOptions.get('statusbar')) {
629
818
  const statusbar = CreateStatusbar(newRootOptions, null).statusbar;
630
819
  fc.get('container').appendChild(statusbar);
@@ -659,7 +848,7 @@ Editor.prototype = {
659
848
  fc.set('options', newRootOptions);
660
849
 
661
850
  // frame styles
662
- this.setEditorStyle(newRootOptions.get('_defaultStyles'), fc);
851
+ this.ui.setEditorStyle(newRootOptions.get('_defaultStyles'), fc);
663
852
 
664
853
  // frame attributes
665
854
  const frame = fc.get('wysiwyg');
@@ -700,9 +889,14 @@ Editor.prototype = {
700
889
  }
701
890
  // shortcuts hint
702
891
  if (options.get('shortcutsHint')) {
703
- domUtils.removeClass(toolbar, 'se-shortcut-hide');
892
+ dom.utils.removeClass(toolbar, 'se-shortcut-hide');
704
893
  } else {
705
- domUtils.addClass(toolbar, 'se-shortcut-hide');
894
+ dom.utils.addClass(toolbar, 'se-shortcut-hide');
895
+ }
896
+
897
+ // theme
898
+ if (this._originOptions.theme !== (newOptions.theme ?? this._originOptions.theme)) {
899
+ this.ui.setTheme(newOptions.theme);
706
900
  }
707
901
 
708
902
  this.effectNode = null;
@@ -711,7 +905,7 @@ Editor.prototype = {
711
905
 
712
906
  /**
713
907
  * @description Change the current root index.
714
- * @param {number} rootKey
908
+ * @param {*} rootKey
715
909
  */
716
910
  changeFrameContext(rootKey) {
717
911
  if (rootKey === this.status.rootKey) return;
@@ -724,8 +918,8 @@ Editor.prototype = {
724
918
  /**
725
919
  * @description javascript execCommand
726
920
  * @param {string} command javascript execCommand function property
727
- * @param {Boolean|undefined} showDefaultUI javascript execCommand function property
728
- * @param {string|undefined} value javascript execCommand function property
921
+ * @param {boolean=} showDefaultUI javascript execCommand function property
922
+ * @param {string=} value javascript execCommand function property
729
923
  */
730
924
  execCommand(command, showDefaultUI, value) {
731
925
  this.frameContext.get('_wd').execCommand(command, showDefaultUI, command === 'formatBlock' ? '<' + value + '>' : value);
@@ -734,23 +928,23 @@ Editor.prototype = {
734
928
 
735
929
  /**
736
930
  * @description Focus to wysiwyg area
737
- * @param {number|undefined} rootKey Root index
931
+ * @param {*} rootKey Root index
738
932
  */
739
933
  focus(rootKey) {
740
934
  if (rootKey) this.changeFrameContext(rootKey);
741
935
  if (this.frameContext.get('wysiwygFrame').style.display === 'none') return;
742
- this._antiBlur = false;
936
+ this._preventBlur = false;
743
937
 
744
938
  if (this.frameOptions.get('iframe') || !this.frameContext.get('wysiwyg').contains(this.selection.getNode())) {
745
939
  this._nativeFocus();
746
940
  } else {
747
941
  try {
748
942
  const range = this.selection.getRange();
749
- if (range.startContainer === range.endContainer && domUtils.isWysiwygFrame(range.startContainer)) {
750
- const currentNode = range.commonAncestorContainer.children[range.startOffset];
943
+ if (range.startContainer === range.endContainer && dom.check.isWysiwygFrame(range.startContainer)) {
944
+ const currentNode = /** @type {HTMLElement} */ (range.commonAncestorContainer).children[range.startOffset];
751
945
  if (!this.format.isLine(currentNode) && !this.component.is(currentNode)) {
752
- const br = domUtils.createElement('BR');
753
- const format = domUtils.createElement(this.options.get('defaultLine'), null, br);
946
+ const br = dom.utils.createElement('BR');
947
+ const format = dom.utils.createElement(this.options.get('defaultLine'), null, br);
754
948
  this.frameContext.get('wysiwyg').insertBefore(format, currentNode);
755
949
  this.selection.setRange(br, 0, br, 0);
756
950
  return;
@@ -768,19 +962,19 @@ Editor.prototype = {
768
962
 
769
963
  /**
770
964
  * @description If "focusEl" is a component, then that component is selected; if it is a format element, the last text is selected
771
- * If "focusEdge" is null, then selected last element
772
- * @param {Element|null} focusEl Focus element
965
+ * - If "focusEdge" is null, then selected last element
966
+ * @param {?Node=} focusEl Focus element
773
967
  */
774
968
  focusEdge(focusEl) {
775
- this._antiBlur = false;
969
+ this._preventBlur = false;
776
970
  if (!focusEl) focusEl = this.frameContext.get('wysiwyg').lastElementChild;
777
971
 
778
972
  const fileComponentInfo = this.component.get(focusEl);
779
973
  if (fileComponentInfo) {
780
- this.component.select(fileComponentInfo.target, fileComponentInfo.pluginName, false);
974
+ this.component.select(fileComponentInfo.target, fileComponentInfo.pluginName);
781
975
  } else if (focusEl) {
782
976
  if (focusEl.nodeType !== 3) {
783
- focusEl = domUtils.getEdgeChild(
977
+ focusEl = dom.query.getEdgeChild(
784
978
  focusEl,
785
979
  function (current) {
786
980
  return current.childNodes.length === 0 || current.nodeType === 3;
@@ -806,163 +1000,6 @@ Editor.prototype = {
806
1000
  }
807
1001
  },
808
1002
 
809
- /**
810
- * @description Set "options.get('editorStyle')" style.
811
- * Define the style of the edit area
812
- * It can also be defined with the "setOptions" method, but the "setEditorStyle" method does not render the editor again.
813
- * @param {string} style Style string
814
- * @param {FrameContext|null} fc Frame context
815
- */
816
- setEditorStyle(style, fc) {
817
- fc = fc || this.frameContext;
818
- const fo = fc.get('options');
819
-
820
- const newStyles = converter._setDefaultOptionStyle(fo, style);
821
- fo.set('_defaultStyles', newStyles);
822
-
823
- // top area
824
- fc.get('topArea').style.cssText = newStyles.top;
825
-
826
- // code view
827
- const code = fc.get('code');
828
- code.style.cssText = fo.get('_defaultStyles').frame;
829
- code.style.display = 'none';
830
-
831
- // wysiwyg frame
832
- if (!fo.get('iframe')) {
833
- fc.get('wysiwygFrame').style.cssText = newStyles.frame + newStyles.editor;
834
- } else {
835
- fc.get('wysiwygFrame').style.cssText = newStyles.frame;
836
- fc.get('wysiwyg').style.cssText = newStyles.editor;
837
- }
838
- },
839
-
840
- /**
841
- * @description Switch to or off "ReadOnly" mode.
842
- * @param {boolean} value "readOnly" boolean value.
843
- * @param {string|undefined} rootKey Root key
844
- */
845
- readOnly(value, rootKey) {
846
- const fc = rootKey ? this.frameRoots.get(rootKey) : this.frameContext;
847
-
848
- fc.set('isReadOnly', !!value);
849
- domUtils.setDisabled(this._controllerOnDisabledButtons, !!value);
850
-
851
- if (value) {
852
- this._offCurrentController();
853
- this._offCurrentModal();
854
-
855
- if (this.toolbar?.currentMoreLayerActiveButton?.disabled) this.toolbar.moreLayerOff();
856
- if (this.subToolbar?.currentMoreLayerActiveButton?.disabled) this.subToolbar.moreLayerOff();
857
- if (this.menu?.currentDropdownActiveButton?.disabled) this.menu.dropdownOff();
858
- if (this.menu?.currentContainerActiveButton?.disabled) this.menu.containerOff();
859
- if (this.modalForm) this.plugins.modal.close.call(this);
860
-
861
- fc.get('code').setAttribute('readOnly', 'true');
862
- domUtils.addClass(fc.get('wysiwygFrame'), 'se-read-only');
863
- } else {
864
- fc.get('code').removeAttribute('readOnly');
865
- domUtils.removeClass(fc.get('wysiwygFrame'), 'se-read-only');
866
- }
867
-
868
- if (this.options.get('hasCodeMirror')) {
869
- this.viewer._codeMirrorEditor('readonly', !!value, rootKey);
870
- }
871
- },
872
-
873
- /**
874
- * @description Disable the suneditor
875
- * @param {string|undefined} rootKey Root key
876
- */
877
- disable(rootKey) {
878
- const fc = rootKey ? this.frameRoots.get(rootKey) : this.frameContext;
879
-
880
- this.toolbar.disable();
881
- this._offCurrentController();
882
- this._offCurrentModal();
883
-
884
- if (this.modalForm) this.plugins.modal.close.call(this);
885
-
886
- fc.get('wysiwyg').setAttribute('contenteditable', false);
887
- fc.set('isDisabled', true);
888
-
889
- if (this.options.get('hasCodeMirror')) {
890
- this.viewer._codeMirrorEditor('readonly', true, rootKey);
891
- } else {
892
- fc.get('code').setAttribute('disabled', true);
893
- }
894
- },
895
-
896
- /**
897
- * @description Enable the suneditor
898
- * @param {string|undefined} rootKey Root key
899
- */
900
- enable(rootKey) {
901
- const fc = rootKey ? this.frameRoots.get(rootKey) : this.frameContext;
902
-
903
- this.toolbar.enable();
904
- fc.get('wysiwyg').setAttribute('contenteditable', true);
905
- fc.set('isDisabled', false);
906
-
907
- if (this.options.get('hasCodeMirror')) {
908
- this.viewer._codeMirrorEditor('readonly', false, rootKey);
909
- } else {
910
- fc.get('code').removeAttribute('disabled');
911
- }
912
- },
913
-
914
- /**
915
- * @description Show the suneditor
916
- * @param {string|undefined} rootKey Root key
917
- */
918
- show(rootKey) {
919
- const fc = rootKey ? this.frameRoots.get(rootKey) : this.frameContext;
920
- const topAreaStyle = fc.get('topArea').style;
921
- if (topAreaStyle.display === 'none') topAreaStyle.display = 'block';
922
- },
923
-
924
- /**
925
- * @description Hide the suneditor
926
- * @param {string|undefined} rootKey Root key
927
- */
928
- hide(rootKey) {
929
- const fc = rootKey ? this.frameRoots.get(rootKey) : this.frameContext;
930
- fc.get('topArea').style.display = 'none';
931
- },
932
-
933
- /**
934
- * @description Show loading box
935
- * @param {string|undefined} rootKey Root key
936
- */
937
- showLoading(rootKey) {
938
- (rootKey ? this.frameRoots.get(rootKey).get('container') : this.carrierWrapper).querySelector('.se-loading-box').style.display = 'block';
939
- },
940
-
941
- /**
942
- * @description Hide loading box
943
- * @param {string|undefined} rootKey Root key
944
- */
945
- hideLoading(rootKey) {
946
- (rootKey ? this.frameRoots.get(rootKey).get('container') : this.carrierWrapper).querySelector('.se-loading-box').style.display = 'none';
947
- },
948
-
949
- /**
950
- * @description Activate the transparent background "div" so that other elements are not affected during resizing.
951
- * @param {cursor} cursor cursor css property
952
- */
953
- enableBackWrapper(cursor) {
954
- this._backWrapper.style.cursor = cursor;
955
- this._backWrapper.style.display = 'block';
956
- },
957
-
958
- /**
959
- * @description Disabled background "div"
960
- */
961
- disableBackWrapper() {
962
- this._backWrapper.style.display = 'none';
963
- this._backWrapper.style.cursor = 'default';
964
- },
965
-
966
1003
  /**
967
1004
  * @description Destroy the suneditor
968
1005
  */
@@ -979,12 +1016,12 @@ Editor.prototype = {
979
1016
  }
980
1017
 
981
1018
  /** remove element */
982
- domUtils.removeItem(this.carrierWrapper);
983
- domUtils.removeItem(this.context.get('toolbar._wrapper'));
984
- domUtils.removeItem(this.context.get('toolbar.sub._wrapper'));
985
- domUtils.removeItem(this.context.get('statusbar._wrapper'));
1019
+ dom.utils.removeItem(this.carrierWrapper);
1020
+ dom.utils.removeItem(this.context.get('toolbar._wrapper'));
1021
+ dom.utils.removeItem(this.context.get('toolbar.sub._wrapper'));
1022
+ dom.utils.removeItem(this.context.get('statusbar._wrapper'));
986
1023
  this.applyFrameRoots((e) => {
987
- domUtils.removeItem(e.get('topArea'));
1024
+ dom.utils.removeItem(e.get('topArea'));
988
1025
  e.get('options').clear();
989
1026
  e.clear();
990
1027
  });
@@ -1007,7 +1044,7 @@ Editor.prototype = {
1007
1044
  delete obj[k];
1008
1045
  }
1009
1046
 
1010
- obj = ['eventManager', 'char', 'component', 'format', 'html', 'menu', 'nodeTransform', 'notice', 'offset', 'selection', 'shortcuts', 'toolbar', 'viewer'];
1047
+ obj = ['eventManager', 'char', 'component', 'format', 'html', 'menu', 'nodeTransform', 'offset', 'selection', 'shortcuts', 'toolbar', 'ui', 'viewer'];
1011
1048
  for (let i = 0, len = obj.length, c; i < len; i++) {
1012
1049
  c = this[obj[i]];
1013
1050
  for (const k in c) {
@@ -1031,8 +1068,9 @@ Editor.prototype = {
1031
1068
 
1032
1069
  /** ----- private methods ----------------------------------------------------------------------------------------------------------------------------- */
1033
1070
  /**
1071
+ * @private
1034
1072
  * @description Set frameContext, frameOptions
1035
- * @param {rootTarget} rt Root target
1073
+ * @param {__se__FrameContext} rt Root target[key] FrameContext
1036
1074
  */
1037
1075
  _setFrameInfo(rt) {
1038
1076
  this.frameContext = rt;
@@ -1043,68 +1081,8 @@ Editor.prototype = {
1043
1081
  },
1044
1082
 
1045
1083
  /**
1046
- * @description visible controllers
1047
- * @param {boolean} value hidden/show
1048
- * @param {boolean?} lineBreakShow Line break hidden/show (default: Follows the value "value".)
1049
1084
  * @private
1050
- */
1051
- _visibleControllers(value, lineBreakShow) {
1052
- const visible = value ? '' : 'hidden';
1053
- const breakerVisible = lineBreakShow ?? visible ? '' : 'hidden';
1054
-
1055
- const cont = this.opendControllers;
1056
- for (let i = 0, c; i < cont.length; i++) {
1057
- c = cont[i];
1058
- if (c.form) c.form.style.visibility = visible;
1059
- }
1060
-
1061
- this._lineBreaker_t.style.visibility = breakerVisible;
1062
- this._lineBreaker_b.style.visibility = breakerVisible;
1063
- },
1064
-
1065
- /**
1066
- * @description Off current controllers
1067
- * @private
1068
- */
1069
- _offCurrentController() {
1070
- this.__offControllers();
1071
- this.component.__deselect();
1072
- },
1073
-
1074
- /**
1075
- * @description Off controllers
1076
- * @private
1077
- */
1078
- __offControllers() {
1079
- const cont = this.opendControllers;
1080
- const fixedCont = [];
1081
- for (let i = 0, c; i < cont.length; i++) {
1082
- c = cont[i];
1083
- if (c.fixed) {
1084
- fixedCont.push(c);
1085
- continue;
1086
- }
1087
- if (typeof c.inst.close === 'function') c.inst.close();
1088
- if (c.form) c.form.style.display = 'none';
1089
- }
1090
- this.opendControllers = fixedCont;
1091
- this.currentControllerName = '';
1092
- this._antiBlur = false;
1093
- },
1094
-
1095
- /**
1096
- * @description Off current modal
1097
- * @private
1098
- */
1099
- _offCurrentModal() {
1100
- if (this.opendModal) {
1101
- this.opendModal.close();
1102
- }
1103
- },
1104
-
1105
- /**
1106
1085
  * @description Focus to wysiwyg area using "native focus function"
1107
- * @private
1108
1086
  */
1109
1087
  _nativeFocus() {
1110
1088
  this.selection.__focus();
@@ -1112,8 +1090,9 @@ Editor.prototype = {
1112
1090
  },
1113
1091
 
1114
1092
  /**
1115
- * @description Check the components such as image and video and modify them according to the format.
1116
1093
  * @private
1094
+ * @description Check the components such as image and video and modify them according to the format.
1095
+ * @param {boolean} loaded If true, the component is loaded.
1117
1096
  */
1118
1097
  _checkComponents(loaded) {
1119
1098
  for (let i = 0, len = this._fileInfoPluginsCheck.length; i < len; i++) {
@@ -1122,8 +1101,8 @@ Editor.prototype = {
1122
1101
  },
1123
1102
 
1124
1103
  /**
1125
- * @description Initialize the information of the components.
1126
1104
  * @private
1105
+ * @description Initialize the information of the components.
1127
1106
  */
1128
1107
  _resetComponents() {
1129
1108
  for (let i = 0, len = this._fileInfoPluginsReset.length; i < len; i++) {
@@ -1132,31 +1111,54 @@ Editor.prototype = {
1132
1111
  },
1133
1112
 
1134
1113
  /**
1114
+ * @private
1135
1115
  * @description Initializ wysiwyg area (Only called from core._init)
1136
- * @param {Map} e frameContext
1116
+ * @param {__se__FrameContext} e frameContext
1137
1117
  * @param {string} value initial html string
1138
- * @private
1139
1118
  */
1140
1119
  _initWysiwygArea(e, value) {
1120
+ // set content
1141
1121
  e.get('wysiwyg').innerHTML =
1142
- 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) ||
1143
- '<' + this.options.get('defaultLine') + '><br></' + this.options.get('defaultLine') + '>';
1144
-
1122
+ this.html.clean(typeof value === 'string' ? value : (/^TEXTAREA$/i.test(e.get('originElement').nodeName) ? e.get('originElement').value : e.get('originElement').innerHTML) || '', {
1123
+ forceFormat: true,
1124
+ whitelist: null,
1125
+ blacklist: null,
1126
+ _freeCodeViewMode: this.options.get('freeCodeViewMode')
1127
+ }) || '<' + this.options.get('defaultLine') + '><br></' + this.options.get('defaultLine') + '>';
1128
+
1129
+ // char counter
1145
1130
  if (e.has('charCounter')) e.get('charCounter').textContent = this.char.getLength();
1131
+
1132
+ // document type init
1133
+ if (this.options.get('type') === 'document') {
1134
+ e.set('documentType', new DocumentType(this, e));
1135
+ if (e.get('documentType').useHeader) {
1136
+ e.set('documentType-use-header', true);
1137
+ }
1138
+ if (e.get('documentType').usePage) {
1139
+ e.set('documentType-use-page', true);
1140
+ e.get('documentTypePageMirror').innerHTML = e.get('wysiwyg').innerHTML;
1141
+ }
1142
+ }
1146
1143
  },
1147
1144
 
1148
1145
  /**
1149
- * @description Called when there are changes to tags in the wysiwyg region.
1150
1146
  * @private
1147
+ * @description Called when there are changes to tags in the wysiwyg region.
1148
+ * @param {__se__FrameContext} fc - Frame context object
1151
1149
  */
1152
1150
  _resourcesStateChange(fc) {
1153
1151
  this._iframeAutoHeight(fc);
1154
1152
  this._checkPlaceholder(fc);
1153
+ if (this.options.get('type') === 'document' && fc.get('documentType').usePage) {
1154
+ fc.get('documentTypePageMirror').innerHTML = fc.get('wysiwyg').innerHTML;
1155
+ }
1155
1156
  },
1156
1157
 
1157
1158
  /**
1158
- * @description Modify the height value of the iframe when the height of the iframe is automatic.
1159
1159
  * @private
1160
+ * @description Modify the height value of the iframe when the height of the iframe is automatic.
1161
+ * @param {__se__FrameContext} fc - Frame context object
1160
1162
  */
1161
1163
  _iframeAutoHeight(fc) {
1162
1164
  const autoFrame = fc.get('_iframeAuto');
@@ -1172,6 +1174,13 @@ Editor.prototype = {
1172
1174
  }
1173
1175
  },
1174
1176
 
1177
+ /**
1178
+ * @private
1179
+ * @description Call the "onResizeEditor" event
1180
+ * @param {__se__FrameContext} fc - Frame context object
1181
+ * @param {number} h - Height value
1182
+ * @param {ResizeObserverEntry} resizeObserverEntry - ResizeObserverEntry object
1183
+ */
1175
1184
  __callResizeFunction(fc, h, resizeObserverEntry) {
1176
1185
  h =
1177
1186
  h === -1
@@ -1183,11 +1192,17 @@ Editor.prototype = {
1183
1192
  this.triggerEvent('onResizeEditor', { height: h, prevHeight: fc.get('_editorHeight'), frameContext: fc, observerEntry: resizeObserverEntry });
1184
1193
  fc.set('_editorHeight', h);
1185
1194
  }
1195
+
1196
+ // document type page
1197
+ if (fc.has('documentType-use-page')) {
1198
+ fc.get('documentType').resizePage();
1199
+ }
1186
1200
  },
1187
1201
 
1188
1202
  /**
1189
- * @description Set display property when there is placeholder.
1190
1203
  * @private
1204
+ * @description Set display property when there is placeholder.
1205
+ * @param {?__se__FrameContext=} fc - Frame context object, If null fc is this.frameContext
1191
1206
  */
1192
1207
  _checkPlaceholder(fc) {
1193
1208
  fc = fc || this.frameContext;
@@ -1208,8 +1223,9 @@ Editor.prototype = {
1208
1223
  },
1209
1224
 
1210
1225
  /**
1211
- * @description Initializ editor
1212
1226
  * @private
1227
+ * @description Initializ editor
1228
+ * @param {EditorInitOptions_editor} options Options
1213
1229
  */
1214
1230
  __editorInit(options) {
1215
1231
  this.applyFrameRoots((e) => {
@@ -1253,8 +1269,9 @@ Editor.prototype = {
1253
1269
  },
1254
1270
 
1255
1271
  /**
1256
- * @description Initializ core variable
1257
1272
  * @private
1273
+ * @description Initializ core variable
1274
+ * @param {EditorInitOptions_editor} options Options
1258
1275
  */
1259
1276
  __init(options) {
1260
1277
  // file components
@@ -1278,20 +1295,19 @@ Editor.prototype = {
1278
1295
  ['onKeyUp', []],
1279
1296
  ['onFocus', []],
1280
1297
  ['onBlur', []],
1281
- ['onPastAndDrop', []]
1298
+ ['onPaste', []],
1299
+ ['onFilePasteAndDrop', []]
1282
1300
  ]);
1283
1301
  this._fileManager.tags = [];
1284
1302
  this._fileManager.pluginMap = {};
1285
1303
  this._fileManager.tagAttrs = {};
1286
1304
 
1287
1305
  const plugins = this.plugins;
1288
- const isArray = Array.isArray;
1289
- const shortcuts = this.options.get('shortcuts');
1290
1306
  const filePluginRegExp = [];
1291
1307
  let plugin;
1292
1308
  for (const key in plugins) {
1293
- this.registerPlugin(key, this._pluginCallButtons[key], options[key], shortcuts[key]);
1294
- this.registerPlugin(key, this._pluginCallButtons_sub[key], options[key], shortcuts[key]);
1309
+ this.registerPlugin(key, this._pluginCallButtons[key], options[key]);
1310
+ this.registerPlugin(key, this._pluginCallButtons_sub[key], options[key]);
1295
1311
  plugin = this.plugins[key];
1296
1312
 
1297
1313
  // Filemanager
@@ -1299,7 +1315,7 @@ Editor.prototype = {
1299
1315
  const fm = plugin.__fileManagement;
1300
1316
  this._fileInfoPluginsCheck.push(fm._checkInfo.bind(fm));
1301
1317
  this._fileInfoPluginsReset.push(fm._resetInfo.bind(fm));
1302
- if (isArray(fm.tagNames)) {
1318
+ if (Array.isArray(fm.tagNames)) {
1303
1319
  const tagNames = fm.tagNames;
1304
1320
  this._fileManager.tags = this._fileManager.tags.concat(tagNames);
1305
1321
  filePluginRegExp.push(key);
@@ -1317,7 +1333,7 @@ Editor.prototype = {
1317
1333
  if (typeof plugin.constructor.component === 'function') {
1318
1334
  this._componentManager.push(
1319
1335
  function (launcher, element) {
1320
- if (!(element = launcher.component?.call(this, element))) return null;
1336
+ if (!element || !(element = launcher.component?.call(this, element))) return null;
1321
1337
  return {
1322
1338
  target: element,
1323
1339
  pluginName: launcher.key,
@@ -1344,6 +1360,24 @@ Editor.prototype = {
1344
1360
  }
1345
1361
  }
1346
1362
 
1363
+ if (this.options.get('buttons').has('pageBreak') || this.options.get('buttons_sub')?.has('pageBreak')) {
1364
+ this._componentManager.push((element) => {
1365
+ if (!element || !dom.utils.hasClass(element, 'se-page-break')) return null;
1366
+ return {
1367
+ target: element,
1368
+ launcher: {
1369
+ destroy: (target) => {
1370
+ const focusEl = target.previousElementSibling || target.nextElementSibling;
1371
+ dom.utils.removeItem(target);
1372
+ // focus
1373
+ this.focusEdge(focusEl);
1374
+ this.history.push(false);
1375
+ }
1376
+ }
1377
+ };
1378
+ });
1379
+ }
1380
+
1347
1381
  this._fileManager.regExp = new RegExp(`^(${this._fileManager.tags.join('|') || '\\^'})$`, 'i');
1348
1382
  this._fileManager.pluginRegExp = new RegExp(`^(${filePluginRegExp.length === 0 ? '\\^' : filePluginRegExp.join('|')})$`, 'i');
1349
1383
 
@@ -1351,11 +1385,12 @@ Editor.prototype = {
1351
1385
  delete this._pluginCallButtons_sub;
1352
1386
 
1353
1387
  this.__cachingButtons();
1388
+ this.__cachingShortcuts();
1354
1389
  },
1355
1390
 
1356
1391
  /**
1357
- * @description Caching basic buttons to use
1358
1392
  * @private
1393
+ * @description Caching basic buttons to use
1359
1394
  */
1360
1395
  __cachingButtons() {
1361
1396
  const ctx = this.context;
@@ -1366,6 +1401,11 @@ Editor.prototype = {
1366
1401
  }
1367
1402
  },
1368
1403
 
1404
+ /**
1405
+ * @private
1406
+ * @description Set the disabled button list
1407
+ * - this._codeViewDisabledButtons, this._controllerOnDisabledButtons
1408
+ */
1369
1409
  __setDisabledButtons() {
1370
1410
  const ctx = this.context;
1371
1411
 
@@ -1379,8 +1419,10 @@ Editor.prototype = {
1379
1419
  },
1380
1420
 
1381
1421
  /**
1382
- * @description Save the current buttons
1383
1422
  * @private
1423
+ * @description Save the current buttons
1424
+ * @param {Map<string, Element>} cmdButtons Command button map
1425
+ * @param {Element} tray Button tray
1384
1426
  */
1385
1427
  __saveCommandButtons(cmdButtons, tray) {
1386
1428
  const currentButtons = tray.querySelectorAll(COMMAND_BUTTONS);
@@ -1390,7 +1432,7 @@ Editor.prototype = {
1390
1432
  const reverseKeys = this.reverseKeys;
1391
1433
 
1392
1434
  for (let i = 0, len = currentButtons.length, e, c; i < len; i++) {
1393
- e = currentButtons[i];
1435
+ e = /** @type {HTMLButtonElement} */ (currentButtons[i]);
1394
1436
  c = e.getAttribute('data-command');
1395
1437
  // command set
1396
1438
  cmdButtons.set(c, e);
@@ -1400,6 +1442,27 @@ Editor.prototype = {
1400
1442
  }
1401
1443
  },
1402
1444
 
1445
+ /**
1446
+ * @private
1447
+ * @description Caches shortcut keys for commands.
1448
+ */
1449
+ __cachingShortcuts() {
1450
+ const shortcuts = this.options.get('shortcuts');
1451
+ const reverseCommandArray = this.options.get('_reverseCommandArray');
1452
+ const keyMap = this.shortcutsKeyMap;
1453
+ const reverseKeys = this.reverseKeys;
1454
+ for (const key of Object.keys(shortcuts)) {
1455
+ if (!key.startsWith('_')) continue;
1456
+ CreateShortcuts('', null, shortcuts[key], keyMap, reverseCommandArray, reverseKeys);
1457
+ }
1458
+ },
1459
+
1460
+ /**
1461
+ * @private
1462
+ * @description Sets command target elements.
1463
+ * @param {string} cmd - The command identifier.
1464
+ * @param {HTMLButtonElement} target - The associated command button.
1465
+ */
1403
1466
  __setCommandTargets(cmd, target) {
1404
1467
  if (!cmd || !target) return;
1405
1468
 
@@ -1413,6 +1476,13 @@ Editor.prototype = {
1413
1476
  }
1414
1477
  },
1415
1478
 
1479
+ /**
1480
+ * @private
1481
+ * @description Configures the document properties of an iframe editor.
1482
+ * @param {HTMLIFrameElement} frame - The editor iframe.
1483
+ * @param {Map<string, *>} originOptions - The original options.
1484
+ * @param {__se__FrameOptions} targetOptions - The new options.
1485
+ */
1416
1486
  __setIframeDocument(frame, originOptions, targetOptions) {
1417
1487
  frame.setAttribute('scrolling', 'auto');
1418
1488
  frame.contentDocument.head.innerHTML =
@@ -1420,9 +1490,14 @@ Editor.prototype = {
1420
1490
  converter._setIframeStyleLinks(targetOptions.get('iframe_cssFileName')) +
1421
1491
  converter._setAutoHeightStyle(targetOptions.get('height'));
1422
1492
  frame.contentDocument.body.className = originOptions.get('_editableClass');
1423
- frame.contentDocument.body.setAttribute('contenteditable', true);
1493
+ frame.contentDocument.body.setAttribute('contenteditable', 'true');
1424
1494
  },
1425
1495
 
1496
+ /**
1497
+ * @private
1498
+ * @description Set the FrameContext parameters and options
1499
+ * @param {__se__FrameContext} e - Frame context object
1500
+ */
1426
1501
  __setEditorParams(e) {
1427
1502
  const frameOptions = e.get('options');
1428
1503
  const _w = this._w;
@@ -1463,10 +1538,16 @@ Editor.prototype = {
1463
1538
  }
1464
1539
  },
1465
1540
 
1541
+ /**
1542
+ * @private
1543
+ * @description Registers and initializes editor classes.
1544
+ */
1466
1545
  __registerClass() {
1467
1546
  // use events
1468
- this.events = { ...Events(), ...this.options.get('events') };
1547
+ this.events = { ...Events, ...this.options.get('events') };
1469
1548
  this.triggerEvent = async (eventName, eventData) => {
1549
+ // [iframe] wysiwyg is disabled, the event is not called.
1550
+ if (eventData?.frameContext?.get('wysiwyg').getAttribute('contenteditable') === 'false') return false;
1470
1551
  const eventHandler = this.events[eventName];
1471
1552
  if (typeof eventHandler === 'function') {
1472
1553
  return await eventHandler({ editor: this, ...eventData });
@@ -1483,10 +1564,9 @@ Editor.prototype = {
1483
1564
  // util classes
1484
1565
  this.offset = new Offset(this);
1485
1566
  this.shortcuts = new Shortcuts(this);
1486
- this.notice = new Notice(this);
1487
1567
  // main classes
1488
1568
  this.toolbar = new Toolbar(this, { keyName: 'toolbar', balloon: this.isBalloon, balloonAlways: this.isBalloonAlways, inline: this.isInline, res: this._responsiveButtons });
1489
- if (this.options.has('_subMode'))
1569
+ if (this.options.has('_subMode')) {
1490
1570
  this.subToolbar = new Toolbar(this, {
1491
1571
  keyName: 'toolbar.sub',
1492
1572
  balloon: this.isSubBalloon,
@@ -1494,13 +1574,15 @@ Editor.prototype = {
1494
1574
  inline: false,
1495
1575
  res: this._responsiveButtons_sub
1496
1576
  });
1497
- this.selection = new Selection(this);
1577
+ }
1578
+ this.selection = new Selection_(this);
1498
1579
  this.html = new HTML(this);
1499
1580
  this.nodeTransform = new NodeTransform(this);
1500
1581
  this.component = new Component(this);
1501
1582
  this.format = new Format(this);
1502
1583
  this.menu = new Menu(this);
1503
1584
  this.char = new Char(this);
1585
+ this.ui = new UI(this);
1504
1586
  this.viewer = new Viewer(this);
1505
1587
 
1506
1588
  // register classes to the eventManager
@@ -1512,26 +1594,39 @@ Editor.prototype = {
1512
1594
  ClassInjector.call(this.html, this);
1513
1595
  ClassInjector.call(this.menu, this);
1514
1596
  ClassInjector.call(this.nodeTransform, this);
1597
+ ClassInjector.call(this.offset, this);
1515
1598
  ClassInjector.call(this.selection, this);
1599
+ ClassInjector.call(this.shortcuts, this);
1516
1600
  ClassInjector.call(this.toolbar, this);
1601
+ ClassInjector.call(this.ui, this);
1517
1602
  ClassInjector.call(this.viewer, this);
1518
1603
  if (this.options.has('_subMode')) ClassInjector.call(this.subToolbar, this);
1519
1604
 
1520
1605
  // delete self reference
1521
- delete this.char.char;
1522
- delete this.component.component;
1523
- delete this.format.format;
1524
- delete this.html.html;
1525
- delete this.menu.menu;
1526
- delete this.nodeTransform.nodeTransform;
1527
- delete this.selection.selection;
1528
- delete this.toolbar.toolbar;
1529
- delete this.viewer.viewer;
1530
- if (this.subToolbar) delete this.subToolbar.subToolbar;
1531
-
1532
- this._responsiveButtons = this._responsiveButtons_res = null;
1606
+ delete this.eventManager['eventManager'];
1607
+ delete this.char['char'];
1608
+ delete this.component['component'];
1609
+ delete this.format['format'];
1610
+ delete this.html['html'];
1611
+ delete this.menu['menu'];
1612
+ delete this.nodeTransform['nodeTransform'];
1613
+ delete this.offset['offset'];
1614
+ delete this.selection['selection'];
1615
+ delete this.shortcuts['shortcuts'];
1616
+ delete this.toolbar['toolbar'];
1617
+ delete this.ui['ui'];
1618
+ delete this.viewer['viewer'];
1619
+ if (this.subToolbar) delete this.subToolbar['subToolbar'];
1620
+
1621
+ this._responsiveButtons = this._responsiveButtons_sub = null;
1533
1622
  },
1534
1623
 
1624
+ /**
1625
+ * @private
1626
+ * @description Creates the editor instance and initializes components.
1627
+ * @param {EditorInitOptions_editor} originOptions - The initial editor options.
1628
+ * @returns {Promise<void>}
1629
+ */
1535
1630
  async __Create(originOptions) {
1536
1631
  // set modes
1537
1632
  this.isInline = /inline/i.test(this.options.get('mode'));
@@ -1570,6 +1665,18 @@ Editor.prototype = {
1570
1665
 
1571
1666
  this.applyFrameRoots((e) => {
1572
1667
  e.get('wrapper').appendChild(e.get('wysiwygFrame'));
1668
+
1669
+ // document type
1670
+ if (e.get('documentTypeInner')) {
1671
+ if (this.options.get('_rtl')) e.get('wrapper').appendChild(e.get('documentTypeInner'));
1672
+ else e.get('wrapper').insertBefore(e.get('documentTypeInner'), e.get('wysiwygFrame'));
1673
+ }
1674
+ if (e.get('documentTypePage')) {
1675
+ if (this.options.get('_rtl')) e.get('wrapper').insertBefore(e.get('documentTypePage'), e.get('wysiwygFrame'));
1676
+ else e.get('wrapper').appendChild(e.get('documentTypePage'));
1677
+ // page mirror
1678
+ e.get('wrapper').appendChild(e.get('documentTypePageMirror'));
1679
+ }
1573
1680
  });
1574
1681
 
1575
1682
  if (iframePromises.length > 0) {
@@ -1590,7 +1697,7 @@ function GetResetDiffKey(key) {
1590
1697
  function CheckResetKeys(keys, plugins, root) {
1591
1698
  for (let i = 0, len = keys.length, k; i < len; i++) {
1592
1699
  k = keys[i];
1593
- if (RO_UNAVAILABD.includes(k) || (plugins && plugins[k])) {
1700
+ if (OPTION_FIXED_FLAG[k] === 'fixed' || (plugins && plugins[k])) {
1594
1701
  console.warn(`[SUNEDITOR.warn.resetOptions] "[${root + k}]" options not available in resetOptions have no effect.`);
1595
1702
  keys.splice(i--, 1);
1596
1703
  len--;