jodit 4.18.6 → 4.18.8

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 (76) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/es2015/jodit.css +1 -1
  3. package/es2015/jodit.fat.min.js +9 -9
  4. package/es2015/jodit.js +265 -36
  5. package/es2015/jodit.min.js +9 -9
  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 +9 -9
  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 +11 -11
  18. package/es2021/jodit.js +264 -36
  19. package/es2021/jodit.min.js +7 -7
  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 +264 -36
  29. package/es2021.en/jodit.min.js +7 -7
  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 +280 -35
  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 +4 -2
  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/dialog/dialog.js +18 -3
  56. package/esm/modules/file-browser/ui/files/files.js +17 -2
  57. package/esm/modules/file-browser/ui/tree/tree.js +17 -2
  58. package/esm/plugins/backspace/cases/check-join-neighbors.js +81 -0
  59. package/esm/plugins/backspace/cases/check-remove-char.d.ts +2 -1
  60. package/esm/plugins/backspace/cases/check-remove-char.js +31 -9
  61. package/esm/plugins/backspace/cases/check-unwrap-list-item.d.ts +26 -0
  62. package/esm/plugins/backspace/cases/check-unwrap-list-item.js +56 -0
  63. package/esm/plugins/backspace/cases/index.js +2 -0
  64. package/esm/plugins/backspace/config.d.ts +4 -2
  65. package/esm/plugins/backspace/config.js +6 -3
  66. package/esm/plugins/enter/enter.js +1 -1
  67. package/esm/plugins/enter/helpers/check-br.js +7 -2
  68. package/esm/plugins/image-properties/image-properties.d.ts +5 -0
  69. package/esm/plugins/image-properties/image-properties.js +30 -5
  70. package/esm/plugins/mobile/mobile.js +7 -4
  71. package/package.json +1 -1
  72. package/types/config.d.ts +4 -2
  73. package/types/plugins/backspace/cases/check-remove-char.d.ts +2 -1
  74. package/types/plugins/backspace/cases/check-unwrap-list-item.d.ts +26 -0
  75. package/types/plugins/backspace/config.d.ts +4 -2
  76. package/types/plugins/image-properties/image-properties.d.ts +5 -0
package/es2021/jodit.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.8
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
@@ -1822,7 +1822,7 @@ __webpack_require__.r(__webpack_exports__);
1822
1822
  * ```
1823
1823
  * @packageDocumentation
1824
1824
  * @module constants
1825
- */ const APP_VERSION = "4.18.6";
1825
+ */ const APP_VERSION = "4.18.8";
1826
1826
  // prettier-ignore
1827
1827
  const ES = "es2021";
1828
1828
  const IS_ES_MODERN = true;
@@ -2560,6 +2560,8 @@ function cacheHTML(target, _, descriptor) {
2560
2560
  */
2561
2561
 
2562
2562
  const componentRegistry = new Map();
2563
+ const decoratedClasses = new WeakSet();
2564
+ const warnedClasses = new WeakSet();
2563
2565
  /**
2564
2566
  * Decorate components and set status isReady after constructor
2565
2567
  * @param constructorFunction - Component constructor class
@@ -2576,9 +2578,16 @@ const componentRegistry = new Map();
2576
2578
  Object.setPrototypeOf(this, newConstructorFunction.prototype);
2577
2579
  }
2578
2580
  this.setStatus('ready');
2581
+ } else if (!jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.IS_PROD && !decoratedClasses.has(this.constructor) && !warnedClasses.has(this.constructor)) {
2582
+ // Only the outermost class's decorator sets `ready`, so a subclass
2583
+ // without its own decorator stays in `beforeInit`. See #1685
2584
+ warnedClasses.add(this.constructor);
2585
+ console.warn(`Component "${this.constructor.name || (0,jodit_core_helpers_utils_get_class_name__WEBPACK_IMPORTED_MODULE_1__.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`);
2579
2586
  }
2580
2587
  }
2581
2588
  }
2589
+ decoratedClasses.add(constructorFunction);
2590
+ decoratedClasses.add(newConstructorFunction);
2582
2591
  const name = (0,jodit_core_helpers_utils_get_class_name__WEBPACK_IMPORTED_MODULE_1__.getClassName)(constructorFunction.prototype);
2583
2592
  if (componentRegistry.has(name) && !jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.IS_PROD) {
2584
2593
  throw new Error(`Component with name "${name}" is already registered`);
@@ -17560,6 +17569,9 @@ class Popup extends jodit_core_ui_group_group__WEBPACK_IMPORTED_MODULE_10__.UIGr
17560
17569
  (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
17561
17570
  jodit_core_decorators__WEBPACK_IMPORTED_MODULE_3__.autobind
17562
17571
  ], Popup.prototype, "__closeOnOutsideClick", null);
17572
+ Popup = (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
17573
+ jodit_core_decorators__WEBPACK_IMPORTED_MODULE_3__.component
17574
+ ], Popup);
17563
17575
 
17564
17576
 
17565
17577
  /***/ }),
@@ -18671,7 +18683,7 @@ class Jodit extends jodit_modules__WEBPACK_IMPORTED_MODULE_10__.ViewWithToolbar
18671
18683
  commands.push(command);
18672
18684
  if (!(0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.isFunction)(command)) {
18673
18685
  const hotkeys = this.o.commandToHotkeys[commandName] || this.o.commandToHotkeys[commandNameOriginal] || command.hotkeys;
18674
- if (hotkeys) {
18686
+ if (hotkeys && hotkeys.length) {
18675
18687
  this.registerHotkeyToCommand(hotkeys, commandName, options?.stopPropagation);
18676
18688
  }
18677
18689
  }
@@ -18680,6 +18692,10 @@ class Jodit extends jodit_modules__WEBPACK_IMPORTED_MODULE_10__.ViewWithToolbar
18680
18692
  /**
18681
18693
  * Register hotkey for command
18682
18694
  */ registerHotkeyToCommand(hotkeys, commandName, shouldStop = true) {
18695
+ // An empty list (e.g. `commandToHotkeys: { cmd: [] }`) turns the key off
18696
+ if (!hotkeys || !hotkeys.length) {
18697
+ return;
18698
+ }
18683
18699
  const shortcuts = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.asArray)(hotkeys).map(jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.normalizeKeyAliases).map((hotkey)=>hotkey + '.hotkey').join(' ');
18684
18700
  this.e.off(shortcuts).on(shortcuts, (type, stop)=>{
18685
18701
  if (stop) {
@@ -19830,6 +19846,9 @@ ContextMenu = (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_0__.__decorat
19830
19846
 
19831
19847
 
19832
19848
 
19849
+ /**
19850
+ * A position from 0 up to `max`, or 0 when the panel is larger than the window
19851
+ */ const clampToWindow = (value, max)=>Math.max(0, Math.min(value, max));
19833
19852
  jodit_config__WEBPACK_IMPORTED_MODULE_15__.Config.prototype.dialog = {
19834
19853
  namespace: '',
19835
19854
  extraButtons: [],
@@ -19920,6 +19939,11 @@ class Dialog extends jodit_core_view_view_with_toolbar__WEBPACK_IMPORTED_MODULE_
19920
19939
  this.startY = e.clientY;
19921
19940
  this.startPoint.x = (0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_10__.css)(this.dialog, 'left');
19922
19941
  this.startPoint.y = (0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_10__.css)(this.dialog, 'top');
19942
+ // Rounded up: at the right edge a fraction of a pixel less room would
19943
+ // wrap the header of a panel that has no width of its own
19944
+ const { width, height } = this.dialog.getBoundingClientRect();
19945
+ this.startPoint.w = Math.ceil(width);
19946
+ this.startPoint.h = Math.ceil(height);
19923
19947
  this.setMaxZIndex();
19924
19948
  if (e.cancelable) {
19925
19949
  e.preventDefault();
@@ -19935,7 +19959,11 @@ class Dialog extends jodit_core_view_view_with_toolbar__WEBPACK_IMPORTED_MODULE_
19935
19959
  }
19936
19960
  __onMouseMove(e) {
19937
19961
  if (this.draggable && this.o.draggable) {
19938
- this.setPosition(this.startPoint.x + e.clientX - this.startX, this.startPoint.y + e.clientY - this.startY);
19962
+ const { documentElement } = this.od;
19963
+ // Keep the whole panel in the window at the size it had when the
19964
+ // drag began. A panel with no width of its own would otherwise
19965
+ // shrink as it neared the right edge, and then leave the window
19966
+ this.setPosition(clampToWindow(this.startPoint.x + e.clientX - this.startX, (documentElement.clientWidth || this.ow.innerWidth) - this.startPoint.w), clampToWindow(this.startPoint.y + e.clientY - this.startY, (documentElement.clientHeight || this.ow.innerHeight) - this.startPoint.h));
19939
19967
  if (this.e) {
19940
19968
  /**
19941
19969
  * Fired when dialog box is moved
@@ -20060,8 +20088,8 @@ class Dialog extends jodit_core_view_view_with_toolbar__WEBPACK_IMPORTED_MODULE_
20060
20088
  }
20061
20089
  // strings on purpose: `css()` would truncate fractional pixels
20062
20090
  ;(0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_10__.css)(this.dialog, {
20063
- left: (x || left) + 'px',
20064
- top: (y || top) + 'px'
20091
+ left: (x ?? left) + 'px',
20092
+ top: (y ?? top) + 'px'
20065
20093
  });
20066
20094
  return this;
20067
20095
  }
@@ -22604,18 +22632,25 @@ const DEFAULT_SOURCE_NAME = 'default';
22604
22632
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
22605
22633
  /* harmony export */ FileBrowserFiles: function() { return /* binding */ FileBrowserFiles; }
22606
22634
  /* harmony export */ });
22607
- /* harmony import */ var jodit_core_ui__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4099);
22635
+ /* harmony import */ var _swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(31635);
22636
+ /* harmony import */ var jodit_core_decorators__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(84839);
22637
+ /* harmony import */ var jodit_core_ui__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(4099);
22638
+
22608
22639
  /*!
22609
22640
  * Jodit Editor (https://xdsoft.net/jodit/)
22610
22641
  * Released under MIT see LICENSE.txt in the project root for license information.
22611
22642
  * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
22612
22643
  */
22613
22644
 
22614
- class FileBrowserFiles extends jodit_core_ui__WEBPACK_IMPORTED_MODULE_0__.UIGroup {
22645
+
22646
+ class FileBrowserFiles extends jodit_core_ui__WEBPACK_IMPORTED_MODULE_2__.UIGroup {
22615
22647
  className() {
22616
22648
  return 'FileBrowserFiles';
22617
22649
  }
22618
22650
  }
22651
+ FileBrowserFiles = (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_0__.__decorate)([
22652
+ jodit_core_decorators__WEBPACK_IMPORTED_MODULE_1__.component
22653
+ ], FileBrowserFiles);
22619
22654
 
22620
22655
 
22621
22656
  /***/ }),
@@ -22649,18 +22684,25 @@ class FileBrowserFiles extends jodit_core_ui__WEBPACK_IMPORTED_MODULE_0__.UIGrou
22649
22684
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
22650
22685
  /* harmony export */ FileBrowserTree: function() { return /* binding */ FileBrowserTree; }
22651
22686
  /* harmony export */ });
22652
- /* harmony import */ var jodit_core_ui__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4099);
22687
+ /* harmony import */ var _swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(31635);
22688
+ /* harmony import */ var jodit_core_decorators__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(84839);
22689
+ /* harmony import */ var jodit_core_ui__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(4099);
22690
+
22653
22691
  /*!
22654
22692
  * Jodit Editor (https://xdsoft.net/jodit/)
22655
22693
  * Released under MIT see LICENSE.txt in the project root for license information.
22656
22694
  * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
22657
22695
  */
22658
22696
 
22659
- class FileBrowserTree extends jodit_core_ui__WEBPACK_IMPORTED_MODULE_0__.UIGroup {
22697
+
22698
+ class FileBrowserTree extends jodit_core_ui__WEBPACK_IMPORTED_MODULE_2__.UIGroup {
22660
22699
  className() {
22661
22700
  return 'FileBrowserTree';
22662
22701
  }
22663
22702
  }
22703
+ FileBrowserTree = (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_0__.__decorate)([
22704
+ jodit_core_decorators__WEBPACK_IMPORTED_MODULE_1__.component
22705
+ ], FileBrowserTree);
22664
22706
 
22665
22707
 
22666
22708
  /***/ }),
@@ -28235,6 +28277,9 @@ jodit_core_global__WEBPACK_IMPORTED_MODULE_3__.pluginSystem.add('backspace', bac
28235
28277
  * Check if two separate elements can be connected
28236
28278
  * @private
28237
28279
  */ function checkJoinNeighbors(jodit, fakeNode, backspace) {
28280
+ if (checkJoinBareText(jodit, fakeNode, backspace)) {
28281
+ return true;
28282
+ }
28238
28283
  let nextBox = fakeNode, mainClosestBox = nextBox;
28239
28284
  // Find the main big closest element
28240
28285
  while(nextBox && !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.findNotEmptySibling(nextBox, backspace) && nextBox.parentElement !== jodit.editor){
@@ -28262,7 +28307,7 @@ jodit_core_global__WEBPACK_IMPORTED_MODULE_3__.pluginSystem.add('backspace', bac
28262
28307
  return true;
28263
28308
  }
28264
28309
  const box = findCaretBox(fakeNode, mainClosestBox);
28265
- if (sibling && (checkPullNextLine(jodit, fakeNode, box, sibling, backspace) || checkMoveListContent(jodit, box, sibling, backspace) || moveContentAndRemoveEmpty(jodit, box, findEdgeBlock(resolveTableSibling(sibling, backspace), backspace, jodit.editor), backspace))) {
28310
+ if (sibling && (checkPullNextLine(jodit, fakeNode, box, sibling, backspace) || checkMoveListContent(jodit, box, sibling, backspace) || checkJoinInlineSibling(jodit, box, sibling, backspace) || moveContentAndRemoveEmpty(jodit, box, findEdgeBlock(resolveTableSibling(sibling, backspace), backspace, jodit.editor), backspace))) {
28266
28311
  jodit.s.setCursorBefore(fakeNode);
28267
28312
  return true;
28268
28313
  }
@@ -28347,6 +28392,70 @@ jodit_core_global__WEBPACK_IMPORTED_MODULE_3__.pluginSystem.add('backspace', bac
28347
28392
  }
28348
28393
  return true;
28349
28394
  }
28395
+ /**
28396
+ * A block next to bare text in the same parent joins that text, as the
28397
+ * browsers do: `<li>one<p>|two</p></li>` gives `<li>one|two</li>`, and
28398
+ * `<li><p>one|</p>two</li>` gives `<li><p>one|two</p></li>`
28399
+ * @private
28400
+ */ function checkJoinInlineSibling(jodit, box, sibling, backspace) {
28401
+ if (jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isBlock(sibling) || !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isBlock(box) || jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isList(box) || // The caret's block is nested deeper than the text: `text<div><p>|x</p></div>`
28402
+ box.parentNode !== sibling.parentNode || Array.from(box.childNodes).some((node)=>jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isBlock(node))) {
28403
+ return false;
28404
+ }
28405
+ if (backspace) {
28406
+ // Text after the block keeps its own line
28407
+ const next = jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.findNotEmptySibling(box, false);
28408
+ if (next && !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isBlock(next) && !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isTag(next, 'br')) {
28409
+ jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.after(box, jodit.createInside.element('br'));
28410
+ }
28411
+ jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.unwrap(box);
28412
+ return true;
28413
+ }
28414
+ const filter = (0,jodit_plugins_backspace_helpers__WEBPACK_IMPORTED_MODULE_2__.getMoveFilter)(jodit);
28415
+ for(let node = sibling; node && !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isBlock(node);){
28416
+ const next = node.nextSibling;
28417
+ if (jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isTag(node, 'br')) {
28418
+ jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.safeRemove(node);
28419
+ break;
28420
+ }
28421
+ filter(node) ? jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.append(box, node) : jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.safeRemove(node);
28422
+ node = next;
28423
+ }
28424
+ return true;
28425
+ }
28426
+ /**
28427
+ * Bare text next to a block in the same parent, as the browsers join them:
28428
+ * Backspace in `<div><p>a</p>|b</div>` gives `<div><p>a|b</p></div>`, Delete
28429
+ * in `<div>a|<p>b</p>c</div>` gives `<div>a|b<br>c</div>`
28430
+ */ function checkJoinBareText(jodit, fakeNode, backspace) {
28431
+ const block = jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.findNotEmptySibling(fakeNode, backspace);
28432
+ if (!jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isElement(block) || !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isBlock(block) || jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isList(block) || jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isTag(block, 'table') || jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isCell(block) || !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isContentEditable(block, jodit.editor) || Array.from(block.childNodes).some((node)=>jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isBlock(node))) {
28433
+ return false;
28434
+ }
28435
+ const filter = (0,jodit_plugins_backspace_helpers__WEBPACK_IMPORTED_MODULE_2__.getMoveFilter)(jodit);
28436
+ if (backspace) {
28437
+ // The caret's line goes to the end of the block before it
28438
+ for(let node = fakeNode; node && !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isBlock(node);){
28439
+ const next = node.nextSibling;
28440
+ if (jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isTag(node, 'br')) {
28441
+ jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.safeRemove(node);
28442
+ break;
28443
+ }
28444
+ filter(node) ? jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.append(block, node) : jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.safeRemove(node);
28445
+ node = next;
28446
+ }
28447
+ } else {
28448
+ // The block's content joins the caret's line, and text after the
28449
+ // block keeps its own line
28450
+ const next = jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.findNotEmptySibling(block, false);
28451
+ if (next && !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isBlock(next) && !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isTag(next, 'br')) {
28452
+ jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.after(block, jodit.createInside.element('br'));
28453
+ }
28454
+ jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.unwrap(block);
28455
+ }
28456
+ jodit.s.setCursorBefore(fakeNode);
28457
+ return true;
28458
+ }
28350
28459
  function checkMoveListContent(jodit, mainClosestBox, sibling, backspace) {
28351
28460
  // Process UL/LI/OL cases
28352
28461
  const siblingIsList = jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isTag(sibling, jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.LIST_TAGS);
@@ -28497,9 +28606,10 @@ function moveContentAndRemoveEmpty(jodit, mainClosestBox, sibling, backspace) {
28497
28606
  * ```html
28498
28607
  * t|st
28499
28608
  * ```
28609
+ * With `stopBeforeSpace`, nothing is removed when the next char is a space.
28500
28610
  * @private
28501
28611
  */ // eslint-disable-next-line complexity
28502
- function checkRemoveChar(jodit, fakeNode, backspace, mode) {
28612
+ function checkRemoveChar(jodit, fakeNode, backspace, mode, stopBeforeSpace = false) {
28503
28613
  const step = backspace ? -1 : 1;
28504
28614
  const anotherSibling = jodit_core_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.sibling(fakeNode, !backspace);
28505
28615
  let sibling = jodit_core_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.sibling(fakeNode, backspace);
@@ -28517,6 +28627,9 @@ function checkRemoveChar(jodit, fakeNode, backspace, mode) {
28517
28627
  break;
28518
28628
  }
28519
28629
  if (sibling.nodeValue?.length) {
28630
+ if (stopBeforeSpace && isSpace(nextChar(sibling.nodeValue, backspace))) {
28631
+ break;
28632
+ }
28520
28633
  removed = tryRemoveChar(sibling, backspace, step, anotherSibling);
28521
28634
  if (!sibling.nodeValue.length && jodit_core_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isInlineBlock(sibling.parentNode)) {
28522
28635
  sibling.nodeValue = jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.INVISIBLE_SPACE;
@@ -28554,10 +28667,11 @@ function getNextInlineSibling(sibling, backspace, root) {
28554
28667
  let nextSibling = jodit_core_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.sibling(sibling, backspace);
28555
28668
  if (!nextSibling && sibling.parentNode && sibling.parentNode !== root) {
28556
28669
  nextSibling = (0,jodit_plugins_backspace_helpers__WEBPACK_IMPORTED_MODULE_3__.findMostNestedNeighbor)(sibling, !backspace, root, true);
28557
- // Do not cross a list-item boundary. At the start of a list item the
28558
- // neighbor can be the text of the parent/previous item; deleting a char
28559
- // there is wrong — the list cases must handle the outdent/merge (#1277).
28560
- if (nextSibling && jodit_core_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.closest(sibling, 'li', root) !== jodit_core_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.closest(nextSibling, 'li', root)) {
28670
+ // Do not cross a block boundary. At the start of a list item the
28671
+ // neighbor can be the text of the parent/previous item (#1277), and at
28672
+ // the start of a paragraph the text before it in the same parent
28673
+ // (#1693); deleting a char there is wrong — the join cases handle them.
28674
+ if (nextSibling && jodit_core_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.closest(sibling, jodit_core_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isBlock, root) !== jodit_core_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.closest(nextSibling, jodit_core_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isBlock, root)) {
28561
28675
  return null;
28562
28676
  }
28563
28677
  }
@@ -28623,9 +28737,25 @@ function replaceSpaceOnNBSP(anotherSibling, backspace, value) {
28623
28737
  }
28624
28738
  function checkRepeatRemoveCharAction(backspace, sibling, fakeNode, mode, removed, jodit) {
28625
28739
  ;(0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_2__.call)(backspace ? jodit_core_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.after : jodit_core_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.before, sibling, fakeNode);
28626
- if (mode === 'sentence' || mode === 'word' && removed !== ' ' && removed !== jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.NBSP_SPACE) {
28627
- checkRemoveChar(jodit, fakeNode, backspace, mode);
28740
+ const wordChar = mode === 'word' && !isSpace(removed);
28741
+ // Backspace by word removes the spaces before the caret, then the word, and keeps the space in front of it
28742
+ if (mode === 'sentence' || wordChar || mode === 'word' && backspace) {
28743
+ checkRemoveChar(jodit, fakeNode, backspace, mode, wordChar && backspace);
28744
+ }
28745
+ }
28746
+ /**
28747
+ * The char tryRemoveChar would remove next
28748
+ */ function nextChar(value, backspace) {
28749
+ const chars = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_2__.toArray)(value);
28750
+ const step = backspace ? -1 : 1;
28751
+ let index = backspace ? chars.length - 1 : 0;
28752
+ while(chars[index] === jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.INVISIBLE_SPACE){
28753
+ index += step;
28628
28754
  }
28755
+ return chars[index];
28756
+ }
28757
+ function isSpace(char) {
28758
+ return char === ' ' || char === jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.NBSP_SPACE;
28629
28759
  }
28630
28760
 
28631
28761
 
@@ -28919,6 +29049,69 @@ function checkRepeatRemoveCharAction(backspace, sibling, fakeNode, mode, removed
28919
29049
  }
28920
29050
 
28921
29051
 
29052
+ /***/ }),
29053
+
29054
+ /***/ 88426:
29055
+ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
29056
+
29057
+ "use strict";
29058
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
29059
+ /* harmony export */ checkUnwrapListItem: function() { return /* binding */ checkUnwrapListItem; }
29060
+ /* harmony export */ });
29061
+ /* harmony import */ var jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(23211);
29062
+ /*!
29063
+ * Jodit Editor (https://xdsoft.net/jodit/)
29064
+ * Released under MIT see LICENSE.txt in the project root for license information.
29065
+ * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
29066
+ */ /**
29067
+ * @module plugins/backspace
29068
+ */
29069
+ /**
29070
+ * Backspace at the start of a later list item takes the bullet off, as Word
29071
+ * does: the item becomes a paragraph where it was, and the list is split
29072
+ * around it. A split `<ol>` carries its numbering on with `start`.
29073
+ *
29074
+ * @example
29075
+ * ```html
29076
+ * <ol><li>first</li><li>|second</li><li>third</li></ol>
29077
+ * ```
29078
+ * Result
29079
+ * ```html
29080
+ * <ol><li>first</li></ol><p>|second</p><ol start="2"><li>third</li></ol>
29081
+ * ```
29082
+ *
29083
+ * @private
29084
+ */ function checkUnwrapListItem(jodit, fakeNode, backspace) {
29085
+ if (!backspace) {
29086
+ return false;
29087
+ }
29088
+ const li = jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.closest(fakeNode, 'li', jodit.editor);
29089
+ const list = li ? li.parentElement : null;
29090
+ if (!li || !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.isList(list) || !li.previousElementSibling || jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.isEmpty(li) || Array.from(li.childNodes).some((node)=>jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.isBlock(node)) || !jodit.s.cursorInTheEdge(true, li)) {
29091
+ return false;
29092
+ }
29093
+ const p = jodit.createInside.element(jodit.o.enterBlock);
29094
+ jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.after(list, p);
29095
+ if (li.nextElementSibling) {
29096
+ const rest = list.cloneNode(false);
29097
+ // Two lists cannot share one id
29098
+ rest.removeAttribute('id');
29099
+ while(li.nextSibling){
29100
+ jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.append(rest, li.nextSibling);
29101
+ }
29102
+ if (jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.isTag(list, 'ol')) {
29103
+ const start = parseInt(list.getAttribute('start') || '1', 10) || 1;
29104
+ rest.setAttribute('start', String(start + list.children.length - 1));
29105
+ }
29106
+ jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.after(p, rest);
29107
+ }
29108
+ jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.moveContent(li, p);
29109
+ jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.safeRemove(li);
29110
+ jodit.s.setCursorBefore(fakeNode);
29111
+ return true;
29112
+ }
29113
+
29114
+
28922
29115
  /***/ }),
28923
29116
 
28924
29117
  /***/ 17523:
@@ -28935,6 +29128,7 @@ function checkRepeatRemoveCharAction(backspace, sibling, fakeNode, mode, removed
28935
29128
  /* harmony import */ var _check_remove_unbreakable_element__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(93890);
28936
29129
  /* harmony import */ var _check_table_cell__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(12443);
28937
29130
  /* harmony import */ var _check_unwrap_first_list_item__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(10157);
29131
+ /* harmony import */ var _check_unwrap_list_item__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(88426);
28938
29132
  /*!
28939
29133
  * Jodit Editor (https://xdsoft.net/jodit/)
28940
29134
  * Released under MIT see LICENSE.txt in the project root for license information.
@@ -28950,6 +29144,7 @@ function checkRepeatRemoveCharAction(backspace, sibling, fakeNode, mode, removed
28950
29144
 
28951
29145
 
28952
29146
 
29147
+
28953
29148
  /**
28954
29149
  * Ordered delete/backspace cases with stable keys. The first one returning
28955
29150
  * `true` wins. The keys are stable across minified builds (function names are
@@ -28984,6 +29179,10 @@ function checkRepeatRemoveCharAction(backspace, sibling, fakeNode, mode, removed
28984
29179
  'join-two-lists',
28985
29180
  _check_join_two_lists__WEBPACK_IMPORTED_MODULE_1__.checkJoinTwoLists
28986
29181
  ],
29182
+ [
29183
+ 'unwrap-list-item',
29184
+ _check_unwrap_list_item__WEBPACK_IMPORTED_MODULE_9__.checkUnwrapListItem
29185
+ ],
28987
29186
  [
28988
29187
  'join-neighbors',
28989
29188
  _check_join_neighbors__WEBPACK_IMPORTED_MODULE_0__.checkJoinNeighbors
@@ -29009,7 +29208,8 @@ function checkRepeatRemoveCharAction(backspace, sibling, fakeNode, mode, removed
29009
29208
  /***/ (function(__unused_webpack_module, __unused_webpack___webpack_exports__, __webpack_require__) {
29010
29209
 
29011
29210
  "use strict";
29012
- /* harmony import */ var jodit_config__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5266);
29211
+ /* harmony import */ var jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(81937);
29212
+ /* harmony import */ var jodit_config__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5266);
29013
29213
  /*!
29014
29214
  * Jodit Editor (https://xdsoft.net/jodit/)
29015
29215
  * Released under MIT see LICENSE.txt in the project root for license information.
@@ -29017,13 +29217,18 @@ function checkRepeatRemoveCharAction(backspace, sibling, fakeNode, mode, removed
29017
29217
  */ /**
29018
29218
  * @module plugins/backspace
29019
29219
  */
29020
- jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.delete = {
29220
+
29221
+ jodit_config__WEBPACK_IMPORTED_MODULE_1__.Config.prototype.delete = {
29021
29222
  hotkeys: {
29022
- delete: [
29223
+ delete: jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.IS_MAC ? [
29224
+ 'delete'
29225
+ ] : [
29023
29226
  'delete',
29024
29227
  'cmd+backspace'
29025
29228
  ],
29026
- deleteWord: [
29229
+ deleteWord: jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.IS_MAC ? [
29230
+ 'ctrl+delete'
29231
+ ] : [
29027
29232
  'ctrl+delete',
29028
29233
  'cmd+alt+backspace',
29029
29234
  'ctrl+alt+backspace'
@@ -29035,7 +29240,7 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.delete = {
29035
29240
  backspace: [
29036
29241
  'backspace'
29037
29242
  ],
29038
- backspaceWord: [
29243
+ backspaceWord: jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.IS_MAC ? [] : [
29039
29244
  'ctrl+backspace'
29040
29245
  ],
29041
29246
  backspaceSentence: [
@@ -32638,7 +32843,7 @@ jodit_core_global__WEBPACK_IMPORTED_MODULE_2__.pluginSystem.add('dtd', dtd);
32638
32843
  ]);
32639
32844
  let block = (0,_helpers__WEBPACK_IMPORTED_MODULE_7__.getBlockWrapper)(fake, jodit);
32640
32845
  const isLi = jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isLeaf(block);
32641
- // if use <br> defaultTag for break line or when was entered SHIFt key or in <td> or <th> or <blockquote>
32846
+ // if use <br> defaultTag for break line or when was entered SHIFt key or in <td>, <th> or <blockquote> without an inner block
32642
32847
  if ((!isLi || event?.shiftKey) && (0,_helpers__WEBPACK_IMPORTED_MODULE_7__.checkBR)(fake, jodit, event?.shiftKey, block)) {
32643
32848
  return false;
32644
32849
  }
@@ -32702,10 +32907,9 @@ jodit_core_global__WEBPACK_IMPORTED_MODULE_4__.pluginSystem.add('enter', enter);
32702
32907
  * Checks the possibility and necessity of inserting a BR instead of a block
32703
32908
  * @private
32704
32909
  */ function checkBR(fake, jodit, shiftKeyPressed, block) {
32705
- const isMultiLineBlock = Boolean(jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.closest(fake, [
32706
- 'pre',
32707
- 'blockquote'
32708
- ], jodit.editor));
32910
+ // Text in a <pre>, or bare text in a quote, gets a BR. A real block inside
32911
+ // a quote (<p>, <h3>, ...) is split like anywhere else, as in a cell below.
32912
+ const isMultiLineBlock = Boolean(jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.closest(fake, 'pre', jodit.editor)) || (block ? jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isTag(block, 'blockquote') : Boolean(jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.closest(fake, 'blockquote', jodit.editor)));
32709
32913
  // A cell itself can't be split into two cells, so bare cell content gets
32710
32914
  // a BR. But when the cell already holds a real block (<p>, <h3>, ...) that
32711
32915
  // block is split like anywhere else, otherwise every line of the cell
@@ -32715,7 +32919,7 @@ jodit_core_global__WEBPACK_IMPORTED_MODULE_4__.pluginSystem.add('enter', enter);
32715
32919
  'th'
32716
32920
  ], jodit.editor)));
32717
32921
  const isBRMode = jodit.o.enter.toLowerCase() === jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.BR.toLowerCase();
32718
- // if you use <br> defaultTag for break line or when was entered SHIFt key or in <td> or <th> or <blockquote>
32922
+ // if you use <br> defaultTag for break line or when was entered SHIFt key or in <td>, <th> or <blockquote> without an inner block
32719
32923
  if (isBRMode || isCell || shiftKeyPressed && !isMultiLineBlock || !shiftKeyPressed && isMultiLineBlock) {
32720
32924
  // 2 BR before
32721
32925
  if (isMultiLineBlock && checkSeveralBR(fake)) {
@@ -35034,8 +35238,12 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.image = {
35034
35238
  dialog.close();
35035
35239
  });
35036
35240
  buttons.remove.onAction(()=>{
35241
+ const caret = j.s.createRange();
35242
+ caret.setStartBefore(this.state.sourceImage);
35243
+ caret.collapse(true);
35037
35244
  j.s.removeNode(this.state.sourceImage);
35038
35245
  dialog.close();
35246
+ j.s.selectRange(caret);
35039
35247
  });
35040
35248
  buttons.cancel.onAction(()=>{
35041
35249
  dialog.close();
@@ -35049,10 +35257,20 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.image = {
35049
35257
  ],
35050
35258
  buttons.check
35051
35259
  ]);
35052
- j.e.on(dialog, 'afterClose', ()=>{
35053
- if (this.state.image.parentNode && j.o.image.selectImageAfterClose) {
35054
- j.s.select(this.state.sourceImage);
35260
+ // The dialog fires `afterClose` on its own emitter, not the editor's
35261
+ dialog.e.on(dialog, 'afterClose', ()=>{
35262
+ const { sourceImage } = this.state;
35263
+ if (j.isInDestruct || !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isOrContains(j.editor, sourceImage)) {
35264
+ return;
35265
+ }
35266
+ if (j.o.image.selectImageAfterClose) {
35267
+ j.s.select(sourceImage);
35268
+ return;
35055
35269
  }
35270
+ const caret = j.s.createRange();
35271
+ caret.setStartAfter(sourceImage);
35272
+ caret.collapse(true);
35273
+ j.s.selectRange(caret);
35056
35274
  });
35057
35275
  dialog.setSize(j.o.image.dialogWidth);
35058
35276
  (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.markOwner)(j, dialog.container);
@@ -35083,6 +35301,7 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.image = {
35083
35301
  this.activeTabState.activeTab = 'Image';
35084
35302
  this.__lock();
35085
35303
  this.dialog.open().setModal(true).setPosition();
35304
+ this.__focusFirstField();
35086
35305
  this.async.promise((resolve, reject)=>(0,_readers__WEBPACK_IMPORTED_MODULE_12__.readValuesFromImage)(this.j, this.state).then(resolve, reject)).catch((e)=>{
35087
35306
  if (!(0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.isAbortError)(e)) {
35088
35307
  this.dialog.message.error(e.message);
@@ -35090,6 +35309,13 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.image = {
35090
35309
  }).finally(()=>this.__unlock());
35091
35310
  return false;
35092
35311
  }
35312
+ /**
35313
+ * Keys typed while the dialog is open must not reach the editor behind it,
35314
+ * so focus the active tab's first field, or else the first field shown
35315
+ */ __focusFirstField() {
35316
+ const fields = (box)=>(0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.toArray)(box.querySelectorAll('input, select, textarea'));
35317
+ fields(this.form.getElm('tabsBox')).concat(fields(this.form.container)).find((field)=>field.offsetParent != null)?.focus();
35318
+ }
35093
35319
  __lock() {
35094
35320
  this.dialog.lock();
35095
35321
  this.form.setMod('lock', true);
@@ -39541,9 +39767,11 @@ const isButtonSeparator = (item)=>item === '|' || item === '---' || item === '\n
39541
39767
  return cleaned;
39542
39768
  }
39543
39769
  /**
39544
- * The width that decides which breakpoint set the toolbar uses. A toolbar
39545
- * rendered into an external container (`toolbar` set to an element or a
39546
- * selector) lays out in that container, so its width is what matters there.
39770
+ * The width that decides which breakpoint set the toolbar uses: the editor's
39771
+ * own width, or its parent's while the editor has none yet (for example
39772
+ * while hidden at init). A toolbar rendered into an external container
39773
+ * (`toolbar` set to an element or a selector) lays out in that container, so
39774
+ * its width is what matters there.
39547
39775
  */ function adaptiveWidth(editor) {
39548
39776
  const { toolbar } = editor.o;
39549
39777
  if ((0,jodit_core_helpers_checker_is_string__WEBPACK_IMPORTED_MODULE_3__.isString)(toolbar) || jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.isHTMLElement(toolbar)) {
@@ -39552,7 +39780,7 @@ const isButtonSeparator = (item)=>item === '|' || item === '---' || item === '\n
39552
39780
  return width;
39553
39781
  }
39554
39782
  }
39555
- return (editor.container.parentElement ?? editor.container).offsetWidth;
39783
+ return editor.container.offsetWidth || (editor.container.parentElement ?? editor.container).offsetWidth;
39556
39784
  }
39557
39785
  /**
39558
39786
  * Rebuild toolbar in depends on editor's width