tinymce-rails 8.5.1 → 8.6.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.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * TinyMCE version 8.5.1 (2026-05-19)
2
+ * TinyMCE version 8.6.0 (2026-06-03)
3
3
  */
4
4
 
5
5
  (function () {
@@ -18492,24 +18492,65 @@
18492
18492
  }
18493
18493
  };
18494
18494
 
18495
- /*! @license DOMPurify 3.3.2 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.3.2/LICENSE */
18496
-
18497
- const {
18498
- entries,
18499
- setPrototypeOf,
18500
- isFrozen,
18501
- getPrototypeOf,
18502
- getOwnPropertyDescriptor
18503
- } = Object;
18504
- let {
18505
- freeze,
18506
- seal,
18507
- create: create$7
18508
- } = Object; // eslint-disable-line import/no-mutable-exports
18509
- let {
18510
- apply,
18511
- construct
18512
- } = typeof Reflect !== 'undefined' && Reflect;
18495
+ /*! @license DOMPurify 3.4.5 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.5/LICENSE */
18496
+
18497
+ function _arrayLikeToArray(r, a) {
18498
+ (null == a || a > r.length) && (a = r.length);
18499
+ for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
18500
+ return n;
18501
+ }
18502
+ function _arrayWithHoles(r) {
18503
+ if (Array.isArray(r)) return r;
18504
+ }
18505
+ function _iterableToArrayLimit(r, l) {
18506
+ var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
18507
+ if (null != t) {
18508
+ var e,
18509
+ n,
18510
+ i,
18511
+ u,
18512
+ a = [],
18513
+ f = true,
18514
+ o = false;
18515
+ try {
18516
+ if (i = (t = t.call(r)).next, 0 === l) ; else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
18517
+ } catch (r) {
18518
+ o = true, n = r;
18519
+ } finally {
18520
+ try {
18521
+ if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;
18522
+ } finally {
18523
+ if (o) throw n;
18524
+ }
18525
+ }
18526
+ return a;
18527
+ }
18528
+ }
18529
+ function _nonIterableRest() {
18530
+ throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
18531
+ }
18532
+ function _slicedToArray(r, e) {
18533
+ return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();
18534
+ }
18535
+ function _unsupportedIterableToArray(r, a) {
18536
+ if (r) {
18537
+ if ("string" == typeof r) return _arrayLikeToArray(r, a);
18538
+ var t = {}.toString.call(r).slice(8, -1);
18539
+ return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
18540
+ }
18541
+ }
18542
+
18543
+ const entries = Object.entries,
18544
+ setPrototypeOf = Object.setPrototypeOf,
18545
+ isFrozen = Object.isFrozen,
18546
+ getPrototypeOf = Object.getPrototypeOf,
18547
+ getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
18548
+ let freeze = Object.freeze,
18549
+ seal = Object.seal,
18550
+ create$7 = Object.create; // eslint-disable-line import/no-mutable-exports
18551
+ let _ref = typeof Reflect !== 'undefined' && Reflect,
18552
+ apply = _ref.apply,
18553
+ construct = _ref.construct;
18513
18554
  if (!freeze) {
18514
18555
  freeze = function freeze(x) {
18515
18556
  return x;
@@ -18541,13 +18582,19 @@
18541
18582
  const arrayPop = unapply(Array.prototype.pop);
18542
18583
  const arrayPush = unapply(Array.prototype.push);
18543
18584
  const arraySplice = unapply(Array.prototype.splice);
18585
+ const arrayIsArray = Array.isArray;
18544
18586
  const stringToLowerCase = unapply(String.prototype.toLowerCase);
18545
18587
  const stringToString = unapply(String.prototype.toString);
18546
18588
  const stringMatch = unapply(String.prototype.match);
18547
18589
  const stringReplace = unapply(String.prototype.replace);
18548
18590
  const stringIndexOf = unapply(String.prototype.indexOf);
18549
18591
  const stringTrim = unapply(String.prototype.trim);
18592
+ const numberToString = unapply(Number.prototype.toString);
18593
+ const booleanToString = unapply(Boolean.prototype.toString);
18594
+ const bigintToString = typeof BigInt === 'undefined' ? null : unapply(BigInt.prototype.toString);
18595
+ const symbolToString = typeof Symbol === 'undefined' ? null : unapply(Symbol.prototype.toString);
18550
18596
  const objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);
18597
+ const objectToString = unapply(Object.prototype.toString);
18551
18598
  const regExpTest = unapply(RegExp.prototype.test);
18552
18599
  const typeErrorCreate = unconstruct(TypeError);
18553
18600
  /**
@@ -18597,6 +18644,9 @@
18597
18644
  // Prevent prototype setters from intercepting set as a this value.
18598
18645
  setPrototypeOf(set, null);
18599
18646
  }
18647
+ if (!arrayIsArray(array)) {
18648
+ return set;
18649
+ }
18600
18650
  let l = array.length;
18601
18651
  while (l--) {
18602
18652
  let element = array[l];
@@ -18637,10 +18687,13 @@
18637
18687
  */
18638
18688
  function clone(object) {
18639
18689
  const newObject = create$7(null);
18640
- for (const [property, value] of entries(object)) {
18690
+ for (const _ref2 of entries(object)) {
18691
+ var _ref3 = _slicedToArray(_ref2, 2);
18692
+ const property = _ref3[0];
18693
+ const value = _ref3[1];
18641
18694
  const isPropertyExist = objectHasOwnProperty(object, property);
18642
18695
  if (isPropertyExist) {
18643
- if (Array.isArray(value)) {
18696
+ if (arrayIsArray(value)) {
18644
18697
  newObject[property] = cleanArray(value);
18645
18698
  } else if (value && typeof value === 'object' && value.constructor === Object) {
18646
18699
  newObject[property] = clone(value);
@@ -18651,6 +18704,58 @@
18651
18704
  }
18652
18705
  return newObject;
18653
18706
  }
18707
+ /**
18708
+ * Convert non-node values into strings without depending on direct property access.
18709
+ *
18710
+ * @param value - The value to stringify.
18711
+ * @returns A string representation of the provided value.
18712
+ */
18713
+ function stringifyValue(value) {
18714
+ switch (typeof value) {
18715
+ case 'string':
18716
+ {
18717
+ return value;
18718
+ }
18719
+ case 'number':
18720
+ {
18721
+ return numberToString(value);
18722
+ }
18723
+ case 'boolean':
18724
+ {
18725
+ return booleanToString(value);
18726
+ }
18727
+ case 'bigint':
18728
+ {
18729
+ return bigintToString ? bigintToString(value) : '0';
18730
+ }
18731
+ case 'symbol':
18732
+ {
18733
+ return symbolToString ? symbolToString(value) : 'Symbol()';
18734
+ }
18735
+ case 'undefined':
18736
+ {
18737
+ return objectToString(value);
18738
+ }
18739
+ case 'function':
18740
+ case 'object':
18741
+ {
18742
+ if (value === null) {
18743
+ return objectToString(value);
18744
+ }
18745
+ const valueAsRecord = value;
18746
+ const valueToString = lookupGetter(valueAsRecord, 'toString');
18747
+ if (typeof valueToString === 'function') {
18748
+ const stringified = valueToString(valueAsRecord);
18749
+ return typeof stringified === 'string' ? stringified : objectToString(stringified);
18750
+ }
18751
+ return objectToString(value);
18752
+ }
18753
+ default:
18754
+ {
18755
+ return objectToString(value);
18756
+ }
18757
+ }
18758
+ }
18654
18759
  /**
18655
18760
  * This method automatically checks if the prop is function or getter and behaves accordingly.
18656
18761
  *
@@ -18676,6 +18781,14 @@
18676
18781
  }
18677
18782
  return fallbackValue;
18678
18783
  }
18784
+ function isRegex(value) {
18785
+ try {
18786
+ regExpTest(value, '');
18787
+ return true;
18788
+ } catch (_unused) {
18789
+ return false;
18790
+ }
18791
+ }
18679
18792
 
18680
18793
  const html$1 = freeze(['a', 'abbr', 'acronym', 'address', 'area', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'big', 'blink', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'content', 'data', 'datalist', 'dd', 'decorator', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'element', 'em', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'main', 'map', 'mark', 'marquee', 'menu', 'menuitem', 'meter', 'nav', 'nobr', 'ol', 'optgroup', 'option', 'output', 'p', 'picture', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'search', 'section', 'select', 'shadow', 'slot', 'small', 'source', 'spacer', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr']);
18681
18794
  const svg$1 = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'enterkeyhint', 'exportparts', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'inputmode', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'part', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'view', 'vkern']);
@@ -18691,15 +18804,14 @@
18691
18804
  const mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);
18692
18805
  const text = freeze(['#text']);
18693
18806
 
18694
- const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'exportparts', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inert', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'part', 'pattern', 'placeholder', 'playsinline', 'popover', 'popovertarget', 'popovertargetaction', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'slot', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'wrap', 'xmlns', 'slot']);
18807
+ const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'command', 'commandfor', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'exportparts', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inert', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'part', 'pattern', 'placeholder', 'playsinline', 'popover', 'popovertarget', 'popovertargetaction', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'slot', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'wrap', 'xmlns']);
18695
18808
  const svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'amplitude', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'exponent', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'intercept', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'mask-type', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'slope', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'tablevalues', 'targetx', 'targety', 'transform', 'transform-origin', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);
18696
- const mathMl = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnsalign', 'columnlines', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lspace', 'lquote', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns']);
18809
+ const mathMl = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnalign', 'columnlines', 'columnspacing', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lquote', 'lspace', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns']);
18697
18810
  const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
18698
18811
 
18699
- // eslint-disable-next-line unicorn/better-regex
18700
- const MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode
18701
- const ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm);
18702
- const TMPLIT_EXPR = seal(/\$\{[\w\W]*/gm); // eslint-disable-line unicorn/better-regex
18812
+ const MUSTACHE_EXPR = seal(/{{[\w\W]*|^[\w\W]*}}/g);
18813
+ const ERB_EXPR = seal(/<%[\w\W]*|^[\w\W]*%>/g);
18814
+ const TMPLIT_EXPR = seal(/\${[\w\W]*/g);
18703
18815
  const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]+$/); // eslint-disable-line no-useless-escape
18704
18816
  const ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
18705
18817
  const IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape
@@ -18710,38 +18822,15 @@
18710
18822
  const DOCTYPE_NAME = seal(/^html$/i);
18711
18823
  const CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i);
18712
18824
 
18713
- var EXPRESSIONS = /*#__PURE__*/Object.freeze({
18714
- __proto__: null,
18715
- ARIA_ATTR: ARIA_ATTR,
18716
- ATTR_WHITESPACE: ATTR_WHITESPACE,
18717
- CUSTOM_ELEMENT: CUSTOM_ELEMENT,
18718
- DATA_ATTR: DATA_ATTR,
18719
- DOCTYPE_NAME: DOCTYPE_NAME,
18720
- ERB_EXPR: ERB_EXPR,
18721
- IS_ALLOWED_URI: IS_ALLOWED_URI,
18722
- IS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA,
18723
- MUSTACHE_EXPR: MUSTACHE_EXPR,
18724
- TMPLIT_EXPR: TMPLIT_EXPR
18725
- });
18726
-
18727
18825
  /* eslint-disable @typescript-eslint/indent */
18728
18826
  // https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
18729
18827
  const NODE_TYPE = {
18730
18828
  element: 1,
18731
- attribute: 2,
18732
18829
  text: 3,
18733
- cdataSection: 4,
18734
- entityReference: 5,
18735
- // Deprecated
18736
- entityNode: 6,
18737
18830
  // Deprecated
18738
18831
  progressingInstruction: 7,
18739
18832
  comment: 8,
18740
- document: 9,
18741
- documentType: 10,
18742
- documentFragment: 11,
18743
- notation: 12 // Deprecated
18744
- };
18833
+ document: 9};
18745
18834
  const getGlobal = function getGlobal() {
18746
18835
  return typeof window === 'undefined' ? null : window;
18747
18836
  };
@@ -18799,7 +18888,7 @@
18799
18888
  function createDOMPurify() {
18800
18889
  let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
18801
18890
  const DOMPurify = root => createDOMPurify(root);
18802
- DOMPurify.version = '3.3.2';
18891
+ DOMPurify.version = '3.4.5';
18803
18892
  DOMPurify.removed = [];
18804
18893
  if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) {
18805
18894
  // Not running in a browser, provide a factory function
@@ -18807,28 +18896,26 @@
18807
18896
  DOMPurify.isSupported = false;
18808
18897
  return DOMPurify;
18809
18898
  }
18810
- let {
18811
- document
18812
- } = window;
18899
+ let document = window.document;
18813
18900
  const originalDocument = document;
18814
18901
  const currentScript = originalDocument.currentScript;
18815
- const {
18816
- DocumentFragment,
18817
- HTMLTemplateElement,
18818
- Node,
18819
- Element,
18820
- NodeFilter,
18821
- NamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap,
18822
- HTMLFormElement,
18823
- DOMParser,
18824
- trustedTypes
18825
- } = window;
18902
+ const DocumentFragment = window.DocumentFragment,
18903
+ HTMLTemplateElement = window.HTMLTemplateElement,
18904
+ Node = window.Node,
18905
+ Element = window.Element,
18906
+ NodeFilter = window.NodeFilter,
18907
+ _window$NamedNodeMap = window.NamedNodeMap,
18908
+ NamedNodeMap = _window$NamedNodeMap === void 0 ? window.NamedNodeMap || window.MozNamedAttrMap : _window$NamedNodeMap,
18909
+ HTMLFormElement = window.HTMLFormElement,
18910
+ DOMParser = window.DOMParser,
18911
+ trustedTypes = window.trustedTypes;
18826
18912
  const ElementPrototype = Element.prototype;
18827
18913
  const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');
18828
18914
  const remove = lookupGetter(ElementPrototype, 'remove');
18829
18915
  const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');
18830
18916
  const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');
18831
18917
  const getParentNode = lookupGetter(ElementPrototype, 'parentNode');
18918
+ const getNodeType = Node && Node.prototype ? lookupGetter(Node.prototype, 'nodeType') : null;
18832
18919
  // As per issue #47, the web-components registry is inherited by a
18833
18920
  // new document created via createHTMLDocument. As per the spec
18834
18921
  // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)
@@ -18843,33 +18930,26 @@
18843
18930
  }
18844
18931
  let trustedTypesPolicy;
18845
18932
  let emptyHTML = '';
18846
- const {
18847
- implementation,
18848
- createNodeIterator,
18849
- createDocumentFragment,
18850
- getElementsByTagName
18851
- } = document;
18852
- const {
18853
- importNode
18854
- } = originalDocument;
18933
+ const _document = document,
18934
+ implementation = _document.implementation,
18935
+ createNodeIterator = _document.createNodeIterator,
18936
+ createDocumentFragment = _document.createDocumentFragment,
18937
+ getElementsByTagName = _document.getElementsByTagName;
18938
+ const importNode = originalDocument.importNode;
18855
18939
  let hooks = _createHooksMap();
18856
18940
  /**
18857
18941
  * Expose whether this browser supports running the full DOMPurify.
18858
18942
  */
18859
18943
  DOMPurify.isSupported = typeof entries === 'function' && typeof getParentNode === 'function' && implementation && implementation.createHTMLDocument !== undefined;
18860
- const {
18861
- MUSTACHE_EXPR,
18862
- ERB_EXPR,
18863
- TMPLIT_EXPR,
18864
- DATA_ATTR,
18865
- ARIA_ATTR,
18866
- IS_SCRIPT_OR_DATA,
18867
- ATTR_WHITESPACE,
18868
- CUSTOM_ELEMENT
18869
- } = EXPRESSIONS;
18870
- let {
18871
- IS_ALLOWED_URI: IS_ALLOWED_URI$1
18872
- } = EXPRESSIONS;
18944
+ const MUSTACHE_EXPR$1 = MUSTACHE_EXPR,
18945
+ ERB_EXPR$1 = ERB_EXPR,
18946
+ TMPLIT_EXPR$1 = TMPLIT_EXPR,
18947
+ DATA_ATTR$1 = DATA_ATTR,
18948
+ ARIA_ATTR$1 = ARIA_ATTR,
18949
+ IS_SCRIPT_OR_DATA$1 = IS_SCRIPT_OR_DATA,
18950
+ ATTR_WHITESPACE$1 = ATTR_WHITESPACE,
18951
+ CUSTOM_ELEMENT$1 = CUSTOM_ELEMENT;
18952
+ let IS_ALLOWED_URI$1 = IS_ALLOWED_URI;
18873
18953
  /**
18874
18954
  * We consider the elements and attributes below to be safe. Ideally
18875
18955
  * don't add any new ones but feel free to remove unwanted ones.
@@ -19047,15 +19127,15 @@
19047
19127
  // HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
19048
19128
  transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase;
19049
19129
  /* Set configuration parameters */
19050
- ALLOWED_TAGS = objectHasOwnProperty(cfg, 'ALLOWED_TAGS') ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;
19051
- ALLOWED_ATTR = objectHasOwnProperty(cfg, 'ALLOWED_ATTR') ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;
19052
- ALLOWED_NAMESPACES = objectHasOwnProperty(cfg, 'ALLOWED_NAMESPACES') ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES;
19053
- URI_SAFE_ATTRIBUTES = objectHasOwnProperty(cfg, 'ADD_URI_SAFE_ATTR') ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR, transformCaseFunc) : DEFAULT_URI_SAFE_ATTRIBUTES;
19054
- DATA_URI_TAGS = objectHasOwnProperty(cfg, 'ADD_DATA_URI_TAGS') ? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS, transformCaseFunc) : DEFAULT_DATA_URI_TAGS;
19055
- FORBID_CONTENTS = objectHasOwnProperty(cfg, 'FORBID_CONTENTS') ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;
19056
- FORBID_TAGS = objectHasOwnProperty(cfg, 'FORBID_TAGS') ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : clone({});
19057
- FORBID_ATTR = objectHasOwnProperty(cfg, 'FORBID_ATTR') ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : clone({});
19058
- USE_PROFILES = objectHasOwnProperty(cfg, 'USE_PROFILES') ? cfg.USE_PROFILES : false;
19130
+ ALLOWED_TAGS = objectHasOwnProperty(cfg, 'ALLOWED_TAGS') && arrayIsArray(cfg.ALLOWED_TAGS) ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;
19131
+ ALLOWED_ATTR = objectHasOwnProperty(cfg, 'ALLOWED_ATTR') && arrayIsArray(cfg.ALLOWED_ATTR) ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;
19132
+ ALLOWED_NAMESPACES = objectHasOwnProperty(cfg, 'ALLOWED_NAMESPACES') && arrayIsArray(cfg.ALLOWED_NAMESPACES) ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES;
19133
+ URI_SAFE_ATTRIBUTES = objectHasOwnProperty(cfg, 'ADD_URI_SAFE_ATTR') && arrayIsArray(cfg.ADD_URI_SAFE_ATTR) ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR, transformCaseFunc) : DEFAULT_URI_SAFE_ATTRIBUTES;
19134
+ DATA_URI_TAGS = objectHasOwnProperty(cfg, 'ADD_DATA_URI_TAGS') && arrayIsArray(cfg.ADD_DATA_URI_TAGS) ? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS, transformCaseFunc) : DEFAULT_DATA_URI_TAGS;
19135
+ FORBID_CONTENTS = objectHasOwnProperty(cfg, 'FORBID_CONTENTS') && arrayIsArray(cfg.FORBID_CONTENTS) ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;
19136
+ FORBID_TAGS = objectHasOwnProperty(cfg, 'FORBID_TAGS') && arrayIsArray(cfg.FORBID_TAGS) ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : clone({});
19137
+ FORBID_ATTR = objectHasOwnProperty(cfg, 'FORBID_ATTR') && arrayIsArray(cfg.FORBID_ATTR) ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : clone({});
19138
+ USE_PROFILES = objectHasOwnProperty(cfg, 'USE_PROFILES') ? cfg.USE_PROFILES && typeof cfg.USE_PROFILES === 'object' ? clone(cfg.USE_PROFILES) : cfg.USE_PROFILES : false;
19059
19139
  ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true
19060
19140
  ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true
19061
19141
  ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false
@@ -19071,19 +19151,20 @@
19071
19151
  SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false
19072
19152
  KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
19073
19153
  IN_PLACE = cfg.IN_PLACE || false; // Default false
19074
- IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI;
19075
- NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
19076
- MATHML_TEXT_INTEGRATION_POINTS = cfg.MATHML_TEXT_INTEGRATION_POINTS || MATHML_TEXT_INTEGRATION_POINTS;
19077
- HTML_INTEGRATION_POINTS = cfg.HTML_INTEGRATION_POINTS || HTML_INTEGRATION_POINTS;
19078
- CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};
19079
- if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {
19080
- CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;
19154
+ IS_ALLOWED_URI$1 = isRegex(cfg.ALLOWED_URI_REGEXP) ? cfg.ALLOWED_URI_REGEXP : IS_ALLOWED_URI; // Default regexp
19155
+ NAMESPACE = typeof cfg.NAMESPACE === 'string' ? cfg.NAMESPACE : HTML_NAMESPACE; // Default HTML namespace
19156
+ MATHML_TEXT_INTEGRATION_POINTS = objectHasOwnProperty(cfg, 'MATHML_TEXT_INTEGRATION_POINTS') && cfg.MATHML_TEXT_INTEGRATION_POINTS && typeof cfg.MATHML_TEXT_INTEGRATION_POINTS === 'object' ? clone(cfg.MATHML_TEXT_INTEGRATION_POINTS) : addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']); // Default built-in map
19157
+ HTML_INTEGRATION_POINTS = objectHasOwnProperty(cfg, 'HTML_INTEGRATION_POINTS') && cfg.HTML_INTEGRATION_POINTS && typeof cfg.HTML_INTEGRATION_POINTS === 'object' ? clone(cfg.HTML_INTEGRATION_POINTS) : addToSet({}, ['annotation-xml']); // Default built-in map
19158
+ const customElementHandling = objectHasOwnProperty(cfg, 'CUSTOM_ELEMENT_HANDLING') && cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING === 'object' ? clone(cfg.CUSTOM_ELEMENT_HANDLING) : create$7(null);
19159
+ CUSTOM_ELEMENT_HANDLING = create$7(null);
19160
+ if (objectHasOwnProperty(customElementHandling, 'tagNameCheck') && isRegexOrFunction(customElementHandling.tagNameCheck)) {
19161
+ CUSTOM_ELEMENT_HANDLING.tagNameCheck = customElementHandling.tagNameCheck; // Default undefined
19081
19162
  }
19082
- if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) {
19083
- CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;
19163
+ if (objectHasOwnProperty(customElementHandling, 'attributeNameCheck') && isRegexOrFunction(customElementHandling.attributeNameCheck)) {
19164
+ CUSTOM_ELEMENT_HANDLING.attributeNameCheck = customElementHandling.attributeNameCheck; // Default undefined
19084
19165
  }
19085
- if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === 'boolean') {
19086
- CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;
19166
+ if (objectHasOwnProperty(customElementHandling, 'allowCustomizedBuiltInElements') && typeof customElementHandling.allowCustomizedBuiltInElements === 'boolean') {
19167
+ CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = customElementHandling.allowCustomizedBuiltInElements; // Default undefined
19087
19168
  }
19088
19169
  if (SAFE_FOR_TEMPLATES) {
19089
19170
  ALLOW_DATA_ATTR = false;
@@ -19115,44 +19196,41 @@
19115
19196
  addToSet(ALLOWED_ATTR, xml);
19116
19197
  }
19117
19198
  }
19118
- /* Prevent function-based ADD_ATTR / ADD_TAGS from leaking across calls */
19119
- if (!objectHasOwnProperty(cfg, 'ADD_TAGS')) {
19120
- EXTRA_ELEMENT_HANDLING.tagCheck = null;
19121
- }
19122
- if (!objectHasOwnProperty(cfg, 'ADD_ATTR')) {
19123
- EXTRA_ELEMENT_HANDLING.attributeCheck = null;
19124
- }
19199
+ /* Always reset function-based ADD_TAGS / ADD_ATTR checks to prevent
19200
+ * leaking across calls when switching from function to array config */
19201
+ EXTRA_ELEMENT_HANDLING.tagCheck = null;
19202
+ EXTRA_ELEMENT_HANDLING.attributeCheck = null;
19125
19203
  /* Merge configuration parameters */
19126
- if (cfg.ADD_TAGS) {
19204
+ if (objectHasOwnProperty(cfg, 'ADD_TAGS')) {
19127
19205
  if (typeof cfg.ADD_TAGS === 'function') {
19128
19206
  EXTRA_ELEMENT_HANDLING.tagCheck = cfg.ADD_TAGS;
19129
- } else {
19207
+ } else if (arrayIsArray(cfg.ADD_TAGS)) {
19130
19208
  if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
19131
19209
  ALLOWED_TAGS = clone(ALLOWED_TAGS);
19132
19210
  }
19133
19211
  addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
19134
19212
  }
19135
19213
  }
19136
- if (cfg.ADD_ATTR) {
19214
+ if (objectHasOwnProperty(cfg, 'ADD_ATTR')) {
19137
19215
  if (typeof cfg.ADD_ATTR === 'function') {
19138
19216
  EXTRA_ELEMENT_HANDLING.attributeCheck = cfg.ADD_ATTR;
19139
- } else {
19217
+ } else if (arrayIsArray(cfg.ADD_ATTR)) {
19140
19218
  if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
19141
19219
  ALLOWED_ATTR = clone(ALLOWED_ATTR);
19142
19220
  }
19143
19221
  addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
19144
19222
  }
19145
19223
  }
19146
- if (cfg.ADD_URI_SAFE_ATTR) {
19224
+ if (objectHasOwnProperty(cfg, 'ADD_URI_SAFE_ATTR') && arrayIsArray(cfg.ADD_URI_SAFE_ATTR)) {
19147
19225
  addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
19148
19226
  }
19149
- if (cfg.FORBID_CONTENTS) {
19227
+ if (objectHasOwnProperty(cfg, 'FORBID_CONTENTS') && arrayIsArray(cfg.FORBID_CONTENTS)) {
19150
19228
  if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
19151
19229
  FORBID_CONTENTS = clone(FORBID_CONTENTS);
19152
19230
  }
19153
19231
  addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
19154
19232
  }
19155
- if (cfg.ADD_FORBID_CONTENTS) {
19233
+ if (objectHasOwnProperty(cfg, 'ADD_FORBID_CONTENTS') && arrayIsArray(cfg.ADD_FORBID_CONTENTS)) {
19156
19234
  if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
19157
19235
  FORBID_CONTENTS = clone(FORBID_CONTENTS);
19158
19236
  }
@@ -19391,6 +19469,40 @@
19391
19469
  // eslint-disable-next-line no-bitwise
19392
19470
  NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION, null);
19393
19471
  };
19472
+ /**
19473
+ * Strip template-engine expressions ({{...}}, ${...}, <%...%>) from the
19474
+ * character data of an element subtree. Used as the final safety net for
19475
+ * SAFE_FOR_TEMPLATES on every DOM-returning code path so that expressions
19476
+ * which only form after text-node normalization (e.g. fragments split across
19477
+ * stripped elements) cannot survive into a template-evaluating framework.
19478
+ *
19479
+ * Walks text/comment/CDATA/processing-instruction nodes and mutates `.data`
19480
+ * in place rather than round-tripping through innerHTML. This preserves
19481
+ * descendant node references (important for IN_PLACE callers), avoids a
19482
+ * serialize/reparse cycle, and reads literal character data — which means
19483
+ * `<%...%>` in text content matches the ERB regex against its real bytes
19484
+ * instead of the HTML-entity-escaped form innerHTML would produce.
19485
+ *
19486
+ * Attribute values are not visited here; SAFE_FOR_TEMPLATES handling for
19487
+ * attributes is performed during the per-node `_sanitizeAttributes` pass.
19488
+ *
19489
+ * @param node The root element whose character data should be scrubbed.
19490
+ */
19491
+ const _scrubTemplateExpressions = function _scrubTemplateExpressions(node) {
19492
+ node.normalize();
19493
+ const walker = createNodeIterator.call(node.ownerDocument || node, node,
19494
+ // eslint-disable-next-line no-bitwise
19495
+ NodeFilter.SHOW_TEXT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_CDATA_SECTION | NodeFilter.SHOW_PROCESSING_INSTRUCTION, null);
19496
+ let currentNode = walker.nextNode();
19497
+ while (currentNode) {
19498
+ let data = currentNode.data;
19499
+ arrayForEach([MUSTACHE_EXPR$1, ERB_EXPR$1, TMPLIT_EXPR$1], expr => {
19500
+ data = stringReplace(data, expr, ' ');
19501
+ });
19502
+ currentNode.data = data;
19503
+ currentNode = walker.nextNode();
19504
+ }
19505
+ };
19394
19506
  /**
19395
19507
  * _isClobbered
19396
19508
  *
@@ -19401,13 +19513,31 @@
19401
19513
  return element instanceof HTMLFormElement && (typeof element.nodeName !== 'string' || typeof element.textContent !== 'string' || typeof element.removeChild !== 'function' || !(element.attributes instanceof NamedNodeMap) || typeof element.removeAttribute !== 'function' || typeof element.setAttribute !== 'function' || typeof element.namespaceURI !== 'string' || typeof element.insertBefore !== 'function' || typeof element.hasChildNodes !== 'function');
19402
19514
  };
19403
19515
  /**
19404
- * Checks whether the given object is a DOM node.
19516
+ * Checks whether the given object is a DOM node, including nodes that
19517
+ * originate from a different window/realm (e.g. an iframe's
19518
+ * contentDocument). The previous `value instanceof Node` check was
19519
+ * realm-bound: nodes from a different window failed it, causing
19520
+ * sanitize() to silently stringify them and reset IN_PLACE to false,
19521
+ * returning the original node unsanitized. See GHSA-4w3q-35jp-p934.
19522
+ *
19523
+ * Implementation: call the cached `nodeType` getter from Node.prototype
19524
+ * directly on the value. This bypasses any clobbered instance property
19525
+ * (e.g. a child element named "nodeType") and works across realms
19526
+ * because the WebIDL `nodeType` getter reads an internal slot that
19527
+ * every real Node has, regardless of which window minted it.
19405
19528
  *
19406
19529
  * @param value object to check whether it's a DOM node
19407
- * @return true is object is a DOM node
19530
+ * @return true if value is a DOM node from any realm
19408
19531
  */
19409
19532
  const _isNode = function _isNode(value) {
19410
- return typeof Node === 'function' && value instanceof Node;
19533
+ if (!getNodeType || typeof value !== 'object' || value === null) {
19534
+ return false;
19535
+ }
19536
+ try {
19537
+ return typeof getNodeType(value) === 'number';
19538
+ } catch (_) {
19539
+ return false;
19540
+ }
19411
19541
  };
19412
19542
  function _executeHooks(hooks, currentNode, data) {
19413
19543
  arrayForEach(hooks, hook => {
@@ -19444,6 +19574,11 @@
19444
19574
  _forceRemove(currentNode);
19445
19575
  return true;
19446
19576
  }
19577
+ /* Remove risky CSS construction leading to mXSS */
19578
+ if (SAFE_FOR_XML && currentNode.namespaceURI === HTML_NAMESPACE && tagName === 'style' && _isNode(currentNode.firstElementChild)) {
19579
+ _forceRemove(currentNode);
19580
+ return true;
19581
+ }
19447
19582
  /* Remove any occurrence of processing instructions */
19448
19583
  if (currentNode.nodeType === NODE_TYPE.progressingInstruction) {
19449
19584
  _forceRemove(currentNode);
@@ -19455,7 +19590,7 @@
19455
19590
  return true;
19456
19591
  }
19457
19592
  /* Remove element if anything forbids its presence */
19458
- if (!(EXTRA_ELEMENT_HANDLING.tagCheck instanceof Function && EXTRA_ELEMENT_HANDLING.tagCheck(tagName)) && (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName])) {
19593
+ if (FORBID_TAGS[tagName] || !(EXTRA_ELEMENT_HANDLING.tagCheck instanceof Function && EXTRA_ELEMENT_HANDLING.tagCheck(tagName)) && !ALLOWED_TAGS[tagName]) {
19459
19594
  /* Check if we have a custom element to handle */
19460
19595
  if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) {
19461
19596
  if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) {
@@ -19473,7 +19608,6 @@
19473
19608
  const childCount = childNodes.length;
19474
19609
  for (let i = childCount - 1; i >= 0; --i) {
19475
19610
  const childClone = cloneNode(childNodes[i], true);
19476
- childClone.__removalCount = (currentNode.__removalCount || 0) + 1;
19477
19611
  parentNode.insertBefore(childClone, getNextSibling(currentNode));
19478
19612
  }
19479
19613
  }
@@ -19495,7 +19629,7 @@
19495
19629
  if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) {
19496
19630
  /* Get the element's text content */
19497
19631
  content = currentNode.textContent;
19498
- arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
19632
+ arrayForEach([MUSTACHE_EXPR$1, ERB_EXPR$1, TMPLIT_EXPR$1], expr => {
19499
19633
  content = stringReplace(content, expr, ' ');
19500
19634
  });
19501
19635
  if (currentNode.textContent !== content) {
@@ -19527,11 +19661,12 @@
19527
19661
  if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
19528
19662
  return false;
19529
19663
  }
19664
+ const nameIsPermitted = ALLOWED_ATTR[lcName] || EXTRA_ELEMENT_HANDLING.attributeCheck instanceof Function && EXTRA_ELEMENT_HANDLING.attributeCheck(lcName, lcTag);
19530
19665
  /* Allow valid data-* attributes: At least one character after "-"
19531
19666
  (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
19532
19667
  XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
19533
19668
  We don't need to check the value; it's always URI safe. */
19534
- if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR, lcName)) ; else if (EXTRA_ELEMENT_HANDLING.attributeCheck instanceof Function && EXTRA_ELEMENT_HANDLING.attributeCheck(lcName, lcTag)) ; else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
19669
+ if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR$1, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR$1, lcName)) ; else if (!nameIsPermitted || FORBID_ATTR[lcName]) {
19535
19670
  if (
19536
19671
  // First condition does a very basic check if a) it's basically a valid custom element tagname AND
19537
19672
  // b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
@@ -19543,11 +19678,15 @@
19543
19678
  return false;
19544
19679
  }
19545
19680
  /* Check value is safe. First, is attr inert? If so, is safe */
19546
- } else if (URI_SAFE_ATTRIBUTES[lcName]) ; else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE, ''))) ; else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]) ; else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA, stringReplace(value, ATTR_WHITESPACE, ''))) ; else if (value) {
19681
+ } else if (URI_SAFE_ATTRIBUTES[lcName]) ; else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE$1, ''))) ; else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]) ; else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA$1, stringReplace(value, ATTR_WHITESPACE$1, ''))) ; else if (value) {
19547
19682
  return false;
19548
19683
  } else ;
19549
19684
  return true;
19550
19685
  };
19686
+ /* Names the HTML spec reserves from valid-custom-element-name; these must
19687
+ * never be treated as basic custom elements even when a permissive
19688
+ * CUSTOM_ELEMENT_HANDLING.tagNameCheck is configured. */
19689
+ const RESERVED_CUSTOM_ELEMENT_NAMES = addToSet({}, ['annotation-xml', 'color-profile', 'font-face', 'font-face-format', 'font-face-name', 'font-face-src', 'font-face-uri', 'missing-glyph']);
19551
19690
  /**
19552
19691
  * _isBasicCustomElement
19553
19692
  * checks if at least one dash is included in tagName, and it's not the first char
@@ -19557,7 +19696,7 @@
19557
19696
  * @returns Returns true if the tag name meets the basic criteria for a custom element, otherwise false.
19558
19697
  */
19559
19698
  const _isBasicCustomElement = function _isBasicCustomElement(tagName) {
19560
- return tagName !== 'annotation-xml' && stringMatch(tagName, CUSTOM_ELEMENT);
19699
+ return !RESERVED_CUSTOM_ELEMENT_NAMES[stringToLowerCase(tagName)] && regExpTest(CUSTOM_ELEMENT$1, tagName);
19561
19700
  };
19562
19701
  /**
19563
19702
  * _sanitizeAttributes
@@ -19572,9 +19711,7 @@
19572
19711
  const _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
19573
19712
  /* Execute a hook if present */
19574
19713
  _executeHooks(hooks.beforeSanitizeAttributes, currentNode, null);
19575
- const {
19576
- attributes
19577
- } = currentNode;
19714
+ const attributes = currentNode.attributes;
19578
19715
  /* Check if we have attributes; if not we might have a text node */
19579
19716
  if (!attributes || _isClobbered(currentNode)) {
19580
19717
  return;
@@ -19590,11 +19727,9 @@
19590
19727
  /* Go backwards over all attributes; safely remove bad ones */
19591
19728
  while (l--) {
19592
19729
  const attr = attributes[l];
19593
- const {
19594
- name,
19595
- namespaceURI,
19596
- value: attrValue
19597
- } = attr;
19730
+ const name = attr.name,
19731
+ namespaceURI = attr.namespaceURI,
19732
+ attrValue = attr.value;
19598
19733
  const lcName = transformCaseFunc(name);
19599
19734
  const initValue = attrValue;
19600
19735
  let value = name === 'value' ? initValue : stringTrim(initValue);
@@ -19608,12 +19743,14 @@
19608
19743
  /* Full DOM Clobbering protection via namespace isolation,
19609
19744
  * Prefix id and name attributes with `user-content-`
19610
19745
  */
19611
- if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {
19746
+ if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name') && stringIndexOf(value, SANITIZE_NAMED_PROPS_PREFIX) !== 0) {
19612
19747
  // Remove the attribute with this value
19613
19748
  _removeAttribute(name, currentNode);
19614
19749
  // Prefix the value and later re-create the attribute with the sanitized value
19615
19750
  value = SANITIZE_NAMED_PROPS_PREFIX + value;
19616
19751
  }
19752
+ // Else: already prefixed, leave the attribute alone — the prefix is
19753
+ // itself the clobbering protection, and re-applying it is incorrect.
19617
19754
  /* Work around a security issue with comments inside attributes */
19618
19755
  if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|script|title|xmp|textarea|noscript|iframe|noembed|noframes)/i, value)) {
19619
19756
  _removeAttribute(name, currentNode);
@@ -19640,7 +19777,7 @@
19640
19777
  }
19641
19778
  /* Sanitize attribute content to be template-safe */
19642
19779
  if (SAFE_FOR_TEMPLATES) {
19643
- arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
19780
+ arrayForEach([MUSTACHE_EXPR$1, ERB_EXPR$1, TMPLIT_EXPR$1], expr => {
19644
19781
  value = stringReplace(value, expr, ' ');
19645
19782
  });
19646
19783
  }
@@ -19694,7 +19831,7 @@
19694
19831
  *
19695
19832
  * @param fragment to iterate over recursively
19696
19833
  */
19697
- const _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {
19834
+ const _sanitizeShadowDOM2 = function _sanitizeShadowDOM(fragment) {
19698
19835
  let shadowNode = null;
19699
19836
  const shadowIterator = _createNodeIterator(fragment);
19700
19837
  /* Execute a hook if present */
@@ -19708,12 +19845,55 @@
19708
19845
  _sanitizeAttributes(shadowNode);
19709
19846
  /* Deep shadow DOM detected */
19710
19847
  if (shadowNode.content instanceof DocumentFragment) {
19711
- _sanitizeShadowDOM(shadowNode.content);
19848
+ _sanitizeShadowDOM2(shadowNode.content);
19712
19849
  }
19713
19850
  }
19714
19851
  /* Execute a hook if present */
19715
19852
  _executeHooks(hooks.afterSanitizeShadowDOM, fragment, null);
19716
19853
  };
19854
+ /**
19855
+ * _sanitizeAttachedShadowRoots
19856
+ *
19857
+ * Walks `root` and feeds every attached shadow root we encounter into
19858
+ * the existing _sanitizeShadowDOM pipeline. The default node iterator
19859
+ * does not descend into shadow trees, so nodes inside an attached
19860
+ * shadow root would otherwise be skipped entirely.
19861
+ *
19862
+ * Two real input paths put attached shadow roots in front of us:
19863
+ * 1. IN_PLACE on a DOM node that already has shadow roots attached.
19864
+ * 2. DOM-node input where importNode(dirty, true) deep-clones the
19865
+ * shadow root because it was created with `clonable: true`.
19866
+ *
19867
+ * This pass runs once, up front, so the main iteration loop (and the
19868
+ * existing _sanitizeShadowDOM template-content recursion) stay
19869
+ * untouched — string-input paths are not affected.
19870
+ *
19871
+ * @param root the subtree root to walk for attached shadow roots
19872
+ */
19873
+ const _sanitizeAttachedShadowRoots2 = function _sanitizeAttachedShadowRoots(root) {
19874
+ if (root.nodeType === NODE_TYPE.element && root.shadowRoot instanceof DocumentFragment) {
19875
+ const sr = root.shadowRoot;
19876
+ // Recurse first so that nested shadow roots are reached even if
19877
+ // _sanitizeShadowDOM removes hosts at this level.
19878
+ _sanitizeAttachedShadowRoots2(sr);
19879
+ _sanitizeShadowDOM2(sr);
19880
+ }
19881
+ // Snapshot children before recursing. Sanitization of one subtree
19882
+ // (e.g. via an uponSanitizeShadowNode hook) may detach siblings,
19883
+ // and naive nextSibling traversal would silently skip the rest of
19884
+ // the list once a node is detached.
19885
+ const childNodes = root.childNodes;
19886
+ if (!childNodes) {
19887
+ return;
19888
+ }
19889
+ const snapshot = [];
19890
+ arrayForEach(childNodes, child => {
19891
+ arrayPush(snapshot, child);
19892
+ });
19893
+ for (const child of snapshot) {
19894
+ _sanitizeAttachedShadowRoots2(child);
19895
+ }
19896
+ };
19717
19897
  // eslint-disable-next-line complexity
19718
19898
  DOMPurify.sanitize = function (dirty) {
19719
19899
  let cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
@@ -19730,13 +19910,9 @@
19730
19910
  }
19731
19911
  /* Stringify, in case dirty is an object */
19732
19912
  if (typeof dirty !== 'string' && !_isNode(dirty)) {
19733
- if (typeof dirty.toString === 'function') {
19734
- dirty = dirty.toString();
19735
- if (typeof dirty !== 'string') {
19736
- throw typeErrorCreate('dirty is not a string, aborting');
19737
- }
19738
- } else {
19739
- throw typeErrorCreate('toString is not a function');
19913
+ dirty = stringifyValue(dirty);
19914
+ if (typeof dirty !== 'string') {
19915
+ throw typeErrorCreate('dirty is not a string, aborting');
19740
19916
  }
19741
19917
  }
19742
19918
  /* Return dirty HTML if DOMPurify cannot run */
@@ -19755,13 +19931,17 @@
19755
19931
  }
19756
19932
  if (IN_PLACE) {
19757
19933
  /* Do some early pre-sanitization to avoid unsafe root nodes */
19758
- if (dirty.nodeName) {
19759
- const tagName = transformCaseFunc(dirty.nodeName);
19934
+ const nn = dirty.nodeName;
19935
+ if (typeof nn === 'string') {
19936
+ const tagName = transformCaseFunc(nn);
19760
19937
  if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
19761
19938
  throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');
19762
19939
  }
19763
19940
  }
19764
- } else if (dirty instanceof Node) {
19941
+ /* Sanitize attached shadow roots before the main iterator runs.
19942
+ The iterator does not descend into shadow trees. */
19943
+ _sanitizeAttachedShadowRoots2(dirty);
19944
+ } else if (_isNode(dirty)) {
19765
19945
  /* If dirty is a DOM element, append to an empty document to avoid
19766
19946
  elements being stripped by the parser */
19767
19947
  body = _initDocument('<!---->');
@@ -19775,6 +19955,10 @@
19775
19955
  // eslint-disable-next-line unicorn/prefer-dom-node-append
19776
19956
  body.appendChild(importedNode);
19777
19957
  }
19958
+ /* Clonable shadow roots are deep-cloned by importNode(); sanitize
19959
+ them before the main iterator runs, since the iterator does not
19960
+ descend into shadow trees. */
19961
+ _sanitizeAttachedShadowRoots2(importedNode);
19778
19962
  } else {
19779
19963
  /* Exit directly if we have nothing to do */
19780
19964
  if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT &&
@@ -19803,15 +19987,21 @@
19803
19987
  _sanitizeAttributes(currentNode);
19804
19988
  /* Shadow DOM detected, sanitize it */
19805
19989
  if (currentNode.content instanceof DocumentFragment) {
19806
- _sanitizeShadowDOM(currentNode.content);
19990
+ _sanitizeShadowDOM2(currentNode.content);
19807
19991
  }
19808
19992
  }
19809
19993
  /* If we sanitized `dirty` in-place, return it. */
19810
19994
  if (IN_PLACE) {
19995
+ if (SAFE_FOR_TEMPLATES) {
19996
+ _scrubTemplateExpressions(dirty);
19997
+ }
19811
19998
  return dirty;
19812
19999
  }
19813
20000
  /* Return sanitized string or DOM */
19814
20001
  if (RETURN_DOM) {
20002
+ if (SAFE_FOR_TEMPLATES) {
20003
+ _scrubTemplateExpressions(body);
20004
+ }
19815
20005
  if (RETURN_DOM_FRAGMENT) {
19816
20006
  returnNode = createDocumentFragment.call(body.ownerDocument);
19817
20007
  while (body.firstChild) {
@@ -19840,7 +20030,7 @@
19840
20030
  }
19841
20031
  /* Sanitize final string template-safe */
19842
20032
  if (SAFE_FOR_TEMPLATES) {
19843
- arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
20033
+ arrayForEach([MUSTACHE_EXPR$1, ERB_EXPR$1, TMPLIT_EXPR$1], expr => {
19844
20034
  serializedHTML = stringReplace(serializedHTML, expr, ' ');
19845
20035
  });
19846
20036
  }
@@ -40777,14 +40967,14 @@
40777
40967
  * @property minorVersion
40778
40968
  * @type String
40779
40969
  */
40780
- minorVersion: '5.1',
40970
+ minorVersion: '6.0',
40781
40971
  /**
40782
40972
  * Release date of TinyMCE build.
40783
40973
  *
40784
40974
  * @property releaseDate
40785
40975
  * @type String
40786
40976
  */
40787
- releaseDate: '2026-05-19',
40977
+ releaseDate: '2026-06-03',
40788
40978
  /**
40789
40979
  * Collection of language pack data.
40790
40980
  *