suneditor 3.0.0-beta.3 → 3.0.0-beta.30

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 (241) hide show
  1. package/CONTRIBUTING.md +8 -8
  2. package/README.md +44 -49
  3. package/dist/suneditor.min.css +1 -1
  4. package/dist/suneditor.min.js +1 -1
  5. package/package.json +95 -53
  6. package/src/assets/design/color.css +2 -2
  7. package/src/assets/design/size.css +2 -0
  8. package/src/assets/icons/defaultIcons.js +16 -1
  9. package/src/assets/suneditor-contents.css +9 -8
  10. package/src/assets/suneditor.css +29 -26
  11. package/src/core/{section → base}/actives.js +20 -12
  12. package/src/core/base/history.js +4 -4
  13. package/src/core/class/char.js +10 -10
  14. package/src/core/class/component.js +146 -57
  15. package/src/core/class/format.js +94 -2458
  16. package/src/core/class/html.js +187 -129
  17. package/src/core/class/inline.js +1853 -0
  18. package/src/core/class/listFormat.js +582 -0
  19. package/src/core/class/menu.js +14 -3
  20. package/src/core/class/nodeTransform.js +9 -14
  21. package/src/core/class/offset.js +162 -197
  22. package/src/core/class/selection.js +137 -34
  23. package/src/core/class/toolbar.js +73 -52
  24. package/src/core/class/ui.js +11 -11
  25. package/src/core/class/viewer.js +56 -55
  26. package/src/core/config/context.js +122 -0
  27. package/src/core/config/frameContext.js +204 -0
  28. package/src/core/config/options.js +639 -0
  29. package/src/core/editor.js +181 -108
  30. package/src/core/event/actions/index.js +229 -0
  31. package/src/core/event/effects/common.registry.js +60 -0
  32. package/src/core/event/effects/keydown.registry.js +551 -0
  33. package/src/core/event/effects/ruleHelpers.js +145 -0
  34. package/src/core/{base → event}/eventManager.js +119 -201
  35. package/src/core/event/executor.js +21 -0
  36. package/src/core/{base/eventHandlers → event/handlers}/handler_toolbar.js +4 -4
  37. package/src/core/{base/eventHandlers → event/handlers}/handler_ww_dragDrop.js +2 -2
  38. package/src/core/event/handlers/handler_ww_input.js +77 -0
  39. package/src/core/event/handlers/handler_ww_key.js +228 -0
  40. package/src/core/{base/eventHandlers → event/handlers}/handler_ww_mouse.js +3 -3
  41. package/src/core/event/ports.js +211 -0
  42. package/src/core/event/reducers/keydown.reducer.js +89 -0
  43. package/src/core/event/rules/keydown.rule.arrow.js +54 -0
  44. package/src/core/event/rules/keydown.rule.backspace.js +202 -0
  45. package/src/core/event/rules/keydown.rule.delete.js +126 -0
  46. package/src/core/event/rules/keydown.rule.enter.js +144 -0
  47. package/src/core/event/rules/keydown.rule.tab.js +29 -0
  48. package/src/core/section/constructor.js +79 -388
  49. package/src/core/section/documentType.js +47 -26
  50. package/src/core/util/instanceCheck.js +59 -0
  51. package/src/editorInjector/_classes.js +4 -0
  52. package/src/editorInjector/_core.js +17 -7
  53. package/src/editorInjector/index.js +10 -2
  54. package/src/events.js +6 -0
  55. package/src/helper/clipboard.js +24 -10
  56. package/src/helper/converter.js +17 -12
  57. package/src/helper/dom/domCheck.js +22 -3
  58. package/src/helper/dom/domQuery.js +91 -45
  59. package/src/helper/dom/domUtils.js +93 -19
  60. package/src/helper/dom/index.js +4 -0
  61. package/src/helper/env.js +11 -7
  62. package/src/helper/keyCodeMap.js +4 -3
  63. package/src/langs/ckb.js +1 -1
  64. package/src/langs/cs.js +1 -1
  65. package/src/langs/da.js +1 -1
  66. package/src/langs/de.js +1 -1
  67. package/src/langs/en.js +1 -1
  68. package/src/langs/es.js +1 -1
  69. package/src/langs/fa.js +1 -1
  70. package/src/langs/fr.js +1 -1
  71. package/src/langs/he.js +1 -1
  72. package/src/langs/hu.js +1 -1
  73. package/src/langs/it.js +1 -1
  74. package/src/langs/ja.js +1 -1
  75. package/src/langs/km.js +1 -1
  76. package/src/langs/ko.js +1 -1
  77. package/src/langs/lv.js +1 -1
  78. package/src/langs/nl.js +1 -1
  79. package/src/langs/pl.js +1 -1
  80. package/src/langs/pt_br.js +10 -10
  81. package/src/langs/ro.js +1 -1
  82. package/src/langs/ru.js +1 -1
  83. package/src/langs/se.js +1 -1
  84. package/src/langs/tr.js +1 -1
  85. package/src/langs/uk.js +1 -1
  86. package/src/langs/ur.js +1 -1
  87. package/src/langs/zh_cn.js +1 -1
  88. package/src/modules/ApiManager.js +25 -18
  89. package/src/modules/Browser.js +52 -61
  90. package/src/modules/ColorPicker.js +37 -38
  91. package/src/modules/Controller.js +85 -79
  92. package/src/modules/Figure.js +275 -187
  93. package/src/modules/FileManager.js +86 -92
  94. package/src/modules/HueSlider.js +67 -35
  95. package/src/modules/Modal.js +84 -77
  96. package/src/modules/ModalAnchorEditor.js +62 -79
  97. package/src/modules/SelectMenu.js +89 -86
  98. package/src/plugins/browser/audioGallery.js +9 -5
  99. package/src/plugins/browser/fileBrowser.js +10 -6
  100. package/src/plugins/browser/fileGallery.js +9 -5
  101. package/src/plugins/browser/imageGallery.js +9 -5
  102. package/src/plugins/browser/videoGallery.js +11 -6
  103. package/src/plugins/command/blockquote.js +1 -0
  104. package/src/plugins/command/exportPDF.js +11 -8
  105. package/src/plugins/command/fileUpload.js +41 -29
  106. package/src/plugins/command/list_bulleted.js +2 -1
  107. package/src/plugins/command/list_numbered.js +2 -1
  108. package/src/plugins/dropdown/align.js +8 -2
  109. package/src/plugins/dropdown/backgroundColor.js +19 -11
  110. package/src/plugins/dropdown/font.js +15 -9
  111. package/src/plugins/dropdown/fontColor.js +19 -11
  112. package/src/plugins/dropdown/formatBlock.js +7 -2
  113. package/src/plugins/dropdown/hr.js +7 -3
  114. package/src/plugins/dropdown/layout.js +6 -2
  115. package/src/plugins/dropdown/lineHeight.js +8 -3
  116. package/src/plugins/dropdown/list.js +2 -1
  117. package/src/plugins/dropdown/paragraphStyle.js +15 -11
  118. package/src/plugins/dropdown/{table.js → table/index.js} +514 -362
  119. package/src/plugins/dropdown/template.js +6 -2
  120. package/src/plugins/dropdown/textStyle.js +7 -3
  121. package/src/plugins/field/mention.js +33 -27
  122. package/src/plugins/input/fontSize.js +44 -37
  123. package/src/plugins/input/pageNavigator.js +3 -2
  124. package/src/plugins/modal/audio.js +90 -85
  125. package/src/plugins/modal/drawing.js +58 -66
  126. package/src/plugins/modal/embed.js +193 -180
  127. package/src/plugins/modal/image.js +441 -439
  128. package/src/plugins/modal/link.js +31 -8
  129. package/src/plugins/modal/math.js +23 -22
  130. package/src/plugins/modal/video.js +233 -230
  131. package/src/plugins/popup/anchor.js +24 -18
  132. package/src/suneditor.js +69 -24
  133. package/src/typedef.js +42 -19
  134. package/types/assets/icons/defaultIcons.d.ts +8 -0
  135. package/types/core/class/char.d.ts +1 -1
  136. package/types/core/class/component.d.ts +29 -7
  137. package/types/core/class/format.d.ts +4 -354
  138. package/types/core/class/html.d.ts +13 -4
  139. package/types/core/class/inline.d.ts +263 -0
  140. package/types/core/class/listFormat.d.ts +135 -0
  141. package/types/core/class/menu.d.ts +10 -2
  142. package/types/core/class/offset.d.ts +24 -26
  143. package/types/core/class/selection.d.ts +2 -0
  144. package/types/core/class/toolbar.d.ts +24 -11
  145. package/types/core/class/ui.d.ts +1 -1
  146. package/types/core/class/viewer.d.ts +1 -1
  147. package/types/core/config/context.d.ts +157 -0
  148. package/types/core/config/frameContext.d.ts +367 -0
  149. package/types/core/config/options.d.ts +1119 -0
  150. package/types/core/editor.d.ts +101 -66
  151. package/types/core/event/actions/index.d.ts +47 -0
  152. package/types/core/event/effects/common.registry.d.ts +50 -0
  153. package/types/core/event/effects/keydown.registry.d.ts +73 -0
  154. package/types/core/event/effects/ruleHelpers.d.ts +31 -0
  155. package/types/core/{base → event}/eventManager.d.ts +15 -46
  156. package/types/core/event/executor.d.ts +6 -0
  157. package/types/core/event/handlers/handler_ww_input.d.ts +41 -0
  158. package/types/core/{base/eventHandlers/handler_ww_key_input.d.ts → event/handlers/handler_ww_key.d.ts} +4 -6
  159. package/types/core/event/ports.d.ts +255 -0
  160. package/types/core/event/reducers/keydown.reducer.d.ts +75 -0
  161. package/types/core/event/rules/keydown.rule.arrow.d.ts +8 -0
  162. package/types/core/event/rules/keydown.rule.backspace.d.ts +9 -0
  163. package/types/core/event/rules/keydown.rule.delete.d.ts +9 -0
  164. package/types/core/event/rules/keydown.rule.enter.d.ts +9 -0
  165. package/types/core/event/rules/keydown.rule.tab.d.ts +9 -0
  166. package/types/core/section/constructor.d.ts +101 -631
  167. package/types/core/section/documentType.d.ts +14 -4
  168. package/types/core/util/instanceCheck.d.ts +50 -0
  169. package/types/editorInjector/_classes.d.ts +4 -0
  170. package/types/editorInjector/_core.d.ts +17 -7
  171. package/types/editorInjector/index.d.ts +10 -2
  172. package/types/events.d.ts +1 -0
  173. package/types/helper/clipboard.d.ts +2 -2
  174. package/types/helper/converter.d.ts +6 -9
  175. package/types/helper/dom/domCheck.d.ts +7 -0
  176. package/types/helper/dom/domQuery.d.ts +19 -8
  177. package/types/helper/dom/domUtils.d.ts +24 -2
  178. package/types/helper/dom/index.d.ts +86 -1
  179. package/types/helper/env.d.ts +6 -1
  180. package/types/helper/index.d.ts +7 -1
  181. package/types/helper/keyCodeMap.d.ts +3 -3
  182. package/types/index.d.ts +23 -117
  183. package/types/langs/index.d.ts +2 -2
  184. package/types/modules/ApiManager.d.ts +1 -8
  185. package/types/modules/Browser.d.ts +4 -62
  186. package/types/modules/ColorPicker.d.ts +4 -21
  187. package/types/modules/Controller.d.ts +8 -64
  188. package/types/modules/Figure.d.ts +54 -50
  189. package/types/modules/FileManager.d.ts +1 -13
  190. package/types/modules/HueSlider.d.ts +13 -3
  191. package/types/modules/Modal.d.ts +0 -43
  192. package/types/modules/ModalAnchorEditor.d.ts +0 -73
  193. package/types/modules/SelectMenu.d.ts +0 -85
  194. package/types/modules/index.d.ts +3 -3
  195. package/types/plugins/browser/audioGallery.d.ts +29 -18
  196. package/types/plugins/browser/fileBrowser.d.ts +38 -27
  197. package/types/plugins/browser/fileGallery.d.ts +29 -18
  198. package/types/plugins/browser/imageGallery.d.ts +24 -16
  199. package/types/plugins/browser/videoGallery.d.ts +29 -18
  200. package/types/plugins/command/blockquote.d.ts +1 -0
  201. package/types/plugins/command/exportPDF.d.ts +18 -18
  202. package/types/plugins/command/fileUpload.d.ts +65 -45
  203. package/types/plugins/command/list_bulleted.d.ts +1 -0
  204. package/types/plugins/command/list_numbered.d.ts +1 -0
  205. package/types/plugins/dropdown/align.d.ts +13 -8
  206. package/types/plugins/dropdown/backgroundColor.d.ts +30 -19
  207. package/types/plugins/dropdown/font.d.ts +13 -12
  208. package/types/plugins/dropdown/fontColor.d.ts +30 -19
  209. package/types/plugins/dropdown/formatBlock.d.ts +13 -8
  210. package/types/plugins/dropdown/hr.d.ts +15 -11
  211. package/types/plugins/dropdown/layout.d.ts +15 -11
  212. package/types/plugins/dropdown/lineHeight.d.ts +16 -11
  213. package/types/plugins/dropdown/list.d.ts +1 -0
  214. package/types/plugins/dropdown/paragraphStyle.d.ts +31 -27
  215. package/types/plugins/dropdown/table/index.d.ts +582 -0
  216. package/types/plugins/dropdown/table.d.ts +41 -86
  217. package/types/plugins/dropdown/template.d.ts +15 -11
  218. package/types/plugins/dropdown/textStyle.d.ts +19 -11
  219. package/types/plugins/field/mention.d.ts +58 -56
  220. package/types/plugins/index.d.ts +38 -38
  221. package/types/plugins/input/fontSize.d.ts +46 -50
  222. package/types/plugins/modal/audio.d.ts +26 -56
  223. package/types/plugins/modal/drawing.d.ts +0 -85
  224. package/types/plugins/modal/embed.d.ts +15 -79
  225. package/types/plugins/modal/image.d.ts +24 -136
  226. package/types/plugins/modal/link.d.ts +34 -15
  227. package/types/plugins/modal/math.d.ts +0 -16
  228. package/types/plugins/modal/video.d.ts +17 -86
  229. package/types/plugins/popup/anchor.d.ts +1 -8
  230. package/types/suneditor.d.ts +70 -19
  231. package/types/typedef.d.ts +60 -46
  232. package/src/core/base/eventHandlers/handler_ww_key_input.js +0 -1200
  233. package/src/core/section/context.js +0 -102
  234. package/types/core/section/context.d.ts +0 -45
  235. package/types/langs/_Lang.d.ts +0 -194
  236. /package/src/core/{base/eventHandlers → event/handlers}/handler_ww_clipboard.js +0 -0
  237. /package/types/core/{section → base}/actives.d.ts +0 -0
  238. /package/types/core/{base/eventHandlers → event/handlers}/handler_toolbar.d.ts +0 -0
  239. /package/types/core/{base/eventHandlers → event/handlers}/handler_ww_clipboard.d.ts +0 -0
  240. /package/types/core/{base/eventHandlers → event/handlers}/handler_ww_dragDrop.d.ts +0 -0
  241. /package/types/core/{base/eventHandlers → event/handlers}/handler_ww_mouse.d.ts +0 -0
@@ -24,8 +24,8 @@ export default function History(editor) {
24
24
 
25
25
  // user event
26
26
  editor.triggerEvent('onChange', { frameContext: fc, data: fc.get('wysiwyg').innerHTML });
27
- if (editor.context.get('toolbar.main').style.display === 'block') editor.toolbar._showBalloon();
28
- else if (editor.isSubBalloon && editor.context.get('toolbar.sub.main').style.display === 'block') editor.subToolbar._showBalloon();
27
+ if (editor.context.get('toolbar_main').style.display === 'block') editor.toolbar._showBalloon();
28
+ else if (editor.isSubBalloon && editor.context.get('toolbar_sub_main').style.display === 'block') editor.subToolbar._showBalloon();
29
29
  }
30
30
 
31
31
  function setContentFromStack(increase) {
@@ -73,7 +73,7 @@ export default function History(editor) {
73
73
  editor._resourcesStateChange(fc);
74
74
 
75
75
  // document type
76
- if (fc.has('documentType-use-header')) {
76
+ if (fc.has('documentType_use_header')) {
77
77
  fc.get('documentType').reHeader();
78
78
  }
79
79
 
@@ -180,7 +180,7 @@ export default function History(editor) {
180
180
  push(delay, rootKey) {
181
181
  if (waiting) return;
182
182
 
183
- rootKey = rootKey || editor.status.rootKey;
183
+ rootKey = rootKey || rootKey === null ? rootKey : editor.status.rootKey;
184
184
  const range = editor.status._range;
185
185
 
186
186
  _w.setTimeout(editor._resourcesStateChange.bind(editor, frameRoots.get(rootKey)), 0);
@@ -28,11 +28,11 @@ Char.prototype = {
28
28
  * @returns {boolean}
29
29
  */
30
30
  check(html) {
31
- const maxCharCount = this.editor.frameOptions.get('charCounter_max');
31
+ const maxCharCount = this.frameOptions.get('charCounter_max');
32
32
  if (maxCharCount) {
33
- const length = this.getLength(typeof html === 'string' ? html : this.editor.frameOptions.get('charCounter_type') === 'byte-html' && html.nodeType === 1 ? /** @type {HTMLElement} */ (html).outerHTML : html.textContent);
33
+ const length = this.getLength(typeof html === 'string' ? html : this.frameOptions.get('charCounter_type') === 'byte-html' && html.nodeType === 1 ? /** @type {HTMLElement} */ (html).outerHTML : html.textContent);
34
34
  if (length > 0 && length + this.getLength() > maxCharCount) {
35
- CounterBlink(this.editor.frameContext.get('charWrapper'));
35
+ CounterBlink(this.frameContext.get('charWrapper'));
36
36
  return false;
37
37
  }
38
38
  }
@@ -43,14 +43,14 @@ Char.prototype = {
43
43
  * @this {CharThis}
44
44
  * @description Get the [content]'s number of characters or binary data size. (frameOptions.get('charCounter_type'))
45
45
  * - If [content] is undefined, get the current editor's number of characters or binary data size.
46
- * @param {string=} content Content to count. (defalut: this.editor.frameContext.get('wysiwyg'))
46
+ * @param {string=} content Content to count. (defalut: this.frameContext.get('wysiwyg'))
47
47
  * @returns {number}
48
48
  */
49
49
  getLength(content) {
50
50
  if (typeof content !== 'string') {
51
- content = this.editor.frameOptions.get('charCounter_type') === 'byte-html' ? this.editor.frameContext.get('wysiwyg').innerHTML : this.editor.frameContext.get('wysiwyg').textContent;
51
+ content = this.frameOptions.get('charCounter_type') === 'byte-html' ? this.frameContext.get('wysiwyg').innerHTML : this.frameContext.get('wysiwyg').textContent;
52
52
  }
53
- return /byte/.test(this.editor.frameOptions.get('charCounter_type')) ? this.getByteLength(content) : content.length;
53
+ return /byte/.test(this.frameOptions.get('charCounter_type')) ? this.getByteLength(content) : content.length;
54
54
  },
55
55
 
56
56
  /**
@@ -91,7 +91,7 @@ Char.prototype = {
91
91
  * @param {?__se__FrameContext=} fc Frame context
92
92
  */
93
93
  display(fc) {
94
- const charCounter = (fc || this.editor.frameContext).get('charCounter');
94
+ const charCounter = (fc || this.frameContext).get('charCounter');
95
95
  if (charCounter) {
96
96
  _w.setTimeout(() => {
97
97
  charCounter.textContent = this.getLength();
@@ -113,7 +113,7 @@ Char.prototype = {
113
113
 
114
114
  this.display();
115
115
 
116
- const maxCharCount = this.editor.frameOptions.get('charCounter_max');
116
+ const maxCharCount = this.frameOptions.get('charCounter_max');
117
117
  if (maxCharCount > 0) {
118
118
  let over = false;
119
119
  const count = this.getLength();
@@ -135,7 +135,7 @@ Char.prototype = {
135
135
  }
136
136
 
137
137
  if (over) {
138
- CounterBlink(this.editor.frameContext.get('charWrapper'));
138
+ CounterBlink(this.frameContext.get('charWrapper'));
139
139
  if (nextCharCount > 0) return false;
140
140
  }
141
141
  }
@@ -149,7 +149,7 @@ Char.prototype = {
149
149
  /**
150
150
  * @private
151
151
  * @description The character counter blinks.
152
- * @param {Element} charWrapper this.editor.frameContext.get('charWrapper')
152
+ * @param {Element} charWrapper this.frameContext.get('charWrapper')
153
153
  */
154
154
  function CounterBlink(charWrapper) {
155
155
  if (charWrapper && !hasClass(charWrapper, 'se-blink')) {
@@ -74,8 +74,6 @@ function Component(editor) {
74
74
  this._bindClose_keydown = null;
75
75
  /** @type {__se__GlobalEventInfo|void} */
76
76
  this._bindClose_mousedown = null;
77
- /** @type {__se__GlobalEventInfo|void} */
78
- this._bindClose_touchstart = null;
79
77
  /** @type {boolean} */
80
78
  this.__selectionSelected = false;
81
79
 
@@ -101,15 +99,19 @@ Component.prototype = {
101
99
  * @param {Node} element Element to be inserted
102
100
  * @param {Object} [options] Options
103
101
  * @param {boolean} [options.skipCharCount=false] If true, it will be inserted even if "frameOptions.get('charCounter_max')" is exceeded.
104
- * @param {boolean} [options.skipSelection=false] If true, do not automatically select the inserted component.
105
102
  * @param {boolean} [options.skipHistory=false] If true, do not push to history.
103
+ * @param {boolean} [options.scrollTo=true] true : Scroll to the inserted element, false : Do not scroll.
104
+ * @param {?__se__ComponentInsertBehaviorType} [options.insertBehavior] If true, do not automatically select the inserted component. [default: options.get('componentInsertBehavior')]
105
+ * - If null, noting action is performed after insertion.
106
106
  * @returns {HTMLElement} The inserted element or new line (for HR)
107
107
  */
108
- insert(element, { skipCharCount, skipSelection, skipHistory } = {}) {
109
- if (this.editor.frameContext.get('isReadOnly') || (!skipCharCount && !this.char.check(element))) {
108
+ insert(element, { skipCharCount = false, skipHistory = false, scrollTo = true, insertBehavior } = {}) {
109
+ if (this.frameContext.get('isReadOnly') || (!skipCharCount && !this.char.check(element))) {
110
110
  return null;
111
111
  }
112
112
 
113
+ if (insertBehavior === undefined) insertBehavior = this.options.get('componentInsertBehavior');
114
+
113
115
  const r = this.html.remove();
114
116
  const isInline = this.isInline(element);
115
117
  this.selection.getRangeAndAddLine(this.selection.getRange(), r.container);
@@ -117,43 +119,95 @@ Component.prototype = {
117
119
  let oNode = null;
118
120
  let formatEl = this.format.getLine(selectionNode, null);
119
121
 
120
- if (dom.check.isListCell(formatEl)) {
121
- this.html.insertNode(element, { afterNode: isInline ? null : selectionNode === formatEl ? null : r.container.nextSibling, skipCharCount: true });
122
- if (!isInline && !element.nextSibling) element.parentNode.appendChild(dom.utils.createElement('BR'));
123
- } else {
124
- if (!isInline && this.selection.getRange().collapsed && (r.container.nodeType === 3 || dom.check.isBreak(r.container))) {
125
- const depthFormat = dom.query.getParentElement(r.container, this.format.isBlock.bind(this.format));
126
- oNode = this.nodeTransform.split(r.container, r.offset, !depthFormat ? 0 : dom.query.getNodeDepth(depthFormat) + 1);
127
- if (oNode) formatEl = /** @type {HTMLElement} */ (oNode.previousSibling);
122
+ try {
123
+ if (dom.check.isListCell(formatEl)) {
124
+ this.html.insertNode(element, { afterNode: isInline ? null : !dom.check.isZeroWidth(selectionNode) ? null : (selectionNode || r.container || {}).nextSibling, skipCharCount: true });
125
+ if (!isInline && !element.nextSibling) element.parentNode.appendChild(dom.utils.createElement('BR'));
126
+ } else {
127
+ if (!isInline && this.selection.getRange().collapsed && (r.container?.nodeType === 3 || dom.check.isBreak(r.container))) {
128
+ const depthFormat = dom.query.getParentElement(r.container, this.format.isBlock.bind(this.format));
129
+ oNode = this.nodeTransform.split(r.container, r.offset, !depthFormat ? 0 : dom.query.getNodeDepth(depthFormat) + 1);
130
+ if (oNode) formatEl = /** @type {HTMLElement} */ (oNode.previousSibling);
131
+ }
132
+ this.html.insertNode(element, { afterNode: isInline ? null : this.format.isBlock(formatEl) ? null : formatEl, skipCharCount: true });
133
+ if (!isInline && formatEl && dom.check.isZeroWidth(formatEl)) dom.utils.removeItem(formatEl);
128
134
  }
129
- this.html.insertNode(element, { afterNode: isInline ? null : this.format.isBlock(formatEl) ? null : formatEl, skipCharCount: true });
130
- if (!isInline && formatEl && dom.check.isZeroWidth(formatEl)) dom.utils.removeItem(formatEl);
131
- }
132
135
 
133
- if (isInline) {
134
- const empty = dom.utils.createTextNode(unicode.zeroWidthSpace);
135
- element.parentNode.insertBefore(empty, element.nextSibling);
136
+ if (isInline) {
137
+ const empty = dom.utils.createTextNode(unicode.zeroWidthSpace);
138
+ element.parentNode.insertBefore(empty, element.nextSibling);
139
+ }
140
+ } catch (e) {
141
+ console.error('Component insert error:', e);
136
142
  }
137
143
 
138
144
  if (!skipHistory) this.history.push(false);
139
145
 
140
- if (!skipSelection) {
141
- this.selection.setRange(element, 0, element, 0);
142
- const fileComponentInfo = this.get(element);
143
- if (fileComponentInfo) {
144
- this.select(fileComponentInfo.target, fileComponentInfo.pluginName);
145
- } else if (oNode) {
146
- oNode = dom.query.getEdgeChildNodes(oNode, null).sc || oNode;
147
- this.selection.setRange(oNode, 0, oNode, 0);
148
- }
146
+ // document type
147
+ if (this.frameContext.has('documentType_use_header')) {
148
+ this.frameContext.get('documentType').reHeader();
149
149
  }
150
150
 
151
- // document type
152
- if (this.editor.frameContext.has('documentType-use-header')) {
153
- this.editor.frameContext.get('documentType').reHeader();
151
+ const targetElement = /** @type {HTMLElement} */ (oNode || element);
152
+
153
+ if (scrollTo) this.selection.scrollTo(targetElement, { behavior: 'auto' });
154
+ if (insertBehavior !== null) this.applyInsertBehavior(element, oNode, insertBehavior);
155
+
156
+ return targetElement;
157
+ },
158
+
159
+ /**
160
+ * @this {ComponentThis}
161
+ * @description Handles post-insertion behavior for a newly created component based on the specified mode.
162
+ * @param {Node} container The inserted component element.
163
+ * @param {Node|null} [oNode] Optional node to use for selection if the component cannot be selected.
164
+ * @param {__se__ComponentInsertBehaviorType} [insertBehavior] Behavior mode after component insertion.
165
+ */
166
+ applyInsertBehavior(container, oNode, insertBehavior) {
167
+ const cInfo = this.get(container);
168
+
169
+ if (this.isInline(container)) {
170
+ const nr = this.selection.getNearRange(container);
171
+ if (nr) {
172
+ this.selection.setRange(nr.container, nr.offset, nr.container, nr.offset);
173
+ } else {
174
+ this.select(cInfo.target, cInfo.pluginName);
175
+ }
176
+ return;
154
177
  }
155
178
 
156
- return /** @type {HTMLElement} */ (oNode || element);
179
+ switch (insertBehavior) {
180
+ case 'auto': {
181
+ if (!this.__moveToNextLineOrAdd(container)) {
182
+ this.select(cInfo.target, cInfo.pluginName);
183
+ }
184
+
185
+ break;
186
+ }
187
+ case 'select': {
188
+ this.selection.setRange(container, 0, container, 0);
189
+
190
+ if (cInfo) {
191
+ this.select(cInfo.target, cInfo.pluginName);
192
+ } else if (oNode) {
193
+ oNode = dom.query.getEdgeChildNodes(oNode, null).sc || oNode;
194
+ this.selection.setRange(oNode, 0, oNode, 0);
195
+ }
196
+ break;
197
+ }
198
+ case 'line': {
199
+ if (!this.__moveToNextLineOrAdd(container)) {
200
+ const line = this.format.addLine(container, null);
201
+ if (line) this.selection.setRange(line, 0, line, 0);
202
+ }
203
+
204
+ break;
205
+ }
206
+ case 'none': {
207
+ // Do not select the component and remove the editor focus
208
+ break;
209
+ }
210
+ }
157
211
  },
158
212
 
159
213
  /**
@@ -173,7 +227,7 @@ Component.prototype = {
173
227
  let launcher = null;
174
228
 
175
229
  if (this.is(element)) {
176
- if (dom.utils.hasClass(element, 'se-component') && !dom.utils.hasClass(element, 'se-inline-component')) element = /** @type {HTMLElement} */ (element).firstElementChild || element;
230
+ if (dom.check.isComponentContainer(element) && !dom.utils.hasClass(element, 'se-inline-component')) element = /** @type {HTMLElement} */ (element).firstElementChild || element;
177
231
  if (/^FIGURE$/i.test(element.nodeName)) element = /** @type {HTMLElement} */ (element).firstElementChild;
178
232
  if (!element) return null;
179
233
 
@@ -204,7 +258,7 @@ Component.prototype = {
204
258
  const figureInfo = Figure.GetContainer(target);
205
259
  const container = figureInfo.container || figureInfo.cover || target;
206
260
  return (this.info = {
207
- target,
261
+ target: figureInfo.target,
208
262
  pluginName,
209
263
  options,
210
264
  container: container,
@@ -275,7 +329,7 @@ Component.prototype = {
275
329
  }, 0)();
276
330
 
277
331
  if (notOver && !this.status.hasFocus && !this.editor._preventFocus) {
278
- this.eventManager.__postFocusEvent(this.editor.frameContext, null);
332
+ this.eventManager.__postFocusEvent(this.frameContext, null);
279
333
  this.editor._preventFocus = true;
280
334
  }
281
335
 
@@ -297,7 +351,7 @@ Component.prototype = {
297
351
 
298
352
  this.editor.status.onSelected = true;
299
353
  } else if (isBreakComponent || !dom.utils.hasClass(info.container, 'se-input-component')) {
300
- const dragHandle = this.editor.frameContext.get('wrapper').querySelector('.se-drag-handle');
354
+ const dragHandle = this.frameContext.get('wrapper').querySelector('.se-drag-handle');
301
355
  dom.utils.addClass(dragHandle, 'se-drag-handle-full');
302
356
  this.ui._visibleControllers(false, false);
303
357
 
@@ -332,7 +386,7 @@ Component.prototype = {
332
386
  this.ui.setControllerOnDisabledButtons(false);
333
387
 
334
388
  if (this.editor._preventFocus && !this.status.hasFocus && !this.__prevent) {
335
- this.eventManager.__postBlurEvent(this.editor.frameContext, null);
389
+ this.eventManager.__postBlurEvent(this.frameContext, null);
336
390
  this.editor._preventFocus = false;
337
391
  }
338
392
  },
@@ -348,7 +402,7 @@ Component.prototype = {
348
402
  is(element) {
349
403
  if (!element) return false;
350
404
 
351
- if (/^FIGURE$/i.test(element.nodeName) || dom.utils.hasClass(element, 'se-component')) return true;
405
+ if (/^FIGURE$/i.test(element.nodeName) || dom.check.isComponentContainer(element)) return true;
352
406
  if (this.editor._componentManager.find((f) => f(element))) return true;
353
407
 
354
408
  return false;
@@ -392,7 +446,7 @@ Component.prototype = {
392
446
  * - This function is different from the one called when the user presses the "Ctrl + C" key combination.
393
447
  * @param {Node} container The DOM node to check.
394
448
  */
395
- copy(container) {
449
+ async copy(container) {
396
450
  const cloneContainer = /** @type {HTMLElement} */ (dom.utils.clone(container, true));
397
451
 
398
452
  // remove selected class
@@ -402,7 +456,7 @@ Component.prototype = {
402
456
  dom.utils.removeClass(cloneContainer.querySelector('.se-selected-cell-focus'), 'se-selected-cell-focus');
403
457
 
404
458
  // copy to clipboard
405
- this.html.copy(cloneContainer);
459
+ if ((await this.html.copy(cloneContainer)) === false) return;
406
460
 
407
461
  // copy effect
408
462
  dom.utils.flashClass(container, 'se-copy');
@@ -442,7 +496,9 @@ Component.prototype = {
442
496
  }
443
497
 
444
498
  const { frameContext } = this.editor;
445
- frameContext.get('lineBreaker_t').style.display = frameContext.get('lineBreaker_b').style.display = 'none';
499
+ if (frameContext.get('lineBreaker_t')) {
500
+ frameContext.get('lineBreaker_t').style.display = frameContext.get('lineBreaker_b').style.display = 'none';
501
+ }
446
502
 
447
503
  if (this.currentPlugin && typeof this.currentPlugin.deselect === 'function') {
448
504
  this.currentPlugin.deselect(this.currentTarget);
@@ -457,6 +513,31 @@ Component.prototype = {
457
513
  this.ui.__offControllers();
458
514
  },
459
515
 
516
+ /**
517
+ * @private
518
+ * @this {ComponentThis}
519
+ * @description
520
+ * Attempts to move the cursor to a valid line after the given container.
521
+ * - If a valid next sibling line exists, moves the selection there.
522
+ * - If no next sibling exists, creates a new line after the container and moves the selection there.
523
+ * - If the next sibling exists but is not a valid line element and cannot create a new line, returns false.
524
+ * @param {Node} container The component container element.
525
+ * @returns {boolean} Returns true if the selection moved to a line (existing or newly created), otherwise false.
526
+ */
527
+ __moveToNextLineOrAdd(container) {
528
+ const nextSibling = /** @type {Element} */ (container).nextElementSibling;
529
+ if (!nextSibling) {
530
+ const line = this.format.addLine(container, null);
531
+ if (line) this.selection.setRange(line, 0, line, 0);
532
+ return true;
533
+ } else if (this.format.isLine(nextSibling)) {
534
+ this.selection.setRange(nextSibling, 0, nextSibling, 0);
535
+ return true;
536
+ }
537
+
538
+ return false;
539
+ },
540
+
460
541
  /**
461
542
  * @private
462
543
  * @this {ComponentThis}
@@ -469,7 +550,7 @@ Component.prototype = {
469
550
  const info = this.get(element);
470
551
  if (!info) return;
471
552
 
472
- const fc = this.editor.frameContext;
553
+ const fc = this.frameContext;
473
554
  const container = info.container;
474
555
  const isNonSelected = dom.utils.hasClass(container, 'se-flex-component');
475
556
  const lb_t = fc.get('lineBreaker_t');
@@ -487,7 +568,7 @@ Component.prototype = {
487
568
  const { top, left, right, scrollX, scrollY } = this.offset.getLocal(offsetTarget);
488
569
  const sideOffset = isRtl ? right : left;
489
570
 
490
- if (isList ? !container.previousSibling : !this.format.isLine(container.previousElementSibling)) {
571
+ if (isList ? (!dom.check.isBreak(container.previousElementSibling) && !container.previousSibling?.textContent?.trim()) || this.is(container.previousElementSibling) : !this.format.isLine(container.previousElementSibling)) {
491
572
  const cStyle = _w.getComputedStyle(lb_t);
492
573
  const cH = numbers.get(cStyle.height, 1);
493
574
  const cW = numbers.get(cStyle.width, 1);
@@ -496,7 +577,7 @@ Component.prototype = {
496
577
  componentTop = top;
497
578
  w = target.offsetWidth / 2 / 2;
498
579
 
499
- t_style.top = componentTop - scrollY - cH / 2 + 'px';
580
+ t_style.top = componentTop - cH / 2 + 'px';
500
581
  t_style[dir[0]] = (isNonSelected ? sideOffset - cW / 2 : sideOffset + w) + 'px';
501
582
  t_style[dir[1]] = '';
502
583
 
@@ -511,7 +592,7 @@ Component.prototype = {
511
592
  }
512
593
 
513
594
  // bottom
514
- if (isList ? !container.nextSibling : !this.format.isLine(container.nextElementSibling)) {
595
+ if (isList ? (!dom.check.isBreak(container.nextElementSibling) && !container.nextSibling?.textContent?.trim()) || this.is(container.nextElementSibling) : !this.format.isLine(container.nextElementSibling)) {
515
596
  const cStyle = _w.getComputedStyle(lb_b);
516
597
  const cH = numbers.get(cStyle.height, 1);
517
598
  const cW = numbers.get(cStyle.width, 1);
@@ -522,7 +603,7 @@ Component.prototype = {
522
603
  w = target.offsetWidth / 2 / 2;
523
604
  }
524
605
 
525
- b_style.top = componentTop + target.offsetHeight - scrollY - cH / 2 + 'px';
606
+ b_style.top = componentTop + target.offsetHeight - cH / 2 + 'px';
526
607
  b_style[dir[0]] = sideOffset + target.offsetWidth - (isNonSelected ? 0 : w) - (isNonSelected ? cW / 2 : cW) + 'px';
527
608
  b_style[dir[1]] = '';
528
609
 
@@ -556,9 +637,9 @@ Component.prototype = {
556
637
  */
557
638
  __removeGlobalEvent() {
558
639
  this.__removeNotFileGlobalEvent();
559
- if (this._bindClose_copy) this._bindClose_copy = this.eventManager.removeGlobalEvent(this._bindClose_copy);
560
- if (this._bindClose_cut) this._bindClose_cut = this.eventManager.removeGlobalEvent(this._bindClose_cut);
561
- if (this._bindClose_keydown) this._bindClose_keydown = this.eventManager.removeGlobalEvent(this._bindClose_keydown);
640
+ this._bindClose_copy &&= this.eventManager.removeGlobalEvent(this._bindClose_copy);
641
+ this._bindClose_cut &&= this.eventManager.removeGlobalEvent(this._bindClose_cut);
642
+ this._bindClose_keydown &&= this.eventManager.removeGlobalEvent(this._bindClose_keydown);
562
643
  },
563
644
 
564
645
  /**
@@ -568,8 +649,7 @@ Component.prototype = {
568
649
  */
569
650
  __addNotFileGlobalEvent() {
570
651
  this.__removeNotFileGlobalEvent();
571
- if (!isMobile) this._bindClose_mousedown = this.eventManager.addGlobalEvent('mousedown', this.__globalEvents.mousedown, true);
572
- else this._bindClose_touchstart = this.eventManager.addGlobalEvent('touchstart', this.__globalEvents.mousedown, true);
652
+ this._bindClose_mousedown = this.eventManager.addGlobalEvent(isMobile ? 'click' : 'mousedown', this.__globalEvents.mousedown, true);
573
653
  },
574
654
 
575
655
  /**
@@ -578,8 +658,7 @@ Component.prototype = {
578
658
  * @description Removes global event listeners related to non-file interactions.
579
659
  */
580
660
  __removeNotFileGlobalEvent() {
581
- if (this._bindClose_mousedown) this._bindClose_mousedown = this.eventManager.removeGlobalEvent(this._bindClose_mousedown);
582
- if (this._bindClose_touchstart) this._bindClose_touchstart = this.eventManager.removeGlobalEvent(this._bindClose_touchstart);
661
+ this._bindClose_mousedown &&= this.eventManager.removeGlobalEvent(this._bindClose_mousedown);
583
662
  },
584
663
 
585
664
  /**
@@ -660,6 +739,8 @@ function OnDragClick(e) {
660
739
  if (!dom.utils.hasClass(target, 'se-drag-handle-full')) return;
661
740
 
662
741
  const dragInst = _DragHandle.get('__dragInst');
742
+ if (!dragInst) return;
743
+
663
744
  this._removeDragEvent();
664
745
  this.select(dragInst.currentTarget, dragInst.currentPluginName);
665
746
  }
@@ -733,10 +814,10 @@ async function OnKeyDown_component(e) {
733
814
  if (ctrl) {
734
815
  if (keyCode !== 'ControlRight' && keyCode !== 'ControlLeft') {
735
816
  const info = this.editor.shortcutsKeyMap.get(keyCode + (e.shiftKey ? '1000' : ''));
736
- if (/^(redo|undo)$/.test(info?.c)) {
817
+ if (/^(redo|undo)$/.test(info?.command)) {
737
818
  e.preventDefault();
738
819
  e.stopPropagation();
739
- this.editor.run(info.c, info.t, info.e);
820
+ this.editor.run(info.command, info.type, info.button);
740
821
  }
741
822
  }
742
823
  return;
@@ -746,10 +827,16 @@ async function OnKeyDown_component(e) {
746
827
  if (keyCodeMap.isRemoveKey(keyCode)) {
747
828
  e.preventDefault();
748
829
  e.stopPropagation();
749
- if (typeof this.currentPlugin?.destroy === 'function') {
830
+ if (typeof this.currentPlugin?.destroy === 'function' && (!this.info.isInputType || !this.status.hasFocus)) {
831
+ const focusNode = this.info.container.previousSibling;
750
832
  await this.currentPlugin.destroy(this.currentTarget);
751
833
  this.deselect();
752
- this.editor.focus();
834
+ if (focusNode) {
835
+ const offset = focusNode.nodeType === 3 ? focusNode.textContent.length : 1;
836
+ this.selection.setRange(focusNode, offset, focusNode, offset);
837
+ } else {
838
+ this.editor.focus();
839
+ }
753
840
  return;
754
841
  }
755
842
  }
@@ -777,6 +864,7 @@ async function OnKeyDown_component(e) {
777
864
  }
778
865
 
779
866
  // up down, left right
867
+ DIR_KEYCODE.lastIndex = 0;
780
868
  if (DIR_KEYCODE.test(keyCode)) {
781
869
  const { container } = this.get(this.currentTarget);
782
870
  const isInline = this.isInline(container || this.currentTarget);
@@ -808,6 +896,7 @@ async function OnKeyDown_component(e) {
808
896
  }
809
897
  }
810
898
  } else {
899
+ DIR_UP_KEYCODE.lastIndex = 0;
811
900
  if (DIR_UP_KEYCODE.test(keyCode)) {
812
901
  el = container.previousElementSibling;
813
902
  } else {