@mgdis/mg-components 6.27.0 → 6.28.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 (65) hide show
  1. package/dist/cjs/loader.cjs.js +1 -1
  2. package/dist/cjs/mg-action-more_36.cjs.entry.js +365 -77
  3. package/dist/cjs/mg-components.cjs.js +1 -1
  4. package/dist/cjs/mg-input-combobox.cjs.entry.js +36 -2
  5. package/dist/cjs/mg-input-file.cjs.entry.js +25 -2
  6. package/dist/cjs/mg-input-rich-text-editor.cjs.entry.js +717 -504
  7. package/dist/collection/assets/jodit/jodit.css +1 -1
  8. package/dist/collection/components/atoms/mg-button/mg-button.js +86 -13
  9. package/dist/collection/components/molecules/inputs/mg-input-checkbox/mg-input-checkbox.js +24 -1
  10. package/dist/collection/components/molecules/inputs/mg-input-combobox/mg-input-combobox.js +36 -2
  11. package/dist/collection/components/molecules/inputs/mg-input-date/mg-input-date.js +25 -9
  12. package/dist/collection/components/molecules/inputs/mg-input-file/mg-input-file.js +25 -2
  13. package/dist/collection/components/molecules/inputs/mg-input-numeric/mg-input-numeric.js +24 -6
  14. package/dist/collection/components/molecules/inputs/mg-input-password/mg-input-password.js +24 -5
  15. package/dist/collection/components/molecules/inputs/mg-input-radio/mg-input-radio.js +64 -16
  16. package/dist/collection/components/molecules/inputs/mg-input-select/mg-input-select.js +32 -10
  17. package/dist/collection/components/molecules/inputs/mg-input-text/mg-input-text.js +24 -5
  18. package/dist/collection/components/molecules/inputs/mg-input-textarea/mg-input-textarea.js +24 -6
  19. package/dist/collection/components/molecules/mg-form/mg-form.js +74 -8
  20. package/dist/components/mg-button2.js +1 -1
  21. package/dist/components/mg-form.js +1 -1
  22. package/dist/components/mg-input-checkbox.js +1 -1
  23. package/dist/components/mg-input-combobox.js +1 -1
  24. package/dist/components/mg-input-date.js +1 -1
  25. package/dist/components/mg-input-file.js +1 -1
  26. package/dist/components/mg-input-numeric.js +1 -1
  27. package/dist/components/mg-input-password.js +1 -1
  28. package/dist/components/mg-input-radio.js +1 -1
  29. package/dist/components/mg-input-rich-text-editor.js +262 -262
  30. package/dist/components/mg-input-select2.js +1 -1
  31. package/dist/components/mg-input-text2.js +1 -1
  32. package/dist/components/mg-input-textarea.js +1 -1
  33. package/dist/components/mg-modal.js +1 -1
  34. package/dist/custom-elements.json +12 -2
  35. package/dist/esm/loader.js +1 -1
  36. package/dist/esm/mg-action-more_36.entry.js +366 -78
  37. package/dist/esm/mg-components.js +1 -1
  38. package/dist/esm/mg-input-combobox.entry.js +36 -2
  39. package/dist/esm/mg-input-file.entry.js +25 -2
  40. package/dist/esm/mg-input-rich-text-editor.entry.js +717 -504
  41. package/dist/mg-components/mg-components.esm.js +1 -1
  42. package/dist/mg-components/p-2198f145.entry.js +1 -0
  43. package/dist/mg-components/p-d4a4eb78.entry.js +1 -0
  44. package/dist/mg-components/{p-6f492676.entry.js → p-e8b5e8d8.entry.js} +261 -261
  45. package/dist/mg-components/p-fdcce8d5.entry.js +1 -0
  46. package/dist/types/components/atoms/mg-button/mg-button.d.ts +41 -2
  47. package/dist/types/components/molecules/inputs/mg-input/mg-input.conf.d.ts +1 -0
  48. package/dist/types/components/molecules/inputs/mg-input-checkbox/mg-input-checkbox.d.ts +9 -0
  49. package/dist/types/components/molecules/inputs/mg-input-combobox/mg-input-combobox.d.ts +10 -1
  50. package/dist/types/components/molecules/inputs/mg-input-date/mg-input-date.d.ts +9 -0
  51. package/dist/types/components/molecules/inputs/mg-input-file/mg-input-file.d.ts +9 -0
  52. package/dist/types/components/molecules/inputs/mg-input-numeric/mg-input-numeric.d.ts +9 -0
  53. package/dist/types/components/molecules/inputs/mg-input-password/mg-input-password.d.ts +9 -0
  54. package/dist/types/components/molecules/inputs/mg-input-radio/mg-input-radio.d.ts +29 -2
  55. package/dist/types/components/molecules/inputs/mg-input-select/mg-input-select.d.ts +10 -1
  56. package/dist/types/components/molecules/inputs/mg-input-text/mg-input-text.d.ts +9 -0
  57. package/dist/types/components/molecules/inputs/mg-input-textarea/mg-input-textarea.d.ts +9 -0
  58. package/dist/types/components/molecules/mg-form/mg-form.d.ts +18 -0
  59. package/dist/types/components.d.ts +10 -2
  60. package/ide/intellij/web-types.json +4 -4
  61. package/ide/vscode/html-custom-data.json +3 -3
  62. package/package.json +19 -19
  63. package/dist/mg-components/p-32a55ddb.entry.js +0 -1
  64. package/dist/mg-components/p-813d69c7.entry.js +0 -1
  65. package/dist/mg-components/p-a2445605.entry.js +0 -1
@@ -1781,7 +1781,6 @@ var bn, xn = o((() => {
1781
1781
  return e.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&").replace(/-/g, "\\x2d");
1782
1782
  };
1783
1783
  })), Cn = /* @__PURE__ */ s(((e) => {
1784
- Object.defineProperty(e, "__esModule", { value: true });
1785
1784
  function t(e) {
1786
1785
  return Object.prototype.toString.call(e) === "[object Object]";
1787
1786
  }
@@ -2022,29 +2021,34 @@ var bn, xn = o((() => {
2022
2021
  let n = "@" + t.name, r = t.params ? e.rawValue(t, "params") : "", a = t.raws.afterName;
2023
2022
  return a === void 0 ? a = r ? " " : "" : a === "" && r && !i.test(r[0]) && (a = " "), n + a + r;
2024
2023
  }
2025
- function l(e, t, n) {
2024
+ function l(e) {
2025
+ if (!e.prop.startsWith("--")) return false;
2026
+ let t = e.raws.before;
2027
+ return t === void 0 || !/\S$/.test(t);
2028
+ }
2029
+ function u(e, t, n) {
2026
2030
  let r = n.nodes, i = r.length - 1;
2027
2031
  for (; i > 0 && r[i].type === "comment";) --i;
2028
2032
  let a = e.raw(n, "semicolon"), o = n.type === "document";
2029
2033
  for (let e = r.length - 1; e >= 0; e--) {
2030
2034
  let n = r[e], s = i !== e || a;
2031
- !s && e < r.length - 1 && (n.type === "atrule" && !n.nodes || n.type === "decl" && n.prop.startsWith("--")) && (s = true), t.push({
2035
+ !s && e < r.length - 1 && (n.type === "atrule" && !n.nodes || n.type === "decl" && l(n)) && (s = true), t.push({
2032
2036
  document: o,
2033
2037
  node: n,
2034
2038
  semicolon: s
2035
2039
  });
2036
2040
  }
2037
2041
  }
2038
- function u(e, t, n, r) {
2042
+ function d(e, t, n, r) {
2039
2043
  let i = e.raw(n, "between", "beforeOpen");
2040
2044
  e.builder(a(r + i) + "{", n, "start");
2041
2045
  let o = n.nodes && n.nodes.length, s = () => {
2042
2046
  let t = o ? e.raw(n, "after") : e.raw(n, "after", "emptyBody");
2043
2047
  t && e.builder(a(t)), e.builder("}", n, "end"), n.type === "rule" && n.raws.ownSemicolon && e.builder(a(n.raws.ownSemicolon), n, "end");
2044
2048
  };
2045
- o ? (t.push(s), l(e, t, n)) : s();
2049
+ o ? (t.push(s), u(e, t, n)) : s();
2046
2050
  }
2047
- var d = class e {
2051
+ var f = class e {
2048
2052
  constructor(e) {
2049
2053
  this.builder = e;
2050
2054
  }
@@ -2081,14 +2085,14 @@ var bn, xn = o((() => {
2081
2085
  "rule",
2082
2086
  "stringify"
2083
2087
  ].every((e) => this[e] === n[e]), i = [];
2084
- for (l(this, i, t); i.length > 0;) {
2088
+ for (u(this, i, t); i.length > 0;) {
2085
2089
  let e = i.pop();
2086
2090
  if (typeof e == "function") {
2087
2091
  e();
2088
2092
  continue;
2089
2093
  }
2090
2094
  let t = e.node, n = this.raw(t, "before");
2091
- n && this.builder(e.document ? n : a(n)), r && t.type === "rule" ? u(this, i, t, this.rawValue(t, "selector")) : r && t.type === "atrule" && t.nodes ? u(this, i, t, c(this, t)) : this.stringify(t, e.semicolon);
2095
+ n && this.builder(e.document ? n : a(n)), r && t.type === "rule" ? d(this, i, t, this.rawValue(t, "selector")) : r && t.type === "atrule" && t.nodes ? d(this, i, t, c(this, t)) : this.stringify(t, e.semicolon);
2092
2096
  }
2093
2097
  }
2094
2098
  comment(e) {
@@ -2198,7 +2202,7 @@ var bn, xn = o((() => {
2198
2202
  this[e.type](e, t);
2199
2203
  }
2200
2204
  };
2201
- t.exports = d, d.default = d;
2205
+ t.exports = f, f.default = f;
2202
2206
  })), kn = /* @__PURE__ */ s(((e, t) => {
2203
2207
  var n = On();
2204
2208
  function r(e, t) {
@@ -2640,7 +2644,7 @@ var bn, xn = o((() => {
2640
2644
  }
2641
2645
  replaceValues(e, t, n) {
2642
2646
  return n || (n = t, t = {}), this.walkDecls((r) => {
2643
- t.props && !t.props.includes(r.prop) || t.fast && !r.value.includes(t.fast) || (r.value = r.value.replace(e, n));
2647
+ (!t.props || t.props.includes(r.prop)) && (!t.fast || r.value.includes(t.fast)) && (r.value = r.value.replace(e, n));
2644
2648
  }), this.markDirty(), this;
2645
2649
  }
2646
2650
  some(e) {
@@ -3034,8 +3038,12 @@ var bn, xn = o((() => {
3034
3038
  split(e, t, n) {
3035
3039
  if (typeof e != "string") return [];
3036
3040
  let r = [], i = "", a = false, o = 0, s = false, c = "", l = false;
3037
- for (let n of e) l ? l = false : n === "\\" ? l = true : s ? n === c && (s = false) : n === "\"" || n === "'" ? (s = true, c = n) : n === "(" ? o += 1 : n === ")" ? o > 0 && --o : o === 0 && t.includes(n) && (a = true), a ? (i !== "" && r.push(i.trim()), i = "", a = false) : i += n;
3038
- return (n || i !== "") && r.push(i.trim()), r;
3041
+ for (let u of e) if (l ? l = false : u === "\\" ? l = true : s ? u === c && (s = false) : u === "\"" || u === "'" ? (s = true, c = u) : u === "(" ? o += 1 : u === ")" ? o > 0 && --o : o === 0 && t.includes(u) && (a = true), a) {
3042
+ let e = i.trim();
3043
+ (n || e !== "") && r.push(e), i = "", a = false;
3044
+ } else i += u;
3045
+ let u = i.trim();
3046
+ return (n || u !== "") && r.push(u), r;
3039
3047
  }
3040
3048
  };
3041
3049
  t.exports = n, n.default = n;
@@ -3138,8 +3146,8 @@ var bn, xn = o((() => {
3138
3146
  for (let t = this.root.nodes.length - 1; t >= 0; t--) e = this.root.nodes[t], e.type === "comment" && e.text.startsWith("# sourceMappingURL=") && this.root.removeChild(t);
3139
3147
  } else if (this.css) {
3140
3148
  let e;
3141
- for (; (e = this.css.lastIndexOf("/*#")) !== -1;) {
3142
- let t = this.css.indexOf("*/", e + 3);
3149
+ for (; (e = this.css.lastIndexOf("/*# sourceMappingURL=")) !== -1;) {
3150
+ let t = this.css.indexOf("*/", e + 21);
3143
3151
  if (t === -1) break;
3144
3152
  for (; e > 0 && this.css[e - 1] === "\n";) e--;
3145
3153
  this.css = this.css.slice(0, e) + this.css.slice(t + 2);
@@ -3576,7 +3584,7 @@ var bn, xn = o((() => {
3576
3584
  freeSemicolon(e) {
3577
3585
  if (this.spaces += e[1], this.current.nodes) {
3578
3586
  let t = this.current.nodes[this.current.nodes.length - 1];
3579
- t && t.type === "rule" && !t.raws.ownSemicolon && (t.raws.ownSemicolon = this.spaces, this.spaces = "", t.source.end = this.getPosition(e[2]), t.source.end.offset += t.raws.ownSemicolon.length);
3587
+ t && t.type === "rule" && !t.raws.ownSemicolon && (t.raws.ownSemicolon = this.spaces, this.spaces = "", t.source.end = this.getPosition(e[2]), t.source.end.offset++);
3580
3588
  }
3581
3589
  }
3582
3590
  getPosition(e) {
@@ -4195,7 +4203,7 @@ var bn, xn = o((() => {
4195
4203
  })), Qn = /* @__PURE__ */ s(((e, t) => {
4196
4204
  var n = Fn(), r = Xn(), i = Zn(), a = zn(), o = class {
4197
4205
  constructor(e = []) {
4198
- this.version = "8.5.26", this.plugins = this.normalize(e);
4206
+ this.version = "8.5.28", this.plugins = this.normalize(e);
4199
4207
  }
4200
4208
  normalize(e) {
4201
4209
  let t = [];
@@ -4221,7 +4229,7 @@ var bn, xn = o((() => {
4221
4229
  b.plugin = function(e, t) {
4222
4230
  let n = false;
4223
4231
  function r(...r) {
4224
- console && console.warn && !n && (n = true, console.warn(e + ": postcss.plugin was deprecated. Migration guide:\nhttps://evilmartians.com/chronicles/postcss-8-plugin-migration"), process.env.LANG && process.env.LANG.startsWith("cn") &&
4232
+ console && console.warn && !n && (n = true, console.warn(e + ": postcss.plugin was deprecated. Migration guide:\nhttps://evilmartians.com/chronicles/postcss-8-plugin-migration"), process.env.LANG && process.env.LANG.startsWith("zh") &&
4225
4233
  /* c8 ignore next 7 */
4226
4234
  console.warn(e + ": 里面 postcss.plugin 被弃用. 迁移指南:\nhttps://www.w3ctech.com/topic/2226"));
4227
4235
  let i = t(...r);
@@ -5132,7 +5140,7 @@ var bn, xn = o((() => {
5132
5140
  * Released under MIT see LICENSE.txt in the project root for license information.
5133
5141
  * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
5134
5142
  */
5135
- const APP_VERSION = "4.13.22";
5143
+ const APP_VERSION = "4.14.2";
5136
5144
  // prettier-ignore
5137
5145
  const ES = "es2020";
5138
5146
  const IS_ES_MODERN = true;
@@ -5640,6 +5648,9 @@ const map$1 = {};
5640
5648
  function reset(key) {
5641
5649
  var _a, _b;
5642
5650
  if (!(key in map$1)) {
5651
+ // Raw DOM API on purpose: this bootstrap helper is imported by
5652
+ // `to-array`, which the `Dom` module itself depends on — importing
5653
+ // `Dom` here would create a circular dependency
5643
5654
  const iframe = globalDocument.createElement('iframe');
5644
5655
  try {
5645
5656
  iframe.src = 'about:blank';
@@ -6012,6 +6023,21 @@ function css(element, key, value, onlyStyleMode = false) {
6012
6023
  /**
6013
6024
  * Clear center align
6014
6025
  */
6026
+ /**
6027
+ * Read the exact inline value of a CSS property (the `style` attribute).
6028
+ * Unlike `css()` it never touches computed styles (no layout access) and does
6029
+ * not normalize the result, so it is safe for exact string comparisons and
6030
+ * save/restore. Returns an empty string when the property is not set inline.
6031
+ *
6032
+ * @example
6033
+ * ```js
6034
+ * cssInline(elm, 'zIndex'); // '' or '100'
6035
+ * cssInline(elm, 'width'); // '0px' (css(elm, 'width', true) would return 0)
6036
+ * ```
6037
+ */
6038
+ function cssInline(element, key) {
6039
+ return element.style.getPropertyValue(kebabCase(key));
6040
+ }
6015
6041
  const clearCenterAlign = (image) => {
6016
6042
  if (css(image, 'display') === 'block') {
6017
6043
  css(image, 'display', '');
@@ -6076,6 +6102,24 @@ function attr(elm, keyOrAttributes, value) {
6076
6102
  }
6077
6103
  return elm.getAttribute(key);
6078
6104
  }
6105
+ /**
6106
+ * Exact-name attribute access: no camelCase → kebab-case conversion, no
6107
+ * `data-` fallback and no `px` stripping. Use it where the attribute name must
6108
+ * be taken verbatim — sanitizers and attribute comparison (`onLoad`, `viewBox`,
6109
+ * `xlink:href`). `null` removes the attribute.
6110
+ */
6111
+ function attrRaw(elm, name, value) {
6112
+ if (value === undefined) {
6113
+ return elm.getAttribute(name);
6114
+ }
6115
+ if (value == null) {
6116
+ if (elm.hasAttribute(name)) {
6117
+ elm.removeAttribute(name);
6118
+ }
6119
+ return;
6120
+ }
6121
+ elm.setAttribute(name, value);
6122
+ }
6079
6123
 
6080
6124
  /*!
6081
6125
  * Jodit Editor (https://xdsoft.net/jodit/)
@@ -6643,56 +6687,39 @@ class Dom {
6643
6687
  * Get first matched node inside root
6644
6688
  */
6645
6689
  static first(root, condition) {
6646
- let first = root === null || root === void 0 ? void 0 : root.firstChild;
6647
- if (!first) {
6648
- return null;
6649
- }
6650
- do {
6651
- if (condition(first)) {
6652
- return first;
6653
- }
6654
- let next = first.firstChild;
6655
- if (!next) {
6656
- next = first.nextSibling;
6657
- }
6658
- if (!next && first.parentNode !== root) {
6659
- do {
6660
- first = first.parentNode;
6661
- } while (first &&
6662
- !(first === null || first === void 0 ? void 0 : first.nextSibling) &&
6663
- first.parentNode !== root);
6664
- next = first === null || first === void 0 ? void 0 : first.nextSibling;
6665
- }
6666
- first = next;
6667
- } while (first);
6668
- return null;
6690
+ return Dom.__deepMost(root, condition, false);
6669
6691
  }
6670
6692
  /**
6671
6693
  * Get last matched node inside root
6672
6694
  */
6673
6695
  static last(root, condition) {
6674
- let last = root === null || root === void 0 ? void 0 : root.lastChild;
6675
- if (!last) {
6696
+ return Dom.__deepMost(root, condition, true);
6697
+ }
6698
+ /**
6699
+ * Depth-first search for the first matched node inside root:
6700
+ * in document order (`reverse = false`) or in reverse order
6701
+ */
6702
+ static __deepMost(root, condition, reverse) {
6703
+ const child = reverse ? 'lastChild' : 'firstChild', sibling = reverse ? 'previousSibling' : 'nextSibling';
6704
+ let current = root === null || root === void 0 ? void 0 : root[child];
6705
+ if (!current) {
6676
6706
  return null;
6677
6707
  }
6678
6708
  do {
6679
- if (condition(last)) {
6680
- return last;
6681
- }
6682
- let next = last.lastChild;
6683
- if (!next) {
6684
- next = last.previousSibling;
6709
+ if (condition(current)) {
6710
+ return current;
6685
6711
  }
6686
- if (!next && last.parentNode !== root) {
6712
+ let next = current[child] || current[sibling];
6713
+ if (!next && current.parentNode !== root) {
6687
6714
  do {
6688
- last = last.parentNode;
6689
- } while (last &&
6690
- !(last === null || last === void 0 ? void 0 : last.previousSibling) &&
6691
- last.parentNode !== root);
6692
- next = last === null || last === void 0 ? void 0 : last.previousSibling;
6693
- }
6694
- last = next;
6695
- } while (last);
6715
+ current = current.parentNode;
6716
+ } while (current &&
6717
+ !current[sibling] &&
6718
+ current.parentNode !== root);
6719
+ next = current === null || current === void 0 ? void 0 : current[sibling];
6720
+ }
6721
+ current = next;
6722
+ } while (current);
6696
6723
  return null;
6697
6724
  }
6698
6725
  /**
@@ -6708,12 +6735,17 @@ class Dom {
6708
6735
  return Dom.find(node, condition, root, true, withChild);
6709
6736
  }
6710
6737
  static prevWithClass(node, className) {
6711
- return Dom.prev(node, node => {
6712
- return (Dom.isElement(node) && node.classList.contains(className));
6713
- }, node.parentNode);
6738
+ return Dom.__siblingWithClass(node, className, true);
6714
6739
  }
6715
6740
  static nextWithClass(node, className) {
6716
- return Dom.next(node, elm => Dom.isElement(elm) && elm.classList.contains(className), node.parentNode);
6741
+ return Dom.__siblingWithClass(node, className, false);
6742
+ }
6743
+ static __siblingWithClass(node, className, left) {
6744
+ const condition = (elm) => Dom.isElement(elm) && elm.classList.contains(className);
6745
+ const parent = node.parentNode;
6746
+ return (left
6747
+ ? Dom.prev(node, condition, parent)
6748
+ : Dom.next(node, condition, parent));
6717
6749
  }
6718
6750
  /**
6719
6751
  * Find next/prev node what `condition(next) === true`
@@ -6848,9 +6880,6 @@ class Dom {
6848
6880
  (!(Dom.isText(n) || Dom.isComment(n)) ||
6849
6881
  trim((n === null || n === void 0 ? void 0 : n.nodeValue) || '').length)), root);
6850
6882
  }
6851
- /**
6852
- * Returns the previous (`left = true`) or next sibling of the node
6853
- */
6854
6883
  static sibling(node, left) {
6855
6884
  return left ? node.previousSibling : node.nextSibling;
6856
6885
  }
@@ -6914,40 +6943,24 @@ class Dom {
6914
6943
  * Append new element in the start of root
6915
6944
  */
6916
6945
  static appendChildFirst(root, newElement) {
6917
- const child = root.firstChild;
6918
- if (child) {
6919
- if (child !== newElement) {
6920
- root.insertBefore(newElement, child);
6921
- }
6922
- }
6923
- else {
6924
- root.appendChild(newElement);
6946
+ if (root.firstChild !== newElement) {
6947
+ Dom.prepend(root, newElement);
6925
6948
  }
6926
6949
  }
6927
6950
  /**
6928
6951
  * Insert newElement after element
6929
6952
  */
6930
6953
  static after(elm, newElement) {
6931
- const { parentNode } = elm;
6932
- if (!parentNode) {
6933
- return;
6934
- }
6935
- if (parentNode.lastChild === elm) {
6936
- parentNode.appendChild(newElement);
6937
- }
6938
- else {
6939
- parentNode.insertBefore(newElement, elm.nextSibling);
6940
- }
6954
+ var _a;
6955
+ // `insertBefore` with a `null` reference appends to the end
6956
+ (_a = elm.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(newElement, elm.nextSibling);
6941
6957
  }
6942
6958
  /**
6943
6959
  * Insert newElement before element
6944
6960
  */
6945
6961
  static before(elm, newElement) {
6946
- const { parentNode } = elm;
6947
- if (!parentNode) {
6948
- return;
6949
- }
6950
- parentNode.insertBefore(newElement, elm);
6962
+ var _a;
6963
+ (_a = elm.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(newElement, elm);
6951
6964
  }
6952
6965
  /**
6953
6966
  * Insert newElement as first child inside element
@@ -6965,10 +6978,10 @@ class Dom {
6965
6978
  root.appendChild(newElement);
6966
6979
  }
6967
6980
  }
6968
- /**
6969
- * Move all content to another element
6970
- */
6971
- static moveContent(from, to, inStart = false, filter = () => true) {
6981
+ static moveContent(from, to, inStart = false,
6982
+ // `any` reconciles the browser `Node` overload with the `VNode` one:
6983
+ // a callback typed for one is not assignable to the other
6984
+ filter = () => true) {
6972
6985
  const fragment = (from.ownerDocument || globalDocument).createDocumentFragment();
6973
6986
  toArray(from.childNodes)
6974
6987
  .filter(elm => {
@@ -6978,15 +6991,11 @@ class Dom {
6978
6991
  Dom.safeRemove(elm);
6979
6992
  return false;
6980
6993
  })
6981
- .forEach((node) => {
6994
+ .forEach(node => {
6982
6995
  fragment.appendChild(node);
6983
6996
  });
6984
- if (!inStart || !to.firstChild) {
6985
- to.appendChild(fragment);
6986
- }
6987
- else {
6988
- to.insertBefore(fragment, to.firstChild);
6989
- }
6997
+ // `appendChild`/`insertBefore` with a `null` reference append to the end
6998
+ to.insertBefore(fragment, inStart ? to.firstChild : null);
6990
6999
  }
6991
7000
  /**
6992
7001
  * Check root contains child or equal child
@@ -7036,8 +7045,8 @@ class Dom {
7036
7045
  if (!node) {
7037
7046
  return;
7038
7047
  }
7039
- dataBind(node, '__old_display', node.style.display);
7040
- node.style.display = 'none';
7048
+ dataBind(node, '__old_display', node.style.getPropertyValue('display'));
7049
+ node.style.setProperty('display', 'none');
7041
7050
  }
7042
7051
  /**
7043
7052
  * Show element
@@ -7047,8 +7056,8 @@ class Dom {
7047
7056
  return;
7048
7057
  }
7049
7058
  const display = dataBind(node, '__old_display');
7050
- if (node.style.display === 'none') {
7051
- node.style.display = display || '';
7059
+ if (node.style.getPropertyValue('display') === 'none') {
7060
+ node.style.setProperty('display', display || null);
7052
7061
  }
7053
7062
  }
7054
7063
  static isTag(node, tagNames) {
@@ -7097,11 +7106,17 @@ class Dom {
7097
7106
  return value.replace(TEMP_ELEMENT_REG_EXP, '$2');
7098
7107
  }
7099
7108
  /**
7100
- * Get temporary list
7101
- * @deprecated Just do not use it, it is not needed anymore
7109
+ * Collect the temporary elements (`data-jodit-temp`) inside the root.
7110
+ * A plain tree walk on purpose: no selector engine, works on VNode.
7102
7111
  */
7103
7112
  static temporaryList(root) {
7104
- return toArray(root.querySelectorAll(`[${TEMP_ATTR}]`));
7113
+ const result = [];
7114
+ Dom.each(root, node => {
7115
+ if (Dom.isHTMLElement(node) && node.hasAttribute(TEMP_ATTR)) {
7116
+ result.push(node);
7117
+ }
7118
+ });
7119
+ return result;
7105
7120
  }
7106
7121
  }
7107
7122
 
@@ -7493,21 +7508,39 @@ function cache(_, name, descriptor) {
7493
7508
  return value;
7494
7509
  };
7495
7510
  }
7511
+ function getOwnerDocument(component) {
7512
+ const od = component.od;
7513
+ return od !== null && od !== void 0 ? od : document;
7514
+ }
7496
7515
  function cacheHTML(target, _, descriptor) {
7497
7516
  const fn = descriptor.value;
7498
7517
  if (!isFunction(fn)) {
7499
7518
  throw error('Handler must be a Function');
7500
7519
  }
7501
7520
  let useCache = true;
7521
+ /**
7522
+ * The cache is keyed by the owner document first and only then by the
7523
+ * component class. A page can create editors inside different documents
7524
+ * (iframes) and destroy those documents later: a template cached from a
7525
+ * dead document would otherwise be cloned for every subsequent editor,
7526
+ * whose buttons then never react to clicks.
7527
+ */
7502
7528
  const cached = new WeakMap();
7503
7529
  descriptor.value = function (...attrs) {
7504
7530
  var _a;
7505
- if (useCache && cached.has(this.constructor)) {
7506
- return (_a = cached.get(this.constructor)) === null || _a === void 0 ? void 0 : _a.cloneNode(true);
7531
+ const doc = getOwnerDocument(this);
7532
+ const docCache = cached.get(doc);
7533
+ if (useCache && (docCache === null || docCache === void 0 ? void 0 : docCache.has(this.constructor))) {
7534
+ return (_a = docCache.get(this.constructor)) === null || _a === void 0 ? void 0 : _a.cloneNode(true);
7507
7535
  }
7508
7536
  const value = fn.apply(this, attrs);
7509
7537
  if (useCache && Dom.isElement(value)) {
7510
- cached.set(this.constructor, value);
7538
+ if (docCache) {
7539
+ docCache.set(this.constructor, value);
7540
+ }
7541
+ else {
7542
+ cached.set(doc, new WeakMap([[this.constructor, value]]));
7543
+ }
7511
7544
  }
7512
7545
  return useCache ? value.cloneNode(true) : value;
7513
7546
  };
@@ -8543,10 +8576,10 @@ const appendScriptAsync = cacheLoaders((jodit, url) => {
8543
8576
  src: completeUrl(url)
8544
8577
  });
8545
8578
  if (jodit.o.nonce) {
8546
- script.setAttribute('nonce', jodit.o.nonce);
8579
+ attr(script, 'nonce', jodit.o.nonce);
8547
8580
  }
8548
8581
  jodit.e.one(script, 'error', reject).one(script, 'load', resolve);
8549
- jodit.od.body.appendChild(script);
8582
+ Dom.append(jodit.od.body, script);
8550
8583
  });
8551
8584
  });
8552
8585
  /**
@@ -8557,22 +8590,23 @@ const appendStyleAsync = cacheLoaders((jodit, url) => {
8557
8590
  if (jodit.isInDestruct) {
8558
8591
  return reject();
8559
8592
  }
8560
- const link = jodit.c.element('link');
8561
- link.rel = 'stylesheet';
8562
- link.media = 'all';
8563
- link.crossOrigin = 'anonymous';
8593
+ const link = jodit.c.element('link', {
8594
+ rel: 'stylesheet',
8595
+ media: 'all',
8596
+ crossorigin: 'anonymous'
8597
+ });
8564
8598
  if (jodit.o.nonce) {
8565
- link.setAttribute('nonce', jodit.o.nonce);
8599
+ attr(link, 'nonce', jodit.o.nonce);
8566
8600
  }
8567
8601
  const callback = () => resolve(link);
8568
8602
  !jodit.isInDestruct &&
8569
8603
  jodit.e.on(link, 'load', callback).on(link, 'error', reject);
8570
- link.href = completeUrl(url);
8604
+ attr(link, 'href', completeUrl(url));
8571
8605
  if (jodit.o.shadowRoot) {
8572
- jodit.o.shadowRoot.appendChild(link);
8606
+ Dom.append(jodit.o.shadowRoot, link);
8573
8607
  }
8574
8608
  else {
8575
- jodit.od.body.appendChild(link);
8609
+ Dom.append(jodit.od.body, link);
8576
8610
  }
8577
8611
  });
8578
8612
  });
@@ -9106,10 +9140,10 @@ function getContainer(jodit, classFunc, tag = 'div', createInsideEditor = false)
9106
9140
  });
9107
9141
  // Let a strict CSP accept the injected <style>/<script> box
9108
9142
  if (view.o.nonce && (tag === 'style' || tag === 'script')) {
9109
- box.setAttribute('nonce', view.o.nonce);
9143
+ attr(box, 'nonce', view.o.nonce);
9110
9144
  }
9111
9145
  box.classList.add(`jodit_theme_${view.o.theme || 'default'}`);
9112
- body.appendChild(box);
9146
+ Dom.append(body, box);
9113
9147
  data[key] = box;
9114
9148
  jodit.hookStatus('beforeDestruct', () => {
9115
9149
  view.events.off(box);
@@ -9203,14 +9237,18 @@ const refs = (root) => {
9203
9237
  if ('container' in root) {
9204
9238
  root = root.container;
9205
9239
  }
9206
- return $$('[ref],[data-ref]', root).reduce((def, child) => {
9207
- const key = attr(child, '-ref');
9208
- if (key && isString(key)) {
9209
- def[camelCase(key)] = child;
9210
- def[key] = child;
9240
+ const def = {};
9241
+ Dom.each(root, child => {
9242
+ if (Dom.isElement(child) &&
9243
+ (child.hasAttribute('ref') || child.hasAttribute('data-ref'))) {
9244
+ const key = attr(child, '-ref');
9245
+ if (key && isString(key)) {
9246
+ def[camelCase(key)] = child;
9247
+ def[key] = child;
9248
+ }
9211
9249
  }
9212
- return def;
9213
- }, {});
9250
+ });
9251
+ return def;
9214
9252
  };
9215
9253
  /**
9216
9254
  * Calculate full CSS selector
@@ -9312,8 +9350,8 @@ function applyStyles(html) {
9312
9350
  html = html.substring(0, closeIndex + '</html>'.length);
9313
9351
  }
9314
9352
  const iframe = globalDocument.createElement('iframe');
9315
- iframe.style.display = 'none';
9316
- globalDocument.body.appendChild(iframe);
9353
+ css(iframe, 'display', 'none');
9354
+ Dom.append(globalDocument.body, iframe);
9317
9355
  let convertedString = '', collection = [];
9318
9356
  try {
9319
9357
  const iframeDoc = iframe.contentDocument ||
@@ -9329,7 +9367,7 @@ function applyStyles(html) {
9329
9367
  // style normalization strips the `mso-list` hint. See #948
9330
9368
  Dom.each(iframeDoc.body, (node) => {
9331
9369
  if (Dom.isElement(node) &&
9332
- /mso-list:\s*ignore/i.test(node.getAttribute('style') || '')) {
9370
+ /mso-list:\s*ignore/i.test(attr(node, 'style') || '')) {
9333
9371
  Dom.safeRemove(node);
9334
9372
  }
9335
9373
  });
@@ -9341,6 +9379,9 @@ function applyStyles(html) {
9341
9379
  continue;
9342
9380
  }
9343
9381
  collection = $$(rules[idx].selectorText, iframeDoc.body);
9382
+ // `style.cssText` on purpose: the CSSOM parses the text,
9383
+ // drops invalid declarations and re-serializes it. The raw
9384
+ // `style` attribute would keep Word-only junk verbatim
9344
9385
  collection.forEach((elm) => {
9345
9386
  elm.style.cssText = normalizeCSS(rules[idx].style.cssText +
9346
9387
  ';' +
@@ -9353,14 +9394,13 @@ function applyStyles(html) {
9353
9394
  }
9354
9395
  Dom.each(iframeDoc.body, node => {
9355
9396
  if (Dom.isElement(node)) {
9356
- const elm = node;
9357
- const css = elm.getAttribute('style');
9358
- if (css) {
9359
- elm.style.cssText = normalizeCSS(css);
9397
+ const cssText = attr(node, 'style');
9398
+ if (cssText) {
9399
+ node.style.cssText =
9400
+ normalizeCSS(cssText);
9360
9401
  }
9361
- if (elm.hasAttribute('style') &&
9362
- !elm.getAttribute('style')) {
9363
- elm.removeAttribute('style');
9402
+ if (!attr(node, 'style')) {
9403
+ attr(node, 'style', null);
9364
9404
  }
9365
9405
  }
9366
9406
  });
@@ -9428,18 +9468,21 @@ function cleanFromWord(html) {
9428
9468
  // with `mso-list:Ignore`. They are display-only
9429
9469
  // and must not be imported, otherwise the marker
9430
9470
  // text leaks into the content. See #948
9431
- if (/mso-list:\s*ignore/i.test(node.getAttribute('style') || '')) {
9471
+ if (/mso-list:\s*ignore/i.test(attr(node, 'style') || '')) {
9432
9472
  marks.push(node);
9433
9473
  break;
9434
9474
  }
9435
- toArray(node.attributes).forEach((attr) => {
9475
+ toArray(node.attributes).forEach((attribute) => {
9436
9476
  if ([
9437
9477
  'src',
9438
9478
  'href',
9439
9479
  'rel',
9440
9480
  'content'
9441
- ].indexOf(attr.name.toLowerCase()) === -1) {
9442
- node.removeAttribute(attr.name);
9481
+ ].indexOf(attribute.name.toLowerCase()) === -1) {
9482
+ // `attrRaw`: SVG keeps camelCase names
9483
+ // (`viewBox`), `attr()` would kebab-case
9484
+ // them and silently skip the removal
9485
+ attrRaw(node, attribute.name, null);
9443
9486
  }
9444
9487
  });
9445
9488
  }
@@ -9533,10 +9576,10 @@ function hAlignElement(image, align) {
9533
9576
  function clearAlign(node) {
9534
9577
  Dom.each(node, elm => {
9535
9578
  if (Dom.isHTMLElement(elm)) {
9536
- if (elm.style.textAlign) {
9537
- elm.style.textAlign = '';
9538
- if (!elm.style.cssText.trim().length) {
9539
- elm.removeAttribute('style');
9579
+ if (cssInline(elm, 'textAlign')) {
9580
+ css(elm, 'textAlign', '');
9581
+ if (!(attr(elm, 'style') || '').trim().length) {
9582
+ attr(elm, 'style', null);
9540
9583
  }
9541
9584
  }
9542
9585
  }
@@ -9545,22 +9588,18 @@ function clearAlign(node) {
9545
9588
  /**
9546
9589
  * Apply align for element
9547
9590
  */
9591
+ const ALIGN_BY_COMMAND = new Map([
9592
+ ['justifyfull', 'justify'],
9593
+ ['justifyright', 'right'],
9594
+ ['justifyleft', 'left'],
9595
+ ['justifycenter', 'center']
9596
+ ]);
9548
9597
  function alignElement(command, box) {
9549
9598
  if (Dom.isNode(box) && Dom.isElement(box)) {
9550
9599
  clearAlign(box);
9551
- switch (command.toLowerCase()) {
9552
- case 'justifyfull':
9553
- box.style.textAlign = 'justify';
9554
- break;
9555
- case 'justifyright':
9556
- box.style.textAlign = 'right';
9557
- break;
9558
- case 'justifyleft':
9559
- box.style.textAlign = 'left';
9560
- break;
9561
- case 'justifycenter':
9562
- box.style.textAlign = 'center';
9563
- break;
9600
+ const align = ALIGN_BY_COMMAND.get(command.toLowerCase());
9601
+ if (align) {
9602
+ css(box, 'textAlign', align);
9564
9603
  }
9565
9604
  }
9566
9605
  }
@@ -11095,26 +11134,30 @@ function markDeprecated(method, names = [''], ctx = null) {
11095
11134
  */
11096
11135
  function fixedAssetsSizeAndAbsoluteLinks(editor, points) {
11097
11136
  const restoreAttributes = [];
11137
+ const images = [];
11138
+ Dom.each(editor.editor, node => {
11139
+ Dom.isTag(node, 'img') && images.push(node);
11140
+ });
11098
11141
  try {
11099
- $$('img', editor.editor).forEach(item => {
11142
+ images.forEach(item => {
11100
11143
  const previousAttrs = [
11101
11144
  attr(item, 'width'),
11102
11145
  attr(item, 'height'),
11103
- item.src
11146
+ attr(item, 'src')
11104
11147
  ];
11105
11148
  attr(item, {
11106
11149
  width: item.offsetWidth + points,
11107
11150
  height: item.offsetHeight + points
11108
11151
  });
11109
11152
  const a = editor.createInside.a();
11110
- editor.ed.body.appendChild(a);
11111
- a.href = item.src;
11112
- item.src = a.href;
11153
+ Dom.append(editor.ed.body, a);
11154
+ attr(a, 'href', attr(item, 'src') || '');
11155
+ // reading the `href` property resolves the URL to an absolute one
11156
+ attr(item, 'src', a.href);
11113
11157
  Dom.safeRemove(a);
11114
11158
  restoreAttributes.push(() => {
11115
- var _a;
11116
- item.src = (_a = previousAttrs[2]) !== null && _a !== void 0 ? _a : '';
11117
11159
  attr(item, {
11160
+ src: previousAttrs[2],
11118
11161
  width: previousAttrs[0] || null,
11119
11162
  height: previousAttrs[1] || null
11120
11163
  });
@@ -11144,7 +11187,7 @@ function previewBox(editor, defaultValue, points = 'px', container = null) {
11144
11187
  }
11145
11188
  let div = editor.c.div('jodit__preview-box jodit-context');
11146
11189
  if (container) {
11147
- container.appendChild(div);
11190
+ Dom.append(container, div);
11148
11191
  }
11149
11192
  css(div, {
11150
11193
  position: 'relative',
@@ -11159,7 +11202,7 @@ function previewBox(editor, defaultValue, points = 'px', container = null) {
11159
11202
  minHeight: 600,
11160
11203
  border: 0
11161
11204
  });
11162
- div.appendChild(iframe);
11205
+ Dom.append(div, iframe);
11163
11206
  const myWindow = iframe.contentWindow;
11164
11207
  if (myWindow) {
11165
11208
  editor.e.fire('generateDocumentStructure.iframe', myWindow.document, editor);
@@ -11169,7 +11212,7 @@ function previewBox(editor, defaultValue, points = 'px', container = null) {
11169
11212
  const elm = myWindow.document.body;
11170
11213
  const resizeObserver = new ResizeObserver(editor.async.debounce(() => {
11171
11214
  resizeObserver.unobserve(elm);
11172
- iframe.style.height = `${elm.offsetHeight + 20}px`;
11215
+ css(iframe, 'height', elm.offsetHeight + 20);
11173
11216
  editor.async.requestAnimationFrame(() => {
11174
11217
  !destructed && resizeObserver.observe(elm);
11175
11218
  });
@@ -11202,7 +11245,7 @@ function previewBox(editor, defaultValue, points = 'px', container = null) {
11202
11245
  if (Dom.isElement(c)) {
11203
11246
  const newNode = box.ownerDocument.createElement(c.nodeName);
11204
11247
  for (let j = 0; j < c.attributes.length; j += 1) {
11205
- attr(newNode, c.attributes[j].nodeName, c.attributes[j].nodeValue);
11248
+ attr(newNode, c.attributes[j].name, c.attributes[j].value);
11206
11249
  }
11207
11250
  if (c.childNodes.length === 0 || Dom.isTag(c, 'table')) {
11208
11251
  switch (c.nodeName) {
@@ -11222,13 +11265,13 @@ function previewBox(editor, defaultValue, points = 'px', container = null) {
11222
11265
  setHTML(newNode, c);
11223
11266
  }
11224
11267
  try {
11225
- box.appendChild(newNode);
11268
+ Dom.append(box, newNode);
11226
11269
  }
11227
11270
  catch (_a) { }
11228
11271
  }
11229
11272
  else {
11230
11273
  try {
11231
- box.appendChild(c.cloneNode(true));
11274
+ Dom.append(box, c.cloneNode(true));
11232
11275
  }
11233
11276
  catch (_b) { }
11234
11277
  }
@@ -11388,9 +11431,6 @@ class LimitedStack {
11388
11431
  * Released under MIT see LICENSE.txt in the project root for license information.
11389
11432
  * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
11390
11433
  */
11391
- /**
11392
- * @module helpers/html
11393
- */
11394
11434
  const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
11395
11435
  /**
11396
11436
  * Integration points where HTML is legitimately allowed inside MathML/SVG foreign content.
@@ -11406,9 +11446,10 @@ const HTML_INTEGRATION_POINTS = new Set([
11406
11446
  * HTML (e.g. `mglyph` / `style` under `<math>`) that a reparse can hoist into a live node. Legitimate
11407
11447
  * MathML/SVG children and HTML below an integration point are kept.
11408
11448
  */
11449
+ const isMathOrSvg = (node) => Boolean(node && /^(math|svg)$/i.test(node.nodeName));
11409
11450
  function isSmuggledForeignHtml(elm) {
11410
11451
  if (elm.namespaceURI !== HTML_NAMESPACE ||
11411
- elm.closest('math,svg') == null) {
11452
+ Dom.up(elm, isMathOrSvg) == null) {
11412
11453
  return false;
11413
11454
  }
11414
11455
  for (let parent = elm.parentElement; parent; parent = parent.parentElement) {
@@ -11431,11 +11472,17 @@ function safeHTML(box, options) {
11431
11472
  return;
11432
11473
  }
11433
11474
  // Drop HTML smuggled into MathML/SVG before the walk: a reparse would otherwise hoist its hidden
11434
- // markup into a live node.
11435
- const foreign = box.querySelectorAll('math *, svg *');
11436
- for (let i = 0; i < foreign.length; i++) {
11437
- if (box.contains(foreign[i]) && isSmuggledForeignHtml(foreign[i])) {
11438
- Dom.safeRemove(foreign[i]);
11475
+ // markup into a live node. Collect the candidates first (like the static
11476
+ // `querySelectorAll` snapshot did) so removals don't affect the traversal.
11477
+ const foreign = [];
11478
+ Dom.each(box, node => {
11479
+ if (Dom.isElement(node) && Dom.up(node.parentNode, isMathOrSvg)) {
11480
+ foreign.push(node);
11481
+ }
11482
+ });
11483
+ for (const elm of foreign) {
11484
+ if (Dom.isOrContains(box, elm) && isSmuggledForeignHtml(elm)) {
11485
+ Dom.safeRemove(elm);
11439
11486
  }
11440
11487
  }
11441
11488
  const removeEvents = (_a = options.removeEventAttributes) !== null && _a !== void 0 ? _a : options.removeOnError;
@@ -11453,8 +11500,8 @@ function safeHTML(box, options) {
11453
11500
  sanitizeHTMLElement(node, options);
11454
11501
  if (options.safeLinksTarget &&
11455
11502
  node.nodeName === 'A' &&
11456
- node.getAttribute('target') === '_blank') {
11457
- const rel = node.getAttribute('rel') || '';
11503
+ attr(node, 'target') === '_blank') {
11504
+ const rel = attr(node, 'rel') || '';
11458
11505
  const parts = rel.split(/\s+/).filter(Boolean);
11459
11506
  if (!parts.includes('noopener')) {
11460
11507
  parts.push('noopener');
@@ -11483,7 +11530,9 @@ function removeAllEventAttributes(elm) {
11483
11530
  }
11484
11531
  }
11485
11532
  for (const name of toRemove) {
11486
- elm.removeAttribute(name);
11533
+ // `attrRaw` on purpose: `attr()` kebab-cases the key
11534
+ // (`onLoad` → `on-load`), which must not happen in a sanitizer
11535
+ attrRaw(elm, name, null);
11487
11536
  effected = true;
11488
11537
  }
11489
11538
  return effected;
@@ -11534,7 +11583,7 @@ function sanitizeHTMLElement(elm, { safeJavaScriptLink, removeOnError } = {
11534
11583
  effected = true;
11535
11584
  }
11536
11585
  const tagName = elm.nodeName.toLowerCase();
11537
- const href = elm.getAttribute('href');
11586
+ const href = attr(elm, 'href');
11538
11587
  // Neutralize executable-scheme `href`s with the same normalization used for
11539
11588
  // every other URL attribute (`isDangerousUrl`), which strips control bytes,
11540
11589
  // tabs and newlines and lowercases before matching the scheme. The previous
@@ -11554,8 +11603,10 @@ function sanitizeHTMLElement(elm, { safeJavaScriptLink, removeOnError } = {
11554
11603
  effected = true;
11555
11604
  }
11556
11605
  // Strip executable schemes from any other URL-bearing attribute.
11606
+ // `attrRaw`: the list contains `xlink:href` and the sanitizer must
11607
+ // read exactly the attribute it will remove.
11557
11608
  for (const name of URL_ATTRIBUTES) {
11558
- const value = elm.getAttribute(name);
11609
+ const value = attrRaw(elm, name);
11559
11610
  if (value && isDangerousUrl(value, tagName)) {
11560
11611
  attr(elm, name, null);
11561
11612
  effected = true;
@@ -11593,9 +11644,15 @@ function stripTags(html, doc = document, exclude = null, blockBr = false) {
11593
11644
  tmp.innerHTML = html;
11594
11645
  }
11595
11646
  else {
11596
- tmp.appendChild(html);
11647
+ Dom.append(tmp, html);
11597
11648
  }
11598
- $$('*', tmp).forEach(p => {
11649
+ // Snapshot of all elements (like `querySelectorAll('*')` did) the loop
11650
+ // below removes and unwraps nodes while iterating
11651
+ const all = [];
11652
+ Dom.each(tmp, node => {
11653
+ Dom.isElement(node) && all.push(node);
11654
+ });
11655
+ all.forEach(p => {
11599
11656
  const pr = p.parentNode;
11600
11657
  if (!pr) {
11601
11658
  return;
@@ -11625,7 +11682,7 @@ function stripTags(html, doc = document, exclude = null, blockBr = false) {
11625
11682
  // plain text). When `blockBr` is set, separate them with a line
11626
11683
  // break instead, so paragraph structure survives — e.g. the
11627
11684
  // "Insert only Text" paste option. See #1232
11628
- pr.insertBefore(doc.createTextNode(blockBr ? '%%%jodit-single-br%%%' : ' '), nx);
11685
+ Dom.before(nx, doc.createTextNode(blockBr ? '%%%jodit-single-br%%%' : ' '));
11629
11686
  }
11630
11687
  });
11631
11688
  return restoreTags(trim(tmp.innerText));
@@ -12201,6 +12258,7 @@ var index = /*#__PURE__*/Object.freeze({
12201
12258
  asArray: asArray,
12202
12259
  assert: assert,
12203
12260
  attr: attr,
12261
+ attrRaw: attrRaw,
12204
12262
  browser: browser,
12205
12263
  buildQuery: buildQuery,
12206
12264
  call: call,
@@ -12217,6 +12275,7 @@ var index = /*#__PURE__*/Object.freeze({
12217
12275
  connection: connection,
12218
12276
  convertMediaUrlToVideoEmbed: convertMediaUrlToVideoEmbed,
12219
12277
  css: css,
12278
+ cssInline: cssInline,
12220
12279
  cssPath: cssPath,
12221
12280
  ctrlKey: ctrlKey,
12222
12281
  dataBind: dataBind,
@@ -13329,13 +13388,21 @@ class Elms {
13329
13388
  * Return element with BEM class name
13330
13389
  */
13331
13390
  getElm(elementName) {
13332
- return this.container.querySelector(`.${this.getFullElName(elementName)}`);
13391
+ const className = this.getFullElName(elementName);
13392
+ return Dom.first(this.container, node => Dom.isHTMLElement(node) && node.classList.contains(className));
13333
13393
  }
13334
13394
  /**
13335
13395
  * Return elements with BEM class name
13336
13396
  */
13337
13397
  getElms(elementName) {
13338
- return toArray(this.container.querySelectorAll(`.${this.getFullElName(elementName)}`));
13398
+ const className = this.getFullElName(elementName);
13399
+ const result = [];
13400
+ Dom.each(this.container, node => {
13401
+ if (Dom.isHTMLElement(node) && node.classList.contains(className)) {
13402
+ result.push(node);
13403
+ }
13404
+ });
13405
+ return result;
13339
13406
  }
13340
13407
  }
13341
13408
 
@@ -13452,9 +13519,9 @@ class Icon {
13452
13519
  }
13453
13520
  if (iconElement) {
13454
13521
  iconElement.classList.add('jodit-icon');
13455
- iconElement.style.fill = fill;
13522
+ css(iconElement, 'fill', fill);
13456
13523
  if (scale != null) {
13457
- iconElement.style.transform = `scale(${scale})`;
13524
+ css(iconElement, 'transform', `scale(${scale})`);
13458
13525
  }
13459
13526
  jodit.o.cache &&
13460
13527
  this.__cache.set(cacheKey, iconElement.cloneNode(true));
@@ -13572,7 +13639,7 @@ let UIElement = UIElement_1 = class UIElement extends ViewComponent {
13572
13639
  * Append container to element
13573
13640
  */
13574
13641
  appendTo(element) {
13575
- element.appendChild(this.container);
13642
+ Dom.append(element, this.container);
13576
13643
  return this;
13577
13644
  }
13578
13645
  /**
@@ -13763,7 +13830,7 @@ let UIButton = class UIButton extends UIElement {
13763
13830
  }
13764
13831
  Dom.detach(this.icon);
13765
13832
  const iconElement = Icon.makeIcon(this.j, this.state.icon);
13766
- iconElement && this.icon.appendChild(iconElement);
13833
+ iconElement && Dom.append(this.icon, iconElement);
13767
13834
  }
13768
13835
  /**
13769
13836
  * Set focus on an element
@@ -13789,8 +13856,8 @@ let UIButton = class UIButton extends UIElement {
13789
13856
  });
13790
13857
  const icon = this.j.c.span(cn + '__icon');
13791
13858
  const text = this.j.c.span(cn + '__text');
13792
- button.appendChild(icon);
13793
- button.appendChild(text);
13859
+ Dom.append(button, icon);
13860
+ Dom.append(button, text);
13794
13861
  return button;
13795
13862
  }
13796
13863
  constructor(jodit, state) {
@@ -13985,7 +14052,7 @@ let UIGroup = UIGroup_1 = class UIGroup extends UIElement {
13985
14052
  if (distElm == null) {
13986
14053
  throw new Error('Element does not exist');
13987
14054
  }
13988
- distElm.appendChild(elm.container);
14055
+ Dom.append(distElm, elm.container);
13989
14056
  }
13990
14057
  else {
13991
14058
  this.appendChildToContainer(elm.container, index);
@@ -14003,14 +14070,14 @@ let UIGroup = UIGroup_1 = class UIGroup extends UIElement {
14003
14070
  * Allow set another container for the box of all children
14004
14071
  */
14005
14072
  appendChildToContainer(childContainer, index) {
14006
- if (index === undefined ||
14007
- index < 0 ||
14008
- index > this.elements.length - 1 ||
14009
- this.container.children[index] == null) {
14010
- this.container.appendChild(childContainer);
14073
+ const ref = index === undefined || index < 0 || index > this.elements.length - 1
14074
+ ? null
14075
+ : this.container.children[index];
14076
+ if (ref == null) {
14077
+ Dom.append(this.container, childContainer);
14011
14078
  }
14012
14079
  else {
14013
- this.container.insertBefore(childContainer, this.container.children[index]);
14080
+ Dom.before(ref, childContainer);
14014
14081
  }
14015
14082
  }
14016
14083
  /**
@@ -14099,7 +14166,7 @@ let UIButtonGroup = class UIButtonGroup extends UIGroup {
14099
14166
  appendChildToContainer(childContainer) {
14100
14167
  const options = this.getElm('options');
14101
14168
  assert(options != null, 'Options does not exist');
14102
- options.appendChild(childContainer);
14169
+ Dom.append(options, childContainer);
14103
14170
  }
14104
14171
  constructor(jodit, options = {
14105
14172
  radio: true
@@ -14201,7 +14268,7 @@ let UITooltip = UITooltip_1 = class UITooltip extends UIElement {
14201
14268
  }
14202
14269
  __onAttach(container) {
14203
14270
  // TODO Move it inside __show method. Now it is here because testcase failed with capturing
14204
- getContainer(this.j, UITooltip_1).appendChild(this.container);
14271
+ Dom.append(getContainer(this.j, UITooltip_1), this.container);
14205
14272
  this.__attachedContainers.add(container);
14206
14273
  this.__attachedContainers.add(this.j.container);
14207
14274
  this.j.e
@@ -14311,7 +14378,7 @@ let UITooltip = UITooltip_1 = class UITooltip extends UIElement {
14311
14378
  if (this.__isOpened) {
14312
14379
  this.__isOpened = false;
14313
14380
  this.setMod('visible', false);
14314
- this.getElm('content').innerHTML = '';
14381
+ Dom.detach(this.getElm('content'));
14315
14382
  css(this.container, {
14316
14383
  left: -5e3
14317
14384
  });
@@ -14515,7 +14582,7 @@ let UIInput = UIInput_1 = class UIInput extends UIElement {
14515
14582
  }
14516
14583
  else {
14517
14584
  this.__errorBox.innerText = this.j.i18n(value, this.j.i18n(this.state.label || ''));
14518
- this.container.appendChild(this.__errorBox);
14585
+ Dom.append(this.container, this.__errorBox);
14519
14586
  }
14520
14587
  }
14521
14588
  get value() {
@@ -14557,11 +14624,11 @@ let UIInput = UIInput_1 = class UIInput extends UIElement {
14557
14624
  __markInputInvalid() {
14558
14625
  var _a, _b, _c, _d;
14559
14626
  if (this.error) {
14560
- this.nativeInput.setAttribute('aria-invalid', 'true');
14627
+ attr(this.nativeInput, 'aria-invalid', 'true');
14561
14628
  (_b = (_a = this.nativeInput).setCustomValidity) === null || _b === void 0 ? void 0 : _b.call(_a, this.error);
14562
14629
  }
14563
14630
  else {
14564
- this.nativeInput.removeAttribute('aria-invalid');
14631
+ attr(this.nativeInput, 'aria-invalid', null);
14565
14632
  (_d = (_c = this.nativeInput).setCustomValidity) === null || _d === void 0 ? void 0 : _d.call(_c, '');
14566
14633
  }
14567
14634
  }
@@ -14574,8 +14641,8 @@ let UIInput = UIInput_1 = class UIInput extends UIElement {
14574
14641
  }
14575
14642
  const { nativeInput } = this;
14576
14643
  nativeInput.classList.add(this.getFullElName('input'));
14577
- this.wrapper.appendChild(nativeInput);
14578
- container.appendChild(this.wrapper);
14644
+ Dom.append(this.wrapper, nativeInput);
14645
+ Dom.append(container, this.wrapper);
14579
14646
  attr(nativeInput, 'dir', this.j.o.direction || 'auto');
14580
14647
  return container;
14581
14648
  }
@@ -14852,12 +14919,12 @@ let UITextArea = UITextArea_1 = class UITextArea extends UIInput {
14852
14919
  this.state = { ...UITextArea_1.defaultState };
14853
14920
  Object.assign(this.state, state);
14854
14921
  if (this.state.resizable === false) {
14855
- this.nativeInput.style.resize = 'none';
14922
+ css(this.nativeInput, 'resize', 'none');
14856
14923
  }
14857
14924
  }
14858
14925
  onChangeStateSize() {
14859
14926
  const { size, resizable } = this.state;
14860
- this.nativeInput.style.resize = resizable ? 'auto' : 'none';
14927
+ css(this.nativeInput, 'resize', resizable ? 'auto' : 'none');
14861
14928
  this.nativeInput.rows = size !== null && size !== void 0 ? size : 5;
14862
14929
  }
14863
14930
  };
@@ -14985,7 +15052,7 @@ let UIFileInput = class UIFileInput extends UIInput {
14985
15052
  const { nativeInput } = this;
14986
15053
  nativeInput.classList.add(this.getFullElName('input'));
14987
15054
  container.classList.add(this.componentName);
14988
- container.appendChild(nativeInput);
15055
+ Dom.append(container, nativeInput);
14989
15056
  return container;
14990
15057
  }
14991
15058
  createNativeInput(options) {
@@ -15343,7 +15410,7 @@ class Popup extends UIGroup {
15343
15410
  appendChildToContainer(childContainer) {
15344
15411
  const content = this.getElm('content');
15345
15412
  assert(content, 'Content element should exist');
15346
- content.appendChild(childContainer);
15413
+ Dom.append(content, childContainer);
15347
15414
  }
15348
15415
  updateParentElement(target) {
15349
15416
  if (target !== this && Component.isInstanceOf(target, Popup)) {
@@ -15393,12 +15460,12 @@ class Popup extends UIGroup {
15393
15460
  ? getBound
15394
15461
  : this.getKeepBound(getBound);
15395
15462
  if (parentContainer) {
15396
- parentContainer.appendChild(this.container);
15463
+ Dom.append(parentContainer, this.container);
15397
15464
  }
15398
15465
  else {
15399
15466
  const popupContainer = getContainer(this.jodit, Popup);
15400
15467
  if (parentContainer !== this.container.parentElement) {
15401
- popupContainer.appendChild(this.container);
15468
+ Dom.append(popupContainer, this.container);
15402
15469
  }
15403
15470
  }
15404
15471
  this.updatePosition();
@@ -15407,11 +15474,11 @@ class Popup extends UIGroup {
15407
15474
  return this;
15408
15475
  }
15409
15476
  __calculateZIndex() {
15410
- if (this.container.style.zIndex) {
15477
+ if (cssInline(this.container, 'zIndex')) {
15411
15478
  return;
15412
15479
  }
15413
15480
  const checkView = (view) => {
15414
- const zIndex = view.container.style.zIndex || view.o.zIndex;
15481
+ const zIndex = cssInline(view.container, 'zIndex') || view.o.zIndex;
15415
15482
  if (zIndex) {
15416
15483
  this.setZIndex(1 + parseInt(zIndex.toString(), 10));
15417
15484
  return true;
@@ -15427,8 +15494,9 @@ class Popup extends UIGroup {
15427
15494
  if (checkView(pe.j)) {
15428
15495
  return;
15429
15496
  }
15430
- if (pe.container.style.zIndex) {
15431
- this.setZIndex(1 + parseInt(pe.container.style.zIndex.toString(), 10));
15497
+ const parentZIndex = cssInline(pe.container, 'zIndex');
15498
+ if (parentZIndex) {
15499
+ this.setZIndex(1 + parseInt(parentZIndex.toString(), 10));
15432
15500
  return;
15433
15501
  }
15434
15502
  if (!pe.parentElement && pe.container.parentElement) {
@@ -15557,6 +15625,18 @@ class Popup extends UIGroup {
15557
15625
  this.j.e.fire(this, 'beforeClose');
15558
15626
  this.j.e.fire('beforePopupClose', this);
15559
15627
  this.__removeGlobalListeners();
15628
+ // Blur a focused control (e.g. the color picker hex input) before
15629
+ // the container goes away. Chrome fires `blur`/`change` for a
15630
+ // removed focused element in the middle of `removeChild`, Firefox
15631
+ // does not fire them at all. Blurring first makes both browsers
15632
+ // run those handlers while the popup is still in the DOM. See #1458
15633
+ const { activeElement } = this.od;
15634
+ if (activeElement &&
15635
+ activeElement !== this.container &&
15636
+ Dom.isOrContains(this.container, activeElement) &&
15637
+ isFunction(activeElement.blur)) {
15638
+ activeElement.blur();
15639
+ }
15560
15640
  Dom.safeRemove(this.container);
15561
15641
  return this;
15562
15642
  }
@@ -15620,7 +15700,7 @@ class Popup extends UIGroup {
15620
15700
  * Set ZIndex
15621
15701
  */
15622
15702
  setZIndex(index) {
15623
- this.container.style.zIndex = index.toString();
15703
+ css(this.container, 'zIndex', index.toString());
15624
15704
  }
15625
15705
  constructor(jodit, smart = true) {
15626
15706
  super(jodit);
@@ -15684,7 +15764,7 @@ class ProgressBar extends UIElement {
15684
15764
  */
15685
15765
  show() {
15686
15766
  const container = this.j.workplace || this.j.container;
15687
- container.appendChild(this.container);
15767
+ Dom.append(container, this.container);
15688
15768
  return this;
15689
15769
  }
15690
15770
  hide() {
@@ -15692,7 +15772,7 @@ class ProgressBar extends UIElement {
15692
15772
  return this;
15693
15773
  }
15694
15774
  progress(percentage) {
15695
- this.container.style.width = percentage.toFixed(2) + '%';
15775
+ css(this.container, 'width', percentage.toFixed(2) + '%');
15696
15776
  return this;
15697
15777
  }
15698
15778
  showFileUploadAnimation(from, to) {
@@ -15716,7 +15796,7 @@ class ProgressBar extends UIElement {
15716
15796
  left: pos.left + start.x,
15717
15797
  top: pos.top + start.y
15718
15798
  });
15719
- box.appendChild(el);
15799
+ Dom.append(box, el);
15720
15800
  this.__animationElement = el;
15721
15801
  css(el, {
15722
15802
  left: pos.left + end.x,
@@ -15769,7 +15849,7 @@ class Create {
15769
15849
  }
15770
15850
  }
15771
15851
  if (children) {
15772
- asArray(children).forEach((child) => elm.appendChild(isString(child) ? this.fromHTML(child) : child));
15852
+ asArray(children).forEach((child) => Dom.append(elm, isString(child) ? this.fromHTML(child) : child));
15773
15853
  }
15774
15854
  return elm;
15775
15855
  }
@@ -15783,7 +15863,7 @@ class Create {
15783
15863
  sandbox() {
15784
15864
  var _a;
15785
15865
  const iframe = this.element('iframe', { sandbox: 'allow-same-origin' });
15786
- this.doc.body.appendChild(iframe);
15866
+ Dom.append(this.doc.body, iframe);
15787
15867
  const doc = (_a = iframe.contentWindow) === null || _a === void 0 ? void 0 : _a.document;
15788
15868
  assert(doc, 'iframe.contentWindow.document');
15789
15869
  if (!doc) {
@@ -16432,7 +16512,7 @@ let UIMessages = class UIMessages extends UIGroup {
16432
16512
  if (!this.__box) {
16433
16513
  throw new Error('Container is not defined: ' + key);
16434
16514
  }
16435
- this.__box.appendChild(this.container);
16515
+ Dom.append(this.__box, this.container);
16436
16516
  const msg = new UIMessage(this.j, { text, variant });
16437
16517
  this.append(msg);
16438
16518
  this.__calcOffsets();
@@ -16704,7 +16784,7 @@ let View = View_1 = class View extends Component {
16704
16784
  }
16705
16785
  /** Add some element to box */
16706
16786
  addDisclaimer(elm) {
16707
- this.container.appendChild(elm);
16787
+ Dom.append(this.container, elm);
16708
16788
  }
16709
16789
  /**
16710
16790
  * Call before destruct
@@ -16869,7 +16949,7 @@ class ViewWithToolbar extends View {
16869
16949
  anchor = anchor.nextElementSibling;
16870
16950
  }
16871
16951
  if (anchor !== box) {
16872
- this.container.insertBefore(box, anchor);
16952
+ anchor ? Dom.before(anchor, box) : Dom.append(this.container, box);
16873
16953
  }
16874
16954
  }
16875
16955
  /**
@@ -17048,7 +17128,7 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
17048
17128
  if (isArray(elm)) {
17049
17129
  const div = this.c.div(this.getFullElName('column'));
17050
17130
  elements_list.push(div);
17051
- root.appendChild(div);
17131
+ Dom.append(root, div);
17052
17132
  return this.setElements(div, elm);
17053
17133
  }
17054
17134
  let element;
@@ -17060,12 +17140,12 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
17060
17140
  }
17061
17141
  elements_list.push(element);
17062
17142
  if (element.parentNode !== root) {
17063
- root.appendChild(element);
17143
+ Dom.append(root, element);
17064
17144
  }
17065
17145
  });
17066
17146
  toArray(root.childNodes).forEach((elm) => {
17067
17147
  if (elements_list.indexOf(elm) === -1) {
17068
- root.removeChild(elm);
17148
+ Dom.safeRemove(elm);
17069
17149
  }
17070
17150
  });
17071
17151
  }
@@ -17243,8 +17323,11 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
17243
17323
  this.offsetY = y;
17244
17324
  this.moved = Math.abs(x - left) > 100 || Math.abs(y - top) > 100;
17245
17325
  }
17246
- this.dialog.style.left = (x || left) + 'px';
17247
- this.dialog.style.top = (y || top) + 'px';
17326
+ // strings on purpose: `css()` would truncate fractional pixels
17327
+ css(this.dialog, {
17328
+ left: (x || left) + 'px',
17329
+ top: (y || top) + 'px'
17330
+ });
17248
17331
  return this;
17249
17332
  }
17250
17333
  /**
@@ -17305,6 +17388,15 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
17305
17388
  this.setMod('footer', Boolean(content));
17306
17389
  return this;
17307
17390
  }
17391
+ __openedSiblings() {
17392
+ const result = [];
17393
+ Dialog_1.__opened.forEach(dialog => {
17394
+ if (dialog.destination === this.destination) {
17395
+ result.push(dialog);
17396
+ }
17397
+ });
17398
+ return result;
17399
+ }
17308
17400
  /**
17309
17401
  * Get zIndex from dialog
17310
17402
  */
@@ -17315,12 +17407,11 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
17315
17407
  * Get dialog instance with maximum z-index displaying it on top of all the dialog boxes
17316
17408
  */
17317
17409
  getMaxZIndexDialog() {
17318
- let maxZi = 0, dlg, zIndex, res = this;
17319
- $$('.jodit-dialog', this.destination).forEach((dialog) => {
17320
- dlg = dialog.component;
17321
- zIndex = parseInt(css(dialog, 'zIndex'), 10);
17322
- if (dlg.isOpened && !isNaN(zIndex) && zIndex > maxZi) {
17323
- res = dlg;
17410
+ let maxZi = 0, res = this;
17411
+ this.__openedSiblings().forEach(dialog => {
17412
+ const zIndex = dialog.getZIndex();
17413
+ if (zIndex > maxZi) {
17414
+ res = dialog;
17324
17415
  maxZi = zIndex;
17325
17416
  }
17326
17417
  });
@@ -17332,12 +17423,11 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
17332
17423
  setMaxZIndex() {
17333
17424
  if (this.getMod('static'))
17334
17425
  return;
17335
- let maxZIndex = 20000004, zIndex = 0;
17336
- $$('.jodit-dialog', this.destination).forEach(dialog => {
17337
- zIndex = parseInt(css(dialog, 'zIndex'), 10);
17338
- maxZIndex = Math.max(isNaN(zIndex) ? 0 : zIndex, maxZIndex);
17426
+ let maxZIndex = 20000004;
17427
+ this.__openedSiblings().forEach(dialog => {
17428
+ maxZIndex = Math.max(dialog.getZIndex(), maxZIndex);
17339
17429
  });
17340
- this.container.style.zIndex = (maxZIndex + 1).toString();
17430
+ css(this.container, 'zIndex', (maxZIndex + 1).toString());
17341
17431
  }
17342
17432
  /**
17343
17433
  * Expands the dialog on full browser window
@@ -17383,14 +17473,15 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
17383
17473
  }
17384
17474
  this.setMod('active', true);
17385
17475
  this.isOpened = true;
17476
+ Dialog_1.__opened.add(this);
17386
17477
  this.setModal(modal);
17387
- this.destination.appendChild(this.container);
17478
+ Dom.append(this.destination, this.container);
17388
17479
  if (this.getMod('static') !== true) {
17389
17480
  this.setPosition(this.offsetX, this.offsetY);
17390
17481
  this.setMaxZIndex();
17391
17482
  }
17392
17483
  else {
17393
- this.container.style.removeProperty('z-index');
17484
+ css(this.container, 'zIndex', null);
17394
17485
  }
17395
17486
  if (this.o.fullsize) {
17396
17487
  this.toggleFullSize(true);
@@ -17445,6 +17536,7 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
17445
17536
  }
17446
17537
  this.setMod('active', false);
17447
17538
  this.isOpened = false;
17539
+ Dialog_1.__opened.delete(this);
17448
17540
  if (this.isFullSize) {
17449
17541
  this.toggleFullSize(false);
17450
17542
  }
@@ -17523,11 +17615,11 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
17523
17615
  </div>
17524
17616
  </div>`);
17525
17617
  if (self.options.direction === 'rtl') {
17526
- self.container.style.direction = 'rtl';
17527
- self.container.setAttribute('dir', 'rtl');
17618
+ css(self.container, 'direction', 'rtl');
17619
+ attr(self.container, 'dir', 'rtl');
17528
17620
  }
17529
17621
  if (this.o.zIndex) {
17530
- this.container.style.zIndex = this.o.zIndex.toString();
17622
+ css(this.container, 'zIndex', this.o.zIndex.toString());
17531
17623
  }
17532
17624
  attr(self.container, 'role', 'dialog');
17533
17625
  Object.defineProperty(self.container, 'component', {
@@ -17594,6 +17686,7 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
17594
17686
  if (this.isOpened) {
17595
17687
  this.close();
17596
17688
  }
17689
+ Dialog_1.__opened.delete(this);
17597
17690
  if (this.events) {
17598
17691
  this.__removeGlobalResizeListeners();
17599
17692
  this.events
@@ -17604,6 +17697,11 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
17604
17697
  super.destruct();
17605
17698
  }
17606
17699
  };
17700
+ /**
17701
+ * Registry of the currently opened dialogs. Replaces a DOM scan of the
17702
+ * whole `destination` (usually `document.body`) for every z-index update.
17703
+ */
17704
+ Dialog.__opened = new Set();
17607
17705
  Dialog.defaultOptions = {
17608
17706
  ...View.defaultOptions,
17609
17707
  closeOnClickOverlay: false,
@@ -17662,7 +17760,7 @@ function Alert(msg, title, callback, className = 'jodit-dialog_alert') {
17662
17760
  ? this
17663
17761
  : new Dialog({ closeOnClickOverlay: true }), container = dialog.c.div(className), okButton = Button(dialog, 'ok', 'Ok');
17664
17762
  asArray(msg).forEach(oneMessage => {
17665
- container.appendChild(Dom.isNode(oneMessage) ? oneMessage : dialog.c.fromHTML(oneMessage));
17763
+ Dom.append(container, Dom.isNode(oneMessage) ? oneMessage : dialog.c.fromHTML(oneMessage));
17666
17764
  });
17667
17765
  okButton.onAction(() => {
17668
17766
  if (!callback || !isFunction(callback) || callback(dialog) !== false) {
@@ -17702,8 +17800,8 @@ function Confirm(msg, title, callback) {
17702
17800
  callback = title;
17703
17801
  title = undefined;
17704
17802
  }
17705
- $label.appendChild(dialog.c.fromHTML(msg));
17706
- $div.appendChild($label);
17803
+ Dom.append($label, dialog.c.fromHTML(msg));
17804
+ Dom.append($div, $label);
17707
17805
  const action = (yes) => () => {
17708
17806
  if (!callback || callback(yes) !== false) {
17709
17807
  dialog.close();
@@ -17762,9 +17860,9 @@ function Prompt(msg, title, callback, placeholder, defaultValue) {
17762
17860
  if (placeholder) {
17763
17861
  attr(inputElement, 'placeholder', placeholder);
17764
17862
  }
17765
- labelElement.appendChild(dialog.c.text(msg));
17766
- form.appendChild(labelElement);
17767
- form.appendChild(inputElement);
17863
+ Dom.append(labelElement, dialog.c.text(msg));
17864
+ Dom.append(form, labelElement);
17865
+ Dom.append(form, inputElement);
17768
17866
  cancelButton.onAction(dialog.close);
17769
17867
  const onclick = () => {
17770
17868
  if (!callback ||
@@ -18185,7 +18283,8 @@ Config.prototype.controls.filebrowser = {
18185
18283
  filter: {
18186
18284
  isInput: true,
18187
18285
  getContent: (filebrowser, b) => {
18188
- const oldInput = b.container.querySelector('.jodit-input');
18286
+ const oldInput = Dom.first(b.container, node => Dom.isHTMLElement(node) &&
18287
+ node.classList.contains('jodit-input'));
18189
18288
  if (oldInput) {
18190
18289
  return oldInput;
18191
18290
  }
@@ -18966,6 +19065,17 @@ var __decorate$q = (undefined && undefined.__decorate) || function (decorators,
18966
19065
  };
18967
19066
  var ImageEditor_1;
18968
19067
  const jie = 'jodit-image-editor';
19068
+ const hasClass = (className) => (elm) => elm.classList.contains(className);
19069
+ function findFirst(root, cond) {
19070
+ return Dom.first(root, n => Dom.isHTMLElement(n) && cond(n));
19071
+ }
19072
+ function findAll(root, cond) {
19073
+ const result = [];
19074
+ Dom.each(root, n => {
19075
+ Dom.isHTMLElement(n) && cond(n) && result.push(n);
19076
+ });
19077
+ return result;
19078
+ }
18969
19079
  const TABS = {
18970
19080
  resize: 'resize',
18971
19081
  crop: 'crop'
@@ -19016,19 +19126,20 @@ let ImageEditor = ImageEditor_1 = class ImageEditor extends ViewComponent {
19016
19126
  return this.j.async.promise((resolve) => {
19017
19127
  const timestamp = new Date().getTime();
19018
19128
  this.image = this.j.c.element('img');
19019
- $$('img,.jodit-icon_loader', this.resize_box).forEach(Dom.safeRemove);
19020
- $$('img,.jodit-icon_loader', this.crop_box).forEach(Dom.safeRemove);
19129
+ const isTrash = (elm) => Dom.isTag(elm, 'img') || hasClass('jodit-icon_loader')(elm);
19130
+ findAll(this.resize_box, isTrash).forEach(Dom.safeRemove);
19131
+ findAll(this.crop_box, isTrash).forEach(Dom.safeRemove);
19021
19132
  css(this.cropHandler, 'background', 'transparent');
19022
19133
  this.onSave = save;
19023
- this.resize_box.appendChild(this.j.c.element('i', { class: 'jodit-icon_loader' }));
19024
- this.crop_box.appendChild(this.j.c.element('i', { class: 'jodit-icon_loader' }));
19134
+ Dom.append(this.resize_box, this.j.c.element('i', { class: 'jodit-icon_loader' }));
19135
+ Dom.append(this.crop_box, this.j.c.element('i', { class: 'jodit-icon_loader' }));
19025
19136
  if (/\?/.test(url)) {
19026
19137
  url += '&_tst=' + timestamp;
19027
19138
  }
19028
19139
  else {
19029
19140
  url += '?_tst=' + timestamp;
19030
19141
  }
19031
- this.image.setAttribute('src', url);
19142
+ attr(this.image, 'src', url);
19032
19143
  this._dialog.open();
19033
19144
  const { widthInput, heightInput } = refs(this.editor);
19034
19145
  const onload = () => {
@@ -19041,10 +19152,10 @@ let ImageEditor = ImageEditor_1 = class ImageEditor extends ViewComponent {
19041
19152
  widthInput.value = this.naturalWidth.toString();
19042
19153
  heightInput.value = this.naturalHeight.toString();
19043
19154
  this.ratio = this.naturalWidth / this.naturalHeight;
19044
- this.resize_box.appendChild(this.image);
19155
+ Dom.append(this.resize_box, this.image);
19045
19156
  this.cropImage = this.image.cloneNode(true);
19046
- this.crop_box.appendChild(this.cropImage);
19047
- Dom.safeRemove.apply(null, $$('.jodit-icon_loader', this.editor));
19157
+ Dom.append(this.crop_box, this.cropImage);
19158
+ Dom.safeRemove.apply(null, findAll(this.editor, hasClass('jodit-icon_loader')));
19048
19159
  if (this.activeTab === TABS.crop) {
19049
19160
  this.showCrop();
19050
19161
  }
@@ -19066,10 +19177,11 @@ let ImageEditor = ImageEditor_1 = class ImageEditor extends ViewComponent {
19066
19177
  if (!slide) {
19067
19178
  return;
19068
19179
  }
19069
- $$(`.${jie}__slider,.${jie}__area`, self.editor).forEach(elm => elm.classList.remove(`${jie}_active`));
19180
+ findAll(self.editor, elm => hasClass(`${jie}__slider`)(elm) || hasClass(`${jie}__area`)(elm)).forEach(elm => elm.classList.remove(`${jie}_active`));
19070
19181
  slide.classList.add(`${jie}_active`);
19071
19182
  this.activeTab = attr(slide, '-area') || TABS.resize;
19072
- const tab = self.editor.querySelector(`.${jie}__area.${jie}__area_` + self.activeTab);
19183
+ const tab = findFirst(self.editor, elm => hasClass(`${jie}__area`)(elm) &&
19184
+ hasClass(`${jie}__area_` + self.activeTab)(elm));
19073
19185
  if (tab) {
19074
19186
  tab.classList.add(`${jie}_active`);
19075
19187
  }
@@ -19294,7 +19406,7 @@ let ImageEditor = ImageEditor_1 = class ImageEditor extends ViewComponent {
19294
19406
  const { widthInput, heightInput } = refs(this.editor);
19295
19407
  self.j.e
19296
19408
  .on([
19297
- self.editor.querySelector('.jodit_bottomright'),
19409
+ findFirst(self.editor, hasClass('jodit_bottomright')),
19298
19410
  self.cropHandler
19299
19411
  ], `mousedown.${jie}`, this.onResizeHandleMouseDown)
19300
19412
  .on(this.j.ow, `resize.${jie}`, () => {
@@ -19303,7 +19415,7 @@ let ImageEditor = ImageEditor_1 = class ImageEditor extends ViewComponent {
19303
19415
  this.j.e.fire(self.cropHandler, 'updatesize');
19304
19416
  });
19305
19417
  self.j.e
19306
- .on(toArray(this.editor.querySelectorAll(`.${jie}__slider-title`)), 'click', this.onTitleModeClick)
19418
+ .on(findAll(this.editor, hasClass(`${jie}__slider-title`)), 'click', this.onTitleModeClick)
19307
19419
  .on([widthInput, heightInput], 'input', this.onChangeSizeInput);
19308
19420
  const { keepAspectRatioResize, keepAspectRatioCrop } = refs(this.editor);
19309
19421
  if (keepAspectRatioResize) {
@@ -19433,9 +19545,11 @@ let ImageEditor = ImageEditor_1 = class ImageEditor extends ViewComponent {
19433
19545
  const { resizeBox, cropBox } = refs(this.editor);
19434
19546
  this.resize_box = resizeBox;
19435
19547
  this.crop_box = cropBox;
19436
- this.sizes = this.editor.querySelector(`.${jie}__area.${jie}__area_crop .jodit-image-editor__sizes`);
19437
- this.resizeHandler = this.editor.querySelector(`.${jie}__resizer`);
19438
- this.cropHandler = this.editor.querySelector(`.${jie}__croper`);
19548
+ this.sizes = findFirst(this.editor, elm => hasClass(`${jie}__sizes`)(elm) &&
19549
+ Boolean(Dom.closest(elm, p => Dom.isHTMLElement(p) &&
19550
+ hasClass(`${jie}__area_crop`)(p), this.editor)));
19551
+ this.resizeHandler = findFirst(this.editor, hasClass(`${jie}__resizer`));
19552
+ this.cropHandler = findFirst(this.editor, hasClass(`${jie}__croper`));
19439
19553
  this._dialog = this.j.dlg({
19440
19554
  buttons: ['fullsize', 'dialog.close']
19441
19555
  });
@@ -19614,7 +19728,7 @@ var contextMenu = (self) => {
19614
19728
  buttons: ['fullsize', 'dialog.close']
19615
19729
  }), 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) => {
19616
19730
  const image = self.c.element('img');
19617
- image.setAttribute('src', src);
19731
+ attr(image, 'src', src);
19618
19732
  const onload = () => {
19619
19733
  var _a;
19620
19734
  if (self.isInDestruct) {
@@ -19624,14 +19738,14 @@ var contextMenu = (self) => {
19624
19738
  Dom.detach(temp_content);
19625
19739
  if (opt.showPreviewNavigation) {
19626
19740
  if (Dom.prevWithClass(item, self.files.getFullElName('item'))) {
19627
- temp_content.appendChild(prev);
19741
+ Dom.append(temp_content, prev);
19628
19742
  }
19629
19743
  if (Dom.nextWithClass(item, self.files.getFullElName('item'))) {
19630
- temp_content.appendChild(next);
19744
+ Dom.append(temp_content, next);
19631
19745
  }
19632
19746
  }
19633
- temp_content.appendChild(preview_box);
19634
- preview_box.appendChild(image);
19747
+ Dom.append(temp_content, preview_box);
19748
+ Dom.append(preview_box, image);
19635
19749
  preview.setPosition();
19636
19750
  (_a = self === null || self === void 0 ? void 0 : self.events) === null || _a === void 0 ? void 0 : _a.fire('previewOpenedAndLoaded');
19637
19751
  };
@@ -19971,11 +20085,11 @@ function stateListeners() {
19971
20085
  Dom.detach(files.container);
19972
20086
  if (state.elements.length) {
19973
20087
  state.elements.forEach(item => {
19974
- this.files.container.appendChild(getDomElement(item));
20088
+ Dom.append(this.files.container, getDomElement(item));
19975
20089
  });
19976
20090
  }
19977
20091
  else {
19978
- files.container.appendChild(create.div(this.componentName + '_no-files_true', this.i18n('There are no files')));
20092
+ Dom.append(files.container, create.div(this.componentName + '_no-files_true', this.i18n('There are no files')));
19979
20093
  }
19980
20094
  }, this.defaultTimeout))
19981
20095
  .on('change.sources', this.async.debounce(() => {
@@ -19983,7 +20097,7 @@ function stateListeners() {
19983
20097
  state.sources.forEach(source => {
19984
20098
  const sourceName = source.name;
19985
20099
  if (sourceName && sourceName !== DEFAULT_SOURCE_NAME) {
19986
- this.tree.container.appendChild(create.div(this.tree.getFullElName('source-title'), sourceName));
20100
+ Dom.append(this.tree.container, create.div(this.tree.getFullElName('source-title'), sourceName));
19987
20101
  }
19988
20102
  source.folders.forEach((name) => {
19989
20103
  const folderElm = create.a(this.tree.getFullElName('item'), {
@@ -20004,7 +20118,7 @@ function stateListeners() {
20004
20118
  e.preventDefault();
20005
20119
  };
20006
20120
  this.e.on(folderElm, 'click', action('openFolder'));
20007
- this.tree.container.appendChild(folderElm);
20121
+ Dom.append(this.tree.container, folderElm);
20008
20122
  if (name === '..' || name === '.') {
20009
20123
  return;
20010
20124
  }
@@ -20017,7 +20131,7 @@ function stateListeners() {
20017
20131
  size: 'tiny'
20018
20132
  });
20019
20133
  btn.onAction(action('renameFolder'));
20020
- folderElm.appendChild(btn.container);
20134
+ Dom.append(folderElm, btn.container);
20021
20135
  }
20022
20136
  if (options.deleteFolder &&
20023
20137
  this.dataProvider.canI('FolderRemove')) {
@@ -20028,7 +20142,7 @@ function stateListeners() {
20028
20142
  size: 'tiny'
20029
20143
  });
20030
20144
  btn.onAction(action('removeFolder'));
20031
- folderElm.appendChild(btn.container);
20145
+ Dom.append(folderElm, btn.container);
20032
20146
  }
20033
20147
  });
20034
20148
  if (options.createNewFolder &&
@@ -20135,7 +20249,8 @@ let FileBrowser = class FileBrowser extends ViewWithToolbar {
20135
20249
  return Storage.makeStorage(Boolean(this.o.saveStateInStorage), this.componentName);
20136
20250
  }
20137
20251
  get isOpened() {
20138
- return this._dialog.isOpened && this.browser.style.display !== 'none';
20252
+ return (this._dialog.isOpened &&
20253
+ cssInline(this.browser, 'display') !== 'none');
20139
20254
  }
20140
20255
  /**
20141
20256
  * It displays a message in the status bar of filebrowser
@@ -20296,10 +20411,10 @@ let FileBrowser = class FileBrowser extends ViewWithToolbar {
20296
20411
  self.browser.component = this;
20297
20412
  self.container = self.browser;
20298
20413
  if (self.o.showFoldersPanel) {
20299
- self.browser.appendChild(self.tree.container);
20414
+ Dom.append(self.browser, self.tree.container);
20300
20415
  }
20301
- self.browser.appendChild(self.files.container);
20302
- self.browser.appendChild(self.status_line);
20416
+ Dom.append(self.browser, self.files.container);
20417
+ Dom.append(self.browser, self.status_line);
20303
20418
  selfListeners.call(self);
20304
20419
  nativeListeners.call(self);
20305
20420
  stateListeners.call(self);
@@ -21004,14 +21119,13 @@ let StatusBar = class StatusBar extends ViewComponent {
21004
21119
  * Add element in statusbar
21005
21120
  */
21006
21121
  append(child, inTheRight = false) {
21007
- var _a;
21008
21122
  const wrapper = this.findEmpty(inTheRight) ||
21009
21123
  this.j.c.div(this.getFullElName('item'));
21010
21124
  if (inTheRight) {
21011
21125
  wrapper.classList.add(this.getFullElName('item-right'));
21012
21126
  }
21013
- wrapper.appendChild(child);
21014
- (_a = this.container) === null || _a === void 0 ? void 0 : _a.appendChild(wrapper);
21127
+ Dom.append(wrapper, child);
21128
+ this.container && Dom.append(this.container, wrapper);
21015
21129
  if (this.j.o.statusbar) {
21016
21130
  this.show();
21017
21131
  }
@@ -21022,7 +21136,7 @@ let StatusBar = class StatusBar extends ViewComponent {
21022
21136
  this.target = target;
21023
21137
  this.mods = {};
21024
21138
  this.container = jodit.c.div('jodit-status-bar');
21025
- target.appendChild(this.container);
21139
+ Dom.append(target, this.container);
21026
21140
  this.hide();
21027
21141
  }
21028
21142
  destruct() {
@@ -21201,37 +21315,40 @@ class Table extends ViewComponent {
21201
21315
  return Table.__formalCoordinate(table, cell, max);
21202
21316
  }
21203
21317
  static __appendRow(table, line, after, create) {
21204
- var _a;
21205
21318
  let row;
21206
21319
  if (!line) {
21207
21320
  const columnsCount = Table.__getColumnsCount(table);
21208
21321
  row = create.element('tr');
21209
21322
  for (let j = 0; j < columnsCount; j += 1) {
21210
- row.appendChild(create.element('td'));
21323
+ Dom.append(row, create.element('td'));
21211
21324
  }
21212
21325
  }
21213
21326
  else {
21214
21327
  row = line.cloneNode(true);
21215
- $$('td,th', line).forEach(cell => {
21328
+ Dom.each(line, cell => {
21329
+ if (!Dom.isCell(cell)) {
21330
+ return;
21331
+ }
21216
21332
  const rowspan = attr(cell, 'rowspan');
21217
21333
  if (rowspan && parseInt(rowspan, 10) > 1) {
21218
21334
  const newRowSpan = parseInt(rowspan, 10) - 1;
21219
21335
  attr(cell, 'rowspan', newRowSpan > 1 ? newRowSpan : null);
21220
21336
  }
21221
21337
  });
21222
- $$('td,th', row).forEach(cell => {
21223
- cell.innerHTML = '';
21338
+ Dom.each(row, cell => {
21339
+ if (Dom.isCell(cell)) {
21340
+ Dom.detach(cell);
21341
+ }
21224
21342
  });
21225
21343
  }
21226
21344
  if (after && line && line.nextSibling) {
21227
- line.parentNode &&
21228
- line.parentNode.insertBefore(row, line.nextSibling);
21345
+ Dom.after(line, row);
21229
21346
  }
21230
21347
  else if (!after && line) {
21231
- line.parentNode && line.parentNode.insertBefore(row, line);
21348
+ Dom.before(line, row);
21232
21349
  }
21233
21350
  else {
21234
- (((_a = table.getElementsByTagName('tbody')) === null || _a === void 0 ? void 0 : _a[0]) || table).appendChild(row);
21351
+ Dom.append(Dom.first(table, node => Dom.isTag(node, 'tbody')) || table, row);
21235
21352
  }
21236
21353
  }
21237
21354
  /**
@@ -21278,10 +21395,10 @@ class Table extends ViewComponent {
21278
21395
  }
21279
21396
  }
21280
21397
  if (referenceCell) {
21281
- nextRow.insertBefore(cell, referenceCell);
21398
+ Dom.before(referenceCell, cell);
21282
21399
  }
21283
21400
  else {
21284
- nextRow.appendChild(cell);
21401
+ Dom.append(nextRow, cell);
21285
21402
  }
21286
21403
  }
21287
21404
  }
@@ -21509,7 +21626,7 @@ class Table extends ViewComponent {
21509
21626
  return;
21510
21627
  }
21511
21628
  alreadyMerged.add(td);
21512
- if (i === bound[0][0] && td.style.width) {
21629
+ if (i === bound[0][0] && cssInline(td, 'width')) {
21513
21630
  w += td.offsetWidth;
21514
21631
  }
21515
21632
  if (trim(cell.innerHTML.replace(/<br(\/)?>/g, '')) !== '') {
@@ -21571,7 +21688,7 @@ class Table extends ViewComponent {
21571
21688
  const __marked = [];
21572
21689
  Table.__getSelectedCellsByTable(table).forEach((cell) => {
21573
21690
  td = jodit.createInside.element('td');
21574
- td.appendChild(jodit.createInside.element('br'));
21691
+ Dom.append(td, jodit.createInside.element('br'));
21575
21692
  tr = jodit.createInside.element('tr');
21576
21693
  coord = Table.__formalCoordinate(table, cell);
21577
21694
  if (cell.rowSpan < 2) {
@@ -21583,7 +21700,7 @@ class Table extends ViewComponent {
21583
21700
  }
21584
21701
  });
21585
21702
  Dom.after(Dom.closest(cell, 'tr', table), tr);
21586
- tr.appendChild(td);
21703
+ Dom.append(tr, td);
21587
21704
  }
21588
21705
  else {
21589
21706
  Table.__mark(cell, 'rowspan', cell.rowSpan - 1, __marked);
@@ -21603,7 +21720,7 @@ class Table extends ViewComponent {
21603
21720
  Dom.after(after, td);
21604
21721
  }
21605
21722
  else {
21606
- parent.insertBefore(td, parent.firstChild);
21723
+ Dom.prepend(parent, td);
21607
21724
  }
21608
21725
  }
21609
21726
  if (cell.colSpan > 1) {
@@ -21636,7 +21753,7 @@ class Table extends ViewComponent {
21636
21753
  Table.__mark(cell, 'colspan', cell.colSpan - 1, __marked);
21637
21754
  }
21638
21755
  td = jodit.createInside.element('td');
21639
- td.appendChild(jodit.createInside.element('br'));
21756
+ Dom.append(td, jodit.createInside.element('br'));
21640
21757
  if (cell.rowSpan > 1) {
21641
21758
  Table.__mark(td, 'rowspan', cell.rowSpan, __marked);
21642
21759
  }
@@ -21715,7 +21832,7 @@ class Table extends ViewComponent {
21715
21832
  }
21716
21833
  }
21717
21834
  else {
21718
- cell.style.width = value.toString();
21835
+ css(cell, 'width', value.toString());
21719
21836
  }
21720
21837
  break;
21721
21838
  }
@@ -21843,20 +21960,20 @@ let ToolbarButton = class ToolbarButton extends UIButton {
21843
21960
  value: this,
21844
21961
  configurable: true
21845
21962
  });
21846
- container.appendChild(button);
21963
+ Dom.append(container, button);
21847
21964
  const trigger = this.j.c.fromHTML(`<span role="button" aria-haspopup="true" aria-expanded="false" class="${cn}__trigger">${Icon.get('chevron')}</span>`);
21848
21965
  // For caching
21849
- button.appendChild(trigger);
21966
+ Dom.append(button, trigger);
21850
21967
  return container;
21851
21968
  }
21852
21969
  /** @override */
21853
21970
  focus() {
21854
21971
  var _a;
21855
- (_a = this.container.querySelector('button')) === null || _a === void 0 ? void 0 : _a.focus();
21972
+ (_a = Dom.first(this.container, node => Dom.isTag(node, 'button'))) === null || _a === void 0 ? void 0 : _a.focus();
21856
21973
  }
21857
21974
  onChangeHasTrigger() {
21858
21975
  if (this.state.hasTrigger) {
21859
- this.container.appendChild(this.trigger);
21976
+ Dom.append(this.container, this.trigger);
21860
21977
  }
21861
21978
  else {
21862
21979
  Dom.safeRemove(this.trigger);
@@ -22093,17 +22210,25 @@ let ToolbarButton = class ToolbarButton extends UIButton {
22093
22210
  return this.openedPopup;
22094
22211
  }
22095
22212
  __closePopup() {
22096
- if (this.openedPopup) {
22097
- this.j.e
22098
- .off(this.ow, 'mousedown touchstart', this.onOutsideClick)
22099
- .off('escape closeAllPopups', this.onOutsideClick);
22100
- this.state.activated = false;
22101
- this.openedPopup.close();
22102
- this.openedPopup.destruct();
22103
- this.openedPopup = null;
22104
- if (this.trigger) {
22105
- attr(this.trigger, 'aria-expanded', false);
22106
- }
22213
+ const popup = this.openedPopup;
22214
+ if (!popup) {
22215
+ return;
22216
+ }
22217
+ // Detach first: removing a popup that holds the focused element
22218
+ // makes Chrome fire `blur`/`change` on it synchronously, and a
22219
+ // handler there may call the popup's `close` callback again.
22220
+ // A re-entrant call must be a no-op, otherwise it destructs the
22221
+ // popup while the outer `removeChild` is still running and Chrome
22222
+ // throws NotFoundError. See #1458
22223
+ this.openedPopup = null;
22224
+ this.j.e
22225
+ .off(this.ow, 'mousedown touchstart', this.onOutsideClick)
22226
+ .off('escape closeAllPopups', this.onOutsideClick);
22227
+ this.state.activated = false;
22228
+ popup.close();
22229
+ popup.destruct();
22230
+ if (this.trigger) {
22231
+ attr(this.trigger, 'aria-expanded', false);
22107
22232
  }
22108
22233
  }
22109
22234
  /**
@@ -22189,6 +22314,12 @@ var __decorate$j = (undefined && undefined.__decorate) || function (decorators,
22189
22314
  r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
22190
22315
  return c > 3 && r && Object.defineProperty(target, key, r), r;
22191
22316
  };
22317
+ const FORM_CONTROL_TAGS = new Set([
22318
+ 'input',
22319
+ 'button',
22320
+ 'select',
22321
+ 'textarea'
22322
+ ]);
22192
22323
  let ToolbarContent = class ToolbarContent extends UIButton {
22193
22324
  /** @override */
22194
22325
  className() {
@@ -22201,7 +22332,7 @@ let ToolbarContent = class ToolbarContent extends UIButton {
22201
22332
  const content = control.getContent(this.j, this);
22202
22333
  if (isString(content) || content.parentNode !== this.container) {
22203
22334
  Dom.detach(this.container);
22204
- this.container.appendChild(isString(content) ? this.j.create.fromHTML(content) : content);
22335
+ Dom.append(this.container, isString(content) ? this.j.create.fromHTML(content) : content);
22205
22336
  }
22206
22337
  // Content controls never went through the ToolbarButton status
22207
22338
  // calculation, so `isDisabled`/`isActive`/`update` declared on the
@@ -22224,9 +22355,11 @@ let ToolbarContent = class ToolbarContent extends UIButton {
22224
22355
  */
22225
22356
  onChangeDisabled() {
22226
22357
  super.onChangeDisabled();
22227
- this.container
22228
- .querySelectorAll('input,button,select,textarea')
22229
- .forEach(elm => attr(elm, 'disabled', this.state.disabled || null));
22358
+ Dom.each(this.container, elm => {
22359
+ if (Dom.isTag(elm, FORM_CONTROL_TAGS)) {
22360
+ attr(elm, 'disabled', this.state.disabled || null);
22361
+ }
22362
+ });
22230
22363
  }
22231
22364
  /** @override */
22232
22365
  createContainer() {
@@ -22354,8 +22487,8 @@ let ToolbarCollection = class ToolbarCollection extends UIList {
22354
22487
  * Set direction
22355
22488
  */
22356
22489
  setDirection(direction) {
22357
- this.container.style.direction = direction;
22358
- this.container.setAttribute('dir', direction);
22490
+ css(this.container, 'direction', direction);
22491
+ attr(this.container, 'dir', direction);
22359
22492
  }
22360
22493
  constructor(jodit) {
22361
22494
  super(jodit);
@@ -22862,11 +22995,11 @@ Config.prototype.uploader = {
22862
22995
  }
22863
22996
  if (resp.files && resp.files.length) {
22864
22997
  resp.files.forEach((filename, index) => {
22865
- const [tagName, attr] = resp.isImages && resp.isImages[index]
22998
+ const [tagName, attrName] = resp.isImages && resp.isImages[index]
22866
22999
  ? ['img', 'src']
22867
23000
  : ['a', 'href'];
22868
23001
  const elm = j.createInside.element(tagName);
22869
- elm.setAttribute(attr, resp.baseurl + filename);
23002
+ attr(elm, attrName, resp.baseurl + filename);
22870
23003
  if (tagName === 'a') {
22871
23004
  elm.textContent = j.o.uploader.getDisplayName.call(this, resp.baseurl, filename);
22872
23005
  }
@@ -23012,7 +23145,11 @@ class Uploader extends ViewComponent {
23012
23145
  sendFiles(self, event.dataTransfer.files, handlerSuccess, handlerError).finally(onFinally);
23013
23146
  }
23014
23147
  });
23015
- const inputFile = form.querySelector('input[type=file]');
23148
+ const inputFile = Dom.first(form, node => {
23149
+ var _a;
23150
+ return Dom.isTag(node, 'input') &&
23151
+ ((_a = attr(node, 'type')) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === 'file';
23152
+ });
23016
23153
  if (inputFile) {
23017
23154
  self.j.e.on(inputFile, 'change', () => {
23018
23155
  sendFiles(self, inputFile.files, handlerSuccess, handlerError)
@@ -23392,6 +23529,7 @@ function getSuitChild(style, font) {
23392
23529
  * @private
23393
23530
  */
23394
23531
  function getSuitParent(style, node, root) {
23532
+ var _a;
23395
23533
  const { parentNode } = node;
23396
23534
  if (parentNode === root ||
23397
23535
  !Dom.isHTMLElement(parentNode) ||
@@ -23405,6 +23543,15 @@ function getSuitParent(style, node, root) {
23405
23543
  !Dom.isBlock(parentNode)) {
23406
23544
  return getSuitParent(style, parentNode, root);
23407
23545
  }
23546
+ // <li>|test|</li> => apply the CSS style to the <li> itself, so the
23547
+ // list marker (bullet/number) gets the same color and size as the text.
23548
+ // Only for pure style commits: bold/italic keep wrapping the content.
23549
+ // See #1460
23550
+ if (Dom.isTag(parentNode, 'li') &&
23551
+ !style.isElementCommit &&
23552
+ ((_a = style.options.attributes) === null || _a === void 0 ? void 0 : _a.style)) {
23553
+ return parentNode;
23554
+ }
23408
23555
  if (isSuitElement(style, parentNode, false) &&
23409
23556
  (!Dom.isBlock(parentNode) || style.elementIsBlock)) {
23410
23557
  return parentNode;
@@ -23457,8 +23604,10 @@ function isSameAttributes(elm, attrs) {
23457
23604
  }
23458
23605
  function elementsEqualAttributes(elm1, elm2) {
23459
23606
  return (elm1.attributes.length === elm2.attributes.length &&
23460
- Array.from(elm1.attributes).every(attr => elm2.hasAttribute(attr.name) &&
23461
- elm2.getAttribute(attr.name) === attr.value));
23607
+ Array.from(elm1.attributes).every(
23608
+ // `attrRaw` on purpose: the comparison must use the exact
23609
+ // attribute name from the live list, without `attr()` name mangling
23610
+ attr => attrRaw(elm2, attr.name) === attr.value));
23462
23611
  }
23463
23612
 
23464
23613
  /*!
@@ -23499,7 +23648,7 @@ function toggleAttributes(commitStyle, elm, jodit, mode, dry = false) {
23499
23648
  function toggleStyle(commitStyle, jodit, style, elm, dry, mode) {
23500
23649
  assert(isPlainObject(style) && size$1(style), 'Style must be an object');
23501
23650
  Object.keys(style).forEach((rule) => {
23502
- const inlineValue = elm.style.getPropertyValue(kebabCase(rule));
23651
+ const inlineValue = cssInline(elm, rule);
23503
23652
  const newValue = style[rule];
23504
23653
  if (inlineValue === '' && newValue == null) {
23505
23654
  return;
@@ -23592,8 +23741,8 @@ function getShadowRoot(jodit) {
23592
23741
  position: 'absolute',
23593
23742
  border: 0
23594
23743
  });
23595
- iframe.src = 'about:blank';
23596
- container.appendChild(iframe);
23744
+ attr(iframe, 'src', 'about:blank');
23745
+ Dom.append(container, iframe);
23597
23746
  const doc = (_a = iframe.contentWindow) === null || _a === void 0 ? void 0 : _a.document;
23598
23747
  const shadowRoot = !doc ? jodit.od.body : doc.body;
23599
23748
  dataBind(jodit, 'shadowRoot', shadowRoot);
@@ -23609,11 +23758,11 @@ function getNativeCSSValue(jodit, elm, key) {
23609
23758
  // browser default black) is recognised. Without this, applying black after
23610
23759
  // the default font color was changed was wrongly treated as a no-op (#1311).
23611
23760
  const wrapper = jodit.create.element('div');
23612
- wrapper.style.color = css(jodit.editor, 'color');
23761
+ css(wrapper, 'color', css(jodit.editor, 'color'));
23613
23762
  const newElm = jodit.create.element(elm.tagName.toLowerCase());
23614
- newElm.style.cssText = elm.style.cssText;
23615
- wrapper.appendChild(newElm);
23616
- root.appendChild(wrapper);
23763
+ attr(newElm, 'style', attr(elm, 'style'));
23764
+ Dom.append(wrapper, newElm);
23765
+ Dom.append(root, wrapper);
23617
23766
  const result = css(newElm, key);
23618
23767
  Dom.safeRemove(wrapper);
23619
23768
  return result;
@@ -23814,12 +23963,12 @@ function wrapUnwrappedText(style, elm, jodit) {
23814
23963
  range.setEndAfter(end);
23815
23964
  const fragment = range.extractContents();
23816
23965
  const wrapper = ci.element(style.element);
23817
- wrapper.appendChild(fragment);
23966
+ Dom.append(wrapper, fragment);
23818
23967
  Dom.safeInsertNode(range, wrapper);
23819
23968
  if (style.elementIsBlock) {
23820
23969
  if (Dom.isEmpty(wrapper) &&
23821
23970
  !Dom.isTag(wrapper.firstElementChild, 'br')) {
23822
- wrapper.appendChild(ci.element('br'));
23971
+ Dom.append(wrapper, ci.element('br'));
23823
23972
  }
23824
23973
  }
23825
23974
  return wrapper;
@@ -23870,7 +24019,9 @@ const WRAP_NODES = new Set([
23870
24019
  */
23871
24020
  function findOrCreateWrapper(commitStyle, font, jodit) {
23872
24021
  if (commitStyle.elementIsBlock) {
23873
- const box = Dom.up(font, node => Dom.isBlock(node) && !Dom.isTag(node, WRAP_NODES), jodit.editor);
24022
+ const box = Dom.up(font, node => Dom.isBlock(node) &&
24023
+ !Dom.isTag(node, WRAP_NODES) &&
24024
+ !hasBlockChildren(node), jodit.editor);
23874
24025
  if (box) {
23875
24026
  return box;
23876
24027
  }
@@ -23879,6 +24030,14 @@ function findOrCreateWrapper(commitStyle, font, jodit) {
23879
24030
  attr(font, 'size', null);
23880
24031
  return font;
23881
24032
  }
24033
+ /**
24034
+ * A block that itself contains block-level children is a layout container:
24035
+ * replacing it wholesale would merge all its blocks into the new element,
24036
+ * so the selection must be wrapped in a new block inside it instead.
24037
+ */
24038
+ function hasBlockChildren(node) {
24039
+ return Array.from(node.childNodes).some(child => Dom.isBlock(child));
24040
+ }
23882
24041
 
23883
24042
  /*!
23884
24043
  * Jodit Editor (https://xdsoft.net/jodit/)
@@ -24039,11 +24198,25 @@ const transactions = {
24039
24198
  },
24040
24199
  [states.UNWRAP]: {
24041
24200
  exec(value) {
24042
- if (value.element.attributes.length &&
24043
- Dom.isTag(value.element, value.style.element)) {
24201
+ const { element, style, jodit } = value;
24202
+ if (element.attributes.length &&
24203
+ Dom.isTag(element, style.element)) {
24204
+ return { ...value, next: states.REPLACE_DEFAULT };
24205
+ }
24206
+ // Unwrapping a block inside a container (e.g. an h3 inside a div)
24207
+ // leaves bare inline content there: the wrapNodes plugin restores
24208
+ // paragraphs only at the editor root. Replace such a block with
24209
+ // the default tag instead.
24210
+ const parent = element.parentElement;
24211
+ if (style.elementIsBlock &&
24212
+ !style.elementIsDefault &&
24213
+ parent &&
24214
+ parent !== jodit.editor &&
24215
+ Dom.isBlock(parent) &&
24216
+ !Dom.isTag(parent, WRAP_NODES)) {
24044
24217
  return { ...value, next: states.REPLACE_DEFAULT };
24045
24218
  }
24046
- Dom.unwrap(value.element);
24219
+ Dom.unwrap(element);
24047
24220
  return { ...value, mode: UNWRAP, next: states.END };
24048
24221
  }
24049
24222
  },
@@ -24188,7 +24361,7 @@ function moveNodeInsideStart(j, node, start) {
24188
24361
  Dom.isContentEditable(sibling, j.editor) &&
24189
24362
  (!anotherSibling || !Dom.closest(node, Dom.isElement, j.editor))) {
24190
24363
  if (start || !sibling.firstChild) {
24191
- sibling.appendChild(node);
24364
+ Dom.append(sibling, node);
24192
24365
  }
24193
24366
  else {
24194
24367
  Dom.before(sibling.firstChild, node);
@@ -24443,11 +24616,13 @@ class Selection {
24443
24616
  Number(new Date()) +
24444
24617
  '_' +
24445
24618
  String(Math.random()).slice(2);
24446
- marker.style.lineHeight = '0';
24447
- marker.style.display = 'none';
24619
+ css(marker, {
24620
+ lineHeight: '0',
24621
+ display: 'none'
24622
+ });
24448
24623
  Dom.markTemporary(marker);
24449
24624
  attr(marker, 'data-' + MARKER_CLASS, atStart ? 'start' : 'end');
24450
- marker.appendChild(this.j.createInside.text(INVISIBLE_SPACE));
24625
+ Dom.append(marker, this.j.createInside.text(INVISIBLE_SPACE));
24451
24626
  if (newRange) {
24452
24627
  if (Dom.isOrContains(this.area, atStart ? newRange.startContainer : newRange.endContainer)) {
24453
24628
  // Here need do unsafe inserting
@@ -24463,9 +24638,11 @@ class Selection {
24463
24638
  */
24464
24639
  restore() {
24465
24640
  let range = false;
24466
- const markAttr = (start) => `span[data-${MARKER_CLASS}=${start ? 'start' : 'end'}]`;
24467
- const start = this.area.querySelector(markAttr(true));
24468
- const end = this.area.querySelector(markAttr(false));
24641
+ const markerFilter = (start) => (node) => Dom.isMarker(node) &&
24642
+ attr(node, 'data-' + MARKER_CLASS) ===
24643
+ (start ? 'start' : 'end');
24644
+ const start = Dom.first(this.area, markerFilter(true));
24645
+ const end = Dom.first(this.area, markerFilter(false));
24469
24646
  if (!start) {
24470
24647
  return;
24471
24648
  }
@@ -24719,7 +24896,7 @@ class Selection {
24719
24896
  Dom.safeInsertNode(range, node);
24720
24897
  }
24721
24898
  else {
24722
- this.area.appendChild(node);
24899
+ Dom.append(this.area, node);
24723
24900
  }
24724
24901
  [
24725
24902
  () => firstChild === null || firstChild === void 0 ? void 0 : firstChild.previousSibling,
@@ -24733,7 +24910,7 @@ class Selection {
24733
24910
  });
24734
24911
  }
24735
24912
  else {
24736
- this.area.appendChild(node);
24913
+ Dom.append(this.area, node);
24737
24914
  }
24738
24915
  const setCursor = (node) => {
24739
24916
  if (Dom.isBlock(node)) {
@@ -24787,7 +24964,7 @@ class Selection {
24787
24964
  node.innerHTML = html.toString();
24788
24965
  }
24789
24966
  else {
24790
- node.appendChild(html);
24967
+ Dom.append(node, html);
24791
24968
  }
24792
24969
  if (!this.j.isEditorMode() &&
24793
24970
  this.j.e.fire('insertHTML', node.innerHTML) === false) {
@@ -24796,9 +24973,7 @@ class Selection {
24796
24973
  if (!node.lastChild) {
24797
24974
  return;
24798
24975
  }
24799
- while (node.firstChild) {
24800
- fragment.appendChild(node.firstChild);
24801
- }
24976
+ Dom.moveContent(node, fragment);
24802
24977
  this.insertNode(fragment, insertCursorAfter, false);
24803
24978
  // There is no need to use synchronizeValues because you need to apply the changes immediately
24804
24979
  this.j.__imdSynchronizeValues();
@@ -24813,7 +24988,7 @@ class Selection {
24813
24988
  insertImage(url, styles = null, defaultWidth = null) {
24814
24989
  const image = isString(url) ? this.j.createInside.element('img') : url;
24815
24990
  if (isString(url)) {
24816
- image.setAttribute('src', url);
24991
+ attr(image, 'src', url);
24817
24992
  }
24818
24993
  if (defaultWidth != null) {
24819
24994
  let dw = defaultWidth.toString();
@@ -24831,8 +25006,10 @@ class Selection {
24831
25006
  const onload = () => {
24832
25007
  if (image.naturalHeight < image.offsetHeight ||
24833
25008
  image.naturalWidth < image.offsetWidth) {
24834
- image.style.width = '';
24835
- image.style.height = '';
25009
+ css(image, {
25010
+ width: '',
25011
+ height: ''
25012
+ });
24836
25013
  }
24837
25014
  image.removeEventListener('load', onload);
24838
25015
  };
@@ -24921,7 +25098,7 @@ class Selection {
24921
25098
  }
24922
25099
  else {
24923
25100
  const currentB = this.j.createInside.text(INVISIBLE_SPACE);
24924
- current.appendChild(currentB);
25101
+ Dom.append(current, currentB);
24925
25102
  current = currentB;
24926
25103
  }
24927
25104
  }
@@ -25072,7 +25249,7 @@ class Selection {
25072
25249
  if (!start) {
25073
25250
  const fakeNode = this.j.createInside.text(INVISIBLE_SPACE);
25074
25251
  if (!Dom.isTag(last, INSEPARABLE_TAGS)) {
25075
- last.appendChild(fakeNode);
25252
+ Dom.append(last, fakeNode);
25076
25253
  last = fakeNode;
25077
25254
  }
25078
25255
  else {
@@ -25140,7 +25317,7 @@ class Selection {
25140
25317
  const range = sel.getRangeAt(0);
25141
25318
  const clonedSelection = range.cloneContents();
25142
25319
  const div = this.j.createInside.div();
25143
- div.appendChild(clonedSelection);
25320
+ Dom.append(div, clonedSelection);
25144
25321
  return div.innerHTML;
25145
25322
  }
25146
25323
  return '';
@@ -25280,11 +25457,10 @@ class Selection {
25280
25457
  return toArray(node.childNodes).some(child => this.__isOrContainsBlock(child));
25281
25458
  }
25282
25459
  __wrapRunInFont(run) {
25283
- var _a;
25284
25460
  const font = this.j.createInside.element('font');
25285
25461
  const [first] = run;
25286
- (_a = first.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(font, first);
25287
- run.forEach(node => font.appendChild(node));
25462
+ Dom.before(first, font);
25463
+ run.forEach(node => Dom.append(font, node));
25288
25464
  return font;
25289
25465
  }
25290
25466
  /**
@@ -25295,7 +25471,7 @@ class Selection {
25295
25471
  const font = this.jodit.createInside.element('font', INVISIBLE_SPACE);
25296
25472
  this.insertNode(font, false, false);
25297
25473
  if (fakes && fakes[0]) {
25298
- font.appendChild(fakes[0]);
25474
+ Dom.append(font, fakes[0]);
25299
25475
  }
25300
25476
  yield font;
25301
25477
  Dom.unwrap(font);
@@ -25430,7 +25606,7 @@ class Selection {
25430
25606
  try {
25431
25607
  clearEmpties(fragment);
25432
25608
  clearEmpties(currentBox);
25433
- currentBox.parentNode.insertBefore(fragment, currentBox);
25609
+ Dom.before(currentBox, fragment);
25434
25610
  if (!edge && cursorOnTheRight && (br === null || br === void 0 ? void 0 : br.parentNode)) {
25435
25611
  const range = this.createRange();
25436
25612
  range.setStartBefore(br);
@@ -25441,9 +25617,9 @@ class Selection {
25441
25617
  }
25442
25618
  // After splitting some part can be empty
25443
25619
  const fillFakeParent = (fake) => {
25444
- var _a, _b, _c;
25445
- if (((_a = fake === null || fake === void 0 ? void 0 : fake.parentNode) === null || _a === void 0 ? void 0 : _a.firstChild) === ((_b = fake === null || fake === void 0 ? void 0 : fake.parentNode) === null || _b === void 0 ? void 0 : _b.lastChild)) {
25446
- (_c = fake === null || fake === void 0 ? void 0 : fake.parentNode) === null || _c === void 0 ? void 0 : _c.appendChild(br.cloneNode());
25620
+ const parent = fake === null || fake === void 0 ? void 0 : fake.parentNode;
25621
+ if (parent && parent.firstChild === parent.lastChild) {
25622
+ Dom.append(parent, br.cloneNode());
25447
25623
  }
25448
25624
  };
25449
25625
  fillFakeParent(prevFake);
@@ -26411,7 +26587,7 @@ let Jodit$1 = Jodit_1 = class Jodit extends ViewWithToolbar {
26411
26587
  this.setReadOnly(isDisabled || readOnly);
26412
26588
  this.__wasReadOnly = readOnly;
26413
26589
  if (this.editor) {
26414
- this.editor.setAttribute('aria-disabled', isDisabled.toString());
26590
+ attr(this.editor, 'aria-disabled', isDisabled);
26415
26591
  this.container.classList.toggle('jodit_disabled', isDisabled);
26416
26592
  this.e.fire('disabled', isDisabled);
26417
26593
  }
@@ -26435,10 +26611,10 @@ let Jodit$1 = Jodit_1 = class Jodit extends ViewWithToolbar {
26435
26611
  this.__wasReadOnly = isReadOnly;
26436
26612
  this.o.readonly = isReadOnly;
26437
26613
  if (isReadOnly) {
26438
- this.editor && this.editor.removeAttribute('contenteditable');
26614
+ this.editor && attr(this.editor, 'contenteditable', null);
26439
26615
  }
26440
26616
  else {
26441
- this.editor && this.editor.setAttribute('contenteditable', 'true');
26617
+ this.editor && attr(this.editor, 'contenteditable', true);
26442
26618
  }
26443
26619
  this.e && this.e.fire('readonly', isReadOnly);
26444
26620
  }
@@ -26597,14 +26773,14 @@ let Jodit$1 = Jodit_1 = class Jodit extends ViewWithToolbar {
26597
26773
  const property = kebabCase(key);
26598
26774
  container.style.setProperty(`--jd-${property}`, styleValues[key]);
26599
26775
  });
26600
- container.setAttribute('contenteditable', 'false');
26776
+ attr(container, 'contenteditable', false);
26601
26777
  let buffer = null;
26602
26778
  if (this.o.inline) {
26603
26779
  if (['TEXTAREA', 'INPUT'].indexOf(element.nodeName) === -1) {
26604
26780
  container = element;
26605
- element.setAttribute(__defaultClassesKey, element.className.toString());
26781
+ attr(element, __defaultClassesKey, element.className.toString());
26606
26782
  buffer = container.innerHTML;
26607
- container.innerHTML = '';
26783
+ Dom.detach(container);
26608
26784
  }
26609
26785
  container.classList.add('jodit_inline');
26610
26786
  container.classList.add('jodit-container');
@@ -26612,32 +26788,33 @@ let Jodit$1 = Jodit_1 = class Jodit extends ViewWithToolbar {
26612
26788
  // actual for inline mode
26613
26789
  if (element !== container) {
26614
26790
  // hide source element
26615
- if (element.style.display) {
26616
- element.setAttribute(__defaultStyleDisplayKey, element.style.display);
26791
+ const display = cssInline(element, 'display');
26792
+ if (display) {
26793
+ attr(element, __defaultStyleDisplayKey, display);
26617
26794
  }
26618
- element.style.display = 'none';
26795
+ css(element, 'display', 'none');
26619
26796
  }
26620
26797
  const SLOT = 'workplace-slot';
26621
26798
  // A slot that always stays ABOVE the toolbar (presence bars, banners…).
26622
26799
  // The `data-jodit-above-toolbar` attribute tells ViewWithToolbar to keep
26623
26800
  // the toolbar box below it when (re)attaching the toolbar container.
26624
26801
  const aboveSlot = this.c.div(this.getFullElName(SLOT, 'above'), NOEDIT);
26625
- aboveSlot.setAttribute('data-jodit-above-toolbar', '');
26802
+ attr(aboveSlot, 'data-jodit-above-toolbar', '');
26626
26803
  Dom.appendChildFirst(container, aboveSlot);
26627
26804
  const topSlot = this.c.div(this.getFullElName(SLOT, 'top'), NOEDIT);
26628
- container.appendChild(topSlot);
26805
+ Dom.append(container, topSlot);
26629
26806
  const centerSlot = this.c.div(this.getFullElName(SLOT, 'center'), NOEDIT);
26630
26807
  const workplace = this.c.div('jodit-workplace', NOEDIT);
26631
26808
  const leftSlot = this.c.div(this.getFullElName(SLOT, 'left'), NOEDIT);
26632
26809
  const rightSlot = this.c.div(this.getFullElName(SLOT, 'right'), NOEDIT);
26633
- centerSlot.appendChild(leftSlot);
26634
- centerSlot.appendChild(workplace);
26635
- centerSlot.appendChild(rightSlot);
26636
- container.appendChild(centerSlot);
26810
+ Dom.append(centerSlot, leftSlot);
26811
+ Dom.append(centerSlot, workplace);
26812
+ Dom.append(centerSlot, rightSlot);
26813
+ Dom.append(container, centerSlot);
26637
26814
  const bottomPanel = this.c.div(this.getFullElName(SLOT, 'bottom'), NOEDIT);
26638
- container.appendChild(bottomPanel);
26815
+ Dom.append(container, bottomPanel);
26639
26816
  if (element.parentNode && element !== container) {
26640
- element.parentNode.insertBefore(container, element);
26817
+ Dom.before(element, container);
26641
26818
  }
26642
26819
  Object.defineProperty(element, 'component', {
26643
26820
  enumerable: false,
@@ -26649,7 +26826,7 @@ let Jodit$1 = Jodit_1 = class Jodit extends ViewWithToolbar {
26649
26826
  'aria-disabled': false,
26650
26827
  tabindex: this.o.tabIndex
26651
26828
  });
26652
- workplace.appendChild(editor);
26829
+ Dom.append(workplace, editor);
26653
26830
  const currentPlace = {
26654
26831
  editor,
26655
26832
  element,
@@ -26703,7 +26880,7 @@ let Jodit$1 = Jodit_1 = class Jodit extends ViewWithToolbar {
26703
26880
  return callPromise(initResult, init);
26704
26881
  }
26705
26882
  addDisclaimer(elm) {
26706
- this.workplace.appendChild(elm);
26883
+ Dom.append(this.workplace, elm);
26707
26884
  }
26708
26885
  /**
26709
26886
  * Set current place object
@@ -26800,10 +26977,10 @@ let Jodit$1 = Jodit_1 = class Jodit extends ViewWithToolbar {
26800
26977
  // direction
26801
26978
  if (this.o.direction) {
26802
26979
  const direction = this.o.direction.toLowerCase() === 'rtl' ? 'rtl' : 'ltr';
26803
- this.editor.style.direction = direction;
26804
- this.editor.setAttribute('dir', direction);
26805
- this.container.style.direction = direction;
26806
- this.container.setAttribute('dir', direction);
26980
+ css(this.editor, 'direction', direction);
26981
+ attr(this.editor, 'dir', direction);
26982
+ css(this.container, 'direction', direction);
26983
+ attr(this.container, 'dir', direction);
26807
26984
  this.toolbar.setDirection(direction);
26808
26985
  }
26809
26986
  // proxy events
@@ -26896,23 +27073,23 @@ let Jodit$1 = Jodit_1 = class Jodit extends ViewWithToolbar {
26896
27073
  if (element.hasAttribute(__defaultStyleDisplayKey)) {
26897
27074
  const display = attr(element, __defaultStyleDisplayKey);
26898
27075
  if (display) {
26899
- element.style.display = display;
26900
- element.removeAttribute(__defaultStyleDisplayKey);
27076
+ css(element, 'display', display);
27077
+ attr(element, __defaultStyleDisplayKey, null);
26901
27078
  }
26902
27079
  }
26903
27080
  else {
26904
- element.style.display = '';
27081
+ css(element, 'display', '');
26905
27082
  }
26906
27083
  }
26907
27084
  else {
26908
27085
  if (element.hasAttribute(__defaultClassesKey)) {
26909
27086
  element.className =
26910
27087
  attr(element, __defaultClassesKey) || '';
26911
- element.removeAttribute(__defaultClassesKey);
27088
+ attr(element, __defaultClassesKey, null);
26912
27089
  }
26913
27090
  }
26914
27091
  if (element.hasAttribute('style') && !attr(element, 'style')) {
26915
- element.removeAttribute('style');
27092
+ attr(element, 'style', null);
26916
27093
  }
26917
27094
  statusbar.destruct();
26918
27095
  this.e.off(container);
@@ -33119,7 +33296,10 @@ function resolveTableSibling(sibling, backspace) {
33119
33296
  if (!Dom.isTag(sibling, 'table')) {
33120
33297
  return sibling;
33121
33298
  }
33122
- const cells = sibling.querySelectorAll('td,th');
33299
+ const cells = [];
33300
+ Dom.each(sibling, node => {
33301
+ Dom.isCell(node) && cells.push(node);
33302
+ });
33123
33303
  return cells.length ? cells[backspace ? cells.length - 1 : 0] : null;
33124
33304
  }
33125
33305
  function checkMoveListContent(jodit, mainClosestBox, sibling, backspace) {
@@ -33716,6 +33896,13 @@ pluginSystem.add('backspace', backspace);
33716
33896
  * Released under MIT see LICENSE.txt in the project root for license information.
33717
33897
  * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
33718
33898
  */
33899
+ const NOT_EMPTY_CONTENT_TAGS = new Set([
33900
+ 'img',
33901
+ 'table',
33902
+ 'jodit',
33903
+ 'iframe',
33904
+ 'hr'
33905
+ ]);
33719
33906
  class deleteCommand extends Plugin {
33720
33907
  afterInit(jodit) {
33721
33908
  jodit.e.on('afterCommand.delete', (command) => {
@@ -33742,9 +33929,9 @@ class deleteCommand extends Plugin {
33742
33929
  jodit.s.removeNode(current.firstChild);
33743
33930
  }
33744
33931
  if (!trim(jodit.editor.textContent || '') &&
33745
- !jodit.editor.querySelector('img,table,jodit,iframe,hr') &&
33932
+ !Dom.first(jodit.editor, node => Dom.isTag(node, NOT_EMPTY_CONTENT_TAGS)) &&
33746
33933
  (!current || !Dom.closest(current, 'table', jodit.editor))) {
33747
- jodit.editor.innerHTML = '';
33934
+ Dom.detach(jodit.editor);
33748
33935
  const node = jodit.s.setCursorIn(jodit.editor);
33749
33936
  jodit.s.removeNode(node);
33750
33937
  }
@@ -34014,13 +34201,20 @@ const ColorPickerWidget = (editor, callback, coldColor) => {
34014
34201
  }
34015
34202
  return stack.join('');
34016
34203
  };
34017
- form.appendChild(editor.c.fromHTML(`<div class="${cn}__groups">${eachColor(editor.o.colors)}</div>`));
34018
- form.appendChild(editor.c.fromHTML(`<div data-ref="extra" class="${cn}__extra"></div>`));
34204
+ Dom.append(form, editor.c.fromHTML(`<div class="${cn}__groups">${eachColor(editor.o.colors)}</div>`));
34205
+ Dom.append(form, editor.c.fromHTML(`<div data-ref="extra" class="${cn}__extra"></div>`));
34019
34206
  const { extra } = refs(form);
34020
- extra.appendChild(editor.c.fromHTML(`<div class="${cn}__hex"><input data-ref="hexInput" type="text" spellcheck="false" aria-label="HEX" placeholder="#FF0000" value="${valueHex || ''}"/></div>`));
34207
+ Dom.append(extra, editor.c.fromHTML(`<div class="${cn}__hex"><input data-ref="hexInput" type="text" spellcheck="false" aria-label="HEX" placeholder="#FF0000" value="${valueHex || ''}"/></div>`));
34021
34208
  const { hexInput } = refs(form);
34209
+ // Enter applies the value and closes the popup; removing the focused
34210
+ // input then makes Chrome fire `change` on it, which would apply the
34211
+ // same color a second time and toggle it off again. See #1459
34212
+ let appliedHexValue = null;
34022
34213
  const applyHexInput = () => {
34023
34214
  const raw = hexInput.value.trim();
34215
+ if (raw === appliedHexValue) {
34216
+ return;
34217
+ }
34024
34218
  const isHex = /^#?[0-9a-f]{3}(?:[0-9a-f]{3})?$/i.test(raw);
34025
34219
  const isRgb = /^rgba?\([\d\s.,%]+\)$/i.test(raw);
34026
34220
  if (!isHex && !isRgb) {
@@ -34028,6 +34222,7 @@ const ColorPickerWidget = (editor, callback, coldColor) => {
34028
34222
  }
34029
34223
  const color = normalizeColor(isHex && !raw.startsWith('#') ? '#' + raw : raw);
34030
34224
  if (color && isFunction(callback)) {
34225
+ appliedHexValue = raw;
34031
34226
  callback(color);
34032
34227
  }
34033
34228
  };
@@ -34044,7 +34239,7 @@ const ColorPickerWidget = (editor, callback, coldColor) => {
34044
34239
  applyHexInput();
34045
34240
  });
34046
34241
  if (editor.o.showBrowserColorPicker && hasBrowserColorPicker()) {
34047
- extra.appendChild(editor.c.fromHTML(`<div class="${cn}__native">${iconPalette}<input type="color" value="#ffffff"/></div>`));
34242
+ Dom.append(extra, editor.c.fromHTML(`<div class="${cn}__native">${iconPalette}<input type="color" value="#ffffff"/></div>`));
34048
34243
  editor.e.on(form, 'change', (e) => {
34049
34244
  e.stopPropagation();
34050
34245
  const target = e.target;
@@ -34134,8 +34329,8 @@ const TabsWidget = (jodit, tabs, state) => {
34134
34329
  const nameToTab = {};
34135
34330
  const buttonList = [];
34136
34331
  let firstTab = '';
34137
- box.appendChild(buttons);
34138
- box.appendChild(tabBox);
34332
+ Dom.append(box, buttons);
34333
+ Dom.append(box, tabBox);
34139
34334
  const setActive = (tab) => {
34140
34335
  if (!nameToTab[tab]) {
34141
34336
  return;
@@ -34159,18 +34354,18 @@ const TabsWidget = (jodit, tabs, state) => {
34159
34354
  if (!firstTab) {
34160
34355
  firstTab = name;
34161
34356
  }
34162
- buttons.appendChild(button.container);
34357
+ Dom.append(buttons, button.container);
34163
34358
  buttonList.push(button);
34164
34359
  button.container.classList.add('jodit-tabs__button', 'jodit-tabs__button_columns_' + tabs.length);
34165
34360
  if (!isFunction(content)) {
34166
- tab.appendChild(Component.isInstanceOf(content, UIElement)
34361
+ Dom.append(tab, Component.isInstanceOf(content, UIElement)
34167
34362
  ? content.container
34168
34363
  : content);
34169
34364
  }
34170
34365
  else {
34171
34366
  tab.classList.add('jodit-tab_empty');
34172
34367
  }
34173
- tabBox.appendChild(tab);
34368
+ Dom.append(tabBox, tab);
34174
34369
  button.onAction(() => {
34175
34370
  setActive(name);
34176
34371
  if (isFunction(content) && !Dom.isElement(content)) {
@@ -34293,13 +34488,13 @@ const FileSelectorWidget = (editor, callbacks, elm, close, isImage = true) => {
34293
34488
  !Dom.isComment(elm) &&
34294
34489
  (Dom.isTag(elm, 'img') || $$('img', elm).length)) {
34295
34490
  currentImage = elm.tagName === 'IMG' ? elm : $$('img', elm)[0];
34296
- val(form.container, 'input[name=url]', attr(currentImage, 'src'));
34297
- val(form.container, 'input[name=text]', attr(currentImage, 'alt'));
34491
+ val(form.container, 'url', attr(currentImage, 'src'));
34492
+ val(form.container, 'text', attr(currentImage, 'alt'));
34298
34493
  button.state.text = 'Update';
34299
34494
  }
34300
34495
  if (elm && Dom.isTag(elm, 'a')) {
34301
- val(form.container, 'input[name=url]', attr(elm, 'href'));
34302
- val(form.container, 'input[name=text]', attr(elm, 'title'));
34496
+ val(form.container, 'url', attr(elm, 'href'));
34497
+ val(form.container, 'text', attr(elm, 'title'));
34303
34498
  button.state.text = 'Update';
34304
34499
  }
34305
34500
  form.onSubmit(data => {
@@ -34321,8 +34516,8 @@ const FileSelectorWidget = (editor, callbacks, elm, close, isImage = true) => {
34321
34516
  box.classList.add('jodit-file-selector');
34322
34517
  return box;
34323
34518
  };
34324
- function val(elm, selector, value) {
34325
- const child = elm.querySelector(selector);
34519
+ function val(elm, name, value) {
34520
+ const child = Dom.first(elm, node => Dom.isTag(node, 'input') && attr(node, 'name') === name);
34326
34521
  if (!child) {
34327
34522
  return '';
34328
34523
  }
@@ -34435,7 +34630,7 @@ Config.prototype.controls.brush = {
34435
34630
  editor.execCommand('background', false, value);
34436
34631
  }
34437
34632
  else {
34438
- currentElement.style.backgroundColor = value;
34633
+ css(currentElement, 'backgroundColor', value);
34439
34634
  }
34440
34635
  dataBind(button, 'color', value);
34441
34636
  dataBind(button, 'color-mode', 'background');
@@ -34446,7 +34641,7 @@ Config.prototype.controls.brush = {
34446
34641
  editor.execCommand('forecolor', false, value);
34447
34642
  }
34448
34643
  else {
34449
- currentElement.style.color = value;
34644
+ css(currentElement, 'color', value);
34450
34645
  }
34451
34646
  dataBind(button, 'color', value);
34452
34647
  dataBind(button, 'color-mode', 'color');
@@ -34478,10 +34673,10 @@ Config.prototype.controls.brush = {
34478
34673
  Dom.isElement(current)) {
34479
34674
  switch (mode) {
34480
34675
  case 'color':
34481
- current.style.color = color;
34676
+ css(current, 'color', color);
34482
34677
  break;
34483
34678
  case 'background':
34484
- current.style.backgroundColor = color;
34679
+ css(current, 'backgroundColor', color);
34485
34680
  break;
34486
34681
  }
34487
34682
  }
@@ -34662,7 +34857,7 @@ function hasPreviousBlock(fake, jodit) {
34662
34857
  function insertParagraph(fake, editor, wrapperTag, style) {
34663
34858
  const isBR = wrapperTag.toLowerCase() === 'br', { createInside } = editor, p = createInside.element(wrapperTag), br = createInside.element('br');
34664
34859
  if (!isBR) {
34665
- p.appendChild(br);
34860
+ Dom.append(p, br);
34666
34861
  }
34667
34862
  Dom.after(fake, p);
34668
34863
  Dom.before(isBR ? p : br, fake);
@@ -34719,11 +34914,11 @@ function processEmptyLILeaf(fake, jodit, li) {
34719
34914
  Dom.safeRemove(list);
34720
34915
  }
34721
34916
  const newLi = insertParagraph(fake, jodit, listInsideLeaf ? 'li' : jodit.o.enter);
34722
- if (!rightPart.querySelector('li')) {
34917
+ if (!Dom.first(rightPart, node => Dom.isTag(node, 'li'))) {
34723
34918
  return;
34724
34919
  }
34725
34920
  if (listInsideLeaf) {
34726
- newLi.appendChild(rightPart);
34921
+ Dom.append(newLi, rightPart);
34727
34922
  }
34728
34923
  else {
34729
34924
  Dom.after(newLi, rightPart);
@@ -34793,7 +34988,7 @@ function wrapText(fake, jodit) {
34793
34988
  const currentBox = Dom.wrapInline(needWrap, jodit.o.enter, jodit);
34794
34989
  if (Dom.isEmpty(currentBox)) {
34795
34990
  const br = jodit.createInside.element('br');
34796
- currentBox.appendChild(br);
34991
+ Dom.append(currentBox, br);
34797
34992
  Dom.before(br, fake);
34798
34993
  }
34799
34994
  return currentBox;
@@ -35436,13 +35631,13 @@ function iframe(editor) {
35436
35631
  const link = doc.createElement('link');
35437
35632
  attr(link, 'rel', 'stylesheet');
35438
35633
  attr(link, 'href', href);
35439
- doc.head && doc.head.appendChild(link);
35634
+ doc.head && Dom.append(doc.head, link);
35440
35635
  });
35441
35636
  }
35442
35637
  if (opt.iframeStyle) {
35443
35638
  const style = doc.createElement('style');
35444
35639
  style.innerHTML = opt.iframeStyle;
35445
- doc.head && doc.head.appendChild(style);
35640
+ doc.head && Dom.append(doc.head, style);
35446
35641
  }
35447
35642
  })
35448
35643
  .on('createEditor', () => {
@@ -35450,7 +35645,7 @@ function iframe(editor) {
35450
35645
  return;
35451
35646
  }
35452
35647
  const iframe = editor.c.element('iframe');
35453
- iframe.style.display = 'block';
35648
+ css(iframe, 'display', 'block');
35454
35649
  iframe.src = 'about:blank';
35455
35650
  iframe.className = 'jodit-wysiwyg_iframe';
35456
35651
  attr(iframe, {
@@ -35461,7 +35656,7 @@ function iframe(editor) {
35461
35656
  if (opt.iframeSandbox != null) {
35462
35657
  attr(iframe, 'sandbox', opt.iframeSandbox);
35463
35658
  }
35464
- editor.workplace.appendChild(iframe);
35659
+ Dom.append(editor.workplace, iframe);
35465
35660
  editor.iframe = iframe;
35466
35661
  const result = editor.e.fire('generateDocumentStructure.iframe', null, editor);
35467
35662
  const init = () => {
@@ -35532,7 +35727,7 @@ function iframe(editor) {
35532
35727
  editor.e.on('afterSetMode afterInit afterAddPlace', toggleEditable);
35533
35728
  if (opt.height === 'auto') {
35534
35729
  doc.documentElement &&
35535
- (doc.documentElement.style.overflowY = 'hidden');
35730
+ css(doc.documentElement, 'overflowY', 'hidden');
35536
35731
  const resizeIframe = editor.async.throttle((...args) => {
35537
35732
  editor.async.requestAnimationFrame(() => {
35538
35733
  if (editor.editor &&
@@ -36999,8 +37194,10 @@ class placeholder extends Plugin {
36999
37194
  }
37000
37195
  this.placeholderElm = editor.c.fromHTML(`<span data-ref="placeholder" style="display: none;" class="jodit-placeholder">${editor.i18n(editor.o.placeholder)}</span>`);
37001
37196
  if (editor.o.direction === 'rtl') {
37002
- this.placeholderElm.style.right = '0px';
37003
- this.placeholderElm.style.direction = 'rtl';
37197
+ css(this.placeholderElm, {
37198
+ right: 0,
37199
+ direction: 'rtl'
37200
+ });
37004
37201
  }
37005
37202
  editor.e
37006
37203
  .on('readonly', (isReadOnly) => {
@@ -37024,22 +37221,22 @@ class placeholder extends Plugin {
37024
37221
  editor.editor;
37025
37222
  const style = editor.ew.getComputedStyle(wrapper);
37026
37223
  const styleEditor = editor.ew.getComputedStyle(editor.editor);
37027
- editor.workplace.appendChild(this.placeholderElm);
37224
+ Dom.append(editor.workplace, this.placeholderElm);
37028
37225
  const { firstChild } = editor.editor;
37029
37226
  if (Dom.isElement(firstChild) && !isMarker(firstChild)) {
37030
37227
  const style2 = editor.ew.getComputedStyle(firstChild);
37031
37228
  marginTop = parseInt(style2.getPropertyValue('margin-top'), 10);
37032
37229
  marginLeft = parseInt(style2.getPropertyValue('margin-left'), 10);
37033
- this.placeholderElm.style.fontSize =
37034
- parseInt(style2.getPropertyValue('font-size'), 10) + 'px';
37035
- this.placeholderElm.style.lineHeight =
37036
- style2.getPropertyValue('line-height');
37230
+ css(this.placeholderElm, {
37231
+ fontSize: parseInt(style2.getPropertyValue('font-size'), 10),
37232
+ lineHeight: style2.getPropertyValue('line-height')
37233
+ });
37037
37234
  }
37038
37235
  else {
37039
- this.placeholderElm.style.fontSize =
37040
- parseInt(style.getPropertyValue('font-size'), 10) + 'px';
37041
- this.placeholderElm.style.lineHeight =
37042
- style.getPropertyValue('line-height');
37236
+ css(this.placeholderElm, {
37237
+ fontSize: parseInt(style.getPropertyValue('font-size'), 10),
37238
+ lineHeight: style.getPropertyValue('line-height')
37239
+ });
37043
37240
  }
37044
37241
  css(this.placeholderElm, {
37045
37242
  display: 'block',
@@ -37521,7 +37718,15 @@ Config.prototype.controls.table = {
37521
37718
  '<label class="jodit-form__center">' +
37522
37719
  '<span>1</span> &times; <span>1</span>' +
37523
37720
  '</label>' +
37524
- '</form>'), rows = form.querySelectorAll('span')[0], cols = form.querySelectorAll('span')[1], blocksContainer = form.querySelector('.jodit-form__container'), options = form.querySelector('.jodit-form__options'), cells = [];
37721
+ '</form>'), spans = (() => {
37722
+ const list = [];
37723
+ Dom.each(form, node => {
37724
+ Dom.isTag(node, 'span') && list.push(node);
37725
+ });
37726
+ return list;
37727
+ })(), [rows, cols] = spans, blocksContainer = Dom.first(form, node => Dom.isHTMLElement(node) &&
37728
+ node.classList.contains('jodit-form__container')), options = Dom.first(form, node => Dom.isHTMLElement(node) &&
37729
+ node.classList.contains('jodit-form__options')), cells = [];
37525
37730
  const cnt = default_rows_count * default_cols_count;
37526
37731
  attr(blocksContainer, {
37527
37732
  role: 'grid',
@@ -37559,7 +37764,7 @@ Config.prototype.controls.table = {
37559
37764
  const k = parseInt(attr(cell, '-index') || '0', 10);
37560
37765
  const rows_count = Math.ceil((k + 1) / default_cols_count), cols_count = (k % default_cols_count) + 1;
37561
37766
  const crt = editor.createInside, tbody = crt.element('tbody'), table = crt.element('table');
37562
- table.appendChild(tbody);
37767
+ Dom.append(table, tbody);
37563
37768
  let first_td = null, tr, td;
37564
37769
  for (let i = 1; i <= rows_count; i += 1) {
37565
37770
  tr = crt.element('tr');
@@ -37569,13 +37774,13 @@ Config.prototype.controls.table = {
37569
37774
  first_td = td;
37570
37775
  }
37571
37776
  css(td, 'width', (100 / cols_count).toFixed(4) + '%');
37572
- td.appendChild(crt.element('br'));
37573
- tr.appendChild(crt.text('\n'));
37574
- tr.appendChild(crt.text('\t'));
37575
- tr.appendChild(td);
37777
+ Dom.append(td, crt.element('br'));
37778
+ Dom.append(tr, crt.text('\n'));
37779
+ Dom.append(tr, crt.text('\t'));
37780
+ Dom.append(tr, td);
37576
37781
  }
37577
- tbody.appendChild(crt.text('\n'));
37578
- tbody.appendChild(tr);
37782
+ Dom.append(tbody, crt.text('\n'));
37783
+ Dom.append(tbody, tr);
37579
37784
  }
37580
37785
  $$('input[type=checkbox]:checked', options).forEach((input) => {
37581
37786
  input.value
@@ -37691,9 +37896,9 @@ Config.prototype.controls.table = {
37691
37896
  const row = editor.c.div();
37692
37897
  attr(row, 'role', 'row');
37693
37898
  for (let j = 0; j < default_cols_count; j += 1) {
37694
- row.appendChild(cells[i * default_cols_count + j]);
37899
+ Dom.append(row, cells[i * default_cols_count + j]);
37695
37900
  }
37696
- blocksContainer.appendChild(row);
37901
+ Dom.append(blocksContainer, row);
37697
37902
  }
37698
37903
  if (cells[0]) {
37699
37904
  cells[0].className = 'hovered';
@@ -37806,7 +38011,7 @@ class wrapNodes extends Plugin {
37806
38011
  Dom.before(child, box);
37807
38012
  while (child && this.isSuitable(child)) {
37808
38013
  const next = child.nextSibling;
37809
- box.appendChild(child);
38014
+ Dom.append(box, child);
37810
38015
  child = next;
37811
38016
  }
37812
38017
  box.normalize();
@@ -37856,7 +38061,7 @@ function checkAloneListLeaf(child, jodit) {
37856
38061
  !Dom.isList(next.parentElement)) {
37857
38062
  const nextChild = Dom.findNotEmptySibling(next, false);
37858
38063
  if (Dom.isTag(result, 'ul')) {
37859
- result.appendChild(next);
38064
+ Dom.append(result, next);
37860
38065
  }
37861
38066
  else {
37862
38067
  result = Dom.wrap(next, 'ul', jodit.createInside);
@@ -38229,7 +38434,7 @@ class select extends Plugin {
38229
38434
  // The text must be the direct content of a list item that has a nested
38230
38435
  // list (the last level has no nested list and behaves correctly).
38231
38436
  if (!Dom.isTag(li, 'li') ||
38232
- !(li.querySelector('ul') || li.querySelector('ol'))) {
38437
+ !Dom.first(li, node => Dom.isTag(node, LIST_TAGS))) {
38233
38438
  return;
38234
38439
  }
38235
38440
  const measure = this.j.ed.createRange();
@@ -38402,7 +38607,7 @@ class resizer extends Plugin {
38402
38607
  }
38403
38608
  if (this.element && this.rect) {
38404
38609
  const workplacePosition = this.getWorkplacePosition();
38405
- const pos = offset(this.element, this.j, this.j.ed), left = parseInt(this.rect.style.left || '0', 10), top = parseInt(this.rect.style.top || '0', 10), w = this.rect.offsetWidth, h = this.rect.offsetHeight;
38610
+ const pos = offset(this.element, this.j, this.j.ed), left = parseInt(cssInline(this.rect, 'left') || '0', 10), top = parseInt(cssInline(this.rect, 'top') || '0', 10), w = this.rect.offsetWidth, h = this.rect.offsetHeight;
38406
38611
  const newTop = pos.top - workplacePosition.top, newLeft = pos.left - workplacePosition.left;
38407
38612
  if (top !== newTop ||
38408
38613
  left !== newLeft ||
@@ -38425,7 +38630,7 @@ class resizer extends Plugin {
38425
38630
  }
38426
38631
  };
38427
38632
  this.hideSizeViewer = () => {
38428
- this.sizeViewer.style.opacity = '0';
38633
+ css(this.sizeViewer, 'opacity', '0');
38429
38634
  };
38430
38635
  }
38431
38636
  /** @override */
@@ -38470,7 +38675,7 @@ class resizer extends Plugin {
38470
38675
  return;
38471
38676
  }
38472
38677
  const width = attr(image, 'width');
38473
- if (width && !css(image, 'width', true)) {
38678
+ if (width && !cssInline(image, 'width')) {
38474
38679
  css(image, 'width', width);
38475
38680
  attr(image, 'width', null);
38476
38681
  }
@@ -38629,7 +38834,7 @@ class resizer extends Plugin {
38629
38834
  if (changeAttrs) {
38630
38835
  attr(element, key, value);
38631
38836
  }
38632
- if (!changeAttrs || element.style[key]) {
38837
+ if (!changeAttrs || cssInline(element, key)) {
38633
38838
  css(element, key, value);
38634
38839
  }
38635
38840
  }
@@ -38684,16 +38889,16 @@ class resizer extends Plugin {
38684
38889
  });
38685
38890
  attr(wrapper, 'style', attr(element, 'style'));
38686
38891
  css(wrapper, {
38687
- display: element.style.display === 'inline-block'
38892
+ display: cssInline(element, 'display') === 'inline-block'
38688
38893
  ? 'inline-block'
38689
38894
  : 'block',
38690
38895
  width: element.offsetWidth,
38691
38896
  height: element.offsetHeight
38692
38897
  });
38693
38898
  if (element.parentNode) {
38694
- element.parentNode.insertBefore(wrapper, element);
38899
+ Dom.before(element, wrapper);
38695
38900
  }
38696
- wrapper.appendChild(element);
38901
+ Dom.append(wrapper, element);
38697
38902
  this.j.e.on(wrapper, 'click', () => {
38698
38903
  attr(wrapper, 'data-jodit-wrapper_active', true);
38699
38904
  });
@@ -38721,7 +38926,7 @@ class resizer extends Plugin {
38721
38926
  this.hideSizeViewer();
38722
38927
  return;
38723
38928
  }
38724
- this.sizeViewer.style.opacity = '1';
38929
+ css(this.sizeViewer, 'opacity', '1');
38725
38930
  this.sizeViewer.textContent = `${w} x ${h}`;
38726
38931
  this.j.async.setTimeout(this.hideSizeViewer, {
38727
38932
  timeout: this.j.o.resizer.hideSizeTimeout,
@@ -38738,10 +38943,10 @@ class resizer extends Plugin {
38738
38943
  this.isShown = true;
38739
38944
  if (!this.rect.parentNode) {
38740
38945
  markOwner(this.j, this.rect);
38741
- this.j.workplace.appendChild(this.rect);
38946
+ Dom.append(this.j.workplace, this.rect);
38742
38947
  }
38743
38948
  if (this.j.isFullSize) {
38744
- this.rect.style.zIndex = css(this.j.container, 'zIndex').toString();
38949
+ css(this.rect, 'zIndex', css(this.j.container, 'zIndex').toString());
38745
38950
  }
38746
38951
  this.updateSize();
38747
38952
  }
@@ -38900,7 +39105,7 @@ class selectCells extends Plugin {
38900
39105
  }
38901
39106
  else {
38902
39107
  if (!cell.firstChild) {
38903
- cell.appendChild(this.j.createInside.element('br'));
39108
+ Dom.append(cell, this.j.createInside.element('br'));
38904
39109
  }
38905
39110
  this.__tableModule.addSelection(cell);
38906
39111
  }
@@ -38922,7 +39127,7 @@ class selectCells extends Plugin {
38922
39127
  return;
38923
39128
  }
38924
39129
  if (!cell.firstChild) {
38925
- cell.appendChild(this.j.createInside.element('br'));
39130
+ Dom.append(cell, this.j.createInside.element('br'));
38926
39131
  }
38927
39132
  this.__isSelectionMode = true;
38928
39133
  this.__selectedCell = cell;
@@ -38989,10 +39194,9 @@ class selectCells extends Plugin {
38989
39194
  // Hack for FireFox for force redraw selection
38990
39195
  (() => {
38991
39196
  const n = this.j.createInside.fromHTML('<div style="color:rgba(0,0,0,0.01);width:0;height:0">&nbsp;</div>');
38992
- cell.appendChild(n);
39197
+ Dom.append(cell, n);
38993
39198
  this.j.async.setTimeout(() => {
38994
- var _a;
38995
- (_a = n.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(n);
39199
+ Dom.safeRemove(n);
38996
39200
  }, this.j.defaultTimeout / 5);
38997
39201
  })();
38998
39202
  }
@@ -39090,7 +39294,7 @@ class selectCells extends Plugin {
39090
39294
  const cells = this.__tableModule.getAllSelectedCells();
39091
39295
  cells.forEach(td => {
39092
39296
  Dom.detach(td);
39093
- td.appendChild(this.j.createInside.element('br'));
39297
+ Dom.append(td, this.j.createInside.element('br'));
39094
39298
  });
39095
39299
  this.unselectCells();
39096
39300
  this.j.s.setCursorIn(cells[0]);
@@ -39265,7 +39469,7 @@ class resizeCells extends Plugin {
39265
39469
  }
39266
39470
  showResizeHandle() {
39267
39471
  this.j.async.clearTimeout(this.hideTimeout);
39268
- this.j.workplace.appendChild(this.resizeHandler);
39472
+ Dom.append(this.j.workplace, this.resizeHandler);
39269
39473
  }
39270
39474
  hideResizeHandle() {
39271
39475
  this.hideTimeout = this.j.async.setTimeout(() => {
@@ -39332,8 +39536,7 @@ class resizeCells extends Plugin {
39332
39536
  }
39333
39537
  this.resizeDelta =
39334
39538
  x - this.startX + (!this.j.o.iframe ? 0 : workplacePosition.left);
39335
- this.resizeHandler.style.left =
39336
- x - (this.j.o.iframe ? 0 : workplacePosition.left) + 'px';
39539
+ css(this.resizeHandler, 'left', x - (this.j.o.iframe ? 0 : workplacePosition.left) + 'px');
39337
39540
  const sel = this.j.s.sel;
39338
39541
  sel && sel.removeAllRanges();
39339
39542
  }
@@ -39385,16 +39588,15 @@ class resizeCells extends Plugin {
39385
39588
  const needChangeWidth = this.isRTL ? !rightSide : rightSide;
39386
39589
  // right side
39387
39590
  if (needChangeWidth) {
39388
- this.workTable.style.width =
39389
- ((width + delta) / parentWidth) * 100 + '%';
39591
+ css(this.workTable, 'width', ((width + delta) / parentWidth) * 100 + '%');
39390
39592
  }
39391
39593
  else {
39392
39594
  const side = this.isRTL ? 'marginRight' : 'marginLeft';
39393
39595
  const margin = parseInt(this.j.ew.getComputedStyle(this.workTable)[side] || '0', 10);
39394
- this.workTable.style.width =
39395
- ((width - delta) / parentWidth) * 100 + '%';
39396
- this.workTable.style[side] =
39397
- ((margin + delta) / parentWidth) * 100 + '%';
39596
+ css(this.workTable, {
39597
+ width: ((width - delta) / parentWidth) * 100 + '%',
39598
+ [side]: ((margin + delta) / parentWidth) * 100 + '%'
39599
+ });
39398
39600
  }
39399
39601
  }
39400
39602
  /**
@@ -39418,11 +39620,10 @@ class resizeCells extends Plugin {
39418
39620
  return;
39419
39621
  }
39420
39622
  const workplacePosition = offset(this.j.workplace, this.j, this.j.od, true), parentBox = offset(table, this.j, this.j.ed);
39421
- this.resizeHandler.style.left =
39422
- (offsetX <= NEARBY ? box.left : box.left + box.width) -
39423
- workplacePosition.left +
39424
- delta +
39425
- 'px';
39623
+ css(this.resizeHandler, 'left', (offsetX <= NEARBY ? box.left : box.left + box.width) -
39624
+ workplacePosition.left +
39625
+ delta +
39626
+ 'px');
39426
39627
  Object.assign(this.resizeHandler.style, {
39427
39628
  height: parentBox.height + 'px',
39428
39629
  top: parentBox.top - workplacePosition.top + 'px'
@@ -39455,7 +39656,7 @@ class resizeCells extends Plugin {
39455
39656
  const parent = Dom.up(this.workCell, (elm) => Dom.isTag(elm, 'table'), editor.editor);
39456
39657
  if (parent) {
39457
39658
  const parentBox = parent.getBoundingClientRect();
39458
- this.resizeHandler.style.top = parentBox.top + 'px';
39659
+ css(this.resizeHandler, 'top', parentBox.top + 'px');
39459
39660
  }
39460
39661
  })
39461
39662
  .on('beforeSetMode.resize-cells', () => {
@@ -39552,7 +39753,7 @@ function tableKeyboardNavigation(editor) {
39552
39753
  if (!next) {
39553
39754
  tableModule.appendRow(table, !isPrev
39554
39755
  ? false
39555
- : table.querySelector('tr'), !isPrev);
39756
+ : Dom.first(table, node => Dom.isTag(node, 'tr')), !isPrev);
39556
39757
  next = getNextCell();
39557
39758
  }
39558
39759
  break;
@@ -39581,7 +39782,7 @@ function tableKeyboardNavigation(editor) {
39581
39782
  editor.e.fire('hidePopup hideResizer');
39582
39783
  if (!next.firstChild) {
39583
39784
  const first = editor.createInside.element('br');
39584
- next.appendChild(first);
39785
+ Dom.append(next, first);
39585
39786
  editor.s.setCursorBefore(first);
39586
39787
  }
39587
39788
  else {
@@ -39869,7 +40070,10 @@ function allowAttributes(jodit, nodeElm, hadEffect, allow) {
39869
40070
  hadEffect = true;
39870
40071
  }
39871
40072
  removeAttrs.forEach(attr => {
39872
- nodeElm.removeAttribute(attr);
40073
+ // `attrRaw` on purpose: the sanitizer must remove exactly the
40074
+ // attribute name from the live list, without the `attr()`
40075
+ // helper name normalization
40076
+ attrRaw(nodeElm, attr, null);
39873
40077
  });
39874
40078
  }
39875
40079
  }
@@ -39933,7 +40137,7 @@ function fillEmptyParagraph(jodit, nodeElm, hadEffect) {
39933
40137
  Dom.isEmpty(nodeElm, INSEPARABLE_TAGS) &&
39934
40138
  !Dom.isTag(nodeElm, TABLE_CONTAINER_TAGS)) {
39935
40139
  const br = jodit.createInside.element('br');
39936
- nodeElm.appendChild(br);
40140
+ Dom.append(nodeElm, br);
39937
40141
  return true;
39938
40142
  }
39939
40143
  return hadEffect;
@@ -39949,7 +40153,13 @@ function fillEmptyParagraph(jodit, nodeElm, hadEffect) {
39949
40153
  */
39950
40154
  function removeEmptyTextNode(jodit, node, hadEffect, arg, argi, currentNode) {
39951
40155
  if (Dom.isText(node) && !node.nodeValue) {
39952
- if (node === currentNode && jodit.s.isCollapsed()) {
40156
+ // Restore the caret only while the editor owns focus. The walker runs
40157
+ // asynchronously, so the user may have already tabbed away — moving the
40158
+ // selection here would call `focus()` and steal focus back from the
40159
+ // element the user navigated to (e.g. Shift+Tab accessibility flow).
40160
+ if (node === currentNode &&
40161
+ jodit.s.isFocused() &&
40162
+ jodit.s.isCollapsed()) {
39953
40163
  jodit.s.setCursorAfter(node);
39954
40164
  }
39955
40165
  Dom.safeRemove(node);
@@ -39978,7 +40188,10 @@ function removeInvTextNodes(jodit, node, hadEffect, arg, argi, currentNode) {
39978
40188
  return hadEffect;
39979
40189
  }
39980
40190
  node.nodeValue = node.nodeValue.replace(INVISIBLE_SPACE_REG_EXP(), '');
39981
- if (node === currentNode && jodit.s.isCollapsed()) {
40191
+ // Same guard as in `removeEmptyTextNode`: the walker is asynchronous, so
40192
+ // never move the selection (it re-focuses the editor) once the user has
40193
+ // moved focus elsewhere.
40194
+ if (node === currentNode && jodit.s.isFocused() && jodit.s.isCollapsed()) {
39982
40195
  jodit.s.setCursorAfter(node);
39983
40196
  }
39984
40197
  if (!node.nodeValue) {
@@ -40591,7 +40804,7 @@ Config.prototype.controls.print = {
40591
40804
  height: 0,
40592
40805
  border: 0
40593
40806
  });
40594
- getContainer(editor, Config).appendChild(iframe);
40807
+ Dom.append(getContainer(editor, Config), iframe);
40595
40808
  const afterFinishPrint = () => {
40596
40809
  editor.e.off(editor.ow, 'mousemove', afterFinishPrint);
40597
40810
  Dom.safeRemove(iframe);
@@ -40620,7 +40833,7 @@ Config.prototype.controls.print = {
40620
40833
  -webkit-print-color-adjust: exact;
40621
40834
  }
40622
40835
  }`;
40623
- myWindow.document.head.appendChild(style);
40836
+ Dom.append(myWindow.document.head, style);
40624
40837
  myWindow.focus();
40625
40838
  myWindow.print();
40626
40839
  }
@@ -40794,7 +41007,7 @@ class AceEditor extends SourceEditor {
40794
41007
  return;
40795
41008
  }
40796
41009
  const fakeMirror = this.j.c.div('jodit-source__mirror-fake');
40797
- this.container.appendChild(fakeMirror);
41010
+ Dom.append(this.container, fakeMirror);
40798
41011
  const ace = editor.ow.ace;
40799
41012
  this.instance = ace.edit(fakeMirror);
40800
41013
  if (editor.o.direction === 'rtl') {
@@ -40951,8 +41164,8 @@ class TextAreaEditor extends SourceEditor {
40951
41164
  constructor() {
40952
41165
  super(...arguments);
40953
41166
  this.autosize = this.j.async.debounce(() => {
40954
- this.instance.style.height = 'auto';
40955
- this.instance.style.height = this.instance.scrollHeight + 'px';
41167
+ css(this.instance, 'height', 'auto');
41168
+ css(this.instance, 'height', this.instance.scrollHeight);
40956
41169
  }, this.j.defaultTimeout, true);
40957
41170
  }
40958
41171
  init(editor) {
@@ -40960,7 +41173,7 @@ class TextAreaEditor extends SourceEditor {
40960
41173
  class: 'jodit-source__mirror',
40961
41174
  dir: editor.o.direction === 'rtl' ? 'rtl' : undefined
40962
41175
  });
40963
- this.container.appendChild(this.instance);
41176
+ Dom.append(this.container, this.instance);
40964
41177
  editor.e
40965
41178
  .on(this.instance, 'mousedown keydown touchstart input', editor.async.debounce(this.toWYSIWYG, editor.defaultTimeout))
40966
41179
  .on('setMinHeight.source', (minHeightD) => {
@@ -41288,9 +41501,9 @@ class source extends Plugin {
41288
41501
  /** @override */
41289
41502
  afterInit(editor) {
41290
41503
  this.mirrorContainer = editor.c.div('jodit-source');
41291
- editor.workplace.appendChild(this.mirrorContainer);
41504
+ Dom.append(editor.workplace, this.mirrorContainer);
41292
41505
  editor.e.on('afterAddPlace changePlace afterInit', () => {
41293
- editor.workplace.appendChild(this.mirrorContainer);
41506
+ Dom.append(editor.workplace, this.mirrorContainer);
41294
41507
  });
41295
41508
  this.sourceEditor = createSourceEditor('area', editor, this.mirrorContainer, this.toWYSIWYG, this.fromWYSIWYG);
41296
41509
  editor.e.on(editor.ow, 'keydown', (e) => {