@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
@@ -1783,7 +1783,6 @@ var bn, xn = o((() => {
1783
1783
  return e.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&").replace(/-/g, "\\x2d");
1784
1784
  };
1785
1785
  })), Cn = /* @__PURE__ */ s(((e) => {
1786
- Object.defineProperty(e, "__esModule", { value: true });
1787
1786
  function t(e) {
1788
1787
  return Object.prototype.toString.call(e) === "[object Object]";
1789
1788
  }
@@ -2024,29 +2023,34 @@ var bn, xn = o((() => {
2024
2023
  let n = "@" + t.name, r = t.params ? e.rawValue(t, "params") : "", a = t.raws.afterName;
2025
2024
  return a === void 0 ? a = r ? " " : "" : a === "" && r && !i.test(r[0]) && (a = " "), n + a + r;
2026
2025
  }
2027
- function l(e, t, n) {
2026
+ function l(e) {
2027
+ if (!e.prop.startsWith("--")) return false;
2028
+ let t = e.raws.before;
2029
+ return t === void 0 || !/\S$/.test(t);
2030
+ }
2031
+ function u(e, t, n) {
2028
2032
  let r = n.nodes, i = r.length - 1;
2029
2033
  for (; i > 0 && r[i].type === "comment";) --i;
2030
2034
  let a = e.raw(n, "semicolon"), o = n.type === "document";
2031
2035
  for (let e = r.length - 1; e >= 0; e--) {
2032
2036
  let n = r[e], s = i !== e || a;
2033
- !s && e < r.length - 1 && (n.type === "atrule" && !n.nodes || n.type === "decl" && n.prop.startsWith("--")) && (s = true), t.push({
2037
+ !s && e < r.length - 1 && (n.type === "atrule" && !n.nodes || n.type === "decl" && l(n)) && (s = true), t.push({
2034
2038
  document: o,
2035
2039
  node: n,
2036
2040
  semicolon: s
2037
2041
  });
2038
2042
  }
2039
2043
  }
2040
- function u(e, t, n, r) {
2044
+ function d(e, t, n, r) {
2041
2045
  let i = e.raw(n, "between", "beforeOpen");
2042
2046
  e.builder(a(r + i) + "{", n, "start");
2043
2047
  let o = n.nodes && n.nodes.length, s = () => {
2044
2048
  let t = o ? e.raw(n, "after") : e.raw(n, "after", "emptyBody");
2045
2049
  t && e.builder(a(t)), e.builder("}", n, "end"), n.type === "rule" && n.raws.ownSemicolon && e.builder(a(n.raws.ownSemicolon), n, "end");
2046
2050
  };
2047
- o ? (t.push(s), l(e, t, n)) : s();
2051
+ o ? (t.push(s), u(e, t, n)) : s();
2048
2052
  }
2049
- var d = class e {
2053
+ var f = class e {
2050
2054
  constructor(e) {
2051
2055
  this.builder = e;
2052
2056
  }
@@ -2083,14 +2087,14 @@ var bn, xn = o((() => {
2083
2087
  "rule",
2084
2088
  "stringify"
2085
2089
  ].every((e) => this[e] === n[e]), i = [];
2086
- for (l(this, i, t); i.length > 0;) {
2090
+ for (u(this, i, t); i.length > 0;) {
2087
2091
  let e = i.pop();
2088
2092
  if (typeof e == "function") {
2089
2093
  e();
2090
2094
  continue;
2091
2095
  }
2092
2096
  let t = e.node, n = this.raw(t, "before");
2093
- 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);
2097
+ 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);
2094
2098
  }
2095
2099
  }
2096
2100
  comment(e) {
@@ -2200,7 +2204,7 @@ var bn, xn = o((() => {
2200
2204
  this[e.type](e, t);
2201
2205
  }
2202
2206
  };
2203
- t.exports = d, d.default = d;
2207
+ t.exports = f, f.default = f;
2204
2208
  })), kn = /* @__PURE__ */ s(((e, t) => {
2205
2209
  var n = On();
2206
2210
  function r(e, t) {
@@ -2642,7 +2646,7 @@ var bn, xn = o((() => {
2642
2646
  }
2643
2647
  replaceValues(e, t, n) {
2644
2648
  return n || (n = t, t = {}), this.walkDecls((r) => {
2645
- t.props && !t.props.includes(r.prop) || t.fast && !r.value.includes(t.fast) || (r.value = r.value.replace(e, n));
2649
+ (!t.props || t.props.includes(r.prop)) && (!t.fast || r.value.includes(t.fast)) && (r.value = r.value.replace(e, n));
2646
2650
  }), this.markDirty(), this;
2647
2651
  }
2648
2652
  some(e) {
@@ -3036,8 +3040,12 @@ var bn, xn = o((() => {
3036
3040
  split(e, t, n) {
3037
3041
  if (typeof e != "string") return [];
3038
3042
  let r = [], i = "", a = false, o = 0, s = false, c = "", l = false;
3039
- 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;
3040
- return (n || i !== "") && r.push(i.trim()), r;
3043
+ 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) {
3044
+ let e = i.trim();
3045
+ (n || e !== "") && r.push(e), i = "", a = false;
3046
+ } else i += u;
3047
+ let u = i.trim();
3048
+ return (n || u !== "") && r.push(u), r;
3041
3049
  }
3042
3050
  };
3043
3051
  t.exports = n, n.default = n;
@@ -3140,8 +3148,8 @@ var bn, xn = o((() => {
3140
3148
  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);
3141
3149
  } else if (this.css) {
3142
3150
  let e;
3143
- for (; (e = this.css.lastIndexOf("/*#")) !== -1;) {
3144
- let t = this.css.indexOf("*/", e + 3);
3151
+ for (; (e = this.css.lastIndexOf("/*# sourceMappingURL=")) !== -1;) {
3152
+ let t = this.css.indexOf("*/", e + 21);
3145
3153
  if (t === -1) break;
3146
3154
  for (; e > 0 && this.css[e - 1] === "\n";) e--;
3147
3155
  this.css = this.css.slice(0, e) + this.css.slice(t + 2);
@@ -3578,7 +3586,7 @@ var bn, xn = o((() => {
3578
3586
  freeSemicolon(e) {
3579
3587
  if (this.spaces += e[1], this.current.nodes) {
3580
3588
  let t = this.current.nodes[this.current.nodes.length - 1];
3581
- 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);
3589
+ 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++);
3582
3590
  }
3583
3591
  }
3584
3592
  getPosition(e) {
@@ -4197,7 +4205,7 @@ var bn, xn = o((() => {
4197
4205
  })), Qn = /* @__PURE__ */ s(((e, t) => {
4198
4206
  var n = Fn(), r = Xn(), i = Zn(), a = zn(), o = class {
4199
4207
  constructor(e = []) {
4200
- this.version = "8.5.26", this.plugins = this.normalize(e);
4208
+ this.version = "8.5.28", this.plugins = this.normalize(e);
4201
4209
  }
4202
4210
  normalize(e) {
4203
4211
  let t = [];
@@ -4223,7 +4231,7 @@ var bn, xn = o((() => {
4223
4231
  b.plugin = function(e, t) {
4224
4232
  let n = false;
4225
4233
  function r(...r) {
4226
- 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") &&
4234
+ 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") &&
4227
4235
  /* c8 ignore next 7 */
4228
4236
  console.warn(e + ": 里面 postcss.plugin 被弃用. 迁移指南:\nhttps://www.w3ctech.com/topic/2226"));
4229
4237
  let i = t(...r);
@@ -5134,7 +5142,7 @@ var bn, xn = o((() => {
5134
5142
  * Released under MIT see LICENSE.txt in the project root for license information.
5135
5143
  * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
5136
5144
  */
5137
- const APP_VERSION = "4.13.22";
5145
+ const APP_VERSION = "4.14.2";
5138
5146
  // prettier-ignore
5139
5147
  const ES = "es2020";
5140
5148
  const IS_ES_MODERN = true;
@@ -5642,6 +5650,9 @@ const map$1 = {};
5642
5650
  function reset(key) {
5643
5651
  var _a, _b;
5644
5652
  if (!(key in map$1)) {
5653
+ // Raw DOM API on purpose: this bootstrap helper is imported by
5654
+ // `to-array`, which the `Dom` module itself depends on — importing
5655
+ // `Dom` here would create a circular dependency
5645
5656
  const iframe = globalDocument.createElement('iframe');
5646
5657
  try {
5647
5658
  iframe.src = 'about:blank';
@@ -6014,6 +6025,21 @@ function css(element, key, value, onlyStyleMode = false) {
6014
6025
  /**
6015
6026
  * Clear center align
6016
6027
  */
6028
+ /**
6029
+ * Read the exact inline value of a CSS property (the `style` attribute).
6030
+ * Unlike `css()` it never touches computed styles (no layout access) and does
6031
+ * not normalize the result, so it is safe for exact string comparisons and
6032
+ * save/restore. Returns an empty string when the property is not set inline.
6033
+ *
6034
+ * @example
6035
+ * ```js
6036
+ * cssInline(elm, 'zIndex'); // '' or '100'
6037
+ * cssInline(elm, 'width'); // '0px' (css(elm, 'width', true) would return 0)
6038
+ * ```
6039
+ */
6040
+ function cssInline(element, key) {
6041
+ return element.style.getPropertyValue(kebabCase(key));
6042
+ }
6017
6043
  const clearCenterAlign = (image) => {
6018
6044
  if (css(image, 'display') === 'block') {
6019
6045
  css(image, 'display', '');
@@ -6078,6 +6104,24 @@ function attr(elm, keyOrAttributes, value) {
6078
6104
  }
6079
6105
  return elm.getAttribute(key);
6080
6106
  }
6107
+ /**
6108
+ * Exact-name attribute access: no camelCase → kebab-case conversion, no
6109
+ * `data-` fallback and no `px` stripping. Use it where the attribute name must
6110
+ * be taken verbatim — sanitizers and attribute comparison (`onLoad`, `viewBox`,
6111
+ * `xlink:href`). `null` removes the attribute.
6112
+ */
6113
+ function attrRaw(elm, name, value) {
6114
+ if (value === undefined) {
6115
+ return elm.getAttribute(name);
6116
+ }
6117
+ if (value == null) {
6118
+ if (elm.hasAttribute(name)) {
6119
+ elm.removeAttribute(name);
6120
+ }
6121
+ return;
6122
+ }
6123
+ elm.setAttribute(name, value);
6124
+ }
6081
6125
 
6082
6126
  /*!
6083
6127
  * Jodit Editor (https://xdsoft.net/jodit/)
@@ -6645,56 +6689,39 @@ class Dom {
6645
6689
  * Get first matched node inside root
6646
6690
  */
6647
6691
  static first(root, condition) {
6648
- let first = root === null || root === void 0 ? void 0 : root.firstChild;
6649
- if (!first) {
6650
- return null;
6651
- }
6652
- do {
6653
- if (condition(first)) {
6654
- return first;
6655
- }
6656
- let next = first.firstChild;
6657
- if (!next) {
6658
- next = first.nextSibling;
6659
- }
6660
- if (!next && first.parentNode !== root) {
6661
- do {
6662
- first = first.parentNode;
6663
- } while (first &&
6664
- !(first === null || first === void 0 ? void 0 : first.nextSibling) &&
6665
- first.parentNode !== root);
6666
- next = first === null || first === void 0 ? void 0 : first.nextSibling;
6667
- }
6668
- first = next;
6669
- } while (first);
6670
- return null;
6692
+ return Dom.__deepMost(root, condition, false);
6671
6693
  }
6672
6694
  /**
6673
6695
  * Get last matched node inside root
6674
6696
  */
6675
6697
  static last(root, condition) {
6676
- let last = root === null || root === void 0 ? void 0 : root.lastChild;
6677
- if (!last) {
6698
+ return Dom.__deepMost(root, condition, true);
6699
+ }
6700
+ /**
6701
+ * Depth-first search for the first matched node inside root:
6702
+ * in document order (`reverse = false`) or in reverse order
6703
+ */
6704
+ static __deepMost(root, condition, reverse) {
6705
+ const child = reverse ? 'lastChild' : 'firstChild', sibling = reverse ? 'previousSibling' : 'nextSibling';
6706
+ let current = root === null || root === void 0 ? void 0 : root[child];
6707
+ if (!current) {
6678
6708
  return null;
6679
6709
  }
6680
6710
  do {
6681
- if (condition(last)) {
6682
- return last;
6683
- }
6684
- let next = last.lastChild;
6685
- if (!next) {
6686
- next = last.previousSibling;
6711
+ if (condition(current)) {
6712
+ return current;
6687
6713
  }
6688
- if (!next && last.parentNode !== root) {
6714
+ let next = current[child] || current[sibling];
6715
+ if (!next && current.parentNode !== root) {
6689
6716
  do {
6690
- last = last.parentNode;
6691
- } while (last &&
6692
- !(last === null || last === void 0 ? void 0 : last.previousSibling) &&
6693
- last.parentNode !== root);
6694
- next = last === null || last === void 0 ? void 0 : last.previousSibling;
6695
- }
6696
- last = next;
6697
- } while (last);
6717
+ current = current.parentNode;
6718
+ } while (current &&
6719
+ !current[sibling] &&
6720
+ current.parentNode !== root);
6721
+ next = current === null || current === void 0 ? void 0 : current[sibling];
6722
+ }
6723
+ current = next;
6724
+ } while (current);
6698
6725
  return null;
6699
6726
  }
6700
6727
  /**
@@ -6710,12 +6737,17 @@ class Dom {
6710
6737
  return Dom.find(node, condition, root, true, withChild);
6711
6738
  }
6712
6739
  static prevWithClass(node, className) {
6713
- return Dom.prev(node, node => {
6714
- return (Dom.isElement(node) && node.classList.contains(className));
6715
- }, node.parentNode);
6740
+ return Dom.__siblingWithClass(node, className, true);
6716
6741
  }
6717
6742
  static nextWithClass(node, className) {
6718
- return Dom.next(node, elm => Dom.isElement(elm) && elm.classList.contains(className), node.parentNode);
6743
+ return Dom.__siblingWithClass(node, className, false);
6744
+ }
6745
+ static __siblingWithClass(node, className, left) {
6746
+ const condition = (elm) => Dom.isElement(elm) && elm.classList.contains(className);
6747
+ const parent = node.parentNode;
6748
+ return (left
6749
+ ? Dom.prev(node, condition, parent)
6750
+ : Dom.next(node, condition, parent));
6719
6751
  }
6720
6752
  /**
6721
6753
  * Find next/prev node what `condition(next) === true`
@@ -6850,9 +6882,6 @@ class Dom {
6850
6882
  (!(Dom.isText(n) || Dom.isComment(n)) ||
6851
6883
  trim((n === null || n === void 0 ? void 0 : n.nodeValue) || '').length)), root);
6852
6884
  }
6853
- /**
6854
- * Returns the previous (`left = true`) or next sibling of the node
6855
- */
6856
6885
  static sibling(node, left) {
6857
6886
  return left ? node.previousSibling : node.nextSibling;
6858
6887
  }
@@ -6916,40 +6945,24 @@ class Dom {
6916
6945
  * Append new element in the start of root
6917
6946
  */
6918
6947
  static appendChildFirst(root, newElement) {
6919
- const child = root.firstChild;
6920
- if (child) {
6921
- if (child !== newElement) {
6922
- root.insertBefore(newElement, child);
6923
- }
6924
- }
6925
- else {
6926
- root.appendChild(newElement);
6948
+ if (root.firstChild !== newElement) {
6949
+ Dom.prepend(root, newElement);
6927
6950
  }
6928
6951
  }
6929
6952
  /**
6930
6953
  * Insert newElement after element
6931
6954
  */
6932
6955
  static after(elm, newElement) {
6933
- const { parentNode } = elm;
6934
- if (!parentNode) {
6935
- return;
6936
- }
6937
- if (parentNode.lastChild === elm) {
6938
- parentNode.appendChild(newElement);
6939
- }
6940
- else {
6941
- parentNode.insertBefore(newElement, elm.nextSibling);
6942
- }
6956
+ var _a;
6957
+ // `insertBefore` with a `null` reference appends to the end
6958
+ (_a = elm.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(newElement, elm.nextSibling);
6943
6959
  }
6944
6960
  /**
6945
6961
  * Insert newElement before element
6946
6962
  */
6947
6963
  static before(elm, newElement) {
6948
- const { parentNode } = elm;
6949
- if (!parentNode) {
6950
- return;
6951
- }
6952
- parentNode.insertBefore(newElement, elm);
6964
+ var _a;
6965
+ (_a = elm.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(newElement, elm);
6953
6966
  }
6954
6967
  /**
6955
6968
  * Insert newElement as first child inside element
@@ -6967,10 +6980,10 @@ class Dom {
6967
6980
  root.appendChild(newElement);
6968
6981
  }
6969
6982
  }
6970
- /**
6971
- * Move all content to another element
6972
- */
6973
- static moveContent(from, to, inStart = false, filter = () => true) {
6983
+ static moveContent(from, to, inStart = false,
6984
+ // `any` reconciles the browser `Node` overload with the `VNode` one:
6985
+ // a callback typed for one is not assignable to the other
6986
+ filter = () => true) {
6974
6987
  const fragment = (from.ownerDocument || globalDocument).createDocumentFragment();
6975
6988
  toArray(from.childNodes)
6976
6989
  .filter(elm => {
@@ -6980,15 +6993,11 @@ class Dom {
6980
6993
  Dom.safeRemove(elm);
6981
6994
  return false;
6982
6995
  })
6983
- .forEach((node) => {
6996
+ .forEach(node => {
6984
6997
  fragment.appendChild(node);
6985
6998
  });
6986
- if (!inStart || !to.firstChild) {
6987
- to.appendChild(fragment);
6988
- }
6989
- else {
6990
- to.insertBefore(fragment, to.firstChild);
6991
- }
6999
+ // `appendChild`/`insertBefore` with a `null` reference append to the end
7000
+ to.insertBefore(fragment, inStart ? to.firstChild : null);
6992
7001
  }
6993
7002
  /**
6994
7003
  * Check root contains child or equal child
@@ -7038,8 +7047,8 @@ class Dom {
7038
7047
  if (!node) {
7039
7048
  return;
7040
7049
  }
7041
- dataBind(node, '__old_display', node.style.display);
7042
- node.style.display = 'none';
7050
+ dataBind(node, '__old_display', node.style.getPropertyValue('display'));
7051
+ node.style.setProperty('display', 'none');
7043
7052
  }
7044
7053
  /**
7045
7054
  * Show element
@@ -7049,8 +7058,8 @@ class Dom {
7049
7058
  return;
7050
7059
  }
7051
7060
  const display = dataBind(node, '__old_display');
7052
- if (node.style.display === 'none') {
7053
- node.style.display = display || '';
7061
+ if (node.style.getPropertyValue('display') === 'none') {
7062
+ node.style.setProperty('display', display || null);
7054
7063
  }
7055
7064
  }
7056
7065
  static isTag(node, tagNames) {
@@ -7099,11 +7108,17 @@ class Dom {
7099
7108
  return value.replace(TEMP_ELEMENT_REG_EXP, '$2');
7100
7109
  }
7101
7110
  /**
7102
- * Get temporary list
7103
- * @deprecated Just do not use it, it is not needed anymore
7111
+ * Collect the temporary elements (`data-jodit-temp`) inside the root.
7112
+ * A plain tree walk on purpose: no selector engine, works on VNode.
7104
7113
  */
7105
7114
  static temporaryList(root) {
7106
- return toArray(root.querySelectorAll(`[${TEMP_ATTR}]`));
7115
+ const result = [];
7116
+ Dom.each(root, node => {
7117
+ if (Dom.isHTMLElement(node) && node.hasAttribute(TEMP_ATTR)) {
7118
+ result.push(node);
7119
+ }
7120
+ });
7121
+ return result;
7107
7122
  }
7108
7123
  }
7109
7124
 
@@ -7495,21 +7510,39 @@ function cache(_, name, descriptor) {
7495
7510
  return value;
7496
7511
  };
7497
7512
  }
7513
+ function getOwnerDocument(component) {
7514
+ const od = component.od;
7515
+ return od !== null && od !== void 0 ? od : document;
7516
+ }
7498
7517
  function cacheHTML(target, _, descriptor) {
7499
7518
  const fn = descriptor.value;
7500
7519
  if (!isFunction(fn)) {
7501
7520
  throw error('Handler must be a Function');
7502
7521
  }
7503
7522
  let useCache = true;
7523
+ /**
7524
+ * The cache is keyed by the owner document first and only then by the
7525
+ * component class. A page can create editors inside different documents
7526
+ * (iframes) and destroy those documents later: a template cached from a
7527
+ * dead document would otherwise be cloned for every subsequent editor,
7528
+ * whose buttons then never react to clicks.
7529
+ */
7504
7530
  const cached = new WeakMap();
7505
7531
  descriptor.value = function (...attrs) {
7506
7532
  var _a;
7507
- if (useCache && cached.has(this.constructor)) {
7508
- return (_a = cached.get(this.constructor)) === null || _a === void 0 ? void 0 : _a.cloneNode(true);
7533
+ const doc = getOwnerDocument(this);
7534
+ const docCache = cached.get(doc);
7535
+ if (useCache && (docCache === null || docCache === void 0 ? void 0 : docCache.has(this.constructor))) {
7536
+ return (_a = docCache.get(this.constructor)) === null || _a === void 0 ? void 0 : _a.cloneNode(true);
7509
7537
  }
7510
7538
  const value = fn.apply(this, attrs);
7511
7539
  if (useCache && Dom.isElement(value)) {
7512
- cached.set(this.constructor, value);
7540
+ if (docCache) {
7541
+ docCache.set(this.constructor, value);
7542
+ }
7543
+ else {
7544
+ cached.set(doc, new WeakMap([[this.constructor, value]]));
7545
+ }
7513
7546
  }
7514
7547
  return useCache ? value.cloneNode(true) : value;
7515
7548
  };
@@ -8545,10 +8578,10 @@ const appendScriptAsync = cacheLoaders((jodit, url) => {
8545
8578
  src: completeUrl(url)
8546
8579
  });
8547
8580
  if (jodit.o.nonce) {
8548
- script.setAttribute('nonce', jodit.o.nonce);
8581
+ attr(script, 'nonce', jodit.o.nonce);
8549
8582
  }
8550
8583
  jodit.e.one(script, 'error', reject).one(script, 'load', resolve);
8551
- jodit.od.body.appendChild(script);
8584
+ Dom.append(jodit.od.body, script);
8552
8585
  });
8553
8586
  });
8554
8587
  /**
@@ -8559,22 +8592,23 @@ const appendStyleAsync = cacheLoaders((jodit, url) => {
8559
8592
  if (jodit.isInDestruct) {
8560
8593
  return reject();
8561
8594
  }
8562
- const link = jodit.c.element('link');
8563
- link.rel = 'stylesheet';
8564
- link.media = 'all';
8565
- link.crossOrigin = 'anonymous';
8595
+ const link = jodit.c.element('link', {
8596
+ rel: 'stylesheet',
8597
+ media: 'all',
8598
+ crossorigin: 'anonymous'
8599
+ });
8566
8600
  if (jodit.o.nonce) {
8567
- link.setAttribute('nonce', jodit.o.nonce);
8601
+ attr(link, 'nonce', jodit.o.nonce);
8568
8602
  }
8569
8603
  const callback = () => resolve(link);
8570
8604
  !jodit.isInDestruct &&
8571
8605
  jodit.e.on(link, 'load', callback).on(link, 'error', reject);
8572
- link.href = completeUrl(url);
8606
+ attr(link, 'href', completeUrl(url));
8573
8607
  if (jodit.o.shadowRoot) {
8574
- jodit.o.shadowRoot.appendChild(link);
8608
+ Dom.append(jodit.o.shadowRoot, link);
8575
8609
  }
8576
8610
  else {
8577
- jodit.od.body.appendChild(link);
8611
+ Dom.append(jodit.od.body, link);
8578
8612
  }
8579
8613
  });
8580
8614
  });
@@ -9108,10 +9142,10 @@ function getContainer(jodit, classFunc, tag = 'div', createInsideEditor = false)
9108
9142
  });
9109
9143
  // Let a strict CSP accept the injected <style>/<script> box
9110
9144
  if (view.o.nonce && (tag === 'style' || tag === 'script')) {
9111
- box.setAttribute('nonce', view.o.nonce);
9145
+ attr(box, 'nonce', view.o.nonce);
9112
9146
  }
9113
9147
  box.classList.add(`jodit_theme_${view.o.theme || 'default'}`);
9114
- body.appendChild(box);
9148
+ Dom.append(body, box);
9115
9149
  data[key] = box;
9116
9150
  jodit.hookStatus('beforeDestruct', () => {
9117
9151
  view.events.off(box);
@@ -9205,14 +9239,18 @@ const refs = (root) => {
9205
9239
  if ('container' in root) {
9206
9240
  root = root.container;
9207
9241
  }
9208
- return $$('[ref],[data-ref]', root).reduce((def, child) => {
9209
- const key = attr(child, '-ref');
9210
- if (key && isString(key)) {
9211
- def[camelCase(key)] = child;
9212
- def[key] = child;
9242
+ const def = {};
9243
+ Dom.each(root, child => {
9244
+ if (Dom.isElement(child) &&
9245
+ (child.hasAttribute('ref') || child.hasAttribute('data-ref'))) {
9246
+ const key = attr(child, '-ref');
9247
+ if (key && isString(key)) {
9248
+ def[camelCase(key)] = child;
9249
+ def[key] = child;
9250
+ }
9213
9251
  }
9214
- return def;
9215
- }, {});
9252
+ });
9253
+ return def;
9216
9254
  };
9217
9255
  /**
9218
9256
  * Calculate full CSS selector
@@ -9314,8 +9352,8 @@ function applyStyles(html) {
9314
9352
  html = html.substring(0, closeIndex + '</html>'.length);
9315
9353
  }
9316
9354
  const iframe = globalDocument.createElement('iframe');
9317
- iframe.style.display = 'none';
9318
- globalDocument.body.appendChild(iframe);
9355
+ css(iframe, 'display', 'none');
9356
+ Dom.append(globalDocument.body, iframe);
9319
9357
  let convertedString = '', collection = [];
9320
9358
  try {
9321
9359
  const iframeDoc = iframe.contentDocument ||
@@ -9331,7 +9369,7 @@ function applyStyles(html) {
9331
9369
  // style normalization strips the `mso-list` hint. See #948
9332
9370
  Dom.each(iframeDoc.body, (node) => {
9333
9371
  if (Dom.isElement(node) &&
9334
- /mso-list:\s*ignore/i.test(node.getAttribute('style') || '')) {
9372
+ /mso-list:\s*ignore/i.test(attr(node, 'style') || '')) {
9335
9373
  Dom.safeRemove(node);
9336
9374
  }
9337
9375
  });
@@ -9343,6 +9381,9 @@ function applyStyles(html) {
9343
9381
  continue;
9344
9382
  }
9345
9383
  collection = $$(rules[idx].selectorText, iframeDoc.body);
9384
+ // `style.cssText` on purpose: the CSSOM parses the text,
9385
+ // drops invalid declarations and re-serializes it. The raw
9386
+ // `style` attribute would keep Word-only junk verbatim
9346
9387
  collection.forEach((elm) => {
9347
9388
  elm.style.cssText = normalizeCSS(rules[idx].style.cssText +
9348
9389
  ';' +
@@ -9355,14 +9396,13 @@ function applyStyles(html) {
9355
9396
  }
9356
9397
  Dom.each(iframeDoc.body, node => {
9357
9398
  if (Dom.isElement(node)) {
9358
- const elm = node;
9359
- const css = elm.getAttribute('style');
9360
- if (css) {
9361
- elm.style.cssText = normalizeCSS(css);
9399
+ const cssText = attr(node, 'style');
9400
+ if (cssText) {
9401
+ node.style.cssText =
9402
+ normalizeCSS(cssText);
9362
9403
  }
9363
- if (elm.hasAttribute('style') &&
9364
- !elm.getAttribute('style')) {
9365
- elm.removeAttribute('style');
9404
+ if (!attr(node, 'style')) {
9405
+ attr(node, 'style', null);
9366
9406
  }
9367
9407
  }
9368
9408
  });
@@ -9430,18 +9470,21 @@ function cleanFromWord(html) {
9430
9470
  // with `mso-list:Ignore`. They are display-only
9431
9471
  // and must not be imported, otherwise the marker
9432
9472
  // text leaks into the content. See #948
9433
- if (/mso-list:\s*ignore/i.test(node.getAttribute('style') || '')) {
9473
+ if (/mso-list:\s*ignore/i.test(attr(node, 'style') || '')) {
9434
9474
  marks.push(node);
9435
9475
  break;
9436
9476
  }
9437
- toArray(node.attributes).forEach((attr) => {
9477
+ toArray(node.attributes).forEach((attribute) => {
9438
9478
  if ([
9439
9479
  'src',
9440
9480
  'href',
9441
9481
  'rel',
9442
9482
  'content'
9443
- ].indexOf(attr.name.toLowerCase()) === -1) {
9444
- node.removeAttribute(attr.name);
9483
+ ].indexOf(attribute.name.toLowerCase()) === -1) {
9484
+ // `attrRaw`: SVG keeps camelCase names
9485
+ // (`viewBox`), `attr()` would kebab-case
9486
+ // them and silently skip the removal
9487
+ attrRaw(node, attribute.name, null);
9445
9488
  }
9446
9489
  });
9447
9490
  }
@@ -9535,10 +9578,10 @@ function hAlignElement(image, align) {
9535
9578
  function clearAlign(node) {
9536
9579
  Dom.each(node, elm => {
9537
9580
  if (Dom.isHTMLElement(elm)) {
9538
- if (elm.style.textAlign) {
9539
- elm.style.textAlign = '';
9540
- if (!elm.style.cssText.trim().length) {
9541
- elm.removeAttribute('style');
9581
+ if (cssInline(elm, 'textAlign')) {
9582
+ css(elm, 'textAlign', '');
9583
+ if (!(attr(elm, 'style') || '').trim().length) {
9584
+ attr(elm, 'style', null);
9542
9585
  }
9543
9586
  }
9544
9587
  }
@@ -9547,22 +9590,18 @@ function clearAlign(node) {
9547
9590
  /**
9548
9591
  * Apply align for element
9549
9592
  */
9593
+ const ALIGN_BY_COMMAND = new Map([
9594
+ ['justifyfull', 'justify'],
9595
+ ['justifyright', 'right'],
9596
+ ['justifyleft', 'left'],
9597
+ ['justifycenter', 'center']
9598
+ ]);
9550
9599
  function alignElement(command, box) {
9551
9600
  if (Dom.isNode(box) && Dom.isElement(box)) {
9552
9601
  clearAlign(box);
9553
- switch (command.toLowerCase()) {
9554
- case 'justifyfull':
9555
- box.style.textAlign = 'justify';
9556
- break;
9557
- case 'justifyright':
9558
- box.style.textAlign = 'right';
9559
- break;
9560
- case 'justifyleft':
9561
- box.style.textAlign = 'left';
9562
- break;
9563
- case 'justifycenter':
9564
- box.style.textAlign = 'center';
9565
- break;
9602
+ const align = ALIGN_BY_COMMAND.get(command.toLowerCase());
9603
+ if (align) {
9604
+ css(box, 'textAlign', align);
9566
9605
  }
9567
9606
  }
9568
9607
  }
@@ -11097,26 +11136,30 @@ function markDeprecated(method, names = [''], ctx = null) {
11097
11136
  */
11098
11137
  function fixedAssetsSizeAndAbsoluteLinks(editor, points) {
11099
11138
  const restoreAttributes = [];
11139
+ const images = [];
11140
+ Dom.each(editor.editor, node => {
11141
+ Dom.isTag(node, 'img') && images.push(node);
11142
+ });
11100
11143
  try {
11101
- $$('img', editor.editor).forEach(item => {
11144
+ images.forEach(item => {
11102
11145
  const previousAttrs = [
11103
11146
  attr(item, 'width'),
11104
11147
  attr(item, 'height'),
11105
- item.src
11148
+ attr(item, 'src')
11106
11149
  ];
11107
11150
  attr(item, {
11108
11151
  width: item.offsetWidth + points,
11109
11152
  height: item.offsetHeight + points
11110
11153
  });
11111
11154
  const a = editor.createInside.a();
11112
- editor.ed.body.appendChild(a);
11113
- a.href = item.src;
11114
- item.src = a.href;
11155
+ Dom.append(editor.ed.body, a);
11156
+ attr(a, 'href', attr(item, 'src') || '');
11157
+ // reading the `href` property resolves the URL to an absolute one
11158
+ attr(item, 'src', a.href);
11115
11159
  Dom.safeRemove(a);
11116
11160
  restoreAttributes.push(() => {
11117
- var _a;
11118
- item.src = (_a = previousAttrs[2]) !== null && _a !== void 0 ? _a : '';
11119
11161
  attr(item, {
11162
+ src: previousAttrs[2],
11120
11163
  width: previousAttrs[0] || null,
11121
11164
  height: previousAttrs[1] || null
11122
11165
  });
@@ -11146,7 +11189,7 @@ function previewBox(editor, defaultValue, points = 'px', container = null) {
11146
11189
  }
11147
11190
  let div = editor.c.div('jodit__preview-box jodit-context');
11148
11191
  if (container) {
11149
- container.appendChild(div);
11192
+ Dom.append(container, div);
11150
11193
  }
11151
11194
  css(div, {
11152
11195
  position: 'relative',
@@ -11161,7 +11204,7 @@ function previewBox(editor, defaultValue, points = 'px', container = null) {
11161
11204
  minHeight: 600,
11162
11205
  border: 0
11163
11206
  });
11164
- div.appendChild(iframe);
11207
+ Dom.append(div, iframe);
11165
11208
  const myWindow = iframe.contentWindow;
11166
11209
  if (myWindow) {
11167
11210
  editor.e.fire('generateDocumentStructure.iframe', myWindow.document, editor);
@@ -11171,7 +11214,7 @@ function previewBox(editor, defaultValue, points = 'px', container = null) {
11171
11214
  const elm = myWindow.document.body;
11172
11215
  const resizeObserver = new ResizeObserver(editor.async.debounce(() => {
11173
11216
  resizeObserver.unobserve(elm);
11174
- iframe.style.height = `${elm.offsetHeight + 20}px`;
11217
+ css(iframe, 'height', elm.offsetHeight + 20);
11175
11218
  editor.async.requestAnimationFrame(() => {
11176
11219
  !destructed && resizeObserver.observe(elm);
11177
11220
  });
@@ -11204,7 +11247,7 @@ function previewBox(editor, defaultValue, points = 'px', container = null) {
11204
11247
  if (Dom.isElement(c)) {
11205
11248
  const newNode = box.ownerDocument.createElement(c.nodeName);
11206
11249
  for (let j = 0; j < c.attributes.length; j += 1) {
11207
- attr(newNode, c.attributes[j].nodeName, c.attributes[j].nodeValue);
11250
+ attr(newNode, c.attributes[j].name, c.attributes[j].value);
11208
11251
  }
11209
11252
  if (c.childNodes.length === 0 || Dom.isTag(c, 'table')) {
11210
11253
  switch (c.nodeName) {
@@ -11224,13 +11267,13 @@ function previewBox(editor, defaultValue, points = 'px', container = null) {
11224
11267
  setHTML(newNode, c);
11225
11268
  }
11226
11269
  try {
11227
- box.appendChild(newNode);
11270
+ Dom.append(box, newNode);
11228
11271
  }
11229
11272
  catch (_a) { }
11230
11273
  }
11231
11274
  else {
11232
11275
  try {
11233
- box.appendChild(c.cloneNode(true));
11276
+ Dom.append(box, c.cloneNode(true));
11234
11277
  }
11235
11278
  catch (_b) { }
11236
11279
  }
@@ -11390,9 +11433,6 @@ class LimitedStack {
11390
11433
  * Released under MIT see LICENSE.txt in the project root for license information.
11391
11434
  * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
11392
11435
  */
11393
- /**
11394
- * @module helpers/html
11395
- */
11396
11436
  const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
11397
11437
  /**
11398
11438
  * Integration points where HTML is legitimately allowed inside MathML/SVG foreign content.
@@ -11408,9 +11448,10 @@ const HTML_INTEGRATION_POINTS = new Set([
11408
11448
  * HTML (e.g. `mglyph` / `style` under `<math>`) that a reparse can hoist into a live node. Legitimate
11409
11449
  * MathML/SVG children and HTML below an integration point are kept.
11410
11450
  */
11451
+ const isMathOrSvg = (node) => Boolean(node && /^(math|svg)$/i.test(node.nodeName));
11411
11452
  function isSmuggledForeignHtml(elm) {
11412
11453
  if (elm.namespaceURI !== HTML_NAMESPACE ||
11413
- elm.closest('math,svg') == null) {
11454
+ Dom.up(elm, isMathOrSvg) == null) {
11414
11455
  return false;
11415
11456
  }
11416
11457
  for (let parent = elm.parentElement; parent; parent = parent.parentElement) {
@@ -11433,11 +11474,17 @@ function safeHTML(box, options) {
11433
11474
  return;
11434
11475
  }
11435
11476
  // Drop HTML smuggled into MathML/SVG before the walk: a reparse would otherwise hoist its hidden
11436
- // markup into a live node.
11437
- const foreign = box.querySelectorAll('math *, svg *');
11438
- for (let i = 0; i < foreign.length; i++) {
11439
- if (box.contains(foreign[i]) && isSmuggledForeignHtml(foreign[i])) {
11440
- Dom.safeRemove(foreign[i]);
11477
+ // markup into a live node. Collect the candidates first (like the static
11478
+ // `querySelectorAll` snapshot did) so removals don't affect the traversal.
11479
+ const foreign = [];
11480
+ Dom.each(box, node => {
11481
+ if (Dom.isElement(node) && Dom.up(node.parentNode, isMathOrSvg)) {
11482
+ foreign.push(node);
11483
+ }
11484
+ });
11485
+ for (const elm of foreign) {
11486
+ if (Dom.isOrContains(box, elm) && isSmuggledForeignHtml(elm)) {
11487
+ Dom.safeRemove(elm);
11441
11488
  }
11442
11489
  }
11443
11490
  const removeEvents = (_a = options.removeEventAttributes) !== null && _a !== void 0 ? _a : options.removeOnError;
@@ -11455,8 +11502,8 @@ function safeHTML(box, options) {
11455
11502
  sanitizeHTMLElement(node, options);
11456
11503
  if (options.safeLinksTarget &&
11457
11504
  node.nodeName === 'A' &&
11458
- node.getAttribute('target') === '_blank') {
11459
- const rel = node.getAttribute('rel') || '';
11505
+ attr(node, 'target') === '_blank') {
11506
+ const rel = attr(node, 'rel') || '';
11460
11507
  const parts = rel.split(/\s+/).filter(Boolean);
11461
11508
  if (!parts.includes('noopener')) {
11462
11509
  parts.push('noopener');
@@ -11485,7 +11532,9 @@ function removeAllEventAttributes(elm) {
11485
11532
  }
11486
11533
  }
11487
11534
  for (const name of toRemove) {
11488
- elm.removeAttribute(name);
11535
+ // `attrRaw` on purpose: `attr()` kebab-cases the key
11536
+ // (`onLoad` → `on-load`), which must not happen in a sanitizer
11537
+ attrRaw(elm, name, null);
11489
11538
  effected = true;
11490
11539
  }
11491
11540
  return effected;
@@ -11536,7 +11585,7 @@ function sanitizeHTMLElement(elm, { safeJavaScriptLink, removeOnError } = {
11536
11585
  effected = true;
11537
11586
  }
11538
11587
  const tagName = elm.nodeName.toLowerCase();
11539
- const href = elm.getAttribute('href');
11588
+ const href = attr(elm, 'href');
11540
11589
  // Neutralize executable-scheme `href`s with the same normalization used for
11541
11590
  // every other URL attribute (`isDangerousUrl`), which strips control bytes,
11542
11591
  // tabs and newlines and lowercases before matching the scheme. The previous
@@ -11556,8 +11605,10 @@ function sanitizeHTMLElement(elm, { safeJavaScriptLink, removeOnError } = {
11556
11605
  effected = true;
11557
11606
  }
11558
11607
  // Strip executable schemes from any other URL-bearing attribute.
11608
+ // `attrRaw`: the list contains `xlink:href` and the sanitizer must
11609
+ // read exactly the attribute it will remove.
11559
11610
  for (const name of URL_ATTRIBUTES) {
11560
- const value = elm.getAttribute(name);
11611
+ const value = attrRaw(elm, name);
11561
11612
  if (value && isDangerousUrl(value, tagName)) {
11562
11613
  attr(elm, name, null);
11563
11614
  effected = true;
@@ -11595,9 +11646,15 @@ function stripTags(html, doc = document, exclude = null, blockBr = false) {
11595
11646
  tmp.innerHTML = html;
11596
11647
  }
11597
11648
  else {
11598
- tmp.appendChild(html);
11649
+ Dom.append(tmp, html);
11599
11650
  }
11600
- $$('*', tmp).forEach(p => {
11651
+ // Snapshot of all elements (like `querySelectorAll('*')` did) the loop
11652
+ // below removes and unwraps nodes while iterating
11653
+ const all = [];
11654
+ Dom.each(tmp, node => {
11655
+ Dom.isElement(node) && all.push(node);
11656
+ });
11657
+ all.forEach(p => {
11601
11658
  const pr = p.parentNode;
11602
11659
  if (!pr) {
11603
11660
  return;
@@ -11627,7 +11684,7 @@ function stripTags(html, doc = document, exclude = null, blockBr = false) {
11627
11684
  // plain text). When `blockBr` is set, separate them with a line
11628
11685
  // break instead, so paragraph structure survives — e.g. the
11629
11686
  // "Insert only Text" paste option. See #1232
11630
- pr.insertBefore(doc.createTextNode(blockBr ? '%%%jodit-single-br%%%' : ' '), nx);
11687
+ Dom.before(nx, doc.createTextNode(blockBr ? '%%%jodit-single-br%%%' : ' '));
11631
11688
  }
11632
11689
  });
11633
11690
  return restoreTags(trim(tmp.innerText));
@@ -12203,6 +12260,7 @@ var index = /*#__PURE__*/Object.freeze({
12203
12260
  asArray: asArray,
12204
12261
  assert: assert,
12205
12262
  attr: attr,
12263
+ attrRaw: attrRaw,
12206
12264
  browser: browser,
12207
12265
  buildQuery: buildQuery,
12208
12266
  call: call,
@@ -12219,6 +12277,7 @@ var index = /*#__PURE__*/Object.freeze({
12219
12277
  connection: connection,
12220
12278
  convertMediaUrlToVideoEmbed: convertMediaUrlToVideoEmbed,
12221
12279
  css: css,
12280
+ cssInline: cssInline,
12222
12281
  cssPath: cssPath,
12223
12282
  ctrlKey: ctrlKey,
12224
12283
  dataBind: dataBind,
@@ -13331,13 +13390,21 @@ class Elms {
13331
13390
  * Return element with BEM class name
13332
13391
  */
13333
13392
  getElm(elementName) {
13334
- return this.container.querySelector(`.${this.getFullElName(elementName)}`);
13393
+ const className = this.getFullElName(elementName);
13394
+ return Dom.first(this.container, node => Dom.isHTMLElement(node) && node.classList.contains(className));
13335
13395
  }
13336
13396
  /**
13337
13397
  * Return elements with BEM class name
13338
13398
  */
13339
13399
  getElms(elementName) {
13340
- return toArray(this.container.querySelectorAll(`.${this.getFullElName(elementName)}`));
13400
+ const className = this.getFullElName(elementName);
13401
+ const result = [];
13402
+ Dom.each(this.container, node => {
13403
+ if (Dom.isHTMLElement(node) && node.classList.contains(className)) {
13404
+ result.push(node);
13405
+ }
13406
+ });
13407
+ return result;
13341
13408
  }
13342
13409
  }
13343
13410
 
@@ -13454,9 +13521,9 @@ class Icon {
13454
13521
  }
13455
13522
  if (iconElement) {
13456
13523
  iconElement.classList.add('jodit-icon');
13457
- iconElement.style.fill = fill;
13524
+ css(iconElement, 'fill', fill);
13458
13525
  if (scale != null) {
13459
- iconElement.style.transform = `scale(${scale})`;
13526
+ css(iconElement, 'transform', `scale(${scale})`);
13460
13527
  }
13461
13528
  jodit.o.cache &&
13462
13529
  this.__cache.set(cacheKey, iconElement.cloneNode(true));
@@ -13574,7 +13641,7 @@ let UIElement = UIElement_1 = class UIElement extends ViewComponent {
13574
13641
  * Append container to element
13575
13642
  */
13576
13643
  appendTo(element) {
13577
- element.appendChild(this.container);
13644
+ Dom.append(element, this.container);
13578
13645
  return this;
13579
13646
  }
13580
13647
  /**
@@ -13765,7 +13832,7 @@ let UIButton = class UIButton extends UIElement {
13765
13832
  }
13766
13833
  Dom.detach(this.icon);
13767
13834
  const iconElement = Icon.makeIcon(this.j, this.state.icon);
13768
- iconElement && this.icon.appendChild(iconElement);
13835
+ iconElement && Dom.append(this.icon, iconElement);
13769
13836
  }
13770
13837
  /**
13771
13838
  * Set focus on an element
@@ -13791,8 +13858,8 @@ let UIButton = class UIButton extends UIElement {
13791
13858
  });
13792
13859
  const icon = this.j.c.span(cn + '__icon');
13793
13860
  const text = this.j.c.span(cn + '__text');
13794
- button.appendChild(icon);
13795
- button.appendChild(text);
13861
+ Dom.append(button, icon);
13862
+ Dom.append(button, text);
13796
13863
  return button;
13797
13864
  }
13798
13865
  constructor(jodit, state) {
@@ -13987,7 +14054,7 @@ let UIGroup = UIGroup_1 = class UIGroup extends UIElement {
13987
14054
  if (distElm == null) {
13988
14055
  throw new Error('Element does not exist');
13989
14056
  }
13990
- distElm.appendChild(elm.container);
14057
+ Dom.append(distElm, elm.container);
13991
14058
  }
13992
14059
  else {
13993
14060
  this.appendChildToContainer(elm.container, index);
@@ -14005,14 +14072,14 @@ let UIGroup = UIGroup_1 = class UIGroup extends UIElement {
14005
14072
  * Allow set another container for the box of all children
14006
14073
  */
14007
14074
  appendChildToContainer(childContainer, index) {
14008
- if (index === undefined ||
14009
- index < 0 ||
14010
- index > this.elements.length - 1 ||
14011
- this.container.children[index] == null) {
14012
- this.container.appendChild(childContainer);
14075
+ const ref = index === undefined || index < 0 || index > this.elements.length - 1
14076
+ ? null
14077
+ : this.container.children[index];
14078
+ if (ref == null) {
14079
+ Dom.append(this.container, childContainer);
14013
14080
  }
14014
14081
  else {
14015
- this.container.insertBefore(childContainer, this.container.children[index]);
14082
+ Dom.before(ref, childContainer);
14016
14083
  }
14017
14084
  }
14018
14085
  /**
@@ -14101,7 +14168,7 @@ let UIButtonGroup = class UIButtonGroup extends UIGroup {
14101
14168
  appendChildToContainer(childContainer) {
14102
14169
  const options = this.getElm('options');
14103
14170
  assert(options != null, 'Options does not exist');
14104
- options.appendChild(childContainer);
14171
+ Dom.append(options, childContainer);
14105
14172
  }
14106
14173
  constructor(jodit, options = {
14107
14174
  radio: true
@@ -14203,7 +14270,7 @@ let UITooltip = UITooltip_1 = class UITooltip extends UIElement {
14203
14270
  }
14204
14271
  __onAttach(container) {
14205
14272
  // TODO Move it inside __show method. Now it is here because testcase failed with capturing
14206
- getContainer(this.j, UITooltip_1).appendChild(this.container);
14273
+ Dom.append(getContainer(this.j, UITooltip_1), this.container);
14207
14274
  this.__attachedContainers.add(container);
14208
14275
  this.__attachedContainers.add(this.j.container);
14209
14276
  this.j.e
@@ -14313,7 +14380,7 @@ let UITooltip = UITooltip_1 = class UITooltip extends UIElement {
14313
14380
  if (this.__isOpened) {
14314
14381
  this.__isOpened = false;
14315
14382
  this.setMod('visible', false);
14316
- this.getElm('content').innerHTML = '';
14383
+ Dom.detach(this.getElm('content'));
14317
14384
  css(this.container, {
14318
14385
  left: -5e3
14319
14386
  });
@@ -14517,7 +14584,7 @@ let UIInput = UIInput_1 = class UIInput extends UIElement {
14517
14584
  }
14518
14585
  else {
14519
14586
  this.__errorBox.innerText = this.j.i18n(value, this.j.i18n(this.state.label || ''));
14520
- this.container.appendChild(this.__errorBox);
14587
+ Dom.append(this.container, this.__errorBox);
14521
14588
  }
14522
14589
  }
14523
14590
  get value() {
@@ -14559,11 +14626,11 @@ let UIInput = UIInput_1 = class UIInput extends UIElement {
14559
14626
  __markInputInvalid() {
14560
14627
  var _a, _b, _c, _d;
14561
14628
  if (this.error) {
14562
- this.nativeInput.setAttribute('aria-invalid', 'true');
14629
+ attr(this.nativeInput, 'aria-invalid', 'true');
14563
14630
  (_b = (_a = this.nativeInput).setCustomValidity) === null || _b === void 0 ? void 0 : _b.call(_a, this.error);
14564
14631
  }
14565
14632
  else {
14566
- this.nativeInput.removeAttribute('aria-invalid');
14633
+ attr(this.nativeInput, 'aria-invalid', null);
14567
14634
  (_d = (_c = this.nativeInput).setCustomValidity) === null || _d === void 0 ? void 0 : _d.call(_c, '');
14568
14635
  }
14569
14636
  }
@@ -14576,8 +14643,8 @@ let UIInput = UIInput_1 = class UIInput extends UIElement {
14576
14643
  }
14577
14644
  const { nativeInput } = this;
14578
14645
  nativeInput.classList.add(this.getFullElName('input'));
14579
- this.wrapper.appendChild(nativeInput);
14580
- container.appendChild(this.wrapper);
14646
+ Dom.append(this.wrapper, nativeInput);
14647
+ Dom.append(container, this.wrapper);
14581
14648
  attr(nativeInput, 'dir', this.j.o.direction || 'auto');
14582
14649
  return container;
14583
14650
  }
@@ -14854,12 +14921,12 @@ let UITextArea = UITextArea_1 = class UITextArea extends UIInput {
14854
14921
  this.state = { ...UITextArea_1.defaultState };
14855
14922
  Object.assign(this.state, state);
14856
14923
  if (this.state.resizable === false) {
14857
- this.nativeInput.style.resize = 'none';
14924
+ css(this.nativeInput, 'resize', 'none');
14858
14925
  }
14859
14926
  }
14860
14927
  onChangeStateSize() {
14861
14928
  const { size, resizable } = this.state;
14862
- this.nativeInput.style.resize = resizable ? 'auto' : 'none';
14929
+ css(this.nativeInput, 'resize', resizable ? 'auto' : 'none');
14863
14930
  this.nativeInput.rows = size !== null && size !== void 0 ? size : 5;
14864
14931
  }
14865
14932
  };
@@ -14987,7 +15054,7 @@ let UIFileInput = class UIFileInput extends UIInput {
14987
15054
  const { nativeInput } = this;
14988
15055
  nativeInput.classList.add(this.getFullElName('input'));
14989
15056
  container.classList.add(this.componentName);
14990
- container.appendChild(nativeInput);
15057
+ Dom.append(container, nativeInput);
14991
15058
  return container;
14992
15059
  }
14993
15060
  createNativeInput(options) {
@@ -15345,7 +15412,7 @@ class Popup extends UIGroup {
15345
15412
  appendChildToContainer(childContainer) {
15346
15413
  const content = this.getElm('content');
15347
15414
  assert(content, 'Content element should exist');
15348
- content.appendChild(childContainer);
15415
+ Dom.append(content, childContainer);
15349
15416
  }
15350
15417
  updateParentElement(target) {
15351
15418
  if (target !== this && Component.isInstanceOf(target, Popup)) {
@@ -15395,12 +15462,12 @@ class Popup extends UIGroup {
15395
15462
  ? getBound
15396
15463
  : this.getKeepBound(getBound);
15397
15464
  if (parentContainer) {
15398
- parentContainer.appendChild(this.container);
15465
+ Dom.append(parentContainer, this.container);
15399
15466
  }
15400
15467
  else {
15401
15468
  const popupContainer = getContainer(this.jodit, Popup);
15402
15469
  if (parentContainer !== this.container.parentElement) {
15403
- popupContainer.appendChild(this.container);
15470
+ Dom.append(popupContainer, this.container);
15404
15471
  }
15405
15472
  }
15406
15473
  this.updatePosition();
@@ -15409,11 +15476,11 @@ class Popup extends UIGroup {
15409
15476
  return this;
15410
15477
  }
15411
15478
  __calculateZIndex() {
15412
- if (this.container.style.zIndex) {
15479
+ if (cssInline(this.container, 'zIndex')) {
15413
15480
  return;
15414
15481
  }
15415
15482
  const checkView = (view) => {
15416
- const zIndex = view.container.style.zIndex || view.o.zIndex;
15483
+ const zIndex = cssInline(view.container, 'zIndex') || view.o.zIndex;
15417
15484
  if (zIndex) {
15418
15485
  this.setZIndex(1 + parseInt(zIndex.toString(), 10));
15419
15486
  return true;
@@ -15429,8 +15496,9 @@ class Popup extends UIGroup {
15429
15496
  if (checkView(pe.j)) {
15430
15497
  return;
15431
15498
  }
15432
- if (pe.container.style.zIndex) {
15433
- this.setZIndex(1 + parseInt(pe.container.style.zIndex.toString(), 10));
15499
+ const parentZIndex = cssInline(pe.container, 'zIndex');
15500
+ if (parentZIndex) {
15501
+ this.setZIndex(1 + parseInt(parentZIndex.toString(), 10));
15434
15502
  return;
15435
15503
  }
15436
15504
  if (!pe.parentElement && pe.container.parentElement) {
@@ -15559,6 +15627,18 @@ class Popup extends UIGroup {
15559
15627
  this.j.e.fire(this, 'beforeClose');
15560
15628
  this.j.e.fire('beforePopupClose', this);
15561
15629
  this.__removeGlobalListeners();
15630
+ // Blur a focused control (e.g. the color picker hex input) before
15631
+ // the container goes away. Chrome fires `blur`/`change` for a
15632
+ // removed focused element in the middle of `removeChild`, Firefox
15633
+ // does not fire them at all. Blurring first makes both browsers
15634
+ // run those handlers while the popup is still in the DOM. See #1458
15635
+ const { activeElement } = this.od;
15636
+ if (activeElement &&
15637
+ activeElement !== this.container &&
15638
+ Dom.isOrContains(this.container, activeElement) &&
15639
+ isFunction(activeElement.blur)) {
15640
+ activeElement.blur();
15641
+ }
15562
15642
  Dom.safeRemove(this.container);
15563
15643
  return this;
15564
15644
  }
@@ -15622,7 +15702,7 @@ class Popup extends UIGroup {
15622
15702
  * Set ZIndex
15623
15703
  */
15624
15704
  setZIndex(index) {
15625
- this.container.style.zIndex = index.toString();
15705
+ css(this.container, 'zIndex', index.toString());
15626
15706
  }
15627
15707
  constructor(jodit, smart = true) {
15628
15708
  super(jodit);
@@ -15686,7 +15766,7 @@ class ProgressBar extends UIElement {
15686
15766
  */
15687
15767
  show() {
15688
15768
  const container = this.j.workplace || this.j.container;
15689
- container.appendChild(this.container);
15769
+ Dom.append(container, this.container);
15690
15770
  return this;
15691
15771
  }
15692
15772
  hide() {
@@ -15694,7 +15774,7 @@ class ProgressBar extends UIElement {
15694
15774
  return this;
15695
15775
  }
15696
15776
  progress(percentage) {
15697
- this.container.style.width = percentage.toFixed(2) + '%';
15777
+ css(this.container, 'width', percentage.toFixed(2) + '%');
15698
15778
  return this;
15699
15779
  }
15700
15780
  showFileUploadAnimation(from, to) {
@@ -15718,7 +15798,7 @@ class ProgressBar extends UIElement {
15718
15798
  left: pos.left + start.x,
15719
15799
  top: pos.top + start.y
15720
15800
  });
15721
- box.appendChild(el);
15801
+ Dom.append(box, el);
15722
15802
  this.__animationElement = el;
15723
15803
  css(el, {
15724
15804
  left: pos.left + end.x,
@@ -15771,7 +15851,7 @@ class Create {
15771
15851
  }
15772
15852
  }
15773
15853
  if (children) {
15774
- asArray(children).forEach((child) => elm.appendChild(isString(child) ? this.fromHTML(child) : child));
15854
+ asArray(children).forEach((child) => Dom.append(elm, isString(child) ? this.fromHTML(child) : child));
15775
15855
  }
15776
15856
  return elm;
15777
15857
  }
@@ -15785,7 +15865,7 @@ class Create {
15785
15865
  sandbox() {
15786
15866
  var _a;
15787
15867
  const iframe = this.element('iframe', { sandbox: 'allow-same-origin' });
15788
- this.doc.body.appendChild(iframe);
15868
+ Dom.append(this.doc.body, iframe);
15789
15869
  const doc = (_a = iframe.contentWindow) === null || _a === void 0 ? void 0 : _a.document;
15790
15870
  assert(doc, 'iframe.contentWindow.document');
15791
15871
  if (!doc) {
@@ -16434,7 +16514,7 @@ let UIMessages = class UIMessages extends UIGroup {
16434
16514
  if (!this.__box) {
16435
16515
  throw new Error('Container is not defined: ' + key);
16436
16516
  }
16437
- this.__box.appendChild(this.container);
16517
+ Dom.append(this.__box, this.container);
16438
16518
  const msg = new UIMessage(this.j, { text, variant });
16439
16519
  this.append(msg);
16440
16520
  this.__calcOffsets();
@@ -16706,7 +16786,7 @@ let View = View_1 = class View extends Component {
16706
16786
  }
16707
16787
  /** Add some element to box */
16708
16788
  addDisclaimer(elm) {
16709
- this.container.appendChild(elm);
16789
+ Dom.append(this.container, elm);
16710
16790
  }
16711
16791
  /**
16712
16792
  * Call before destruct
@@ -16871,7 +16951,7 @@ class ViewWithToolbar extends View {
16871
16951
  anchor = anchor.nextElementSibling;
16872
16952
  }
16873
16953
  if (anchor !== box) {
16874
- this.container.insertBefore(box, anchor);
16954
+ anchor ? Dom.before(anchor, box) : Dom.append(this.container, box);
16875
16955
  }
16876
16956
  }
16877
16957
  /**
@@ -17050,7 +17130,7 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
17050
17130
  if (isArray(elm)) {
17051
17131
  const div = this.c.div(this.getFullElName('column'));
17052
17132
  elements_list.push(div);
17053
- root.appendChild(div);
17133
+ Dom.append(root, div);
17054
17134
  return this.setElements(div, elm);
17055
17135
  }
17056
17136
  let element;
@@ -17062,12 +17142,12 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
17062
17142
  }
17063
17143
  elements_list.push(element);
17064
17144
  if (element.parentNode !== root) {
17065
- root.appendChild(element);
17145
+ Dom.append(root, element);
17066
17146
  }
17067
17147
  });
17068
17148
  toArray(root.childNodes).forEach((elm) => {
17069
17149
  if (elements_list.indexOf(elm) === -1) {
17070
- root.removeChild(elm);
17150
+ Dom.safeRemove(elm);
17071
17151
  }
17072
17152
  });
17073
17153
  }
@@ -17245,8 +17325,11 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
17245
17325
  this.offsetY = y;
17246
17326
  this.moved = Math.abs(x - left) > 100 || Math.abs(y - top) > 100;
17247
17327
  }
17248
- this.dialog.style.left = (x || left) + 'px';
17249
- this.dialog.style.top = (y || top) + 'px';
17328
+ // strings on purpose: `css()` would truncate fractional pixels
17329
+ css(this.dialog, {
17330
+ left: (x || left) + 'px',
17331
+ top: (y || top) + 'px'
17332
+ });
17250
17333
  return this;
17251
17334
  }
17252
17335
  /**
@@ -17307,6 +17390,15 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
17307
17390
  this.setMod('footer', Boolean(content));
17308
17391
  return this;
17309
17392
  }
17393
+ __openedSiblings() {
17394
+ const result = [];
17395
+ Dialog_1.__opened.forEach(dialog => {
17396
+ if (dialog.destination === this.destination) {
17397
+ result.push(dialog);
17398
+ }
17399
+ });
17400
+ return result;
17401
+ }
17310
17402
  /**
17311
17403
  * Get zIndex from dialog
17312
17404
  */
@@ -17317,12 +17409,11 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
17317
17409
  * Get dialog instance with maximum z-index displaying it on top of all the dialog boxes
17318
17410
  */
17319
17411
  getMaxZIndexDialog() {
17320
- let maxZi = 0, dlg, zIndex, res = this;
17321
- $$('.jodit-dialog', this.destination).forEach((dialog) => {
17322
- dlg = dialog.component;
17323
- zIndex = parseInt(css(dialog, 'zIndex'), 10);
17324
- if (dlg.isOpened && !isNaN(zIndex) && zIndex > maxZi) {
17325
- res = dlg;
17412
+ let maxZi = 0, res = this;
17413
+ this.__openedSiblings().forEach(dialog => {
17414
+ const zIndex = dialog.getZIndex();
17415
+ if (zIndex > maxZi) {
17416
+ res = dialog;
17326
17417
  maxZi = zIndex;
17327
17418
  }
17328
17419
  });
@@ -17334,12 +17425,11 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
17334
17425
  setMaxZIndex() {
17335
17426
  if (this.getMod('static'))
17336
17427
  return;
17337
- let maxZIndex = 20000004, zIndex = 0;
17338
- $$('.jodit-dialog', this.destination).forEach(dialog => {
17339
- zIndex = parseInt(css(dialog, 'zIndex'), 10);
17340
- maxZIndex = Math.max(isNaN(zIndex) ? 0 : zIndex, maxZIndex);
17428
+ let maxZIndex = 20000004;
17429
+ this.__openedSiblings().forEach(dialog => {
17430
+ maxZIndex = Math.max(dialog.getZIndex(), maxZIndex);
17341
17431
  });
17342
- this.container.style.zIndex = (maxZIndex + 1).toString();
17432
+ css(this.container, 'zIndex', (maxZIndex + 1).toString());
17343
17433
  }
17344
17434
  /**
17345
17435
  * Expands the dialog on full browser window
@@ -17385,14 +17475,15 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
17385
17475
  }
17386
17476
  this.setMod('active', true);
17387
17477
  this.isOpened = true;
17478
+ Dialog_1.__opened.add(this);
17388
17479
  this.setModal(modal);
17389
- this.destination.appendChild(this.container);
17480
+ Dom.append(this.destination, this.container);
17390
17481
  if (this.getMod('static') !== true) {
17391
17482
  this.setPosition(this.offsetX, this.offsetY);
17392
17483
  this.setMaxZIndex();
17393
17484
  }
17394
17485
  else {
17395
- this.container.style.removeProperty('z-index');
17486
+ css(this.container, 'zIndex', null);
17396
17487
  }
17397
17488
  if (this.o.fullsize) {
17398
17489
  this.toggleFullSize(true);
@@ -17447,6 +17538,7 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
17447
17538
  }
17448
17539
  this.setMod('active', false);
17449
17540
  this.isOpened = false;
17541
+ Dialog_1.__opened.delete(this);
17450
17542
  if (this.isFullSize) {
17451
17543
  this.toggleFullSize(false);
17452
17544
  }
@@ -17525,11 +17617,11 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
17525
17617
  </div>
17526
17618
  </div>`);
17527
17619
  if (self.options.direction === 'rtl') {
17528
- self.container.style.direction = 'rtl';
17529
- self.container.setAttribute('dir', 'rtl');
17620
+ css(self.container, 'direction', 'rtl');
17621
+ attr(self.container, 'dir', 'rtl');
17530
17622
  }
17531
17623
  if (this.o.zIndex) {
17532
- this.container.style.zIndex = this.o.zIndex.toString();
17624
+ css(this.container, 'zIndex', this.o.zIndex.toString());
17533
17625
  }
17534
17626
  attr(self.container, 'role', 'dialog');
17535
17627
  Object.defineProperty(self.container, 'component', {
@@ -17596,6 +17688,7 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
17596
17688
  if (this.isOpened) {
17597
17689
  this.close();
17598
17690
  }
17691
+ Dialog_1.__opened.delete(this);
17599
17692
  if (this.events) {
17600
17693
  this.__removeGlobalResizeListeners();
17601
17694
  this.events
@@ -17606,6 +17699,11 @@ let Dialog = Dialog_1 = class Dialog extends ViewWithToolbar {
17606
17699
  super.destruct();
17607
17700
  }
17608
17701
  };
17702
+ /**
17703
+ * Registry of the currently opened dialogs. Replaces a DOM scan of the
17704
+ * whole `destination` (usually `document.body`) for every z-index update.
17705
+ */
17706
+ Dialog.__opened = new Set();
17609
17707
  Dialog.defaultOptions = {
17610
17708
  ...View.defaultOptions,
17611
17709
  closeOnClickOverlay: false,
@@ -17664,7 +17762,7 @@ function Alert(msg, title, callback, className = 'jodit-dialog_alert') {
17664
17762
  ? this
17665
17763
  : new Dialog({ closeOnClickOverlay: true }), container = dialog.c.div(className), okButton = Button(dialog, 'ok', 'Ok');
17666
17764
  asArray(msg).forEach(oneMessage => {
17667
- container.appendChild(Dom.isNode(oneMessage) ? oneMessage : dialog.c.fromHTML(oneMessage));
17765
+ Dom.append(container, Dom.isNode(oneMessage) ? oneMessage : dialog.c.fromHTML(oneMessage));
17668
17766
  });
17669
17767
  okButton.onAction(() => {
17670
17768
  if (!callback || !isFunction(callback) || callback(dialog) !== false) {
@@ -17704,8 +17802,8 @@ function Confirm(msg, title, callback) {
17704
17802
  callback = title;
17705
17803
  title = undefined;
17706
17804
  }
17707
- $label.appendChild(dialog.c.fromHTML(msg));
17708
- $div.appendChild($label);
17805
+ Dom.append($label, dialog.c.fromHTML(msg));
17806
+ Dom.append($div, $label);
17709
17807
  const action = (yes) => () => {
17710
17808
  if (!callback || callback(yes) !== false) {
17711
17809
  dialog.close();
@@ -17764,9 +17862,9 @@ function Prompt(msg, title, callback, placeholder, defaultValue) {
17764
17862
  if (placeholder) {
17765
17863
  attr(inputElement, 'placeholder', placeholder);
17766
17864
  }
17767
- labelElement.appendChild(dialog.c.text(msg));
17768
- form.appendChild(labelElement);
17769
- form.appendChild(inputElement);
17865
+ Dom.append(labelElement, dialog.c.text(msg));
17866
+ Dom.append(form, labelElement);
17867
+ Dom.append(form, inputElement);
17770
17868
  cancelButton.onAction(dialog.close);
17771
17869
  const onclick = () => {
17772
17870
  if (!callback ||
@@ -18187,7 +18285,8 @@ Config.prototype.controls.filebrowser = {
18187
18285
  filter: {
18188
18286
  isInput: true,
18189
18287
  getContent: (filebrowser, b) => {
18190
- const oldInput = b.container.querySelector('.jodit-input');
18288
+ const oldInput = Dom.first(b.container, node => Dom.isHTMLElement(node) &&
18289
+ node.classList.contains('jodit-input'));
18191
18290
  if (oldInput) {
18192
18291
  return oldInput;
18193
18292
  }
@@ -18968,6 +19067,17 @@ var __decorate$q = (undefined && undefined.__decorate) || function (decorators,
18968
19067
  };
18969
19068
  var ImageEditor_1;
18970
19069
  const jie = 'jodit-image-editor';
19070
+ const hasClass = (className) => (elm) => elm.classList.contains(className);
19071
+ function findFirst(root, cond) {
19072
+ return Dom.first(root, n => Dom.isHTMLElement(n) && cond(n));
19073
+ }
19074
+ function findAll(root, cond) {
19075
+ const result = [];
19076
+ Dom.each(root, n => {
19077
+ Dom.isHTMLElement(n) && cond(n) && result.push(n);
19078
+ });
19079
+ return result;
19080
+ }
18971
19081
  const TABS = {
18972
19082
  resize: 'resize',
18973
19083
  crop: 'crop'
@@ -19018,19 +19128,20 @@ let ImageEditor = ImageEditor_1 = class ImageEditor extends ViewComponent {
19018
19128
  return this.j.async.promise((resolve) => {
19019
19129
  const timestamp = new Date().getTime();
19020
19130
  this.image = this.j.c.element('img');
19021
- $$('img,.jodit-icon_loader', this.resize_box).forEach(Dom.safeRemove);
19022
- $$('img,.jodit-icon_loader', this.crop_box).forEach(Dom.safeRemove);
19131
+ const isTrash = (elm) => Dom.isTag(elm, 'img') || hasClass('jodit-icon_loader')(elm);
19132
+ findAll(this.resize_box, isTrash).forEach(Dom.safeRemove);
19133
+ findAll(this.crop_box, isTrash).forEach(Dom.safeRemove);
19023
19134
  css(this.cropHandler, 'background', 'transparent');
19024
19135
  this.onSave = save;
19025
- this.resize_box.appendChild(this.j.c.element('i', { class: 'jodit-icon_loader' }));
19026
- this.crop_box.appendChild(this.j.c.element('i', { class: 'jodit-icon_loader' }));
19136
+ Dom.append(this.resize_box, this.j.c.element('i', { class: 'jodit-icon_loader' }));
19137
+ Dom.append(this.crop_box, this.j.c.element('i', { class: 'jodit-icon_loader' }));
19027
19138
  if (/\?/.test(url)) {
19028
19139
  url += '&_tst=' + timestamp;
19029
19140
  }
19030
19141
  else {
19031
19142
  url += '?_tst=' + timestamp;
19032
19143
  }
19033
- this.image.setAttribute('src', url);
19144
+ attr(this.image, 'src', url);
19034
19145
  this._dialog.open();
19035
19146
  const { widthInput, heightInput } = refs(this.editor);
19036
19147
  const onload = () => {
@@ -19043,10 +19154,10 @@ let ImageEditor = ImageEditor_1 = class ImageEditor extends ViewComponent {
19043
19154
  widthInput.value = this.naturalWidth.toString();
19044
19155
  heightInput.value = this.naturalHeight.toString();
19045
19156
  this.ratio = this.naturalWidth / this.naturalHeight;
19046
- this.resize_box.appendChild(this.image);
19157
+ Dom.append(this.resize_box, this.image);
19047
19158
  this.cropImage = this.image.cloneNode(true);
19048
- this.crop_box.appendChild(this.cropImage);
19049
- Dom.safeRemove.apply(null, $$('.jodit-icon_loader', this.editor));
19159
+ Dom.append(this.crop_box, this.cropImage);
19160
+ Dom.safeRemove.apply(null, findAll(this.editor, hasClass('jodit-icon_loader')));
19050
19161
  if (this.activeTab === TABS.crop) {
19051
19162
  this.showCrop();
19052
19163
  }
@@ -19068,10 +19179,11 @@ let ImageEditor = ImageEditor_1 = class ImageEditor extends ViewComponent {
19068
19179
  if (!slide) {
19069
19180
  return;
19070
19181
  }
19071
- $$(`.${jie}__slider,.${jie}__area`, self.editor).forEach(elm => elm.classList.remove(`${jie}_active`));
19182
+ findAll(self.editor, elm => hasClass(`${jie}__slider`)(elm) || hasClass(`${jie}__area`)(elm)).forEach(elm => elm.classList.remove(`${jie}_active`));
19072
19183
  slide.classList.add(`${jie}_active`);
19073
19184
  this.activeTab = attr(slide, '-area') || TABS.resize;
19074
- const tab = self.editor.querySelector(`.${jie}__area.${jie}__area_` + self.activeTab);
19185
+ const tab = findFirst(self.editor, elm => hasClass(`${jie}__area`)(elm) &&
19186
+ hasClass(`${jie}__area_` + self.activeTab)(elm));
19075
19187
  if (tab) {
19076
19188
  tab.classList.add(`${jie}_active`);
19077
19189
  }
@@ -19296,7 +19408,7 @@ let ImageEditor = ImageEditor_1 = class ImageEditor extends ViewComponent {
19296
19408
  const { widthInput, heightInput } = refs(this.editor);
19297
19409
  self.j.e
19298
19410
  .on([
19299
- self.editor.querySelector('.jodit_bottomright'),
19411
+ findFirst(self.editor, hasClass('jodit_bottomright')),
19300
19412
  self.cropHandler
19301
19413
  ], `mousedown.${jie}`, this.onResizeHandleMouseDown)
19302
19414
  .on(this.j.ow, `resize.${jie}`, () => {
@@ -19305,7 +19417,7 @@ let ImageEditor = ImageEditor_1 = class ImageEditor extends ViewComponent {
19305
19417
  this.j.e.fire(self.cropHandler, 'updatesize');
19306
19418
  });
19307
19419
  self.j.e
19308
- .on(toArray(this.editor.querySelectorAll(`.${jie}__slider-title`)), 'click', this.onTitleModeClick)
19420
+ .on(findAll(this.editor, hasClass(`${jie}__slider-title`)), 'click', this.onTitleModeClick)
19309
19421
  .on([widthInput, heightInput], 'input', this.onChangeSizeInput);
19310
19422
  const { keepAspectRatioResize, keepAspectRatioCrop } = refs(this.editor);
19311
19423
  if (keepAspectRatioResize) {
@@ -19435,9 +19547,11 @@ let ImageEditor = ImageEditor_1 = class ImageEditor extends ViewComponent {
19435
19547
  const { resizeBox, cropBox } = refs(this.editor);
19436
19548
  this.resize_box = resizeBox;
19437
19549
  this.crop_box = cropBox;
19438
- this.sizes = this.editor.querySelector(`.${jie}__area.${jie}__area_crop .jodit-image-editor__sizes`);
19439
- this.resizeHandler = this.editor.querySelector(`.${jie}__resizer`);
19440
- this.cropHandler = this.editor.querySelector(`.${jie}__croper`);
19550
+ this.sizes = findFirst(this.editor, elm => hasClass(`${jie}__sizes`)(elm) &&
19551
+ Boolean(Dom.closest(elm, p => Dom.isHTMLElement(p) &&
19552
+ hasClass(`${jie}__area_crop`)(p), this.editor)));
19553
+ this.resizeHandler = findFirst(this.editor, hasClass(`${jie}__resizer`));
19554
+ this.cropHandler = findFirst(this.editor, hasClass(`${jie}__croper`));
19441
19555
  this._dialog = this.j.dlg({
19442
19556
  buttons: ['fullsize', 'dialog.close']
19443
19557
  });
@@ -19616,7 +19730,7 @@ var contextMenu = (self) => {
19616
19730
  buttons: ['fullsize', 'dialog.close']
19617
19731
  }), 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) => {
19618
19732
  const image = self.c.element('img');
19619
- image.setAttribute('src', src);
19733
+ attr(image, 'src', src);
19620
19734
  const onload = () => {
19621
19735
  var _a;
19622
19736
  if (self.isInDestruct) {
@@ -19626,14 +19740,14 @@ var contextMenu = (self) => {
19626
19740
  Dom.detach(temp_content);
19627
19741
  if (opt.showPreviewNavigation) {
19628
19742
  if (Dom.prevWithClass(item, self.files.getFullElName('item'))) {
19629
- temp_content.appendChild(prev);
19743
+ Dom.append(temp_content, prev);
19630
19744
  }
19631
19745
  if (Dom.nextWithClass(item, self.files.getFullElName('item'))) {
19632
- temp_content.appendChild(next);
19746
+ Dom.append(temp_content, next);
19633
19747
  }
19634
19748
  }
19635
- temp_content.appendChild(preview_box);
19636
- preview_box.appendChild(image);
19749
+ Dom.append(temp_content, preview_box);
19750
+ Dom.append(preview_box, image);
19637
19751
  preview.setPosition();
19638
19752
  (_a = self === null || self === void 0 ? void 0 : self.events) === null || _a === void 0 ? void 0 : _a.fire('previewOpenedAndLoaded');
19639
19753
  };
@@ -19973,11 +20087,11 @@ function stateListeners() {
19973
20087
  Dom.detach(files.container);
19974
20088
  if (state.elements.length) {
19975
20089
  state.elements.forEach(item => {
19976
- this.files.container.appendChild(getDomElement(item));
20090
+ Dom.append(this.files.container, getDomElement(item));
19977
20091
  });
19978
20092
  }
19979
20093
  else {
19980
- files.container.appendChild(create.div(this.componentName + '_no-files_true', this.i18n('There are no files')));
20094
+ Dom.append(files.container, create.div(this.componentName + '_no-files_true', this.i18n('There are no files')));
19981
20095
  }
19982
20096
  }, this.defaultTimeout))
19983
20097
  .on('change.sources', this.async.debounce(() => {
@@ -19985,7 +20099,7 @@ function stateListeners() {
19985
20099
  state.sources.forEach(source => {
19986
20100
  const sourceName = source.name;
19987
20101
  if (sourceName && sourceName !== DEFAULT_SOURCE_NAME) {
19988
- this.tree.container.appendChild(create.div(this.tree.getFullElName('source-title'), sourceName));
20102
+ Dom.append(this.tree.container, create.div(this.tree.getFullElName('source-title'), sourceName));
19989
20103
  }
19990
20104
  source.folders.forEach((name) => {
19991
20105
  const folderElm = create.a(this.tree.getFullElName('item'), {
@@ -20006,7 +20120,7 @@ function stateListeners() {
20006
20120
  e.preventDefault();
20007
20121
  };
20008
20122
  this.e.on(folderElm, 'click', action('openFolder'));
20009
- this.tree.container.appendChild(folderElm);
20123
+ Dom.append(this.tree.container, folderElm);
20010
20124
  if (name === '..' || name === '.') {
20011
20125
  return;
20012
20126
  }
@@ -20019,7 +20133,7 @@ function stateListeners() {
20019
20133
  size: 'tiny'
20020
20134
  });
20021
20135
  btn.onAction(action('renameFolder'));
20022
- folderElm.appendChild(btn.container);
20136
+ Dom.append(folderElm, btn.container);
20023
20137
  }
20024
20138
  if (options.deleteFolder &&
20025
20139
  this.dataProvider.canI('FolderRemove')) {
@@ -20030,7 +20144,7 @@ function stateListeners() {
20030
20144
  size: 'tiny'
20031
20145
  });
20032
20146
  btn.onAction(action('removeFolder'));
20033
- folderElm.appendChild(btn.container);
20147
+ Dom.append(folderElm, btn.container);
20034
20148
  }
20035
20149
  });
20036
20150
  if (options.createNewFolder &&
@@ -20137,7 +20251,8 @@ let FileBrowser = class FileBrowser extends ViewWithToolbar {
20137
20251
  return Storage.makeStorage(Boolean(this.o.saveStateInStorage), this.componentName);
20138
20252
  }
20139
20253
  get isOpened() {
20140
- return this._dialog.isOpened && this.browser.style.display !== 'none';
20254
+ return (this._dialog.isOpened &&
20255
+ cssInline(this.browser, 'display') !== 'none');
20141
20256
  }
20142
20257
  /**
20143
20258
  * It displays a message in the status bar of filebrowser
@@ -20298,10 +20413,10 @@ let FileBrowser = class FileBrowser extends ViewWithToolbar {
20298
20413
  self.browser.component = this;
20299
20414
  self.container = self.browser;
20300
20415
  if (self.o.showFoldersPanel) {
20301
- self.browser.appendChild(self.tree.container);
20416
+ Dom.append(self.browser, self.tree.container);
20302
20417
  }
20303
- self.browser.appendChild(self.files.container);
20304
- self.browser.appendChild(self.status_line);
20418
+ Dom.append(self.browser, self.files.container);
20419
+ Dom.append(self.browser, self.status_line);
20305
20420
  selfListeners.call(self);
20306
20421
  nativeListeners.call(self);
20307
20422
  stateListeners.call(self);
@@ -21006,14 +21121,13 @@ let StatusBar = class StatusBar extends ViewComponent {
21006
21121
  * Add element in statusbar
21007
21122
  */
21008
21123
  append(child, inTheRight = false) {
21009
- var _a;
21010
21124
  const wrapper = this.findEmpty(inTheRight) ||
21011
21125
  this.j.c.div(this.getFullElName('item'));
21012
21126
  if (inTheRight) {
21013
21127
  wrapper.classList.add(this.getFullElName('item-right'));
21014
21128
  }
21015
- wrapper.appendChild(child);
21016
- (_a = this.container) === null || _a === void 0 ? void 0 : _a.appendChild(wrapper);
21129
+ Dom.append(wrapper, child);
21130
+ this.container && Dom.append(this.container, wrapper);
21017
21131
  if (this.j.o.statusbar) {
21018
21132
  this.show();
21019
21133
  }
@@ -21024,7 +21138,7 @@ let StatusBar = class StatusBar extends ViewComponent {
21024
21138
  this.target = target;
21025
21139
  this.mods = {};
21026
21140
  this.container = jodit.c.div('jodit-status-bar');
21027
- target.appendChild(this.container);
21141
+ Dom.append(target, this.container);
21028
21142
  this.hide();
21029
21143
  }
21030
21144
  destruct() {
@@ -21203,37 +21317,40 @@ class Table extends ViewComponent {
21203
21317
  return Table.__formalCoordinate(table, cell, max);
21204
21318
  }
21205
21319
  static __appendRow(table, line, after, create) {
21206
- var _a;
21207
21320
  let row;
21208
21321
  if (!line) {
21209
21322
  const columnsCount = Table.__getColumnsCount(table);
21210
21323
  row = create.element('tr');
21211
21324
  for (let j = 0; j < columnsCount; j += 1) {
21212
- row.appendChild(create.element('td'));
21325
+ Dom.append(row, create.element('td'));
21213
21326
  }
21214
21327
  }
21215
21328
  else {
21216
21329
  row = line.cloneNode(true);
21217
- $$('td,th', line).forEach(cell => {
21330
+ Dom.each(line, cell => {
21331
+ if (!Dom.isCell(cell)) {
21332
+ return;
21333
+ }
21218
21334
  const rowspan = attr(cell, 'rowspan');
21219
21335
  if (rowspan && parseInt(rowspan, 10) > 1) {
21220
21336
  const newRowSpan = parseInt(rowspan, 10) - 1;
21221
21337
  attr(cell, 'rowspan', newRowSpan > 1 ? newRowSpan : null);
21222
21338
  }
21223
21339
  });
21224
- $$('td,th', row).forEach(cell => {
21225
- cell.innerHTML = '';
21340
+ Dom.each(row, cell => {
21341
+ if (Dom.isCell(cell)) {
21342
+ Dom.detach(cell);
21343
+ }
21226
21344
  });
21227
21345
  }
21228
21346
  if (after && line && line.nextSibling) {
21229
- line.parentNode &&
21230
- line.parentNode.insertBefore(row, line.nextSibling);
21347
+ Dom.after(line, row);
21231
21348
  }
21232
21349
  else if (!after && line) {
21233
- line.parentNode && line.parentNode.insertBefore(row, line);
21350
+ Dom.before(line, row);
21234
21351
  }
21235
21352
  else {
21236
- (((_a = table.getElementsByTagName('tbody')) === null || _a === void 0 ? void 0 : _a[0]) || table).appendChild(row);
21353
+ Dom.append(Dom.first(table, node => Dom.isTag(node, 'tbody')) || table, row);
21237
21354
  }
21238
21355
  }
21239
21356
  /**
@@ -21280,10 +21397,10 @@ class Table extends ViewComponent {
21280
21397
  }
21281
21398
  }
21282
21399
  if (referenceCell) {
21283
- nextRow.insertBefore(cell, referenceCell);
21400
+ Dom.before(referenceCell, cell);
21284
21401
  }
21285
21402
  else {
21286
- nextRow.appendChild(cell);
21403
+ Dom.append(nextRow, cell);
21287
21404
  }
21288
21405
  }
21289
21406
  }
@@ -21511,7 +21628,7 @@ class Table extends ViewComponent {
21511
21628
  return;
21512
21629
  }
21513
21630
  alreadyMerged.add(td);
21514
- if (i === bound[0][0] && td.style.width) {
21631
+ if (i === bound[0][0] && cssInline(td, 'width')) {
21515
21632
  w += td.offsetWidth;
21516
21633
  }
21517
21634
  if (trim(cell.innerHTML.replace(/<br(\/)?>/g, '')) !== '') {
@@ -21573,7 +21690,7 @@ class Table extends ViewComponent {
21573
21690
  const __marked = [];
21574
21691
  Table.__getSelectedCellsByTable(table).forEach((cell) => {
21575
21692
  td = jodit.createInside.element('td');
21576
- td.appendChild(jodit.createInside.element('br'));
21693
+ Dom.append(td, jodit.createInside.element('br'));
21577
21694
  tr = jodit.createInside.element('tr');
21578
21695
  coord = Table.__formalCoordinate(table, cell);
21579
21696
  if (cell.rowSpan < 2) {
@@ -21585,7 +21702,7 @@ class Table extends ViewComponent {
21585
21702
  }
21586
21703
  });
21587
21704
  Dom.after(Dom.closest(cell, 'tr', table), tr);
21588
- tr.appendChild(td);
21705
+ Dom.append(tr, td);
21589
21706
  }
21590
21707
  else {
21591
21708
  Table.__mark(cell, 'rowspan', cell.rowSpan - 1, __marked);
@@ -21605,7 +21722,7 @@ class Table extends ViewComponent {
21605
21722
  Dom.after(after, td);
21606
21723
  }
21607
21724
  else {
21608
- parent.insertBefore(td, parent.firstChild);
21725
+ Dom.prepend(parent, td);
21609
21726
  }
21610
21727
  }
21611
21728
  if (cell.colSpan > 1) {
@@ -21638,7 +21755,7 @@ class Table extends ViewComponent {
21638
21755
  Table.__mark(cell, 'colspan', cell.colSpan - 1, __marked);
21639
21756
  }
21640
21757
  td = jodit.createInside.element('td');
21641
- td.appendChild(jodit.createInside.element('br'));
21758
+ Dom.append(td, jodit.createInside.element('br'));
21642
21759
  if (cell.rowSpan > 1) {
21643
21760
  Table.__mark(td, 'rowspan', cell.rowSpan, __marked);
21644
21761
  }
@@ -21717,7 +21834,7 @@ class Table extends ViewComponent {
21717
21834
  }
21718
21835
  }
21719
21836
  else {
21720
- cell.style.width = value.toString();
21837
+ css(cell, 'width', value.toString());
21721
21838
  }
21722
21839
  break;
21723
21840
  }
@@ -21845,20 +21962,20 @@ let ToolbarButton = class ToolbarButton extends UIButton {
21845
21962
  value: this,
21846
21963
  configurable: true
21847
21964
  });
21848
- container.appendChild(button);
21965
+ Dom.append(container, button);
21849
21966
  const trigger = this.j.c.fromHTML(`<span role="button" aria-haspopup="true" aria-expanded="false" class="${cn}__trigger">${Icon.get('chevron')}</span>`);
21850
21967
  // For caching
21851
- button.appendChild(trigger);
21968
+ Dom.append(button, trigger);
21852
21969
  return container;
21853
21970
  }
21854
21971
  /** @override */
21855
21972
  focus() {
21856
21973
  var _a;
21857
- (_a = this.container.querySelector('button')) === null || _a === void 0 ? void 0 : _a.focus();
21974
+ (_a = Dom.first(this.container, node => Dom.isTag(node, 'button'))) === null || _a === void 0 ? void 0 : _a.focus();
21858
21975
  }
21859
21976
  onChangeHasTrigger() {
21860
21977
  if (this.state.hasTrigger) {
21861
- this.container.appendChild(this.trigger);
21978
+ Dom.append(this.container, this.trigger);
21862
21979
  }
21863
21980
  else {
21864
21981
  Dom.safeRemove(this.trigger);
@@ -22095,17 +22212,25 @@ let ToolbarButton = class ToolbarButton extends UIButton {
22095
22212
  return this.openedPopup;
22096
22213
  }
22097
22214
  __closePopup() {
22098
- if (this.openedPopup) {
22099
- this.j.e
22100
- .off(this.ow, 'mousedown touchstart', this.onOutsideClick)
22101
- .off('escape closeAllPopups', this.onOutsideClick);
22102
- this.state.activated = false;
22103
- this.openedPopup.close();
22104
- this.openedPopup.destruct();
22105
- this.openedPopup = null;
22106
- if (this.trigger) {
22107
- attr(this.trigger, 'aria-expanded', false);
22108
- }
22215
+ const popup = this.openedPopup;
22216
+ if (!popup) {
22217
+ return;
22218
+ }
22219
+ // Detach first: removing a popup that holds the focused element
22220
+ // makes Chrome fire `blur`/`change` on it synchronously, and a
22221
+ // handler there may call the popup's `close` callback again.
22222
+ // A re-entrant call must be a no-op, otherwise it destructs the
22223
+ // popup while the outer `removeChild` is still running and Chrome
22224
+ // throws NotFoundError. See #1458
22225
+ this.openedPopup = null;
22226
+ this.j.e
22227
+ .off(this.ow, 'mousedown touchstart', this.onOutsideClick)
22228
+ .off('escape closeAllPopups', this.onOutsideClick);
22229
+ this.state.activated = false;
22230
+ popup.close();
22231
+ popup.destruct();
22232
+ if (this.trigger) {
22233
+ attr(this.trigger, 'aria-expanded', false);
22109
22234
  }
22110
22235
  }
22111
22236
  /**
@@ -22191,6 +22316,12 @@ var __decorate$j = (undefined && undefined.__decorate) || function (decorators,
22191
22316
  r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
22192
22317
  return c > 3 && r && Object.defineProperty(target, key, r), r;
22193
22318
  };
22319
+ const FORM_CONTROL_TAGS = new Set([
22320
+ 'input',
22321
+ 'button',
22322
+ 'select',
22323
+ 'textarea'
22324
+ ]);
22194
22325
  let ToolbarContent = class ToolbarContent extends UIButton {
22195
22326
  /** @override */
22196
22327
  className() {
@@ -22203,7 +22334,7 @@ let ToolbarContent = class ToolbarContent extends UIButton {
22203
22334
  const content = control.getContent(this.j, this);
22204
22335
  if (isString(content) || content.parentNode !== this.container) {
22205
22336
  Dom.detach(this.container);
22206
- this.container.appendChild(isString(content) ? this.j.create.fromHTML(content) : content);
22337
+ Dom.append(this.container, isString(content) ? this.j.create.fromHTML(content) : content);
22207
22338
  }
22208
22339
  // Content controls never went through the ToolbarButton status
22209
22340
  // calculation, so `isDisabled`/`isActive`/`update` declared on the
@@ -22226,9 +22357,11 @@ let ToolbarContent = class ToolbarContent extends UIButton {
22226
22357
  */
22227
22358
  onChangeDisabled() {
22228
22359
  super.onChangeDisabled();
22229
- this.container
22230
- .querySelectorAll('input,button,select,textarea')
22231
- .forEach(elm => attr(elm, 'disabled', this.state.disabled || null));
22360
+ Dom.each(this.container, elm => {
22361
+ if (Dom.isTag(elm, FORM_CONTROL_TAGS)) {
22362
+ attr(elm, 'disabled', this.state.disabled || null);
22363
+ }
22364
+ });
22232
22365
  }
22233
22366
  /** @override */
22234
22367
  createContainer() {
@@ -22356,8 +22489,8 @@ let ToolbarCollection = class ToolbarCollection extends UIList {
22356
22489
  * Set direction
22357
22490
  */
22358
22491
  setDirection(direction) {
22359
- this.container.style.direction = direction;
22360
- this.container.setAttribute('dir', direction);
22492
+ css(this.container, 'direction', direction);
22493
+ attr(this.container, 'dir', direction);
22361
22494
  }
22362
22495
  constructor(jodit) {
22363
22496
  super(jodit);
@@ -22864,11 +22997,11 @@ Config.prototype.uploader = {
22864
22997
  }
22865
22998
  if (resp.files && resp.files.length) {
22866
22999
  resp.files.forEach((filename, index) => {
22867
- const [tagName, attr] = resp.isImages && resp.isImages[index]
23000
+ const [tagName, attrName] = resp.isImages && resp.isImages[index]
22868
23001
  ? ['img', 'src']
22869
23002
  : ['a', 'href'];
22870
23003
  const elm = j.createInside.element(tagName);
22871
- elm.setAttribute(attr, resp.baseurl + filename);
23004
+ attr(elm, attrName, resp.baseurl + filename);
22872
23005
  if (tagName === 'a') {
22873
23006
  elm.textContent = j.o.uploader.getDisplayName.call(this, resp.baseurl, filename);
22874
23007
  }
@@ -23014,7 +23147,11 @@ class Uploader extends ViewComponent {
23014
23147
  sendFiles(self, event.dataTransfer.files, handlerSuccess, handlerError).finally(onFinally);
23015
23148
  }
23016
23149
  });
23017
- const inputFile = form.querySelector('input[type=file]');
23150
+ const inputFile = Dom.first(form, node => {
23151
+ var _a;
23152
+ return Dom.isTag(node, 'input') &&
23153
+ ((_a = attr(node, 'type')) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === 'file';
23154
+ });
23018
23155
  if (inputFile) {
23019
23156
  self.j.e.on(inputFile, 'change', () => {
23020
23157
  sendFiles(self, inputFile.files, handlerSuccess, handlerError)
@@ -23394,6 +23531,7 @@ function getSuitChild(style, font) {
23394
23531
  * @private
23395
23532
  */
23396
23533
  function getSuitParent(style, node, root) {
23534
+ var _a;
23397
23535
  const { parentNode } = node;
23398
23536
  if (parentNode === root ||
23399
23537
  !Dom.isHTMLElement(parentNode) ||
@@ -23407,6 +23545,15 @@ function getSuitParent(style, node, root) {
23407
23545
  !Dom.isBlock(parentNode)) {
23408
23546
  return getSuitParent(style, parentNode, root);
23409
23547
  }
23548
+ // <li>|test|</li> => apply the CSS style to the <li> itself, so the
23549
+ // list marker (bullet/number) gets the same color and size as the text.
23550
+ // Only for pure style commits: bold/italic keep wrapping the content.
23551
+ // See #1460
23552
+ if (Dom.isTag(parentNode, 'li') &&
23553
+ !style.isElementCommit &&
23554
+ ((_a = style.options.attributes) === null || _a === void 0 ? void 0 : _a.style)) {
23555
+ return parentNode;
23556
+ }
23410
23557
  if (isSuitElement(style, parentNode, false) &&
23411
23558
  (!Dom.isBlock(parentNode) || style.elementIsBlock)) {
23412
23559
  return parentNode;
@@ -23459,8 +23606,10 @@ function isSameAttributes(elm, attrs) {
23459
23606
  }
23460
23607
  function elementsEqualAttributes(elm1, elm2) {
23461
23608
  return (elm1.attributes.length === elm2.attributes.length &&
23462
- Array.from(elm1.attributes).every(attr => elm2.hasAttribute(attr.name) &&
23463
- elm2.getAttribute(attr.name) === attr.value));
23609
+ Array.from(elm1.attributes).every(
23610
+ // `attrRaw` on purpose: the comparison must use the exact
23611
+ // attribute name from the live list, without `attr()` name mangling
23612
+ attr => attrRaw(elm2, attr.name) === attr.value));
23464
23613
  }
23465
23614
 
23466
23615
  /*!
@@ -23501,7 +23650,7 @@ function toggleAttributes(commitStyle, elm, jodit, mode, dry = false) {
23501
23650
  function toggleStyle(commitStyle, jodit, style, elm, dry, mode) {
23502
23651
  assert(isPlainObject(style) && size$1(style), 'Style must be an object');
23503
23652
  Object.keys(style).forEach((rule) => {
23504
- const inlineValue = elm.style.getPropertyValue(kebabCase(rule));
23653
+ const inlineValue = cssInline(elm, rule);
23505
23654
  const newValue = style[rule];
23506
23655
  if (inlineValue === '' && newValue == null) {
23507
23656
  return;
@@ -23594,8 +23743,8 @@ function getShadowRoot(jodit) {
23594
23743
  position: 'absolute',
23595
23744
  border: 0
23596
23745
  });
23597
- iframe.src = 'about:blank';
23598
- container.appendChild(iframe);
23746
+ attr(iframe, 'src', 'about:blank');
23747
+ Dom.append(container, iframe);
23599
23748
  const doc = (_a = iframe.contentWindow) === null || _a === void 0 ? void 0 : _a.document;
23600
23749
  const shadowRoot = !doc ? jodit.od.body : doc.body;
23601
23750
  dataBind(jodit, 'shadowRoot', shadowRoot);
@@ -23611,11 +23760,11 @@ function getNativeCSSValue(jodit, elm, key) {
23611
23760
  // browser default black) is recognised. Without this, applying black after
23612
23761
  // the default font color was changed was wrongly treated as a no-op (#1311).
23613
23762
  const wrapper = jodit.create.element('div');
23614
- wrapper.style.color = css(jodit.editor, 'color');
23763
+ css(wrapper, 'color', css(jodit.editor, 'color'));
23615
23764
  const newElm = jodit.create.element(elm.tagName.toLowerCase());
23616
- newElm.style.cssText = elm.style.cssText;
23617
- wrapper.appendChild(newElm);
23618
- root.appendChild(wrapper);
23765
+ attr(newElm, 'style', attr(elm, 'style'));
23766
+ Dom.append(wrapper, newElm);
23767
+ Dom.append(root, wrapper);
23619
23768
  const result = css(newElm, key);
23620
23769
  Dom.safeRemove(wrapper);
23621
23770
  return result;
@@ -23816,12 +23965,12 @@ function wrapUnwrappedText(style, elm, jodit) {
23816
23965
  range.setEndAfter(end);
23817
23966
  const fragment = range.extractContents();
23818
23967
  const wrapper = ci.element(style.element);
23819
- wrapper.appendChild(fragment);
23968
+ Dom.append(wrapper, fragment);
23820
23969
  Dom.safeInsertNode(range, wrapper);
23821
23970
  if (style.elementIsBlock) {
23822
23971
  if (Dom.isEmpty(wrapper) &&
23823
23972
  !Dom.isTag(wrapper.firstElementChild, 'br')) {
23824
- wrapper.appendChild(ci.element('br'));
23973
+ Dom.append(wrapper, ci.element('br'));
23825
23974
  }
23826
23975
  }
23827
23976
  return wrapper;
@@ -23872,7 +24021,9 @@ const WRAP_NODES = new Set([
23872
24021
  */
23873
24022
  function findOrCreateWrapper(commitStyle, font, jodit) {
23874
24023
  if (commitStyle.elementIsBlock) {
23875
- const box = Dom.up(font, node => Dom.isBlock(node) && !Dom.isTag(node, WRAP_NODES), jodit.editor);
24024
+ const box = Dom.up(font, node => Dom.isBlock(node) &&
24025
+ !Dom.isTag(node, WRAP_NODES) &&
24026
+ !hasBlockChildren(node), jodit.editor);
23876
24027
  if (box) {
23877
24028
  return box;
23878
24029
  }
@@ -23881,6 +24032,14 @@ function findOrCreateWrapper(commitStyle, font, jodit) {
23881
24032
  attr(font, 'size', null);
23882
24033
  return font;
23883
24034
  }
24035
+ /**
24036
+ * A block that itself contains block-level children is a layout container:
24037
+ * replacing it wholesale would merge all its blocks into the new element,
24038
+ * so the selection must be wrapped in a new block inside it instead.
24039
+ */
24040
+ function hasBlockChildren(node) {
24041
+ return Array.from(node.childNodes).some(child => Dom.isBlock(child));
24042
+ }
23884
24043
 
23885
24044
  /*!
23886
24045
  * Jodit Editor (https://xdsoft.net/jodit/)
@@ -24041,11 +24200,25 @@ const transactions = {
24041
24200
  },
24042
24201
  [states.UNWRAP]: {
24043
24202
  exec(value) {
24044
- if (value.element.attributes.length &&
24045
- Dom.isTag(value.element, value.style.element)) {
24203
+ const { element, style, jodit } = value;
24204
+ if (element.attributes.length &&
24205
+ Dom.isTag(element, style.element)) {
24206
+ return { ...value, next: states.REPLACE_DEFAULT };
24207
+ }
24208
+ // Unwrapping a block inside a container (e.g. an h3 inside a div)
24209
+ // leaves bare inline content there: the wrapNodes plugin restores
24210
+ // paragraphs only at the editor root. Replace such a block with
24211
+ // the default tag instead.
24212
+ const parent = element.parentElement;
24213
+ if (style.elementIsBlock &&
24214
+ !style.elementIsDefault &&
24215
+ parent &&
24216
+ parent !== jodit.editor &&
24217
+ Dom.isBlock(parent) &&
24218
+ !Dom.isTag(parent, WRAP_NODES)) {
24046
24219
  return { ...value, next: states.REPLACE_DEFAULT };
24047
24220
  }
24048
- Dom.unwrap(value.element);
24221
+ Dom.unwrap(element);
24049
24222
  return { ...value, mode: UNWRAP, next: states.END };
24050
24223
  }
24051
24224
  },
@@ -24190,7 +24363,7 @@ function moveNodeInsideStart(j, node, start) {
24190
24363
  Dom.isContentEditable(sibling, j.editor) &&
24191
24364
  (!anotherSibling || !Dom.closest(node, Dom.isElement, j.editor))) {
24192
24365
  if (start || !sibling.firstChild) {
24193
- sibling.appendChild(node);
24366
+ Dom.append(sibling, node);
24194
24367
  }
24195
24368
  else {
24196
24369
  Dom.before(sibling.firstChild, node);
@@ -24445,11 +24618,13 @@ class Selection {
24445
24618
  Number(new Date()) +
24446
24619
  '_' +
24447
24620
  String(Math.random()).slice(2);
24448
- marker.style.lineHeight = '0';
24449
- marker.style.display = 'none';
24621
+ css(marker, {
24622
+ lineHeight: '0',
24623
+ display: 'none'
24624
+ });
24450
24625
  Dom.markTemporary(marker);
24451
24626
  attr(marker, 'data-' + MARKER_CLASS, atStart ? 'start' : 'end');
24452
- marker.appendChild(this.j.createInside.text(INVISIBLE_SPACE));
24627
+ Dom.append(marker, this.j.createInside.text(INVISIBLE_SPACE));
24453
24628
  if (newRange) {
24454
24629
  if (Dom.isOrContains(this.area, atStart ? newRange.startContainer : newRange.endContainer)) {
24455
24630
  // Here need do unsafe inserting
@@ -24465,9 +24640,11 @@ class Selection {
24465
24640
  */
24466
24641
  restore() {
24467
24642
  let range = false;
24468
- const markAttr = (start) => `span[data-${MARKER_CLASS}=${start ? 'start' : 'end'}]`;
24469
- const start = this.area.querySelector(markAttr(true));
24470
- const end = this.area.querySelector(markAttr(false));
24643
+ const markerFilter = (start) => (node) => Dom.isMarker(node) &&
24644
+ attr(node, 'data-' + MARKER_CLASS) ===
24645
+ (start ? 'start' : 'end');
24646
+ const start = Dom.first(this.area, markerFilter(true));
24647
+ const end = Dom.first(this.area, markerFilter(false));
24471
24648
  if (!start) {
24472
24649
  return;
24473
24650
  }
@@ -24721,7 +24898,7 @@ class Selection {
24721
24898
  Dom.safeInsertNode(range, node);
24722
24899
  }
24723
24900
  else {
24724
- this.area.appendChild(node);
24901
+ Dom.append(this.area, node);
24725
24902
  }
24726
24903
  [
24727
24904
  () => firstChild === null || firstChild === void 0 ? void 0 : firstChild.previousSibling,
@@ -24735,7 +24912,7 @@ class Selection {
24735
24912
  });
24736
24913
  }
24737
24914
  else {
24738
- this.area.appendChild(node);
24915
+ Dom.append(this.area, node);
24739
24916
  }
24740
24917
  const setCursor = (node) => {
24741
24918
  if (Dom.isBlock(node)) {
@@ -24789,7 +24966,7 @@ class Selection {
24789
24966
  node.innerHTML = html.toString();
24790
24967
  }
24791
24968
  else {
24792
- node.appendChild(html);
24969
+ Dom.append(node, html);
24793
24970
  }
24794
24971
  if (!this.j.isEditorMode() &&
24795
24972
  this.j.e.fire('insertHTML', node.innerHTML) === false) {
@@ -24798,9 +24975,7 @@ class Selection {
24798
24975
  if (!node.lastChild) {
24799
24976
  return;
24800
24977
  }
24801
- while (node.firstChild) {
24802
- fragment.appendChild(node.firstChild);
24803
- }
24978
+ Dom.moveContent(node, fragment);
24804
24979
  this.insertNode(fragment, insertCursorAfter, false);
24805
24980
  // There is no need to use synchronizeValues because you need to apply the changes immediately
24806
24981
  this.j.__imdSynchronizeValues();
@@ -24815,7 +24990,7 @@ class Selection {
24815
24990
  insertImage(url, styles = null, defaultWidth = null) {
24816
24991
  const image = isString(url) ? this.j.createInside.element('img') : url;
24817
24992
  if (isString(url)) {
24818
- image.setAttribute('src', url);
24993
+ attr(image, 'src', url);
24819
24994
  }
24820
24995
  if (defaultWidth != null) {
24821
24996
  let dw = defaultWidth.toString();
@@ -24833,8 +25008,10 @@ class Selection {
24833
25008
  const onload = () => {
24834
25009
  if (image.naturalHeight < image.offsetHeight ||
24835
25010
  image.naturalWidth < image.offsetWidth) {
24836
- image.style.width = '';
24837
- image.style.height = '';
25011
+ css(image, {
25012
+ width: '',
25013
+ height: ''
25014
+ });
24838
25015
  }
24839
25016
  image.removeEventListener('load', onload);
24840
25017
  };
@@ -24923,7 +25100,7 @@ class Selection {
24923
25100
  }
24924
25101
  else {
24925
25102
  const currentB = this.j.createInside.text(INVISIBLE_SPACE);
24926
- current.appendChild(currentB);
25103
+ Dom.append(current, currentB);
24927
25104
  current = currentB;
24928
25105
  }
24929
25106
  }
@@ -25074,7 +25251,7 @@ class Selection {
25074
25251
  if (!start) {
25075
25252
  const fakeNode = this.j.createInside.text(INVISIBLE_SPACE);
25076
25253
  if (!Dom.isTag(last, INSEPARABLE_TAGS)) {
25077
- last.appendChild(fakeNode);
25254
+ Dom.append(last, fakeNode);
25078
25255
  last = fakeNode;
25079
25256
  }
25080
25257
  else {
@@ -25142,7 +25319,7 @@ class Selection {
25142
25319
  const range = sel.getRangeAt(0);
25143
25320
  const clonedSelection = range.cloneContents();
25144
25321
  const div = this.j.createInside.div();
25145
- div.appendChild(clonedSelection);
25322
+ Dom.append(div, clonedSelection);
25146
25323
  return div.innerHTML;
25147
25324
  }
25148
25325
  return '';
@@ -25282,11 +25459,10 @@ class Selection {
25282
25459
  return toArray(node.childNodes).some(child => this.__isOrContainsBlock(child));
25283
25460
  }
25284
25461
  __wrapRunInFont(run) {
25285
- var _a;
25286
25462
  const font = this.j.createInside.element('font');
25287
25463
  const [first] = run;
25288
- (_a = first.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(font, first);
25289
- run.forEach(node => font.appendChild(node));
25464
+ Dom.before(first, font);
25465
+ run.forEach(node => Dom.append(font, node));
25290
25466
  return font;
25291
25467
  }
25292
25468
  /**
@@ -25297,7 +25473,7 @@ class Selection {
25297
25473
  const font = this.jodit.createInside.element('font', INVISIBLE_SPACE);
25298
25474
  this.insertNode(font, false, false);
25299
25475
  if (fakes && fakes[0]) {
25300
- font.appendChild(fakes[0]);
25476
+ Dom.append(font, fakes[0]);
25301
25477
  }
25302
25478
  yield font;
25303
25479
  Dom.unwrap(font);
@@ -25432,7 +25608,7 @@ class Selection {
25432
25608
  try {
25433
25609
  clearEmpties(fragment);
25434
25610
  clearEmpties(currentBox);
25435
- currentBox.parentNode.insertBefore(fragment, currentBox);
25611
+ Dom.before(currentBox, fragment);
25436
25612
  if (!edge && cursorOnTheRight && (br === null || br === void 0 ? void 0 : br.parentNode)) {
25437
25613
  const range = this.createRange();
25438
25614
  range.setStartBefore(br);
@@ -25443,9 +25619,9 @@ class Selection {
25443
25619
  }
25444
25620
  // After splitting some part can be empty
25445
25621
  const fillFakeParent = (fake) => {
25446
- var _a, _b, _c;
25447
- 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)) {
25448
- (_c = fake === null || fake === void 0 ? void 0 : fake.parentNode) === null || _c === void 0 ? void 0 : _c.appendChild(br.cloneNode());
25622
+ const parent = fake === null || fake === void 0 ? void 0 : fake.parentNode;
25623
+ if (parent && parent.firstChild === parent.lastChild) {
25624
+ Dom.append(parent, br.cloneNode());
25449
25625
  }
25450
25626
  };
25451
25627
  fillFakeParent(prevFake);
@@ -26413,7 +26589,7 @@ let Jodit$1 = Jodit_1 = class Jodit extends ViewWithToolbar {
26413
26589
  this.setReadOnly(isDisabled || readOnly);
26414
26590
  this.__wasReadOnly = readOnly;
26415
26591
  if (this.editor) {
26416
- this.editor.setAttribute('aria-disabled', isDisabled.toString());
26592
+ attr(this.editor, 'aria-disabled', isDisabled);
26417
26593
  this.container.classList.toggle('jodit_disabled', isDisabled);
26418
26594
  this.e.fire('disabled', isDisabled);
26419
26595
  }
@@ -26437,10 +26613,10 @@ let Jodit$1 = Jodit_1 = class Jodit extends ViewWithToolbar {
26437
26613
  this.__wasReadOnly = isReadOnly;
26438
26614
  this.o.readonly = isReadOnly;
26439
26615
  if (isReadOnly) {
26440
- this.editor && this.editor.removeAttribute('contenteditable');
26616
+ this.editor && attr(this.editor, 'contenteditable', null);
26441
26617
  }
26442
26618
  else {
26443
- this.editor && this.editor.setAttribute('contenteditable', 'true');
26619
+ this.editor && attr(this.editor, 'contenteditable', true);
26444
26620
  }
26445
26621
  this.e && this.e.fire('readonly', isReadOnly);
26446
26622
  }
@@ -26599,14 +26775,14 @@ let Jodit$1 = Jodit_1 = class Jodit extends ViewWithToolbar {
26599
26775
  const property = kebabCase(key);
26600
26776
  container.style.setProperty(`--jd-${property}`, styleValues[key]);
26601
26777
  });
26602
- container.setAttribute('contenteditable', 'false');
26778
+ attr(container, 'contenteditable', false);
26603
26779
  let buffer = null;
26604
26780
  if (this.o.inline) {
26605
26781
  if (['TEXTAREA', 'INPUT'].indexOf(element.nodeName) === -1) {
26606
26782
  container = element;
26607
- element.setAttribute(__defaultClassesKey, element.className.toString());
26783
+ attr(element, __defaultClassesKey, element.className.toString());
26608
26784
  buffer = container.innerHTML;
26609
- container.innerHTML = '';
26785
+ Dom.detach(container);
26610
26786
  }
26611
26787
  container.classList.add('jodit_inline');
26612
26788
  container.classList.add('jodit-container');
@@ -26614,32 +26790,33 @@ let Jodit$1 = Jodit_1 = class Jodit extends ViewWithToolbar {
26614
26790
  // actual for inline mode
26615
26791
  if (element !== container) {
26616
26792
  // hide source element
26617
- if (element.style.display) {
26618
- element.setAttribute(__defaultStyleDisplayKey, element.style.display);
26793
+ const display = cssInline(element, 'display');
26794
+ if (display) {
26795
+ attr(element, __defaultStyleDisplayKey, display);
26619
26796
  }
26620
- element.style.display = 'none';
26797
+ css(element, 'display', 'none');
26621
26798
  }
26622
26799
  const SLOT = 'workplace-slot';
26623
26800
  // A slot that always stays ABOVE the toolbar (presence bars, banners…).
26624
26801
  // The `data-jodit-above-toolbar` attribute tells ViewWithToolbar to keep
26625
26802
  // the toolbar box below it when (re)attaching the toolbar container.
26626
26803
  const aboveSlot = this.c.div(this.getFullElName(SLOT, 'above'), NOEDIT);
26627
- aboveSlot.setAttribute('data-jodit-above-toolbar', '');
26804
+ attr(aboveSlot, 'data-jodit-above-toolbar', '');
26628
26805
  Dom.appendChildFirst(container, aboveSlot);
26629
26806
  const topSlot = this.c.div(this.getFullElName(SLOT, 'top'), NOEDIT);
26630
- container.appendChild(topSlot);
26807
+ Dom.append(container, topSlot);
26631
26808
  const centerSlot = this.c.div(this.getFullElName(SLOT, 'center'), NOEDIT);
26632
26809
  const workplace = this.c.div('jodit-workplace', NOEDIT);
26633
26810
  const leftSlot = this.c.div(this.getFullElName(SLOT, 'left'), NOEDIT);
26634
26811
  const rightSlot = this.c.div(this.getFullElName(SLOT, 'right'), NOEDIT);
26635
- centerSlot.appendChild(leftSlot);
26636
- centerSlot.appendChild(workplace);
26637
- centerSlot.appendChild(rightSlot);
26638
- container.appendChild(centerSlot);
26812
+ Dom.append(centerSlot, leftSlot);
26813
+ Dom.append(centerSlot, workplace);
26814
+ Dom.append(centerSlot, rightSlot);
26815
+ Dom.append(container, centerSlot);
26639
26816
  const bottomPanel = this.c.div(this.getFullElName(SLOT, 'bottom'), NOEDIT);
26640
- container.appendChild(bottomPanel);
26817
+ Dom.append(container, bottomPanel);
26641
26818
  if (element.parentNode && element !== container) {
26642
- element.parentNode.insertBefore(container, element);
26819
+ Dom.before(element, container);
26643
26820
  }
26644
26821
  Object.defineProperty(element, 'component', {
26645
26822
  enumerable: false,
@@ -26651,7 +26828,7 @@ let Jodit$1 = Jodit_1 = class Jodit extends ViewWithToolbar {
26651
26828
  'aria-disabled': false,
26652
26829
  tabindex: this.o.tabIndex
26653
26830
  });
26654
- workplace.appendChild(editor);
26831
+ Dom.append(workplace, editor);
26655
26832
  const currentPlace = {
26656
26833
  editor,
26657
26834
  element,
@@ -26705,7 +26882,7 @@ let Jodit$1 = Jodit_1 = class Jodit extends ViewWithToolbar {
26705
26882
  return callPromise(initResult, init);
26706
26883
  }
26707
26884
  addDisclaimer(elm) {
26708
- this.workplace.appendChild(elm);
26885
+ Dom.append(this.workplace, elm);
26709
26886
  }
26710
26887
  /**
26711
26888
  * Set current place object
@@ -26802,10 +26979,10 @@ let Jodit$1 = Jodit_1 = class Jodit extends ViewWithToolbar {
26802
26979
  // direction
26803
26980
  if (this.o.direction) {
26804
26981
  const direction = this.o.direction.toLowerCase() === 'rtl' ? 'rtl' : 'ltr';
26805
- this.editor.style.direction = direction;
26806
- this.editor.setAttribute('dir', direction);
26807
- this.container.style.direction = direction;
26808
- this.container.setAttribute('dir', direction);
26982
+ css(this.editor, 'direction', direction);
26983
+ attr(this.editor, 'dir', direction);
26984
+ css(this.container, 'direction', direction);
26985
+ attr(this.container, 'dir', direction);
26809
26986
  this.toolbar.setDirection(direction);
26810
26987
  }
26811
26988
  // proxy events
@@ -26898,23 +27075,23 @@ let Jodit$1 = Jodit_1 = class Jodit extends ViewWithToolbar {
26898
27075
  if (element.hasAttribute(__defaultStyleDisplayKey)) {
26899
27076
  const display = attr(element, __defaultStyleDisplayKey);
26900
27077
  if (display) {
26901
- element.style.display = display;
26902
- element.removeAttribute(__defaultStyleDisplayKey);
27078
+ css(element, 'display', display);
27079
+ attr(element, __defaultStyleDisplayKey, null);
26903
27080
  }
26904
27081
  }
26905
27082
  else {
26906
- element.style.display = '';
27083
+ css(element, 'display', '');
26907
27084
  }
26908
27085
  }
26909
27086
  else {
26910
27087
  if (element.hasAttribute(__defaultClassesKey)) {
26911
27088
  element.className =
26912
27089
  attr(element, __defaultClassesKey) || '';
26913
- element.removeAttribute(__defaultClassesKey);
27090
+ attr(element, __defaultClassesKey, null);
26914
27091
  }
26915
27092
  }
26916
27093
  if (element.hasAttribute('style') && !attr(element, 'style')) {
26917
- element.removeAttribute('style');
27094
+ attr(element, 'style', null);
26918
27095
  }
26919
27096
  statusbar.destruct();
26920
27097
  this.e.off(container);
@@ -33121,7 +33298,10 @@ function resolveTableSibling(sibling, backspace) {
33121
33298
  if (!Dom.isTag(sibling, 'table')) {
33122
33299
  return sibling;
33123
33300
  }
33124
- const cells = sibling.querySelectorAll('td,th');
33301
+ const cells = [];
33302
+ Dom.each(sibling, node => {
33303
+ Dom.isCell(node) && cells.push(node);
33304
+ });
33125
33305
  return cells.length ? cells[backspace ? cells.length - 1 : 0] : null;
33126
33306
  }
33127
33307
  function checkMoveListContent(jodit, mainClosestBox, sibling, backspace) {
@@ -33718,6 +33898,13 @@ pluginSystem.add('backspace', backspace);
33718
33898
  * Released under MIT see LICENSE.txt in the project root for license information.
33719
33899
  * Copyright (c) 2013-2026 Valerii Chupurnov. All rights reserved. https://xdsoft.net
33720
33900
  */
33901
+ const NOT_EMPTY_CONTENT_TAGS = new Set([
33902
+ 'img',
33903
+ 'table',
33904
+ 'jodit',
33905
+ 'iframe',
33906
+ 'hr'
33907
+ ]);
33721
33908
  class deleteCommand extends Plugin {
33722
33909
  afterInit(jodit) {
33723
33910
  jodit.e.on('afterCommand.delete', (command) => {
@@ -33744,9 +33931,9 @@ class deleteCommand extends Plugin {
33744
33931
  jodit.s.removeNode(current.firstChild);
33745
33932
  }
33746
33933
  if (!trim(jodit.editor.textContent || '') &&
33747
- !jodit.editor.querySelector('img,table,jodit,iframe,hr') &&
33934
+ !Dom.first(jodit.editor, node => Dom.isTag(node, NOT_EMPTY_CONTENT_TAGS)) &&
33748
33935
  (!current || !Dom.closest(current, 'table', jodit.editor))) {
33749
- jodit.editor.innerHTML = '';
33936
+ Dom.detach(jodit.editor);
33750
33937
  const node = jodit.s.setCursorIn(jodit.editor);
33751
33938
  jodit.s.removeNode(node);
33752
33939
  }
@@ -34016,13 +34203,20 @@ const ColorPickerWidget = (editor, callback, coldColor) => {
34016
34203
  }
34017
34204
  return stack.join('');
34018
34205
  };
34019
- form.appendChild(editor.c.fromHTML(`<div class="${cn}__groups">${eachColor(editor.o.colors)}</div>`));
34020
- form.appendChild(editor.c.fromHTML(`<div data-ref="extra" class="${cn}__extra"></div>`));
34206
+ Dom.append(form, editor.c.fromHTML(`<div class="${cn}__groups">${eachColor(editor.o.colors)}</div>`));
34207
+ Dom.append(form, editor.c.fromHTML(`<div data-ref="extra" class="${cn}__extra"></div>`));
34021
34208
  const { extra } = refs(form);
34022
- 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>`));
34209
+ 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>`));
34023
34210
  const { hexInput } = refs(form);
34211
+ // Enter applies the value and closes the popup; removing the focused
34212
+ // input then makes Chrome fire `change` on it, which would apply the
34213
+ // same color a second time and toggle it off again. See #1459
34214
+ let appliedHexValue = null;
34024
34215
  const applyHexInput = () => {
34025
34216
  const raw = hexInput.value.trim();
34217
+ if (raw === appliedHexValue) {
34218
+ return;
34219
+ }
34026
34220
  const isHex = /^#?[0-9a-f]{3}(?:[0-9a-f]{3})?$/i.test(raw);
34027
34221
  const isRgb = /^rgba?\([\d\s.,%]+\)$/i.test(raw);
34028
34222
  if (!isHex && !isRgb) {
@@ -34030,6 +34224,7 @@ const ColorPickerWidget = (editor, callback, coldColor) => {
34030
34224
  }
34031
34225
  const color = normalizeColor(isHex && !raw.startsWith('#') ? '#' + raw : raw);
34032
34226
  if (color && isFunction(callback)) {
34227
+ appliedHexValue = raw;
34033
34228
  callback(color);
34034
34229
  }
34035
34230
  };
@@ -34046,7 +34241,7 @@ const ColorPickerWidget = (editor, callback, coldColor) => {
34046
34241
  applyHexInput();
34047
34242
  });
34048
34243
  if (editor.o.showBrowserColorPicker && hasBrowserColorPicker()) {
34049
- extra.appendChild(editor.c.fromHTML(`<div class="${cn}__native">${iconPalette}<input type="color" value="#ffffff"/></div>`));
34244
+ Dom.append(extra, editor.c.fromHTML(`<div class="${cn}__native">${iconPalette}<input type="color" value="#ffffff"/></div>`));
34050
34245
  editor.e.on(form, 'change', (e) => {
34051
34246
  e.stopPropagation();
34052
34247
  const target = e.target;
@@ -34136,8 +34331,8 @@ const TabsWidget = (jodit, tabs, state) => {
34136
34331
  const nameToTab = {};
34137
34332
  const buttonList = [];
34138
34333
  let firstTab = '';
34139
- box.appendChild(buttons);
34140
- box.appendChild(tabBox);
34334
+ Dom.append(box, buttons);
34335
+ Dom.append(box, tabBox);
34141
34336
  const setActive = (tab) => {
34142
34337
  if (!nameToTab[tab]) {
34143
34338
  return;
@@ -34161,18 +34356,18 @@ const TabsWidget = (jodit, tabs, state) => {
34161
34356
  if (!firstTab) {
34162
34357
  firstTab = name;
34163
34358
  }
34164
- buttons.appendChild(button.container);
34359
+ Dom.append(buttons, button.container);
34165
34360
  buttonList.push(button);
34166
34361
  button.container.classList.add('jodit-tabs__button', 'jodit-tabs__button_columns_' + tabs.length);
34167
34362
  if (!isFunction(content)) {
34168
- tab.appendChild(Component.isInstanceOf(content, UIElement)
34363
+ Dom.append(tab, Component.isInstanceOf(content, UIElement)
34169
34364
  ? content.container
34170
34365
  : content);
34171
34366
  }
34172
34367
  else {
34173
34368
  tab.classList.add('jodit-tab_empty');
34174
34369
  }
34175
- tabBox.appendChild(tab);
34370
+ Dom.append(tabBox, tab);
34176
34371
  button.onAction(() => {
34177
34372
  setActive(name);
34178
34373
  if (isFunction(content) && !Dom.isElement(content)) {
@@ -34295,13 +34490,13 @@ const FileSelectorWidget = (editor, callbacks, elm, close, isImage = true) => {
34295
34490
  !Dom.isComment(elm) &&
34296
34491
  (Dom.isTag(elm, 'img') || $$('img', elm).length)) {
34297
34492
  currentImage = elm.tagName === 'IMG' ? elm : $$('img', elm)[0];
34298
- val(form.container, 'input[name=url]', attr(currentImage, 'src'));
34299
- val(form.container, 'input[name=text]', attr(currentImage, 'alt'));
34493
+ val(form.container, 'url', attr(currentImage, 'src'));
34494
+ val(form.container, 'text', attr(currentImage, 'alt'));
34300
34495
  button.state.text = 'Update';
34301
34496
  }
34302
34497
  if (elm && Dom.isTag(elm, 'a')) {
34303
- val(form.container, 'input[name=url]', attr(elm, 'href'));
34304
- val(form.container, 'input[name=text]', attr(elm, 'title'));
34498
+ val(form.container, 'url', attr(elm, 'href'));
34499
+ val(form.container, 'text', attr(elm, 'title'));
34305
34500
  button.state.text = 'Update';
34306
34501
  }
34307
34502
  form.onSubmit(data => {
@@ -34323,8 +34518,8 @@ const FileSelectorWidget = (editor, callbacks, elm, close, isImage = true) => {
34323
34518
  box.classList.add('jodit-file-selector');
34324
34519
  return box;
34325
34520
  };
34326
- function val(elm, selector, value) {
34327
- const child = elm.querySelector(selector);
34521
+ function val(elm, name, value) {
34522
+ const child = Dom.first(elm, node => Dom.isTag(node, 'input') && attr(node, 'name') === name);
34328
34523
  if (!child) {
34329
34524
  return '';
34330
34525
  }
@@ -34437,7 +34632,7 @@ Config.prototype.controls.brush = {
34437
34632
  editor.execCommand('background', false, value);
34438
34633
  }
34439
34634
  else {
34440
- currentElement.style.backgroundColor = value;
34635
+ css(currentElement, 'backgroundColor', value);
34441
34636
  }
34442
34637
  dataBind(button, 'color', value);
34443
34638
  dataBind(button, 'color-mode', 'background');
@@ -34448,7 +34643,7 @@ Config.prototype.controls.brush = {
34448
34643
  editor.execCommand('forecolor', false, value);
34449
34644
  }
34450
34645
  else {
34451
- currentElement.style.color = value;
34646
+ css(currentElement, 'color', value);
34452
34647
  }
34453
34648
  dataBind(button, 'color', value);
34454
34649
  dataBind(button, 'color-mode', 'color');
@@ -34480,10 +34675,10 @@ Config.prototype.controls.brush = {
34480
34675
  Dom.isElement(current)) {
34481
34676
  switch (mode) {
34482
34677
  case 'color':
34483
- current.style.color = color;
34678
+ css(current, 'color', color);
34484
34679
  break;
34485
34680
  case 'background':
34486
- current.style.backgroundColor = color;
34681
+ css(current, 'backgroundColor', color);
34487
34682
  break;
34488
34683
  }
34489
34684
  }
@@ -34664,7 +34859,7 @@ function hasPreviousBlock(fake, jodit) {
34664
34859
  function insertParagraph(fake, editor, wrapperTag, style) {
34665
34860
  const isBR = wrapperTag.toLowerCase() === 'br', { createInside } = editor, p = createInside.element(wrapperTag), br = createInside.element('br');
34666
34861
  if (!isBR) {
34667
- p.appendChild(br);
34862
+ Dom.append(p, br);
34668
34863
  }
34669
34864
  Dom.after(fake, p);
34670
34865
  Dom.before(isBR ? p : br, fake);
@@ -34721,11 +34916,11 @@ function processEmptyLILeaf(fake, jodit, li) {
34721
34916
  Dom.safeRemove(list);
34722
34917
  }
34723
34918
  const newLi = insertParagraph(fake, jodit, listInsideLeaf ? 'li' : jodit.o.enter);
34724
- if (!rightPart.querySelector('li')) {
34919
+ if (!Dom.first(rightPart, node => Dom.isTag(node, 'li'))) {
34725
34920
  return;
34726
34921
  }
34727
34922
  if (listInsideLeaf) {
34728
- newLi.appendChild(rightPart);
34923
+ Dom.append(newLi, rightPart);
34729
34924
  }
34730
34925
  else {
34731
34926
  Dom.after(newLi, rightPart);
@@ -34795,7 +34990,7 @@ function wrapText(fake, jodit) {
34795
34990
  const currentBox = Dom.wrapInline(needWrap, jodit.o.enter, jodit);
34796
34991
  if (Dom.isEmpty(currentBox)) {
34797
34992
  const br = jodit.createInside.element('br');
34798
- currentBox.appendChild(br);
34993
+ Dom.append(currentBox, br);
34799
34994
  Dom.before(br, fake);
34800
34995
  }
34801
34996
  return currentBox;
@@ -35438,13 +35633,13 @@ function iframe(editor) {
35438
35633
  const link = doc.createElement('link');
35439
35634
  attr(link, 'rel', 'stylesheet');
35440
35635
  attr(link, 'href', href);
35441
- doc.head && doc.head.appendChild(link);
35636
+ doc.head && Dom.append(doc.head, link);
35442
35637
  });
35443
35638
  }
35444
35639
  if (opt.iframeStyle) {
35445
35640
  const style = doc.createElement('style');
35446
35641
  style.innerHTML = opt.iframeStyle;
35447
- doc.head && doc.head.appendChild(style);
35642
+ doc.head && Dom.append(doc.head, style);
35448
35643
  }
35449
35644
  })
35450
35645
  .on('createEditor', () => {
@@ -35452,7 +35647,7 @@ function iframe(editor) {
35452
35647
  return;
35453
35648
  }
35454
35649
  const iframe = editor.c.element('iframe');
35455
- iframe.style.display = 'block';
35650
+ css(iframe, 'display', 'block');
35456
35651
  iframe.src = 'about:blank';
35457
35652
  iframe.className = 'jodit-wysiwyg_iframe';
35458
35653
  attr(iframe, {
@@ -35463,7 +35658,7 @@ function iframe(editor) {
35463
35658
  if (opt.iframeSandbox != null) {
35464
35659
  attr(iframe, 'sandbox', opt.iframeSandbox);
35465
35660
  }
35466
- editor.workplace.appendChild(iframe);
35661
+ Dom.append(editor.workplace, iframe);
35467
35662
  editor.iframe = iframe;
35468
35663
  const result = editor.e.fire('generateDocumentStructure.iframe', null, editor);
35469
35664
  const init = () => {
@@ -35534,7 +35729,7 @@ function iframe(editor) {
35534
35729
  editor.e.on('afterSetMode afterInit afterAddPlace', toggleEditable);
35535
35730
  if (opt.height === 'auto') {
35536
35731
  doc.documentElement &&
35537
- (doc.documentElement.style.overflowY = 'hidden');
35732
+ css(doc.documentElement, 'overflowY', 'hidden');
35538
35733
  const resizeIframe = editor.async.throttle((...args) => {
35539
35734
  editor.async.requestAnimationFrame(() => {
35540
35735
  if (editor.editor &&
@@ -37001,8 +37196,10 @@ class placeholder extends Plugin {
37001
37196
  }
37002
37197
  this.placeholderElm = editor.c.fromHTML(`<span data-ref="placeholder" style="display: none;" class="jodit-placeholder">${editor.i18n(editor.o.placeholder)}</span>`);
37003
37198
  if (editor.o.direction === 'rtl') {
37004
- this.placeholderElm.style.right = '0px';
37005
- this.placeholderElm.style.direction = 'rtl';
37199
+ css(this.placeholderElm, {
37200
+ right: 0,
37201
+ direction: 'rtl'
37202
+ });
37006
37203
  }
37007
37204
  editor.e
37008
37205
  .on('readonly', (isReadOnly) => {
@@ -37026,22 +37223,22 @@ class placeholder extends Plugin {
37026
37223
  editor.editor;
37027
37224
  const style = editor.ew.getComputedStyle(wrapper);
37028
37225
  const styleEditor = editor.ew.getComputedStyle(editor.editor);
37029
- editor.workplace.appendChild(this.placeholderElm);
37226
+ Dom.append(editor.workplace, this.placeholderElm);
37030
37227
  const { firstChild } = editor.editor;
37031
37228
  if (Dom.isElement(firstChild) && !isMarker(firstChild)) {
37032
37229
  const style2 = editor.ew.getComputedStyle(firstChild);
37033
37230
  marginTop = parseInt(style2.getPropertyValue('margin-top'), 10);
37034
37231
  marginLeft = parseInt(style2.getPropertyValue('margin-left'), 10);
37035
- this.placeholderElm.style.fontSize =
37036
- parseInt(style2.getPropertyValue('font-size'), 10) + 'px';
37037
- this.placeholderElm.style.lineHeight =
37038
- style2.getPropertyValue('line-height');
37232
+ css(this.placeholderElm, {
37233
+ fontSize: parseInt(style2.getPropertyValue('font-size'), 10),
37234
+ lineHeight: style2.getPropertyValue('line-height')
37235
+ });
37039
37236
  }
37040
37237
  else {
37041
- this.placeholderElm.style.fontSize =
37042
- parseInt(style.getPropertyValue('font-size'), 10) + 'px';
37043
- this.placeholderElm.style.lineHeight =
37044
- style.getPropertyValue('line-height');
37238
+ css(this.placeholderElm, {
37239
+ fontSize: parseInt(style.getPropertyValue('font-size'), 10),
37240
+ lineHeight: style.getPropertyValue('line-height')
37241
+ });
37045
37242
  }
37046
37243
  css(this.placeholderElm, {
37047
37244
  display: 'block',
@@ -37523,7 +37720,15 @@ Config.prototype.controls.table = {
37523
37720
  '<label class="jodit-form__center">' +
37524
37721
  '<span>1</span> &times; <span>1</span>' +
37525
37722
  '</label>' +
37526
- '</form>'), rows = form.querySelectorAll('span')[0], cols = form.querySelectorAll('span')[1], blocksContainer = form.querySelector('.jodit-form__container'), options = form.querySelector('.jodit-form__options'), cells = [];
37723
+ '</form>'), spans = (() => {
37724
+ const list = [];
37725
+ Dom.each(form, node => {
37726
+ Dom.isTag(node, 'span') && list.push(node);
37727
+ });
37728
+ return list;
37729
+ })(), [rows, cols] = spans, blocksContainer = Dom.first(form, node => Dom.isHTMLElement(node) &&
37730
+ node.classList.contains('jodit-form__container')), options = Dom.first(form, node => Dom.isHTMLElement(node) &&
37731
+ node.classList.contains('jodit-form__options')), cells = [];
37527
37732
  const cnt = default_rows_count * default_cols_count;
37528
37733
  attr(blocksContainer, {
37529
37734
  role: 'grid',
@@ -37561,7 +37766,7 @@ Config.prototype.controls.table = {
37561
37766
  const k = parseInt(attr(cell, '-index') || '0', 10);
37562
37767
  const rows_count = Math.ceil((k + 1) / default_cols_count), cols_count = (k % default_cols_count) + 1;
37563
37768
  const crt = editor.createInside, tbody = crt.element('tbody'), table = crt.element('table');
37564
- table.appendChild(tbody);
37769
+ Dom.append(table, tbody);
37565
37770
  let first_td = null, tr, td;
37566
37771
  for (let i = 1; i <= rows_count; i += 1) {
37567
37772
  tr = crt.element('tr');
@@ -37571,13 +37776,13 @@ Config.prototype.controls.table = {
37571
37776
  first_td = td;
37572
37777
  }
37573
37778
  css(td, 'width', (100 / cols_count).toFixed(4) + '%');
37574
- td.appendChild(crt.element('br'));
37575
- tr.appendChild(crt.text('\n'));
37576
- tr.appendChild(crt.text('\t'));
37577
- tr.appendChild(td);
37779
+ Dom.append(td, crt.element('br'));
37780
+ Dom.append(tr, crt.text('\n'));
37781
+ Dom.append(tr, crt.text('\t'));
37782
+ Dom.append(tr, td);
37578
37783
  }
37579
- tbody.appendChild(crt.text('\n'));
37580
- tbody.appendChild(tr);
37784
+ Dom.append(tbody, crt.text('\n'));
37785
+ Dom.append(tbody, tr);
37581
37786
  }
37582
37787
  $$('input[type=checkbox]:checked', options).forEach((input) => {
37583
37788
  input.value
@@ -37693,9 +37898,9 @@ Config.prototype.controls.table = {
37693
37898
  const row = editor.c.div();
37694
37899
  attr(row, 'role', 'row');
37695
37900
  for (let j = 0; j < default_cols_count; j += 1) {
37696
- row.appendChild(cells[i * default_cols_count + j]);
37901
+ Dom.append(row, cells[i * default_cols_count + j]);
37697
37902
  }
37698
- blocksContainer.appendChild(row);
37903
+ Dom.append(blocksContainer, row);
37699
37904
  }
37700
37905
  if (cells[0]) {
37701
37906
  cells[0].className = 'hovered';
@@ -37808,7 +38013,7 @@ class wrapNodes extends Plugin {
37808
38013
  Dom.before(child, box);
37809
38014
  while (child && this.isSuitable(child)) {
37810
38015
  const next = child.nextSibling;
37811
- box.appendChild(child);
38016
+ Dom.append(box, child);
37812
38017
  child = next;
37813
38018
  }
37814
38019
  box.normalize();
@@ -37858,7 +38063,7 @@ function checkAloneListLeaf(child, jodit) {
37858
38063
  !Dom.isList(next.parentElement)) {
37859
38064
  const nextChild = Dom.findNotEmptySibling(next, false);
37860
38065
  if (Dom.isTag(result, 'ul')) {
37861
- result.appendChild(next);
38066
+ Dom.append(result, next);
37862
38067
  }
37863
38068
  else {
37864
38069
  result = Dom.wrap(next, 'ul', jodit.createInside);
@@ -38231,7 +38436,7 @@ class select extends Plugin {
38231
38436
  // The text must be the direct content of a list item that has a nested
38232
38437
  // list (the last level has no nested list and behaves correctly).
38233
38438
  if (!Dom.isTag(li, 'li') ||
38234
- !(li.querySelector('ul') || li.querySelector('ol'))) {
38439
+ !Dom.first(li, node => Dom.isTag(node, LIST_TAGS))) {
38235
38440
  return;
38236
38441
  }
38237
38442
  const measure = this.j.ed.createRange();
@@ -38404,7 +38609,7 @@ class resizer extends Plugin {
38404
38609
  }
38405
38610
  if (this.element && this.rect) {
38406
38611
  const workplacePosition = this.getWorkplacePosition();
38407
- 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;
38612
+ 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;
38408
38613
  const newTop = pos.top - workplacePosition.top, newLeft = pos.left - workplacePosition.left;
38409
38614
  if (top !== newTop ||
38410
38615
  left !== newLeft ||
@@ -38427,7 +38632,7 @@ class resizer extends Plugin {
38427
38632
  }
38428
38633
  };
38429
38634
  this.hideSizeViewer = () => {
38430
- this.sizeViewer.style.opacity = '0';
38635
+ css(this.sizeViewer, 'opacity', '0');
38431
38636
  };
38432
38637
  }
38433
38638
  /** @override */
@@ -38472,7 +38677,7 @@ class resizer extends Plugin {
38472
38677
  return;
38473
38678
  }
38474
38679
  const width = attr(image, 'width');
38475
- if (width && !css(image, 'width', true)) {
38680
+ if (width && !cssInline(image, 'width')) {
38476
38681
  css(image, 'width', width);
38477
38682
  attr(image, 'width', null);
38478
38683
  }
@@ -38631,7 +38836,7 @@ class resizer extends Plugin {
38631
38836
  if (changeAttrs) {
38632
38837
  attr(element, key, value);
38633
38838
  }
38634
- if (!changeAttrs || element.style[key]) {
38839
+ if (!changeAttrs || cssInline(element, key)) {
38635
38840
  css(element, key, value);
38636
38841
  }
38637
38842
  }
@@ -38686,16 +38891,16 @@ class resizer extends Plugin {
38686
38891
  });
38687
38892
  attr(wrapper, 'style', attr(element, 'style'));
38688
38893
  css(wrapper, {
38689
- display: element.style.display === 'inline-block'
38894
+ display: cssInline(element, 'display') === 'inline-block'
38690
38895
  ? 'inline-block'
38691
38896
  : 'block',
38692
38897
  width: element.offsetWidth,
38693
38898
  height: element.offsetHeight
38694
38899
  });
38695
38900
  if (element.parentNode) {
38696
- element.parentNode.insertBefore(wrapper, element);
38901
+ Dom.before(element, wrapper);
38697
38902
  }
38698
- wrapper.appendChild(element);
38903
+ Dom.append(wrapper, element);
38699
38904
  this.j.e.on(wrapper, 'click', () => {
38700
38905
  attr(wrapper, 'data-jodit-wrapper_active', true);
38701
38906
  });
@@ -38723,7 +38928,7 @@ class resizer extends Plugin {
38723
38928
  this.hideSizeViewer();
38724
38929
  return;
38725
38930
  }
38726
- this.sizeViewer.style.opacity = '1';
38931
+ css(this.sizeViewer, 'opacity', '1');
38727
38932
  this.sizeViewer.textContent = `${w} x ${h}`;
38728
38933
  this.j.async.setTimeout(this.hideSizeViewer, {
38729
38934
  timeout: this.j.o.resizer.hideSizeTimeout,
@@ -38740,10 +38945,10 @@ class resizer extends Plugin {
38740
38945
  this.isShown = true;
38741
38946
  if (!this.rect.parentNode) {
38742
38947
  markOwner(this.j, this.rect);
38743
- this.j.workplace.appendChild(this.rect);
38948
+ Dom.append(this.j.workplace, this.rect);
38744
38949
  }
38745
38950
  if (this.j.isFullSize) {
38746
- this.rect.style.zIndex = css(this.j.container, 'zIndex').toString();
38951
+ css(this.rect, 'zIndex', css(this.j.container, 'zIndex').toString());
38747
38952
  }
38748
38953
  this.updateSize();
38749
38954
  }
@@ -38902,7 +39107,7 @@ class selectCells extends Plugin {
38902
39107
  }
38903
39108
  else {
38904
39109
  if (!cell.firstChild) {
38905
- cell.appendChild(this.j.createInside.element('br'));
39110
+ Dom.append(cell, this.j.createInside.element('br'));
38906
39111
  }
38907
39112
  this.__tableModule.addSelection(cell);
38908
39113
  }
@@ -38924,7 +39129,7 @@ class selectCells extends Plugin {
38924
39129
  return;
38925
39130
  }
38926
39131
  if (!cell.firstChild) {
38927
- cell.appendChild(this.j.createInside.element('br'));
39132
+ Dom.append(cell, this.j.createInside.element('br'));
38928
39133
  }
38929
39134
  this.__isSelectionMode = true;
38930
39135
  this.__selectedCell = cell;
@@ -38991,10 +39196,9 @@ class selectCells extends Plugin {
38991
39196
  // Hack for FireFox for force redraw selection
38992
39197
  (() => {
38993
39198
  const n = this.j.createInside.fromHTML('<div style="color:rgba(0,0,0,0.01);width:0;height:0">&nbsp;</div>');
38994
- cell.appendChild(n);
39199
+ Dom.append(cell, n);
38995
39200
  this.j.async.setTimeout(() => {
38996
- var _a;
38997
- (_a = n.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(n);
39201
+ Dom.safeRemove(n);
38998
39202
  }, this.j.defaultTimeout / 5);
38999
39203
  })();
39000
39204
  }
@@ -39092,7 +39296,7 @@ class selectCells extends Plugin {
39092
39296
  const cells = this.__tableModule.getAllSelectedCells();
39093
39297
  cells.forEach(td => {
39094
39298
  Dom.detach(td);
39095
- td.appendChild(this.j.createInside.element('br'));
39299
+ Dom.append(td, this.j.createInside.element('br'));
39096
39300
  });
39097
39301
  this.unselectCells();
39098
39302
  this.j.s.setCursorIn(cells[0]);
@@ -39267,7 +39471,7 @@ class resizeCells extends Plugin {
39267
39471
  }
39268
39472
  showResizeHandle() {
39269
39473
  this.j.async.clearTimeout(this.hideTimeout);
39270
- this.j.workplace.appendChild(this.resizeHandler);
39474
+ Dom.append(this.j.workplace, this.resizeHandler);
39271
39475
  }
39272
39476
  hideResizeHandle() {
39273
39477
  this.hideTimeout = this.j.async.setTimeout(() => {
@@ -39334,8 +39538,7 @@ class resizeCells extends Plugin {
39334
39538
  }
39335
39539
  this.resizeDelta =
39336
39540
  x - this.startX + (!this.j.o.iframe ? 0 : workplacePosition.left);
39337
- this.resizeHandler.style.left =
39338
- x - (this.j.o.iframe ? 0 : workplacePosition.left) + 'px';
39541
+ css(this.resizeHandler, 'left', x - (this.j.o.iframe ? 0 : workplacePosition.left) + 'px');
39339
39542
  const sel = this.j.s.sel;
39340
39543
  sel && sel.removeAllRanges();
39341
39544
  }
@@ -39387,16 +39590,15 @@ class resizeCells extends Plugin {
39387
39590
  const needChangeWidth = this.isRTL ? !rightSide : rightSide;
39388
39591
  // right side
39389
39592
  if (needChangeWidth) {
39390
- this.workTable.style.width =
39391
- ((width + delta) / parentWidth) * 100 + '%';
39593
+ css(this.workTable, 'width', ((width + delta) / parentWidth) * 100 + '%');
39392
39594
  }
39393
39595
  else {
39394
39596
  const side = this.isRTL ? 'marginRight' : 'marginLeft';
39395
39597
  const margin = parseInt(this.j.ew.getComputedStyle(this.workTable)[side] || '0', 10);
39396
- this.workTable.style.width =
39397
- ((width - delta) / parentWidth) * 100 + '%';
39398
- this.workTable.style[side] =
39399
- ((margin + delta) / parentWidth) * 100 + '%';
39598
+ css(this.workTable, {
39599
+ width: ((width - delta) / parentWidth) * 100 + '%',
39600
+ [side]: ((margin + delta) / parentWidth) * 100 + '%'
39601
+ });
39400
39602
  }
39401
39603
  }
39402
39604
  /**
@@ -39420,11 +39622,10 @@ class resizeCells extends Plugin {
39420
39622
  return;
39421
39623
  }
39422
39624
  const workplacePosition = offset(this.j.workplace, this.j, this.j.od, true), parentBox = offset(table, this.j, this.j.ed);
39423
- this.resizeHandler.style.left =
39424
- (offsetX <= NEARBY ? box.left : box.left + box.width) -
39425
- workplacePosition.left +
39426
- delta +
39427
- 'px';
39625
+ css(this.resizeHandler, 'left', (offsetX <= NEARBY ? box.left : box.left + box.width) -
39626
+ workplacePosition.left +
39627
+ delta +
39628
+ 'px');
39428
39629
  Object.assign(this.resizeHandler.style, {
39429
39630
  height: parentBox.height + 'px',
39430
39631
  top: parentBox.top - workplacePosition.top + 'px'
@@ -39457,7 +39658,7 @@ class resizeCells extends Plugin {
39457
39658
  const parent = Dom.up(this.workCell, (elm) => Dom.isTag(elm, 'table'), editor.editor);
39458
39659
  if (parent) {
39459
39660
  const parentBox = parent.getBoundingClientRect();
39460
- this.resizeHandler.style.top = parentBox.top + 'px';
39661
+ css(this.resizeHandler, 'top', parentBox.top + 'px');
39461
39662
  }
39462
39663
  })
39463
39664
  .on('beforeSetMode.resize-cells', () => {
@@ -39554,7 +39755,7 @@ function tableKeyboardNavigation(editor) {
39554
39755
  if (!next) {
39555
39756
  tableModule.appendRow(table, !isPrev
39556
39757
  ? false
39557
- : table.querySelector('tr'), !isPrev);
39758
+ : Dom.first(table, node => Dom.isTag(node, 'tr')), !isPrev);
39558
39759
  next = getNextCell();
39559
39760
  }
39560
39761
  break;
@@ -39583,7 +39784,7 @@ function tableKeyboardNavigation(editor) {
39583
39784
  editor.e.fire('hidePopup hideResizer');
39584
39785
  if (!next.firstChild) {
39585
39786
  const first = editor.createInside.element('br');
39586
- next.appendChild(first);
39787
+ Dom.append(next, first);
39587
39788
  editor.s.setCursorBefore(first);
39588
39789
  }
39589
39790
  else {
@@ -39871,7 +40072,10 @@ function allowAttributes(jodit, nodeElm, hadEffect, allow) {
39871
40072
  hadEffect = true;
39872
40073
  }
39873
40074
  removeAttrs.forEach(attr => {
39874
- nodeElm.removeAttribute(attr);
40075
+ // `attrRaw` on purpose: the sanitizer must remove exactly the
40076
+ // attribute name from the live list, without the `attr()`
40077
+ // helper name normalization
40078
+ attrRaw(nodeElm, attr, null);
39875
40079
  });
39876
40080
  }
39877
40081
  }
@@ -39935,7 +40139,7 @@ function fillEmptyParagraph(jodit, nodeElm, hadEffect) {
39935
40139
  Dom.isEmpty(nodeElm, INSEPARABLE_TAGS) &&
39936
40140
  !Dom.isTag(nodeElm, TABLE_CONTAINER_TAGS)) {
39937
40141
  const br = jodit.createInside.element('br');
39938
- nodeElm.appendChild(br);
40142
+ Dom.append(nodeElm, br);
39939
40143
  return true;
39940
40144
  }
39941
40145
  return hadEffect;
@@ -39951,7 +40155,13 @@ function fillEmptyParagraph(jodit, nodeElm, hadEffect) {
39951
40155
  */
39952
40156
  function removeEmptyTextNode(jodit, node, hadEffect, arg, argi, currentNode) {
39953
40157
  if (Dom.isText(node) && !node.nodeValue) {
39954
- if (node === currentNode && jodit.s.isCollapsed()) {
40158
+ // Restore the caret only while the editor owns focus. The walker runs
40159
+ // asynchronously, so the user may have already tabbed away — moving the
40160
+ // selection here would call `focus()` and steal focus back from the
40161
+ // element the user navigated to (e.g. Shift+Tab accessibility flow).
40162
+ if (node === currentNode &&
40163
+ jodit.s.isFocused() &&
40164
+ jodit.s.isCollapsed()) {
39955
40165
  jodit.s.setCursorAfter(node);
39956
40166
  }
39957
40167
  Dom.safeRemove(node);
@@ -39980,7 +40190,10 @@ function removeInvTextNodes(jodit, node, hadEffect, arg, argi, currentNode) {
39980
40190
  return hadEffect;
39981
40191
  }
39982
40192
  node.nodeValue = node.nodeValue.replace(INVISIBLE_SPACE_REG_EXP(), '');
39983
- if (node === currentNode && jodit.s.isCollapsed()) {
40193
+ // Same guard as in `removeEmptyTextNode`: the walker is asynchronous, so
40194
+ // never move the selection (it re-focuses the editor) once the user has
40195
+ // moved focus elsewhere.
40196
+ if (node === currentNode && jodit.s.isFocused() && jodit.s.isCollapsed()) {
39984
40197
  jodit.s.setCursorAfter(node);
39985
40198
  }
39986
40199
  if (!node.nodeValue) {
@@ -40593,7 +40806,7 @@ Config.prototype.controls.print = {
40593
40806
  height: 0,
40594
40807
  border: 0
40595
40808
  });
40596
- getContainer(editor, Config).appendChild(iframe);
40809
+ Dom.append(getContainer(editor, Config), iframe);
40597
40810
  const afterFinishPrint = () => {
40598
40811
  editor.e.off(editor.ow, 'mousemove', afterFinishPrint);
40599
40812
  Dom.safeRemove(iframe);
@@ -40622,7 +40835,7 @@ Config.prototype.controls.print = {
40622
40835
  -webkit-print-color-adjust: exact;
40623
40836
  }
40624
40837
  }`;
40625
- myWindow.document.head.appendChild(style);
40838
+ Dom.append(myWindow.document.head, style);
40626
40839
  myWindow.focus();
40627
40840
  myWindow.print();
40628
40841
  }
@@ -40796,7 +41009,7 @@ class AceEditor extends SourceEditor {
40796
41009
  return;
40797
41010
  }
40798
41011
  const fakeMirror = this.j.c.div('jodit-source__mirror-fake');
40799
- this.container.appendChild(fakeMirror);
41012
+ Dom.append(this.container, fakeMirror);
40800
41013
  const ace = editor.ow.ace;
40801
41014
  this.instance = ace.edit(fakeMirror);
40802
41015
  if (editor.o.direction === 'rtl') {
@@ -40953,8 +41166,8 @@ class TextAreaEditor extends SourceEditor {
40953
41166
  constructor() {
40954
41167
  super(...arguments);
40955
41168
  this.autosize = this.j.async.debounce(() => {
40956
- this.instance.style.height = 'auto';
40957
- this.instance.style.height = this.instance.scrollHeight + 'px';
41169
+ css(this.instance, 'height', 'auto');
41170
+ css(this.instance, 'height', this.instance.scrollHeight);
40958
41171
  }, this.j.defaultTimeout, true);
40959
41172
  }
40960
41173
  init(editor) {
@@ -40962,7 +41175,7 @@ class TextAreaEditor extends SourceEditor {
40962
41175
  class: 'jodit-source__mirror',
40963
41176
  dir: editor.o.direction === 'rtl' ? 'rtl' : undefined
40964
41177
  });
40965
- this.container.appendChild(this.instance);
41178
+ Dom.append(this.container, this.instance);
40966
41179
  editor.e
40967
41180
  .on(this.instance, 'mousedown keydown touchstart input', editor.async.debounce(this.toWYSIWYG, editor.defaultTimeout))
40968
41181
  .on('setMinHeight.source', (minHeightD) => {
@@ -41290,9 +41503,9 @@ class source extends Plugin {
41290
41503
  /** @override */
41291
41504
  afterInit(editor) {
41292
41505
  this.mirrorContainer = editor.c.div('jodit-source');
41293
- editor.workplace.appendChild(this.mirrorContainer);
41506
+ Dom.append(editor.workplace, this.mirrorContainer);
41294
41507
  editor.e.on('afterAddPlace changePlace afterInit', () => {
41295
- editor.workplace.appendChild(this.mirrorContainer);
41508
+ Dom.append(editor.workplace, this.mirrorContainer);
41296
41509
  });
41297
41510
  this.sourceEditor = createSourceEditor('area', editor, this.mirrorContainer, this.toWYSIWYG, this.fromWYSIWYG);
41298
41511
  editor.e.on(editor.ow, 'keydown', (e) => {