suneditor 2.44.2 → 2.44.4

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 (131) hide show
  1. package/LICENSE.txt +20 -20
  2. package/README.md +1585 -1585
  3. package/dist/css/suneditor.min.css +1 -1
  4. package/dist/suneditor.min.js +2 -2
  5. package/package.json +71 -71
  6. package/src/assets/css/suneditor-contents.css +556 -556
  7. package/src/assets/css/suneditor.css +0 -0
  8. package/src/assets/defaultIcons.js +103 -103
  9. package/src/lang/Lang.d.ts +143 -143
  10. package/src/lang/ckb.d.ts +4 -4
  11. package/src/lang/ckb.js +187 -187
  12. package/src/lang/da.d.ts +4 -4
  13. package/src/lang/da.js +191 -191
  14. package/src/lang/de.d.ts +4 -4
  15. package/src/lang/de.js +187 -187
  16. package/src/lang/en.d.ts +4 -4
  17. package/src/lang/en.js +187 -187
  18. package/src/lang/es.d.ts +4 -4
  19. package/src/lang/es.js +187 -187
  20. package/src/lang/fr.d.ts +4 -4
  21. package/src/lang/fr.js +188 -188
  22. package/src/lang/he.d.ts +4 -4
  23. package/src/lang/he.js +188 -188
  24. package/src/lang/index.d.ts +22 -21
  25. package/src/lang/index.js +25 -24
  26. package/src/lang/it.d.ts +4 -4
  27. package/src/lang/it.js +188 -188
  28. package/src/lang/ja.d.ts +4 -4
  29. package/src/lang/ja.js +187 -187
  30. package/src/lang/ko.d.ts +4 -4
  31. package/src/lang/ko.js +187 -187
  32. package/src/lang/lv.d.ts +4 -4
  33. package/src/lang/lv.js +187 -187
  34. package/src/lang/nl.d.ts +4 -4
  35. package/src/lang/nl.js +187 -187
  36. package/src/lang/pl.d.ts +4 -4
  37. package/src/lang/pl.js +187 -187
  38. package/src/lang/pt_br.d.ts +4 -4
  39. package/src/lang/pt_br.js +189 -189
  40. package/src/lang/ro.d.ts +4 -4
  41. package/src/lang/ro.js +187 -187
  42. package/src/lang/ru.d.ts +4 -4
  43. package/src/lang/ru.js +187 -187
  44. package/src/lang/se.d.ts +4 -4
  45. package/src/lang/se.js +191 -191
  46. package/src/lang/ua.d.ts +5 -5
  47. package/src/lang/ua.js +188 -188
  48. package/src/lang/ur.d.ts +5 -0
  49. package/src/lang/ur.js +188 -0
  50. package/src/lang/zh_cn.d.ts +4 -4
  51. package/src/lang/zh_cn.js +187 -187
  52. package/src/lib/constructor.js +1 -2
  53. package/src/lib/context.d.ts +42 -42
  54. package/src/lib/context.js +0 -0
  55. package/src/lib/core.d.ts +1101 -1101
  56. package/src/lib/core.js +220 -99
  57. package/src/lib/history.d.ts +48 -48
  58. package/src/lib/history.js +218 -218
  59. package/src/lib/util.d.ts +677 -677
  60. package/src/lib/util.js +38 -12
  61. package/src/options.d.ts +608 -608
  62. package/src/plugins/CommandPlugin.d.ts +7 -7
  63. package/src/plugins/DialogPlugin.d.ts +19 -19
  64. package/src/plugins/FileBrowserPlugin.d.ts +29 -29
  65. package/src/plugins/Module.d.ts +14 -14
  66. package/src/plugins/Plugin.d.ts +41 -41
  67. package/src/plugins/SubmenuPlugin.d.ts +7 -7
  68. package/src/plugins/command/blockquote.d.ts +4 -4
  69. package/src/plugins/command/blockquote.js +46 -46
  70. package/src/plugins/dialog/audio.d.ts +4 -4
  71. package/src/plugins/dialog/audio.js +556 -554
  72. package/src/plugins/dialog/image.d.ts +4 -4
  73. package/src/plugins/dialog/image.js +1122 -1107
  74. package/src/plugins/dialog/link.d.ts +4 -4
  75. package/src/plugins/dialog/link.js +223 -223
  76. package/src/plugins/dialog/math.d.ts +4 -4
  77. package/src/plugins/dialog/math.js +294 -294
  78. package/src/plugins/dialog/mention.d.ts +5 -5
  79. package/src/plugins/dialog/mention.js +242 -242
  80. package/src/plugins/dialog/video.d.ts +4 -4
  81. package/src/plugins/dialog/video.js +983 -981
  82. package/src/plugins/fileBrowser/imageGallery.d.ts +4 -4
  83. package/src/plugins/fileBrowser/imageGallery.js +63 -63
  84. package/src/plugins/index.d.ts +79 -79
  85. package/src/plugins/index.js +32 -32
  86. package/src/plugins/modules/_anchor.js +461 -462
  87. package/src/plugins/modules/_colorPicker.d.ts +59 -59
  88. package/src/plugins/modules/_colorPicker.js +0 -0
  89. package/src/plugins/modules/_notice.d.ts +20 -20
  90. package/src/plugins/modules/_notice.js +72 -72
  91. package/src/plugins/modules/_selectMenu.js +118 -118
  92. package/src/plugins/modules/component.d.ts +24 -24
  93. package/src/plugins/modules/component.js +82 -82
  94. package/src/plugins/modules/dialog.d.ts +27 -27
  95. package/src/plugins/modules/dialog.js +174 -174
  96. package/src/plugins/modules/fileBrowser.d.ts +41 -41
  97. package/src/plugins/modules/fileBrowser.js +373 -373
  98. package/src/plugins/modules/fileManager.d.ts +66 -66
  99. package/src/plugins/modules/fileManager.js +325 -324
  100. package/src/plugins/modules/index.d.ts +10 -10
  101. package/src/plugins/modules/index.js +8 -8
  102. package/src/plugins/modules/resizing.d.ts +153 -153
  103. package/src/plugins/modules/resizing.js +895 -895
  104. package/src/plugins/submenu/align.d.ts +4 -4
  105. package/src/plugins/submenu/align.js +160 -160
  106. package/src/plugins/submenu/font.d.ts +4 -4
  107. package/src/plugins/submenu/font.js +120 -120
  108. package/src/plugins/submenu/fontColor.d.ts +4 -4
  109. package/src/plugins/submenu/fontColor.js +0 -0
  110. package/src/plugins/submenu/fontSize.d.ts +4 -4
  111. package/src/plugins/submenu/fontSize.js +112 -112
  112. package/src/plugins/submenu/formatBlock.d.ts +4 -4
  113. package/src/plugins/submenu/formatBlock.js +273 -273
  114. package/src/plugins/submenu/hiliteColor.d.ts +4 -4
  115. package/src/plugins/submenu/hiliteColor.js +0 -0
  116. package/src/plugins/submenu/horizontalRule.d.ts +4 -4
  117. package/src/plugins/submenu/horizontalRule.js +98 -98
  118. package/src/plugins/submenu/lineHeight.d.ts +4 -4
  119. package/src/plugins/submenu/lineHeight.js +104 -104
  120. package/src/plugins/submenu/list.d.ts +4 -4
  121. package/src/plugins/submenu/list.js +456 -455
  122. package/src/plugins/submenu/paragraphStyle.d.ts +4 -4
  123. package/src/plugins/submenu/paragraphStyle.js +135 -135
  124. package/src/plugins/submenu/table.d.ts +4 -4
  125. package/src/plugins/submenu/template.d.ts +4 -4
  126. package/src/plugins/submenu/template.js +71 -71
  127. package/src/plugins/submenu/textStyle.d.ts +4 -4
  128. package/src/plugins/submenu/textStyle.js +167 -167
  129. package/src/suneditor.d.ts +9 -9
  130. package/src/suneditor.js +75 -75
  131. package/src/suneditor_build.js +17 -17
@@ -1,1107 +1,1122 @@
1
- /*
2
- * wysiwyg web editor
3
- *
4
- * suneditor.js
5
- * Copyright 2017 JiHong Lee.
6
- * MIT license.
7
- */
8
- 'use strict';
9
-
10
- import dialog from '../modules/dialog';
11
- import anchor from '../modules/_anchor';
12
- import component from '../modules/component';
13
- import resizing from '../modules/resizing';
14
- import fileManager from '../modules/fileManager';
15
-
16
- export default {
17
- name: 'image',
18
- display: 'dialog',
19
- add: function (core) {
20
- core.addModule([dialog, anchor, component, resizing, fileManager]);
21
-
22
- const options = core.options;
23
- const context = core.context;
24
- const contextImage = context.image = {
25
- _infoList: [], // @Override fileManager
26
- _infoIndex: 0, // @Override fileManager
27
- _uploadFileLength: 0, // @Override fileManager
28
- focusElement: null, // @Override dialog // This element has focus when the dialog is opened.
29
- sizeUnit: options._imageSizeUnit,
30
- _linkElement: '',
31
- _altText: '',
32
- _align: 'none',
33
- _floatClassRegExp: '__se__float\\-[a-z]+',
34
- _v_src: {_linkValue: ''},
35
- svgDefaultSize: '30%',
36
- base64RenderIndex: 0,
37
- // @require @Override component
38
- _element: null,
39
- _cover: null,
40
- _container: null,
41
- // @Override resizing properties
42
- inputX: null,
43
- inputY: null,
44
- _element_w: 1,
45
- _element_h: 1,
46
- _element_l: 0,
47
- _element_t: 0,
48
- _defaultSizeX: 'auto',
49
- _defaultSizeY: 'auto',
50
- _origin_w: options.imageWidth === 'auto' ? '' : options.imageWidth,
51
- _origin_h: options.imageHeight === 'auto' ? '' : options.imageHeight,
52
- _proportionChecked: true,
53
- _resizing: options.imageResizing,
54
- _resizeDotHide: !options.imageHeightShow,
55
- _rotation: options.imageRotation,
56
- _alignHide: !options.imageAlignShow,
57
- _onlyPercentage: options.imageSizeOnlyPercentage,
58
- _ratio: false,
59
- _ratioX: 1,
60
- _ratioY: 1,
61
- _captionShow: true,
62
- _captionChecked: false,
63
- _caption: null,
64
- captionCheckEl: null
65
- };
66
-
67
- /** image dialog */
68
- let image_dialog = this.setDialog(core);
69
- contextImage.modal = image_dialog;
70
- contextImage.imgInputFile = image_dialog.querySelector('._se_image_file');
71
- contextImage.imgUrlFile = image_dialog.querySelector('._se_image_url');
72
- contextImage.focusElement = contextImage.imgInputFile || contextImage.imgUrlFile;
73
- contextImage.altText = image_dialog.querySelector('._se_image_alt');
74
- contextImage.captionCheckEl = image_dialog.querySelector('._se_image_check_caption');
75
- contextImage.previewSrc = image_dialog.querySelector('._se_tab_content_image .se-link-preview');
76
-
77
- /** add event listeners */
78
- image_dialog.querySelector('.se-dialog-tabs').addEventListener('click', this.openTab.bind(core));
79
- image_dialog.querySelector('form').addEventListener('submit', this.submit.bind(core));
80
- if (contextImage.imgInputFile) image_dialog.querySelector('.se-file-remove').addEventListener('click', this._removeSelectedFiles.bind(contextImage.imgInputFile, contextImage.imgUrlFile, contextImage.previewSrc));
81
- if (contextImage.imgUrlFile) contextImage.imgUrlFile.addEventListener('input', this._onLinkPreview.bind(contextImage.previewSrc, contextImage._v_src, options.linkProtocol));
82
- if (contextImage.imgInputFile && contextImage.imgUrlFile) contextImage.imgInputFile.addEventListener('change', this._fileInputChange.bind(contextImage));
83
-
84
- const imageGalleryButton = image_dialog.querySelector('.__se__gallery');
85
- if (imageGalleryButton) imageGalleryButton.addEventListener('click', this._openGallery.bind(core));
86
-
87
- contextImage.proportion = {};
88
- contextImage.inputX = {};
89
- contextImage.inputY = {};
90
- if (options.imageResizing) {
91
- contextImage.proportion = image_dialog.querySelector('._se_image_check_proportion');
92
- contextImage.inputX = image_dialog.querySelector('._se_image_size_x');
93
- contextImage.inputY = image_dialog.querySelector('._se_image_size_y');
94
- contextImage.inputX.value = options.imageWidth;
95
- contextImage.inputY.value = options.imageHeight;
96
-
97
- contextImage.inputX.addEventListener('keyup', this.setInputSize.bind(core, 'x'));
98
- contextImage.inputY.addEventListener('keyup', this.setInputSize.bind(core, 'y'));
99
-
100
- contextImage.inputX.addEventListener('change', this.setRatio.bind(core));
101
- contextImage.inputY.addEventListener('change', this.setRatio.bind(core));
102
- contextImage.proportion.addEventListener('change', this.setRatio.bind(core));
103
-
104
- image_dialog.querySelector('.se-dialog-btn-revert').addEventListener('click', this.sizeRevert.bind(core));
105
- }
106
-
107
- /** append html */
108
- context.dialog.modal.appendChild(image_dialog);
109
-
110
- /** link event */
111
- core.plugins.anchor.initEvent.call(core, 'image', image_dialog.querySelector('._se_tab_content_url'));
112
- contextImage.anchorCtx = core.context.anchor.caller.image;
113
-
114
- /** empty memory */
115
- image_dialog = null;
116
- },
117
-
118
- /** dialog */
119
- setDialog: function (core) {
120
- const option = core.options;
121
- const lang = core.lang;
122
- const dialog = core.util.createElement('DIV');
123
-
124
- dialog.className = 'se-dialog-content se-dialog-image';
125
- dialog.style.display = 'none';
126
-
127
- let html = '' +
128
- '<div class="se-dialog-header">' +
129
- '<button type="button" data-command="close" class="se-btn se-dialog-close" class="close" title="' + lang.dialogBox.close + '" aria-label="' + lang.dialogBox.close + '">' +
130
- core.icons.cancel +
131
- '</button>' +
132
- '<span class="se-modal-title">' + lang.dialogBox.imageBox.title + '</span>' +
133
- '</div>' +
134
- '<div class="se-dialog-tabs">' +
135
- '<button type="button" class="_se_tab_link active" data-tab-link="image">' + lang.toolbar.image + '</button>' +
136
- '<button type="button" class="_se_tab_link" data-tab-link="url">' + lang.toolbar.link + '</button>' +
137
- '</div>' +
138
- '<form method="post" enctype="multipart/form-data">' +
139
- '<div class="_se_tab_content _se_tab_content_image">' +
140
- '<div class="se-dialog-body"><div style="border-bottom: 1px dashed #ccc;">';
141
-
142
- if (option.imageFileInput) {
143
- html += '' +
144
- '<div class="se-dialog-form">' +
145
- '<label>' + lang.dialogBox.imageBox.file + '</label>' +
146
- '<div class="se-dialog-form-files">' +
147
- '<input class="se-input-form _se_image_file" type="file" accept="' + option.imageAccept + '"' + (option.imageMultipleFile ? ' multiple="multiple"' : '') + '/>' +
148
- '<button type="button" class="se-btn se-dialog-files-edge-button se-file-remove" title="' + lang.controller.remove + '" aria-label="' + lang.controller.remove + '">' + core.icons.cancel + '</button>' +
149
- '</div>' +
150
- '</div>' ;
151
- }
152
-
153
- if (option.imageUrlInput) {
154
- html += '' +
155
- '<div class="se-dialog-form">' +
156
- '<label>' + lang.dialogBox.imageBox.url + '</label>' +
157
- '<div class="se-dialog-form-files">' +
158
- '<input class="se-input-form se-input-url _se_image_url" type="text" />' +
159
- ((option.imageGalleryUrl && core.plugins.imageGallery) ? '<button type="button" class="se-btn se-dialog-files-edge-button __se__gallery" title="' + lang.toolbar.imageGallery + '" aria-label="' + lang.toolbar.imageGallery + '">' + core.icons.image_gallery + '</button>' : '') +
160
- '</div>' +
161
- '<pre class="se-link-preview"></pre>' +
162
- '</div>';
163
- }
164
-
165
- html += '</div>' +
166
- '<div class="se-dialog-form">' +
167
- '<label>' + lang.dialogBox.imageBox.altText + '</label><input class="se-input-form _se_image_alt" type="text" />' +
168
- '</div>';
169
-
170
- if (option.imageResizing) {
171
- const onlyPercentage = option.imageSizeOnlyPercentage;
172
- const onlyPercentDisplay = onlyPercentage ? ' style="display: none !important;"' : '';
173
- const heightDisplay = !option.imageHeightShow ? ' style="display: none !important;"' : '';
174
- html += '<div class="se-dialog-form">';
175
- if (onlyPercentage || !option.imageHeightShow) {
176
- html += '' +
177
- '<div class="se-dialog-size-text">' +
178
- '<label class="size-w">' + lang.dialogBox.size + '</label>' +
179
- '</div>';
180
- } else {
181
- html += '' +
182
- '<div class="se-dialog-size-text">' +
183
- '<label class="size-w">' + lang.dialogBox.width + '</label>' +
184
- '<label class="se-dialog-size-x">&nbsp;</label>' +
185
- '<label class="size-h">' + lang.dialogBox.height + '</label>' +
186
- '</div>';
187
- }
188
- html += '' +
189
- '<input class="se-input-control _se_image_size_x" placeholder="auto"' + (onlyPercentage ? ' type="number" min="1"' : 'type="text"') + (onlyPercentage ? ' max="100"' : '') + ' />' +
190
- '<label class="se-dialog-size-x"' + heightDisplay + '>' + (onlyPercentage ? '%' : 'x') + '</label>' +
191
- '<input type="text" class="se-input-control _se_image_size_y" placeholder="auto"' + onlyPercentDisplay + (onlyPercentage ? ' max="100"' : '') + heightDisplay + '/>' +
192
- '<label' + onlyPercentDisplay + heightDisplay + '><input type="checkbox" class="se-dialog-btn-check _se_image_check_proportion" checked/>&nbsp;' + lang.dialogBox.proportion + '</label>' +
193
- '<button type="button" title="' + lang.dialogBox.revertButton + '" aria-label="' + lang.dialogBox.revertButton + '" class="se-btn se-dialog-btn-revert" style="float: right;">' + core.icons.revert + '</button>' +
194
- '</div>' ;
195
- }
196
-
197
- html += '' +
198
- '<div class="se-dialog-form se-dialog-form-footer">' +
199
- '<label><input type="checkbox" class="se-dialog-btn-check _se_image_check_caption" />&nbsp;' + lang.dialogBox.caption + '</label>' +
200
- '</div>' +
201
- '</div>' +
202
- '</div>' +
203
- '<div class="_se_tab_content _se_tab_content_url" style="display: none">' +
204
- core.context.anchor.forms.innerHTML +
205
- '</div>' +
206
- '<div class="se-dialog-footer">' +
207
- '<div' + (option.imageAlignShow ? '' : ' style="display: none"') + '>' +
208
- '<label><input type="radio" name="suneditor_image_radio" class="se-dialog-btn-radio" value="none" checked>' + lang.dialogBox.basic + '</label>' +
209
- '<label><input type="radio" name="suneditor_image_radio" class="se-dialog-btn-radio" value="left">' + lang.dialogBox.left + '</label>' +
210
- '<label><input type="radio" name="suneditor_image_radio" class="se-dialog-btn-radio" value="center">' + lang.dialogBox.center + '</label>' +
211
- '<label><input type="radio" name="suneditor_image_radio" class="se-dialog-btn-radio" value="right">' + lang.dialogBox.right + '</label>' +
212
- '</div>' +
213
- '<button type="submit" class="se-btn-primary" title="' + lang.dialogBox.submitButton + '" aria-label="' + lang.dialogBox.submitButton + '"><span>' + lang.dialogBox.submitButton + '</span></button>' +
214
- '</div>' +
215
- '</form>';
216
-
217
- dialog.innerHTML = html;
218
-
219
- return dialog;
220
- },
221
-
222
- _fileInputChange: function () {
223
- if (!this.imgInputFile.value) {
224
- this.imgUrlFile.removeAttribute('disabled');
225
- this.previewSrc.style.textDecoration = '';
226
- } else {
227
- this.imgUrlFile.setAttribute('disabled', true);
228
- this.previewSrc.style.textDecoration = 'line-through';
229
- }
230
- },
231
-
232
- _removeSelectedFiles: function (urlInput, previewSrc) {
233
- this.value = '';
234
- if (urlInput) {
235
- urlInput.removeAttribute('disabled');
236
- previewSrc.style.textDecoration = '';
237
- }
238
- },
239
-
240
- _openGallery: function () {
241
- this.callPlugin('imageGallery', this.plugins.imageGallery.open.bind(this, this.plugins.image._setUrlInput.bind(this.context.image)), null);
242
- },
243
-
244
- _setUrlInput: function (target) {
245
- this.altText.value = target.alt;
246
- this._v_src._linkValue = this.previewSrc.textContent = this.imgUrlFile.value = target.src;
247
- this.imgUrlFile.focus();
248
- },
249
-
250
- _onLinkPreview: function (context, protocol, e) {
251
- const value = e.target.value.trim();
252
- context._linkValue = this.textContent = !value ? '' : (protocol && value.indexOf('://') === -1 && value.indexOf('#') !== 0) ? protocol + value : value.indexOf('://') === -1 ? '/' + value : value;
253
- },
254
-
255
- /**
256
- * @Override @Required fileManager
257
- */
258
- fileTags: ['img'],
259
-
260
- /**
261
- * @Override core, fileManager, resizing
262
- * @description It is called from core.selectComponent.
263
- * @param {Element} element Target element
264
- */
265
- select: function (element) {
266
- this.plugins.image.onModifyMode.call(this, element, this.plugins.resizing.call_controller_resize.call(this, element, 'image'));
267
- },
268
-
269
- /**
270
- * @Override fileManager, resizing
271
- */
272
- destroy: function (element) {
273
- const imageEl = element || this.context.image._element;
274
- const imageContainer = this.util.getParentElement(imageEl, this.util.isMediaComponent) || imageEl;
275
- const dataIndex = imageEl.getAttribute('data-index') * 1;
276
- let focusEl = (imageContainer.previousElementSibling || imageContainer.nextElementSibling);
277
-
278
- const emptyDiv = imageContainer.parentNode;
279
- this.util.removeItem(imageContainer);
280
- this.plugins.image.init.call(this);
281
- this.controllersOff();
282
-
283
- if (emptyDiv !== this.context.element.wysiwyg) this.util.removeItemAllParents(emptyDiv, function (current) { return current.childNodes.length === 0; }, null);
284
-
285
- // focus
286
- this.focusEdge(focusEl);
287
-
288
- // event
289
- this.plugins.fileManager.deleteInfo.call(this, 'image', dataIndex, this.functions.onImageUpload);
290
-
291
- // history stack
292
- this.history.push(false);
293
- },
294
-
295
- /**
296
- * @Required @Override dialog
297
- */
298
- on: function (update) {
299
- const contextImage = this.context.image;
300
-
301
- if (!update) {
302
- contextImage.inputX.value = contextImage._origin_w = this.options.imageWidth === contextImage._defaultSizeX ? '' : this.options.imageWidth;
303
- contextImage.inputY.value = contextImage._origin_h = this.options.imageHeight === contextImage._defaultSizeY ? '' : this.options.imageHeight;
304
- if (contextImage.imgInputFile && this.options.imageMultipleFile) contextImage.imgInputFile.setAttribute('multiple', 'multiple');
305
- } else {
306
- if (contextImage.imgInputFile && this.options.imageMultipleFile) contextImage.imgInputFile.removeAttribute('multiple');
307
- }
308
- this.plugins.anchor.on.call(this, contextImage.anchorCtx, update);
309
- },
310
-
311
- /**
312
- * @Required @Override dialog
313
- */
314
- open: function () {
315
- this.plugins.dialog.open.call(this, 'image', 'image' === this.currentControllerName);
316
- },
317
-
318
- openTab: function (e) {
319
- const modal = this.context.image.modal;
320
- const targetElement = (e === 'init' ? modal.querySelector('._se_tab_link') : e.target);
321
-
322
- if (!/^BUTTON$/i.test(targetElement.tagName)) {
323
- return false;
324
- }
325
-
326
- // Declare all variables
327
- const tabName = targetElement.getAttribute('data-tab-link');
328
- const contentClassName = '_se_tab_content';
329
- let i, tabContent, tabLinks;
330
-
331
- // Get all elements with class="tabcontent" and hide them
332
- tabContent = modal.getElementsByClassName(contentClassName);
333
- for (i = 0; i < tabContent.length; i++) {
334
- tabContent[i].style.display = 'none';
335
- }
336
-
337
- // Get all elements with class="tablinks" and remove the class "active"
338
- tabLinks = modal.getElementsByClassName('_se_tab_link');
339
- for (i = 0; i < tabLinks.length; i++) {
340
- this.util.removeClass(tabLinks[i], 'active');
341
- }
342
-
343
- // Show the current tab, and add an "active" class to the button that opened the tab
344
- modal.querySelector('.' + contentClassName + '_' + tabName).style.display = 'block';
345
- this.util.addClass(targetElement, 'active');
346
-
347
- // focus
348
- if (tabName === 'image' && this.context.image.focusElement) {
349
- this.context.image.focusElement.focus();
350
- } else if (tabName === 'url') {
351
- this.context.anchor.caller.image.urlInput.focus();
352
- }
353
-
354
- return false;
355
- },
356
-
357
- submit: function (e) {
358
- const contextImage = this.context.image;
359
- const imagePlugin = this.plugins.image;
360
-
361
- e.preventDefault();
362
- e.stopPropagation();
363
-
364
- contextImage._altText = contextImage.altText.value;
365
- contextImage._align = contextImage.modal.querySelector('input[name="suneditor_image_radio"]:checked').value;
366
- contextImage._captionChecked = contextImage.captionCheckEl.checked;
367
- if (contextImage._resizing) contextImage._proportionChecked = contextImage.proportion.checked;
368
-
369
- try {
370
- if (this.context.dialog.updateModal) {
371
- imagePlugin.update_image.call(this, false, true, false);
372
- }
373
-
374
- if (contextImage.imgInputFile && contextImage.imgInputFile.files.length > 0) {
375
- this.showLoading();
376
- imagePlugin.submitAction.call(this, this.context.image.imgInputFile.files);
377
- } else if (contextImage.imgUrlFile && contextImage._v_src._linkValue.length > 0) {
378
- this.showLoading();
379
- imagePlugin.onRender_imgUrl.call(this, contextImage._v_src._linkValue);
380
- }
381
- } catch (error) {
382
- this.closeLoading();
383
- throw Error('[SUNEDITOR.image.submit.fail] cause : "' + error.message + '"');
384
- } finally {
385
- this.plugins.dialog.close.call(this);
386
- }
387
-
388
- return false;
389
- },
390
-
391
- submitAction: function (fileList) {
392
- if (fileList.length === 0) return;
393
-
394
- let fileSize = 0;
395
- let files = [];
396
- for (let i = 0, len = fileList.length; i < len; i++) {
397
- if (/image/i.test(fileList[i].type)) {
398
- files.push(fileList[i]);
399
- fileSize += fileList[i].size;
400
- }
401
- }
402
-
403
- const limitSize = this.options.imageUploadSizeLimit;
404
- if (limitSize > 0) {
405
- let infoSize = 0;
406
- const imagesInfo = this.context.image._infoList;
407
- for (let i = 0, len = imagesInfo.length; i < len; i++) {
408
- infoSize += imagesInfo[i].size * 1;
409
- }
410
-
411
- if ((fileSize + infoSize) > limitSize) {
412
- this.closeLoading();
413
- const err = '[SUNEDITOR.imageUpload.fail] Size of uploadable total images: ' + (limitSize/1000) + 'KB';
414
- if (typeof this.functions.onImageUploadError !== 'function' || this.functions.onImageUploadError(err, { 'limitSize': limitSize, 'currentSize': infoSize, 'uploadSize': fileSize }, this)) {
415
- this.functions.noticeOpen(err);
416
- }
417
- return;
418
- }
419
- }
420
-
421
- const contextImage = this.context.image;
422
- contextImage._uploadFileLength = files.length;
423
-
424
- const anchor = this.plugins.anchor.createAnchor.call(this, contextImage.anchorCtx, true);
425
- const info = {
426
- anchor: anchor,
427
- inputWidth: contextImage.inputX.value,
428
- inputHeight: contextImage.inputY.value,
429
- align: contextImage._align,
430
- isUpdate: this.context.dialog.updateModal,
431
- alt: contextImage._altText,
432
- element: contextImage._element
433
- };
434
-
435
- if (typeof this.functions.onImageUploadBefore === 'function') {
436
- const result = this.functions.onImageUploadBefore(files, info, this, function (data) {
437
- if (data && this._w.Array.isArray(data.result)) {
438
- this.plugins.image.register.call(this, info, data);
439
- } else {
440
- this.plugins.image.upload.call(this, info, data);
441
- }
442
- }.bind(this));
443
-
444
- if (typeof result === 'undefined') return;
445
- if (!result) {
446
- this.closeLoading();
447
- return;
448
- }
449
- if (this._w.Array.isArray(result) && result.length > 0) files = result;
450
- }
451
-
452
- this.plugins.image.upload.call(this, info, files);
453
- },
454
-
455
- error: function (message, response) {
456
- this.closeLoading();
457
- if (typeof this.functions.onImageUploadError !== 'function' || this.functions.onImageUploadError(message, response, this)) {
458
- this.functions.noticeOpen(message);
459
- throw Error('[SUNEDITOR.plugin.image.error] response: ' + message);
460
- }
461
- },
462
-
463
- upload: function (info, files) {
464
- if (!files) {
465
- this.closeLoading();
466
- return;
467
- }
468
- if (typeof files === 'string') {
469
- this.plugins.image.error.call(this, files, null);
470
- return;
471
- }
472
-
473
- const imageUploadUrl = this.options.imageUploadUrl;
474
- const filesLen = this.context.dialog.updateModal ? 1 : files.length;
475
-
476
- // server upload
477
- if (typeof imageUploadUrl === 'string' && imageUploadUrl.length > 0) {
478
- const formData = new FormData();
479
- for (let i = 0; i < filesLen; i++) {
480
- formData.append('file-' + i, files[i]);
481
- }
482
- this.plugins.fileManager.upload.call(this, imageUploadUrl, this.options.imageUploadHeader, formData, this.plugins.image.callBack_imgUpload.bind(this, info), this.functions.onImageUploadError);
483
- } else { // base64
484
- this.plugins.image.setup_reader.call(this, files, info.anchor, info.inputWidth, info.inputHeight, info.align, info.alt, filesLen, info.isUpdate);
485
- }
486
- },
487
-
488
- callBack_imgUpload: function (info, xmlHttp) {
489
- if (typeof this.functions.imageUploadHandler === 'function') {
490
- this.functions.imageUploadHandler(xmlHttp, info, this);
491
- } else {
492
- const response = JSON.parse(xmlHttp.responseText);
493
- if (response.errorMessage) {
494
- this.plugins.image.error.call(this, response.errorMessage, response);
495
- } else {
496
- this.plugins.image.register.call(this, info, response);
497
- }
498
- }
499
- },
500
-
501
- register: function (info, response) {
502
- const fileList = response.result;
503
-
504
- for (let i = 0, len = fileList.length, file; i < len; i++) {
505
- file = { name: fileList[i].name, size: fileList[i].size };
506
- if (info.isUpdate) {
507
- this.plugins.image.update_src.call(this, fileList[i].url, info.element, file);
508
- break;
509
- } else {
510
- this.plugins.image.create_image.call(this, fileList[i].url, info.anchor, info.inputWidth, info.inputHeight, info.align, file, info.alt);
511
- }
512
- }
513
-
514
- this.closeLoading();
515
- },
516
-
517
- setup_reader: function (files, anchor, width, height, align, alt, filesLen, isUpdate) {
518
- try {
519
- this.context.image.base64RenderIndex = filesLen;
520
- const wFileReader = this._w.FileReader;
521
- const filesStack = [filesLen];
522
- this.context.image.inputX.value = width;
523
- this.context.image.inputY.value = height;
524
-
525
- for (let i = 0, reader, file; i < filesLen; i++) {
526
- reader = new wFileReader();
527
- file = files[i];
528
-
529
- reader.onload = function (reader, update, updateElement, file, index) {
530
- filesStack[index] = { result: reader.result, file: file };
531
-
532
- if (--this.context.image.base64RenderIndex === 0) {
533
- this.plugins.image.onRender_imgBase64.call(this, update, filesStack, updateElement, anchor, width, height, align, alt);
534
- this.closeLoading();
535
- }
536
- }.bind(this, reader, isUpdate, this.context.image._element, file, i);
537
-
538
- reader.readAsDataURL(file);
539
- }
540
- } catch (e) {
541
- this.closeLoading();
542
- throw Error('[SUNEDITOR.image.setup_reader.fail] cause : "' + e.message + '"');
543
- }
544
- },
545
-
546
- onRender_imgBase64: function (update, filesStack, updateElement, anchor, width, height, align, alt) {
547
- const updateMethod = this.plugins.image.update_src;
548
- const createMethod = this.plugins.image.create_image;
549
-
550
- for (let i = 0, len = filesStack.length; i < len; i++) {
551
- if (update) {
552
- this.context.image._element.setAttribute('data-file-name', filesStack[i].file.name);
553
- this.context.image._element.setAttribute('data-file-size', filesStack[i].file.size);
554
- updateMethod.call(this, filesStack[i].result, updateElement, filesStack[i].file);
555
- } else {
556
- createMethod.call(this, filesStack[i].result, anchor, width, height, align, filesStack[i].file, alt);
557
- }
558
- }
559
- },
560
-
561
- onRender_imgUrl: function (url) {
562
- if (!url) url = this.context.image._v_src._linkValue;
563
- if (!url) return false;
564
- const contextImage = this.context.image;
565
-
566
- try {
567
- const file = {name: url.split('/').pop(), size: 0};
568
- if (this.context.dialog.updateModal) this.plugins.image.update_src.call(this, url, contextImage._element, file);
569
- else this.plugins.image.create_image.call(this, url, this.plugins.anchor.createAnchor.call(this, contextImage.anchorCtx, true), contextImage.inputX.value, contextImage.inputY.value, contextImage._align, file, contextImage._altText);
570
- } catch (e) {
571
- throw Error('[SUNEDITOR.image.URLRendering.fail] cause : "' + e.message + '"');
572
- } finally {
573
- this.closeLoading();
574
- }
575
- },
576
-
577
- onRender_link: function (imgTag, anchor) {
578
- if (anchor) {
579
- anchor.setAttribute('data-image-link', 'image');
580
- imgTag.setAttribute('data-image-link', anchor.href);
581
- anchor.appendChild(imgTag);
582
- return anchor;
583
- }
584
-
585
- return imgTag;
586
- },
587
-
588
- /**
589
- * @Override resizing
590
- * @param {String} xy 'x': width, 'y': height
591
- * @param {KeyboardEvent} e Event object
592
- */
593
- setInputSize: function (xy, e) {
594
- if (e && e.keyCode === 32) {
595
- e.preventDefault();
596
- return;
597
- }
598
-
599
- this.plugins.resizing._module_setInputSize.call(this, this.context.image, xy);
600
- },
601
-
602
- /**
603
- * @Override resizing
604
- */
605
- setRatio: function () {
606
- this.plugins.resizing._module_setRatio.call(this, this.context.image);
607
- },
608
-
609
- /**
610
- * @Override fileManager
611
- */
612
- checkFileInfo: function () {
613
- const imagePlugin = this.plugins.image;
614
- const contextImage = this.context.image;
615
-
616
- const modifyHandler = function (tag) {
617
- imagePlugin.onModifyMode.call(this, tag, null);
618
- imagePlugin.openModify.call(this, true);
619
- // get size
620
- contextImage.inputX.value = contextImage._origin_w;
621
- contextImage.inputY.value = contextImage._origin_h;
622
- // get align
623
- const format = this.util.getFormatElement(tag);
624
- if (format) contextImage._align = format.style.textAlign || format.style.float;
625
- // link
626
- const link = this.util.getParentElement(tag, this.util.isAnchor);
627
- if (link && !contextImage.anchorCtx.linkValue) contextImage.anchorCtx.linkValue = ' ';
628
-
629
- imagePlugin.update_image.call(this, true, false, true);
630
- imagePlugin.init.call(this);
631
- }.bind(this);
632
-
633
- this.plugins.fileManager.checkInfo.call(this, 'image', ['img'], this.functions.onImageUpload, modifyHandler, true);
634
- },
635
-
636
- /**
637
- * @Override fileManager
638
- */
639
- resetFileInfo: function () {
640
- this.plugins.fileManager.resetInfo.call(this, 'image', this.functions.onImageUpload);
641
- },
642
-
643
- create_image: function (src, anchor, width, height, align, file, alt) {
644
- const imagePlugin = this.plugins.image;
645
- const contextImage = this.context.image;
646
- this.context.resizing._resize_plugin = 'image';
647
-
648
- let oImg = this.util.createElement('IMG');
649
- oImg.src = src;
650
- oImg.alt = alt;
651
- oImg.setAttribute('data-rotate', '0');
652
- anchor = imagePlugin.onRender_link.call(this, oImg, anchor ? anchor.cloneNode(false) : null);
653
-
654
- if (contextImage._resizing) {
655
- oImg.setAttribute('data-proportion', contextImage._proportionChecked);
656
- }
657
-
658
- const cover = this.plugins.component.set_cover.call(this, anchor);
659
- const container = this.plugins.component.set_container.call(this, cover, 'se-image-container');
660
-
661
- // caption
662
- if (contextImage._captionChecked) {
663
- contextImage._caption = this.plugins.component.create_caption.call(this);
664
- contextImage._caption.setAttribute('contenteditable', false);
665
- cover.appendChild(contextImage._caption);
666
- }
667
-
668
- contextImage._element = oImg;
669
- contextImage._cover = cover;
670
- contextImage._container = container;
671
-
672
- // set size
673
- imagePlugin.applySize.call(this, width, height);
674
-
675
- // align
676
- imagePlugin.setAlign.call(this, align, oImg, cover, container);
677
-
678
- oImg.onload = imagePlugin._image_create_onload.bind(this, oImg, contextImage.svgDefaultSize, container);
679
- if (this.insertComponent(container, true, true, true)) this.plugins.fileManager.setInfo.call(this, 'image', oImg, this.functions.onImageUpload, file, true);
680
- this.context.resizing._resize_plugin = '';
681
- },
682
-
683
- _image_create_onload: function (oImg, svgDefaultSize, container) {
684
- // svg exception handling
685
- if (oImg.offsetWidth === 0) this.plugins.image.applySize.call(this, svgDefaultSize, '');
686
- if (this.options.mediaAutoSelect) {
687
- this.selectComponent(oImg, 'image');
688
- } else {
689
- const line = this.appendFormatTag(container, null);
690
- if (line) this.setRange(line, 0, line, 0);
691
- }
692
- },
693
-
694
- update_image: function (init, openController, notHistoryPush) {
695
- const contextImage = this.context.image;
696
- let imageEl = contextImage._element;
697
- let cover = contextImage._cover;
698
- let container = contextImage._container;
699
- let isNewContainer = false;
700
-
701
- if (cover === null) {
702
- isNewContainer = true;
703
- imageEl = contextImage._element.cloneNode(true);
704
- cover = this.plugins.component.set_cover.call(this, imageEl);
705
- }
706
-
707
- if (container === null) {
708
- cover = cover.cloneNode(true);
709
- imageEl = cover.querySelector('img');
710
- isNewContainer = true;
711
- container = this.plugins.component.set_container.call(this, cover, 'se-image-container');
712
- } else if (isNewContainer) {
713
- container.innerHTML = '';
714
- container.appendChild(cover);
715
- contextImage._cover = cover;
716
- contextImage._element = imageEl;
717
- isNewContainer = false;
718
- }
719
-
720
- // check size
721
- let changeSize;
722
- const x = this.util.isNumber(contextImage.inputX.value) ? contextImage.inputX.value + contextImage.sizeUnit : contextImage.inputX.value;
723
- const y = this.util.isNumber(contextImage.inputY.value) ? contextImage.inputY.value + contextImage.sizeUnit : contextImage.inputY.value;
724
- if (/%$/.test(imageEl.style.width)) {
725
- changeSize = x !== container.style.width || y !== container.style.height;
726
- } else {
727
- changeSize = x !== imageEl.style.width || y !== imageEl.style.height;
728
- }
729
-
730
- // alt
731
- imageEl.alt = contextImage._altText;
732
-
733
- // caption
734
- let modifiedCaption = false;
735
- if (contextImage._captionChecked) {
736
- if (!contextImage._caption) {
737
- contextImage._caption = this.plugins.component.create_caption.call(this);
738
- cover.appendChild(contextImage._caption);
739
- modifiedCaption = true;
740
- }
741
- } else {
742
- if (contextImage._caption) {
743
- this.util.removeItem(contextImage._caption);
744
- contextImage._caption = null;
745
- modifiedCaption = true;
746
- }
747
- }
748
-
749
- // link
750
- const anchor = this.plugins.anchor.createAnchor.call(this, contextImage.anchorCtx, true);
751
- if (anchor) {
752
- if (contextImage._linkElement !== anchor) {
753
- contextImage._linkElement = anchor.cloneNode(false);
754
- cover.insertBefore(this.plugins.image.onRender_link.call(this, imageEl, contextImage._linkElement), contextImage._caption);
755
- this.util.removeItem(anchor);
756
- } else {
757
- contextImage._linkElement.setAttribute('data-image-link', 'image');
758
- }
759
- } else if (contextImage._linkElement !== null) {
760
- const imageElement = imageEl;
761
- imageElement.setAttribute('data-image-link', '');
762
- if (cover.contains(contextImage._linkElement)) {
763
- const newEl = imageElement.cloneNode(true);
764
- cover.removeChild(contextImage._linkElement);
765
- cover.insertBefore(newEl, contextImage._caption);
766
- contextImage._element = imageEl = newEl;
767
- }
768
- }
769
-
770
- if (isNewContainer) {
771
- let existElement = (this.util.isRangeFormatElement(contextImage._element.parentNode) || this.util.isWysiwygDiv(contextImage._element.parentNode)) ?
772
- contextImage._element :
773
- /^A$/i.test(contextImage._element.parentNode.nodeName) ? contextImage._element.parentNode : this.util.getFormatElement(contextImage._element) || contextImage._element;
774
-
775
- if (this.util.isListCell(existElement)) {
776
- const refer = this.util.getParentElement(contextImage._element, function (current) { return current.parentNode === existElement; });
777
- existElement.insertBefore(container, refer);
778
- this.util.removeItem(contextImage._element);
779
- this.util.removeEmptyNode(refer, null);
780
- } else if (this.util.isFormatElement(existElement)) {
781
- const refer = this.util.getParentElement(contextImage._element, function (current) { return current.parentNode === existElement; });
782
- existElement = this.util.splitElement(existElement, refer);
783
- existElement.parentNode.insertBefore(container, existElement);
784
- this.util.removeItem(contextImage._element);
785
- this.util.removeEmptyNode(existElement, null);
786
- if (existElement.children.length === 0) existElement.innerHTML = this.util.htmlRemoveWhiteSpace(existElement.innerHTML);
787
- } else {
788
- if (this.util.isFormatElement(existElement.parentNode)) {
789
- const formats = existElement.parentNode;
790
- formats.parentNode.insertBefore(container, existElement.previousSibling ? formats.nextElementSibling : formats);
791
- this.util.removeItem(existElement);
792
- } else {
793
- existElement.parentNode.replaceChild(container, existElement);
794
- }
795
- }
796
-
797
- imageEl = container.querySelector('img');
798
-
799
- contextImage._element = imageEl;
800
- contextImage._cover = cover;
801
- contextImage._container = container;
802
- }
803
-
804
- // transform
805
- if (modifiedCaption || (!contextImage._onlyPercentage && changeSize)) {
806
- if (!init && (/\d+/.test(imageEl.style.height) || (this.context.resizing._rotateVertical && contextImage._captionChecked))) {
807
- if (/%$/.test(contextImage.inputX.value) || /%$/.test(contextImage.inputY.value)) {
808
- this.plugins.resizing.resetTransform.call(this, imageEl);
809
- } else {
810
- this.plugins.resizing.setTransformSize.call(this, imageEl, this.util.getNumber(contextImage.inputX.value, 0), this.util.getNumber(contextImage.inputY.value, 0));
811
- }
812
- }
813
- }
814
-
815
- // size
816
- if (contextImage._resizing) {
817
- imageEl.setAttribute('data-proportion', contextImage._proportionChecked);
818
- if (changeSize) {
819
- this.plugins.image.applySize.call(this);
820
- }
821
- }
822
-
823
- // align
824
- this.plugins.image.setAlign.call(this, null, imageEl, null, null);
825
-
826
- // set imagesInfo
827
- if (init) {
828
- this.plugins.fileManager.setInfo.call(this, 'image', imageEl, this.functions.onImageUpload, null, true);
829
- }
830
-
831
- if (openController) {
832
- this.selectComponent(imageEl, 'image');
833
- }
834
-
835
- // history stack
836
- if (!notHistoryPush) this.history.push(false);
837
- },
838
-
839
- update_src: function (src, element, file) {
840
- element.src = src;
841
- this._w.setTimeout(this.plugins.fileManager.setInfo.bind(this, 'image', element, this.functions.onImageUpload, file, true));
842
- this.selectComponent(element, 'image');
843
- },
844
-
845
- /**
846
- * @Required @Override fileManager, resizing
847
- */
848
- onModifyMode: function (element, size) {
849
- if (!element) return;
850
-
851
- const contextImage = this.context.image;
852
- contextImage._linkElement = contextImage.anchorCtx.linkAnchor = /^A$/i.test(element.parentNode.nodeName) ? element.parentNode : null;
853
- contextImage._element = element;
854
- contextImage._cover = this.util.getParentElement(element, 'FIGURE');
855
- contextImage._container = this.util.getParentElement(element, this.util.isMediaComponent);
856
- contextImage._caption = this.util.getChildElement(contextImage._cover, 'FIGCAPTION');
857
- contextImage._align = element.style.float || element.getAttribute('data-align') || 'none';
858
- element.style.float = '';
859
- this.plugins.anchor.setCtx(contextImage._linkElement, contextImage.anchorCtx);
860
-
861
- if (size) {
862
- contextImage._element_w = size.w;
863
- contextImage._element_h = size.h;
864
- contextImage._element_t = size.t;
865
- contextImage._element_l = size.l;
866
- }
867
-
868
- let userSize = contextImage._element.getAttribute('data-size') || contextImage._element.getAttribute('data-origin');
869
- let w, h;
870
- if (userSize) {
871
- userSize = userSize.split(',');
872
- w = userSize[0];
873
- h = userSize[1];
874
- } else if (size) {
875
- w = size.w;
876
- h = size.h;
877
- }
878
-
879
- contextImage._origin_w = w || element.style.width || element.width || '';
880
- contextImage._origin_h = h || element.style.height || element.height || '';
881
- },
882
-
883
- /**
884
- * @Required @Override fileManager, resizing
885
- */
886
- openModify: function (notOpen) {
887
- const contextImage = this.context.image;
888
- if (contextImage.imgUrlFile) {
889
- contextImage._v_src._linkValue = contextImage.previewSrc.textContent = contextImage.imgUrlFile.value = contextImage._element.src;
890
- }
891
- contextImage._altText = contextImage.altText.value = contextImage._element.alt;
892
- (contextImage.modal.querySelector('input[name="suneditor_image_radio"][value="' + contextImage._align + '"]') || contextImage.modal.querySelector('input[name="suneditor_image_radio"][value="none"]')).checked = true;
893
- contextImage._align = contextImage.modal.querySelector('input[name="suneditor_image_radio"]:checked').value;
894
- contextImage._captionChecked = contextImage.captionCheckEl.checked = !!contextImage._caption;
895
-
896
- if (contextImage._resizing) {
897
- this.plugins.resizing._module_setModifyInputSize.call(this, contextImage, this.plugins.image);
898
- }
899
-
900
- if (!notOpen) this.plugins.dialog.open.call(this, 'image', true);
901
- },
902
-
903
- /**
904
- * @Override fileManager
905
- */
906
- applySize: function (w, h) {
907
- const contextImage = this.context.image;
908
-
909
- if (!w) w = contextImage.inputX.value || this.options.imageWidth;
910
- if (!h) h = contextImage.inputY.value || this.options.imageHeight;
911
-
912
- if ((contextImage._onlyPercentage && !!w) || /%$/.test(w)) {
913
- this.plugins.image.setPercentSize.call(this, w, h);
914
- return true;
915
- } else if ((!w || w === 'auto') && (!h || h === 'auto')) {
916
- this.plugins.image.setAutoSize.call(this);
917
- } else {
918
- this.plugins.image.setSize.call(this, w, h, false);
919
- }
920
-
921
- return false;
922
- },
923
-
924
- /**
925
- * @Override resizing
926
- */
927
- sizeRevert: function () {
928
- this.plugins.resizing._module_sizeRevert.call(this, this.context.image);
929
- },
930
-
931
- /**
932
- * @Override resizing
933
- */
934
- setSize: function (w, h, notResetPercentage, direction) {
935
- const contextImage = this.context.image;
936
- const onlyW = /^(rw|lw)$/.test(direction) && /\d+/.test(contextImage._element.style.height);
937
- const onlyH = /^(th|bh)$/.test(direction) && /\d+/.test(contextImage._element.style.width);
938
-
939
- if (!onlyH) {
940
- contextImage._element.style.width = this.util.isNumber(w) ? w + contextImage.sizeUnit : w;
941
- this.plugins.image.cancelPercentAttr.call(this);
942
- }
943
- if (!onlyW) {
944
- contextImage._element.style.height = this.util.isNumber(h) ? h + contextImage.sizeUnit : /%$/.test(h) ? '' : h;
945
- }
946
-
947
- if (contextImage._align === 'center') this.plugins.image.setAlign.call(this, null, null, null, null);
948
- if (!notResetPercentage) contextImage._element.removeAttribute('data-percentage');
949
-
950
- // save current size
951
- this.plugins.resizing._module_saveCurrentSize.call(this, contextImage);
952
- },
953
-
954
- /**
955
- * @Override resizing
956
- */
957
- setAutoSize: function () {
958
- const contextImage = this.context.image;
959
-
960
- if (contextImage._caption) contextImage._caption.style.marginTop = '';
961
- this.plugins.resizing.resetTransform.call(this, contextImage._element);
962
- this.plugins.image.cancelPercentAttr.call(this);
963
-
964
- contextImage._element.style.maxWidth = '';
965
- contextImage._element.style.width = '';
966
- contextImage._element.style.height = '';
967
- contextImage._cover.style.width = '';
968
- contextImage._cover.style.height = '';
969
-
970
- this.plugins.image.setAlign.call(this, null, null, null, null);
971
- contextImage._element.setAttribute('data-percentage', 'auto,auto');
972
-
973
- // save current size
974
- this.plugins.resizing._module_saveCurrentSize.call(this, contextImage);
975
- },
976
-
977
- /**
978
- * @Override resizing
979
- */
980
- setOriginSize: function () {
981
- const contextImage = this.context.image;
982
- contextImage._element.removeAttribute('data-percentage');
983
-
984
- this.plugins.resizing.resetTransform.call(this, contextImage._element);
985
- this.plugins.image.cancelPercentAttr.call(this);
986
-
987
- const originSize = (contextImage._element.getAttribute('data-origin') || '').split(',');
988
- const w = originSize[0];
989
- const h = originSize[1];
990
-
991
- if (originSize) {
992
- if (contextImage._onlyPercentage || (/%$/.test(w) && (/%$/.test(h) || !/\d/.test(h)))) {
993
- this.plugins.image.setPercentSize.call(this, w, h);
994
- } else {
995
- this.plugins.image.setSize.call(this, w, h);
996
- }
997
-
998
- // save current size
999
- this.plugins.resizing._module_saveCurrentSize.call(this, contextImage);
1000
- }
1001
- },
1002
-
1003
- /**
1004
- * @Override resizing
1005
- */
1006
- setPercentSize: function (w, h) {
1007
- const contextImage = this.context.image;
1008
- h = !!h && !/%$/.test(h) && !this.util.getNumber(h, 0) ? this.util.isNumber(h) ? h + '%' : h : this.util.isNumber(h) ? h + contextImage.sizeUnit : (h || '');
1009
- const heightPercentage = /%$/.test(h);
1010
-
1011
- contextImage._container.style.width = this.util.isNumber(w) ? w + '%' : w;
1012
- contextImage._container.style.height = '';
1013
- contextImage._cover.style.width = '100%';
1014
- contextImage._cover.style.height = !heightPercentage ? '' : h;
1015
- contextImage._element.style.width = '100%';
1016
- contextImage._element.style.height = heightPercentage ? '' : h;
1017
- contextImage._element.style.maxWidth = '';
1018
-
1019
- if (contextImage._align === 'center') this.plugins.image.setAlign.call(this, null, null, null, null);
1020
-
1021
- contextImage._element.setAttribute('data-percentage', w + ',' + h);
1022
- this.plugins.resizing.setCaptionPosition.call(this, contextImage._element);
1023
-
1024
- // save current size
1025
- this.plugins.resizing._module_saveCurrentSize.call(this, contextImage);
1026
- },
1027
-
1028
- /**
1029
- * @Override resizing
1030
- */
1031
- cancelPercentAttr: function () {
1032
- const contextImage = this.context.image;
1033
-
1034
- contextImage._cover.style.width = '';
1035
- contextImage._cover.style.height = '';
1036
- contextImage._container.style.width = '';
1037
- contextImage._container.style.height = '';
1038
-
1039
- this.util.removeClass(contextImage._container, this.context.image._floatClassRegExp);
1040
- this.util.addClass(contextImage._container, '__se__float-' + contextImage._align);
1041
-
1042
- if (contextImage._align === 'center') this.plugins.image.setAlign.call(this, null, null, null, null);
1043
- },
1044
-
1045
- /**
1046
- * @Override resizing
1047
- */
1048
- setAlign: function (align, element, cover, container) {
1049
- const contextImage = this.context.image;
1050
-
1051
- if (!align) align = contextImage._align;
1052
- if (!element) element = contextImage._element;
1053
- if (!cover) cover = contextImage._cover;
1054
- if (!container) container = contextImage._container;
1055
-
1056
- if (align && align !== 'none') {
1057
- cover.style.margin = 'auto';
1058
- } else {
1059
- cover.style.margin = '0';
1060
- }
1061
-
1062
- if (/%$/.test(element.style.width) && align === 'center') {
1063
- container.style.minWidth = '100%';
1064
- cover.style.width = container.style.width;
1065
- } else {
1066
- container.style.minWidth = '';
1067
- cover.style.width = this.context.resizing._rotateVertical ? (element.style.height || element.offsetHeight) : ((!element.style.width || element.style.width === 'auto') ? '' : element.style.width || '100%');
1068
- }
1069
-
1070
- if (!this.util.hasClass(container, '__se__float-' + align)) {
1071
- this.util.removeClass(container, contextImage._floatClassRegExp);
1072
- this.util.addClass(container, '__se__float-' + align);
1073
- }
1074
-
1075
- element.setAttribute('data-align', align);
1076
- },
1077
-
1078
- /**
1079
- * @Override dialog
1080
- */
1081
- init: function () {
1082
- const contextImage = this.context.image;
1083
- if (contextImage.imgInputFile) contextImage.imgInputFile.value = '';
1084
- if (contextImage.imgUrlFile) contextImage._v_src._linkValue = contextImage.previewSrc.textContent = contextImage.imgUrlFile.value = '';
1085
- if (contextImage.imgInputFile && contextImage.imgUrlFile) {
1086
- contextImage.imgUrlFile.removeAttribute('disabled');
1087
- contextImage.previewSrc.style.textDecoration = '';
1088
- }
1089
-
1090
- contextImage.altText.value = '';
1091
- contextImage.modal.querySelector('input[name="suneditor_image_radio"][value="none"]').checked = true;
1092
- contextImage.captionCheckEl.checked = false;
1093
- contextImage._element = null;
1094
- this.plugins.image.openTab.call(this, 'init');
1095
-
1096
- if (contextImage._resizing) {
1097
- contextImage.inputX.value = this.options.imageWidth === contextImage._defaultSizeX ? '' : this.options.imageWidth;
1098
- contextImage.inputY.value = this.options.imageHeight === contextImage._defaultSizeY ? '' : this.options.imageHeight;
1099
- contextImage.proportion.checked = true;
1100
- contextImage._ratio = false;
1101
- contextImage._ratioX = 1;
1102
- contextImage._ratioY = 1;
1103
- }
1104
-
1105
- this.plugins.anchor.init.call(this, contextImage.anchorCtx);
1106
- }
1107
- };
1
+ /*
2
+ * wysiwyg web editor
3
+ *
4
+ * suneditor.js
5
+ * Copyright 2017 JiHong Lee.
6
+ * MIT license.
7
+ */
8
+ 'use strict';
9
+
10
+ import dialog from '../modules/dialog';
11
+ import anchor from '../modules/_anchor';
12
+ import component from '../modules/component';
13
+ import resizing from '../modules/resizing';
14
+ import fileManager from '../modules/fileManager';
15
+
16
+ export default {
17
+ name: 'image',
18
+ display: 'dialog',
19
+ add: function (core) {
20
+ core.addModule([dialog, anchor, component, resizing, fileManager]);
21
+
22
+ const options = core.options;
23
+ const context = core.context;
24
+ const contextImage = context.image = {
25
+ _infoList: [], // @Override fileManager
26
+ _infoIndex: 0, // @Override fileManager
27
+ _uploadFileLength: 0, // @Override fileManager
28
+ focusElement: null, // @Override dialog // This element has focus when the dialog is opened.
29
+ sizeUnit: options._imageSizeUnit,
30
+ _linkElement: '',
31
+ _altText: '',
32
+ _align: 'none',
33
+ _floatClassRegExp: '__se__float\\-[a-z]+',
34
+ _v_src: {_linkValue: ''},
35
+ svgDefaultSize: '30%',
36
+ base64RenderIndex: 0,
37
+ // @require @Override component
38
+ _element: null,
39
+ _cover: null,
40
+ _container: null,
41
+ // @Override resizing properties
42
+ inputX: null,
43
+ inputY: null,
44
+ _element_w: 1,
45
+ _element_h: 1,
46
+ _element_l: 0,
47
+ _element_t: 0,
48
+ _defaultSizeX: 'auto',
49
+ _defaultSizeY: 'auto',
50
+ _origin_w: options.imageWidth === 'auto' ? '' : options.imageWidth,
51
+ _origin_h: options.imageHeight === 'auto' ? '' : options.imageHeight,
52
+ _proportionChecked: true,
53
+ _resizing: options.imageResizing,
54
+ _resizeDotHide: !options.imageHeightShow,
55
+ _rotation: options.imageRotation,
56
+ _alignHide: !options.imageAlignShow,
57
+ _onlyPercentage: options.imageSizeOnlyPercentage,
58
+ _ratio: false,
59
+ _ratioX: 1,
60
+ _ratioY: 1,
61
+ _captionShow: true,
62
+ _captionChecked: false,
63
+ _caption: null,
64
+ captionCheckEl: null
65
+ };
66
+
67
+ /** image dialog */
68
+ let image_dialog = this.setDialog(core);
69
+ contextImage.modal = image_dialog;
70
+ contextImage.imgInputFile = image_dialog.querySelector('._se_image_file');
71
+ contextImage.imgUrlFile = image_dialog.querySelector('._se_image_url');
72
+ contextImage.focusElement = contextImage.imgInputFile || contextImage.imgUrlFile;
73
+ contextImage.altText = image_dialog.querySelector('._se_image_alt');
74
+ contextImage.captionCheckEl = image_dialog.querySelector('._se_image_check_caption');
75
+ contextImage.previewSrc = image_dialog.querySelector('._se_tab_content_image .se-link-preview');
76
+
77
+ /** add event listeners */
78
+ image_dialog.querySelector('.se-dialog-tabs').addEventListener('click', this.openTab.bind(core));
79
+ image_dialog.querySelector('form').addEventListener('submit', this.submit.bind(core));
80
+ if (contextImage.imgInputFile) image_dialog.querySelector('.se-file-remove').addEventListener('click', this._removeSelectedFiles.bind(contextImage.imgInputFile, contextImage.imgUrlFile, contextImage.previewSrc));
81
+ if (contextImage.imgUrlFile) contextImage.imgUrlFile.addEventListener('input', this._onLinkPreview.bind(contextImage.previewSrc, contextImage._v_src, options.linkProtocol));
82
+ if (contextImage.imgInputFile && contextImage.imgUrlFile) contextImage.imgInputFile.addEventListener('change', this._fileInputChange.bind(contextImage));
83
+
84
+ const imageGalleryButton = image_dialog.querySelector('.__se__gallery');
85
+ if (imageGalleryButton) imageGalleryButton.addEventListener('click', this._openGallery.bind(core));
86
+
87
+ contextImage.proportion = {};
88
+ contextImage.inputX = {};
89
+ contextImage.inputY = {};
90
+ if (options.imageResizing) {
91
+ contextImage.proportion = image_dialog.querySelector('._se_image_check_proportion');
92
+ contextImage.inputX = image_dialog.querySelector('._se_image_size_x');
93
+ contextImage.inputY = image_dialog.querySelector('._se_image_size_y');
94
+ contextImage.inputX.value = options.imageWidth;
95
+ contextImage.inputY.value = options.imageHeight;
96
+
97
+ contextImage.inputX.addEventListener('keyup', this.setInputSize.bind(core, 'x'));
98
+ contextImage.inputY.addEventListener('keyup', this.setInputSize.bind(core, 'y'));
99
+
100
+ contextImage.inputX.addEventListener('change', this.setRatio.bind(core));
101
+ contextImage.inputY.addEventListener('change', this.setRatio.bind(core));
102
+ contextImage.proportion.addEventListener('change', this.setRatio.bind(core));
103
+
104
+ image_dialog.querySelector('.se-dialog-btn-revert').addEventListener('click', this.sizeRevert.bind(core));
105
+ }
106
+
107
+ /** append html */
108
+ context.dialog.modal.appendChild(image_dialog);
109
+
110
+ /** link event */
111
+ core.plugins.anchor.initEvent.call(core, 'image', image_dialog.querySelector('._se_tab_content_url'));
112
+ contextImage.anchorCtx = core.context.anchor.caller.image;
113
+
114
+ /** empty memory */
115
+ image_dialog = null;
116
+ },
117
+
118
+ /** dialog */
119
+ setDialog: function (core) {
120
+ const option = core.options;
121
+ const lang = core.lang;
122
+ const dialog = core.util.createElement('DIV');
123
+
124
+ dialog.className = 'se-dialog-content se-dialog-image';
125
+ dialog.style.display = 'none';
126
+
127
+ let html = '' +
128
+ '<div class="se-dialog-header">' +
129
+ '<button type="button" data-command="close" class="se-btn se-dialog-close" class="close" title="' + lang.dialogBox.close + '" aria-label="' + lang.dialogBox.close + '">' +
130
+ core.icons.cancel +
131
+ '</button>' +
132
+ '<span class="se-modal-title">' + lang.dialogBox.imageBox.title + '</span>' +
133
+ '</div>' +
134
+ '<div class="se-dialog-tabs">' +
135
+ '<button type="button" class="_se_tab_link active" data-tab-link="image">' + lang.toolbar.image + '</button>' +
136
+ '<button type="button" class="_se_tab_link" data-tab-link="url">' + lang.toolbar.link + '</button>' +
137
+ '</div>' +
138
+ '<form method="post" enctype="multipart/form-data">' +
139
+ '<div class="_se_tab_content _se_tab_content_image">' +
140
+ '<div class="se-dialog-body"><div style="border-bottom: 1px dashed #ccc;">';
141
+
142
+ if (option.imageFileInput) {
143
+ html += '' +
144
+ '<div class="se-dialog-form">' +
145
+ '<label>' + lang.dialogBox.imageBox.file + '</label>' +
146
+ '<div class="se-dialog-form-files">' +
147
+ '<input class="se-input-form _se_image_file" type="file" accept="' + option.imageAccept + '"' + (option.imageMultipleFile ? ' multiple="multiple"' : '') + '/>' +
148
+ '<button type="button" class="se-btn se-dialog-files-edge-button se-file-remove" title="' + lang.controller.remove + '" aria-label="' + lang.controller.remove + '">' + core.icons.cancel + '</button>' +
149
+ '</div>' +
150
+ '</div>' ;
151
+ }
152
+
153
+ if (option.imageUrlInput) {
154
+ html += '' +
155
+ '<div class="se-dialog-form">' +
156
+ '<label>' + lang.dialogBox.imageBox.url + '</label>' +
157
+ '<div class="se-dialog-form-files">' +
158
+ '<input class="se-input-form se-input-url _se_image_url" type="text" />' +
159
+ ((option.imageGalleryUrl && core.plugins.imageGallery) ? '<button type="button" class="se-btn se-dialog-files-edge-button __se__gallery" title="' + lang.toolbar.imageGallery + '" aria-label="' + lang.toolbar.imageGallery + '">' + core.icons.image_gallery + '</button>' : '') +
160
+ '</div>' +
161
+ '<pre class="se-link-preview"></pre>' +
162
+ '</div>';
163
+ }
164
+
165
+ html += '</div>' +
166
+ '<div class="se-dialog-form">' +
167
+ '<label>' + lang.dialogBox.imageBox.altText + '</label><input class="se-input-form _se_image_alt" type="text" />' +
168
+ '</div>';
169
+
170
+ if (option.imageResizing) {
171
+ const onlyPercentage = option.imageSizeOnlyPercentage;
172
+ const onlyPercentDisplay = onlyPercentage ? ' style="display: none !important;"' : '';
173
+ const heightDisplay = !option.imageHeightShow ? ' style="display: none !important;"' : '';
174
+ html += '<div class="se-dialog-form">';
175
+ if (onlyPercentage || !option.imageHeightShow) {
176
+ html += '' +
177
+ '<div class="se-dialog-size-text">' +
178
+ '<label class="size-w">' + lang.dialogBox.size + '</label>' +
179
+ '</div>';
180
+ } else {
181
+ html += '' +
182
+ '<div class="se-dialog-size-text">' +
183
+ '<label class="size-w">' + lang.dialogBox.width + '</label>' +
184
+ '<label class="se-dialog-size-x">&nbsp;</label>' +
185
+ '<label class="size-h">' + lang.dialogBox.height + '</label>' +
186
+ '</div>';
187
+ }
188
+ html += '' +
189
+ '<input class="se-input-control _se_image_size_x" placeholder="auto"' + (onlyPercentage ? ' type="number" min="1"' : 'type="text"') + (onlyPercentage ? ' max="100"' : '') + ' />' +
190
+ '<label class="se-dialog-size-x"' + heightDisplay + '>' + (onlyPercentage ? '%' : 'x') + '</label>' +
191
+ '<input type="text" class="se-input-control _se_image_size_y" placeholder="auto"' + onlyPercentDisplay + (onlyPercentage ? ' max="100"' : '') + heightDisplay + '/>' +
192
+ '<label' + onlyPercentDisplay + heightDisplay + '><input type="checkbox" class="se-dialog-btn-check _se_image_check_proportion" checked/>&nbsp;' + lang.dialogBox.proportion + '</label>' +
193
+ '<button type="button" title="' + lang.dialogBox.revertButton + '" aria-label="' + lang.dialogBox.revertButton + '" class="se-btn se-dialog-btn-revert" style="float: right;">' + core.icons.revert + '</button>' +
194
+ '</div>' ;
195
+ }
196
+
197
+ html += '' +
198
+ '<div class="se-dialog-form se-dialog-form-footer">' +
199
+ '<label><input type="checkbox" class="se-dialog-btn-check _se_image_check_caption" />&nbsp;' + lang.dialogBox.caption + '</label>' +
200
+ '</div>' +
201
+ '</div>' +
202
+ '</div>' +
203
+ '<div class="_se_tab_content _se_tab_content_url" style="display: none">' +
204
+ core.context.anchor.forms.innerHTML +
205
+ '</div>' +
206
+ '<div class="se-dialog-footer">' +
207
+ '<div' + (option.imageAlignShow ? '' : ' style="display: none"') + '>' +
208
+ '<label><input type="radio" name="suneditor_image_radio" class="se-dialog-btn-radio" value="none" checked>' + lang.dialogBox.basic + '</label>' +
209
+ '<label><input type="radio" name="suneditor_image_radio" class="se-dialog-btn-radio" value="left">' + lang.dialogBox.left + '</label>' +
210
+ '<label><input type="radio" name="suneditor_image_radio" class="se-dialog-btn-radio" value="center">' + lang.dialogBox.center + '</label>' +
211
+ '<label><input type="radio" name="suneditor_image_radio" class="se-dialog-btn-radio" value="right">' + lang.dialogBox.right + '</label>' +
212
+ '</div>' +
213
+ '<button type="submit" class="se-btn-primary" title="' + lang.dialogBox.submitButton + '" aria-label="' + lang.dialogBox.submitButton + '"><span>' + lang.dialogBox.submitButton + '</span></button>' +
214
+ '</div>' +
215
+ '</form>';
216
+
217
+ dialog.innerHTML = html;
218
+
219
+ return dialog;
220
+ },
221
+
222
+ _fileInputChange: function () {
223
+ if (!this.imgInputFile.value) {
224
+ this.imgUrlFile.removeAttribute('disabled');
225
+ this.previewSrc.style.textDecoration = '';
226
+ } else {
227
+ this.imgUrlFile.setAttribute('disabled', true);
228
+ this.previewSrc.style.textDecoration = 'line-through';
229
+ }
230
+ },
231
+
232
+ _removeSelectedFiles: function (urlInput, previewSrc) {
233
+ this.value = '';
234
+ if (urlInput) {
235
+ urlInput.removeAttribute('disabled');
236
+ previewSrc.style.textDecoration = '';
237
+ }
238
+ },
239
+
240
+ _openGallery: function () {
241
+ this.callPlugin('imageGallery', this.plugins.imageGallery.open.bind(this, this.plugins.image._setUrlInput.bind(this.context.image)), null);
242
+ },
243
+
244
+ _setUrlInput: function (target) {
245
+ this.altText.value = target.alt;
246
+ this._v_src._linkValue = this.previewSrc.textContent = this.imgUrlFile.value = target.src;
247
+ this.imgUrlFile.focus();
248
+ },
249
+
250
+ _onLinkPreview: function (context, protocol, e) {
251
+ const value = e.target.value.trim();
252
+ context._linkValue = this.textContent = !value ? '' : (protocol && value.indexOf('://') === -1 && value.indexOf('#') !== 0) ? protocol + value : value.indexOf('://') === -1 ? '/' + value : value;
253
+ },
254
+
255
+ /**
256
+ * @Override @Required fileManager
257
+ */
258
+ fileTags: ['img'],
259
+
260
+ /**
261
+ * @Override core, fileManager, resizing
262
+ * @description It is called from core.selectComponent.
263
+ * @param {Element} element Target element
264
+ */
265
+ select: function (element) {
266
+ this.plugins.image.onModifyMode.call(this, element, this.plugins.resizing.call_controller_resize.call(this, element, 'image'));
267
+ },
268
+
269
+ /**
270
+ * @Override fileManager, resizing
271
+ */
272
+ destroy: function (element) {
273
+ const imageEl = element || this.context.image._element;
274
+ const imageContainer = this.util.getParentElement(imageEl, this.util.isMediaComponent) || imageEl;
275
+ const dataIndex = imageEl.getAttribute('data-index') * 1;
276
+ let focusEl = (imageContainer.previousElementSibling || imageContainer.nextElementSibling);
277
+
278
+ const emptyDiv = imageContainer.parentNode;
279
+ this.util.removeItem(imageContainer);
280
+ this.plugins.image.init.call(this);
281
+ this.controllersOff();
282
+
283
+ if (emptyDiv !== this.context.element.wysiwyg) this.util.removeItemAllParents(emptyDiv, function (current) { return current.childNodes.length === 0; }, null);
284
+
285
+ // focus
286
+ this.focusEdge(focusEl);
287
+
288
+ // event
289
+ this.plugins.fileManager.deleteInfo.call(this, 'image', dataIndex, this.functions.onImageUpload);
290
+
291
+ // history stack
292
+ this.history.push(false);
293
+ },
294
+
295
+ /**
296
+ * @Required @Override dialog
297
+ */
298
+ on: function (update) {
299
+ const contextImage = this.context.image;
300
+
301
+ if (!update) {
302
+ contextImage.inputX.value = contextImage._origin_w = this.options.imageWidth === contextImage._defaultSizeX ? '' : this.options.imageWidth;
303
+ contextImage.inputY.value = contextImage._origin_h = this.options.imageHeight === contextImage._defaultSizeY ? '' : this.options.imageHeight;
304
+ if (contextImage.imgInputFile && this.options.imageMultipleFile) contextImage.imgInputFile.setAttribute('multiple', 'multiple');
305
+ } else {
306
+ if (contextImage.imgInputFile && this.options.imageMultipleFile) contextImage.imgInputFile.removeAttribute('multiple');
307
+ }
308
+ this.plugins.anchor.on.call(this, contextImage.anchorCtx, update);
309
+ },
310
+
311
+ /**
312
+ * @Required @Override dialog
313
+ */
314
+ open: function () {
315
+ this.plugins.dialog.open.call(this, 'image', 'image' === this.currentControllerName);
316
+ },
317
+
318
+ openTab: function (e) {
319
+ const modal = this.context.image.modal;
320
+ const targetElement = (e === 'init' ? modal.querySelector('._se_tab_link') : e.target);
321
+
322
+ if (!/^BUTTON$/i.test(targetElement.tagName)) {
323
+ return false;
324
+ }
325
+
326
+ // Declare all variables
327
+ const tabName = targetElement.getAttribute('data-tab-link');
328
+ const contentClassName = '_se_tab_content';
329
+ let i, tabContent, tabLinks;
330
+
331
+ // Get all elements with class="tabcontent" and hide them
332
+ tabContent = modal.getElementsByClassName(contentClassName);
333
+ for (i = 0; i < tabContent.length; i++) {
334
+ tabContent[i].style.display = 'none';
335
+ }
336
+
337
+ // Get all elements with class="tablinks" and remove the class "active"
338
+ tabLinks = modal.getElementsByClassName('_se_tab_link');
339
+ for (i = 0; i < tabLinks.length; i++) {
340
+ this.util.removeClass(tabLinks[i], 'active');
341
+ }
342
+
343
+ // Show the current tab, and add an "active" class to the button that opened the tab
344
+ modal.querySelector('.' + contentClassName + '_' + tabName).style.display = 'block';
345
+ this.util.addClass(targetElement, 'active');
346
+
347
+ // focus
348
+ if (tabName === 'image' && this.context.image.focusElement) {
349
+ this.context.image.focusElement.focus();
350
+ } else if (tabName === 'url') {
351
+ this.context.anchor.caller.image.urlInput.focus();
352
+ }
353
+
354
+ return false;
355
+ },
356
+
357
+ submit: function (e) {
358
+ const contextImage = this.context.image;
359
+ const imagePlugin = this.plugins.image;
360
+
361
+ e.preventDefault();
362
+ e.stopPropagation();
363
+
364
+ contextImage._altText = contextImage.altText.value;
365
+ contextImage._align = contextImage.modal.querySelector('input[name="suneditor_image_radio"]:checked').value;
366
+ contextImage._captionChecked = contextImage.captionCheckEl.checked;
367
+ if (contextImage._resizing) contextImage._proportionChecked = contextImage.proportion.checked;
368
+
369
+ try {
370
+ if (this.context.dialog.updateModal) {
371
+ imagePlugin.update_image.call(this, false, true, false);
372
+ }
373
+
374
+ if (contextImage.imgInputFile && contextImage.imgInputFile.files.length > 0) {
375
+ this.showLoading();
376
+ imagePlugin.submitAction.call(this, this.context.image.imgInputFile.files);
377
+ } else if (contextImage.imgUrlFile && contextImage._v_src._linkValue.length > 0) {
378
+ this.showLoading();
379
+ imagePlugin.onRender_imgUrl.call(this, contextImage._v_src._linkValue);
380
+ }
381
+ } catch (error) {
382
+ this.closeLoading();
383
+ throw Error('[SUNEDITOR.image.submit.fail] cause : "' + error.message + '"');
384
+ } finally {
385
+ this.plugins.dialog.close.call(this);
386
+ }
387
+
388
+ return false;
389
+ },
390
+
391
+ submitAction: function (fileList) {
392
+ if (fileList.length === 0) return;
393
+
394
+ let fileSize = 0;
395
+ let files = [];
396
+ for (let i = 0, len = fileList.length; i < len; i++) {
397
+ if (/image/i.test(fileList[i].type)) {
398
+ files.push(fileList[i]);
399
+ fileSize += fileList[i].size;
400
+ }
401
+ }
402
+
403
+ const limitSize = this.options.imageUploadSizeLimit;
404
+ if (limitSize > 0) {
405
+ let infoSize = 0;
406
+ const imagesInfo = this.context.image._infoList;
407
+ for (let i = 0, len = imagesInfo.length; i < len; i++) {
408
+ infoSize += imagesInfo[i].size * 1;
409
+ }
410
+
411
+ if ((fileSize + infoSize) > limitSize) {
412
+ this.closeLoading();
413
+ const err = '[SUNEDITOR.imageUpload.fail] Size of uploadable total images: ' + (limitSize/1000) + 'KB';
414
+ if (typeof this.functions.onImageUploadError !== 'function' || this.functions.onImageUploadError(err, { 'limitSize': limitSize, 'currentSize': infoSize, 'uploadSize': fileSize }, this)) {
415
+ this.functions.noticeOpen(err);
416
+ }
417
+ return;
418
+ }
419
+ }
420
+
421
+ const contextImage = this.context.image;
422
+ contextImage._uploadFileLength = files.length;
423
+
424
+ const anchor = this.plugins.anchor.createAnchor.call(this, contextImage.anchorCtx, true);
425
+ const info = {
426
+ anchor: anchor,
427
+ inputWidth: contextImage.inputX.value,
428
+ inputHeight: contextImage.inputY.value,
429
+ align: contextImage._align,
430
+ isUpdate: this.context.dialog.updateModal,
431
+ alt: contextImage._altText,
432
+ element: contextImage._element
433
+ };
434
+
435
+ if (typeof this.functions.onImageUploadBefore === 'function') {
436
+ const result = this.functions.onImageUploadBefore(files, info, this, function (data) {
437
+ if (data && this._w.Array.isArray(data.result)) {
438
+ this.plugins.image.register.call(this, info, data);
439
+ } else {
440
+ this.plugins.image.upload.call(this, info, data);
441
+ }
442
+ }.bind(this));
443
+
444
+ if (typeof result === 'undefined') return;
445
+ if (!result) {
446
+ this.closeLoading();
447
+ return;
448
+ }
449
+ if (this._w.Array.isArray(result) && result.length > 0) files = result;
450
+ }
451
+
452
+ this.plugins.image.upload.call(this, info, files);
453
+ },
454
+
455
+ error: function (message, response) {
456
+ this.closeLoading();
457
+ if (typeof this.functions.onImageUploadError !== 'function' || this.functions.onImageUploadError(message, response, this)) {
458
+ this.functions.noticeOpen(message);
459
+ throw Error('[SUNEDITOR.plugin.image.error] response: ' + message);
460
+ }
461
+ },
462
+
463
+ upload: function (info, files) {
464
+ if (!files) {
465
+ this.closeLoading();
466
+ return;
467
+ }
468
+ if (typeof files === 'string') {
469
+ this.plugins.image.error.call(this, files, null);
470
+ return;
471
+ }
472
+
473
+ const imageUploadUrl = this.options.imageUploadUrl;
474
+ const filesLen = this.context.dialog.updateModal ? 1 : files.length;
475
+
476
+ // server upload
477
+ if (typeof imageUploadUrl === 'string' && imageUploadUrl.length > 0) {
478
+ const formData = new FormData();
479
+ for (let i = 0; i < filesLen; i++) {
480
+ formData.append('file-' + i, files[i]);
481
+ }
482
+ this.plugins.fileManager.upload.call(this, imageUploadUrl, this.options.imageUploadHeader, formData, this.plugins.image.callBack_imgUpload.bind(this, info), this.functions.onImageUploadError);
483
+ } else { // base64
484
+ this.plugins.image.setup_reader.call(this, files, info.anchor, info.inputWidth, info.inputHeight, info.align, info.alt, filesLen, info.isUpdate);
485
+ }
486
+ },
487
+
488
+ callBack_imgUpload: function (info, xmlHttp) {
489
+ if (typeof this.functions.imageUploadHandler === 'function') {
490
+ this.functions.imageUploadHandler(xmlHttp, info, this);
491
+ } else {
492
+ const response = JSON.parse(xmlHttp.responseText);
493
+ if (response.errorMessage) {
494
+ this.plugins.image.error.call(this, response.errorMessage, response);
495
+ } else {
496
+ this.plugins.image.register.call(this, info, response);
497
+ }
498
+ }
499
+ },
500
+
501
+ register: function (info, response) {
502
+ const fileList = response.result;
503
+
504
+ for (let i = 0, len = fileList.length, file; i < len; i++) {
505
+ file = { name: fileList[i].name, size: fileList[i].size };
506
+ if (info.isUpdate) {
507
+ this.plugins.image.update_src.call(this, fileList[i].url, info.element, file);
508
+ break;
509
+ } else {
510
+ this.plugins.image.create_image.call(this, fileList[i].url, info.anchor, info.inputWidth, info.inputHeight, info.align, file, info.alt);
511
+ }
512
+ }
513
+
514
+ this.closeLoading();
515
+ },
516
+
517
+ setup_reader: function (files, anchor, width, height, align, alt, filesLen, isUpdate) {
518
+ try {
519
+ this.context.image.base64RenderIndex = filesLen;
520
+ const wFileReader = this._w.FileReader;
521
+ const filesStack = [filesLen];
522
+ this.context.image.inputX.value = width;
523
+ this.context.image.inputY.value = height;
524
+
525
+ for (let i = 0, reader, file; i < filesLen; i++) {
526
+ reader = new wFileReader();
527
+ file = files[i];
528
+
529
+ reader.onload = function (reader, update, updateElement, file, index) {
530
+ filesStack[index] = { result: reader.result, file: file };
531
+
532
+ if (--this.context.image.base64RenderIndex === 0) {
533
+ this.plugins.image.onRender_imgBase64.call(this, update, filesStack, updateElement, anchor, width, height, align, alt);
534
+ this.closeLoading();
535
+ }
536
+ }.bind(this, reader, isUpdate, this.context.image._element, file, i);
537
+
538
+ reader.readAsDataURL(file);
539
+ }
540
+ } catch (e) {
541
+ this.closeLoading();
542
+ throw Error('[SUNEDITOR.image.setup_reader.fail] cause : "' + e.message + '"');
543
+ }
544
+ },
545
+
546
+ onRender_imgBase64: function (update, filesStack, updateElement, anchor, width, height, align, alt) {
547
+ const updateMethod = this.plugins.image.update_src;
548
+ const createMethod = this.plugins.image.create_image;
549
+
550
+ for (let i = 0, len = filesStack.length; i < len; i++) {
551
+ if (update) {
552
+ this.context.image._element.setAttribute('data-file-name', filesStack[i].file.name);
553
+ this.context.image._element.setAttribute('data-file-size', filesStack[i].file.size);
554
+ updateMethod.call(this, filesStack[i].result, updateElement, filesStack[i].file);
555
+ } else {
556
+ createMethod.call(this, filesStack[i].result, anchor, width, height, align, filesStack[i].file, alt);
557
+ }
558
+ }
559
+ },
560
+
561
+ onRender_imgUrl: function (url) {
562
+ if (!url) url = this.context.image._v_src._linkValue;
563
+ if (!url) return false;
564
+ const contextImage = this.context.image;
565
+
566
+ try {
567
+ const file = {name: url.split('/').pop(), size: 0};
568
+ if (this.context.dialog.updateModal) this.plugins.image.update_src.call(this, url, contextImage._element, file);
569
+ else this.plugins.image.create_image.call(this, url, this.plugins.anchor.createAnchor.call(this, contextImage.anchorCtx, true), contextImage.inputX.value, contextImage.inputY.value, contextImage._align, file, contextImage._altText);
570
+ } catch (e) {
571
+ throw Error('[SUNEDITOR.image.URLRendering.fail] cause : "' + e.message + '"');
572
+ } finally {
573
+ this.closeLoading();
574
+ }
575
+ },
576
+
577
+ onRender_link: function (imgTag, anchor) {
578
+ if (anchor) {
579
+ anchor.setAttribute('data-image-link', 'image');
580
+ imgTag.setAttribute('data-image-link', anchor.href);
581
+ anchor.appendChild(imgTag);
582
+ return anchor;
583
+ }
584
+
585
+ return imgTag;
586
+ },
587
+
588
+ /**
589
+ * @Override resizing
590
+ * @param {String} xy 'x': width, 'y': height
591
+ * @param {KeyboardEvent} e Event object
592
+ */
593
+ setInputSize: function (xy, e) {
594
+ if (e && e.keyCode === 32) {
595
+ e.preventDefault();
596
+ return;
597
+ }
598
+
599
+ this.plugins.resizing._module_setInputSize.call(this, this.context.image, xy);
600
+ },
601
+
602
+ /**
603
+ * @Override resizing
604
+ */
605
+ setRatio: function () {
606
+ this.plugins.resizing._module_setRatio.call(this, this.context.image);
607
+ },
608
+
609
+ /**
610
+ * @Override fileManager
611
+ */
612
+ checkFileInfo: function () {
613
+ const imagePlugin = this.plugins.image;
614
+ const contextImage = this.context.image;
615
+
616
+ const modifyHandler = function (tag) {
617
+ imagePlugin.onModifyMode.call(this, tag, null);
618
+ imagePlugin.openModify.call(this, true);
619
+ // get size
620
+ contextImage.inputX.value = contextImage._origin_w;
621
+ contextImage.inputY.value = contextImage._origin_h;
622
+ // get align
623
+ const format = this.util.getFormatElement(tag);
624
+ if (format) contextImage._align = format.style.textAlign || format.style.float;
625
+ // link
626
+ if (this.util.isAnchor(tag.parentNode) && !contextImage.anchorCtx.linkValue) contextImage.anchorCtx.linkValue = ' ';
627
+
628
+ imagePlugin.update_image.call(this, true, false, true);
629
+ imagePlugin.init.call(this);
630
+ }.bind(this);
631
+
632
+ this.plugins.fileManager.checkInfo.call(this, 'image', ['img'], this.functions.onImageUpload, modifyHandler, true);
633
+ },
634
+
635
+ /**
636
+ * @Override fileManager
637
+ */
638
+ resetFileInfo: function () {
639
+ this.plugins.fileManager.resetInfo.call(this, 'image', this.functions.onImageUpload);
640
+ },
641
+
642
+ create_image: function (src, anchor, width, height, align, file, alt) {
643
+ const imagePlugin = this.plugins.image;
644
+ const contextImage = this.context.image;
645
+ this.context.resizing._resize_plugin = 'image';
646
+
647
+ let oImg = this.util.createElement('IMG');
648
+ oImg.src = src;
649
+ oImg.alt = alt;
650
+ oImg.setAttribute('data-rotate', '0');
651
+ anchor = imagePlugin.onRender_link.call(this, oImg, anchor ? anchor.cloneNode(false) : null);
652
+
653
+ if (contextImage._resizing) {
654
+ oImg.setAttribute('data-proportion', contextImage._proportionChecked);
655
+ }
656
+
657
+ const cover = this.plugins.component.set_cover.call(this, anchor);
658
+ const container = this.plugins.component.set_container.call(this, cover, 'se-image-container');
659
+
660
+ // caption
661
+ if (contextImage._captionChecked) {
662
+ contextImage._caption = this.plugins.component.create_caption.call(this);
663
+ contextImage._caption.setAttribute('contenteditable', false);
664
+ cover.appendChild(contextImage._caption);
665
+ }
666
+
667
+ contextImage._element = oImg;
668
+ contextImage._cover = cover;
669
+ contextImage._container = container;
670
+
671
+ // set size
672
+ imagePlugin.applySize.call(this, width, height);
673
+
674
+ // align
675
+ imagePlugin.setAlign.call(this, align, oImg, cover, container);
676
+
677
+ oImg.onload = imagePlugin._image_create_onload.bind(this, oImg, contextImage.svgDefaultSize, container);
678
+ if (this.insertComponent(container, true, true, true)) this.plugins.fileManager.setInfo.call(this, 'image', oImg, this.functions.onImageUpload, file, true);
679
+ this.context.resizing._resize_plugin = '';
680
+ },
681
+
682
+ _image_create_onload: function (oImg, svgDefaultSize, container) {
683
+ // svg exception handling
684
+ if (oImg.offsetWidth === 0) this.plugins.image.applySize.call(this, svgDefaultSize, '');
685
+ if (this.options.mediaAutoSelect) {
686
+ this.selectComponent(oImg, 'image');
687
+ } else {
688
+ const line = this.appendFormatTag(container, null);
689
+ if (line) this.setRange(line, 0, line, 0);
690
+ }
691
+ },
692
+
693
+ update_image: function (init, openController, notHistoryPush) {
694
+ const contextImage = this.context.image;
695
+ let imageEl = contextImage._element;
696
+ let cover = contextImage._cover;
697
+ let container = contextImage._container;
698
+ let isNewContainer = false;
699
+
700
+ if (cover === null) {
701
+ isNewContainer = true;
702
+ imageEl = contextImage._element.cloneNode(true);
703
+ cover = this.plugins.component.set_cover.call(this, imageEl);
704
+ }
705
+
706
+ if (container === null) {
707
+ cover = cover.cloneNode(true);
708
+ imageEl = cover.querySelector('img');
709
+ isNewContainer = true;
710
+ container = this.plugins.component.set_container.call(this, cover, 'se-image-container');
711
+ } else if (isNewContainer) {
712
+ container.innerHTML = '';
713
+ container.appendChild(cover);
714
+ contextImage._cover = cover;
715
+ contextImage._element = imageEl;
716
+ isNewContainer = false;
717
+ }
718
+
719
+ // check size
720
+ let changeSize;
721
+ const x = this.util.isNumber(contextImage.inputX.value) ? contextImage.inputX.value + contextImage.sizeUnit : contextImage.inputX.value;
722
+ const y = this.util.isNumber(contextImage.inputY.value) ? contextImage.inputY.value + contextImage.sizeUnit : contextImage.inputY.value;
723
+ if (/%$/.test(imageEl.style.width)) {
724
+ changeSize = x !== container.style.width || y !== container.style.height;
725
+ } else {
726
+ changeSize = x !== imageEl.style.width || y !== imageEl.style.height;
727
+ }
728
+
729
+ // alt
730
+ imageEl.alt = contextImage._altText;
731
+
732
+ // caption
733
+ let modifiedCaption = false;
734
+ if (contextImage._captionChecked) {
735
+ if (!contextImage._caption) {
736
+ contextImage._caption = this.plugins.component.create_caption.call(this);
737
+ cover.appendChild(contextImage._caption);
738
+ modifiedCaption = true;
739
+ }
740
+ } else {
741
+ if (contextImage._caption) {
742
+ this.util.removeItem(contextImage._caption);
743
+ contextImage._caption = null;
744
+ modifiedCaption = true;
745
+ }
746
+ }
747
+
748
+ // link
749
+ let isNewAnchor = null;
750
+ const anchor = this.plugins.anchor.createAnchor.call(this, contextImage.anchorCtx, true);
751
+ if (anchor) {
752
+ if (contextImage._linkElement !== anchor || (isNewContainer && !container.contains(anchor))) {
753
+ contextImage._linkElement = anchor.cloneNode(false);
754
+ cover.insertBefore(this.plugins.image.onRender_link.call(this, imageEl, contextImage._linkElement), contextImage._caption);
755
+ isNewAnchor = contextImage._element;
756
+ } else {
757
+ contextImage._linkElement.setAttribute('data-image-link', 'image');
758
+ }
759
+ } else if (contextImage._linkElement !== null) {
760
+ const imageElement = imageEl;
761
+ imageElement.setAttribute('data-image-link', '');
762
+ if (cover.contains(contextImage._linkElement)) {
763
+ const newEl = imageElement.cloneNode(true);
764
+ cover.removeChild(contextImage._linkElement);
765
+ cover.insertBefore(newEl, contextImage._caption);
766
+ contextImage._element = imageEl = newEl;
767
+ }
768
+ }
769
+
770
+ let existElement = null;
771
+ if (isNewContainer) {
772
+ existElement = (this.util.isRangeFormatElement(contextImage._element.parentNode) || this.util.isWysiwygDiv(contextImage._element.parentNode)) ?
773
+ contextImage._element :
774
+ this.util.isAnchor(contextImage._element.parentNode) ? contextImage._element.parentNode : this.util.getFormatElement(contextImage._element) || contextImage._element;
775
+
776
+ if (this.util.getParentElement(contextImage._element, this.util.isNotCheckingNode)) {
777
+ existElement = isNewAnchor ? anchor : contextImage._element;
778
+ existElement.parentNode.replaceChild(container, existElement);
779
+ } else if (this.util.isListCell(existElement)) {
780
+ const refer = this.util.getParentElement(contextImage._element, function (current) { return current.parentNode === existElement; });
781
+ existElement.insertBefore(container, refer);
782
+ this.util.removeItem(contextImage._element);
783
+ this.util.removeEmptyNode(refer, null, true);
784
+ } else if (this.util.isFormatElement(existElement)) {
785
+ const refer = this.util.getParentElement(contextImage._element, function (current) { return current.parentNode === existElement; });
786
+ existElement = this.util.splitElement(existElement, refer);
787
+ existElement.parentNode.insertBefore(container, existElement);
788
+ this.util.removeItem(contextImage._element);
789
+ this.util.removeEmptyNode(existElement, null, true);
790
+ if (existElement.children.length === 0) existElement.innerHTML = this.util.htmlRemoveWhiteSpace(existElement.innerHTML);
791
+ } else {
792
+ if (this.util.isFormatElement(existElement.parentNode)) {
793
+ const formats = existElement.parentNode;
794
+ formats.parentNode.insertBefore(container, existElement.previousSibling ? formats.nextElementSibling : formats);
795
+ if (contextImage.__updateTags.map(function (current) { return existElement.contains(current); }).length === 0) this.util.removeItem(existElement);
796
+ } else {
797
+ existElement.parentNode.replaceChild(container, existElement);
798
+ }
799
+ }
800
+
801
+ imageEl = container.querySelector('img');
802
+
803
+ contextImage._element = imageEl;
804
+ contextImage._cover = cover;
805
+ contextImage._container = container;
806
+ }
807
+
808
+ if (isNewAnchor) {
809
+ if (!isNewContainer) {
810
+ this.util.removeItem(anchor);
811
+ } else {
812
+ this.util.removeItem(isNewAnchor);
813
+ if (this.util.getListChildren(anchor, function (current) { return /IMG/i.test(current.tagName); }).length === 0) {
814
+ this.util.removeItem(anchor);
815
+ }
816
+ }
817
+ }
818
+
819
+ // transform
820
+ if (modifiedCaption || (!contextImage._onlyPercentage && changeSize)) {
821
+ if (!init && (/\d+/.test(imageEl.style.height) || (this.context.resizing._rotateVertical && contextImage._captionChecked))) {
822
+ if (/%$/.test(contextImage.inputX.value) || /%$/.test(contextImage.inputY.value)) {
823
+ this.plugins.resizing.resetTransform.call(this, imageEl);
824
+ } else {
825
+ this.plugins.resizing.setTransformSize.call(this, imageEl, this.util.getNumber(contextImage.inputX.value, 0), this.util.getNumber(contextImage.inputY.value, 0));
826
+ }
827
+ }
828
+ }
829
+
830
+ // size
831
+ if (contextImage._resizing) {
832
+ imageEl.setAttribute('data-proportion', contextImage._proportionChecked);
833
+ if (changeSize) {
834
+ this.plugins.image.applySize.call(this);
835
+ }
836
+ }
837
+
838
+ // align
839
+ this.plugins.image.setAlign.call(this, null, imageEl, null, null);
840
+
841
+ // set imagesInfo
842
+ if (init) {
843
+ this.plugins.fileManager.setInfo.call(this, 'image', imageEl, this.functions.onImageUpload, null, true);
844
+ }
845
+
846
+ if (openController) {
847
+ this.selectComponent(imageEl, 'image');
848
+ }
849
+
850
+ // history stack
851
+ if (!notHistoryPush) this.history.push(false);
852
+ },
853
+
854
+ update_src: function (src, element, file) {
855
+ element.src = src;
856
+ this._w.setTimeout(this.plugins.fileManager.setInfo.bind(this, 'image', element, this.functions.onImageUpload, file, true));
857
+ this.selectComponent(element, 'image');
858
+ },
859
+
860
+ /**
861
+ * @Required @Override fileManager, resizing
862
+ */
863
+ onModifyMode: function (element, size) {
864
+ if (!element) return;
865
+
866
+ const contextImage = this.context.image;
867
+ contextImage._linkElement = contextImage.anchorCtx.linkAnchor = this.util.isAnchor(element.parentNode) ? element.parentNode : null;
868
+ contextImage._element = element;
869
+ contextImage._cover = this.util.getParentElement(element, 'FIGURE');
870
+ contextImage._container = this.util.getParentElement(element, this.util.isMediaComponent);
871
+ contextImage._caption = this.util.getChildElement(contextImage._cover, 'FIGCAPTION');
872
+ contextImage._align = element.style.float || element.getAttribute('data-align') || 'none';
873
+ element.style.float = '';
874
+ this.plugins.anchor.setCtx(contextImage._linkElement, contextImage.anchorCtx);
875
+
876
+ if (size) {
877
+ contextImage._element_w = size.w;
878
+ contextImage._element_h = size.h;
879
+ contextImage._element_t = size.t;
880
+ contextImage._element_l = size.l;
881
+ }
882
+
883
+ let userSize = contextImage._element.getAttribute('data-size') || contextImage._element.getAttribute('data-origin');
884
+ let w, h;
885
+ if (userSize) {
886
+ userSize = userSize.split(',');
887
+ w = userSize[0];
888
+ h = userSize[1];
889
+ } else if (size) {
890
+ w = size.w;
891
+ h = size.h;
892
+ }
893
+
894
+ contextImage._origin_w = w || element.style.width || element.width || '';
895
+ contextImage._origin_h = h || element.style.height || element.height || '';
896
+ },
897
+
898
+ /**
899
+ * @Required @Override fileManager, resizing
900
+ */
901
+ openModify: function (notOpen) {
902
+ const contextImage = this.context.image;
903
+ if (contextImage.imgUrlFile) {
904
+ contextImage._v_src._linkValue = contextImage.previewSrc.textContent = contextImage.imgUrlFile.value = contextImage._element.src;
905
+ }
906
+ contextImage._altText = contextImage.altText.value = contextImage._element.alt;
907
+ (contextImage.modal.querySelector('input[name="suneditor_image_radio"][value="' + contextImage._align + '"]') || contextImage.modal.querySelector('input[name="suneditor_image_radio"][value="none"]')).checked = true;
908
+ contextImage._align = contextImage.modal.querySelector('input[name="suneditor_image_radio"]:checked').value;
909
+ contextImage._captionChecked = contextImage.captionCheckEl.checked = !!contextImage._caption;
910
+
911
+ if (contextImage._resizing) {
912
+ this.plugins.resizing._module_setModifyInputSize.call(this, contextImage, this.plugins.image);
913
+ }
914
+
915
+ if (!notOpen) this.plugins.dialog.open.call(this, 'image', true);
916
+ },
917
+
918
+ /**
919
+ * @Override fileManager
920
+ */
921
+ applySize: function (w, h) {
922
+ const contextImage = this.context.image;
923
+
924
+ if (!w) w = contextImage.inputX.value || this.options.imageWidth;
925
+ if (!h) h = contextImage.inputY.value || this.options.imageHeight;
926
+
927
+ if ((contextImage._onlyPercentage && !!w) || /%$/.test(w)) {
928
+ this.plugins.image.setPercentSize.call(this, w, h);
929
+ return true;
930
+ } else if ((!w || w === 'auto') && (!h || h === 'auto')) {
931
+ this.plugins.image.setAutoSize.call(this);
932
+ } else {
933
+ this.plugins.image.setSize.call(this, w, h, false);
934
+ }
935
+
936
+ return false;
937
+ },
938
+
939
+ /**
940
+ * @Override resizing
941
+ */
942
+ sizeRevert: function () {
943
+ this.plugins.resizing._module_sizeRevert.call(this, this.context.image);
944
+ },
945
+
946
+ /**
947
+ * @Override resizing
948
+ */
949
+ setSize: function (w, h, notResetPercentage, direction) {
950
+ const contextImage = this.context.image;
951
+ const onlyW = /^(rw|lw)$/.test(direction) && /\d+/.test(contextImage._element.style.height);
952
+ const onlyH = /^(th|bh)$/.test(direction) && /\d+/.test(contextImage._element.style.width);
953
+
954
+ if (!onlyH) {
955
+ contextImage._element.style.width = this.util.isNumber(w) ? w + contextImage.sizeUnit : w;
956
+ this.plugins.image.cancelPercentAttr.call(this);
957
+ }
958
+ if (!onlyW) {
959
+ contextImage._element.style.height = this.util.isNumber(h) ? h + contextImage.sizeUnit : /%$/.test(h) ? '' : h;
960
+ }
961
+
962
+ if (contextImage._align === 'center') this.plugins.image.setAlign.call(this, null, null, null, null);
963
+ if (!notResetPercentage) contextImage._element.removeAttribute('data-percentage');
964
+
965
+ // save current size
966
+ this.plugins.resizing._module_saveCurrentSize.call(this, contextImage);
967
+ },
968
+
969
+ /**
970
+ * @Override resizing
971
+ */
972
+ setAutoSize: function () {
973
+ const contextImage = this.context.image;
974
+
975
+ if (contextImage._caption) contextImage._caption.style.marginTop = '';
976
+ this.plugins.resizing.resetTransform.call(this, contextImage._element);
977
+ this.plugins.image.cancelPercentAttr.call(this);
978
+
979
+ contextImage._element.style.maxWidth = '';
980
+ contextImage._element.style.width = '';
981
+ contextImage._element.style.height = '';
982
+ contextImage._cover.style.width = '';
983
+ contextImage._cover.style.height = '';
984
+
985
+ this.plugins.image.setAlign.call(this, null, null, null, null);
986
+ contextImage._element.setAttribute('data-percentage', 'auto,auto');
987
+
988
+ // save current size
989
+ this.plugins.resizing._module_saveCurrentSize.call(this, contextImage);
990
+ },
991
+
992
+ /**
993
+ * @Override resizing
994
+ */
995
+ setOriginSize: function () {
996
+ const contextImage = this.context.image;
997
+ contextImage._element.removeAttribute('data-percentage');
998
+
999
+ this.plugins.resizing.resetTransform.call(this, contextImage._element);
1000
+ this.plugins.image.cancelPercentAttr.call(this);
1001
+
1002
+ const originSize = (contextImage._element.getAttribute('data-origin') || '').split(',');
1003
+ const w = originSize[0];
1004
+ const h = originSize[1];
1005
+
1006
+ if (originSize) {
1007
+ if (contextImage._onlyPercentage || (/%$/.test(w) && (/%$/.test(h) || !/\d/.test(h)))) {
1008
+ this.plugins.image.setPercentSize.call(this, w, h);
1009
+ } else {
1010
+ this.plugins.image.setSize.call(this, w, h);
1011
+ }
1012
+
1013
+ // save current size
1014
+ this.plugins.resizing._module_saveCurrentSize.call(this, contextImage);
1015
+ }
1016
+ },
1017
+
1018
+ /**
1019
+ * @Override resizing
1020
+ */
1021
+ setPercentSize: function (w, h) {
1022
+ const contextImage = this.context.image;
1023
+ h = !!h && !/%$/.test(h) && !this.util.getNumber(h, 0) ? this.util.isNumber(h) ? h + '%' : h : this.util.isNumber(h) ? h + contextImage.sizeUnit : (h || '');
1024
+ const heightPercentage = /%$/.test(h);
1025
+
1026
+ contextImage._container.style.width = this.util.isNumber(w) ? w + '%' : w;
1027
+ contextImage._container.style.height = '';
1028
+ contextImage._cover.style.width = '100%';
1029
+ contextImage._cover.style.height = !heightPercentage ? '' : h;
1030
+ contextImage._element.style.width = '100%';
1031
+ contextImage._element.style.height = heightPercentage ? '' : h;
1032
+ contextImage._element.style.maxWidth = '';
1033
+
1034
+ if (contextImage._align === 'center') this.plugins.image.setAlign.call(this, null, null, null, null);
1035
+
1036
+ contextImage._element.setAttribute('data-percentage', w + ',' + h);
1037
+ this.plugins.resizing.setCaptionPosition.call(this, contextImage._element);
1038
+
1039
+ // save current size
1040
+ this.plugins.resizing._module_saveCurrentSize.call(this, contextImage);
1041
+ },
1042
+
1043
+ /**
1044
+ * @Override resizing
1045
+ */
1046
+ cancelPercentAttr: function () {
1047
+ const contextImage = this.context.image;
1048
+
1049
+ contextImage._cover.style.width = '';
1050
+ contextImage._cover.style.height = '';
1051
+ contextImage._container.style.width = '';
1052
+ contextImage._container.style.height = '';
1053
+
1054
+ this.util.removeClass(contextImage._container, this.context.image._floatClassRegExp);
1055
+ this.util.addClass(contextImage._container, '__se__float-' + contextImage._align);
1056
+
1057
+ if (contextImage._align === 'center') this.plugins.image.setAlign.call(this, null, null, null, null);
1058
+ },
1059
+
1060
+ /**
1061
+ * @Override resizing
1062
+ */
1063
+ setAlign: function (align, element, cover, container) {
1064
+ const contextImage = this.context.image;
1065
+
1066
+ if (!align) align = contextImage._align;
1067
+ if (!element) element = contextImage._element;
1068
+ if (!cover) cover = contextImage._cover;
1069
+ if (!container) container = contextImage._container;
1070
+
1071
+ if (align && align !== 'none') {
1072
+ cover.style.margin = 'auto';
1073
+ } else {
1074
+ cover.style.margin = '0';
1075
+ }
1076
+
1077
+ if (/%$/.test(element.style.width) && align === 'center') {
1078
+ container.style.minWidth = '100%';
1079
+ cover.style.width = container.style.width;
1080
+ } else {
1081
+ container.style.minWidth = '';
1082
+ cover.style.width = this.context.resizing._rotateVertical ? (element.style.height || element.offsetHeight) : ((!element.style.width || element.style.width === 'auto') ? '' : element.style.width || '100%');
1083
+ }
1084
+
1085
+ if (!this.util.hasClass(container, '__se__float-' + align)) {
1086
+ this.util.removeClass(container, contextImage._floatClassRegExp);
1087
+ this.util.addClass(container, '__se__float-' + align);
1088
+ }
1089
+
1090
+ element.setAttribute('data-align', align);
1091
+ },
1092
+
1093
+ /**
1094
+ * @Override dialog
1095
+ */
1096
+ init: function () {
1097
+ const contextImage = this.context.image;
1098
+ if (contextImage.imgInputFile) contextImage.imgInputFile.value = '';
1099
+ if (contextImage.imgUrlFile) contextImage._v_src._linkValue = contextImage.previewSrc.textContent = contextImage.imgUrlFile.value = '';
1100
+ if (contextImage.imgInputFile && contextImage.imgUrlFile) {
1101
+ contextImage.imgUrlFile.removeAttribute('disabled');
1102
+ contextImage.previewSrc.style.textDecoration = '';
1103
+ }
1104
+
1105
+ contextImage.altText.value = '';
1106
+ contextImage.modal.querySelector('input[name="suneditor_image_radio"][value="none"]').checked = true;
1107
+ contextImage.captionCheckEl.checked = false;
1108
+ contextImage._element = null;
1109
+ this.plugins.image.openTab.call(this, 'init');
1110
+
1111
+ if (contextImage._resizing) {
1112
+ contextImage.inputX.value = this.options.imageWidth === contextImage._defaultSizeX ? '' : this.options.imageWidth;
1113
+ contextImage.inputY.value = this.options.imageHeight === contextImage._defaultSizeY ? '' : this.options.imageHeight;
1114
+ contextImage.proportion.checked = true;
1115
+ contextImage._ratio = false;
1116
+ contextImage._ratioX = 1;
1117
+ contextImage._ratioY = 1;
1118
+ }
1119
+
1120
+ this.plugins.anchor.init.call(this, contextImage.anchorCtx);
1121
+ }
1122
+ };