jodit 4.1.16 → 4.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/CHANGELOG.md +22 -5
  2. package/es2015/jodit.css +82 -31
  3. package/es2015/jodit.fat.min.css +1 -1
  4. package/es2015/jodit.fat.min.js +2 -2
  5. package/es2015/jodit.js +1339 -543
  6. package/es2015/jodit.min.css +1 -1
  7. package/es2015/jodit.min.js +2 -2
  8. package/es2015/plugins/debug/debug.js +1 -1
  9. package/es2015/plugins/debug/debug.min.js +1 -1
  10. package/es2015/plugins/speech-recognize/speech-recognize.css +1 -1
  11. package/es2015/plugins/speech-recognize/speech-recognize.js +1 -1
  12. package/es2015/plugins/speech-recognize/speech-recognize.min.js +1 -1
  13. package/es2018/jodit.css +82 -31
  14. package/es2018/jodit.fat.min.css +1 -1
  15. package/es2018/jodit.fat.min.js +2 -2
  16. package/es2018/jodit.js +1325 -543
  17. package/es2018/jodit.min.css +1 -1
  18. package/es2018/jodit.min.js +2 -2
  19. package/es2018/plugins/debug/debug.js +1 -1
  20. package/es2018/plugins/debug/debug.min.js +1 -1
  21. package/es2018/plugins/speech-recognize/speech-recognize.css +1 -1
  22. package/es2018/plugins/speech-recognize/speech-recognize.js +1 -1
  23. package/es2018/plugins/speech-recognize/speech-recognize.min.js +1 -1
  24. package/es2021/jodit.css +82 -31
  25. package/es2021/jodit.fat.min.css +1 -1
  26. package/es2021/jodit.fat.min.js +2 -2
  27. package/es2021/jodit.js +1322 -543
  28. package/es2021/jodit.min.css +1 -1
  29. package/es2021/jodit.min.js +2 -2
  30. package/es2021/plugins/debug/debug.js +1 -1
  31. package/es2021/plugins/debug/debug.min.js +1 -1
  32. package/es2021/plugins/speech-recognize/speech-recognize.css +1 -1
  33. package/es2021/plugins/speech-recognize/speech-recognize.js +1 -1
  34. package/es2021/plugins/speech-recognize/speech-recognize.min.js +1 -1
  35. package/es2021.en/jodit.css +82 -31
  36. package/es2021.en/jodit.fat.min.css +1 -1
  37. package/es2021.en/jodit.fat.min.js +2 -2
  38. package/es2021.en/jodit.js +1322 -543
  39. package/es2021.en/jodit.min.css +1 -1
  40. package/es2021.en/jodit.min.js +2 -2
  41. package/es2021.en/plugins/debug/debug.js +1 -1
  42. package/es2021.en/plugins/debug/debug.min.js +1 -1
  43. package/es2021.en/plugins/speech-recognize/speech-recognize.css +1 -1
  44. package/es2021.en/plugins/speech-recognize/speech-recognize.js +1 -1
  45. package/es2021.en/plugins/speech-recognize/speech-recognize.min.js +1 -1
  46. package/es5/jodit.css +131 -35
  47. package/es5/jodit.fat.min.css +1 -1
  48. package/es5/jodit.fat.min.js +2 -2
  49. package/es5/jodit.js +1363 -479
  50. package/es5/jodit.min.css +3 -3
  51. package/es5/jodit.min.js +2 -2
  52. package/es5/plugins/debug/debug.js +1 -1
  53. package/es5/plugins/debug/debug.min.js +1 -1
  54. package/es5/plugins/speech-recognize/speech-recognize.css +1 -1
  55. package/es5/plugins/speech-recognize/speech-recognize.js +1 -1
  56. package/es5/plugins/speech-recognize/speech-recognize.min.js +1 -1
  57. package/esm/core/constants.js +1 -1
  58. package/esm/core/helpers/size/position.js +2 -2
  59. package/esm/core/helpers/utils/selector.d.ts +3 -1
  60. package/esm/core/helpers/utils/selector.js +3 -3
  61. package/esm/core/ui/button/tooltip/tooltip.js +2 -1
  62. package/esm/core/ui/popup/popup.js +1 -1
  63. package/esm/modules/dialog/dialog.js +1 -0
  64. package/esm/modules/file-browser/file-browser.js +8 -1
  65. package/esm/modules/image-editor/templates/form.js +6 -5
  66. package/esm/modules/toolbar/button/button.d.ts +1 -1
  67. package/esm/modules/widget/tabs/tabs.d.ts +4 -4
  68. package/esm/modules/widget/tabs/tabs.js +9 -7
  69. package/esm/plugins/ai-assistant/ai-assistant.d.ts +1 -1
  70. package/esm/plugins/ai-assistant/ai-assistant.js +3 -3
  71. package/esm/plugins/image-properties/config.d.ts +5 -83
  72. package/esm/plugins/image-properties/config.js +0 -3
  73. package/esm/plugins/image-properties/image-properties.d.ts +22 -32
  74. package/esm/plugins/image-properties/image-properties.js +129 -402
  75. package/{types/plugins/image-properties/templates/form.d.ts → esm/plugins/image-properties/readers/align.d.ts} +3 -5
  76. package/esm/plugins/image-properties/readers/align.js +24 -0
  77. package/esm/plugins/image-properties/readers/index.d.ts +12 -0
  78. package/esm/plugins/image-properties/readers/index.js +38 -0
  79. package/esm/plugins/image-properties/readers/link.d.ts +9 -0
  80. package/esm/plugins/image-properties/readers/link.js +19 -0
  81. package/esm/plugins/image-properties/readers/margin.d.ts +8 -0
  82. package/esm/plugins/image-properties/readers/margin.js +28 -0
  83. package/esm/plugins/image-properties/readers/size.d.ts +8 -0
  84. package/esm/plugins/image-properties/readers/size.js +36 -0
  85. package/esm/plugins/image-properties/ui/ui-image-form.d.ts +29 -0
  86. package/esm/plugins/image-properties/ui/ui-image-form.js +171 -0
  87. package/esm/plugins/image-properties/ui/ui-image-main-tab.d.ts +36 -0
  88. package/esm/plugins/image-properties/ui/ui-image-main-tab.js +179 -0
  89. package/esm/plugins/image-properties/ui/ui-image-position-tab.d.ts +36 -0
  90. package/esm/plugins/image-properties/ui/ui-image-position-tab.js +261 -0
  91. package/esm/plugins/image-properties/{templates/main-tab.d.ts → utils/open-image-editor.d.ts} +5 -3
  92. package/esm/plugins/image-properties/utils/open-image-editor.js +52 -0
  93. package/esm/plugins/image-properties/utils/open-image-popup.d.ts +9 -0
  94. package/esm/plugins/image-properties/utils/open-image-popup.js +34 -0
  95. package/esm/plugins/image-properties/utils/utils.d.ts +9 -0
  96. package/esm/plugins/image-properties/utils/utils.js +21 -0
  97. package/esm/plugins/image-properties/writers/index.d.ts +12 -0
  98. package/esm/plugins/image-properties/writers/index.js +53 -0
  99. package/esm/plugins/image-properties/{templates/form.d.ts → writers/link.d.ts} +2 -4
  100. package/esm/plugins/image-properties/writers/link.js +24 -0
  101. package/esm/plugins/image-properties/writers/margin.d.ts +8 -0
  102. package/esm/plugins/image-properties/writers/margin.js +33 -0
  103. package/esm/plugins/image-properties/writers/size.d.ts +7 -0
  104. package/esm/plugins/image-properties/writers/size.js +28 -0
  105. package/esm/plugins/select/config.d.ts +7 -0
  106. package/esm/plugins/select/config.js +2 -1
  107. package/esm/plugins/select/select.d.ts +7 -3
  108. package/esm/plugins/select/select.js +21 -4
  109. package/esm/types/ui.d.ts +1 -1
  110. package/package.json +1 -1
  111. package/types/core/helpers/utils/selector.d.ts +3 -1
  112. package/types/modules/toolbar/button/button.d.ts +1 -1
  113. package/types/modules/widget/tabs/tabs.d.ts +4 -4
  114. package/types/plugins/ai-assistant/ai-assistant.d.ts +1 -1
  115. package/types/plugins/image-properties/config.d.ts +5 -83
  116. package/types/plugins/image-properties/image-properties.d.ts +22 -32
  117. package/types/plugins/image-properties/{templates/main-tab.d.ts → readers/align.d.ts} +3 -5
  118. package/types/plugins/image-properties/readers/index.d.ts +12 -0
  119. package/types/plugins/image-properties/readers/link.d.ts +9 -0
  120. package/types/plugins/image-properties/readers/margin.d.ts +8 -0
  121. package/types/plugins/image-properties/readers/size.d.ts +8 -0
  122. package/types/plugins/image-properties/ui/ui-image-form.d.ts +29 -0
  123. package/types/plugins/image-properties/ui/ui-image-main-tab.d.ts +36 -0
  124. package/types/plugins/image-properties/ui/ui-image-position-tab.d.ts +36 -0
  125. package/types/plugins/image-properties/utils/open-image-editor.d.ts +12 -0
  126. package/types/plugins/image-properties/utils/open-image-popup.d.ts +9 -0
  127. package/types/plugins/image-properties/utils/utils.d.ts +9 -0
  128. package/types/plugins/image-properties/writers/index.d.ts +12 -0
  129. package/{esm/plugins/image-properties/templates/position-tab.d.ts → types/plugins/image-properties/writers/link.d.ts} +2 -4
  130. package/types/plugins/image-properties/writers/margin.d.ts +8 -0
  131. package/types/plugins/image-properties/writers/size.d.ts +7 -0
  132. package/types/plugins/select/config.d.ts +7 -0
  133. package/types/plugins/select/select.d.ts +7 -3
  134. package/types/types/ui.d.ts +1 -1
  135. package/esm/plugins/image-properties/templates/form.js +0 -26
  136. package/esm/plugins/image-properties/templates/main-tab.js +0 -47
  137. package/esm/plugins/image-properties/templates/position-tab.js +0 -66
  138. package/types/plugins/image-properties/templates/position-tab.d.ts +0 -10
@@ -13,17 +13,18 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
13
13
  r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
14
14
  return c > 3 && r && Object.defineProperty(target, key, r), r;
15
15
  };
16
- import { autobind, watch } from "jodit/esm/core/decorators/index.js";
16
+ import { cache, cached, watch } from "jodit/esm/core/decorators/index.js";
17
+ import { Dom } from "jodit/esm/core/dom/dom.js";
17
18
  import { pluginSystem } from "jodit/esm/core/global.js";
18
- import { attr, css, hAlignElement, isArray, isNumeric, isString, kebabCase, markOwner, position, refs, trim } from "jodit/esm/core/helpers/index.js";
19
+ import { isNumeric, markOwner } from "jodit/esm/core/helpers/index.js";
20
+ import { Plugin } from "jodit/esm/core/plugin/plugin.js";
19
21
  import { Button } from "jodit/esm/core/ui/button/index.js";
20
- import { Dom, Icon, Plugin, Popup } from "jodit/esm/modules/index.js";
21
- import { openImageEditor } from "jodit/esm/modules/image-editor/image-editor.js";
22
- import { FileSelectorWidget, TabsWidget } from "jodit/esm/modules/widget/index.js";
23
22
  import "./config";
24
- import { form } from "./templates/form";
25
- import { mainTab } from "./templates/main-tab";
26
- import { positionTab } from "./templates/position-tab";
23
+ import { UIImagePropertiesForm } from "./ui/ui-image-form";
24
+ import { openImageEditorDialog } from "./utils/open-image-editor";
25
+ import { openImagePopup } from "./utils/open-image-popup";
26
+ import { readValuesFromImage } from "./readers";
27
+ import { applyValuesToImage } from "./writers";
27
28
  /**
28
29
  * Plug-in for image editing window
29
30
  *
@@ -37,15 +38,6 @@ import { positionTab } from "./templates/position-tab";
37
38
  * });
38
39
  * ```
39
40
  */
40
- const normalSizeToString = (value) => {
41
- value = trim(value);
42
- return /^[0-9]+$/.test(value) ? value + 'px' : value;
43
- };
44
- const normalSizeFromString = (value) => {
45
- return /^[-+]?[0-9.]+px$/.test(value.toString())
46
- ? parseFloat(value.toString())
47
- : value;
48
- };
49
41
  /**
50
42
  * Show dialog with image's options
51
43
  */
@@ -54,38 +46,85 @@ export class imageProperties extends Plugin {
54
46
  super(...arguments);
55
47
  this.state = {
56
48
  image: new Image(),
49
+ sourceImage: new Image(),
57
50
  get ratio() {
58
- return this.image.naturalWidth / this.image.naturalHeight || 1;
51
+ const { naturalWidth, naturalHeight } = this.image;
52
+ return naturalWidth / naturalHeight || 1;
59
53
  },
60
54
  sizeIsLocked: true,
61
- marginIsLocked: true
55
+ marginIsLocked: true,
56
+ values: {
57
+ style: '',
58
+ imageSrc: '',
59
+ borderRadius: 0,
60
+ imageTitle: '',
61
+ imageAlt: '',
62
+ imageLink: '',
63
+ imageLinkOpenInNewTab: false,
64
+ imageWidth: 0,
65
+ imageHeight: 0,
66
+ marginTop: 0,
67
+ marginRight: 0,
68
+ marginBottom: 0,
69
+ marginLeft: 0,
70
+ classes: '',
71
+ id: '',
72
+ align: ''
73
+ }
62
74
  };
63
75
  this.activeTabState = {
64
- __activeTab: 'Image'
76
+ activeTab: 'Image'
65
77
  };
66
78
  }
67
- onChangeMarginIsLocked() {
68
- if (!this.form) {
69
- return;
70
- }
71
- const { marginRight, marginBottom, marginLeft, lockMargin } = refs(this.form);
72
- [marginRight, marginBottom, marginLeft].forEach(elm => {
73
- attr(elm, 'disabled', this.state.marginIsLocked || null);
79
+ get form() {
80
+ return new UIImagePropertiesForm(this.j, this.state, this.activeTabState, {
81
+ openImageEditor: () => openImageEditorDialog(this.j, this.state),
82
+ openImagePopup: target => openImagePopup(this.j, this.dialog, this.state, target)
74
83
  });
75
- lockMargin.innerHTML = Icon.get(this.state.marginIsLocked ? 'lock' : 'unlock');
76
84
  }
77
- onChangeSizeIsLocked() {
78
- if (!this.form) {
79
- return;
80
- }
81
- const { lockSize, imageWidth } = refs(this.form);
82
- lockSize.innerHTML = Icon.get(this.state.sizeIsLocked ? 'lock' : 'unlock');
83
- lockSize.classList.remove('jodit-properties__lock');
84
- lockSize.classList.remove('jodit-properties__unlock');
85
- lockSize.classList.add(this.state.sizeIsLocked
86
- ? 'jodit-properties__lock'
87
- : 'jodit-properties__unlock');
88
- this.j.e.fire(imageWidth, 'change');
85
+ /**
86
+ * Dialog for form
87
+ */
88
+ get dialog() {
89
+ const { j } = this;
90
+ const dialog = j.dlg({
91
+ minWidth: Math.min(400, screen.width),
92
+ minHeight: 590,
93
+ buttons: ['fullsize', 'dialog.close']
94
+ });
95
+ const buttons = this.__buttons;
96
+ buttons.check.onAction(() => {
97
+ applyValuesToImage(j, this.state, this.state.sourceImage);
98
+ j.synchronizeValues();
99
+ dialog.close();
100
+ });
101
+ buttons.remove.onAction(() => {
102
+ j.s.removeNode(this.state.sourceImage);
103
+ dialog.close();
104
+ });
105
+ buttons.cancel.onAction(() => {
106
+ dialog.close();
107
+ });
108
+ dialog.setHeader(j.i18n('Image properties'));
109
+ dialog.setContent(this.form);
110
+ dialog.setFooter([[buttons.cancel, buttons.remove], buttons.check]);
111
+ j.e.on(dialog, 'afterClose', () => {
112
+ if (this.state.image.parentNode &&
113
+ j.o.image.selectImageAfterClose) {
114
+ j.s.select(this.state.sourceImage);
115
+ }
116
+ });
117
+ dialog.setSize(j.o.image.dialogWidth);
118
+ markOwner(j, dialog.container);
119
+ return dialog;
120
+ }
121
+ get __buttons() {
122
+ const { j } = this;
123
+ return {
124
+ check: Button(j, 'ok', 'Apply', 'primary'),
125
+ remove: Button(j, 'bin', 'Delete'),
126
+ cancel: Button(j, 'cancel', 'Cancel')
127
+ };
89
128
  }
90
129
  /**
91
130
  * Open dialog editing image properties
@@ -102,358 +141,24 @@ export class imageProperties extends Plugin {
102
141
  * ```
103
142
  */
104
143
  open() {
105
- this.makeForm();
106
- this.activeTabState.__activeTab = 'Image';
107
- this.j.e.fire('hidePopup');
108
- markOwner(this.j, this.dialog.container);
109
- this.state.marginIsLocked = true;
110
- this.state.sizeIsLocked = true;
111
- this.onChangeMarginIsLocked();
112
- this.onChangeSizeIsLocked();
113
- this.updateValues();
144
+ this.activeTabState.activeTab = 'Image';
145
+ this.__lock();
114
146
  this.dialog.open().setModal(true).setPosition();
147
+ this.async
148
+ .promise((resolve, reject) => readValuesFromImage(this.j, this.state).then(resolve, reject))
149
+ .catch((e) => this.dialog.message.error(e.message))
150
+ .finally(() => this.__unlock());
115
151
  return false;
116
152
  }
117
- /**
118
- * Create form for edit image properties
119
- */
120
- makeForm() {
121
- if (this.dialog) {
122
- return;
123
- }
124
- this.dialog = this.j.dlg({
125
- minWidth: Math.min(400, screen.width),
126
- minHeight: 590,
127
- buttons: ['fullsize', 'dialog.close']
128
- });
129
- const editor = this.j, opt = editor.o, i18n = editor.i18n.bind(editor), buttons = {
130
- check: Button(editor, 'ok', 'Apply', 'primary'),
131
- remove: Button(editor, 'bin', 'Delete')
132
- };
133
- editor.e.on(this.dialog, 'afterClose', () => {
134
- if (this.state.image.parentNode &&
135
- opt.image.selectImageAfterClose) {
136
- editor.s.select(this.state.image);
137
- }
138
- });
139
- buttons.remove.onAction(() => {
140
- editor.s.removeNode(this.state.image);
141
- this.dialog.close();
142
- });
143
- const { dialog } = this;
144
- dialog.setHeader(i18n('Image properties'));
145
- const mainForm = form(editor);
146
- this.form = mainForm;
147
- dialog.setContent(mainForm);
148
- const { tabsBox } = refs(this.form);
149
- if (tabsBox) {
150
- tabsBox.appendChild(TabsWidget(editor, [
151
- { name: 'Image', content: mainTab(editor) },
152
- { name: 'Advanced', content: positionTab(editor) }
153
- ], this.activeTabState));
154
- }
155
- buttons.check.onAction(this.onApply);
156
- const { changeImage, editImage } = refs(this.form);
157
- editor.e.on(changeImage, 'click', this.openImagePopup);
158
- if (opt.image.useImageEditor) {
159
- editor.e.on(editImage, 'click', this.openImageEditor);
160
- }
161
- const { lockSize, lockMargin, imageWidth, imageHeight } = refs(mainForm);
162
- if (lockSize) {
163
- editor.e.on(lockSize, 'click', () => {
164
- this.state.sizeIsLocked = !this.state.sizeIsLocked;
165
- });
166
- }
167
- editor.e.on(lockMargin, 'click', (e) => {
168
- this.state.marginIsLocked = !this.state.marginIsLocked;
169
- e.preventDefault();
170
- });
171
- const changeSizes = (event) => {
172
- if (!isNumeric(imageWidth.value) || !isNumeric(imageHeight.value)) {
173
- return;
174
- }
175
- const w = parseFloat(imageWidth.value), h = parseFloat(imageHeight.value);
176
- if (event.target === imageWidth) {
177
- imageHeight.value = Math.round(w / this.state.ratio).toString();
178
- }
179
- else {
180
- imageWidth.value = Math.round(h * this.state.ratio).toString();
181
- }
182
- };
183
- editor.e.on([imageWidth, imageHeight], 'change keydown mousedown paste', (event) => {
184
- if (!this.state.sizeIsLocked) {
185
- return;
186
- }
187
- editor.async.setTimeout(changeSizes.bind(this, event), {
188
- timeout: editor.defaultTimeout,
189
- label: 'image-properties-changeSize'
190
- });
191
- });
192
- dialog.setFooter([buttons.remove, buttons.check]);
193
- dialog.setSize(this.j.o.image.dialogWidth);
153
+ __lock() {
154
+ this.dialog.lock();
155
+ this.form.setMod('lock', true);
156
+ Object.values(this.__buttons).forEach(b => (b.state.disabled = true));
194
157
  }
195
- /**
196
- * Set input values from image
197
- */
198
- updateValues() {
199
- const opt = this.j.o;
200
- const { image } = this.state;
201
- const { marginTop, marginRight, marginBottom, marginLeft, lockMargin, imageSrc, id, classes, align, style, imageTitle, imageAlt, borderRadius, imageLink, imageWidth, imageHeight, imageLinkOpenInNewTab, imageViewSrc, lockSize } = refs(this.form);
202
- const updateLock = () => {
203
- lockMargin.checked = this.state.marginIsLocked;
204
- lockSize.checked = this.state.sizeIsLocked;
205
- }, updateAlign = () => {
206
- if (image.style.cssFloat &&
207
- ['left', 'right'].indexOf(image.style.cssFloat.toLowerCase()) !== -1) {
208
- align.value = css(image, 'float');
209
- }
210
- else {
211
- if (css(image, 'display') === 'block' &&
212
- image.style.marginLeft === 'auto' &&
213
- image.style.marginRight === 'auto') {
214
- align.value = 'center';
215
- }
216
- }
217
- }, updateBorderRadius = () => {
218
- borderRadius.value = (parseInt(image.style.borderRadius || '0', 10) || '0').toString();
219
- }, updateId = () => {
220
- id.value = attr(image, 'id') || '';
221
- }, updateStyle = () => {
222
- style.value = attr(image, 'style') || '';
223
- }, updateClasses = () => {
224
- classes.value = (attr(image, 'class') || '').replace(/jodit_focused_image[\s]*/, '');
225
- }, updateMargins = () => {
226
- if (!opt.image.editMargins) {
227
- return;
228
- }
229
- let equal = true, wasEmptyField = false;
230
- [marginTop, marginRight, marginBottom, marginLeft].forEach(elm => {
231
- const id = attr(elm, 'data-ref') || '';
232
- let value = image.style.getPropertyValue(kebabCase(id));
233
- if (!value) {
234
- wasEmptyField = true;
235
- elm.value = '';
236
- return;
237
- }
238
- if (/^[0-9]+(px)?$/.test(value)) {
239
- value = parseInt(value, 10);
240
- }
241
- elm.value = value.toString() || '';
242
- if ((wasEmptyField && elm.value) ||
243
- (equal &&
244
- id !== 'marginTop' &&
245
- elm.value !== marginTop.value)) {
246
- equal = false;
247
- }
248
- });
249
- this.state.marginIsLocked = equal;
250
- }, updateSizes = () => {
251
- const width = attr(image, 'width') ||
252
- css(image, 'width', true) ||
253
- false, height = attr(image, 'height') ||
254
- css(image, 'height', true) ||
255
- false;
256
- imageWidth.value =
257
- width !== false
258
- ? normalSizeFromString(width).toString()
259
- : image.offsetWidth.toString();
260
- imageHeight.value =
261
- height !== false
262
- ? normalSizeFromString(height).toString()
263
- : image.offsetHeight.toString();
264
- this.state.sizeIsLocked = (() => {
265
- if (!isNumeric(imageWidth.value) ||
266
- !isNumeric(imageHeight.value)) {
267
- return false;
268
- }
269
- const w = parseFloat(imageWidth.value), h = parseFloat(imageHeight.value);
270
- return Math.abs(w - h * this.state.ratio) < 1;
271
- })();
272
- }, updateText = () => {
273
- imageTitle.value = attr(image, 'title') || '';
274
- imageAlt.value = attr(image, 'alt') || '';
275
- const a = Dom.closest(image, 'a', this.j.editor);
276
- if (a) {
277
- imageLink.value = attr(a, 'href') || '';
278
- imageLinkOpenInNewTab.checked =
279
- attr(a, 'target') === '_blank';
280
- }
281
- else {
282
- imageLink.value = '';
283
- imageLinkOpenInNewTab.checked = false;
284
- }
285
- }, updateSrc = () => {
286
- imageSrc.value = attr(image, 'src') || '';
287
- if (imageViewSrc) {
288
- attr(imageViewSrc, 'src', attr(image, 'src') || '');
289
- }
290
- };
291
- updateLock();
292
- updateSrc();
293
- updateText();
294
- updateSizes();
295
- updateMargins();
296
- updateClasses();
297
- updateId();
298
- updateBorderRadius();
299
- updateAlign();
300
- updateStyle();
301
- }
302
- /**
303
- * Apply form's values to image
304
- */
305
- onApply() {
306
- const { style, imageSrc, borderRadius, imageTitle, imageAlt, imageLink, imageWidth, imageHeight, marginTop, marginRight, marginBottom, marginLeft, imageLinkOpenInNewTab, align, classes, id } = refs(this.form);
307
- const opt = this.j.o;
308
- const { image } = this.state;
309
- // styles
310
- if (opt.image.editStyle) {
311
- attr(image, 'style', style.value || null);
312
- }
313
- // Src
314
- if (imageSrc.value) {
315
- attr(image, 'src', imageSrc.value);
316
- }
317
- else {
318
- Dom.safeRemove(image);
319
- this.dialog.close();
320
- return;
321
- }
322
- // Border radius
323
- if (borderRadius.value !== '0' && /^[0-9]+$/.test(borderRadius.value)) {
324
- image.style.borderRadius = borderRadius.value + 'px';
325
- }
326
- else {
327
- image.style.borderRadius = '';
328
- }
329
- // Title
330
- attr(image, 'title', imageTitle.value || null);
331
- // Alt
332
- attr(image, 'alt', imageAlt.value || null);
333
- // Link
334
- let link = Dom.closest(image, 'a', this.j.editor);
335
- if (imageLink.value) {
336
- if (!link) {
337
- link = Dom.wrap(image, 'a', this.j.createInside);
338
- }
339
- attr(link, 'href', imageLink.value);
340
- attr(link, 'target', imageLinkOpenInNewTab.checked ? '_blank' : null);
341
- }
342
- else {
343
- if (link && link.parentNode) {
344
- link.parentNode.replaceChild(image, link);
345
- }
346
- }
347
- // Size
348
- if (imageWidth.value !== image.offsetWidth.toString() ||
349
- imageHeight.value !== image.offsetHeight.toString()) {
350
- const updatedtWidth = trim(imageWidth.value)
351
- ? normalSizeToString(imageWidth.value)
352
- : null;
353
- const updatedHeight = trim(imageHeight.value)
354
- ? normalSizeToString(imageHeight.value)
355
- : null;
356
- css(image, {
357
- width: updatedtWidth,
358
- height: updatedHeight
359
- });
360
- attr(image, 'width', attr(image, 'width') ? updatedtWidth : null);
361
- attr(image, 'height', attr(image, 'height') ? updatedHeight : null);
362
- }
363
- const margins = [marginTop, marginRight, marginBottom, marginLeft];
364
- if (opt.image.editMargins) {
365
- if (!this.state.marginIsLocked) {
366
- margins.forEach((margin) => {
367
- const side = attr(margin, 'data-ref') || '';
368
- css(image, side, normalSizeToString(margin.value));
369
- });
370
- }
371
- else {
372
- css(image, 'margin', normalSizeToString(marginTop.value));
373
- }
374
- }
375
- if (opt.image.editClass) {
376
- attr(image, 'class', classes.value || null);
377
- }
378
- if (opt.image.editId) {
379
- attr(image, 'id', id.value || null);
380
- }
381
- if (opt.image.editAlign) {
382
- hAlignElement(image, align.value);
383
- }
384
- this.j.synchronizeValues();
385
- this.dialog.close();
386
- }
387
- /**
388
- * Open image editor dialog
389
- */
390
- openImageEditor() {
391
- const url = attr(this.state.image, 'src') || '', a = this.j.c.element('a'), loadExternal = () => {
392
- if (a.host !== location.host) {
393
- this.j.confirm('You can only edit your own images. Download this image on the host?', yes => {
394
- if (yes && this.j.uploader) {
395
- this.j.uploader.uploadRemoteImage(a.href.toString(), resp => {
396
- this.j.alert('The image has been successfully uploaded to the host!', () => {
397
- if (isString(resp.newfilename)) {
398
- attr(this.state.image, 'src', resp.baseurl +
399
- resp.newfilename);
400
- this.updateValues();
401
- }
402
- });
403
- }, error => {
404
- this.j.alert('There was an error loading %s', error.message);
405
- });
406
- }
407
- });
408
- return;
409
- }
410
- };
411
- a.href = url;
412
- this.j.filebrowser.dataProvider
413
- .getPathByUrl(a.href.toString())
414
- .then(resp => {
415
- openImageEditor.call(this.j.filebrowser, a.href, resp.name, resp.path, resp.source, () => {
416
- const timestamp = new Date().getTime();
417
- attr(this.state.image, 'src', url +
418
- (url.indexOf('?') !== -1 ? '' : '?') +
419
- '&_tmp=' +
420
- timestamp.toString());
421
- this.updateValues();
422
- }, error => {
423
- this.j.alert(error.message);
424
- });
425
- })
426
- .catch(error => {
427
- this.j.alert(error.message, loadExternal);
428
- });
429
- }
430
- /**
431
- * Open popup with filebrowser/uploader buttons for image
432
- */
433
- openImagePopup(event) {
434
- const popup = new Popup(this.j), { changeImage } = refs(this.form);
435
- popup.setZIndex(this.dialog.getZIndex() + 1);
436
- popup
437
- .setContent(FileSelectorWidget(this.j, {
438
- upload: (data) => {
439
- if (data.files && data.files.length) {
440
- attr(this.state.image, 'src', data.baseurl + data.files[0]);
441
- }
442
- this.updateValues();
443
- popup.close();
444
- },
445
- filebrowser: (data) => {
446
- if (data &&
447
- isArray(data.files) &&
448
- data.files.length) {
449
- attr(this.state.image, 'src', data.files[0]);
450
- popup.close();
451
- this.updateValues();
452
- }
453
- }
454
- }, this.state.image, popup.close))
455
- .open(() => position(changeImage));
456
- event.stopPropagation();
158
+ __unlock() {
159
+ this.dialog.unlock();
160
+ this.form.setMod('lock', false);
161
+ Object.values(this.__buttons).forEach(b => (b.state.disabled = false));
457
162
  }
458
163
  /** @override **/
459
164
  afterInit(editor) {
@@ -472,7 +177,8 @@ export class imageProperties extends Plugin {
472
177
  false) {
473
178
  return;
474
179
  }
475
- self.state.image = image;
180
+ self.state.sourceImage = image;
181
+ self.state.image = image.cloneNode(true);
476
182
  if (!editor.o.readonly) {
477
183
  e.stopImmediatePropagation();
478
184
  e.preventDefault();
@@ -486,29 +192,50 @@ export class imageProperties extends Plugin {
486
192
  });
487
193
  })
488
194
  .on('openImageProperties.imageproperties', (image) => {
489
- this.state.image = image;
195
+ self.state.sourceImage = image;
196
+ this.state.image = image.cloneNode(true);
490
197
  this.open();
491
198
  });
492
199
  }
200
+ async onStateValuesImageSrcChange() {
201
+ const { image, values } = this.state;
202
+ if (!image.src) {
203
+ return;
204
+ }
205
+ try {
206
+ this.__lock();
207
+ await image.decode();
208
+ if (this.state.sizeIsLocked && isNumeric(values.imageWidth)) {
209
+ const w = parseFloat(values.imageWidth.toString());
210
+ values.imageHeight = Math.round(w / this.state.ratio);
211
+ }
212
+ this.j.e.fire('updateImageProperties.imageproperties', image);
213
+ }
214
+ catch (e) {
215
+ this.j.alert(e.message);
216
+ }
217
+ finally {
218
+ this.__unlock();
219
+ }
220
+ }
493
221
  /** @override */
494
222
  beforeDestruct(editor) {
495
- this.dialog && this.dialog.destruct();
223
+ Object.values(cached(this, '__buttons') ?? {}).forEach(b => b.destruct());
224
+ cached(this, 'dialog')?.destruct();
225
+ cached(this, 'form')?.destruct();
496
226
  editor.e.off(editor.editor, '.imageproperties').off('.imageproperties');
497
227
  }
498
228
  }
499
229
  __decorate([
500
- watch('state.marginIsLocked')
501
- ], imageProperties.prototype, "onChangeMarginIsLocked", null);
502
- __decorate([
503
- watch('state.sizeIsLocked')
504
- ], imageProperties.prototype, "onChangeSizeIsLocked", null);
230
+ cache
231
+ ], imageProperties.prototype, "form", null);
505
232
  __decorate([
506
- autobind
507
- ], imageProperties.prototype, "onApply", null);
233
+ cache
234
+ ], imageProperties.prototype, "dialog", null);
508
235
  __decorate([
509
- autobind
510
- ], imageProperties.prototype, "openImageEditor", null);
236
+ cache
237
+ ], imageProperties.prototype, "__buttons", null);
511
238
  __decorate([
512
- autobind
513
- ], imageProperties.prototype, "openImagePopup", null);
239
+ watch('state.image')
240
+ ], imageProperties.prototype, "onStateValuesImageSrcChange", null);
514
241
  pluginSystem.add('imageProperties', imageProperties);
@@ -3,8 +3,6 @@
3
3
  * Released under MIT see LICENSE.txt in the project root for license information.
4
4
  * Copyright (c) 2013-2024 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
5
5
  */
6
- /**
7
- * @module plugins/image-properties
8
- */
9
- import type { IJodit } from "jodit/esm/types";
10
- export declare function form(editor: IJodit): HTMLElement;
6
+ import type { EditValues } from "../interface";
7
+ /** @private */
8
+ export declare function readAlign(image: HTMLImageElement, values: EditValues): void;
@@ -0,0 +1,24 @@
1
+ /*!
2
+ * Jodit Editor (https://xdsoft.net/jodit/)
3
+ * Released under MIT see LICENSE.txt in the project root for license information.
4
+ * Copyright (c) 2013-2024 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
5
+ */
6
+ import { css } from "jodit/esm/core/helpers/utils/css.js";
7
+ /** @private */
8
+ export function readAlign(image, values) {
9
+ // Align
10
+ if (image.style.cssFloat &&
11
+ ['left', 'right'].indexOf(image.style.cssFloat.toLowerCase()) !== -1) {
12
+ values.align = css(image, 'float');
13
+ }
14
+ else {
15
+ if (css(image, 'display') === 'block' &&
16
+ image.style.marginLeft === 'auto' &&
17
+ image.style.marginRight === 'auto') {
18
+ values.align = 'center';
19
+ }
20
+ else {
21
+ values.align = '';
22
+ }
23
+ }
24
+ }
@@ -0,0 +1,12 @@
1
+ /*!
2
+ * Jodit Editor (https://xdsoft.net/jodit/)
3
+ * Released under MIT see LICENSE.txt in the project root for license information.
4
+ * Copyright (c) 2013-2024 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
5
+ */
6
+ import type { IJodit } from "jodit/esm/types";
7
+ import type { ImagePropertiesState } from "../interface";
8
+ /**
9
+ * Read values from image and set it to state
10
+ * @private
11
+ */
12
+ export declare function readValuesFromImage(j: IJodit, state: ImagePropertiesState): Promise<void>;