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
@@ -1,7 +1,7 @@
1
1
  import EditorInjector from '../../editorInjector';
2
2
  import { Modal, Figure } from '../../modules';
3
3
  import { dom, numbers, env, keyCodeMap } from '../../helper';
4
- const { NO_EVENT } = env;
4
+ const { _w, NO_EVENT } = env;
5
5
 
6
6
  /**
7
7
  * @typedef {import('../../events').ProcessInfo} ProcessInfo_embed
@@ -46,6 +46,11 @@ const { NO_EVENT } = env;
46
46
  * // Additional services...
47
47
  * }
48
48
  * @property {FigureControls_embed} [controls] - Figure controls.
49
+ * @property {__se__ComponentInsertBehaviorType} [insertBehavior] - Component insertion behavior for selection and cursor placement. [default: options.get('componentInsertBehavior')]
50
+ * - `auto`: Move cursor to the next line if possible, otherwise select the component.
51
+ * - `select`: Always select the inserted component.
52
+ * - `line`: Move cursor to the next line if possible, or create a new line and move there.
53
+ * - `none`: Do nothing.
49
54
  */
50
55
 
51
56
  /**
@@ -63,16 +68,46 @@ class Embed extends EditorInjector {
63
68
  * @returns {HTMLElement|null} Returns a node if the node is a valid component.
64
69
  */
65
70
  static component(node) {
71
+ const children = node.children;
66
72
  let src = '';
67
- if (dom.check.isIFrame(node)) src = node.src;
68
- if (/^DIV$/i.test(node?.nodeName) && dom.check.isIFrame(node.firstElementChild)) src = node.firstElementChild.src;
73
+ let target = null;
74
+
75
+ if (dom.check.isIFrame(node)) {
76
+ target = node;
77
+ src = node.src;
78
+ }
79
+ if (!src && /^DIV$/i.test(node?.nodeName) && dom.check.isIFrame(children[0])) {
80
+ target = children[0];
81
+ src = target.src;
82
+ }
83
+ if (!src && dom.utils.hasClass(node, 'se-embed-container')) {
84
+ /** @type {*} */
85
+ const srcNode = dom.query.getChildNode(node, (current) => current.src || current.href);
86
+ target = srcNode;
87
+ src = target?.src || target?.href;
88
+ }
69
89
 
70
90
  if (src) {
71
- return this.checkContentType(src) ? node : null;
91
+ return this.checkContentType(src) ? target : null;
72
92
  }
73
- return null;
93
+
94
+ return target;
74
95
  }
75
96
 
97
+ #linkValue;
98
+ #align;
99
+ #defaultSizeX;
100
+ #defaultSizeY;
101
+ #element;
102
+ #cover;
103
+ #container;
104
+ #ratio;
105
+ #origin_w;
106
+ #origin_h;
107
+ #resizing;
108
+ #onlyPercentage;
109
+ #nonResizing;
110
+
76
111
  /**
77
112
  * @constructor
78
113
  * @param {__se__EditorCore} editor - The root editor instance
@@ -97,13 +132,14 @@ class Embed extends EditorInjector {
97
132
  uploadSingleSizeLimit: numbers.get(pluginOptions.uploadSingleSizeLimit, 0),
98
133
  iframeTagAttributes: pluginOptions.iframeTagAttributes || null,
99
134
  query_youtube: pluginOptions.query_youtube || '',
100
- query_vimeo: pluginOptions.query_vimeo || ''
135
+ query_vimeo: pluginOptions.query_vimeo || '',
136
+ insertBehavior: pluginOptions.insertBehavior
101
137
  };
102
138
 
103
139
  // create HTML
104
140
  const sizeUnit = this.pluginOptions.percentageOnlySize ? '%' : 'px';
105
141
  const modalEl = CreateHTML_modal(editor, this.pluginOptions);
106
- const figureControls = pluginOptions.controls || !this.pluginOptions.canResize ? [['align', 'edit', 'copy', 'remove']] : [['resize_auto,75,50', 'align', 'edit', 'revert', 'copy', 'remove']];
142
+ const figureControls = pluginOptions.controls || (!this.pluginOptions.canResize ? [['align', 'edit', 'copy', 'remove']] : [['resize_auto,75,50', 'align', 'edit', 'revert', 'copy', 'remove']]);
107
143
 
108
144
  // show align
109
145
  if (!figureControls.some((subArray) => subArray.includes('align'))) modalEl.figureAlignBtn.style.display = 'none';
@@ -117,23 +153,25 @@ class Embed extends EditorInjector {
117
153
  this.embedInput = modalEl.embedInput;
118
154
  this.focusElement = this.embedInput;
119
155
  this.previewSrc = modalEl.previewSrc;
120
- this._linkValue = '';
121
- this._align = 'none';
122
- this._defaultSizeX = this.pluginOptions.defaultWidth;
123
- this._defaultSizeY = this.pluginOptions.defaultHeight;
124
156
  this.sizeUnit = sizeUnit;
125
157
  this.proportion = null;
126
158
  this.inputX = null;
127
159
  this.inputY = null;
128
- this._element = null;
129
- this._cover = null;
130
- this._container = null;
131
- this._ratio = { w: 1, h: 1 };
132
- this._origin_w = this.pluginOptions.defaultWidth === 'auto' ? '' : this.pluginOptions.defaultWidth;
133
- this._origin_h = this.pluginOptions.defaultHeight === 'auto' ? '' : this.pluginOptions.defaultHeight;
134
- this._resizing = this.pluginOptions.canResize;
135
- this._onlyPercentage = this.pluginOptions.percentageOnlySize;
136
- this._nonResizing = !this._resizing || !this.pluginOptions.showHeightInput || this._onlyPercentage;
160
+
161
+ this.#linkValue = '';
162
+ this.#align = 'none';
163
+ this.#defaultSizeX = this.pluginOptions.defaultWidth;
164
+ this.#defaultSizeY = this.pluginOptions.defaultHeight;
165
+ this.#element = null;
166
+ this.#cover = null;
167
+ this.#container = null;
168
+ this.#ratio = { w: 0, h: 0 };
169
+ this.#origin_w = this.pluginOptions.defaultWidth === 'auto' ? '' : this.pluginOptions.defaultWidth;
170
+ this.#origin_h = this.pluginOptions.defaultHeight === 'auto' ? '' : this.pluginOptions.defaultHeight;
171
+ this.#resizing = this.pluginOptions.canResize;
172
+ this.#onlyPercentage = this.pluginOptions.percentageOnlySize;
173
+ this.#nonResizing = !this.#resizing || !this.pluginOptions.showHeightInput || this.#onlyPercentage;
174
+
137
175
  this.query = {
138
176
  facebook: {
139
177
  pattern: /(?:https?:\/\/)?(?:www\.)?(?:facebook\.com)\/(.+)/i,
@@ -143,7 +181,7 @@ class Embed extends EditorInjector {
143
181
  tag: 'iframe'
144
182
  },
145
183
  twitter: {
146
- pattern: /(?:https?:\/\/)?(?:www\.)?(?:twitter\.com)\/(status|embed)\/(.+)/i,
184
+ pattern: /^(?:https?:\/\/)?(?:(?:www\.)?(?:twitter\.com|x\.com)\/(?:[^/?#]+\/)?status\/\d+(?:[/?#]|$)|platform\.twitter\.com\/embed\/Tweet\.html(?:[?#].*)?$)/i,
147
185
  action: (url) => {
148
186
  return `https://platform.twitter.com/embed/Tweet.html?url=${encodeURIComponent(url)}`;
149
187
  },
@@ -202,7 +240,7 @@ class Embed extends EditorInjector {
202
240
  // init
203
241
  this.eventManager.addEvent(this.embedInput, 'input', this.#OnLinkPreview.bind(this));
204
242
 
205
- if (this._resizing) {
243
+ if (this.#resizing) {
206
244
  this.proportion = modalEl.proportion;
207
245
  this.inputX = modalEl.inputX;
208
246
  this.inputY = modalEl.inputY;
@@ -237,10 +275,12 @@ class Embed extends EditorInjector {
237
275
  * @param {boolean} isUpdate "Indicates whether the modal is for editing an existing component (true) or registering a new one (false)."
238
276
  */
239
277
  on(isUpdate) {
240
- if (!isUpdate && this._resizing) {
241
- this.inputX.value = this._origin_w = this.pluginOptions.defaultWidth === 'auto' ? '' : this.pluginOptions.defaultWidth;
242
- this.inputY.value = this._origin_h = this.pluginOptions.defaultHeight === 'auto' ? '' : this.pluginOptions.defaultHeight;
278
+ if (!isUpdate && this.#resizing) {
279
+ this.inputX.value = this.#origin_w = this.pluginOptions.defaultWidth === 'auto' ? '' : this.pluginOptions.defaultWidth;
280
+ this.inputY.value = this.#origin_h = this.pluginOptions.defaultHeight === 'auto' ? '' : this.pluginOptions.defaultHeight;
243
281
  this.proportion.disabled = true;
282
+ } else if (isUpdate) {
283
+ this.#linkValue = this.previewSrc.textContent = this.embedInput.value = this.#cover.getAttribute('data-se-origin') || '';
244
284
  }
245
285
  }
246
286
 
@@ -250,14 +290,14 @@ class Embed extends EditorInjector {
250
290
  * @returns {Promise<boolean>} Success / failure
251
291
  */
252
292
  async modalAction() {
253
- this._align = /** @type {HTMLInputElement} */ (this.modal.form.querySelector('input[name="suneditor_embed_radio"]:checked')).value;
293
+ this.#align = /** @type {HTMLInputElement} */ (this.modal.form.querySelector('input[name="suneditor_embed_radio"]:checked')).value;
254
294
 
255
295
  let result = false;
256
- if (this._linkValue.length > 0) {
257
- result = await this.submitSRC(this._linkValue);
296
+ if (this.#linkValue.length > 0) {
297
+ result = await this.submitSRC(this.#linkValue);
258
298
  }
259
299
 
260
- if (result) this._w.setTimeout(this.component.select.bind(this.component, this._element, Embed.key), 0);
300
+ if (result) _w.setTimeout(this.component.select.bind(this.component, this.#element, Embed.key), 0);
261
301
 
262
302
  return result;
263
303
  }
@@ -282,11 +322,11 @@ class Embed extends EditorInjector {
282
322
  const figureInfo = Figure.GetContainer(element);
283
323
  if (figureInfo && figureInfo.container && figureInfo.cover) return;
284
324
 
285
- this._ready(element);
325
+ this.#ready(element, true);
286
326
  const line = this.format.getLine(element);
287
- if (line) this._align = line.style.textAlign || line.style.float;
327
+ if (line) this.#align = line.style.textAlign || line.style.float;
288
328
 
289
- this._update(element);
329
+ this.#fixTagStructure(element);
290
330
  }
291
331
  };
292
332
  }
@@ -297,15 +337,15 @@ class Embed extends EditorInjector {
297
337
  */
298
338
  init() {
299
339
  Modal.OnChangeFile(this.fileModalWrapper, []);
300
- this._linkValue = this.previewSrc.textContent = this.embedInput.value = '';
340
+ this.#linkValue = this.previewSrc.textContent = this.embedInput.value = '';
301
341
 
302
342
  /** @type {HTMLInputElement} */ (this.modal.form.querySelector('input[name="suneditor_embed_radio"][value="none"]')).checked = true;
303
- this._ratio = { w: 1, h: 1 };
304
- this._nonResizing = false;
343
+ this.#ratio = { w: 0, h: 0 };
344
+ this.#nonResizing = false;
305
345
 
306
- if (this._resizing) {
307
- this.inputX.value = this.pluginOptions.defaultWidth === this._defaultSizeX ? '' : this.pluginOptions.defaultWidth;
308
- this.inputY.value = this.pluginOptions.defaultHeight === this._defaultSizeY ? '' : this.pluginOptions.defaultHeight;
346
+ if (this.#resizing) {
347
+ this.inputX.value = this.pluginOptions.defaultWidth === this.#defaultSizeX ? '' : this.pluginOptions.defaultWidth;
348
+ this.inputY.value = this.pluginOptions.defaultHeight === this.#defaultSizeY ? '' : this.pluginOptions.defaultHeight;
309
349
  this.proportion.checked = false;
310
350
  this.proportion.disabled = true;
311
351
  }
@@ -317,61 +357,7 @@ class Embed extends EditorInjector {
317
357
  * @param {HTMLElement} target Target component element
318
358
  */
319
359
  select(target) {
320
- this._ready(target);
321
- }
322
-
323
- /**
324
- * @private
325
- * @description Prepares the component for selection.
326
- * - Ensures that the controller is properly positioned and initialized.
327
- * - Prevents duplicate event handling if the component is already selected.
328
- * @param {HTMLElement} target - The selected element.
329
- */
330
- _ready(target) {
331
- if (!target) return;
332
- const figureInfo = this.figure.open(target, { nonResizing: this._nonResizing, nonSizeInfo: false, nonBorder: false, figureTarget: false, __fileManagerInfo: false });
333
-
334
- this._element = target;
335
- this._cover = figureInfo.cover;
336
- this._container = figureInfo.container;
337
- this._caption = figureInfo.caption;
338
- this._align = figureInfo.align;
339
- target.style.float = '';
340
-
341
- this._origin_w = String(figureInfo.originWidth || figureInfo.w || '');
342
- this._origin_h = String(figureInfo.originHeight || figureInfo.h || '');
343
-
344
- /** @type {HTMLInputElement} */
345
- const activeAlign = this.modal.form.querySelector('input[name="suneditor_embed_radio"][value="' + this._align + '"]') || this.modal.form.querySelector('input[name="suneditor_embed_radio"][value="none"]');
346
- activeAlign.checked = true;
347
-
348
- if (!this._resizing) return;
349
-
350
- const percentageRotation = this._onlyPercentage && this.figure.isVertical;
351
- let w = percentageRotation ? '' : figureInfo.width;
352
- if (this._onlyPercentage) {
353
- w = numbers.get(w, 2);
354
- if (w > 100) w = 100;
355
- }
356
-
357
- this.inputX.value = String(w === 'auto' ? '' : w);
358
-
359
- if (!this._onlyPercentage) {
360
- const h = percentageRotation ? '' : figureInfo.height;
361
- this.inputY.value = String(h === 'auto' ? '' : h);
362
- }
363
-
364
- this.proportion.checked = true;
365
- this.inputX.disabled = percentageRotation ? true : false;
366
- this.inputY.disabled = percentageRotation ? true : false;
367
- this.proportion.disabled = percentageRotation ? true : false;
368
-
369
- this._ratio = this.proportion.checked
370
- ? figureInfo.ratio
371
- : {
372
- w: 1,
373
- h: 1
374
- };
360
+ this.#ready(target);
375
361
  }
376
362
 
377
363
  /**
@@ -381,18 +367,18 @@ class Embed extends EditorInjector {
381
367
  * @returns {Promise<void>}
382
368
  */
383
369
  async destroy(target) {
384
- const targetEl = target || this._element;
370
+ const targetEl = target || this.#element;
385
371
  const container = dom.query.getParentElement(targetEl, Figure.is) || targetEl;
386
372
  const focusEl = container.previousElementSibling || container.nextElementSibling;
387
373
  const emptyDiv = container.parentNode;
388
374
 
389
- const message = await this.triggerEvent('onEmbedDeleteBefore', { element: targetEl, container, align: this._align, url: this._linkValue });
375
+ const message = await this.triggerEvent('onEmbedDeleteBefore', { element: targetEl, container, align: this.#align, url: this.#linkValue });
390
376
  if (message === false) return;
391
377
 
392
378
  dom.utils.removeItem(container);
393
379
  this.init();
394
380
 
395
- if (emptyDiv !== this.editor.frameContext.get('wysiwyg')) {
381
+ if (emptyDiv !== this.frameContext.get('wysiwyg')) {
396
382
  this.nodeTransform.removeAllParents(
397
383
  emptyDiv,
398
384
  function (current) {
@@ -450,27 +436,24 @@ class Embed extends EditorInjector {
450
436
  * @returns {Promise<boolean>} A promise that resolves to true on success or false on failure.
451
437
  */
452
438
  async submitSRC(src) {
453
- if (!src) src = this._linkValue;
454
- if (!src) return false;
439
+ if (!(src ||= this.#linkValue)) return false;
455
440
 
456
441
  let embedInfo = null;
457
442
  if (/^<iframe\s|^<blockquote\s/i.test(src)) {
458
443
  const embedDOM = new DOMParser().parseFromString(src, 'text/html').body.children;
459
444
  if (embedDOM.length === 0) return false;
460
- embedInfo = { children: embedDOM, ...this._getInfo(), process: null };
445
+ embedInfo = { children: embedDOM, ...this.#getInfo(), process: null };
461
446
  } else {
462
447
  const processUrl = this.findProcessUrl(src);
463
448
  if (!processUrl) return false;
464
449
  src = processUrl.url;
465
- embedInfo = { url: src, ...this._getInfo(), process: processUrl };
450
+ embedInfo = { url: src, ...this.#getInfo(), process: processUrl };
466
451
  }
467
452
 
468
- const handler = function (infos, newInfos) {
453
+ const handler = function (uploadCallback, infos, newInfos) {
469
454
  infos = newInfos || infos;
470
- this._create(infos.process, infos.url, infos.children, infos.inputWidth, infos.inputHeight, infos.align, infos.isUpdate);
471
- }.bind(this, embedInfo);
472
- // se-ts-ignore
473
- void this._create;
455
+ uploadCallback(src, infos.process, infos.url, infos.children, infos.inputWidth, infos.inputHeight, infos.align, infos.isUpdate);
456
+ }.bind(this, this.#create.bind(this), embedInfo);
474
457
 
475
458
  const result = await this.triggerEvent('onEmbedInputBefore', {
476
459
  ...embedInfo,
@@ -487,39 +470,82 @@ class Embed extends EditorInjector {
487
470
  }
488
471
 
489
472
  /**
490
- * @private
473
+ * @description Prepares the component for selection.
474
+ * - Ensures that the controller is properly positioned and initialized.
475
+ * - Prevents duplicate event handling if the component is already selected.
476
+ * @param {HTMLElement} target - The selected element.
477
+ * @param {boolean} [infoOnly=false] - If true, only retrieves information without opening the controller.
478
+ */
479
+ #ready(target, infoOnly = false) {
480
+ if (!target) return;
481
+ const figureInfo = this.figure.open(target, { nonResizing: this.#nonResizing, nonSizeInfo: false, nonBorder: false, figureTarget: false, infoOnly });
482
+
483
+ this.#element = target;
484
+ this.#cover = figureInfo.cover;
485
+ this.#container = figureInfo.container;
486
+ this._caption = figureInfo.caption;
487
+ this.#align = figureInfo.align;
488
+ target.style.float = '';
489
+
490
+ this.#origin_w = String(figureInfo.originWidth || figureInfo.w || '');
491
+ this.#origin_h = String(figureInfo.originHeight || figureInfo.h || '');
492
+
493
+ /** @type {HTMLInputElement} */
494
+ const activeAlign = this.modal.form.querySelector('input[name="suneditor_embed_radio"][value="' + this.#align + '"]') || this.modal.form.querySelector('input[name="suneditor_embed_radio"][value="none"]');
495
+ activeAlign.checked = true;
496
+
497
+ if (!this.#resizing) return;
498
+
499
+ const percentageRotation = this.#onlyPercentage && this.figure.isVertical;
500
+ const { dw, dh } = this.figure.getSize(target);
501
+ this.inputX.value = dw === 'auto' ? '' : dw;
502
+ this.inputY.value = dh === 'auto' ? '' : dh;
503
+
504
+ this.proportion.checked = true;
505
+ this.inputX.disabled = percentageRotation ? true : false;
506
+ this.inputY.disabled = percentageRotation ? true : false;
507
+ this.proportion.disabled = percentageRotation ? true : false;
508
+
509
+ this.#ratio = this.proportion.checked
510
+ ? figureInfo.ratio
511
+ : {
512
+ w: 0,
513
+ h: 0
514
+ };
515
+ }
516
+
517
+ /**
491
518
  * @description Creates an iframe element for embedding external content.
492
519
  * @returns {HTMLIFrameElement} The created iframe element.
493
520
  */
494
- _createIframeTag() {
521
+ #createIframeTag() {
495
522
  /** @type {HTMLIFrameElement} */
496
523
  const iframeTag = dom.utils.createElement('IFRAME');
497
- this._setIframeAttrs(iframeTag);
524
+ this.#setIframeAttrs(iframeTag);
498
525
  return iframeTag;
499
526
  }
500
527
 
501
528
  /**
502
- * @private
503
529
  * @description Creates an blockquote element for embedding external content.
504
530
  * @returns {HTMLElement} The created iframe element.
505
531
  */
506
- _createEmbedTag() {
532
+ #createEmbedTag() {
507
533
  const quoteTag = dom.utils.createElement('BLOCKQUOTE');
508
534
  return quoteTag;
509
535
  }
510
536
 
511
537
  /**
512
- * @private
513
538
  * @description Creates an embed component (iframe or blockquote) and inserts it into the editor.
514
- * @param {?ProcessInfo_embed} process - Processed embed information.
515
- * @param {?string} src - The source URL.
516
- * @param {?Node[]} children - The embed elements.
539
+ * @param {string} originSrc - The origin input source.
540
+ * @param {ProcessInfo_embed} process - Processed embed information.
541
+ * @param {string} src - The source URL.
542
+ * @param {Node[]} children - The embed elements.
517
543
  * @param {string} width - The width of the embed component.
518
544
  * @param {string} height - The height of the embed component.
519
545
  * @param {string} align - The alignment of the embed component.
520
546
  * @param {boolean} isUpdate - Whether this is an update to an existing embed component.
521
547
  */
522
- _create(process, src, children, width, height, align, isUpdate) {
548
+ #create(originSrc, process, src, children, width, height, align, isUpdate) {
523
549
  let oFrame = null;
524
550
  let cover = null;
525
551
  let container = null;
@@ -527,16 +553,16 @@ class Embed extends EditorInjector {
527
553
 
528
554
  /** update */
529
555
  if (isUpdate) {
530
- oFrame = this._element;
556
+ oFrame = this.#element;
531
557
  if (oFrame.src !== src) {
532
558
  const processUrl = this.findProcessUrl(src);
533
559
  if (/^iframe$/i.test(processUrl?.tag) && !/^iframe$/i.test(oFrame.nodeName)) {
534
- const newTag = this._createIframeTag();
560
+ const newTag = this.#createIframeTag();
535
561
  newTag.src = src;
536
562
  oFrame.replaceWith(newTag);
537
563
  oFrame = newTag;
538
564
  } else if (/^blockquote$/i.test(processUrl?.tag) && !/^blockquote$/i.test(oFrame.nodeName)) {
539
- const newTag = this._createEmbedTag();
565
+ const newTag = this.#createEmbedTag();
540
566
  newTag.setAttribute('src', src);
541
567
  oFrame.replaceWith(newTag);
542
568
  oFrame = newTag;
@@ -544,12 +570,12 @@ class Embed extends EditorInjector {
544
570
  oFrame.src = src;
545
571
  }
546
572
  }
547
- container = this._container;
573
+ container = this.#container;
548
574
  cover = dom.query.getParentElement(oFrame, 'FIGURE');
549
575
  } else {
550
576
  /** create */
551
577
  if (process) {
552
- oFrame = this._createIframeTag();
578
+ oFrame = this.#createIframeTag();
553
579
  oFrame.src = src;
554
580
  const figure = Figure.CreateContainer(oFrame, 'se-embed-container');
555
581
  cover = figure.cover;
@@ -574,27 +600,31 @@ class Embed extends EditorInjector {
574
600
  }
575
601
 
576
602
  /** rendering */
577
- this._element = oFrame;
578
- this._cover = cover;
579
- this._container = container;
580
- this.figure.open(oFrame, { nonResizing: this._nonResizing, nonSizeInfo: false, nonBorder: false, figureTarget: false, __fileManagerInfo: true });
603
+ this.#element = oFrame;
604
+ this.#cover = cover;
605
+ this.#container = container;
606
+ this.figure.open(oFrame, { nonResizing: this.#nonResizing, nonSizeInfo: false, nonBorder: false, figureTarget: false, infoOnly: true });
607
+
608
+ width ||= this.#defaultSizeX;
609
+ height ||= this.#defaultSizeY;
581
610
 
582
- width = width || this._defaultSizeX;
583
- height = height || this._defaultSizeY;
584
611
  const size = this.figure.getSize(oFrame);
585
612
  const inputUpdate = size.w !== width || size.h !== height;
586
613
  const changeSize = !isUpdate || inputUpdate;
587
614
 
588
615
  // set size
589
616
  if (changeSize) {
590
- this._applySize(width, height);
617
+ this.#applySize(width, height);
591
618
  }
592
619
 
593
620
  // align
594
621
  this.figure.setAlign(oFrame, align);
595
622
 
623
+ // origin src
624
+ cover.setAttribute('data-se-origin', originSrc);
625
+
596
626
  if (!isUpdate) {
597
- this.component.insert(container, { skipCharCount: false, skipSelection: true, skipHistory: true });
627
+ this.component.insert(container, { skipHistory: true, scrollTo: false, insertBehavior: this.pluginOptions.insertBehavior });
598
628
 
599
629
  if (scriptTag) {
600
630
  try {
@@ -619,7 +649,7 @@ class Embed extends EditorInjector {
619
649
  }
620
650
  });
621
651
 
622
- observer.observe(this.editor.frameContext.get('wysiwyg'), {
652
+ observer.observe(this.frameContext.get('wysiwyg'), {
623
653
  subtree: true,
624
654
  childList: true
625
655
  });
@@ -629,28 +659,25 @@ class Embed extends EditorInjector {
629
659
  }
630
660
  }
631
661
 
632
- if (!this.options.get('componentAutoSelect')) {
662
+ if (!this.options.get('componentInsertBehavior')) {
633
663
  const line = this.format.addLine(container, null);
634
664
  if (line) this.selection.setRange(line, 0, line, 0);
635
665
  }
636
666
  return;
637
667
  }
638
668
 
639
- if (this._resizing && changeSize && this.figure.isVertical) this.figure.setTransform(oFrame, width, height, 0);
669
+ if (!this.#resizing || !changeSize || !this.figure.isVertical) this.figure.setTransform(oFrame, width, height, 0);
640
670
  if (!scriptTag) this.history.push(false);
641
671
  }
642
672
 
643
673
  /**
644
- * @private
645
674
  * @description Updates an existing embed component within the editor.
646
675
  * @param {HTMLIFrameElement} oFrame - The existing embed element to be updated.
647
676
  */
648
- _update(oFrame) {
677
+ #fixTagStructure(oFrame) {
649
678
  if (!oFrame) return;
650
679
 
651
- this._setIframeAttrs(oFrame);
652
-
653
- let existElement = this.format.isBlock(oFrame.parentNode) || dom.check.isWysiwygFrame(oFrame.parentNode) ? oFrame : this.format.getLine(oFrame) || oFrame;
680
+ this.#setIframeAttrs(oFrame);
654
681
 
655
682
  const prevFrame = oFrame;
656
683
  oFrame = /** @type {HTMLIFrameElement} */ (oFrame.cloneNode(true));
@@ -658,45 +685,33 @@ class Embed extends EditorInjector {
658
685
  const container = figure.container;
659
686
 
660
687
  // size
661
- this.figure.open(oFrame, { nonResizing: this._nonResizing, nonSizeInfo: false, nonBorder: false, figureTarget: false, __fileManagerInfo: true });
688
+ this.figure.open(oFrame, { nonResizing: this.#nonResizing, nonSizeInfo: false, nonBorder: false, figureTarget: false, infoOnly: true });
662
689
  const size = (oFrame.getAttribute('data-se-size') || ',').split(',');
663
- this._applySize(size[0] || prevFrame.style.width || prevFrame.width || '', size[1] || prevFrame.style.height || prevFrame.height || '');
690
+
691
+ const width = size[0] || prevFrame.width || '';
692
+ const height = size[1] || prevFrame.height || '';
693
+ this.#applySize(width, height);
664
694
 
665
695
  // align
666
696
  const format = this.format.getLine(prevFrame);
667
- if (format) this._align = format.style.textAlign || format.style.float;
668
- this.figure.setAlign(oFrame, this._align);
669
-
670
- if (dom.query.getParentElement(prevFrame, dom.check.isExcludeFormat)) {
671
- prevFrame.replaceWith(container);
672
- } else if (dom.check.isListCell(existElement)) {
673
- const refer = dom.query.getParentElement(prevFrame, (current) => current.parentNode === existElement);
674
- existElement.insertBefore(container, refer);
675
- dom.utils.removeItem(prevFrame);
676
- this.nodeTransform.removeEmptyNode(refer, null, true);
677
- } else if (this.format.isLine(existElement)) {
678
- const refer = dom.query.getParentElement(prevFrame, (current) => current.parentNode === existElement);
679
- existElement = this.nodeTransform.split(existElement, refer);
680
- existElement.parentNode.insertBefore(container, existElement);
681
- dom.utils.removeItem(prevFrame);
682
- this.nodeTransform.removeEmptyNode(existElement, null, true);
683
- } else {
684
- /** @type {Element} */ (existElement).replaceWith(container);
685
- }
697
+ if (format) this.#align = format.style.textAlign || format.style.float;
698
+ this.figure.setAlign(oFrame, this.#align);
699
+
700
+ this.figure.retainFigureFormat(container, this.#element, null, null);
686
701
 
687
702
  return oFrame;
688
703
  }
689
704
 
690
705
  /**
691
- * @private
692
706
  * @description Applies width and height to the embed component.
693
707
  * @param {string|number} w - The width to apply.
694
708
  * @param {string|number} h - The height to apply.
695
709
  */
696
- _applySize(w, h) {
697
- if (!w) w = this.inputX?.value || this.pluginOptions.defaultWidth;
698
- if (!h) h = this.inputY?.value || this.pluginOptions.defaultHeight;
699
- if (this._onlyPercentage) {
710
+ #applySize(w, h) {
711
+ w ||= this.inputX?.value || this.pluginOptions.defaultWidth;
712
+ h ||= this.inputY?.value || this.pluginOptions.defaultHeight;
713
+
714
+ if (this.#onlyPercentage) {
700
715
  if (!w) w = '100%';
701
716
  else if (/%$/.test(w + '')) w += '%';
702
717
  }
@@ -704,7 +719,6 @@ class Embed extends EditorInjector {
704
719
  }
705
720
 
706
721
  /**
707
- * @private
708
722
  * @description Retrieves embed component size and alignment information.
709
723
  * @returns {{inputWidth: string, inputHeight: string, align: string, isUpdate: boolean, element: Element}} An object containing
710
724
  * - inputWidth : The width of the embed component.
@@ -713,22 +727,21 @@ class Embed extends EditorInjector {
713
727
  * - isUpdate : Whether the component is being updated.
714
728
  * - element : The target element.
715
729
  */
716
- _getInfo() {
730
+ #getInfo() {
717
731
  return {
718
732
  inputWidth: this.inputX?.value || '',
719
733
  inputHeight: this.inputY?.value || '',
720
- align: this._align,
734
+ align: this.#align,
721
735
  isUpdate: this.modal.isUpdate,
722
- element: this._element
736
+ element: this.#element
723
737
  };
724
738
  }
725
739
 
726
740
  /**
727
- * @private
728
741
  * @description Sets default attributes for an iframe element.
729
742
  * @param {HTMLIFrameElement} element - The iframe element to modify.
730
743
  */
731
- _setIframeAttrs(element) {
744
+ #setIframeAttrs(element) {
732
745
  element.frameBorder = '0';
733
746
  element.allowFullscreen = true;
734
747
 
@@ -749,25 +762,25 @@ class Embed extends EditorInjector {
749
762
  const eventTarget = dom.query.getEventTarget(e);
750
763
  const value = eventTarget.value.trim();
751
764
  if (/^<iframe.*\/iframe>$/.test(value)) {
752
- this._linkValue = value;
765
+ this.#linkValue = value;
753
766
  this.previewSrc.textContent = '<IFrame :src=".."></IFrame>';
754
767
  } else {
755
- this._linkValue = this.previewSrc.textContent = !value
768
+ this.#linkValue = this.previewSrc.textContent = !value
756
769
  ? ''
757
770
  : this.options.get('defaultUrlProtocol') && !value.includes('://') && value.indexOf('#') !== 0
758
- ? this.options.get('defaultUrlProtocol') + value
759
- : !value.includes('://')
760
- ? '/' + value
761
- : value;
771
+ ? this.options.get('defaultUrlProtocol') + value
772
+ : !value.includes('://')
773
+ ? '/' + value
774
+ : value;
762
775
  }
763
776
  }
764
777
 
765
778
  #OnClickRevert() {
766
- if (this._onlyPercentage) {
767
- this.inputX.value = Number(this._origin_w) > 100 ? '100' : this._origin_w;
779
+ if (this.#onlyPercentage) {
780
+ this.inputX.value = Number(this.#origin_w) > 100 ? '100' : this.#origin_w;
768
781
  } else {
769
- this.inputX.value = this._origin_w;
770
- this.inputY.value = this._origin_h;
782
+ this.inputX.value = this.#origin_w;
783
+ this.inputY.value = this.#origin_h;
771
784
  }
772
785
  }
773
786
 
@@ -784,10 +797,10 @@ class Embed extends EditorInjector {
784
797
  /** @type {HTMLInputElement} */
785
798
  const eventTarget = dom.query.getEventTarget(e);
786
799
 
787
- if (xy === 'x' && this._onlyPercentage && Number(eventTarget.value) > 100) {
800
+ if (xy === 'x' && this.#onlyPercentage && Number(eventTarget.value) > 100) {
788
801
  eventTarget.value = '100';
789
802
  } else if (this.proportion.checked) {
790
- const ratioSize = Figure.CalcRatio(this.inputX.value, this.inputY.value, this.sizeUnit, this._ratio);
803
+ const ratioSize = Figure.CalcRatio(this.inputX.value, this.inputY.value, this.sizeUnit, this.#ratio);
791
804
  if (xy === 'x') {
792
805
  this.inputY.value = String(ratioSize.h);
793
806
  } else {