jodit 4.12.34 → 4.12.36

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 (75) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/es2015/jodit.css +1 -1
  3. package/es2015/jodit.fat.min.js +2 -2
  4. package/es2015/jodit.js +106 -50
  5. package/es2015/jodit.min.js +2 -2
  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 +2 -2
  13. package/es2018/jodit.min.js +2 -2
  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 +3 -3
  18. package/es2021/jodit.js +105 -48
  19. package/es2021/jodit.min.js +3 -3
  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 +3 -3
  28. package/es2021.en/jodit.js +105 -48
  29. package/es2021.en/jodit.min.js +3 -3
  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 +255 -196
  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/core/constants.js +1 -1
  51. package/esm/core/dom/dom.d.ts +35 -12
  52. package/esm/core/dom/dom.js +42 -20
  53. package/esm/core/dom/lazy-walker.d.ts +18 -1
  54. package/esm/core/dom/lazy-walker.js +23 -3
  55. package/esm/core/request/ajax.js +1 -1
  56. package/esm/core/selection/helpers/index.d.ts +3 -1
  57. package/esm/core/selection/helpers/index.js +3 -1
  58. package/esm/core/selection/selection.d.ts +14 -0
  59. package/esm/core/selection/selection.js +19 -8
  60. package/esm/core/selection/style/api/is-same-attributes.d.ts +4 -2
  61. package/esm/core/selection/style/api/is-same-attributes.js +3 -4
  62. package/esm/core/selection/style/api/is-suit-element.d.ts +2 -1
  63. package/esm/core/selection/style/api/is-suit-element.js +2 -1
  64. package/esm/core/selection/style/api/list/toggle-ordered-list.js +7 -0
  65. package/esm/core/selection/style/api/toggle-attributes.js +3 -1
  66. package/esm/core/selection/style/commit-style.d.ts +1 -1
  67. package/esm/core/selection/style/commit-style.js +2 -2
  68. package/package.json +1 -1
  69. package/types/core/dom/dom.d.ts +35 -12
  70. package/types/core/dom/lazy-walker.d.ts +18 -1
  71. package/types/core/selection/helpers/index.d.ts +3 -1
  72. package/types/core/selection/selection.d.ts +14 -0
  73. package/types/core/selection/style/api/is-same-attributes.d.ts +4 -2
  74. package/types/core/selection/style/api/is-suit-element.d.ts +2 -1
  75. package/types/core/selection/style/commit-style.d.ts +1 -1
package/es2015/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.12.34
4
+ * Version: v4.12.36
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
@@ -1816,7 +1816,7 @@ __webpack_require__.r(__webpack_exports__);
1816
1816
  * ```
1817
1817
  * @packageDocumentation
1818
1818
  * @module constants
1819
- */ const APP_VERSION = "4.12.34";
1819
+ */ const APP_VERSION = "4.12.36";
1820
1820
  // prettier-ignore
1821
1821
  const ES = "es2015";
1822
1822
  const IS_ES_MODERN = true;
@@ -3008,6 +3008,7 @@ function wait(condition) {
3008
3008
 
3009
3009
 
3010
3010
 
3011
+ const TEMP_ELEMENT_REG_EXP = new RegExp(`<([a-z]+)[^>]+${jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.TEMP_ATTR}[^>]*>(.+?)</\\1>`, 'gi');
3011
3012
  /**
3012
3013
  * Module for working with DOM
3013
3014
  */ class Dom {
@@ -3108,7 +3109,11 @@ function wait(condition) {
3108
3109
  }
3109
3110
  }
3110
3111
  /**
3111
- * Call functions for all nodes between `start` and `end`
3112
+ * Call callback for all nodes between `start` and `end` in document order
3113
+ * (`start` and `end` are not included). Iteration stops when the callback returns `true`.
3114
+ *
3115
+ * `end` must be positioned after `start` in the document (e.g. selection markers),
3116
+ * otherwise iteration will stop only at the end of the tree.
3112
3117
  */ static between(start, end, callback) {
3113
3118
  let next = start;
3114
3119
  while(next && next !== end){
@@ -3119,6 +3124,10 @@ function wait(condition) {
3119
3124
  if (!step) {
3120
3125
  while(next && !next.nextSibling){
3121
3126
  next = next.parentNode;
3127
+ // `end` was reached while ascending - all nodes between were visited
3128
+ if (next === end) {
3129
+ return;
3130
+ }
3122
3131
  }
3123
3132
  step = next === null || next === void 0 ? void 0 : next.nextSibling;
3124
3133
  }
@@ -3200,7 +3209,7 @@ function wait(condition) {
3200
3209
  return Dom.isNode(elm) && (elm.nodeName === 'TD' || elm.nodeName === 'TH');
3201
3210
  }
3202
3211
  /**
3203
- * Check if element is a list element UL or OL
3212
+ * Check if element is a list element UL or OL
3204
3213
  */ static isList(elm) {
3205
3214
  return Dom.isTag(elm, jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.LIST_TAGS);
3206
3215
  }
@@ -3243,12 +3252,13 @@ function wait(condition) {
3243
3252
  /**
3244
3253
  * Check if element is document fragment
3245
3254
  */ static isFragment(node) {
3246
- var _node_ownerDocument;
3247
3255
  if (!Dom.isNode(node)) {
3248
3256
  return false;
3249
3257
  }
3250
- const win = (_node_ownerDocument = node.ownerDocument) === null || _node_ownerDocument === void 0 ? void 0 : _node_ownerDocument.defaultView;
3251
- return Boolean(win && node.nodeType === Node.DOCUMENT_FRAGMENT_NODE);
3258
+ // no `defaultView` requirement fragments of an inert document
3259
+ // (`template.content`, `DOMParser`, `implementation.createHTMLDocument`)
3260
+ // are still fragments
3261
+ return node.nodeType === Node.DOCUMENT_FRAGMENT_NODE;
3252
3262
  }
3253
3263
  /**
3254
3264
  * Check if element is HTMLElement node
@@ -3357,16 +3367,19 @@ function wait(condition) {
3357
3367
  return null;
3358
3368
  }
3359
3369
  /**
3360
- * Find next/prev node what `condition(next) === true`
3370
+ * Lazily iterate over all nodes what follow after `start` (in document order
3371
+ * for `leftToRight = true`, in reverse order otherwise) inside `root`.
3372
+ * Ancestors of `start` are not yielded.
3361
3373
  */ static *nextGen(start, root, leftToRight = true, withChild = true) {
3362
3374
  const stack = [];
3363
3375
  let currentNode = start;
3364
3376
  do {
3365
3377
  let next = leftToRight ? currentNode.nextSibling : currentNode.previousSibling;
3366
3378
  while(next){
3367
- stack.unshift(next);
3379
+ stack.push(next);
3368
3380
  next = leftToRight ? next.nextSibling : next.previousSibling;
3369
3381
  }
3382
+ stack.reverse();
3370
3383
  yield* this.runInStack(start, stack, leftToRight, withChild);
3371
3384
  currentNode = currentNode.parentNode;
3372
3385
  }while (currentNode && currentNode !== root)
@@ -3381,7 +3394,7 @@ function wait(condition) {
3381
3394
  * ```javascript
3382
3395
  * Jodit.modules.Dom.each(editor.s.current(), function (node) {
3383
3396
  * if (node.nodeType === Node.TEXT_NODE) {
3384
- * node.nodeValue = node.nodeValue.replace(Jodit.INVISIBLE_SPACE_REG_EX, '') // remove all of the text element codes invisible character
3397
+ * node.nodeValue = node.nodeValue.replace(Jodit.INVISIBLE_SPACE_REG_EXP(), '') // remove all of the text element codes invisible character
3385
3398
  * }
3386
3399
  * });
3387
3400
  * ```
@@ -3461,11 +3474,17 @@ function wait(condition) {
3461
3474
  */ static findNotEmptyNeighbor(node, left, root) {
3462
3475
  return (0,jodit_core_helpers_utils_utils__WEBPACK_IMPORTED_MODULE_14__.call)(left ? Dom.prev : Dom.next, node, (n)=>Boolean(n && (!(Dom.isText(n) || Dom.isComment(n)) || (0,jodit_core_helpers_string_trim__WEBPACK_IMPORTED_MODULE_8__.trim)((n === null || n === void 0 ? void 0 : n.nodeValue) || '').length)), root);
3463
3476
  }
3464
- static sibling(node, left) {
3477
+ /**
3478
+ * Returns the previous (`left = true`) or next sibling of the node
3479
+ */ static sibling(node, left) {
3465
3480
  return left ? node.previousSibling : node.nextSibling;
3466
3481
  }
3467
3482
  /**
3468
3483
  * It goes through all the elements in ascending order, and checks to see if they meet the predetermined condition
3484
+ *
3485
+ * The condition is checked for the `node` itself too. The `root` reached
3486
+ * while ascending is checked only when `checkRoot = true`
3487
+ * (but if `node === root` it is checked in any case).
3469
3488
  */ static up(node, condition, root, checkRoot = false) {
3470
3489
  let start = node;
3471
3490
  if (!start) {
@@ -3590,7 +3609,12 @@ function wait(condition) {
3590
3609
  */ static safeRemove(...nodes) {
3591
3610
  nodes.forEach((node)=>Dom.isNode(node) && node.parentNode && node.parentNode.removeChild(node));
3592
3611
  }
3593
- static safeInsertNode(range, node) {
3612
+ /**
3613
+ * Insert a node into the range and collapse the range to the start of
3614
+ * the inserted content. Unlike the native `Range.insertNode` it does not
3615
+ * split inseparable elements (BR, HR, IMG etc.) and removes empty text
3616
+ * nodes produced by the split of a text container.
3617
+ */ static safeInsertNode(range, node) {
3594
3618
  range.collapsed || range.deleteContents();
3595
3619
  const child = Dom.isFragment(node) ? node.lastChild : node;
3596
3620
  if (range.startContainer === range.endContainer && range.collapsed && Dom.isTag(range.startContainer, jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.INSEPARABLE_TAGS)) {
@@ -3629,22 +3653,17 @@ function wait(condition) {
3629
3653
  }
3630
3654
  }
3631
3655
  static isTag(node, tagNames) {
3656
+ if (Array.isArray(tagNames)) {
3657
+ throw new TypeError('Dom.isTag does not support array');
3658
+ }
3632
3659
  if (!this.isElement(node)) {
3633
3660
  return false;
3634
3661
  }
3635
3662
  const nameL = node.tagName.toLowerCase();
3636
- const nameU = node.tagName.toUpperCase();
3637
3663
  if (tagNames instanceof Set) {
3638
- return tagNames.has(nameL) || tagNames.has(nameU);
3639
- }
3640
- if (Array.isArray(tagNames)) {
3641
- throw new TypeError('Dom.isTag does not support array');
3664
+ return tagNames.has(nameL) || tagNames.has(node.tagName.toUpperCase());
3642
3665
  }
3643
- const tags = tagNames;
3644
- if (nameL === tags || nameU === tags) {
3645
- return true;
3646
- }
3647
- return false;
3666
+ return nameL === tagNames || node.tagName.toUpperCase() === tagNames;
3648
3667
  }
3649
3668
  /**
3650
3669
  * Marks an item as temporary
@@ -3667,9 +3686,9 @@ function wait(condition) {
3667
3686
  return Dom.isNode(elm) && Dom.isTag(elm, 'span') && elm.hasAttribute('data-' + jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.MARKER_CLASS);
3668
3687
  }
3669
3688
  /**
3670
- * Replace temporary elements from string
3689
+ * Unwrap temporary elements inside a HTML string (keeps their content)
3671
3690
  */ static replaceTemporaryFromString(value) {
3672
- return value.replace(/<([a-z]+)[^>]+data-jodit-temp[^>]+>(.+?)<\/\1>/gi, '$2');
3691
+ return value.replace(TEMP_ELEMENT_REG_EXP, '$2');
3673
3692
  }
3674
3693
  /**
3675
3694
  * Get temporary list
@@ -3730,13 +3749,29 @@ function wait(condition) {
3730
3749
 
3731
3750
 
3732
3751
 
3733
- class LazyWalker extends jodit_core_event_emitter_eventify__WEBPACK_IMPORTED_MODULE_4__.Eventify {
3734
- setWork(root) {
3752
+ /**
3753
+ * Walks the DOM tree in small chunks between browser tasks so that even huge
3754
+ * documents do not block the main thread.
3755
+ *
3756
+ * Events:
3757
+ * - `visit` - is called for every node; return `true` to mark the pass as
3758
+ * "had effect" (it will be passed into the `end` event)
3759
+ * - `break` - the pass was interrupted via [[LazyWalker.break]]
3760
+ * - `end` - the pass is finished, receives `true` if some `visit` handler returned `true`
3761
+ */ class LazyWalker extends jodit_core_event_emitter_eventify__WEBPACK_IMPORTED_MODULE_4__.Eventify {
3762
+ /**
3763
+ * Starts a new pass over the `root` tree.
3764
+ * If a previous pass is still running it will be stopped first.
3765
+ */ setWork(root) {
3735
3766
  if (this.isWorked) {
3736
3767
  this.break();
3768
+ } else {
3769
+ // cancel a not yet started pass scheduled by the previous `setWork` call
3770
+ this.stop();
3737
3771
  }
3738
3772
  this.workNodes = jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.eachGen(root, !this.options.reverse);
3739
3773
  this.isFinished = false;
3774
+ this.hadAffect = false;
3740
3775
  this._requestStarting();
3741
3776
  return this;
3742
3777
  }
@@ -3761,10 +3796,12 @@ class LazyWalker extends jodit_core_event_emitter_eventify__WEBPACK_IMPORTED_MOD
3761
3796
  }
3762
3797
  }
3763
3798
  stop() {
3799
+ var _this___schedulerController;
3764
3800
  this.isWorked = false;
3765
3801
  this.isFinished = true;
3766
3802
  this.workNodes = null;
3767
- this.async.cancelIdleCallback(this.idleId);
3803
+ (_this___schedulerController = this.__schedulerController) === null || _this___schedulerController === void 0 ? void 0 : _this___schedulerController.abort();
3804
+ this.__schedulerController = null;
3768
3805
  }
3769
3806
  destruct() {
3770
3807
  super.destruct();
@@ -3776,7 +3813,7 @@ class LazyWalker extends jodit_core_event_emitter_eventify__WEBPACK_IMPORTED_MOD
3776
3813
  this.isWorked = true;
3777
3814
  let count = 0;
3778
3815
  const chunkSize = (_this_options_timeoutChunkSize = this.options.timeoutChunkSize) !== null && _this_options_timeoutChunkSize !== void 0 ? _this_options_timeoutChunkSize : 50;
3779
- while(!this.isFinished && count <= chunkSize){
3816
+ while(!this.isFinished && count < chunkSize){
3780
3817
  const item = this.workNodes.next();
3781
3818
  count += 1;
3782
3819
  if (this.visitNode(item.value)) {
@@ -3802,7 +3839,7 @@ class LazyWalker extends jodit_core_event_emitter_eventify__WEBPACK_IMPORTED_MOD
3802
3839
  return (_this_emit = this.emit('visit', nodeElm)) !== null && _this_emit !== void 0 ? _this_emit : false;
3803
3840
  }
3804
3841
  constructor(async, options = {}){
3805
- super(), (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "async", void 0), (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "options", void 0), (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "workNodes", void 0), (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "hadAffect", void 0), (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "isWorked", void 0), (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "isFinished", void 0), (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "idleId", void 0), (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "__schedulerController", void 0), this.async = async, this.options = options, this.workNodes = null, this.hadAffect = false, this.isWorked = false, this.isFinished = false, this.idleId = 0, this.__schedulerController = null;
3842
+ super(), (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "async", void 0), (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "options", void 0), (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "workNodes", void 0), (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "hadAffect", void 0), (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "isWorked", void 0), (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "isFinished", void 0), (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "__schedulerController", void 0), this.async = async, this.options = options, this.workNodes = null, this.hadAffect = false, this.isWorked = false, this.isFinished = false, this.__schedulerController = null;
3806
3843
  }
3807
3844
  }
3808
3845
  (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
@@ -10139,7 +10176,7 @@ class Ajax {
10139
10176
  if (method === 'get' && data && (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_9__.isPlainObject)(data)) {
10140
10177
  const qIndex = url.indexOf('?');
10141
10178
  if (qIndex !== -1) {
10142
- const urlData = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_9__.parseQuery)(url);
10179
+ const urlData = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_9__.parseQuery)(url.substring(qIndex));
10143
10180
  url = url.substring(0, qIndex) + '?' + (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_9__.buildQuery)((0,_swc_helpers_object_spread__WEBPACK_IMPORTED_MODULE_3__._)({}, urlData, data));
10144
10181
  } else {
10145
10182
  url += '?' + (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_9__.buildQuery)(this.o.data);
@@ -10312,7 +10349,9 @@ class Response {
10312
10349
 
10313
10350
 
10314
10351
  /**
10315
- * Check if the cursor is at the edge of the string
10352
+ * Despite the name, returns `true` when the cursor is NOT at the checked edge
10353
+ * of the text node: there is significant (non invisible-space) text between
10354
+ * the offset and the start (`start = true`) or the end (`end = true`) of the string.
10316
10355
  * @private
10317
10356
  */ function cursorInTheEdgeOfString(container, offset, start, end) {
10318
10357
  var _container_nodeValue;
@@ -10633,7 +10672,7 @@ class Selection {
10633
10672
  /**
10634
10673
  * Remove all markers
10635
10674
  */ removeMarkers() {
10636
- jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_4__.Dom.safeRemove.apply(null, this.markers);
10675
+ jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_4__.Dom.safeRemove(...this.markers);
10637
10676
  }
10638
10677
  /**
10639
10678
  * Create marker element
@@ -10690,7 +10729,11 @@ class Selection {
10690
10729
  this.selectRange(range);
10691
10730
  }
10692
10731
  }
10693
- fakes() {
10732
+ /**
10733
+ * Inserts invisible fake nodes on the boundaries of the current selection
10734
+ * and returns them. Unlike [[Select.save]] the selection stays valid while
10735
+ * the DOM around it is being modified. Restore it later with [[Select.restoreFakes]].
10736
+ */ fakes() {
10694
10737
  const sel = this.sel;
10695
10738
  if (!sel || !sel.rangeCount) {
10696
10739
  return [];
@@ -10716,7 +10759,10 @@ class Selection {
10716
10759
  this.selectRange(range);
10717
10760
  return result;
10718
10761
  }
10719
- restoreFakes(fakes) {
10762
+ /**
10763
+ * Restores the selection previously saved with [[Select.fakes]]
10764
+ * and removes the fake nodes (disconnected fakes are ignored).
10765
+ */ restoreFakes(fakes) {
10720
10766
  var _fakeLeft_parentNode, _fakeLeft_parentNode1, _fakeRight_parentNode, _fakeRight_parentNode1;
10721
10767
  const nodes = fakes.filter((n)=>n.isConnected);
10722
10768
  if (!nodes.length) {
@@ -10958,7 +11004,6 @@ class Selection {
10958
11004
  }
10959
11005
  const node = this.j.createInside.div();
10960
11006
  const fragment = this.j.createInside.fragment();
10961
- let lastChild;
10962
11007
  if (!this.isFocused() && this.j.isEditorMode()) {
10963
11008
  this.focus();
10964
11009
  this.restore();
@@ -10971,12 +11016,10 @@ class Selection {
10971
11016
  if (!this.j.isEditorMode() && this.j.e.fire('insertHTML', node.innerHTML) === false) {
10972
11017
  return;
10973
11018
  }
10974
- lastChild = node.lastChild;
10975
- if (!lastChild) {
11019
+ if (!node.lastChild) {
10976
11020
  return;
10977
11021
  }
10978
11022
  while(node.firstChild){
10979
- lastChild = node.firstChild;
10980
11023
  fragment.appendChild(node.firstChild);
10981
11024
  }
10982
11025
  this.insertNode(fragment, insertCursorAfter, false);
@@ -11089,7 +11132,8 @@ class Selection {
11089
11132
  if (jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_4__.Dom.isEmptyTextNode(start)) {
11090
11133
  nodes.push(start);
11091
11134
  }
11092
- if (start.firstChild) {
11135
+ // `start` can be undefined for an empty root
11136
+ if (start === null || start === void 0 ? void 0 : start.firstChild) {
11093
11137
  nodes.push(start.firstChild);
11094
11138
  }
11095
11139
  }
@@ -11104,8 +11148,7 @@ class Selection {
11104
11148
  *
11105
11149
  * @returns true - the cursor is at the end(start) block, null - cursor somewhere outside
11106
11150
  */ cursorInTheEdge(start, parentBlock, fake = null) {
11107
- var _this_sel;
11108
- const end = !start, range = (_this_sel = this.sel) === null || _this_sel === void 0 ? void 0 : _this_sel.getRangeAt(0);
11151
+ const end = !start, sel = this.sel, range = (sel === null || sel === void 0 ? void 0 : sel.rangeCount) ? sel.getRangeAt(0) : null;
11109
11152
  fake !== null && fake !== void 0 ? fake : fake = this.current(false);
11110
11153
  if (!range || !fake || !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_4__.Dom.isOrContains(parentBlock, fake, true)) {
11111
11154
  return null;
@@ -11448,7 +11491,11 @@ class Selection {
11448
11491
  }
11449
11492
  return currentBox.previousElementSibling;
11450
11493
  }
11451
- expandSelection() {
11494
+ /**
11495
+ * Expands the non-collapsed selection outward: boundaries positioned on the
11496
+ * edge of their parents are moved out of them (e.g. `<p><b>|test|</b></p>`
11497
+ * becomes `<p>|<b>test</b>|</p>`)
11498
+ */ expandSelection() {
11452
11499
  if (this.isCollapsed()) {
11453
11500
  return this;
11454
11501
  }
@@ -11944,12 +11991,11 @@ if (jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.globalDocument) {
11944
11991
 
11945
11992
 
11946
11993
  /**
11947
- * Compares whether the given attributes match the element's own attributes
11994
+ * Checks that every attribute from `attrs` is present on the element with
11995
+ * the same value (one-directional match: extra own attributes of the element
11996
+ * are ignored, empty `attrs` matches any element)
11948
11997
  * @private
11949
11998
  */ function isSameAttributes(elm, attrs) {
11950
- if (!elm.attributes.length && !(0,jodit_core_helpers_size_object_size__WEBPACK_IMPORTED_MODULE_0__.size)(attrs)) {
11951
- return true;
11952
- }
11953
11999
  if (!(0,jodit_core_helpers_size_object_size__WEBPACK_IMPORTED_MODULE_0__.size)(attrs)) {
11954
12000
  return true;
11955
12001
  }
@@ -11998,7 +12044,8 @@ function elementsEqualAttributes(elm1, elm2) {
11998
12044
  * @param commitStyle - style commit
11999
12045
  * @param elm - checked item
12000
12046
  * @param strict - strict mode - false - the default tag is suitable for us if it is also in the commit
12001
- * @param strictStyle - strict style mode - true - the element has the same style keys as in the commit, but not their values
12047
+ * @param strictStyle - strict style mode - true - the element must have the same style keys AND values
12048
+ * as in the commit, false - matching style keys are enough
12002
12049
  * @private
12003
12050
  */ function isSuitElement(commitStyle, elm, strict, strictStyle = true) {
12004
12051
  var _options_attributes;
@@ -12110,6 +12157,13 @@ function unwrapList(mode, list, li, jodit, cs) {
12110
12157
  (0,jodit_core_selection_style_api_extract__WEBPACK_IMPORTED_MODULE_2__.extractSelectedPart)(list, li, jodit);
12111
12158
  (0,jodit_core_helpers_utils_assert__WEBPACK_IMPORTED_MODULE_1__.assert)(jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.isHTMLElement(li.parentElement), 'Element should be inside the list');
12112
12159
  jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.unwrap(li.parentElement);
12160
+ // In the REPLACE mode the content will be immediately wrapped in a `li`
12161
+ // of the new list inside `wrapList`, so it should stay in the document.
12162
+ // Replacing it with a fragment here would dissolve the content
12163
+ // (with `enter: 'br'`) and the new list would never be inserted.
12164
+ if (mode === jodit_core_selection_style_constants__WEBPACK_IMPORTED_MODULE_4__.REPLACE) {
12165
+ return li;
12166
+ }
12113
12167
  return jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.replace(li, jodit.o.enter.toLowerCase() !== 'br' ? jodit.o.enter : jodit.createInside.fragment(), jodit.createInside);
12114
12168
  }
12115
12169
 
@@ -12279,7 +12333,9 @@ function toggleClass(jodit, value, elm, mode, dry) {
12279
12333
  function toggleAttribute(jodit, value, elm, key, dry, mode) {
12280
12334
  (0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_7__.assert)((0,jodit_core_helpers_checker__WEBPACK_IMPORTED_MODULE_3__.isString)(value) || (0,jodit_core_helpers_checker__WEBPACK_IMPORTED_MODULE_3__.isNumber)(value) || (0,jodit_core_helpers_checker__WEBPACK_IMPORTED_MODULE_3__.isBoolean)(value) || value == null, 'Attribute value must be a string or number or boolean or null');
12281
12335
  const hook = jodit.e.fire.bind(jodit.e, `${jodit_core_selection_style_constants__WEBPACK_IMPORTED_MODULE_10__._PREFIX}AfterToggleAttribute`);
12282
- if ((0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_7__.attr)(elm, key) === value) {
12336
+ // `attr()` getter always returns a string, so a number/boolean value
12337
+ // must be normalized, otherwise the toggle-off branch is unreachable
12338
+ if ((0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_7__.attr)(elm, key) === (value == null ? value : String(value))) {
12283
12339
  !dry && (0,jodit_core_helpers_utils__WEBPACK_IMPORTED_MODULE_7__.attr)(elm, key, null);
12284
12340
  mode = jodit_core_selection_style_constants__WEBPACK_IMPORTED_MODULE_10__.UNSET;
12285
12341
  !dry && hook(mode, elm, key, value);
@@ -12632,7 +12688,7 @@ class CommitStyle {
12632
12688
  if (!data) {
12633
12689
  return false;
12634
12690
  }
12635
- return data[key];
12691
+ return Boolean(data[key]);
12636
12692
  }
12637
12693
  setApplied(elm, key) {
12638
12694
  var _this___applyMap_get;
@@ -12647,7 +12703,7 @@ class CommitStyle {
12647
12703
  return this.options.element || this.defaultTag;
12648
12704
  }
12649
12705
  /**
12650
- * New element is blocked
12706
+ * New element is a block element
12651
12707
  */ get elementIsBlock() {
12652
12708
  return Boolean(this.options.element && jodit_core_constants__WEBPACK_IMPORTED_MODULE_1__.IS_BLOCK.test(this.options.element));
12653
12709
  }