jodit 4.13.26 → 4.14.0

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 (167) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/es2015/jodit.css +1 -1
  3. package/es2015/jodit.fat.min.js +19 -19
  4. package/es2015/jodit.js +1104 -884
  5. package/es2015/jodit.min.js +20 -20
  6. package/es2015/plugins/debug/debug.css +1 -1
  7. package/es2015/plugins/debug/debug.js +10 -10
  8. package/es2015/plugins/debug/debug.min.js +4 -4
  9. package/es2015/plugins/speech-recognize/speech-recognize.css +1 -1
  10. package/es2015/plugins/speech-recognize/speech-recognize.js +2 -2
  11. package/es2015/plugins/speech-recognize/speech-recognize.min.js +2 -2
  12. package/es2018/jodit.fat.min.js +19 -19
  13. package/es2018/jodit.min.js +19 -19
  14. package/es2018/plugins/debug/debug.min.js +4 -4
  15. package/es2018/plugins/speech-recognize/speech-recognize.min.js +2 -2
  16. package/es2021/jodit.css +1 -1
  17. package/es2021/jodit.fat.min.js +29 -29
  18. package/es2021/jodit.js +1097 -875
  19. package/es2021/jodit.min.js +29 -29
  20. package/es2021/plugins/debug/debug.css +1 -1
  21. package/es2021/plugins/debug/debug.js +10 -10
  22. package/es2021/plugins/debug/debug.min.js +4 -4
  23. package/es2021/plugins/speech-recognize/speech-recognize.css +1 -1
  24. package/es2021/plugins/speech-recognize/speech-recognize.js +2 -2
  25. package/es2021/plugins/speech-recognize/speech-recognize.min.js +2 -2
  26. package/es2021.en/jodit.css +1 -1
  27. package/es2021.en/jodit.fat.min.js +29 -29
  28. package/es2021.en/jodit.js +1097 -875
  29. package/es2021.en/jodit.min.js +29 -29
  30. package/es2021.en/plugins/debug/debug.css +1 -1
  31. package/es2021.en/plugins/debug/debug.js +10 -10
  32. package/es2021.en/plugins/debug/debug.min.js +4 -4
  33. package/es2021.en/plugins/speech-recognize/speech-recognize.css +1 -1
  34. package/es2021.en/plugins/speech-recognize/speech-recognize.js +2 -2
  35. package/es2021.en/plugins/speech-recognize/speech-recognize.min.js +2 -2
  36. package/es5/jodit.css +2 -2
  37. package/es5/jodit.fat.min.js +2 -2
  38. package/es5/jodit.js +1221 -925
  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 +10 -10
  43. package/es5/plugins/debug/debug.min.js +2 -2
  44. package/es5/plugins/speech-recognize/speech-recognize.css +1 -1
  45. package/es5/plugins/speech-recognize/speech-recognize.js +2 -2
  46. package/es5/plugins/speech-recognize/speech-recognize.min.js +2 -2
  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/create/create.js +2 -2
  52. package/esm/core/dom/dom.d.ts +21 -13
  53. package/esm/core/dom/dom.js +58 -87
  54. package/esm/core/global.js +3 -2
  55. package/esm/core/helpers/html/apply-styles.js +14 -10
  56. package/esm/core/helpers/html/clean-from-word.js +8 -4
  57. package/esm/core/helpers/html/safe-html.js +23 -14
  58. package/esm/core/helpers/html/strip-tags.js +9 -4
  59. package/esm/core/helpers/utils/align.d.ts +0 -3
  60. package/esm/core/helpers/utils/align.js +15 -18
  61. package/esm/core/helpers/utils/append-script.js +13 -10
  62. package/esm/core/helpers/utils/attr.d.ts +3 -1
  63. package/esm/core/helpers/utils/attr.js +18 -0
  64. package/esm/core/helpers/utils/css.d.ts +18 -1
  65. package/esm/core/helpers/utils/css.js +15 -0
  66. package/esm/core/helpers/utils/print.js +17 -14
  67. package/esm/core/helpers/utils/reset.js +3 -0
  68. package/esm/core/helpers/utils/selector.js +11 -7
  69. package/esm/core/selection/helpers/move-node-inside-start.js +1 -1
  70. package/esm/core/selection/selection.js +29 -26
  71. package/esm/core/selection/style/api/get-suit-parent.js +10 -0
  72. package/esm/core/selection/style/api/is-same-attributes.js +5 -2
  73. package/esm/core/selection/style/api/toggle-attributes.js +8 -9
  74. package/esm/core/selection/style/api/wrap-unwrapped-text.js +2 -2
  75. package/esm/core/traits/elms.js +11 -3
  76. package/esm/core/ui/button/button/button.js +3 -3
  77. package/esm/core/ui/button/group/group.js +2 -1
  78. package/esm/core/ui/button/tooltip/tooltip.js +2 -2
  79. package/esm/core/ui/element.js +1 -1
  80. package/esm/core/ui/form/inputs/area/area.js +3 -2
  81. package/esm/core/ui/form/inputs/file/file.js +2 -1
  82. package/esm/core/ui/form/inputs/input/input.js +5 -5
  83. package/esm/core/ui/group/group.js +7 -7
  84. package/esm/core/ui/icon.js +2 -2
  85. package/esm/core/ui/popup/popup.js +10 -8
  86. package/esm/core/ui/progress-bar/progress-bar.js +3 -4
  87. package/esm/core/view/view-with-toolbar.js +1 -1
  88. package/esm/core/view/view.js +1 -1
  89. package/esm/jodit.js +30 -28
  90. package/esm/modules/dialog/alert.js +1 -1
  91. package/esm/modules/dialog/confirm.js +3 -2
  92. package/esm/modules/dialog/dialog.d.ts +6 -0
  93. package/esm/modules/dialog/dialog.js +40 -22
  94. package/esm/modules/dialog/prompt.js +4 -3
  95. package/esm/modules/file-browser/builders/context-menu.js +5 -5
  96. package/esm/modules/file-browser/config.js +3 -1
  97. package/esm/modules/file-browser/file-browser.js +7 -4
  98. package/esm/modules/file-browser/listeners/state-listeners.js +6 -6
  99. package/esm/modules/image-editor/image-editor.js +31 -17
  100. package/esm/modules/messages/messages.js +2 -1
  101. package/esm/modules/status-bar/status-bar.js +3 -4
  102. package/esm/modules/table/table.js +22 -18
  103. package/esm/modules/toolbar/button/button.js +4 -4
  104. package/esm/modules/toolbar/button/content.js +12 -4
  105. package/esm/modules/toolbar/collection/collection.js +4 -2
  106. package/esm/modules/uploader/config.js +3 -2
  107. package/esm/modules/uploader/helpers/process-old-browser-drag.js +1 -1
  108. package/esm/modules/uploader/uploader.js +7 -2
  109. package/esm/modules/widget/color-picker/color-picker.js +4 -4
  110. package/esm/modules/widget/file-selector/file-selector.js +6 -6
  111. package/esm/modules/widget/tabs/tabs.js +5 -5
  112. package/esm/plugins/add-new-line/add-new-line.js +8 -7
  113. package/esm/plugins/ai-assistant/ui/ui-ai-assistant.js +4 -4
  114. package/esm/plugins/backspace/cases/check-join-neighbors.js +4 -1
  115. package/esm/plugins/clean-html/helpers/visitor/filters/allow-attributes.js +5 -1
  116. package/esm/plugins/clean-html/helpers/visitor/filters/fill-empty-paragraph.js +1 -1
  117. package/esm/plugins/color/config.js +4 -4
  118. package/esm/plugins/copy-format/copy-format.js +1 -1
  119. package/esm/plugins/delete/delete.js +9 -2
  120. package/esm/plugins/drag-and-drop/drag-and-drop.js +1 -1
  121. package/esm/plugins/drag-and-drop-element/drag-and-drop-element.js +1 -1
  122. package/esm/plugins/enter/helpers/insert-paragraph.js +1 -1
  123. package/esm/plugins/enter/helpers/process-empty-li-leaf.js +2 -2
  124. package/esm/plugins/enter/helpers/wrap-text.js +1 -1
  125. package/esm/plugins/fullsize/fullsize.js +3 -2
  126. package/esm/plugins/iframe/iframe.js +6 -5
  127. package/esm/plugins/image-properties/readers/align.js +6 -5
  128. package/esm/plugins/image-properties/readers/index.js +3 -1
  129. package/esm/plugins/image-properties/ui/ui-image-form.js +2 -1
  130. package/esm/plugins/image-properties/writers/index.js +2 -1
  131. package/esm/plugins/image-properties/writers/link.js +1 -1
  132. package/esm/plugins/indent/config.js +3 -2
  133. package/esm/plugins/indent/indent.js +4 -2
  134. package/esm/plugins/media/media.js +10 -7
  135. package/esm/plugins/mobile/config.js +2 -2
  136. package/esm/plugins/paste-storage/paste-storage.js +5 -5
  137. package/esm/plugins/placeholder/placeholder.js +13 -11
  138. package/esm/plugins/print/print.js +2 -2
  139. package/esm/plugins/resize-cells/resize-cells.js +13 -15
  140. package/esm/plugins/resize-handler/resize-handler.js +3 -4
  141. package/esm/plugins/resizer/resizer.js +11 -10
  142. package/esm/plugins/search/helpers/highlight-text-ranges.js +1 -1
  143. package/esm/plugins/search/ui/search.js +1 -1
  144. package/esm/plugins/select/select.js +2 -2
  145. package/esm/plugins/select-cells/select-cells.js +5 -6
  146. package/esm/plugins/source/editor/engines/ace.js +2 -1
  147. package/esm/plugins/source/editor/engines/area.js +3 -3
  148. package/esm/plugins/source/source.js +2 -2
  149. package/esm/plugins/speech-recognize/speech-recognize.js +1 -1
  150. package/esm/plugins/sticky/sticky.js +1 -1
  151. package/esm/plugins/symbols/config.js +3 -2
  152. package/esm/plugins/symbols/symbols.js +6 -5
  153. package/esm/plugins/tab/cases/on-tab-inside-li.js +2 -2
  154. package/esm/plugins/table/config.js +18 -10
  155. package/esm/plugins/table-keyboard-navigation/table-keyboard-navigation.js +2 -2
  156. package/esm/plugins/wrap-nodes/wrap-nodes.js +2 -2
  157. package/esm/plugins/xpath/xpath.js +2 -3
  158. package/esm/types/index.d.ts +1 -0
  159. package/esm/types/vdom.d.ts +96 -0
  160. package/package.json +1 -1
  161. package/types/core/dom/dom.d.ts +21 -13
  162. package/types/core/helpers/utils/align.d.ts +0 -3
  163. package/types/core/helpers/utils/attr.d.ts +3 -1
  164. package/types/core/helpers/utils/css.d.ts +18 -1
  165. package/types/modules/dialog/dialog.d.ts +6 -0
  166. package/types/types/index.d.ts +1 -0
  167. package/types/types/vdom.d.ts +96 -0
package/esm/jodit.js CHANGED
@@ -19,6 +19,7 @@ import { FAT_MODE, IS_PROD, lang } from "./core/constants.js";
19
19
  import { autobind, cache, cached, derive, throttle, watch } from "./core/decorators/index.js";
20
20
  import { eventEmitter, instances, modules, pluginSystem } from "./core/global.js";
21
21
  import { asArray, attr, callPromise, ConfigMerge, ConfigProto, css, error, isFunction, isJoditObject, isNumber, isPromise, isString, isVoid, kebabCase, markAsAtomic, normalizeKeyAliases, resolveElement, toArray, ucfirst } from "./core/helpers/index.js";
22
+ import { cssInline } from "./core/helpers/utils/css.js";
22
23
  import { Ajax } from "./core/request/index.js";
23
24
  import { Dlgs } from "./core/traits/dlgs.js";
24
25
  import { Config } from "./config.js";
@@ -806,7 +807,7 @@ let Jodit = Jodit_1 = class Jodit extends ViewWithToolbar {
806
807
  this.setReadOnly(isDisabled || readOnly);
807
808
  this.__wasReadOnly = readOnly;
808
809
  if (this.editor) {
809
- this.editor.setAttribute('aria-disabled', isDisabled.toString());
810
+ attr(this.editor, 'aria-disabled', isDisabled);
810
811
  this.container.classList.toggle('jodit_disabled', isDisabled);
811
812
  this.e.fire('disabled', isDisabled);
812
813
  }
@@ -830,10 +831,10 @@ let Jodit = Jodit_1 = class Jodit extends ViewWithToolbar {
830
831
  this.__wasReadOnly = isReadOnly;
831
832
  this.o.readonly = isReadOnly;
832
833
  if (isReadOnly) {
833
- this.editor && this.editor.removeAttribute('contenteditable');
834
+ this.editor && attr(this.editor, 'contenteditable', null);
834
835
  }
835
836
  else {
836
- this.editor && this.editor.setAttribute('contenteditable', 'true');
837
+ this.editor && attr(this.editor, 'contenteditable', true);
837
838
  }
838
839
  this.e && this.e.fire('readonly', isReadOnly);
839
840
  }
@@ -995,14 +996,14 @@ let Jodit = Jodit_1 = class Jodit extends ViewWithToolbar {
995
996
  const property = kebabCase(key);
996
997
  container.style.setProperty(`--jd-${property}`, styleValues[key]);
997
998
  });
998
- container.setAttribute('contenteditable', 'false');
999
+ attr(container, 'contenteditable', false);
999
1000
  let buffer = null;
1000
1001
  if (this.o.inline) {
1001
1002
  if (['TEXTAREA', 'INPUT'].indexOf(element.nodeName) === -1) {
1002
1003
  container = element;
1003
- element.setAttribute(__defaultClassesKey, element.className.toString());
1004
+ attr(element, __defaultClassesKey, element.className.toString());
1004
1005
  buffer = container.innerHTML;
1005
- container.innerHTML = '';
1006
+ Dom.detach(container);
1006
1007
  }
1007
1008
  container.classList.add('jodit_inline');
1008
1009
  container.classList.add('jodit-container');
@@ -1010,32 +1011,33 @@ let Jodit = Jodit_1 = class Jodit extends ViewWithToolbar {
1010
1011
  // actual for inline mode
1011
1012
  if (element !== container) {
1012
1013
  // hide source element
1013
- if (element.style.display) {
1014
- element.setAttribute(__defaultStyleDisplayKey, element.style.display);
1014
+ const display = cssInline(element, 'display');
1015
+ if (display) {
1016
+ attr(element, __defaultStyleDisplayKey, display);
1015
1017
  }
1016
- element.style.display = 'none';
1018
+ css(element, 'display', 'none');
1017
1019
  }
1018
1020
  const SLOT = 'workplace-slot';
1019
1021
  // A slot that always stays ABOVE the toolbar (presence bars, banners…).
1020
1022
  // The `data-jodit-above-toolbar` attribute tells ViewWithToolbar to keep
1021
1023
  // the toolbar box below it when (re)attaching the toolbar container.
1022
1024
  const aboveSlot = this.c.div(this.getFullElName(SLOT, 'above'), NOEDIT);
1023
- aboveSlot.setAttribute('data-jodit-above-toolbar', '');
1025
+ attr(aboveSlot, 'data-jodit-above-toolbar', '');
1024
1026
  Dom.appendChildFirst(container, aboveSlot);
1025
1027
  const topSlot = this.c.div(this.getFullElName(SLOT, 'top'), NOEDIT);
1026
- container.appendChild(topSlot);
1028
+ Dom.append(container, topSlot);
1027
1029
  const centerSlot = this.c.div(this.getFullElName(SLOT, 'center'), NOEDIT);
1028
1030
  const workplace = this.c.div('jodit-workplace', NOEDIT);
1029
1031
  const leftSlot = this.c.div(this.getFullElName(SLOT, 'left'), NOEDIT);
1030
1032
  const rightSlot = this.c.div(this.getFullElName(SLOT, 'right'), NOEDIT);
1031
- centerSlot.appendChild(leftSlot);
1032
- centerSlot.appendChild(workplace);
1033
- centerSlot.appendChild(rightSlot);
1034
- container.appendChild(centerSlot);
1033
+ Dom.append(centerSlot, leftSlot);
1034
+ Dom.append(centerSlot, workplace);
1035
+ Dom.append(centerSlot, rightSlot);
1036
+ Dom.append(container, centerSlot);
1035
1037
  const bottomPanel = this.c.div(this.getFullElName(SLOT, 'bottom'), NOEDIT);
1036
- container.appendChild(bottomPanel);
1038
+ Dom.append(container, bottomPanel);
1037
1039
  if (element.parentNode && element !== container) {
1038
- element.parentNode.insertBefore(container, element);
1040
+ Dom.before(element, container);
1039
1041
  }
1040
1042
  Object.defineProperty(element, 'component', {
1041
1043
  enumerable: false,
@@ -1047,7 +1049,7 @@ let Jodit = Jodit_1 = class Jodit extends ViewWithToolbar {
1047
1049
  'aria-disabled': false,
1048
1050
  tabindex: this.o.tabIndex
1049
1051
  });
1050
- workplace.appendChild(editor);
1052
+ Dom.append(workplace, editor);
1051
1053
  const currentPlace = {
1052
1054
  editor,
1053
1055
  element,
@@ -1101,7 +1103,7 @@ let Jodit = Jodit_1 = class Jodit extends ViewWithToolbar {
1101
1103
  return callPromise(initResult, init);
1102
1104
  }
1103
1105
  addDisclaimer(elm) {
1104
- this.workplace.appendChild(elm);
1106
+ Dom.append(this.workplace, elm);
1105
1107
  }
1106
1108
  /**
1107
1109
  * Set current place object
@@ -1198,10 +1200,10 @@ let Jodit = Jodit_1 = class Jodit extends ViewWithToolbar {
1198
1200
  // direction
1199
1201
  if (this.o.direction) {
1200
1202
  const direction = this.o.direction.toLowerCase() === 'rtl' ? 'rtl' : 'ltr';
1201
- this.editor.style.direction = direction;
1202
- this.editor.setAttribute('dir', direction);
1203
- this.container.style.direction = direction;
1204
- this.container.setAttribute('dir', direction);
1203
+ css(this.editor, 'direction', direction);
1204
+ attr(this.editor, 'dir', direction);
1205
+ css(this.container, 'direction', direction);
1206
+ attr(this.container, 'dir', direction);
1205
1207
  this.toolbar.setDirection(direction);
1206
1208
  }
1207
1209
  // proxy events
@@ -1294,23 +1296,23 @@ let Jodit = Jodit_1 = class Jodit extends ViewWithToolbar {
1294
1296
  if (element.hasAttribute(__defaultStyleDisplayKey)) {
1295
1297
  const display = attr(element, __defaultStyleDisplayKey);
1296
1298
  if (display) {
1297
- element.style.display = display;
1298
- element.removeAttribute(__defaultStyleDisplayKey);
1299
+ css(element, 'display', display);
1300
+ attr(element, __defaultStyleDisplayKey, null);
1299
1301
  }
1300
1302
  }
1301
1303
  else {
1302
- element.style.display = '';
1304
+ css(element, 'display', '');
1303
1305
  }
1304
1306
  }
1305
1307
  else {
1306
1308
  if (element.hasAttribute(__defaultClassesKey)) {
1307
1309
  element.className =
1308
1310
  attr(element, __defaultClassesKey) || '';
1309
- element.removeAttribute(__defaultClassesKey);
1311
+ attr(element, __defaultClassesKey, null);
1310
1312
  }
1311
1313
  }
1312
1314
  if (element.hasAttribute('style') && !attr(element, 'style')) {
1313
- element.removeAttribute('style');
1315
+ attr(element, 'style', null);
1314
1316
  }
1315
1317
  statusbar.destruct();
1316
1318
  this.e.off(container);
@@ -31,7 +31,7 @@ export function Alert(msg, title, callback, className = 'jodit-dialog_alert') {
31
31
  ? this
32
32
  : new Dialog({ closeOnClickOverlay: true }), container = dialog.c.div(className), okButton = Button(dialog, 'ok', 'Ok');
33
33
  asArray(msg).forEach(oneMessage => {
34
- container.appendChild(Dom.isNode(oneMessage) ? oneMessage : dialog.c.fromHTML(oneMessage));
34
+ Dom.append(container, Dom.isNode(oneMessage) ? oneMessage : dialog.c.fromHTML(oneMessage));
35
35
  });
36
36
  okButton.onAction(() => {
37
37
  if (!callback || !isFunction(callback) || callback(dialog) !== false) {
@@ -3,6 +3,7 @@
3
3
  * Released under MIT see LICENSE.txt in the project root for license information.
4
4
  * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
5
5
  */
6
+ import { Dom } from "../../core/dom/dom.js";
6
7
  import { isFunction } from "../../core/helpers/checker/is-function.js";
7
8
  import { Button } from "../../core/ui/button/button/button.js";
8
9
  import { Dialog } from "./dialog.js";
@@ -28,8 +29,8 @@ export function Confirm(msg, title, callback) {
28
29
  callback = title;
29
30
  title = undefined;
30
31
  }
31
- $label.appendChild(dialog.c.fromHTML(msg));
32
- $div.appendChild($label);
32
+ Dom.append($label, dialog.c.fromHTML(msg));
33
+ Dom.append($div, $label);
33
34
  const action = (yes) => () => {
34
35
  if (!callback || callback(yes) !== false) {
35
36
  dialog.close();
@@ -124,6 +124,12 @@ export declare class Dialog extends ViewWithToolbar implements IDialog {
124
124
  * ```
125
125
  */
126
126
  setFooter(content: Content): this;
127
+ /**
128
+ * Registry of the currently opened dialogs. Replaces a DOM scan of the
129
+ * whole `destination` (usually `document.body`) for every z-index update.
130
+ */
131
+ private static readonly __opened;
132
+ private __openedSiblings;
127
133
  /**
128
134
  * Get zIndex from dialog
129
135
  */
@@ -21,7 +21,7 @@ import { Dom } from "../../core/dom/dom.js";
21
21
  import { eventEmitter, pluginSystem } from "../../core/global.js";
22
22
  import { asArray, splitArray, toArray } from "../../core/helpers/array/index.js";
23
23
  import { hasContainer, isArray, isBoolean, isFunction, isNumber, isString, isVoid } from "../../core/helpers/checker/index.js";
24
- import { $$, attr, ConfigProto, css } from "../../core/helpers/utils/index.js";
24
+ import { attr, ConfigProto, css } from "../../core/helpers/utils/index.js";
25
25
  import { assert } from "../../core/helpers/utils/assert.js";
26
26
  import { Icon } from "../../core/ui/index.js";
27
27
  import { View } from "../../core/view/view.js";
@@ -75,7 +75,7 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
75
75
  if (isArray(elm)) {
76
76
  const div = this.c.div(this.getFullElName('column'));
77
77
  elements_list.push(div);
78
- root.appendChild(div);
78
+ Dom.append(root, div);
79
79
  return this.setElements(div, elm);
80
80
  }
81
81
  let element;
@@ -87,12 +87,12 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
87
87
  }
88
88
  elements_list.push(element);
89
89
  if (element.parentNode !== root) {
90
- root.appendChild(element);
90
+ Dom.append(root, element);
91
91
  }
92
92
  });
93
93
  toArray(root.childNodes).forEach((elm) => {
94
94
  if (elements_list.indexOf(elm) === -1) {
95
- root.removeChild(elm);
95
+ Dom.safeRemove(elm);
96
96
  }
97
97
  });
98
98
  }
@@ -270,8 +270,11 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
270
270
  this.offsetY = y;
271
271
  this.moved = Math.abs(x - left) > 100 || Math.abs(y - top) > 100;
272
272
  }
273
- this.dialog.style.left = (x || left) + 'px';
274
- this.dialog.style.top = (y || top) + 'px';
273
+ // strings on purpose: `css()` would truncate fractional pixels
274
+ css(this.dialog, {
275
+ left: (x || left) + 'px',
276
+ top: (y || top) + 'px'
277
+ });
275
278
  return this;
276
279
  }
277
280
  /**
@@ -332,6 +335,15 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
332
335
  this.setMod('footer', Boolean(content));
333
336
  return this;
334
337
  }
338
+ __openedSiblings() {
339
+ const result = [];
340
+ Dialog_1.__opened.forEach(dialog => {
341
+ if (dialog.destination === this.destination) {
342
+ result.push(dialog);
343
+ }
344
+ });
345
+ return result;
346
+ }
335
347
  /**
336
348
  * Get zIndex from dialog
337
349
  */
@@ -342,12 +354,11 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
342
354
  * Get dialog instance with maximum z-index displaying it on top of all the dialog boxes
343
355
  */
344
356
  getMaxZIndexDialog() {
345
- let maxZi = 0, dlg, zIndex, res = this;
346
- $$('.jodit-dialog', this.destination).forEach((dialog) => {
347
- dlg = dialog.component;
348
- zIndex = parseInt(css(dialog, 'zIndex'), 10);
349
- if (dlg.isOpened && !isNaN(zIndex) && zIndex > maxZi) {
350
- res = dlg;
357
+ let maxZi = 0, res = this;
358
+ this.__openedSiblings().forEach(dialog => {
359
+ const zIndex = dialog.getZIndex();
360
+ if (zIndex > maxZi) {
361
+ res = dialog;
351
362
  maxZi = zIndex;
352
363
  }
353
364
  });
@@ -359,12 +370,11 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
359
370
  setMaxZIndex() {
360
371
  if (this.getMod('static'))
361
372
  return;
362
- let maxZIndex = 20000004, zIndex = 0;
363
- $$('.jodit-dialog', this.destination).forEach(dialog => {
364
- zIndex = parseInt(css(dialog, 'zIndex'), 10);
365
- maxZIndex = Math.max(isNaN(zIndex) ? 0 : zIndex, maxZIndex);
373
+ let maxZIndex = 20000004;
374
+ this.__openedSiblings().forEach(dialog => {
375
+ maxZIndex = Math.max(dialog.getZIndex(), maxZIndex);
366
376
  });
367
- this.container.style.zIndex = (maxZIndex + 1).toString();
377
+ css(this.container, 'zIndex', (maxZIndex + 1).toString());
368
378
  }
369
379
  /**
370
380
  * Expands the dialog on full browser window
@@ -410,14 +420,15 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
410
420
  }
411
421
  this.setMod('active', true);
412
422
  this.isOpened = true;
423
+ Dialog_1.__opened.add(this);
413
424
  this.setModal(modal);
414
- this.destination.appendChild(this.container);
425
+ Dom.append(this.destination, this.container);
415
426
  if (this.getMod('static') !== true) {
416
427
  this.setPosition(this.offsetX, this.offsetY);
417
428
  this.setMaxZIndex();
418
429
  }
419
430
  else {
420
- this.container.style.removeProperty('z-index');
431
+ css(this.container, 'zIndex', null);
421
432
  }
422
433
  if (this.o.fullsize) {
423
434
  this.toggleFullSize(true);
@@ -472,6 +483,7 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
472
483
  }
473
484
  this.setMod('active', false);
474
485
  this.isOpened = false;
486
+ Dialog_1.__opened.delete(this);
475
487
  if (this.isFullSize) {
476
488
  this.toggleFullSize(false);
477
489
  }
@@ -550,11 +562,11 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
550
562
  </div>
551
563
  </div>`);
552
564
  if (self.options.direction === 'rtl') {
553
- self.container.style.direction = 'rtl';
554
- self.container.setAttribute('dir', 'rtl');
565
+ css(self.container, 'direction', 'rtl');
566
+ attr(self.container, 'dir', 'rtl');
555
567
  }
556
568
  if (this.o.zIndex) {
557
- this.container.style.zIndex = this.o.zIndex.toString();
569
+ css(this.container, 'zIndex', this.o.zIndex.toString());
558
570
  }
559
571
  attr(self.container, 'role', 'dialog');
560
572
  Object.defineProperty(self.container, 'component', {
@@ -621,6 +633,7 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
621
633
  if (this.isOpened) {
622
634
  this.close();
623
635
  }
636
+ Dialog_1.__opened.delete(this);
624
637
  if (this.events) {
625
638
  this.__removeGlobalResizeListeners();
626
639
  this.events
@@ -631,6 +644,11 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
631
644
  super.destruct();
632
645
  }
633
646
  };
647
+ /**
648
+ * Registry of the currently opened dialogs. Replaces a DOM scan of the
649
+ * whole `destination` (usually `document.body`) for every z-index update.
650
+ */
651
+ Dialog.__opened = new Set();
634
652
  Dialog.defaultOptions = {
635
653
  ...View.defaultOptions,
636
654
  closeOnClickOverlay: false,
@@ -3,6 +3,7 @@
3
3
  * Released under MIT see LICENSE.txt in the project root for license information.
4
4
  * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
5
5
  */
6
+ import { Dom } from "../../core/dom/dom.js";
6
7
  import { isFunction } from "../../core/helpers/checker/is-function.js";
7
8
  import { attr } from "../../core/helpers/utils/attr.js";
8
9
  import { Button } from "../../core/ui/button/button/button.js";
@@ -41,9 +42,9 @@ export function Prompt(msg, title, callback, placeholder, defaultValue) {
41
42
  if (placeholder) {
42
43
  attr(inputElement, 'placeholder', placeholder);
43
44
  }
44
- labelElement.appendChild(dialog.c.text(msg));
45
- form.appendChild(labelElement);
46
- form.appendChild(inputElement);
45
+ Dom.append(labelElement, dialog.c.text(msg));
46
+ Dom.append(form, labelElement);
47
+ Dom.append(form, inputElement);
47
48
  cancelButton.onAction(dialog.close);
48
49
  const onclick = () => {
49
50
  if (!callback ||
@@ -80,7 +80,7 @@ export default (self) => {
80
80
  buttons: ['fullsize', 'dialog.close']
81
81
  }), temp_content = self.c.div(CLASS_PREVIEW, '<div class="jodit-icon_loader"></div>'), preview_box = self.c.div(CLASS_PREVIEW + '__box'), next = self.c.fromHTML(preview_tpl_next()), prev = self.c.fromHTML(preview_tpl_next('prev', 'left')), addLoadHandler = (src) => {
82
82
  const image = self.c.element('img');
83
- image.setAttribute('src', src);
83
+ attr(image, 'src', src);
84
84
  const onload = () => {
85
85
  var _a;
86
86
  if (self.isInDestruct) {
@@ -90,14 +90,14 @@ export default (self) => {
90
90
  Dom.detach(temp_content);
91
91
  if (opt.showPreviewNavigation) {
92
92
  if (Dom.prevWithClass(item, self.files.getFullElName('item'))) {
93
- temp_content.appendChild(prev);
93
+ Dom.append(temp_content, prev);
94
94
  }
95
95
  if (Dom.nextWithClass(item, self.files.getFullElName('item'))) {
96
- temp_content.appendChild(next);
96
+ Dom.append(temp_content, next);
97
97
  }
98
98
  }
99
- temp_content.appendChild(preview_box);
100
- preview_box.appendChild(image);
99
+ Dom.append(temp_content, preview_box);
100
+ Dom.append(preview_box, image);
101
101
  preview.setPosition();
102
102
  (_a = self === null || self === void 0 ? void 0 : self.events) === null || _a === void 0 ? void 0 : _a.fire('previewOpenedAndLoaded');
103
103
  };
@@ -4,6 +4,7 @@
4
4
  * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
5
5
  */
6
6
  import "../../core/request/config.js";
7
+ import { Dom } from "../../core/dom/dom.js";
7
8
  import { isArray, isString } from "../../core/helpers/checker/index.js";
8
9
  import { humanSizeToBytes } from "../../core/helpers/utils/human-size-to-bytes.js";
9
10
  import { UIFileInput } from "../../core/ui/form/inputs/file/file.js";
@@ -290,7 +291,8 @@ Config.prototype.controls.filebrowser = {
290
291
  filter: {
291
292
  isInput: true,
292
293
  getContent: (filebrowser, b) => {
293
- const oldInput = b.container.querySelector('.jodit-input');
294
+ const oldInput = Dom.first(b.container, node => Dom.isHTMLElement(node) &&
295
+ node.classList.contains('jodit-input'));
294
296
  if (oldInput) {
295
297
  return oldInput;
296
298
  }
@@ -18,8 +18,10 @@ import * as consts from "../../core/constants.js";
18
18
  import { IS_PROD } from "../../core/constants.js";
19
19
  import { autobind, cache, cached, derive } from "../../core/decorators/index.js";
20
20
  import { watch } from "../../core/decorators/watch/watch.js";
21
+ import { Dom } from "../../core/dom/dom.js";
21
22
  import { observable } from "../../core/event-emitter/index.js";
22
23
  import { ConfigProto, error, isAbortError, isFunction, isString, trim } from "../../core/helpers/index.js";
24
+ import { cssInline } from "../../core/helpers/utils/css.js";
23
25
  import { Storage } from "../../core/storage/index.js";
24
26
  import { Dlgs } from "../../core/traits/dlgs.js";
25
27
  import { ViewWithToolbar } from "../../core/view/view-with-toolbar.js";
@@ -85,7 +87,8 @@ let FileBrowser = class FileBrowser extends ViewWithToolbar {
85
87
  return Storage.makeStorage(Boolean(this.o.saveStateInStorage), this.componentName);
86
88
  }
87
89
  get isOpened() {
88
- return this._dialog.isOpened && this.browser.style.display !== 'none';
90
+ return (this._dialog.isOpened &&
91
+ cssInline(this.browser, 'display') !== 'none');
89
92
  }
90
93
  /**
91
94
  * It displays a message in the status bar of filebrowser
@@ -249,10 +252,10 @@ let FileBrowser = class FileBrowser extends ViewWithToolbar {
249
252
  self.browser.component = this;
250
253
  self.container = self.browser;
251
254
  if (self.o.showFoldersPanel) {
252
- self.browser.appendChild(self.tree.container);
255
+ Dom.append(self.browser, self.tree.container);
253
256
  }
254
- self.browser.appendChild(self.files.container);
255
- self.browser.appendChild(self.status_line);
257
+ Dom.append(self.browser, self.files.container);
258
+ Dom.append(self.browser, self.status_line);
256
259
  selfListeners.call(self);
257
260
  nativeListeners.call(self);
258
261
  stateListeners.call(self);
@@ -70,11 +70,11 @@ export function stateListeners() {
70
70
  Dom.detach(files.container);
71
71
  if (state.elements.length) {
72
72
  state.elements.forEach(item => {
73
- this.files.container.appendChild(getDomElement(item));
73
+ Dom.append(this.files.container, getDomElement(item));
74
74
  });
75
75
  }
76
76
  else {
77
- files.container.appendChild(create.div(this.componentName + '_no-files_true', this.i18n('There are no files')));
77
+ Dom.append(files.container, create.div(this.componentName + '_no-files_true', this.i18n('There are no files')));
78
78
  }
79
79
  }, this.defaultTimeout))
80
80
  .on('change.sources', this.async.debounce(() => {
@@ -82,7 +82,7 @@ export function stateListeners() {
82
82
  state.sources.forEach(source => {
83
83
  const sourceName = source.name;
84
84
  if (sourceName && sourceName !== DEFAULT_SOURCE_NAME) {
85
- this.tree.container.appendChild(create.div(this.tree.getFullElName('source-title'), sourceName));
85
+ Dom.append(this.tree.container, create.div(this.tree.getFullElName('source-title'), sourceName));
86
86
  }
87
87
  source.folders.forEach((name) => {
88
88
  const folderElm = create.a(this.tree.getFullElName('item'), {
@@ -103,7 +103,7 @@ export function stateListeners() {
103
103
  e.preventDefault();
104
104
  };
105
105
  this.e.on(folderElm, 'click', action('openFolder'));
106
- this.tree.container.appendChild(folderElm);
106
+ Dom.append(this.tree.container, folderElm);
107
107
  if (name === '..' || name === '.') {
108
108
  return;
109
109
  }
@@ -116,7 +116,7 @@ export function stateListeners() {
116
116
  size: 'tiny'
117
117
  });
118
118
  btn.onAction(action('renameFolder'));
119
- folderElm.appendChild(btn.container);
119
+ Dom.append(folderElm, btn.container);
120
120
  }
121
121
  if (options.deleteFolder &&
122
122
  this.dataProvider.canI('FolderRemove')) {
@@ -127,7 +127,7 @@ export function stateListeners() {
127
127
  size: 'tiny'
128
128
  });
129
129
  btn.onAction(action('removeFolder'));
130
- folderElm.appendChild(btn.container);
130
+ Dom.append(folderElm, btn.container);
131
131
  }
132
132
  });
133
133
  if (options.createNewFolder &&
@@ -17,17 +17,27 @@ var ImageEditor_1;
17
17
  import { ViewComponent } from "../../core/component/index.js";
18
18
  import { autobind, component, debounce, throttle } from "../../core/decorators/index.js";
19
19
  import { Dom } from "../../core/dom/index.js";
20
- import { toArray } from "../../core/helpers/array/to-array.js";
21
20
  import { trim } from "../../core/helpers/string/trim.js";
22
21
  import { attr } from "../../core/helpers/utils/attr.js";
23
22
  import { css } from "../../core/helpers/utils/css.js";
24
- import { $$, refs } from "../../core/helpers/utils/selector.js";
23
+ import { refs } from "../../core/helpers/utils/selector.js";
25
24
  import { call } from "../../core/helpers/utils/utils.js";
26
25
  import { Button } from "../../core/ui/button/index.js";
27
26
  import { Config } from "../../config.js";
28
27
  import "./config.js";
29
28
  import { form } from "./templates/form.js";
30
29
  const jie = 'jodit-image-editor';
30
+ const hasClass = (className) => (elm) => elm.classList.contains(className);
31
+ function findFirst(root, cond) {
32
+ return Dom.first(root, n => Dom.isHTMLElement(n) && cond(n));
33
+ }
34
+ function findAll(root, cond) {
35
+ const result = [];
36
+ Dom.each(root, n => {
37
+ Dom.isHTMLElement(n) && cond(n) && result.push(n);
38
+ });
39
+ return result;
40
+ }
31
41
  const TABS = {
32
42
  resize: 'resize',
33
43
  crop: 'crop'
@@ -78,19 +88,20 @@ let ImageEditor = ImageEditor_1 = class ImageEditor extends ViewComponent {
78
88
  return this.j.async.promise((resolve) => {
79
89
  const timestamp = new Date().getTime();
80
90
  this.image = this.j.c.element('img');
81
- $$('img,.jodit-icon_loader', this.resize_box).forEach(Dom.safeRemove);
82
- $$('img,.jodit-icon_loader', this.crop_box).forEach(Dom.safeRemove);
91
+ const isTrash = (elm) => Dom.isTag(elm, 'img') || hasClass('jodit-icon_loader')(elm);
92
+ findAll(this.resize_box, isTrash).forEach(Dom.safeRemove);
93
+ findAll(this.crop_box, isTrash).forEach(Dom.safeRemove);
83
94
  css(this.cropHandler, 'background', 'transparent');
84
95
  this.onSave = save;
85
- this.resize_box.appendChild(this.j.c.element('i', { class: 'jodit-icon_loader' }));
86
- this.crop_box.appendChild(this.j.c.element('i', { class: 'jodit-icon_loader' }));
96
+ Dom.append(this.resize_box, this.j.c.element('i', { class: 'jodit-icon_loader' }));
97
+ Dom.append(this.crop_box, this.j.c.element('i', { class: 'jodit-icon_loader' }));
87
98
  if (/\?/.test(url)) {
88
99
  url += '&_tst=' + timestamp;
89
100
  }
90
101
  else {
91
102
  url += '?_tst=' + timestamp;
92
103
  }
93
- this.image.setAttribute('src', url);
104
+ attr(this.image, 'src', url);
94
105
  this._dialog.open();
95
106
  const { widthInput, heightInput } = refs(this.editor);
96
107
  const onload = () => {
@@ -103,10 +114,10 @@ let ImageEditor = ImageEditor_1 = class ImageEditor extends ViewComponent {
103
114
  widthInput.value = this.naturalWidth.toString();
104
115
  heightInput.value = this.naturalHeight.toString();
105
116
  this.ratio = this.naturalWidth / this.naturalHeight;
106
- this.resize_box.appendChild(this.image);
117
+ Dom.append(this.resize_box, this.image);
107
118
  this.cropImage = this.image.cloneNode(true);
108
- this.crop_box.appendChild(this.cropImage);
109
- Dom.safeRemove.apply(null, $$('.jodit-icon_loader', this.editor));
119
+ Dom.append(this.crop_box, this.cropImage);
120
+ Dom.safeRemove.apply(null, findAll(this.editor, hasClass('jodit-icon_loader')));
110
121
  if (this.activeTab === TABS.crop) {
111
122
  this.showCrop();
112
123
  }
@@ -128,10 +139,11 @@ let ImageEditor = ImageEditor_1 = class ImageEditor extends ViewComponent {
128
139
  if (!slide) {
129
140
  return;
130
141
  }
131
- $$(`.${jie}__slider,.${jie}__area`, self.editor).forEach(elm => elm.classList.remove(`${jie}_active`));
142
+ findAll(self.editor, elm => hasClass(`${jie}__slider`)(elm) || hasClass(`${jie}__area`)(elm)).forEach(elm => elm.classList.remove(`${jie}_active`));
132
143
  slide.classList.add(`${jie}_active`);
133
144
  this.activeTab = attr(slide, '-area') || TABS.resize;
134
- const tab = self.editor.querySelector(`.${jie}__area.${jie}__area_` + self.activeTab);
145
+ const tab = findFirst(self.editor, elm => hasClass(`${jie}__area`)(elm) &&
146
+ hasClass(`${jie}__area_` + self.activeTab)(elm));
135
147
  if (tab) {
136
148
  tab.classList.add(`${jie}_active`);
137
149
  }
@@ -356,7 +368,7 @@ let ImageEditor = ImageEditor_1 = class ImageEditor extends ViewComponent {
356
368
  const { widthInput, heightInput } = refs(this.editor);
357
369
  self.j.e
358
370
  .on([
359
- self.editor.querySelector('.jodit_bottomright'),
371
+ findFirst(self.editor, hasClass('jodit_bottomright')),
360
372
  self.cropHandler
361
373
  ], `mousedown.${jie}`, this.onResizeHandleMouseDown)
362
374
  .on(this.j.ow, `resize.${jie}`, () => {
@@ -365,7 +377,7 @@ let ImageEditor = ImageEditor_1 = class ImageEditor extends ViewComponent {
365
377
  this.j.e.fire(self.cropHandler, 'updatesize');
366
378
  });
367
379
  self.j.e
368
- .on(toArray(this.editor.querySelectorAll(`.${jie}__slider-title`)), 'click', this.onTitleModeClick)
380
+ .on(findAll(this.editor, hasClass(`${jie}__slider-title`)), 'click', this.onTitleModeClick)
369
381
  .on([widthInput, heightInput], 'input', this.onChangeSizeInput);
370
382
  const { keepAspectRatioResize, keepAspectRatioCrop } = refs(this.editor);
371
383
  if (keepAspectRatioResize) {
@@ -495,9 +507,11 @@ let ImageEditor = ImageEditor_1 = class ImageEditor extends ViewComponent {
495
507
  const { resizeBox, cropBox } = refs(this.editor);
496
508
  this.resize_box = resizeBox;
497
509
  this.crop_box = cropBox;
498
- this.sizes = this.editor.querySelector(`.${jie}__area.${jie}__area_crop .jodit-image-editor__sizes`);
499
- this.resizeHandler = this.editor.querySelector(`.${jie}__resizer`);
500
- this.cropHandler = this.editor.querySelector(`.${jie}__croper`);
510
+ this.sizes = findFirst(this.editor, elm => hasClass(`${jie}__sizes`)(elm) &&
511
+ Boolean(Dom.closest(elm, p => Dom.isHTMLElement(p) &&
512
+ hasClass(`${jie}__area_crop`)(p), this.editor)));
513
+ this.resizeHandler = findFirst(this.editor, hasClass(`${jie}__resizer`));
514
+ this.cropHandler = findFirst(this.editor, hasClass(`${jie}__croper`));
501
515
  this._dialog = this.j.dlg({
502
516
  buttons: ['fullsize', 'dialog.close']
503
517
  });
@@ -14,6 +14,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
14
14
  return c > 3 && r && Object.defineProperty(target, key, r), r;
15
15
  };
16
16
  import { component } from "../../core/decorators/component/component.js";
17
+ import { Dom } from "../../core/dom/dom.js";
17
18
  import { css } from "../../core/helpers/utils/css.js";
18
19
  import { UIGroup } from "../../core/ui/group/group.js";
19
20
  import { UIMessage } from "./message.js";
@@ -82,7 +83,7 @@ let UIMessages = class UIMessages extends UIGroup {
82
83
  if (!this.__box) {
83
84
  throw new Error('Container is not defined: ' + key);
84
85
  }
85
- this.__box.appendChild(this.container);
86
+ Dom.append(this.__box, this.container);
86
87
  const msg = new UIMessage(this.j, { text, variant });
87
88
  this.append(msg);
88
89
  this.__calcOffsets();