suneditor 3.0.0-alpha.9 → 3.0.0-beta.2
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.
- package/CONTRIBUTING.md +170 -22
- package/{LICENSE.txt → LICENSE} +9 -9
- package/README.md +168 -30
- package/dist/suneditor.min.css +1 -1
- package/dist/suneditor.min.js +1 -1
- package/package.json +47 -21
- package/src/assets/design/color.css +121 -0
- package/src/assets/design/index.css +3 -0
- package/src/assets/design/size.css +35 -0
- package/src/assets/design/typography.css +37 -0
- package/src/assets/icons/defaultIcons.js +232 -0
- package/src/assets/suneditor-contents.css +181 -46
- package/src/assets/suneditor.css +1403 -650
- package/src/core/base/eventHandlers/handler_toolbar.js +35 -14
- package/src/core/base/eventHandlers/handler_ww_clipboard.js +23 -4
- package/src/core/base/eventHandlers/handler_ww_dragDrop.js +49 -10
- package/src/core/base/eventHandlers/handler_ww_key_input.js +422 -224
- package/src/core/base/eventHandlers/handler_ww_mouse.js +83 -36
- package/src/core/base/eventManager.js +520 -179
- package/src/core/base/history.js +95 -41
- package/src/core/class/char.js +26 -11
- package/src/core/class/component.js +345 -137
- package/src/core/class/format.js +683 -519
- package/src/core/class/html.js +485 -305
- package/src/core/class/menu.js +133 -47
- package/src/core/class/nodeTransform.js +90 -71
- package/src/core/class/offset.js +408 -92
- package/src/core/class/selection.js +216 -106
- package/src/core/class/shortcuts.js +68 -8
- package/src/core/class/toolbar.js +106 -116
- package/src/core/class/ui.js +422 -0
- package/src/core/class/viewer.js +178 -74
- package/src/core/editor.js +496 -389
- package/src/core/section/actives.js +123 -27
- package/src/core/section/constructor.js +615 -206
- package/src/core/section/context.js +28 -23
- package/src/core/section/documentType.js +561 -0
- package/src/editorInjector/_classes.js +19 -5
- package/src/editorInjector/_core.js +71 -7
- package/src/editorInjector/index.js +63 -1
- package/src/events.js +622 -0
- package/src/helper/clipboard.js +59 -0
- package/src/helper/converter.js +202 -26
- package/src/helper/dom/domCheck.js +304 -0
- package/src/helper/dom/domQuery.js +669 -0
- package/src/helper/dom/domUtils.js +557 -0
- package/src/helper/dom/index.js +12 -0
- package/src/helper/env.js +46 -56
- package/src/helper/index.js +10 -4
- package/src/helper/keyCodeMap.js +183 -0
- package/src/helper/numbers.js +12 -8
- package/src/helper/unicode.js +9 -5
- package/src/langs/ckb.js +74 -4
- package/src/langs/cs.js +72 -2
- package/src/langs/da.js +73 -3
- package/src/langs/de.js +73 -4
- package/src/langs/en.js +23 -3
- package/src/langs/es.js +73 -4
- package/src/langs/fa.js +75 -3
- package/src/langs/fr.js +73 -3
- package/src/langs/he.js +73 -4
- package/src/langs/hu.js +230 -0
- package/src/langs/index.js +7 -3
- package/src/langs/it.js +70 -1
- package/src/langs/ja.js +72 -4
- package/src/langs/km.js +230 -0
- package/src/langs/ko.js +22 -2
- package/src/langs/lv.js +74 -5
- package/src/langs/nl.js +73 -4
- package/src/langs/pl.js +73 -4
- package/src/langs/pt_br.js +70 -1
- package/src/langs/ro.js +74 -5
- package/src/langs/ru.js +73 -4
- package/src/langs/se.js +73 -4
- package/src/langs/tr.js +73 -1
- package/src/langs/{ua.js → uk.js} +75 -6
- package/src/langs/ur.js +77 -8
- package/src/langs/zh_cn.js +74 -5
- package/src/modules/ApiManager.js +77 -54
- package/src/modules/Browser.js +667 -0
- package/src/modules/ColorPicker.js +162 -102
- package/src/modules/Controller.js +273 -142
- package/src/modules/Figure.js +925 -484
- package/src/modules/FileManager.js +121 -69
- package/src/modules/HueSlider.js +113 -61
- package/src/modules/Modal.js +291 -122
- package/src/modules/ModalAnchorEditor.js +383 -234
- package/src/modules/SelectMenu.js +270 -168
- package/src/modules/_DragHandle.js +2 -1
- package/src/modules/index.js +3 -3
- package/src/plugins/browser/audioGallery.js +83 -0
- package/src/plugins/browser/fileBrowser.js +103 -0
- package/src/plugins/browser/fileGallery.js +83 -0
- package/src/plugins/browser/imageGallery.js +81 -0
- package/src/plugins/browser/videoGallery.js +103 -0
- package/src/plugins/command/blockquote.js +40 -27
- package/src/plugins/command/exportPDF.js +134 -0
- package/src/plugins/command/fileUpload.js +229 -162
- package/src/plugins/command/list_bulleted.js +83 -47
- package/src/plugins/command/list_numbered.js +83 -47
- package/src/plugins/dropdown/align.js +66 -54
- package/src/plugins/dropdown/backgroundColor.js +63 -49
- package/src/plugins/dropdown/font.js +71 -47
- package/src/plugins/dropdown/fontColor.js +63 -48
- package/src/plugins/dropdown/formatBlock.js +70 -33
- package/src/plugins/dropdown/hr.js +92 -51
- package/src/plugins/dropdown/layout.js +37 -26
- package/src/plugins/dropdown/lineHeight.js +54 -38
- package/src/plugins/dropdown/list.js +60 -45
- package/src/plugins/dropdown/paragraphStyle.js +51 -30
- package/src/plugins/dropdown/table.js +2003 -813
- package/src/plugins/dropdown/template.js +38 -26
- package/src/plugins/dropdown/textStyle.js +43 -31
- package/src/plugins/field/mention.js +147 -86
- package/src/plugins/index.js +32 -6
- package/src/plugins/input/fontSize.js +161 -108
- package/src/plugins/input/pageNavigator.js +70 -0
- package/src/plugins/modal/audio.js +358 -173
- package/src/plugins/modal/drawing.js +531 -0
- package/src/plugins/modal/embed.js +886 -0
- package/src/plugins/modal/image.js +674 -362
- package/src/plugins/modal/link.js +100 -71
- package/src/plugins/modal/math.js +367 -167
- package/src/plugins/modal/video.js +691 -335
- package/src/plugins/popup/anchor.js +222 -0
- package/src/suneditor.js +50 -13
- package/src/themes/dark.css +122 -0
- package/src/typedef.js +130 -0
- package/types/assets/icons/defaultIcons.d.ts +153 -0
- package/types/core/base/eventHandlers/handler_toolbar.d.ts +41 -0
- package/types/core/base/eventHandlers/handler_ww_clipboard.d.ts +40 -0
- package/types/core/base/eventHandlers/handler_ww_dragDrop.d.ts +35 -0
- package/types/core/base/eventHandlers/handler_ww_key_input.d.ts +45 -0
- package/types/core/base/eventHandlers/handler_ww_mouse.d.ts +39 -0
- package/types/core/base/eventManager.d.ts +385 -0
- package/types/core/base/history.d.ts +81 -0
- package/types/core/class/char.d.ts +60 -0
- package/types/core/class/component.d.ts +212 -0
- package/types/core/class/format.d.ts +616 -0
- package/types/core/class/html.d.ts +422 -0
- package/types/core/class/menu.d.ts +126 -0
- package/types/core/class/nodeTransform.d.ts +93 -0
- package/types/core/class/offset.d.ts +522 -0
- package/types/core/class/selection.d.ts +188 -0
- package/types/core/class/shortcuts.d.ts +142 -0
- package/types/core/class/toolbar.d.ts +189 -0
- package/types/core/class/ui.d.ts +164 -0
- package/types/core/class/viewer.d.ts +140 -0
- package/types/core/editor.d.ts +610 -0
- package/types/core/section/actives.d.ts +46 -0
- package/types/core/section/constructor.d.ts +777 -0
- package/types/core/section/context.d.ts +45 -0
- package/types/core/section/documentType.d.ts +178 -0
- package/types/editorInjector/_classes.d.ts +41 -0
- package/types/editorInjector/_core.d.ts +92 -0
- package/types/editorInjector/index.d.ts +71 -0
- package/types/events.d.ts +273 -0
- package/types/helper/clipboard.d.ts +12 -0
- package/types/helper/converter.d.ts +197 -0
- package/types/helper/dom/domCheck.d.ts +189 -0
- package/types/helper/dom/domQuery.d.ts +223 -0
- package/types/helper/dom/domUtils.d.ts +226 -0
- package/types/helper/dom/index.d.ts +9 -0
- package/types/helper/env.d.ts +132 -0
- package/types/helper/index.d.ts +174 -0
- package/types/helper/keyCodeMap.d.ts +110 -0
- package/types/helper/numbers.d.ts +46 -0
- package/types/helper/unicode.d.ts +28 -0
- package/types/index.d.ts +120 -0
- package/{typings/Lang.d.ts → types/langs/_Lang.d.ts} +173 -103
- package/types/langs/ckb.d.ts +3 -0
- package/types/langs/cs.d.ts +3 -0
- package/types/langs/da.d.ts +3 -0
- package/types/langs/de.d.ts +3 -0
- package/types/langs/en.d.ts +3 -0
- package/types/langs/es.d.ts +3 -0
- package/types/langs/fa.d.ts +3 -0
- package/types/langs/fr.d.ts +3 -0
- package/types/langs/he.d.ts +3 -0
- package/types/langs/hu.d.ts +3 -0
- package/types/langs/index.d.ts +54 -0
- package/types/langs/it.d.ts +3 -0
- package/types/langs/ja.d.ts +3 -0
- package/types/langs/km.d.ts +3 -0
- package/types/langs/ko.d.ts +3 -0
- package/types/langs/lv.d.ts +3 -0
- package/types/langs/nl.d.ts +3 -0
- package/types/langs/pl.d.ts +3 -0
- package/types/langs/pt_br.d.ts +3 -0
- package/types/langs/ro.d.ts +3 -0
- package/types/langs/ru.d.ts +3 -0
- package/types/langs/se.d.ts +3 -0
- package/types/langs/tr.d.ts +3 -0
- package/types/langs/uk.d.ts +3 -0
- package/types/langs/ur.d.ts +3 -0
- package/types/langs/zh_cn.d.ts +3 -0
- package/types/modules/ApiManager.d.ts +125 -0
- package/types/modules/Browser.d.ts +326 -0
- package/types/modules/ColorPicker.d.ts +131 -0
- package/types/modules/Controller.d.ts +251 -0
- package/types/modules/Figure.d.ts +517 -0
- package/types/modules/FileManager.d.ts +202 -0
- package/types/modules/HueSlider.d.ts +136 -0
- package/types/modules/Modal.d.ts +111 -0
- package/types/modules/ModalAnchorEditor.d.ts +236 -0
- package/types/modules/SelectMenu.d.ts +194 -0
- package/types/modules/_DragHandle.d.ts +7 -0
- package/types/modules/index.d.ts +26 -0
- package/types/plugins/browser/audioGallery.d.ts +55 -0
- package/types/plugins/browser/fileBrowser.d.ts +64 -0
- package/types/plugins/browser/fileGallery.d.ts +55 -0
- package/types/plugins/browser/imageGallery.d.ts +51 -0
- package/types/plugins/browser/videoGallery.d.ts +57 -0
- package/types/plugins/command/blockquote.d.ts +28 -0
- package/types/plugins/command/exportPDF.d.ts +46 -0
- package/types/plugins/command/fileUpload.d.ts +156 -0
- package/types/plugins/command/list_bulleted.d.ts +46 -0
- package/types/plugins/command/list_numbered.d.ts +46 -0
- package/types/plugins/dropdown/align.d.ts +60 -0
- package/types/plugins/dropdown/backgroundColor.d.ts +63 -0
- package/types/plugins/dropdown/font.d.ts +54 -0
- package/types/plugins/dropdown/fontColor.d.ts +63 -0
- package/types/plugins/dropdown/formatBlock.d.ts +54 -0
- package/types/plugins/dropdown/hr.d.ts +71 -0
- package/types/plugins/dropdown/layout.d.ts +40 -0
- package/types/plugins/dropdown/lineHeight.d.ts +50 -0
- package/types/plugins/dropdown/list.d.ts +39 -0
- package/types/plugins/dropdown/paragraphStyle.d.ts +54 -0
- package/types/plugins/dropdown/table.d.ts +627 -0
- package/types/plugins/dropdown/template.d.ts +40 -0
- package/types/plugins/dropdown/textStyle.d.ts +41 -0
- package/types/plugins/field/mention.d.ts +102 -0
- package/types/plugins/index.d.ts +107 -0
- package/types/plugins/input/fontSize.d.ts +170 -0
- package/types/plugins/input/pageNavigator.d.ts +28 -0
- package/types/plugins/modal/audio.d.ts +269 -0
- package/types/plugins/modal/drawing.d.ts +246 -0
- package/types/plugins/modal/embed.d.ts +387 -0
- package/types/plugins/modal/image.d.ts +451 -0
- package/types/plugins/modal/link.d.ts +128 -0
- package/types/plugins/modal/math.d.ts +193 -0
- package/types/plugins/modal/video.d.ts +485 -0
- package/types/plugins/popup/anchor.d.ts +56 -0
- package/types/suneditor.d.ts +51 -0
- package/types/typedef.d.ts +233 -0
- package/.eslintignore +0 -7
- package/.eslintrc.json +0 -64
- package/src/assets/icons/_default.js +0 -194
- package/src/core/base/events.js +0 -320
- package/src/core/class/notice.js +0 -42
- package/src/helper/domUtils.js +0 -1177
- package/src/modules/FileBrowser.js +0 -271
- package/src/plugins/command/exportPdf.js +0 -168
- package/src/plugins/fileBrowser/imageGallery.js +0 -81
- package/src/themes/test.css +0 -61
- package/typings/CommandPlugin.d.ts +0 -8
- package/typings/DialogPlugin.d.ts +0 -20
- package/typings/FileBrowserPlugin.d.ts +0 -30
- package/typings/Module.d.ts +0 -15
- package/typings/Plugin.d.ts +0 -42
- package/typings/SubmenuPlugin.d.ts +0 -8
- package/typings/_classes.d.ts +0 -17
- package/typings/_colorPicker.d.ts +0 -60
- package/typings/_core.d.ts +0 -55
- package/typings/align.d.ts +0 -5
- package/typings/audio.d.ts +0 -5
- package/typings/backgroundColor.d.ts +0 -5
- package/typings/blockquote.d.ts +0 -5
- package/typings/char.d.ts +0 -39
- package/typings/component.d.ts +0 -38
- package/typings/context.d.ts +0 -39
- package/typings/converter.d.ts +0 -33
- package/typings/dialog.d.ts +0 -28
- package/typings/domUtils.d.ts +0 -361
- package/typings/editor.d.ts +0 -7
- package/typings/editor.ts +0 -542
- package/typings/env.d.ts +0 -70
- package/typings/eventManager.d.ts +0 -37
- package/typings/events.d.ts +0 -262
- package/typings/fileBrowser.d.ts +0 -42
- package/typings/fileManager.d.ts +0 -67
- package/typings/font.d.ts +0 -5
- package/typings/fontColor.d.ts +0 -5
- package/typings/fontSize.d.ts +0 -5
- package/typings/format.d.ts +0 -191
- package/typings/formatBlock.d.ts +0 -5
- package/typings/history.d.ts +0 -48
- package/typings/horizontalRule.d.ts +0 -5
- package/typings/image.d.ts +0 -5
- package/typings/imageGallery.d.ts +0 -5
- package/typings/index.d.ts +0 -21
- package/typings/index.modules.d.ts +0 -11
- package/typings/index.plugins.d.ts +0 -58
- package/typings/lineHeight.d.ts +0 -5
- package/typings/link.d.ts +0 -5
- package/typings/list.d.ts +0 -5
- package/typings/math.d.ts +0 -5
- package/typings/mediaContainer.d.ts +0 -25
- package/typings/mention.d.ts +0 -5
- package/typings/node.d.ts +0 -57
- package/typings/notice.d.ts +0 -16
- package/typings/numbers.d.ts +0 -29
- package/typings/offset.d.ts +0 -24
- package/typings/options.d.ts +0 -589
- package/typings/paragraphStyle.d.ts +0 -5
- package/typings/resizing.d.ts +0 -141
- package/typings/selection.d.ts +0 -94
- package/typings/shortcuts.d.ts +0 -13
- package/typings/suneditor.d.ts +0 -9
- package/typings/table.d.ts +0 -5
- package/typings/template.d.ts +0 -5
- package/typings/textStyle.d.ts +0 -5
- package/typings/toolbar.d.ts +0 -32
- package/typings/unicode.d.ts +0 -25
- package/typings/video.d.ts +0 -5
|
@@ -1,194 +1,253 @@
|
|
|
1
1
|
import EditorInjector from '../../editorInjector';
|
|
2
2
|
import { Modal, Figure, FileManager, ModalAnchorEditor } from '../../modules';
|
|
3
|
-
import {
|
|
4
|
-
import { CreateTooltipInner } from '../../core/section/constructor';
|
|
3
|
+
import { dom, numbers, env, keyCodeMap } from '../../helper';
|
|
5
4
|
const { NO_EVENT } = env;
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
defaultRel: Link.defaultRel,
|
|
55
|
-
noAutoPrefix: Link.noAutoPrefix,
|
|
56
|
-
enableFileUpload: pluginOptions.linkEnableFileUpload
|
|
57
|
-
});
|
|
58
|
-
this.modal = new Modal(this, modalEl);
|
|
59
|
-
this.figure = new Figure(this, figureControls, {
|
|
60
|
-
sizeUnit: sizeUnit
|
|
61
|
-
});
|
|
62
|
-
this.fileManager = new FileManager(this, {
|
|
63
|
-
query: 'img',
|
|
64
|
-
loadHandler: this.events.onImageLoad,
|
|
65
|
-
eventHandler: this.events.onImageAction
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
// members
|
|
69
|
-
this.fileModalWrapper = modalEl.querySelector('.se-flex-input-wrapper');
|
|
70
|
-
this.imgInputFile = modalEl.querySelector('.__se__file_input');
|
|
71
|
-
this.imgUrlFile = modalEl.querySelector('._se_image_url');
|
|
72
|
-
this.focusElement = this.imgInputFile || this.imgUrlFile;
|
|
73
|
-
this.altText = modalEl.querySelector('._se_image_alt');
|
|
74
|
-
this.captionCheckEl = modalEl.querySelector('._se_image_check_caption');
|
|
75
|
-
this.previewSrc = modalEl.querySelector('._se_tab_content_image .se-link-preview');
|
|
76
|
-
this.sizeUnit = sizeUnit;
|
|
77
|
-
this.proportion = {};
|
|
78
|
-
this.inputX = {};
|
|
79
|
-
this.inputY = {};
|
|
80
|
-
this._linkElement = null;
|
|
81
|
-
this._linkValue = '';
|
|
82
|
-
this._align = 'none';
|
|
83
|
-
this._svgDefaultSize = '30%';
|
|
84
|
-
this._base64RenderIndex = 0;
|
|
85
|
-
this._element = null;
|
|
86
|
-
this._cover = null;
|
|
87
|
-
this._container = null;
|
|
88
|
-
this._caption = null;
|
|
89
|
-
this._ratio = {
|
|
90
|
-
w: 1,
|
|
91
|
-
h: 1
|
|
92
|
-
};
|
|
93
|
-
this._origin_w = this.pluginOptions.defaultWidth === 'auto' ? '' : this.pluginOptions.defaultWidth;
|
|
94
|
-
this._origin_h = this.pluginOptions.defaultHeight === 'auto' ? '' : this.pluginOptions.defaultHeight;
|
|
95
|
-
this._resizing = this.pluginOptions.canResize;
|
|
96
|
-
this._onlyPercentage = this.pluginOptions.percentageOnlySize;
|
|
97
|
-
this._nonResizing = !this._resizing || !this.pluginOptions.showHeightInput || this._onlyPercentage;
|
|
98
|
-
|
|
99
|
-
// init
|
|
100
|
-
this.eventManager.addEvent(modalEl.querySelector('.se-modal-tabs'), 'click', this._openTab.bind(this));
|
|
101
|
-
if (this.imgInputFile) this.eventManager.addEvent(modalEl.querySelector('.se-file-remove'), 'click', RemoveSelectedFiles.bind(this));
|
|
102
|
-
if (this.imgUrlFile) this.eventManager.addEvent(this.imgUrlFile, 'input', OnLinkPreview.bind(this));
|
|
103
|
-
if (this.imgInputFile && this.imgUrlFile) this.eventManager.addEvent(this.imgInputFile, 'change', OnfileInputChange.bind(this));
|
|
104
|
-
|
|
105
|
-
const imageGalleryButton = modalEl.querySelector('.__se__gallery');
|
|
106
|
-
if (imageGalleryButton) this.eventManager.addEvent(imageGalleryButton, 'click', OpenGallery.bind(this));
|
|
107
|
-
|
|
108
|
-
if (this._resizing) {
|
|
109
|
-
this.proportion = modalEl.querySelector('._se_image_check_proportion');
|
|
110
|
-
this.inputX = modalEl.querySelector('._se_image_size_x');
|
|
111
|
-
this.inputY = modalEl.querySelector('._se_image_size_y');
|
|
112
|
-
this.inputX.value = this.pluginOptions.defaultWidth;
|
|
113
|
-
this.inputY.value = this.pluginOptions.defaultHeight;
|
|
114
|
-
|
|
115
|
-
const ratioChange = OnChangeRatio.bind(this);
|
|
116
|
-
this.eventManager.addEvent(this.inputX, 'keyup', OnInputSize.bind(this, 'x'));
|
|
117
|
-
this.eventManager.addEvent(this.inputY, 'keyup', OnInputSize.bind(this, 'y'));
|
|
118
|
-
this.eventManager.addEvent(this.inputX, 'change', ratioChange);
|
|
119
|
-
this.eventManager.addEvent(this.inputY, 'change', ratioChange);
|
|
120
|
-
this.eventManager.addEvent(this.proportion, 'change', ratioChange);
|
|
121
|
-
this.eventManager.addEvent(modalEl.querySelector('.se-modal-btn-revert'), 'click', OnClickRevert.bind(this));
|
|
6
|
+
/**
|
|
7
|
+
* @typedef {import('../../events').ImageInfo} ImageInfo_image
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @typedef {import('../../modules/Figure').FigureControls} FigureControls_image
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @typedef {Object} ImagePluginOptions
|
|
16
|
+
* @property {boolean} [canResize=true] - Whether the image element can be resized.
|
|
17
|
+
* @property {boolean} [showHeightInput=true] - Whether to display the height input field.
|
|
18
|
+
* @property {string} [defaultWidth="auto"] - The default width of the image. If a number is provided, "px" will be appended.
|
|
19
|
+
* @property {string} [defaultHeight="auto"] - The default height of the image. If a number is provided, "px" will be appended.
|
|
20
|
+
* @property {boolean} [percentageOnlySize=false] - Whether to allow only percentage-based sizing.
|
|
21
|
+
* @property {boolean} [createFileInput=true] - Whether to create a file input element for image uploads.
|
|
22
|
+
* @property {boolean} [createUrlInput=true] - Whether to create a URL input element for image insertion.
|
|
23
|
+
* @property {string} [uploadUrl] - The URL endpoint for image file uploads.
|
|
24
|
+
* @property {Object<string, string>} [uploadHeaders] - Additional headers to include in the file upload request.
|
|
25
|
+
* @property {number} [uploadSizeLimit] - The total upload size limit in bytes.
|
|
26
|
+
* @property {number} [uploadSingleSizeLimit] - The single file upload size limit in bytes.
|
|
27
|
+
* @property {boolean} [allowMultiple=false] - Whether multiple image uploads are allowed.
|
|
28
|
+
* @property {string} [acceptedFormats="image/*"] - The accepted file formats for image uploads.
|
|
29
|
+
* @property {boolean} [useFormatType=true] - Whether to enable format type selection (block or inline).
|
|
30
|
+
* @property {string} [defaultFormatType="block"] - The default image format type ("block" or "inline").
|
|
31
|
+
* @property {boolean} [keepFormatType=false] - Whether to retain the chosen format type after image insertion.
|
|
32
|
+
* @property {boolean} [linkEnableFileUpload] - Whether to enable file uploads for linked images.
|
|
33
|
+
* @property {FigureControls_image} [controls] - Figure controls.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @class
|
|
38
|
+
* @description Image plugin.
|
|
39
|
+
* - This plugin provides image insertion functionality within the editor, supporting both file upload and URL input.
|
|
40
|
+
*/
|
|
41
|
+
class Image_ extends EditorInjector {
|
|
42
|
+
static key = 'image';
|
|
43
|
+
static type = 'modal';
|
|
44
|
+
static className = '';
|
|
45
|
+
/**
|
|
46
|
+
* @this {Image_}
|
|
47
|
+
* @param {Element} node - The node to check.
|
|
48
|
+
* @returns {Element|null} Returns a node if the node is a valid component.
|
|
49
|
+
*/
|
|
50
|
+
static component(node) {
|
|
51
|
+
const compNode = dom.check.isFigure(node) || (/^span$/i.test(node.nodeName) && dom.utils.hasClass(node, 'se-component')) ? node.firstElementChild : node;
|
|
52
|
+
return /^IMG$/i.test(compNode?.nodeName) ? compNode : dom.check.isAnchor(compNode) && /^IMG$/i.test(compNode?.firstElementChild?.nodeName) ? compNode?.firstElementChild : null;
|
|
122
53
|
}
|
|
123
54
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
55
|
+
/**
|
|
56
|
+
* @constructor
|
|
57
|
+
* @param {__se__EditorCore} editor - The root editor instance
|
|
58
|
+
* @param {ImagePluginOptions} pluginOptions
|
|
59
|
+
*/
|
|
60
|
+
constructor(editor, pluginOptions) {
|
|
61
|
+
// plugin bisic properties
|
|
62
|
+
super(editor);
|
|
63
|
+
this.title = this.lang.image;
|
|
64
|
+
this.icon = 'image';
|
|
65
|
+
|
|
66
|
+
this.pluginOptions = {
|
|
67
|
+
canResize: pluginOptions.canResize === undefined ? true : pluginOptions.canResize,
|
|
68
|
+
showHeightInput: pluginOptions.showHeightInput === undefined ? true : !!pluginOptions.showHeightInput,
|
|
69
|
+
defaultWidth: !pluginOptions.defaultWidth ? 'auto' : numbers.is(pluginOptions.defaultWidth) ? pluginOptions.defaultWidth + 'px' : pluginOptions.defaultWidth,
|
|
70
|
+
defaultHeight: !pluginOptions.defaultHeight ? 'auto' : numbers.is(pluginOptions.defaultHeight) ? pluginOptions.defaultHeight + 'px' : pluginOptions.defaultHeight,
|
|
71
|
+
percentageOnlySize: !!pluginOptions.percentageOnlySize,
|
|
72
|
+
createFileInput: pluginOptions.createFileInput === undefined ? true : pluginOptions.createFileInput,
|
|
73
|
+
createUrlInput: pluginOptions.createUrlInput === undefined || !pluginOptions.createFileInput ? true : pluginOptions.createUrlInput,
|
|
74
|
+
uploadUrl: typeof pluginOptions.uploadUrl === 'string' ? pluginOptions.uploadUrl : null,
|
|
75
|
+
uploadHeaders: pluginOptions.uploadHeaders || null,
|
|
76
|
+
uploadSizeLimit: numbers.get(pluginOptions.uploadSizeLimit, 0),
|
|
77
|
+
uploadSingleSizeLimit: numbers.get(pluginOptions.uploadSingleSizeLimit, 0),
|
|
78
|
+
allowMultiple: !!pluginOptions.allowMultiple,
|
|
79
|
+
acceptedFormats: typeof pluginOptions.acceptedFormats !== 'string' || pluginOptions.acceptedFormats.trim() === '*' ? 'image/*' : pluginOptions.acceptedFormats.trim() || 'image/*',
|
|
80
|
+
useFormatType: pluginOptions.useFormatType ?? true,
|
|
81
|
+
defaultFormatType: ['block', 'inline'].includes(pluginOptions.defaultFormatType) ? pluginOptions.defaultFormatType : 'block',
|
|
82
|
+
keepFormatType: pluginOptions.keepFormatType ?? false
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// create HTML
|
|
86
|
+
const sizeUnit = this.pluginOptions.percentageOnlySize ? '%' : 'px';
|
|
87
|
+
const modalEl = CreateHTML_modal(editor, this.pluginOptions);
|
|
88
|
+
const ctrlAs = this.pluginOptions.useFormatType ? 'as' : '';
|
|
89
|
+
const figureControls =
|
|
90
|
+
pluginOptions.controls || !this.pluginOptions.canResize
|
|
91
|
+
? [[ctrlAs, 'mirror_h', 'mirror_v', 'align', 'caption', 'edit', 'revert', 'copy', 'remove']]
|
|
92
|
+
: [
|
|
93
|
+
[ctrlAs, 'resize_auto,100,75,50', 'rotate_l', 'rotate_r', 'mirror_h', 'mirror_v'],
|
|
94
|
+
['align', 'caption', 'edit', 'revert', 'copy', 'remove']
|
|
95
|
+
];
|
|
96
|
+
|
|
97
|
+
// show align
|
|
98
|
+
this.alignForm = modalEl.alignForm;
|
|
99
|
+
if (!figureControls.some((subArray) => subArray.includes('align'))) this.alignForm.style.display = 'none';
|
|
100
|
+
|
|
101
|
+
// modules
|
|
102
|
+
const Link = this.plugins.link ? this.plugins.link.pluginOptions : {};
|
|
103
|
+
this.anchor = new ModalAnchorEditor(this, modalEl.html, {
|
|
104
|
+
textToDisplay: false,
|
|
105
|
+
title: true,
|
|
106
|
+
openNewWindow: Link.openNewWindow,
|
|
107
|
+
relList: Link.relList,
|
|
108
|
+
defaultRel: Link.defaultRel,
|
|
109
|
+
noAutoPrefix: Link.noAutoPrefix,
|
|
110
|
+
enableFileUpload: pluginOptions.linkEnableFileUpload
|
|
111
|
+
});
|
|
112
|
+
this.modal = new Modal(this, modalEl.html);
|
|
113
|
+
this.figure = new Figure(this, figureControls, {
|
|
114
|
+
sizeUnit: sizeUnit
|
|
115
|
+
});
|
|
116
|
+
this.fileManager = new FileManager(this, {
|
|
117
|
+
query: 'img',
|
|
118
|
+
loadHandler: this.events.onImageLoad,
|
|
119
|
+
eventHandler: this.events.onImageAction
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// members
|
|
123
|
+
this.fileModalWrapper = modalEl.fileModalWrapper;
|
|
124
|
+
this.imgInputFile = modalEl.imgInputFile;
|
|
125
|
+
this.imgUrlFile = modalEl.imgUrlFile;
|
|
126
|
+
this.focusElement = this.imgInputFile || this.imgUrlFile;
|
|
127
|
+
this.altText = modalEl.altText;
|
|
128
|
+
this.captionCheckEl = modalEl.captionCheckEl;
|
|
129
|
+
this.captionEl = this.captionCheckEl?.parentElement;
|
|
130
|
+
this.previewSrc = modalEl.previewSrc;
|
|
131
|
+
this.sizeUnit = sizeUnit;
|
|
132
|
+
this.as = 'block';
|
|
133
|
+
this.proportion = null;
|
|
134
|
+
this.inputX = null;
|
|
135
|
+
this.inputY = null;
|
|
136
|
+
this._linkElement = null;
|
|
137
|
+
this._linkValue = '';
|
|
138
|
+
this._align = 'none';
|
|
139
|
+
this._svgDefaultSize = '30%';
|
|
140
|
+
this._base64RenderIndex = 0;
|
|
141
|
+
this._element = null;
|
|
142
|
+
this._cover = null;
|
|
143
|
+
this._container = null;
|
|
144
|
+
this._caption = null;
|
|
145
|
+
this._ratio = {
|
|
146
|
+
w: 1,
|
|
147
|
+
h: 1
|
|
148
|
+
};
|
|
149
|
+
this._origin_w = this.pluginOptions.defaultWidth === 'auto' ? '' : this.pluginOptions.defaultWidth;
|
|
150
|
+
this._origin_h = this.pluginOptions.defaultHeight === 'auto' ? '' : this.pluginOptions.defaultHeight;
|
|
151
|
+
this._resizing = this.pluginOptions.canResize;
|
|
152
|
+
this._onlyPercentage = this.pluginOptions.percentageOnlySize;
|
|
153
|
+
this._nonResizing = !this._resizing || !this.pluginOptions.showHeightInput || this._onlyPercentage;
|
|
154
|
+
|
|
155
|
+
// init
|
|
156
|
+
this.eventManager.addEvent(modalEl.tabs, 'click', this.#OpenTab.bind(this));
|
|
157
|
+
if (this.imgInputFile) this.eventManager.addEvent(modalEl.fileRemoveBtn, 'click', this.#RemoveSelectedFiles.bind(this));
|
|
158
|
+
if (this.imgUrlFile) this.eventManager.addEvent(this.imgUrlFile, 'input', this.#OnLinkPreview.bind(this));
|
|
159
|
+
if (this.imgInputFile && this.imgUrlFile) this.eventManager.addEvent(this.imgInputFile, 'change', this.#OnfileInputChange.bind(this));
|
|
160
|
+
|
|
161
|
+
const galleryButton = modalEl.galleryButton;
|
|
162
|
+
if (galleryButton) this.eventManager.addEvent(galleryButton, 'click', this.#OpenGallery.bind(this));
|
|
163
|
+
|
|
164
|
+
if (this._resizing) {
|
|
165
|
+
this.proportion = modalEl.proportion;
|
|
166
|
+
this.inputX = modalEl.inputX;
|
|
167
|
+
this.inputY = modalEl.inputY;
|
|
168
|
+
this.inputX.value = this.pluginOptions.defaultWidth;
|
|
169
|
+
this.inputY.value = this.pluginOptions.defaultHeight;
|
|
170
|
+
|
|
171
|
+
const ratioChange = this.#OnChangeRatio.bind(this);
|
|
172
|
+
this.eventManager.addEvent(this.inputX, 'keyup', this.#OnInputSize.bind(this, 'x'));
|
|
173
|
+
this.eventManager.addEvent(this.inputY, 'keyup', this.#OnInputSize.bind(this, 'y'));
|
|
174
|
+
this.eventManager.addEvent(this.inputX, 'change', ratioChange);
|
|
175
|
+
this.eventManager.addEvent(this.inputY, 'change', ratioChange);
|
|
176
|
+
this.eventManager.addEvent(this.proportion, 'change', ratioChange);
|
|
177
|
+
this.eventManager.addEvent(modalEl.revertBtn, 'click', this.#OnClickRevert.bind(this));
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (this.pluginOptions.useFormatType) {
|
|
181
|
+
this.as = this.pluginOptions.defaultFormatType;
|
|
182
|
+
this.asBlock = modalEl.asBlock;
|
|
183
|
+
this.asInline = modalEl.asInline;
|
|
184
|
+
this.eventManager.addEvent([this.asBlock, this.asInline], 'click', this.#OnClickAsButton.bind(this));
|
|
185
|
+
}
|
|
129
186
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
Image_.key = 'image';
|
|
133
|
-
Image_.type = 'modal';
|
|
134
|
-
Image_.component = function (node) {
|
|
135
|
-
node = domUtils.isFigure(node) ? node.firstElementChild : node;
|
|
136
|
-
return /^IMG$/i.test(node?.nodeName) ? node : domUtils.isAnchor(node) && /^IMG$/i.test(node?.firstElementChild?.nodeName) ? node?.firstElementChild : null;
|
|
137
|
-
};
|
|
138
|
-
Image_.className = '';
|
|
139
|
-
Image_.prototype = {
|
|
187
|
+
|
|
140
188
|
/**
|
|
141
|
-
* @
|
|
189
|
+
* @editorMethod Modules.Modal
|
|
190
|
+
* @description Executes the method that is called when a "Modal" module's is opened.
|
|
142
191
|
*/
|
|
143
192
|
open() {
|
|
144
193
|
this.modal.open();
|
|
145
|
-
}
|
|
194
|
+
}
|
|
146
195
|
|
|
147
196
|
/**
|
|
148
|
-
* @
|
|
197
|
+
* @editorMethod Modules.Controller(Figure)
|
|
198
|
+
* @description Executes the method that is called when a target component is edited.
|
|
149
199
|
*/
|
|
150
200
|
edit() {
|
|
151
201
|
this.modal.open();
|
|
152
|
-
}
|
|
202
|
+
}
|
|
153
203
|
|
|
154
204
|
/**
|
|
155
|
-
* @
|
|
156
|
-
* @
|
|
205
|
+
* @editorMethod Modules.Modal
|
|
206
|
+
* @description Executes the method that is called when a plugin's modal is opened.
|
|
207
|
+
* @param {boolean} isUpdate "Indicates whether the modal is for editing an existing component (true) or registering a new one (false)."
|
|
157
208
|
*/
|
|
158
209
|
on(isUpdate) {
|
|
159
210
|
if (!isUpdate) {
|
|
160
|
-
|
|
161
|
-
|
|
211
|
+
if (this._resizing) {
|
|
212
|
+
this.inputX.value = this._origin_w = this.pluginOptions.defaultWidth === 'auto' ? '' : this.pluginOptions.defaultWidth;
|
|
213
|
+
this.inputY.value = this._origin_h = this.pluginOptions.defaultHeight === 'auto' ? '' : this.pluginOptions.defaultHeight;
|
|
214
|
+
}
|
|
162
215
|
if (this.imgInputFile && this.pluginOptions.allowMultiple) this.imgInputFile.setAttribute('multiple', 'multiple');
|
|
163
216
|
} else {
|
|
164
217
|
if (this.imgInputFile && this.pluginOptions.allowMultiple) this.imgInputFile.removeAttribute('multiple');
|
|
165
218
|
}
|
|
166
219
|
|
|
167
220
|
this.anchor.on(isUpdate);
|
|
168
|
-
}
|
|
221
|
+
}
|
|
169
222
|
|
|
170
223
|
/**
|
|
171
|
-
* @
|
|
172
|
-
* @
|
|
224
|
+
* @editorMethod Editor.EventManager
|
|
225
|
+
* @description Executes the event function of "paste" or "drop".
|
|
226
|
+
* @param {Object} params { frameContext, event, file }
|
|
227
|
+
* @param {__se__FrameContext} params.frameContext Frame context
|
|
228
|
+
* @param {ClipboardEvent} params.event Event object
|
|
229
|
+
* @param {File} params.file File object
|
|
230
|
+
* @returns {boolean} - If return false, the file upload will be canceled
|
|
173
231
|
*/
|
|
174
|
-
|
|
232
|
+
onFilePasteAndDrop({ file }) {
|
|
175
233
|
if (!/^image/.test(file.type)) return;
|
|
176
234
|
|
|
177
235
|
this.submitFile([file]);
|
|
178
236
|
this.editor.focus();
|
|
179
237
|
|
|
180
238
|
return false;
|
|
181
|
-
}
|
|
239
|
+
}
|
|
182
240
|
|
|
183
241
|
/**
|
|
184
|
-
* @
|
|
185
|
-
* @
|
|
242
|
+
* @editorMethod Modules.Modal
|
|
243
|
+
* @description This function is called when a form within a modal window is "submit".
|
|
244
|
+
* @returns {Promise<boolean>} Success or failure
|
|
186
245
|
*/
|
|
187
246
|
async modalAction() {
|
|
188
|
-
this._align = this.modal.form.querySelector('input[name="suneditor_image_radio"]:checked').value;
|
|
247
|
+
this._align = /** @type {HTMLInputElement} */ (this.modal.form.querySelector('input[name="suneditor_image_radio"]:checked')).value;
|
|
189
248
|
|
|
190
249
|
if (this.modal.isUpdate) {
|
|
191
|
-
this._update(this.inputX
|
|
250
|
+
this._update(this.inputX?.value, this.inputY?.value);
|
|
192
251
|
this.history.push(false);
|
|
193
252
|
}
|
|
194
253
|
|
|
@@ -199,10 +258,18 @@ Image_.prototype = {
|
|
|
199
258
|
}
|
|
200
259
|
|
|
201
260
|
return false;
|
|
202
|
-
}
|
|
261
|
+
}
|
|
203
262
|
|
|
204
263
|
/**
|
|
205
|
-
* @
|
|
264
|
+
* @editorMethod Editor.core
|
|
265
|
+
* @description This method is used to validate and preserve the format of the component within the editor.
|
|
266
|
+
* - It ensures that the structure and attributes of the element are maintained and secure.
|
|
267
|
+
* - The method checks if the element is already wrapped in a valid container and updates its attributes if necessary.
|
|
268
|
+
* - If the element isn't properly contained, a new container is created to retain the format.
|
|
269
|
+
* @returns {{query: string, method: (element: HTMLImageElement) => void}} The format retention object containing the query and method to process the element.
|
|
270
|
+
* - query: The selector query to identify the relevant elements (in this case, 'audio').
|
|
271
|
+
* - method:The function to execute on the element to validate and preserve its format.
|
|
272
|
+
* - The function takes the element as an argument, checks if it is contained correctly, and applies necessary adjustments.
|
|
206
273
|
*/
|
|
207
274
|
retainFormat() {
|
|
208
275
|
return {
|
|
@@ -211,33 +278,34 @@ Image_.prototype = {
|
|
|
211
278
|
const figureInfo = Figure.GetContainer(element);
|
|
212
279
|
if (figureInfo && figureInfo.container && figureInfo.cover) return;
|
|
213
280
|
|
|
214
|
-
this.
|
|
281
|
+
this._ready(element);
|
|
215
282
|
this._fileCheck(this._origin_w, this._origin_h);
|
|
216
283
|
}
|
|
217
284
|
};
|
|
218
|
-
}
|
|
285
|
+
}
|
|
219
286
|
|
|
220
287
|
/**
|
|
221
|
-
* @
|
|
288
|
+
* @editorMethod Modules.Modal
|
|
289
|
+
* @description This function is called before the modal window is opened, but before it is closed.
|
|
222
290
|
*/
|
|
223
291
|
init() {
|
|
224
292
|
Modal.OnChangeFile(this.fileModalWrapper, []);
|
|
225
293
|
if (this.imgInputFile) this.imgInputFile.value = '';
|
|
226
294
|
if (this.imgUrlFile) this._linkValue = this.previewSrc.textContent = this.imgUrlFile.value = '';
|
|
227
295
|
if (this.imgInputFile && this.imgUrlFile) {
|
|
228
|
-
this.imgUrlFile.
|
|
296
|
+
this.imgUrlFile.disabled = false;
|
|
229
297
|
this.previewSrc.style.textDecoration = '';
|
|
230
298
|
}
|
|
231
299
|
|
|
232
300
|
this.altText.value = '';
|
|
233
|
-
this.modal.form.querySelector('input[name="suneditor_image_radio"][value="none"]').checked = true;
|
|
301
|
+
/** @type {HTMLInputElement} */ (this.modal.form.querySelector('input[name="suneditor_image_radio"][value="none"]')).checked = true;
|
|
234
302
|
this.captionCheckEl.checked = false;
|
|
235
303
|
this._element = null;
|
|
236
304
|
this._ratio = {
|
|
237
305
|
w: 1,
|
|
238
306
|
h: 1
|
|
239
307
|
};
|
|
240
|
-
this
|
|
308
|
+
this.#OpenTab('init');
|
|
241
309
|
|
|
242
310
|
if (this._resizing) {
|
|
243
311
|
this.inputX.value = this.pluginOptions.defaultWidth === 'auto' ? '' : this.pluginOptions.defaultWidth;
|
|
@@ -246,28 +314,32 @@ Image_.prototype = {
|
|
|
246
314
|
}
|
|
247
315
|
|
|
248
316
|
if (this.pluginOptions.useFormatType) {
|
|
249
|
-
this._activeAsInline(this.pluginOptions.defaultFormatType === 'inline');
|
|
317
|
+
this._activeAsInline((this.pluginOptions.keepFormatType ? this.as : this.pluginOptions.defaultFormatType) === 'inline');
|
|
250
318
|
}
|
|
251
319
|
|
|
252
320
|
this.anchor.init();
|
|
253
|
-
}
|
|
321
|
+
}
|
|
254
322
|
|
|
255
323
|
/**
|
|
256
|
-
* @
|
|
257
|
-
* @description
|
|
258
|
-
* @param {
|
|
324
|
+
* @editorMethod Editor.Component
|
|
325
|
+
* @description Executes the method that is called when a component of a plugin is selected.
|
|
326
|
+
* @param {HTMLElement} target Target component element
|
|
259
327
|
*/
|
|
260
|
-
select(
|
|
261
|
-
this.
|
|
262
|
-
}
|
|
328
|
+
select(target) {
|
|
329
|
+
this._ready(target);
|
|
330
|
+
}
|
|
263
331
|
|
|
264
332
|
/**
|
|
265
|
-
* @
|
|
333
|
+
* @private
|
|
334
|
+
* @description Prepares the component for selection.
|
|
335
|
+
* - Ensures that the controller is properly positioned and initialized.
|
|
336
|
+
* - Prevents duplicate event handling if the component is already selected.
|
|
337
|
+
* @param {HTMLElement} target - The selected element.
|
|
266
338
|
*/
|
|
267
|
-
|
|
339
|
+
_ready(target) {
|
|
268
340
|
if (!target) return;
|
|
269
341
|
const figureInfo = this.figure.open(target, { nonResizing: this._nonResizing, nonSizeInfo: false, nonBorder: false, figureTarget: false, __fileManagerInfo: false });
|
|
270
|
-
this.anchor.set(
|
|
342
|
+
this.anchor.set(dom.check.isAnchor(target.parentNode) ? target.parentNode : null);
|
|
271
343
|
|
|
272
344
|
this._linkElement = this.anchor.currentTarget;
|
|
273
345
|
this._element = target;
|
|
@@ -277,13 +349,15 @@ Image_.prototype = {
|
|
|
277
349
|
this._align = figureInfo.align;
|
|
278
350
|
target.style.float = '';
|
|
279
351
|
|
|
280
|
-
this._origin_w = figureInfo.originWidth || figureInfo.w || '';
|
|
281
|
-
this._origin_h = figureInfo.originHeight || figureInfo.h || '';
|
|
352
|
+
this._origin_w = String(figureInfo.originWidth || figureInfo.w || '');
|
|
353
|
+
this._origin_h = String(figureInfo.originHeight || figureInfo.h || '');
|
|
282
354
|
this.altText.value = this._element.alt;
|
|
283
355
|
|
|
284
356
|
if (this.imgUrlFile) this._linkValue = this.previewSrc.textContent = this.imgUrlFile.value = this._element.src;
|
|
285
357
|
|
|
286
|
-
|
|
358
|
+
/** @type {HTMLInputElement} */
|
|
359
|
+
const activeAlign = this.modal.form.querySelector('input[name="suneditor_image_radio"][value="' + this._align + '"]') || this.modal.form.querySelector('input[name="suneditor_image_radio"][value="none"]');
|
|
360
|
+
activeAlign.checked = true;
|
|
287
361
|
this.captionCheckEl.checked = !!this._caption;
|
|
288
362
|
|
|
289
363
|
if (!this._resizing) return;
|
|
@@ -294,11 +368,11 @@ Image_.prototype = {
|
|
|
294
368
|
w = numbers.get(w, 2);
|
|
295
369
|
if (w > 100) w = 100;
|
|
296
370
|
}
|
|
297
|
-
this.inputX.value = w === 'auto' ? '' : w;
|
|
371
|
+
this.inputX.value = String(w === 'auto' ? '' : w);
|
|
298
372
|
|
|
299
373
|
if (!this._onlyPercentage) {
|
|
300
374
|
const h = percentageRotation ? '' : figureInfo.height;
|
|
301
|
-
this.inputY.value = h === 'auto' ? '' : h;
|
|
375
|
+
this.inputY.value = String(h === 'auto' ? '' : h);
|
|
302
376
|
}
|
|
303
377
|
|
|
304
378
|
this.proportion.checked = true;
|
|
@@ -316,21 +390,24 @@ Image_.prototype = {
|
|
|
316
390
|
if (this.pluginOptions.useFormatType) {
|
|
317
391
|
this._activeAsInline(this.component.isInline(figureInfo.container));
|
|
318
392
|
}
|
|
319
|
-
}
|
|
393
|
+
}
|
|
320
394
|
|
|
321
395
|
/**
|
|
322
|
-
* @
|
|
396
|
+
* @editorMethod Editor.Component
|
|
397
|
+
* @description Method to delete a component of a plugin, called by the "FileManager", "Controller" module.
|
|
398
|
+
* @param {HTMLElement} target Target element
|
|
399
|
+
* @returns {Promise<void>}
|
|
323
400
|
*/
|
|
324
|
-
async destroy(
|
|
325
|
-
const targetEl =
|
|
326
|
-
const container =
|
|
401
|
+
async destroy(target) {
|
|
402
|
+
const targetEl = target || this._element;
|
|
403
|
+
const container = dom.query.getParentElement(targetEl, Figure.is) || targetEl;
|
|
327
404
|
const focusEl = container.previousElementSibling || container.nextElementSibling;
|
|
328
405
|
const emptyDiv = container.parentNode;
|
|
329
406
|
|
|
330
|
-
const message = await this.triggerEvent('onImageDeleteBefore', {
|
|
407
|
+
const message = await this.triggerEvent('onImageDeleteBefore', { element: targetEl, container, align: this._align, alt: this.altText.value, url: this._linkValue });
|
|
331
408
|
if (message === false) return;
|
|
332
409
|
|
|
333
|
-
|
|
410
|
+
dom.utils.removeItem(container);
|
|
334
411
|
this.init();
|
|
335
412
|
|
|
336
413
|
if (emptyDiv !== this.editor.frameContext.get('wysiwyg')) {
|
|
@@ -346,46 +423,61 @@ Image_.prototype = {
|
|
|
346
423
|
// focus
|
|
347
424
|
this.editor.focusEdge(focusEl);
|
|
348
425
|
this.history.push(false);
|
|
349
|
-
}
|
|
426
|
+
}
|
|
350
427
|
|
|
428
|
+
/**
|
|
429
|
+
* @private
|
|
430
|
+
* @description Retrieves the current image information.
|
|
431
|
+
* @returns {*} - The image data.
|
|
432
|
+
*/
|
|
351
433
|
_getInfo() {
|
|
352
434
|
return {
|
|
353
435
|
element: this._element,
|
|
354
436
|
anchor: this.anchor.create(true),
|
|
355
|
-
inputWidth: this.inputX
|
|
356
|
-
inputHeight: this.inputY
|
|
437
|
+
inputWidth: this.inputX?.value || '',
|
|
438
|
+
inputHeight: this.inputY?.value || '',
|
|
357
439
|
align: this._align,
|
|
358
440
|
isUpdate: this.modal.isUpdate,
|
|
359
441
|
alt: this.altText.value
|
|
360
442
|
};
|
|
361
|
-
}
|
|
443
|
+
}
|
|
362
444
|
|
|
445
|
+
/**
|
|
446
|
+
* @private
|
|
447
|
+
* @description Toggles between block and inline image format.
|
|
448
|
+
* @param {boolean} isInline - Whether the image should be inline.
|
|
449
|
+
*/
|
|
363
450
|
_activeAsInline(isInline) {
|
|
364
|
-
const ctrlAlignBtn = this.figure.controller.form.querySelector('[data-command="onalign"]');
|
|
365
|
-
|
|
366
451
|
if (isInline) {
|
|
367
|
-
|
|
368
|
-
|
|
452
|
+
dom.utils.addClass(this.asInline, 'on');
|
|
453
|
+
dom.utils.removeClass(this.asBlock, 'on');
|
|
369
454
|
this.as = 'inline';
|
|
370
455
|
// buttns
|
|
371
456
|
if (this.alignForm) this.alignForm.style.display = 'none';
|
|
372
|
-
|
|
457
|
+
// caption
|
|
458
|
+
if (this.captionEl) this.captionEl.style.display = 'none';
|
|
373
459
|
} else {
|
|
374
|
-
|
|
375
|
-
|
|
460
|
+
dom.utils.addClass(this.asBlock, 'on');
|
|
461
|
+
dom.utils.removeClass(this.asInline, 'on');
|
|
376
462
|
this.as = 'block';
|
|
377
463
|
// buttns
|
|
378
464
|
if (this.alignForm) this.alignForm.style.display = '';
|
|
379
|
-
|
|
465
|
+
// caption
|
|
466
|
+
if (this.captionEl) this.captionEl.style.display = '';
|
|
380
467
|
}
|
|
381
|
-
}
|
|
468
|
+
}
|
|
382
469
|
|
|
470
|
+
/**
|
|
471
|
+
* @description Create an "image" component using the provided files.
|
|
472
|
+
* @param {FileList|File[]} fileList File object list
|
|
473
|
+
* @returns {Promise<boolean>} If return false, the file upload will be canceled
|
|
474
|
+
*/
|
|
383
475
|
async submitFile(fileList) {
|
|
384
476
|
if (fileList.length === 0) return false;
|
|
385
477
|
|
|
386
478
|
let fileSize = 0;
|
|
387
479
|
const files = [];
|
|
388
|
-
const slngleSizeLimit = this.uploadSingleSizeLimit;
|
|
480
|
+
const slngleSizeLimit = this.pluginOptions.uploadSingleSizeLimit;
|
|
389
481
|
for (let i = 0, len = fileList.length, f, s; i < len; i++) {
|
|
390
482
|
f = fileList[i];
|
|
391
483
|
if (!/image/i.test(f.type)) continue;
|
|
@@ -400,7 +492,7 @@ Image_.prototype = {
|
|
|
400
492
|
file: f
|
|
401
493
|
});
|
|
402
494
|
|
|
403
|
-
this.
|
|
495
|
+
this.ui.alertOpen(message === NO_EVENT ? err : message || err, 'error');
|
|
404
496
|
|
|
405
497
|
return false;
|
|
406
498
|
}
|
|
@@ -420,7 +512,7 @@ Image_.prototype = {
|
|
|
420
512
|
uploadSize: fileSize
|
|
421
513
|
});
|
|
422
514
|
|
|
423
|
-
this.
|
|
515
|
+
this.ui.alertOpen(message === NO_EVENT ? err : message || err, 'error');
|
|
424
516
|
|
|
425
517
|
return false;
|
|
426
518
|
}
|
|
@@ -430,9 +522,11 @@ Image_.prototype = {
|
|
|
430
522
|
infos = newInfos || infos;
|
|
431
523
|
this._serverUpload(infos, infos.files);
|
|
432
524
|
}.bind(this, imgInfo);
|
|
525
|
+
// se-ts-ignore
|
|
526
|
+
this._serverUpload;
|
|
433
527
|
|
|
434
528
|
const result = await this.triggerEvent('onImageUploadBefore', {
|
|
435
|
-
|
|
529
|
+
info: imgInfo,
|
|
436
530
|
handler
|
|
437
531
|
});
|
|
438
532
|
|
|
@@ -441,8 +535,13 @@ Image_.prototype = {
|
|
|
441
535
|
if (result !== null && typeof result === 'object') handler(result);
|
|
442
536
|
|
|
443
537
|
if (result === true || result === NO_EVENT) handler(null);
|
|
444
|
-
}
|
|
538
|
+
}
|
|
445
539
|
|
|
540
|
+
/**
|
|
541
|
+
* @description Create an "image" component using the provided url.
|
|
542
|
+
* @param {string} url File url
|
|
543
|
+
* @returns {Promise<boolean>} If return false, the file upload will be canceled
|
|
544
|
+
*/
|
|
446
545
|
async submitURL(url) {
|
|
447
546
|
if (!url) url = this._linkValue;
|
|
448
547
|
if (!url) return false;
|
|
@@ -458,11 +557,11 @@ Image_.prototype = {
|
|
|
458
557
|
infos = newInfos || infos;
|
|
459
558
|
const infoUrl = infos.url;
|
|
460
559
|
if (this.modal.isUpdate) this._updateSrc(infoUrl, infos.element, infos.files);
|
|
461
|
-
else this.
|
|
560
|
+
else this._produce(infoUrl, infos.anchor, infos.inputWidth, infos.inputHeight, infos.align, infos.files, infos.alt);
|
|
462
561
|
}.bind(this, imgInfo);
|
|
463
562
|
|
|
464
563
|
const result = await this.triggerEvent('onImageUploadBefore', {
|
|
465
|
-
|
|
564
|
+
info: imgInfo,
|
|
466
565
|
handler
|
|
467
566
|
});
|
|
468
567
|
|
|
@@ -473,11 +572,17 @@ Image_.prototype = {
|
|
|
473
572
|
if (result === true || result === NO_EVENT) handler(null);
|
|
474
573
|
|
|
475
574
|
return true;
|
|
476
|
-
}
|
|
575
|
+
}
|
|
477
576
|
|
|
577
|
+
/**
|
|
578
|
+
* @private
|
|
579
|
+
* @description Updates the selected image size, alt text, and caption.
|
|
580
|
+
* @param {string} width - New image width.
|
|
581
|
+
* @param {string} height - New image height.
|
|
582
|
+
*/
|
|
478
583
|
_update(width, height) {
|
|
479
|
-
if (!width) width = this.inputX
|
|
480
|
-
if (!height) height = this.inputY
|
|
584
|
+
if (!width) width = this.inputX?.value || 'auto';
|
|
585
|
+
if (!height) height = this.inputY?.value || 'auto';
|
|
481
586
|
|
|
482
587
|
let imageEl = this._element;
|
|
483
588
|
const cover = this._cover;
|
|
@@ -505,7 +610,7 @@ Image_.prototype = {
|
|
|
505
610
|
}
|
|
506
611
|
} else {
|
|
507
612
|
if (this._caption) {
|
|
508
|
-
|
|
613
|
+
dom.utils.removeItem(this._caption);
|
|
509
614
|
this._caption = null;
|
|
510
615
|
modifiedCaption = true;
|
|
511
616
|
}
|
|
@@ -531,11 +636,11 @@ Image_.prototype = {
|
|
|
531
636
|
|
|
532
637
|
// size
|
|
533
638
|
if (this._resizing && changeSize) {
|
|
534
|
-
this.
|
|
639
|
+
this._applySize(width, height);
|
|
535
640
|
}
|
|
536
641
|
|
|
537
642
|
if (isNewAnchor) {
|
|
538
|
-
|
|
643
|
+
dom.utils.removeItem(anchor);
|
|
539
644
|
}
|
|
540
645
|
|
|
541
646
|
// transform
|
|
@@ -556,23 +661,34 @@ Image_.prototype = {
|
|
|
556
661
|
imageEl.onload = () => {
|
|
557
662
|
this.select(imageEl);
|
|
558
663
|
};
|
|
559
|
-
}
|
|
664
|
+
}
|
|
560
665
|
|
|
666
|
+
/**
|
|
667
|
+
* @private
|
|
668
|
+
* @description Validates the image size and applies necessary transformations.
|
|
669
|
+
* @param {string} width - The width of the image.
|
|
670
|
+
* @param {string} height - The height of the image.
|
|
671
|
+
*/
|
|
561
672
|
_fileCheck(width, height) {
|
|
562
|
-
if (!width) width = this.inputX
|
|
563
|
-
if (!height) height = this.inputY
|
|
673
|
+
if (!width) width = this.inputX?.value || 'auto';
|
|
674
|
+
if (!height) height = this.inputY?.value || 'auto';
|
|
564
675
|
|
|
565
676
|
let imageEl = this._element;
|
|
566
677
|
let cover = this._cover;
|
|
678
|
+
let inlineCover = null;
|
|
567
679
|
let container = this._container === this._cover ? null : this._container;
|
|
568
680
|
let isNewContainer = false;
|
|
569
681
|
|
|
570
682
|
if (!cover || !container) {
|
|
571
683
|
isNewContainer = true;
|
|
572
684
|
imageEl = this._element.cloneNode(true);
|
|
573
|
-
const figureInfo =
|
|
685
|
+
const figureInfo =
|
|
686
|
+
this.pluginOptions.useFormatType && width !== 'auto' && (/^span$/i.test(this._element.parentElement?.nodeName) || this.format.isLine(this._element.parentElement))
|
|
687
|
+
? Figure.CreateInlineContainer(imageEl, 'se-image-container')
|
|
688
|
+
: Figure.CreateContainer(imageEl, 'se-image-container');
|
|
574
689
|
cover = figureInfo.cover;
|
|
575
690
|
container = figureInfo.container;
|
|
691
|
+
inlineCover = figureInfo.inlineCover;
|
|
576
692
|
this.figure.open(imageEl, { nonResizing: true, nonSizeInfo: false, nonBorder: false, figureTarget: false, __fileManagerInfo: true });
|
|
577
693
|
}
|
|
578
694
|
|
|
@@ -591,16 +707,18 @@ Image_.prototype = {
|
|
|
591
707
|
|
|
592
708
|
// caption
|
|
593
709
|
let modifiedCaption = false;
|
|
594
|
-
if (
|
|
595
|
-
if (
|
|
596
|
-
this._caption
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
710
|
+
if (!inlineCover) {
|
|
711
|
+
if (this.captionCheckEl.checked) {
|
|
712
|
+
if (!this._caption || isNewContainer) {
|
|
713
|
+
this._caption = Figure.CreateCaption(cover, this.lang.caption);
|
|
714
|
+
modifiedCaption = true;
|
|
715
|
+
}
|
|
716
|
+
} else {
|
|
717
|
+
if (this._caption) {
|
|
718
|
+
dom.utils.removeItem(this._caption);
|
|
719
|
+
this._caption = null;
|
|
720
|
+
modifiedCaption = true;
|
|
721
|
+
}
|
|
604
722
|
}
|
|
605
723
|
}
|
|
606
724
|
|
|
@@ -624,7 +742,7 @@ Image_.prototype = {
|
|
|
624
742
|
|
|
625
743
|
if (isNewContainer) {
|
|
626
744
|
imageEl = this._element;
|
|
627
|
-
this.figure.
|
|
745
|
+
this.figure.retainFigureFormat(container, this._element, isNewAnchor ? anchor : null, this.fileManager);
|
|
628
746
|
this._element = imageEl = container.querySelector('img');
|
|
629
747
|
this._cover = cover;
|
|
630
748
|
this._container = container;
|
|
@@ -632,16 +750,16 @@ Image_.prototype = {
|
|
|
632
750
|
|
|
633
751
|
// size
|
|
634
752
|
if (this._resizing && changeSize) {
|
|
635
|
-
this.
|
|
753
|
+
this._applySize(width, height);
|
|
636
754
|
}
|
|
637
755
|
|
|
638
756
|
if (isNewAnchor) {
|
|
639
757
|
if (!isNewContainer) {
|
|
640
|
-
|
|
758
|
+
dom.utils.removeItem(anchor);
|
|
641
759
|
} else {
|
|
642
|
-
|
|
643
|
-
if (
|
|
644
|
-
|
|
760
|
+
dom.utils.removeItem(isNewAnchor);
|
|
761
|
+
if (dom.query.getListChildren(anchor, (current) => /IMG/i.test(current.tagName)).length === 0) {
|
|
762
|
+
dom.utils.removeItem(anchor);
|
|
645
763
|
}
|
|
646
764
|
}
|
|
647
765
|
}
|
|
@@ -659,11 +777,16 @@ Image_.prototype = {
|
|
|
659
777
|
|
|
660
778
|
// align
|
|
661
779
|
this.figure.setAlign(imageEl, this._align);
|
|
662
|
-
}
|
|
780
|
+
}
|
|
663
781
|
|
|
664
|
-
|
|
782
|
+
/**
|
|
783
|
+
* @description Opens a specific tab inside the modal.
|
|
784
|
+
* @param {MouseEvent|string} e - The event object or tab name.
|
|
785
|
+
* @returns {boolean} - Whether the tab was successfully opened.
|
|
786
|
+
*/
|
|
787
|
+
#OpenTab(e) {
|
|
665
788
|
const modalForm = this.modal.form;
|
|
666
|
-
const targetElement = e === '
|
|
789
|
+
const targetElement = typeof e === 'string' ? modalForm.querySelector('._se_tab_link') : dom.query.getEventTarget(e);
|
|
667
790
|
|
|
668
791
|
if (!/^BUTTON$/i.test(targetElement.tagName)) {
|
|
669
792
|
return false;
|
|
@@ -674,7 +797,7 @@ Image_.prototype = {
|
|
|
674
797
|
let i;
|
|
675
798
|
|
|
676
799
|
// Get all elements with class="tabcontent" and hide them
|
|
677
|
-
const tabContent = modalForm.getElementsByClassName('_se_tab_content');
|
|
800
|
+
const tabContent = /** @type {HTMLCollectionOf<HTMLElement>}*/ (modalForm.getElementsByClassName('_se_tab_content'));
|
|
678
801
|
for (i = 0; i < tabContent.length; i++) {
|
|
679
802
|
tabContent[i].style.display = 'none';
|
|
680
803
|
}
|
|
@@ -682,12 +805,12 @@ Image_.prototype = {
|
|
|
682
805
|
// Get all elements with class="tablinks" and remove the class "active"
|
|
683
806
|
const tabLinks = modalForm.getElementsByClassName('_se_tab_link');
|
|
684
807
|
for (i = 0; i < tabLinks.length; i++) {
|
|
685
|
-
|
|
808
|
+
dom.utils.removeClass(tabLinks[i], 'active');
|
|
686
809
|
}
|
|
687
810
|
|
|
688
811
|
// Show the current tab, and add an "active" class to the button that opened the tab
|
|
689
|
-
modalForm.querySelector('._se_tab_content_' + tabName).style.display = 'block';
|
|
690
|
-
|
|
812
|
+
/** @type {HTMLElement}*/ (modalForm.querySelector('._se_tab_content_' + tabName)).style.display = 'block';
|
|
813
|
+
dom.utils.addClass(targetElement, 'active');
|
|
691
814
|
|
|
692
815
|
// focus
|
|
693
816
|
if (e !== 'init') {
|
|
@@ -699,20 +822,57 @@ Image_.prototype = {
|
|
|
699
822
|
}
|
|
700
823
|
|
|
701
824
|
return false;
|
|
702
|
-
}
|
|
825
|
+
}
|
|
703
826
|
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
827
|
+
/**
|
|
828
|
+
* @private
|
|
829
|
+
* @description Creates a new image component based on provided parameters.
|
|
830
|
+
* @param {string} src - The image source URL.
|
|
831
|
+
* @param {?Node} anchor - Optional anchor wrapping the image.
|
|
832
|
+
* @param {string} width - Image width.
|
|
833
|
+
* @param {string} height - Image height.
|
|
834
|
+
* @param {string} align - Image alignment.
|
|
835
|
+
* @param {{name: string, size: number}} file - File metadata.
|
|
836
|
+
* @param {string} alt - Alternative text.
|
|
837
|
+
*/
|
|
838
|
+
_produce(src, anchor, width, height, align, file, alt) {
|
|
839
|
+
if (this.as !== 'inline') {
|
|
840
|
+
this.create(src, anchor, width, height, align, file, alt);
|
|
841
|
+
} else {
|
|
842
|
+
this.createInline(src, anchor, width, height, file, alt);
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
/**
|
|
847
|
+
* @private
|
|
848
|
+
* @description Applies the specified width and height to the image.
|
|
849
|
+
* @param {string} w - Image width.
|
|
850
|
+
* @param {string} h - Image height.
|
|
851
|
+
*/
|
|
852
|
+
_applySize(w, h) {
|
|
853
|
+
if (!w) w = this.inputX?.value || this.pluginOptions.defaultWidth;
|
|
854
|
+
if (!h) h = this.inputY?.value || this.pluginOptions.defaultHeight;
|
|
707
855
|
if (this._onlyPercentage) {
|
|
708
856
|
if (!w) w = '100%';
|
|
709
857
|
else if (/%$/.test(w)) w += '%';
|
|
710
858
|
}
|
|
711
|
-
this.figure.setSize(w, h
|
|
712
|
-
}
|
|
859
|
+
this.figure.setSize(w, h);
|
|
860
|
+
}
|
|
713
861
|
|
|
862
|
+
/**
|
|
863
|
+
* @description Creates a new image component, wraps it in a figure container with an optional anchor,
|
|
864
|
+
* - applies size and alignment settings, and inserts it into the editor.
|
|
865
|
+
* @param {string} src - The URL of the image to be inserted.
|
|
866
|
+
* @param {?Node} anchor - An optional anchor element to wrap the image. If provided, a clone is used.
|
|
867
|
+
* @param {string} width - The width value to be applied to the image.
|
|
868
|
+
* @param {string} height - The height value to be applied to the image.
|
|
869
|
+
* @param {string} align - The alignment setting for the image (e.g., 'left', 'center', 'right').
|
|
870
|
+
* @param {{name: string, size: number}} file - File metadata associated with the image
|
|
871
|
+
* @param {string} alt - The alternative text for the image.
|
|
872
|
+
*/
|
|
714
873
|
create(src, anchor, width, height, align, file, alt) {
|
|
715
|
-
|
|
874
|
+
/** @type {HTMLImageElement} */
|
|
875
|
+
const oImg = dom.utils.createElement('IMG');
|
|
716
876
|
oImg.src = src;
|
|
717
877
|
oImg.alt = alt;
|
|
718
878
|
anchor = this._setAnchor(oImg, anchor ? anchor.cloneNode(false) : null);
|
|
@@ -732,23 +892,69 @@ Image_.prototype = {
|
|
|
732
892
|
this.figure.open(oImg, { nonResizing: this._nonResizing, nonSizeInfo: false, nonBorder: false, figureTarget: false, __fileManagerInfo: true });
|
|
733
893
|
|
|
734
894
|
// set size
|
|
735
|
-
this.
|
|
895
|
+
this._applySize(width, height);
|
|
736
896
|
|
|
737
897
|
// align
|
|
738
898
|
this.figure.setAlign(oImg, align);
|
|
739
899
|
|
|
740
900
|
this.fileManager.setFileData(oImg, file);
|
|
741
901
|
|
|
742
|
-
oImg.onload = OnloadImg.bind(this, oImg, this._svgDefaultSize, container);
|
|
743
|
-
this.component.insert(container, false,
|
|
744
|
-
}
|
|
902
|
+
oImg.onload = this.#OnloadImg.bind(this, oImg, this._svgDefaultSize, container);
|
|
903
|
+
this.component.insert(container, { skipCharCount: false, skipSelection: !this.options.get('componentAutoSelect'), skipHistory: false });
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
/**
|
|
907
|
+
* @description Creates a new inline image component, wraps it in an inline figure container with an optional anchor,
|
|
908
|
+
* - applies size settings, and inserts it into the editor.
|
|
909
|
+
* @param {string} src - The URL of the image to be inserted.
|
|
910
|
+
* @param {?Node} anchor - An optional anchor element to wrap the image. If provided, a clone is used.
|
|
911
|
+
* @param {string} width - The width value to be applied to the image.
|
|
912
|
+
* @param {string} height - The height value to be applied to the image.
|
|
913
|
+
* @param {{name: string, size: number}} file - File metadata associated with the image
|
|
914
|
+
* @param {string} alt - The alternative text for the image.
|
|
915
|
+
*/
|
|
916
|
+
createInline(src, anchor, width, height, file, alt) {
|
|
917
|
+
/** @type {HTMLImageElement} */
|
|
918
|
+
const oImg = dom.utils.createElement('IMG');
|
|
919
|
+
oImg.src = src;
|
|
920
|
+
oImg.alt = alt;
|
|
921
|
+
anchor = this._setAnchor(oImg, anchor ? anchor.cloneNode(false) : null);
|
|
922
|
+
|
|
923
|
+
const figureInfo = Figure.CreateInlineContainer(anchor, 'se-image-container');
|
|
924
|
+
const container = figureInfo.container;
|
|
925
|
+
|
|
926
|
+
this._element = oImg;
|
|
927
|
+
this._container = container;
|
|
928
|
+
this.figure.open(oImg, { nonResizing: this._nonResizing, nonSizeInfo: false, nonBorder: false, figureTarget: false, __fileManagerInfo: true });
|
|
929
|
+
|
|
930
|
+
// set size
|
|
931
|
+
this._applySize(width, height);
|
|
932
|
+
|
|
933
|
+
this.fileManager.setFileData(oImg, file);
|
|
934
|
+
|
|
935
|
+
oImg.onload = this.#OnloadImg.bind(this, oImg, this._svgDefaultSize, container);
|
|
936
|
+
this.component.insert(container, { skipCharCount: false, skipSelection: true, skipHistory: false });
|
|
937
|
+
}
|
|
745
938
|
|
|
939
|
+
/**
|
|
940
|
+
* @private
|
|
941
|
+
* @description Updates the image source URL.
|
|
942
|
+
* @param {string} src - The new image source.
|
|
943
|
+
* @param {HTMLImageElement} element - The image element.
|
|
944
|
+
* @param {{ name: string, size: number }} file - File metadata.
|
|
945
|
+
*/
|
|
746
946
|
_updateSrc(src, element, file) {
|
|
747
947
|
element.src = src;
|
|
748
948
|
this.fileManager.setFileData(element, file);
|
|
749
|
-
this.component.select(element, Image_.key
|
|
750
|
-
}
|
|
949
|
+
this.component.select(element, Image_.key);
|
|
950
|
+
}
|
|
751
951
|
|
|
952
|
+
/**
|
|
953
|
+
* @private
|
|
954
|
+
* @description Registers the uploaded image and inserts it into the editor.
|
|
955
|
+
* @param {ImageInfo_image} info - Image info.
|
|
956
|
+
* @param {Object<string, *>} response - Server response data.
|
|
957
|
+
*/
|
|
752
958
|
_register(info, response) {
|
|
753
959
|
const fileList = response.result;
|
|
754
960
|
|
|
@@ -761,37 +967,57 @@ Image_.prototype = {
|
|
|
761
967
|
this._updateSrc(fileList[i].url, info.element, file);
|
|
762
968
|
break;
|
|
763
969
|
} else {
|
|
764
|
-
this.
|
|
970
|
+
this._produce(fileList[i].url, info.anchor, info.inputWidth, info.inputHeight, info.align, file, info.alt);
|
|
765
971
|
}
|
|
766
972
|
}
|
|
767
|
-
}
|
|
973
|
+
}
|
|
768
974
|
|
|
975
|
+
/**
|
|
976
|
+
* @private
|
|
977
|
+
* @description Uploads the image to the server.
|
|
978
|
+
* @param {ImageInfo_image} info - Image upload info.
|
|
979
|
+
* @param {FileList} files - List of image files.
|
|
980
|
+
*/
|
|
769
981
|
_serverUpload(info, files) {
|
|
770
982
|
if (!files) return;
|
|
771
983
|
|
|
772
984
|
// server upload
|
|
773
985
|
const imageUploadUrl = this.pluginOptions.uploadUrl;
|
|
774
986
|
if (typeof imageUploadUrl === 'string' && imageUploadUrl.length > 0) {
|
|
775
|
-
this.fileManager.upload(imageUploadUrl, this.pluginOptions.uploadHeaders, files, UploadCallBack.bind(this, info), this._error.bind(this));
|
|
987
|
+
this.fileManager.upload(imageUploadUrl, this.pluginOptions.uploadHeaders, files, this.#UploadCallBack.bind(this, info), this._error.bind(this));
|
|
776
988
|
} else {
|
|
777
989
|
this._setBase64(files, info.anchor, info.inputWidth, info.inputHeight, info.align, info.alt, info.isUpdate);
|
|
778
990
|
}
|
|
779
|
-
}
|
|
991
|
+
}
|
|
780
992
|
|
|
993
|
+
/**
|
|
994
|
+
* @private
|
|
995
|
+
* @description Converts an image file to Base64 and inserts it into the editor.
|
|
996
|
+
* @param {FileList|File[]} files - List of image files.
|
|
997
|
+
* @param {?Node} anchor - Optional anchor wrapping the image.
|
|
998
|
+
* @param {string} width - Image width.
|
|
999
|
+
* @param {string} height - Image height.
|
|
1000
|
+
* @param {string} align - Image alignment.
|
|
1001
|
+
* @param {string} alt - Alternative text.
|
|
1002
|
+
* @param {boolean} isUpdate - Whether the image is being updated.
|
|
1003
|
+
*/
|
|
781
1004
|
_setBase64(files, anchor, width, height, align, alt, isUpdate) {
|
|
782
1005
|
try {
|
|
783
1006
|
const filesLen = this.modal.isUpdate ? 1 : files.length;
|
|
784
1007
|
|
|
785
1008
|
if (filesLen === 0) {
|
|
786
|
-
this.
|
|
1009
|
+
this.ui.hideLoading();
|
|
787
1010
|
console.warn('[SUNEDITOR.image.base64.fail] cause : No applicable files');
|
|
788
1011
|
return;
|
|
789
1012
|
}
|
|
790
1013
|
|
|
791
1014
|
this._base64RenderIndex = filesLen;
|
|
792
|
-
const filesStack =
|
|
793
|
-
|
|
794
|
-
this.
|
|
1015
|
+
const filesStack = new Array(filesLen);
|
|
1016
|
+
|
|
1017
|
+
if (this._resizing) {
|
|
1018
|
+
this.inputX.value = width;
|
|
1019
|
+
this.inputY.value = height;
|
|
1020
|
+
}
|
|
795
1021
|
|
|
796
1022
|
for (let i = 0, reader, file; i < filesLen; i++) {
|
|
797
1023
|
reader = new FileReader();
|
|
@@ -805,28 +1031,51 @@ Image_.prototype = {
|
|
|
805
1031
|
|
|
806
1032
|
if (--this._base64RenderIndex === 0) {
|
|
807
1033
|
this._onRenderBase64(update, filesStack, updateElement, anchor, width, height, align, alt);
|
|
808
|
-
this.
|
|
1034
|
+
this.ui.hideLoading();
|
|
809
1035
|
}
|
|
810
1036
|
}.bind(this, reader, isUpdate, this._element, file, i);
|
|
1037
|
+
// se-ts-ignore
|
|
1038
|
+
this._onRenderBase64;
|
|
811
1039
|
|
|
812
1040
|
reader.readAsDataURL(file);
|
|
813
1041
|
}
|
|
814
1042
|
} catch (error) {
|
|
815
|
-
this.
|
|
1043
|
+
this.ui.hideLoading();
|
|
816
1044
|
throw Error(`[SUNEDITOR.plugins.image._setBase64.fail] ${error.message}`);
|
|
817
1045
|
}
|
|
818
|
-
}
|
|
1046
|
+
}
|
|
819
1047
|
|
|
1048
|
+
/**
|
|
1049
|
+
* @private
|
|
1050
|
+
* @description Inserts an image using a Base64-encoded string.
|
|
1051
|
+
* @param {boolean} update - Whether the image is being updated.
|
|
1052
|
+
* @param {Array<{result: string, file: { name: string, size: number }}>} filesStack - Stack of Base64-encoded files.
|
|
1053
|
+
* - result: Image url or Base64-encoded string
|
|
1054
|
+
* - file: File metadata ({ name: string, size: number })
|
|
1055
|
+
* @param {HTMLImageElement} updateElement - The image element being updated.
|
|
1056
|
+
* @param {?HTMLAnchorElement} anchor - Optional anchor wrapping the image.
|
|
1057
|
+
* @param {string} width - Image width.
|
|
1058
|
+
* @param {string} height - Image height.
|
|
1059
|
+
* @param {string} align - Image alignment.
|
|
1060
|
+
* @param {string} alt - Alternative text.
|
|
1061
|
+
*/
|
|
820
1062
|
_onRenderBase64(update, filesStack, updateElement, anchor, width, height, align, alt) {
|
|
821
1063
|
for (let i = 0, len = filesStack.length; i < len; i++) {
|
|
822
1064
|
if (update) {
|
|
823
1065
|
this._updateSrc(filesStack[i].result, updateElement, filesStack[i].file);
|
|
824
1066
|
} else {
|
|
825
|
-
this.
|
|
1067
|
+
this._produce(filesStack[i].result, anchor, width, height, align, filesStack[i].file, alt);
|
|
826
1068
|
}
|
|
827
1069
|
}
|
|
828
|
-
}
|
|
1070
|
+
}
|
|
829
1071
|
|
|
1072
|
+
/**
|
|
1073
|
+
* @private
|
|
1074
|
+
* @description Wraps an image element with an anchor if provided.
|
|
1075
|
+
* @param {Node} imgTag - The image element to be wrapped.
|
|
1076
|
+
* @param {?Node} anchor - The anchor element to wrap around the image. If null, returns the image itself.
|
|
1077
|
+
* @returns {Node} - The wrapped image inside the anchor or the original image element.
|
|
1078
|
+
*/
|
|
830
1079
|
_setAnchor(imgTag, anchor) {
|
|
831
1080
|
if (anchor) {
|
|
832
1081
|
anchor.appendChild(imgTag);
|
|
@@ -834,129 +1083,172 @@ Image_.prototype = {
|
|
|
834
1083
|
}
|
|
835
1084
|
|
|
836
1085
|
return imgTag;
|
|
837
|
-
}
|
|
1086
|
+
}
|
|
838
1087
|
|
|
1088
|
+
/**
|
|
1089
|
+
* @private
|
|
1090
|
+
* @description Handles errors during image upload and displays appropriate messages.
|
|
1091
|
+
* @param {Object<string, *>} response - The error response from the server.
|
|
1092
|
+
* @returns {Promise<void>}
|
|
1093
|
+
*/
|
|
839
1094
|
async _error(response) {
|
|
840
1095
|
const message = await this.triggerEvent('onImageUploadError', { error: response });
|
|
841
1096
|
const err = message === NO_EVENT ? response.errorMessage : message || response.errorMessage;
|
|
842
|
-
this.
|
|
1097
|
+
this.ui.alertOpen(err, 'error');
|
|
843
1098
|
console.error('[SUNEDITOR.plugin.image.error]', err);
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
constructor: Image_
|
|
847
|
-
};
|
|
1099
|
+
}
|
|
848
1100
|
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
1101
|
+
/**
|
|
1102
|
+
* @description Handles the callback function for image upload completion.
|
|
1103
|
+
* @param {ImageInfo_image} info - Image information.
|
|
1104
|
+
* @param {XMLHttpRequest} xmlHttp - The XMLHttpRequest object.
|
|
1105
|
+
*/
|
|
1106
|
+
async #UploadCallBack(info, xmlHttp) {
|
|
1107
|
+
if ((await this.triggerEvent('imageUploadHandler', { xmlHttp, info })) === NO_EVENT) {
|
|
1108
|
+
const response = JSON.parse(xmlHttp.responseText);
|
|
1109
|
+
if (response.errorMessage) {
|
|
1110
|
+
this._error(response);
|
|
1111
|
+
} else {
|
|
1112
|
+
this._register(info, response);
|
|
1113
|
+
}
|
|
856
1114
|
}
|
|
857
1115
|
}
|
|
858
|
-
}
|
|
859
1116
|
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
1117
|
+
#RemoveSelectedFiles() {
|
|
1118
|
+
this.imgInputFile.value = '';
|
|
1119
|
+
if (this.imgUrlFile) {
|
|
1120
|
+
this.imgUrlFile.disabled = false;
|
|
1121
|
+
this.previewSrc.style.textDecoration = '';
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
// inputFile check
|
|
1125
|
+
Modal.OnChangeFile(this.fileModalWrapper, []);
|
|
865
1126
|
}
|
|
866
1127
|
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
1128
|
+
#OnInputSize(xy, e) {
|
|
1129
|
+
if (keyCodeMap.isSpace(e.code)) {
|
|
1130
|
+
e.preventDefault();
|
|
1131
|
+
return;
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
if (xy === 'x' && this._onlyPercentage && e.target.value > 100) {
|
|
1135
|
+
e.target.value = 100;
|
|
1136
|
+
} else if (this.proportion.checked) {
|
|
1137
|
+
const ratioSize = Figure.CalcRatio(this.inputX.value, this.inputY.value, this.sizeUnit, this._ratio);
|
|
1138
|
+
if (xy === 'x') {
|
|
1139
|
+
this.inputY.value = String(ratioSize.h);
|
|
1140
|
+
} else {
|
|
1141
|
+
this.inputX.value = String(ratioSize.w);
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
870
1145
|
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
1146
|
+
#OnChangeRatio() {
|
|
1147
|
+
this._ratio = this.proportion.checked
|
|
1148
|
+
? Figure.GetRatio(this.inputX.value, this.inputY.value, this.sizeUnit)
|
|
1149
|
+
: {
|
|
1150
|
+
w: 1,
|
|
1151
|
+
h: 1
|
|
1152
|
+
};
|
|
875
1153
|
}
|
|
876
1154
|
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
const ratioSize = Figure.CalcRatio(this.inputX.value, this.inputY.value, this.sizeUnit, this._ratio);
|
|
881
|
-
if (xy === 'x') {
|
|
882
|
-
this.inputY.value = ratioSize.h;
|
|
1155
|
+
#OnClickRevert() {
|
|
1156
|
+
if (this._onlyPercentage) {
|
|
1157
|
+
this.inputX.value = Number(this._origin_w) > 100 ? '100' : this._origin_w;
|
|
883
1158
|
} else {
|
|
884
|
-
this.inputX.value =
|
|
1159
|
+
this.inputX.value = this._origin_w;
|
|
1160
|
+
this.inputY.value = this._origin_h;
|
|
885
1161
|
}
|
|
886
1162
|
}
|
|
887
|
-
}
|
|
888
1163
|
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
: {
|
|
893
|
-
w: 1,
|
|
894
|
-
h: 1
|
|
895
|
-
};
|
|
896
|
-
}
|
|
1164
|
+
#OnClickAsButton({ target }) {
|
|
1165
|
+
this._activeAsInline(target.getAttribute('data-command') === 'asInline');
|
|
1166
|
+
}
|
|
897
1167
|
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
this.
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
1168
|
+
#OnLinkPreview(e) {
|
|
1169
|
+
const value = e.target.value.trim();
|
|
1170
|
+
this._linkValue = this.previewSrc.textContent = !value
|
|
1171
|
+
? ''
|
|
1172
|
+
: this.options.get('defaultUrlProtocol') && !value.includes('://') && value.indexOf('#') !== 0
|
|
1173
|
+
? this.options.get('defaultUrlProtocol') + value
|
|
1174
|
+
: !value.includes('://')
|
|
1175
|
+
? '/' + value
|
|
1176
|
+
: value;
|
|
904
1177
|
}
|
|
905
|
-
}
|
|
906
1178
|
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
1179
|
+
#OnfileInputChange({ target }) {
|
|
1180
|
+
if (!this.imgInputFile.value) {
|
|
1181
|
+
this.imgUrlFile.disabled = false;
|
|
1182
|
+
this.previewSrc.style.textDecoration = '';
|
|
1183
|
+
} else {
|
|
1184
|
+
this.imgUrlFile.disabled = true;
|
|
1185
|
+
this.previewSrc.style.textDecoration = 'line-through';
|
|
1186
|
+
}
|
|
910
1187
|
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
? ''
|
|
915
|
-
: this.options.get('defaultUrlProtocol') && !value.includes('://') && value.indexOf('#') !== 0
|
|
916
|
-
? this.options.get('defaultUrlProtocol') + value
|
|
917
|
-
: !value.includes('://')
|
|
918
|
-
? '/' + value
|
|
919
|
-
: value;
|
|
920
|
-
}
|
|
1188
|
+
// inputFile check
|
|
1189
|
+
Modal.OnChangeFile(this.fileModalWrapper, target.files);
|
|
1190
|
+
}
|
|
921
1191
|
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
this.imgUrlFile.removeAttribute('disabled');
|
|
925
|
-
this.previewSrc.style.textDecoration = '';
|
|
926
|
-
} else {
|
|
927
|
-
this.imgUrlFile.setAttribute('disabled', true);
|
|
928
|
-
this.previewSrc.style.textDecoration = 'line-through';
|
|
1192
|
+
#OpenGallery() {
|
|
1193
|
+
this.plugins.imageGallery.open(this.#SetUrlInput.bind(this));
|
|
929
1194
|
}
|
|
930
1195
|
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
1196
|
+
#SetUrlInput(target) {
|
|
1197
|
+
this.altText.value = target.getAttribute('data-value') || target.alt;
|
|
1198
|
+
this._linkValue = this.previewSrc.textContent = this.imgUrlFile.value = target.getAttribute('data-command') || target.src;
|
|
1199
|
+
this.imgUrlFile.focus();
|
|
1200
|
+
}
|
|
934
1201
|
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
1202
|
+
#OnloadImg(oImg, _svgDefaultSize, container) {
|
|
1203
|
+
// svg exception handling
|
|
1204
|
+
if (oImg.offsetWidth === 0) this._applySize(_svgDefaultSize, '');
|
|
1205
|
+
if (this.options.get('componentAutoSelect')) {
|
|
1206
|
+
this.component.select(oImg, Image_.key);
|
|
1207
|
+
} else {
|
|
1208
|
+
if (!this.component.isInline(container)) {
|
|
1209
|
+
const line = this.format.addLine(container, null);
|
|
1210
|
+
if (line) this.selection.setRange(line, 0, line, 0);
|
|
1211
|
+
} else {
|
|
1212
|
+
const r = this.selection.getNearRange(container);
|
|
1213
|
+
if (r) {
|
|
1214
|
+
this.selection.setRange(r.container, r.offset, r.container, r.offset);
|
|
1215
|
+
} else {
|
|
1216
|
+
this.component.select(oImg, Image_.key);
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
938
1220
|
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
this._linkValue = this.previewSrc.textContent = this.imgUrlFile.value = target.getAttribute('data-command') || target.src;
|
|
942
|
-
this.imgUrlFile.focus();
|
|
943
|
-
}
|
|
1221
|
+
this.editor._iframeAutoHeight(this.editor.frameContext);
|
|
1222
|
+
this.history.push(false);
|
|
944
1223
|
|
|
945
|
-
|
|
946
|
-
// svg exception handling
|
|
947
|
-
if (oImg.offsetWidth === 0) this.applySize(_svgDefaultSize, '');
|
|
948
|
-
if (this.options.get('componentAutoSelect')) {
|
|
949
|
-
this.component.select(oImg, Image_.key, false);
|
|
950
|
-
} else {
|
|
951
|
-
const line = this.format.addLine(container, null);
|
|
952
|
-
if (line) this.selection.setRange(line, 0, line, 0);
|
|
1224
|
+
delete oImg.onload;
|
|
953
1225
|
}
|
|
954
|
-
|
|
955
|
-
this.editor._iframeAutoHeight(this.editor.frameContext);
|
|
956
|
-
|
|
957
|
-
delete oImg.onload;
|
|
958
1226
|
}
|
|
959
1227
|
|
|
1228
|
+
/**
|
|
1229
|
+
* @typedef {Object} ModalReturns_image
|
|
1230
|
+
* @property {HTMLElement} html
|
|
1231
|
+
* @property {HTMLElement} alignForm
|
|
1232
|
+
* @property {HTMLElement} fileModalWrapper
|
|
1233
|
+
* @property {HTMLInputElement} imgInputFile
|
|
1234
|
+
* @property {HTMLInputElement} imgUrlFile
|
|
1235
|
+
* @property {HTMLInputElement} altText
|
|
1236
|
+
* @property {HTMLInputElement} captionCheckEl
|
|
1237
|
+
* @property {HTMLElement} previewSrc
|
|
1238
|
+
* @property {HTMLElement} tabs
|
|
1239
|
+
* @property {HTMLButtonElement} galleryButton
|
|
1240
|
+
* @property {HTMLInputElement} proportion
|
|
1241
|
+
* @property {HTMLInputElement} inputX
|
|
1242
|
+
* @property {HTMLInputElement} inputY
|
|
1243
|
+
* @property {HTMLButtonElement} revertBtn
|
|
1244
|
+
* @property {HTMLButtonElement} asBlock
|
|
1245
|
+
* @property {HTMLButtonElement} asInline
|
|
1246
|
+
* @property {HTMLButtonElement} fileRemoveBtn
|
|
1247
|
+
*
|
|
1248
|
+
* @param {__se__EditorCore} editor
|
|
1249
|
+
* @param {*} pluginOptions
|
|
1250
|
+
* @returns {ModalReturns_image}
|
|
1251
|
+
*/
|
|
960
1252
|
function CreateHTML_modal({ lang, icons, plugins }, pluginOptions) {
|
|
961
1253
|
const createFileInputHtml = !pluginOptions.createFileInput
|
|
962
1254
|
? ''
|
|
@@ -972,12 +1264,12 @@ function CreateHTML_modal({ lang, icons, plugins }, pluginOptions) {
|
|
|
972
1264
|
<div class="se-modal-form">
|
|
973
1265
|
<label>${lang.image_modal_url}</label>
|
|
974
1266
|
<div class="se-modal-form-files">
|
|
975
|
-
<input class="se-input-form se-input-url
|
|
1267
|
+
<input class="se-input-form se-input-url" data-focus type="text" />
|
|
976
1268
|
${
|
|
977
1269
|
plugins.imageGallery
|
|
978
1270
|
? `<button type="button" class="se-btn se-tooltip se-modal-files-edge-button __se__gallery" aria-label="${lang.imageGallery}">
|
|
979
1271
|
${icons.image_gallery}
|
|
980
|
-
${
|
|
1272
|
+
${dom.utils.createTooltipInner(lang.imageGallery)}
|
|
981
1273
|
</button>`
|
|
982
1274
|
: ''
|
|
983
1275
|
}
|
|
@@ -994,13 +1286,13 @@ function CreateHTML_modal({ lang, icons, plugins }, pluginOptions) {
|
|
|
994
1286
|
<label class="se-modal-size-x"> </label>
|
|
995
1287
|
<label class="size-h">${lang.height}</label>
|
|
996
1288
|
</div>
|
|
997
|
-
<input class="se-input-control
|
|
1289
|
+
<input class="se-input-control _se_size_x" placeholder="auto" type="text" />
|
|
998
1290
|
<label class="se-modal-size-x">x</label>
|
|
999
|
-
<input type="text" class="se-input-control
|
|
1000
|
-
<label><input type="checkbox" class="se-modal-btn-check
|
|
1291
|
+
<input type="text" class="se-input-control _se_size_y" placeholder="auto" />
|
|
1292
|
+
<label><input type="checkbox" class="se-modal-btn-check _se_check_proportion" checked/> ${lang.proportion}</label>
|
|
1001
1293
|
<button type="button" aria-label="${lang.revert}" class="se-btn se-tooltip se-modal-btn-revert">
|
|
1002
1294
|
${icons.revert}
|
|
1003
|
-
${
|
|
1295
|
+
${dom.utils.createTooltipInner(lang.revert)}
|
|
1004
1296
|
</button>
|
|
1005
1297
|
</div>`;
|
|
1006
1298
|
|
|
@@ -1010,12 +1302,12 @@ function CreateHTML_modal({ lang, icons, plugins }, pluginOptions) {
|
|
|
1010
1302
|
<div class="se-modal-form">
|
|
1011
1303
|
<div class="se-modal-flex-form">
|
|
1012
1304
|
<button type="button" data-command="asBlock" class="se-btn se-tooltip" aria-label="${lang.inlineStyle}">
|
|
1013
|
-
${icons.
|
|
1014
|
-
${
|
|
1305
|
+
${icons.as_block}
|
|
1306
|
+
${dom.utils.createTooltipInner(lang.blockStyle)}
|
|
1015
1307
|
</button>
|
|
1016
1308
|
<button type="button" data-command="asInline" class="se-btn se-tooltip" aria-label="${lang.inlineStyle}">
|
|
1017
|
-
${icons.
|
|
1018
|
-
${
|
|
1309
|
+
${icons.as_inline}
|
|
1310
|
+
${dom.utils.createTooltipInner(lang.inlineStyle)}
|
|
1019
1311
|
</button>
|
|
1020
1312
|
</div>
|
|
1021
1313
|
</div>`;
|
|
@@ -1058,7 +1350,27 @@ function CreateHTML_modal({ lang, icons, plugins }, pluginOptions) {
|
|
|
1058
1350
|
</div>
|
|
1059
1351
|
</form>`;
|
|
1060
1352
|
|
|
1061
|
-
|
|
1353
|
+
const content = dom.utils.createElement('DIV', { class: 'se-modal-content' }, html);
|
|
1354
|
+
|
|
1355
|
+
return {
|
|
1356
|
+
html: content,
|
|
1357
|
+
alignForm: content.querySelector('.se-figure-align'),
|
|
1358
|
+
fileModalWrapper: content.querySelector('.se-flex-input-wrapper'),
|
|
1359
|
+
imgInputFile: content.querySelector('.__se__file_input'),
|
|
1360
|
+
imgUrlFile: content.querySelector('.se-input-url'),
|
|
1361
|
+
altText: content.querySelector('._se_image_alt'),
|
|
1362
|
+
captionCheckEl: content.querySelector('._se_image_check_caption'),
|
|
1363
|
+
previewSrc: content.querySelector('._se_tab_content_image .se-link-preview'),
|
|
1364
|
+
tabs: content.querySelector('.se-modal-tabs'),
|
|
1365
|
+
galleryButton: content.querySelector('.__se__gallery'),
|
|
1366
|
+
proportion: content.querySelector('._se_check_proportion'),
|
|
1367
|
+
inputX: content.querySelector('._se_size_x'),
|
|
1368
|
+
inputY: content.querySelector('._se_size_y'),
|
|
1369
|
+
revertBtn: content.querySelector('.se-modal-btn-revert'),
|
|
1370
|
+
asBlock: content.querySelector('[data-command="asBlock"]'),
|
|
1371
|
+
asInline: content.querySelector('[data-command="asInline"]'),
|
|
1372
|
+
fileRemoveBtn: content.querySelector('.se-file-remove')
|
|
1373
|
+
};
|
|
1062
1374
|
}
|
|
1063
1375
|
|
|
1064
1376
|
export default Image_;
|