suneditor 2.46.2 → 3.0.0-alpha.1

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 (290) hide show
  1. package/.eslintignore +7 -0
  2. package/.eslintrc.json +64 -0
  3. package/CONTRIBUTING.md +36 -0
  4. package/LICENSE.txt +1 -1
  5. package/README.md +174 -805
  6. package/dist/suneditor.min.css +1 -0
  7. package/dist/suneditor.min.js +1 -2
  8. package/package.json +96 -69
  9. package/src/assets/icons/_default.js +194 -0
  10. package/src/assets/suneditor-content.css +646 -0
  11. package/src/assets/suneditor.css +3378 -0
  12. package/src/core/base/eventHandlers/handler_toolbar.js +114 -0
  13. package/src/core/base/eventHandlers/handler_ww_clipboard.js +31 -0
  14. package/src/core/base/eventHandlers/handler_ww_dragDrop.js +69 -0
  15. package/src/core/base/eventHandlers/handler_ww_key_input.js +975 -0
  16. package/src/core/base/eventHandlers/handler_ww_mouse.js +118 -0
  17. package/src/core/base/eventManager.js +1115 -0
  18. package/src/core/base/events.js +320 -0
  19. package/src/core/base/history.js +301 -0
  20. package/src/core/class/char.js +146 -0
  21. package/src/core/class/component.js +627 -0
  22. package/src/core/class/format.js +3255 -0
  23. package/src/core/class/html.js +1621 -0
  24. package/src/core/class/menu.js +260 -0
  25. package/src/core/class/nodeTransform.js +379 -0
  26. package/src/core/class/notice.js +42 -0
  27. package/src/core/class/offset.js +578 -0
  28. package/src/core/class/selection.js +508 -0
  29. package/src/core/class/shortcuts.js +38 -0
  30. package/src/core/class/toolbar.js +440 -0
  31. package/src/core/class/viewer.js +646 -0
  32. package/src/core/editor.js +1593 -0
  33. package/src/core/section/actives.js +107 -0
  34. package/src/core/section/constructor.js +1237 -0
  35. package/src/core/section/context.js +97 -0
  36. package/src/editorInjector/_classes.js +22 -0
  37. package/src/editorInjector/_core.js +28 -0
  38. package/src/editorInjector/index.js +13 -0
  39. package/src/helper/converter.js +313 -0
  40. package/src/helper/domUtils.js +1177 -0
  41. package/src/helper/env.js +250 -0
  42. package/src/helper/index.js +19 -0
  43. package/src/helper/numbers.js +68 -0
  44. package/src/helper/unicode.js +43 -0
  45. package/src/langs/ckb.js +161 -0
  46. package/src/langs/cs.js +161 -0
  47. package/src/langs/da.js +161 -0
  48. package/src/langs/de.js +162 -0
  49. package/src/langs/en.js +199 -0
  50. package/src/langs/es.js +162 -0
  51. package/src/langs/fa.js +159 -0
  52. package/src/langs/fr.js +161 -0
  53. package/src/langs/he.js +162 -0
  54. package/src/{lang → langs}/index.js +0 -2
  55. package/src/langs/it.js +162 -0
  56. package/src/langs/ja.js +162 -0
  57. package/src/langs/ko.js +162 -0
  58. package/src/langs/lv.js +162 -0
  59. package/src/langs/nl.js +162 -0
  60. package/src/langs/pl.js +162 -0
  61. package/src/langs/pt_br.js +162 -0
  62. package/src/langs/ro.js +162 -0
  63. package/src/langs/ru.js +162 -0
  64. package/src/langs/se.js +162 -0
  65. package/src/langs/tr.js +159 -0
  66. package/src/langs/ua.js +162 -0
  67. package/src/langs/ur.js +162 -0
  68. package/src/langs/zh_cn.js +162 -0
  69. package/src/modules/ApiManager.js +168 -0
  70. package/src/modules/ColorPicker.js +302 -0
  71. package/src/modules/Controller.js +315 -0
  72. package/src/modules/Figure.js +1160 -0
  73. package/src/modules/FileBrowser.js +271 -0
  74. package/src/modules/FileManager.js +290 -0
  75. package/src/modules/HueSlider.js +513 -0
  76. package/src/modules/Modal.js +177 -0
  77. package/src/modules/ModalAnchorEditor.js +494 -0
  78. package/src/modules/SelectMenu.js +447 -0
  79. package/src/modules/_DragHandle.js +16 -0
  80. package/src/modules/index.js +14 -0
  81. package/src/plugins/command/blockquote.js +47 -47
  82. package/src/plugins/command/exportPdf.js +168 -0
  83. package/src/plugins/command/fileUpload.js +389 -0
  84. package/src/plugins/command/list_bulleted.js +112 -0
  85. package/src/plugins/command/list_numbered.js +115 -0
  86. package/src/plugins/dropdown/align.js +143 -0
  87. package/src/plugins/dropdown/backgroundColor.js +73 -0
  88. package/src/plugins/dropdown/font.js +113 -0
  89. package/src/plugins/dropdown/fontColor.js +73 -0
  90. package/src/plugins/dropdown/formatBlock.js +141 -0
  91. package/src/plugins/dropdown/hr.js +111 -0
  92. package/src/plugins/dropdown/layout.js +72 -0
  93. package/src/plugins/dropdown/lineHeight.js +114 -0
  94. package/src/plugins/dropdown/list.js +107 -0
  95. package/src/plugins/dropdown/paragraphStyle.js +117 -0
  96. package/src/plugins/dropdown/table.js +2810 -0
  97. package/src/plugins/dropdown/template.js +71 -0
  98. package/src/plugins/dropdown/textStyle.js +137 -0
  99. package/src/plugins/field/mention.js +172 -0
  100. package/src/plugins/fileBrowser/imageGallery.js +76 -59
  101. package/src/plugins/index.js +86 -24
  102. package/src/plugins/input/fontSize.js +357 -0
  103. package/src/plugins/modal/audio.js +510 -0
  104. package/src/plugins/modal/image.js +1062 -0
  105. package/src/plugins/modal/link.js +211 -0
  106. package/src/plugins/modal/math.js +347 -0
  107. package/src/plugins/modal/video.js +870 -0
  108. package/src/suneditor.js +62 -67
  109. package/src/themes/test.css +61 -0
  110. package/typings/CommandPlugin.d.ts +8 -0
  111. package/typings/DialogPlugin.d.ts +20 -0
  112. package/typings/FileBrowserPlugin.d.ts +30 -0
  113. package/typings/Lang.d.ts +124 -0
  114. package/typings/Module.d.ts +15 -0
  115. package/typings/Plugin.d.ts +42 -0
  116. package/typings/SubmenuPlugin.d.ts +8 -0
  117. package/typings/_classes.d.ts +17 -0
  118. package/typings/_colorPicker.d.ts +60 -0
  119. package/typings/_core.d.ts +55 -0
  120. package/typings/align.d.ts +5 -0
  121. package/{src/plugins/dialog → typings}/audio.d.ts +1 -1
  122. package/typings/backgroundColor.d.ts +5 -0
  123. package/{src/plugins/command → typings}/blockquote.d.ts +1 -1
  124. package/typings/char.d.ts +39 -0
  125. package/typings/component.d.ts +38 -0
  126. package/typings/context.d.ts +39 -0
  127. package/typings/converter.d.ts +33 -0
  128. package/typings/dialog.d.ts +28 -0
  129. package/typings/domUtils.d.ts +361 -0
  130. package/typings/editor.d.ts +7 -0
  131. package/typings/editor.ts +542 -0
  132. package/typings/env.d.ts +70 -0
  133. package/typings/eventManager.d.ts +37 -0
  134. package/typings/events.d.ts +262 -0
  135. package/typings/fileBrowser.d.ts +42 -0
  136. package/typings/fileManager.d.ts +67 -0
  137. package/typings/font.d.ts +5 -0
  138. package/typings/fontColor.d.ts +5 -0
  139. package/typings/fontSize.d.ts +5 -0
  140. package/typings/format.d.ts +191 -0
  141. package/typings/formatBlock.d.ts +5 -0
  142. package/typings/history.d.ts +48 -0
  143. package/typings/horizontalRule.d.ts +5 -0
  144. package/{src/plugins/dialog → typings}/image.d.ts +1 -1
  145. package/{src/plugins/fileBrowser → typings}/imageGallery.d.ts +1 -1
  146. package/typings/index.d.ts +21 -0
  147. package/{src/plugins/modules/index.d.ts → typings/index.modules.d.ts} +3 -3
  148. package/typings/index.plugins.d.ts +58 -0
  149. package/typings/lineHeight.d.ts +5 -0
  150. package/{src/plugins/dialog → typings}/link.d.ts +1 -1
  151. package/typings/list.d.ts +5 -0
  152. package/{src/plugins/dialog → typings}/math.d.ts +1 -1
  153. package/typings/mediaContainer.d.ts +25 -0
  154. package/typings/node.d.ts +57 -0
  155. package/typings/notice.d.ts +16 -0
  156. package/typings/numbers.d.ts +29 -0
  157. package/typings/offset.d.ts +24 -0
  158. package/typings/options.d.ts +589 -0
  159. package/typings/paragraphStyle.d.ts +5 -0
  160. package/typings/resizing.d.ts +141 -0
  161. package/typings/selection.d.ts +94 -0
  162. package/typings/shortcuts.d.ts +13 -0
  163. package/typings/suneditor.d.ts +9 -0
  164. package/typings/table.d.ts +5 -0
  165. package/typings/template.d.ts +5 -0
  166. package/typings/textStyle.d.ts +5 -0
  167. package/typings/toolbar.d.ts +32 -0
  168. package/typings/unicode.d.ts +25 -0
  169. package/{src/plugins/dialog → typings}/video.d.ts +1 -1
  170. package/dist/css/suneditor.min.css +0 -1
  171. package/src/assets/css/suneditor-contents.css +0 -562
  172. package/src/assets/css/suneditor.css +0 -566
  173. package/src/assets/defaultIcons.js +0 -103
  174. package/src/lang/Lang.d.ts +0 -144
  175. package/src/lang/ckb.d.ts +0 -5
  176. package/src/lang/ckb.js +0 -188
  177. package/src/lang/cs.d.ts +0 -5
  178. package/src/lang/cs.js +0 -188
  179. package/src/lang/da.d.ts +0 -5
  180. package/src/lang/da.js +0 -191
  181. package/src/lang/de.d.ts +0 -5
  182. package/src/lang/de.js +0 -188
  183. package/src/lang/en.d.ts +0 -5
  184. package/src/lang/en.js +0 -188
  185. package/src/lang/es.d.ts +0 -5
  186. package/src/lang/es.js +0 -188
  187. package/src/lang/fa.d.ts +0 -5
  188. package/src/lang/fa.js +0 -188
  189. package/src/lang/fr.d.ts +0 -5
  190. package/src/lang/fr.js +0 -188
  191. package/src/lang/he.d.ts +0 -5
  192. package/src/lang/he.js +0 -188
  193. package/src/lang/index.d.ts +0 -23
  194. package/src/lang/it.d.ts +0 -5
  195. package/src/lang/it.js +0 -188
  196. package/src/lang/ja.d.ts +0 -5
  197. package/src/lang/ja.js +0 -188
  198. package/src/lang/ko.d.ts +0 -5
  199. package/src/lang/ko.js +0 -188
  200. package/src/lang/lv.d.ts +0 -5
  201. package/src/lang/lv.js +0 -188
  202. package/src/lang/nl.d.ts +0 -5
  203. package/src/lang/nl.js +0 -188
  204. package/src/lang/pl.d.ts +0 -5
  205. package/src/lang/pl.js +0 -188
  206. package/src/lang/pt_br.d.ts +0 -5
  207. package/src/lang/pt_br.js +0 -189
  208. package/src/lang/ro.d.ts +0 -5
  209. package/src/lang/ro.js +0 -188
  210. package/src/lang/ru.d.ts +0 -5
  211. package/src/lang/ru.js +0 -188
  212. package/src/lang/se.d.ts +0 -5
  213. package/src/lang/se.js +0 -191
  214. package/src/lang/tr.d.ts +0 -5
  215. package/src/lang/tr.js +0 -191
  216. package/src/lang/ua.d.ts +0 -5
  217. package/src/lang/ua.js +0 -188
  218. package/src/lang/ur.d.ts +0 -5
  219. package/src/lang/ur.js +0 -188
  220. package/src/lang/zh_cn.d.ts +0 -5
  221. package/src/lang/zh_cn.js +0 -187
  222. package/src/lib/constructor.js +0 -954
  223. package/src/lib/context.d.ts +0 -42
  224. package/src/lib/context.js +0 -71
  225. package/src/lib/core.d.ts +0 -1135
  226. package/src/lib/core.js +0 -9395
  227. package/src/lib/history.d.ts +0 -48
  228. package/src/lib/history.js +0 -219
  229. package/src/lib/util.d.ts +0 -678
  230. package/src/lib/util.js +0 -2131
  231. package/src/options.d.ts +0 -608
  232. package/src/plugins/CommandPlugin.d.ts +0 -8
  233. package/src/plugins/DialogPlugin.d.ts +0 -20
  234. package/src/plugins/FileBrowserPlugin.d.ts +0 -30
  235. package/src/plugins/Module.d.ts +0 -15
  236. package/src/plugins/Plugin.d.ts +0 -42
  237. package/src/plugins/SubmenuPlugin.d.ts +0 -8
  238. package/src/plugins/dialog/audio.js +0 -559
  239. package/src/plugins/dialog/image.js +0 -1126
  240. package/src/plugins/dialog/link.js +0 -223
  241. package/src/plugins/dialog/math.js +0 -295
  242. package/src/plugins/dialog/mention.js +0 -242
  243. package/src/plugins/dialog/video.js +0 -979
  244. package/src/plugins/index.d.ts +0 -79
  245. package/src/plugins/modules/_anchor.js +0 -461
  246. package/src/plugins/modules/_colorPicker.d.ts +0 -60
  247. package/src/plugins/modules/_colorPicker.js +0 -201
  248. package/src/plugins/modules/_notice.d.ts +0 -21
  249. package/src/plugins/modules/_notice.js +0 -72
  250. package/src/plugins/modules/_selectMenu.js +0 -119
  251. package/src/plugins/modules/component.d.ts +0 -25
  252. package/src/plugins/modules/component.js +0 -81
  253. package/src/plugins/modules/dialog.d.ts +0 -28
  254. package/src/plugins/modules/dialog.js +0 -175
  255. package/src/plugins/modules/fileBrowser.d.ts +0 -42
  256. package/src/plugins/modules/fileBrowser.js +0 -374
  257. package/src/plugins/modules/fileManager.d.ts +0 -67
  258. package/src/plugins/modules/fileManager.js +0 -326
  259. package/src/plugins/modules/index.js +0 -9
  260. package/src/plugins/modules/resizing.d.ts +0 -154
  261. package/src/plugins/modules/resizing.js +0 -903
  262. package/src/plugins/submenu/align.d.ts +0 -5
  263. package/src/plugins/submenu/align.js +0 -160
  264. package/src/plugins/submenu/font.d.ts +0 -5
  265. package/src/plugins/submenu/font.js +0 -123
  266. package/src/plugins/submenu/fontColor.d.ts +0 -5
  267. package/src/plugins/submenu/fontColor.js +0 -101
  268. package/src/plugins/submenu/fontSize.d.ts +0 -5
  269. package/src/plugins/submenu/fontSize.js +0 -112
  270. package/src/plugins/submenu/formatBlock.d.ts +0 -5
  271. package/src/plugins/submenu/formatBlock.js +0 -273
  272. package/src/plugins/submenu/hiliteColor.d.ts +0 -5
  273. package/src/plugins/submenu/hiliteColor.js +0 -102
  274. package/src/plugins/submenu/horizontalRule.d.ts +0 -5
  275. package/src/plugins/submenu/horizontalRule.js +0 -98
  276. package/src/plugins/submenu/lineHeight.d.ts +0 -5
  277. package/src/plugins/submenu/lineHeight.js +0 -104
  278. package/src/plugins/submenu/list.d.ts +0 -5
  279. package/src/plugins/submenu/list.js +0 -456
  280. package/src/plugins/submenu/paragraphStyle.d.ts +0 -5
  281. package/src/plugins/submenu/paragraphStyle.js +0 -135
  282. package/src/plugins/submenu/table.d.ts +0 -5
  283. package/src/plugins/submenu/table.js +0 -1431
  284. package/src/plugins/submenu/template.d.ts +0 -5
  285. package/src/plugins/submenu/template.js +0 -72
  286. package/src/plugins/submenu/textStyle.d.ts +0 -5
  287. package/src/plugins/submenu/textStyle.js +0 -167
  288. package/src/suneditor.d.ts +0 -9
  289. package/src/suneditor_build.js +0 -18
  290. /package/{src/plugins/dialog → typings}/mention.d.ts +0 -0
@@ -0,0 +1,1062 @@
1
+ import EditorInjector from '../../editorInjector';
2
+ import { Modal, Figure, FileManager, ModalAnchorEditor } from '../../modules';
3
+ import { domUtils, numbers, env } from '../../helper';
4
+ import { CreateTooltipInner } from '../../core/section/constructor';
5
+ const { NO_EVENT } = env;
6
+
7
+ const Image_ = function (editor, pluginOptions) {
8
+ // plugin bisic properties
9
+ EditorInjector.call(this, editor);
10
+ this.title = this.lang.image;
11
+ this.icon = 'image';
12
+
13
+ // define plugin options
14
+ this.pluginOptions = {
15
+ canResize: pluginOptions.canResize === undefined ? true : pluginOptions.canResize,
16
+ showHeightInput: pluginOptions.showHeightInput === undefined ? true : !!pluginOptions.showHeightInput,
17
+ defaultWidth: !pluginOptions.defaultWidth ? 'auto' : numbers.is(pluginOptions.defaultWidth) ? pluginOptions.defaultWidth + 'px' : pluginOptions.defaultWidth,
18
+ defaultHeight: !pluginOptions.defaultHeight ? 'auto' : numbers.is(pluginOptions.defaultHeight) ? pluginOptions.defaultHeight + 'px' : pluginOptions.defaultHeight,
19
+ percentageOnlySize: !!pluginOptions.percentageOnlySize,
20
+ createFileInput: pluginOptions.createFileInput === undefined ? true : pluginOptions.createFileInput,
21
+ createUrlInput: pluginOptions.createUrlInput === undefined || !pluginOptions.createFileInput ? true : pluginOptions.createUrlInput,
22
+ uploadUrl: typeof pluginOptions.uploadUrl === 'string' ? pluginOptions.uploadUrl : null,
23
+ uploadHeaders: pluginOptions.uploadHeaders || null,
24
+ uploadSizeLimit: /\d+/.test(pluginOptions.uploadSizeLimit) ? numbers.get(pluginOptions.uploadSizeLimit, 0) : null,
25
+ uploadSingleSizeLimit: /\d+/.test(pluginOptions.uploadSingleSizeLimit) ? numbers.get(pluginOptions.uploadSingleSizeLimit, 0) : null,
26
+ allowMultiple: !!pluginOptions.allowMultiple,
27
+ acceptedFormats: typeof pluginOptions.acceptedFormats !== 'string' || pluginOptions.acceptedFormats.trim() === '*' ? 'image/*' : pluginOptions.acceptedFormats.trim() || 'image/*'
28
+ // useFormatType: pluginOptions.useFormatType ?? false,
29
+ // defaultFormatType: ['block', 'inline'].includes(pluginOptions.defaultFormatType) ? pluginOptions.defaultFormatType : 'block'
30
+ };
31
+
32
+ // create HTML
33
+ const sizeUnit = this.pluginOptions.percentageOnlySize ? '%' : 'px';
34
+ const modalEl = CreateHTML_modal(editor, this.pluginOptions);
35
+ const figureControls =
36
+ pluginOptions.controls || !this.pluginOptions.canResize
37
+ ? [['mirror_h', 'mirror_v', 'align', 'caption', 'revert', 'edit', 'remove']]
38
+ : [
39
+ ['resize_auto,100,75,50', 'rotate_l', 'rotate_r', 'mirror_h', 'mirror_v'],
40
+ ['edit', 'align', 'caption', 'revert', 'remove']
41
+ ];
42
+
43
+ // show align
44
+ this.alignForm = modalEl.querySelector('.se-figure-align');
45
+ if (!figureControls.some((subArray) => subArray.includes('align'))) this.alignForm.style.display = 'none';
46
+
47
+ // modules
48
+ const Link = this.plugins.link ? this.plugins.link.pluginOptions : {};
49
+ this.anchor = new ModalAnchorEditor(this, modalEl, {
50
+ textToDisplay: false,
51
+ title: true,
52
+ openNewWindow: Link.openNewWindow,
53
+ relList: Link.relList,
54
+ defaultRel: Link.defaultRel,
55
+ noAutoPrefix: Link.noAutoPrefix,
56
+ enableFileUpload: pluginOptions.linkEnableFileUpload
57
+ });
58
+ this.modal = new Modal(this, modalEl);
59
+ this.figure = new Figure(this, figureControls, {
60
+ sizeUnit: sizeUnit
61
+ });
62
+ this.fileManager = new FileManager(this, {
63
+ query: 'img',
64
+ loadHandler: this.events.onImageLoad,
65
+ eventHandler: this.events.onImageAction
66
+ });
67
+
68
+ // members
69
+ this.fileModalWrapper = modalEl.querySelector('.se-flex-input-wrapper');
70
+ this.imgInputFile = modalEl.querySelector('.__se__file_input');
71
+ this.imgUrlFile = modalEl.querySelector('._se_image_url');
72
+ this.focusElement = this.imgInputFile || this.imgUrlFile;
73
+ this.altText = modalEl.querySelector('._se_image_alt');
74
+ this.captionCheckEl = modalEl.querySelector('._se_image_check_caption');
75
+ this.previewSrc = modalEl.querySelector('._se_tab_content_image .se-link-preview');
76
+ this.sizeUnit = sizeUnit;
77
+ this.proportion = {};
78
+ this.inputX = {};
79
+ this.inputY = {};
80
+ this._linkElement = null;
81
+ this._linkValue = '';
82
+ this._align = 'none';
83
+ this._svgDefaultSize = '30%';
84
+ this._base64RenderIndex = 0;
85
+ this._element = null;
86
+ this._cover = null;
87
+ this._container = null;
88
+ this._caption = null;
89
+ this._ratio = {
90
+ w: 1,
91
+ h: 1
92
+ };
93
+ this._origin_w = this.pluginOptions.defaultWidth === 'auto' ? '' : this.pluginOptions.defaultWidth;
94
+ this._origin_h = this.pluginOptions.defaultHeight === 'auto' ? '' : this.pluginOptions.defaultHeight;
95
+ this._resizing = this.pluginOptions.canResize;
96
+ this._onlyPercentage = this.pluginOptions.percentageOnlySize;
97
+ this._nonResizing = !this._resizing || !this.pluginOptions.showHeightInput || this._onlyPercentage;
98
+
99
+ // init
100
+ modalEl.querySelector('.se-modal-tabs').addEventListener('click', this._openTab.bind(this));
101
+ if (this.imgInputFile) modalEl.querySelector('.se-file-remove').addEventListener('click', RemoveSelectedFiles.bind(this));
102
+ if (this.imgUrlFile) this.imgUrlFile.addEventListener('input', OnLinkPreview.bind(this));
103
+ if (this.imgInputFile && this.imgUrlFile) this.imgInputFile.addEventListener('change', OnfileInputChange.bind(this));
104
+
105
+ const imageGalleryButton = modalEl.querySelector('.__se__gallery');
106
+ if (imageGalleryButton) imageGalleryButton.addEventListener('click', OpenGallery.bind(this));
107
+
108
+ if (this._resizing) {
109
+ this.proportion = modalEl.querySelector('._se_image_check_proportion');
110
+ this.inputX = modalEl.querySelector('._se_image_size_x');
111
+ this.inputY = modalEl.querySelector('._se_image_size_y');
112
+ this.inputX.value = this.pluginOptions.defaultWidth;
113
+ this.inputY.value = this.pluginOptions.defaultHeight;
114
+
115
+ const ratioChange = OnChangeRatio.bind(this);
116
+ this.eventManager.addEvent(this.inputX, 'keyup', OnInputSize.bind(this, 'x'));
117
+ this.eventManager.addEvent(this.inputY, 'keyup', OnInputSize.bind(this, 'y'));
118
+ this.eventManager.addEvent(this.inputX, 'change', ratioChange);
119
+ this.eventManager.addEvent(this.inputY, 'change', ratioChange);
120
+ this.eventManager.addEvent(this.proportion, 'change', ratioChange);
121
+ this.eventManager.addEvent(modalEl.querySelector('.se-modal-btn-revert'), 'click', OnClickRevert.bind(this));
122
+ }
123
+
124
+ if (this.pluginOptions.useFormatType) {
125
+ this.as = this.pluginOptions.defaultFormatType;
126
+ this.asBlock = modalEl.querySelector('[data-command="asBlock"]');
127
+ this.asInline = modalEl.querySelector('[data-command="asInline"]');
128
+ this.eventManager.addEvent([this.asBlock, this.asInline], 'click', OnClickAsButton.bind(this));
129
+ }
130
+ };
131
+
132
+ Image_.key = 'image';
133
+ Image_.type = 'modal';
134
+ Image_.component = function (node) {
135
+ node = domUtils.isFigure(node) ? node.firstElementChild : node;
136
+ return /^IMG$/i.test(node?.nodeName) ? node : domUtils.isAnchor(node) && /^IMG$/i.test(node?.firstElementChild?.nodeName) ? node?.firstElementChild : null;
137
+ };
138
+ Image_.className = '';
139
+ Image_.prototype = {
140
+ /**
141
+ * @override type = "modal"
142
+ */
143
+ open() {
144
+ this.modal.open();
145
+ },
146
+
147
+ /**
148
+ * @override Figure
149
+ */
150
+ edit() {
151
+ this.modal.open();
152
+ },
153
+
154
+ /**
155
+ * @override modal
156
+ * @param {boolean} isUpdate open state is update
157
+ */
158
+ on(isUpdate) {
159
+ if (!isUpdate) {
160
+ this.inputX.value = this._origin_w = this.pluginOptions.defaultWidth === 'auto' ? '' : this.pluginOptions.defaultWidth;
161
+ this.inputY.value = this._origin_h = this.pluginOptions.defaultHeight === 'auto' ? '' : this.pluginOptions.defaultHeight;
162
+ if (this.imgInputFile && this.pluginOptions.allowMultiple) this.imgInputFile.setAttribute('multiple', 'multiple');
163
+ } else {
164
+ if (this.imgInputFile && this.pluginOptions.allowMultiple) this.imgInputFile.removeAttribute('multiple');
165
+ }
166
+
167
+ this.anchor.on(isUpdate);
168
+ },
169
+
170
+ /**
171
+ * @description On paste or drop
172
+ * @param {*} params { frameContext, event, file }
173
+ */
174
+ onPastAndDrop({ file }) {
175
+ if (!/^image/.test(file.type)) return;
176
+
177
+ this._submitFile([file]);
178
+ this.editor.focus();
179
+
180
+ return false;
181
+ },
182
+
183
+ /**
184
+ * @override modal
185
+ * @returns {boolean | undefined}
186
+ */
187
+ async modalAction() {
188
+ this._align = this.modal.form.querySelector('input[name="suneditor_image_radio"]:checked').value;
189
+
190
+ if (this.modal.isUpdate) {
191
+ this._update(this.inputX.value, this.inputY.value);
192
+ this.history.push(false);
193
+ }
194
+
195
+ if (this.imgInputFile && this.imgInputFile.files.length > 0) {
196
+ return await this._submitFile(this.imgInputFile.files);
197
+ } else if (this.imgUrlFile && this._linkValue.length > 0) {
198
+ return await this._submitURL(this._linkValue);
199
+ }
200
+
201
+ return false;
202
+ },
203
+
204
+ /**
205
+ * @override core
206
+ */
207
+ retainFormat() {
208
+ return {
209
+ query: 'img',
210
+ method: (element) => {
211
+ const figureInfo = Figure.GetContainer(element);
212
+ if (figureInfo && figureInfo.container && figureInfo.cover) return;
213
+
214
+ this.ready(element);
215
+ this._fileCheck(this._origin_w, this._origin_h);
216
+ }
217
+ };
218
+ },
219
+
220
+ /**
221
+ * @override modal
222
+ */
223
+ init() {
224
+ Modal.OnChangeFile(this.fileModalWrapper, []);
225
+ if (this.imgInputFile) this.imgInputFile.value = '';
226
+ if (this.imgUrlFile) this._linkValue = this.previewSrc.textContent = this.imgUrlFile.value = '';
227
+ if (this.imgInputFile && this.imgUrlFile) {
228
+ this.imgUrlFile.removeAttribute('disabled');
229
+ this.previewSrc.style.textDecoration = '';
230
+ }
231
+
232
+ this.altText.value = '';
233
+ this.modal.form.querySelector('input[name="suneditor_image_radio"][value="none"]').checked = true;
234
+ this.captionCheckEl.checked = false;
235
+ this._element = null;
236
+ this._ratio = {
237
+ w: 1,
238
+ h: 1
239
+ };
240
+ this._openTab('init');
241
+
242
+ if (this._resizing) {
243
+ this.inputX.value = this.pluginOptions.defaultWidth === 'auto' ? '' : this.pluginOptions.defaultWidth;
244
+ this.inputY.value = this.pluginOptions.defaultHeight === 'auto' ? '' : this.pluginOptions.defaultHeight;
245
+ this.proportion.checked = true;
246
+ }
247
+
248
+ if (this.pluginOptions.useFormatType) {
249
+ this._activeAsInline(this.pluginOptions.defaultFormatType === 'inline');
250
+ }
251
+
252
+ this.anchor.init();
253
+ },
254
+
255
+ /**
256
+ * @override component, fileManager
257
+ * @description Called when a container is selected.
258
+ * @param {Element} element Target element
259
+ */
260
+ select(element) {
261
+ this.ready(element);
262
+ },
263
+
264
+ /**
265
+ * @override fileManager, figure
266
+ */
267
+ ready(target) {
268
+ if (!target) return;
269
+ const figureInfo = this.figure.open(target, { nonResizing: this._nonResizing, nonSizeInfo: false, nonBorder: false, figureTarget: false, __fileManagerInfo: false });
270
+ this.anchor.set(domUtils.isAnchor(target.parentNode) ? target.parentNode : null);
271
+
272
+ this._linkElement = this.anchor.currentTarget;
273
+ this._element = target;
274
+ this._cover = figureInfo.cover;
275
+ this._container = figureInfo.container;
276
+ this._caption = figureInfo.caption;
277
+ this._align = figureInfo.align;
278
+ target.style.float = '';
279
+
280
+ this._origin_w = figureInfo.originWidth || figureInfo.w || '';
281
+ this._origin_h = figureInfo.originHeight || figureInfo.h || '';
282
+ this.altText.value = this._element.alt;
283
+
284
+ if (this.imgUrlFile) this._linkValue = this.previewSrc.textContent = this.imgUrlFile.value = this._element.src;
285
+
286
+ (this.modal.form.querySelector('input[name="suneditor_image_radio"][value="' + this._align + '"]') || this.modal.form.querySelector('input[name="suneditor_image_radio"][value="none"]')).checked = true;
287
+ this.captionCheckEl.checked = !!this._caption;
288
+
289
+ if (!this._resizing) return;
290
+
291
+ const percentageRotation = this._onlyPercentage && this.figure.isVertical;
292
+ let w = percentageRotation ? '' : figureInfo.width;
293
+ if (this._onlyPercentage) {
294
+ w = numbers.get(w, 2);
295
+ if (w > 100) w = 100;
296
+ }
297
+ this.inputX.value = w === 'auto' ? '' : w;
298
+
299
+ if (!this._onlyPercentage) {
300
+ const h = percentageRotation ? '' : figureInfo.height;
301
+ this.inputY.value = h === 'auto' ? '' : h;
302
+ }
303
+
304
+ this.proportion.checked = true;
305
+ this.inputX.disabled = percentageRotation ? true : false;
306
+ this.inputY.disabled = percentageRotation ? true : false;
307
+ this.proportion.disabled = percentageRotation ? true : false;
308
+
309
+ this._ratio = this.proportion.checked
310
+ ? figureInfo.ratio
311
+ : {
312
+ w: 1,
313
+ h: 1
314
+ };
315
+
316
+ if (this.pluginOptions.useFormatType) {
317
+ this._activeAsInline(this.component.isInline(figureInfo.container));
318
+ }
319
+ },
320
+
321
+ /**
322
+ * @override fileManager
323
+ */
324
+ async destroy(element) {
325
+ const targetEl = element || this._element;
326
+ const container = domUtils.getParentElement(targetEl, Figure.__is) || targetEl;
327
+ const focusEl = container.previousElementSibling || container.nextElementSibling;
328
+ const emptyDiv = container.parentNode;
329
+
330
+ const message = await this.triggerEvent('onImageDeleteBefore', { target: targetEl, container, align: this._align, alt: this.altText.value, url: this._linkValue });
331
+ if (message === false) return;
332
+
333
+ domUtils.removeItem(container);
334
+ this.init();
335
+
336
+ if (emptyDiv !== this.editor.frameContext.get('wysiwyg')) {
337
+ this.nodeTransform.removeAllParents(
338
+ emptyDiv,
339
+ function (current) {
340
+ return current.childNodes.length === 0;
341
+ },
342
+ null
343
+ );
344
+ }
345
+
346
+ // focus
347
+ this.editor.focusEdge(focusEl);
348
+ this.history.push(false);
349
+ },
350
+
351
+ _getInfo() {
352
+ return {
353
+ element: this._element,
354
+ anchor: this.anchor.create(true),
355
+ inputWidth: this.inputX.value,
356
+ inputHeight: this.inputY.value,
357
+ align: this._align,
358
+ isUpdate: this.modal.isUpdate,
359
+ alt: this.altText.value
360
+ };
361
+ },
362
+
363
+ _activeAsInline(isInline) {
364
+ const ctrlAlignBtn = this.figure.controller.form.querySelector('[data-command="onalign"]');
365
+
366
+ if (isInline) {
367
+ domUtils.addClass(this.asInline, 'on');
368
+ domUtils.removeClass(this.asBlock, 'on');
369
+ this.as = 'inline';
370
+ // buttns
371
+ if (this.alignForm) this.alignForm.style.display = 'none';
372
+ if (ctrlAlignBtn) ctrlAlignBtn.style.display = 'none';
373
+ } else {
374
+ domUtils.addClass(this.asBlock, 'on');
375
+ domUtils.removeClass(this.asInline, 'on');
376
+ this.as = 'block';
377
+ // buttns
378
+ if (this.alignForm) this.alignForm.style.display = '';
379
+ if (ctrlAlignBtn) ctrlAlignBtn.style.display = '';
380
+ }
381
+ },
382
+
383
+ async _submitFile(fileList) {
384
+ if (fileList.length === 0) return false;
385
+
386
+ let fileSize = 0;
387
+ const files = [];
388
+ const slngleSizeLimit = this.uploadSingleSizeLimit;
389
+ for (let i = 0, len = fileList.length, f, s; i < len; i++) {
390
+ f = fileList[i];
391
+ if (!/image/i.test(f.type)) continue;
392
+
393
+ s = f.size;
394
+ if (slngleSizeLimit && slngleSizeLimit > s) {
395
+ const err = '[SUNEDITOR.imageUpload.fail] Size of uploadable single file: ' + slngleSizeLimit / 1000 + 'KB';
396
+ const message = await this.triggerEvent('onImageUploadError', {
397
+ error: err,
398
+ limitSize: slngleSizeLimit,
399
+ uploadSize: s,
400
+ file: f
401
+ });
402
+
403
+ this.notice.open(message === NO_EVENT ? err : message || err);
404
+
405
+ return false;
406
+ }
407
+
408
+ files.push(f);
409
+ fileSize += s;
410
+ }
411
+
412
+ const limitSize = this.pluginOptions.uploadSizeLimit;
413
+ const currentSize = this.fileManager.getSize();
414
+ if (limitSize > 0 && fileSize + currentSize > limitSize) {
415
+ const err = '[SUNEDITOR.imageUpload.fail] Size of uploadable total images: ' + limitSize / 1000 + 'KB';
416
+ const message = await this.triggerEvent('onImageUploadError', {
417
+ error: err,
418
+ limitSize,
419
+ currentSize,
420
+ uploadSize: fileSize
421
+ });
422
+
423
+ this.notice.open(message === NO_EVENT ? err : message || err);
424
+
425
+ return false;
426
+ }
427
+
428
+ const imgInfo = { files, ...this._getInfo() };
429
+ const handler = function (infos, newInfos) {
430
+ infos = newInfos || infos;
431
+ this._serverUpload(infos, infos.files);
432
+ }.bind(this, imgInfo);
433
+
434
+ const result = await this.triggerEvent('onImageUploadBefore', {
435
+ ...imgInfo,
436
+ handler
437
+ });
438
+
439
+ if (result === undefined) return true;
440
+ if (result === false) return false;
441
+ if (result !== null && typeof result === 'object') handler(result);
442
+
443
+ if (result === true || result === NO_EVENT) handler(null);
444
+ },
445
+
446
+ async _submitURL(url) {
447
+ if (!url) url = this._linkValue;
448
+ if (!url) return false;
449
+
450
+ const file = { name: url.split('/').pop(), size: 0 };
451
+ const imgInfo = {
452
+ url,
453
+ files: file,
454
+ ...this._getInfo()
455
+ };
456
+
457
+ const handler = function (infos, newInfos) {
458
+ infos = newInfos || infos;
459
+ const infoUrl = infos.url;
460
+ if (this.modal.isUpdate) this._updateSrc(infoUrl, infos.element, infos.files);
461
+ else this.create(infoUrl, infos.anchor, infos.inputWidth, infos.inputHeight, infos.align, infos.files, infos.alt);
462
+ }.bind(this, imgInfo);
463
+
464
+ const result = await this.triggerEvent('onImageUploadBefore', {
465
+ ...imgInfo,
466
+ handler
467
+ });
468
+
469
+ if (result === undefined) return true;
470
+ if (result === false) return false;
471
+ if (result !== null && typeof result === 'object') handler(result);
472
+
473
+ if (result === true || result === NO_EVENT) handler(null);
474
+
475
+ return true;
476
+ },
477
+
478
+ _update(width, height) {
479
+ if (!width) width = this.inputX.value || 'auto';
480
+ if (!height) height = this.inputY.value || 'auto';
481
+
482
+ let imageEl = this._element;
483
+ const cover = this._cover;
484
+ const container = this._container === this._cover ? null : this._container;
485
+
486
+ // check size
487
+ let changeSize;
488
+ const x = numbers.is(width) ? width + this.sizeUnit : width;
489
+ const y = numbers.is(height) ? height + this.sizeUnit : height;
490
+ if (/%$/.test(imageEl.style.width)) {
491
+ changeSize = x !== container.style.width || y !== container.style.height;
492
+ } else {
493
+ changeSize = x !== imageEl.style.width || y !== imageEl.style.height;
494
+ }
495
+
496
+ // alt
497
+ imageEl.alt = this.altText.value;
498
+
499
+ // caption
500
+ let modifiedCaption = false;
501
+ if (this.captionCheckEl.checked) {
502
+ if (!this._caption) {
503
+ this._caption = Figure.CreateCaption(cover, this.lang.caption);
504
+ modifiedCaption = true;
505
+ }
506
+ } else {
507
+ if (this._caption) {
508
+ domUtils.removeItem(this._caption);
509
+ this._caption = null;
510
+ modifiedCaption = true;
511
+ }
512
+ }
513
+
514
+ // link
515
+ let isNewAnchor = false;
516
+ const anchor = this.anchor.create(true);
517
+ if (anchor) {
518
+ if (this._linkElement !== anchor || !container.contains(anchor)) {
519
+ this._linkElement = anchor.cloneNode(false);
520
+ cover.insertBefore(this._setAnchor(imageEl, this._linkElement), this._caption);
521
+ isNewAnchor = true;
522
+ }
523
+ } else if (this._linkElement !== null) {
524
+ if (cover.contains(this._linkElement)) {
525
+ const newEl = imageEl.cloneNode(true);
526
+ cover.removeChild(this._linkElement);
527
+ cover.insertBefore(newEl, this._caption);
528
+ imageEl = newEl;
529
+ }
530
+ }
531
+
532
+ // size
533
+ if (this._resizing && changeSize) {
534
+ this.applySize(width, height);
535
+ }
536
+
537
+ if (isNewAnchor) {
538
+ domUtils.removeItem(anchor);
539
+ }
540
+
541
+ // transform
542
+ if (modifiedCaption || (!this._onlyPercentage && changeSize)) {
543
+ if (/\d+/.test(imageEl.style.height) || (this.figure.isVertical && this.captionCheckEl.checked)) {
544
+ if (/auto|%$/.test(width) || /auto|%$/.test(height)) {
545
+ this.figure.deleteTransform(imageEl);
546
+ } else {
547
+ this.figure.setTransform(imageEl, width, height, 0);
548
+ }
549
+ }
550
+ }
551
+
552
+ // align
553
+ this.figure.setAlign(imageEl, this._align);
554
+
555
+ // select
556
+ imageEl.onload = () => {
557
+ this.select(imageEl);
558
+ };
559
+ },
560
+
561
+ _fileCheck(width, height) {
562
+ if (!width) width = this.inputX.value || 'auto';
563
+ if (!height) height = this.inputY.value || 'auto';
564
+
565
+ let imageEl = this._element;
566
+ let cover = this._cover;
567
+ let container = this._container === this._cover ? null : this._container;
568
+ let isNewContainer = false;
569
+
570
+ if (!cover || !container) {
571
+ isNewContainer = true;
572
+ imageEl = this._element.cloneNode(true);
573
+ const figureInfo = Figure.CreateContainer(imageEl, 'se-image-container');
574
+ cover = figureInfo.cover;
575
+ container = figureInfo.container;
576
+ this.figure.open(imageEl, { nonResizing: true, nonSizeInfo: false, nonBorder: false, figureTarget: false, __fileManagerInfo: true });
577
+ }
578
+
579
+ // check size
580
+ let changeSize;
581
+ const x = numbers.is(width) ? width + this.sizeUnit : width;
582
+ const y = numbers.is(height) ? height + this.sizeUnit : height;
583
+ if (/%$/.test(imageEl.style.width)) {
584
+ changeSize = x !== container.style.width || y !== container.style.height;
585
+ } else {
586
+ changeSize = x !== imageEl.style.width || y !== imageEl.style.height;
587
+ }
588
+
589
+ // alt
590
+ imageEl.alt = this.altText.value;
591
+
592
+ // caption
593
+ let modifiedCaption = false;
594
+ if (this.captionCheckEl.checked) {
595
+ if (!this._caption || isNewContainer) {
596
+ this._caption = Figure.CreateCaption(cover, this.lang.caption);
597
+ modifiedCaption = true;
598
+ }
599
+ } else {
600
+ if (this._caption) {
601
+ domUtils.removeItem(this._caption);
602
+ this._caption = null;
603
+ modifiedCaption = true;
604
+ }
605
+ }
606
+
607
+ // link
608
+ let isNewAnchor = null;
609
+ const anchor = this.anchor.create(true);
610
+ if (anchor) {
611
+ if (this._linkElement !== anchor || (isNewContainer && !container.contains(anchor))) {
612
+ this._linkElement = anchor.cloneNode(false);
613
+ cover.insertBefore(this._setAnchor(imageEl, this._linkElement), this._caption);
614
+ isNewAnchor = this._element;
615
+ }
616
+ } else if (this._linkElement !== null) {
617
+ if (cover.contains(this._linkElement)) {
618
+ const newEl = imageEl.cloneNode(true);
619
+ cover.removeChild(this._linkElement);
620
+ cover.insertBefore(newEl, this._caption);
621
+ imageEl = newEl;
622
+ }
623
+ }
624
+
625
+ if (isNewContainer) {
626
+ imageEl = this._element;
627
+ this.figure._retainFigureFormat(container, this._element, isNewAnchor ? anchor : null);
628
+ this._element = imageEl = container.querySelector('img');
629
+ this._cover = cover;
630
+ this._container = container;
631
+ }
632
+
633
+ // size
634
+ if (this._resizing && changeSize) {
635
+ this.applySize(width, height);
636
+ }
637
+
638
+ if (isNewAnchor) {
639
+ if (!isNewContainer) {
640
+ domUtils.removeItem(anchor);
641
+ } else {
642
+ domUtils.removeItem(isNewAnchor);
643
+ if (domUtils.getListChildren(anchor, (current) => /IMG/i.test(current.tagName)).length === 0) {
644
+ domUtils.removeItem(anchor);
645
+ }
646
+ }
647
+ }
648
+
649
+ // transform
650
+ if (modifiedCaption || (!this._onlyPercentage && changeSize)) {
651
+ if (/\d+/.test(imageEl.style.height) || (this.figure.isVertical && this.captionCheckEl.checked)) {
652
+ if (/auto|%$/.test(width) || /auto|%$/.test(height)) {
653
+ this.figure.deleteTransform(imageEl);
654
+ } else {
655
+ this.figure.setTransform(imageEl, width, height, 0);
656
+ }
657
+ }
658
+ }
659
+
660
+ // align
661
+ this.figure.setAlign(imageEl, this._align);
662
+ },
663
+
664
+ _openTab(e) {
665
+ const modalForm = this.modal.form;
666
+ const targetElement = e === 'init' ? modalForm.querySelector('._se_tab_link') : e.target;
667
+
668
+ if (!/^BUTTON$/i.test(targetElement.tagName)) {
669
+ return false;
670
+ }
671
+
672
+ // Declare all variables
673
+ const tabName = targetElement.getAttribute('data-tab-link');
674
+ let i;
675
+
676
+ // Get all elements with class="tabcontent" and hide them
677
+ const tabContent = modalForm.getElementsByClassName('_se_tab_content');
678
+ for (i = 0; i < tabContent.length; i++) {
679
+ tabContent[i].style.display = 'none';
680
+ }
681
+
682
+ // Get all elements with class="tablinks" and remove the class "active"
683
+ const tabLinks = modalForm.getElementsByClassName('_se_tab_link');
684
+ for (i = 0; i < tabLinks.length; i++) {
685
+ domUtils.removeClass(tabLinks[i], 'active');
686
+ }
687
+
688
+ // Show the current tab, and add an "active" class to the button that opened the tab
689
+ modalForm.querySelector('._se_tab_content_' + tabName).style.display = 'block';
690
+ domUtils.addClass(targetElement, 'active');
691
+
692
+ // focus
693
+ if (e !== 'init') {
694
+ if (tabName === 'image') {
695
+ this.focusElement.focus();
696
+ } else if (tabName === 'url') {
697
+ this.anchor.urlInput.focus();
698
+ }
699
+ }
700
+
701
+ return false;
702
+ },
703
+
704
+ applySize(w, h) {
705
+ if (!w) w = this.inputX.value || this.pluginOptions.defaultWidth;
706
+ if (!h) h = this.inputY.value || this.pluginOptions.defaultHeight;
707
+ if (this._onlyPercentage) {
708
+ if (!w) w = '100%';
709
+ else if (/%$/.test(w)) w += '%';
710
+ }
711
+ this.figure.setSize(w, h, null);
712
+ },
713
+
714
+ create(src, anchor, width, height, align, file, alt) {
715
+ const oImg = domUtils.createElement('IMG');
716
+ oImg.src = src;
717
+ oImg.alt = alt;
718
+ anchor = this._setAnchor(oImg, anchor ? anchor.cloneNode(false) : null);
719
+
720
+ const figureInfo = Figure.CreateContainer(anchor, 'se-image-container');
721
+ const cover = figureInfo.cover;
722
+ const container = figureInfo.container;
723
+
724
+ // caption
725
+ if (this.captionCheckEl.checked) {
726
+ this._caption = Figure.CreateCaption(cover, this.lang.caption);
727
+ }
728
+
729
+ this._element = oImg;
730
+ this._cover = cover;
731
+ this._container = container;
732
+ this.figure.open(oImg, { nonResizing: this._nonResizing, nonSizeInfo: false, nonBorder: false, figureTarget: false, __fileManagerInfo: true });
733
+
734
+ // set size
735
+ this.applySize(width, height);
736
+
737
+ // align
738
+ this.figure.setAlign(oImg, align);
739
+
740
+ this.fileManager.setFileData(oImg, file);
741
+
742
+ oImg.onload = OnloadImg.bind(this, oImg, this._svgDefaultSize, container);
743
+ this.component.insert(container, false, true);
744
+ },
745
+
746
+ _updateSrc(src, element, file) {
747
+ element.src = src;
748
+ this.fileManager.setFileData(element, file);
749
+ this.component.select(element, Image_.key, false);
750
+ },
751
+
752
+ _register(info, response) {
753
+ const fileList = response.result;
754
+
755
+ for (let i = 0, len = fileList.length, file; i < len; i++) {
756
+ file = {
757
+ name: fileList[i].name,
758
+ size: fileList[i].size
759
+ };
760
+ if (info.isUpdate) {
761
+ this._updateSrc(fileList[i].url, info.element, file);
762
+ break;
763
+ } else {
764
+ this.create(fileList[i].url, info.anchor, info.inputWidth, info.inputHeight, info.align, file, info.alt);
765
+ }
766
+ }
767
+ },
768
+
769
+ _serverUpload(info, files) {
770
+ if (!files) return;
771
+
772
+ // server upload
773
+ const imageUploadUrl = this.pluginOptions.uploadUrl;
774
+ if (typeof imageUploadUrl === 'string' && imageUploadUrl.length > 0) {
775
+ this.fileManager.upload(imageUploadUrl, this.pluginOptions.uploadHeaders, files, UploadCallBack.bind(this, info), this._error.bind(this));
776
+ } else {
777
+ this._setBase64(files, info.anchor, info.inputWidth, info.inputHeight, info.align, info.alt, info.isUpdate);
778
+ }
779
+ },
780
+
781
+ _setBase64(files, anchor, width, height, align, alt, isUpdate) {
782
+ try {
783
+ const filesLen = this.modal.isUpdate ? 1 : files.length;
784
+
785
+ if (filesLen === 0) {
786
+ this.editor.hideLoading();
787
+ console.warn('[SUNEDITOR.image.base64.fail] cause : No applicable files');
788
+ return;
789
+ }
790
+
791
+ this._base64RenderIndex = filesLen;
792
+ const filesStack = [filesLen];
793
+ this.inputX.value = width;
794
+ this.inputY.value = height;
795
+
796
+ for (let i = 0, reader, file; i < filesLen; i++) {
797
+ reader = new FileReader();
798
+ file = files[i];
799
+
800
+ reader.onload = function (on_reader, update, updateElement, on_file, index) {
801
+ filesStack[index] = {
802
+ result: on_reader.result,
803
+ file: on_file
804
+ };
805
+
806
+ if (--this._base64RenderIndex === 0) {
807
+ this._onRenderBase64(update, filesStack, updateElement, anchor, width, height, align, alt);
808
+ this.editor.hideLoading();
809
+ }
810
+ }.bind(this, reader, isUpdate, this._element, file, i);
811
+
812
+ reader.readAsDataURL(file);
813
+ }
814
+ } catch (error) {
815
+ this.editor.hideLoading();
816
+ throw Error(`[SUNEDITOR.plugins.image._setBase64.fail] ${error.message}`);
817
+ }
818
+ },
819
+
820
+ _onRenderBase64(update, filesStack, updateElement, anchor, width, height, align, alt) {
821
+ for (let i = 0, len = filesStack.length; i < len; i++) {
822
+ if (update) {
823
+ this._updateSrc(filesStack[i].result, updateElement, filesStack[i].file);
824
+ } else {
825
+ this.create(filesStack[i].result, anchor, width, height, align, filesStack[i].file, alt);
826
+ }
827
+ }
828
+ },
829
+
830
+ _setAnchor(imgTag, anchor) {
831
+ if (anchor) {
832
+ anchor.appendChild(imgTag);
833
+ return anchor;
834
+ }
835
+
836
+ return imgTag;
837
+ },
838
+
839
+ async _error(response) {
840
+ const message = await this.triggerEvent('onImageUploadError', { error: response });
841
+ const err = message === NO_EVENT ? response.errorMessage : message || response.errorMessage;
842
+ this.notice.open(err);
843
+ console.error('[SUNEDITOR.plugin.image.error]', err);
844
+ },
845
+
846
+ constructor: Image_
847
+ };
848
+
849
+ async function UploadCallBack(info, xmlHttp) {
850
+ if ((await this.triggerEvent('imageUploadHandler', { xmlHttp, info })) === NO_EVENT) {
851
+ const response = JSON.parse(xmlHttp.responseText);
852
+ if (response.errorMessage) {
853
+ this._error(response);
854
+ } else {
855
+ this._register(info, response);
856
+ }
857
+ }
858
+ }
859
+
860
+ function RemoveSelectedFiles() {
861
+ this.imgInputFile.value = '';
862
+ if (this.imgUrlFile) {
863
+ this.imgUrlFile.removeAttribute('disabled');
864
+ this.previewSrc.style.textDecoration = '';
865
+ }
866
+
867
+ // inputFile check
868
+ Modal.OnChangeFile(this.fileModalWrapper, []);
869
+ }
870
+
871
+ function OnInputSize(xy, e) {
872
+ if (e.keyCode === 32) {
873
+ e.preventDefault();
874
+ return;
875
+ }
876
+
877
+ if (xy === 'x' && this._onlyPercentage && e.target.value > 100) {
878
+ e.target.value = 100;
879
+ } else if (this.proportion.checked) {
880
+ const ratioSize = Figure.CalcRatio(this.inputX.value, this.inputY.value, this.sizeUnit, this._ratio);
881
+ if (xy === 'x') {
882
+ this.inputY.value = ratioSize.h;
883
+ } else {
884
+ this.inputX.value = ratioSize.w;
885
+ }
886
+ }
887
+ }
888
+
889
+ function OnChangeRatio() {
890
+ this._ratio = this.proportion.checked
891
+ ? Figure.GetRatio(this.inputX.value, this.inputY.value, this.sizeUnit)
892
+ : {
893
+ w: 1,
894
+ h: 1
895
+ };
896
+ }
897
+
898
+ function OnClickRevert() {
899
+ if (this._onlyPercentage) {
900
+ this.inputX.value = this._origin_w > 100 ? 100 : this._origin_w;
901
+ } else {
902
+ this.inputX.value = this._origin_w;
903
+ this.inputY.value = this._origin_h;
904
+ }
905
+ }
906
+
907
+ function OnClickAsButton({ target }) {
908
+ this._activeAsInline(target.getAttribute('data-command') === 'asInline');
909
+ }
910
+
911
+ function OnLinkPreview(e) {
912
+ const value = e.target.value.trim();
913
+ this._linkValue = this.previewSrc.textContent = !value
914
+ ? ''
915
+ : this.options.get('defaultUrlProtocol') && !value.includes('://') && value.indexOf('#') !== 0
916
+ ? this.options.get('defaultUrlProtocol') + value
917
+ : !value.includes('://')
918
+ ? '/' + value
919
+ : value;
920
+ }
921
+
922
+ function OnfileInputChange({ target }) {
923
+ if (!this.imgInputFile.value) {
924
+ this.imgUrlFile.removeAttribute('disabled');
925
+ this.previewSrc.style.textDecoration = '';
926
+ } else {
927
+ this.imgUrlFile.setAttribute('disabled', true);
928
+ this.previewSrc.style.textDecoration = 'line-through';
929
+ }
930
+
931
+ // inputFile check
932
+ Modal.OnChangeFile(this.fileModalWrapper, target.files);
933
+ }
934
+
935
+ function OpenGallery() {
936
+ this.plugins.imageGallery.open(_setUrlInput.bind(this));
937
+ }
938
+
939
+ function _setUrlInput(target) {
940
+ this.altText.value = target.getAttribute('data-value') || target.alt;
941
+ this._linkValue = this.previewSrc.textContent = this.imgUrlFile.value = target.getAttribute('data-command') || target.src;
942
+ this.imgUrlFile.focus();
943
+ }
944
+
945
+ function OnloadImg(oImg, _svgDefaultSize, container) {
946
+ // svg exception handling
947
+ if (oImg.offsetWidth === 0) this.applySize(_svgDefaultSize, '');
948
+ if (this.options.get('mediaAutoSelect')) {
949
+ this.component.select(oImg, Image_.key, false);
950
+ } else {
951
+ const line = this.format.addLine(container, null);
952
+ if (line) this.setRange(line, 0, line, 0);
953
+ }
954
+
955
+ delete oImg.onload;
956
+ }
957
+
958
+ function CreateHTML_modal({ lang, icons, plugins }, pluginOptions) {
959
+ const createFileInputHtml = !pluginOptions.createFileInput
960
+ ? ''
961
+ : /*html*/ `
962
+ <div class="se-modal-form">
963
+ <label>${lang.image_modal_file}</label>
964
+ ${Modal.CreateFileInput({ icons, lang }, pluginOptions)}
965
+ </div>`;
966
+
967
+ const createUrlInputHtml = !pluginOptions.createUrlInput
968
+ ? ''
969
+ : /*html*/ `
970
+ <div class="se-modal-form">
971
+ <label>${lang.image_modal_url}</label>
972
+ <div class="se-modal-form-files">
973
+ <input class="se-input-form se-input-url _se_image_url" data-focus type="text" />
974
+ ${
975
+ plugins.imageGallery
976
+ ? `<button type="button" class="se-btn se-tooltip se-modal-files-edge-button __se__gallery" aria-label="${lang.imageGallery}">
977
+ ${icons.image_gallery}
978
+ ${CreateTooltipInner(lang.imageGallery)}
979
+ </button>`
980
+ : ''
981
+ }
982
+ </div>
983
+ <pre class="se-link-preview"></pre>
984
+ </div>`;
985
+
986
+ const canResizeHtml = !pluginOptions.canResize
987
+ ? ''
988
+ : /*html*/ `
989
+ <div class="se-modal-form">
990
+ <div class="se-modal-size-text">
991
+ <label class="size-w">${lang.width}</label>
992
+ <label class="se-modal-size-x">&nbsp;</label>
993
+ <label class="size-h">${lang.height}</label>
994
+ </div>
995
+ <input class="se-input-control _se_image_size_x" placeholder="auto" type="text" />
996
+ <label class="se-modal-size-x">x</label>
997
+ <input type="text" class="se-input-control _se_image_size_y" placeholder="auto" />
998
+ <label><input type="checkbox" class="se-modal-btn-check _se_image_check_proportion" checked/>&nbsp;${lang.proportion}</label>
999
+ <button type="button" aria-label="${lang.revert}" class="se-btn se-tooltip se-modal-btn-revert">
1000
+ ${icons.revert}
1001
+ ${CreateTooltipInner(lang.revert)}
1002
+ </button>
1003
+ </div>`;
1004
+
1005
+ const useFormatTypeHtml = !pluginOptions.useFormatType
1006
+ ? ''
1007
+ : /*html*/ `
1008
+ <div class="se-modal-form">
1009
+ <div class="se-modal-flex-form">
1010
+ <button type="button" data-command="asBlock" class="se-btn se-tooltip" aria-label="${lang.inlineStyle}">
1011
+ ${icons.component_outline}
1012
+ ${CreateTooltipInner(lang.blockStyle)}
1013
+ </button>
1014
+ <button type="button" data-command="asInline" class="se-btn se-tooltip" aria-label="${lang.inlineStyle}">
1015
+ ${icons.component_inline}
1016
+ ${CreateTooltipInner(lang.inlineStyle)}
1017
+ </button>
1018
+ </div>
1019
+ </div>`;
1020
+
1021
+ const html = /*html*/ `
1022
+ <div class="se-modal-header">
1023
+ <button type="button" data-command="close" class="se-btn se-close-btn close" title="${lang.close}" aria-label="${lang.close}">${icons.cancel}</button>
1024
+ <span class="se-modal-title">${lang.image_modal_title}</span>
1025
+ </div>
1026
+ <div class="se-modal-tabs">
1027
+ <button type="button" class="_se_tab_link active" data-tab-link="image">${lang.image}</button>
1028
+ <button type="button" class="_se_tab_link" data-tab-link="url">${lang.link}</button>
1029
+ </div>
1030
+ <form method="post" enctype="multipart/form-data">
1031
+ <div class="_se_tab_content _se_tab_content_image">
1032
+ <div class="se-modal-body">
1033
+ ${createFileInputHtml}
1034
+ ${createUrlInputHtml}
1035
+ <div style="border-bottom: 1px dashed #ccc;"></div>
1036
+ <div class="se-modal-form">
1037
+ <label>${lang.image_modal_altText}</label><input class="se-input-form _se_image_alt" type="text" />
1038
+ </div>
1039
+ ${canResizeHtml}
1040
+ ${useFormatTypeHtml}
1041
+ <div class="se-modal-form se-modal-form-footer">
1042
+ <label><input type="checkbox" class="se-modal-btn-check _se_image_check_caption" />&nbsp;${lang.caption}</label>
1043
+ </div>
1044
+ </div>
1045
+ </div>
1046
+ <div class="se-anchor-editor _se_tab_content _se_tab_content_url" style="display: none;">
1047
+ </div>
1048
+ <div class="se-modal-footer">
1049
+ <div class="se-figure-align">
1050
+ <label><input type="radio" name="suneditor_image_radio" class="se-modal-btn-radio" value="none" checked>${lang.basic}</label>
1051
+ <label><input type="radio" name="suneditor_image_radio" class="se-modal-btn-radio" value="left">${lang.left}</label>
1052
+ <label><input type="radio" name="suneditor_image_radio" class="se-modal-btn-radio" value="center">${lang.center}</label>
1053
+ <label><input type="radio" name="suneditor_image_radio" class="se-modal-btn-radio" value="right">${lang.right}</label>
1054
+ </div>
1055
+ <button type="submit" class="se-btn-primary" title="${lang.submitButton}" aria-label="${lang.submitButton}"><span>${lang.submitButton}</span></button>
1056
+ </div>
1057
+ </form>`;
1058
+
1059
+ return domUtils.createElement('DIV', { class: 'se-modal-content' }, html);
1060
+ }
1061
+
1062
+ export default Image_;