jodit 4.18.6 → 4.18.7

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 (68) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/es2015/jodit.css +1 -1
  3. package/es2015/jodit.fat.min.js +8 -8
  4. package/es2015/jodit.js +103 -22
  5. package/es2015/jodit.min.js +8 -8
  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 +6 -6
  13. package/es2018/jodit.min.js +6 -6
  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 +6 -6
  18. package/es2021/jodit.js +102 -22
  19. package/es2021/jodit.min.js +6 -6
  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 +10 -10
  28. package/es2021.en/jodit.js +102 -22
  29. package/es2021.en/jodit.min.js +6 -6
  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 +110 -21
  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 +2 -0
  51. package/esm/core/constants.js +1 -1
  52. package/esm/core/decorators/component/component.js +12 -0
  53. package/esm/core/ui/popup/popup.js +14 -9
  54. package/esm/jodit.js +5 -1
  55. package/esm/modules/file-browser/ui/files/files.js +17 -2
  56. package/esm/modules/file-browser/ui/tree/tree.js +17 -2
  57. package/esm/plugins/backspace/cases/check-remove-char.d.ts +2 -1
  58. package/esm/plugins/backspace/cases/check-remove-char.js +25 -4
  59. package/esm/plugins/backspace/config.d.ts +2 -0
  60. package/esm/plugins/backspace/config.js +6 -3
  61. package/esm/plugins/image-properties/image-properties.d.ts +5 -0
  62. package/esm/plugins/image-properties/image-properties.js +30 -5
  63. package/esm/plugins/mobile/mobile.js +7 -4
  64. package/package.json +1 -1
  65. package/types/config.d.ts +2 -0
  66. package/types/plugins/backspace/cases/check-remove-char.d.ts +2 -1
  67. package/types/plugins/backspace/config.d.ts +2 -0
  68. package/types/plugins/image-properties/image-properties.d.ts +5 -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.18.6
4
+ * Version: v4.18.7
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.18.6
4
+ * Version: v4.18.7
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.18.6
4
+ * Version: v4.18.7
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.18.6
4
+ * Version: v4.18.7
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.18.6
4
+ * Version: v4.18.7
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.18.6
4
+ * Version: v4.18.7
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.18.6
4
+ * Version: v4.18.7
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.18.6
4
+ * Version: v4.18.7
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.18.6
4
+ * Version: v4.18.7
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
package/esm/config.d.ts CHANGED
@@ -1034,6 +1034,8 @@ interface Config {
1034
1034
  interface Config {
1035
1035
  /**
1036
1036
  * Keyboard hotkey mappings for delete and backspace operations (character, word, sentence).
1037
+ * On macOS the defaults leave out Cmd+Backspace, Ctrl+Backspace, Ctrl+Option+Backspace
1038
+ * and Cmd+Option+Backspace, so the browser applies the system's own bindings to them.
1037
1039
  */
1038
1040
  delete: {
1039
1041
  hotkeys: {
@@ -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.18.6";
6
+ export const APP_VERSION = "4.18.7";
7
7
  // prettier-ignore
8
8
  export const ES = "es2020";
9
9
  export const IS_ES_MODERN = true;
@@ -6,6 +6,8 @@
6
6
  import { IS_PROD } from "../../constants.js";
7
7
  import { getClassName } from "../../helpers/utils/get-class-name.js";
8
8
  const componentRegistry = new Map();
9
+ const decoratedClasses = new WeakSet();
10
+ const warnedClasses = new WeakSet();
9
11
  /**
10
12
  * Decorate components and set status isReady after constructor
11
13
  * @param constructorFunction - Component constructor class
@@ -24,8 +26,18 @@ export function component(constructorFunction) {
24
26
  }
25
27
  this.setStatus('ready');
26
28
  }
29
+ else if (!IS_PROD &&
30
+ !decoratedClasses.has(this.constructor) &&
31
+ !warnedClasses.has(this.constructor)) {
32
+ // Only the outermost class's decorator sets `ready`, so a subclass
33
+ // without its own decorator stays in `beforeInit`. See #1685
34
+ warnedClasses.add(this.constructor);
35
+ console.warn(`Component "${this.constructor.name || getClassName(this)}" extends a @component class without being decorated itself, so it never becomes ready and its @watch, @debounce, @throttle and @hook handlers never run`);
36
+ }
27
37
  }
28
38
  }
39
+ decoratedClasses.add(constructorFunction);
40
+ decoratedClasses.add(newConstructorFunction);
29
41
  const name = getClassName(constructorFunction.prototype);
30
42
  if (componentRegistry.has(name) && !IS_PROD) {
31
43
  throw new Error(`Component with name "${name}" is already registered`);
@@ -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
+ var Popup_1;
16
17
  import { Component } from "../../component/component.js";
17
- import { autobind, throttle } from "../../decorators/index.js";
18
+ import { autobind, component, throttle } from "../../decorators/index.js";
18
19
  import { Dom } from "../../dom/dom.js";
19
20
  import { eventEmitter, getContainer } from "../../global.js";
20
21
  import { attr, css, getFixedPositionOffset, isFunction, isString, kebabCase, markOwner, position, ucfirst } from "../../helpers/index.js";
@@ -29,7 +30,7 @@ const EVENTS_FOR_AUTOCLOSE = [
29
30
  'backSpaceAfterDelete',
30
31
  'beforeCommandDelete'
31
32
  ];
32
- export class Popup extends UIGroup {
33
+ let Popup = Popup_1 = class Popup extends UIGroup {
33
34
  className() {
34
35
  return 'Popup';
35
36
  }
@@ -39,7 +40,7 @@ export class Popup extends UIGroup {
39
40
  Dom.append(content, childContainer);
40
41
  }
41
42
  updateParentElement(target) {
42
- if (target !== this && Component.isInstanceOf(target, Popup)) {
43
+ if (target !== this && Component.isInstanceOf(target, Popup_1)) {
43
44
  this.__childrenPopups.forEach(popup => {
44
45
  if (!target.closest(popup) && popup.isOpened) {
45
46
  popup.close();
@@ -89,7 +90,7 @@ export class Popup extends UIGroup {
89
90
  Dom.append(parentContainer, this.container);
90
91
  }
91
92
  else {
92
- const popupContainer = getContainer(this.jodit, Popup);
93
+ const popupContainer = getContainer(this.jodit, Popup_1);
93
94
  if (parentContainer !== this.container.parentElement) {
94
95
  Dom.append(popupContainer, this.container);
95
96
  }
@@ -207,13 +208,13 @@ export class Popup extends UIGroup {
207
208
  };
208
209
  const getMatchStrategy = (inBox) => {
209
210
  let strategy;
210
- if (Popup.boxInView(getPointByStrategy(defaultStrategy), inBox)) {
211
+ if (Popup_1.boxInView(getPointByStrategy(defaultStrategy), inBox)) {
211
212
  strategy = defaultStrategy;
212
213
  }
213
214
  else {
214
215
  strategy =
215
216
  list.find((key) => {
216
- if (Popup.boxInView(getPointByStrategy(key), inBox)) {
217
+ if (Popup_1.boxInView(getPointByStrategy(key), inBox)) {
217
218
  return key;
218
219
  }
219
220
  return;
@@ -224,7 +225,7 @@ export class Popup extends UIGroup {
224
225
  // Try to find match position inside Jodit.container
225
226
  let strategy = getMatchStrategy(position(this.j.container, this.j));
226
227
  // If not found or is not inside window view
227
- if (!strategy || !Popup.boxInView(getPointByStrategy(strategy), view)) {
228
+ if (!strategy || !Popup_1.boxInView(getPointByStrategy(strategy), view)) {
228
229
  // Find match strategy inside window view
229
230
  strategy = getMatchStrategy(view) || strategy || defaultStrategy;
230
231
  }
@@ -280,7 +281,7 @@ export class Popup extends UIGroup {
280
281
  if (!e.target) {
281
282
  return false;
282
283
  }
283
- const box = UIElement.closestElement(e.target, Popup);
284
+ const box = UIElement.closestElement(e.target, Popup_1);
284
285
  return Boolean(box && (this === box || box.closest(this)));
285
286
  }
286
287
  __addGlobalListeners() {
@@ -353,7 +354,7 @@ export class Popup extends UIGroup {
353
354
  this.close();
354
355
  return super.destruct();
355
356
  }
356
- }
357
+ };
357
358
  __decorate([
358
359
  autobind
359
360
  ], Popup.prototype, "updatePosition", null);
@@ -367,3 +368,7 @@ __decorate([
367
368
  __decorate([
368
369
  autobind
369
370
  ], Popup.prototype, "__closeOnOutsideClick", null);
371
+ Popup = Popup_1 = __decorate([
372
+ component
373
+ ], Popup);
374
+ export { Popup };
package/esm/jodit.js CHANGED
@@ -557,7 +557,7 @@ let Jodit = Jodit_1 = class Jodit extends ViewWithToolbar {
557
557
  const hotkeys = this.o.commandToHotkeys[commandName] ||
558
558
  this.o.commandToHotkeys[commandNameOriginal] ||
559
559
  command.hotkeys;
560
- if (hotkeys) {
560
+ if (hotkeys && hotkeys.length) {
561
561
  this.registerHotkeyToCommand(hotkeys, commandName, options === null || options === void 0 ? void 0 : options.stopPropagation);
562
562
  }
563
563
  }
@@ -567,6 +567,10 @@ let Jodit = Jodit_1 = class Jodit extends ViewWithToolbar {
567
567
  * Register hotkey for command
568
568
  */
569
569
  registerHotkeyToCommand(hotkeys, commandName, shouldStop = true) {
570
+ // An empty list (e.g. `commandToHotkeys: { cmd: [] }`) turns the key off
571
+ if (!hotkeys || !hotkeys.length) {
572
+ return;
573
+ }
570
574
  const shortcuts = asArray(hotkeys)
571
575
  .map(normalizeKeyAliases)
572
576
  .map(hotkey => hotkey + '.hotkey')
@@ -3,9 +3,24 @@
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
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
7
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
8
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
9
+ r = Reflect.decorate(decorators, target, key, desc);
10
+ else
11
+ for (var i = decorators.length - 1; i >= 0; i--)
12
+ if (d = decorators[i])
13
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
14
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
15
+ };
16
+ import { component } from "../../../../core/decorators/index.js";
6
17
  import { UIGroup } from "../../../../core/ui/index.js";
7
- export class FileBrowserFiles extends UIGroup {
18
+ let FileBrowserFiles = class FileBrowserFiles extends UIGroup {
8
19
  className() {
9
20
  return 'FileBrowserFiles';
10
21
  }
11
- }
22
+ };
23
+ FileBrowserFiles = __decorate([
24
+ component
25
+ ], FileBrowserFiles);
26
+ export { FileBrowserFiles };
@@ -3,9 +3,24 @@
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
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
7
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
8
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
9
+ r = Reflect.decorate(decorators, target, key, desc);
10
+ else
11
+ for (var i = decorators.length - 1; i >= 0; i--)
12
+ if (d = decorators[i])
13
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
14
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
15
+ };
16
+ import { component } from "../../../../core/decorators/index.js";
6
17
  import { UIGroup } from "../../../../core/ui/index.js";
7
- export class FileBrowserTree extends UIGroup {
18
+ let FileBrowserTree = class FileBrowserTree extends UIGroup {
8
19
  className() {
9
20
  return 'FileBrowserTree';
10
21
  }
11
- }
22
+ };
23
+ FileBrowserTree = __decorate([
24
+ component
25
+ ], FileBrowserTree);
26
+ export { FileBrowserTree };
@@ -19,6 +19,7 @@ import type { DeleteMode } from "../interface";
19
19
  * ```html
20
20
  * t|st
21
21
  * ```
22
+ * With `stopBeforeSpace`, nothing is removed when the next char is a space.
22
23
  * @private
23
24
  */
24
- export declare function checkRemoveChar(jodit: IJodit, fakeNode: Node, backspace: boolean, mode: DeleteMode): boolean;
25
+ export declare function checkRemoveChar(jodit: IJodit, fakeNode: Node, backspace: boolean, mode: DeleteMode, stopBeforeSpace?: boolean): boolean;
@@ -18,10 +18,11 @@ import { findMostNestedNeighbor } from "../helpers.js";
18
18
  * ```html
19
19
  * t|st
20
20
  * ```
21
+ * With `stopBeforeSpace`, nothing is removed when the next char is a space.
21
22
  * @private
22
23
  */
23
24
  // eslint-disable-next-line complexity
24
- export function checkRemoveChar(jodit, fakeNode, backspace, mode) {
25
+ export function checkRemoveChar(jodit, fakeNode, backspace, mode, stopBeforeSpace = false) {
25
26
  var _a, _b;
26
27
  const step = backspace ? -1 : 1;
27
28
  const anotherSibling = Dom.sibling(fakeNode, !backspace);
@@ -40,6 +41,10 @@ export function checkRemoveChar(jodit, fakeNode, backspace, mode) {
40
41
  break;
41
42
  }
42
43
  if ((_a = sibling.nodeValue) === null || _a === void 0 ? void 0 : _a.length) {
44
+ if (stopBeforeSpace &&
45
+ isSpace(nextChar(sibling.nodeValue, backspace))) {
46
+ break;
47
+ }
43
48
  removed = tryRemoveChar(sibling, backspace, step, anotherSibling);
44
49
  if (!sibling.nodeValue.length &&
45
50
  Dom.isInlineBlock(sibling.parentNode)) {
@@ -160,8 +165,24 @@ function replaceSpaceOnNBSP(anotherSibling, backspace, value) {
160
165
  }
161
166
  function checkRepeatRemoveCharAction(backspace, sibling, fakeNode, mode, removed, jodit) {
162
167
  call(backspace ? Dom.after : Dom.before, sibling, fakeNode);
163
- if (mode === 'sentence' ||
164
- (mode === 'word' && removed !== ' ' && removed !== NBSP_SPACE)) {
165
- checkRemoveChar(jodit, fakeNode, backspace, mode);
168
+ const wordChar = mode === 'word' && !isSpace(removed);
169
+ // Backspace by word removes the spaces before the caret, then the word, and keeps the space in front of it
170
+ if (mode === 'sentence' || wordChar || (mode === 'word' && backspace)) {
171
+ checkRemoveChar(jodit, fakeNode, backspace, mode, wordChar && backspace);
166
172
  }
167
173
  }
174
+ /**
175
+ * The char tryRemoveChar would remove next
176
+ */
177
+ function nextChar(value, backspace) {
178
+ const chars = toArray(value);
179
+ const step = backspace ? -1 : 1;
180
+ let index = backspace ? chars.length - 1 : 0;
181
+ while (chars[index] === INVISIBLE_SPACE) {
182
+ index += step;
183
+ }
184
+ return chars[index];
185
+ }
186
+ function isSpace(char) {
187
+ return char === ' ' || char === NBSP_SPACE;
188
+ }
@@ -7,6 +7,8 @@ declare module 'jodit/config' {
7
7
  interface Config {
8
8
  /**
9
9
  * Keyboard hotkey mappings for delete and backspace operations (character, word, sentence).
10
+ * On macOS the defaults leave out Cmd+Backspace, Ctrl+Backspace, Ctrl+Option+Backspace
11
+ * and Cmd+Option+Backspace, so the browser applies the system's own bindings to them.
10
12
  */
11
13
  delete: {
12
14
  hotkeys: {
@@ -6,14 +6,17 @@
6
6
  /**
7
7
  * @module plugins/backspace
8
8
  */
9
+ import { IS_MAC } from "../../core/constants.js";
9
10
  import { Config } from "../../config.js";
10
11
  Config.prototype.delete = {
11
12
  hotkeys: {
12
- delete: ['delete', 'cmd+backspace'],
13
- deleteWord: ['ctrl+delete', 'cmd+alt+backspace', 'ctrl+alt+backspace'],
13
+ delete: IS_MAC ? ['delete'] : ['delete', 'cmd+backspace'],
14
+ deleteWord: IS_MAC
15
+ ? ['ctrl+delete']
16
+ : ['ctrl+delete', 'cmd+alt+backspace', 'ctrl+alt+backspace'],
14
17
  deleteSentence: ['ctrl+shift+delete', 'cmd+shift+delete'],
15
18
  backspace: ['backspace'],
16
- backspaceWord: ['ctrl+backspace'],
19
+ backspaceWord: IS_MAC ? [] : ['ctrl+backspace'],
17
20
  backspaceSentence: ['ctrl+shift+backspace', 'cmd+shift+backspace']
18
21
  }
19
22
  };
@@ -52,6 +52,11 @@ export declare class imageProperties extends Plugin {
52
52
  * ```
53
53
  */
54
54
  protected open(): void | false;
55
+ /**
56
+ * Keys typed while the dialog is open must not reach the editor behind it,
57
+ * so focus the active tab's first field, or else the first field shown
58
+ */
59
+ private __focusFirstField;
55
60
  private __lock;
56
61
  private __unlock;
57
62
  /** @override **/
@@ -16,7 +16,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
16
16
  import { cache, cached, watch } from "../../core/decorators/index.js";
17
17
  import { Dom } from "../../core/dom/dom.js";
18
18
  import { pluginSystem } from "../../core/global.js";
19
- import { isAbortError, isNumeric, markOwner } from "../../core/helpers/index.js";
19
+ import { isAbortError, isNumeric, markOwner, toArray } from "../../core/helpers/index.js";
20
20
  import { Plugin } from "../../core/plugin/plugin.js";
21
21
  import { Button } from "../../core/ui/button/index.js";
22
22
  import "./config.js";
@@ -99,8 +99,12 @@ export class imageProperties extends Plugin {
99
99
  dialog.close();
100
100
  });
101
101
  buttons.remove.onAction(() => {
102
+ const caret = j.s.createRange();
103
+ caret.setStartBefore(this.state.sourceImage);
104
+ caret.collapse(true);
102
105
  j.s.removeNode(this.state.sourceImage);
103
106
  dialog.close();
107
+ j.s.selectRange(caret);
104
108
  });
105
109
  buttons.cancel.onAction(() => {
106
110
  dialog.close();
@@ -108,11 +112,20 @@ export class imageProperties extends Plugin {
108
112
  dialog.setHeader(j.i18n('Image properties'));
109
113
  dialog.setContent(this.form);
110
114
  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
+ // The dialog fires `afterClose` on its own emitter, not the editor's
116
+ dialog.e.on(dialog, 'afterClose', () => {
117
+ const { sourceImage } = this.state;
118
+ if (j.isInDestruct || !Dom.isOrContains(j.editor, sourceImage)) {
119
+ return;
115
120
  }
121
+ if (j.o.image.selectImageAfterClose) {
122
+ j.s.select(sourceImage);
123
+ return;
124
+ }
125
+ const caret = j.s.createRange();
126
+ caret.setStartAfter(sourceImage);
127
+ caret.collapse(true);
128
+ j.s.selectRange(caret);
116
129
  });
117
130
  dialog.setSize(j.o.image.dialogWidth);
118
131
  markOwner(j, dialog.container);
@@ -144,6 +157,7 @@ export class imageProperties extends Plugin {
144
157
  this.activeTabState.activeTab = 'Image';
145
158
  this.__lock();
146
159
  this.dialog.open().setModal(true).setPosition();
160
+ this.__focusFirstField();
147
161
  this.async
148
162
  .promise((resolve, reject) => readValuesFromImage(this.j, this.state).then(resolve, reject))
149
163
  .catch((e) => {
@@ -154,6 +168,17 @@ export class imageProperties extends Plugin {
154
168
  .finally(() => this.__unlock());
155
169
  return false;
156
170
  }
171
+ /**
172
+ * Keys typed while the dialog is open must not reach the editor behind it,
173
+ * so focus the active tab's first field, or else the first field shown
174
+ */
175
+ __focusFirstField() {
176
+ var _a;
177
+ const fields = (box) => toArray(box.querySelectorAll('input, select, textarea'));
178
+ (_a = fields(this.form.getElm('tabsBox'))
179
+ .concat(fields(this.form.container))
180
+ .find(field => field.offsetParent != null)) === null || _a === void 0 ? void 0 : _a.focus();
181
+ }
157
182
  __lock() {
158
183
  this.dialog.lock();
159
184
  this.form.setMod('lock', true);
@@ -78,9 +78,11 @@ function fitToButtons(list, editor) {
78
78
  return cleaned;
79
79
  }
80
80
  /**
81
- * The width that decides which breakpoint set the toolbar uses. A toolbar
82
- * rendered into an external container (`toolbar` set to an element or a
83
- * selector) lays out in that container, so its width is what matters there.
81
+ * The width that decides which breakpoint set the toolbar uses: the editor's
82
+ * own width, or its parent's while the editor has none yet (for example
83
+ * while hidden at init). A toolbar rendered into an external container
84
+ * (`toolbar` set to an element or a selector) lays out in that container, so
85
+ * its width is what matters there.
84
86
  */
85
87
  function adaptiveWidth(editor) {
86
88
  var _a;
@@ -91,7 +93,8 @@ function adaptiveWidth(editor) {
91
93
  return width;
92
94
  }
93
95
  }
94
- return ((_a = editor.container.parentElement) !== null && _a !== void 0 ? _a : editor.container).offsetWidth;
96
+ return (editor.container.offsetWidth ||
97
+ ((_a = editor.container.parentElement) !== null && _a !== void 0 ? _a : editor.container).offsetWidth);
95
98
  }
96
99
  /**
97
100
  * Rebuild toolbar in depends on editor's width
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jodit",
3
- "version": "4.18.6",
3
+ "version": "4.18.7",
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
@@ -1034,6 +1034,8 @@ interface Config {
1034
1034
  interface Config {
1035
1035
  /**
1036
1036
  * Keyboard hotkey mappings for delete and backspace operations (character, word, sentence).
1037
+ * On macOS the defaults leave out Cmd+Backspace, Ctrl+Backspace, Ctrl+Option+Backspace
1038
+ * and Cmd+Option+Backspace, so the browser applies the system's own bindings to them.
1037
1039
  */
1038
1040
  delete: {
1039
1041
  hotkeys: {
@@ -19,6 +19,7 @@ import type { DeleteMode } from "../interface";
19
19
  * ```html
20
20
  * t|st
21
21
  * ```
22
+ * With `stopBeforeSpace`, nothing is removed when the next char is a space.
22
23
  * @private
23
24
  */
24
- export declare function checkRemoveChar(jodit: IJodit, fakeNode: Node, backspace: boolean, mode: DeleteMode): boolean;
25
+ export declare function checkRemoveChar(jodit: IJodit, fakeNode: Node, backspace: boolean, mode: DeleteMode, stopBeforeSpace?: boolean): boolean;
@@ -7,6 +7,8 @@ declare module 'jodit/config' {
7
7
  interface Config {
8
8
  /**
9
9
  * Keyboard hotkey mappings for delete and backspace operations (character, word, sentence).
10
+ * On macOS the defaults leave out Cmd+Backspace, Ctrl+Backspace, Ctrl+Option+Backspace
11
+ * and Cmd+Option+Backspace, so the browser applies the system's own bindings to them.
10
12
  */
11
13
  delete: {
12
14
  hotkeys: {
@@ -52,6 +52,11 @@ export declare class imageProperties extends Plugin {
52
52
  * ```
53
53
  */
54
54
  protected open(): void | false;
55
+ /**
56
+ * Keys typed while the dialog is open must not reach the editor behind it,
57
+ * so focus the active tab's first field, or else the first field shown
58
+ */
59
+ private __focusFirstField;
55
60
  private __lock;
56
61
  private __unlock;
57
62
  /** @override **/