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
@@ -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) {
@@ -19806,6 +19822,9 @@ ContextMenu = (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_0__.__decorat
19806
19822
 
19807
19823
 
19808
19824
 
19825
+ /**
19826
+ * A position from 0 up to `max`, or 0 when the panel is larger than the window
19827
+ */ const clampToWindow = (value, max)=>Math.max(0, Math.min(value, max));
19809
19828
  jodit_config__WEBPACK_IMPORTED_MODULE_15__.Config.prototype.dialog = {
19810
19829
  namespace: '',
19811
19830
  extraButtons: [],
@@ -19896,6 +19915,11 @@ class Dialog extends jodit_core_view_view_with_toolbar__WEBPACK_IMPORTED_MODULE_
19896
19915
  this.startY = e.clientY;
19897
19916
  this.startPoint.x = (0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_10__.css)(this.dialog, 'left');
19898
19917
  this.startPoint.y = (0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_10__.css)(this.dialog, 'top');
19918
+ // Rounded up: at the right edge a fraction of a pixel less room would
19919
+ // wrap the header of a panel that has no width of its own
19920
+ const { width, height } = this.dialog.getBoundingClientRect();
19921
+ this.startPoint.w = Math.ceil(width);
19922
+ this.startPoint.h = Math.ceil(height);
19899
19923
  this.setMaxZIndex();
19900
19924
  if (e.cancelable) {
19901
19925
  e.preventDefault();
@@ -19911,7 +19935,11 @@ class Dialog extends jodit_core_view_view_with_toolbar__WEBPACK_IMPORTED_MODULE_
19911
19935
  }
19912
19936
  __onMouseMove(e) {
19913
19937
  if (this.draggable && this.o.draggable) {
19914
- this.setPosition(this.startPoint.x + e.clientX - this.startX, this.startPoint.y + e.clientY - this.startY);
19938
+ const { documentElement } = this.od;
19939
+ // Keep the whole panel in the window at the size it had when the
19940
+ // drag began. A panel with no width of its own would otherwise
19941
+ // shrink as it neared the right edge, and then leave the window
19942
+ 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));
19915
19943
  if (this.e) {
19916
19944
  /**
19917
19945
  * Fired when dialog box is moved
@@ -20036,8 +20064,8 @@ class Dialog extends jodit_core_view_view_with_toolbar__WEBPACK_IMPORTED_MODULE_
20036
20064
  }
20037
20065
  // strings on purpose: `css()` would truncate fractional pixels
20038
20066
  ;(0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_10__.css)(this.dialog, {
20039
- left: (x || left) + 'px',
20040
- top: (y || top) + 'px'
20067
+ left: (x ?? left) + 'px',
20068
+ top: (y ?? top) + 'px'
20041
20069
  });
20042
20070
  return this;
20043
20071
  }
@@ -22580,18 +22608,25 @@ const DEFAULT_SOURCE_NAME = 'default';
22580
22608
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
22581
22609
  /* harmony export */ FileBrowserFiles: function() { return /* binding */ FileBrowserFiles; }
22582
22610
  /* harmony export */ });
22583
- /* harmony import */ var jodit_core_ui__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4099);
22611
+ /* harmony import */ var _swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(31635);
22612
+ /* harmony import */ var jodit_core_decorators__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(84839);
22613
+ /* harmony import */ var jodit_core_ui__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(4099);
22614
+
22584
22615
  /*!
22585
22616
  * Jodit Editor (https://xdsoft.net/jodit/)
22586
22617
  * Released under MIT see LICENSE.txt in the project root for license information.
22587
22618
  * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
22588
22619
  */
22589
22620
 
22590
- class FileBrowserFiles extends jodit_core_ui__WEBPACK_IMPORTED_MODULE_0__.UIGroup {
22621
+
22622
+ class FileBrowserFiles extends jodit_core_ui__WEBPACK_IMPORTED_MODULE_2__.UIGroup {
22591
22623
  className() {
22592
22624
  return 'FileBrowserFiles';
22593
22625
  }
22594
22626
  }
22627
+ FileBrowserFiles = (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_0__.__decorate)([
22628
+ jodit_core_decorators__WEBPACK_IMPORTED_MODULE_1__.component
22629
+ ], FileBrowserFiles);
22595
22630
 
22596
22631
 
22597
22632
  /***/ }),
@@ -22625,18 +22660,25 @@ class FileBrowserFiles extends jodit_core_ui__WEBPACK_IMPORTED_MODULE_0__.UIGrou
22625
22660
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
22626
22661
  /* harmony export */ FileBrowserTree: function() { return /* binding */ FileBrowserTree; }
22627
22662
  /* harmony export */ });
22628
- /* harmony import */ var jodit_core_ui__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4099);
22663
+ /* harmony import */ var _swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(31635);
22664
+ /* harmony import */ var jodit_core_decorators__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(84839);
22665
+ /* harmony import */ var jodit_core_ui__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(4099);
22666
+
22629
22667
  /*!
22630
22668
  * Jodit Editor (https://xdsoft.net/jodit/)
22631
22669
  * Released under MIT see LICENSE.txt in the project root for license information.
22632
22670
  * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
22633
22671
  */
22634
22672
 
22635
- class FileBrowserTree extends jodit_core_ui__WEBPACK_IMPORTED_MODULE_0__.UIGroup {
22673
+
22674
+ class FileBrowserTree extends jodit_core_ui__WEBPACK_IMPORTED_MODULE_2__.UIGroup {
22636
22675
  className() {
22637
22676
  return 'FileBrowserTree';
22638
22677
  }
22639
22678
  }
22679
+ FileBrowserTree = (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_0__.__decorate)([
22680
+ jodit_core_decorators__WEBPACK_IMPORTED_MODULE_1__.component
22681
+ ], FileBrowserTree);
22640
22682
 
22641
22683
 
22642
22684
  /***/ }),
@@ -28161,6 +28203,9 @@ jodit_core_global__WEBPACK_IMPORTED_MODULE_3__.pluginSystem.add('backspace', bac
28161
28203
  * Check if two separate elements can be connected
28162
28204
  * @private
28163
28205
  */ function checkJoinNeighbors(jodit, fakeNode, backspace) {
28206
+ if (checkJoinBareText(jodit, fakeNode, backspace)) {
28207
+ return true;
28208
+ }
28164
28209
  let nextBox = fakeNode, mainClosestBox = nextBox;
28165
28210
  // Find the main big closest element
28166
28211
  while(nextBox && !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.findNotEmptySibling(nextBox, backspace) && nextBox.parentElement !== jodit.editor){
@@ -28188,7 +28233,7 @@ jodit_core_global__WEBPACK_IMPORTED_MODULE_3__.pluginSystem.add('backspace', bac
28188
28233
  return true;
28189
28234
  }
28190
28235
  const box = findCaretBox(fakeNode, mainClosestBox);
28191
- if (sibling && (checkPullNextLine(jodit, fakeNode, box, sibling, backspace) || checkMoveListContent(jodit, box, sibling, backspace) || moveContentAndRemoveEmpty(jodit, box, findEdgeBlock(resolveTableSibling(sibling, backspace), backspace, jodit.editor), backspace))) {
28236
+ 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))) {
28192
28237
  jodit.s.setCursorBefore(fakeNode);
28193
28238
  return true;
28194
28239
  }
@@ -28273,6 +28318,70 @@ jodit_core_global__WEBPACK_IMPORTED_MODULE_3__.pluginSystem.add('backspace', bac
28273
28318
  }
28274
28319
  return true;
28275
28320
  }
28321
+ /**
28322
+ * A block next to bare text in the same parent joins that text, as the
28323
+ * browsers do: `<li>one<p>|two</p></li>` gives `<li>one|two</li>`, and
28324
+ * `<li><p>one|</p>two</li>` gives `<li><p>one|two</p></li>`
28325
+ * @private
28326
+ */ function checkJoinInlineSibling(jodit, box, sibling, backspace) {
28327
+ 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>`
28328
+ box.parentNode !== sibling.parentNode || Array.from(box.childNodes).some((node)=>jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isBlock(node))) {
28329
+ return false;
28330
+ }
28331
+ if (backspace) {
28332
+ // Text after the block keeps its own line
28333
+ const next = jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.findNotEmptySibling(box, false);
28334
+ 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')) {
28335
+ jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.after(box, jodit.createInside.element('br'));
28336
+ }
28337
+ jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.unwrap(box);
28338
+ return true;
28339
+ }
28340
+ const filter = (0,jodit_plugins_backspace_helpers__WEBPACK_IMPORTED_MODULE_2__.getMoveFilter)(jodit);
28341
+ for(let node = sibling; node && !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isBlock(node);){
28342
+ const next = node.nextSibling;
28343
+ if (jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isTag(node, 'br')) {
28344
+ jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.safeRemove(node);
28345
+ break;
28346
+ }
28347
+ 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);
28348
+ node = next;
28349
+ }
28350
+ return true;
28351
+ }
28352
+ /**
28353
+ * Bare text next to a block in the same parent, as the browsers join them:
28354
+ * Backspace in `<div><p>a</p>|b</div>` gives `<div><p>a|b</p></div>`, Delete
28355
+ * in `<div>a|<p>b</p>c</div>` gives `<div>a|b<br>c</div>`
28356
+ */ function checkJoinBareText(jodit, fakeNode, backspace) {
28357
+ const block = jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.findNotEmptySibling(fakeNode, backspace);
28358
+ 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))) {
28359
+ return false;
28360
+ }
28361
+ const filter = (0,jodit_plugins_backspace_helpers__WEBPACK_IMPORTED_MODULE_2__.getMoveFilter)(jodit);
28362
+ if (backspace) {
28363
+ // The caret's line goes to the end of the block before it
28364
+ for(let node = fakeNode; node && !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isBlock(node);){
28365
+ const next = node.nextSibling;
28366
+ if (jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isTag(node, 'br')) {
28367
+ jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.safeRemove(node);
28368
+ break;
28369
+ }
28370
+ 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);
28371
+ node = next;
28372
+ }
28373
+ } else {
28374
+ // The block's content joins the caret's line, and text after the
28375
+ // block keeps its own line
28376
+ const next = jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.findNotEmptySibling(block, false);
28377
+ 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')) {
28378
+ jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.after(block, jodit.createInside.element('br'));
28379
+ }
28380
+ jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.unwrap(block);
28381
+ }
28382
+ jodit.s.setCursorBefore(fakeNode);
28383
+ return true;
28384
+ }
28276
28385
  function checkMoveListContent(jodit, mainClosestBox, sibling, backspace) {
28277
28386
  // Process UL/LI/OL cases
28278
28387
  const siblingIsList = jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isTag(sibling, jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.LIST_TAGS);
@@ -28423,9 +28532,10 @@ function moveContentAndRemoveEmpty(jodit, mainClosestBox, sibling, backspace) {
28423
28532
  * ```html
28424
28533
  * t|st
28425
28534
  * ```
28535
+ * With `stopBeforeSpace`, nothing is removed when the next char is a space.
28426
28536
  * @private
28427
28537
  */ // eslint-disable-next-line complexity
28428
- function checkRemoveChar(jodit, fakeNode, backspace, mode) {
28538
+ function checkRemoveChar(jodit, fakeNode, backspace, mode, stopBeforeSpace = false) {
28429
28539
  const step = backspace ? -1 : 1;
28430
28540
  const anotherSibling = jodit_core_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.sibling(fakeNode, !backspace);
28431
28541
  let sibling = jodit_core_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.sibling(fakeNode, backspace);
@@ -28443,6 +28553,9 @@ function checkRemoveChar(jodit, fakeNode, backspace, mode) {
28443
28553
  break;
28444
28554
  }
28445
28555
  if (sibling.nodeValue?.length) {
28556
+ if (stopBeforeSpace && isSpace(nextChar(sibling.nodeValue, backspace))) {
28557
+ break;
28558
+ }
28446
28559
  removed = tryRemoveChar(sibling, backspace, step, anotherSibling);
28447
28560
  if (!sibling.nodeValue.length && jodit_core_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isInlineBlock(sibling.parentNode)) {
28448
28561
  sibling.nodeValue = jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.INVISIBLE_SPACE;
@@ -28480,10 +28593,11 @@ function getNextInlineSibling(sibling, backspace, root) {
28480
28593
  let nextSibling = jodit_core_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.sibling(sibling, backspace);
28481
28594
  if (!nextSibling && sibling.parentNode && sibling.parentNode !== root) {
28482
28595
  nextSibling = (0,jodit_plugins_backspace_helpers__WEBPACK_IMPORTED_MODULE_3__.findMostNestedNeighbor)(sibling, !backspace, root, true);
28483
- // Do not cross a list-item boundary. At the start of a list item the
28484
- // neighbor can be the text of the parent/previous item; deleting a char
28485
- // there is wrong — the list cases must handle the outdent/merge (#1277).
28486
- 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)) {
28596
+ // Do not cross a block boundary. At the start of a list item the
28597
+ // neighbor can be the text of the parent/previous item (#1277), and at
28598
+ // the start of a paragraph the text before it in the same parent
28599
+ // (#1693); deleting a char there is wrong — the join cases handle them.
28600
+ 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)) {
28487
28601
  return null;
28488
28602
  }
28489
28603
  }
@@ -28549,9 +28663,25 @@ function replaceSpaceOnNBSP(anotherSibling, backspace, value) {
28549
28663
  }
28550
28664
  function checkRepeatRemoveCharAction(backspace, sibling, fakeNode, mode, removed, jodit) {
28551
28665
  ;(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);
28552
- if (mode === 'sentence' || mode === 'word' && removed !== ' ' && removed !== jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.NBSP_SPACE) {
28553
- checkRemoveChar(jodit, fakeNode, backspace, mode);
28666
+ const wordChar = mode === 'word' && !isSpace(removed);
28667
+ // Backspace by word removes the spaces before the caret, then the word, and keeps the space in front of it
28668
+ if (mode === 'sentence' || wordChar || mode === 'word' && backspace) {
28669
+ checkRemoveChar(jodit, fakeNode, backspace, mode, wordChar && backspace);
28670
+ }
28671
+ }
28672
+ /**
28673
+ * The char tryRemoveChar would remove next
28674
+ */ function nextChar(value, backspace) {
28675
+ const chars = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_2__.toArray)(value);
28676
+ const step = backspace ? -1 : 1;
28677
+ let index = backspace ? chars.length - 1 : 0;
28678
+ while(chars[index] === jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.INVISIBLE_SPACE){
28679
+ index += step;
28554
28680
  }
28681
+ return chars[index];
28682
+ }
28683
+ function isSpace(char) {
28684
+ return char === ' ' || char === jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.NBSP_SPACE;
28555
28685
  }
28556
28686
 
28557
28687
 
@@ -28845,6 +28975,69 @@ function checkRepeatRemoveCharAction(backspace, sibling, fakeNode, mode, removed
28845
28975
  }
28846
28976
 
28847
28977
 
28978
+ /***/ }),
28979
+
28980
+ /***/ 88426:
28981
+ /***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
28982
+
28983
+ "use strict";
28984
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
28985
+ /* harmony export */ checkUnwrapListItem: function() { return /* binding */ checkUnwrapListItem; }
28986
+ /* harmony export */ });
28987
+ /* harmony import */ var jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(23211);
28988
+ /*!
28989
+ * Jodit Editor (https://xdsoft.net/jodit/)
28990
+ * Released under MIT see LICENSE.txt in the project root for license information.
28991
+ * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
28992
+ */ /**
28993
+ * @module plugins/backspace
28994
+ */
28995
+ /**
28996
+ * Backspace at the start of a later list item takes the bullet off, as Word
28997
+ * does: the item becomes a paragraph where it was, and the list is split
28998
+ * around it. A split `<ol>` carries its numbering on with `start`.
28999
+ *
29000
+ * @example
29001
+ * ```html
29002
+ * <ol><li>first</li><li>|second</li><li>third</li></ol>
29003
+ * ```
29004
+ * Result
29005
+ * ```html
29006
+ * <ol><li>first</li></ol><p>|second</p><ol start="2"><li>third</li></ol>
29007
+ * ```
29008
+ *
29009
+ * @private
29010
+ */ function checkUnwrapListItem(jodit, fakeNode, backspace) {
29011
+ if (!backspace) {
29012
+ return false;
29013
+ }
29014
+ const li = jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.closest(fakeNode, 'li', jodit.editor);
29015
+ const list = li ? li.parentElement : null;
29016
+ 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)) {
29017
+ return false;
29018
+ }
29019
+ const p = jodit.createInside.element(jodit.o.enterBlock);
29020
+ jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.after(list, p);
29021
+ if (li.nextElementSibling) {
29022
+ const rest = list.cloneNode(false);
29023
+ // Two lists cannot share one id
29024
+ rest.removeAttribute('id');
29025
+ while(li.nextSibling){
29026
+ jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.append(rest, li.nextSibling);
29027
+ }
29028
+ if (jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.isTag(list, 'ol')) {
29029
+ const start = parseInt(list.getAttribute('start') || '1', 10) || 1;
29030
+ rest.setAttribute('start', String(start + list.children.length - 1));
29031
+ }
29032
+ jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.after(p, rest);
29033
+ }
29034
+ jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.moveContent(li, p);
29035
+ jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.safeRemove(li);
29036
+ jodit.s.setCursorBefore(fakeNode);
29037
+ return true;
29038
+ }
29039
+
29040
+
28848
29041
  /***/ }),
28849
29042
 
28850
29043
  /***/ 17523:
@@ -28861,6 +29054,7 @@ function checkRepeatRemoveCharAction(backspace, sibling, fakeNode, mode, removed
28861
29054
  /* harmony import */ var _check_remove_unbreakable_element__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(93890);
28862
29055
  /* harmony import */ var _check_table_cell__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(12443);
28863
29056
  /* harmony import */ var _check_unwrap_first_list_item__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(10157);
29057
+ /* harmony import */ var _check_unwrap_list_item__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(88426);
28864
29058
  /*!
28865
29059
  * Jodit Editor (https://xdsoft.net/jodit/)
28866
29060
  * Released under MIT see LICENSE.txt in the project root for license information.
@@ -28876,6 +29070,7 @@ function checkRepeatRemoveCharAction(backspace, sibling, fakeNode, mode, removed
28876
29070
 
28877
29071
 
28878
29072
 
29073
+
28879
29074
  /**
28880
29075
  * Ordered delete/backspace cases with stable keys. The first one returning
28881
29076
  * `true` wins. The keys are stable across minified builds (function names are
@@ -28910,6 +29105,10 @@ function checkRepeatRemoveCharAction(backspace, sibling, fakeNode, mode, removed
28910
29105
  'join-two-lists',
28911
29106
  _check_join_two_lists__WEBPACK_IMPORTED_MODULE_1__.checkJoinTwoLists
28912
29107
  ],
29108
+ [
29109
+ 'unwrap-list-item',
29110
+ _check_unwrap_list_item__WEBPACK_IMPORTED_MODULE_9__.checkUnwrapListItem
29111
+ ],
28913
29112
  [
28914
29113
  'join-neighbors',
28915
29114
  _check_join_neighbors__WEBPACK_IMPORTED_MODULE_0__.checkJoinNeighbors
@@ -28935,7 +29134,8 @@ function checkRepeatRemoveCharAction(backspace, sibling, fakeNode, mode, removed
28935
29134
  /***/ (function(__unused_webpack_module, __unused_webpack___webpack_exports__, __webpack_require__) {
28936
29135
 
28937
29136
  "use strict";
28938
- /* harmony import */ var jodit_config__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5266);
29137
+ /* harmony import */ var jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(81937);
29138
+ /* harmony import */ var jodit_config__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5266);
28939
29139
  /*!
28940
29140
  * Jodit Editor (https://xdsoft.net/jodit/)
28941
29141
  * Released under MIT see LICENSE.txt in the project root for license information.
@@ -28943,13 +29143,18 @@ function checkRepeatRemoveCharAction(backspace, sibling, fakeNode, mode, removed
28943
29143
  */ /**
28944
29144
  * @module plugins/backspace
28945
29145
  */
28946
- jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.delete = {
29146
+
29147
+ jodit_config__WEBPACK_IMPORTED_MODULE_1__.Config.prototype.delete = {
28947
29148
  hotkeys: {
28948
- delete: [
29149
+ delete: jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.IS_MAC ? [
29150
+ 'delete'
29151
+ ] : [
28949
29152
  'delete',
28950
29153
  'cmd+backspace'
28951
29154
  ],
28952
- deleteWord: [
29155
+ deleteWord: jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.IS_MAC ? [
29156
+ 'ctrl+delete'
29157
+ ] : [
28953
29158
  'ctrl+delete',
28954
29159
  'cmd+alt+backspace',
28955
29160
  'ctrl+alt+backspace'
@@ -28961,7 +29166,7 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.delete = {
28961
29166
  backspace: [
28962
29167
  'backspace'
28963
29168
  ],
28964
- backspaceWord: [
29169
+ backspaceWord: jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.IS_MAC ? [] : [
28965
29170
  'ctrl+backspace'
28966
29171
  ],
28967
29172
  backspaceSentence: [
@@ -32251,7 +32456,7 @@ jodit_core_global__WEBPACK_IMPORTED_MODULE_2__.pluginSystem.add('dtd', dtd);
32251
32456
  ]);
32252
32457
  let block = (0,_helpers__WEBPACK_IMPORTED_MODULE_7__.getBlockWrapper)(fake, jodit);
32253
32458
  const isLi = jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isLeaf(block);
32254
- // if use <br> defaultTag for break line or when was entered SHIFt key or in <td> or <th> or <blockquote>
32459
+ // if use <br> defaultTag for break line or when was entered SHIFt key or in <td>, <th> or <blockquote> without an inner block
32255
32460
  if ((!isLi || event?.shiftKey) && (0,_helpers__WEBPACK_IMPORTED_MODULE_7__.checkBR)(fake, jodit, event?.shiftKey, block)) {
32256
32461
  return false;
32257
32462
  }
@@ -32315,10 +32520,9 @@ jodit_core_global__WEBPACK_IMPORTED_MODULE_4__.pluginSystem.add('enter', enter);
32315
32520
  * Checks the possibility and necessity of inserting a BR instead of a block
32316
32521
  * @private
32317
32522
  */ function checkBR(fake, jodit, shiftKeyPressed, block) {
32318
- const isMultiLineBlock = Boolean(jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.closest(fake, [
32319
- 'pre',
32320
- 'blockquote'
32321
- ], jodit.editor));
32523
+ // Text in a <pre>, or bare text in a quote, gets a BR. A real block inside
32524
+ // a quote (<p>, <h3>, ...) is split like anywhere else, as in a cell below.
32525
+ 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)));
32322
32526
  // A cell itself can't be split into two cells, so bare cell content gets
32323
32527
  // a BR. But when the cell already holds a real block (<p>, <h3>, ...) that
32324
32528
  // block is split like anywhere else, otherwise every line of the cell
@@ -32328,7 +32532,7 @@ jodit_core_global__WEBPACK_IMPORTED_MODULE_4__.pluginSystem.add('enter', enter);
32328
32532
  'th'
32329
32533
  ], jodit.editor)));
32330
32534
  const isBRMode = jodit.o.enter.toLowerCase() === jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.BR.toLowerCase();
32331
- // if you use <br> defaultTag for break line or when was entered SHIFt key or in <td> or <th> or <blockquote>
32535
+ // if you use <br> defaultTag for break line or when was entered SHIFt key or in <td>, <th> or <blockquote> without an inner block
32332
32536
  if (isBRMode || isCell || shiftKeyPressed && !isMultiLineBlock || !shiftKeyPressed && isMultiLineBlock) {
32333
32537
  // 2 BR before
32334
32538
  if (isMultiLineBlock && checkSeveralBR(fake)) {
@@ -34647,8 +34851,12 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.image = {
34647
34851
  dialog.close();
34648
34852
  });
34649
34853
  buttons.remove.onAction(()=>{
34854
+ const caret = j.s.createRange();
34855
+ caret.setStartBefore(this.state.sourceImage);
34856
+ caret.collapse(true);
34650
34857
  j.s.removeNode(this.state.sourceImage);
34651
34858
  dialog.close();
34859
+ j.s.selectRange(caret);
34652
34860
  });
34653
34861
  buttons.cancel.onAction(()=>{
34654
34862
  dialog.close();
@@ -34662,10 +34870,20 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.image = {
34662
34870
  ],
34663
34871
  buttons.check
34664
34872
  ]);
34665
- j.e.on(dialog, 'afterClose', ()=>{
34666
- if (this.state.image.parentNode && j.o.image.selectImageAfterClose) {
34667
- j.s.select(this.state.sourceImage);
34873
+ // The dialog fires `afterClose` on its own emitter, not the editor's
34874
+ dialog.e.on(dialog, 'afterClose', ()=>{
34875
+ const { sourceImage } = this.state;
34876
+ if (j.isInDestruct || !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isOrContains(j.editor, sourceImage)) {
34877
+ return;
34878
+ }
34879
+ if (j.o.image.selectImageAfterClose) {
34880
+ j.s.select(sourceImage);
34881
+ return;
34668
34882
  }
34883
+ const caret = j.s.createRange();
34884
+ caret.setStartAfter(sourceImage);
34885
+ caret.collapse(true);
34886
+ j.s.selectRange(caret);
34669
34887
  });
34670
34888
  dialog.setSize(j.o.image.dialogWidth);
34671
34889
  (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.markOwner)(j, dialog.container);
@@ -34696,6 +34914,7 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.image = {
34696
34914
  this.activeTabState.activeTab = 'Image';
34697
34915
  this.__lock();
34698
34916
  this.dialog.open().setModal(true).setPosition();
34917
+ this.__focusFirstField();
34699
34918
  this.async.promise((resolve, reject)=>(0,_readers__WEBPACK_IMPORTED_MODULE_12__.readValuesFromImage)(this.j, this.state).then(resolve, reject)).catch((e)=>{
34700
34919
  if (!(0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.isAbortError)(e)) {
34701
34920
  this.dialog.message.error(e.message);
@@ -34703,6 +34922,13 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.image = {
34703
34922
  }).finally(()=>this.__unlock());
34704
34923
  return false;
34705
34924
  }
34925
+ /**
34926
+ * Keys typed while the dialog is open must not reach the editor behind it,
34927
+ * so focus the active tab's first field, or else the first field shown
34928
+ */ __focusFirstField() {
34929
+ const fields = (box)=>(0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.toArray)(box.querySelectorAll('input, select, textarea'));
34930
+ fields(this.form.getElm('tabsBox')).concat(fields(this.form.container)).find((field)=>field.offsetParent != null)?.focus();
34931
+ }
34706
34932
  __lock() {
34707
34933
  this.dialog.lock();
34708
34934
  this.form.setMod('lock', true);
@@ -38788,9 +39014,11 @@ const isButtonSeparator = (item)=>item === '|' || item === '---' || item === '\n
38788
39014
  return cleaned;
38789
39015
  }
38790
39016
  /**
38791
- * The width that decides which breakpoint set the toolbar uses. A toolbar
38792
- * rendered into an external container (`toolbar` set to an element or a
38793
- * selector) lays out in that container, so its width is what matters there.
39017
+ * The width that decides which breakpoint set the toolbar uses: the editor's
39018
+ * own width, or its parent's while the editor has none yet (for example
39019
+ * while hidden at init). A toolbar rendered into an external container
39020
+ * (`toolbar` set to an element or a selector) lays out in that container, so
39021
+ * its width is what matters there.
38794
39022
  */ function adaptiveWidth(editor) {
38795
39023
  const { toolbar } = editor.o;
38796
39024
  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)) {
@@ -38799,7 +39027,7 @@ const isButtonSeparator = (item)=>item === '|' || item === '---' || item === '\n
38799
39027
  return width;
38800
39028
  }
38801
39029
  }
38802
- return (editor.container.parentElement ?? editor.container).offsetWidth;
39030
+ return editor.container.offsetWidth || (editor.container.parentElement ?? editor.container).offsetWidth;
38803
39031
  }
38804
39032
  /**
38805
39033
  * Rebuild toolbar in depends on editor's width