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