jodit 4.12.21 → 4.12.23

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 (86) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/es2015/jodit.css +1 -1
  3. package/es2015/jodit.fat.min.js +11 -11
  4. package/es2015/jodit.js +362 -101
  5. package/es2015/jodit.min.js +11 -11
  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 +11 -11
  13. package/es2018/jodit.min.js +25 -25
  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 +13 -13
  18. package/es2021/jodit.js +352 -99
  19. package/es2021/jodit.min.js +23 -23
  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 +14 -14
  28. package/es2021.en/jodit.js +330 -77
  29. package/es2021.en/jodit.min.js +14 -14
  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 +415 -136
  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/component/view-component.js +8 -0
  51. package/esm/core/constants.js +1 -1
  52. package/esm/core/dom/dom.js +6 -4
  53. package/esm/core/helpers/checker/is-html-from-word.d.ts +1 -1
  54. package/esm/core/helpers/checker/is-html-from-word.js +12 -1
  55. package/esm/core/selection/style/api/wrap.js +18 -3
  56. package/esm/core/ui/popup/popup.js +4 -1
  57. package/esm/jodit.js +12 -0
  58. package/esm/langs/tr.js +1 -1
  59. package/esm/modules/dialog/dialog.d.ts +5 -0
  60. package/esm/modules/dialog/dialog.js +25 -2
  61. package/esm/modules/toolbar/button/content.d.ts +6 -0
  62. package/esm/modules/toolbar/button/content.js +26 -1
  63. package/esm/plugins/add-new-line/add-new-line.js +4 -1
  64. package/esm/plugins/ai-assistant/ai-assistant.js +7 -1
  65. package/esm/plugins/backspace/cases/check-join-neighbors.js +15 -1
  66. package/esm/plugins/clean-html/clean-html.js +8 -2
  67. package/esm/plugins/clean-html/helpers/visitor/filters/allow-attributes.js +9 -2
  68. package/esm/plugins/clipboard/clipboard.js +29 -1
  69. package/esm/plugins/color/color.js +21 -21
  70. package/esm/plugins/inline-popup/inline-popup.d.ts +15 -0
  71. package/esm/plugins/inline-popup/inline-popup.js +60 -3
  72. package/esm/plugins/limit/limit.js +7 -1
  73. package/esm/plugins/paste/config.js +11 -2
  74. package/esm/plugins/paste/paste.d.ts +1 -1
  75. package/esm/plugins/paste/paste.js +7 -5
  76. package/esm/plugins/resize-handler/resize-handler.js +13 -2
  77. package/esm/plugins/resizer/resizer.js +5 -1
  78. package/esm/plugins/search/ui/search.js +22 -12
  79. package/esm/plugins/select-cells/select-cells.js +10 -6
  80. package/esm/plugins/source/source.js +9 -0
  81. package/package.json +1 -1
  82. package/types/core/helpers/checker/is-html-from-word.d.ts +1 -1
  83. package/types/modules/dialog/dialog.d.ts +5 -0
  84. package/types/modules/toolbar/button/content.d.ts +6 -0
  85. package/types/plugins/inline-popup/inline-popup.d.ts +15 -0
  86. package/types/plugins/paste/paste.d.ts +1 -1
@@ -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.21
4
+ * Version: v4.12.23
5
5
  * Url: https://xdsoft.net/jodit/
6
6
  * License(s): MIT
7
7
  */
@@ -1698,6 +1698,14 @@ class ViewComponent extends _component__WEBPACK_IMPORTED_MODULE_1__.Component {
1698
1698
  * Attach component to View
1699
1699
  */ setParentView(jodit) {
1700
1700
  this.jodit = jodit;
1701
+ // Inherit the owner window from the parent view — for an editor
1702
+ // created with a custom `ownerWindow` (e.g. inside an iframe) the
1703
+ // component default (the global `window`) is wrong: outside-click
1704
+ // handlers of dropdowns/popups listened to the wrong window. See
1705
+ // https://github.com/xdan/jodit/issues/965
1706
+ if (jodit.ow) {
1707
+ this.ownerWindow = jodit.ow;
1708
+ }
1701
1709
  jodit.components.add(this);
1702
1710
  return this;
1703
1711
  }
@@ -1802,7 +1810,7 @@ __webpack_require__.r(__webpack_exports__);
1802
1810
  * ```
1803
1811
  * @packageDocumentation
1804
1812
  * @module constants
1805
- */ const APP_VERSION = "4.12.21";
1813
+ */ const APP_VERSION = "4.12.23";
1806
1814
  // prettier-ignore
1807
1815
  const ES = "es2021";
1808
1816
  const IS_ES_MODERN = true;
@@ -3218,8 +3226,9 @@ function wait(condition) {
3218
3226
  if (!Dom.isNode(node)) {
3219
3227
  return false;
3220
3228
  }
3221
- const win = node.ownerDocument?.defaultView;
3222
- return Boolean(win && node.nodeType === Node.ELEMENT_NODE);
3229
+ // no `defaultView` requirement — nodes of an inert document
3230
+ // (`DOMParser`, `implementation.createHTMLDocument`) are still elements
3231
+ return node.nodeType === Node.ELEMENT_NODE;
3223
3232
  }
3224
3233
  /**
3225
3234
  * Check if element is document fragment
@@ -3236,8 +3245,10 @@ function wait(condition) {
3236
3245
  if (!Dom.isNode(node)) {
3237
3246
  return false;
3238
3247
  }
3248
+ // an inert document has no browsing context (`defaultView` is null),
3249
+ // but its nodes are same-realm HTMLElements
3239
3250
  const win = node.ownerDocument?.defaultView;
3240
- return Boolean(win && node instanceof win.HTMLElement);
3251
+ return node instanceof (win ? win.HTMLElement : HTMLElement);
3241
3252
  }
3242
3253
  /**
3243
3254
  * Check element is inline block
@@ -5167,9 +5178,15 @@ function isFastEqual(a, b) {
5167
5178
  */ /**
5168
5179
  * @module helpers/checker
5169
5180
  */ /**
5170
- * Detect if string is HTML from MS Word or Excel
5181
+ * Detect if string is HTML from MS Word, Excel or LibreOffice/OpenOffice
5171
5182
  */ function isHtmlFromWord(data) {
5172
- return data.search(/<meta.*?Microsoft Excel\s[\d].*?>/) !== -1 || data.search(/<meta.*?Microsoft Word\s[\d].*?>/) !== -1 || data.search(/style="[^"]*mso-/) !== -1 && data.search(/<font/) !== -1;
5183
+ return data.search(/<meta.*?Microsoft Excel\s[\d].*?>/) !== -1 || data.search(/<meta.*?Microsoft Word\s[\d].*?>/) !== -1 || // `<meta name=ProgId content=Word.Document>` attribute values are
5184
+ // unquoted in the raw Word clipboard fragment
5185
+ data.search(/<meta[^>]*?ProgId[^>]*?(Word|Excel)\./i) !== -1 || // LibreOffice/OpenOffice Writer & Calc
5186
+ data.search(/<meta[^>]*?(LibreOffice|OpenOffice)/i) !== -1 || // Office namespaces on the root element of the clipboard fragment
5187
+ data.search(/urn:schemas-microsoft-com:office:(word|excel)/) !== -1 || // `class=MsoNormal` and friends (unquoted/quoted)
5188
+ data.search(/<\w[^>]*\sclass=("|')?Mso/) !== -1 || // the raw Word clipboard uses SINGLE quotes: style='mso-…'
5189
+ data.search(/style='[^']*mso-/) !== -1 || data.search(/style="[^"]*mso-/) !== -1 && data.search(/<font/) !== -1;
5173
5190
  }
5174
5191
 
5175
5192
 
@@ -12311,8 +12328,9 @@ function toggleAttribute(jodit, value, elm, key, dry, mode) {
12311
12328
  /* harmony export */ });
12312
12329
  /* harmony import */ var jodit_core_dom__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(27795);
12313
12330
  /* harmony import */ var jodit_core_helpers_utils_attr__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7909);
12314
- /* harmony import */ var _list_wrap_list__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(97110);
12315
- /* harmony import */ var _wrap_unwrapped_text__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(83335);
12331
+ /* harmony import */ var jodit_core_helpers_utils_css__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(80991);
12332
+ /* harmony import */ var _list_wrap_list__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(97110);
12333
+ /* harmony import */ var _wrap_unwrapped_text__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(83335);
12316
12334
  /*!
12317
12335
  * Jodit Editor (https://xdsoft.net/jodit/)
12318
12336
  * Released under MIT see LICENSE.txt in the project root for license information.
@@ -12321,12 +12339,29 @@ function toggleAttribute(jodit, value, elm, key, dry, mode) {
12321
12339
 
12322
12340
 
12323
12341
 
12342
+
12324
12343
  /**
12325
12344
  * Replaces the parent tag with the applicable one, or wraps the text and also replaces the tag
12326
12345
  * @private
12327
12346
  */ function wrap(commitStyle, font, jodit) {
12328
12347
  const wrapper = findOrCreateWrapper(commitStyle, font, jodit);
12329
- return commitStyle.elementIsList ? (0,_list_wrap_list__WEBPACK_IMPORTED_MODULE_2__.wrapList)(commitStyle, wrapper, jodit) : jodit_core_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.replace(wrapper, commitStyle.element, jodit.createInside, true);
12348
+ if (commitStyle.elementIsList) {
12349
+ return (0,_list_wrap_list__WEBPACK_IMPORTED_MODULE_3__.wrapList)(commitStyle, wrapper, jodit);
12350
+ }
12351
+ const newWrapper = jodit_core_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.replace(wrapper, commitStyle.element, jodit.createInside, true);
12352
+ if (commitStyle.elementIsBlock) {
12353
+ // Inline font styles left over from pasted content visually override
12354
+ // the new block format — e.g. an h2 with `font-weight: normal;
12355
+ // font-size: 24px` does not look like a heading at all, so the
12356
+ // command seems to do nothing. See
12357
+ // https://github.com/xdan/jodit/issues/1063
12358
+ (0,jodit_core_helpers_utils_css__WEBPACK_IMPORTED_MODULE_2__.css)(newWrapper, 'fontSize', null);
12359
+ (0,jodit_core_helpers_utils_css__WEBPACK_IMPORTED_MODULE_2__.css)(newWrapper, 'fontWeight', null);
12360
+ if (!(0,jodit_core_helpers_utils_attr__WEBPACK_IMPORTED_MODULE_1__.attr)(newWrapper, 'style')) {
12361
+ (0,jodit_core_helpers_utils_attr__WEBPACK_IMPORTED_MODULE_1__.attr)(newWrapper, 'style', null);
12362
+ }
12363
+ }
12364
+ return newWrapper;
12330
12365
  }
12331
12366
  const WRAP_NODES = new Set([
12332
12367
  'td',
@@ -12347,7 +12382,7 @@ const WRAP_NODES = new Set([
12347
12382
  if (box) {
12348
12383
  return box;
12349
12384
  }
12350
- return (0,_wrap_unwrapped_text__WEBPACK_IMPORTED_MODULE_3__.wrapUnwrappedText)(commitStyle, font, jodit);
12385
+ return (0,_wrap_unwrapped_text__WEBPACK_IMPORTED_MODULE_4__.wrapUnwrappedText)(commitStyle, font, jodit);
12351
12386
  }
12352
12387
  (0,jodit_core_helpers_utils_attr__WEBPACK_IMPORTED_MODULE_1__.attr)(font, 'size', null);
12353
12388
  return font;
@@ -15943,7 +15978,9 @@ class Popup extends jodit_core_ui_group_group__WEBPACK_IMPORTED_MODULE_9__.UIGro
15943
15978
  * Calculate static bound for point
15944
15979
  */ getKeepBound(getBound) {
15945
15980
  const oldBound = getBound();
15946
- const elmUnderCursor = this.od.elementFromPoint(oldBound.left, oldBound.top);
15981
+ // Inside Shadow DOM `document.elementFromPoint` returns the shadow
15982
+ // host, so the lookup must start from the shadow root
15983
+ const elmUnderCursor = (this.j.o.shadowRoot ?? this.od).elementFromPoint(oldBound.left, oldBound.top);
15947
15984
  if (!elmUnderCursor) {
15948
15985
  return getBound;
15949
15986
  }
@@ -17611,6 +17648,16 @@ class Jodit extends jodit_modules__WEBPACK_IMPORTED_MODULE_9__.ViewWithToolbar {
17611
17648
  const init = ()=>{
17612
17649
  if (opt.enableDragAndDropFileToEditor && opt.uploader && (opt.uploader.url || opt.uploader.insertImageAsBase64URI)) {
17613
17650
  this.uploader.bind(this.editor);
17651
+ } else if (!opt.enableDragAndDropFileToEditor) {
17652
+ // Without a bound uploader nobody cancels a file drop, and
17653
+ // Firefox inserts the dropped image natively — the option
17654
+ // must mean "do nothing". See
17655
+ // https://github.com/xdan/jodit/issues/1077
17656
+ this.e.on(editor, 'drop', (e)=>{
17657
+ if (e.dataTransfer?.files?.length) {
17658
+ e.preventDefault();
17659
+ }
17660
+ });
17614
17661
  }
17615
17662
  // in initEditor - the editor could change
17616
17663
  if (!this.__elementToPlace.get(this.editor)) {
@@ -18410,7 +18457,7 @@ class Dialog extends jodit_core_view_view_with_toolbar__WEBPACK_IMPORTED_MODULE_
18410
18457
  e.stopImmediatePropagation();
18411
18458
  }
18412
18459
  if (this.resizable && this.o.resizable) {
18413
- this.setSize(this.startPoint.w + e.clientX - this.startX, this.startPoint.h + e.clientY - this.startY);
18460
+ this.setSize(Math.max(this.startPoint.w + e.clientX - this.startX, this.minSize.w), Math.max(this.startPoint.h + e.clientY - this.startY, this.minSize.h));
18414
18461
  if (this.e) {
18415
18462
  /**
18416
18463
  * Fired when dialog box is resized
@@ -18438,6 +18485,14 @@ class Dialog extends jodit_core_view_view_with_toolbar__WEBPACK_IMPORTED_MODULE_
18438
18485
  this.startY = e.clientY;
18439
18486
  this.startPoint.w = this.dialog.offsetWidth;
18440
18487
  this.startPoint.h = this.dialog.offsetHeight;
18488
+ const header = this.getElm('header');
18489
+ const footer = this.getElm('footer');
18490
+ const content = this.getElm('content');
18491
+ // the content area does not shrink below its CSS `min-height`,
18492
+ // so it is part of the smallest height the panel can take
18493
+ const contentMinHeight = content ? parseFloat(this.ow.getComputedStyle(content).minHeight) || 0 : 0;
18494
+ this.minSize.w = (0,jodit_core_helpers_checker__WEBPACK_IMPORTED_MODULE_8__.isNumber)(this.o.minWidth) ? this.o.minWidth : Math.max(100, footer?.scrollWidth ?? 0);
18495
+ this.minSize.h = (0,jodit_core_helpers_checker__WEBPACK_IMPORTED_MODULE_8__.isNumber)(this.o.minHeight) ? this.o.minHeight : (header?.offsetHeight ?? 0) + (footer?.offsetHeight ?? 0) + contentMinHeight + this.resizer.offsetHeight;
18441
18496
  this.lockSelect();
18442
18497
  this.__addGlobalResizeListeners();
18443
18498
  if (this.e) {
@@ -18732,6 +18787,12 @@ class Dialog extends jodit_core_view_view_with_toolbar__WEBPACK_IMPORTED_MODULE_
18732
18787
  if (this.options && this.o.resizable && !this.moved && this.isOpened && !this.offsetX && !this.offsetY) {
18733
18788
  this.setPosition();
18734
18789
  }
18790
+ }), /**
18791
+ * Minimal size the dialog can be resized to — the header and the footer
18792
+ * (with its buttons) must always stay inside the panel
18793
+ */ (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "minSize", {
18794
+ w: 0,
18795
+ h: 0
18735
18796
  }), (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "dialog", void 0), (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "workplace", void 0), (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "dialogbox_header", void 0), (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "dialogbox_content", void 0), (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "dialogbox_footer", void 0), (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "dialogbox_toolbar", void 0), (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "isModal", false), /**
18736
18797
  * True, if dialog was opened
18737
18798
  */ (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "isOpened", false);
@@ -23696,13 +23757,34 @@ class ToolbarContent extends jodit_core_ui_button__WEBPACK_IMPORTED_MODULE_5__.U
23696
23757
  return 'ToolbarContent';
23697
23758
  }
23698
23759
  /** @override */ update() {
23699
- const content = this.control.getContent(this.j, this);
23760
+ const { control } = this;
23761
+ const content = control.getContent(this.j, this);
23700
23762
  if ((0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_4__.isString)(content) || content.parentNode !== this.container) {
23701
23763
  jodit_core_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.detach(this.container);
23702
23764
  this.container.appendChild((0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_4__.isString)(content) ? this.j.create.fromHTML(content) : content);
23703
23765
  }
23766
+ // Content controls never went through the ToolbarButton status
23767
+ // calculation, so `isDisabled`/`isActive`/`update` declared on the
23768
+ // control were silently ignored (e.g. the FileBrowser Upload button
23769
+ // ignored the backend permissions). See
23770
+ // https://github.com/xdan/jodit/issues/1094
23771
+ this.state.disabled = Boolean(control.isDisabled?.(this.j, this));
23772
+ this.state.activated = Boolean(control.isActive?.(this.j, this));
23773
+ control.update?.(this.j, this);
23774
+ // The first update() runs before the state watchers are attached, so
23775
+ // apply the calculated state explicitly (the calls are idempotent)
23776
+ this.onChangeDisabled();
23777
+ this.onChangeActivated();
23704
23778
  super.update();
23705
23779
  }
23780
+ /**
23781
+ * The content is arbitrary HTML — propagate the disabled state to the
23782
+ * nested form controls (e.g. the file input of the Upload button),
23783
+ * otherwise they stay interactive.
23784
+ */ onChangeDisabled() {
23785
+ super.onChangeDisabled();
23786
+ this.container.querySelectorAll('input,button,select,textarea').forEach((elm)=>(0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_4__.attr)(elm, 'disabled', this.state.disabled || null));
23787
+ }
23706
23788
  /** @override */ createContainer() {
23707
23789
  return this.j.c.span(this.componentName);
23708
23790
  }
@@ -25358,7 +25440,9 @@ const ns = 'addnewline';
25358
25440
  }
25359
25441
  __onMouseMove(e) {
25360
25442
  const editor = this.j;
25361
- let currentElement = editor.ed.elementFromPoint(e.clientX, e.clientY);
25443
+ // Inside Shadow DOM `document.elementFromPoint` returns the shadow
25444
+ // host, so the lookup must start from the shadow root
25445
+ let currentElement = (editor.o.shadowRoot ?? editor.ed).elementFromPoint(e.clientX, e.clientY);
25362
25446
  if (!jodit_modules__WEBPACK_IMPORTED_MODULE_5__.Dom.isHTMLElement(currentElement) || !jodit_modules__WEBPACK_IMPORTED_MODULE_5__.Dom.isOrContains(editor.editor, currentElement)) {
25363
25447
  return;
25364
25448
  }
@@ -25548,7 +25632,13 @@ jodit_core_ui_icon__WEBPACK_IMPORTED_MODULE_0__.Icon.set('enter', (_enter_svg__W
25548
25632
  return new _ui_ui_ai_assistant__WEBPACK_IMPORTED_MODULE_8__.UiAiAssistant(jodit, {
25549
25633
  onInsertAfter (html) {
25550
25634
  jodit.s.focus();
25551
- jodit.s.setCursorAfter(jodit.s.current());
25635
+ // `current()` returns a node of the selection START, so with
25636
+ // several selected paragraphs the result landed after the
25637
+ // first one — collapse the range to the END of the selection
25638
+ // instead. See https://github.com/xdan/jodit/issues/1263
25639
+ const range = jodit.s.range;
25640
+ range.collapse(false);
25641
+ jodit.s.selectRange(range);
25552
25642
  jodit.s.insertHTML(html);
25553
25643
  __dialog.close();
25554
25644
  },
@@ -26117,13 +26207,26 @@ jodit_core_global__WEBPACK_IMPORTED_MODULE_3__.pluginSystem.add('backspace', bac
26117
26207
  jodit.s.setCursorBefore(fakeNode);
26118
26208
  return true;
26119
26209
  }
26120
- if (sibling && (checkMoveListContent(jodit, mainClosestBox, sibling, backspace) || moveContentAndRemoveEmpty(jodit, mainClosestBox, sibling, backspace))) {
26210
+ if (sibling && (checkMoveListContent(jodit, mainClosestBox, sibling, backspace) || moveContentAndRemoveEmpty(jodit, mainClosestBox, resolveTableSibling(sibling, backspace), backspace))) {
26121
26211
  jodit.s.setCursorBefore(fakeNode);
26122
26212
  return true;
26123
26213
  }
26124
26214
  }
26125
26215
  return false;
26126
26216
  }
26217
+ /**
26218
+ * Content cannot be merged into the `<table>` element itself — it would land
26219
+ * between the table sections (after `</tbody>`), which is invalid HTML and
26220
+ * gets foster-parented out of the table on the next parse. Merge into the
26221
+ * edge cell instead. See https://github.com/xdan/jodit/issues/1064
26222
+ * @private
26223
+ */ function resolveTableSibling(sibling, backspace) {
26224
+ if (!jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isTag(sibling, 'table')) {
26225
+ return sibling;
26226
+ }
26227
+ const cells = sibling.querySelectorAll('td,th');
26228
+ return cells.length ? cells[backspace ? cells.length - 1 : 0] : null;
26229
+ }
26127
26230
  function checkMoveListContent(jodit, mainClosestBox, sibling, backspace) {
26128
26231
  // Process UL/LI/OL cases
26129
26232
  const siblingIsList = jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_1__.Dom.isTag(sibling, jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.LIST_TAGS);
@@ -27208,10 +27311,14 @@ jodit_core_ui_icon__WEBPACK_IMPORTED_MODULE_5__.Icon.set('class-span', (_class_s
27208
27311
  * Event handler when manually assigning a value to the HTML editor.
27209
27312
  */ onBeforeSetNativeEditorValue(data) {
27210
27313
  const [sandBox, iframe] = this.j.o.cleanHTML.useIframeSandbox ? this.j.createInside.sandbox() : [
27211
- this.j.createInside.div()
27314
+ // an inert document never loads sub-resources, so the
27315
+ // images in the value are not re-requested from the
27316
+ // server on every assignment (e.g. on each change in
27317
+ // jodit-react). See #1237
27318
+ this.j.od.implementation.createHTMLDocument('').body
27212
27319
  ];
27213
27320
  sandBox.innerHTML = data.value;
27214
- this.onSafeHTML(sandBox);
27321
+ this.j.e.fire('safeHTML', sandBox);
27215
27322
  data.value = sandBox.innerHTML;
27216
27323
  (0,jodit_core_helpers_html_safe_html__WEBPACK_IMPORTED_MODULE_6__.safeHTML)(sandBox, {
27217
27324
  safeJavaScriptLink: true,
@@ -27546,12 +27653,19 @@ jodit_core_ui_icon__WEBPACK_IMPORTED_MODULE_0__.Icon.set('eraser', (_eraser_svg_
27546
27653
  /**
27547
27654
  * @private
27548
27655
  */ function allowAttributes(jodit, nodeElm, hadEffect, allow) {
27549
- if (allow && jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.isElement(nodeElm) && allow[nodeElm.nodeName] !== true) {
27656
+ const allowedForTag = allow && jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.isElement(nodeElm) && allow[nodeElm.nodeName];
27657
+ if (allow && jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_0__.Dom.isElement(nodeElm) && allowedForTag !== true) {
27658
+ // the tag is not in the allow list at all — attributes do not matter,
27659
+ // the element itself will be removed by the tags filter. Without this
27660
+ // check `allow[nodeName][attr]` threw on e.g. `<meta charset>`. See #1224
27661
+ if (!allowedForTag) {
27662
+ return hadEffect;
27663
+ }
27550
27664
  const attrs = nodeElm.attributes;
27551
27665
  if (attrs && attrs.length) {
27552
27666
  const removeAttrs = [];
27553
27667
  for(let i = 0; i < attrs.length; i += 1){
27554
- const attr = allow[nodeElm.nodeName][attrs[i].name];
27668
+ const attr = allowedForTag[attrs[i].name];
27555
27669
  if (!attr || attr !== true && attr !== attrs[i].value) {
27556
27670
  removeAttrs.push(attrs[i].name);
27557
27671
  }
@@ -28129,9 +28243,10 @@ const keys = Object.keys(_filters__WEBPACK_IMPORTED_MODULE_1__);
28129
28243
  /* harmony import */ var _swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25045);
28130
28244
  /* harmony import */ var jodit_core_constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(81937);
28131
28245
  /* harmony import */ var jodit_core_decorators_cache_cache__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(51676);
28132
- /* harmony import */ var jodit_core_global__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(28077);
28133
- /* harmony import */ var jodit_core_helpers__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(65946);
28134
- /* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(81008);
28246
+ /* harmony import */ var jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(23211);
28247
+ /* harmony import */ var jodit_core_global__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(28077);
28248
+ /* harmony import */ var jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(65946);
28249
+ /* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(81008);
28135
28250
  /*!
28136
28251
  * Jodit Editor (https://xdsoft.net/jodit/)
28137
28252
  * Released under MIT see LICENSE.txt in the project root for license information.
@@ -28146,16 +28261,17 @@ const keys = Object.keys(_filters__WEBPACK_IMPORTED_MODULE_1__);
28146
28261
 
28147
28262
 
28148
28263
 
28264
+
28149
28265
  /**
28150
28266
  * Clipboard plugin - cut and copy functionality
28151
28267
  */ class clipboard {
28152
28268
  init(editor) {
28153
28269
  this.buttons?.forEach((btn)=>editor.registerButton(btn));
28154
28270
  editor.e.off(`copy.${jodit_core_constants__WEBPACK_IMPORTED_MODULE_1__.CLIPBOARD_ID} cut.${jodit_core_constants__WEBPACK_IMPORTED_MODULE_1__.CLIPBOARD_ID}`).on(`copy.${jodit_core_constants__WEBPACK_IMPORTED_MODULE_1__.CLIPBOARD_ID} cut.${jodit_core_constants__WEBPACK_IMPORTED_MODULE_1__.CLIPBOARD_ID}`, (event)=>{
28155
- const selectedText = editor.s.html;
28156
- const clipboardData = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_4__.getDataTransfer)(event) || (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_4__.getDataTransfer)(editor.ew) || (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_4__.getDataTransfer)(event.originalEvent);
28271
+ const selectedText = wrapWithInlineAncestors(editor, editor.s.html);
28272
+ const clipboardData = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.getDataTransfer)(event) || (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.getDataTransfer)(editor.ew) || (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.getDataTransfer)(event.originalEvent);
28157
28273
  if (clipboardData) {
28158
- clipboardData.setData(jodit_core_constants__WEBPACK_IMPORTED_MODULE_1__.TEXT_PLAIN, (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_4__.stripTags)(selectedText));
28274
+ clipboardData.setData(jodit_core_constants__WEBPACK_IMPORTED_MODULE_1__.TEXT_PLAIN, (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.stripTags)(selectedText));
28159
28275
  clipboardData.setData(jodit_core_constants__WEBPACK_IMPORTED_MODULE_1__.TEXT_HTML, selectedText);
28160
28276
  }
28161
28277
  editor.buffer.set(jodit_core_constants__WEBPACK_IMPORTED_MODULE_1__.CLIPBOARD_ID, selectedText);
@@ -28197,7 +28313,30 @@ const keys = Object.keys(_filters__WEBPACK_IMPORTED_MODULE_1__);
28197
28313
  ]);
28198
28314
  }
28199
28315
  }
28200
- jodit_core_global__WEBPACK_IMPORTED_MODULE_3__.pluginSystem.add('clipboard', clipboard);
28316
+ /**
28317
+ * `Selection.html` clones only the range contents — when the selection sits
28318
+ * entirely inside the text of a formatted element (`<strong>te|st|</strong>`),
28319
+ * the clone is bare text and the formatting would be lost on paste. Native
28320
+ * browser copy keeps that context, so the interception must restore it: wrap
28321
+ * the fragment in shallow clones of the inline ancestors of the range. See #1202
28322
+ */ function wrapWithInlineAncestors(editor, html) {
28323
+ if (!html || editor.s.isCollapsed()) {
28324
+ return html;
28325
+ }
28326
+ let node = editor.s.range.commonAncestorContainer;
28327
+ if (!jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isElement(node)) {
28328
+ node = node.parentElement;
28329
+ }
28330
+ let result = html;
28331
+ while(node && node !== editor.editor && jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isElement(node) && !jodit_core_dom_dom__WEBPACK_IMPORTED_MODULE_3__.Dom.isBlock(node)){
28332
+ const shell = node.cloneNode(false);
28333
+ shell.innerHTML = result;
28334
+ result = shell.outerHTML;
28335
+ node = node.parentElement;
28336
+ }
28337
+ return result;
28338
+ }
28339
+ jodit_core_global__WEBPACK_IMPORTED_MODULE_4__.pluginSystem.add('clipboard', clipboard);
28201
28340
 
28202
28341
 
28203
28342
  /***/ }),
@@ -28276,25 +28415,33 @@ jodit_core_ui_icon__WEBPACK_IMPORTED_MODULE_0__.Icon.set('copy', (_icons_copy_sv
28276
28415
  });
28277
28416
  const callback = (command, second, third)=>{
28278
28417
  const colorHEX = (0,jodit_core_helpers___WEBPACK_IMPORTED_MODULE_1__.normalizeColor)(third);
28279
- switch(command){
28280
- case 'background':
28281
- editor.s.commitStyle({
28282
- attributes: {
28283
- style: {
28284
- backgroundColor: !colorHEX ? '' : colorHEX
28285
- }
28286
- }
28287
- });
28288
- break;
28289
- case 'forecolor':
28418
+ const value = !colorHEX ? '' : colorHEX;
28419
+ const style = command === 'background' ? {
28420
+ backgroundColor: value
28421
+ } : {
28422
+ color: value
28423
+ };
28424
+ // Cells selected with the `select-cells` plugin drop or collapse the
28425
+ // native range, so `commitStyle` would paint a pending caret format
28426
+ // outside the table instead of the selection the user sees. Apply the
28427
+ // style to the content of every selected cell instead. See #1250
28428
+ const selectedCells = editor.getInstance('Table', editor.o).getAllSelectedCells();
28429
+ if (selectedCells.length && editor.s.isCollapsed()) {
28430
+ selectedCells.forEach((cell)=>{
28431
+ editor.s.select(cell, true);
28290
28432
  editor.s.commitStyle({
28291
28433
  attributes: {
28292
- style: {
28293
- color: !colorHEX ? '' : colorHEX
28294
- }
28434
+ style
28295
28435
  }
28296
28436
  });
28297
- break;
28437
+ });
28438
+ editor.s.sel?.removeAllRanges();
28439
+ } else {
28440
+ editor.s.commitStyle({
28441
+ attributes: {
28442
+ style
28443
+ }
28444
+ });
28298
28445
  }
28299
28446
  editor.synchronizeValues();
28300
28447
  return false;
@@ -33724,9 +33871,54 @@ const align = {
33724
33871
  }).on([
33725
33872
  this.j.ew,
33726
33873
  this.j.ow
33727
- ], 'mouseup keyup', this.onSelectionEnd);
33874
+ ], 'mouseup keyup', this.onSelectionEnd).on([
33875
+ this.j.ew,
33876
+ this.j.ow
33877
+ ], 'mousedown touchstart', this.__onDocumentMouseDown).on('closeAllPopups', this.__onCloseAllPopups);
33728
33878
  this.addListenersForElements();
33729
33879
  }
33880
+ __onDocumentMouseDown(e) {
33881
+ if (this.popup.isOpened && this.type === 'selection' && e.target && jodit_core_ui__WEBPACK_IMPORTED_MODULE_7__.UIElement.closestElement(e.target, jodit_core_ui_popup__WEBPACK_IMPORTED_MODULE_8__.Popup)) {
33882
+ this.__reopenSelectionPopup = true;
33883
+ }
33884
+ }
33885
+ __onCloseAllPopups() {
33886
+ if (!this.__reopenSelectionPopup) {
33887
+ return;
33888
+ }
33889
+ this.__reopenSelectionPopup = false;
33890
+ if (!this.j.o.toolbarInlineForSelection) {
33891
+ return;
33892
+ }
33893
+ // a zero timeout would run synchronously — before the popup's own
33894
+ // `closeAllPopups` handler closes it; defer to the next macrotask
33895
+ this.j.async.setTimeout(()=>{
33896
+ const sel = this.j.s.sel;
33897
+ if (sel && !sel.isCollapsed) {
33898
+ this.showPopup(()=>this.__selectionBound(), 'selection');
33899
+ }
33900
+ }, 1);
33901
+ }
33902
+ /**
33903
+ * The selection rect comes from the editor document — in iframe mode its
33904
+ * coordinates are iframe-local, while the popup lives in the host
33905
+ * document, so the iframe offset must be added. See
33906
+ * https://github.com/xdan/jodit/issues/1058
33907
+ */ __selectionBound() {
33908
+ const rect = this.j.s.range.getBoundingClientRect();
33909
+ let { left, top } = rect;
33910
+ if (this.j.iframe) {
33911
+ const offset = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.position)(this.j.iframe, this.j, true);
33912
+ left += offset.left;
33913
+ top += offset.top;
33914
+ }
33915
+ return {
33916
+ left,
33917
+ top,
33918
+ width: rect.width,
33919
+ height: rect.height
33920
+ };
33921
+ }
33730
33922
  onSelectionStart() {
33731
33923
  this.snapRange = this.j.s.range.cloneRange();
33732
33924
  }
@@ -33758,7 +33950,7 @@ const align = {
33758
33950
  if (!node) {
33759
33951
  return;
33760
33952
  }
33761
- this.showPopup(()=>range.getBoundingClientRect(), type);
33953
+ this.showPopup(()=>this.__selectionBound(), type);
33762
33954
  }
33763
33955
  /**
33764
33956
  * In not collapsed selection - only one image
@@ -33775,7 +33967,10 @@ const align = {
33775
33967
  jodit.e.off('showPopup').off([
33776
33968
  this.j.ew,
33777
33969
  this.j.ow
33778
- ], 'mouseup keyup', this.onSelectionEnd);
33970
+ ], 'mouseup keyup', this.onSelectionEnd).off([
33971
+ this.j.ew,
33972
+ this.j.ow
33973
+ ], 'mousedown touchstart', this.__onDocumentMouseDown).off('closeAllPopups', this.__onCloseAllPopups);
33779
33974
  this.removeListenersForElements();
33780
33975
  }
33781
33976
  _eventsList() {
@@ -33800,7 +33995,11 @@ const align = {
33800
33995
  }, 'toolbar');
33801
33996
  }
33802
33997
  constructor(...args){
33803
- super(...args), (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "type", null), (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "previousTarget", void 0), (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "snapRange", null), (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "elmsList", (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.keys)(this.j.o.popup, false).filter((s)=>!this.isExcludedTarget(s)));
33998
+ super(...args), (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "type", null), (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "previousTarget", void 0), /**
33999
+ * The user pressed a button inside the selection toolbar — after the
34000
+ * command fires `closeAllPopups`, the toolbar should be shown again
34001
+ * while the selection is still there. See #1238
34002
+ */ (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "__reopenSelectionPopup", false), (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "snapRange", null), (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "elmsList", (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.keys)(this.j.o.popup, false).filter((s)=>!this.isExcludedTarget(s)));
33804
34003
  }
33805
34004
  }
33806
34005
  (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(inlinePopup, "requires", [
@@ -33829,6 +34028,12 @@ const align = {
33829
34028
  (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
33830
34029
  (0,jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__.watch)(':outsideClick')
33831
34030
  ], inlinePopup.prototype, "onOutsideClick", null);
34031
+ (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
34032
+ jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__.autobind
34033
+ ], inlinePopup.prototype, "__onDocumentMouseDown", null);
34034
+ (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
34035
+ jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__.autobind
34036
+ ], inlinePopup.prototype, "__onCloseAllPopups", null);
33832
34037
  (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
33833
34038
  jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__.autobind
33834
34039
  ], inlinePopup.prototype, "onSelectionStart", null);
@@ -34114,7 +34319,10 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.limitHTML = false;
34114
34319
  jodit.e.fire('denyWords.limit limit.limit');
34115
34320
  return true;
34116
34321
  }
34117
- const should = Boolean(limitChars && isGt(words.join('').length, limitChars, strict));
34322
+ // with `countTextSpaces` enabled the limiter counts characters the
34323
+ // same way as the `stat` plugin's counter — including spaces. See #1144
34324
+ const charsCount = jodit.o.countTextSpaces ? text.replace((0,jodit_core_constants__WEBPACK_IMPORTED_MODULE_1__.INVISIBLE_SPACE_REG_EXP)(), '').replace(/[\r\n]/g, '').length : words.join('').length;
34325
+ const should = Boolean(limitChars && isGt(charsCount, limitChars, strict));
34118
34326
  if (should) {
34119
34327
  jodit.e.fire('denyChars.limit limit.limit');
34120
34328
  }
@@ -35678,7 +35886,13 @@ jodit_config__WEBPACK_IMPORTED_MODULE_1__.Config.prototype.controls.paste = {
35678
35886
  try {
35679
35887
  const items = await navigator.clipboard.read();
35680
35888
  if (items && items.length) {
35681
- const textBlob = await items[0].getType(jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.TEXT_PLAIN);
35889
+ const item = items[0];
35890
+ // Prefer the HTML flavor so the button behaves like the
35891
+ // Ctrl+V shortcut (which receives text/html from the
35892
+ // native paste event). See
35893
+ // https://github.com/xdan/jodit/issues/1061
35894
+ const type = item.types?.includes(jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.TEXT_HTML) ? jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.TEXT_HTML : jodit_core_constants__WEBPACK_IMPORTED_MODULE_0__.TEXT_PLAIN;
35895
+ const textBlob = await item.getType(type);
35682
35896
  text = await new Response(textBlob).text();
35683
35897
  }
35684
35898
  error = false;
@@ -35884,9 +36098,7 @@ jodit_config__WEBPACK_IMPORTED_MODULE_1__.Config.prototype.controls.paste = {
35884
36098
  */ class paste extends jodit_core_plugin_plugin__WEBPACK_IMPORTED_MODULE_7__.Plugin {
35885
36099
  /** @override **/ afterInit(jodit) {
35886
36100
  jodit.e.on('paste.paste', this.onPaste).on('pasteStack.paste', (item)=>this.pasteStack.push(item));
35887
- if (jodit.o.nl2brInPlainText) {
35888
- this.j.e.on('processPaste.paste', this.onProcessPasteReplaceNl2Br);
35889
- }
36101
+ this.j.e.on('processPaste.paste', this.onProcessPasteReplaceNl2Br);
35890
36102
  }
35891
36103
  /** @override **/ beforeDestruct(jodit) {
35892
36104
  jodit.e.off('paste.paste', this.onPaste).off('processPaste.paste', this.onProcessPasteReplaceNl2Br).off('.paste');
@@ -36006,10 +36218,14 @@ jodit_config__WEBPACK_IMPORTED_MODULE_1__.Config.prototype.controls.paste = {
36006
36218
  (0,_helpers__WEBPACK_IMPORTED_MODULE_9__.pasteInsertHtml)(e, this.j, html);
36007
36219
  }
36008
36220
  /**
36009
- * Replace all \\n chars in plain text to br
36221
+ * Escape plain text and replace all \\n chars with br
36010
36222
  */ onProcessPasteReplaceNl2Br(ignore, text, type) {
36011
36223
  if (type === jodit_core_constants__WEBPACK_IMPORTED_MODULE_2__.TEXT_PLAIN + ';' && !(0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_6__.isHTML)(text)) {
36012
- return (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_6__.nl2br)(text);
36224
+ // the clipboard contains only plain text — escape special chars
36225
+ // so a stray `<` is not parsed as an unclosed tag and does not
36226
+ // swallow the rest of the string. See #1227
36227
+ const escaped = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_6__.htmlspecialchars)(text);
36228
+ return this.j.o.nl2brInPlainText ? (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_6__.nl2br)(escaped) : escaped;
36013
36229
  }
36014
36230
  }
36015
36231
  constructor(...args){
@@ -36877,9 +37093,10 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.allowResizeY = true;
36877
37093
  /* harmony import */ var jodit_core_decorators__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(84839);
36878
37094
  /* harmony import */ var jodit_core_dom__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(27795);
36879
37095
  /* harmony import */ var jodit_core_global__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(28077);
36880
- /* harmony import */ var jodit_core_plugin__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(91206);
36881
- /* harmony import */ var jodit_core_ui__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(4099);
36882
- /* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(58293);
37096
+ /* harmony import */ var jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(65946);
37097
+ /* harmony import */ var jodit_core_plugin__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(91206);
37098
+ /* harmony import */ var jodit_core_ui__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(4099);
37099
+ /* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(58293);
36883
37100
  /*!
36884
37101
  * Jodit Editor (https://xdsoft.net/jodit/)
36885
37102
  * Released under MIT see LICENSE.txt in the project root for license information.
@@ -36896,7 +37113,8 @@ jodit_config__WEBPACK_IMPORTED_MODULE_0__.Config.prototype.allowResizeY = true;
36896
37113
 
36897
37114
 
36898
37115
 
36899
- class resizeHandler extends jodit_core_plugin__WEBPACK_IMPORTED_MODULE_5__.Plugin {
37116
+
37117
+ class resizeHandler extends jodit_core_plugin__WEBPACK_IMPORTED_MODULE_6__.Plugin {
36900
37118
  /** @override **/ afterInit(editor) {
36901
37119
  const { height, width, allowResizeX } = editor.o;
36902
37120
  let { allowResizeY } = editor.o;
@@ -36930,11 +37148,21 @@ class resizeHandler extends jodit_core_plugin__WEBPACK_IMPORTED_MODULE_5__.Plugi
36930
37148
  if (!this.isResized) {
36931
37149
  return;
36932
37150
  }
37151
+ let { clientX, clientY } = e;
37152
+ if (e.view === this.j.ew && this.j.ew !== this.j.ow) {
37153
+ // the event was proxied from the editor's iframe — its client
37154
+ // coordinates are relative to the iframe viewport, while the
37155
+ // start point was captured on the host-document handle;
37156
+ // shift them into the host coordinate space
37157
+ const workplacePosition = (0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.offset)(this.j.workplace, this.j, this.j.od, true);
37158
+ clientX += workplacePosition.left;
37159
+ clientY += workplacePosition.top;
37160
+ }
36933
37161
  if (this.j.o.allowResizeY) {
36934
- this.j.e.fire('setHeight', this.start.h + e.clientY - this.start.y);
37162
+ this.j.e.fire('setHeight', this.start.h + clientY - this.start.y);
36935
37163
  }
36936
37164
  if (this.j.o.allowResizeX) {
36937
- this.j.e.fire('setWidth', this.start.w + e.clientX - this.start.x);
37165
+ this.j.e.fire('setWidth', this.start.w + clientX - this.start.x);
36938
37166
  }
36939
37167
  this.j.e.fire('resize');
36940
37168
  }
@@ -36963,7 +37191,7 @@ class resizeHandler extends jodit_core_plugin__WEBPACK_IMPORTED_MODULE_5__.Plugi
36963
37191
  h: 0
36964
37192
  }), /**
36965
37193
  * Resize handle
36966
- */ (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "handle", this.j.c.div('jodit-editor__resize', jodit_core_ui__WEBPACK_IMPORTED_MODULE_6__.Icon.get('resize_handler')));
37194
+ */ (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(this, "handle", this.j.c.div('jodit-editor__resize', jodit_core_ui__WEBPACK_IMPORTED_MODULE_7__.Icon.get('resize_handler')));
36967
37195
  }
36968
37196
  }
36969
37197
  /** @override **/ (0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_0__._)(resizeHandler, "requires", [
@@ -37148,7 +37376,11 @@ const keyBInd = '__jodit-resizer_binded';
37148
37376
  this.pointerX = e.clientX;
37149
37377
  this.pointerY = e.clientY;
37150
37378
  let diff_x, diff_y;
37151
- if (this.j.options.iframe) {
37379
+ if (this.j.options.iframe && e.view === this.j.ew) {
37380
+ // the event was proxied from the editor's iframe — its client
37381
+ // coordinates are relative to the iframe viewport, while
37382
+ // `startX/startY` were captured on a host-document handle;
37383
+ // shift them into the host coordinate space
37152
37384
  const workplacePosition = this.getWorkplacePosition();
37153
37385
  diff_x = e.clientX + workplacePosition.left - this.startX;
37154
37386
  diff_y = e.clientY + workplacePosition.top - this.startY;
@@ -38266,20 +38498,30 @@ class UISearch extends jodit_core_ui__WEBPACK_IMPORTED_MODULE_6__.UIElement {
38266
38498
  return false;
38267
38499
  }).on(this.queryInput, 'input', ()=>{
38268
38500
  this.setMod('empty-query', !(0,jodit_core_helpers__WEBPACK_IMPORTED_MODULE_5__.trim)(this.queryInput.value).length);
38269
- }).on(this.queryInput, 'keydown', this.j.async.debounce(async (e)=>{
38270
- switch(e.key){
38271
- case jodit_core_constants__WEBPACK_IMPORTED_MODULE_2__.KEY_ENTER:
38501
+ }).on(this.queryInput, 'keydown', (()=>{
38502
+ const debounced = this.j.async.debounce(async (e)=>{
38503
+ switch(e.key){
38504
+ case jodit_core_constants__WEBPACK_IMPORTED_MODULE_2__.KEY_ENTER:
38505
+ if (await jodit.e.fire('searchNext')) {
38506
+ this.close();
38507
+ }
38508
+ break;
38509
+ default:
38510
+ jodit.e.fire(this, 'needUpdateCounters');
38511
+ break;
38512
+ }
38513
+ }, this.j.defaultTimeout);
38514
+ return (e)=>{
38515
+ // Must be canceled synchronously — inside the debounced
38516
+ // handler the browser has already submitted the parent
38517
+ // form. See https://github.com/xdan/jodit/issues/918
38518
+ if (e.key === jodit_core_constants__WEBPACK_IMPORTED_MODULE_2__.KEY_ENTER) {
38272
38519
  e.preventDefault();
38273
38520
  e.stopImmediatePropagation();
38274
- if (await jodit.e.fire('searchNext')) {
38275
- this.close();
38276
- }
38277
- break;
38278
- default:
38279
- jodit.e.fire(this, 'needUpdateCounters');
38280
- break;
38281
- }
38282
- }, this.j.defaultTimeout));
38521
+ }
38522
+ debounced(e);
38523
+ };
38524
+ })());
38283
38525
  }
38284
38526
  }
38285
38527
  (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_1__.__decorate)([
@@ -38434,7 +38676,9 @@ class selectCells extends jodit_core_plugin__WEBPACK_IMPORTED_MODULE_7__.Plugin
38434
38676
  if (this.j.isLockedNotBy(key)) {
38435
38677
  return;
38436
38678
  }
38437
- const node = this.j.ed.elementFromPoint(e.clientX, e.clientY);
38679
+ // Inside Shadow DOM `document.elementFromPoint` returns the shadow
38680
+ // host, so the lookup must start from the shadow root
38681
+ const node = (this.j.o.shadowRoot ?? this.j.ed).elementFromPoint(e.clientX, e.clientY);
38438
38682
  if (!node) {
38439
38683
  return;
38440
38684
  }
@@ -38493,7 +38737,9 @@ class selectCells extends jodit_core_plugin__WEBPACK_IMPORTED_MODULE_7__.Plugin
38493
38737
  }
38494
38738
  this.__isSelectionMode = false;
38495
38739
  this.j.unlock();
38496
- const node = this.j.ed.elementFromPoint(e.clientX, e.clientY);
38740
+ // Inside Shadow DOM `document.elementFromPoint` returns the shadow
38741
+ // host, so the lookup must start from the shadow root
38742
+ const node = (this.j.o.shadowRoot ?? this.j.ed).elementFromPoint(e.clientX, e.clientY);
38497
38743
  if (!node) {
38498
38744
  return;
38499
38745
  }
@@ -39764,6 +40010,13 @@ class SourceEditor {
39764
40010
  this.sourceEditor?.setValue(value);
39765
40011
  }
39766
40012
  setFocusToMirror() {
40013
+ const active = this.j.od.activeElement;
40014
+ // do not steal focus from another editor or control — e.g. when the
40015
+ // mode is switched programmatically (a Vue/React wrapper re-render)
40016
+ // while the user is already typing elsewhere. See #1356
40017
+ if (active && active !== this.j.od.body && !this.j.container.contains(active)) {
40018
+ return;
40019
+ }
39767
40020
  this.sourceEditor?.focus();
39768
40021
  }
39769
40022
  saveSelection() {
@@ -41911,7 +42164,7 @@ module.exports["default"] = {"Type something":"Start writing...","pencil":"Edit"
41911
42164
  /***/ 53414:
41912
42165
  /***/ (function(module) {
41913
42166
 
41914
- module.exports["default"] = ["Type something","About Jodit","Jodit Editor","Jodit User's Guide","contains detailed help for using","For information about the license, please go to our website:","Buy full version","Copyright © XDSoft.net - Chupurnov Valeriy. All rights reserved.","Anchor","Open in new tab","Open in fullsize","Clear Formatting","Fill color or set the text color","Redo","Undo","Bold","Italic","Insert Unordered List","Insert Ordered List","Align Center","Align Justify","Align Left","Align Right","Insert Horizontal Line","Insert Image","Insert file","Insert youtube/vimeo video","Insert link","Font size","Font family","Insert format block","Normal","Heading 1","Heading 2","Heading 3","Heading 4","Quote","Code","Insert","Insert table","Decrease Indent","Increase Indent","Select Special Character","Insert Special Character","Paint format","Change mode","Margins","top","right","bottom","left","Styles","Classes","Align","Right","Center","Left","--Not Set--","Src","Title","Alternative","Link","Open link in new tab","Image","file","Advanced","Image properties","Cancel","Ok","File Browser","Error on load list","Error on load folders","Are you sure?","Enter Directory name","Create directory","type name","Drop image","Drop file","or click","Alternative text","Upload","Browse","Background","Text","Top","Middle","Bottom","Insert column before","Insert column after","Insert row above","Insert row below","Delete table","Delete row","Delete column","Empty cell","Chars: %d","Words: %d","Strike through","Underline","superscript","subscript","Cut selection","Select all","Break","Search for","Replace with","Replace","Paste","Choose Content to Paste","source","bold","italic","brush","link","undo","redo","table","image","eraser","paragraph","fontsize","video","font","about","print","underline","strikethrough","indent","outdent","fullsize","shrink","hr","ul","ol","cut","selectall","Embed code","Open link","Edit link","No follow","Unlink","Update","pencil","Eye"," URL","Edit","Horizontal align","Filter","Sort by changed","Sort by name","Sort by size","Add folder","Reset","Save","Save as ...","Resize","Crop","Width","Height","Keep Aspect Ratio","Yes","No","Remove","Select","Select %s","Vertical align","Split","Merge","Add column","Add row","License: %s","Delete","Split vertical","Split horizontal","Border","Your code is similar to HTML. Keep as HTML?","Paste as HTML","Keep","Insert as Text","Insert only Text","You can only edit your own images. Download this image on the host?","The image has been successfully uploaded to the host!","palette","There are no files","Rename","Enter new name","preview","download","Paste from clipboard","Your browser doesn't support direct access to the clipboard.","Copy selection","copy","Border radius","Show all","Apply","Please fill out this field","Please enter a web address","Default","Circle","Dot","Quadrate","Find","Find Previous","Find Next","The pasted content is coming from a Microsoft Word/Excel document. Do you want to keep the format or clean it up?","Word Paste Detected","Clean","Insert className","Press Alt for custom resizing","Line height","spellcheck","Speech Recognize","All"]
42167
+ module.exports["default"] = [" URL","--Not Set--","About Jodit","Add column","Add folder","Add row","Advanced","Align","Align Center","Align Justify","Align Left","Align Right","All","Alternative","Alternative text","Anchor","Apply","Are you sure?","Background","Bold","Border","Border radius","Bottom","Break","Browse","Buy full version","Cancel","Center","Change mode","Chars: %d","Choose Content to Paste","Circle","Class name","Classes","Clean","Clear Formatting","Code","Copy selection","Copyright © XDSoft.net - Chupurnov Valeriy. All rights reserved.","Create directory","Crop","Cut selection","Decrease Indent","Default","Delete","Delete column","Delete row","Delete table","Dot","Drop file","Drop image","Edit","Edit link","Embed code","Empty cell","Enter Directory name","Enter new name","Error on load folders","Error on load list","Eye","File Browser","Fill color or set the text color","Filter","Find","Find Next","Find Previous","Font family","Font size","For information about the license, please go to our website:","Free Non-commercial Version","Heading 1","Heading 2","Heading 3","Heading 4","Height","Horizontal align","Image","Image properties","Increase Indent","Insert","Insert Horizontal Line","Insert Image","Insert Ordered List","Insert Special Character","Insert Unordered List","Insert as Text","Insert className","Insert column after","Insert column before","Insert file","Insert format block","Insert link","Insert only Text","Insert row above","Insert row below","Insert table","Insert youtube/vimeo video","Interim Results","Italic","Jodit Editor","Jodit User's Guide","Keep","Keep Aspect Ratio","Left","License: %s","Line height","Link","Lower Alpha","Lower Greek","Lower Roman","Margins","Merge","Middle","No","No follow","Normal","Ok","Open in fullsize","Open in new tab","Open link","Open link in new tab","Paint format","Paste","Paste as HTML","Paste from clipboard","Please enter a web address","Please fill out this field","Press Alt for custom resizing","Print","Quadrate","Quote","Redo","Remove","Rename","Replace","Replace with","Reset","Resize","Right","Save","Save as ...","Search for","Select","Select %s","Select Special Character","Select all","Show all","Sort by changed","Sort by name","Sort by size","Sound","Speech Recognize","Split","Split horizontal","Split vertical","Src","Strike through","Styles","Text","The image has been successfully uploaded to the host!","The pasted content is coming from a Microsoft Word/Excel document. Do you want to keep the format or clean it up?","There are no files","Title","Top","Type something","Underline","Undo","Unlink","Update","Upload","Upper Alpha","Upper Roman","Vertical align","Width","Word Paste Detected","Words: %d","Yes","You can only edit your own images. Download this image on the host?","Your browser doesn't support direct access to the clipboard.","Your code is similar to HTML. Keep as HTML?","about","apply","bold","bottom","brush","circle","contains detailed help for using","copy","cut","default","dot","download","edit","eraser","file","font","fontsize","fullsize","hr","image","indent","italic","left","link","ol","or click","outdent","palette","paragraph","pencil","preview","print","redo","right","selectall","shrink","sound","source","spellcheck","square","strikethrough","subscript","superscript","table","top","type name","ul","underline","undo","video"]
41915
42168
 
41916
42169
  /***/ }),
41917
42170