hoeditor-web 2.0.26 → 2.0.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,7 +3,7 @@
3
3
  /***/ "c0c4":
4
4
  /***/ (function(module, exports, __webpack_require__) {
5
5
 
6
- /*! @license DOMPurify 2.3.2 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/2.3.2/LICENSE */
6
+ /*! @license DOMPurify 2.3.6 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/2.3.6/LICENSE */
7
7
 
8
8
  (function (global, factory) {
9
9
  true ? module.exports = factory() :
@@ -160,13 +160,13 @@
160
160
  // SVG
161
161
  var svg = 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']);
162
162
 
163
- var svgFilters = freeze(['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence']);
163
+ var svgFilters = freeze(['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence']);
164
164
 
165
165
  // List of SVG elements that are disallowed by default.
166
166
  // We still need to know them so that we can do namespace
167
167
  // checks properly in case one wants to add them to
168
168
  // allow-list.
169
- var svgDisallowed = freeze(['animate', 'color-profile', 'cursor', 'discard', 'fedropshadow', 'feimage', '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']);
169
+ var svgDisallowed = freeze(['animate', 'color-profile', 'cursor', 'discard', 'fedropshadow', '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']);
170
170
 
171
171
  var mathMl = 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']);
172
172
 
@@ -176,9 +176,9 @@
176
176
 
177
177
  var text = freeze(['#text']);
178
178
 
179
- var html$1 = 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', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'pattern', 'placeholder', 'playsinline', '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', 'xmlns', 'slot']);
179
+ var html$1 = 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', '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', 'xmlns', 'slot']);
180
180
 
181
- var svg$1 = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', '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', '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', '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', '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', 'targetx', 'targety', 'transform', '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']);
181
+ var svg$1 = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', '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', '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', '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', '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', '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']);
182
182
 
183
183
  var mathMl$1 = 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']);
184
184
 
@@ -194,6 +194,7 @@
194
194
  var IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
195
195
  var ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g // eslint-disable-line no-control-regex
196
196
  );
197
+ var DOCTYPE_NAME = seal(/^html$/i);
197
198
 
198
199
  var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
199
200
 
@@ -253,7 +254,7 @@
253
254
  * Version label, exposed for easier checks
254
255
  * if DOMPurify is up to date or not
255
256
  */
256
- DOMPurify.version = '2.3.2';
257
+ DOMPurify.version = '2.3.6';
257
258
 
258
259
  /**
259
260
  * Array of elements that DOMPurify removed during sanitation.
@@ -279,8 +280,7 @@
279
280
  NodeFilter = window.NodeFilter,
280
281
  _window$NamedNodeMap = window.NamedNodeMap,
281
282
  NamedNodeMap = _window$NamedNodeMap === undefined ? window.NamedNodeMap || window.MozNamedAttrMap : _window$NamedNodeMap,
282
- Text = window.Text,
283
- Comment = window.Comment,
283
+ HTMLFormElement = window.HTMLFormElement,
284
284
  DOMParser = window.DOMParser,
285
285
  trustedTypes = window.trustedTypes;
286
286
 
@@ -306,7 +306,7 @@
306
306
  }
307
307
 
308
308
  var trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, originalDocument);
309
- var emptyHTML = trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML('') : '';
309
+ var emptyHTML = trustedTypesPolicy ? trustedTypesPolicy.createHTML('') : '';
310
310
 
311
311
  var _document = document,
312
312
  implementation = _document.implementation,
@@ -350,6 +350,33 @@
350
350
  var ALLOWED_ATTR = null;
351
351
  var DEFAULT_ALLOWED_ATTR = addToSet({}, [].concat(_toConsumableArray$1(html$1), _toConsumableArray$1(svg$1), _toConsumableArray$1(mathMl$1), _toConsumableArray$1(xml)));
352
352
 
353
+ /*
354
+ * Configure how DOMPUrify should handle custom elements and their attributes as well as customized built-in elements.
355
+ * @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)
356
+ * @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list)
357
+ * @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.
358
+ */
359
+ var CUSTOM_ELEMENT_HANDLING = Object.seal(Object.create(null, {
360
+ tagNameCheck: {
361
+ writable: true,
362
+ configurable: false,
363
+ enumerable: true,
364
+ value: null
365
+ },
366
+ attributeNameCheck: {
367
+ writable: true,
368
+ configurable: false,
369
+ enumerable: true,
370
+ value: null
371
+ },
372
+ allowCustomizedBuiltInElements: {
373
+ writable: true,
374
+ configurable: false,
375
+ enumerable: true,
376
+ value: false
377
+ }
378
+ }));
379
+
353
380
  /* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */
354
381
  var FORBID_TAGS = null;
355
382
 
@@ -390,17 +417,6 @@
390
417
  * string (or a TrustedHTML object if Trusted Types are supported) */
391
418
  var RETURN_DOM_FRAGMENT = false;
392
419
 
393
- /* If `RETURN_DOM` or `RETURN_DOM_FRAGMENT` is enabled, decide if the returned DOM
394
- * `Node` is imported into the current `Document`. If this flag is not enabled the
395
- * `Node` will belong (its ownerDocument) to a fresh `HTMLDocument`, created by
396
- * DOMPurify.
397
- *
398
- * This defaults to `true` starting DOMPurify 2.2.0. Note that setting it to `false`
399
- * might cause XSS from attacks hidden in closed shadowroots in case the browser
400
- * supports Declarative Shadow: DOM https://web.dev/declarative-shadow-dom/
401
- */
402
- var RETURN_DOM_IMPORT = true;
403
-
404
420
  /* Try to return a Trusted Type object instead of a string, return a string in
405
421
  * case Trusted Types are not supported */
406
422
  var RETURN_TRUSTED_TYPE = false;
@@ -451,6 +467,10 @@
451
467
 
452
468
  var formElement = document.createElement('form');
453
469
 
470
+ var isRegexOrFunction = function isRegexOrFunction(testValue) {
471
+ return testValue instanceof RegExp || testValue instanceof Function;
472
+ };
473
+
454
474
  /**
455
475
  * _parseConfig
456
476
  *
@@ -486,7 +506,6 @@
486
506
  WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false
487
507
  RETURN_DOM = cfg.RETURN_DOM || false; // Default false
488
508
  RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false
489
- RETURN_DOM_IMPORT = cfg.RETURN_DOM_IMPORT !== false; // Default true
490
509
  RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false
491
510
  FORCE_BODY = cfg.FORCE_BODY || false; // Default false
492
511
  SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true
@@ -494,7 +513,22 @@
494
513
  IN_PLACE = cfg.IN_PLACE || false; // Default false
495
514
  IS_ALLOWED_URI$$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI$$1;
496
515
  NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
497
- PARSER_MEDIA_TYPE = cfg.PARSER_MEDIA_TYPE in SUPPORTED_PARSER_MEDIA_TYPES ? cfg.PARSER_MEDIA_TYPE : DEFAULT_PARSER_MEDIA_TYPE;
516
+ if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {
517
+ CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;
518
+ }
519
+
520
+ if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) {
521
+ CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;
522
+ }
523
+
524
+ if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === 'boolean') {
525
+ CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;
526
+ }
527
+
528
+ PARSER_MEDIA_TYPE =
529
+ // eslint-disable-next-line unicorn/prefer-includes
530
+ SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? PARSER_MEDIA_TYPE = DEFAULT_PARSER_MEDIA_TYPE : PARSER_MEDIA_TYPE = cfg.PARSER_MEDIA_TYPE;
531
+
498
532
  // HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
499
533
  transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? function (x) {
500
534
  return x;
@@ -815,7 +849,9 @@
815
849
  * @return {Iterator} iterator instance
816
850
  */
817
851
  var _createIterator = function _createIterator(root) {
818
- return createNodeIterator.call(root.ownerDocument || root, root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT, null, false);
852
+ return createNodeIterator.call(root.ownerDocument || root, root,
853
+ // eslint-disable-next-line no-bitwise
854
+ NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT, null, false);
819
855
  };
820
856
 
821
857
  /**
@@ -825,15 +861,7 @@
825
861
  * @return {Boolean} true if clobbered, false if safe
826
862
  */
827
863
  var _isClobbered = function _isClobbered(elm) {
828
- if (elm instanceof Text || elm instanceof Comment) {
829
- return false;
830
- }
831
-
832
- if (typeof elm.nodeName !== 'string' || typeof elm.textContent !== 'string' || typeof elm.removeChild !== 'function' || !(elm.attributes instanceof NamedNodeMap) || typeof elm.removeAttribute !== 'function' || typeof elm.setAttribute !== 'function' || typeof elm.namespaceURI !== 'string' || typeof elm.insertBefore !== 'function') {
833
- return true;
834
- }
835
-
836
- return false;
864
+ return elm instanceof HTMLFormElement && (typeof elm.nodeName !== 'string' || typeof elm.textContent !== 'string' || typeof elm.removeChild !== 'function' || !(elm.attributes instanceof NamedNodeMap) || typeof elm.removeAttribute !== 'function' || typeof elm.setAttribute !== 'function' || typeof elm.namespaceURI !== 'string' || typeof elm.insertBefore !== 'function');
837
865
  };
838
866
 
839
867
  /**
@@ -915,6 +943,12 @@
915
943
 
916
944
  /* Remove element if anything forbids its presence */
917
945
  if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
946
+ /* Check if we have a custom element to handle */
947
+ if (!FORBID_TAGS[tagName] && _basicCustomElementTest(tagName)) {
948
+ if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) return false;
949
+ if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) return false;
950
+ }
951
+
918
952
  /* Keep content except for bad-listed elements */
919
953
  if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
920
954
  var parentNode = getParentNode(currentNode) || currentNode.parentNode;
@@ -982,8 +1016,16 @@
982
1016
  XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
983
1017
  We don't need to check the value; it's always URI safe. */
984
1018
  if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR$$1, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR$$1, lcName)) ; else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
985
- return false;
986
-
1019
+ if (
1020
+ // First condition does a very basic check if a) it's basically a valid custom element tagname AND
1021
+ // b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
1022
+ // and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck
1023
+ _basicCustomElementTest(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)) ||
1024
+ // Alternative, second condition checks if it's an `is`-attribute, AND
1025
+ // the value passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
1026
+ 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 {
1027
+ return false;
1028
+ }
987
1029
  /* Check value is safe. First, is attr inert? If so, is safe */
988
1030
  } else if (URI_SAFE_ATTRIBUTES[lcName]) ; else if (regExpTest(IS_ALLOWED_URI$$1, stringReplace(value, ATTR_WHITESPACE$$1, ''))) ; else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]) ; else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA$$1, stringReplace(value, ATTR_WHITESPACE$$1, ''))) ; else if (!value) ; else {
989
1031
  return false;
@@ -992,6 +1034,16 @@
992
1034
  return true;
993
1035
  };
994
1036
 
1037
+ /**
1038
+ * _basicCustomElementCheck
1039
+ * checks if at least one dash is included in tagName, and it's not the first char
1040
+ * for more sophisticated checking see https://github.com/sindresorhus/validate-element-name
1041
+ * @param {string} tagName name of the tag of the node to sanitize
1042
+ */
1043
+ var _basicCustomElementTest = function _basicCustomElementTest(tagName) {
1044
+ return tagName.indexOf('-') > 0;
1045
+ };
1046
+
995
1047
  /**
996
1048
  * _sanitizeAttributes
997
1049
  *
@@ -1188,7 +1240,15 @@
1188
1240
  IN_PLACE = false;
1189
1241
  }
1190
1242
 
1191
- if (IN_PLACE) ; else if (dirty instanceof Node) {
1243
+ if (IN_PLACE) {
1244
+ /* Do some early pre-sanitization to avoid unsafe root nodes */
1245
+ if (dirty.nodeName) {
1246
+ var tagName = transformCaseFunc(dirty.nodeName);
1247
+ if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
1248
+ throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');
1249
+ }
1250
+ }
1251
+ } else if (dirty instanceof Node) {
1192
1252
  /* If dirty is a DOM element, append to an empty document to avoid
1193
1253
  elements being stripped by the parser */
1194
1254
  body = _initDocument('<!---->');
@@ -1215,7 +1275,7 @@
1215
1275
 
1216
1276
  /* Check we have a DOM node from the data */
1217
1277
  if (!body) {
1218
- return RETURN_DOM ? null : emptyHTML;
1278
+ return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';
1219
1279
  }
1220
1280
  }
1221
1281
 
@@ -1270,7 +1330,7 @@
1270
1330
  returnNode = body;
1271
1331
  }
1272
1332
 
1273
- if (RETURN_DOM_IMPORT) {
1333
+ if (ALLOWED_ATTR.shadowroot) {
1274
1334
  /*
1275
1335
  AdoptNode() is not used because internal state is not reset
1276
1336
  (e.g. the past names map of a HTMLFormElement), this is safe
@@ -1286,6 +1346,11 @@
1286
1346
 
1287
1347
  var serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;
1288
1348
 
1349
+ /* Serialize doctype if allowed */
1350
+ if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {
1351
+ serializedHTML = '<!DOCTYPE ' + body.ownerDocument.doctype.name + '>\n' + serializedHTML;
1352
+ }
1353
+
1289
1354
  /* Sanitize final string template-safe */
1290
1355
  if (SAFE_FOR_TEMPLATES) {
1291
1356
  serializedHTML = stringReplace(serializedHTML, MUSTACHE_EXPR$$1, ' ');