suneditor 3.0.0-alpha.2 → 3.0.0-alpha.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (306) hide show
  1. package/.eslintrc.json +4 -3
  2. package/CONTRIBUTING.md +4 -2
  3. package/README.md +19 -11
  4. package/README_V3_TEMP.md +705 -0
  5. package/dist/suneditor.min.css +1 -0
  6. package/dist/suneditor.min.js +1 -0
  7. package/example.md +587 -0
  8. package/package.json +15 -9
  9. package/src/assets/icons/_default.js +166 -131
  10. package/src/assets/{suneditor-content.css → suneditor-contents.css} +182 -45
  11. package/src/assets/suneditor.css +1195 -556
  12. package/src/assets/variables.css +138 -0
  13. package/src/core/base/eventHandlers/handler_toolbar.js +35 -14
  14. package/src/core/base/eventHandlers/handler_ww_clipboard.js +29 -4
  15. package/src/core/base/eventHandlers/handler_ww_dragDrop.js +59 -15
  16. package/src/core/base/eventHandlers/handler_ww_key_input.js +426 -212
  17. package/src/core/base/eventHandlers/handler_ww_mouse.js +108 -32
  18. package/src/core/base/eventManager.js +540 -209
  19. package/src/core/base/events.js +616 -320
  20. package/src/core/base/history.js +93 -39
  21. package/src/core/class/char.js +29 -13
  22. package/src/core/class/component.js +332 -145
  23. package/src/core/class/format.js +671 -509
  24. package/src/core/class/html.js +504 -290
  25. package/src/core/class/menu.js +114 -47
  26. package/src/core/class/nodeTransform.js +111 -66
  27. package/src/core/class/offset.js +409 -105
  28. package/src/core/class/selection.js +220 -108
  29. package/src/core/class/shortcuts.js +68 -8
  30. package/src/core/class/toolbar.js +106 -116
  31. package/src/core/class/ui.js +330 -0
  32. package/src/core/class/viewer.js +178 -74
  33. package/src/core/editor.js +489 -384
  34. package/src/core/section/actives.js +118 -22
  35. package/src/core/section/constructor.js +504 -170
  36. package/src/core/section/context.js +28 -23
  37. package/src/core/section/documentType.js +561 -0
  38. package/src/editorInjector/_classes.js +19 -5
  39. package/src/editorInjector/_core.js +71 -7
  40. package/src/editorInjector/index.js +63 -1
  41. package/src/helper/converter.js +137 -19
  42. package/src/helper/dom/domCheck.js +294 -0
  43. package/src/helper/dom/domQuery.js +609 -0
  44. package/src/helper/dom/domUtils.js +533 -0
  45. package/src/helper/dom/index.js +12 -0
  46. package/src/helper/env.js +42 -19
  47. package/src/helper/index.js +7 -4
  48. package/src/helper/keyCodeMap.js +183 -0
  49. package/src/helper/numbers.js +8 -8
  50. package/src/helper/unicode.js +5 -5
  51. package/src/langs/ckb.js +69 -3
  52. package/src/langs/cs.js +67 -1
  53. package/src/langs/da.js +68 -2
  54. package/src/langs/de.js +68 -3
  55. package/src/langs/en.js +29 -1
  56. package/src/langs/es.js +68 -3
  57. package/src/langs/fa.js +70 -2
  58. package/src/langs/fr.js +68 -2
  59. package/src/langs/he.js +68 -3
  60. package/src/langs/hu.js +226 -0
  61. package/src/langs/index.js +3 -2
  62. package/src/langs/it.js +65 -0
  63. package/src/langs/ja.js +68 -3
  64. package/src/langs/ko.js +66 -1
  65. package/src/langs/lv.js +68 -3
  66. package/src/langs/nl.js +68 -3
  67. package/src/langs/pl.js +68 -3
  68. package/src/langs/pt_br.js +65 -0
  69. package/src/langs/ro.js +69 -4
  70. package/src/langs/ru.js +68 -3
  71. package/src/langs/se.js +68 -3
  72. package/src/langs/tr.js +68 -0
  73. package/src/langs/ua.js +68 -3
  74. package/src/langs/ur.js +71 -6
  75. package/src/langs/zh_cn.js +69 -4
  76. package/src/modules/ApiManager.js +77 -54
  77. package/src/modules/Browser.js +667 -0
  78. package/src/modules/ColorPicker.js +162 -102
  79. package/src/modules/Controller.js +233 -136
  80. package/src/modules/Figure.js +913 -489
  81. package/src/modules/FileManager.js +141 -72
  82. package/src/modules/HueSlider.js +113 -61
  83. package/src/modules/Modal.js +292 -113
  84. package/src/modules/ModalAnchorEditor.js +380 -230
  85. package/src/modules/SelectMenu.js +270 -168
  86. package/src/modules/_DragHandle.js +2 -1
  87. package/src/modules/index.js +3 -3
  88. package/src/plugins/browser/audioGallery.js +83 -0
  89. package/src/plugins/browser/fileBrowser.js +103 -0
  90. package/src/plugins/browser/fileGallery.js +83 -0
  91. package/src/plugins/browser/imageGallery.js +81 -0
  92. package/src/plugins/browser/videoGallery.js +103 -0
  93. package/src/plugins/command/blockquote.js +40 -27
  94. package/src/plugins/command/exportPDF.js +134 -0
  95. package/src/plugins/command/fileUpload.js +226 -158
  96. package/src/plugins/command/list_bulleted.js +93 -47
  97. package/src/plugins/command/list_numbered.js +93 -47
  98. package/src/plugins/dropdown/align.js +66 -54
  99. package/src/plugins/dropdown/backgroundColor.js +76 -45
  100. package/src/plugins/dropdown/font.js +71 -47
  101. package/src/plugins/dropdown/fontColor.js +78 -46
  102. package/src/plugins/dropdown/formatBlock.js +74 -33
  103. package/src/plugins/dropdown/hr.js +102 -51
  104. package/src/plugins/dropdown/layout.js +37 -26
  105. package/src/plugins/dropdown/lineHeight.js +54 -38
  106. package/src/plugins/dropdown/list.js +60 -45
  107. package/src/plugins/dropdown/paragraphStyle.js +51 -30
  108. package/src/plugins/dropdown/table.js +1269 -777
  109. package/src/plugins/dropdown/template.js +38 -26
  110. package/src/plugins/dropdown/textStyle.js +43 -31
  111. package/src/plugins/field/mention.js +144 -82
  112. package/src/plugins/index.js +32 -6
  113. package/src/plugins/input/fontSize.js +161 -108
  114. package/src/plugins/input/pageNavigator.js +70 -0
  115. package/src/plugins/modal/audio.js +341 -169
  116. package/src/plugins/modal/drawing.js +530 -0
  117. package/src/plugins/modal/embed.js +886 -0
  118. package/src/plugins/modal/image.js +673 -358
  119. package/src/plugins/modal/link.js +100 -71
  120. package/src/plugins/modal/math.js +384 -168
  121. package/src/plugins/modal/video.js +693 -336
  122. package/src/plugins/popup/anchor.js +222 -0
  123. package/src/suneditor.js +54 -12
  124. package/src/themes/dark.css +85 -0
  125. package/src/typedef.js +86 -0
  126. package/types/assets/icons/_default.d.ts +152 -0
  127. package/types/core/base/eventHandlers/handler_toolbar.d.ts +41 -0
  128. package/types/core/base/eventHandlers/handler_ww_clipboard.d.ts +40 -0
  129. package/types/core/base/eventHandlers/handler_ww_dragDrop.d.ts +35 -0
  130. package/types/core/base/eventHandlers/handler_ww_key_input.d.ts +45 -0
  131. package/types/core/base/eventHandlers/handler_ww_mouse.d.ts +39 -0
  132. package/types/core/base/eventManager.d.ts +377 -0
  133. package/types/core/base/events.d.ts +297 -0
  134. package/types/core/base/history.d.ts +81 -0
  135. package/types/core/class/char.d.ts +60 -0
  136. package/types/core/class/component.d.ts +259 -0
  137. package/types/core/class/format.d.ts +615 -0
  138. package/types/core/class/html.d.ts +377 -0
  139. package/types/core/class/menu.d.ts +118 -0
  140. package/types/core/class/nodeTransform.d.ts +93 -0
  141. package/types/core/class/offset.d.ts +512 -0
  142. package/types/core/class/selection.d.ts +188 -0
  143. package/types/core/class/shortcuts.d.ts +142 -0
  144. package/types/core/class/toolbar.d.ts +189 -0
  145. package/types/core/class/ui.d.ts +144 -0
  146. package/types/core/class/viewer.d.ts +140 -0
  147. package/types/core/editor.d.ts +606 -0
  148. package/types/core/section/actives.d.ts +46 -0
  149. package/types/core/section/constructor.d.ts +748 -0
  150. package/types/core/section/context.d.ts +45 -0
  151. package/types/core/section/documentType.d.ts +178 -0
  152. package/types/editorInjector/_classes.d.ts +41 -0
  153. package/types/editorInjector/_core.d.ts +92 -0
  154. package/types/editorInjector/index.d.ts +71 -0
  155. package/types/helper/converter.d.ts +150 -0
  156. package/types/helper/dom/domCheck.d.ts +182 -0
  157. package/types/helper/dom/domQuery.d.ts +214 -0
  158. package/types/helper/dom/domUtils.d.ts +211 -0
  159. package/types/helper/dom/index.d.ts +9 -0
  160. package/types/helper/env.d.ts +149 -0
  161. package/types/helper/index.d.ts +163 -0
  162. package/types/helper/keyCodeMap.d.ts +110 -0
  163. package/types/helper/numbers.d.ts +43 -0
  164. package/types/helper/unicode.d.ts +28 -0
  165. package/types/index.d.ts +0 -0
  166. package/{typings/Lang.d.ts → types/langs/_Lang.d.ts} +170 -103
  167. package/types/langs/ckb.d.ts +384 -0
  168. package/types/langs/cs.d.ts +384 -0
  169. package/types/langs/da.d.ts +384 -0
  170. package/types/langs/de.d.ts +384 -0
  171. package/types/langs/en.d.ts +384 -0
  172. package/types/langs/es.d.ts +384 -0
  173. package/types/langs/fa.d.ts +384 -0
  174. package/types/langs/fr.d.ts +384 -0
  175. package/types/langs/he.d.ts +384 -0
  176. package/types/langs/hu.d.ts +384 -0
  177. package/types/langs/index.d.ts +48 -0
  178. package/types/langs/it.d.ts +384 -0
  179. package/types/langs/ja.d.ts +384 -0
  180. package/types/langs/ko.d.ts +384 -0
  181. package/types/langs/lv.d.ts +384 -0
  182. package/types/langs/nl.d.ts +384 -0
  183. package/types/langs/pl.d.ts +384 -0
  184. package/types/langs/pt_br.d.ts +384 -0
  185. package/types/langs/ro.d.ts +384 -0
  186. package/types/langs/ru.d.ts +384 -0
  187. package/types/langs/se.d.ts +384 -0
  188. package/types/langs/tr.d.ts +384 -0
  189. package/types/langs/ua.d.ts +384 -0
  190. package/types/langs/ur.d.ts +384 -0
  191. package/types/langs/zh_cn.d.ts +384 -0
  192. package/types/modules/ApiManager.d.ts +125 -0
  193. package/types/modules/Browser.d.ts +326 -0
  194. package/types/modules/ColorPicker.d.ts +131 -0
  195. package/types/modules/Controller.d.ts +231 -0
  196. package/types/modules/Figure.d.ts +504 -0
  197. package/types/modules/FileManager.d.ts +202 -0
  198. package/types/modules/HueSlider.d.ts +136 -0
  199. package/types/modules/Modal.d.ts +117 -0
  200. package/types/modules/ModalAnchorEditor.d.ts +236 -0
  201. package/types/modules/SelectMenu.d.ts +194 -0
  202. package/types/modules/_DragHandle.d.ts +7 -0
  203. package/types/modules/index.d.ts +26 -0
  204. package/types/plugins/browser/audioGallery.d.ts +55 -0
  205. package/types/plugins/browser/fileBrowser.d.ts +64 -0
  206. package/types/plugins/browser/fileGallery.d.ts +55 -0
  207. package/types/plugins/browser/imageGallery.d.ts +51 -0
  208. package/types/plugins/browser/videoGallery.d.ts +57 -0
  209. package/types/plugins/command/blockquote.d.ts +28 -0
  210. package/types/plugins/command/exportPDF.d.ts +46 -0
  211. package/types/plugins/command/fileUpload.d.ts +156 -0
  212. package/types/plugins/command/list_bulleted.d.ts +56 -0
  213. package/types/plugins/command/list_numbered.d.ts +56 -0
  214. package/types/plugins/dropdown/align.d.ts +60 -0
  215. package/types/plugins/dropdown/backgroundColor.d.ts +63 -0
  216. package/types/plugins/dropdown/font.d.ts +54 -0
  217. package/types/plugins/dropdown/fontColor.d.ts +63 -0
  218. package/types/plugins/dropdown/formatBlock.d.ts +58 -0
  219. package/types/plugins/dropdown/hr.d.ts +81 -0
  220. package/types/plugins/dropdown/layout.d.ts +40 -0
  221. package/types/plugins/dropdown/lineHeight.d.ts +50 -0
  222. package/types/plugins/dropdown/list.d.ts +39 -0
  223. package/types/plugins/dropdown/paragraphStyle.d.ts +54 -0
  224. package/types/plugins/dropdown/table.d.ts +579 -0
  225. package/types/plugins/dropdown/template.d.ts +40 -0
  226. package/types/plugins/dropdown/textStyle.d.ts +41 -0
  227. package/types/plugins/field/mention.d.ts +102 -0
  228. package/types/plugins/index.d.ts +107 -0
  229. package/types/plugins/input/fontSize.d.ts +170 -0
  230. package/types/plugins/input/pageNavigator.d.ts +28 -0
  231. package/types/plugins/modal/audio.d.ts +269 -0
  232. package/types/plugins/modal/drawing.d.ts +246 -0
  233. package/types/plugins/modal/embed.d.ts +387 -0
  234. package/types/plugins/modal/image.d.ts +451 -0
  235. package/types/plugins/modal/link.d.ts +128 -0
  236. package/types/plugins/modal/math.d.ts +193 -0
  237. package/types/plugins/modal/video.d.ts +485 -0
  238. package/types/plugins/popup/anchor.d.ts +56 -0
  239. package/types/suneditor.d.ts +51 -0
  240. package/types/typedef-global.d.ts +144 -0
  241. package/src/core/class/notice.js +0 -42
  242. package/src/helper/domUtils.js +0 -1177
  243. package/src/modules/FileBrowser.js +0 -271
  244. package/src/plugins/command/exportPdf.js +0 -168
  245. package/src/plugins/fileBrowser/imageGallery.js +0 -81
  246. package/src/themes/test.css +0 -61
  247. package/typings/CommandPlugin.d.ts +0 -8
  248. package/typings/DialogPlugin.d.ts +0 -20
  249. package/typings/FileBrowserPlugin.d.ts +0 -30
  250. package/typings/Module.d.ts +0 -15
  251. package/typings/Plugin.d.ts +0 -42
  252. package/typings/SubmenuPlugin.d.ts +0 -8
  253. package/typings/_classes.d.ts +0 -17
  254. package/typings/_colorPicker.d.ts +0 -60
  255. package/typings/_core.d.ts +0 -55
  256. package/typings/align.d.ts +0 -5
  257. package/typings/audio.d.ts +0 -5
  258. package/typings/backgroundColor.d.ts +0 -5
  259. package/typings/blockquote.d.ts +0 -5
  260. package/typings/char.d.ts +0 -39
  261. package/typings/component.d.ts +0 -38
  262. package/typings/context.d.ts +0 -39
  263. package/typings/converter.d.ts +0 -33
  264. package/typings/dialog.d.ts +0 -28
  265. package/typings/domUtils.d.ts +0 -361
  266. package/typings/editor.d.ts +0 -7
  267. package/typings/editor.ts +0 -542
  268. package/typings/env.d.ts +0 -70
  269. package/typings/eventManager.d.ts +0 -37
  270. package/typings/events.d.ts +0 -262
  271. package/typings/fileBrowser.d.ts +0 -42
  272. package/typings/fileManager.d.ts +0 -67
  273. package/typings/font.d.ts +0 -5
  274. package/typings/fontColor.d.ts +0 -5
  275. package/typings/fontSize.d.ts +0 -5
  276. package/typings/format.d.ts +0 -191
  277. package/typings/formatBlock.d.ts +0 -5
  278. package/typings/history.d.ts +0 -48
  279. package/typings/horizontalRule.d.ts +0 -5
  280. package/typings/image.d.ts +0 -5
  281. package/typings/imageGallery.d.ts +0 -5
  282. package/typings/index.d.ts +0 -21
  283. package/typings/index.modules.d.ts +0 -11
  284. package/typings/index.plugins.d.ts +0 -58
  285. package/typings/lineHeight.d.ts +0 -5
  286. package/typings/link.d.ts +0 -5
  287. package/typings/list.d.ts +0 -5
  288. package/typings/math.d.ts +0 -5
  289. package/typings/mediaContainer.d.ts +0 -25
  290. package/typings/mention.d.ts +0 -5
  291. package/typings/node.d.ts +0 -57
  292. package/typings/notice.d.ts +0 -16
  293. package/typings/numbers.d.ts +0 -29
  294. package/typings/offset.d.ts +0 -24
  295. package/typings/options.d.ts +0 -589
  296. package/typings/paragraphStyle.d.ts +0 -5
  297. package/typings/resizing.d.ts +0 -141
  298. package/typings/selection.d.ts +0 -94
  299. package/typings/shortcuts.d.ts +0 -13
  300. package/typings/suneditor.d.ts +0 -9
  301. package/typings/table.d.ts +0 -5
  302. package/typings/template.d.ts +0 -5
  303. package/typings/textStyle.d.ts +0 -5
  304. package/typings/toolbar.d.ts +0 -32
  305. package/typings/unicode.d.ts +0 -25
  306. package/typings/video.d.ts +0 -5
@@ -1,82 +1,129 @@
1
1
  import EditorInjector from '../../editorInjector';
2
2
  import { Modal, Controller, FileManager, Figure, _DragHandle } from '../../modules';
3
- import { domUtils, numbers, env } from '../../helper';
3
+ import { dom, numbers, env } from '../../helper';
4
+ import { CreateTooltipInner } from '../../core/section/constructor';
4
5
  const { NO_EVENT, ON_OVER_COMPONENT } = env;
5
6
 
6
- const Audio_ = function (editor, pluginOptions) {
7
- // plugin bisic properties
8
- EditorInjector.call(this, editor);
9
- this.title = this.lang.audio;
10
- this.icon = 'audio';
11
-
12
- // define plugin options
13
- this.pluginOptions = {
14
- defaultWidth: !pluginOptions.defaultWidth ? '' : numbers.is(pluginOptions.defaultWidth) ? pluginOptions.defaultWidth + 'px' : pluginOptions.defaultWidth,
15
- defaultHeight: !pluginOptions.defaultHeight ? '' : numbers.is(pluginOptions.defaultHeight) ? pluginOptions.defaultHeight + 'px' : pluginOptions.defaultHeight,
16
- createFileInput: !!pluginOptions.createFileInput,
17
- createUrlInput: pluginOptions.createUrlInput === undefined || !pluginOptions.createFileInput ? true : pluginOptions.createUrlInput,
18
- uploadUrl: typeof pluginOptions.uploadUrl === 'string' ? pluginOptions.uploadUrl : null,
19
- uploadHeaders: pluginOptions.uploadHeaders || null,
20
- uploadSizeLimit: /\d+/.test(pluginOptions.uploadSizeLimit) ? numbers.get(pluginOptions.uploadSizeLimit, 0) : null,
21
- uploadSingleSizeLimit: /\d+/.test(pluginOptions.uploadSingleSizeLimit) ? numbers.get(pluginOptions.uploadSingleSizeLimit, 0) : null,
22
- allowMultiple: !!pluginOptions.allowMultiple,
23
- acceptedFormats: typeof pluginOptions.acceptedFormats !== 'string' || pluginOptions.acceptedFormats.trim() === '*' ? 'audio/*' : pluginOptions.acceptedFormats.trim() || 'audio/*',
24
- audioTagAttributes: pluginOptions.audioTagAttributes || null
25
- };
26
-
27
- // create HTML
28
- const modalEl = CreateHTML_modal(editor, this.pluginOptions);
29
- const controllerEl = CreateHTML_controller(editor);
30
-
31
- // modules
32
- this.modal = new Modal(this, modalEl);
33
- this.controller = new Controller(this, controllerEl, { position: 'bottom', disabled: true });
34
- this.fileManager = new FileManager(this, {
35
- query: 'audio',
36
- loadHandler: this.events.onAudioLoad,
37
- eventHandler: this.events.onAudioAction
38
- });
39
-
40
- // members
41
- this.figure = new Figure(this, null, {});
42
- this.fileModalWrapper = modalEl.querySelector('.se-flex-input-wrapper');
43
- this.audioInputFile = modalEl.querySelector('.__se__file_input');
44
- this.audioUrlFile = modalEl.querySelector('.se-input-url');
45
- this.preview = modalEl.querySelector('.se-link-preview');
46
- this.defaultWidth = this.pluginOptions.defaultWidth;
47
- this.defaultHeight = this.pluginOptions.defaultHeight;
48
- this.urlValue = '';
49
- this._element = null;
50
-
51
- // init
52
- if (this.audioInputFile) {
53
- modalEl.querySelector('.se-modal-files-edge-button').addEventListener('click', RemoveSelectedFiles.bind(this.audioInputFile, this.audioUrlFile, this.preview));
7
+ /**
8
+ * @typedef {import('../../core/base/events').AudioInfo} AudioInfo
9
+ */
10
+
11
+ /**
12
+ * @typedef {Object} AudioPluginOptions
13
+ * @property {string} [defaultWidth="300px"] - The default width of the audio tag (e.g., "300px").
14
+ * @property {string} [defaultHeight="150px"] - The default height of the audio tag (e.g., "150px").
15
+ * @property {boolean} [createFileInput] - Whether to create a file input element.
16
+ * @property {boolean} [createUrlInput] - Whether to create a URL input element (default is true if file input is not created).
17
+ * @property {string} [uploadUrl] - The URL to which files will be uploaded.
18
+ * @property {Object<string, string>} [uploadHeaders] - Headers to include in the file upload request.
19
+ * @property {number} [uploadSizeLimit] - The total upload size limit in bytes.
20
+ * @property {number} [uploadSingleSizeLimit] - The single file size limit in bytes.
21
+ * @property {boolean} [allowMultiple] - Whether to allow multiple file uploads.
22
+ * @property {string} [acceptedFormats="audio/*"] - Accepted file formats (default is "audio/*").
23
+ * @property {Object<string, string>} [audioTagAttributes] - Additional attributes to set on the audio tag.
24
+ */
25
+
26
+ /**
27
+ * @class
28
+ * @description Audio modal plugin.
29
+ */
30
+ class Audio_ extends EditorInjector {
31
+ static key = 'audio';
32
+ static type = 'modal';
33
+ static className = '';
34
+ /**
35
+ * @this {Audio_}
36
+ * @param {HTMLElement} node - The node to check.
37
+ * @returns {HTMLElement|null} Returns a node if the node is a valid component.
38
+ */
39
+ static component(node) {
40
+ return /^AUDIO$/i.test(node?.nodeName) ? node : null;
41
+ }
42
+
43
+ /**
44
+ * @constructor
45
+ * @param {__se__EditorCore} editor - The root editor instance
46
+ * @param {AudioPluginOptions} pluginOptions
47
+ */
48
+ constructor(editor, pluginOptions) {
49
+ // plugin bisic properties
50
+ super(editor);
51
+ this.title = this.lang.audio;
52
+ this.icon = 'audio';
53
+
54
+ // define plugin options
55
+ this.pluginOptions = {
56
+ defaultWidth: !pluginOptions.defaultWidth ? '' : numbers.is(pluginOptions.defaultWidth) ? pluginOptions.defaultWidth + 'px' : pluginOptions.defaultWidth,
57
+ defaultHeight: !pluginOptions.defaultHeight ? '' : numbers.is(pluginOptions.defaultHeight) ? pluginOptions.defaultHeight + 'px' : pluginOptions.defaultHeight,
58
+ createFileInput: !!pluginOptions.createFileInput,
59
+ createUrlInput: pluginOptions.createUrlInput === undefined || !pluginOptions.createFileInput ? true : pluginOptions.createUrlInput,
60
+ uploadUrl: typeof pluginOptions.uploadUrl === 'string' ? pluginOptions.uploadUrl : null,
61
+ uploadHeaders: pluginOptions.uploadHeaders || null,
62
+ uploadSizeLimit: numbers.get(pluginOptions.uploadSizeLimit, 0),
63
+ uploadSingleSizeLimit: numbers.get(pluginOptions.uploadSingleSizeLimit, 0),
64
+ allowMultiple: !!pluginOptions.allowMultiple,
65
+ acceptedFormats: typeof pluginOptions.acceptedFormats !== 'string' || pluginOptions.acceptedFormats.trim() === '*' ? 'audio/*' : pluginOptions.acceptedFormats.trim() || 'audio/*',
66
+ audioTagAttributes: pluginOptions.audioTagAttributes || null
67
+ };
68
+
69
+ // create HTML
70
+ const modalEl = CreateHTML_modal(editor, this.pluginOptions);
71
+ const controllerEl = CreateHTML_controller(editor);
72
+
73
+ // modules
74
+ this.modal = new Modal(this, modalEl);
75
+ this.controller = new Controller(this, controllerEl, { position: 'bottom', disabled: true });
76
+ this.fileManager = new FileManager(this, {
77
+ query: 'audio',
78
+ loadHandler: this.events.onAudioLoad,
79
+ eventHandler: this.events.onAudioAction
80
+ });
81
+
82
+ // members
83
+ this.figure = new Figure(this, null, {});
84
+
85
+ /** @type {HTMLElement} */
86
+ this.fileModalWrapper = modalEl.querySelector('.se-flex-input-wrapper');
87
+ /** @type {HTMLInputElement} */
88
+ this.audioInputFile = modalEl.querySelector('.__se__file_input');
89
+ /** @type {HTMLInputElement} */
90
+ this.audioUrlFile = modalEl.querySelector('.se-input-url');
91
+ /** @type {HTMLElement} */
92
+ this.preview = modalEl.querySelector('.se-link-preview');
93
+ /** @type {HTMLAudioElement} */
94
+ this._element = null;
95
+
96
+ this.defaultWidth = this.pluginOptions.defaultWidth;
97
+ this.defaultHeight = this.pluginOptions.defaultHeight;
98
+ this.urlValue = '';
99
+
100
+ const galleryButton = modalEl.querySelector('.__se__gallery');
101
+ if (galleryButton) this.eventManager.addEvent(galleryButton, 'click', this.#OpenGallery.bind(this));
102
+
103
+ // init
104
+ if (this.audioInputFile) {
105
+ this.eventManager.addEvent(modalEl.querySelector('.se-modal-files-edge-button'), 'click', this.#RemoveSelectedFiles.bind(this, this.audioUrlFile, this.preview));
106
+ if (this.audioUrlFile) {
107
+ this.eventManager.addEvent(this.audioInputFile, 'change', this.#FileInputChange.bind(this));
108
+ }
109
+ }
54
110
  if (this.audioUrlFile) {
55
- this.audioInputFile.addEventListener('change', FileInputChange.bind(this));
111
+ this.eventManager.addEvent(this.audioUrlFile, 'input', this.#OnLinkPreview.bind(this));
56
112
  }
57
113
  }
58
- if (this.audioUrlFile) {
59
- this.audioUrlFile.addEventListener('input', OnLinkPreview.bind(this));
60
- }
61
- };
62
-
63
- Audio_.key = 'audio';
64
- Audio_.type = 'modal';
65
- Audio_.className = '';
66
- Audio_.component = function (node) {
67
- return /^AUDIO$/i.test(node?.nodeName) ? node : null;
68
- };
69
- Audio_.prototype = {
114
+
70
115
  /**
71
- * @override type = "modal"
116
+ * @editorMethod Modules.Modal
117
+ * @description Executes the method that is called when a "Modal" module's is opened.
72
118
  */
73
119
  open() {
74
120
  this.modal.open();
75
- },
121
+ }
76
122
 
77
123
  /**
78
- * @override modal
79
- * @param {boolean} isUpdate open state is update
124
+ * @editorMethod Modules.Modal
125
+ * @description Executes the method that is called when a plugin's modal is opened.
126
+ * @param {boolean} isUpdate "Indicates whether the modal is for editing an existing component (true) or registering a new one (false)."
80
127
  */
81
128
  on(isUpdate) {
82
129
  if (!isUpdate) {
@@ -87,51 +134,58 @@ Audio_.prototype = {
87
134
  } else {
88
135
  if (this.audioInputFile && this.pluginOptions.allowMultiple) this.audioInputFile.removeAttribute('multiple');
89
136
  }
90
- },
137
+ }
91
138
 
92
139
  /**
93
- * @description On paste or drop
94
- * @param {*} params { frameContext, event, file }
140
+ * @editorMethod Editor.EventManager
141
+ * @description Executes the event function of "paste" or "drop".
142
+ * @param {Object} params { frameContext, event, file }
143
+ * @param {__se__FrameContext} params.frameContext Frame context
144
+ * @param {ClipboardEvent} params.event Event object
145
+ * @param {File} params.file File object
146
+ * @returns {boolean} - If return false, the file upload will be canceled
95
147
  */
96
148
  onPastAndDrop({ file }) {
97
149
  if (!/^audio/.test(file.type)) return;
98
150
 
99
- this._submitFile([file]);
151
+ this.submitFile([file]);
100
152
  this.editor.focus();
101
153
 
102
154
  return false;
103
- },
155
+ }
104
156
 
105
157
  /**
106
- * @override modal
107
- * @returns {boolean | undefined}
158
+ * @editorMethod Modules.Modal
159
+ * @description This function is called when a form within a modal window is "submit".
160
+ * @returns {Promise<boolean>} Success or failure
108
161
  */
109
- modalAction() {
162
+ async modalAction() {
110
163
  if (this.audioInputFile && this.audioInputFile?.files.length > 0) {
111
- return this._submitFile(this.audioInputFile.files);
164
+ return await this.submitFile(this.audioInputFile.files);
112
165
  } else if (this.audioUrlFile && this.urlValue.length > 0) {
113
- return this._submitURL(this.urlValue);
166
+ return await this.submitURL(this.urlValue);
114
167
  }
115
168
  return false;
116
- },
169
+ }
117
170
 
118
171
  /**
119
- * @override modal
172
+ * @editorMethod Modules.Modal
173
+ * @description This function is called before the modal window is opened, but before it is closed.
120
174
  */
121
175
  init() {
122
176
  Modal.OnChangeFile(this.fileModalWrapper, []);
123
177
  if (this.audioInputFile) this.audioInputFile.value = '';
124
178
  if (this.audioUrlFile) this.urlValue = this.preview.textContent = this.audioUrlFile.value = '';
125
179
  if (this.audioInputFile && this.audioUrlFile) {
126
- this.audioUrlFile.removeAttribute('disabled');
180
+ this.audioUrlFile.disabled = false;
127
181
  this.preview.style.textDecoration = '';
128
182
  }
129
- },
183
+ }
130
184
 
131
185
  /**
132
- * @override controller
133
- * @param {Element} target Target button element
134
- * @returns
186
+ * @editorMethod Modules.Controller
187
+ * @description Executes the method that is called when a button is clicked in the "controller".
188
+ * @param {HTMLButtonElement} target Target button element
135
189
  */
136
190
  controllerAction(target) {
137
191
  if (/update/.test(target.getAttribute('data-command'))) {
@@ -140,10 +194,18 @@ Audio_.prototype = {
140
194
  } else {
141
195
  this.destroy();
142
196
  }
143
- },
197
+ }
144
198
 
145
199
  /**
146
- * @override core
200
+ * @editorMethod Editor.core
201
+ * @description This method is used to validate and preserve the format of the component within the editor.
202
+ * - It ensures that the structure and attributes of the element are maintained and secure.
203
+ * - The method checks if the element is already wrapped in a valid container and updates its attributes if necessary.
204
+ * - If the element isn't properly contained, a new container is created to retain the format.
205
+ * @returns {{query: string, method: (element: HTMLAudioElement) => void}} The format retention object containing the query and method to process the element.
206
+ * - query: The selector query to identify the relevant elements (in this case, 'audio').
207
+ * - method:The function to execute on the element to validate and preserve its format.
208
+ * - The function takes the element as an argument, checks if it is contained correctly, and applies necessary adjustments.
147
209
  */
148
210
  retainFormat() {
149
211
  return {
@@ -154,44 +216,51 @@ Audio_.prototype = {
154
216
 
155
217
  this._setTagAttrs(element);
156
218
  const figure = Figure.CreateContainer(element.cloneNode(true), 'se-flex-component');
157
- this.figure._retainFigureFormat(figure.container, element, null);
219
+ this.figure.retainFigureFormat(figure.container, element, null, this.fileManager);
158
220
  }
159
221
  };
160
- },
222
+ }
161
223
 
162
224
  /**
163
- * @override component, fileManager
164
- * @description Called when a container is selected.
165
- * @param {Element} element Target element
225
+ * @editorMethod Editor.Component
226
+ * @description Executes the method that is called when a component of a plugin is selected.
227
+ * @param {HTMLElement} target Target component element
166
228
  */
167
- select(element) {
168
- this.figure.open(element, { nonResizing: true, nonSizeInfo: true, nonBorder: true, figureTarget: true, __fileManagerInfo: false });
169
- this.ready(element);
170
- },
229
+ select(target) {
230
+ this.figure.open(target, { nonResizing: true, nonSizeInfo: true, nonBorder: true, figureTarget: true, __fileManagerInfo: false });
231
+ this._ready(target);
232
+ }
171
233
 
172
234
  /**
173
- * @override fileManager
235
+ * @private
236
+ * @description Prepares the component for selection.
237
+ * - Ensures that the controller is properly positioned and initialized.
238
+ * - Prevents duplicate event handling if the component is already selected.
239
+ * @param {HTMLElement} target - The selected element.
174
240
  */
175
- ready(target) {
241
+ _ready(target) {
176
242
  if (_DragHandle.get('__overInfo') === ON_OVER_COMPONENT) return;
177
- this._element = target;
243
+ this._element = /** @type {HTMLAudioElement} */ (target);
178
244
  this.controller.open(target, null, { isWWTarget: false, addOffset: null });
179
- },
245
+ }
180
246
 
181
247
  /**
182
- * @override fileManager
248
+ * @editorMethod Editor.Component
249
+ * @description Method to delete a component of a plugin, called by the "FileManager", "Controller" module.
250
+ * @param {HTMLElement=} target Target element, if null current selected element
251
+ * @returns {Promise<void>}
183
252
  */
184
- async destroy(element) {
185
- element = element || this._element;
253
+ async destroy(target) {
254
+ const element = target || this._element;
186
255
  const figure = Figure.GetContainer(element);
187
256
  const container = figure.container || element;
188
257
  const focusEl = container.previousElementSibling || container.nextElementSibling;
189
258
 
190
- const message = await this.triggerEvent('onAudioDeleteBefore', { target: element, container: figure, url: element.getAttribute('src') });
259
+ const message = await this.triggerEvent('onAudioDeleteBefore', { element: element, container: figure, url: element.getAttribute('src') });
191
260
  if (message === false) return;
192
261
 
193
262
  const emptyDiv = container.parentNode;
194
- domUtils.removeItem(container);
263
+ dom.utils.removeItem(container);
195
264
  this.init();
196
265
  this.controller.close();
197
266
 
@@ -208,8 +277,15 @@ Audio_.prototype = {
208
277
  // focus
209
278
  this.editor.focusEdge(focusEl);
210
279
  this.history.push(false);
211
- },
280
+ }
212
281
 
282
+ /**
283
+ * @private
284
+ * @description Registers uploaded audio files and creates the corresponding audio elements.
285
+ * - Iterates through the uploaded files and inserts them into the editor.
286
+ * @param {AudioInfo} info - Upload metadata, including `isUpdate` flag and `element`.
287
+ * @param {Object<string, *>} response - Server response containing uploaded file details.
288
+ */
213
289
  _register(info, response) {
214
290
  const fileList = response.result;
215
291
 
@@ -220,14 +296,19 @@ Audio_.prototype = {
220
296
  file = { name: fileList[i].name, size: fileList[i].size };
221
297
  this._createComp(oAudio, fileList[i].url, file, info.isUpdate);
222
298
  }
223
- },
299
+ }
224
300
 
225
- async _submitFile(fileList) {
301
+ /**
302
+ * @description Create an "audio" component using the provided files.
303
+ * @param {FileList|File[]} fileList File object list
304
+ * @returns {Promise<boolean>} If return false, the file upload will be canceled
305
+ */
306
+ async submitFile(fileList) {
226
307
  if (fileList.length === 0) return false;
227
308
 
228
309
  let fileSize = 0;
229
310
  const files = [];
230
- const slngleSizeLimit = this.uploadSingleSizeLimit;
311
+ const slngleSizeLimit = this.pluginOptions.uploadSingleSizeLimit;
231
312
  for (let i = 0, len = fileList.length, f, s; i < len; i++) {
232
313
  f = fileList[i];
233
314
  if (!/audio/i.test(f.type)) continue;
@@ -242,7 +323,7 @@ Audio_.prototype = {
242
323
  file: f
243
324
  });
244
325
 
245
- this.notice.open(message === NO_EVENT ? err : message || err);
326
+ this.ui.noticeOpen(message === NO_EVENT ? err : message || err);
246
327
 
247
328
  return false;
248
329
  }
@@ -256,7 +337,7 @@ Audio_.prototype = {
256
337
  const err = '[SUNEDITOR.audioUpload.fail] Size of uploadable total audios: ' + limitSize / 1000 + 'KB';
257
338
  const message = await this.triggerEvent('onAudioUploadError', { error: err, limitSize, currentSize: this.fileManager.getSize(), uploadSize: fileSize });
258
339
 
259
- this.notice.open(message === NO_EVENT ? err : message || err);
340
+ this.ui.noticeOpen(message === NO_EVENT ? err : message || err);
260
341
 
261
342
  return false;
262
343
  }
@@ -273,7 +354,7 @@ Audio_.prototype = {
273
354
  }.bind(this, audioInfo);
274
355
 
275
356
  const result = await this.triggerEvent('onAudioUploadBefore', {
276
- ...audioInfo,
357
+ info: audioInfo,
277
358
  handler
278
359
  });
279
360
 
@@ -284,9 +365,14 @@ Audio_.prototype = {
284
365
  if (result === true || result === NO_EVENT) handler(null);
285
366
 
286
367
  return true;
287
- },
368
+ }
288
369
 
289
- async _submitURL(url) {
370
+ /**
371
+ * @description Create an "audio" component using the provided url.
372
+ * @param {string} url File url
373
+ * @returns {Promise<boolean>}
374
+ */
375
+ async submitURL(url) {
290
376
  if (url.length === 0) return false;
291
377
 
292
378
  const file = { name: url.split('/').pop(), size: 0 };
@@ -303,7 +389,7 @@ Audio_.prototype = {
303
389
  }.bind(this, audioInfo);
304
390
 
305
391
  const result = await this.triggerEvent('onAudioUploadBefore', {
306
- ...audioInfo,
392
+ info: audioInfo,
307
393
  handler
308
394
  });
309
395
 
@@ -314,19 +400,29 @@ Audio_.prototype = {
314
400
  if (result === true || result === NO_EVENT) handler(null);
315
401
 
316
402
  return true;
317
- },
403
+ }
318
404
 
405
+ /**
406
+ * @private
407
+ * @description Creates or updates an audio component within the editor.
408
+ * - If `isUpdate` is `true`, updates the existing element's `src`.
409
+ * - Otherwise, inserts a new audio component with the given file.
410
+ * @param {HTMLAudioElement} element - The target audio element.
411
+ * @param {string} src - The source URL of the audio file.
412
+ * @param {{name: string, size: number}} file - The file metadata (name, size).
413
+ * @param {boolean} isUpdate - Whether to update an existing element.
414
+ */
319
415
  _createComp(element, src, file, isUpdate) {
320
416
  // create new tag
321
417
  if (!isUpdate) {
322
418
  this.fileManager.setFileData(element, file);
323
419
  element.src = src;
324
420
  const figure = Figure.CreateContainer(element, 'se-flex-component');
325
- if (!this.component.insert(figure.container, false, !this.options.get('mediaAutoSelect'))) {
421
+ if (!this.component.insert(figure.container, { skipCharCount: false, skipSelection: !this.options.get('componentAutoSelect'), skipHistory: false })) {
326
422
  this.editor.focus();
327
423
  return;
328
424
  }
329
- if (!this.options.get('mediaAutoSelect')) {
425
+ if (!this.options.get('componentAutoSelect')) {
330
426
  const line = this.format.addLine(figure.container, null);
331
427
  if (line) this.selection.setRange(line, 0, line, 0);
332
428
  }
@@ -343,18 +439,31 @@ Audio_.prototype = {
343
439
  }
344
440
 
345
441
  if (isUpdate) this.history.push(false);
346
- },
442
+ }
347
443
 
444
+ /**
445
+ * @private
446
+ * @description Creates a new `<audio>` element with default attributes.
447
+ * - Applies width, height, and additional attributes from plugin options.
448
+ * @returns {HTMLAudioElement} - The newly created `<audio>` element.
449
+ */
348
450
  _createAudioTag() {
349
451
  const w = this.defaultWidth;
350
452
  const h = this.defaultHeight;
351
- const oAudio = domUtils.createElement('AUDIO', { style: (w ? 'width:' + w + '; ' : '') + (h ? 'height:' + h + ';' : '') });
453
+ /** @type {HTMLAudioElement} */
454
+ const oAudio = dom.utils.createElement('AUDIO', { style: (w ? 'width:' + w + '; ' : '') + (h ? 'height:' + h + ';' : '') });
352
455
  this._setTagAttrs(oAudio);
353
456
  return oAudio;
354
- },
457
+ }
355
458
 
459
+ /**
460
+ * @private
461
+ * @description Sets attributes on an audio element based on plugin options.
462
+ * - Adds the `controls` attribute and applies any custom attributes.
463
+ * @param {HTMLElement} element - The `<audio>` element to modify.
464
+ */
356
465
  _setTagAttrs(element) {
357
- element.setAttribute('controls', true);
466
+ element.setAttribute('controls', 'true');
358
467
 
359
468
  const attrs = this.pluginOptions.audioTagAttributes;
360
469
  if (!attrs) return;
@@ -362,74 +471,127 @@ Audio_.prototype = {
362
471
  for (const key in attrs) {
363
472
  element.setAttribute(key, attrs[key]);
364
473
  }
365
- },
474
+ }
366
475
 
476
+ /**
477
+ * @private
478
+ * @description Uploads audio files to the server.
479
+ * - Sends a request to the configured upload URL and processes the response.
480
+ * @param {AudioInfo} info - Upload metadata, including `files` and `isUpdate`.
481
+ * @param {FileList|File[]} files - The files to be uploaded.
482
+ */
367
483
  _serverUpload(info, files) {
368
484
  if (!files) return;
369
485
 
370
486
  const uploadFiles = this.modal.isUpdate ? [files[0]] : files;
371
- this.fileManager.upload(this.pluginOptions.uploadUrl, this.pluginOptions.uploadHeaders, uploadFiles, UploadCallBack.bind(this, info), this._error.bind(this));
372
- },
487
+ this.fileManager.upload(this.pluginOptions.uploadUrl, this.pluginOptions.uploadHeaders, uploadFiles, this.#UploadCallBack.bind(this, info), this._error.bind(this));
488
+ }
373
489
 
490
+ /**
491
+ * @private
492
+ * @description Handles errors that occur during the audio upload process.
493
+ * - Triggers the `onAudioUploadError` event to allow custom handling of errors.
494
+ * - Displays an error message in the editor's UI.
495
+ * - Logs the error to the console for debugging.
496
+ * @param {Object<string, *>} response - The error response object from the server or upload process.
497
+ * @returns {Promise<void>}
498
+ */
374
499
  async _error(response) {
375
500
  const message = await this.triggerEvent('onAudioUploadError', { error: response });
376
501
  const err = message === NO_EVENT ? response.errorMessage : message || response.errorMessage;
377
- this.notice.open(err);
502
+ this.ui.noticeOpen(err);
378
503
  console.error('[SUNEDITOR.plugin.audio.error]', err);
379
- },
380
-
381
- constructor: Audio_
382
- };
504
+ }
383
505
 
384
- async function UploadCallBack(info, xmlHttp) {
385
- if ((await this.triggerEvent('audioUploadHandler', { xmlHttp, info })) === NO_EVENT) {
386
- const response = JSON.parse(xmlHttp.responseText);
387
- if (response.errorMessage) {
388
- this._error(response);
389
- } else {
390
- this._register(info, response);
506
+ /**
507
+ * @description Handles the server response after a file upload.
508
+ * - If the upload is successful, registers the uploaded audio.
509
+ * - If an error occurs, triggers an error event.
510
+ * @param {AudioInfo} info - Upload metadata.
511
+ * @param {XMLHttpRequest} xmlHttp - The completed XHR request.
512
+ */
513
+ async #UploadCallBack(info, xmlHttp) {
514
+ if ((await this.triggerEvent('audioUploadHandler', { xmlHttp, info })) === NO_EVENT) {
515
+ const response = JSON.parse(xmlHttp.responseText);
516
+ if (response.errorMessage) {
517
+ this._error(response);
518
+ } else {
519
+ this._register(info, response);
520
+ }
391
521
  }
392
522
  }
393
- }
394
523
 
395
- function OnLinkPreview(e) {
396
- const value = e.target.value.trim();
397
- this.urlValue = this.preview.textContent = !value
398
- ? ''
399
- : this.options.get('defaultUrlProtocol') && !value.includes('://') && value.indexOf('#') !== 0
400
- ? this.options.get('defaultUrlProtocol') + value
401
- : !value.includes('://')
402
- ? '/' + value
403
- : value;
404
- }
524
+ /**
525
+ * @description Updates the preview text for the entered audio URL.
526
+ * - Formats the URL correctly based on the editor’s settings.
527
+ * @param {InputEvent} e - The input event triggered when the user types a URL.
528
+ */
529
+ #OnLinkPreview(e) {
530
+ /** @type {HTMLInputElement} */
531
+ const target = dom.query.getEventTarget(e);
532
+ const value = target.value.trim();
533
+ this.urlValue = this.preview.textContent = !value
534
+ ? ''
535
+ : this.options.get('defaultUrlProtocol') && !value.includes('://') && value.indexOf('#') !== 0
536
+ ? this.options.get('defaultUrlProtocol') + value
537
+ : !value.includes('://')
538
+ ? '/' + value
539
+ : value;
540
+ }
405
541
 
406
- // Disable url input when uploading files
407
- function RemoveSelectedFiles(urlInput, preview) {
408
- this.value = '';
409
- if (urlInput) {
410
- urlInput.removeAttribute('disabled');
411
- preview.style.textDecoration = '';
542
+ /**
543
+ * @description Opens the audio gallery plugin, if available.
544
+ * - Calls a function to populate the URL input with the selected audio file.
545
+ */
546
+ #OpenGallery() {
547
+ this.plugins.audioGallery.open(this.#SetUrlInput.bind(this));
412
548
  }
413
549
 
414
- // inputFile check
415
- Modal.OnChangeFile(this.fileModalWrapper, []);
416
- }
550
+ /**
551
+ * @param {HTMLInputElement} target - The target element.
552
+ */
553
+ #SetUrlInput(target) {
554
+ this.urlValue = this.preview.textContent = this.audioUrlFile.value = target.getAttribute('data-command') || target.src;
555
+ this.audioUrlFile.focus();
556
+ }
417
557
 
418
- // Disable url input when uploading files
419
- function FileInputChange({ target }) {
420
- if (!this.audioInputFile.value) {
421
- this.audioUrlFile.removeAttribute('disabled');
422
- this.preview.style.textDecoration = '';
423
- } else {
424
- this.audioUrlFile.setAttribute('disabled', true);
425
- this.preview.style.textDecoration = 'line-through';
558
+ /**
559
+ * @description Clears the selected file input and re-enables the URL input.
560
+ * - Ensures that only one input method (file or URL) is used at a time.
561
+ * @param {HTMLInputElement} urlInput - The URL input field.
562
+ * @param {HTMLElement} preview - The preview text element.
563
+ */
564
+ #RemoveSelectedFiles(urlInput, preview) {
565
+ this.audioInputFile.value = '';
566
+ if (urlInput) {
567
+ urlInput.disabled = false;
568
+ preview.style.textDecoration = '';
569
+ }
570
+
571
+ // inputFile check
572
+ Modal.OnChangeFile(this.fileModalWrapper, []);
426
573
  }
427
574
 
428
- // inputFile check
429
- Modal.OnChangeFile(this.fileModalWrapper, target.files);
575
+ /**
576
+ * @param {InputEvent} e - Event object
577
+ */
578
+ #FileInputChange(e) {
579
+ /** @type {HTMLInputElement} */
580
+ const target = dom.query.getEventTarget(e);
581
+ if (!this.audioInputFile.value) {
582
+ this.audioUrlFile.disabled = false;
583
+ this.preview.style.textDecoration = '';
584
+ } else {
585
+ this.audioUrlFile.disabled = true;
586
+ this.preview.style.textDecoration = 'line-through';
587
+ }
588
+
589
+ // inputFile check
590
+ Modal.OnChangeFile(this.fileModalWrapper, target.files);
591
+ }
430
592
  }
431
593
 
432
- function CreateHTML_modal({ lang, icons }, pluginOptions) {
594
+ function CreateHTML_modal({ lang, icons, plugins }, pluginOptions) {
433
595
  let html = /*html*/ `
434
596
  <form method="post" enctype="multipart/form-data">
435
597
  <div class="se-modal-header">
@@ -450,7 +612,17 @@ function CreateHTML_modal({ lang, icons }, pluginOptions) {
450
612
  html += /*html*/ `
451
613
  <div class="se-modal-form">
452
614
  <label>${lang.audio_modal_url}</label>
453
- <input class="se-input-form se-input-url" data-focus type="text" />
615
+ <div class="se-modal-form-files">
616
+ <input class="se-input-form se-input-url" data-focus type="text" />
617
+ ${
618
+ plugins.audioGallery
619
+ ? `<button type="button" class="se-btn se-tooltip se-modal-files-edge-button __se__gallery" aria-label="${lang.audioGallery}">
620
+ ${icons.audio_gallery}
621
+ ${CreateTooltipInner(lang.audioGallery)}
622
+ </button>`
623
+ : ''
624
+ }
625
+ </div>
454
626
  <pre class="se-link-preview"></pre>
455
627
  </div>`;
456
628
  }
@@ -463,7 +635,7 @@ function CreateHTML_modal({ lang, icons }, pluginOptions) {
463
635
  </div>
464
636
  </form>`;
465
637
 
466
- return domUtils.createElement('DIV', { class: 'se-modal-content' }, html);
638
+ return dom.utils.createElement('DIV', { class: 'se-modal-content' }, html);
467
639
  }
468
640
 
469
641
  function CreateHTML_controller({ lang, icons }) {
@@ -486,7 +658,7 @@ function CreateHTML_controller({ lang, icons }) {
486
658
  </div>
487
659
  </div>`;
488
660
 
489
- return domUtils.createElement('DIV', { class: 'se-controller' }, html);
661
+ return dom.utils.createElement('DIV', { class: 'se-controller' }, html);
490
662
  }
491
663
 
492
664
  export default Audio_;