jodit 4.15.16 → 4.15.18

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 (69) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/es2015/jodit.css +1 -1
  3. package/es2015/jodit.fat.min.js +7 -7
  4. package/es2015/jodit.js +165 -48
  5. package/es2015/jodit.min.js +7 -7
  6. package/es2015/plugins/debug/debug.css +1 -1
  7. package/es2015/plugins/debug/debug.js +1 -1
  8. package/es2015/plugins/debug/debug.min.js +1 -1
  9. package/es2015/plugins/speech-recognize/speech-recognize.css +1 -1
  10. package/es2015/plugins/speech-recognize/speech-recognize.js +1 -1
  11. package/es2015/plugins/speech-recognize/speech-recognize.min.js +1 -1
  12. package/es2018/jodit.fat.min.js +4 -4
  13. package/es2018/jodit.min.js +7 -7
  14. package/es2018/plugins/debug/debug.min.js +1 -1
  15. package/es2018/plugins/speech-recognize/speech-recognize.min.js +1 -1
  16. package/es2021/jodit.css +1 -1
  17. package/es2021/jodit.fat.min.js +8 -8
  18. package/es2021/jodit.js +162 -48
  19. package/es2021/jodit.min.js +12 -12
  20. package/es2021/plugins/debug/debug.css +1 -1
  21. package/es2021/plugins/debug/debug.js +1 -1
  22. package/es2021/plugins/debug/debug.min.js +1 -1
  23. package/es2021/plugins/speech-recognize/speech-recognize.css +1 -1
  24. package/es2021/plugins/speech-recognize/speech-recognize.js +1 -1
  25. package/es2021/plugins/speech-recognize/speech-recognize.min.js +1 -1
  26. package/es2021.en/jodit.css +1 -1
  27. package/es2021.en/jodit.fat.min.js +8 -8
  28. package/es2021.en/jodit.js +162 -48
  29. package/es2021.en/jodit.min.js +8 -8
  30. package/es2021.en/plugins/debug/debug.css +1 -1
  31. package/es2021.en/plugins/debug/debug.js +1 -1
  32. package/es2021.en/plugins/debug/debug.min.js +1 -1
  33. package/es2021.en/plugins/speech-recognize/speech-recognize.css +1 -1
  34. package/es2021.en/plugins/speech-recognize/speech-recognize.js +1 -1
  35. package/es2021.en/plugins/speech-recognize/speech-recognize.min.js +1 -1
  36. package/es5/jodit.css +2 -2
  37. package/es5/jodit.fat.min.js +2 -2
  38. package/es5/jodit.js +213 -77
  39. package/es5/jodit.min.css +2 -2
  40. package/es5/jodit.min.js +2 -2
  41. package/es5/plugins/debug/debug.css +1 -1
  42. package/es5/plugins/debug/debug.js +1 -1
  43. package/es5/plugins/debug/debug.min.js +1 -1
  44. package/es5/plugins/speech-recognize/speech-recognize.css +1 -1
  45. package/es5/plugins/speech-recognize/speech-recognize.js +1 -1
  46. package/es5/plugins/speech-recognize/speech-recognize.min.js +1 -1
  47. package/es5/polyfills.fat.min.js +1 -1
  48. package/es5/polyfills.js +1 -1
  49. package/es5/polyfills.min.js +1 -1
  50. package/esm/config.d.ts +23 -0
  51. package/esm/config.js +21 -0
  52. package/esm/core/constants.js +1 -1
  53. package/esm/core/helpers/utils/align.d.ts +8 -3
  54. package/esm/core/helpers/utils/align.js +40 -2
  55. package/esm/core/selection/selection.js +5 -0
  56. package/esm/plugins/focus/focus.js +17 -1
  57. package/esm/plugins/image-processor/image-processor.js +20 -1
  58. package/esm/plugins/image-properties/readers/align.d.ts +5 -1
  59. package/esm/plugins/image-properties/readers/align.js +4 -18
  60. package/esm/plugins/image-properties/readers/index.js +1 -1
  61. package/esm/plugins/image-properties/writers/index.js +1 -1
  62. package/esm/plugins/image-properties/writers/margin.js +5 -3
  63. package/esm/plugins/inline-popup/config/items/img.js +24 -2
  64. package/esm/types/types.d.ts +4 -0
  65. package/package.json +1 -1
  66. package/types/config.d.ts +23 -0
  67. package/types/core/helpers/utils/align.d.ts +8 -3
  68. package/types/plugins/image-properties/readers/align.d.ts +5 -1
  69. package/types/types/types.d.ts +4 -0
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * jodit - Jodit is an awesome and useful wysiwyg editor with filebrowser
3
3
  * Author: Chupurnov <chupurnov@gmail.com> (https://xdsoft.net/jodit/)
4
- * Version: v4.15.16
4
+ * Version: v4.15.18
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * jodit - Jodit is an awesome and useful wysiwyg editor with filebrowser
3
3
  * Author: Chupurnov <chupurnov@gmail.com> (https://xdsoft.net/jodit/)
4
- * Version: v4.15.16
4
+ * Version: v4.15.18
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * jodit - Jodit is an awesome and useful wysiwyg editor with filebrowser
3
3
  * Author: Chupurnov <chupurnov@gmail.com> (https://xdsoft.net/jodit/)
4
- * Version: v4.15.16
4
+ * Version: v4.15.18
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * jodit - Jodit is an awesome and useful wysiwyg editor with filebrowser
3
3
  * Author: Chupurnov <chupurnov@gmail.com> (https://xdsoft.net/jodit/)
4
- * Version: v4.15.16
4
+ * Version: v4.15.18
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * jodit - Jodit is an awesome and useful wysiwyg editor with filebrowser
3
3
  * Author: Chupurnov <chupurnov@gmail.com> (https://xdsoft.net/jodit/)
4
- * Version: v4.15.16
4
+ * Version: v4.15.18
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * jodit - Jodit is an awesome and useful wysiwyg editor with filebrowser
3
3
  * Author: Chupurnov <chupurnov@gmail.com> (https://xdsoft.net/jodit/)
4
- * Version: v4.15.16
4
+ * Version: v4.15.18
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * jodit - Jodit is an awesome and useful wysiwyg editor with filebrowser
3
3
  * Author: Chupurnov <chupurnov@gmail.com> (https://xdsoft.net/jodit/)
4
- * Version: v4.15.16
4
+ * Version: v4.15.18
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
package/es5/polyfills.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * jodit - Jodit is an awesome and useful wysiwyg editor with filebrowser
3
3
  * Author: Chupurnov <chupurnov@gmail.com> (https://xdsoft.net/jodit/)
4
- * Version: v4.15.16
4
+ * Version: v4.15.18
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
@@ -1,7 +1,7 @@
1
1
  /*!
2
2
  * jodit - Jodit is an awesome and useful wysiwyg editor with filebrowser
3
3
  * Author: Chupurnov <chupurnov@gmail.com> (https://xdsoft.net/jodit/)
4
- * Version: v4.15.16
4
+ * Version: v4.15.18
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
package/esm/config.d.ts CHANGED
@@ -23,6 +23,8 @@ import type { Attributes } from "./types/index";
23
23
  import type { Controls } from "./types/index";
24
24
  import type { IAsyncStorageOptions } from "./types/index";
25
25
  import type { IExtraPlugin } from "./types/index";
26
+ import type { ImageAlignClasses } from "./types/index";
27
+ import type { ImageHAlign } from "./types/index";
26
28
  import type { IUIButtonState } from "./types/index";
27
29
  import type { IViewOptions } from "./types/index";
28
30
  import type { NodeFunction } from "./types/index";
@@ -631,6 +633,27 @@ declare class Config implements IViewOptions {
631
633
  * Default width (in pixels) applied to images inserted into the editor
632
634
  */
633
635
  imageDefaultWidth: number;
636
+ /**
637
+ * Alignment given to images inserted into the editor. `'normal'` leaves
638
+ * them unaligned
639
+ */
640
+ imageDefaultAlign: ImageHAlign;
641
+ /**
642
+ * Class names to align images with, instead of an inline `float` or
643
+ * `margin`. Aligning an image removes every class listed here and adds the
644
+ * chosen alignment's, which can be several separated by spaces.
645
+ *
646
+ * ```javascript
647
+ * Jodit.make('#editor', {
648
+ * imageAlignClasses: {
649
+ * left: 'align-left',
650
+ * right: 'align-right',
651
+ * center: 'align-center'
652
+ * }
653
+ * });
654
+ * ```
655
+ */
656
+ imageAlignClasses: Nullable<ImageAlignClasses>;
634
657
  /**
635
658
  * Do not display these buttons that are on the list
636
659
  *
package/esm/config.js CHANGED
@@ -740,6 +740,27 @@ class Config {
740
740
  * Default width (in pixels) applied to images inserted into the editor
741
741
  */
742
742
  this.imageDefaultWidth = 300;
743
+ /**
744
+ * Alignment given to images inserted into the editor. `'normal'` leaves
745
+ * them unaligned
746
+ */
747
+ this.imageDefaultAlign = 'normal';
748
+ /**
749
+ * Class names to align images with, instead of an inline `float` or
750
+ * `margin`. Aligning an image removes every class listed here and adds the
751
+ * chosen alignment's, which can be several separated by spaces.
752
+ *
753
+ * ```javascript
754
+ * Jodit.make('#editor', {
755
+ * imageAlignClasses: {
756
+ * left: 'align-left',
757
+ * right: 'align-right',
758
+ * center: 'align-center'
759
+ * }
760
+ * });
761
+ * ```
762
+ */
763
+ this.imageAlignClasses = null;
743
764
  /**
744
765
  * Do not display these buttons that are on the list
745
766
  *
@@ -3,7 +3,7 @@
3
3
  * Released under MIT see LICENSE.txt in the project root for license information.
4
4
  * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
5
5
  */
6
- export const APP_VERSION = "4.15.16";
6
+ export const APP_VERSION = "4.15.18";
7
7
  // prettier-ignore
8
8
  export const ES = "es2020";
9
9
  export const IS_ES_MODERN = true;
@@ -6,11 +6,16 @@
6
6
  /**
7
7
  * @module helpers/utils
8
8
  */
9
- import type { ImageHAlign } from "../../../types/index";
9
+ import type { ImageAlignClasses, ImageHAlign, Nullable } from "../../../types/index";
10
10
  /**
11
- * Align image
11
+ * Align image, with `classes` (see `imageAlignClasses`) instead of inline
12
+ * styles when they are given
12
13
  */
13
- export declare function hAlignElement(image: HTMLElement, align: ImageHAlign): void;
14
+ export declare function hAlignElement(image: HTMLElement, align: ImageHAlign, classes?: Nullable<ImageAlignClasses>): void;
15
+ /**
16
+ * The alignment `hAlignElement` has set on an element
17
+ */
18
+ export declare function getHAlign(elm: HTMLElement, classes?: Nullable<ImageAlignClasses>): ImageHAlign;
14
19
  /**
15
20
  * Remove text-align style for all selected children
16
21
  */
@@ -6,10 +6,24 @@
6
6
  import { Dom } from "../../dom/index.js";
7
7
  import { attr } from "./attr.js";
8
8
  import { clearCenterAlign, css, cssInline } from "./css.js";
9
+ const classNames = (value) => (value !== null && value !== void 0 ? value : '').split(/\s+/).filter(Boolean);
9
10
  /**
10
- * Align image
11
+ * Align image, with `classes` (see `imageAlignClasses`) instead of inline
12
+ * styles when they are given
11
13
  */
12
- export function hAlignElement(image, align) {
14
+ export function hAlignElement(image, align, classes) {
15
+ if (classes) {
16
+ hAlignElement(image, 'normal');
17
+ Object.values(classes).forEach(value => image.classList.remove(...classNames(value)));
18
+ image.classList.add(...classNames(classes[align || 'normal']));
19
+ ['class', 'style'].forEach(name => {
20
+ var _a;
21
+ if (!((_a = attr(image, name)) === null || _a === void 0 ? void 0 : _a.trim())) {
22
+ attr(image, name, null);
23
+ }
24
+ });
25
+ return;
26
+ }
13
27
  if (align && align !== 'normal') {
14
28
  if (align !== 'center') {
15
29
  css(image, 'float', align);
@@ -32,6 +46,30 @@ export function hAlignElement(image, align) {
32
46
  clearCenterAlign(image);
33
47
  }
34
48
  }
49
+ /**
50
+ * The alignment `hAlignElement` has set on an element
51
+ */
52
+ export function getHAlign(elm, classes) {
53
+ if (classes) {
54
+ for (const align of ['left', 'right', 'center', 'normal']) {
55
+ const names = classNames(classes[align]);
56
+ if (names.length &&
57
+ names.every(name => elm.classList.contains(name))) {
58
+ return align;
59
+ }
60
+ }
61
+ }
62
+ const float = cssInline(elm, 'float').toLowerCase();
63
+ if (float === 'left' || float === 'right') {
64
+ return float;
65
+ }
66
+ if (css(elm, 'display') === 'block' &&
67
+ cssInline(elm, 'margin-left') === 'auto' &&
68
+ cssInline(elm, 'margin-right') === 'auto') {
69
+ return 'center';
70
+ }
71
+ return 'normal';
72
+ }
35
73
  /**
36
74
  * Remove text-align style for all selected children
37
75
  */
@@ -19,6 +19,7 @@ import { autobind } from "../decorators/index.js";
19
19
  import { Dom } from "../dom/dom.js";
20
20
  import { $$, attr, css, error, getScrollParent, scrollIntoViewIfNeeded, size, toArray } from "../helpers/index.js";
21
21
  import { isFunction, isMarker, isString } from "../helpers/checker/index.js";
22
+ import { hAlignElement } from "../helpers/utils/align.js";
22
23
  import { assert } from "../helpers/utils/assert.js";
23
24
  import { moveTheNodeAlongTheEdgeOutward } from "./helpers/move-the-node-along-the-edge-outward.js";
24
25
  import "./interface.js";
@@ -661,6 +662,10 @@ export class Selection {
661
662
  if (styles && typeof styles === 'object') {
662
663
  css(image, styles);
663
664
  }
665
+ const { imageDefaultAlign, imageAlignClasses } = this.j.o;
666
+ if (imageDefaultAlign && imageDefaultAlign !== 'normal') {
667
+ hAlignElement(image, imageDefaultAlign, imageAlignClasses);
668
+ }
664
669
  const onload = () => {
665
670
  if (image.naturalHeight < image.offsetHeight ||
666
671
  image.naturalWidth < image.offsetWidth) {
@@ -20,16 +20,32 @@ Config.prototype.cursorAfterAutofocus = 'end';
20
20
  Config.prototype.saveSelectionOnBlur = true;
21
21
  export function focus(editor) {
22
22
  if (editor.o.saveSelectionOnBlur) {
23
+ // A click that brings focus back places the caret itself, and Chrome
24
+ // has already placed it when focus fires, so restoring would move it
25
+ // back to the old selection. The saved markers are dropped instead.
26
+ let focusByPointer = false;
23
27
  editor.e
24
28
  .on('blur', () => {
29
+ // A press that never brought the focus back must not decide
30
+ // what the next focus does
31
+ focusByPointer = false;
25
32
  if (editor.isEditorMode()) {
26
33
  editor.s.save(true);
27
34
  }
35
+ })
36
+ .on('mousedown touchstart', () => {
37
+ focusByPointer = !editor.editorIsActive;
28
38
  })
29
39
  .on('focus', () => {
30
40
  if (editor.isEditorMode()) {
31
- editor.s.restore();
41
+ if (focusByPointer) {
42
+ editor.s.removeMarkers();
43
+ }
44
+ else {
45
+ editor.s.restore();
46
+ }
32
47
  }
48
+ focusByPointer = false;
33
49
  });
34
50
  }
35
51
  const focus = () => {
@@ -13,8 +13,9 @@ 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 { SOURCE_CONSUMER } from "../../core/constants.js";
16
+ import { INVISIBLE_SPACE_REG_EXP, SOURCE_CONSUMER } from "../../core/constants.js";
17
17
  import { cached, debounce, watch } from "../../core/decorators/index.js";
18
+ import { Dom } from "../../core/dom/dom.js";
18
19
  import { pluginSystem } from "../../core/global.js";
19
20
  import { $$, dataBind } from "../../core/helpers/index.js";
20
21
  import { Plugin } from "../../core/plugin/index.js";
@@ -77,6 +78,7 @@ export class imageProcessor extends Plugin {
77
78
  replaceDataURIToBlobUUID(editor, elm);
78
79
  }
79
80
  editor.e.on(elm, 'mousedown touchstart', () => {
81
+ removeCaretText(elm);
80
82
  editor.s.select(elm);
81
83
  });
82
84
  }
@@ -93,6 +95,23 @@ __decorate([
93
95
  watch([':change', ':afterInit', ':changePlace']),
94
96
  debounce()
95
97
  ], imageProcessor.prototype, "afterChange", null);
98
+ /**
99
+ * Remove the invisible-space text beside an image, which only held a caret.
100
+ * Selecting the image replaces the caret, and with the text still after a
101
+ * block image, Safari highlights the rest of the image's line. See #1512
102
+ */
103
+ function removeCaretText(elm) {
104
+ var _a;
105
+ for (const side of ['previousSibling', 'nextSibling']) {
106
+ let node = elm[side];
107
+ while (Dom.isText(node) &&
108
+ !((_a = node.nodeValue) === null || _a === void 0 ? void 0 : _a.replace(INVISIBLE_SPACE_REG_EXP(), ''))) {
109
+ const next = node[side];
110
+ Dom.safeRemove(node);
111
+ node = next;
112
+ }
113
+ }
114
+ }
96
115
  function replaceDataURIToBlobUUID(editor, elm) {
97
116
  if (!editor.o.imageProcessor.replaceDataURIToBlobIdInView) {
98
117
  return;
@@ -3,8 +3,12 @@
3
3
  * Released under MIT see LICENSE.txt in the project root for license information.
4
4
  * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
5
5
  */
6
+ /**
7
+ * @module plugins/image-properties
8
+ */
9
+ import type { ImageAlignClasses, Nullable } from "../../../types/index";
6
10
  import type { EditValues } from "../interface";
7
11
  /**
8
12
  * @private
9
13
  */
10
- export declare function readAlign(image: HTMLImageElement, values: EditValues): void;
14
+ export declare function readAlign(image: HTMLImageElement, values: EditValues, classes?: Nullable<ImageAlignClasses>): void;
@@ -3,25 +3,11 @@
3
3
  * Released under MIT see LICENSE.txt in the project root for license information.
4
4
  * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
5
5
  */
6
- import { css, cssInline } from "../../../core/helpers/utils/css.js";
6
+ import { getHAlign } from "../../../core/helpers/utils/align.js";
7
7
  /**
8
8
  * @private
9
9
  */
10
- export function readAlign(image, values) {
11
- // Align
12
- if (cssInline(image, 'float') &&
13
- ['left', 'right'].indexOf(cssInline(image, 'float').toLowerCase()) !==
14
- -1) {
15
- values.align = css(image, 'float');
16
- }
17
- else {
18
- if (css(image, 'display') === 'block' &&
19
- cssInline(image, 'margin-left') === 'auto' &&
20
- cssInline(image, 'margin-right') === 'auto') {
21
- values.align = 'center';
22
- }
23
- else {
24
- values.align = '';
25
- }
26
- }
10
+ export function readAlign(image, values, classes) {
11
+ const align = getHAlign(image, classes);
12
+ values.align = align === 'normal' ? '' : align;
27
13
  }
@@ -15,7 +15,7 @@ import { readSizes } from "./size.js";
15
15
  */
16
16
  export async function readValuesFromImage(j, state) {
17
17
  const { sourceImage: image, values } = state;
18
- readAlign(image, values);
18
+ readAlign(image, values, j.o.imageAlignClasses);
19
19
  // Border radius
20
20
  values.borderRadius =
21
21
  parseInt(cssInline(image, 'border-radius') || '0', 10) || 0;
@@ -49,6 +49,6 @@ export function applyValuesToImage(j, state, image) {
49
49
  attr(image, 'id', id || null);
50
50
  }
51
51
  if (opt.image.editAlign) {
52
- hAlignElement(image, align);
52
+ hAlignElement(image, align, j.o.imageAlignClasses);
53
53
  }
54
54
  }
@@ -3,15 +3,17 @@
3
3
  * Released under MIT see LICENSE.txt in the project root for license information.
4
4
  * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
5
5
  */
6
- import { css } from "../../../core/helpers/utils/css.js";
6
+ import { css, cssInline } from "../../../core/helpers/utils/css.js";
7
7
  import { normalSizeToString } from "../utils/utils.js";
8
8
  /** @private */
9
9
  export function applyMargin(j, marginTop, marginRight, marginBottom, marginLeft, image, marginIsLocked) {
10
10
  const margins = [marginTop, marginRight, marginBottom, marginLeft];
11
+ // Compared with the inline value, which is what `readMargins` showed, so a
12
+ // margin from a stylesheet is not overwritten when the field is unchanged
11
13
  const applyMargin = (key, value) => {
12
- const oldValue = css(image, key);
14
+ const oldValue = normalSizeToString(cssInline(image, key) || 0);
13
15
  const v = normalSizeToString(value);
14
- if (oldValue.toString() !== v.toString()) {
16
+ if (oldValue !== v) {
15
17
  css(image, key, v);
16
18
  }
17
19
  };
@@ -5,12 +5,27 @@
5
5
  */
6
6
  import { Dom } from "../../../../core/dom/index.js";
7
7
  import { isString } from "../../../../core/helpers/checker/is-string.js";
8
- import { hAlignElement } from "../../../../core/helpers/utils/align.js";
8
+ import { getHAlign, hAlignElement } from "../../../../core/helpers/utils/align.js";
9
9
  import { css } from "../../../../core/helpers/utils/css.js";
10
+ // Images align with `imageAlignClasses`; the wrappers of iframes and media
11
+ // keep inline styles
12
+ const alignClasses = (editor, elm) => Dom.isTag(elm, 'img') ? editor.o.imageAlignClasses : null;
13
+ const currentAlign = (editor, elm) => (elm ? getHAlign(elm, alignClasses(editor, elm)) : 'normal');
10
14
  export const align = {
11
15
  name: 'left',
12
16
  childTemplate: (_, __, value) => value,
13
17
  list: ['Left', 'Right', 'Center', 'Normal'],
18
+ update: (editor, button) => {
19
+ const current = currentAlign(editor, button.target);
20
+ button.state.icon.name = current === 'normal' ? 'left' : current;
21
+ },
22
+ isActive: (editor, button) => currentAlign(editor, button.target) !== 'normal',
23
+ isChildActive: (editor, button) => {
24
+ var _a;
25
+ const [value] = (_a = button.control.args) !== null && _a !== void 0 ? _a : [];
26
+ return (isString(value) &&
27
+ currentAlign(editor, button.target) === value.toLowerCase());
28
+ },
14
29
  exec: (editor, elm, { control }) => {
15
30
  if (!Dom.isTag(elm, new Set(['img', 'jodit', 'jodit-media']))) {
16
31
  return;
@@ -21,7 +36,7 @@ export const align = {
21
36
  if (!command) {
22
37
  return false;
23
38
  }
24
- hAlignElement(elm, command);
39
+ hAlignElement(elm, command, alignClasses(editor, elm));
25
40
  if (Dom.isTag(elm, new Set(['jodit', 'jodit-media'])) &&
26
41
  elm.firstElementChild) {
27
42
  hAlignElement(elm.firstElementChild, command);
@@ -54,6 +69,13 @@ export default [
54
69
  name: 'valign',
55
70
  list: ['Top', 'Middle', 'Bottom', 'Normal'],
56
71
  tooltip: 'Vertical align',
72
+ // `vertical-align` only moves an image in the line, not a floated or block one
73
+ isDisabled: (editor, button) => {
74
+ const image = button.target;
75
+ return Boolean(image &&
76
+ (['left', 'right'].includes(css(image, 'float')) ||
77
+ css(image, 'display') === 'block'));
78
+ },
57
79
  exec: (editor, image, { control }) => {
58
80
  if (!Dom.isTag(image, 'img')) {
59
81
  return;
@@ -187,6 +187,10 @@ export interface ImageEditorOptions {
187
187
  export type InsertMode = 'insert_as_html' | 'insert_as_text' | 'insert_clear_html' | 'insert_only_text';
188
188
  export type ImageAction = 'resize' | 'crop';
189
189
  export type ImageHAlign = 'normal' | 'left' | 'right' | 'center' | '';
190
+ /**
191
+ * Class names for each image alignment, see `imageAlignClasses`
192
+ */
193
+ export type ImageAlignClasses = Partial<Record<Exclude<ImageHAlign, ''>, string>>;
190
194
  export interface ImageBox {
191
195
  w: number;
192
196
  h: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jodit",
3
- "version": "4.15.16",
3
+ "version": "4.15.18",
4
4
  "description": "Jodit is an awesome and useful wysiwyg editor with filebrowser",
5
5
  "main": "esm/index.js",
6
6
  "types": "types/index.d.ts",
package/types/config.d.ts CHANGED
@@ -23,6 +23,8 @@ import type { Attributes } from "./types/index";
23
23
  import type { Controls } from "./types/index";
24
24
  import type { IAsyncStorageOptions } from "./types/index";
25
25
  import type { IExtraPlugin } from "./types/index";
26
+ import type { ImageAlignClasses } from "./types/index";
27
+ import type { ImageHAlign } from "./types/index";
26
28
  import type { IUIButtonState } from "./types/index";
27
29
  import type { IViewOptions } from "./types/index";
28
30
  import type { NodeFunction } from "./types/index";
@@ -631,6 +633,27 @@ declare class Config implements IViewOptions {
631
633
  * Default width (in pixels) applied to images inserted into the editor
632
634
  */
633
635
  imageDefaultWidth: number;
636
+ /**
637
+ * Alignment given to images inserted into the editor. `'normal'` leaves
638
+ * them unaligned
639
+ */
640
+ imageDefaultAlign: ImageHAlign;
641
+ /**
642
+ * Class names to align images with, instead of an inline `float` or
643
+ * `margin`. Aligning an image removes every class listed here and adds the
644
+ * chosen alignment's, which can be several separated by spaces.
645
+ *
646
+ * ```javascript
647
+ * Jodit.make('#editor', {
648
+ * imageAlignClasses: {
649
+ * left: 'align-left',
650
+ * right: 'align-right',
651
+ * center: 'align-center'
652
+ * }
653
+ * });
654
+ * ```
655
+ */
656
+ imageAlignClasses: Nullable<ImageAlignClasses>;
634
657
  /**
635
658
  * Do not display these buttons that are on the list
636
659
  *
@@ -6,11 +6,16 @@
6
6
  /**
7
7
  * @module helpers/utils
8
8
  */
9
- import type { ImageHAlign } from "../../../types/index";
9
+ import type { ImageAlignClasses, ImageHAlign, Nullable } from "../../../types/index";
10
10
  /**
11
- * Align image
11
+ * Align image, with `classes` (see `imageAlignClasses`) instead of inline
12
+ * styles when they are given
12
13
  */
13
- export declare function hAlignElement(image: HTMLElement, align: ImageHAlign): void;
14
+ export declare function hAlignElement(image: HTMLElement, align: ImageHAlign, classes?: Nullable<ImageAlignClasses>): void;
15
+ /**
16
+ * The alignment `hAlignElement` has set on an element
17
+ */
18
+ export declare function getHAlign(elm: HTMLElement, classes?: Nullable<ImageAlignClasses>): ImageHAlign;
14
19
  /**
15
20
  * Remove text-align style for all selected children
16
21
  */
@@ -3,8 +3,12 @@
3
3
  * Released under MIT see LICENSE.txt in the project root for license information.
4
4
  * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
5
5
  */
6
+ /**
7
+ * @module plugins/image-properties
8
+ */
9
+ import type { ImageAlignClasses, Nullable } from "../../../types/index";
6
10
  import type { EditValues } from "../interface";
7
11
  /**
8
12
  * @private
9
13
  */
10
- export declare function readAlign(image: HTMLImageElement, values: EditValues): void;
14
+ export declare function readAlign(image: HTMLImageElement, values: EditValues, classes?: Nullable<ImageAlignClasses>): void;
@@ -187,6 +187,10 @@ export interface ImageEditorOptions {
187
187
  export type InsertMode = 'insert_as_html' | 'insert_as_text' | 'insert_clear_html' | 'insert_only_text';
188
188
  export type ImageAction = 'resize' | 'crop';
189
189
  export type ImageHAlign = 'normal' | 'left' | 'right' | 'center' | '';
190
+ /**
191
+ * Class names for each image alignment, see `imageAlignClasses`
192
+ */
193
+ export type ImageAlignClasses = Partial<Record<Exclude<ImageHAlign, ''>, string>>;
190
194
  export interface ImageBox {
191
195
  w: number;
192
196
  h: number;