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,39 +3,98 @@
3
3
  */
4
4
 
5
5
  import CoreInjector from '../../editorInjector/_core';
6
- import { domUtils, env, numbers, unicode } from '../../helper';
6
+ import { dom, env, numbers, unicode, keyCodeMap } from '../../helper';
7
7
  import { Figure, _DragHandle } from '../../modules';
8
8
 
9
- const { _w, ON_OVER_COMPONENT } = env;
9
+ const { _w, ON_OVER_COMPONENT, isMobile } = env;
10
10
  const DIR_KEYCODE = /^(3[7-9]|40)$/;
11
11
  const DIR_UP_KEYCODE = /^3[7-8]$/;
12
12
 
13
- const Component = function (editor) {
13
+ /**
14
+ * @typedef {Omit<Component & Partial<__se__EditorInjector>, 'component'>} ComponentThis
15
+ */
16
+
17
+ /**
18
+ * @typedef {Object} ComponentInfo
19
+ * @property {HTMLElement} target - The target element associated with the component.
20
+ * @property {string} pluginName - The name of the plugin related to the component.
21
+ * @property {Object<string, *>} options - Options related to the component.
22
+ * @property {HTMLElement} container - The main container element for the component.
23
+ * @property {?HTMLElement} cover - The cover element, if applicable.
24
+ * @property {?HTMLElement} inlineCover - The inline cover element, if applicable.
25
+ * @property {?HTMLElement} caption - The caption element, if applicable.
26
+ * @property {boolean} isFile - Whether the component is a file-related component.
27
+ * @property {?HTMLElement} launcher - The element that triggered the component, if applicable.
28
+ */
29
+
30
+ /**
31
+ * @constructor
32
+ * @this {ComponentThis}
33
+ * @description Class for managing components such as images and tables that are not in line format
34
+ * @param {__se__EditorCore} editor - The root editor instance
35
+ */
36
+ function Component(editor) {
14
37
  CoreInjector.call(this, editor);
15
38
 
16
- // members
39
+ /**
40
+ * @description The current component information, used copy, cut, and keydown events
41
+ * @type {ComponentInfo}
42
+ */
17
43
  this.info = null;
44
+
45
+ /**
46
+ * @description Component is selected
47
+ * @type {boolean}
48
+ */
18
49
  this.isSelected = false;
50
+
51
+ /**
52
+ * @description Currently selected component target
53
+ * @type {Node|null}
54
+ */
19
55
  this.currentTarget = null;
56
+
57
+ /**
58
+ * @description Currently selected component plugin instance
59
+ * @type {*}
60
+ */
20
61
  this.currentPlugin = null;
62
+
63
+ /**
64
+ * @description Currently selected component plugin name
65
+ * @type {*}
66
+ */
21
67
  this.currentPluginName = '';
68
+
69
+ /**
70
+ * @description Currently selected component information
71
+ * @type {ComponentInfo|null}
72
+ */
22
73
  this.currentInfo = null;
74
+
75
+ /** @type {Object<string, (...args: *) => *>} */
23
76
  this.__globalEvents = {
24
77
  copy: OnCopy_component.bind(this),
25
78
  cut: OnCut_component.bind(this),
26
79
  keydown: OnKeyDown_component.bind(this),
27
80
  mousedown: CloseListener_mousedown.bind(this)
28
81
  };
82
+ /** @type {__se__GlobalEventInfo|void} */
29
83
  this._bindClose_copy = null;
84
+ /** @type {__se__GlobalEventInfo|void} */
30
85
  this._bindClose_cut = null;
86
+ /** @type {__se__GlobalEventInfo|void} */
31
87
  this._bindClose_keydown = null;
88
+ /** @type {__se__GlobalEventInfo|void} */
32
89
  this._bindClose_mousedown = null;
90
+ /** @type {__se__GlobalEventInfo|void} */
33
91
  this._bindClose_touchstart = null;
92
+ /** @type {boolean} */
34
93
  this.__selectionSelected = false;
35
94
 
36
95
  this.editor.applyFrameRoots((e) => {
37
96
  // drag
38
- const dragHandle = domUtils.createElement('DIV', { class: 'se-drag-handle', draggable: 'true' }, this.icons.selection);
97
+ const dragHandle = dom.utils.createElement('DIV', { class: 'se-drag-handle', draggable: 'true' }, this.icons.selection);
39
98
  e.get('wrapper').appendChild(dragHandle);
40
99
  this.eventManager.addEvent(dragHandle, 'mouseenter', OnDragEnter.bind(this));
41
100
  this.eventManager.addEvent(dragHandle, 'mouseleave', OnDragLeave.bind(this));
@@ -43,19 +102,22 @@ const Component = function (editor) {
43
102
  this.eventManager.addEvent(dragHandle, 'dragend', OnDragEnd.bind(this));
44
103
  this.eventManager.addEvent(dragHandle, 'click', OnDragClick.bind(this));
45
104
  });
46
- };
105
+ }
47
106
 
48
107
  Component.prototype = {
49
108
  /**
50
- * @description The method to insert a element and return. (used elements : table, hr, image, video)
51
- * If "element" is "HR", insert and return the new line.
52
- * @param {Element} element Element to be inserted
53
- * @param {boolean} notCheckCharCount If true, it will be inserted even if "frameOptions.get('charCounter_max')" is exceeded.
54
- * @param {boolean} notSelect If true, Do not automatically select the inserted component.
55
- * @returns {Element}
109
+ * @this {ComponentThis}
110
+ * @description Inserts an element and returns it. (Used for elements: table, hr, image, video)
111
+ * - If "element" is "HR", inserts and returns the new line.
112
+ * @param {Node} element Element to be inserted
113
+ * @param {Object} [options] Options
114
+ * @param {boolean} [options.skipCharCount=false] If true, it will be inserted even if "frameOptions.get('charCounter_max')" is exceeded.
115
+ * @param {boolean} [options.skipSelection=false] If true, do not automatically select the inserted component.
116
+ * @param {boolean} [options.skipHistory=false] If true, do not push to history.
117
+ * @returns {HTMLElement} The inserted element or new line (for HR)
56
118
  */
57
- insert(element, notCheckCharCount, notSelect) {
58
- if (this.editor.frameContext.get('isReadOnly') || (!notCheckCharCount && !this.char.check(element))) {
119
+ insert(element, { skipCharCount, skipSelection, skipHistory } = {}) {
120
+ if (this.editor.frameContext.get('isReadOnly') || (!skipCharCount && !this.char.check(element))) {
59
121
  return null;
60
122
  }
61
123
 
@@ -66,45 +128,51 @@ Component.prototype = {
66
128
  let oNode = null;
67
129
  let formatEl = this.format.getLine(selectionNode, null);
68
130
 
69
- if (domUtils.isListCell(formatEl)) {
70
- this.html.insertNode(element, isInline ? null : selectionNode === formatEl ? null : r.container.nextSibling, true);
71
- if (!isInline && !element.nextSibling) element.parentNode.appendChild(domUtils.createElement('BR'));
131
+ if (dom.check.isListCell(formatEl)) {
132
+ this.html.insertNode(element, { afterNode: isInline ? null : selectionNode === formatEl ? null : r.container.nextSibling, skipCharCount: true });
133
+ if (!isInline && !element.nextSibling) element.parentNode.appendChild(dom.utils.createElement('BR'));
72
134
  } else {
73
- if (this.selection.getRange().collapsed && (r.container.nodeType === 3 || domUtils.isBreak(r.container))) {
74
- const depthFormat = domUtils.getParentElement(r.container, this.format.isBlock.bind(this.format));
75
- oNode = this.nodeTransform.split(r.container, r.offset, !depthFormat ? 0 : domUtils.getNodeDepth(depthFormat) + 1);
76
- if (oNode) formatEl = oNode.previousSibling;
135
+ if (!isInline && this.selection.getRange().collapsed && (r.container.nodeType === 3 || dom.check.isBreak(r.container))) {
136
+ const depthFormat = dom.query.getParentElement(r.container, this.format.isBlock.bind(this.format));
137
+ oNode = this.nodeTransform.split(r.container, r.offset, !depthFormat ? 0 : dom.query.getNodeDepth(depthFormat) + 1);
138
+ if (oNode) formatEl = /** @type {HTMLElement} */ (oNode.previousSibling);
77
139
  }
78
- this.html.insertNode(element, isInline ? null : this.format.isBlock(formatEl) ? null : formatEl, true);
79
- if (!isInline && formatEl && domUtils.isZeroWith(formatEl)) domUtils.removeItem(formatEl);
140
+ this.html.insertNode(element, { afterNode: isInline ? null : this.format.isBlock(formatEl) ? null : formatEl, skipCharCount: true });
141
+ if (!isInline && formatEl && dom.check.isZeroWidth(formatEl)) dom.utils.removeItem(formatEl);
80
142
  }
81
143
 
82
144
  if (isInline) {
83
- const empty = domUtils.createTextNode(unicode.zeroWidthSpace);
145
+ const empty = dom.utils.createTextNode(unicode.zeroWidthSpace);
84
146
  element.parentNode.insertBefore(empty, element.nextSibling);
85
147
  }
86
148
 
87
- this.history.push(false);
149
+ if (!skipHistory) this.history.push(false);
88
150
 
89
- if (!notSelect) {
151
+ if (!skipSelection) {
90
152
  this.selection.setRange(element, 0, element, 0);
91
153
  const fileComponentInfo = this.get(element);
92
154
  if (fileComponentInfo) {
93
155
  this.select(fileComponentInfo.target, fileComponentInfo.pluginName);
94
156
  } else if (oNode) {
95
- oNode = domUtils.getEdgeChildNodes(oNode, null).sc || oNode;
157
+ oNode = dom.query.getEdgeChildNodes(oNode, null).sc || oNode;
96
158
  this.selection.setRange(oNode, 0, oNode, 0);
97
159
  }
98
160
  }
99
161
 
100
- return oNode || element;
162
+ // document type
163
+ if (this.editor.frameContext.has('documentType-use-header')) {
164
+ this.editor.frameContext.get('documentType').reHeader();
165
+ }
166
+
167
+ return /** @type {HTMLElement} */ (oNode || element);
101
168
  },
102
169
 
103
170
  /**
171
+ * @this {ComponentThis}
104
172
  * @description Gets the file component and that plugin name
105
- * return: {target, component, pluginName} | null
106
- * @param {Element} element Target element (figure tag, component div, file tag)
107
- * @returns {Object|null}
173
+ * - return: {target, component, pluginName} | null
174
+ * @param {Node} element Target element (figure tag, component div, file tag)
175
+ * @returns {ComponentInfo|null}
108
176
  */
109
177
  get(element) {
110
178
  if (!element) return null;
@@ -113,10 +181,11 @@ Component.prototype = {
113
181
  let pluginName = '';
114
182
  let options = {};
115
183
  let isFile = false;
184
+ let launcher = null;
116
185
 
117
186
  if (this.is(element)) {
118
- if (domUtils.hasClass(element, 'se-component') && !domUtils.hasClass(element, 'se-inline-component')) element = element.firstElementChild || element;
119
- if (/^FIGURE$/i.test(element.nodeName)) element = element.firstElementChild;
187
+ if (dom.utils.hasClass(element, 'se-component') && !dom.utils.hasClass(element, 'se-inline-component')) element = /** @type {HTMLElement} */ (element).firstElementChild || element;
188
+ if (/^FIGURE$/i.test(element.nodeName)) element = /** @type {HTMLElement} */ (element).firstElementChild;
120
189
  if (!element) return null;
121
190
 
122
191
  const comp = this.editor._componentManager.map((f) => f(element)).find((e) => e);
@@ -124,6 +193,7 @@ Component.prototype = {
124
193
  target = comp.target;
125
194
  pluginName = comp.pluginName;
126
195
  options = comp.options;
196
+ launcher = comp.launcher;
127
197
  }
128
198
 
129
199
  if (!target && element.nodeName) {
@@ -135,6 +205,7 @@ Component.prototype = {
135
205
  target = comp.target;
136
206
  pluginName = comp.pluginName;
137
207
  options = comp.options;
208
+ launcher = comp.launcher;
138
209
  }
139
210
 
140
211
  if (!target) {
@@ -148,25 +219,31 @@ Component.prototype = {
148
219
  options,
149
220
  container: figureInfo.container || figureInfo.cover || target,
150
221
  cover: figureInfo.cover,
222
+ inlineCover: figureInfo.inlineCover,
151
223
  caption: figureInfo.caption,
152
- isFile: isFile
224
+ isFile,
225
+ launcher
153
226
  });
154
227
  },
155
228
 
156
229
  /**
157
- * @description The component(image, video) is selected and the resizing module is called.
158
- * @param {Element} element Element tag (img, iframe, video)
159
- * @param {string} pluginName Plugin name (image, video)
230
+ * @this {ComponentThis}
231
+ * @description The component(media, file component, table, etc) is selected and the resizing module is called.
232
+ * @param {Node} element Target element
233
+ * @param {string} pluginName The plugin name for the selected target.
234
+ * @param {boolean=} isInput Whether the target is an input component.(table)
160
235
  */
161
236
  select(element, pluginName, isInput) {
162
237
  const info = this.get(element);
163
- if (!info || domUtils.isUneditable(domUtils.getParentElement(element, this.is.bind(this))) || domUtils.isUneditable(element)) return false;
238
+ if (!info || dom.check.isUneditable(dom.query.getParentElement(element, this.is.bind(this))) || dom.check.isUneditable(element)) return false;
164
239
 
165
- const plugin = this.plugins[pluginName];
240
+ const plugin = info.launcher || this.plugins[pluginName];
166
241
  if (!plugin) return;
167
242
 
168
243
  if (!isInput && _DragHandle.get('__overInfo') !== ON_OVER_COMPONENT) {
169
- this.editor._antiBlur = true;
244
+ if (this.editor.status._onMousedown) return;
245
+
246
+ this.editor._preventBlur = true;
170
247
  this.__selectionSelected = true;
171
248
  if (this.isInline(info.container)) {
172
249
  this.selection.setRange(info.container, 0, info.container, 0);
@@ -182,7 +259,8 @@ Component.prototype = {
182
259
  let isNonFigureComponent;
183
260
  if (typeof plugin.select === 'function') isNonFigureComponent = plugin.select(element);
184
261
 
185
- if (!isNonFigureComponent && !domUtils.hasClass(info.container, 'se-inline-component')) this._setComponentLineBreaker(info.container || info.cover || element);
262
+ const isBreakComponent = dom.utils.hasClass(info.target, 'se-component-line-break');
263
+ if (isBreakComponent || (!isNonFigureComponent && !dom.utils.hasClass(info.container, 'se-inline-component'))) this._setComponentLineBreaker(/** @type {HTMLElement} */ (info.container || info.cover || element));
186
264
 
187
265
  this.currentTarget = element;
188
266
  this.currentPlugin = plugin;
@@ -197,38 +275,40 @@ Component.prototype = {
197
275
  if (__overInfo !== ON_OVER_COMPONENT) this.__addGlobalEvent();
198
276
  if (!info.isFile) this.__addNotFileGlobalEvent();
199
277
  }, 0);
200
- domUtils.addClass(info.container, 'se-component-selected');
201
-
202
- if (__overInfo !== ON_OVER_COMPONENT) {
203
- domUtils.setDisabled(this.editor._controllerOnDisabledButtons, true);
278
+ dom.utils.addClass(info.container, 'se-component-selected');
204
279
 
280
+ if (!isBreakComponent && __overInfo !== ON_OVER_COMPONENT) {
205
281
  // set zero width space
206
282
  if (!this.isInline(info.container)) return;
207
283
 
208
284
  const oNode = info.container;
209
285
  let zeroWidth = null;
210
- if (!oNode.previousSibling || domUtils.isBreak(oNode.previousSibling)) {
211
- zeroWidth = domUtils.createTextNode(unicode.zeroWidthSpace);
286
+ if (!oNode.previousSibling || dom.check.isBreak(oNode.previousSibling)) {
287
+ zeroWidth = dom.utils.createTextNode(unicode.zeroWidthSpace);
212
288
  oNode.parentNode.insertBefore(zeroWidth, oNode);
213
289
  }
214
290
 
215
- if (!oNode.nextSibling || domUtils.isBreak(oNode.nextSibling)) {
216
- zeroWidth = domUtils.createTextNode(unicode.zeroWidthSpace);
291
+ if (!oNode.nextSibling || dom.check.isBreak(oNode.nextSibling)) {
292
+ zeroWidth = dom.utils.createTextNode(unicode.zeroWidthSpace);
217
293
  oNode.parentNode.insertBefore(zeroWidth, oNode.nextSibling);
218
294
  }
219
- } else if (!domUtils.hasClass(info.container, 'se-input-component')) {
295
+
296
+ this.editor.status.onSelected = true;
297
+ } else if (isBreakComponent || !dom.utils.hasClass(info.container, 'se-input-component')) {
220
298
  const dragHandle = this.editor.frameContext.get('wrapper').querySelector('.se-drag-handle');
221
- domUtils.addClass(dragHandle, 'se-drag-handle-full');
222
- this.editor._visibleControllers(false, false);
299
+ dom.utils.addClass(dragHandle, 'se-drag-handle-full');
300
+ this.ui._visibleControllers(false, false);
223
301
 
224
302
  const sizeTarget = info.caption ? info.target : info.cover || info.container || info.target;
225
- const { w, h, t, l } = this.offset.getSize(sizeTarget);
303
+ const w = sizeTarget.offsetWidth;
304
+ const h = sizeTarget.offsetHeight;
305
+ const { top, left } = this.offset.getLocal(sizeTarget);
226
306
 
227
307
  dragHandle.style.opacity = 0;
228
308
  dragHandle.style.width = w + 'px';
229
309
  dragHandle.style.height = h + 'px';
230
- dragHandle.style.top = t + 'px';
231
- dragHandle.style.left = l + 'px';
310
+ dragHandle.style.top = top - 1 + 'px';
311
+ dragHandle.style.left = left + 'px';
232
312
 
233
313
  _DragHandle.set('__dragHandler', dragHandle);
234
314
  _DragHandle.set('__dragContainer', info.container);
@@ -238,51 +318,40 @@ Component.prototype = {
238
318
  }
239
319
  },
240
320
 
321
+ /**
322
+ * @this {ComponentThis}
323
+ * @description Deselects the selected component.
324
+ */
241
325
  deselect() {
242
- this.editor._antiBlur = false;
243
- _DragHandle.set('__overInfo', null);
244
- this._removeDragEvent(this);
245
- domUtils.removeClass(this.currentInfo?.container, 'se-component-selected|');
246
- domUtils.removeClass(this.currentInfo?.cover, 'se-figure-over-selected');
247
-
248
- const { frameContext } = this.editor;
249
- frameContext.get('lineBreaker_t').style.display = frameContext.get('lineBreaker_b').style.display = 'none';
250
-
251
- if (this.currentPlugin && typeof this.currentPlugin.deselect === 'function') {
252
- this.currentPlugin.deselect(this.currentTarget);
253
- }
254
-
255
- this.isSelected = false;
256
- this.currentPlugin = null;
257
- this.currentTarget = null;
258
- this.currentPluginName = '';
259
- this.currentInfo = null;
260
- this.__removeGlobalEvent();
261
- this.editor.__offControllers();
262
-
263
- domUtils.setDisabled(this.editor._controllerOnDisabledButtons, false);
326
+ _w.setTimeout(() => {
327
+ this.editor.status.onSelected = false;
328
+ }, 0);
329
+ this.__deselect();
330
+ this.ui.setControllerOnDisabledButtons(false);
264
331
  },
265
332
 
266
333
  /**
334
+ * @this {ComponentThis}
267
335
  * @description Determines if the specified node is a block component (e.g., img, iframe, video, audio, table) with the class "se-component"
268
- * or a direct FIGURE node. This function checks if the node itself is a component
269
- * or if it belongs to any components identified by the component manager.
336
+ * - or a direct FIGURE node. This function checks if the node itself is a component
337
+ * - or if it belongs to any components identified by the component manager.
270
338
  * @param {Node} element The DOM node to check.
271
339
  * @returns {boolean} True if the node is a block component or part of it, otherwise false.
272
340
  */
273
341
  is(element) {
274
342
  if (!element) return false;
275
343
 
276
- if (/^FIGURE$/i.test(element.nodeName) || domUtils.hasClass(element, 'se-component')) return true;
344
+ if (/^FIGURE$/i.test(element.nodeName) || dom.utils.hasClass(element, 'se-component')) return true;
277
345
  if (this.editor._componentManager.find((f) => f(element))) return true;
278
346
 
279
347
  return false;
280
348
  },
281
349
 
282
350
  /**
351
+ * @this {ComponentThis}
283
352
  * @description Checks if the given node is an inline component (class "se-inline-component").
284
- * If the node is a FIGURE, it checks the parent element instead.
285
- * It also verifies whether the node is part of an inline component recognized by the component manager.
353
+ * - If the node is a FIGURE, it checks the parent element instead.
354
+ * - It also verifies whether the node is part of an inline component recognized by the component manager.
286
355
  * @param {Node} element The DOM node to check.
287
356
  * @returns {boolean} True if the node is an inline component or part of it, otherwise false.
288
357
  */
@@ -290,18 +359,19 @@ Component.prototype = {
290
359
  if (!element) return false;
291
360
 
292
361
  if (/^FIGURE$/i.test(element.nodeName)) element = element.parentElement;
293
- if (domUtils.hasClass(element, 'se-inline-component')) return true;
362
+ if (dom.utils.hasClass(element, 'se-inline-component')) return true;
294
363
 
295
364
  const container = this.editor._componentManager.find((f) => f(element));
296
- if (container && domUtils.hasClass(element, 'se-inline-component')) return true;
365
+ if (container && dom.utils.hasClass(element, 'se-inline-component')) return true;
297
366
 
298
367
  return false;
299
368
  },
300
369
 
301
370
  /**
371
+ * @this {ComponentThis}
302
372
  * @description Checks if the specified node qualifies as a basic component within the editor.
303
- * This function verifies whether the node is recognized as a component by the `is` function, while also ensuring that it is not an inline component as determined by the `isInline` function.
304
- * This is used to identify block-level elements or standalone components that are not part of the inline component classification.
373
+ * - This function verifies whether the node is recognized as a component by the `is` function, while also ensuring that it is not an inline component as determined by the `isInline` function.
374
+ * - This is used to identify block-level elements or standalone components that are not part of the inline component classification.
305
375
  * @param {Node} element The DOM node to check.
306
376
  * @returns {boolean} True if the node is a basic (non-inline) component, otherwise false.
307
377
  */
@@ -309,46 +379,91 @@ Component.prototype = {
309
379
  return this.is(element) && !this.isInline(element);
310
380
  },
311
381
 
382
+ /**
383
+ * @private
384
+ * @this {ComponentThis}
385
+ * @description Checks if the given element is a file component by matching its tag name against the file manager's regular expressions.
386
+ * - It also verifies whether the element has the required attributes based on the tag type.
387
+ * @param {Node} element The element to check.
388
+ * @returns {boolean} Returns true if the element is a file component, otherwise false.
389
+ */
312
390
  __isFiles(element) {
313
391
  const nodeName = element.nodeName.toLowerCase();
314
- return this.editor._fileManager.regExp.test(nodeName) && (!this.editor._fileManager.tagAttrs[nodeName] || this.editor._fileManager.tagAttrs[nodeName]?.every((v) => element.hasAttribute(v)));
392
+ return this.editor._fileManager.regExp.test(nodeName) && (!this.editor._fileManager.tagAttrs[nodeName] || this.editor._fileManager.tagAttrs[nodeName]?.every((v) => /** @type {HTMLElement} */ (element).hasAttribute(v)));
393
+ },
394
+
395
+ /**
396
+ * @private
397
+ * @this {ComponentThis}
398
+ * @description Deselects the currently selected component, removing any selection effects and associated event listeners.
399
+ * - This method resets the selection state and hides UI elements related to the component selection.
400
+ */
401
+ __deselect() {
402
+ this.editor._preventBlur = false;
403
+ _DragHandle.set('__overInfo', null);
404
+ this._removeDragEvent();
405
+ dom.utils.removeClass(this.currentInfo?.container, 'se-component-selected|');
406
+ dom.utils.removeClass(this.currentInfo?.cover, 'se-figure-over-selected');
407
+
408
+ const { frameContext } = this.editor;
409
+ frameContext.get('lineBreaker_t').style.display = frameContext.get('lineBreaker_b').style.display = 'none';
410
+
411
+ if (this.currentPlugin && typeof this.currentPlugin.deselect === 'function') {
412
+ this.currentPlugin.deselect(this.currentTarget);
413
+ }
414
+
415
+ this.isSelected = false;
416
+ this.currentPlugin = null;
417
+ this.currentTarget = null;
418
+ this.currentPluginName = '';
419
+ this.currentInfo = null;
420
+ this.__removeGlobalEvent();
421
+ this.ui.__offControllers();
315
422
  },
316
423
 
317
424
  /**
318
- * @description Set line breaker of component
319
- * @param {Element} element Element tag
320
425
  * @private
426
+ * @this {ComponentThis}
427
+ * @description Set line breaker of component
428
+ * @param {HTMLElement} element Element tag
321
429
  */
322
430
  _setComponentLineBreaker(element) {
431
+ const _overInfo = _DragHandle.get('__overInfo') === ON_OVER_COMPONENT;
323
432
  this.eventManager._lineBreakComp = null;
324
433
  const info = this.get(element);
325
434
  if (!info) return;
326
435
 
327
436
  const fc = this.editor.frameContext;
328
437
  const container = info.container;
329
- const isNonSelected = domUtils.hasClass(container, 'se-flex-component');
438
+ const isNonSelected = dom.utils.hasClass(container, 'se-flex-component');
330
439
  const lb_t = fc.get('lineBreaker_t');
331
440
  const lb_b = fc.get('lineBreaker_b');
332
441
  const t_style = lb_t.style;
333
442
  const b_style = lb_b.style;
334
443
  const offsetTarget = container.offsetWidth < element.offsetWidth ? container : element;
335
444
  const target = this.editor._figureContainer?.style.display === 'block' ? this.editor._figureContainer : offsetTarget;
336
- const isList = domUtils.isListCell(container.parentNode);
445
+ const isList = dom.check.isListCell(container.parentNode);
337
446
 
338
447
  // top
339
448
  let componentTop, w;
340
449
  const isRtl = this.options.get('_rtl');
341
450
  const dir = isRtl ? ['right', 'left'] : ['left', 'right'];
342
- const { t, scrollX, scrollY } = this.offset.getSize(offsetTarget);
451
+ const { top, left, scrollX, scrollY } = this.offset.getLocal(offsetTarget);
452
+
343
453
  if (isList ? !container.previousSibling : !this.format.isLine(container.previousElementSibling)) {
344
- const tH = numbers.get(_w.getComputedStyle(lb_t).height, 1);
454
+ const tlComputedStyle = _w.getComputedStyle(lb_t);
455
+ const tH = numbers.get(tlComputedStyle.height, 1);
345
456
  this.eventManager._lineBreakComp = container;
346
- componentTop = t + scrollY;
457
+ componentTop = top;
347
458
  w = target.offsetWidth / 2 / 2;
348
459
  t_style.top = componentTop - scrollY - tH / 2 + 'px';
349
- t_style[dir[0]] = (isNonSelected ? 4 : this.offset.get(target).left + w) + 'px';
460
+ t_style[dir[0]] = (isNonSelected ? left - numbers.get(tlComputedStyle.height, 0) / 2 : left + w) + 'px';
350
461
  t_style[dir[1]] = '';
462
+
351
463
  lb_t.setAttribute('data-offset', scrollY + ',' + scrollX);
464
+ if (_overInfo) dom.utils.removeClass(lb_t, 'se-on-selected');
465
+ else dom.utils.addClass(lb_t, 'se-on-selected');
466
+
352
467
  t_style.display = 'block';
353
468
  } else {
354
469
  t_style.display = 'none';
@@ -362,22 +477,30 @@ Component.prototype = {
362
477
 
363
478
  if (!componentTop) {
364
479
  this.eventManager._lineBreakComp = container;
365
- componentTop = t + scrollY;
480
+ componentTop = top;
366
481
  w = target.offsetWidth / 2 / 2;
367
482
  }
368
483
 
369
484
  b_style.top = componentTop + target.offsetHeight - scrollY - bH / 2 + 'px';
370
485
  b_style.right = '';
371
- b_style.left = this.offset.get(target).left + (isRtl ? 0 : target.offsetWidth) - (isNonSelected ? 0 : w) - (isNonSelected ? bW / 2 : bW) + 'px';
486
+ b_style.left = left + (isRtl ? 0 : target.offsetWidth) - (isNonSelected ? 0 : w) - (isNonSelected ? bW / 2 : bW) + 'px';
372
487
 
373
488
  const bDir = 'left';
374
489
  lb_b.setAttribute('data-offset', scrollY + ',' + bDir + ',' + scrollX);
490
+ if (_overInfo) dom.utils.removeClass(lb_b, 'se-on-selected');
491
+ else dom.utils.addClass(lb_b, 'se-on-selected');
492
+
375
493
  b_style.display = 'block';
376
494
  } else {
377
495
  b_style.display = 'none';
378
496
  }
379
497
  },
380
498
 
499
+ /**
500
+ * @private
501
+ * @this {ComponentThis}
502
+ * @description Adds global event listeners for component interactions such as copy, cut, and keydown events.
503
+ */
381
504
  __addGlobalEvent() {
382
505
  this.__removeGlobalEvent();
383
506
  this._bindClose_copy = this.eventManager.addGlobalEvent('copy', this.__globalEvents.copy);
@@ -385,6 +508,11 @@ Component.prototype = {
385
508
  this._bindClose_keydown = this.eventManager.addGlobalEvent('keydown', this.__globalEvents.keydown);
386
509
  },
387
510
 
511
+ /**
512
+ * @private
513
+ * @this {ComponentThis}
514
+ * @description Removes global event listeners that were previously added for component interactions.
515
+ */
388
516
  __removeGlobalEvent() {
389
517
  this.__removeNotFileGlobalEvent();
390
518
  if (this._bindClose_copy) this._bindClose_copy = this.eventManager.removeGlobalEvent(this._bindClose_copy);
@@ -392,23 +520,38 @@ Component.prototype = {
392
520
  if (this._bindClose_keydown) this._bindClose_keydown = this.eventManager.removeGlobalEvent(this._bindClose_keydown);
393
521
  },
394
522
 
523
+ /**
524
+ * @private
525
+ * @this {ComponentThis}
526
+ * @description Adds global event listeners for non-file-related interactions such as mouse and touch events.
527
+ */
395
528
  __addNotFileGlobalEvent() {
396
529
  this.__removeNotFileGlobalEvent();
397
- this._bindClose_mousedown = this.eventManager.addGlobalEvent('mousedown', this.__globalEvents.mousedown, true);
398
- this._bindClose_touchstart = this.eventManager.addGlobalEvent('touchstart', this.__globalEvents.mousedown, true);
530
+ if (!isMobile) this._bindClose_mousedown = this.eventManager.addGlobalEvent('mousedown', this.__globalEvents.mousedown, true);
531
+ else this._bindClose_touchstart = this.eventManager.addGlobalEvent('touchstart', this.__globalEvents.mousedown, true);
399
532
  },
400
533
 
534
+ /**
535
+ * @private
536
+ * @this {ComponentThis}
537
+ * @description Removes global event listeners related to non-file interactions.
538
+ */
401
539
  __removeNotFileGlobalEvent() {
402
540
  if (this._bindClose_mousedown) this._bindClose_mousedown = this.eventManager.removeGlobalEvent(this._bindClose_mousedown);
403
541
  if (this._bindClose_touchstart) this._bindClose_touchstart = this.eventManager.removeGlobalEvent(this._bindClose_touchstart);
404
542
  },
405
543
 
544
+ /**
545
+ * @private
546
+ * @this {ComponentThis}
547
+ * @description Removes drag-related events and resets drag-related states.
548
+ */
406
549
  _removeDragEvent() {
407
- this.carrierWrapper.querySelector('.se-drag-cursor').style.left = '-10000px';
550
+ /** @type {HTMLElement} */ (this.carrierWrapper.querySelector('.se-drag-cursor')).style.left = '-10000px';
408
551
  if (_DragHandle.get('__dragHandler')) _DragHandle.get('__dragHandler').style.display = 'none';
409
552
 
410
- domUtils.removeClass([_DragHandle.get('__dragHandler'), _DragHandle.get('__dragContainer')], 'se-dragging');
411
- domUtils.removeClass([_DragHandle.get('__dragCover'), _DragHandle.get('__dragContainer')], 'se-drag-over');
553
+ dom.utils.removeClass([_DragHandle.get('__dragHandler'), _DragHandle.get('__dragContainer')], 'se-dragging');
554
+ dom.utils.removeClass([_DragHandle.get('__dragCover'), _DragHandle.get('__dragContainer')], 'se-drag-over');
412
555
 
413
556
  _DragHandle.set('__figureInst', null);
414
557
  _DragHandle.set('__dragInst', null);
@@ -422,18 +565,28 @@ Component.prototype = {
422
565
  constructor: Component
423
566
  };
424
567
 
568
+ /**
569
+ * @this {ComponentThis}
570
+ */
425
571
  function OnDragEnter() {
426
- this.editor._antiBlur = true;
427
- this.editor._visibleControllers(false, domUtils.hasClass(_DragHandle.get('__dragHandler'), 'se-drag-handle-full'));
428
- domUtils.addClass(_DragHandle.get('__dragCover') || _DragHandle.get('__dragContainer'), 'se-drag-over');
572
+ this.editor._preventBlur = true;
573
+ this.ui._visibleControllers(false, dom.utils.hasClass(_DragHandle.get('__dragHandler'), 'se-drag-handle-full'));
574
+ dom.utils.addClass(_DragHandle.get('__dragCover') || _DragHandle.get('__dragContainer'), 'se-drag-over');
429
575
  }
430
576
 
577
+ /**
578
+ * @this {ComponentThis}
579
+ */
431
580
  function OnDragLeave() {
432
- this.editor._antiBlur = false;
433
- if (!domUtils.hasClass(_DragHandle.get('__dragHandler'), 'se-drag-handle-full')) this.editor._visibleControllers(true, true);
434
- domUtils.removeClass([_DragHandle.get('__dragCover'), _DragHandle.get('__dragContainer')], 'se-drag-over');
581
+ this.editor._preventBlur = false;
582
+ if (!dom.utils.hasClass(_DragHandle.get('__dragHandler'), 'se-drag-handle-full')) this.ui._visibleControllers(true, true);
583
+ dom.utils.removeClass([_DragHandle.get('__dragCover'), _DragHandle.get('__dragContainer')], 'se-drag-over');
435
584
  }
436
585
 
586
+ /**
587
+ * @this {ComponentThis}
588
+ * @param {DragEvent} e - Drag event
589
+ */
437
590
  function OnDragStart(e) {
438
591
  const cover = _DragHandle.get('__dragCover') || _DragHandle.get('__dragContainer');
439
592
 
@@ -442,29 +595,44 @@ function OnDragStart(e) {
442
595
  return;
443
596
  }
444
597
 
445
- this.editor._antiBlur = false;
446
- domUtils.addClass(_DragHandle.get('__dragHandler'), 'se-dragging');
447
- domUtils.addClass(_DragHandle.get('__dragContainer'), 'se-dragging');
598
+ this.editor._preventBlur = false;
599
+ dom.utils.addClass(_DragHandle.get('__dragHandler'), 'se-dragging');
600
+ dom.utils.addClass(_DragHandle.get('__dragContainer'), 'se-dragging');
448
601
  e.dataTransfer.setDragImage(cover, this.options.get('_rtl') ? cover.offsetWidth : -5, -5);
449
602
  }
450
603
 
604
+ /**
605
+ * @this {ComponentThis}
606
+ */
451
607
  function OnDragEnd() {
452
- this.editor._antiBlur = false;
453
- domUtils.removeClass([_DragHandle.get('__dragHandler'), _DragHandle.get('__dragContainer')], 'se-dragging');
608
+ this.editor._preventBlur = false;
609
+ dom.utils.removeClass([_DragHandle.get('__dragHandler'), _DragHandle.get('__dragContainer')], 'se-dragging');
454
610
  this._removeDragEvent();
455
611
  }
456
612
 
457
- function OnDragClick({ target }) {
458
- if (!domUtils.hasClass(target, 'se-drag-handle-full')) return;
613
+ /**
614
+ * @this {ComponentThis}
615
+ * @param {MouseEvent} e - Mouse event
616
+ */
617
+ function OnDragClick(e) {
618
+ const target = dom.query.getEventTarget(e);
619
+ if (!dom.utils.hasClass(target, 'se-drag-handle-full')) return;
620
+
459
621
  const dragInst = _DragHandle.get('__dragInst');
622
+ this._removeDragEvent();
460
623
  this.select(dragInst.currentTarget, dragInst.currentPluginName, false);
461
624
  }
462
625
 
463
- function CloseListener_mousedown({ target }) {
626
+ /**
627
+ * @this {ComponentThis}
628
+ * @param {MouseEvent} e - Mouse event
629
+ */
630
+ function CloseListener_mousedown(e) {
631
+ const target = dom.query.getEventTarget(e);
464
632
  if (
465
633
  this.currentTarget?.contains(target) ||
466
- domUtils.getParentElement(target, '.se-controller') ||
467
- domUtils.hasClass(target, 'se-drag-handle') ||
634
+ dom.query.getParentElement(target, '.se-controller') ||
635
+ dom.utils.hasClass(target, 'se-drag-handle') ||
468
636
  (this.currentPluginName === this.editor.currentControllerName && this.editor.opendControllers.some(({ form }) => form.contains(target)))
469
637
  ) {
470
638
  return;
@@ -472,39 +640,52 @@ function CloseListener_mousedown({ target }) {
472
640
  this.deselect();
473
641
  }
474
642
 
643
+ /**
644
+ * @this {ComponentThis}
645
+ * @param {ClipboardEvent} e - Event object
646
+ */
475
647
  function OnCopy_component(e) {
476
- if (domUtils.isInputElement(e.target) && domUtils.getParentElement(e.target, '.se-modal')) return;
648
+ const target = dom.query.getEventTarget(e);
649
+ if (dom.check.isInputElement(target) && dom.query.getParentElement(target, '.se-modal')) return;
477
650
 
478
651
  const info = this.info;
479
652
  if (!info) return;
480
653
 
481
654
  SetClipboardComponent(e, info.container, e.clipboardData);
482
- domUtils.addClass(info.container, 'se-copy');
655
+ dom.utils.addClass(info.container, 'se-copy');
483
656
  // copy effect
484
657
  _w.setTimeout(() => {
485
- domUtils.removeClass(info.container, 'se-copy');
658
+ dom.utils.removeClass(info.container, 'se-copy');
486
659
  }, 120);
487
660
  }
488
661
 
662
+ /**
663
+ * @this {ComponentThis}
664
+ * @param {ClipboardEvent} e - Event object
665
+ */
489
666
  function OnCut_component(e) {
490
667
  const info = this.info;
491
668
  if (!info) return;
492
669
 
493
670
  SetClipboardComponent(e, info.container, e.clipboardData);
494
671
  this.deselect();
495
- domUtils.removeItem(info.container);
672
+ dom.utils.removeItem(info.container);
496
673
  }
497
674
 
498
- function OnKeyDown_component(e) {
675
+ /**
676
+ * @this {ComponentThis}
677
+ * @param {KeyboardEvent} e - Event object
678
+ */
679
+ async function OnKeyDown_component(e) {
499
680
  if (this.editor.selectMenuOn) return;
500
681
 
501
- const keyCode = e.keyCode;
502
- const ctrl = e.ctrlKey || e.metaKey || keyCode === 91 || keyCode === 92 || keyCode === 224;
682
+ const keyCode = e.code;
683
+ const ctrl = keyCodeMap.isCtrl(e);
503
684
 
504
685
  // redo, undo
505
686
  if (ctrl) {
506
- if (keyCode !== 17) {
507
- const info = this.editor.shortcutsKeyMap.get(keyCode + (e.shiftKey ? 1000 : 0));
687
+ if (keyCode !== 'ControlRight' && keyCode !== 'ControlLeft') {
688
+ const info = this.editor.shortcutsKeyMap.get(keyCode + (e.shiftKey ? '1000' : ''));
508
689
  if (/^(redo|undo)$/.test(info?.c)) {
509
690
  e.preventDefault();
510
691
  e.stopPropagation();
@@ -514,29 +695,29 @@ function OnKeyDown_component(e) {
514
695
  return;
515
696
  }
516
697
 
517
- // backspace, delete
518
- if (keyCode === 8 || keyCode === 46) {
698
+ // backspace key, delete key
699
+ if (keyCodeMap.isRemoveKey(keyCode)) {
519
700
  e.preventDefault();
520
701
  e.stopPropagation();
521
702
  if (typeof this.currentPlugin?.destroy === 'function') {
522
- this.currentPlugin.destroy(this.currentTarget);
703
+ await this.currentPlugin.destroy(this.currentTarget);
523
704
  this.deselect();
524
705
  this.editor.focus();
525
706
  return;
526
707
  }
527
708
  }
528
709
 
529
- // enter
530
- if (keyCode === 13) {
710
+ // enter key
711
+ if (keyCodeMap.isEnter(keyCode)) {
531
712
  e.preventDefault();
532
713
  const compContext = this.currentInfo || this.get(this.currentTarget);
533
714
  const container = compContext.container || compContext.target;
534
715
  const sibling = container.previousElementSibling || container.nextElementSibling;
535
716
  let newEl = null;
536
- if (domUtils.isListCell(container.parentNode)) {
537
- newEl = domUtils.createElement('BR');
717
+ if (dom.check.isListCell(container.parentNode)) {
718
+ newEl = dom.utils.createElement('BR');
538
719
  } else {
539
- newEl = domUtils.createElement(this.format.isLine(sibling) && !this.format.isBlock(sibling) ? sibling.nodeName : this.options.get('defaultLine'), null, '<br>');
720
+ newEl = dom.utils.createElement(this.format.isLine(sibling) ? sibling.nodeName : this.options.get('defaultLine'), null, '<br>');
540
721
  }
541
722
 
542
723
  const pluginName = this.currentPluginName;
@@ -557,21 +738,22 @@ function OnKeyDown_component(e) {
557
738
  let offset = 1;
558
739
  if (isInline) {
559
740
  switch (keyCode) {
560
- case 37: // left
741
+ case 'ArrowLeft': // left
561
742
  el = container.previousSibling;
562
743
  offset = el?.nodeType === 3 ? el.textContent.length : 1;
563
744
  break;
564
- case 39: // right
745
+ case 'ArrowRight': // right
565
746
  el = container.nextSibling;
747
+ offset = 0;
566
748
  break;
567
- case 38: {
749
+ case 'ArrowUp': {
568
750
  // up
569
751
  const line = this.format.getLine(container, null);
570
752
  el = line?.previousElementSibling;
571
753
  offset = 0;
572
754
  break;
573
755
  }
574
- case 40: {
756
+ case 'ArrowDown': {
575
757
  // down
576
758
  const line = this.format.getLine(container, null);
577
759
  el = line?.nextElementSibling;
@@ -597,16 +779,21 @@ function OnKeyDown_component(e) {
597
779
  e.preventDefault();
598
780
  this.select(elComp.target, elComp.pluginName);
599
781
  } else {
600
- e.stopPropagation();
601
- e.preventDefault();
602
- this.selection.setRange(el, offset, el, offset);
782
+ try {
783
+ this.editor._preventBlur = true;
784
+ e.stopPropagation();
785
+ e.preventDefault();
786
+ this.selection.setRange(el, offset, el, offset);
787
+ } finally {
788
+ this.editor._preventBlur = false;
789
+ }
603
790
  }
604
791
 
605
792
  return;
606
793
  }
607
794
 
608
795
  // ESC
609
- if (keyCode === 27) {
796
+ if (keyCodeMap.isEsc(keyCode)) {
610
797
  this.deselect();
611
798
  return;
612
799
  }
@@ -616,8 +803,8 @@ function SetClipboardComponent(e, container, clipboardData) {
616
803
  e.preventDefault();
617
804
  e.stopPropagation();
618
805
  const pasteContainer = container.cloneNode(true);
619
- domUtils.removeClass(pasteContainer, 'se-component-selected');
620
- pasteContainer.querySelectorAll('.se-figure-selected').forEach((el) => domUtils.removeClass(el, 'se-figure-selected'));
806
+ dom.utils.removeClass(pasteContainer, 'se-component-selected');
807
+ pasteContainer.querySelectorAll('.se-figure-selected').forEach((el) => dom.utils.removeClass(el, 'se-figure-selected'));
621
808
  clipboardData.setData('text/html', pasteContainer.outerHTML);
622
809
  }
623
810