actiontext 7.2.2.1 → 8.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,5 @@
1
1
  /*
2
- Trix 2.1.10
2
+ Trix 2.1.1
3
3
  Copyright © 2024 37signals, LLC
4
4
  */
5
5
  (function (global, factory) {
@@ -9,7 +9,7 @@ Copyright © 2024 37signals, LLC
9
9
  })(this, (function () { 'use strict';
10
10
 
11
11
  var name = "trix";
12
- var version = "2.1.10";
12
+ var version = "2.1.1";
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";
@@ -78,9 +78,6 @@ Copyright © 2024 37signals, LLC
78
78
  dev: "web-dev-server --app-index index.html --root-dir dist --node-resolve --open",
79
79
  start: "yarn build-assets && concurrently --kill-others --names js,css,dev-server 'yarn watch' 'yarn build-css --watch' 'yarn dev'"
80
80
  };
81
- var dependencies = {
82
- dompurify: "^3.2.3"
83
- };
84
81
  var _package = {
85
82
  name: name,
86
83
  version: version,
@@ -97,8 +94,7 @@ Copyright © 2024 37signals, LLC
97
94
  homepage: homepage,
98
95
  devDependencies: devDependencies,
99
96
  resolutions: resolutions,
100
- scripts: scripts,
101
- dependencies: dependencies
97
+ scripts: scripts
102
98
  };
103
99
 
104
100
  const attachmentSelector = "[data-trix-attachment]";
@@ -279,8 +275,8 @@ Copyright © 2024 37signals, LLC
279
275
  return this;
280
276
  };
281
277
 
282
- const html$2 = document.documentElement;
283
- const match = html$2.matches;
278
+ const html = document.documentElement;
279
+ const match = html.matches;
284
280
  const handleEvent = function (eventName) {
285
281
  let {
286
282
  onElement,
@@ -290,7 +286,7 @@ Copyright © 2024 37signals, LLC
290
286
  preventDefault,
291
287
  times
292
288
  } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
293
- const element = onElement ? onElement : html$2;
289
+ const element = onElement ? onElement : html;
294
290
  const selector = matchingSelector;
295
291
  const useCapture = inPhase === "capturing";
296
292
  const handler = function (event) {
@@ -323,7 +319,7 @@ Copyright © 2024 37signals, LLC
323
319
  cancelable,
324
320
  attributes
325
321
  } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
326
- const element = onElement != null ? onElement : html$2;
322
+ const element = onElement != null ? onElement : html;
327
323
  bubbles = bubbles !== false;
328
324
  cancelable = cancelable !== false;
329
325
  const event = document.createEvent("Events");
@@ -680,11 +676,11 @@ Copyright © 2024 37signals, LLC
680
676
  var _object;
681
677
  subject = (_object = object) === null || _object === void 0 ? void 0 : _object[name];
682
678
  if (subject) {
683
- return apply$1.call(subject, object, arguments);
679
+ return apply.call(subject, object, arguments);
684
680
  }
685
681
  } else {
686
682
  subject = object[name];
687
- return apply$1.call(subject, object, arguments);
683
+ return apply.call(subject, object, arguments);
688
684
  }
689
685
  };
690
686
  }
@@ -708,7 +704,7 @@ Copyright © 2024 37signals, LLC
708
704
  return args;
709
705
  };
710
706
  const {
711
- apply: apply$1
707
+ apply
712
708
  } = Function.prototype;
713
709
  const proxyMethodExpressionPattern = new RegExp("\
714
710
  ^\
@@ -1041,11 +1037,7 @@ $\
1041
1037
  const getCSPNonce = function () {
1042
1038
  const element = getMetaElement("trix-csp-nonce") || getMetaElement("csp-nonce");
1043
1039
  if (element) {
1044
- const {
1045
- nonce,
1046
- content
1047
- } = element;
1048
- return nonce == "" ? content : nonce;
1040
+ return element.getAttribute("content");
1049
1041
  }
1050
1042
  };
1051
1043
  const getMetaElement = name => document.head.querySelector("meta[name=".concat(name, "]"));
@@ -1067,12 +1059,6 @@ $\
1067
1059
  return text === null || text === void 0 ? void 0 : text.length;
1068
1060
  }
1069
1061
  };
1070
- const dataTransferIsMsOfficePaste = _ref => {
1071
- let {
1072
- dataTransfer
1073
- } = _ref;
1074
- return dataTransfer.types.includes("Files") && dataTransfer.types.includes("text/html") && dataTransfer.getData("text/html").includes("urn:schemas-microsoft-com:office:office");
1075
- };
1076
1062
  const dataTransferIsWritable = function (dataTransfer) {
1077
1063
  if (!(dataTransfer !== null && dataTransfer !== void 0 && dataTransfer.setData)) return false;
1078
1064
  for (const key in testTransferData) {
@@ -1093,19 +1079,6 @@ $\
1093
1079
  return event => event.ctrlKey;
1094
1080
  }
1095
1081
  }();
1096
- function shouldRenderInmmediatelyToDealWithIOSDictation(inputEvent) {
1097
- if (/iPhone|iPad/.test(navigator.userAgent)) {
1098
- // Handle garbled content and duplicated newlines when using dictation on iOS 18+. Upon dictation completion, iOS sends
1099
- // the list of insertText / insertParagraph events in a quick sequence. If we don't render
1100
- // the editor synchronously, the internal range fails to update and results in garbled content or duplicated newlines.
1101
- //
1102
- // This workaround is necessary because iOS doesn't send composing events as expected while dictating:
1103
- // https://bugs.webkit.org/show_bug.cgi?id=261764
1104
- return !inputEvent.inputType || inputEvent.inputType === "insertParagraph";
1105
- } else {
1106
- return false;
1107
- }
1108
- }
1109
1082
 
1110
1083
  const defer = fn => setTimeout(fn, 1);
1111
1084
 
@@ -1708,1475 +1681,31 @@ $\
1708
1681
  constructor() {
1709
1682
  super(...arguments);
1710
1683
  this.objectGroup = this.object;
1711
- this.viewClass = this.options.viewClass;
1712
- delete this.options.viewClass;
1713
- }
1714
- getChildViews() {
1715
- if (!this.childViews.length) {
1716
- Array.from(this.objectGroup.getObjects()).forEach(object => {
1717
- this.findOrCreateCachedChildView(this.viewClass, object, this.options);
1718
- });
1719
- }
1720
- return this.childViews;
1721
- }
1722
- createNodes() {
1723
- const element = this.createContainerElement();
1724
- this.getChildViews().forEach(view => {
1725
- Array.from(view.getNodes()).forEach(node => {
1726
- element.appendChild(node);
1727
- });
1728
- });
1729
- return [element];
1730
- }
1731
- createContainerElement() {
1732
- let depth = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.objectGroup.getDepth();
1733
- return this.getChildViews()[0].createContainerElement(depth);
1734
- }
1735
- }
1736
-
1737
- /*! @license DOMPurify 3.2.3 | (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.3/LICENSE */
1738
-
1739
- const {
1740
- entries,
1741
- setPrototypeOf,
1742
- isFrozen,
1743
- getPrototypeOf,
1744
- getOwnPropertyDescriptor
1745
- } = Object;
1746
- let {
1747
- freeze,
1748
- seal,
1749
- create
1750
- } = Object; // eslint-disable-line import/no-mutable-exports
1751
- let {
1752
- apply,
1753
- construct
1754
- } = typeof Reflect !== 'undefined' && Reflect;
1755
- if (!freeze) {
1756
- freeze = function freeze(x) {
1757
- return x;
1758
- };
1759
- }
1760
- if (!seal) {
1761
- seal = function seal(x) {
1762
- return x;
1763
- };
1764
- }
1765
- if (!apply) {
1766
- apply = function apply(fun, thisValue, args) {
1767
- return fun.apply(thisValue, args);
1768
- };
1769
- }
1770
- if (!construct) {
1771
- construct = function construct(Func, args) {
1772
- return new Func(...args);
1773
- };
1774
- }
1775
- const arrayForEach = unapply(Array.prototype.forEach);
1776
- const arrayPop = unapply(Array.prototype.pop);
1777
- const arrayPush = unapply(Array.prototype.push);
1778
- const stringToLowerCase = unapply(String.prototype.toLowerCase);
1779
- const stringToString = unapply(String.prototype.toString);
1780
- const stringMatch = unapply(String.prototype.match);
1781
- const stringReplace = unapply(String.prototype.replace);
1782
- const stringIndexOf = unapply(String.prototype.indexOf);
1783
- const stringTrim = unapply(String.prototype.trim);
1784
- const objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);
1785
- const regExpTest = unapply(RegExp.prototype.test);
1786
- const typeErrorCreate = unconstruct(TypeError);
1787
- /**
1788
- * Creates a new function that calls the given function with a specified thisArg and arguments.
1789
- *
1790
- * @param func - The function to be wrapped and called.
1791
- * @returns A new function that calls the given function with a specified thisArg and arguments.
1792
- */
1793
- function unapply(func) {
1794
- return function (thisArg) {
1795
- for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
1796
- args[_key - 1] = arguments[_key];
1797
- }
1798
- return apply(func, thisArg, args);
1799
- };
1800
- }
1801
- /**
1802
- * Creates a new function that constructs an instance of the given constructor function with the provided arguments.
1803
- *
1804
- * @param func - The constructor function to be wrapped and called.
1805
- * @returns A new function that constructs an instance of the given constructor function with the provided arguments.
1806
- */
1807
- function unconstruct(func) {
1808
- return function () {
1809
- for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
1810
- args[_key2] = arguments[_key2];
1811
- }
1812
- return construct(func, args);
1813
- };
1814
- }
1815
- /**
1816
- * Add properties to a lookup table
1817
- *
1818
- * @param set - The set to which elements will be added.
1819
- * @param array - The array containing elements to be added to the set.
1820
- * @param transformCaseFunc - An optional function to transform the case of each element before adding to the set.
1821
- * @returns The modified set with added elements.
1822
- */
1823
- function addToSet(set, array) {
1824
- let transformCaseFunc = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : stringToLowerCase;
1825
- if (setPrototypeOf) {
1826
- // Make 'in' and truthy checks like Boolean(set.constructor)
1827
- // independent of any properties defined on Object.prototype.
1828
- // Prevent prototype setters from intercepting set as a this value.
1829
- setPrototypeOf(set, null);
1830
- }
1831
- let l = array.length;
1832
- while (l--) {
1833
- let element = array[l];
1834
- if (typeof element === 'string') {
1835
- const lcElement = transformCaseFunc(element);
1836
- if (lcElement !== element) {
1837
- // Config presets (e.g. tags.js, attrs.js) are immutable.
1838
- if (!isFrozen(array)) {
1839
- array[l] = lcElement;
1840
- }
1841
- element = lcElement;
1842
- }
1843
- }
1844
- set[element] = true;
1845
- }
1846
- return set;
1847
- }
1848
- /**
1849
- * Clean up an array to harden against CSPP
1850
- *
1851
- * @param array - The array to be cleaned.
1852
- * @returns The cleaned version of the array
1853
- */
1854
- function cleanArray(array) {
1855
- for (let index = 0; index < array.length; index++) {
1856
- const isPropertyExist = objectHasOwnProperty(array, index);
1857
- if (!isPropertyExist) {
1858
- array[index] = null;
1859
- }
1860
- }
1861
- return array;
1862
- }
1863
- /**
1864
- * Shallow clone an object
1865
- *
1866
- * @param object - The object to be cloned.
1867
- * @returns A new object that copies the original.
1868
- */
1869
- function clone(object) {
1870
- const newObject = create(null);
1871
- for (const [property, value] of entries(object)) {
1872
- const isPropertyExist = objectHasOwnProperty(object, property);
1873
- if (isPropertyExist) {
1874
- if (Array.isArray(value)) {
1875
- newObject[property] = cleanArray(value);
1876
- } else if (value && typeof value === 'object' && value.constructor === Object) {
1877
- newObject[property] = clone(value);
1878
- } else {
1879
- newObject[property] = value;
1880
- }
1881
- }
1882
- }
1883
- return newObject;
1884
- }
1885
- /**
1886
- * This method automatically checks if the prop is function or getter and behaves accordingly.
1887
- *
1888
- * @param object - The object to look up the getter function in its prototype chain.
1889
- * @param prop - The property name for which to find the getter function.
1890
- * @returns The getter function found in the prototype chain or a fallback function.
1891
- */
1892
- function lookupGetter(object, prop) {
1893
- while (object !== null) {
1894
- const desc = getOwnPropertyDescriptor(object, prop);
1895
- if (desc) {
1896
- if (desc.get) {
1897
- return unapply(desc.get);
1898
- }
1899
- if (typeof desc.value === 'function') {
1900
- return unapply(desc.value);
1901
- }
1902
- }
1903
- object = getPrototypeOf(object);
1904
- }
1905
- function fallbackValue() {
1906
- return null;
1907
- }
1908
- return fallbackValue;
1909
- }
1910
- 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', 'section', 'select', 'shadow', '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']);
1911
- const svg$1 = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'view', 'vkern']);
1912
- 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']);
1913
- // List of SVG elements that are disallowed by default.
1914
- // We still need to know them so that we can do namespace
1915
- // checks properly in case one wants to add them to
1916
- // allow-list.
1917
- const svgDisallowed = freeze(['animate', 'color-profile', 'cursor', 'discard', 'font-face', 'font-face-format', 'font-face-name', 'font-face-src', 'font-face-uri', 'foreignobject', 'hatch', 'hatchpath', 'mesh', 'meshgradient', 'meshpatch', 'meshrow', 'missing-glyph', 'script', 'set', 'solidcolor', 'unknown', 'use']);
1918
- const mathMl$1 = freeze(['math', 'menclose', 'merror', 'mfenced', 'mfrac', 'mglyph', 'mi', 'mlabeledtr', 'mmultiscripts', 'mn', 'mo', 'mover', 'mpadded', 'mphantom', 'mroot', 'mrow', 'ms', 'mspace', 'msqrt', 'mstyle', 'msub', 'msup', 'msubsup', 'mtable', 'mtd', 'mtext', 'mtr', 'munder', 'munderover', 'mprescripts']);
1919
- // Similarly to SVG, we want to know all MathML elements,
1920
- // even those that we disallow by default.
1921
- const mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);
1922
- const text = freeze(['#text']);
1923
- 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', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', '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', 'pattern', 'placeholder', 'playsinline', 'popover', 'popovertarget', 'popovertargetaction', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'wrap', 'xmlns', 'slot']);
1924
- 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']);
1925
- 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']);
1926
- const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
1927
-
1928
- // eslint-disable-next-line unicorn/better-regex
1929
- const MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode
1930
- const ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm);
1931
- const TMPLIT_EXPR = seal(/\$\{[\w\W]*}/gm); // eslint-disable-line unicorn/better-regex
1932
- const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]+$/); // eslint-disable-line no-useless-escape
1933
- const ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
1934
- const IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape
1935
- );
1936
-
1937
- const IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
1938
- const ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g // eslint-disable-line no-control-regex
1939
- );
1940
-
1941
- const DOCTYPE_NAME = seal(/^html$/i);
1942
- const CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i);
1943
- var EXPRESSIONS = /*#__PURE__*/Object.freeze({
1944
- __proto__: null,
1945
- ARIA_ATTR: ARIA_ATTR,
1946
- ATTR_WHITESPACE: ATTR_WHITESPACE,
1947
- CUSTOM_ELEMENT: CUSTOM_ELEMENT,
1948
- DATA_ATTR: DATA_ATTR,
1949
- DOCTYPE_NAME: DOCTYPE_NAME,
1950
- ERB_EXPR: ERB_EXPR,
1951
- IS_ALLOWED_URI: IS_ALLOWED_URI,
1952
- IS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA,
1953
- MUSTACHE_EXPR: MUSTACHE_EXPR,
1954
- TMPLIT_EXPR: TMPLIT_EXPR
1955
- });
1956
-
1957
- /* eslint-disable @typescript-eslint/indent */
1958
- // https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
1959
- const NODE_TYPE = {
1960
- element: 1,
1961
- attribute: 2,
1962
- text: 3,
1963
- cdataSection: 4,
1964
- entityReference: 5,
1965
- // Deprecated
1966
- entityNode: 6,
1967
- // Deprecated
1968
- progressingInstruction: 7,
1969
- comment: 8,
1970
- document: 9,
1971
- documentType: 10,
1972
- documentFragment: 11,
1973
- notation: 12 // Deprecated
1974
- };
1975
-
1976
- const getGlobal = function getGlobal() {
1977
- return typeof window === 'undefined' ? null : window;
1978
- };
1979
- /**
1980
- * Creates a no-op policy for internal use only.
1981
- * Don't export this function outside this module!
1982
- * @param trustedTypes The policy factory.
1983
- * @param purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix).
1984
- * @return The policy created (or null, if Trusted Types
1985
- * are not supported or creating the policy failed).
1986
- */
1987
- const _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, purifyHostElement) {
1988
- if (typeof trustedTypes !== 'object' || typeof trustedTypes.createPolicy !== 'function') {
1989
- return null;
1990
- }
1991
- // Allow the callers to control the unique policy name
1992
- // by adding a data-tt-policy-suffix to the script element with the DOMPurify.
1993
- // Policy creation with duplicate names throws in Trusted Types.
1994
- let suffix = null;
1995
- const ATTR_NAME = 'data-tt-policy-suffix';
1996
- if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) {
1997
- suffix = purifyHostElement.getAttribute(ATTR_NAME);
1998
- }
1999
- const policyName = 'dompurify' + (suffix ? '#' + suffix : '');
2000
- try {
2001
- return trustedTypes.createPolicy(policyName, {
2002
- createHTML(html) {
2003
- return html;
2004
- },
2005
- createScriptURL(scriptUrl) {
2006
- return scriptUrl;
2007
- }
2008
- });
2009
- } catch (_) {
2010
- // Policy creation failed (most likely another DOMPurify script has
2011
- // already run). Skip creating the policy, as this will only cause errors
2012
- // if TT are enforced.
2013
- console.warn('TrustedTypes policy ' + policyName + ' could not be created.');
2014
- return null;
2015
- }
2016
- };
2017
- const _createHooksMap = function _createHooksMap() {
2018
- return {
2019
- afterSanitizeAttributes: [],
2020
- afterSanitizeElements: [],
2021
- afterSanitizeShadowDOM: [],
2022
- beforeSanitizeAttributes: [],
2023
- beforeSanitizeElements: [],
2024
- beforeSanitizeShadowDOM: [],
2025
- uponSanitizeAttribute: [],
2026
- uponSanitizeElement: [],
2027
- uponSanitizeShadowNode: []
2028
- };
2029
- };
2030
- function createDOMPurify() {
2031
- let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
2032
- const DOMPurify = root => createDOMPurify(root);
2033
- DOMPurify.version = '3.2.3';
2034
- DOMPurify.removed = [];
2035
- if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document) {
2036
- // Not running in a browser, provide a factory function
2037
- // so that you can pass your own Window
2038
- DOMPurify.isSupported = false;
2039
- return DOMPurify;
2040
- }
2041
- let {
2042
- document
2043
- } = window;
2044
- const originalDocument = document;
2045
- const currentScript = originalDocument.currentScript;
2046
- const {
2047
- DocumentFragment,
2048
- HTMLTemplateElement,
2049
- Node,
2050
- Element,
2051
- NodeFilter,
2052
- NamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap,
2053
- HTMLFormElement,
2054
- DOMParser,
2055
- trustedTypes
2056
- } = window;
2057
- const ElementPrototype = Element.prototype;
2058
- const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');
2059
- const remove = lookupGetter(ElementPrototype, 'remove');
2060
- const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');
2061
- const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');
2062
- const getParentNode = lookupGetter(ElementPrototype, 'parentNode');
2063
- // As per issue #47, the web-components registry is inherited by a
2064
- // new document created via createHTMLDocument. As per the spec
2065
- // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)
2066
- // a new empty registry is used when creating a template contents owner
2067
- // document, so we use that as our parent document to ensure nothing
2068
- // is inherited.
2069
- if (typeof HTMLTemplateElement === 'function') {
2070
- const template = document.createElement('template');
2071
- if (template.content && template.content.ownerDocument) {
2072
- document = template.content.ownerDocument;
2073
- }
2074
- }
2075
- let trustedTypesPolicy;
2076
- let emptyHTML = '';
2077
- const {
2078
- implementation,
2079
- createNodeIterator,
2080
- createDocumentFragment,
2081
- getElementsByTagName
2082
- } = document;
2083
- const {
2084
- importNode
2085
- } = originalDocument;
2086
- let hooks = _createHooksMap();
2087
- /**
2088
- * Expose whether this browser supports running the full DOMPurify.
2089
- */
2090
- DOMPurify.isSupported = typeof entries === 'function' && typeof getParentNode === 'function' && implementation && implementation.createHTMLDocument !== undefined;
2091
- const {
2092
- MUSTACHE_EXPR,
2093
- ERB_EXPR,
2094
- TMPLIT_EXPR,
2095
- DATA_ATTR,
2096
- ARIA_ATTR,
2097
- IS_SCRIPT_OR_DATA,
2098
- ATTR_WHITESPACE,
2099
- CUSTOM_ELEMENT
2100
- } = EXPRESSIONS;
2101
- let {
2102
- IS_ALLOWED_URI: IS_ALLOWED_URI$1
2103
- } = EXPRESSIONS;
2104
- /**
2105
- * We consider the elements and attributes below to be safe. Ideally
2106
- * don't add any new ones but feel free to remove unwanted ones.
2107
- */
2108
- /* allowed element names */
2109
- let ALLOWED_TAGS = null;
2110
- const DEFAULT_ALLOWED_TAGS = addToSet({}, [...html$1, ...svg$1, ...svgFilters, ...mathMl$1, ...text]);
2111
- /* Allowed attribute names */
2112
- let ALLOWED_ATTR = null;
2113
- const DEFAULT_ALLOWED_ATTR = addToSet({}, [...html, ...svg, ...mathMl, ...xml]);
2114
- /*
2115
- * Configure how DOMPurify should handle custom elements and their attributes as well as customized built-in elements.
2116
- * @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)
2117
- * @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list)
2118
- * @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.
2119
- */
2120
- let CUSTOM_ELEMENT_HANDLING = Object.seal(create(null, {
2121
- tagNameCheck: {
2122
- writable: true,
2123
- configurable: false,
2124
- enumerable: true,
2125
- value: null
2126
- },
2127
- attributeNameCheck: {
2128
- writable: true,
2129
- configurable: false,
2130
- enumerable: true,
2131
- value: null
2132
- },
2133
- allowCustomizedBuiltInElements: {
2134
- writable: true,
2135
- configurable: false,
2136
- enumerable: true,
2137
- value: false
2138
- }
2139
- }));
2140
- /* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */
2141
- let FORBID_TAGS = null;
2142
- /* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */
2143
- let FORBID_ATTR = null;
2144
- /* Decide if ARIA attributes are okay */
2145
- let ALLOW_ARIA_ATTR = true;
2146
- /* Decide if custom data attributes are okay */
2147
- let ALLOW_DATA_ATTR = true;
2148
- /* Decide if unknown protocols are okay */
2149
- let ALLOW_UNKNOWN_PROTOCOLS = false;
2150
- /* Decide if self-closing tags in attributes are allowed.
2151
- * Usually removed due to a mXSS issue in jQuery 3.0 */
2152
- let ALLOW_SELF_CLOSE_IN_ATTR = true;
2153
- /* Output should be safe for common template engines.
2154
- * This means, DOMPurify removes data attributes, mustaches and ERB
2155
- */
2156
- let SAFE_FOR_TEMPLATES = false;
2157
- /* Output should be safe even for XML used within HTML and alike.
2158
- * This means, DOMPurify removes comments when containing risky content.
2159
- */
2160
- let SAFE_FOR_XML = true;
2161
- /* Decide if document with <html>... should be returned */
2162
- let WHOLE_DOCUMENT = false;
2163
- /* Track whether config is already set on this instance of DOMPurify. */
2164
- let SET_CONFIG = false;
2165
- /* Decide if all elements (e.g. style, script) must be children of
2166
- * document.body. By default, browsers might move them to document.head */
2167
- let FORCE_BODY = false;
2168
- /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html
2169
- * string (or a TrustedHTML object if Trusted Types are supported).
2170
- * If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead
2171
- */
2172
- let RETURN_DOM = false;
2173
- /* Decide if a DOM `DocumentFragment` should be returned, instead of a html
2174
- * string (or a TrustedHTML object if Trusted Types are supported) */
2175
- let RETURN_DOM_FRAGMENT = false;
2176
- /* Try to return a Trusted Type object instead of a string, return a string in
2177
- * case Trusted Types are not supported */
2178
- let RETURN_TRUSTED_TYPE = false;
2179
- /* Output should be free from DOM clobbering attacks?
2180
- * This sanitizes markups named with colliding, clobberable built-in DOM APIs.
2181
- */
2182
- let SANITIZE_DOM = true;
2183
- /* Achieve full DOM Clobbering protection by isolating the namespace of named
2184
- * properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules.
2185
- *
2186
- * HTML/DOM spec rules that enable DOM Clobbering:
2187
- * - Named Access on Window (§7.3.3)
2188
- * - DOM Tree Accessors (§3.1.5)
2189
- * - Form Element Parent-Child Relations (§4.10.3)
2190
- * - Iframe srcdoc / Nested WindowProxies (§4.8.5)
2191
- * - HTMLCollection (§4.2.10.2)
2192
- *
2193
- * Namespace isolation is implemented by prefixing `id` and `name` attributes
2194
- * with a constant string, i.e., `user-content-`
2195
- */
2196
- let SANITIZE_NAMED_PROPS = false;
2197
- const SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';
2198
- /* Keep element content when removing element? */
2199
- let KEEP_CONTENT = true;
2200
- /* If a `Node` is passed to sanitize(), then performs sanitization in-place instead
2201
- * of importing it into a new Document and returning a sanitized copy */
2202
- let IN_PLACE = false;
2203
- /* Allow usage of profiles like html, svg and mathMl */
2204
- let USE_PROFILES = {};
2205
- /* Tags to ignore content of when KEEP_CONTENT is true */
2206
- let FORBID_CONTENTS = null;
2207
- const DEFAULT_FORBID_CONTENTS = addToSet({}, ['annotation-xml', 'audio', 'colgroup', 'desc', 'foreignobject', 'head', 'iframe', 'math', 'mi', 'mn', 'mo', 'ms', 'mtext', 'noembed', 'noframes', 'noscript', 'plaintext', 'script', 'style', 'svg', 'template', 'thead', 'title', 'video', 'xmp']);
2208
- /* Tags that are safe for data: URIs */
2209
- let DATA_URI_TAGS = null;
2210
- const DEFAULT_DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image', 'track']);
2211
- /* Attributes safe for values like "javascript:" */
2212
- let URI_SAFE_ATTRIBUTES = null;
2213
- const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'role', 'summary', 'title', 'value', 'style', 'xmlns']);
2214
- const MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
2215
- const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
2216
- const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
2217
- /* Document namespace */
2218
- let NAMESPACE = HTML_NAMESPACE;
2219
- let IS_EMPTY_INPUT = false;
2220
- /* Allowed XHTML+XML namespaces */
2221
- let ALLOWED_NAMESPACES = null;
2222
- const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE], stringToString);
2223
- let MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);
2224
- let HTML_INTEGRATION_POINTS = addToSet({}, ['annotation-xml']);
2225
- // Certain elements are allowed in both SVG and HTML
2226
- // namespace. We need to specify them explicitly
2227
- // so that they don't get erroneously deleted from
2228
- // HTML namespace.
2229
- const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ['title', 'style', 'font', 'a', 'script']);
2230
- /* Parsing of strict XHTML documents */
2231
- let PARSER_MEDIA_TYPE = null;
2232
- const SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html'];
2233
- const DEFAULT_PARSER_MEDIA_TYPE = 'text/html';
2234
- let transformCaseFunc = null;
2235
- /* Keep a reference to config to pass to hooks */
2236
- let CONFIG = null;
2237
- /* Ideally, do not touch anything below this line */
2238
- /* ______________________________________________ */
2239
- const formElement = document.createElement('form');
2240
- const isRegexOrFunction = function isRegexOrFunction(testValue) {
2241
- return testValue instanceof RegExp || testValue instanceof Function;
2242
- };
2243
- /**
2244
- * _parseConfig
2245
- *
2246
- * @param cfg optional config literal
2247
- */
2248
- // eslint-disable-next-line complexity
2249
- const _parseConfig = function _parseConfig() {
2250
- let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
2251
- if (CONFIG && CONFIG === cfg) {
2252
- return;
2253
- }
2254
- /* Shield configuration object from tampering */
2255
- if (!cfg || typeof cfg !== 'object') {
2256
- cfg = {};
2257
- }
2258
- /* Shield configuration object from prototype pollution */
2259
- cfg = clone(cfg);
2260
- PARSER_MEDIA_TYPE =
2261
- // eslint-disable-next-line unicorn/prefer-includes
2262
- SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? DEFAULT_PARSER_MEDIA_TYPE : cfg.PARSER_MEDIA_TYPE;
2263
- // HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
2264
- transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase;
2265
- /* Set configuration parameters */
2266
- ALLOWED_TAGS = objectHasOwnProperty(cfg, 'ALLOWED_TAGS') ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;
2267
- ALLOWED_ATTR = objectHasOwnProperty(cfg, 'ALLOWED_ATTR') ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;
2268
- ALLOWED_NAMESPACES = objectHasOwnProperty(cfg, 'ALLOWED_NAMESPACES') ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES;
2269
- 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;
2270
- 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;
2271
- FORBID_CONTENTS = objectHasOwnProperty(cfg, 'FORBID_CONTENTS') ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;
2272
- FORBID_TAGS = objectHasOwnProperty(cfg, 'FORBID_TAGS') ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : {};
2273
- FORBID_ATTR = objectHasOwnProperty(cfg, 'FORBID_ATTR') ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : {};
2274
- USE_PROFILES = objectHasOwnProperty(cfg, 'USE_PROFILES') ? cfg.USE_PROFILES : false;
2275
- ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true
2276
- ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true
2277
- ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false
2278
- ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false; // Default true
2279
- SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false
2280
- SAFE_FOR_XML = cfg.SAFE_FOR_XML !== false; // Default true
2281
- WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false
2282
- RETURN_DOM = cfg.RETURN_DOM || false; // Default false
2283
- RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false
2284
- RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false
2285
- FORCE_BODY = cfg.FORCE_BODY || false; // Default false
2286
- SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true
2287
- SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false
2288
- KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
2289
- IN_PLACE = cfg.IN_PLACE || false; // Default false
2290
- IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI;
2291
- NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
2292
- MATHML_TEXT_INTEGRATION_POINTS = cfg.MATHML_TEXT_INTEGRATION_POINTS || MATHML_TEXT_INTEGRATION_POINTS;
2293
- HTML_INTEGRATION_POINTS = cfg.HTML_INTEGRATION_POINTS || HTML_INTEGRATION_POINTS;
2294
- CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};
2295
- if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {
2296
- CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;
2297
- }
2298
- if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) {
2299
- CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;
2300
- }
2301
- if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === 'boolean') {
2302
- CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;
2303
- }
2304
- if (SAFE_FOR_TEMPLATES) {
2305
- ALLOW_DATA_ATTR = false;
2306
- }
2307
- if (RETURN_DOM_FRAGMENT) {
2308
- RETURN_DOM = true;
2309
- }
2310
- /* Parse profile info */
2311
- if (USE_PROFILES) {
2312
- ALLOWED_TAGS = addToSet({}, text);
2313
- ALLOWED_ATTR = [];
2314
- if (USE_PROFILES.html === true) {
2315
- addToSet(ALLOWED_TAGS, html$1);
2316
- addToSet(ALLOWED_ATTR, html);
2317
- }
2318
- if (USE_PROFILES.svg === true) {
2319
- addToSet(ALLOWED_TAGS, svg$1);
2320
- addToSet(ALLOWED_ATTR, svg);
2321
- addToSet(ALLOWED_ATTR, xml);
2322
- }
2323
- if (USE_PROFILES.svgFilters === true) {
2324
- addToSet(ALLOWED_TAGS, svgFilters);
2325
- addToSet(ALLOWED_ATTR, svg);
2326
- addToSet(ALLOWED_ATTR, xml);
2327
- }
2328
- if (USE_PROFILES.mathMl === true) {
2329
- addToSet(ALLOWED_TAGS, mathMl$1);
2330
- addToSet(ALLOWED_ATTR, mathMl);
2331
- addToSet(ALLOWED_ATTR, xml);
2332
- }
2333
- }
2334
- /* Merge configuration parameters */
2335
- if (cfg.ADD_TAGS) {
2336
- if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
2337
- ALLOWED_TAGS = clone(ALLOWED_TAGS);
2338
- }
2339
- addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
2340
- }
2341
- if (cfg.ADD_ATTR) {
2342
- if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
2343
- ALLOWED_ATTR = clone(ALLOWED_ATTR);
2344
- }
2345
- addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
2346
- }
2347
- if (cfg.ADD_URI_SAFE_ATTR) {
2348
- addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
2349
- }
2350
- if (cfg.FORBID_CONTENTS) {
2351
- if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
2352
- FORBID_CONTENTS = clone(FORBID_CONTENTS);
2353
- }
2354
- addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
2355
- }
2356
- /* Add #text in case KEEP_CONTENT is set to true */
2357
- if (KEEP_CONTENT) {
2358
- ALLOWED_TAGS['#text'] = true;
2359
- }
2360
- /* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */
2361
- if (WHOLE_DOCUMENT) {
2362
- addToSet(ALLOWED_TAGS, ['html', 'head', 'body']);
2363
- }
2364
- /* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */
2365
- if (ALLOWED_TAGS.table) {
2366
- addToSet(ALLOWED_TAGS, ['tbody']);
2367
- delete FORBID_TAGS.tbody;
2368
- }
2369
- if (cfg.TRUSTED_TYPES_POLICY) {
2370
- if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== 'function') {
2371
- throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');
2372
- }
2373
- if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== 'function') {
2374
- throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');
2375
- }
2376
- // Overwrite existing TrustedTypes policy.
2377
- trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY;
2378
- // Sign local variables required by `sanitize`.
2379
- emptyHTML = trustedTypesPolicy.createHTML('');
2380
- } else {
2381
- // Uninitialized policy, attempt to initialize the internal dompurify policy.
2382
- if (trustedTypesPolicy === undefined) {
2383
- trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript);
2384
- }
2385
- // If creating the internal policy succeeded sign internal variables.
2386
- if (trustedTypesPolicy !== null && typeof emptyHTML === 'string') {
2387
- emptyHTML = trustedTypesPolicy.createHTML('');
2388
- }
2389
- }
2390
- // Prevent further manipulation of configuration.
2391
- // Not available in IE8, Safari 5, etc.
2392
- if (freeze) {
2393
- freeze(cfg);
2394
- }
2395
- CONFIG = cfg;
2396
- };
2397
- /* Keep track of all possible SVG and MathML tags
2398
- * so that we can perform the namespace checks
2399
- * correctly. */
2400
- const ALL_SVG_TAGS = addToSet({}, [...svg$1, ...svgFilters, ...svgDisallowed]);
2401
- const ALL_MATHML_TAGS = addToSet({}, [...mathMl$1, ...mathMlDisallowed]);
2402
- /**
2403
- * @param element a DOM element whose namespace is being checked
2404
- * @returns Return false if the element has a
2405
- * namespace that a spec-compliant parser would never
2406
- * return. Return true otherwise.
2407
- */
2408
- const _checkValidNamespace = function _checkValidNamespace(element) {
2409
- let parent = getParentNode(element);
2410
- // In JSDOM, if we're inside shadow DOM, then parentNode
2411
- // can be null. We just simulate parent in this case.
2412
- if (!parent || !parent.tagName) {
2413
- parent = {
2414
- namespaceURI: NAMESPACE,
2415
- tagName: 'template'
2416
- };
2417
- }
2418
- const tagName = stringToLowerCase(element.tagName);
2419
- const parentTagName = stringToLowerCase(parent.tagName);
2420
- if (!ALLOWED_NAMESPACES[element.namespaceURI]) {
2421
- return false;
2422
- }
2423
- if (element.namespaceURI === SVG_NAMESPACE) {
2424
- // The only way to switch from HTML namespace to SVG
2425
- // is via <svg>. If it happens via any other tag, then
2426
- // it should be killed.
2427
- if (parent.namespaceURI === HTML_NAMESPACE) {
2428
- return tagName === 'svg';
2429
- }
2430
- // The only way to switch from MathML to SVG is via`
2431
- // svg if parent is either <annotation-xml> or MathML
2432
- // text integration points.
2433
- if (parent.namespaceURI === MATHML_NAMESPACE) {
2434
- return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);
2435
- }
2436
- // We only allow elements that are defined in SVG
2437
- // spec. All others are disallowed in SVG namespace.
2438
- return Boolean(ALL_SVG_TAGS[tagName]);
2439
- }
2440
- if (element.namespaceURI === MATHML_NAMESPACE) {
2441
- // The only way to switch from HTML namespace to MathML
2442
- // is via <math>. If it happens via any other tag, then
2443
- // it should be killed.
2444
- if (parent.namespaceURI === HTML_NAMESPACE) {
2445
- return tagName === 'math';
2446
- }
2447
- // The only way to switch from SVG to MathML is via
2448
- // <math> and HTML integration points
2449
- if (parent.namespaceURI === SVG_NAMESPACE) {
2450
- return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];
2451
- }
2452
- // We only allow elements that are defined in MathML
2453
- // spec. All others are disallowed in MathML namespace.
2454
- return Boolean(ALL_MATHML_TAGS[tagName]);
2455
- }
2456
- if (element.namespaceURI === HTML_NAMESPACE) {
2457
- // The only way to switch from SVG to HTML is via
2458
- // HTML integration points, and from MathML to HTML
2459
- // is via MathML text integration points
2460
- if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) {
2461
- return false;
2462
- }
2463
- if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {
2464
- return false;
2465
- }
2466
- // We disallow tags that are specific for MathML
2467
- // or SVG and should never appear in HTML namespace
2468
- return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);
2469
- }
2470
- // For XHTML and XML documents that support custom namespaces
2471
- if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && ALLOWED_NAMESPACES[element.namespaceURI]) {
2472
- return true;
2473
- }
2474
- // The code should never reach this place (this means
2475
- // that the element somehow got namespace that is not
2476
- // HTML, SVG, MathML or allowed via ALLOWED_NAMESPACES).
2477
- // Return false just in case.
2478
- return false;
2479
- };
2480
- /**
2481
- * _forceRemove
2482
- *
2483
- * @param node a DOM node
2484
- */
2485
- const _forceRemove = function _forceRemove(node) {
2486
- arrayPush(DOMPurify.removed, {
2487
- element: node
2488
- });
2489
- try {
2490
- // eslint-disable-next-line unicorn/prefer-dom-node-remove
2491
- getParentNode(node).removeChild(node);
2492
- } catch (_) {
2493
- remove(node);
2494
- }
2495
- };
2496
- /**
2497
- * _removeAttribute
2498
- *
2499
- * @param name an Attribute name
2500
- * @param element a DOM node
2501
- */
2502
- const _removeAttribute = function _removeAttribute(name, element) {
2503
- try {
2504
- arrayPush(DOMPurify.removed, {
2505
- attribute: element.getAttributeNode(name),
2506
- from: element
2507
- });
2508
- } catch (_) {
2509
- arrayPush(DOMPurify.removed, {
2510
- attribute: null,
2511
- from: element
2512
- });
2513
- }
2514
- element.removeAttribute(name);
2515
- // We void attribute values for unremovable "is" attributes
2516
- if (name === 'is') {
2517
- if (RETURN_DOM || RETURN_DOM_FRAGMENT) {
2518
- try {
2519
- _forceRemove(element);
2520
- } catch (_) {}
2521
- } else {
2522
- try {
2523
- element.setAttribute(name, '');
2524
- } catch (_) {}
2525
- }
2526
- }
2527
- };
2528
- /**
2529
- * _initDocument
2530
- *
2531
- * @param dirty - a string of dirty markup
2532
- * @return a DOM, filled with the dirty markup
2533
- */
2534
- const _initDocument = function _initDocument(dirty) {
2535
- /* Create a HTML document */
2536
- let doc = null;
2537
- let leadingWhitespace = null;
2538
- if (FORCE_BODY) {
2539
- dirty = '<remove></remove>' + dirty;
2540
- } else {
2541
- /* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */
2542
- const matches = stringMatch(dirty, /^[\r\n\t ]+/);
2543
- leadingWhitespace = matches && matches[0];
2544
- }
2545
- if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && NAMESPACE === HTML_NAMESPACE) {
2546
- // Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict)
2547
- dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + '</body></html>';
2548
- }
2549
- const dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
2550
- /*
2551
- * Use the DOMParser API by default, fallback later if needs be
2552
- * DOMParser not work for svg when has multiple root element.
2553
- */
2554
- if (NAMESPACE === HTML_NAMESPACE) {
2555
- try {
2556
- doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);
2557
- } catch (_) {}
2558
- }
2559
- /* Use createHTMLDocument in case DOMParser is not available */
2560
- if (!doc || !doc.documentElement) {
2561
- doc = implementation.createDocument(NAMESPACE, 'template', null);
2562
- try {
2563
- doc.documentElement.innerHTML = IS_EMPTY_INPUT ? emptyHTML : dirtyPayload;
2564
- } catch (_) {
2565
- // Syntax error if dirtyPayload is invalid xml
2566
- }
2567
- }
2568
- const body = doc.body || doc.documentElement;
2569
- if (dirty && leadingWhitespace) {
2570
- body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);
2571
- }
2572
- /* Work on whole document or just its body */
2573
- if (NAMESPACE === HTML_NAMESPACE) {
2574
- return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
2575
- }
2576
- return WHOLE_DOCUMENT ? doc.documentElement : body;
2577
- };
2578
- /**
2579
- * Creates a NodeIterator object that you can use to traverse filtered lists of nodes or elements in a document.
2580
- *
2581
- * @param root The root element or node to start traversing on.
2582
- * @return The created NodeIterator
2583
- */
2584
- const _createNodeIterator = function _createNodeIterator(root) {
2585
- return createNodeIterator.call(root.ownerDocument || root, root,
2586
- // eslint-disable-next-line no-bitwise
2587
- NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION, null);
2588
- };
2589
- /**
2590
- * _isClobbered
2591
- *
2592
- * @param element element to check for clobbering attacks
2593
- * @return true if clobbered, false if safe
2594
- */
2595
- const _isClobbered = function _isClobbered(element) {
2596
- 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');
2597
- };
2598
- /**
2599
- * Checks whether the given object is a DOM node.
2600
- *
2601
- * @param value object to check whether it's a DOM node
2602
- * @return true is object is a DOM node
2603
- */
2604
- const _isNode = function _isNode(value) {
2605
- return typeof Node === 'function' && value instanceof Node;
2606
- };
2607
- function _executeHooks(hooks, currentNode, data) {
2608
- arrayForEach(hooks, hook => {
2609
- hook.call(DOMPurify, currentNode, data, CONFIG);
2610
- });
2611
- }
2612
- /**
2613
- * _sanitizeElements
2614
- *
2615
- * @protect nodeName
2616
- * @protect textContent
2617
- * @protect removeChild
2618
- * @param currentNode to check for permission to exist
2619
- * @return true if node was killed, false if left alive
2620
- */
2621
- const _sanitizeElements = function _sanitizeElements(currentNode) {
2622
- let content = null;
2623
- /* Execute a hook if present */
2624
- _executeHooks(hooks.beforeSanitizeElements, currentNode, null);
2625
- /* Check if element is clobbered or can clobber */
2626
- if (_isClobbered(currentNode)) {
2627
- _forceRemove(currentNode);
2628
- return true;
2629
- }
2630
- /* Now let's check the element's type and name */
2631
- const tagName = transformCaseFunc(currentNode.nodeName);
2632
- /* Execute a hook if present */
2633
- _executeHooks(hooks.uponSanitizeElement, currentNode, {
2634
- tagName,
2635
- allowedTags: ALLOWED_TAGS
2636
- });
2637
- /* Detect mXSS attempts abusing namespace confusion */
2638
- if (currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(/<[/\w]/g, currentNode.innerHTML) && regExpTest(/<[/\w]/g, currentNode.textContent)) {
2639
- _forceRemove(currentNode);
2640
- return true;
2641
- }
2642
- /* Remove any occurrence of processing instructions */
2643
- if (currentNode.nodeType === NODE_TYPE.progressingInstruction) {
2644
- _forceRemove(currentNode);
2645
- return true;
2646
- }
2647
- /* Remove any kind of possibly harmful comments */
2648
- if (SAFE_FOR_XML && currentNode.nodeType === NODE_TYPE.comment && regExpTest(/<[/\w]/g, currentNode.data)) {
2649
- _forceRemove(currentNode);
2650
- return true;
2651
- }
2652
- /* Remove element if anything forbids its presence */
2653
- if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
2654
- /* Check if we have a custom element to handle */
2655
- if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) {
2656
- if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) {
2657
- return false;
2658
- }
2659
- if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) {
2660
- return false;
2661
- }
2662
- }
2663
- /* Keep content except for bad-listed elements */
2664
- if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
2665
- const parentNode = getParentNode(currentNode) || currentNode.parentNode;
2666
- const childNodes = getChildNodes(currentNode) || currentNode.childNodes;
2667
- if (childNodes && parentNode) {
2668
- const childCount = childNodes.length;
2669
- for (let i = childCount - 1; i >= 0; --i) {
2670
- const childClone = cloneNode(childNodes[i], true);
2671
- childClone.__removalCount = (currentNode.__removalCount || 0) + 1;
2672
- parentNode.insertBefore(childClone, getNextSibling(currentNode));
2673
- }
2674
- }
2675
- }
2676
- _forceRemove(currentNode);
2677
- return true;
2678
- }
2679
- /* Check whether element has a valid namespace */
2680
- if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {
2681
- _forceRemove(currentNode);
2682
- return true;
2683
- }
2684
- /* Make sure that older browsers don't get fallback-tag mXSS */
2685
- if ((tagName === 'noscript' || tagName === 'noembed' || tagName === 'noframes') && regExpTest(/<\/no(script|embed|frames)/i, currentNode.innerHTML)) {
2686
- _forceRemove(currentNode);
2687
- return true;
2688
- }
2689
- /* Sanitize element content to be template-safe */
2690
- if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) {
2691
- /* Get the element's text content */
2692
- content = currentNode.textContent;
2693
- arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
2694
- content = stringReplace(content, expr, ' ');
2695
- });
2696
- if (currentNode.textContent !== content) {
2697
- arrayPush(DOMPurify.removed, {
2698
- element: currentNode.cloneNode()
2699
- });
2700
- currentNode.textContent = content;
2701
- }
2702
- }
2703
- /* Execute a hook if present */
2704
- _executeHooks(hooks.afterSanitizeElements, currentNode, null);
2705
- return false;
2706
- };
2707
- /**
2708
- * _isValidAttribute
2709
- *
2710
- * @param lcTag Lowercase tag name of containing element.
2711
- * @param lcName Lowercase attribute name.
2712
- * @param value Attribute value.
2713
- * @return Returns true if `value` is valid, otherwise false.
2714
- */
2715
- // eslint-disable-next-line complexity
2716
- const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
2717
- /* Make sure attribute cannot clobber */
2718
- if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
2719
- return false;
2720
- }
2721
- /* Allow valid data-* attributes: At least one character after "-"
2722
- (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
2723
- XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
2724
- We don't need to check the value; it's always URI safe. */
2725
- 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]) {
2726
- if (
2727
- // First condition does a very basic check if a) it's basically a valid custom element tagname AND
2728
- // b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
2729
- // and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck
2730
- _isBasicCustomElement(lcTag) && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, lcTag) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(lcTag)) && (CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.attributeNameCheck, lcName) || CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.attributeNameCheck(lcName)) ||
2731
- // Alternative, second condition checks if it's an `is`-attribute, AND
2732
- // the value passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
2733
- lcName === 'is' && CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, value) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(value))) ;else {
2734
- return false;
2735
- }
2736
- /* Check value is safe. First, is attr inert? If so, is safe */
2737
- } 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) {
2738
- return false;
2739
- } else ;
2740
- return true;
2741
- };
2742
- /**
2743
- * _isBasicCustomElement
2744
- * checks if at least one dash is included in tagName, and it's not the first char
2745
- * for more sophisticated checking see https://github.com/sindresorhus/validate-element-name
2746
- *
2747
- * @param tagName name of the tag of the node to sanitize
2748
- * @returns Returns true if the tag name meets the basic criteria for a custom element, otherwise false.
2749
- */
2750
- const _isBasicCustomElement = function _isBasicCustomElement(tagName) {
2751
- return tagName !== 'annotation-xml' && stringMatch(tagName, CUSTOM_ELEMENT);
2752
- };
2753
- /**
2754
- * _sanitizeAttributes
2755
- *
2756
- * @protect attributes
2757
- * @protect nodeName
2758
- * @protect removeAttribute
2759
- * @protect setAttribute
2760
- *
2761
- * @param currentNode to sanitize
2762
- */
2763
- const _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
2764
- /* Execute a hook if present */
2765
- _executeHooks(hooks.beforeSanitizeAttributes, currentNode, null);
2766
- const {
2767
- attributes
2768
- } = currentNode;
2769
- /* Check if we have attributes; if not we might have a text node */
2770
- if (!attributes || _isClobbered(currentNode)) {
2771
- return;
2772
- }
2773
- const hookEvent = {
2774
- attrName: '',
2775
- attrValue: '',
2776
- keepAttr: true,
2777
- allowedAttributes: ALLOWED_ATTR,
2778
- forceKeepAttr: undefined
2779
- };
2780
- let l = attributes.length;
2781
- /* Go backwards over all attributes; safely remove bad ones */
2782
- while (l--) {
2783
- const attr = attributes[l];
2784
- const {
2785
- name,
2786
- namespaceURI,
2787
- value: attrValue
2788
- } = attr;
2789
- const lcName = transformCaseFunc(name);
2790
- let value = name === 'value' ? attrValue : stringTrim(attrValue);
2791
- /* Execute a hook if present */
2792
- hookEvent.attrName = lcName;
2793
- hookEvent.attrValue = value;
2794
- hookEvent.keepAttr = true;
2795
- hookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set
2796
- _executeHooks(hooks.uponSanitizeAttribute, currentNode, hookEvent);
2797
- value = hookEvent.attrValue;
2798
- /* Full DOM Clobbering protection via namespace isolation,
2799
- * Prefix id and name attributes with `user-content-`
2800
- */
2801
- if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {
2802
- // Remove the attribute with this value
2803
- _removeAttribute(name, currentNode);
2804
- // Prefix the value and later re-create the attribute with the sanitized value
2805
- value = SANITIZE_NAMED_PROPS_PREFIX + value;
2806
- }
2807
- /* Work around a security issue with comments inside attributes */
2808
- if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|title)/i, value)) {
2809
- _removeAttribute(name, currentNode);
2810
- continue;
2811
- }
2812
- /* Did the hooks approve of the attribute? */
2813
- if (hookEvent.forceKeepAttr) {
2814
- continue;
2815
- }
2816
- /* Remove attribute */
2817
- _removeAttribute(name, currentNode);
2818
- /* Did the hooks approve of the attribute? */
2819
- if (!hookEvent.keepAttr) {
2820
- continue;
2821
- }
2822
- /* Work around a security issue in jQuery 3.0 */
2823
- if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(/\/>/i, value)) {
2824
- _removeAttribute(name, currentNode);
2825
- continue;
2826
- }
2827
- /* Sanitize attribute content to be template-safe */
2828
- if (SAFE_FOR_TEMPLATES) {
2829
- arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
2830
- value = stringReplace(value, expr, ' ');
2831
- });
2832
- }
2833
- /* Is `value` valid for this attribute? */
2834
- const lcTag = transformCaseFunc(currentNode.nodeName);
2835
- if (!_isValidAttribute(lcTag, lcName, value)) {
2836
- continue;
2837
- }
2838
- /* Handle attributes that require Trusted Types */
2839
- if (trustedTypesPolicy && typeof trustedTypes === 'object' && typeof trustedTypes.getAttributeType === 'function') {
2840
- if (namespaceURI) ;else {
2841
- switch (trustedTypes.getAttributeType(lcTag, lcName)) {
2842
- case 'TrustedHTML':
2843
- {
2844
- value = trustedTypesPolicy.createHTML(value);
2845
- break;
2846
- }
2847
- case 'TrustedScriptURL':
2848
- {
2849
- value = trustedTypesPolicy.createScriptURL(value);
2850
- break;
2851
- }
2852
- }
2853
- }
2854
- }
2855
- /* Handle invalid data-* attribute set by try-catching it */
2856
- try {
2857
- if (namespaceURI) {
2858
- currentNode.setAttributeNS(namespaceURI, name, value);
2859
- } else {
2860
- /* Fallback to setAttribute() for browser-unrecognized namespaces e.g. "x-schema". */
2861
- currentNode.setAttribute(name, value);
2862
- }
2863
- if (_isClobbered(currentNode)) {
2864
- _forceRemove(currentNode);
2865
- } else {
2866
- arrayPop(DOMPurify.removed);
2867
- }
2868
- } catch (_) {}
2869
- }
2870
- /* Execute a hook if present */
2871
- _executeHooks(hooks.afterSanitizeAttributes, currentNode, null);
2872
- };
2873
- /**
2874
- * _sanitizeShadowDOM
2875
- *
2876
- * @param fragment to iterate over recursively
2877
- */
2878
- const _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {
2879
- let shadowNode = null;
2880
- const shadowIterator = _createNodeIterator(fragment);
2881
- /* Execute a hook if present */
2882
- _executeHooks(hooks.beforeSanitizeShadowDOM, fragment, null);
2883
- while (shadowNode = shadowIterator.nextNode()) {
2884
- /* Execute a hook if present */
2885
- _executeHooks(hooks.uponSanitizeShadowNode, shadowNode, null);
2886
- /* Sanitize tags and elements */
2887
- _sanitizeElements(shadowNode);
2888
- /* Check attributes next */
2889
- _sanitizeAttributes(shadowNode);
2890
- /* Deep shadow DOM detected */
2891
- if (shadowNode.content instanceof DocumentFragment) {
2892
- _sanitizeShadowDOM(shadowNode.content);
2893
- }
2894
- }
2895
- /* Execute a hook if present */
2896
- _executeHooks(hooks.afterSanitizeShadowDOM, fragment, null);
2897
- };
2898
- // eslint-disable-next-line complexity
2899
- DOMPurify.sanitize = function (dirty) {
2900
- let cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
2901
- let body = null;
2902
- let importedNode = null;
2903
- let currentNode = null;
2904
- let returnNode = null;
2905
- /* Make sure we have a string to sanitize.
2906
- DO NOT return early, as this will return the wrong type if
2907
- the user has requested a DOM object rather than a string */
2908
- IS_EMPTY_INPUT = !dirty;
2909
- if (IS_EMPTY_INPUT) {
2910
- dirty = '<!-->';
2911
- }
2912
- /* Stringify, in case dirty is an object */
2913
- if (typeof dirty !== 'string' && !_isNode(dirty)) {
2914
- if (typeof dirty.toString === 'function') {
2915
- dirty = dirty.toString();
2916
- if (typeof dirty !== 'string') {
2917
- throw typeErrorCreate('dirty is not a string, aborting');
2918
- }
2919
- } else {
2920
- throw typeErrorCreate('toString is not a function');
2921
- }
2922
- }
2923
- /* Return dirty HTML if DOMPurify cannot run */
2924
- if (!DOMPurify.isSupported) {
2925
- return dirty;
2926
- }
2927
- /* Assign config vars */
2928
- if (!SET_CONFIG) {
2929
- _parseConfig(cfg);
2930
- }
2931
- /* Clean up removed elements */
2932
- DOMPurify.removed = [];
2933
- /* Check if dirty is correctly typed for IN_PLACE */
2934
- if (typeof dirty === 'string') {
2935
- IN_PLACE = false;
2936
- }
2937
- if (IN_PLACE) {
2938
- /* Do some early pre-sanitization to avoid unsafe root nodes */
2939
- if (dirty.nodeName) {
2940
- const tagName = transformCaseFunc(dirty.nodeName);
2941
- if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
2942
- throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');
2943
- }
2944
- }
2945
- } else if (dirty instanceof Node) {
2946
- /* If dirty is a DOM element, append to an empty document to avoid
2947
- elements being stripped by the parser */
2948
- body = _initDocument('<!---->');
2949
- importedNode = body.ownerDocument.importNode(dirty, true);
2950
- if (importedNode.nodeType === NODE_TYPE.element && importedNode.nodeName === 'BODY') {
2951
- /* Node is already a body, use as is */
2952
- body = importedNode;
2953
- } else if (importedNode.nodeName === 'HTML') {
2954
- body = importedNode;
2955
- } else {
2956
- // eslint-disable-next-line unicorn/prefer-dom-node-append
2957
- body.appendChild(importedNode);
2958
- }
2959
- } else {
2960
- /* Exit directly if we have nothing to do */
2961
- if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT &&
2962
- // eslint-disable-next-line unicorn/prefer-includes
2963
- dirty.indexOf('<') === -1) {
2964
- return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;
2965
- }
2966
- /* Initialize the document to work on */
2967
- body = _initDocument(dirty);
2968
- /* Check we have a DOM node from the data */
2969
- if (!body) {
2970
- return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';
2971
- }
2972
- }
2973
- /* Remove first element node (ours) if FORCE_BODY is set */
2974
- if (body && FORCE_BODY) {
2975
- _forceRemove(body.firstChild);
2976
- }
2977
- /* Get node iterator */
2978
- const nodeIterator = _createNodeIterator(IN_PLACE ? dirty : body);
2979
- /* Now start iterating over the created document */
2980
- while (currentNode = nodeIterator.nextNode()) {
2981
- /* Sanitize tags and elements */
2982
- _sanitizeElements(currentNode);
2983
- /* Check attributes next */
2984
- _sanitizeAttributes(currentNode);
2985
- /* Shadow DOM detected, sanitize it */
2986
- if (currentNode.content instanceof DocumentFragment) {
2987
- _sanitizeShadowDOM(currentNode.content);
2988
- }
2989
- }
2990
- /* If we sanitized `dirty` in-place, return it. */
2991
- if (IN_PLACE) {
2992
- return dirty;
2993
- }
2994
- /* Return sanitized string or DOM */
2995
- if (RETURN_DOM) {
2996
- if (RETURN_DOM_FRAGMENT) {
2997
- returnNode = createDocumentFragment.call(body.ownerDocument);
2998
- while (body.firstChild) {
2999
- // eslint-disable-next-line unicorn/prefer-dom-node-append
3000
- returnNode.appendChild(body.firstChild);
3001
- }
3002
- } else {
3003
- returnNode = body;
3004
- }
3005
- if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmode) {
3006
- /*
3007
- AdoptNode() is not used because internal state is not reset
3008
- (e.g. the past names map of a HTMLFormElement), this is safe
3009
- in theory but we would rather not risk another attack vector.
3010
- The state that is cloned by importNode() is explicitly defined
3011
- by the specs.
3012
- */
3013
- returnNode = importNode.call(originalDocument, returnNode, true);
3014
- }
3015
- return returnNode;
3016
- }
3017
- let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;
3018
- /* Serialize doctype if allowed */
3019
- if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {
3020
- serializedHTML = '<!DOCTYPE ' + body.ownerDocument.doctype.name + '>\n' + serializedHTML;
3021
- }
3022
- /* Sanitize final string template-safe */
3023
- if (SAFE_FOR_TEMPLATES) {
3024
- arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
3025
- serializedHTML = stringReplace(serializedHTML, expr, ' ');
3026
- });
3027
- }
3028
- return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
3029
- };
3030
- DOMPurify.setConfig = function () {
3031
- let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
3032
- _parseConfig(cfg);
3033
- SET_CONFIG = true;
3034
- };
3035
- DOMPurify.clearConfig = function () {
3036
- CONFIG = null;
3037
- SET_CONFIG = false;
3038
- };
3039
- DOMPurify.isValidAttribute = function (tag, attr, value) {
3040
- /* Initialize shared config vars if necessary. */
3041
- if (!CONFIG) {
3042
- _parseConfig({});
3043
- }
3044
- const lcTag = transformCaseFunc(tag);
3045
- const lcName = transformCaseFunc(attr);
3046
- return _isValidAttribute(lcTag, lcName, value);
3047
- };
3048
- DOMPurify.addHook = function (entryPoint, hookFunction) {
3049
- if (typeof hookFunction !== 'function') {
3050
- return;
3051
- }
3052
- arrayPush(hooks[entryPoint], hookFunction);
3053
- };
3054
- DOMPurify.removeHook = function (entryPoint) {
3055
- return arrayPop(hooks[entryPoint]);
3056
- };
3057
- DOMPurify.removeHooks = function (entryPoint) {
3058
- hooks[entryPoint] = [];
3059
- };
3060
- DOMPurify.removeAllHooks = function () {
3061
- hooks = _createHooksMap();
3062
- };
3063
- return DOMPurify;
3064
- }
3065
- var purify = createDOMPurify();
3066
-
3067
- const DEFAULT_ALLOWED_ATTRIBUTES = "style href src width height language class".split(" ");
3068
- const DEFAULT_FORBIDDEN_PROTOCOLS = "javascript:".split(" ");
3069
- const DEFAULT_FORBIDDEN_ELEMENTS = "script iframe form noscript".split(" ");
3070
- class HTMLSanitizer extends BasicObject {
3071
- static setHTML(element, html) {
3072
- const sanitizedElement = new this(html).sanitize();
3073
- const sanitizedHtml = sanitizedElement.getHTML ? sanitizedElement.getHTML() : sanitizedElement.outerHTML;
3074
- element.innerHTML = sanitizedHtml;
3075
- }
3076
- static sanitize(html, options) {
3077
- const sanitizer = new this(html, options);
3078
- sanitizer.sanitize();
3079
- return sanitizer;
3080
- }
3081
- constructor(html) {
3082
- let {
3083
- allowedAttributes,
3084
- forbiddenProtocols,
3085
- forbiddenElements
3086
- } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
3087
- super(...arguments);
3088
- this.allowedAttributes = allowedAttributes || DEFAULT_ALLOWED_ATTRIBUTES;
3089
- this.forbiddenProtocols = forbiddenProtocols || DEFAULT_FORBIDDEN_PROTOCOLS;
3090
- this.forbiddenElements = forbiddenElements || DEFAULT_FORBIDDEN_ELEMENTS;
3091
- this.body = createBodyElementForHTML(html);
3092
- }
3093
- sanitize() {
3094
- this.sanitizeElements();
3095
- this.normalizeListElementNesting();
3096
- return purify.sanitize(this.body, {
3097
- ADD_ATTR: ["language"],
3098
- RETURN_DOM: true
3099
- });
3100
- }
3101
- getHTML() {
3102
- return this.body.innerHTML;
3103
- }
3104
- getBody() {
3105
- return this.body;
3106
- }
3107
-
3108
- // Private
3109
-
3110
- sanitizeElements() {
3111
- const walker = walkTree(this.body);
3112
- const nodesToRemove = [];
3113
- while (walker.nextNode()) {
3114
- const node = walker.currentNode;
3115
- switch (node.nodeType) {
3116
- case Node.ELEMENT_NODE:
3117
- if (this.elementIsRemovable(node)) {
3118
- nodesToRemove.push(node);
3119
- } else {
3120
- this.sanitizeElement(node);
3121
- }
3122
- break;
3123
- case Node.COMMENT_NODE:
3124
- nodesToRemove.push(node);
3125
- break;
3126
- }
3127
- }
3128
- nodesToRemove.forEach(node => removeNode(node));
3129
- return this.body;
3130
- }
3131
- sanitizeElement(element) {
3132
- if (element.hasAttribute("href")) {
3133
- if (this.forbiddenProtocols.includes(element.protocol)) {
3134
- element.removeAttribute("href");
3135
- }
3136
- }
3137
- Array.from(element.attributes).forEach(_ref => {
3138
- let {
3139
- name
3140
- } = _ref;
3141
- if (!this.allowedAttributes.includes(name) && name.indexOf("data-trix") !== 0) {
3142
- element.removeAttribute(name);
3143
- }
3144
- });
3145
- return element;
3146
- }
3147
- normalizeListElementNesting() {
3148
- Array.from(this.body.querySelectorAll("ul,ol")).forEach(listElement => {
3149
- const previousElement = listElement.previousElementSibling;
3150
- if (previousElement) {
3151
- if (tagName(previousElement) === "li") {
3152
- previousElement.appendChild(listElement);
3153
- }
3154
- }
3155
- });
3156
- return this.body;
1684
+ this.viewClass = this.options.viewClass;
1685
+ delete this.options.viewClass;
3157
1686
  }
3158
- elementIsRemovable(element) {
3159
- if ((element === null || element === void 0 ? void 0 : element.nodeType) !== Node.ELEMENT_NODE) return;
3160
- return this.elementIsForbidden(element) || this.elementIsntSerializable(element);
1687
+ getChildViews() {
1688
+ if (!this.childViews.length) {
1689
+ Array.from(this.objectGroup.getObjects()).forEach(object => {
1690
+ this.findOrCreateCachedChildView(this.viewClass, object, this.options);
1691
+ });
1692
+ }
1693
+ return this.childViews;
3161
1694
  }
3162
- elementIsForbidden(element) {
3163
- return this.forbiddenElements.includes(tagName(element));
1695
+ createNodes() {
1696
+ const element = this.createContainerElement();
1697
+ this.getChildViews().forEach(view => {
1698
+ Array.from(view.getNodes()).forEach(node => {
1699
+ element.appendChild(node);
1700
+ });
1701
+ });
1702
+ return [element];
3164
1703
  }
3165
- elementIsntSerializable(element) {
3166
- return element.getAttribute("data-trix-serialize") === "false" && !nodeIsAttachmentElement(element);
1704
+ createContainerElement() {
1705
+ let depth = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.objectGroup.getDepth();
1706
+ return this.getChildViews()[0].createContainerElement(depth);
3167
1707
  }
3168
1708
  }
3169
- const createBodyElementForHTML = function () {
3170
- let html = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "";
3171
- // Remove everything after </html>
3172
- html = html.replace(/<\/html[^>]*>[^]*$/i, "</html>");
3173
- const doc = document.implementation.createHTMLDocument("");
3174
- doc.documentElement.innerHTML = html;
3175
- Array.from(doc.head.querySelectorAll("style")).forEach(element => {
3176
- doc.body.appendChild(element);
3177
- });
3178
- return doc.body;
3179
- };
3180
1709
 
3181
1710
  const {
3182
1711
  css: css$2
@@ -3212,7 +1741,7 @@ $\
3212
1741
  figure.appendChild(innerElement);
3213
1742
  }
3214
1743
  if (this.attachment.hasContent()) {
3215
- HTMLSanitizer.setHTML(innerElement, this.attachment.getContent());
1744
+ innerElement.innerHTML = this.attachment.getContent();
3216
1745
  } else {
3217
1746
  this.createContentNodes().forEach(node => {
3218
1747
  innerElement.appendChild(node);
@@ -3340,7 +1869,7 @@ $\
3340
1869
  });
3341
1870
  const htmlContainsTagName = function (html, tagName) {
3342
1871
  const div = makeElement("div");
3343
- HTMLSanitizer.setHTML(div, html || "");
1872
+ div.innerHTML = html || "";
3344
1873
  return div.querySelector(tagName);
3345
1874
  };
3346
1875
 
@@ -8287,6 +6816,111 @@ $\
8287
6816
  return attributes;
8288
6817
  };
8289
6818
 
6819
+ const DEFAULT_ALLOWED_ATTRIBUTES = "style href src width height language class".split(" ");
6820
+ const DEFAULT_FORBIDDEN_PROTOCOLS = "javascript:".split(" ");
6821
+ const DEFAULT_FORBIDDEN_ELEMENTS = "script iframe form noscript".split(" ");
6822
+ class HTMLSanitizer extends BasicObject {
6823
+ static sanitize(html, options) {
6824
+ const sanitizer = new this(html, options);
6825
+ sanitizer.sanitize();
6826
+ return sanitizer;
6827
+ }
6828
+ constructor(html) {
6829
+ let {
6830
+ allowedAttributes,
6831
+ forbiddenProtocols,
6832
+ forbiddenElements
6833
+ } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
6834
+ super(...arguments);
6835
+ this.allowedAttributes = allowedAttributes || DEFAULT_ALLOWED_ATTRIBUTES;
6836
+ this.forbiddenProtocols = forbiddenProtocols || DEFAULT_FORBIDDEN_PROTOCOLS;
6837
+ this.forbiddenElements = forbiddenElements || DEFAULT_FORBIDDEN_ELEMENTS;
6838
+ this.body = createBodyElementForHTML(html);
6839
+ }
6840
+ sanitize() {
6841
+ this.sanitizeElements();
6842
+ return this.normalizeListElementNesting();
6843
+ }
6844
+ getHTML() {
6845
+ return this.body.innerHTML;
6846
+ }
6847
+ getBody() {
6848
+ return this.body;
6849
+ }
6850
+
6851
+ // Private
6852
+
6853
+ sanitizeElements() {
6854
+ const walker = walkTree(this.body);
6855
+ const nodesToRemove = [];
6856
+ while (walker.nextNode()) {
6857
+ const node = walker.currentNode;
6858
+ switch (node.nodeType) {
6859
+ case Node.ELEMENT_NODE:
6860
+ if (this.elementIsRemovable(node)) {
6861
+ nodesToRemove.push(node);
6862
+ } else {
6863
+ this.sanitizeElement(node);
6864
+ }
6865
+ break;
6866
+ case Node.COMMENT_NODE:
6867
+ nodesToRemove.push(node);
6868
+ break;
6869
+ }
6870
+ }
6871
+ nodesToRemove.forEach(node => removeNode(node));
6872
+ return this.body;
6873
+ }
6874
+ sanitizeElement(element) {
6875
+ if (element.hasAttribute("href")) {
6876
+ if (this.forbiddenProtocols.includes(element.protocol)) {
6877
+ element.removeAttribute("href");
6878
+ }
6879
+ }
6880
+ Array.from(element.attributes).forEach(_ref => {
6881
+ let {
6882
+ name
6883
+ } = _ref;
6884
+ if (!this.allowedAttributes.includes(name) && name.indexOf("data-trix") !== 0) {
6885
+ element.removeAttribute(name);
6886
+ }
6887
+ });
6888
+ return element;
6889
+ }
6890
+ normalizeListElementNesting() {
6891
+ Array.from(this.body.querySelectorAll("ul,ol")).forEach(listElement => {
6892
+ const previousElement = listElement.previousElementSibling;
6893
+ if (previousElement) {
6894
+ if (tagName(previousElement) === "li") {
6895
+ previousElement.appendChild(listElement);
6896
+ }
6897
+ }
6898
+ });
6899
+ return this.body;
6900
+ }
6901
+ elementIsRemovable(element) {
6902
+ if ((element === null || element === void 0 ? void 0 : element.nodeType) !== Node.ELEMENT_NODE) return;
6903
+ return this.elementIsForbidden(element) || this.elementIsntSerializable(element);
6904
+ }
6905
+ elementIsForbidden(element) {
6906
+ return this.forbiddenElements.includes(tagName(element));
6907
+ }
6908
+ elementIsntSerializable(element) {
6909
+ return element.getAttribute("data-trix-serialize") === "false" && !nodeIsAttachmentElement(element);
6910
+ }
6911
+ }
6912
+ const createBodyElementForHTML = function () {
6913
+ let html = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "";
6914
+ // Remove everything after </html>
6915
+ html = html.replace(/<\/html[^>]*>[^]*$/i, "</html>");
6916
+ const doc = document.implementation.createHTMLDocument("");
6917
+ doc.documentElement.innerHTML = html;
6918
+ Array.from(doc.head.querySelectorAll("style")).forEach(element => {
6919
+ doc.body.appendChild(element);
6920
+ });
6921
+ return doc.body;
6922
+ };
6923
+
8290
6924
  /* eslint-disable
8291
6925
  no-case-declarations,
8292
6926
  no-irregular-whitespace,
@@ -8322,7 +6956,11 @@ $\
8322
6956
  };
8323
6957
  const parseTrixDataAttribute = (element, name) => {
8324
6958
  try {
8325
- return JSON.parse(element.getAttribute("data-trix-".concat(name)));
6959
+ const data = JSON.parse(element.getAttribute("data-trix-".concat(name)));
6960
+ if (data.contentType === "text/html" && data.content) {
6961
+ data.content = HTMLSanitizer.sanitize(data.content).getHTML();
6962
+ }
6963
+ return data;
8326
6964
  } catch (error) {
8327
6965
  return {};
8328
6966
  }
@@ -8365,7 +7003,8 @@ $\
8365
7003
  parse() {
8366
7004
  try {
8367
7005
  this.createHiddenContainer();
8368
- HTMLSanitizer.setHTML(this.containerElement, this.html);
7006
+ const html = HTMLSanitizer.sanitize(this.html).getHTML();
7007
+ this.containerElement.innerHTML = html;
8369
7008
  const walker = walkTree(this.containerElement, {
8370
7009
  usingFilter: nodeFilter
8371
7010
  });
@@ -11888,7 +10527,7 @@ $\
11888
10527
  return (_this$responder4 = this.responder) === null || _this$responder4 === void 0 ? void 0 : _this$responder4.deleteInDirection(direction);
11889
10528
  };
11890
10529
  const domRange = this.getTargetDOMRange({
11891
- minLength: this.composing ? 1 : 2
10530
+ minLength: 2
11892
10531
  });
11893
10532
  if (domRange) {
11894
10533
  return this.withTargetDOMRange(domRange, perform);
@@ -12002,15 +10641,9 @@ $\
12002
10641
  },
12003
10642
  beforeinput(event) {
12004
10643
  const handler = this.constructor.inputTypes[event.inputType];
12005
- const immmediateRender = shouldRenderInmmediatelyToDealWithIOSDictation(event);
12006
10644
  if (handler) {
12007
10645
  this.withEvent(event, handler);
12008
- if (!immmediateRender) {
12009
- this.scheduleRender();
12010
- }
12011
- }
12012
- if (immmediateRender) {
12013
- this.render();
10646
+ this.scheduleRender();
12014
10647
  }
12015
10648
  },
12016
10649
  input(event) {
@@ -12272,6 +10905,7 @@ $\
12272
10905
  }
12273
10906
  },
12274
10907
  insertFromPaste() {
10908
+ var _dataTransfer$files;
12275
10909
  const {
12276
10910
  dataTransfer
12277
10911
  } = this.event;
@@ -12314,28 +10948,28 @@ $\
12314
10948
  var _this$delegate21;
12315
10949
  return (_this$delegate21 = this.delegate) === null || _this$delegate21 === void 0 ? void 0 : _this$delegate21.inputControllerDidPaste(paste);
12316
10950
  };
12317
- } else if (processableFilePaste(this.event)) {
10951
+ } else if (html) {
12318
10952
  var _this$delegate22;
12319
- paste.type = "File";
12320
- paste.file = dataTransfer.files[0];
10953
+ this.event.preventDefault();
10954
+ paste.type = "text/html";
10955
+ paste.html = html;
12321
10956
  (_this$delegate22 = this.delegate) === null || _this$delegate22 === void 0 || _this$delegate22.inputControllerWillPaste(paste);
12322
10957
  this.withTargetDOMRange(function () {
12323
10958
  var _this$responder34;
12324
- return (_this$responder34 = this.responder) === null || _this$responder34 === void 0 ? void 0 : _this$responder34.insertFile(paste.file);
10959
+ return (_this$responder34 = this.responder) === null || _this$responder34 === void 0 ? void 0 : _this$responder34.insertHTML(paste.html);
12325
10960
  });
12326
10961
  this.afterRender = () => {
12327
10962
  var _this$delegate23;
12328
10963
  return (_this$delegate23 = this.delegate) === null || _this$delegate23 === void 0 ? void 0 : _this$delegate23.inputControllerDidPaste(paste);
12329
10964
  };
12330
- } else if (html) {
10965
+ } else if ((_dataTransfer$files = dataTransfer.files) !== null && _dataTransfer$files !== void 0 && _dataTransfer$files.length) {
12331
10966
  var _this$delegate24;
12332
- this.event.preventDefault();
12333
- paste.type = "text/html";
12334
- paste.html = html;
10967
+ paste.type = "File";
10968
+ paste.file = dataTransfer.files[0];
12335
10969
  (_this$delegate24 = this.delegate) === null || _this$delegate24 === void 0 || _this$delegate24.inputControllerWillPaste(paste);
12336
10970
  this.withTargetDOMRange(function () {
12337
10971
  var _this$responder35;
12338
- return (_this$responder35 = this.responder) === null || _this$responder35 === void 0 ? void 0 : _this$responder35.insertHTML(paste.html);
10972
+ return (_this$responder35 = this.responder) === null || _this$responder35 === void 0 ? void 0 : _this$responder35.insertFile(paste.file);
12339
10973
  });
12340
10974
  this.afterRender = () => {
12341
10975
  var _this$delegate25;
@@ -12396,20 +11030,10 @@ $\
12396
11030
  var _event$dataTransfer;
12397
11031
  return Array.from(((_event$dataTransfer = event.dataTransfer) === null || _event$dataTransfer === void 0 ? void 0 : _event$dataTransfer.types) || []).includes("Files");
12398
11032
  };
12399
- const processableFilePaste = event => {
12400
- var _event$dataTransfer$f;
12401
- // Paste events that only have files are handled by the paste event handler,
12402
- // to work around Safari not supporting beforeinput.insertFromPaste for files.
12403
-
12404
- // MS Office text pastes include a file with a screenshot of the text, but we should
12405
- // handle them as text pastes.
12406
- return ((_event$dataTransfer$f = event.dataTransfer.files) === null || _event$dataTransfer$f === void 0 ? void 0 : _event$dataTransfer$f[0]) && !pasteEventHasFilesOnly(event) && !dataTransferIsMsOfficePaste(event);
12407
- };
12408
11033
  const pasteEventHasFilesOnly = function (event) {
12409
11034
  const clipboard = event.clipboardData;
12410
11035
  if (clipboard) {
12411
- const fileTypes = Array.from(clipboard.types).filter(type => type.match(/file/i)); // "Files", "application/x-moz-file"
12412
- return fileTypes.length === clipboard.types.length && clipboard.files.length >= 1;
11036
+ return clipboard.types.includes("Files") && clipboard.types.length === 1 && clipboard.files.length >= 1;
12413
11037
  }
12414
11038
  };
12415
11039
  const pasteEventHasPlainTextOnly = function (event) {
@@ -13075,7 +11699,7 @@ $\
13075
11699
  updateInputElement() {
13076
11700
  const element = this.compositionController.getSerializableElement();
13077
11701
  const value = serializeToContentType(element, "text/html");
13078
- return this.editorElement.setFormValue(value);
11702
+ return this.editorElement.setInputElementValue(value);
13079
11703
  }
13080
11704
  notifyEditorElement(message, data) {
13081
11705
  switch (message) {
@@ -13332,187 +11956,8 @@ $\
13332
11956
  };
13333
11957
  }
13334
11958
  }();
13335
- installDefaultCSSForTagName("trix-editor", "%t {\n display: block;\n}\n\n%t:empty::before {\n content: attr(placeholder);\n color: graytext;\n cursor: text;\n pointer-events: none;\n white-space: pre-line;\n}\n\n%t a[contenteditable=false] {\n cursor: text;\n}\n\n%t img {\n max-width: 100%;\n height: auto;\n}\n\n%t ".concat(attachmentSelector, " figcaption textarea {\n resize: none;\n}\n\n%t ").concat(attachmentSelector, " figcaption textarea.trix-autoresize-clone {\n position: absolute;\n left: -9999px;\n max-height: 0px;\n}\n\n%t ").concat(attachmentSelector, " figcaption[data-trix-placeholder]:empty::before {\n content: attr(data-trix-placeholder);\n color: graytext;\n}\n\n%t [data-trix-cursor-target] {\n display: ").concat(cursorTargetStyles.display, " !important;\n width: ").concat(cursorTargetStyles.width, " !important;\n padding: 0 !important;\n margin: 0 !important;\n border: none !important;\n}\n\n%t [data-trix-cursor-target=left] {\n vertical-align: top !important;\n margin-left: -1px !important;\n}\n\n%t [data-trix-cursor-target=right] {\n vertical-align: bottom !important;\n margin-right: -1px !important;\n}"));
13336
- var _internals = /*#__PURE__*/new WeakMap();
13337
- var _validate = /*#__PURE__*/new WeakSet();
13338
- class ElementInternalsDelegate {
13339
- constructor(element) {
13340
- _classPrivateMethodInitSpec(this, _validate);
13341
- _classPrivateFieldInitSpec(this, _internals, {
13342
- writable: true,
13343
- value: void 0
13344
- });
13345
- this.element = element;
13346
- _classPrivateFieldSet(this, _internals, element.attachInternals());
13347
- }
13348
- connectedCallback() {
13349
- _classPrivateMethodGet(this, _validate, _validate2).call(this);
13350
- }
13351
- disconnectedCallback() {}
13352
- get labels() {
13353
- return _classPrivateFieldGet(this, _internals).labels;
13354
- }
13355
- get disabled() {
13356
- var _this$element$inputEl;
13357
- return (_this$element$inputEl = this.element.inputElement) === null || _this$element$inputEl === void 0 ? void 0 : _this$element$inputEl.disabled;
13358
- }
13359
- set disabled(value) {
13360
- this.element.toggleAttribute("disabled", value);
13361
- }
13362
- get required() {
13363
- return this.element.hasAttribute("required");
13364
- }
13365
- set required(value) {
13366
- this.element.toggleAttribute("required", value);
13367
- _classPrivateMethodGet(this, _validate, _validate2).call(this);
13368
- }
13369
- get validity() {
13370
- return _classPrivateFieldGet(this, _internals).validity;
13371
- }
13372
- get validationMessage() {
13373
- return _classPrivateFieldGet(this, _internals).validationMessage;
13374
- }
13375
- get willValidate() {
13376
- return _classPrivateFieldGet(this, _internals).willValidate;
13377
- }
13378
- setFormValue(value) {
13379
- _classPrivateMethodGet(this, _validate, _validate2).call(this);
13380
- }
13381
- checkValidity() {
13382
- return _classPrivateFieldGet(this, _internals).checkValidity();
13383
- }
13384
- reportValidity() {
13385
- return _classPrivateFieldGet(this, _internals).reportValidity();
13386
- }
13387
- setCustomValidity(validationMessage) {
13388
- _classPrivateMethodGet(this, _validate, _validate2).call(this, validationMessage);
13389
- }
13390
- }
13391
- function _validate2() {
13392
- let customValidationMessage = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "";
13393
- const {
13394
- required,
13395
- value
13396
- } = this.element;
13397
- const valueMissing = required && !value;
13398
- const customError = !!customValidationMessage;
13399
- const input = makeElement("input", {
13400
- required
13401
- });
13402
- const validationMessage = customValidationMessage || input.validationMessage;
13403
- _classPrivateFieldGet(this, _internals).setValidity({
13404
- valueMissing,
13405
- customError
13406
- }, validationMessage);
13407
- }
13408
- var _focusHandler = /*#__PURE__*/new WeakMap();
13409
- var _resetBubbled = /*#__PURE__*/new WeakMap();
13410
- var _clickBubbled = /*#__PURE__*/new WeakMap();
13411
- class LegacyDelegate {
13412
- constructor(element) {
13413
- _classPrivateFieldInitSpec(this, _focusHandler, {
13414
- writable: true,
13415
- value: void 0
13416
- });
13417
- _classPrivateFieldInitSpec(this, _resetBubbled, {
13418
- writable: true,
13419
- value: event => {
13420
- if (event.defaultPrevented) return;
13421
- if (event.target !== this.element.form) return;
13422
- this.element.reset();
13423
- }
13424
- });
13425
- _classPrivateFieldInitSpec(this, _clickBubbled, {
13426
- writable: true,
13427
- value: event => {
13428
- if (event.defaultPrevented) return;
13429
- if (this.element.contains(event.target)) return;
13430
- const label = findClosestElementFromNode(event.target, {
13431
- matchingSelector: "label"
13432
- });
13433
- if (!label) return;
13434
- if (!Array.from(this.labels).includes(label)) return;
13435
- this.element.focus();
13436
- }
13437
- });
13438
- this.element = element;
13439
- }
13440
- connectedCallback() {
13441
- _classPrivateFieldSet(this, _focusHandler, ensureAriaLabel(this.element));
13442
- window.addEventListener("reset", _classPrivateFieldGet(this, _resetBubbled), false);
13443
- window.addEventListener("click", _classPrivateFieldGet(this, _clickBubbled), false);
13444
- }
13445
- disconnectedCallback() {
13446
- var _classPrivateFieldGet2;
13447
- (_classPrivateFieldGet2 = _classPrivateFieldGet(this, _focusHandler)) === null || _classPrivateFieldGet2 === void 0 || _classPrivateFieldGet2.destroy();
13448
- window.removeEventListener("reset", _classPrivateFieldGet(this, _resetBubbled), false);
13449
- window.removeEventListener("click", _classPrivateFieldGet(this, _clickBubbled), false);
13450
- }
13451
- get labels() {
13452
- const labels = [];
13453
- if (this.element.id && this.element.ownerDocument) {
13454
- labels.push(...Array.from(this.element.ownerDocument.querySelectorAll("label[for='".concat(this.element.id, "']")) || []));
13455
- }
13456
- const label = findClosestElementFromNode(this.element, {
13457
- matchingSelector: "label"
13458
- });
13459
- if (label) {
13460
- if ([this.element, null].includes(label.control)) {
13461
- labels.push(label);
13462
- }
13463
- }
13464
- return labels;
13465
- }
13466
- get disabled() {
13467
- console.warn("This browser does not support the [disabled] attribute for trix-editor elements.");
13468
- return false;
13469
- }
13470
- set disabled(value) {
13471
- console.warn("This browser does not support the [disabled] attribute for trix-editor elements.");
13472
- }
13473
- get required() {
13474
- console.warn("This browser does not support the [required] attribute for trix-editor elements.");
13475
- return false;
13476
- }
13477
- set required(value) {
13478
- console.warn("This browser does not support the [required] attribute for trix-editor elements.");
13479
- }
13480
- get validity() {
13481
- console.warn("This browser does not support the validity property for trix-editor elements.");
13482
- return null;
13483
- }
13484
- get validationMessage() {
13485
- console.warn("This browser does not support the validationMessage property for trix-editor elements.");
13486
- return "";
13487
- }
13488
- get willValidate() {
13489
- console.warn("This browser does not support the willValidate property for trix-editor elements.");
13490
- return false;
13491
- }
13492
- setFormValue(value) {}
13493
- checkValidity() {
13494
- console.warn("This browser does not support checkValidity() for trix-editor elements.");
13495
- return true;
13496
- }
13497
- reportValidity() {
13498
- console.warn("This browser does not support reportValidity() for trix-editor elements.");
13499
- return true;
13500
- }
13501
- setCustomValidity(validationMessage) {
13502
- console.warn("This browser does not support setCustomValidity(validationMessage) for trix-editor elements.");
13503
- }
13504
- }
13505
- var _delegate = /*#__PURE__*/new WeakMap();
11959
+ installDefaultCSSForTagName("trix-editor", "%t {\n display: block;\n}\n\n%t:empty:not(:focus)::before {\n content: attr(placeholder);\n color: graytext;\n cursor: text;\n pointer-events: none;\n white-space: pre-line;\n}\n\n%t a[contenteditable=false] {\n cursor: text;\n}\n\n%t img {\n max-width: 100%;\n height: auto;\n}\n\n%t ".concat(attachmentSelector, " figcaption textarea {\n resize: none;\n}\n\n%t ").concat(attachmentSelector, " figcaption textarea.trix-autoresize-clone {\n position: absolute;\n left: -9999px;\n max-height: 0px;\n}\n\n%t ").concat(attachmentSelector, " figcaption[data-trix-placeholder]:empty::before {\n content: attr(data-trix-placeholder);\n color: graytext;\n}\n\n%t [data-trix-cursor-target] {\n display: ").concat(cursorTargetStyles.display, " !important;\n width: ").concat(cursorTargetStyles.width, " !important;\n padding: 0 !important;\n margin: 0 !important;\n border: none !important;\n}\n\n%t [data-trix-cursor-target=left] {\n vertical-align: top !important;\n margin-left: -1px !important;\n}\n\n%t [data-trix-cursor-target=right] {\n vertical-align: bottom !important;\n margin-right: -1px !important;\n}"));
13506
11960
  class TrixEditorElement extends HTMLElement {
13507
- constructor() {
13508
- super();
13509
- _classPrivateFieldInitSpec(this, _delegate, {
13510
- writable: true,
13511
- value: void 0
13512
- });
13513
- _classPrivateFieldSet(this, _delegate, this.constructor.formAssociated ? new ElementInternalsDelegate(this) : new LegacyDelegate(this));
13514
- }
13515
-
13516
11961
  // Properties
13517
11962
 
13518
11963
  get trixId() {
@@ -13524,31 +11969,19 @@ $\
13524
11969
  }
13525
11970
  }
13526
11971
  get labels() {
13527
- return _classPrivateFieldGet(this, _delegate).labels;
13528
- }
13529
- get disabled() {
13530
- return _classPrivateFieldGet(this, _delegate).disabled;
13531
- }
13532
- set disabled(value) {
13533
- _classPrivateFieldGet(this, _delegate).disabled = value;
13534
- }
13535
- get required() {
13536
- return _classPrivateFieldGet(this, _delegate).required;
13537
- }
13538
- set required(value) {
13539
- _classPrivateFieldGet(this, _delegate).required = value;
13540
- }
13541
- get validity() {
13542
- return _classPrivateFieldGet(this, _delegate).validity;
13543
- }
13544
- get validationMessage() {
13545
- return _classPrivateFieldGet(this, _delegate).validationMessage;
13546
- }
13547
- get willValidate() {
13548
- return _classPrivateFieldGet(this, _delegate).willValidate;
13549
- }
13550
- get type() {
13551
- return this.localName;
11972
+ const labels = [];
11973
+ if (this.id && this.ownerDocument) {
11974
+ labels.push(...Array.from(this.ownerDocument.querySelectorAll("label[for='".concat(this.id, "']")) || []));
11975
+ }
11976
+ const label = findClosestElementFromNode(this, {
11977
+ matchingSelector: "label"
11978
+ });
11979
+ if (label) {
11980
+ if ([this, null].includes(label.control)) {
11981
+ labels.push(label);
11982
+ }
11983
+ }
11984
+ return labels;
13552
11985
  }
13553
11986
  get toolbarElement() {
13554
11987
  if (this.hasAttribute("toolbar")) {
@@ -13615,10 +12048,9 @@ $\
13615
12048
  });
13616
12049
  }
13617
12050
  }
13618
- setFormValue(value) {
12051
+ setInputElementValue(value) {
13619
12052
  if (this.inputElement) {
13620
12053
  this.inputElement.value = value;
13621
- _classPrivateFieldGet(this, _delegate).setFormValue(value);
13622
12054
  }
13623
12055
  }
13624
12056
 
@@ -13628,6 +12060,7 @@ $\
13628
12060
  if (!this.hasAttribute("data-trix-internal")) {
13629
12061
  makeEditable(this);
13630
12062
  addAccessibilityRole(this);
12063
+ ensureAriaLabel(this);
13631
12064
  if (!this.editorController) {
13632
12065
  triggerEvent("trix-before-initialize", {
13633
12066
  onElement: this
@@ -13641,41 +12074,53 @@ $\
13641
12074
  }));
13642
12075
  }
13643
12076
  this.editorController.registerSelectionManager();
13644
- _classPrivateFieldGet(this, _delegate).connectedCallback();
12077
+ this.registerResetListener();
12078
+ this.registerClickListener();
13645
12079
  autofocus(this);
13646
12080
  }
13647
12081
  }
13648
12082
  disconnectedCallback() {
13649
12083
  var _this$editorControlle2;
13650
12084
  (_this$editorControlle2 = this.editorController) === null || _this$editorControlle2 === void 0 || _this$editorControlle2.unregisterSelectionManager();
13651
- _classPrivateFieldGet(this, _delegate).disconnectedCallback();
12085
+ this.unregisterResetListener();
12086
+ return this.unregisterClickListener();
13652
12087
  }
13653
12088
 
13654
12089
  // Form support
13655
12090
 
13656
- checkValidity() {
13657
- return _classPrivateFieldGet(this, _delegate).checkValidity();
12091
+ registerResetListener() {
12092
+ this.resetListener = this.resetBubbled.bind(this);
12093
+ return window.addEventListener("reset", this.resetListener, false);
13658
12094
  }
13659
- reportValidity() {
13660
- return _classPrivateFieldGet(this, _delegate).reportValidity();
12095
+ unregisterResetListener() {
12096
+ return window.removeEventListener("reset", this.resetListener, false);
13661
12097
  }
13662
- setCustomValidity(validationMessage) {
13663
- _classPrivateFieldGet(this, _delegate).setCustomValidity(validationMessage);
12098
+ registerClickListener() {
12099
+ this.clickListener = this.clickBubbled.bind(this);
12100
+ return window.addEventListener("click", this.clickListener, false);
13664
12101
  }
13665
- formDisabledCallback(disabled) {
13666
- if (this.inputElement) {
13667
- this.inputElement.disabled = disabled;
13668
- }
13669
- this.toggleAttribute("contenteditable", !disabled);
12102
+ unregisterClickListener() {
12103
+ return window.removeEventListener("click", this.clickListener, false);
13670
12104
  }
13671
- formResetCallback() {
13672
- this.reset();
12105
+ resetBubbled(event) {
12106
+ if (event.defaultPrevented) return;
12107
+ if (event.target !== this.form) return;
12108
+ return this.reset();
12109
+ }
12110
+ clickBubbled(event) {
12111
+ if (event.defaultPrevented) return;
12112
+ if (this.contains(event.target)) return;
12113
+ const label = findClosestElementFromNode(event.target, {
12114
+ matchingSelector: "label"
12115
+ });
12116
+ if (!label) return;
12117
+ if (!Array.from(this.labels).includes(label)) return;
12118
+ return this.focus();
13673
12119
  }
13674
12120
  reset() {
13675
12121
  this.value = this.defaultValue;
13676
12122
  }
13677
12123
  }
13678
- _defineProperty(TrixEditorElement, "formAssociated", "ElementInternals" in window);
13679
12124
 
13680
12125
  var elements = /*#__PURE__*/Object.freeze({
13681
12126
  __proto__: null,