action_text-trix 2.1.17 → 2.1.19

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8cf5a80e4ea3934de46916afc13b3d2d598a704b29c07aa399ab545a0e54cc4f
4
- data.tar.gz: 273ddae41040f29675d28a2387154abf3facbcb8beb0ecf4c9b0e3415b34ecab
3
+ metadata.gz: 14985d71593b521f0ddc7c0488ad00483db8a3423b58f1dac7fd19c5568e2d78
4
+ data.tar.gz: 6d2fc6d9de5e0b992b66e1a17d77c572e1b695c084fedf3bc79aaf6cd5b56107
5
5
  SHA512:
6
- metadata.gz: e5e1b53de72ab8ce7f9a61f287b806154741cb8c9321c875bbb05bf7c49ae526bcd710a74a00196cb4dda833e01f8cba9936df9ca800826c0055e7b90193178c
7
- data.tar.gz: 444d9bcb83134dff0bc91df57ddef1f167ee4d314ff70021687d287ccb4a013da9d45ba653e4eee87a51df89e884804a1aaeacbed3a9198b2beec0325e1da209
6
+ metadata.gz: 6a48e8c1dcdf076d11a930df88d45180fef46c42584522ddb01a58ecf5e4d2afa767e2985363ceae427779373237d7196760d150f93ea26485b3661d00a3fe29
7
+ data.tar.gz: 0f4305effe253c9a6f7aaf3c68324a477fbd3e7451d3f4479ca1f13f7777e1af9e93c2304e3120b48f70e703f73731cc2c7b6c8ef42541e87a0106f2f7c6f31e
@@ -1,5 +1,5 @@
1
1
  /*
2
- Trix 2.1.17
2
+ Trix 2.1.19
3
3
  Copyright © 2026 37signals, LLC
4
4
  */
5
5
  (function (global, factory) {
@@ -9,7 +9,7 @@ Copyright © 2026 37signals, LLC
9
9
  })(this, (function () { 'use strict';
10
10
 
11
11
  var name = "trix";
12
- var version = "2.1.17";
12
+ var version = "2.1.19";
13
13
  var description = "A rich text editor for everyday writing";
14
14
  var main = "dist/trix.umd.min.js";
15
15
  var module = "dist/trix.esm.min.js";
@@ -1765,7 +1765,7 @@ $\
1765
1765
  }
1766
1766
  }
1767
1767
 
1768
- /*! @license DOMPurify 3.2.7 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.2.7/LICENSE */
1768
+ /*! @license DOMPurify 3.4.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.4.2/LICENSE */
1769
1769
 
1770
1770
  const {
1771
1771
  entries,
@@ -1814,13 +1814,19 @@ $\
1814
1814
  const arrayPop = unapply(Array.prototype.pop);
1815
1815
  const arrayPush = unapply(Array.prototype.push);
1816
1816
  const arraySplice = unapply(Array.prototype.splice);
1817
+ const arrayIsArray = Array.isArray;
1817
1818
  const stringToLowerCase = unapply(String.prototype.toLowerCase);
1818
1819
  const stringToString = unapply(String.prototype.toString);
1819
1820
  const stringMatch = unapply(String.prototype.match);
1820
1821
  const stringReplace = unapply(String.prototype.replace);
1821
1822
  const stringIndexOf = unapply(String.prototype.indexOf);
1822
1823
  const stringTrim = unapply(String.prototype.trim);
1824
+ const numberToString = unapply(Number.prototype.toString);
1825
+ const booleanToString = unapply(Boolean.prototype.toString);
1826
+ const bigintToString = typeof BigInt === 'undefined' ? null : unapply(BigInt.prototype.toString);
1827
+ const symbolToString = typeof Symbol === 'undefined' ? null : unapply(Symbol.prototype.toString);
1823
1828
  const objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);
1829
+ const objectToString = unapply(Object.prototype.toString);
1824
1830
  const regExpTest = unapply(RegExp.prototype.test);
1825
1831
  const typeErrorCreate = unconstruct(TypeError);
1826
1832
  /**
@@ -1870,6 +1876,9 @@ $\
1870
1876
  // Prevent prototype setters from intercepting set as a this value.
1871
1877
  setPrototypeOf(set, null);
1872
1878
  }
1879
+ if (!arrayIsArray(array)) {
1880
+ return set;
1881
+ }
1873
1882
  let l = array.length;
1874
1883
  while (l--) {
1875
1884
  let element = array[l];
@@ -1913,7 +1922,7 @@ $\
1913
1922
  for (const [property, value] of entries(object)) {
1914
1923
  const isPropertyExist = objectHasOwnProperty(object, property);
1915
1924
  if (isPropertyExist) {
1916
- if (Array.isArray(value)) {
1925
+ if (arrayIsArray(value)) {
1917
1926
  newObject[property] = cleanArray(value);
1918
1927
  } else if (value && typeof value === 'object' && value.constructor === Object) {
1919
1928
  newObject[property] = clone(value);
@@ -1924,6 +1933,58 @@ $\
1924
1933
  }
1925
1934
  return newObject;
1926
1935
  }
1936
+ /**
1937
+ * Convert non-node values into strings without depending on direct property access.
1938
+ *
1939
+ * @param value - The value to stringify.
1940
+ * @returns A string representation of the provided value.
1941
+ */
1942
+ function stringifyValue(value) {
1943
+ switch (typeof value) {
1944
+ case 'string':
1945
+ {
1946
+ return value;
1947
+ }
1948
+ case 'number':
1949
+ {
1950
+ return numberToString(value);
1951
+ }
1952
+ case 'boolean':
1953
+ {
1954
+ return booleanToString(value);
1955
+ }
1956
+ case 'bigint':
1957
+ {
1958
+ return bigintToString ? bigintToString(value) : '0';
1959
+ }
1960
+ case 'symbol':
1961
+ {
1962
+ return symbolToString ? symbolToString(value) : 'Symbol()';
1963
+ }
1964
+ case 'undefined':
1965
+ {
1966
+ return objectToString(value);
1967
+ }
1968
+ case 'function':
1969
+ case 'object':
1970
+ {
1971
+ if (value === null) {
1972
+ return objectToString(value);
1973
+ }
1974
+ const valueAsRecord = value;
1975
+ const valueToString = lookupGetter(valueAsRecord, 'toString');
1976
+ if (typeof valueToString === 'function') {
1977
+ const stringified = valueToString(valueAsRecord);
1978
+ return typeof stringified === 'string' ? stringified : objectToString(stringified);
1979
+ }
1980
+ return objectToString(value);
1981
+ }
1982
+ default:
1983
+ {
1984
+ return objectToString(value);
1985
+ }
1986
+ }
1987
+ }
1927
1988
  /**
1928
1989
  * This method automatically checks if the prop is function or getter and behaves accordingly.
1929
1990
  *
@@ -1949,8 +2010,16 @@ $\
1949
2010
  }
1950
2011
  return fallbackValue;
1951
2012
  }
2013
+ function isRegex(value) {
2014
+ try {
2015
+ regExpTest(value, '');
2016
+ return true;
2017
+ } catch (_unused) {
2018
+ return false;
2019
+ }
2020
+ }
1952
2021
  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']);
1953
- 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', 'slot', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'view', 'vkern']);
2022
+ 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']);
1954
2023
  const svgFilters = freeze(['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feDropShadow', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence']);
1955
2024
  // List of SVG elements that are disallowed by default.
1956
2025
  // We still need to know them so that we can do namespace
@@ -1962,9 +2031,9 @@ $\
1962
2031
  // even those that we disallow by default.
1963
2032
  const mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);
1964
2033
  const text = freeze(['#text']);
1965
- 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']);
1966
- 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', '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']);
1967
- 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']);
2034
+ 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']);
2035
+ 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']);
2036
+ 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']);
1968
2037
  const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
1969
2038
 
1970
2039
  // eslint-disable-next-line unicorn/better-regex
@@ -1998,19 +2067,11 @@ $\
1998
2067
  // https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
1999
2068
  const NODE_TYPE = {
2000
2069
  element: 1,
2001
- attribute: 2,
2002
2070
  text: 3,
2003
- cdataSection: 4,
2004
- entityReference: 5,
2005
- // Deprecated
2006
- entityNode: 6,
2007
2071
  // Deprecated
2008
2072
  progressingInstruction: 7,
2009
2073
  comment: 8,
2010
- document: 9,
2011
- documentType: 10,
2012
- documentFragment: 11,
2013
- notation: 12 // Deprecated
2074
+ document: 9
2014
2075
  };
2015
2076
  const getGlobal = function getGlobal() {
2016
2077
  return typeof window === 'undefined' ? null : window;
@@ -2069,7 +2130,7 @@ $\
2069
2130
  function createDOMPurify() {
2070
2131
  let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
2071
2132
  const DOMPurify = root => createDOMPurify(root);
2072
- DOMPurify.version = '3.2.7';
2133
+ DOMPurify.version = '3.4.2';
2073
2134
  DOMPurify.removed = [];
2074
2135
  if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) {
2075
2136
  // Not running in a browser, provide a factory function
@@ -2180,6 +2241,21 @@ $\
2180
2241
  let FORBID_TAGS = null;
2181
2242
  /* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */
2182
2243
  let FORBID_ATTR = null;
2244
+ /* Config object to store ADD_TAGS/ADD_ATTR functions (when used as functions) */
2245
+ const EXTRA_ELEMENT_HANDLING = Object.seal(create(null, {
2246
+ tagCheck: {
2247
+ writable: true,
2248
+ configurable: false,
2249
+ enumerable: true,
2250
+ value: null
2251
+ },
2252
+ attributeCheck: {
2253
+ writable: true,
2254
+ configurable: false,
2255
+ enumerable: true,
2256
+ value: null
2257
+ }
2258
+ }));
2183
2259
  /* Decide if ARIA attributes are okay */
2184
2260
  let ALLOW_ARIA_ATTR = true;
2185
2261
  /* Decide if custom data attributes are okay */
@@ -2302,15 +2378,15 @@ $\
2302
2378
  // HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
2303
2379
  transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase;
2304
2380
  /* Set configuration parameters */
2305
- ALLOWED_TAGS = objectHasOwnProperty(cfg, 'ALLOWED_TAGS') ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;
2306
- ALLOWED_ATTR = objectHasOwnProperty(cfg, 'ALLOWED_ATTR') ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;
2307
- ALLOWED_NAMESPACES = objectHasOwnProperty(cfg, 'ALLOWED_NAMESPACES') ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES;
2308
- 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;
2309
- 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;
2310
- FORBID_CONTENTS = objectHasOwnProperty(cfg, 'FORBID_CONTENTS') ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;
2311
- FORBID_TAGS = objectHasOwnProperty(cfg, 'FORBID_TAGS') ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : clone({});
2312
- FORBID_ATTR = objectHasOwnProperty(cfg, 'FORBID_ATTR') ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : clone({});
2313
- USE_PROFILES = objectHasOwnProperty(cfg, 'USE_PROFILES') ? cfg.USE_PROFILES : false;
2381
+ ALLOWED_TAGS = objectHasOwnProperty(cfg, 'ALLOWED_TAGS') && arrayIsArray(cfg.ALLOWED_TAGS) ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;
2382
+ ALLOWED_ATTR = objectHasOwnProperty(cfg, 'ALLOWED_ATTR') && arrayIsArray(cfg.ALLOWED_ATTR) ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;
2383
+ ALLOWED_NAMESPACES = objectHasOwnProperty(cfg, 'ALLOWED_NAMESPACES') && arrayIsArray(cfg.ALLOWED_NAMESPACES) ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES;
2384
+ 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;
2385
+ 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;
2386
+ FORBID_CONTENTS = objectHasOwnProperty(cfg, 'FORBID_CONTENTS') && arrayIsArray(cfg.FORBID_CONTENTS) ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;
2387
+ FORBID_TAGS = objectHasOwnProperty(cfg, 'FORBID_TAGS') && arrayIsArray(cfg.FORBID_TAGS) ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : clone({});
2388
+ FORBID_ATTR = objectHasOwnProperty(cfg, 'FORBID_ATTR') && arrayIsArray(cfg.FORBID_ATTR) ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : clone({});
2389
+ USE_PROFILES = objectHasOwnProperty(cfg, 'USE_PROFILES') ? cfg.USE_PROFILES && typeof cfg.USE_PROFILES === 'object' ? clone(cfg.USE_PROFILES) : cfg.USE_PROFILES : false;
2314
2390
  ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true
2315
2391
  ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true
2316
2392
  ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false
@@ -2326,19 +2402,20 @@ $\
2326
2402
  SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false
2327
2403
  KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
2328
2404
  IN_PLACE = cfg.IN_PLACE || false; // Default false
2329
- IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI;
2330
- NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
2331
- MATHML_TEXT_INTEGRATION_POINTS = cfg.MATHML_TEXT_INTEGRATION_POINTS || MATHML_TEXT_INTEGRATION_POINTS;
2332
- HTML_INTEGRATION_POINTS = cfg.HTML_INTEGRATION_POINTS || HTML_INTEGRATION_POINTS;
2333
- CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};
2334
- if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {
2335
- CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;
2405
+ IS_ALLOWED_URI$1 = isRegex(cfg.ALLOWED_URI_REGEXP) ? cfg.ALLOWED_URI_REGEXP : IS_ALLOWED_URI; // Default regexp
2406
+ NAMESPACE = typeof cfg.NAMESPACE === 'string' ? cfg.NAMESPACE : HTML_NAMESPACE; // Default HTML namespace
2407
+ 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
2408
+ 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
2409
+ const customElementHandling = objectHasOwnProperty(cfg, 'CUSTOM_ELEMENT_HANDLING') && cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING === 'object' ? clone(cfg.CUSTOM_ELEMENT_HANDLING) : create(null);
2410
+ CUSTOM_ELEMENT_HANDLING = create(null);
2411
+ if (objectHasOwnProperty(customElementHandling, 'tagNameCheck') && isRegexOrFunction(customElementHandling.tagNameCheck)) {
2412
+ CUSTOM_ELEMENT_HANDLING.tagNameCheck = customElementHandling.tagNameCheck; // Default undefined
2336
2413
  }
2337
- if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) {
2338
- CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;
2414
+ if (objectHasOwnProperty(customElementHandling, 'attributeNameCheck') && isRegexOrFunction(customElementHandling.attributeNameCheck)) {
2415
+ CUSTOM_ELEMENT_HANDLING.attributeNameCheck = customElementHandling.attributeNameCheck; // Default undefined
2339
2416
  }
2340
- if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === 'boolean') {
2341
- CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;
2417
+ if (objectHasOwnProperty(customElementHandling, 'allowCustomizedBuiltInElements') && typeof customElementHandling.allowCustomizedBuiltInElements === 'boolean') {
2418
+ CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = customElementHandling.allowCustomizedBuiltInElements; // Default undefined
2342
2419
  }
2343
2420
  if (SAFE_FOR_TEMPLATES) {
2344
2421
  ALLOW_DATA_ATTR = false;
@@ -2349,7 +2426,7 @@ $\
2349
2426
  /* Parse profile info */
2350
2427
  if (USE_PROFILES) {
2351
2428
  ALLOWED_TAGS = addToSet({}, text);
2352
- ALLOWED_ATTR = [];
2429
+ ALLOWED_ATTR = create(null);
2353
2430
  if (USE_PROFILES.html === true) {
2354
2431
  addToSet(ALLOWED_TAGS, html$1);
2355
2432
  addToSet(ALLOWED_ATTR, html);
@@ -2370,28 +2447,46 @@ $\
2370
2447
  addToSet(ALLOWED_ATTR, xml);
2371
2448
  }
2372
2449
  }
2450
+ /* Always reset function-based ADD_TAGS / ADD_ATTR checks to prevent
2451
+ * leaking across calls when switching from function to array config */
2452
+ EXTRA_ELEMENT_HANDLING.tagCheck = null;
2453
+ EXTRA_ELEMENT_HANDLING.attributeCheck = null;
2373
2454
  /* Merge configuration parameters */
2374
- if (cfg.ADD_TAGS) {
2375
- if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
2376
- ALLOWED_TAGS = clone(ALLOWED_TAGS);
2455
+ if (objectHasOwnProperty(cfg, 'ADD_TAGS')) {
2456
+ if (typeof cfg.ADD_TAGS === 'function') {
2457
+ EXTRA_ELEMENT_HANDLING.tagCheck = cfg.ADD_TAGS;
2458
+ } else if (arrayIsArray(cfg.ADD_TAGS)) {
2459
+ if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
2460
+ ALLOWED_TAGS = clone(ALLOWED_TAGS);
2461
+ }
2462
+ addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
2377
2463
  }
2378
- addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
2379
2464
  }
2380
- if (cfg.ADD_ATTR) {
2381
- if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
2382
- ALLOWED_ATTR = clone(ALLOWED_ATTR);
2465
+ if (objectHasOwnProperty(cfg, 'ADD_ATTR')) {
2466
+ if (typeof cfg.ADD_ATTR === 'function') {
2467
+ EXTRA_ELEMENT_HANDLING.attributeCheck = cfg.ADD_ATTR;
2468
+ } else if (arrayIsArray(cfg.ADD_ATTR)) {
2469
+ if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
2470
+ ALLOWED_ATTR = clone(ALLOWED_ATTR);
2471
+ }
2472
+ addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
2383
2473
  }
2384
- addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
2385
2474
  }
2386
- if (cfg.ADD_URI_SAFE_ATTR) {
2475
+ if (objectHasOwnProperty(cfg, 'ADD_URI_SAFE_ATTR') && arrayIsArray(cfg.ADD_URI_SAFE_ATTR)) {
2387
2476
  addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
2388
2477
  }
2389
- if (cfg.FORBID_CONTENTS) {
2478
+ if (objectHasOwnProperty(cfg, 'FORBID_CONTENTS') && arrayIsArray(cfg.FORBID_CONTENTS)) {
2390
2479
  if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
2391
2480
  FORBID_CONTENTS = clone(FORBID_CONTENTS);
2392
2481
  }
2393
2482
  addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
2394
2483
  }
2484
+ if (objectHasOwnProperty(cfg, 'ADD_FORBID_CONTENTS') && arrayIsArray(cfg.ADD_FORBID_CONTENTS)) {
2485
+ if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
2486
+ FORBID_CONTENTS = clone(FORBID_CONTENTS);
2487
+ }
2488
+ addToSet(FORBID_CONTENTS, cfg.ADD_FORBID_CONTENTS, transformCaseFunc);
2489
+ }
2395
2490
  /* Add #text in case KEEP_CONTENT is set to true */
2396
2491
  if (KEEP_CONTENT) {
2397
2492
  ALLOWED_TAGS['#text'] = true;
@@ -2678,6 +2773,11 @@ $\
2678
2773
  _forceRemove(currentNode);
2679
2774
  return true;
2680
2775
  }
2776
+ /* Remove risky CSS construction leading to mXSS */
2777
+ if (SAFE_FOR_XML && currentNode.namespaceURI === HTML_NAMESPACE && tagName === 'style' && _isNode(currentNode.firstElementChild)) {
2778
+ _forceRemove(currentNode);
2779
+ return true;
2780
+ }
2681
2781
  /* Remove any occurrence of processing instructions */
2682
2782
  if (currentNode.nodeType === NODE_TYPE.progressingInstruction) {
2683
2783
  _forceRemove(currentNode);
@@ -2689,7 +2789,7 @@ $\
2689
2789
  return true;
2690
2790
  }
2691
2791
  /* Remove element if anything forbids its presence */
2692
- if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
2792
+ if (FORBID_TAGS[tagName] || !(EXTRA_ELEMENT_HANDLING.tagCheck instanceof Function && EXTRA_ELEMENT_HANDLING.tagCheck(tagName)) && !ALLOWED_TAGS[tagName]) {
2693
2793
  /* Check if we have a custom element to handle */
2694
2794
  if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) {
2695
2795
  if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) {
@@ -2707,7 +2807,6 @@ $\
2707
2807
  const childCount = childNodes.length;
2708
2808
  for (let i = childCount - 1; i >= 0; --i) {
2709
2809
  const childClone = cloneNode(childNodes[i], true);
2710
- childClone.__removalCount = (currentNode.__removalCount || 0) + 1;
2711
2810
  parentNode.insertBefore(childClone, getNextSibling(currentNode));
2712
2811
  }
2713
2812
  }
@@ -2753,15 +2852,20 @@ $\
2753
2852
  */
2754
2853
  // eslint-disable-next-line complexity
2755
2854
  const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
2855
+ /* FORBID_ATTR must always win, even if ADD_ATTR predicate would allow it */
2856
+ if (FORBID_ATTR[lcName]) {
2857
+ return false;
2858
+ }
2756
2859
  /* Make sure attribute cannot clobber */
2757
2860
  if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
2758
2861
  return false;
2759
2862
  }
2863
+ const nameIsPermitted = ALLOWED_ATTR[lcName] || EXTRA_ELEMENT_HANDLING.attributeCheck instanceof Function && EXTRA_ELEMENT_HANDLING.attributeCheck(lcName, lcTag);
2760
2864
  /* Allow valid data-* attributes: At least one character after "-"
2761
2865
  (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
2762
2866
  XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
2763
2867
  We don't need to check the value; it's always URI safe. */
2764
- if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR, lcName)) ;else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR, lcName)) ;else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
2868
+ if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR, lcName)) ;else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR, lcName)) ;else if (!nameIsPermitted || FORBID_ATTR[lcName]) {
2765
2869
  if (
2766
2870
  // First condition does a very basic check if a) it's basically a valid custom element tagname AND
2767
2871
  // b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
@@ -2778,6 +2882,10 @@ $\
2778
2882
  } else ;
2779
2883
  return true;
2780
2884
  };
2885
+ /* Names the HTML spec reserves from valid-custom-element-name; these must
2886
+ * never be treated as basic custom elements even when a permissive
2887
+ * CUSTOM_ELEMENT_HANDLING.tagNameCheck is configured. */
2888
+ 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']);
2781
2889
  /**
2782
2890
  * _isBasicCustomElement
2783
2891
  * checks if at least one dash is included in tagName, and it's not the first char
@@ -2787,7 +2895,7 @@ $\
2787
2895
  * @returns Returns true if the tag name meets the basic criteria for a custom element, otherwise false.
2788
2896
  */
2789
2897
  const _isBasicCustomElement = function _isBasicCustomElement(tagName) {
2790
- return tagName !== 'annotation-xml' && stringMatch(tagName, CUSTOM_ELEMENT);
2898
+ return !RESERVED_CUSTOM_ELEMENT_NAMES[stringToLowerCase(tagName)] && regExpTest(CUSTOM_ELEMENT, tagName);
2791
2899
  };
2792
2900
  /**
2793
2901
  * _sanitizeAttributes
@@ -2838,14 +2946,16 @@ $\
2838
2946
  /* Full DOM Clobbering protection via namespace isolation,
2839
2947
  * Prefix id and name attributes with `user-content-`
2840
2948
  */
2841
- if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {
2949
+ if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name') && stringIndexOf(value, SANITIZE_NAMED_PROPS_PREFIX) !== 0) {
2842
2950
  // Remove the attribute with this value
2843
2951
  _removeAttribute(name, currentNode);
2844
2952
  // Prefix the value and later re-create the attribute with the sanitized value
2845
2953
  value = SANITIZE_NAMED_PROPS_PREFIX + value;
2846
2954
  }
2955
+ // Else: already prefixed, leave the attribute alone — the prefix is
2956
+ // itself the clobbering protection, and re-applying it is incorrect.
2847
2957
  /* Work around a security issue with comments inside attributes */
2848
- if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|title|textarea)/i, value)) {
2958
+ if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|script|title|xmp|textarea|noscript|iframe|noembed|noframes)/i, value)) {
2849
2959
  _removeAttribute(name, currentNode);
2850
2960
  continue;
2851
2961
  }
@@ -2924,7 +3034,7 @@ $\
2924
3034
  *
2925
3035
  * @param fragment to iterate over recursively
2926
3036
  */
2927
- const _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {
3037
+ const _sanitizeShadowDOM2 = function _sanitizeShadowDOM(fragment) {
2928
3038
  let shadowNode = null;
2929
3039
  const shadowIterator = _createNodeIterator(fragment);
2930
3040
  /* Execute a hook if present */
@@ -2938,7 +3048,7 @@ $\
2938
3048
  _sanitizeAttributes(shadowNode);
2939
3049
  /* Deep shadow DOM detected */
2940
3050
  if (shadowNode.content instanceof DocumentFragment) {
2941
- _sanitizeShadowDOM(shadowNode.content);
3051
+ _sanitizeShadowDOM2(shadowNode.content);
2942
3052
  }
2943
3053
  }
2944
3054
  /* Execute a hook if present */
@@ -2960,13 +3070,9 @@ $\
2960
3070
  }
2961
3071
  /* Stringify, in case dirty is an object */
2962
3072
  if (typeof dirty !== 'string' && !_isNode(dirty)) {
2963
- if (typeof dirty.toString === 'function') {
2964
- dirty = dirty.toString();
2965
- if (typeof dirty !== 'string') {
2966
- throw typeErrorCreate('dirty is not a string, aborting');
2967
- }
2968
- } else {
2969
- throw typeErrorCreate('toString is not a function');
3073
+ dirty = stringifyValue(dirty);
3074
+ if (typeof dirty !== 'string') {
3075
+ throw typeErrorCreate('dirty is not a string, aborting');
2970
3076
  }
2971
3077
  }
2972
3078
  /* Return dirty HTML if DOMPurify cannot run */
@@ -2985,8 +3091,9 @@ $\
2985
3091
  }
2986
3092
  if (IN_PLACE) {
2987
3093
  /* Do some early pre-sanitization to avoid unsafe root nodes */
2988
- if (dirty.nodeName) {
2989
- const tagName = transformCaseFunc(dirty.nodeName);
3094
+ const nn = dirty.nodeName;
3095
+ if (typeof nn === 'string') {
3096
+ const tagName = transformCaseFunc(nn);
2990
3097
  if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
2991
3098
  throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');
2992
3099
  }
@@ -3033,7 +3140,7 @@ $\
3033
3140
  _sanitizeAttributes(currentNode);
3034
3141
  /* Shadow DOM detected, sanitize it */
3035
3142
  if (currentNode.content instanceof DocumentFragment) {
3036
- _sanitizeShadowDOM(currentNode.content);
3143
+ _sanitizeShadowDOM2(currentNode.content);
3037
3144
  }
3038
3145
  }
3039
3146
  /* If we sanitized `dirty` in-place, return it. */
@@ -3042,6 +3149,14 @@ $\
3042
3149
  }
3043
3150
  /* Return sanitized string or DOM */
3044
3151
  if (RETURN_DOM) {
3152
+ if (SAFE_FOR_TEMPLATES) {
3153
+ body.normalize();
3154
+ let html = body.innerHTML;
3155
+ arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
3156
+ html = stringReplace(html, expr, ' ');
3157
+ });
3158
+ body.innerHTML = html;
3159
+ }
3045
3160
  if (RETURN_DOM_FRAGMENT) {
3046
3161
  returnNode = createDocumentFragment.call(body.ownerDocument);
3047
3162
  while (body.firstChild) {
@@ -6862,7 +6977,13 @@ $\
6862
6977
 
6863
6978
  class StringPiece extends Piece {
6864
6979
  static fromJSON(pieceJSON) {
6865
- return new this(pieceJSON.string, pieceJSON.attributes);
6980
+ const attributes = {
6981
+ ...pieceJSON.attributes
6982
+ };
6983
+ if (attributes.href && !purify.isValidAttribute("a", "href", attributes.href)) {
6984
+ delete attributes.href;
6985
+ }
6986
+ return new this(pieceJSON.string, attributes);
6866
6987
  }
6867
6988
  constructor(string) {
6868
6989
  super(...arguments);
@@ -1,3 +1,3 @@
1
1
  module Trix
2
- VERSION = "2.1.17"
2
+ VERSION = "2.1.19"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: action_text-trix
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.17
4
+ version: 2.1.19
5
5
  platform: ruby
6
6
  authors:
7
7
  - 37signals, LLC
@@ -55,7 +55,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
55
55
  - !ruby/object:Gem::Version
56
56
  version: '0'
57
57
  requirements: []
58
- rubygems_version: 4.0.3
58
+ rubygems_version: 4.0.6
59
59
  specification_version: 4
60
60
  summary: A rich text editor for everyday writing
61
61
  test_files: []