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, FileManager } from '../../modules';
3
3
  import { dom, numbers, env, converter, keyCodeMap } from '../../helper';
4
- const { NO_EVENT } = env;
4
+ const { _w, NO_EVENT } = env;
5
5
 
6
6
  /**
7
7
  * @typedef {import('../../events').VideoInfo} VideoInfo_video
@@ -37,6 +37,11 @@ const { NO_EVENT } = env;
37
37
  * @property {Array<RegExp>} [urlPatterns] - Additional URL patterns for video embedding.
38
38
  * @property {Array<string>} [extensions] - Additional file extensions to be recognized for video uploads.
39
39
  * @property {FigureControls_video} [controls] - Figure controls.
40
+ * @property {__se__ComponentInsertBehaviorType} [insertBehavior] - Component insertion behavior for selection and cursor placement. [default: options.get('componentInsertBehavior')]
41
+ * - `auto`: Move cursor to the next line if possible, otherwise select the component.
42
+ * - `select`: Always select the inserted component.
43
+ * - `line`: Move cursor to the next line if possible, or create a new line and move there.
44
+ * - `none`: Do nothing.
40
45
  */
41
46
 
42
47
  /**
@@ -63,6 +68,22 @@ class Video extends EditorInjector {
63
68
  return null;
64
69
  }
65
70
 
71
+ #linkValue;
72
+ #align;
73
+ #frameRatio;
74
+ #defaultRatio;
75
+ #defaultSizeX;
76
+ #defaultSizeY;
77
+ #element;
78
+ #container;
79
+ #ratio;
80
+ #origin_w;
81
+ #origin_h;
82
+ #resizing;
83
+ #onlyPercentage;
84
+ #nonResizing;
85
+ #initRatioValue;
86
+
66
87
  /**
67
88
  * @constructor
68
89
  * @param {__se__EditorCore} editor - The root editor instance
@@ -95,13 +116,14 @@ class Video extends EditorInjector {
95
116
  videoTagAttributes: pluginOptions.videoTagAttributes || null,
96
117
  iframeTagAttributes: pluginOptions.iframeTagAttributes || null,
97
118
  query_youtube: pluginOptions.query_youtube || '',
98
- query_vimeo: pluginOptions.query_vimeo || ''
119
+ query_vimeo: pluginOptions.query_vimeo || '',
120
+ insertBehavior: pluginOptions.insertBehavior
99
121
  };
100
122
 
101
123
  // create HTML
102
124
  const sizeUnit = this.pluginOptions.percentageOnlySize ? '%' : 'px';
103
125
  const modalEl = CreateHTML_modal(editor, this.pluginOptions);
104
- const figureControls = pluginOptions.controls || !this.pluginOptions.canResize ? [['align', 'edit', 'copy', 'remove']] : [['resize_auto,75,50', 'align', 'edit', 'revert', 'copy', 'remove']];
126
+ const figureControls = pluginOptions.controls || (!this.pluginOptions.canResize ? [['align', 'edit', 'copy', 'remove']] : [['resize_auto,75,50', 'align', 'edit', 'revert', 'copy', 'remove']]);
105
127
 
106
128
  // show align
107
129
  if (!figureControls.some((subArray) => subArray.includes('align'))) modalEl.alignForm.style.display = 'none';
@@ -122,26 +144,27 @@ class Video extends EditorInjector {
122
144
  this.videoUrlFile = modalEl.videoUrlFile;
123
145
  this.focusElement = this.videoUrlFile || this.videoInputFile;
124
146
  this.previewSrc = modalEl.previewSrc;
125
- this._linkValue = '';
126
- this._align = 'none';
127
- this._frameRatio = defaultRatio;
128
- this._defaultRatio = defaultRatio;
129
- this._defaultSizeX = '100%';
130
- this._defaultSizeY = this.pluginOptions.defaultRatio * 100 + '%';
131
147
  this.sizeUnit = sizeUnit;
132
148
  this.proportion = null;
133
149
  this.frameRatioOption = null;
134
150
  this.inputX = null;
135
151
  this.inputY = null;
136
- this._element = null;
137
- this._cover = null;
138
- this._container = null;
139
- this._ratio = { w: 1, h: 1 };
140
- this._origin_w = this.pluginOptions.defaultWidth === '100%' ? '' : this.pluginOptions.defaultWidth;
141
- this._origin_h = this.pluginOptions.defaultHeight === defaultRatio ? '' : this.pluginOptions.defaultHeight;
142
- this._resizing = this.pluginOptions.canResize;
143
- this._onlyPercentage = this.pluginOptions.percentageOnlySize;
144
- this._nonResizing = !this._resizing || !this.pluginOptions.showHeightInput || this._onlyPercentage;
152
+
153
+ this.#linkValue = '';
154
+ this.#align = 'none';
155
+ this.#frameRatio = defaultRatio;
156
+ this.#defaultRatio = defaultRatio;
157
+ this.#defaultSizeX = '100%';
158
+ this.#defaultSizeY = this.pluginOptions.defaultRatio * 100 + '%';
159
+ this.#element = null;
160
+ this.#container = null;
161
+ this.#ratio = { w: 0, h: 0 };
162
+ this.#origin_w = this.pluginOptions.defaultWidth === '100%' ? '' : this.pluginOptions.defaultWidth;
163
+ this.#origin_h = this.pluginOptions.defaultHeight === defaultRatio ? '' : this.pluginOptions.defaultHeight;
164
+ this.#resizing = this.pluginOptions.canResize;
165
+ this.#onlyPercentage = this.pluginOptions.percentageOnlySize;
166
+ this.#nonResizing = !this.#resizing || !this.pluginOptions.showHeightInput || this.#onlyPercentage;
167
+
145
168
  this.query = {
146
169
  youtube: {
147
170
  pattern: /youtu\.?be/i,
@@ -195,7 +218,8 @@ class Video extends EditorInjector {
195
218
  if (this.videoUrlFile) this.eventManager.addEvent(this.videoUrlFile, 'input', this.#OnLinkPreview.bind(this));
196
219
  if (this.videoInputFile && this.videoUrlFile) this.eventManager.addEvent(this.videoInputFile, 'change', this.#OnfileInputChange.bind(this));
197
220
 
198
- if (this._resizing) {
221
+ if (this.#resizing) {
222
+ this.#initRatioValue = null;
199
223
  this.proportion = modalEl.proportion;
200
224
  this.frameRatioOption = modalEl.frameRatioOption;
201
225
  this.inputX = modalEl.inputX;
@@ -237,9 +261,9 @@ class Video extends EditorInjector {
237
261
  */
238
262
  on(isUpdate) {
239
263
  if (!isUpdate) {
240
- if (this._resizing) {
241
- this.inputX.value = this._origin_w = this.pluginOptions.defaultWidth === this._defaultSizeX ? '' : this.pluginOptions.defaultWidth;
242
- this.inputY.value = this._origin_h = this.pluginOptions.defaultHeight === this._defaultSizeY ? '' : this.pluginOptions.defaultHeight;
264
+ if (this.#resizing) {
265
+ this.inputX.value = this.#origin_w = this.pluginOptions.defaultWidth === this.#defaultSizeX ? '' : this.pluginOptions.defaultWidth;
266
+ this.inputY.value = this.#origin_h = this.pluginOptions.defaultHeight === this.#defaultSizeY ? '' : this.pluginOptions.defaultHeight;
243
267
  this.proportion.disabled = true;
244
268
  }
245
269
  if (this.videoInputFile && this.pluginOptions.allowMultiple) this.videoInputFile.setAttribute('multiple', 'multiple');
@@ -247,8 +271,9 @@ class Video extends EditorInjector {
247
271
  if (this.videoInputFile && this.pluginOptions.allowMultiple) this.videoInputFile.removeAttribute('multiple');
248
272
  }
249
273
 
250
- if (this._resizing) {
251
- this._setRatioSelect(this._origin_h || this._defaultRatio);
274
+ if (this.#resizing) {
275
+ this.#setRatioSelect(this.figure.isVertical ? '' : this.#origin_h || this.#defaultRatio);
276
+ this.#initRatioValue = this.frameRatioOption?.value;
252
277
  }
253
278
  }
254
279
 
@@ -276,16 +301,16 @@ class Video extends EditorInjector {
276
301
  * @returns {Promise<boolean>} Success / failure
277
302
  */
278
303
  async modalAction() {
279
- this._align = /** @type {HTMLInputElement} */ (this.modal.form.querySelector('input[name="suneditor_video_radio"]:checked')).value;
304
+ this.#align = /** @type {HTMLInputElement} */ (this.modal.form.querySelector('input[name="suneditor_video_radio"]:checked')).value;
280
305
 
281
306
  let result = false;
282
307
  if (this.videoInputFile && this.videoInputFile.files.length > 0) {
283
308
  result = await this.submitFile(this.videoInputFile.files);
284
- } else if (this.videoUrlFile && this._linkValue.length > 0) {
285
- result = await this.submitURL(this._linkValue);
309
+ } else if (this.videoUrlFile && this.#linkValue.length > 0) {
310
+ result = await this.submitURL(this.#linkValue);
286
311
  }
287
312
 
288
- if (result) this._w.setTimeout(this.component.select.bind(this.component, this._element, Video.key), 0);
313
+ if (result) _w.setTimeout(this.component.select.bind(this.component, this.#element, Video.key), 0);
289
314
 
290
315
  return result;
291
316
  }
@@ -312,11 +337,11 @@ class Video extends EditorInjector {
312
337
  const figureInfo = Figure.GetContainer(element);
313
338
  if (figureInfo && figureInfo.container && figureInfo.cover) return;
314
339
 
315
- this._ready(element);
340
+ this.#ready(element, true);
316
341
  const line = this.format.getLine(element);
317
- if (line) this._align = line.style.textAlign || line.style.float;
342
+ if (line) this.#align = line.style.textAlign || line.style.float;
318
343
 
319
- this._update(element);
344
+ this.#fixTagStructure(element);
320
345
  }
321
346
  };
322
347
  }
@@ -328,22 +353,22 @@ class Video extends EditorInjector {
328
353
  init() {
329
354
  Modal.OnChangeFile(this.fileModalWrapper, []);
330
355
  if (this.videoInputFile) this.videoInputFile.value = '';
331
- if (this.videoUrlFile) this._linkValue = this.previewSrc.textContent = this.videoUrlFile.value = '';
356
+ if (this.videoUrlFile) this.#linkValue = this.previewSrc.textContent = this.videoUrlFile.value = '';
332
357
  if (this.videoInputFile && this.videoUrlFile) {
333
358
  this.videoUrlFile.disabled = false;
334
359
  this.previewSrc.style.textDecoration = '';
335
360
  }
336
361
 
337
362
  /** @type {HTMLInputElement} */ (this.modal.form.querySelector('input[name="suneditor_video_radio"][value="none"]')).checked = true;
338
- this._ratio = { w: 1, h: 1 };
339
- this._nonResizing = false;
363
+ this.#ratio = { w: 0, h: 0 };
364
+ this.#nonResizing = false;
340
365
 
341
- if (this._resizing) {
342
- this.inputX.value = this.pluginOptions.defaultWidth === this._defaultSizeX ? '' : this.pluginOptions.defaultWidth;
343
- this.inputY.value = this.pluginOptions.defaultHeight === this._defaultSizeY ? '' : this.pluginOptions.defaultHeight;
366
+ if (this.#resizing) {
367
+ this.inputX.value = this.pluginOptions.defaultWidth === this.#defaultSizeX ? '' : this.pluginOptions.defaultWidth;
368
+ this.inputY.value = this.pluginOptions.defaultHeight === this.#defaultSizeY ? '' : this.pluginOptions.defaultHeight;
344
369
  this.proportion.checked = false;
345
370
  this.proportion.disabled = true;
346
- this._setRatioSelect(this._defaultRatio);
371
+ this.#setRatioSelect(this.#defaultRatio);
347
372
  }
348
373
  }
349
374
 
@@ -353,60 +378,7 @@ class Video extends EditorInjector {
353
378
  * @param {HTMLIFrameElement|HTMLVideoElement} target Target component element
354
379
  */
355
380
  select(target) {
356
- this._ready(target);
357
- }
358
-
359
- /**
360
- * @private
361
- * @description Prepares the component for selection.
362
- * - Ensures that the controller is properly positioned and initialized.
363
- * - Prevents duplicate event handling if the component is already selected.
364
- * @param {HTMLIFrameElement|HTMLVideoElement} target - The selected element.
365
- */
366
- _ready(target) {
367
- if (!target) return;
368
- const figureInfo = this.figure.open(target, { nonResizing: this._nonResizing, nonSizeInfo: false, nonBorder: false, figureTarget: false, __fileManagerInfo: false });
369
-
370
- this._element = target;
371
- this._cover = figureInfo.cover;
372
- this._container = figureInfo.container;
373
- this._align = figureInfo.align;
374
- target.style.float = '';
375
-
376
- this._origin_w = String(figureInfo.width || figureInfo.originWidth || figureInfo.w || '');
377
- this._origin_h = String(figureInfo.height || figureInfo.originHeight || figureInfo.h || '');
378
-
379
- let w = figureInfo.width || figureInfo.w || this._origin_w || '';
380
- const h = figureInfo.height || figureInfo.h || this._origin_h || '';
381
-
382
- if (this.videoUrlFile) this._linkValue = this.previewSrc.textContent = this.videoUrlFile.value = this._element.src || this._element.querySelector('source')?.src || '';
383
-
384
- /** @type {HTMLInputElement} */
385
- const activeAlgin = this.modal.form.querySelector('input[name="suneditor_video_radio"][value="' + this._align + '"]') || this.modal.form.querySelector('input[name="suneditor_video_radio"][value="none"]');
386
- activeAlgin.checked = true;
387
-
388
- if (!this._resizing) return;
389
-
390
- const percentageRotation = this._onlyPercentage && this.figure.isVertical;
391
- if (this._onlyPercentage) {
392
- w = numbers.get(w, 2);
393
- if (w > 100) w = 100;
394
- }
395
- this.inputX.value = String(w === 'auto' ? '' : w);
396
-
397
- if (!this._onlyPercentage) {
398
- const infoH = percentageRotation ? '' : figureInfo.height;
399
- this.inputY.value = String(infoH === 'auto' ? '' : infoH);
400
- }
401
-
402
- if (!this._setRatioSelect(h)) this.inputY.value = String(this._onlyPercentage ? numbers.get(h, 2) : h);
403
-
404
- this.proportion.checked = true;
405
- this.inputX.disabled = percentageRotation ? true : false;
406
- this.inputY.disabled = percentageRotation ? true : false;
407
- this.proportion.disabled = percentageRotation ? true : false;
408
-
409
- this._ratio = this.proportion.checked ? figureInfo.ratio : { w: 1, h: 1 };
381
+ this.#ready(target);
410
382
  }
411
383
 
412
384
  /**
@@ -416,18 +388,18 @@ class Video extends EditorInjector {
416
388
  * @returns {Promise<void>}
417
389
  */
418
390
  async destroy(target) {
419
- const targetEl = target || this._element;
391
+ const targetEl = target || this.#element;
420
392
  const container = dom.query.getParentElement(targetEl, Figure.is) || targetEl;
421
393
  const focusEl = container.previousElementSibling || container.nextElementSibling;
422
394
  const emptyDiv = container.parentNode;
423
395
 
424
- const message = await this.triggerEvent('onVideoDeleteBefore', { element: targetEl, container, align: this._align, url: this._linkValue });
396
+ const message = await this.triggerEvent('onVideoDeleteBefore', { element: targetEl, container, align: this.#align, url: this.#linkValue });
425
397
  if (message === false) return;
426
398
 
427
399
  dom.utils.removeItem(container);
428
400
  this.init();
429
401
 
430
- if (emptyDiv !== this.editor.frameContext.get('wysiwyg')) {
402
+ if (emptyDiv !== this.frameContext.get('wysiwyg')) {
431
403
  this.nodeTransform.removeAllParents(
432
404
  emptyDiv,
433
405
  function (current) {
@@ -537,56 +509,55 @@ class Video extends EditorInjector {
537
509
  * @param {string} align - The alignment to apply to the video element (e.g., 'left', 'center', 'right').
538
510
  * @param {boolean} isUpdate - Indicates whether this is an update to an existing component (true) or a new creation (false).
539
511
  * @param {{name: string, size: number}} file - File metadata associated with the video
512
+ * @param {boolean} isLast - Indicates whether this is the last file in the batch (used for scroll and insert actions).
540
513
  */
541
- create(oFrame, src, width, height, align, isUpdate, file) {
542
- let cover = null;
514
+ create(oFrame, src, width, height, align, isUpdate, file, isLast) {
543
515
  let container = null;
544
516
 
545
517
  /** update */
546
518
  if (isUpdate) {
547
- oFrame = this._element;
519
+ oFrame = this.#element;
548
520
  if (oFrame.src !== src) {
549
521
  const processUrl = this.findProcessUrl(src);
550
522
  if (/^iframe$/i.test(processUrl?.tag) && !/^iframe$/i.test(oFrame.nodeName)) {
551
523
  const newTag = this.createIframeTag();
552
524
  newTag.src = src;
553
525
  oFrame.replaceWith(newTag);
554
- this._element = oFrame = newTag;
526
+ this.#element = oFrame = newTag;
555
527
  } else if (/^video$/i.test(processUrl?.tag) && !/^video$/i.test(oFrame.nodeName)) {
556
528
  const newTag = this.createVideoTag();
557
529
  newTag.src = src;
558
530
  oFrame.replaceWith(newTag);
559
- this._element = oFrame = newTag;
531
+ this.#element = oFrame = newTag;
560
532
  } else {
561
533
  oFrame.src = src;
562
534
  }
563
535
  }
564
- container = this._container;
565
- cover = dom.query.getParentElement(oFrame, 'FIGURE');
536
+ container = this.#container;
566
537
  } else {
567
538
  /** create */
568
539
  oFrame.src = src;
569
- this._element = oFrame;
540
+ this.#element = oFrame;
570
541
  const figure = Figure.CreateContainer(oFrame, 'se-video-container');
571
- cover = figure.cover;
572
542
  container = figure.container;
573
543
  }
574
544
 
575
545
  /** rendering */
576
- this._element = oFrame;
577
- this._cover = cover;
578
- this._container = container;
579
- this.figure.open(oFrame, { nonResizing: this._nonResizing, nonSizeInfo: false, nonBorder: false, figureTarget: false, __fileManagerInfo: true });
546
+ this.#element = oFrame;
547
+ this.#container = container;
548
+ this.figure.open(oFrame, { nonResizing: this.#nonResizing, nonSizeInfo: false, nonBorder: false, figureTarget: false, infoOnly: true });
549
+
550
+ width ||= this.#defaultSizeX;
551
+ height ||= this.#frameRatio;
580
552
 
581
- width = width || this._defaultSizeX;
582
- height = height || this._frameRatio;
583
553
  const size = this.figure.getSize(oFrame);
584
554
  const inputUpdate = size.w !== width || size.h !== height;
585
555
  const changeSize = !isUpdate || inputUpdate;
586
556
 
587
557
  // set size
588
558
  if (changeSize) {
589
- this._applySize(width, height);
559
+ if (this.#initRatioValue !== this.frameRatioOption?.value) this.figure.deleteTransform();
560
+ this.#applySize(width, height);
590
561
  }
591
562
 
592
563
  // align
@@ -597,15 +568,11 @@ class Video extends EditorInjector {
597
568
  this.fileManager.setFileData(oFrame, file);
598
569
 
599
570
  if (!isUpdate) {
600
- this.component.insert(container, { skipCharCount: false, skipSelection: true, skipHistory: false });
601
- if (!this.options.get('componentAutoSelect')) {
602
- const line = this.format.addLine(container, null);
603
- if (line) this.selection.setRange(line, 0, line, 0);
604
- }
571
+ this.component.insert(container, { scrollTo: isLast ? true : false, insertBehavior: isLast ? this.pluginOptions.insertBehavior : 'line' });
605
572
  return;
606
573
  }
607
574
 
608
- if (this._resizing && changeSize && this.figure.isVertical) this.figure.setTransform(oFrame, width, height, 0);
575
+ if (!this.#resizing || !changeSize || !this.figure.isVertical) this.figure.setTransform(oFrame, width, height, 0);
609
576
  this.history.push(false);
610
577
  }
611
578
 
@@ -623,7 +590,7 @@ class Video extends EditorInjector {
623
590
  iframeTag[key] = props[key];
624
591
  }
625
592
  }
626
- this._setIframeAttrs(iframeTag);
593
+ this.#setIframeAttrs(iframeTag);
627
594
  return iframeTag;
628
595
  }
629
596
 
@@ -641,41 +608,10 @@ class Video extends EditorInjector {
641
608
  videoTag[key] = props[key];
642
609
  }
643
610
  }
644
- this._setTagAttrs(videoTag);
611
+ this.#setTagAttrs(videoTag);
645
612
  return videoTag;
646
613
  }
647
614
 
648
- /**
649
- * @private
650
- * @description Sets the size of the video element.
651
- * @param {string|number} w - The width of the video.
652
- * @param {string|number} h - The height of the video.
653
- */
654
- _applySize(w, h) {
655
- if (!w) w = this.inputX?.value || this.pluginOptions.defaultWidth;
656
- if (!h) h = this.inputY?.value || this.pluginOptions.defaultHeight;
657
- if (this._onlyPercentage) {
658
- if (!w) w = '100%';
659
- else if (/%$/.test(w + '')) w += '%';
660
- }
661
- this.figure.setSize(w, h);
662
- }
663
-
664
- /**
665
- * @private
666
- * @description Retrieves video information including size and alignment.
667
- * @returns {*} Video information object.
668
- */
669
- _getInfo() {
670
- return {
671
- inputWidth: this.inputX?.value || '',
672
- inputHeight: this.inputY?.value || '',
673
- align: this._align,
674
- isUpdate: this.modal.isUpdate,
675
- element: this._element
676
- };
677
- }
678
-
679
615
  /**
680
616
  * @description Create an "video" component using the provided files.
681
617
  * @param {FileList|File[]} fileList File object list
@@ -692,7 +628,7 @@ class Video extends EditorInjector {
692
628
  if (!/video/i.test(f.type)) continue;
693
629
 
694
630
  s = f.size;
695
- if (slngleSizeLimit && slngleSizeLimit > s) {
631
+ if (slngleSizeLimit > 0 && s > slngleSizeLimit) {
696
632
  const err = '[SUNEDITOR.videoUpload.fail] Size of uploadable single file: ' + slngleSizeLimit / 1000 + 'KB';
697
633
  const message = await this.triggerEvent('onVideoUploadError', {
698
634
  error: err,
@@ -724,15 +660,13 @@ class Video extends EditorInjector {
724
660
  const videoInfo = {
725
661
  url: null,
726
662
  files,
727
- ...this._getInfo()
663
+ ...this.#getInfo()
728
664
  };
729
665
 
730
- const handler = function (infos, newInfos) {
666
+ const handler = function (uploadCallback, infos, newInfos) {
731
667
  infos = newInfos || infos;
732
- this._serverUpload(infos, infos.files);
733
- }.bind(this, videoInfo);
734
- // se-ts-ignore
735
- this._serverUpload;
668
+ uploadCallback(infos, infos.files);
669
+ }.bind(this, this.#serverUpload.bind(this), videoInfo);
736
670
 
737
671
  const result = await this.triggerEvent('onVideoUploadBefore', {
738
672
  info: videoInfo,
@@ -752,8 +686,7 @@ class Video extends EditorInjector {
752
686
  * @returns {Promise<boolean>} If return false, the file upload will be canceled
753
687
  */
754
688
  async submitURL(url) {
755
- if (!url) url = this._linkValue;
756
- if (!url) return false;
689
+ if (!(url = this.#linkValue)) return false;
757
690
 
758
691
  /** iframe source */
759
692
  if (/^<iframe.*\/iframe>$/.test(url)) {
@@ -768,11 +701,11 @@ class Video extends EditorInjector {
768
701
  }
769
702
 
770
703
  const file = { name: url.split('/').pop(), size: 0 };
771
- const videoInfo = { url, files: file, ...this._getInfo(), process: processUrl };
704
+ const videoInfo = { url, files: file, ...this.#getInfo(), process: processUrl };
772
705
 
773
706
  const handler = function (infos, newInfos) {
774
707
  infos = newInfos || infos;
775
- this.create(this[/^iframe$/i.test(infos.process?.tag) ? 'createIframeTag' : 'createVideoTag'](), infos.url, infos.inputWidth, infos.inputHeight, infos.align, infos.isUpdate, infos.files);
708
+ this.create(this[/^iframe$/i.test(infos.process?.tag) ? 'createIframeTag' : 'createVideoTag'](), infos.url, infos.inputWidth, infos.inputHeight, infos.align, infos.isUpdate, infos.files, true);
776
709
  }.bind(this, videoInfo);
777
710
 
778
711
  const result = await this.triggerEvent('onVideoUploadBefore', {
@@ -790,106 +723,175 @@ class Video extends EditorInjector {
790
723
  }
791
724
 
792
725
  /**
793
- * @private
726
+ * @description Prepares the component for selection.
727
+ * - Ensures that the controller is properly positioned and initialized.
728
+ * - Prevents duplicate event handling if the component is already selected.
729
+ * @param {HTMLIFrameElement|HTMLVideoElement} target - The selected element.
730
+ * @param {boolean} [infoOnly=false] - If true, only retrieves information without opening the controller.
731
+ */
732
+ #ready(target, infoOnly = false) {
733
+ if (!target) return;
734
+ const figureInfo = this.figure.open(target, { nonResizing: this.#nonResizing, nonSizeInfo: false, nonBorder: false, figureTarget: false, infoOnly });
735
+
736
+ this.#element = target;
737
+ this.#container = figureInfo.container;
738
+ this.#align = figureInfo.align;
739
+ target.style.float = '';
740
+
741
+ this.#origin_w = String(figureInfo.width || figureInfo.originWidth || figureInfo.w || '');
742
+ this.#origin_h = String(figureInfo.height || figureInfo.originHeight || figureInfo.h || '');
743
+
744
+ const h = figureInfo.height || figureInfo.h || this.#origin_h || '';
745
+
746
+ if (this.videoUrlFile) this.#linkValue = this.previewSrc.textContent = this.videoUrlFile.value = this.#element.src || this.#element.querySelector('source')?.src || '';
747
+
748
+ /** @type {HTMLInputElement} */
749
+ const activeAlgin = this.modal.form.querySelector('input[name="suneditor_video_radio"][value="' + this.#align + '"]') || this.modal.form.querySelector('input[name="suneditor_video_radio"][value="none"]');
750
+ activeAlgin.checked = true;
751
+
752
+ if (!this.#resizing) return;
753
+
754
+ const percentageRotation = this.#onlyPercentage && this.figure.isVertical;
755
+ const { dw, dh } = this.figure.getSize(target);
756
+ this.inputX.value = dw === 'auto' ? '' : dw;
757
+ this.inputY.value = dh === 'auto' ? '' : dh;
758
+
759
+ if (!this.#setRatioSelect(h)) this.inputY.value = String(this.#onlyPercentage ? numbers.get(h, 2) : h);
760
+
761
+ this.proportion.checked = true;
762
+ this.inputX.disabled = percentageRotation ? true : false;
763
+ this.inputY.disabled = percentageRotation ? true : false;
764
+ this.proportion.disabled = percentageRotation ? true : false;
765
+
766
+ if (figureInfo.isVertical) {
767
+ this.proportion.checked = false;
768
+ }
769
+
770
+ this.#ratio = this.proportion.checked ? figureInfo.ratio : { w: 0, h: 0 };
771
+ }
772
+
773
+ /**
774
+ * @description Sets the size of the video element.
775
+ * @param {string|number} w - The width of the video.
776
+ * @param {string|number} h - The height of the video.
777
+ */
778
+ #applySize(w, h) {
779
+ w ||= this.inputX?.value || this.pluginOptions.defaultWidth;
780
+ h ||= this.inputY?.value || this.pluginOptions.defaultHeight;
781
+
782
+ if (this.#onlyPercentage) {
783
+ if (!w) w = '100%';
784
+ else if (/%$/.test(w + '')) w += '%';
785
+ }
786
+ this.figure.setSize(w, h);
787
+ }
788
+
789
+ /**
790
+ * @description Retrieves video information including size and alignment.
791
+ * @returns {*} Video information object.
792
+ */
793
+ #getInfo() {
794
+ return {
795
+ inputWidth: this.inputX?.value || '',
796
+ inputHeight: this.inputY?.value || '',
797
+ align: this.#align,
798
+ isUpdate: this.modal.isUpdate,
799
+ element: this.#element
800
+ };
801
+ }
802
+
803
+ /**
794
804
  * @description Updates the video component within the editor.
795
805
  * @param {HTMLIFrameElement|HTMLVideoElement} oFrame - The video element to update.
796
806
  */
797
- _update(oFrame) {
807
+ #fixTagStructure(oFrame) {
798
808
  if (!oFrame) return;
799
809
 
800
- if (/^video$/i.test(oFrame.nodeName)) {
801
- this._setTagAttrs(/** @type {HTMLVideoElement} */ (oFrame));
810
+ const isVideoTag = /^video$/i.test(oFrame.nodeName);
811
+ if (isVideoTag) {
812
+ this.#setTagAttrs(/** @type {HTMLVideoElement} */ (oFrame));
802
813
  } else if (/^iframe$/i.test(oFrame.nodeName)) {
803
- this._setIframeAttrs(/** @type {HTMLIFrameElement} */ (oFrame));
814
+ this.#setIframeAttrs(/** @type {HTMLIFrameElement} */ (oFrame));
804
815
  }
805
816
 
806
- let existElement = this.format.isBlock(oFrame.parentNode) || dom.check.isWysiwygFrame(oFrame.parentNode) ? oFrame : this.format.getLine(oFrame) || oFrame;
807
-
808
817
  const prevFrame = oFrame;
809
818
  const cloneFrame = /** @type {HTMLIFrameElement|HTMLVideoElement} */ (oFrame.cloneNode(true));
810
819
  const figure = Figure.CreateContainer(cloneFrame, 'se-video-container');
811
820
  const container = figure.container;
812
821
 
813
- const figcaption = existElement.querySelector('figcaption');
822
+ const figcaption = Figure.GetContainer(prevFrame)?.container?.querySelector('figcaption');
814
823
  let caption = null;
815
824
  if (figcaption) {
816
- caption = dom.utils.createElement('DIV');
825
+ caption = dom.utils.createElement('figcaption');
817
826
  caption.innerHTML = figcaption.innerHTML;
818
827
  dom.utils.removeItem(figcaption);
828
+ figure.cover.appendChild(caption);
819
829
  }
820
830
 
821
831
  // size
822
- this.figure.open(cloneFrame, { nonResizing: this._nonResizing, nonSizeInfo: false, nonBorder: false, figureTarget: false, __fileManagerInfo: true });
832
+ this.figure.open(cloneFrame, { nonResizing: this.#nonResizing, nonSizeInfo: false, nonBorder: false, figureTarget: false, infoOnly: true });
823
833
  const size = (cloneFrame.getAttribute('data-se-size') || ',').split(',');
824
- this._applySize(size[0] || prevFrame.style.width || prevFrame.width || '', size[1] || prevFrame.style.height || prevFrame.height || '');
834
+
835
+ const width = size[0] || prevFrame.width || '';
836
+ const height = size[1] || prevFrame.height || this.#defaultRatio || '';
837
+ this.#applySize(width, height);
825
838
 
826
839
  // align
827
840
  const format = this.format.getLine(prevFrame);
828
- if (format) this._align = format.style.textAlign || format.style.float;
829
- this.figure.setAlign(cloneFrame, this._align);
830
-
831
- if (dom.query.getParentElement(prevFrame, dom.check.isExcludeFormat)) {
832
- prevFrame.replaceWith(container);
833
- } else if (dom.check.isListCell(existElement)) {
834
- const refer = dom.query.getParentElement(prevFrame, (current) => current.parentNode === existElement);
835
- existElement.insertBefore(container, refer);
836
- dom.utils.removeItem(prevFrame);
837
- this.nodeTransform.removeEmptyNode(refer, null, true);
838
- } else if (this.format.isLine(existElement)) {
839
- const refer = dom.query.getParentElement(prevFrame, (current) => current.parentNode === existElement);
840
- existElement = this.nodeTransform.split(existElement, refer);
841
- existElement.parentNode.insertBefore(container, existElement);
842
- dom.utils.removeItem(prevFrame);
843
- this.nodeTransform.removeEmptyNode(existElement, null, true);
844
- } else {
845
- /** @type {Element} */ (existElement).replaceWith(container);
846
- }
841
+ if (format) this.#align = format.style.textAlign || format.style.float;
842
+ this.figure.setAlign(cloneFrame, this.#align);
847
843
 
848
- if (caption) existElement.parentNode.insertBefore(caption, container.nextElementSibling);
844
+ this.figure.retainFigureFormat(container, this.#element, null, this.fileManager);
849
845
 
850
846
  return cloneFrame;
851
847
  }
852
848
 
853
849
  /**
854
- * @private
855
850
  * @description Registers the uploaded video in the editor.
856
851
  * @param {VideoInfo_video} info - Video information object.
857
852
  * @param {Object<string, *>} response - Server response containing video data.
858
853
  */
859
- _register(info, response) {
854
+ #register(info, response) {
860
855
  const fileList = response.result;
861
856
  const videoTag = this.createVideoTag();
862
857
 
863
858
  for (let i = 0, len = fileList.length; i < len; i++) {
864
859
  const ctag = info.isUpdate ? info.element : /** @type {HTMLIFrameElement|HTMLVideoElement} */ (videoTag.cloneNode(false));
865
- this.create(ctag, fileList[i].url, info.inputWidth, info.inputHeight, info.align, info.isUpdate, {
866
- name: fileList[i].name,
867
- size: fileList[i].size
868
- });
860
+ this.create(
861
+ ctag,
862
+ fileList[i].url,
863
+ info.inputWidth,
864
+ info.inputHeight,
865
+ info.align,
866
+ info.isUpdate,
867
+ {
868
+ name: fileList[i].name,
869
+ size: fileList[i].size
870
+ },
871
+ i === len - 1
872
+ );
869
873
  }
870
874
  }
871
875
 
872
876
  /**
873
- * @private
874
877
  * @description Uploads a video to the server using an external upload handler.
875
878
  * @param {VideoInfo_video} info - Video information object.
876
879
  * @param {FileList} files - The video files to upload.
877
880
  */
878
- _serverUpload(info, files) {
881
+ #serverUpload(info, files) {
879
882
  if (!files) return;
880
883
 
881
884
  const videoUploadUrl = this.pluginOptions.uploadUrl;
882
885
  if (typeof videoUploadUrl === 'string' && videoUploadUrl.length > 0) {
883
- this.fileManager.upload(videoUploadUrl, this.pluginOptions.uploadHeaders, files, this.#UploadCallBack.bind(this, info), this._error.bind(this));
886
+ this.fileManager.upload(videoUploadUrl, this.pluginOptions.uploadHeaders, files, this.#UploadCallBack.bind(this, info), this.#error.bind(this));
884
887
  }
885
888
  }
886
889
 
887
890
  /**
888
- * @private
889
891
  * @description Sets attributes for the video tag.
890
892
  * @param {HTMLVideoElement} element - The video element.
891
893
  */
892
- _setTagAttrs(element) {
894
+ #setTagAttrs(element) {
893
895
  element.setAttribute('controls', 'true');
894
896
 
895
897
  const attrs = this.pluginOptions.videoTagAttributes;
@@ -901,11 +903,10 @@ class Video extends EditorInjector {
901
903
  }
902
904
 
903
905
  /**
904
- * @private
905
906
  * @description Sets attributes for the iframe tag.
906
907
  * @param {HTMLIFrameElement} element - The iframe element.
907
908
  */
908
- _setIframeAttrs(element) {
909
+ #setIframeAttrs(element) {
909
910
  element.frameBorder = '0';
910
911
  element.allowFullscreen = true;
911
912
 
@@ -918,16 +919,17 @@ class Video extends EditorInjector {
918
919
  }
919
920
 
920
921
  /**
921
- * @private
922
922
  * @description Selects a ratio option in the ratio dropdown.
923
923
  * @param {string|number} value - The selected ratio value.
924
924
  * @returns {boolean} Returns true if a ratio was selected.
925
925
  */
926
- _setRatioSelect(value) {
926
+ #setRatioSelect(value) {
927
+ if (!this.frameRatioOption) return;
928
+
927
929
  let ratioSelected = false;
928
930
  const ratioOption = this.frameRatioOption.options;
929
931
 
930
- if (/%$/.test(value + '') || this._onlyPercentage) value = numbers.get(value, 2) / 100 + '';
932
+ if (/%$/.test(value + '') || this.#onlyPercentage) value = numbers.get(value, 2) / 100 + '';
931
933
  else if (!numbers.is(value) || Number(value) >= 1) value = '';
932
934
 
933
935
  this.inputY.placeholder = '';
@@ -935,19 +937,20 @@ class Video extends EditorInjector {
935
937
  if (ratioOption[i].value === value) {
936
938
  ratioSelected = ratioOption[i].selected = true;
937
939
  this.inputY.placeholder = !value ? '' : Number(value) * 100 + '%';
938
- } else ratioOption[i].selected = false;
940
+ } else {
941
+ ratioOption[i].selected = false;
942
+ }
939
943
  }
940
944
 
941
945
  return ratioSelected;
942
946
  }
943
947
 
944
948
  /**
945
- * @private
946
949
  * @description Handles video upload errors.
947
950
  * @param {Object<string, *>} response - The error response object.
948
951
  * @returns {Promise<void>}
949
952
  */
950
- async _error(response) {
953
+ async #error(response) {
951
954
  const message = await this.triggerEvent('onVideoUploadError', { error: response });
952
955
  const err = message === NO_EVENT ? response.errorMessage : message || response.errorMessage;
953
956
  this.ui.alertOpen(err, 'error');
@@ -963,9 +966,9 @@ class Video extends EditorInjector {
963
966
  if ((await this.triggerEvent('videoUploadHandler', { xmlHttp, info })) === NO_EVENT) {
964
967
  const response = JSON.parse(xmlHttp.responseText);
965
968
  if (response.errorMessage) {
966
- this._error(response);
969
+ this.#error(response);
967
970
  } else {
968
- this._register(info, response);
971
+ this.#register(info, response);
969
972
  }
970
973
  }
971
974
  }
@@ -993,16 +996,16 @@ class Video extends EditorInjector {
993
996
  const eventTarget = dom.query.getEventTarget(e);
994
997
  const value = eventTarget.value.trim();
995
998
  if (/^<iframe.*\/iframe>$/.test(value)) {
996
- this._linkValue = value;
999
+ this.#linkValue = value;
997
1000
  this.previewSrc.textContent = '<IFrame :src=".."></IFrame>';
998
1001
  } else {
999
- this._linkValue = this.previewSrc.textContent = !value
1002
+ this.#linkValue = this.previewSrc.textContent = !value
1000
1003
  ? ''
1001
1004
  : this.options.get('defaultUrlProtocol') && !value.includes('://') && value.indexOf('#') !== 0
1002
- ? this.options.get('defaultUrlProtocol') + value
1003
- : !value.includes('://')
1004
- ? '/' + value
1005
- : value;
1005
+ ? this.options.get('defaultUrlProtocol') + value
1006
+ : !value.includes('://')
1007
+ ? '/' + value
1008
+ : value;
1006
1009
  }
1007
1010
  }
1008
1011
 
@@ -1018,7 +1021,7 @@ class Video extends EditorInjector {
1018
1021
  * @param {HTMLInputElement} target - The selected video element.
1019
1022
  */
1020
1023
  #SetUrlInput(target) {
1021
- this._linkValue = this.previewSrc.textContent = this.videoUrlFile.value = target.getAttribute('data-command') || target.src;
1024
+ this.#linkValue = this.previewSrc.textContent = this.videoUrlFile.value = target.getAttribute('data-command') || target.src;
1022
1025
  this.videoUrlFile.focus();
1023
1026
  }
1024
1027
 
@@ -1041,11 +1044,11 @@ class Video extends EditorInjector {
1041
1044
  }
1042
1045
 
1043
1046
  #OnClickRevert() {
1044
- if (this._onlyPercentage) {
1045
- this.inputX.value = Number(this._origin_w) > 100 ? '100' : this._origin_w;
1047
+ if (this.#onlyPercentage) {
1048
+ this.inputX.value = Number(this.#origin_w) > 100 ? '100' : this.#origin_w;
1046
1049
  } else {
1047
- this.inputX.value = this._origin_w;
1048
- this.inputY.value = this._origin_h;
1050
+ this.inputX.value = this.#origin_w;
1051
+ this.inputY.value = this.#origin_h;
1049
1052
  }
1050
1053
  }
1051
1054
 
@@ -1056,13 +1059,13 @@ class Video extends EditorInjector {
1056
1059
  /** @type {HTMLSelectElement} */
1057
1060
  const eventTarget = dom.query.getEventTarget(e);
1058
1061
  const value = eventTarget.options[eventTarget.selectedIndex].value;
1059
- this._defaultSizeY = this.figure.autoRatio.current = this._frameRatio = !value ? this._defaultSizeY : Number(value) * 100 + '%';
1062
+ this.#defaultSizeY = this.figure.autoRatio.current = this.#frameRatio = !value ? this.#defaultSizeY : Number(value) * 100 + '%';
1060
1063
  this.inputY.placeholder = !value ? '' : Number(value) * 100 + '%';
1061
1064
  this.inputY.value = '';
1062
1065
  }
1063
1066
 
1064
1067
  #OnChangeRatio() {
1065
- this._ratio = this.proportion.checked ? Figure.GetRatio(this.inputX.value, this.inputY.value, this.sizeUnit) : { w: 1, h: 1 };
1068
+ this.#ratio = this.proportion.checked ? Figure.GetRatio(this.inputX.value, this.inputY.value, this.sizeUnit) : { w: 0, h: 0 };
1066
1069
  }
1067
1070
 
1068
1071
  /**
@@ -1077,10 +1080,10 @@ class Video extends EditorInjector {
1077
1080
 
1078
1081
  /** @type {HTMLInputElement} */
1079
1082
  const eventTarget = dom.query.getEventTarget(e);
1080
- if (xy === 'x' && this._onlyPercentage && Number(eventTarget.value) > 100) {
1083
+ if (xy === 'x' && this.#onlyPercentage && Number(eventTarget.value) > 100) {
1081
1084
  eventTarget.value = '100';
1082
- } else if (this.proportion.checked) {
1083
- const ratioSize = Figure.CalcRatio(this.inputX.value, this.inputY.value, this.sizeUnit, this._ratio);
1085
+ } else if (this.proportion.checked && !this.frameRatioOption?.value) {
1086
+ const ratioSize = Figure.CalcRatio(this.inputX.value, this.inputY.value, this.sizeUnit, this.#ratio);
1084
1087
  if (xy === 'x') {
1085
1088
  this.inputY.value = String(ratioSize.h);
1086
1089
  } else {
@@ -1089,7 +1092,7 @@ class Video extends EditorInjector {
1089
1092
  }
1090
1093
 
1091
1094
  if (xy === 'y') {
1092
- this._setRatioSelect(eventTarget.value || this._defaultRatio);
1095
+ this.#setRatioSelect(eventTarget.value || this.#defaultRatio);
1093
1096
  }
1094
1097
  }
1095
1098
  }