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