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
@@ -3,7 +3,7 @@
3
3
  */
4
4
 
5
5
  import CoreInjector from '../../editorInjector/_core';
6
- import { domUtils, unicode, numbers, env, converter } from '../../helper';
6
+ import { dom, unicode, numbers, env, converter } from '../../helper';
7
7
  import { _DragHandle } from '../../modules';
8
8
 
9
9
  // event handlers
@@ -11,81 +11,122 @@ import { ButtonsHandler, OnClick_menuTray, OnClick_toolbar } from './eventHandle
11
11
  import { OnMouseDown_wysiwyg, OnMouseUp_wysiwyg, OnClick_wysiwyg, OnMouseMove_wysiwyg, OnMouseLeave_wysiwyg } from './eventHandlers/handler_ww_mouse';
12
12
  import { OnInput_wysiwyg, OnKeyDown_wysiwyg, OnKeyUp_wysiwyg } from './eventHandlers/handler_ww_key_input';
13
13
  import { OnPaste_wysiwyg, OnCopy_wysiwyg, OnCut_wysiwyg } from './eventHandlers/handler_ww_clipboard';
14
- import { OnDragOver_wysiwyg, OnDrop_wysiwyg } from './eventHandlers/handler_ww_dragDrop';
14
+ import { OnDragOver_wysiwyg, OnDragEnd_wysiwyg, OnDrop_wysiwyg } from './eventHandlers/handler_ww_dragDrop';
15
15
 
16
16
  const { _w, ON_OVER_COMPONENT, isMobile } = env;
17
17
 
18
- const EventManager = function (editor) {
18
+ /**
19
+ * @typedef {Omit<EventManager & Partial<__se__EditorInjector>, 'eventManager'>} EventManagerThis
20
+ */
21
+
22
+ /**
23
+ * @constructor
24
+ * @this {EventManagerThis}
25
+ * @description Event manager, editor's all event management class
26
+ * @param {__se__EditorCore} editor - The root editor instance
27
+ * @property {__se__EditorCore} editor - The root editor instance
28
+ */
29
+ function EventManager(editor) {
19
30
  CoreInjector.call(this, editor);
31
+
32
+ /**
33
+ * @description Old browsers: When there is no 'e.isComposing' in the keyup event
34
+ * @type {boolean}
35
+ */
36
+ this.isComposing = false;
37
+
38
+ /** @type {Array<*>} */
20
39
  this._events = [];
40
+ /** @type {RegExp} */
21
41
  this._onButtonsCheck = new RegExp(`^(${Object.keys(editor.options.get('_defaultStyleTagMap')).join('|')})$`, 'i');
42
+ /** @type {boolean} */
22
43
  this._onShortcutKey = false;
23
- this.isComposing = false; // Old browsers: When there is no 'e.isComposing' in the keyup event.
44
+ /** @type {number} */
24
45
  this._balloonDelay = null;
46
+ /** @type {ResizeObserver} */
25
47
  this._wwFrameObserver = null;
48
+ /** @type {ResizeObserver} */
26
49
  this._toolbarObserver = null;
27
- this._lineBreakDir = null;
50
+ /** @type {Element|null} */
28
51
  this._lineBreakComp = null;
52
+ /** @type {Object<string, *>|null} */
29
53
  this._formatAttrsTemp = null;
54
+ /** @type {number} */
30
55
  this._resizeClientY = 0;
56
+ /** @type {__se__GlobalEventInfo|null} */
31
57
  this.__resize_editor = null;
58
+ /** @type {__se__GlobalEventInfo|null} */
32
59
  this.__close_move = null;
60
+ /** @type {__se__GlobalEventInfo|null} */
33
61
  this.__geckoActiveEvent = null;
62
+ /** @type {Array<Element>} */
34
63
  this.__scrollparents = [];
64
+ /** @type {Array<Node>} */
35
65
  this.__cacheStyleNodes = [];
66
+ /** @type {__se__GlobalEventInfo|null} */
36
67
  this.__selectionSyncEvent = null;
68
+
37
69
  // input plugins
70
+ /** @type {boolean} */
38
71
  this._inputFocus = false;
72
+ /** @type {Object<string, *>|null} */
39
73
  this.__inputPlugin = null;
74
+ /** @type {?__se__EventInfo=} */
40
75
  this.__inputBlurEvent = null;
76
+ /** @type {?__se__EventInfo=} */
41
77
  this.__inputKeyEvent = null;
78
+
42
79
  // viewport
43
- this._vitualKeyboardHeight = 0;
80
+ /** @type {HTMLInputElement} */
44
81
  this.__focusTemp = this.carrierWrapper.querySelector('.__se__focus__temp__');
82
+ /** @type {number|void} */
45
83
  this.__retainTimer = null;
84
+ /** @type {Element} */
46
85
  this.__eventDoc = null;
47
- // this.__scrollID = '';
48
- };
86
+ /** @type {string} */
87
+ this.__secopy = null;
88
+ }
49
89
 
50
90
  EventManager.prototype = {
51
91
  /**
92
+ * @this {EventManagerThis}
52
93
  * @description Register for an event.
53
- * Only events registered with this method are unregistered or re-registered when methods such as 'setOptions', 'destroy' are called.
54
- * @param {Element|Array.<Element>} target Target element
94
+ * - Only events registered with this method are unregistered or re-registered when methods such as 'setOptions', 'destroy' are called.
95
+ * @param {*} target Target element
55
96
  * @param {string} type Event type
56
- * @param {Function} listener Event handler
57
- * @param {boolean|undefined} useCapture Event useCapture option
58
- * @return {boolean}
97
+ * @param {(...args: *) => *} listener Event handler
98
+ * @param {boolean|AddEventListenerOptions=} useCapture Event useCapture option
99
+ * @return {__se__EventInfo|null} Registered event information
59
100
  */
60
101
  addEvent(target, type, listener, useCapture) {
61
- if (!target) return false;
102
+ if (!target) return null;
62
103
  if (!numbers.is(target.length) || target.nodeName || (!Array.isArray(target) && target.length < 1)) target = [target];
63
- if (target.length === 0) return false;
104
+ if (target.length === 0) return null;
64
105
 
65
106
  const len = target.length;
66
107
  for (let i = 0; i < len; i++) {
67
108
  target[i].addEventListener(type, listener, useCapture);
68
109
  this._events.push({
69
110
  target: target[i],
70
- type: type,
71
- handler: listener,
72
- useCapture: useCapture
111
+ type,
112
+ listener,
113
+ useCapture
73
114
  });
74
115
  }
75
116
 
76
117
  return {
77
118
  target: len > 1 ? target : target[0],
78
- type: type,
119
+ type,
79
120
  listener,
80
- handler: listener,
81
- useCapture: useCapture
121
+ useCapture
82
122
  };
83
123
  },
84
124
 
85
125
  /**
126
+ * @this {EventManagerThis}
86
127
  * @description Remove event
87
- * @param {object} params { target, type, listener, useCapture } = this.addEvent()
88
- * @returns {null}
128
+ * @param {__se__EventInfo} params event info = this.addEvent()
129
+ * @returns {undefined|null} Success: null, Not found: undefined
89
130
  */
90
131
  removeEvent(params) {
91
132
  if (!params) return;
@@ -95,9 +136,9 @@ EventManager.prototype = {
95
136
  const listener = params.listener;
96
137
  const useCapture = params.useCapture;
97
138
 
98
- if (!target) return false;
99
- if (!numbers.is(target.length) || target.nodeName || (!Array.isArray(target) && target.length < 1)) target = [target];
100
- if (target.length === 0) return false;
139
+ if (!target) return;
140
+ if (!numbers.is(target.length) || target.nodeName || (!Array.isArray(target) && target.length < 1)) target = /** @type {Array<Element>} */ ([target]);
141
+ if (target.length === 0) return;
101
142
 
102
143
  for (let i = 0, len = target.length; i < len; i++) {
103
144
  target[i].removeEventListener(type, listener, useCapture);
@@ -107,12 +148,13 @@ EventManager.prototype = {
107
148
  },
108
149
 
109
150
  /**
151
+ * @this {EventManagerThis}
110
152
  * @description Add an event to document.
111
- * When created as an Iframe, the same event is added to the document in the Iframe.
153
+ * - When created as an Iframe, the same event is added to the document in the Iframe.
112
154
  * @param {string} type Event type
113
- * @param {Function} listener Event listener
114
- * @param {boolean|undefined} useCapture Use event capture
115
- * @return {type, listener, useCapture}
155
+ * @param {(...args: *) => *} listener Event listener
156
+ * @param {boolean|AddEventListenerOptions=} useCapture Use event capture
157
+ * @return {__se__GlobalEventInfo} Registered event information
116
158
  */
117
159
  addGlobalEvent(type, listener, useCapture) {
118
160
  if (this.editor.frameOptions.get('iframe')) {
@@ -120,18 +162,20 @@ EventManager.prototype = {
120
162
  }
121
163
  this._w.addEventListener(type, listener, useCapture);
122
164
  return {
123
- type: type,
124
- listener: listener,
125
- useCapture: useCapture
165
+ type,
166
+ listener,
167
+ useCapture
126
168
  };
127
169
  },
128
170
 
129
171
  /**
172
+ * @this {EventManagerThis}
130
173
  * @description Remove events from document.
131
- * When created as an Iframe, the event of the document inside the Iframe is also removed.
132
- * @param {string|object} type Event type
133
- * @param {Function} listener Event listener
134
- * @param {boolean|undefined} useCapture Use event capture
174
+ * - When created as an Iframe, the event of the document inside the Iframe is also removed.
175
+ * @param {string|__se__GlobalEventInfo} type Event type or (Event info = this.addGlobalEvent())
176
+ * @param {(...args: *) => *=} listener Event listener
177
+ * @param {boolean|AddEventListenerOptions=} useCapture Use event capture
178
+ * @returns {undefined|null} Success: null, Not found: undefined
135
179
  */
136
180
  removeGlobalEvent(type, listener, useCapture) {
137
181
  if (!type) return;
@@ -145,12 +189,15 @@ EventManager.prototype = {
145
189
  this.editor.frameContext.get('_ww').removeEventListener(type, listener, useCapture);
146
190
  }
147
191
  this._w.removeEventListener(type, listener, useCapture);
192
+
193
+ return null;
148
194
  },
149
195
 
150
196
  /**
197
+ * @this {EventManagerThis}
151
198
  * @description Activates the corresponding button with the tags information of the current cursor position,
152
- * such as 'bold', 'underline', etc., and executes the 'active' method of the plugins.
153
- * @param {Node|null} selectionNode selectionNode
199
+ * - such as 'bold', 'underline', etc., and executes the 'active' method of the plugins.
200
+ * @param {?Node=} selectionNode selectionNode
154
201
  * @returns {Node|undefined} selectionNode
155
202
  */
156
203
  applyTagEffect(selectionNode) {
@@ -173,21 +220,22 @@ EventManager.prototype = {
173
220
  const cLen = activeCommands.length;
174
221
  let nodeName = '';
175
222
 
176
- while (selectionNode.firstChild) {
177
- selectionNode = selectionNode.firstChild;
178
- }
179
-
180
223
  if (this.component.is(selectionNode) && !this.component.__selectionSelected) {
181
224
  const component = this.component.get(selectionNode);
225
+ if (!component) return;
182
226
  this.component.select(component.target, component.pluginName, false);
183
227
  return;
184
228
  }
185
229
 
230
+ while (selectionNode.firstChild) {
231
+ selectionNode = selectionNode.firstChild;
232
+ }
233
+
186
234
  const fc = this.editor.frameContext;
187
235
  const notReadonly = !fc.get('isReadOnly');
188
- for (let element = selectionNode; !domUtils.isWysiwygFrame(element); element = element.parentNode) {
236
+ for (let element = selectionNode; !dom.check.isWysiwygFrame(element); element = element.parentElement) {
189
237
  if (!element) break;
190
- if (element.nodeType !== 1 || domUtils.isBreak(element)) continue;
238
+ if (element.nodeType !== 1 || dom.check.isBreak(element)) continue;
191
239
  if (this._isNonFocusNode(element)) {
192
240
  this.editor.blur();
193
241
  return;
@@ -216,11 +264,11 @@ EventManager.prototype = {
216
264
  /** indent, outdent */
217
265
  if (this.format.isLine(element)) {
218
266
  /* Outdent */
219
- if (!commandMapNodes.includes('outdent') && commandTargets.has('outdent') && (domUtils.isListCell(element) || (element.style[marginDir] && numbers.get(element.style[marginDir], 0) > 0))) {
267
+ if (!commandMapNodes.includes('outdent') && commandTargets.has('outdent') && (dom.check.isListCell(element) || (element.style[marginDir] && numbers.get(element.style[marginDir], 0) > 0))) {
220
268
  if (
221
- commandTargets.get('outdent').filter(function (e) {
222
- if (domUtils.isImportantDisabled(e)) return false;
223
- e.removeAttribute('disabled');
269
+ commandTargets.get('outdent').filter((e) => {
270
+ if (dom.check.isImportantDisabled(e)) return false;
271
+ e.disabled = false;
224
272
  return true;
225
273
  }).length > 0
226
274
  ) {
@@ -229,15 +277,11 @@ EventManager.prototype = {
229
277
  }
230
278
  /* Indent */
231
279
  if (!commandMapNodes.includes('indent') && commandTargets.has('indent')) {
232
- const indentDisable = domUtils.isListCell(element) && !element.previousElementSibling;
280
+ const indentDisable = dom.check.isListCell(element) && !element.previousElementSibling;
233
281
  if (
234
- commandTargets.get('indent').filter(function (e) {
235
- if (domUtils.isImportantDisabled(e)) return false;
236
- if (indentDisable) {
237
- e.setAttribute('disabled', true);
238
- } else {
239
- e.removeAttribute('disabled');
240
- }
282
+ commandTargets.get('indent').filter((e) => {
283
+ if (dom.check.isImportantDisabled(e)) return false;
284
+ e.disabled = indentDisable;
241
285
  return true;
242
286
  }).length > 0
243
287
  ) {
@@ -252,7 +296,7 @@ EventManager.prototype = {
252
296
  if (classOnCheck.test(nodeName)) {
253
297
  nodeName = styleCommand[nodeName] || nodeName;
254
298
  commandMapNodes.push(nodeName);
255
- domUtils.addClass(commandTargets.get(nodeName), 'active');
299
+ dom.utils.addClass(commandTargets.get(nodeName), 'active');
256
300
  }
257
301
  }
258
302
 
@@ -274,21 +318,25 @@ EventManager.prototype = {
274
318
  },
275
319
 
276
320
  /**
321
+ * @private
322
+ * @this {EventManagerThis}
277
323
  * @description Gives an active effect when the mouse down event is blocked. (Used when "env.isGecko" is true)
278
- * @param {Element} target Target element
324
+ * @param {Node} target Target element
279
325
  * @private
280
326
  */
281
327
  _injectActiveEvent(target) {
282
- domUtils.addClass(target, '__se__active');
328
+ dom.utils.addClass(target, '__se__active');
283
329
  this.__geckoActiveEvent = this.addGlobalEvent('mouseup', () => {
284
- domUtils.removeClass(target, '__se__active');
330
+ dom.utils.removeClass(target, '__se__active');
285
331
  this.__geckoActiveEvent = this.removeGlobalEvent(this.__geckoActiveEvent);
286
332
  });
287
333
  },
288
334
 
289
335
  /**
336
+ * @private
337
+ * @this {EventManagerThis}
290
338
  * @description remove class, display text.
291
- * @param {Array|null} ignoredList Igonred button list
339
+ * @param {Array<string>} ignoredList Igonred button list
292
340
  * @private
293
341
  */
294
342
  _setKeyEffect(ignoredList) {
@@ -302,20 +350,25 @@ EventManager.prototype = {
302
350
  p = plugins[k];
303
351
  for (let j = 0, jLen = c.length, e; j < jLen; j++) {
304
352
  e = c[j];
305
- if (!e || e.length === 0) continue;
353
+ if (!e) continue;
306
354
  if (p) {
307
355
  p.active(null, e);
308
356
  } else if (/^outdent$/i.test(k)) {
309
- if (!domUtils.isImportantDisabled(e)) e.setAttribute('disabled', true);
357
+ if (!dom.check.isImportantDisabled(e)) e.disabled = true;
310
358
  } else if (/^indent$/i.test(k)) {
311
- if (!domUtils.isImportantDisabled(e)) e.removeAttribute('disabled');
359
+ if (!dom.check.isImportantDisabled(e)) e.disabled = false;
312
360
  } else {
313
- domUtils.removeClass(e, 'active');
361
+ dom.utils.removeClass(e, 'active');
314
362
  }
315
363
  }
316
364
  }
317
365
  },
318
366
 
367
+ /**
368
+ * @private
369
+ * @this {EventManagerThis}
370
+ * @description Show toolbar-balloon with delay.
371
+ */
319
372
  _showToolbarBalloonDelay() {
320
373
  if (this._balloonDelay) {
321
374
  _w.clearTimeout(this._balloonDelay);
@@ -329,12 +382,17 @@ EventManager.prototype = {
329
382
  }, 250);
330
383
  },
331
384
 
385
+ /**
386
+ * @private
387
+ * @this {EventManagerThis}
388
+ * @description Show or hide the toolbar-balloon.
389
+ */
332
390
  _toggleToolbarBalloon() {
333
391
  this.selection._init();
334
392
  const range = this.selection.getRange();
335
393
  const hasSubMode = this.options.has('_subMode');
336
394
 
337
- if (this.menu._bindControllersOff || (!(hasSubMode ? this.editor.isSubBalloonAlways : this.editor.isBalloonAlways) && range.collapsed)) {
395
+ if (!(hasSubMode ? this.editor.isSubBalloonAlways : this.editor.isBalloonAlways) && range.collapsed) {
338
396
  if (hasSubMode) this._hideToolbar_sub();
339
397
  else this._hideToolbar();
340
398
  } else {
@@ -343,38 +401,73 @@ EventManager.prototype = {
343
401
  }
344
402
  },
345
403
 
404
+ /**
405
+ * @private
406
+ * @this {EventManagerThis}
407
+ * @description Hide the toolbar.
408
+ */
346
409
  _hideToolbar() {
347
410
  if (!this.editor._notHideToolbar && !this.editor.frameContext.get('isFullScreen')) {
348
411
  this.toolbar.hide();
349
412
  }
350
413
  },
351
414
 
415
+ /**
416
+ * @private
417
+ * @this {EventManagerThis}
418
+ * @description Hide the Sub-Toolbar.
419
+ */
352
420
  _hideToolbar_sub() {
353
421
  if (this.subToolbar && !this.editor._notHideToolbar) {
354
422
  this.subToolbar.hide();
355
423
  }
356
424
  },
357
425
 
426
+ /**
427
+ * @private
428
+ * @this {EventManagerThis}
429
+ * @description Checks if a node is a non-focusable element(.data-se-non-focus). (e.g. fileUpload.component > span)
430
+ * @param {Node} node Node to check
431
+ * @returns {boolean} True if the node is non-focusable, otherwise false
432
+ */
358
433
  _isNonFocusNode(node) {
359
- return node.nodeType === 1 && node.getAttribute('data-se-non-focus') === 'true';
434
+ return dom.check.isElement(node) && node.getAttribute('data-se-non-focus') === 'true';
360
435
  },
361
436
 
437
+ /**
438
+ * @private
439
+ * @this {EventManagerThis}
440
+ * @description Determines if the "range" is within an uneditable node.
441
+ * @param {Range} range The range object
442
+ * @param {boolean} isFront Whether to check the start or end of the range
443
+ * @returns {Node|null} The uneditable node if found, otherwise null
444
+ */
362
445
  _isUneditableNode(range, isFront) {
363
446
  const container = isFront ? range.startContainer : range.endContainer;
364
447
  const offset = isFront ? range.startOffset : range.endOffset;
365
448
  const siblingKey = isFront ? 'previousSibling' : 'nextSibling';
366
449
  const isElement = container.nodeType === 1;
367
- let siblingNode;
368
450
 
451
+ let siblingNode;
369
452
  if (isElement) {
370
- siblingNode = this._isUneditableNode_getSibling(container.childNodes[offset], siblingKey, container);
453
+ siblingNode = /** @type {HTMLElement} */ (this._isUneditableNode_getSibling(container.childNodes[offset], siblingKey, container));
371
454
  return siblingNode && siblingNode.nodeType === 1 && siblingNode.getAttribute('contenteditable') === 'false' ? siblingNode : null;
372
455
  } else {
373
- siblingNode = this._isUneditableNode_getSibling(container, siblingKey, container);
374
- return domUtils.isEdgePoint(container, offset, isFront ? 'front' : 'end') && siblingNode && siblingNode.nodeType === 1 && siblingNode.getAttribute('contenteditable') === 'false' ? siblingNode : null;
456
+ siblingNode = /** @type {HTMLElement} */ (this._isUneditableNode_getSibling(container, siblingKey, container));
457
+ return dom.check.isEdgePoint(container, offset, isFront ? 'front' : 'end') && siblingNode && siblingNode.nodeType === 1 && siblingNode.getAttribute('contenteditable') === 'false' ? siblingNode : null;
375
458
  }
376
459
  },
377
460
 
461
+ /**
462
+ * @private
463
+ * @this {EventManagerThis}
464
+ * @description Retrieves the sibling node of a selected node if it is uneditable.
465
+ * - Used only in `_isUneditableNode`.
466
+ * @param {Node} selectNode The selected node
467
+ * @param {string} siblingKey The key to access the sibling (`previousSibling` or `nextSibling`)
468
+ * @param {Node} container The parent container node
469
+ * @returns {Node|null} The sibling node if found, otherwise null
470
+ */
378
471
  _isUneditableNode_getSibling(selectNode, siblingKey, container) {
379
472
  if (!selectNode) return null;
380
473
  let siblingNode = selectNode[siblingKey];
@@ -389,7 +482,13 @@ EventManager.prototype = {
389
482
  return siblingNode;
390
483
  },
391
484
 
392
- // FireFox - table delete, Chrome - image, video, audio
485
+ /**
486
+ * @private
487
+ * @this {EventManagerThis}
488
+ * @description Deletes specific elements such as tables in "Firefox" and media elements (image, video, audio) in "Chrome".
489
+ * - Handles deletion logic based on selection range and node types.
490
+ * @returns {boolean} Returns `true` if an element was deleted and focus was adjusted, otherwise `false`.
491
+ */
393
492
  _hardDelete() {
394
493
  const range = this.selection.getRange();
395
494
  const sc = range.startContainer;
@@ -398,55 +497,60 @@ EventManager.prototype = {
398
497
  // table
399
498
  const sCell = this.format.getBlock(sc);
400
499
  const eCell = this.format.getBlock(ec);
401
- const sIsCell = domUtils.isTableCell(sCell);
402
- const eIsCell = domUtils.isTableCell(eCell);
500
+ const sIsCell = dom.check.isTableCell(sCell);
501
+ const eIsCell = dom.check.isTableCell(eCell);
403
502
  const ancestor = range.commonAncestorContainer;
404
503
  if (((sIsCell && !sCell.previousElementSibling && !sCell.parentElement.previousElementSibling) || (eIsCell && !eCell.nextElementSibling && !eCell.parentElement.nextElementSibling)) && sCell !== eCell) {
405
504
  if (!sIsCell) {
406
- domUtils.removeItem(domUtils.getParentElement(eCell, (current) => ancestor === current.parentNode));
505
+ dom.utils.removeItem(dom.query.getParentElement(eCell, (current) => ancestor === current.parentNode));
407
506
  } else if (!eIsCell) {
408
- domUtils.removeItem(domUtils.getParentElement(sCell, (current) => ancestor === current.parentNode));
507
+ dom.utils.removeItem(dom.query.getParentElement(sCell, (current) => ancestor === current.parentNode));
409
508
  } else {
410
- domUtils.removeItem(domUtils.getParentElement(sCell, (current) => ancestor === current.parentNode));
509
+ dom.utils.removeItem(dom.query.getParentElement(sCell, (current) => ancestor === current.parentNode));
411
510
  this.editor._nativeFocus();
412
511
  return true;
413
512
  }
414
513
  }
415
514
 
416
515
  // component
417
- const sComp = sc.nodeType === 1 ? domUtils.getParentElement(sc, '.se-component') : null;
418
- const eComp = ec.nodeType === 1 ? domUtils.getParentElement(ec, '.se-component') : null;
419
- if (sComp) domUtils.removeItem(sComp);
420
- if (eComp) domUtils.removeItem(eComp);
516
+ const sComp = sc.nodeType === 1 ? dom.query.getParentElement(sc, '.se-component') : null;
517
+ const eComp = ec.nodeType === 1 ? dom.query.getParentElement(ec, '.se-component') : null;
518
+ if (sComp) dom.utils.removeItem(sComp);
519
+ if (eComp) dom.utils.removeItem(eComp);
421
520
 
422
521
  return false;
423
522
  },
424
523
 
425
524
  /**
525
+ * @private
526
+ * @this {EventManagerThis}
426
527
  * @description If there is no default format, add a line and move 'selection'.
427
528
  * @param {string|null} formatName Format tag name (default: 'P')
428
- * @private
429
529
  */
430
530
  _setDefaultLine(formatName) {
531
+ if (!this.options.get('__lineFormatFilter')) return null;
431
532
  if (this.editor._fileManager.pluginRegExp.test(this.editor.currentControllerName)) return;
432
533
 
433
534
  const range = this.selection.getRange();
434
- const commonCon = range.commonAncestorContainer;
535
+ const commonCon = /** @type {HTMLElement} */ (range.commonAncestorContainer);
435
536
  const startCon = range.startContainer;
436
537
  const rangeEl = this.format.getBlock(commonCon, null);
437
- let focusNode, offset, format;
538
+
539
+ /** @type {Node} */
540
+ let focusNode;
541
+ let offset, format;
438
542
 
439
543
  if (rangeEl) {
440
- format = domUtils.createElement(formatName || this.options.get('defaultLine'));
544
+ format = dom.utils.createElement(formatName || this.options.get('defaultLine'));
441
545
  format.innerHTML = rangeEl.innerHTML;
442
546
  if (format.childNodes.length === 0) format.innerHTML = unicode.zeroWidthSpace;
443
547
 
444
548
  rangeEl.innerHTML = format.outerHTML;
445
549
  format = rangeEl.firstChild;
446
- focusNode = domUtils.getEdgeChildNodes(format, null).sc;
550
+ focusNode = dom.query.getEdgeChildNodes(format, null).sc;
447
551
 
448
552
  if (!focusNode) {
449
- focusNode = domUtils.createTextNode(unicode.zeroWidthSpace);
553
+ focusNode = dom.utils.createTextNode(unicode.zeroWidthSpace);
450
554
  format.insertBefore(focusNode, format.firstChild);
451
555
  }
452
556
 
@@ -455,13 +559,20 @@ EventManager.prototype = {
455
559
  return;
456
560
  }
457
561
 
458
- const fileComponent = domUtils.getParentElement(commonCon, this.component.is.bind(this.component));
459
- if (fileComponent && commonCon.nodeType === 3) {
460
- const siblingEl = commonCon.nextElementSibling ? fileComponent : fileComponent.nextElementSibling;
461
- const el = domUtils.createElement(this.options.get('defaultLine'), null, commonCon);
462
- fileComponent.parentElement.insertBefore(el, siblingEl);
463
- this.editor.focusEdge(el);
464
- return;
562
+ if (commonCon.nodeType === 3 && this.component.is(commonCon.parentElement)) {
563
+ const compInfo = this.component.get(commonCon.parentElement);
564
+ const container = compInfo.container;
565
+
566
+ if (commonCon.parentElement === container) {
567
+ const siblingEl = commonCon.nextElementSibling ? container : container.nextElementSibling;
568
+ const el = dom.utils.createElement(this.options.get('defaultLine'), null, commonCon);
569
+ container.parentElement.insertBefore(el, siblingEl);
570
+ this.editor.focusEdge(el);
571
+ return;
572
+ }
573
+
574
+ this.component.select(compInfo.target, compInfo.pluginName, false);
575
+ return null;
465
576
  } else if (commonCon.nodeType === 1 && commonCon.getAttribute('data-se-embed') === 'true') {
466
577
  let el = commonCon.nextElementSibling;
467
578
  if (!this.format.isLine(el)) el = this.format.addLine(commonCon, this.options.get('defaultLine'));
@@ -469,15 +580,15 @@ EventManager.prototype = {
469
580
  return;
470
581
  }
471
582
 
472
- if ((this.format.isBlock(startCon) || domUtils.isWysiwygFrame(startCon)) && (this.component.is(startCon.children[range.startOffset]) || this.component.is(startCon.children[range.startOffset - 1]))) return;
473
- if (domUtils.getParentElement(commonCon, domUtils.isExcludeFormat)) return null;
583
+ if ((this.format.isBlock(startCon) || dom.check.isWysiwygFrame(startCon)) && (this.component.is(startCon.children[range.startOffset]) || this.component.is(startCon.children[range.startOffset - 1]))) return;
584
+ if (dom.query.getParentElement(commonCon, dom.check.isExcludeFormat)) return null;
474
585
 
475
586
  if (this.format.isBlock(commonCon) && commonCon.childNodes.length <= 1) {
476
587
  let br = null;
477
- if (commonCon.childNodes.length === 1 && domUtils.isBreak(commonCon.firstChild)) {
588
+ if (commonCon.childNodes.length === 1 && dom.check.isBreak(commonCon.firstChild)) {
478
589
  br = commonCon.firstChild;
479
590
  } else {
480
- br = domUtils.createTextNode(unicode.zeroWidthSpace);
591
+ br = dom.utils.createTextNode(unicode.zeroWidthSpace);
481
592
  commonCon.appendChild(br);
482
593
  }
483
594
 
@@ -487,15 +598,15 @@ EventManager.prototype = {
487
598
 
488
599
  try {
489
600
  if (commonCon.nodeType === 3) {
490
- format = domUtils.createElement(formatName || this.options.get('defaultLine'));
601
+ format = dom.utils.createElement(formatName || this.options.get('defaultLine'));
491
602
  commonCon.parentNode.insertBefore(format, commonCon);
492
603
  format.appendChild(commonCon);
493
604
  }
494
605
 
495
- if (domUtils.isBreak(format.nextSibling)) domUtils.removeItem(format.nextSibling);
496
- if (domUtils.isBreak(format.previousSibling)) domUtils.removeItem(format.previousSibling);
497
- if (domUtils.isBreak(focusNode)) {
498
- const zeroWidth = domUtils.createTextNode(unicode.zeroWidthSpace);
606
+ if (dom.check.isBreak(format.nextSibling)) dom.utils.removeItem(format.nextSibling);
607
+ if (dom.check.isBreak(format.previousSibling)) dom.utils.removeItem(format.previousSibling);
608
+ if (dom.check.isBreak(focusNode)) {
609
+ const zeroWidth = dom.utils.createTextNode(unicode.zeroWidthSpace);
499
610
  focusNode.parentNode.insertBefore(zeroWidth, focusNode);
500
611
  focusNode = zeroWidth;
501
612
  }
@@ -503,55 +614,103 @@ EventManager.prototype = {
503
614
  this.editor.execCommand('formatBlock', false, formatName || this.options.get('defaultLine'));
504
615
  this.selection.removeRange();
505
616
  this.selection._init();
617
+ this.editor.effectNode = null;
618
+ return;
506
619
  }
507
620
 
508
621
  if (format) {
509
- if (domUtils.isBreak(format.nextSibling)) domUtils.removeItem(format.nextSibling);
510
- if (domUtils.isBreak(format.previousSibling)) domUtils.removeItem(format.previousSibling);
511
- if (domUtils.isBreak(focusNode)) {
512
- const zeroWidth = domUtils.createTextNode(unicode.zeroWidthSpace);
622
+ if (dom.check.isBreak(format.nextSibling)) dom.utils.removeItem(format.nextSibling);
623
+ if (dom.check.isBreak(format.previousSibling)) dom.utils.removeItem(format.previousSibling);
624
+ if (dom.check.isBreak(focusNode)) {
625
+ const zeroWidth = dom.utils.createTextNode(unicode.zeroWidthSpace);
513
626
  focusNode.parentNode.insertBefore(zeroWidth, focusNode);
514
627
  focusNode = zeroWidth;
515
628
  }
516
629
  }
517
630
 
518
631
  this.editor.effectNode = null;
519
- this.editor._nativeFocus();
632
+ if (startCon) {
633
+ this.selection.setRange(startCon, 1, startCon, 1);
634
+ } else {
635
+ this.editor._nativeFocus();
636
+ }
520
637
  },
521
638
 
522
- _dataTransferAction(type, e, data, frameContext) {
523
- const plainText = data.getData('text/plain');
524
- const cleanData = data.getData('text/html');
639
+ /**
640
+ * @private
641
+ * @this {EventManagerThis}
642
+ * @description Handles data transfer actions for paste and drop events.
643
+ * - It processes clipboard data, triggers relevant events, and inserts cleaned data into the editor.
644
+ * @param {"paste"|"drop"} type The type of event
645
+ * @param {Event} e The original event object
646
+ * @param {DataTransfer} clipboardData The clipboard data object
647
+ * @param {__se__FrameContext} frameContext The frame context
648
+ * @returns {Promise<boolean>} Resolves to `false` if processing is complete, otherwise allows default behavior
649
+ */
650
+ async _dataTransferAction(type, e, clipboardData, frameContext) {
525
651
  try {
526
- this._setClipboardData(type, e, plainText, cleanData, data, frameContext);
652
+ this.ui.showLoading();
653
+ await this._setClipboardData(type, e, clipboardData, frameContext);
527
654
  e.preventDefault();
528
655
  e.stopPropagation();
529
656
  return false;
530
657
  } catch (err) {
531
658
  console.warn('[SUNEDITOR.paste.error]', err);
659
+ } finally {
660
+ this.ui.hideLoading();
532
661
  }
533
662
  },
534
663
 
535
- async _setClipboardData(type, e, plainText, cleanData, data, frameContext) {
664
+ /**
665
+ * @private
666
+ * @this {EventManagerThis}
667
+ * @description Processes clipboard data for paste and drop events, handling text and HTML cleanup.
668
+ * - Supports specific handling for content from Microsoft Office applications.
669
+ * @param {"paste"|"drop"} type The type of event
670
+ * @param {Event} e The original event object
671
+ * @param {DataTransfer} clipboardData The clipboard data object
672
+ * @param {__se__FrameContext} frameContext The frame context
673
+ * @returns {Promise<boolean>} Resolves to `false` if processing is complete, otherwise allows default behavior
674
+ */
675
+ async _setClipboardData(type, e, clipboardData, frameContext) {
676
+ let plainText = clipboardData.getData('text/plain');
677
+ let cleanData = clipboardData.getData('text/html');
678
+ const onlyText = !cleanData;
679
+
680
+ // SE copy data
681
+ const SEData = this.__secopy === plainText;
536
682
  // MS word, OneNode, Excel
537
683
  const MSData = /class=["']*Mso(Normal|List)/i.test(cleanData) || /content=["']*Word.Document/i.test(cleanData) || /content=["']*OneNote.File/i.test(cleanData) || /content=["']*Excel.Sheet/i.test(cleanData);
538
- const onlyText = !cleanData;
684
+ // from
685
+ const from = SEData ? 'SE' : MSData ? 'MS' : '';
539
686
 
540
- if (!onlyText) {
687
+ if (onlyText) {
688
+ cleanData = converter.htmlToEntity(plainText).replace(/\n/g, '<br>');
689
+ } else {
541
690
  cleanData = cleanData.replace(/^<html>\r?\n?<body>\r?\n?\x3C!--StartFragment-->|\x3C!--EndFragment-->\r?\n?<\/body>\r?\n?<\/html>$/g, '');
542
691
  if (MSData) {
543
692
  cleanData = cleanData.replace(/\n/g, ' ');
544
693
  plainText = plainText.replace(/\n/g, ' ');
545
694
  }
546
- cleanData = this.html.clean(cleanData, false, null, null);
547
- } else {
548
- cleanData = converter.htmlToEntity(plainText).replace(/\n/g, '<br>');
695
+ }
696
+
697
+ if (!SEData) {
698
+ const autoLinkify = this.options.get('autoLinkify');
699
+ if (autoLinkify) {
700
+ const domParser = new DOMParser().parseFromString(cleanData, 'text/html');
701
+ dom.query.getListChildNodes(domParser.body, converter.textToAnchor);
702
+ cleanData = domParser.body.innerHTML;
703
+ }
704
+ }
705
+
706
+ if (!onlyText) {
707
+ cleanData = this.html.clean(cleanData, { forceFormat: false, whitelist: null, blacklist: null });
549
708
  }
550
709
 
551
710
  const maxCharCount = this.char.test(this.editor.frameOptions.get('charCounter_type') === 'byte-html' ? cleanData : plainText, false);
552
711
  // user event - paste
553
712
  if (type === 'paste') {
554
- const value = await this.triggerEvent('onPaste', { frameContext, event: e, cleanData, maxCharCount });
713
+ const value = await this.triggerEvent('onPaste', { frameContext, event: e, data: cleanData, maxCharCount, from });
555
714
  if (value === false) {
556
715
  return false;
557
716
  } else if (typeof value === 'string') {
@@ -561,7 +720,7 @@ EventManager.prototype = {
561
720
  }
562
721
  // user event - drop
563
722
  if (type === 'drop') {
564
- const value = await this.triggerEvent('onDrop', { frameContext, event: e, cleanData, maxCharCount });
723
+ const value = await this.triggerEvent('onDrop', { frameContext, event: e, data: cleanData, maxCharCount, from });
565
724
  if (value === false) {
566
725
  return false;
567
726
  } else if (typeof value === 'string') {
@@ -571,7 +730,7 @@ EventManager.prototype = {
571
730
  }
572
731
 
573
732
  // files
574
- const files = data.files;
733
+ const files = clipboardData.files;
575
734
  if (files.length > 0 && !MSData) {
576
735
  for (let i = 0, len = files.length; i < len; i++) {
577
736
  this._callPluginEvent('onPastAndDrop', { frameContext, event: e, file: files[i] });
@@ -585,11 +744,21 @@ EventManager.prototype = {
585
744
  }
586
745
 
587
746
  if (cleanData) {
588
- this.html.insert(cleanData, false, true, true);
747
+ this.html.insert(cleanData, { selectInserted: false, skipCharCount: true, skipCleaning: true });
748
+ // document type
749
+ if (frameContext.has('documentType-use-header')) {
750
+ frameContext.get('documentType').reHeader();
751
+ }
589
752
  return false;
590
753
  }
591
754
  },
592
755
 
756
+ /**
757
+ * @private
758
+ * @this {EventManagerThis}
759
+ * @description Registers common UI events such as toolbar and menu interactions.
760
+ * - Adds event listeners for various UI elements, sets up observers, and configures window events.
761
+ */
593
762
  _addCommonEvents() {
594
763
  const buttonsHandler = ButtonsHandler.bind(this);
595
764
  const toolbarHandler = OnClick_toolbar.bind(this);
@@ -620,22 +789,41 @@ EventManager.prototype = {
620
789
  this._wwFrameObserver = new ResizeObserver((entries) => {
621
790
  _w.setTimeout(() => {
622
791
  entries.forEach((e) => {
623
- this.editor.__callResizeFunction(this.editor.frameRoots.get(e.target.getAttribute('data-root-key')), -1, e);
792
+ this.editor.__callResizeFunction(this.frameRoots.get(e.target.getAttribute('data-root-key')), -1, e);
624
793
  });
625
794
  }, 0);
626
795
  });
627
796
  }
628
797
 
798
+ /** modal outside click */
799
+ if (this.options.get('closeModalOutsideClick')) {
800
+ this.addEvent(
801
+ this.carrierWrapper.querySelector('.se-modal-inner'),
802
+ 'click',
803
+ (e) => {
804
+ if (e.target === this.carrierWrapper.querySelector('.se-modal-inner')) {
805
+ this.ui._offCurrentModal();
806
+ }
807
+ },
808
+ false
809
+ );
810
+ }
811
+
629
812
  /** window event */
630
813
  this.addEvent(_w, 'resize', OnResize_window.bind(this), false);
631
814
  this.addEvent(_w, 'scroll', OnScroll_window.bind(this), false);
632
815
  if (env.isMobile) {
633
- this.addEvent(_w.visualViewport, 'resize', OnResize_viewport.bind(this), false);
634
816
  this.addEvent(_w.visualViewport, 'scroll', OnScroll_viewport.bind(this), false);
635
- this.addEvent(_w.visualViewport, 'scroll', converter.debounce(OnScroll_viewport_onKeyboardOn.bind(this), 200), false);
636
817
  }
637
818
  },
638
819
 
820
+ /**
821
+ * @private
822
+ * @this {EventManagerThis}
823
+ * @description Registers event listeners for the editor's frame, including text input, selection, and UI interactions.
824
+ * - Handles events inside an iframe or within the standard wysiwyg editor.
825
+ * @param {__se__FrameContext} fc The frame context object
826
+ */
639
827
  _addFrameEvents(fc) {
640
828
  const isIframe = fc.get('options').get('iframe');
641
829
  const eventWysiwyg = isIframe ? fc.get('_ww') : fc.get('wysiwyg');
@@ -656,15 +844,21 @@ EventManager.prototype = {
656
844
  this.addEvent(eventWysiwyg, 'paste', OnPaste_wysiwyg.bind(this, fc), false);
657
845
  this.addEvent(eventWysiwyg, 'copy', OnCopy_wysiwyg.bind(this, fc), false);
658
846
  this.addEvent(eventWysiwyg, 'cut', OnCut_wysiwyg.bind(this, fc), false);
659
- this.addEvent(eventWysiwyg, 'dragover', OnDragOver_wysiwyg.bind(this, dragCursor, isIframe ? this.editor.frameContext.get('topArea') : null), false);
847
+ this.addEvent(
848
+ eventWysiwyg,
849
+ 'dragover',
850
+ OnDragOver_wysiwyg.bind(this, fc, dragCursor, isIframe ? this.editor.frameContext.get('topArea') : null, !this.options.get('toolbar_container') && !this.editor.isBalloon && !this.editor.isInline),
851
+ false
852
+ );
853
+ this.addEvent(eventWysiwyg, 'dragend', OnDragEnd_wysiwyg.bind(this, dragCursor), false);
660
854
  this.addEvent(eventWysiwyg, 'drop', OnDrop_wysiwyg.bind(this, fc, dragCursor), false);
661
- this.addEvent(eventWysiwyg, 'scroll', OnScroll_wysiwyg.bind(this, fc, eventWysiwyg), { passive: true, useCapture: false });
855
+ this.addEvent(eventWysiwyg, 'scroll', OnScroll_wysiwyg.bind(this, fc, eventWysiwyg), { passive: true, capture: false });
662
856
  this.addEvent(eventWysiwyg, 'focus', OnFocus_wysiwyg.bind(this, fc), false);
663
857
  this.addEvent(eventWysiwyg, 'blur', OnBlur_wysiwyg.bind(this, fc), false);
664
858
  this.addEvent(codeArea, 'mousedown', OnFocus_code.bind(this, fc), false);
665
859
 
666
860
  /** drag handle */
667
- const dragHandle = this.editor.frameContext.get('wrapper').querySelector('.se-drag-handle');
861
+ const dragHandle = fc.get('wrapper').querySelector('.se-drag-handle');
668
862
  this.addEvent(
669
863
  dragHandle,
670
864
  'wheel',
@@ -676,22 +870,23 @@ EventManager.prototype = {
676
870
  );
677
871
 
678
872
  /** line breaker */
873
+ const lineBreakEventName = isMobile ? 'touchstart' : 'mousedown';
679
874
  this.addEvent(
680
875
  [fc.get('lineBreaker_t'), fc.get('lineBreaker_b')],
681
- 'mousedown',
876
+ lineBreakEventName,
682
877
  (e) => {
683
878
  e.preventDefault();
684
879
  },
685
880
  false
686
881
  );
687
- this.addEvent(fc.get('lineBreaker_t'), 'mousedown', DisplayLineBreak.bind(this, 't'), false);
688
- this.addEvent(fc.get('lineBreaker_b'), 'mousedown', DisplayLineBreak.bind(this, 'b'), false);
882
+ this.addEvent(fc.get('lineBreaker_t'), lineBreakEventName, DisplayLineBreak.bind(this, 't'), false);
883
+ this.addEvent(fc.get('lineBreaker_b'), lineBreakEventName, DisplayLineBreak.bind(this, 'b'), false);
689
884
 
690
885
  /** Events are registered mobile. */
691
886
  if (isMobile) {
692
887
  this.addEvent(eventWysiwyg, 'touchstart', wwMouseMove, {
693
888
  passive: true,
694
- useCapture: false
889
+ capture: false
695
890
  });
696
891
  }
697
892
 
@@ -712,7 +907,7 @@ EventManager.prototype = {
712
907
 
713
908
  const OnScrollAbs = OnScroll_Abs.bind(this);
714
909
  let scrollParent = fc.get('originElement');
715
- while ((scrollParent = domUtils.getScrollParent(scrollParent.parentElement))) {
910
+ while ((scrollParent = dom.query.getScrollParent(scrollParent.parentElement))) {
716
911
  this.__scrollparents.push(scrollParent);
717
912
  this.addEvent(scrollParent, 'scroll', OnScrollAbs, false);
718
913
  }
@@ -727,18 +922,32 @@ EventManager.prototype = {
727
922
  }
728
923
  },
729
924
 
925
+ /**
926
+ * @private
927
+ * @this {EventManagerThis}
928
+ * @description Adds event listeners for resizing the status bar if resizing is enabled.
929
+ * - If resizing is not enabled, applies a non-resizable class.
930
+ * @param {__se__FrameContext} fc The frame context object
931
+ * @param {__se__FrameOptions} fo The frame options object
932
+ */
730
933
  __addStatusbarEvent(fc, fo) {
731
934
  if (/\d+/.test(fo.get('height')) && fo.get('statusbar_resizeEnable')) {
732
935
  fo.set('__statusbarEvent', this.addEvent(fc.get('statusbar'), 'mousedown', OnMouseDown_statusbar.bind(this), false));
733
936
  } else {
734
- domUtils.addClass(fc.get('statusbar'), 'se-resizing-none');
937
+ dom.utils.addClass(fc.get('statusbar'), 'se-resizing-none');
735
938
  }
736
939
  },
737
940
 
941
+ /**
942
+ * @private
943
+ * @this {EventManagerThis}
944
+ * @description Removes all registered event listeners from the editor.
945
+ * - Disconnects observers and clears stored event references.
946
+ */
738
947
  _removeAllEvents() {
739
948
  for (let i = 0, len = this._events.length, e; i < len; i++) {
740
949
  e = this._events[i];
741
- e.target.removeEventListener(e.type, e.handler, e.useCapture);
950
+ e.target.removeEventListener(e.type, e.listener, e.useCapture);
742
951
  }
743
952
 
744
953
  this._events = [];
@@ -754,9 +963,16 @@ EventManager.prototype = {
754
963
  }
755
964
  },
756
965
 
966
+ /**
967
+ * @private
968
+ * @this {EventManagerThis}
969
+ * @description Adjusts the position of the editor's toolbar, controllers, and other floating elements based on scroll position.
970
+ * - Ensures UI elements maintain their intended relative positions when scrolling.
971
+ * @param {Element} eventWysiwyg The wysiwyg event object containing scroll data
972
+ */
757
973
  _moveContainer(eventWysiwyg) {
758
- const y = eventWysiwyg.scrollY || eventWysiwyg.scrollTop || 0;
759
- const x = eventWysiwyg.scrollX || eventWysiwyg.scrollLeft || 0;
974
+ const y = eventWysiwyg.scrollTop || 0;
975
+ const x = eventWysiwyg.scrollLeft || 0;
760
976
 
761
977
  if (this.editor.isBalloon) {
762
978
  this.context.get('toolbar.main').style.top = this.toolbar._balloonOffset.top - y + 'px';
@@ -767,7 +983,7 @@ EventManager.prototype = {
767
983
  }
768
984
 
769
985
  if (this.editor._controllerTargetContext !== this.editor.frameContext.get('topArea')) {
770
- this.editor._offCurrentController();
986
+ this.ui._offCurrentController();
771
987
  }
772
988
 
773
989
  if (this.editor._lineBreaker_t) {
@@ -798,32 +1014,26 @@ EventManager.prototype = {
798
1014
  }
799
1015
  },
800
1016
 
1017
+ /**
1018
+ * @private
1019
+ * @this {EventManagerThis}
1020
+ * @description Handles the scrolling of the editor container.
1021
+ * - Repositions open controllers if necessary.
1022
+ */
801
1023
  _scrollContainer() {
802
1024
  const openCont = this.editor.opendControllers;
803
1025
  if (!openCont.length) return;
804
1026
 
805
1027
  this.__rePositionController(openCont);
806
-
807
- // if (isMobile) {
808
- // this.__rePositionController(openCont);
809
- // } else {
810
- // if (this.__scrollID) _w.clearTimeout(this.__scrollID);
811
-
812
- // if (_DragHandle.get('__dragHandler') && !domUtils.hasClass(_DragHandle.get('__dragHandler'), 'se-drag-handle-full')) _DragHandle.get('__dragHandler').style.display = 'none';
813
-
814
- // for (let i = 0; i < openCont.length; i++) {
815
- // if (openCont[i].notInCarrier) continue;
816
- // openCont[i].inst?.hide();
817
- // }
818
-
819
- // this.__scrollID = _w.setTimeout(() => {
820
- // _w.clearTimeout(this.__scrollID);
821
- // this.__scrollID = '';
822
- // this.__rePositionController(openCont);
823
- // }, 250);
824
- // }
825
1028
  },
826
1029
 
1030
+ /**
1031
+ * @private
1032
+ * @this {EventManagerThis}
1033
+ * @description Repositions the currently open controllers within the editor.
1034
+ * - Ensures elements are displayed in their correct positions after scrolling.
1035
+ * @param {Array<object>} cont List of controllers to reposition
1036
+ */
827
1037
  __rePositionController(cont) {
828
1038
  if (_DragHandle.get('__dragMove')) _DragHandle.get('__dragMove')();
829
1039
  for (let i = 0; i < cont.length; i++) {
@@ -832,6 +1042,12 @@ EventManager.prototype = {
832
1042
  }
833
1043
  },
834
1044
 
1045
+ /**
1046
+ * @private
1047
+ * @this {EventManagerThis}
1048
+ * @description Resets the frame status, adjusting toolbar and UI elements based on the current state.
1049
+ * - Handles inline editor adjustments, fullscreen mode, and responsive toolbar updates.
1050
+ */
835
1051
  _resetFrameStatus() {
836
1052
  if (!env.isResizeObserverSupported) {
837
1053
  this.toolbar.resetResponsiveToolbar();
@@ -842,10 +1058,9 @@ EventManager.prototype = {
842
1058
  const isToolbarHidden = toolbar.style.display === 'none' || (this.editor.isInline && !this.toolbar._inlineToolbarAttr.isShow);
843
1059
  if (toolbar.offsetWidth === 0 && !isToolbarHidden) return;
844
1060
 
845
- const fc = this.editor.frameContext;
846
- const fileBrowser = fc.get('fileBrowser');
847
- if (fileBrowser && fileBrowser.area.style.display === 'block') {
848
- fileBrowser.body.style.maxHeight = domUtils.getClientSize().h - fileBrowser.header.offsetHeight - 50 + 'px';
1061
+ const opendBrowser = this.editor.opendBrowser;
1062
+ if (opendBrowser && opendBrowser.area.style.display === 'block') {
1063
+ opendBrowser.body.style.maxHeight = dom.utils.getClientSize().h - opendBrowser.header.offsetHeight - 50 + 'px';
849
1064
  }
850
1065
 
851
1066
  if (this.menu.currentDropdownActiveButton && this.menu.currentDropdown) {
@@ -854,6 +1069,7 @@ EventManager.prototype = {
854
1069
 
855
1070
  if (this.viewer._resetFullScreenHeight()) return;
856
1071
 
1072
+ const fc = this.editor.frameContext;
857
1073
  if (fc.get('isCodeView') && this.editor.isInline) {
858
1074
  this.toolbar._showInline();
859
1075
  return;
@@ -867,6 +1083,12 @@ EventManager.prototype = {
867
1083
  }
868
1084
  },
869
1085
 
1086
+ /**
1087
+ * @private
1088
+ * @this {EventManagerThis}
1089
+ * @description Synchronizes the selection state by resetting it on mouseup.
1090
+ * - Ensures selection updates correctly across different interactions.
1091
+ */
870
1092
  _setSelectionSync() {
871
1093
  this.removeGlobalEvent(this.__selectionSyncEvent);
872
1094
  this.__selectionSyncEvent = this.addGlobalEvent('mouseup', () => {
@@ -875,6 +1097,14 @@ EventManager.prototype = {
875
1097
  });
876
1098
  },
877
1099
 
1100
+ /**
1101
+ * @private
1102
+ * @this {EventManagerThis}
1103
+ * @description Retains the style nodes for formatting consistency when applying styles.
1104
+ * - Preserves nested styling by cloning and restructuring the style nodes.
1105
+ * @param {HTMLElement} formatEl The format element where styles should be retained
1106
+ * @param {Array<Node>} _styleNodes The list of style nodes to retain
1107
+ */
878
1108
  _retainStyleNodes(formatEl, _styleNodes) {
879
1109
  const el = _styleNodes[0].cloneNode(false);
880
1110
  let n = el;
@@ -884,19 +1114,37 @@ EventManager.prototype = {
884
1114
  n = t;
885
1115
  }
886
1116
 
887
- const zeroWidth = domUtils.createTextNode(unicode.zeroWidthSpace);
888
- formatEl.innerHTML = n.innerHTML = '';
889
- n.appendChild(zeroWidth);
890
- formatEl.appendChild(el);
1117
+ const { parent, inner } = this.nodeTransform.createNestedNode(_styleNodes, null);
1118
+ const zeroWidth = dom.utils.createTextNode(unicode.zeroWidthSpace);
1119
+ inner.appendChild(zeroWidth);
1120
+
1121
+ formatEl.innerHTML = '';
1122
+ formatEl.appendChild(parent);
891
1123
 
892
1124
  this.selection.setRange(zeroWidth, 1, zeroWidth, 1);
893
1125
  },
894
1126
 
1127
+ /**
1128
+ * @private
1129
+ * @this {EventManagerThis}
1130
+ * @description Clears retained style nodes by replacing content with a single line break.
1131
+ * - Resets the selection to the start of the cleared element.
1132
+ * @param {HTMLElement} formatEl The format element where styles should be cleared
1133
+ */
895
1134
  _clearRetainStyleNodes(formatEl) {
896
1135
  formatEl.innerHTML = '<br>';
897
1136
  this.selection.setRange(formatEl, 0, formatEl, 0);
898
1137
  },
899
1138
 
1139
+ /**
1140
+ * @private
1141
+ * @this {EventManagerThis}
1142
+ * @description Calls a registered plugin event and executes associated handlers.
1143
+ * - If any handler returns `false`, the event propagation stops.
1144
+ * @param {string} name The name of the plugin event
1145
+ * @param {{ frameContext: __se__FrameContext, event: Event, data?: string, line?: Node, range?: Range, file?: File }} e The event object passed to the plugin event handler
1146
+ * @returns {boolean|undefined} Returns `false` if any handler stops the event, otherwise `undefined`
1147
+ */
900
1148
  _callPluginEvent(name, e) {
901
1149
  const eventPlugins = this.editor._onPluginEvents.get(name);
902
1150
  for (let i = 0; i < eventPlugins.length; i++) {
@@ -904,39 +1152,64 @@ EventManager.prototype = {
904
1152
  }
905
1153
  },
906
1154
 
1155
+ /**
1156
+ * @private
1157
+ * @this {EventManagerThis}
1158
+ * @description Handles the selection of a component when hovering over it.
1159
+ * - If the target is a component, it ensures that the component is selected properly.
1160
+ * @param {Element} target The element being hovered over
1161
+ */
907
1162
  _overComponentSelect(target) {
908
- const figure = domUtils.getParentElement(target, domUtils.isFigure);
1163
+ const figure = dom.query.getParentElement(target, dom.check.isFigure);
909
1164
  let info = this.component.get(target);
910
1165
  if (info || figure) {
911
1166
  if (!info) info = this.component.get(figure);
912
- if (info && !domUtils.hasClass(info.container, 'se-component-selected')) {
913
- this.editor._offCurrentController();
1167
+ if (info && !dom.utils.hasClass(info.container, 'se-component-selected')) {
1168
+ this.ui._offCurrentController();
914
1169
  _DragHandle.set('__overInfo', ON_OVER_COMPONENT);
915
1170
  this.component.select(info.target, info.pluginName, false);
916
1171
  }
917
- } else if (_DragHandle.get('__overInfo') !== null && !domUtils.hasClass(target, 'se-drag-handle')) {
918
- this.component.deselect();
1172
+ } else if (_DragHandle.get('__overInfo') !== null && !dom.utils.hasClass(target, 'se-drag-handle')) {
1173
+ this.component.__deselect();
919
1174
  _DragHandle.set('__overInfo', null);
920
1175
  }
921
1176
  },
922
1177
 
1178
+ /**
1179
+ * @private
1180
+ * @this {EventManagerThis}
1181
+ * @description Removes input event listeners and resets input-related properties.
1182
+ */
923
1183
  __removeInput() {
924
- this._inputFocus = this.editor._antiBlur = false;
1184
+ this._inputFocus = this.editor._preventBlur = false;
925
1185
  this.__inputBlurEvent = this.removeEvent(this.__inputBlurEvent);
926
1186
  this.__inputKeyEvent = this.removeEvent(this.__inputKeyEvent);
927
1187
  this.__inputPlugin = null;
928
1188
  },
929
1189
 
1190
+ /**
1191
+ * @private
1192
+ * @this {EventManagerThis}
1193
+ * @description Prevents the default behavior of the Enter key and refocuses the editor.
1194
+ * @param {Event} e The keyboard event
1195
+ */
930
1196
  __enterPrevent(e) {
931
1197
  e.preventDefault();
932
1198
  if (!isMobile) return;
933
1199
 
934
1200
  this.__focusTemp.focus();
1201
+ this.editor.frameContext.get('wysiwyg').focus();
935
1202
  },
936
1203
 
937
1204
  constructor: EventManager
938
1205
  };
939
1206
 
1207
+ /**
1208
+ * @this {EventManagerThis}
1209
+ * @param {__se__FrameContext} frameContext - frame context object
1210
+ * @param {Element} eventWysiwyg - wysiwyg event object
1211
+ * @param {Event} e - Event object
1212
+ */
940
1213
  function OnScroll_wysiwyg(frameContext, eventWysiwyg, e) {
941
1214
  this._moveContainer(eventWysiwyg);
942
1215
  this._scrollContainer();
@@ -944,11 +1217,26 @@ function OnScroll_wysiwyg(frameContext, eventWysiwyg, e) {
944
1217
  // plugin event
945
1218
  this._callPluginEvent('onScroll', { frameContext, event: e });
946
1219
 
1220
+ // document type page
1221
+ if (frameContext.has('documentType-use-page')) {
1222
+ frameContext.get('documentType').scrollPage();
1223
+ }
1224
+
947
1225
  // user event
948
1226
  this.triggerEvent('onScroll', { frameContext, event: e });
949
1227
  }
950
1228
 
1229
+ /**
1230
+ * @this {EventManagerThis}
1231
+ * @param {__se__FrameContext} frameContext - frame context object
1232
+ * @param {Event} e - Event object
1233
+ */
951
1234
  function OnFocus_wysiwyg(frameContext, e) {
1235
+ if (this.selection.__iframeFocus || frameContext.get('isReadOnly') || frameContext.get('isDisabled')) {
1236
+ e.preventDefault();
1237
+ return false;
1238
+ }
1239
+
952
1240
  const rootKey = frameContext.get('key');
953
1241
 
954
1242
  if (this._inputFocus) {
@@ -960,17 +1248,22 @@ function OnFocus_wysiwyg(frameContext, e) {
960
1248
  return;
961
1249
  }
962
1250
 
963
- if (this.status.rootKey === rootKey && this.editor._antiBlur) return;
1251
+ if (this.status.rootKey === rootKey && this.editor._preventBlur) return;
964
1252
 
965
- this.editor._offCurrentController();
1253
+ const onSelected = this.editor.status.onSelected || this.editor.opendModal;
1254
+ this.ui._offCurrentController();
966
1255
  this.status.hasFocus = true;
967
1256
 
968
- domUtils.removeClass(this.editor.commandTargets.get('codeView'), 'active');
969
- domUtils.setDisabled(this.editor._codeViewDisabledButtons, false);
1257
+ dom.utils.removeClass(this.editor.commandTargets.get('codeView'), 'active');
1258
+ dom.utils.setDisabled(this.editor._codeViewDisabledButtons, false);
970
1259
 
971
1260
  this.editor.changeFrameContext(rootKey);
972
1261
  this.history.resetButtons(rootKey, null);
973
1262
 
1263
+ if (!onSelected) {
1264
+ this.applyTagEffect();
1265
+ }
1266
+
974
1267
  this._w.setTimeout(() => {
975
1268
  if (this.editor.isInline) this.toolbar._showInline();
976
1269
 
@@ -981,12 +1274,16 @@ function OnFocus_wysiwyg(frameContext, e) {
981
1274
  }, 0);
982
1275
  }
983
1276
 
1277
+ /**
1278
+ * @this {EventManagerThis}
1279
+ * @param {__se__FrameContext} frameContext - frame context object
1280
+ * @param {Event} e - Event object
1281
+ */
984
1282
  function OnBlur_wysiwyg(frameContext, e) {
985
- if (this._inputFocus || this.editor._antiBlur || frameContext.get('isCodeView')) return;
1283
+ if (this._inputFocus || this.editor._preventBlur || frameContext.get('isCodeView') || frameContext.get('isReadOnly') || frameContext.get('isDisabled')) return;
986
1284
 
987
1285
  this.status.hasFocus = false;
988
1286
  this.editor.effectNode = null;
989
- this.editor._offCurrentController();
990
1287
  if (this.editor.isInline || this.editor.isBalloon) this._hideToolbar();
991
1288
  if (this.editor.isSubBalloon) this._hideToolbar_sub();
992
1289
 
@@ -1007,38 +1304,53 @@ function OnBlur_wysiwyg(frameContext, e) {
1007
1304
  this._callPluginEvent('onBlur', { frameContext, event: e });
1008
1305
  }
1009
1306
 
1307
+ /**
1308
+ * @this {EventManagerThis}
1309
+ * @param {MouseEvent} e - Event object
1310
+ */
1010
1311
  function OnMouseDown_statusbar(e) {
1011
1312
  e.stopPropagation();
1012
1313
  this._resizeClientY = e.clientY;
1013
- this.editor.enableBackWrapper('ns-resize');
1314
+ this.ui.enableBackWrapper('ns-resize');
1014
1315
  this.__resize_editor = this.addGlobalEvent('mousemove', __resizeEditor.bind(this));
1015
1316
  this.__close_move = this.addGlobalEvent('mouseup', __closeMove.bind(this));
1016
1317
  }
1017
1318
 
1319
+ /**
1320
+ * @this {EventManagerThis}
1321
+ * @param {MouseEvent} e - Event object
1322
+ */
1018
1323
  function __resizeEditor(e) {
1019
1324
  const fc = this.editor.frameContext;
1020
1325
  const resizeInterval = fc.get('wrapper').offsetHeight + (e.clientY - this._resizeClientY);
1021
1326
  const h = resizeInterval < fc.get('_minHeight') ? fc.get('_minHeight') : resizeInterval;
1022
1327
  fc.get('wysiwygFrame').style.height = fc.get('code').style.height = h + 'px';
1023
1328
  this._resizeClientY = e.clientY;
1024
- if (!env.isResizeObserverSupported) this.editor.__callResizeFunction(h, null);
1329
+ if (!env.isResizeObserverSupported) this.editor.__callResizeFunction(fc, h, null);
1025
1330
  }
1026
1331
 
1332
+ /**
1333
+ * @this {EventManagerThis}
1334
+ */
1027
1335
  function __closeMove() {
1028
- this.editor.disableBackWrapper();
1336
+ this.ui.disableBackWrapper();
1029
1337
  if (this.__resize_editor) this.__resize_editor = this.removeGlobalEvent(this.__resize_editor);
1030
1338
  if (this.__close_move) this.__close_move = this.removeGlobalEvent(this.__close_move);
1031
1339
  }
1032
1340
 
1341
+ /**
1342
+ * @this {EventManagerThis}
1343
+ * @param {"t"|"b"} dir - Direction
1344
+ * @param {Event} e - Event object
1345
+ */
1033
1346
  function DisplayLineBreak(dir, e) {
1034
1347
  e.preventDefault();
1035
1348
 
1036
1349
  const component = this._lineBreakComp;
1037
1350
  if (!component) return;
1038
1351
 
1039
- dir = !dir ? this._lineBreakDir : dir;
1040
- const isList = domUtils.isListCell(component.parentNode);
1041
- const format = domUtils.createElement(isList ? 'BR' : domUtils.isTableCell(component.parentNode) ? 'DIV' : this.options.get('defaultLine'));
1352
+ const isList = dom.check.isListCell(component.parentElement);
1353
+ const format = dom.utils.createElement(isList ? 'BR' : dom.check.isTableCell(component.parentElement) ? 'DIV' : this.options.get('defaultLine'));
1042
1354
  if (!isList) format.innerHTML = '<br>';
1043
1355
 
1044
1356
  if (this.editor.frameOptions.get('charCounter_type') === 'byte-html' && !this.char.check(format.outerHTML)) return;
@@ -1046,16 +1358,24 @@ function DisplayLineBreak(dir, e) {
1046
1358
  component.parentNode.insertBefore(format, dir === 't' ? component : component.nextSibling);
1047
1359
  this.component.deselect();
1048
1360
 
1049
- const focusEl = isList ? format : format.firstChild;
1050
- this.selection.setRange(focusEl, 1, focusEl, 1);
1051
- this.history.push(false);
1361
+ try {
1362
+ this.editor._preventBlur = true;
1363
+ const focusEl = isList ? format : format.firstChild;
1364
+ this.selection.setRange(focusEl, 1, focusEl, 1);
1365
+ this.history.push(false);
1366
+ } finally {
1367
+ this.editor._preventBlur = false;
1368
+ }
1052
1369
  }
1053
1370
 
1371
+ /**
1372
+ * @this {EventManagerThis}
1373
+ */
1054
1374
  function OnResize_window() {
1055
1375
  if (isMobile) {
1056
1376
  this._scrollContainer();
1057
1377
  } else {
1058
- this.editor._offCurrentController();
1378
+ this.ui._offCurrentController();
1059
1379
  }
1060
1380
 
1061
1381
  if (this.editor.isBalloon) this.toolbar.hide();
@@ -1064,13 +1384,12 @@ function OnResize_window() {
1064
1384
  this._resetFrameStatus();
1065
1385
  }
1066
1386
 
1387
+ /**
1388
+ * @this {EventManagerThis}
1389
+ */
1067
1390
  function OnScroll_window() {
1068
1391
  if (this.options.get('toolbar_sticky') > -1) {
1069
- if (this._vitualKeyboardHeight && this.toolbar._sticky) {
1070
- this.toolbar._visible(false);
1071
- } else {
1072
- this.toolbar._resetSticky();
1073
- }
1392
+ this.toolbar._resetSticky();
1074
1393
  }
1075
1394
 
1076
1395
  if (this.editor.isBalloon && this.context.get('toolbar.main').style.display === 'block') {
@@ -1080,50 +1399,62 @@ function OnScroll_window() {
1080
1399
  }
1081
1400
 
1082
1401
  this._scrollContainer();
1083
- }
1084
1402
 
1085
- function OnResize_viewport() {
1086
- this._vitualKeyboardHeight = _w.innerHeight - _w.visualViewport.height;
1403
+ // document type page
1404
+ if (this.editor.frameContext.has('documentType-use-page')) {
1405
+ this.editor.frameContext.get('documentType').scrollWindow();
1406
+ }
1087
1407
  }
1088
1408
 
1409
+ /**
1410
+ * @this {EventManagerThis}
1411
+ */
1089
1412
  function OnScroll_viewport() {
1090
1413
  if (this.options.get('toolbar_sticky') > -1) {
1091
- if (this._vitualKeyboardHeight && this.toolbar._sticky) {
1092
- this.toolbar._visible(false);
1093
- } else {
1094
- this.toolbar._resetSticky();
1095
- }
1096
- }
1097
- }
1098
-
1099
- function OnScroll_viewport_onKeyboardOn() {
1100
- this.toolbar._visible(true);
1101
- if (this._vitualKeyboardHeight && this.options.get('toolbar_sticky') > -1) {
1102
1414
  this.toolbar._resetSticky();
1103
1415
  }
1104
1416
  }
1105
1417
 
1418
+ /**
1419
+ * @this {EventManagerThis}
1420
+ * @param {Document} _wd - Wysiwyg document
1421
+ */
1106
1422
  function OnSelectionchange_document(_wd) {
1107
1423
  const selection = _wd.getSelection();
1108
1424
  let anchorNode = selection.anchorNode;
1109
1425
 
1110
1426
  this.editor.applyFrameRoots((root) => {
1111
1427
  if (anchorNode && root.get('wysiwyg').contains(anchorNode)) {
1428
+ if (root.get('isReadOnly') || root.get('isDisabled')) return;
1429
+
1112
1430
  anchorNode = null;
1113
1431
  this.selection._init();
1114
1432
  this.applyTagEffect();
1433
+
1434
+ // document type
1435
+ if (root.has('documentType-use-header')) {
1436
+ const el = dom.query.getParentElement(this.selection.selectionNode, this.format.isLine.bind(this.format));
1437
+ root.get('documentType').on(el);
1438
+ }
1115
1439
  }
1116
1440
  });
1117
1441
  }
1118
1442
 
1443
+ /**
1444
+ * @this {EventManagerThis}
1445
+ */
1119
1446
  function OnScroll_Abs() {
1120
1447
  this._scrollContainer();
1121
1448
  }
1122
1449
 
1450
+ /**
1451
+ * @this {EventManagerThis}
1452
+ * @param {__se__FrameContext} frameContext - frame context object
1453
+ */
1123
1454
  function OnFocus_code(frameContext) {
1124
1455
  this.editor.changeFrameContext(frameContext.get('key'));
1125
- domUtils.addClass(this.editor.commandTargets.get('codeView'), 'active');
1126
- domUtils.setDisabled(this.editor._codeViewDisabledButtons, true);
1456
+ dom.utils.addClass(this.editor.commandTargets.get('codeView'), 'active');
1457
+ dom.utils.setDisabled(this.editor._codeViewDisabledButtons, true);
1127
1458
  }
1128
1459
 
1129
1460
  export default EventManager;