@formio/js 5.0.0-dev.5588.0f690c8 → 5.0.0-dev.5589.fd575d0
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.
- package/Changelog.md +10 -0
- package/dist/formio.form.js +20 -10
- package/dist/formio.form.min.js +1 -1
- package/dist/formio.form.min.js.LICENSE.txt +2 -0
- package/dist/formio.full.js +22 -12
- package/dist/formio.full.min.js +1 -1
- package/dist/formio.full.min.js.LICENSE.txt +2 -0
- package/dist/formio.utils.js +12 -2
- package/dist/formio.utils.min.js +1 -1
- package/dist/formio.utils.min.js.LICENSE.txt +2 -0
- package/lib/cjs/Webform.js +13 -6
- package/lib/cjs/WebformBuilder.js +1 -6
- package/lib/cjs/components/_classes/component/Component.d.ts +5 -3
- package/lib/cjs/components/_classes/component/Component.js +1 -2
- package/lib/cjs/components/checkbox/Checkbox.js +2 -9
- package/lib/cjs/components/checkbox/fixtures/comp5.d.ts +34 -0
- package/lib/cjs/components/checkbox/fixtures/comp5.js +55 -0
- package/lib/cjs/components/checkbox/fixtures/index.d.ts +2 -1
- package/lib/cjs/components/checkbox/fixtures/index.js +3 -1
- package/lib/cjs/components/form/Form.js +5 -1
- package/lib/cjs/components/form/fixtures/comp7.d.ts +36 -0
- package/lib/cjs/components/form/fixtures/comp7.js +37 -0
- package/lib/cjs/components/form/fixtures/comp8.d.ts +26 -0
- package/lib/cjs/components/form/fixtures/comp8.js +29 -0
- package/lib/cjs/components/form/fixtures/index.d.ts +3 -1
- package/lib/cjs/components/form/fixtures/index.js +5 -1
- package/lib/cjs/components/radio/Radio.d.ts +1 -1
- package/lib/cjs/components/radio/Radio.js +5 -3
- package/lib/cjs/components/recaptcha/editForm/ReCaptcha.edit.display.d.ts +5 -0
- package/lib/cjs/components/recaptcha/editForm/ReCaptcha.edit.display.js +3 -0
- package/lib/cjs/components/select/Select.js +6 -1
- package/lib/cjs/components/select/fixtures/comp23.d.ts +47 -0
- package/lib/cjs/components/select/fixtures/comp23.js +40 -0
- package/lib/cjs/components/select/fixtures/index.d.ts +2 -1
- package/lib/cjs/components/select/fixtures/index.js +3 -1
- package/lib/cjs/components/selectboxes/SelectBoxes.js +4 -1
- package/lib/cjs/translations/en.d.ts +1 -0
- package/lib/cjs/translations/en.js +1 -0
- package/lib/mjs/Webform.js +13 -6
- package/lib/mjs/WebformBuilder.js +1 -5
- package/lib/mjs/components/_classes/component/Component.d.ts +5 -3
- package/lib/mjs/components/_classes/component/Component.js +1 -2
- package/lib/mjs/components/checkbox/Checkbox.js +2 -9
- package/lib/mjs/components/checkbox/fixtures/comp5.d.ts +34 -0
- package/lib/mjs/components/checkbox/fixtures/comp5.js +53 -0
- package/lib/mjs/components/checkbox/fixtures/index.d.ts +2 -1
- package/lib/mjs/components/checkbox/fixtures/index.js +2 -1
- package/lib/mjs/components/form/Form.js +5 -1
- package/lib/mjs/components/form/fixtures/comp7.d.ts +36 -0
- package/lib/mjs/components/form/fixtures/comp7.js +35 -0
- package/lib/mjs/components/form/fixtures/comp8.d.ts +26 -0
- package/lib/mjs/components/form/fixtures/comp8.js +27 -0
- package/lib/mjs/components/form/fixtures/index.d.ts +3 -1
- package/lib/mjs/components/form/fixtures/index.js +3 -1
- package/lib/mjs/components/radio/Radio.d.ts +1 -1
- package/lib/mjs/components/radio/Radio.js +5 -3
- package/lib/mjs/components/recaptcha/editForm/ReCaptcha.edit.display.d.ts +5 -0
- package/lib/mjs/components/recaptcha/editForm/ReCaptcha.edit.display.js +3 -0
- package/lib/mjs/components/select/Select.js +6 -1
- package/lib/mjs/components/select/fixtures/comp23.d.ts +47 -0
- package/lib/mjs/components/select/fixtures/comp23.js +38 -0
- package/lib/mjs/components/select/fixtures/index.d.ts +2 -1
- package/lib/mjs/components/select/fixtures/index.js +2 -1
- package/lib/mjs/components/selectboxes/SelectBoxes.js +4 -1
- package/lib/mjs/translations/en.d.ts +1 -0
- package/lib/mjs/translations/en.js +1 -0
- package/package.json +3 -3
package/dist/formio.form.js
CHANGED
|
@@ -1894,7 +1894,7 @@ eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexpo
|
|
|
1894
1894
|
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
|
|
1895
1895
|
|
|
1896
1896
|
"use strict";
|
|
1897
|
-
eval("\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.sanitize = void 0;\nconst dompurify_1 = __importDefault(__webpack_require__(/*! dompurify */ \"./node_modules/dompurify/dist/purify.js\"));\nlet DOMPurify = null;\nconst getDOMPurify = () => {\n if (DOMPurify) {\n return DOMPurify;\n }\n if (window) {\n DOMPurify = (0, dompurify_1.default)(window);\n return DOMPurify;\n }\n return null;\n};\n/**\n * Sanitize an html string.\n *\n * @param string\n * @returns {*}\n */\nfunction sanitize(string, options) {\n const dompurify = getDOMPurify();\n if (!dompurify) {\n console.log('DOMPurify unable to sanitize the contents.');\n return string;\n }\n // Dompurify configuration\n const sanitizeOptions = {\n ADD_ATTR: ['ref', 'target', 'within'],\n USE_PROFILES: { html: true }\n };\n // Add attrs\n if (options.sanitizeConfig && Array.isArray(options.sanitizeConfig.addAttr) && options.sanitizeConfig.addAttr.length > 0) {\n options.sanitizeConfig.addAttr.forEach((attr) => {\n sanitizeOptions.ADD_ATTR.push(attr);\n });\n }\n // Add tags\n if (options.sanitizeConfig && Array.isArray(options.sanitizeConfig.addTags) && options.sanitizeConfig.addTags.length > 0) {\n sanitizeOptions.ADD_TAGS = options.sanitizeConfig.addTags;\n }\n // Allow tags\n if (options.sanitizeConfig && Array.isArray(options.sanitizeConfig.allowedTags) && options.sanitizeConfig.allowedTags.length > 0) {\n sanitizeOptions.ALLOWED_TAGS = options.sanitizeConfig.allowedTags;\n }\n // Allow attributes\n if (options.sanitizeConfig && Array.isArray(options.sanitizeConfig.allowedAttrs) && options.sanitizeConfig.allowedAttrs.length > 0) {\n sanitizeOptions.ALLOWED_ATTR = options.sanitizeConfig.allowedAttrs;\n }\n // Allowd URI Regex\n if (options.sanitizeConfig && options.sanitizeConfig.allowedUriRegex) {\n sanitizeOptions.ALLOWED_URI_REGEXP = options.sanitizeConfig.allowedUriRegex;\n }\n // Allow to extend the existing array of elements that are safe for URI-like values\n if (options.sanitizeConfig && Array.isArray(options.sanitizeConfig.addUriSafeAttr) && options.sanitizeConfig.addUriSafeAttr.length > 0) {\n sanitizeOptions.ADD_URI_SAFE_ATTR = options.sanitizeConfig.addUriSafeAttr;\n }\n return dompurify.sanitize(string, sanitizeOptions);\n}\nexports.sanitize = sanitize;\n\n\n//# sourceURL=webpack://Formio/./node_modules/@formio/core/lib/utils/sanitize.js?");
|
|
1897
|
+
eval("\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.sanitize = void 0;\nconst dompurify_1 = __importDefault(__webpack_require__(/*! dompurify */ \"./node_modules/@formio/core/node_modules/dompurify/dist/purify.js\"));\nlet DOMPurify = null;\nconst getDOMPurify = () => {\n if (DOMPurify) {\n return DOMPurify;\n }\n if (window) {\n DOMPurify = (0, dompurify_1.default)(window);\n return DOMPurify;\n }\n return null;\n};\n/**\n * Sanitize an html string.\n *\n * @param string\n * @returns {*}\n */\nfunction sanitize(string, options) {\n const dompurify = getDOMPurify();\n if (!dompurify) {\n console.log('DOMPurify unable to sanitize the contents.');\n return string;\n }\n // Dompurify configuration\n const sanitizeOptions = {\n ADD_ATTR: ['ref', 'target', 'within'],\n USE_PROFILES: { html: true }\n };\n // Add attrs\n if (options.sanitizeConfig && Array.isArray(options.sanitizeConfig.addAttr) && options.sanitizeConfig.addAttr.length > 0) {\n options.sanitizeConfig.addAttr.forEach((attr) => {\n sanitizeOptions.ADD_ATTR.push(attr);\n });\n }\n // Add tags\n if (options.sanitizeConfig && Array.isArray(options.sanitizeConfig.addTags) && options.sanitizeConfig.addTags.length > 0) {\n sanitizeOptions.ADD_TAGS = options.sanitizeConfig.addTags;\n }\n // Allow tags\n if (options.sanitizeConfig && Array.isArray(options.sanitizeConfig.allowedTags) && options.sanitizeConfig.allowedTags.length > 0) {\n sanitizeOptions.ALLOWED_TAGS = options.sanitizeConfig.allowedTags;\n }\n // Allow attributes\n if (options.sanitizeConfig && Array.isArray(options.sanitizeConfig.allowedAttrs) && options.sanitizeConfig.allowedAttrs.length > 0) {\n sanitizeOptions.ALLOWED_ATTR = options.sanitizeConfig.allowedAttrs;\n }\n // Allowd URI Regex\n if (options.sanitizeConfig && options.sanitizeConfig.allowedUriRegex) {\n sanitizeOptions.ALLOWED_URI_REGEXP = options.sanitizeConfig.allowedUriRegex;\n }\n // Allow to extend the existing array of elements that are safe for URI-like values\n if (options.sanitizeConfig && Array.isArray(options.sanitizeConfig.addUriSafeAttr) && options.sanitizeConfig.addUriSafeAttr.length > 0) {\n sanitizeOptions.ADD_URI_SAFE_ATTR = options.sanitizeConfig.addUriSafeAttr;\n }\n return dompurify.sanitize(string, sanitizeOptions);\n}\nexports.sanitize = sanitize;\n\n\n//# sourceURL=webpack://Formio/./node_modules/@formio/core/lib/utils/sanitize.js?");
|
|
1898
1898
|
|
|
1899
1899
|
/***/ }),
|
|
1900
1900
|
|
|
@@ -1920,6 +1920,16 @@ eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexpo
|
|
|
1920
1920
|
|
|
1921
1921
|
/***/ }),
|
|
1922
1922
|
|
|
1923
|
+
/***/ "./node_modules/@formio/core/node_modules/dompurify/dist/purify.js":
|
|
1924
|
+
/*!*************************************************************************!*\
|
|
1925
|
+
!*** ./node_modules/@formio/core/node_modules/dompurify/dist/purify.js ***!
|
|
1926
|
+
\*************************************************************************/
|
|
1927
|
+
/***/ (function(module) {
|
|
1928
|
+
|
|
1929
|
+
eval("/*! @license DOMPurify 3.1.0 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.1.0/LICENSE */\n\n(function (global, factory) {\n true ? module.exports = factory() :\n 0;\n})(this, (function () { 'use strict';\n\n const {\n entries,\n setPrototypeOf,\n isFrozen,\n getPrototypeOf,\n getOwnPropertyDescriptor\n } = Object;\n let {\n freeze,\n seal,\n create\n } = Object; // eslint-disable-line import/no-mutable-exports\n let {\n apply,\n construct\n } = typeof Reflect !== 'undefined' && Reflect;\n if (!freeze) {\n freeze = function freeze(x) {\n return x;\n };\n }\n if (!seal) {\n seal = function seal(x) {\n return x;\n };\n }\n if (!apply) {\n apply = function apply(fun, thisValue, args) {\n return fun.apply(thisValue, args);\n };\n }\n if (!construct) {\n construct = function construct(Func, args) {\n return new Func(...args);\n };\n }\n const arrayForEach = unapply(Array.prototype.forEach);\n const arrayPop = unapply(Array.prototype.pop);\n const arrayPush = unapply(Array.prototype.push);\n const stringToLowerCase = unapply(String.prototype.toLowerCase);\n const stringToString = unapply(String.prototype.toString);\n const stringMatch = unapply(String.prototype.match);\n const stringReplace = unapply(String.prototype.replace);\n const stringIndexOf = unapply(String.prototype.indexOf);\n const stringTrim = unapply(String.prototype.trim);\n const objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);\n const regExpTest = unapply(RegExp.prototype.test);\n const typeErrorCreate = unconstruct(TypeError);\n\n /**\n * Creates a new function that calls the given function with a specified thisArg and arguments.\n *\n * @param {Function} func - The function to be wrapped and called.\n * @returns {Function} A new function that calls the given function with a specified thisArg and arguments.\n */\n function unapply(func) {\n return function (thisArg) {\n for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n args[_key - 1] = arguments[_key];\n }\n return apply(func, thisArg, args);\n };\n }\n\n /**\n * Creates a new function that constructs an instance of the given constructor function with the provided arguments.\n *\n * @param {Function} func - The constructor function to be wrapped and called.\n * @returns {Function} A new function that constructs an instance of the given constructor function with the provided arguments.\n */\n function unconstruct(func) {\n return function () {\n for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {\n args[_key2] = arguments[_key2];\n }\n return construct(func, args);\n };\n }\n\n /**\n * Add properties to a lookup table\n *\n * @param {Object} set - The set to which elements will be added.\n * @param {Array} array - The array containing elements to be added to the set.\n * @param {Function} transformCaseFunc - An optional function to transform the case of each element before adding to the set.\n * @returns {Object} The modified set with added elements.\n */\n function addToSet(set, array) {\n let transformCaseFunc = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : stringToLowerCase;\n if (setPrototypeOf) {\n // Make 'in' and truthy checks like Boolean(set.constructor)\n // independent of any properties defined on Object.prototype.\n // Prevent prototype setters from intercepting set as a this value.\n setPrototypeOf(set, null);\n }\n let l = array.length;\n while (l--) {\n let element = array[l];\n if (typeof element === 'string') {\n const lcElement = transformCaseFunc(element);\n if (lcElement !== element) {\n // Config presets (e.g. tags.js, attrs.js) are immutable.\n if (!isFrozen(array)) {\n array[l] = lcElement;\n }\n element = lcElement;\n }\n }\n set[element] = true;\n }\n return set;\n }\n\n /**\n * Clean up an array to harden against CSPP\n *\n * @param {Array} array - The array to be cleaned.\n * @returns {Array} The cleaned version of the array\n */\n function cleanArray(array) {\n for (let index = 0; index < array.length; index++) {\n const isPropertyExist = objectHasOwnProperty(array, index);\n if (!isPropertyExist) {\n array[index] = null;\n }\n }\n return array;\n }\n\n /**\n * Shallow clone an object\n *\n * @param {Object} object - The object to be cloned.\n * @returns {Object} A new object that copies the original.\n */\n function clone(object) {\n const newObject = create(null);\n for (const [property, value] of entries(object)) {\n const isPropertyExist = objectHasOwnProperty(object, property);\n if (isPropertyExist) {\n if (Array.isArray(value)) {\n newObject[property] = cleanArray(value);\n } else if (value && typeof value === 'object' && value.constructor === Object) {\n newObject[property] = clone(value);\n } else {\n newObject[property] = value;\n }\n }\n }\n return newObject;\n }\n\n /**\n * This method automatically checks if the prop is function or getter and behaves accordingly.\n *\n * @param {Object} object - The object to look up the getter function in its prototype chain.\n * @param {String} prop - The property name for which to find the getter function.\n * @returns {Function} The getter function found in the prototype chain or a fallback function.\n */\n function lookupGetter(object, prop) {\n while (object !== null) {\n const desc = getOwnPropertyDescriptor(object, prop);\n if (desc) {\n if (desc.get) {\n return unapply(desc.get);\n }\n if (typeof desc.value === 'function') {\n return unapply(desc.value);\n }\n }\n object = getPrototypeOf(object);\n }\n function fallbackValue() {\n return null;\n }\n return fallbackValue;\n }\n\n 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']);\n\n // SVG\n 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']);\n 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']);\n\n // List of SVG elements that are disallowed by default.\n // We still need to know them so that we can do namespace\n // checks properly in case one wants to add them to\n // allow-list.\n 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']);\n 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']);\n\n // Similarly to SVG, we want to know all MathML elements,\n // even those that we disallow by default.\n const mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);\n const text = freeze(['#text']);\n\n 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', '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']);\n const svg = 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']);\n 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']);\n const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);\n\n // eslint-disable-next-line unicorn/better-regex\n const MUSTACHE_EXPR = seal(/\\{\\{[\\w\\W]*|[\\w\\W]*\\}\\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode\n const ERB_EXPR = seal(/<%[\\w\\W]*|[\\w\\W]*%>/gm);\n const TMPLIT_EXPR = seal(/\\${[\\w\\W]*}/gm);\n const DATA_ATTR = seal(/^data-[\\-\\w.\\u00B7-\\uFFFF]/); // eslint-disable-line no-useless-escape\n const ARIA_ATTR = seal(/^aria-[\\-\\w]+$/); // eslint-disable-line no-useless-escape\n 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\n );\n\n const IS_SCRIPT_OR_DATA = seal(/^(?:\\w+script|data):/i);\n const ATTR_WHITESPACE = seal(/[\\u0000-\\u0020\\u00A0\\u1680\\u180E\\u2000-\\u2029\\u205F\\u3000]/g // eslint-disable-line no-control-regex\n );\n\n const DOCTYPE_NAME = seal(/^html$/i);\n const CUSTOM_ELEMENT = seal(/^[a-z][.\\w]*(-[.\\w]+)+$/i);\n\n var EXPRESSIONS = /*#__PURE__*/Object.freeze({\n __proto__: null,\n MUSTACHE_EXPR: MUSTACHE_EXPR,\n ERB_EXPR: ERB_EXPR,\n TMPLIT_EXPR: TMPLIT_EXPR,\n DATA_ATTR: DATA_ATTR,\n ARIA_ATTR: ARIA_ATTR,\n IS_ALLOWED_URI: IS_ALLOWED_URI,\n IS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA,\n ATTR_WHITESPACE: ATTR_WHITESPACE,\n DOCTYPE_NAME: DOCTYPE_NAME,\n CUSTOM_ELEMENT: CUSTOM_ELEMENT\n });\n\n const getGlobal = function getGlobal() {\n return typeof window === 'undefined' ? null : window;\n };\n\n /**\n * Creates a no-op policy for internal use only.\n * Don't export this function outside this module!\n * @param {TrustedTypePolicyFactory} trustedTypes The policy factory.\n * @param {HTMLScriptElement} purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix).\n * @return {TrustedTypePolicy} The policy created (or null, if Trusted Types\n * are not supported or creating the policy failed).\n */\n const _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, purifyHostElement) {\n if (typeof trustedTypes !== 'object' || typeof trustedTypes.createPolicy !== 'function') {\n return null;\n }\n\n // Allow the callers to control the unique policy name\n // by adding a data-tt-policy-suffix to the script element with the DOMPurify.\n // Policy creation with duplicate names throws in Trusted Types.\n let suffix = null;\n const ATTR_NAME = 'data-tt-policy-suffix';\n if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) {\n suffix = purifyHostElement.getAttribute(ATTR_NAME);\n }\n const policyName = 'dompurify' + (suffix ? '#' + suffix : '');\n try {\n return trustedTypes.createPolicy(policyName, {\n createHTML(html) {\n return html;\n },\n createScriptURL(scriptUrl) {\n return scriptUrl;\n }\n });\n } catch (_) {\n // Policy creation failed (most likely another DOMPurify script has\n // already run). Skip creating the policy, as this will only cause errors\n // if TT are enforced.\n console.warn('TrustedTypes policy ' + policyName + ' could not be created.');\n return null;\n }\n };\n function createDOMPurify() {\n let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();\n const DOMPurify = root => createDOMPurify(root);\n\n /**\n * Version label, exposed for easier checks\n * if DOMPurify is up to date or not\n */\n DOMPurify.version = '3.1.0';\n\n /**\n * Array of elements that DOMPurify removed during sanitation.\n * Empty if nothing was removed.\n */\n DOMPurify.removed = [];\n if (!window || !window.document || window.document.nodeType !== 9) {\n // Not running in a browser, provide a factory function\n // so that you can pass your own Window\n DOMPurify.isSupported = false;\n return DOMPurify;\n }\n let {\n document\n } = window;\n const originalDocument = document;\n const currentScript = originalDocument.currentScript;\n const {\n DocumentFragment,\n HTMLTemplateElement,\n Node,\n Element,\n NodeFilter,\n NamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap,\n HTMLFormElement,\n DOMParser,\n trustedTypes\n } = window;\n const ElementPrototype = Element.prototype;\n const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');\n const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');\n const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');\n const getParentNode = lookupGetter(ElementPrototype, 'parentNode');\n\n // As per issue #47, the web-components registry is inherited by a\n // new document created via createHTMLDocument. As per the spec\n // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)\n // a new empty registry is used when creating a template contents owner\n // document, so we use that as our parent document to ensure nothing\n // is inherited.\n if (typeof HTMLTemplateElement === 'function') {\n const template = document.createElement('template');\n if (template.content && template.content.ownerDocument) {\n document = template.content.ownerDocument;\n }\n }\n let trustedTypesPolicy;\n let emptyHTML = '';\n const {\n implementation,\n createNodeIterator,\n createDocumentFragment,\n getElementsByTagName\n } = document;\n const {\n importNode\n } = originalDocument;\n let hooks = {};\n\n /**\n * Expose whether this browser supports running the full DOMPurify.\n */\n DOMPurify.isSupported = typeof entries === 'function' && typeof getParentNode === 'function' && implementation && implementation.createHTMLDocument !== undefined;\n const {\n MUSTACHE_EXPR,\n ERB_EXPR,\n TMPLIT_EXPR,\n DATA_ATTR,\n ARIA_ATTR,\n IS_SCRIPT_OR_DATA,\n ATTR_WHITESPACE,\n CUSTOM_ELEMENT\n } = EXPRESSIONS;\n let {\n IS_ALLOWED_URI: IS_ALLOWED_URI$1\n } = EXPRESSIONS;\n\n /**\n * We consider the elements and attributes below to be safe. Ideally\n * don't add any new ones but feel free to remove unwanted ones.\n */\n\n /* allowed element names */\n let ALLOWED_TAGS = null;\n const DEFAULT_ALLOWED_TAGS = addToSet({}, [...html$1, ...svg$1, ...svgFilters, ...mathMl$1, ...text]);\n\n /* Allowed attribute names */\n let ALLOWED_ATTR = null;\n const DEFAULT_ALLOWED_ATTR = addToSet({}, [...html, ...svg, ...mathMl, ...xml]);\n\n /*\n * Configure how DOMPUrify should handle custom elements and their attributes as well as customized built-in elements.\n * @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)\n * @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list)\n * @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.\n */\n let CUSTOM_ELEMENT_HANDLING = Object.seal(create(null, {\n tagNameCheck: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: null\n },\n attributeNameCheck: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: null\n },\n allowCustomizedBuiltInElements: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: false\n }\n }));\n\n /* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */\n let FORBID_TAGS = null;\n\n /* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */\n let FORBID_ATTR = null;\n\n /* Decide if ARIA attributes are okay */\n let ALLOW_ARIA_ATTR = true;\n\n /* Decide if custom data attributes are okay */\n let ALLOW_DATA_ATTR = true;\n\n /* Decide if unknown protocols are okay */\n let ALLOW_UNKNOWN_PROTOCOLS = false;\n\n /* Decide if self-closing tags in attributes are allowed.\n * Usually removed due to a mXSS issue in jQuery 3.0 */\n let ALLOW_SELF_CLOSE_IN_ATTR = true;\n\n /* Output should be safe for common template engines.\n * This means, DOMPurify removes data attributes, mustaches and ERB\n */\n let SAFE_FOR_TEMPLATES = false;\n\n /* Output should be safe even for XML used within HTML and alike.\n * This means, DOMPurify removes comments when containing risky content.\n */\n let SAFE_FOR_XML = true;\n\n /* Decide if document with <html>... should be returned */\n let WHOLE_DOCUMENT = false;\n\n /* Track whether config is already set on this instance of DOMPurify. */\n let SET_CONFIG = false;\n\n /* Decide if all elements (e.g. style, script) must be children of\n * document.body. By default, browsers might move them to document.head */\n let FORCE_BODY = false;\n\n /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html\n * string (or a TrustedHTML object if Trusted Types are supported).\n * If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead\n */\n let RETURN_DOM = false;\n\n /* Decide if a DOM `DocumentFragment` should be returned, instead of a html\n * string (or a TrustedHTML object if Trusted Types are supported) */\n let RETURN_DOM_FRAGMENT = false;\n\n /* Try to return a Trusted Type object instead of a string, return a string in\n * case Trusted Types are not supported */\n let RETURN_TRUSTED_TYPE = false;\n\n /* Output should be free from DOM clobbering attacks?\n * This sanitizes markups named with colliding, clobberable built-in DOM APIs.\n */\n let SANITIZE_DOM = true;\n\n /* Achieve full DOM Clobbering protection by isolating the namespace of named\n * properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules.\n *\n * HTML/DOM spec rules that enable DOM Clobbering:\n * - Named Access on Window (§7.3.3)\n * - DOM Tree Accessors (§3.1.5)\n * - Form Element Parent-Child Relations (§4.10.3)\n * - Iframe srcdoc / Nested WindowProxies (§4.8.5)\n * - HTMLCollection (§4.2.10.2)\n *\n * Namespace isolation is implemented by prefixing `id` and `name` attributes\n * with a constant string, i.e., `user-content-`\n */\n let SANITIZE_NAMED_PROPS = false;\n const SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';\n\n /* Keep element content when removing element? */\n let KEEP_CONTENT = true;\n\n /* If a `Node` is passed to sanitize(), then performs sanitization in-place instead\n * of importing it into a new Document and returning a sanitized copy */\n let IN_PLACE = false;\n\n /* Allow usage of profiles like html, svg and mathMl */\n let USE_PROFILES = {};\n\n /* Tags to ignore content of when KEEP_CONTENT is true */\n let FORBID_CONTENTS = null;\n 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']);\n\n /* Tags that are safe for data: URIs */\n let DATA_URI_TAGS = null;\n const DEFAULT_DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image', 'track']);\n\n /* Attributes safe for values like \"javascript:\" */\n let URI_SAFE_ATTRIBUTES = null;\n const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'role', 'summary', 'title', 'value', 'style', 'xmlns']);\n const MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';\n const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';\n const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';\n /* Document namespace */\n let NAMESPACE = HTML_NAMESPACE;\n let IS_EMPTY_INPUT = false;\n\n /* Allowed XHTML+XML namespaces */\n let ALLOWED_NAMESPACES = null;\n const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE], stringToString);\n\n /* Parsing of strict XHTML documents */\n let PARSER_MEDIA_TYPE = null;\n const SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html'];\n const DEFAULT_PARSER_MEDIA_TYPE = 'text/html';\n let transformCaseFunc = null;\n\n /* Keep a reference to config to pass to hooks */\n let CONFIG = null;\n\n /* Ideally, do not touch anything below this line */\n /* ______________________________________________ */\n\n const formElement = document.createElement('form');\n const isRegexOrFunction = function isRegexOrFunction(testValue) {\n return testValue instanceof RegExp || testValue instanceof Function;\n };\n\n /**\n * _parseConfig\n *\n * @param {Object} cfg optional config literal\n */\n // eslint-disable-next-line complexity\n const _parseConfig = function _parseConfig() {\n let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n if (CONFIG && CONFIG === cfg) {\n return;\n }\n\n /* Shield configuration object from tampering */\n if (!cfg || typeof cfg !== 'object') {\n cfg = {};\n }\n\n /* Shield configuration object from prototype pollution */\n cfg = clone(cfg);\n PARSER_MEDIA_TYPE =\n // eslint-disable-next-line unicorn/prefer-includes\n SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? DEFAULT_PARSER_MEDIA_TYPE : cfg.PARSER_MEDIA_TYPE;\n\n // HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.\n transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase;\n\n /* Set configuration parameters */\n ALLOWED_TAGS = objectHasOwnProperty(cfg, 'ALLOWED_TAGS') ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;\n ALLOWED_ATTR = objectHasOwnProperty(cfg, 'ALLOWED_ATTR') ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;\n ALLOWED_NAMESPACES = objectHasOwnProperty(cfg, 'ALLOWED_NAMESPACES') ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES;\n URI_SAFE_ATTRIBUTES = objectHasOwnProperty(cfg, 'ADD_URI_SAFE_ATTR') ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES),\n // eslint-disable-line indent\n cfg.ADD_URI_SAFE_ATTR,\n // eslint-disable-line indent\n transformCaseFunc // eslint-disable-line indent\n ) // eslint-disable-line indent\n : DEFAULT_URI_SAFE_ATTRIBUTES;\n DATA_URI_TAGS = objectHasOwnProperty(cfg, 'ADD_DATA_URI_TAGS') ? addToSet(clone(DEFAULT_DATA_URI_TAGS),\n // eslint-disable-line indent\n cfg.ADD_DATA_URI_TAGS,\n // eslint-disable-line indent\n transformCaseFunc // eslint-disable-line indent\n ) // eslint-disable-line indent\n : DEFAULT_DATA_URI_TAGS;\n FORBID_CONTENTS = objectHasOwnProperty(cfg, 'FORBID_CONTENTS') ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;\n FORBID_TAGS = objectHasOwnProperty(cfg, 'FORBID_TAGS') ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : {};\n FORBID_ATTR = objectHasOwnProperty(cfg, 'FORBID_ATTR') ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : {};\n USE_PROFILES = objectHasOwnProperty(cfg, 'USE_PROFILES') ? cfg.USE_PROFILES : false;\n ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true\n ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true\n ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false\n ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false; // Default true\n SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false\n SAFE_FOR_XML = cfg.SAFE_FOR_XML !== false; // Default true\n WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false\n RETURN_DOM = cfg.RETURN_DOM || false; // Default false\n RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false\n RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false\n FORCE_BODY = cfg.FORCE_BODY || false; // Default false\n SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true\n SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false\n KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true\n IN_PLACE = cfg.IN_PLACE || false; // Default false\n IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI;\n NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;\n CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};\n if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {\n CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;\n }\n if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) {\n CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;\n }\n if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === 'boolean') {\n CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;\n }\n if (SAFE_FOR_TEMPLATES) {\n ALLOW_DATA_ATTR = false;\n }\n if (RETURN_DOM_FRAGMENT) {\n RETURN_DOM = true;\n }\n\n /* Parse profile info */\n if (USE_PROFILES) {\n ALLOWED_TAGS = addToSet({}, text);\n ALLOWED_ATTR = [];\n if (USE_PROFILES.html === true) {\n addToSet(ALLOWED_TAGS, html$1);\n addToSet(ALLOWED_ATTR, html);\n }\n if (USE_PROFILES.svg === true) {\n addToSet(ALLOWED_TAGS, svg$1);\n addToSet(ALLOWED_ATTR, svg);\n addToSet(ALLOWED_ATTR, xml);\n }\n if (USE_PROFILES.svgFilters === true) {\n addToSet(ALLOWED_TAGS, svgFilters);\n addToSet(ALLOWED_ATTR, svg);\n addToSet(ALLOWED_ATTR, xml);\n }\n if (USE_PROFILES.mathMl === true) {\n addToSet(ALLOWED_TAGS, mathMl$1);\n addToSet(ALLOWED_ATTR, mathMl);\n addToSet(ALLOWED_ATTR, xml);\n }\n }\n\n /* Merge configuration parameters */\n if (cfg.ADD_TAGS) {\n if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {\n ALLOWED_TAGS = clone(ALLOWED_TAGS);\n }\n addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);\n }\n if (cfg.ADD_ATTR) {\n if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {\n ALLOWED_ATTR = clone(ALLOWED_ATTR);\n }\n addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);\n }\n if (cfg.ADD_URI_SAFE_ATTR) {\n addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);\n }\n if (cfg.FORBID_CONTENTS) {\n if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {\n FORBID_CONTENTS = clone(FORBID_CONTENTS);\n }\n addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);\n }\n\n /* Add #text in case KEEP_CONTENT is set to true */\n if (KEEP_CONTENT) {\n ALLOWED_TAGS['#text'] = true;\n }\n\n /* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */\n if (WHOLE_DOCUMENT) {\n addToSet(ALLOWED_TAGS, ['html', 'head', 'body']);\n }\n\n /* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */\n if (ALLOWED_TAGS.table) {\n addToSet(ALLOWED_TAGS, ['tbody']);\n delete FORBID_TAGS.tbody;\n }\n if (cfg.TRUSTED_TYPES_POLICY) {\n if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== 'function') {\n throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a \"createHTML\" hook.');\n }\n if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== 'function') {\n throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a \"createScriptURL\" hook.');\n }\n\n // Overwrite existing TrustedTypes policy.\n trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY;\n\n // Sign local variables required by `sanitize`.\n emptyHTML = trustedTypesPolicy.createHTML('');\n } else {\n // Uninitialized policy, attempt to initialize the internal dompurify policy.\n if (trustedTypesPolicy === undefined) {\n trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript);\n }\n\n // If creating the internal policy succeeded sign internal variables.\n if (trustedTypesPolicy !== null && typeof emptyHTML === 'string') {\n emptyHTML = trustedTypesPolicy.createHTML('');\n }\n }\n\n // Prevent further manipulation of configuration.\n // Not available in IE8, Safari 5, etc.\n if (freeze) {\n freeze(cfg);\n }\n CONFIG = cfg;\n };\n const MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);\n const HTML_INTEGRATION_POINTS = addToSet({}, ['foreignobject', 'desc', 'title', 'annotation-xml']);\n\n // Certain elements are allowed in both SVG and HTML\n // namespace. We need to specify them explicitly\n // so that they don't get erroneously deleted from\n // HTML namespace.\n const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ['title', 'style', 'font', 'a', 'script']);\n\n /* Keep track of all possible SVG and MathML tags\n * so that we can perform the namespace checks\n * correctly. */\n const ALL_SVG_TAGS = addToSet({}, [...svg$1, ...svgFilters, ...svgDisallowed]);\n const ALL_MATHML_TAGS = addToSet({}, [...mathMl$1, ...mathMlDisallowed]);\n\n /**\n * @param {Element} element a DOM element whose namespace is being checked\n * @returns {boolean} Return false if the element has a\n * namespace that a spec-compliant parser would never\n * return. Return true otherwise.\n */\n const _checkValidNamespace = function _checkValidNamespace(element) {\n let parent = getParentNode(element);\n\n // In JSDOM, if we're inside shadow DOM, then parentNode\n // can be null. We just simulate parent in this case.\n if (!parent || !parent.tagName) {\n parent = {\n namespaceURI: NAMESPACE,\n tagName: 'template'\n };\n }\n const tagName = stringToLowerCase(element.tagName);\n const parentTagName = stringToLowerCase(parent.tagName);\n if (!ALLOWED_NAMESPACES[element.namespaceURI]) {\n return false;\n }\n if (element.namespaceURI === SVG_NAMESPACE) {\n // The only way to switch from HTML namespace to SVG\n // is via <svg>. If it happens via any other tag, then\n // it should be killed.\n if (parent.namespaceURI === HTML_NAMESPACE) {\n return tagName === 'svg';\n }\n\n // The only way to switch from MathML to SVG is via`\n // svg if parent is either <annotation-xml> or MathML\n // text integration points.\n if (parent.namespaceURI === MATHML_NAMESPACE) {\n return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);\n }\n\n // We only allow elements that are defined in SVG\n // spec. All others are disallowed in SVG namespace.\n return Boolean(ALL_SVG_TAGS[tagName]);\n }\n if (element.namespaceURI === MATHML_NAMESPACE) {\n // The only way to switch from HTML namespace to MathML\n // is via <math>. If it happens via any other tag, then\n // it should be killed.\n if (parent.namespaceURI === HTML_NAMESPACE) {\n return tagName === 'math';\n }\n\n // The only way to switch from SVG to MathML is via\n // <math> and HTML integration points\n if (parent.namespaceURI === SVG_NAMESPACE) {\n return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];\n }\n\n // We only allow elements that are defined in MathML\n // spec. All others are disallowed in MathML namespace.\n return Boolean(ALL_MATHML_TAGS[tagName]);\n }\n if (element.namespaceURI === HTML_NAMESPACE) {\n // The only way to switch from SVG to HTML is via\n // HTML integration points, and from MathML to HTML\n // is via MathML text integration points\n if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) {\n return false;\n }\n if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {\n return false;\n }\n\n // We disallow tags that are specific for MathML\n // or SVG and should never appear in HTML namespace\n return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);\n }\n\n // For XHTML and XML documents that support custom namespaces\n if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && ALLOWED_NAMESPACES[element.namespaceURI]) {\n return true;\n }\n\n // The code should never reach this place (this means\n // that the element somehow got namespace that is not\n // HTML, SVG, MathML or allowed via ALLOWED_NAMESPACES).\n // Return false just in case.\n return false;\n };\n\n /**\n * _forceRemove\n *\n * @param {Node} node a DOM node\n */\n const _forceRemove = function _forceRemove(node) {\n arrayPush(DOMPurify.removed, {\n element: node\n });\n try {\n // eslint-disable-next-line unicorn/prefer-dom-node-remove\n node.parentNode.removeChild(node);\n } catch (_) {\n node.remove();\n }\n };\n\n /**\n * _removeAttribute\n *\n * @param {String} name an Attribute name\n * @param {Node} node a DOM node\n */\n const _removeAttribute = function _removeAttribute(name, node) {\n try {\n arrayPush(DOMPurify.removed, {\n attribute: node.getAttributeNode(name),\n from: node\n });\n } catch (_) {\n arrayPush(DOMPurify.removed, {\n attribute: null,\n from: node\n });\n }\n node.removeAttribute(name);\n\n // We void attribute values for unremovable \"is\"\" attributes\n if (name === 'is' && !ALLOWED_ATTR[name]) {\n if (RETURN_DOM || RETURN_DOM_FRAGMENT) {\n try {\n _forceRemove(node);\n } catch (_) {}\n } else {\n try {\n node.setAttribute(name, '');\n } catch (_) {}\n }\n }\n };\n\n /**\n * _initDocument\n *\n * @param {String} dirty a string of dirty markup\n * @return {Document} a DOM, filled with the dirty markup\n */\n const _initDocument = function _initDocument(dirty) {\n /* Create a HTML document */\n let doc = null;\n let leadingWhitespace = null;\n if (FORCE_BODY) {\n dirty = '<remove></remove>' + dirty;\n } else {\n /* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */\n const matches = stringMatch(dirty, /^[\\r\\n\\t ]+/);\n leadingWhitespace = matches && matches[0];\n }\n if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && NAMESPACE === HTML_NAMESPACE) {\n // Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict)\n dirty = '<html xmlns=\"http://www.w3.org/1999/xhtml\"><head></head><body>' + dirty + '</body></html>';\n }\n const dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;\n /*\n * Use the DOMParser API by default, fallback later if needs be\n * DOMParser not work for svg when has multiple root element.\n */\n if (NAMESPACE === HTML_NAMESPACE) {\n try {\n doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);\n } catch (_) {}\n }\n\n /* Use createHTMLDocument in case DOMParser is not available */\n if (!doc || !doc.documentElement) {\n doc = implementation.createDocument(NAMESPACE, 'template', null);\n try {\n doc.documentElement.innerHTML = IS_EMPTY_INPUT ? emptyHTML : dirtyPayload;\n } catch (_) {\n // Syntax error if dirtyPayload is invalid xml\n }\n }\n const body = doc.body || doc.documentElement;\n if (dirty && leadingWhitespace) {\n body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);\n }\n\n /* Work on whole document or just its body */\n if (NAMESPACE === HTML_NAMESPACE) {\n return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];\n }\n return WHOLE_DOCUMENT ? doc.documentElement : body;\n };\n\n /**\n * Creates a NodeIterator object that you can use to traverse filtered lists of nodes or elements in a document.\n *\n * @param {Node} root The root element or node to start traversing on.\n * @return {NodeIterator} The created NodeIterator\n */\n const _createNodeIterator = function _createNodeIterator(root) {\n return createNodeIterator.call(root.ownerDocument || root, root,\n // eslint-disable-next-line no-bitwise\n NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION, null);\n };\n\n /**\n * _isClobbered\n *\n * @param {Node} elm element to check for clobbering attacks\n * @return {Boolean} true if clobbered, false if safe\n */\n const _isClobbered = function _isClobbered(elm) {\n 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' || typeof elm.hasChildNodes !== 'function');\n };\n\n /**\n * Checks whether the given object is a DOM node.\n *\n * @param {Node} object object to check whether it's a DOM node\n * @return {Boolean} true is object is a DOM node\n */\n const _isNode = function _isNode(object) {\n return typeof Node === 'function' && object instanceof Node;\n };\n\n /**\n * _executeHook\n * Execute user configurable hooks\n *\n * @param {String} entryPoint Name of the hook's entry point\n * @param {Node} currentNode node to work on with the hook\n * @param {Object} data additional hook parameters\n */\n const _executeHook = function _executeHook(entryPoint, currentNode, data) {\n if (!hooks[entryPoint]) {\n return;\n }\n arrayForEach(hooks[entryPoint], hook => {\n hook.call(DOMPurify, currentNode, data, CONFIG);\n });\n };\n\n /**\n * _sanitizeElements\n *\n * @protect nodeName\n * @protect textContent\n * @protect removeChild\n *\n * @param {Node} currentNode to check for permission to exist\n * @return {Boolean} true if node was killed, false if left alive\n */\n const _sanitizeElements = function _sanitizeElements(currentNode) {\n let content = null;\n\n /* Execute a hook if present */\n _executeHook('beforeSanitizeElements', currentNode, null);\n\n /* Check if element is clobbered or can clobber */\n if (_isClobbered(currentNode)) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Now let's check the element's type and name */\n const tagName = transformCaseFunc(currentNode.nodeName);\n\n /* Execute a hook if present */\n _executeHook('uponSanitizeElement', currentNode, {\n tagName,\n allowedTags: ALLOWED_TAGS\n });\n\n /* Detect mXSS attempts abusing namespace confusion */\n if (currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(/<[/\\w]/g, currentNode.innerHTML) && regExpTest(/<[/\\w]/g, currentNode.textContent)) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Remove any ocurrence of processing instructions */\n if (currentNode.nodeType === 7) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Remove any kind of possibly harmful comments */\n if (SAFE_FOR_XML && currentNode.nodeType === 8 && regExpTest(/<[/\\w]/g, currentNode.data)) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Remove element if anything forbids its presence */\n if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {\n /* Check if we have a custom element to handle */\n if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) {\n if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) {\n return false;\n }\n if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) {\n return false;\n }\n }\n\n /* Keep content except for bad-listed elements */\n if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {\n const parentNode = getParentNode(currentNode) || currentNode.parentNode;\n const childNodes = getChildNodes(currentNode) || currentNode.childNodes;\n if (childNodes && parentNode) {\n const childCount = childNodes.length;\n for (let i = childCount - 1; i >= 0; --i) {\n parentNode.insertBefore(cloneNode(childNodes[i], true), getNextSibling(currentNode));\n }\n }\n }\n _forceRemove(currentNode);\n return true;\n }\n\n /* Check whether element has a valid namespace */\n if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Make sure that older browsers don't get fallback-tag mXSS */\n if ((tagName === 'noscript' || tagName === 'noembed' || tagName === 'noframes') && regExpTest(/<\\/no(script|embed|frames)/i, currentNode.innerHTML)) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Sanitize element content to be template-safe */\n if (SAFE_FOR_TEMPLATES && currentNode.nodeType === 3) {\n /* Get the element's text content */\n content = currentNode.textContent;\n arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {\n content = stringReplace(content, expr, ' ');\n });\n if (currentNode.textContent !== content) {\n arrayPush(DOMPurify.removed, {\n element: currentNode.cloneNode()\n });\n currentNode.textContent = content;\n }\n }\n\n /* Execute a hook if present */\n _executeHook('afterSanitizeElements', currentNode, null);\n return false;\n };\n\n /**\n * _isValidAttribute\n *\n * @param {string} lcTag Lowercase tag name of containing element.\n * @param {string} lcName Lowercase attribute name.\n * @param {string} value Attribute value.\n * @return {Boolean} Returns true if `value` is valid, otherwise false.\n */\n // eslint-disable-next-line complexity\n const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {\n /* Make sure attribute cannot clobber */\n if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {\n return false;\n }\n\n /* Allow valid data-* attributes: At least one character after \"-\"\n (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)\n XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)\n We don't need to check the value; it's always URI safe. */\n 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]) {\n if (\n // First condition does a very basic check if a) it's basically a valid custom element tagname AND\n // b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck\n // and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck\n _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)) ||\n // Alternative, second condition checks if it's an `is`-attribute, AND\n // the value passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck\n 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 {\n return false;\n }\n /* Check value is safe. First, is attr inert? If so, is safe */\n } 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) {\n return false;\n } else ;\n return true;\n };\n\n /**\n * _isBasicCustomElement\n * checks if at least one dash is included in tagName, and it's not the first char\n * for more sophisticated checking see https://github.com/sindresorhus/validate-element-name\n *\n * @param {string} tagName name of the tag of the node to sanitize\n * @returns {boolean} Returns true if the tag name meets the basic criteria for a custom element, otherwise false.\n */\n const _isBasicCustomElement = function _isBasicCustomElement(tagName) {\n return tagName !== 'annotation-xml' && stringMatch(tagName, CUSTOM_ELEMENT);\n };\n\n /**\n * _sanitizeAttributes\n *\n * @protect attributes\n * @protect nodeName\n * @protect removeAttribute\n * @protect setAttribute\n *\n * @param {Node} currentNode to sanitize\n */\n const _sanitizeAttributes = function _sanitizeAttributes(currentNode) {\n /* Execute a hook if present */\n _executeHook('beforeSanitizeAttributes', currentNode, null);\n const {\n attributes\n } = currentNode;\n\n /* Check if we have attributes; if not we might have a text node */\n if (!attributes) {\n return;\n }\n const hookEvent = {\n attrName: '',\n attrValue: '',\n keepAttr: true,\n allowedAttributes: ALLOWED_ATTR\n };\n let l = attributes.length;\n\n /* Go backwards over all attributes; safely remove bad ones */\n while (l--) {\n const attr = attributes[l];\n const {\n name,\n namespaceURI,\n value: attrValue\n } = attr;\n const lcName = transformCaseFunc(name);\n let value = name === 'value' ? attrValue : stringTrim(attrValue);\n\n /* Execute a hook if present */\n hookEvent.attrName = lcName;\n hookEvent.attrValue = value;\n hookEvent.keepAttr = true;\n hookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set\n _executeHook('uponSanitizeAttribute', currentNode, hookEvent);\n value = hookEvent.attrValue;\n /* Did the hooks approve of the attribute? */\n if (hookEvent.forceKeepAttr) {\n continue;\n }\n\n /* Remove attribute */\n _removeAttribute(name, currentNode);\n\n /* Did the hooks approve of the attribute? */\n if (!hookEvent.keepAttr) {\n continue;\n }\n\n /* Work around a security issue in jQuery 3.0 */\n if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(/\\/>/i, value)) {\n _removeAttribute(name, currentNode);\n continue;\n }\n\n /* Sanitize attribute content to be template-safe */\n if (SAFE_FOR_TEMPLATES) {\n arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {\n value = stringReplace(value, expr, ' ');\n });\n }\n\n /* Is `value` valid for this attribute? */\n const lcTag = transformCaseFunc(currentNode.nodeName);\n if (!_isValidAttribute(lcTag, lcName, value)) {\n continue;\n }\n\n /* Full DOM Clobbering protection via namespace isolation,\n * Prefix id and name attributes with `user-content-`\n */\n if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {\n // Remove the attribute with this value\n _removeAttribute(name, currentNode);\n\n // Prefix the value and later re-create the attribute with the sanitized value\n value = SANITIZE_NAMED_PROPS_PREFIX + value;\n }\n\n /* Handle attributes that require Trusted Types */\n if (trustedTypesPolicy && typeof trustedTypes === 'object' && typeof trustedTypes.getAttributeType === 'function') {\n if (namespaceURI) ; else {\n switch (trustedTypes.getAttributeType(lcTag, lcName)) {\n case 'TrustedHTML':\n {\n value = trustedTypesPolicy.createHTML(value);\n break;\n }\n case 'TrustedScriptURL':\n {\n value = trustedTypesPolicy.createScriptURL(value);\n break;\n }\n }\n }\n }\n\n /* Handle invalid data-* attribute set by try-catching it */\n try {\n if (namespaceURI) {\n currentNode.setAttributeNS(namespaceURI, name, value);\n } else {\n /* Fallback to setAttribute() for browser-unrecognized namespaces e.g. \"x-schema\". */\n currentNode.setAttribute(name, value);\n }\n arrayPop(DOMPurify.removed);\n } catch (_) {}\n }\n\n /* Execute a hook if present */\n _executeHook('afterSanitizeAttributes', currentNode, null);\n };\n\n /**\n * _sanitizeShadowDOM\n *\n * @param {DocumentFragment} fragment to iterate over recursively\n */\n const _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {\n let shadowNode = null;\n const shadowIterator = _createNodeIterator(fragment);\n\n /* Execute a hook if present */\n _executeHook('beforeSanitizeShadowDOM', fragment, null);\n while (shadowNode = shadowIterator.nextNode()) {\n /* Execute a hook if present */\n _executeHook('uponSanitizeShadowNode', shadowNode, null);\n\n /* Sanitize tags and elements */\n if (_sanitizeElements(shadowNode)) {\n continue;\n }\n\n /* Deep shadow DOM detected */\n if (shadowNode.content instanceof DocumentFragment) {\n _sanitizeShadowDOM(shadowNode.content);\n }\n\n /* Check attributes, sanitize if necessary */\n _sanitizeAttributes(shadowNode);\n }\n\n /* Execute a hook if present */\n _executeHook('afterSanitizeShadowDOM', fragment, null);\n };\n\n /**\n * Sanitize\n * Public method providing core sanitation functionality\n *\n * @param {String|Node} dirty string or DOM node\n * @param {Object} cfg object\n */\n // eslint-disable-next-line complexity\n DOMPurify.sanitize = function (dirty) {\n let cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n let body = null;\n let importedNode = null;\n let currentNode = null;\n let returnNode = null;\n /* Make sure we have a string to sanitize.\n DO NOT return early, as this will return the wrong type if\n the user has requested a DOM object rather than a string */\n IS_EMPTY_INPUT = !dirty;\n if (IS_EMPTY_INPUT) {\n dirty = '<!-->';\n }\n\n /* Stringify, in case dirty is an object */\n if (typeof dirty !== 'string' && !_isNode(dirty)) {\n if (typeof dirty.toString === 'function') {\n dirty = dirty.toString();\n if (typeof dirty !== 'string') {\n throw typeErrorCreate('dirty is not a string, aborting');\n }\n } else {\n throw typeErrorCreate('toString is not a function');\n }\n }\n\n /* Return dirty HTML if DOMPurify cannot run */\n if (!DOMPurify.isSupported) {\n return dirty;\n }\n\n /* Assign config vars */\n if (!SET_CONFIG) {\n _parseConfig(cfg);\n }\n\n /* Clean up removed elements */\n DOMPurify.removed = [];\n\n /* Check if dirty is correctly typed for IN_PLACE */\n if (typeof dirty === 'string') {\n IN_PLACE = false;\n }\n if (IN_PLACE) {\n /* Do some early pre-sanitization to avoid unsafe root nodes */\n if (dirty.nodeName) {\n const tagName = transformCaseFunc(dirty.nodeName);\n if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {\n throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');\n }\n }\n } else if (dirty instanceof Node) {\n /* If dirty is a DOM element, append to an empty document to avoid\n elements being stripped by the parser */\n body = _initDocument('<!---->');\n importedNode = body.ownerDocument.importNode(dirty, true);\n if (importedNode.nodeType === 1 && importedNode.nodeName === 'BODY') {\n /* Node is already a body, use as is */\n body = importedNode;\n } else if (importedNode.nodeName === 'HTML') {\n body = importedNode;\n } else {\n // eslint-disable-next-line unicorn/prefer-dom-node-append\n body.appendChild(importedNode);\n }\n } else {\n /* Exit directly if we have nothing to do */\n if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT &&\n // eslint-disable-next-line unicorn/prefer-includes\n dirty.indexOf('<') === -1) {\n return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;\n }\n\n /* Initialize the document to work on */\n body = _initDocument(dirty);\n\n /* Check we have a DOM node from the data */\n if (!body) {\n return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';\n }\n }\n\n /* Remove first element node (ours) if FORCE_BODY is set */\n if (body && FORCE_BODY) {\n _forceRemove(body.firstChild);\n }\n\n /* Get node iterator */\n const nodeIterator = _createNodeIterator(IN_PLACE ? dirty : body);\n\n /* Now start iterating over the created document */\n while (currentNode = nodeIterator.nextNode()) {\n /* Sanitize tags and elements */\n if (_sanitizeElements(currentNode)) {\n continue;\n }\n\n /* Shadow DOM detected, sanitize it */\n if (currentNode.content instanceof DocumentFragment) {\n _sanitizeShadowDOM(currentNode.content);\n }\n\n /* Check attributes, sanitize if necessary */\n _sanitizeAttributes(currentNode);\n }\n\n /* If we sanitized `dirty` in-place, return it. */\n if (IN_PLACE) {\n return dirty;\n }\n\n /* Return sanitized string or DOM */\n if (RETURN_DOM) {\n if (RETURN_DOM_FRAGMENT) {\n returnNode = createDocumentFragment.call(body.ownerDocument);\n while (body.firstChild) {\n // eslint-disable-next-line unicorn/prefer-dom-node-append\n returnNode.appendChild(body.firstChild);\n }\n } else {\n returnNode = body;\n }\n if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmode) {\n /*\n AdoptNode() is not used because internal state is not reset\n (e.g. the past names map of a HTMLFormElement), this is safe\n in theory but we would rather not risk another attack vector.\n The state that is cloned by importNode() is explicitly defined\n by the specs.\n */\n returnNode = importNode.call(originalDocument, returnNode, true);\n }\n return returnNode;\n }\n let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;\n\n /* Serialize doctype if allowed */\n if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {\n serializedHTML = '<!DOCTYPE ' + body.ownerDocument.doctype.name + '>\\n' + serializedHTML;\n }\n\n /* Sanitize final string template-safe */\n if (SAFE_FOR_TEMPLATES) {\n arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {\n serializedHTML = stringReplace(serializedHTML, expr, ' ');\n });\n }\n return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;\n };\n\n /**\n * Public method to set the configuration once\n * setConfig\n *\n * @param {Object} cfg configuration object\n */\n DOMPurify.setConfig = function () {\n let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n _parseConfig(cfg);\n SET_CONFIG = true;\n };\n\n /**\n * Public method to remove the configuration\n * clearConfig\n *\n */\n DOMPurify.clearConfig = function () {\n CONFIG = null;\n SET_CONFIG = false;\n };\n\n /**\n * Public method to check if an attribute value is valid.\n * Uses last set config, if any. Otherwise, uses config defaults.\n * isValidAttribute\n *\n * @param {String} tag Tag name of containing element.\n * @param {String} attr Attribute name.\n * @param {String} value Attribute value.\n * @return {Boolean} Returns true if `value` is valid. Otherwise, returns false.\n */\n DOMPurify.isValidAttribute = function (tag, attr, value) {\n /* Initialize shared config vars if necessary. */\n if (!CONFIG) {\n _parseConfig({});\n }\n const lcTag = transformCaseFunc(tag);\n const lcName = transformCaseFunc(attr);\n return _isValidAttribute(lcTag, lcName, value);\n };\n\n /**\n * AddHook\n * Public method to add DOMPurify hooks\n *\n * @param {String} entryPoint entry point for the hook to add\n * @param {Function} hookFunction function to execute\n */\n DOMPurify.addHook = function (entryPoint, hookFunction) {\n if (typeof hookFunction !== 'function') {\n return;\n }\n hooks[entryPoint] = hooks[entryPoint] || [];\n arrayPush(hooks[entryPoint], hookFunction);\n };\n\n /**\n * RemoveHook\n * Public method to remove a DOMPurify hook at a given entryPoint\n * (pops it from the stack of hooks if more are present)\n *\n * @param {String} entryPoint entry point for the hook to remove\n * @return {Function} removed(popped) hook\n */\n DOMPurify.removeHook = function (entryPoint) {\n if (hooks[entryPoint]) {\n return arrayPop(hooks[entryPoint]);\n }\n };\n\n /**\n * RemoveHooks\n * Public method to remove all DOMPurify hooks at a given entryPoint\n *\n * @param {String} entryPoint entry point for the hooks to remove\n */\n DOMPurify.removeHooks = function (entryPoint) {\n if (hooks[entryPoint]) {\n hooks[entryPoint] = [];\n }\n };\n\n /**\n * RemoveAllHooks\n * Public method to remove all DOMPurify hooks\n */\n DOMPurify.removeAllHooks = function () {\n hooks = {};\n };\n return DOMPurify;\n }\n var purify = createDOMPurify();\n\n return purify;\n\n}));\n//# sourceMappingURL=purify.js.map\n\n\n//# sourceURL=webpack://Formio/./node_modules/@formio/core/node_modules/dompurify/dist/purify.js?");
|
|
1930
|
+
|
|
1931
|
+
/***/ }),
|
|
1932
|
+
|
|
1923
1933
|
/***/ "./node_modules/@formio/core/node_modules/inputmask/dist/inputmask.js":
|
|
1924
1934
|
/*!****************************************************************************!*\
|
|
1925
1935
|
!*** ./node_modules/@formio/core/node_modules/inputmask/dist/inputmask.js ***!
|
|
@@ -2718,7 +2728,7 @@ eval("!function(t,i){ true?module.exports=i():0}(this,(function(){\"use strict\"
|
|
|
2718
2728
|
\***********************************************/
|
|
2719
2729
|
/***/ (function(module) {
|
|
2720
2730
|
|
|
2721
|
-
eval("/*! @license DOMPurify 3.1.0 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.1.0/LICENSE */\n\n(function (global, factory) {\n true ? module.exports = factory() :\n 0;\n})(this, (function () { 'use strict';\n\n const {\n entries,\n setPrototypeOf,\n isFrozen,\n getPrototypeOf,\n getOwnPropertyDescriptor\n } = Object;\n let {\n freeze,\n seal,\n create\n } = Object; // eslint-disable-line import/no-mutable-exports\n let {\n apply,\n construct\n } = typeof Reflect !== 'undefined' && Reflect;\n if (!freeze) {\n freeze = function freeze(x) {\n return x;\n };\n }\n if (!seal) {\n seal = function seal(x) {\n return x;\n };\n }\n if (!apply) {\n apply = function apply(fun, thisValue, args) {\n return fun.apply(thisValue, args);\n };\n }\n if (!construct) {\n construct = function construct(Func, args) {\n return new Func(...args);\n };\n }\n const arrayForEach = unapply(Array.prototype.forEach);\n const arrayPop = unapply(Array.prototype.pop);\n const arrayPush = unapply(Array.prototype.push);\n const stringToLowerCase = unapply(String.prototype.toLowerCase);\n const stringToString = unapply(String.prototype.toString);\n const stringMatch = unapply(String.prototype.match);\n const stringReplace = unapply(String.prototype.replace);\n const stringIndexOf = unapply(String.prototype.indexOf);\n const stringTrim = unapply(String.prototype.trim);\n const objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);\n const regExpTest = unapply(RegExp.prototype.test);\n const typeErrorCreate = unconstruct(TypeError);\n\n /**\n * Creates a new function that calls the given function with a specified thisArg and arguments.\n *\n * @param {Function} func - The function to be wrapped and called.\n * @returns {Function} A new function that calls the given function with a specified thisArg and arguments.\n */\n function unapply(func) {\n return function (thisArg) {\n for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n args[_key - 1] = arguments[_key];\n }\n return apply(func, thisArg, args);\n };\n }\n\n /**\n * Creates a new function that constructs an instance of the given constructor function with the provided arguments.\n *\n * @param {Function} func - The constructor function to be wrapped and called.\n * @returns {Function} A new function that constructs an instance of the given constructor function with the provided arguments.\n */\n function unconstruct(func) {\n return function () {\n for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {\n args[_key2] = arguments[_key2];\n }\n return construct(func, args);\n };\n }\n\n /**\n * Add properties to a lookup table\n *\n * @param {Object} set - The set to which elements will be added.\n * @param {Array} array - The array containing elements to be added to the set.\n * @param {Function} transformCaseFunc - An optional function to transform the case of each element before adding to the set.\n * @returns {Object} The modified set with added elements.\n */\n function addToSet(set, array) {\n let transformCaseFunc = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : stringToLowerCase;\n if (setPrototypeOf) {\n // Make 'in' and truthy checks like Boolean(set.constructor)\n // independent of any properties defined on Object.prototype.\n // Prevent prototype setters from intercepting set as a this value.\n setPrototypeOf(set, null);\n }\n let l = array.length;\n while (l--) {\n let element = array[l];\n if (typeof element === 'string') {\n const lcElement = transformCaseFunc(element);\n if (lcElement !== element) {\n // Config presets (e.g. tags.js, attrs.js) are immutable.\n if (!isFrozen(array)) {\n array[l] = lcElement;\n }\n element = lcElement;\n }\n }\n set[element] = true;\n }\n return set;\n }\n\n /**\n * Clean up an array to harden against CSPP\n *\n * @param {Array} array - The array to be cleaned.\n * @returns {Array} The cleaned version of the array\n */\n function cleanArray(array) {\n for (let index = 0; index < array.length; index++) {\n const isPropertyExist = objectHasOwnProperty(array, index);\n if (!isPropertyExist) {\n array[index] = null;\n }\n }\n return array;\n }\n\n /**\n * Shallow clone an object\n *\n * @param {Object} object - The object to be cloned.\n * @returns {Object} A new object that copies the original.\n */\n function clone(object) {\n const newObject = create(null);\n for (const [property, value] of entries(object)) {\n const isPropertyExist = objectHasOwnProperty(object, property);\n if (isPropertyExist) {\n if (Array.isArray(value)) {\n newObject[property] = cleanArray(value);\n } else if (value && typeof value === 'object' && value.constructor === Object) {\n newObject[property] = clone(value);\n } else {\n newObject[property] = value;\n }\n }\n }\n return newObject;\n }\n\n /**\n * This method automatically checks if the prop is function or getter and behaves accordingly.\n *\n * @param {Object} object - The object to look up the getter function in its prototype chain.\n * @param {String} prop - The property name for which to find the getter function.\n * @returns {Function} The getter function found in the prototype chain or a fallback function.\n */\n function lookupGetter(object, prop) {\n while (object !== null) {\n const desc = getOwnPropertyDescriptor(object, prop);\n if (desc) {\n if (desc.get) {\n return unapply(desc.get);\n }\n if (typeof desc.value === 'function') {\n return unapply(desc.value);\n }\n }\n object = getPrototypeOf(object);\n }\n function fallbackValue() {\n return null;\n }\n return fallbackValue;\n }\n\n 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']);\n\n // SVG\n 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']);\n 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']);\n\n // List of SVG elements that are disallowed by default.\n // We still need to know them so that we can do namespace\n // checks properly in case one wants to add them to\n // allow-list.\n 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']);\n 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']);\n\n // Similarly to SVG, we want to know all MathML elements,\n // even those that we disallow by default.\n const mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);\n const text = freeze(['#text']);\n\n 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', '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']);\n const svg = 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']);\n 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']);\n const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);\n\n // eslint-disable-next-line unicorn/better-regex\n const MUSTACHE_EXPR = seal(/\\{\\{[\\w\\W]*|[\\w\\W]*\\}\\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode\n const ERB_EXPR = seal(/<%[\\w\\W]*|[\\w\\W]*%>/gm);\n const TMPLIT_EXPR = seal(/\\${[\\w\\W]*}/gm);\n const DATA_ATTR = seal(/^data-[\\-\\w.\\u00B7-\\uFFFF]/); // eslint-disable-line no-useless-escape\n const ARIA_ATTR = seal(/^aria-[\\-\\w]+$/); // eslint-disable-line no-useless-escape\n 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\n );\n\n const IS_SCRIPT_OR_DATA = seal(/^(?:\\w+script|data):/i);\n const ATTR_WHITESPACE = seal(/[\\u0000-\\u0020\\u00A0\\u1680\\u180E\\u2000-\\u2029\\u205F\\u3000]/g // eslint-disable-line no-control-regex\n );\n\n const DOCTYPE_NAME = seal(/^html$/i);\n const CUSTOM_ELEMENT = seal(/^[a-z][.\\w]*(-[.\\w]+)+$/i);\n\n var EXPRESSIONS = /*#__PURE__*/Object.freeze({\n __proto__: null,\n MUSTACHE_EXPR: MUSTACHE_EXPR,\n ERB_EXPR: ERB_EXPR,\n TMPLIT_EXPR: TMPLIT_EXPR,\n DATA_ATTR: DATA_ATTR,\n ARIA_ATTR: ARIA_ATTR,\n IS_ALLOWED_URI: IS_ALLOWED_URI,\n IS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA,\n ATTR_WHITESPACE: ATTR_WHITESPACE,\n DOCTYPE_NAME: DOCTYPE_NAME,\n CUSTOM_ELEMENT: CUSTOM_ELEMENT\n });\n\n const getGlobal = function getGlobal() {\n return typeof window === 'undefined' ? null : window;\n };\n\n /**\n * Creates a no-op policy for internal use only.\n * Don't export this function outside this module!\n * @param {TrustedTypePolicyFactory} trustedTypes The policy factory.\n * @param {HTMLScriptElement} purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix).\n * @return {TrustedTypePolicy} The policy created (or null, if Trusted Types\n * are not supported or creating the policy failed).\n */\n const _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, purifyHostElement) {\n if (typeof trustedTypes !== 'object' || typeof trustedTypes.createPolicy !== 'function') {\n return null;\n }\n\n // Allow the callers to control the unique policy name\n // by adding a data-tt-policy-suffix to the script element with the DOMPurify.\n // Policy creation with duplicate names throws in Trusted Types.\n let suffix = null;\n const ATTR_NAME = 'data-tt-policy-suffix';\n if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) {\n suffix = purifyHostElement.getAttribute(ATTR_NAME);\n }\n const policyName = 'dompurify' + (suffix ? '#' + suffix : '');\n try {\n return trustedTypes.createPolicy(policyName, {\n createHTML(html) {\n return html;\n },\n createScriptURL(scriptUrl) {\n return scriptUrl;\n }\n });\n } catch (_) {\n // Policy creation failed (most likely another DOMPurify script has\n // already run). Skip creating the policy, as this will only cause errors\n // if TT are enforced.\n console.warn('TrustedTypes policy ' + policyName + ' could not be created.');\n return null;\n }\n };\n function createDOMPurify() {\n let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();\n const DOMPurify = root => createDOMPurify(root);\n\n /**\n * Version label, exposed for easier checks\n * if DOMPurify is up to date or not\n */\n DOMPurify.version = '3.1.0';\n\n /**\n * Array of elements that DOMPurify removed during sanitation.\n * Empty if nothing was removed.\n */\n DOMPurify.removed = [];\n if (!window || !window.document || window.document.nodeType !== 9) {\n // Not running in a browser, provide a factory function\n // so that you can pass your own Window\n DOMPurify.isSupported = false;\n return DOMPurify;\n }\n let {\n document\n } = window;\n const originalDocument = document;\n const currentScript = originalDocument.currentScript;\n const {\n DocumentFragment,\n HTMLTemplateElement,\n Node,\n Element,\n NodeFilter,\n NamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap,\n HTMLFormElement,\n DOMParser,\n trustedTypes\n } = window;\n const ElementPrototype = Element.prototype;\n const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');\n const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');\n const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');\n const getParentNode = lookupGetter(ElementPrototype, 'parentNode');\n\n // As per issue #47, the web-components registry is inherited by a\n // new document created via createHTMLDocument. As per the spec\n // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)\n // a new empty registry is used when creating a template contents owner\n // document, so we use that as our parent document to ensure nothing\n // is inherited.\n if (typeof HTMLTemplateElement === 'function') {\n const template = document.createElement('template');\n if (template.content && template.content.ownerDocument) {\n document = template.content.ownerDocument;\n }\n }\n let trustedTypesPolicy;\n let emptyHTML = '';\n const {\n implementation,\n createNodeIterator,\n createDocumentFragment,\n getElementsByTagName\n } = document;\n const {\n importNode\n } = originalDocument;\n let hooks = {};\n\n /**\n * Expose whether this browser supports running the full DOMPurify.\n */\n DOMPurify.isSupported = typeof entries === 'function' && typeof getParentNode === 'function' && implementation && implementation.createHTMLDocument !== undefined;\n const {\n MUSTACHE_EXPR,\n ERB_EXPR,\n TMPLIT_EXPR,\n DATA_ATTR,\n ARIA_ATTR,\n IS_SCRIPT_OR_DATA,\n ATTR_WHITESPACE,\n CUSTOM_ELEMENT\n } = EXPRESSIONS;\n let {\n IS_ALLOWED_URI: IS_ALLOWED_URI$1\n } = EXPRESSIONS;\n\n /**\n * We consider the elements and attributes below to be safe. Ideally\n * don't add any new ones but feel free to remove unwanted ones.\n */\n\n /* allowed element names */\n let ALLOWED_TAGS = null;\n const DEFAULT_ALLOWED_TAGS = addToSet({}, [...html$1, ...svg$1, ...svgFilters, ...mathMl$1, ...text]);\n\n /* Allowed attribute names */\n let ALLOWED_ATTR = null;\n const DEFAULT_ALLOWED_ATTR = addToSet({}, [...html, ...svg, ...mathMl, ...xml]);\n\n /*\n * Configure how DOMPUrify should handle custom elements and their attributes as well as customized built-in elements.\n * @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)\n * @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list)\n * @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.\n */\n let CUSTOM_ELEMENT_HANDLING = Object.seal(create(null, {\n tagNameCheck: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: null\n },\n attributeNameCheck: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: null\n },\n allowCustomizedBuiltInElements: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: false\n }\n }));\n\n /* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */\n let FORBID_TAGS = null;\n\n /* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */\n let FORBID_ATTR = null;\n\n /* Decide if ARIA attributes are okay */\n let ALLOW_ARIA_ATTR = true;\n\n /* Decide if custom data attributes are okay */\n let ALLOW_DATA_ATTR = true;\n\n /* Decide if unknown protocols are okay */\n let ALLOW_UNKNOWN_PROTOCOLS = false;\n\n /* Decide if self-closing tags in attributes are allowed.\n * Usually removed due to a mXSS issue in jQuery 3.0 */\n let ALLOW_SELF_CLOSE_IN_ATTR = true;\n\n /* Output should be safe for common template engines.\n * This means, DOMPurify removes data attributes, mustaches and ERB\n */\n let SAFE_FOR_TEMPLATES = false;\n\n /* Output should be safe even for XML used within HTML and alike.\n * This means, DOMPurify removes comments when containing risky content.\n */\n let SAFE_FOR_XML = true;\n\n /* Decide if document with <html>... should be returned */\n let WHOLE_DOCUMENT = false;\n\n /* Track whether config is already set on this instance of DOMPurify. */\n let SET_CONFIG = false;\n\n /* Decide if all elements (e.g. style, script) must be children of\n * document.body. By default, browsers might move them to document.head */\n let FORCE_BODY = false;\n\n /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html\n * string (or a TrustedHTML object if Trusted Types are supported).\n * If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead\n */\n let RETURN_DOM = false;\n\n /* Decide if a DOM `DocumentFragment` should be returned, instead of a html\n * string (or a TrustedHTML object if Trusted Types are supported) */\n let RETURN_DOM_FRAGMENT = false;\n\n /* Try to return a Trusted Type object instead of a string, return a string in\n * case Trusted Types are not supported */\n let RETURN_TRUSTED_TYPE = false;\n\n /* Output should be free from DOM clobbering attacks?\n * This sanitizes markups named with colliding, clobberable built-in DOM APIs.\n */\n let SANITIZE_DOM = true;\n\n /* Achieve full DOM Clobbering protection by isolating the namespace of named\n * properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules.\n *\n * HTML/DOM spec rules that enable DOM Clobbering:\n * - Named Access on Window (§7.3.3)\n * - DOM Tree Accessors (§3.1.5)\n * - Form Element Parent-Child Relations (§4.10.3)\n * - Iframe srcdoc / Nested WindowProxies (§4.8.5)\n * - HTMLCollection (§4.2.10.2)\n *\n * Namespace isolation is implemented by prefixing `id` and `name` attributes\n * with a constant string, i.e., `user-content-`\n */\n let SANITIZE_NAMED_PROPS = false;\n const SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';\n\n /* Keep element content when removing element? */\n let KEEP_CONTENT = true;\n\n /* If a `Node` is passed to sanitize(), then performs sanitization in-place instead\n * of importing it into a new Document and returning a sanitized copy */\n let IN_PLACE = false;\n\n /* Allow usage of profiles like html, svg and mathMl */\n let USE_PROFILES = {};\n\n /* Tags to ignore content of when KEEP_CONTENT is true */\n let FORBID_CONTENTS = null;\n 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']);\n\n /* Tags that are safe for data: URIs */\n let DATA_URI_TAGS = null;\n const DEFAULT_DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image', 'track']);\n\n /* Attributes safe for values like \"javascript:\" */\n let URI_SAFE_ATTRIBUTES = null;\n const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'role', 'summary', 'title', 'value', 'style', 'xmlns']);\n const MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';\n const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';\n const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';\n /* Document namespace */\n let NAMESPACE = HTML_NAMESPACE;\n let IS_EMPTY_INPUT = false;\n\n /* Allowed XHTML+XML namespaces */\n let ALLOWED_NAMESPACES = null;\n const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE], stringToString);\n\n /* Parsing of strict XHTML documents */\n let PARSER_MEDIA_TYPE = null;\n const SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html'];\n const DEFAULT_PARSER_MEDIA_TYPE = 'text/html';\n let transformCaseFunc = null;\n\n /* Keep a reference to config to pass to hooks */\n let CONFIG = null;\n\n /* Ideally, do not touch anything below this line */\n /* ______________________________________________ */\n\n const formElement = document.createElement('form');\n const isRegexOrFunction = function isRegexOrFunction(testValue) {\n return testValue instanceof RegExp || testValue instanceof Function;\n };\n\n /**\n * _parseConfig\n *\n * @param {Object} cfg optional config literal\n */\n // eslint-disable-next-line complexity\n const _parseConfig = function _parseConfig() {\n let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n if (CONFIG && CONFIG === cfg) {\n return;\n }\n\n /* Shield configuration object from tampering */\n if (!cfg || typeof cfg !== 'object') {\n cfg = {};\n }\n\n /* Shield configuration object from prototype pollution */\n cfg = clone(cfg);\n PARSER_MEDIA_TYPE =\n // eslint-disable-next-line unicorn/prefer-includes\n SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? DEFAULT_PARSER_MEDIA_TYPE : cfg.PARSER_MEDIA_TYPE;\n\n // HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.\n transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase;\n\n /* Set configuration parameters */\n ALLOWED_TAGS = objectHasOwnProperty(cfg, 'ALLOWED_TAGS') ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;\n ALLOWED_ATTR = objectHasOwnProperty(cfg, 'ALLOWED_ATTR') ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;\n ALLOWED_NAMESPACES = objectHasOwnProperty(cfg, 'ALLOWED_NAMESPACES') ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES;\n URI_SAFE_ATTRIBUTES = objectHasOwnProperty(cfg, 'ADD_URI_SAFE_ATTR') ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES),\n // eslint-disable-line indent\n cfg.ADD_URI_SAFE_ATTR,\n // eslint-disable-line indent\n transformCaseFunc // eslint-disable-line indent\n ) // eslint-disable-line indent\n : DEFAULT_URI_SAFE_ATTRIBUTES;\n DATA_URI_TAGS = objectHasOwnProperty(cfg, 'ADD_DATA_URI_TAGS') ? addToSet(clone(DEFAULT_DATA_URI_TAGS),\n // eslint-disable-line indent\n cfg.ADD_DATA_URI_TAGS,\n // eslint-disable-line indent\n transformCaseFunc // eslint-disable-line indent\n ) // eslint-disable-line indent\n : DEFAULT_DATA_URI_TAGS;\n FORBID_CONTENTS = objectHasOwnProperty(cfg, 'FORBID_CONTENTS') ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;\n FORBID_TAGS = objectHasOwnProperty(cfg, 'FORBID_TAGS') ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : {};\n FORBID_ATTR = objectHasOwnProperty(cfg, 'FORBID_ATTR') ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : {};\n USE_PROFILES = objectHasOwnProperty(cfg, 'USE_PROFILES') ? cfg.USE_PROFILES : false;\n ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true\n ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true\n ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false\n ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false; // Default true\n SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false\n SAFE_FOR_XML = cfg.SAFE_FOR_XML !== false; // Default true\n WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false\n RETURN_DOM = cfg.RETURN_DOM || false; // Default false\n RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false\n RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false\n FORCE_BODY = cfg.FORCE_BODY || false; // Default false\n SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true\n SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false\n KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true\n IN_PLACE = cfg.IN_PLACE || false; // Default false\n IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI;\n NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;\n CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};\n if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {\n CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;\n }\n if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) {\n CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;\n }\n if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === 'boolean') {\n CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;\n }\n if (SAFE_FOR_TEMPLATES) {\n ALLOW_DATA_ATTR = false;\n }\n if (RETURN_DOM_FRAGMENT) {\n RETURN_DOM = true;\n }\n\n /* Parse profile info */\n if (USE_PROFILES) {\n ALLOWED_TAGS = addToSet({}, text);\n ALLOWED_ATTR = [];\n if (USE_PROFILES.html === true) {\n addToSet(ALLOWED_TAGS, html$1);\n addToSet(ALLOWED_ATTR, html);\n }\n if (USE_PROFILES.svg === true) {\n addToSet(ALLOWED_TAGS, svg$1);\n addToSet(ALLOWED_ATTR, svg);\n addToSet(ALLOWED_ATTR, xml);\n }\n if (USE_PROFILES.svgFilters === true) {\n addToSet(ALLOWED_TAGS, svgFilters);\n addToSet(ALLOWED_ATTR, svg);\n addToSet(ALLOWED_ATTR, xml);\n }\n if (USE_PROFILES.mathMl === true) {\n addToSet(ALLOWED_TAGS, mathMl$1);\n addToSet(ALLOWED_ATTR, mathMl);\n addToSet(ALLOWED_ATTR, xml);\n }\n }\n\n /* Merge configuration parameters */\n if (cfg.ADD_TAGS) {\n if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {\n ALLOWED_TAGS = clone(ALLOWED_TAGS);\n }\n addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);\n }\n if (cfg.ADD_ATTR) {\n if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {\n ALLOWED_ATTR = clone(ALLOWED_ATTR);\n }\n addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);\n }\n if (cfg.ADD_URI_SAFE_ATTR) {\n addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);\n }\n if (cfg.FORBID_CONTENTS) {\n if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {\n FORBID_CONTENTS = clone(FORBID_CONTENTS);\n }\n addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);\n }\n\n /* Add #text in case KEEP_CONTENT is set to true */\n if (KEEP_CONTENT) {\n ALLOWED_TAGS['#text'] = true;\n }\n\n /* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */\n if (WHOLE_DOCUMENT) {\n addToSet(ALLOWED_TAGS, ['html', 'head', 'body']);\n }\n\n /* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */\n if (ALLOWED_TAGS.table) {\n addToSet(ALLOWED_TAGS, ['tbody']);\n delete FORBID_TAGS.tbody;\n }\n if (cfg.TRUSTED_TYPES_POLICY) {\n if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== 'function') {\n throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a \"createHTML\" hook.');\n }\n if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== 'function') {\n throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a \"createScriptURL\" hook.');\n }\n\n // Overwrite existing TrustedTypes policy.\n trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY;\n\n // Sign local variables required by `sanitize`.\n emptyHTML = trustedTypesPolicy.createHTML('');\n } else {\n // Uninitialized policy, attempt to initialize the internal dompurify policy.\n if (trustedTypesPolicy === undefined) {\n trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript);\n }\n\n // If creating the internal policy succeeded sign internal variables.\n if (trustedTypesPolicy !== null && typeof emptyHTML === 'string') {\n emptyHTML = trustedTypesPolicy.createHTML('');\n }\n }\n\n // Prevent further manipulation of configuration.\n // Not available in IE8, Safari 5, etc.\n if (freeze) {\n freeze(cfg);\n }\n CONFIG = cfg;\n };\n const MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);\n const HTML_INTEGRATION_POINTS = addToSet({}, ['foreignobject', 'desc', 'title', 'annotation-xml']);\n\n // Certain elements are allowed in both SVG and HTML\n // namespace. We need to specify them explicitly\n // so that they don't get erroneously deleted from\n // HTML namespace.\n const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ['title', 'style', 'font', 'a', 'script']);\n\n /* Keep track of all possible SVG and MathML tags\n * so that we can perform the namespace checks\n * correctly. */\n const ALL_SVG_TAGS = addToSet({}, [...svg$1, ...svgFilters, ...svgDisallowed]);\n const ALL_MATHML_TAGS = addToSet({}, [...mathMl$1, ...mathMlDisallowed]);\n\n /**\n * @param {Element} element a DOM element whose namespace is being checked\n * @returns {boolean} Return false if the element has a\n * namespace that a spec-compliant parser would never\n * return. Return true otherwise.\n */\n const _checkValidNamespace = function _checkValidNamespace(element) {\n let parent = getParentNode(element);\n\n // In JSDOM, if we're inside shadow DOM, then parentNode\n // can be null. We just simulate parent in this case.\n if (!parent || !parent.tagName) {\n parent = {\n namespaceURI: NAMESPACE,\n tagName: 'template'\n };\n }\n const tagName = stringToLowerCase(element.tagName);\n const parentTagName = stringToLowerCase(parent.tagName);\n if (!ALLOWED_NAMESPACES[element.namespaceURI]) {\n return false;\n }\n if (element.namespaceURI === SVG_NAMESPACE) {\n // The only way to switch from HTML namespace to SVG\n // is via <svg>. If it happens via any other tag, then\n // it should be killed.\n if (parent.namespaceURI === HTML_NAMESPACE) {\n return tagName === 'svg';\n }\n\n // The only way to switch from MathML to SVG is via`\n // svg if parent is either <annotation-xml> or MathML\n // text integration points.\n if (parent.namespaceURI === MATHML_NAMESPACE) {\n return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);\n }\n\n // We only allow elements that are defined in SVG\n // spec. All others are disallowed in SVG namespace.\n return Boolean(ALL_SVG_TAGS[tagName]);\n }\n if (element.namespaceURI === MATHML_NAMESPACE) {\n // The only way to switch from HTML namespace to MathML\n // is via <math>. If it happens via any other tag, then\n // it should be killed.\n if (parent.namespaceURI === HTML_NAMESPACE) {\n return tagName === 'math';\n }\n\n // The only way to switch from SVG to MathML is via\n // <math> and HTML integration points\n if (parent.namespaceURI === SVG_NAMESPACE) {\n return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];\n }\n\n // We only allow elements that are defined in MathML\n // spec. All others are disallowed in MathML namespace.\n return Boolean(ALL_MATHML_TAGS[tagName]);\n }\n if (element.namespaceURI === HTML_NAMESPACE) {\n // The only way to switch from SVG to HTML is via\n // HTML integration points, and from MathML to HTML\n // is via MathML text integration points\n if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) {\n return false;\n }\n if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {\n return false;\n }\n\n // We disallow tags that are specific for MathML\n // or SVG and should never appear in HTML namespace\n return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);\n }\n\n // For XHTML and XML documents that support custom namespaces\n if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && ALLOWED_NAMESPACES[element.namespaceURI]) {\n return true;\n }\n\n // The code should never reach this place (this means\n // that the element somehow got namespace that is not\n // HTML, SVG, MathML or allowed via ALLOWED_NAMESPACES).\n // Return false just in case.\n return false;\n };\n\n /**\n * _forceRemove\n *\n * @param {Node} node a DOM node\n */\n const _forceRemove = function _forceRemove(node) {\n arrayPush(DOMPurify.removed, {\n element: node\n });\n try {\n // eslint-disable-next-line unicorn/prefer-dom-node-remove\n node.parentNode.removeChild(node);\n } catch (_) {\n node.remove();\n }\n };\n\n /**\n * _removeAttribute\n *\n * @param {String} name an Attribute name\n * @param {Node} node a DOM node\n */\n const _removeAttribute = function _removeAttribute(name, node) {\n try {\n arrayPush(DOMPurify.removed, {\n attribute: node.getAttributeNode(name),\n from: node\n });\n } catch (_) {\n arrayPush(DOMPurify.removed, {\n attribute: null,\n from: node\n });\n }\n node.removeAttribute(name);\n\n // We void attribute values for unremovable \"is\"\" attributes\n if (name === 'is' && !ALLOWED_ATTR[name]) {\n if (RETURN_DOM || RETURN_DOM_FRAGMENT) {\n try {\n _forceRemove(node);\n } catch (_) {}\n } else {\n try {\n node.setAttribute(name, '');\n } catch (_) {}\n }\n }\n };\n\n /**\n * _initDocument\n *\n * @param {String} dirty a string of dirty markup\n * @return {Document} a DOM, filled with the dirty markup\n */\n const _initDocument = function _initDocument(dirty) {\n /* Create a HTML document */\n let doc = null;\n let leadingWhitespace = null;\n if (FORCE_BODY) {\n dirty = '<remove></remove>' + dirty;\n } else {\n /* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */\n const matches = stringMatch(dirty, /^[\\r\\n\\t ]+/);\n leadingWhitespace = matches && matches[0];\n }\n if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && NAMESPACE === HTML_NAMESPACE) {\n // Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict)\n dirty = '<html xmlns=\"http://www.w3.org/1999/xhtml\"><head></head><body>' + dirty + '</body></html>';\n }\n const dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;\n /*\n * Use the DOMParser API by default, fallback later if needs be\n * DOMParser not work for svg when has multiple root element.\n */\n if (NAMESPACE === HTML_NAMESPACE) {\n try {\n doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);\n } catch (_) {}\n }\n\n /* Use createHTMLDocument in case DOMParser is not available */\n if (!doc || !doc.documentElement) {\n doc = implementation.createDocument(NAMESPACE, 'template', null);\n try {\n doc.documentElement.innerHTML = IS_EMPTY_INPUT ? emptyHTML : dirtyPayload;\n } catch (_) {\n // Syntax error if dirtyPayload is invalid xml\n }\n }\n const body = doc.body || doc.documentElement;\n if (dirty && leadingWhitespace) {\n body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);\n }\n\n /* Work on whole document or just its body */\n if (NAMESPACE === HTML_NAMESPACE) {\n return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];\n }\n return WHOLE_DOCUMENT ? doc.documentElement : body;\n };\n\n /**\n * Creates a NodeIterator object that you can use to traverse filtered lists of nodes or elements in a document.\n *\n * @param {Node} root The root element or node to start traversing on.\n * @return {NodeIterator} The created NodeIterator\n */\n const _createNodeIterator = function _createNodeIterator(root) {\n return createNodeIterator.call(root.ownerDocument || root, root,\n // eslint-disable-next-line no-bitwise\n NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION, null);\n };\n\n /**\n * _isClobbered\n *\n * @param {Node} elm element to check for clobbering attacks\n * @return {Boolean} true if clobbered, false if safe\n */\n const _isClobbered = function _isClobbered(elm) {\n 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' || typeof elm.hasChildNodes !== 'function');\n };\n\n /**\n * Checks whether the given object is a DOM node.\n *\n * @param {Node} object object to check whether it's a DOM node\n * @return {Boolean} true is object is a DOM node\n */\n const _isNode = function _isNode(object) {\n return typeof Node === 'function' && object instanceof Node;\n };\n\n /**\n * _executeHook\n * Execute user configurable hooks\n *\n * @param {String} entryPoint Name of the hook's entry point\n * @param {Node} currentNode node to work on with the hook\n * @param {Object} data additional hook parameters\n */\n const _executeHook = function _executeHook(entryPoint, currentNode, data) {\n if (!hooks[entryPoint]) {\n return;\n }\n arrayForEach(hooks[entryPoint], hook => {\n hook.call(DOMPurify, currentNode, data, CONFIG);\n });\n };\n\n /**\n * _sanitizeElements\n *\n * @protect nodeName\n * @protect textContent\n * @protect removeChild\n *\n * @param {Node} currentNode to check for permission to exist\n * @return {Boolean} true if node was killed, false if left alive\n */\n const _sanitizeElements = function _sanitizeElements(currentNode) {\n let content = null;\n\n /* Execute a hook if present */\n _executeHook('beforeSanitizeElements', currentNode, null);\n\n /* Check if element is clobbered or can clobber */\n if (_isClobbered(currentNode)) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Now let's check the element's type and name */\n const tagName = transformCaseFunc(currentNode.nodeName);\n\n /* Execute a hook if present */\n _executeHook('uponSanitizeElement', currentNode, {\n tagName,\n allowedTags: ALLOWED_TAGS\n });\n\n /* Detect mXSS attempts abusing namespace confusion */\n if (currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(/<[/\\w]/g, currentNode.innerHTML) && regExpTest(/<[/\\w]/g, currentNode.textContent)) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Remove any ocurrence of processing instructions */\n if (currentNode.nodeType === 7) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Remove any kind of possibly harmful comments */\n if (SAFE_FOR_XML && currentNode.nodeType === 8 && regExpTest(/<[/\\w]/g, currentNode.data)) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Remove element if anything forbids its presence */\n if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {\n /* Check if we have a custom element to handle */\n if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) {\n if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) {\n return false;\n }\n if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) {\n return false;\n }\n }\n\n /* Keep content except for bad-listed elements */\n if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {\n const parentNode = getParentNode(currentNode) || currentNode.parentNode;\n const childNodes = getChildNodes(currentNode) || currentNode.childNodes;\n if (childNodes && parentNode) {\n const childCount = childNodes.length;\n for (let i = childCount - 1; i >= 0; --i) {\n parentNode.insertBefore(cloneNode(childNodes[i], true), getNextSibling(currentNode));\n }\n }\n }\n _forceRemove(currentNode);\n return true;\n }\n\n /* Check whether element has a valid namespace */\n if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Make sure that older browsers don't get fallback-tag mXSS */\n if ((tagName === 'noscript' || tagName === 'noembed' || tagName === 'noframes') && regExpTest(/<\\/no(script|embed|frames)/i, currentNode.innerHTML)) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Sanitize element content to be template-safe */\n if (SAFE_FOR_TEMPLATES && currentNode.nodeType === 3) {\n /* Get the element's text content */\n content = currentNode.textContent;\n arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {\n content = stringReplace(content, expr, ' ');\n });\n if (currentNode.textContent !== content) {\n arrayPush(DOMPurify.removed, {\n element: currentNode.cloneNode()\n });\n currentNode.textContent = content;\n }\n }\n\n /* Execute a hook if present */\n _executeHook('afterSanitizeElements', currentNode, null);\n return false;\n };\n\n /**\n * _isValidAttribute\n *\n * @param {string} lcTag Lowercase tag name of containing element.\n * @param {string} lcName Lowercase attribute name.\n * @param {string} value Attribute value.\n * @return {Boolean} Returns true if `value` is valid, otherwise false.\n */\n // eslint-disable-next-line complexity\n const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {\n /* Make sure attribute cannot clobber */\n if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {\n return false;\n }\n\n /* Allow valid data-* attributes: At least one character after \"-\"\n (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)\n XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)\n We don't need to check the value; it's always URI safe. */\n 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]) {\n if (\n // First condition does a very basic check if a) it's basically a valid custom element tagname AND\n // b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck\n // and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck\n _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)) ||\n // Alternative, second condition checks if it's an `is`-attribute, AND\n // the value passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck\n 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 {\n return false;\n }\n /* Check value is safe. First, is attr inert? If so, is safe */\n } 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) {\n return false;\n } else ;\n return true;\n };\n\n /**\n * _isBasicCustomElement\n * checks if at least one dash is included in tagName, and it's not the first char\n * for more sophisticated checking see https://github.com/sindresorhus/validate-element-name\n *\n * @param {string} tagName name of the tag of the node to sanitize\n * @returns {boolean} Returns true if the tag name meets the basic criteria for a custom element, otherwise false.\n */\n const _isBasicCustomElement = function _isBasicCustomElement(tagName) {\n return tagName !== 'annotation-xml' && stringMatch(tagName, CUSTOM_ELEMENT);\n };\n\n /**\n * _sanitizeAttributes\n *\n * @protect attributes\n * @protect nodeName\n * @protect removeAttribute\n * @protect setAttribute\n *\n * @param {Node} currentNode to sanitize\n */\n const _sanitizeAttributes = function _sanitizeAttributes(currentNode) {\n /* Execute a hook if present */\n _executeHook('beforeSanitizeAttributes', currentNode, null);\n const {\n attributes\n } = currentNode;\n\n /* Check if we have attributes; if not we might have a text node */\n if (!attributes) {\n return;\n }\n const hookEvent = {\n attrName: '',\n attrValue: '',\n keepAttr: true,\n allowedAttributes: ALLOWED_ATTR\n };\n let l = attributes.length;\n\n /* Go backwards over all attributes; safely remove bad ones */\n while (l--) {\n const attr = attributes[l];\n const {\n name,\n namespaceURI,\n value: attrValue\n } = attr;\n const lcName = transformCaseFunc(name);\n let value = name === 'value' ? attrValue : stringTrim(attrValue);\n\n /* Execute a hook if present */\n hookEvent.attrName = lcName;\n hookEvent.attrValue = value;\n hookEvent.keepAttr = true;\n hookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set\n _executeHook('uponSanitizeAttribute', currentNode, hookEvent);\n value = hookEvent.attrValue;\n /* Did the hooks approve of the attribute? */\n if (hookEvent.forceKeepAttr) {\n continue;\n }\n\n /* Remove attribute */\n _removeAttribute(name, currentNode);\n\n /* Did the hooks approve of the attribute? */\n if (!hookEvent.keepAttr) {\n continue;\n }\n\n /* Work around a security issue in jQuery 3.0 */\n if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(/\\/>/i, value)) {\n _removeAttribute(name, currentNode);\n continue;\n }\n\n /* Sanitize attribute content to be template-safe */\n if (SAFE_FOR_TEMPLATES) {\n arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {\n value = stringReplace(value, expr, ' ');\n });\n }\n\n /* Is `value` valid for this attribute? */\n const lcTag = transformCaseFunc(currentNode.nodeName);\n if (!_isValidAttribute(lcTag, lcName, value)) {\n continue;\n }\n\n /* Full DOM Clobbering protection via namespace isolation,\n * Prefix id and name attributes with `user-content-`\n */\n if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {\n // Remove the attribute with this value\n _removeAttribute(name, currentNode);\n\n // Prefix the value and later re-create the attribute with the sanitized value\n value = SANITIZE_NAMED_PROPS_PREFIX + value;\n }\n\n /* Handle attributes that require Trusted Types */\n if (trustedTypesPolicy && typeof trustedTypes === 'object' && typeof trustedTypes.getAttributeType === 'function') {\n if (namespaceURI) ; else {\n switch (trustedTypes.getAttributeType(lcTag, lcName)) {\n case 'TrustedHTML':\n {\n value = trustedTypesPolicy.createHTML(value);\n break;\n }\n case 'TrustedScriptURL':\n {\n value = trustedTypesPolicy.createScriptURL(value);\n break;\n }\n }\n }\n }\n\n /* Handle invalid data-* attribute set by try-catching it */\n try {\n if (namespaceURI) {\n currentNode.setAttributeNS(namespaceURI, name, value);\n } else {\n /* Fallback to setAttribute() for browser-unrecognized namespaces e.g. \"x-schema\". */\n currentNode.setAttribute(name, value);\n }\n arrayPop(DOMPurify.removed);\n } catch (_) {}\n }\n\n /* Execute a hook if present */\n _executeHook('afterSanitizeAttributes', currentNode, null);\n };\n\n /**\n * _sanitizeShadowDOM\n *\n * @param {DocumentFragment} fragment to iterate over recursively\n */\n const _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {\n let shadowNode = null;\n const shadowIterator = _createNodeIterator(fragment);\n\n /* Execute a hook if present */\n _executeHook('beforeSanitizeShadowDOM', fragment, null);\n while (shadowNode = shadowIterator.nextNode()) {\n /* Execute a hook if present */\n _executeHook('uponSanitizeShadowNode', shadowNode, null);\n\n /* Sanitize tags and elements */\n if (_sanitizeElements(shadowNode)) {\n continue;\n }\n\n /* Deep shadow DOM detected */\n if (shadowNode.content instanceof DocumentFragment) {\n _sanitizeShadowDOM(shadowNode.content);\n }\n\n /* Check attributes, sanitize if necessary */\n _sanitizeAttributes(shadowNode);\n }\n\n /* Execute a hook if present */\n _executeHook('afterSanitizeShadowDOM', fragment, null);\n };\n\n /**\n * Sanitize\n * Public method providing core sanitation functionality\n *\n * @param {String|Node} dirty string or DOM node\n * @param {Object} cfg object\n */\n // eslint-disable-next-line complexity\n DOMPurify.sanitize = function (dirty) {\n let cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n let body = null;\n let importedNode = null;\n let currentNode = null;\n let returnNode = null;\n /* Make sure we have a string to sanitize.\n DO NOT return early, as this will return the wrong type if\n the user has requested a DOM object rather than a string */\n IS_EMPTY_INPUT = !dirty;\n if (IS_EMPTY_INPUT) {\n dirty = '<!-->';\n }\n\n /* Stringify, in case dirty is an object */\n if (typeof dirty !== 'string' && !_isNode(dirty)) {\n if (typeof dirty.toString === 'function') {\n dirty = dirty.toString();\n if (typeof dirty !== 'string') {\n throw typeErrorCreate('dirty is not a string, aborting');\n }\n } else {\n throw typeErrorCreate('toString is not a function');\n }\n }\n\n /* Return dirty HTML if DOMPurify cannot run */\n if (!DOMPurify.isSupported) {\n return dirty;\n }\n\n /* Assign config vars */\n if (!SET_CONFIG) {\n _parseConfig(cfg);\n }\n\n /* Clean up removed elements */\n DOMPurify.removed = [];\n\n /* Check if dirty is correctly typed for IN_PLACE */\n if (typeof dirty === 'string') {\n IN_PLACE = false;\n }\n if (IN_PLACE) {\n /* Do some early pre-sanitization to avoid unsafe root nodes */\n if (dirty.nodeName) {\n const tagName = transformCaseFunc(dirty.nodeName);\n if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {\n throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');\n }\n }\n } else if (dirty instanceof Node) {\n /* If dirty is a DOM element, append to an empty document to avoid\n elements being stripped by the parser */\n body = _initDocument('<!---->');\n importedNode = body.ownerDocument.importNode(dirty, true);\n if (importedNode.nodeType === 1 && importedNode.nodeName === 'BODY') {\n /* Node is already a body, use as is */\n body = importedNode;\n } else if (importedNode.nodeName === 'HTML') {\n body = importedNode;\n } else {\n // eslint-disable-next-line unicorn/prefer-dom-node-append\n body.appendChild(importedNode);\n }\n } else {\n /* Exit directly if we have nothing to do */\n if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT &&\n // eslint-disable-next-line unicorn/prefer-includes\n dirty.indexOf('<') === -1) {\n return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;\n }\n\n /* Initialize the document to work on */\n body = _initDocument(dirty);\n\n /* Check we have a DOM node from the data */\n if (!body) {\n return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';\n }\n }\n\n /* Remove first element node (ours) if FORCE_BODY is set */\n if (body && FORCE_BODY) {\n _forceRemove(body.firstChild);\n }\n\n /* Get node iterator */\n const nodeIterator = _createNodeIterator(IN_PLACE ? dirty : body);\n\n /* Now start iterating over the created document */\n while (currentNode = nodeIterator.nextNode()) {\n /* Sanitize tags and elements */\n if (_sanitizeElements(currentNode)) {\n continue;\n }\n\n /* Shadow DOM detected, sanitize it */\n if (currentNode.content instanceof DocumentFragment) {\n _sanitizeShadowDOM(currentNode.content);\n }\n\n /* Check attributes, sanitize if necessary */\n _sanitizeAttributes(currentNode);\n }\n\n /* If we sanitized `dirty` in-place, return it. */\n if (IN_PLACE) {\n return dirty;\n }\n\n /* Return sanitized string or DOM */\n if (RETURN_DOM) {\n if (RETURN_DOM_FRAGMENT) {\n returnNode = createDocumentFragment.call(body.ownerDocument);\n while (body.firstChild) {\n // eslint-disable-next-line unicorn/prefer-dom-node-append\n returnNode.appendChild(body.firstChild);\n }\n } else {\n returnNode = body;\n }\n if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmode) {\n /*\n AdoptNode() is not used because internal state is not reset\n (e.g. the past names map of a HTMLFormElement), this is safe\n in theory but we would rather not risk another attack vector.\n The state that is cloned by importNode() is explicitly defined\n by the specs.\n */\n returnNode = importNode.call(originalDocument, returnNode, true);\n }\n return returnNode;\n }\n let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;\n\n /* Serialize doctype if allowed */\n if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {\n serializedHTML = '<!DOCTYPE ' + body.ownerDocument.doctype.name + '>\\n' + serializedHTML;\n }\n\n /* Sanitize final string template-safe */\n if (SAFE_FOR_TEMPLATES) {\n arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {\n serializedHTML = stringReplace(serializedHTML, expr, ' ');\n });\n }\n return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;\n };\n\n /**\n * Public method to set the configuration once\n * setConfig\n *\n * @param {Object} cfg configuration object\n */\n DOMPurify.setConfig = function () {\n let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n _parseConfig(cfg);\n SET_CONFIG = true;\n };\n\n /**\n * Public method to remove the configuration\n * clearConfig\n *\n */\n DOMPurify.clearConfig = function () {\n CONFIG = null;\n SET_CONFIG = false;\n };\n\n /**\n * Public method to check if an attribute value is valid.\n * Uses last set config, if any. Otherwise, uses config defaults.\n * isValidAttribute\n *\n * @param {String} tag Tag name of containing element.\n * @param {String} attr Attribute name.\n * @param {String} value Attribute value.\n * @return {Boolean} Returns true if `value` is valid. Otherwise, returns false.\n */\n DOMPurify.isValidAttribute = function (tag, attr, value) {\n /* Initialize shared config vars if necessary. */\n if (!CONFIG) {\n _parseConfig({});\n }\n const lcTag = transformCaseFunc(tag);\n const lcName = transformCaseFunc(attr);\n return _isValidAttribute(lcTag, lcName, value);\n };\n\n /**\n * AddHook\n * Public method to add DOMPurify hooks\n *\n * @param {String} entryPoint entry point for the hook to add\n * @param {Function} hookFunction function to execute\n */\n DOMPurify.addHook = function (entryPoint, hookFunction) {\n if (typeof hookFunction !== 'function') {\n return;\n }\n hooks[entryPoint] = hooks[entryPoint] || [];\n arrayPush(hooks[entryPoint], hookFunction);\n };\n\n /**\n * RemoveHook\n * Public method to remove a DOMPurify hook at a given entryPoint\n * (pops it from the stack of hooks if more are present)\n *\n * @param {String} entryPoint entry point for the hook to remove\n * @return {Function} removed(popped) hook\n */\n DOMPurify.removeHook = function (entryPoint) {\n if (hooks[entryPoint]) {\n return arrayPop(hooks[entryPoint]);\n }\n };\n\n /**\n * RemoveHooks\n * Public method to remove all DOMPurify hooks at a given entryPoint\n *\n * @param {String} entryPoint entry point for the hooks to remove\n */\n DOMPurify.removeHooks = function (entryPoint) {\n if (hooks[entryPoint]) {\n hooks[entryPoint] = [];\n }\n };\n\n /**\n * RemoveAllHooks\n * Public method to remove all DOMPurify hooks\n */\n DOMPurify.removeAllHooks = function () {\n hooks = {};\n };\n return DOMPurify;\n }\n var purify = createDOMPurify();\n\n return purify;\n\n}));\n//# sourceMappingURL=purify.js.map\n\n\n//# sourceURL=webpack://Formio/./node_modules/dompurify/dist/purify.js?");
|
|
2731
|
+
eval("/*! @license DOMPurify 3.1.4 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.1.4/LICENSE */\n\n(function (global, factory) {\n true ? module.exports = factory() :\n 0;\n})(this, (function () { 'use strict';\n\n const {\n entries,\n setPrototypeOf,\n isFrozen,\n getPrototypeOf,\n getOwnPropertyDescriptor\n } = Object;\n let {\n freeze,\n seal,\n create\n } = Object; // eslint-disable-line import/no-mutable-exports\n let {\n apply,\n construct\n } = typeof Reflect !== 'undefined' && Reflect;\n if (!freeze) {\n freeze = function freeze(x) {\n return x;\n };\n }\n if (!seal) {\n seal = function seal(x) {\n return x;\n };\n }\n if (!apply) {\n apply = function apply(fun, thisValue, args) {\n return fun.apply(thisValue, args);\n };\n }\n if (!construct) {\n construct = function construct(Func, args) {\n return new Func(...args);\n };\n }\n const arrayForEach = unapply(Array.prototype.forEach);\n const arrayPop = unapply(Array.prototype.pop);\n const arrayPush = unapply(Array.prototype.push);\n const stringToLowerCase = unapply(String.prototype.toLowerCase);\n const stringToString = unapply(String.prototype.toString);\n const stringMatch = unapply(String.prototype.match);\n const stringReplace = unapply(String.prototype.replace);\n const stringIndexOf = unapply(String.prototype.indexOf);\n const stringTrim = unapply(String.prototype.trim);\n const objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);\n const regExpTest = unapply(RegExp.prototype.test);\n const typeErrorCreate = unconstruct(TypeError);\n function numberIsNaN(x) {\n // eslint-disable-next-line unicorn/prefer-number-properties\n return typeof x === 'number' && isNaN(x);\n }\n\n /**\n * Creates a new function that calls the given function with a specified thisArg and arguments.\n *\n * @param {Function} func - The function to be wrapped and called.\n * @returns {Function} A new function that calls the given function with a specified thisArg and arguments.\n */\n function unapply(func) {\n return function (thisArg) {\n for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n args[_key - 1] = arguments[_key];\n }\n return apply(func, thisArg, args);\n };\n }\n\n /**\n * Creates a new function that constructs an instance of the given constructor function with the provided arguments.\n *\n * @param {Function} func - The constructor function to be wrapped and called.\n * @returns {Function} A new function that constructs an instance of the given constructor function with the provided arguments.\n */\n function unconstruct(func) {\n return function () {\n for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {\n args[_key2] = arguments[_key2];\n }\n return construct(func, args);\n };\n }\n\n /**\n * Add properties to a lookup table\n *\n * @param {Object} set - The set to which elements will be added.\n * @param {Array} array - The array containing elements to be added to the set.\n * @param {Function} transformCaseFunc - An optional function to transform the case of each element before adding to the set.\n * @returns {Object} The modified set with added elements.\n */\n function addToSet(set, array) {\n let transformCaseFunc = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : stringToLowerCase;\n if (setPrototypeOf) {\n // Make 'in' and truthy checks like Boolean(set.constructor)\n // independent of any properties defined on Object.prototype.\n // Prevent prototype setters from intercepting set as a this value.\n setPrototypeOf(set, null);\n }\n let l = array.length;\n while (l--) {\n let element = array[l];\n if (typeof element === 'string') {\n const lcElement = transformCaseFunc(element);\n if (lcElement !== element) {\n // Config presets (e.g. tags.js, attrs.js) are immutable.\n if (!isFrozen(array)) {\n array[l] = lcElement;\n }\n element = lcElement;\n }\n }\n set[element] = true;\n }\n return set;\n }\n\n /**\n * Clean up an array to harden against CSPP\n *\n * @param {Array} array - The array to be cleaned.\n * @returns {Array} The cleaned version of the array\n */\n function cleanArray(array) {\n for (let index = 0; index < array.length; index++) {\n const isPropertyExist = objectHasOwnProperty(array, index);\n if (!isPropertyExist) {\n array[index] = null;\n }\n }\n return array;\n }\n\n /**\n * Shallow clone an object\n *\n * @param {Object} object - The object to be cloned.\n * @returns {Object} A new object that copies the original.\n */\n function clone(object) {\n const newObject = create(null);\n for (const [property, value] of entries(object)) {\n const isPropertyExist = objectHasOwnProperty(object, property);\n if (isPropertyExist) {\n if (Array.isArray(value)) {\n newObject[property] = cleanArray(value);\n } else if (value && typeof value === 'object' && value.constructor === Object) {\n newObject[property] = clone(value);\n } else {\n newObject[property] = value;\n }\n }\n }\n return newObject;\n }\n\n /**\n * This method automatically checks if the prop is function or getter and behaves accordingly.\n *\n * @param {Object} object - The object to look up the getter function in its prototype chain.\n * @param {String} prop - The property name for which to find the getter function.\n * @returns {Function} The getter function found in the prototype chain or a fallback function.\n */\n function lookupGetter(object, prop) {\n while (object !== null) {\n const desc = getOwnPropertyDescriptor(object, prop);\n if (desc) {\n if (desc.get) {\n return unapply(desc.get);\n }\n if (typeof desc.value === 'function') {\n return unapply(desc.value);\n }\n }\n object = getPrototypeOf(object);\n }\n function fallbackValue() {\n return null;\n }\n return fallbackValue;\n }\n\n 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']);\n\n // SVG\n 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']);\n 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']);\n\n // List of SVG elements that are disallowed by default.\n // We still need to know them so that we can do namespace\n // checks properly in case one wants to add them to\n // allow-list.\n 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']);\n 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']);\n\n // Similarly to SVG, we want to know all MathML elements,\n // even those that we disallow by default.\n const mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);\n const text = freeze(['#text']);\n\n 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']);\n const svg = 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']);\n 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']);\n const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);\n\n // eslint-disable-next-line unicorn/better-regex\n const MUSTACHE_EXPR = seal(/\\{\\{[\\w\\W]*|[\\w\\W]*\\}\\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode\n const ERB_EXPR = seal(/<%[\\w\\W]*|[\\w\\W]*%>/gm);\n const TMPLIT_EXPR = seal(/\\${[\\w\\W]*}/gm);\n const DATA_ATTR = seal(/^data-[\\-\\w.\\u00B7-\\uFFFF]/); // eslint-disable-line no-useless-escape\n const ARIA_ATTR = seal(/^aria-[\\-\\w]+$/); // eslint-disable-line no-useless-escape\n 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\n );\n\n const IS_SCRIPT_OR_DATA = seal(/^(?:\\w+script|data):/i);\n const ATTR_WHITESPACE = seal(/[\\u0000-\\u0020\\u00A0\\u1680\\u180E\\u2000-\\u2029\\u205F\\u3000]/g // eslint-disable-line no-control-regex\n );\n\n const DOCTYPE_NAME = seal(/^html$/i);\n const CUSTOM_ELEMENT = seal(/^[a-z][.\\w]*(-[.\\w]+)+$/i);\n\n var EXPRESSIONS = /*#__PURE__*/Object.freeze({\n __proto__: null,\n MUSTACHE_EXPR: MUSTACHE_EXPR,\n ERB_EXPR: ERB_EXPR,\n TMPLIT_EXPR: TMPLIT_EXPR,\n DATA_ATTR: DATA_ATTR,\n ARIA_ATTR: ARIA_ATTR,\n IS_ALLOWED_URI: IS_ALLOWED_URI,\n IS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA,\n ATTR_WHITESPACE: ATTR_WHITESPACE,\n DOCTYPE_NAME: DOCTYPE_NAME,\n CUSTOM_ELEMENT: CUSTOM_ELEMENT\n });\n\n // https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType\n const NODE_TYPE = {\n element: 1,\n attribute: 2,\n text: 3,\n cdataSection: 4,\n entityReference: 5,\n // Deprecated\n entityNode: 6,\n // Deprecated\n progressingInstruction: 7,\n comment: 8,\n document: 9,\n documentType: 10,\n documentFragment: 11,\n notation: 12 // Deprecated\n };\n\n const getGlobal = function getGlobal() {\n return typeof window === 'undefined' ? null : window;\n };\n\n /**\n * Creates a no-op policy for internal use only.\n * Don't export this function outside this module!\n * @param {TrustedTypePolicyFactory} trustedTypes The policy factory.\n * @param {HTMLScriptElement} purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix).\n * @return {TrustedTypePolicy} The policy created (or null, if Trusted Types\n * are not supported or creating the policy failed).\n */\n const _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, purifyHostElement) {\n if (typeof trustedTypes !== 'object' || typeof trustedTypes.createPolicy !== 'function') {\n return null;\n }\n\n // Allow the callers to control the unique policy name\n // by adding a data-tt-policy-suffix to the script element with the DOMPurify.\n // Policy creation with duplicate names throws in Trusted Types.\n let suffix = null;\n const ATTR_NAME = 'data-tt-policy-suffix';\n if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) {\n suffix = purifyHostElement.getAttribute(ATTR_NAME);\n }\n const policyName = 'dompurify' + (suffix ? '#' + suffix : '');\n try {\n return trustedTypes.createPolicy(policyName, {\n createHTML(html) {\n return html;\n },\n createScriptURL(scriptUrl) {\n return scriptUrl;\n }\n });\n } catch (_) {\n // Policy creation failed (most likely another DOMPurify script has\n // already run). Skip creating the policy, as this will only cause errors\n // if TT are enforced.\n console.warn('TrustedTypes policy ' + policyName + ' could not be created.');\n return null;\n }\n };\n function createDOMPurify() {\n let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();\n const DOMPurify = root => createDOMPurify(root);\n\n /**\n * Version label, exposed for easier checks\n * if DOMPurify is up to date or not\n */\n DOMPurify.version = '3.1.4';\n\n /**\n * Array of elements that DOMPurify removed during sanitation.\n * Empty if nothing was removed.\n */\n DOMPurify.removed = [];\n if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document) {\n // Not running in a browser, provide a factory function\n // so that you can pass your own Window\n DOMPurify.isSupported = false;\n return DOMPurify;\n }\n let {\n document\n } = window;\n const originalDocument = document;\n const currentScript = originalDocument.currentScript;\n const {\n DocumentFragment,\n HTMLTemplateElement,\n Node,\n Element,\n NodeFilter,\n NamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap,\n HTMLFormElement,\n DOMParser,\n trustedTypes\n } = window;\n const ElementPrototype = Element.prototype;\n const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');\n const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');\n const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');\n const getParentNode = lookupGetter(ElementPrototype, 'parentNode');\n\n // As per issue #47, the web-components registry is inherited by a\n // new document created via createHTMLDocument. As per the spec\n // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)\n // a new empty registry is used when creating a template contents owner\n // document, so we use that as our parent document to ensure nothing\n // is inherited.\n if (typeof HTMLTemplateElement === 'function') {\n const template = document.createElement('template');\n if (template.content && template.content.ownerDocument) {\n document = template.content.ownerDocument;\n }\n }\n let trustedTypesPolicy;\n let emptyHTML = '';\n const {\n implementation,\n createNodeIterator,\n createDocumentFragment,\n getElementsByTagName\n } = document;\n const {\n importNode\n } = originalDocument;\n let hooks = {};\n\n /**\n * Expose whether this browser supports running the full DOMPurify.\n */\n DOMPurify.isSupported = typeof entries === 'function' && typeof getParentNode === 'function' && implementation && implementation.createHTMLDocument !== undefined;\n const {\n MUSTACHE_EXPR,\n ERB_EXPR,\n TMPLIT_EXPR,\n DATA_ATTR,\n ARIA_ATTR,\n IS_SCRIPT_OR_DATA,\n ATTR_WHITESPACE,\n CUSTOM_ELEMENT\n } = EXPRESSIONS;\n let {\n IS_ALLOWED_URI: IS_ALLOWED_URI$1\n } = EXPRESSIONS;\n\n /**\n * We consider the elements and attributes below to be safe. Ideally\n * don't add any new ones but feel free to remove unwanted ones.\n */\n\n /* allowed element names */\n let ALLOWED_TAGS = null;\n const DEFAULT_ALLOWED_TAGS = addToSet({}, [...html$1, ...svg$1, ...svgFilters, ...mathMl$1, ...text]);\n\n /* Allowed attribute names */\n let ALLOWED_ATTR = null;\n const DEFAULT_ALLOWED_ATTR = addToSet({}, [...html, ...svg, ...mathMl, ...xml]);\n\n /*\n * Configure how DOMPUrify should handle custom elements and their attributes as well as customized built-in elements.\n * @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)\n * @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list)\n * @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.\n */\n let CUSTOM_ELEMENT_HANDLING = Object.seal(create(null, {\n tagNameCheck: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: null\n },\n attributeNameCheck: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: null\n },\n allowCustomizedBuiltInElements: {\n writable: true,\n configurable: false,\n enumerable: true,\n value: false\n }\n }));\n\n /* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */\n let FORBID_TAGS = null;\n\n /* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */\n let FORBID_ATTR = null;\n\n /* Decide if ARIA attributes are okay */\n let ALLOW_ARIA_ATTR = true;\n\n /* Decide if custom data attributes are okay */\n let ALLOW_DATA_ATTR = true;\n\n /* Decide if unknown protocols are okay */\n let ALLOW_UNKNOWN_PROTOCOLS = false;\n\n /* Decide if self-closing tags in attributes are allowed.\n * Usually removed due to a mXSS issue in jQuery 3.0 */\n let ALLOW_SELF_CLOSE_IN_ATTR = true;\n\n /* Output should be safe for common template engines.\n * This means, DOMPurify removes data attributes, mustaches and ERB\n */\n let SAFE_FOR_TEMPLATES = false;\n\n /* Output should be safe even for XML used within HTML and alike.\n * This means, DOMPurify removes comments when containing risky content.\n */\n let SAFE_FOR_XML = true;\n\n /* Decide if document with <html>... should be returned */\n let WHOLE_DOCUMENT = false;\n\n /* Track whether config is already set on this instance of DOMPurify. */\n let SET_CONFIG = false;\n\n /* Decide if all elements (e.g. style, script) must be children of\n * document.body. By default, browsers might move them to document.head */\n let FORCE_BODY = false;\n\n /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html\n * string (or a TrustedHTML object if Trusted Types are supported).\n * If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead\n */\n let RETURN_DOM = false;\n\n /* Decide if a DOM `DocumentFragment` should be returned, instead of a html\n * string (or a TrustedHTML object if Trusted Types are supported) */\n let RETURN_DOM_FRAGMENT = false;\n\n /* Try to return a Trusted Type object instead of a string, return a string in\n * case Trusted Types are not supported */\n let RETURN_TRUSTED_TYPE = false;\n\n /* Output should be free from DOM clobbering attacks?\n * This sanitizes markups named with colliding, clobberable built-in DOM APIs.\n */\n let SANITIZE_DOM = true;\n\n /* Achieve full DOM Clobbering protection by isolating the namespace of named\n * properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules.\n *\n * HTML/DOM spec rules that enable DOM Clobbering:\n * - Named Access on Window (§7.3.3)\n * - DOM Tree Accessors (§3.1.5)\n * - Form Element Parent-Child Relations (§4.10.3)\n * - Iframe srcdoc / Nested WindowProxies (§4.8.5)\n * - HTMLCollection (§4.2.10.2)\n *\n * Namespace isolation is implemented by prefixing `id` and `name` attributes\n * with a constant string, i.e., `user-content-`\n */\n let SANITIZE_NAMED_PROPS = false;\n const SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';\n\n /* Keep element content when removing element? */\n let KEEP_CONTENT = true;\n\n /* If a `Node` is passed to sanitize(), then performs sanitization in-place instead\n * of importing it into a new Document and returning a sanitized copy */\n let IN_PLACE = false;\n\n /* Allow usage of profiles like html, svg and mathMl */\n let USE_PROFILES = {};\n\n /* Tags to ignore content of when KEEP_CONTENT is true */\n let FORBID_CONTENTS = null;\n 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']);\n\n /* Tags that are safe for data: URIs */\n let DATA_URI_TAGS = null;\n const DEFAULT_DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image', 'track']);\n\n /* Attributes safe for values like \"javascript:\" */\n let URI_SAFE_ATTRIBUTES = null;\n const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'role', 'summary', 'title', 'value', 'style', 'xmlns']);\n const MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';\n const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';\n const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';\n /* Document namespace */\n let NAMESPACE = HTML_NAMESPACE;\n let IS_EMPTY_INPUT = false;\n\n /* Allowed XHTML+XML namespaces */\n let ALLOWED_NAMESPACES = null;\n const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE], stringToString);\n\n /* Parsing of strict XHTML documents */\n let PARSER_MEDIA_TYPE = null;\n const SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html'];\n const DEFAULT_PARSER_MEDIA_TYPE = 'text/html';\n let transformCaseFunc = null;\n\n /* Keep a reference to config to pass to hooks */\n let CONFIG = null;\n\n /* Specify the maximum element nesting depth to prevent mXSS */\n const MAX_NESTING_DEPTH = 255;\n\n /* Ideally, do not touch anything below this line */\n /* ______________________________________________ */\n\n const formElement = document.createElement('form');\n const isRegexOrFunction = function isRegexOrFunction(testValue) {\n return testValue instanceof RegExp || testValue instanceof Function;\n };\n\n /**\n * _parseConfig\n *\n * @param {Object} cfg optional config literal\n */\n // eslint-disable-next-line complexity\n const _parseConfig = function _parseConfig() {\n let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n if (CONFIG && CONFIG === cfg) {\n return;\n }\n\n /* Shield configuration object from tampering */\n if (!cfg || typeof cfg !== 'object') {\n cfg = {};\n }\n\n /* Shield configuration object from prototype pollution */\n cfg = clone(cfg);\n PARSER_MEDIA_TYPE =\n // eslint-disable-next-line unicorn/prefer-includes\n SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? DEFAULT_PARSER_MEDIA_TYPE : cfg.PARSER_MEDIA_TYPE;\n\n // HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.\n transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase;\n\n /* Set configuration parameters */\n ALLOWED_TAGS = objectHasOwnProperty(cfg, 'ALLOWED_TAGS') ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;\n ALLOWED_ATTR = objectHasOwnProperty(cfg, 'ALLOWED_ATTR') ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;\n ALLOWED_NAMESPACES = objectHasOwnProperty(cfg, 'ALLOWED_NAMESPACES') ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES;\n URI_SAFE_ATTRIBUTES = objectHasOwnProperty(cfg, 'ADD_URI_SAFE_ATTR') ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES),\n // eslint-disable-line indent\n cfg.ADD_URI_SAFE_ATTR,\n // eslint-disable-line indent\n transformCaseFunc // eslint-disable-line indent\n ) // eslint-disable-line indent\n : DEFAULT_URI_SAFE_ATTRIBUTES;\n DATA_URI_TAGS = objectHasOwnProperty(cfg, 'ADD_DATA_URI_TAGS') ? addToSet(clone(DEFAULT_DATA_URI_TAGS),\n // eslint-disable-line indent\n cfg.ADD_DATA_URI_TAGS,\n // eslint-disable-line indent\n transformCaseFunc // eslint-disable-line indent\n ) // eslint-disable-line indent\n : DEFAULT_DATA_URI_TAGS;\n FORBID_CONTENTS = objectHasOwnProperty(cfg, 'FORBID_CONTENTS') ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;\n FORBID_TAGS = objectHasOwnProperty(cfg, 'FORBID_TAGS') ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : {};\n FORBID_ATTR = objectHasOwnProperty(cfg, 'FORBID_ATTR') ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : {};\n USE_PROFILES = objectHasOwnProperty(cfg, 'USE_PROFILES') ? cfg.USE_PROFILES : false;\n ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true\n ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true\n ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false\n ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false; // Default true\n SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false\n SAFE_FOR_XML = cfg.SAFE_FOR_XML !== false; // Default true\n WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false\n RETURN_DOM = cfg.RETURN_DOM || false; // Default false\n RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false\n RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false\n FORCE_BODY = cfg.FORCE_BODY || false; // Default false\n SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true\n SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false\n KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true\n IN_PLACE = cfg.IN_PLACE || false; // Default false\n IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI;\n NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;\n CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};\n if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {\n CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;\n }\n if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) {\n CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;\n }\n if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === 'boolean') {\n CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;\n }\n if (SAFE_FOR_TEMPLATES) {\n ALLOW_DATA_ATTR = false;\n }\n if (RETURN_DOM_FRAGMENT) {\n RETURN_DOM = true;\n }\n\n /* Parse profile info */\n if (USE_PROFILES) {\n ALLOWED_TAGS = addToSet({}, text);\n ALLOWED_ATTR = [];\n if (USE_PROFILES.html === true) {\n addToSet(ALLOWED_TAGS, html$1);\n addToSet(ALLOWED_ATTR, html);\n }\n if (USE_PROFILES.svg === true) {\n addToSet(ALLOWED_TAGS, svg$1);\n addToSet(ALLOWED_ATTR, svg);\n addToSet(ALLOWED_ATTR, xml);\n }\n if (USE_PROFILES.svgFilters === true) {\n addToSet(ALLOWED_TAGS, svgFilters);\n addToSet(ALLOWED_ATTR, svg);\n addToSet(ALLOWED_ATTR, xml);\n }\n if (USE_PROFILES.mathMl === true) {\n addToSet(ALLOWED_TAGS, mathMl$1);\n addToSet(ALLOWED_ATTR, mathMl);\n addToSet(ALLOWED_ATTR, xml);\n }\n }\n\n /* Merge configuration parameters */\n if (cfg.ADD_TAGS) {\n if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {\n ALLOWED_TAGS = clone(ALLOWED_TAGS);\n }\n addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);\n }\n if (cfg.ADD_ATTR) {\n if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {\n ALLOWED_ATTR = clone(ALLOWED_ATTR);\n }\n addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);\n }\n if (cfg.ADD_URI_SAFE_ATTR) {\n addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);\n }\n if (cfg.FORBID_CONTENTS) {\n if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {\n FORBID_CONTENTS = clone(FORBID_CONTENTS);\n }\n addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);\n }\n\n /* Add #text in case KEEP_CONTENT is set to true */\n if (KEEP_CONTENT) {\n ALLOWED_TAGS['#text'] = true;\n }\n\n /* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */\n if (WHOLE_DOCUMENT) {\n addToSet(ALLOWED_TAGS, ['html', 'head', 'body']);\n }\n\n /* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */\n if (ALLOWED_TAGS.table) {\n addToSet(ALLOWED_TAGS, ['tbody']);\n delete FORBID_TAGS.tbody;\n }\n if (cfg.TRUSTED_TYPES_POLICY) {\n if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== 'function') {\n throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a \"createHTML\" hook.');\n }\n if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== 'function') {\n throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a \"createScriptURL\" hook.');\n }\n\n // Overwrite existing TrustedTypes policy.\n trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY;\n\n // Sign local variables required by `sanitize`.\n emptyHTML = trustedTypesPolicy.createHTML('');\n } else {\n // Uninitialized policy, attempt to initialize the internal dompurify policy.\n if (trustedTypesPolicy === undefined) {\n trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript);\n }\n\n // If creating the internal policy succeeded sign internal variables.\n if (trustedTypesPolicy !== null && typeof emptyHTML === 'string') {\n emptyHTML = trustedTypesPolicy.createHTML('');\n }\n }\n\n // Prevent further manipulation of configuration.\n // Not available in IE8, Safari 5, etc.\n if (freeze) {\n freeze(cfg);\n }\n CONFIG = cfg;\n };\n const MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);\n const HTML_INTEGRATION_POINTS = addToSet({}, ['foreignobject', 'annotation-xml']);\n\n // Certain elements are allowed in both SVG and HTML\n // namespace. We need to specify them explicitly\n // so that they don't get erroneously deleted from\n // HTML namespace.\n const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ['title', 'style', 'font', 'a', 'script']);\n\n /* Keep track of all possible SVG and MathML tags\n * so that we can perform the namespace checks\n * correctly. */\n const ALL_SVG_TAGS = addToSet({}, [...svg$1, ...svgFilters, ...svgDisallowed]);\n const ALL_MATHML_TAGS = addToSet({}, [...mathMl$1, ...mathMlDisallowed]);\n\n /**\n * @param {Element} element a DOM element whose namespace is being checked\n * @returns {boolean} Return false if the element has a\n * namespace that a spec-compliant parser would never\n * return. Return true otherwise.\n */\n const _checkValidNamespace = function _checkValidNamespace(element) {\n let parent = getParentNode(element);\n\n // In JSDOM, if we're inside shadow DOM, then parentNode\n // can be null. We just simulate parent in this case.\n if (!parent || !parent.tagName) {\n parent = {\n namespaceURI: NAMESPACE,\n tagName: 'template'\n };\n }\n const tagName = stringToLowerCase(element.tagName);\n const parentTagName = stringToLowerCase(parent.tagName);\n if (!ALLOWED_NAMESPACES[element.namespaceURI]) {\n return false;\n }\n if (element.namespaceURI === SVG_NAMESPACE) {\n // The only way to switch from HTML namespace to SVG\n // is via <svg>. If it happens via any other tag, then\n // it should be killed.\n if (parent.namespaceURI === HTML_NAMESPACE) {\n return tagName === 'svg';\n }\n\n // The only way to switch from MathML to SVG is via`\n // svg if parent is either <annotation-xml> or MathML\n // text integration points.\n if (parent.namespaceURI === MATHML_NAMESPACE) {\n return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);\n }\n\n // We only allow elements that are defined in SVG\n // spec. All others are disallowed in SVG namespace.\n return Boolean(ALL_SVG_TAGS[tagName]);\n }\n if (element.namespaceURI === MATHML_NAMESPACE) {\n // The only way to switch from HTML namespace to MathML\n // is via <math>. If it happens via any other tag, then\n // it should be killed.\n if (parent.namespaceURI === HTML_NAMESPACE) {\n return tagName === 'math';\n }\n\n // The only way to switch from SVG to MathML is via\n // <math> and HTML integration points\n if (parent.namespaceURI === SVG_NAMESPACE) {\n return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];\n }\n\n // We only allow elements that are defined in MathML\n // spec. All others are disallowed in MathML namespace.\n return Boolean(ALL_MATHML_TAGS[tagName]);\n }\n if (element.namespaceURI === HTML_NAMESPACE) {\n // The only way to switch from SVG to HTML is via\n // HTML integration points, and from MathML to HTML\n // is via MathML text integration points\n if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) {\n return false;\n }\n if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {\n return false;\n }\n\n // We disallow tags that are specific for MathML\n // or SVG and should never appear in HTML namespace\n return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);\n }\n\n // For XHTML and XML documents that support custom namespaces\n if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && ALLOWED_NAMESPACES[element.namespaceURI]) {\n return true;\n }\n\n // The code should never reach this place (this means\n // that the element somehow got namespace that is not\n // HTML, SVG, MathML or allowed via ALLOWED_NAMESPACES).\n // Return false just in case.\n return false;\n };\n\n /**\n * _forceRemove\n *\n * @param {Node} node a DOM node\n */\n const _forceRemove = function _forceRemove(node) {\n arrayPush(DOMPurify.removed, {\n element: node\n });\n try {\n // eslint-disable-next-line unicorn/prefer-dom-node-remove\n node.parentNode.removeChild(node);\n } catch (_) {\n node.remove();\n }\n };\n\n /**\n * _removeAttribute\n *\n * @param {String} name an Attribute name\n * @param {Node} node a DOM node\n */\n const _removeAttribute = function _removeAttribute(name, node) {\n try {\n arrayPush(DOMPurify.removed, {\n attribute: node.getAttributeNode(name),\n from: node\n });\n } catch (_) {\n arrayPush(DOMPurify.removed, {\n attribute: null,\n from: node\n });\n }\n node.removeAttribute(name);\n\n // We void attribute values for unremovable \"is\"\" attributes\n if (name === 'is' && !ALLOWED_ATTR[name]) {\n if (RETURN_DOM || RETURN_DOM_FRAGMENT) {\n try {\n _forceRemove(node);\n } catch (_) {}\n } else {\n try {\n node.setAttribute(name, '');\n } catch (_) {}\n }\n }\n };\n\n /**\n * _initDocument\n *\n * @param {String} dirty a string of dirty markup\n * @return {Document} a DOM, filled with the dirty markup\n */\n const _initDocument = function _initDocument(dirty) {\n /* Create a HTML document */\n let doc = null;\n let leadingWhitespace = null;\n if (FORCE_BODY) {\n dirty = '<remove></remove>' + dirty;\n } else {\n /* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */\n const matches = stringMatch(dirty, /^[\\r\\n\\t ]+/);\n leadingWhitespace = matches && matches[0];\n }\n if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && NAMESPACE === HTML_NAMESPACE) {\n // Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict)\n dirty = '<html xmlns=\"http://www.w3.org/1999/xhtml\"><head></head><body>' + dirty + '</body></html>';\n }\n const dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;\n /*\n * Use the DOMParser API by default, fallback later if needs be\n * DOMParser not work for svg when has multiple root element.\n */\n if (NAMESPACE === HTML_NAMESPACE) {\n try {\n doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);\n } catch (_) {}\n }\n\n /* Use createHTMLDocument in case DOMParser is not available */\n if (!doc || !doc.documentElement) {\n doc = implementation.createDocument(NAMESPACE, 'template', null);\n try {\n doc.documentElement.innerHTML = IS_EMPTY_INPUT ? emptyHTML : dirtyPayload;\n } catch (_) {\n // Syntax error if dirtyPayload is invalid xml\n }\n }\n const body = doc.body || doc.documentElement;\n if (dirty && leadingWhitespace) {\n body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);\n }\n\n /* Work on whole document or just its body */\n if (NAMESPACE === HTML_NAMESPACE) {\n return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];\n }\n return WHOLE_DOCUMENT ? doc.documentElement : body;\n };\n\n /**\n * Creates a NodeIterator object that you can use to traverse filtered lists of nodes or elements in a document.\n *\n * @param {Node} root The root element or node to start traversing on.\n * @return {NodeIterator} The created NodeIterator\n */\n const _createNodeIterator = function _createNodeIterator(root) {\n return createNodeIterator.call(root.ownerDocument || root, root,\n // eslint-disable-next-line no-bitwise\n NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION, null);\n };\n\n /**\n * _isClobbered\n *\n * @param {Node} elm element to check for clobbering attacks\n * @return {Boolean} true if clobbered, false if safe\n */\n const _isClobbered = function _isClobbered(elm) {\n return elm instanceof HTMLFormElement && (\n // eslint-disable-next-line unicorn/no-typeof-undefined\n typeof elm.__depth !== 'undefined' && typeof elm.__depth !== 'number' ||\n // eslint-disable-next-line unicorn/no-typeof-undefined\n typeof elm.__removalCount !== 'undefined' && typeof elm.__removalCount !== 'number' || 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' || typeof elm.hasChildNodes !== 'function');\n };\n\n /**\n * Checks whether the given object is a DOM node.\n *\n * @param {Node} object object to check whether it's a DOM node\n * @return {Boolean} true is object is a DOM node\n */\n const _isNode = function _isNode(object) {\n return typeof Node === 'function' && object instanceof Node;\n };\n\n /**\n * _executeHook\n * Execute user configurable hooks\n *\n * @param {String} entryPoint Name of the hook's entry point\n * @param {Node} currentNode node to work on with the hook\n * @param {Object} data additional hook parameters\n */\n const _executeHook = function _executeHook(entryPoint, currentNode, data) {\n if (!hooks[entryPoint]) {\n return;\n }\n arrayForEach(hooks[entryPoint], hook => {\n hook.call(DOMPurify, currentNode, data, CONFIG);\n });\n };\n\n /**\n * _sanitizeElements\n *\n * @protect nodeName\n * @protect textContent\n * @protect removeChild\n *\n * @param {Node} currentNode to check for permission to exist\n * @return {Boolean} true if node was killed, false if left alive\n */\n const _sanitizeElements = function _sanitizeElements(currentNode) {\n let content = null;\n\n /* Execute a hook if present */\n _executeHook('beforeSanitizeElements', currentNode, null);\n\n /* Check if element is clobbered or can clobber */\n if (_isClobbered(currentNode)) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Now let's check the element's type and name */\n const tagName = transformCaseFunc(currentNode.nodeName);\n\n /* Execute a hook if present */\n _executeHook('uponSanitizeElement', currentNode, {\n tagName,\n allowedTags: ALLOWED_TAGS\n });\n\n /* Detect mXSS attempts abusing namespace confusion */\n if (currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(/<[/\\w]/g, currentNode.innerHTML) && regExpTest(/<[/\\w]/g, currentNode.textContent)) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Remove any ocurrence of processing instructions */\n if (currentNode.nodeType === NODE_TYPE.progressingInstruction) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Remove any kind of possibly harmful comments */\n if (SAFE_FOR_XML && currentNode.nodeType === NODE_TYPE.comment && regExpTest(/<[/\\w]/g, currentNode.data)) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Remove element if anything forbids its presence */\n if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {\n /* Check if we have a custom element to handle */\n if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) {\n if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) {\n return false;\n }\n if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) {\n return false;\n }\n }\n\n /* Keep content except for bad-listed elements */\n if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {\n const parentNode = getParentNode(currentNode) || currentNode.parentNode;\n const childNodes = getChildNodes(currentNode) || currentNode.childNodes;\n if (childNodes && parentNode) {\n const childCount = childNodes.length;\n for (let i = childCount - 1; i >= 0; --i) {\n const childClone = cloneNode(childNodes[i], true);\n childClone.__removalCount = (currentNode.__removalCount || 0) + 1;\n parentNode.insertBefore(childClone, getNextSibling(currentNode));\n }\n }\n }\n _forceRemove(currentNode);\n return true;\n }\n\n /* Check whether element has a valid namespace */\n if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Make sure that older browsers don't get fallback-tag mXSS */\n if ((tagName === 'noscript' || tagName === 'noembed' || tagName === 'noframes') && regExpTest(/<\\/no(script|embed|frames)/i, currentNode.innerHTML)) {\n _forceRemove(currentNode);\n return true;\n }\n\n /* Sanitize element content to be template-safe */\n if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) {\n /* Get the element's text content */\n content = currentNode.textContent;\n arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {\n content = stringReplace(content, expr, ' ');\n });\n if (currentNode.textContent !== content) {\n arrayPush(DOMPurify.removed, {\n element: currentNode.cloneNode()\n });\n currentNode.textContent = content;\n }\n }\n\n /* Execute a hook if present */\n _executeHook('afterSanitizeElements', currentNode, null);\n return false;\n };\n\n /**\n * _isValidAttribute\n *\n * @param {string} lcTag Lowercase tag name of containing element.\n * @param {string} lcName Lowercase attribute name.\n * @param {string} value Attribute value.\n * @return {Boolean} Returns true if `value` is valid, otherwise false.\n */\n // eslint-disable-next-line complexity\n const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {\n /* Make sure attribute cannot clobber */\n if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement || value === '__depth' || value === '__removalCount')) {\n return false;\n }\n\n /* Allow valid data-* attributes: At least one character after \"-\"\n (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)\n XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)\n We don't need to check the value; it's always URI safe. */\n 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]) {\n if (\n // First condition does a very basic check if a) it's basically a valid custom element tagname AND\n // b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck\n // and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck\n _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)) ||\n // Alternative, second condition checks if it's an `is`-attribute, AND\n // the value passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck\n 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 {\n return false;\n }\n /* Check value is safe. First, is attr inert? If so, is safe */\n } 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) {\n return false;\n } else ;\n return true;\n };\n\n /**\n * _isBasicCustomElement\n * checks if at least one dash is included in tagName, and it's not the first char\n * for more sophisticated checking see https://github.com/sindresorhus/validate-element-name\n *\n * @param {string} tagName name of the tag of the node to sanitize\n * @returns {boolean} Returns true if the tag name meets the basic criteria for a custom element, otherwise false.\n */\n const _isBasicCustomElement = function _isBasicCustomElement(tagName) {\n return tagName !== 'annotation-xml' && stringMatch(tagName, CUSTOM_ELEMENT);\n };\n\n /**\n * _sanitizeAttributes\n *\n * @protect attributes\n * @protect nodeName\n * @protect removeAttribute\n * @protect setAttribute\n *\n * @param {Node} currentNode to sanitize\n */\n const _sanitizeAttributes = function _sanitizeAttributes(currentNode) {\n /* Execute a hook if present */\n _executeHook('beforeSanitizeAttributes', currentNode, null);\n const {\n attributes\n } = currentNode;\n\n /* Check if we have attributes; if not we might have a text node */\n if (!attributes) {\n return;\n }\n const hookEvent = {\n attrName: '',\n attrValue: '',\n keepAttr: true,\n allowedAttributes: ALLOWED_ATTR\n };\n let l = attributes.length;\n\n /* Go backwards over all attributes; safely remove bad ones */\n while (l--) {\n const attr = attributes[l];\n const {\n name,\n namespaceURI,\n value: attrValue\n } = attr;\n const lcName = transformCaseFunc(name);\n let value = name === 'value' ? attrValue : stringTrim(attrValue);\n\n /* Execute a hook if present */\n hookEvent.attrName = lcName;\n hookEvent.attrValue = value;\n hookEvent.keepAttr = true;\n hookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set\n _executeHook('uponSanitizeAttribute', currentNode, hookEvent);\n value = hookEvent.attrValue;\n /* Did the hooks approve of the attribute? */\n if (hookEvent.forceKeepAttr) {\n continue;\n }\n\n /* Remove attribute */\n _removeAttribute(name, currentNode);\n\n /* Did the hooks approve of the attribute? */\n if (!hookEvent.keepAttr) {\n continue;\n }\n\n /* Work around a security issue in jQuery 3.0 */\n if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(/\\/>/i, value)) {\n _removeAttribute(name, currentNode);\n continue;\n }\n\n /* Work around a security issue with comments inside attributes */\n if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\\/(style|title)/i, value)) {\n _removeAttribute(name, currentNode);\n continue;\n }\n\n /* Sanitize attribute content to be template-safe */\n if (SAFE_FOR_TEMPLATES) {\n arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {\n value = stringReplace(value, expr, ' ');\n });\n }\n\n /* Is `value` valid for this attribute? */\n const lcTag = transformCaseFunc(currentNode.nodeName);\n if (!_isValidAttribute(lcTag, lcName, value)) {\n continue;\n }\n\n /* Full DOM Clobbering protection via namespace isolation,\n * Prefix id and name attributes with `user-content-`\n */\n if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {\n // Remove the attribute with this value\n _removeAttribute(name, currentNode);\n\n // Prefix the value and later re-create the attribute with the sanitized value\n value = SANITIZE_NAMED_PROPS_PREFIX + value;\n }\n\n /* Handle attributes that require Trusted Types */\n if (trustedTypesPolicy && typeof trustedTypes === 'object' && typeof trustedTypes.getAttributeType === 'function') {\n if (namespaceURI) ; else {\n switch (trustedTypes.getAttributeType(lcTag, lcName)) {\n case 'TrustedHTML':\n {\n value = trustedTypesPolicy.createHTML(value);\n break;\n }\n case 'TrustedScriptURL':\n {\n value = trustedTypesPolicy.createScriptURL(value);\n break;\n }\n }\n }\n }\n\n /* Handle invalid data-* attribute set by try-catching it */\n try {\n if (namespaceURI) {\n currentNode.setAttributeNS(namespaceURI, name, value);\n } else {\n /* Fallback to setAttribute() for browser-unrecognized namespaces e.g. \"x-schema\". */\n currentNode.setAttribute(name, value);\n }\n if (_isClobbered(currentNode)) {\n _forceRemove(currentNode);\n } else {\n arrayPop(DOMPurify.removed);\n }\n } catch (_) {}\n }\n\n /* Execute a hook if present */\n _executeHook('afterSanitizeAttributes', currentNode, null);\n };\n\n /**\n * _sanitizeShadowDOM\n *\n * @param {DocumentFragment} fragment to iterate over recursively\n */\n const _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {\n let shadowNode = null;\n const shadowIterator = _createNodeIterator(fragment);\n\n /* Execute a hook if present */\n _executeHook('beforeSanitizeShadowDOM', fragment, null);\n while (shadowNode = shadowIterator.nextNode()) {\n /* Execute a hook if present */\n _executeHook('uponSanitizeShadowNode', shadowNode, null);\n\n /* Sanitize tags and elements */\n if (_sanitizeElements(shadowNode)) {\n continue;\n }\n const parentNode = getParentNode(shadowNode);\n\n /* Set the nesting depth of an element */\n if (shadowNode.nodeType === NODE_TYPE.element) {\n if (parentNode && parentNode.__depth) {\n /*\n We want the depth of the node in the original tree, which can\n change when it's removed from its parent.\n */\n shadowNode.__depth = (shadowNode.__removalCount || 0) + parentNode.__depth + 1;\n } else {\n shadowNode.__depth = 1;\n }\n }\n\n /*\n * Remove an element if nested too deeply to avoid mXSS\n * or if the __depth might have been tampered with\n */\n if (shadowNode.__depth >= MAX_NESTING_DEPTH || shadowNode.__depth < 0 || numberIsNaN(shadowNode.__depth)) {\n _forceRemove(shadowNode);\n }\n\n /* Deep shadow DOM detected */\n if (shadowNode.content instanceof DocumentFragment) {\n shadowNode.content.__depth = shadowNode.__depth;\n _sanitizeShadowDOM(shadowNode.content);\n }\n\n /* Check attributes, sanitize if necessary */\n _sanitizeAttributes(shadowNode);\n }\n\n /* Execute a hook if present */\n _executeHook('afterSanitizeShadowDOM', fragment, null);\n };\n\n /**\n * Sanitize\n * Public method providing core sanitation functionality\n *\n * @param {String|Node} dirty string or DOM node\n * @param {Object} cfg object\n */\n // eslint-disable-next-line complexity\n DOMPurify.sanitize = function (dirty) {\n let cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n let body = null;\n let importedNode = null;\n let currentNode = null;\n let returnNode = null;\n /* Make sure we have a string to sanitize.\n DO NOT return early, as this will return the wrong type if\n the user has requested a DOM object rather than a string */\n IS_EMPTY_INPUT = !dirty;\n if (IS_EMPTY_INPUT) {\n dirty = '<!-->';\n }\n\n /* Stringify, in case dirty is an object */\n if (typeof dirty !== 'string' && !_isNode(dirty)) {\n if (typeof dirty.toString === 'function') {\n dirty = dirty.toString();\n if (typeof dirty !== 'string') {\n throw typeErrorCreate('dirty is not a string, aborting');\n }\n } else {\n throw typeErrorCreate('toString is not a function');\n }\n }\n\n /* Return dirty HTML if DOMPurify cannot run */\n if (!DOMPurify.isSupported) {\n return dirty;\n }\n\n /* Assign config vars */\n if (!SET_CONFIG) {\n _parseConfig(cfg);\n }\n\n /* Clean up removed elements */\n DOMPurify.removed = [];\n\n /* Check if dirty is correctly typed for IN_PLACE */\n if (typeof dirty === 'string') {\n IN_PLACE = false;\n }\n if (IN_PLACE) {\n /* Do some early pre-sanitization to avoid unsafe root nodes */\n if (dirty.nodeName) {\n const tagName = transformCaseFunc(dirty.nodeName);\n if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {\n throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');\n }\n }\n } else if (dirty instanceof Node) {\n /* If dirty is a DOM element, append to an empty document to avoid\n elements being stripped by the parser */\n body = _initDocument('<!---->');\n importedNode = body.ownerDocument.importNode(dirty, true);\n if (importedNode.nodeType === NODE_TYPE.element && importedNode.nodeName === 'BODY') {\n /* Node is already a body, use as is */\n body = importedNode;\n } else if (importedNode.nodeName === 'HTML') {\n body = importedNode;\n } else {\n // eslint-disable-next-line unicorn/prefer-dom-node-append\n body.appendChild(importedNode);\n }\n } else {\n /* Exit directly if we have nothing to do */\n if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT &&\n // eslint-disable-next-line unicorn/prefer-includes\n dirty.indexOf('<') === -1) {\n return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;\n }\n\n /* Initialize the document to work on */\n body = _initDocument(dirty);\n\n /* Check we have a DOM node from the data */\n if (!body) {\n return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';\n }\n }\n\n /* Remove first element node (ours) if FORCE_BODY is set */\n if (body && FORCE_BODY) {\n _forceRemove(body.firstChild);\n }\n\n /* Get node iterator */\n const nodeIterator = _createNodeIterator(IN_PLACE ? dirty : body);\n\n /* Now start iterating over the created document */\n while (currentNode = nodeIterator.nextNode()) {\n /* Sanitize tags and elements */\n if (_sanitizeElements(currentNode)) {\n continue;\n }\n const parentNode = getParentNode(currentNode);\n\n /* Set the nesting depth of an element */\n if (currentNode.nodeType === NODE_TYPE.element) {\n if (parentNode && parentNode.__depth) {\n /*\n We want the depth of the node in the original tree, which can\n change when it's removed from its parent.\n */\n currentNode.__depth = (currentNode.__removalCount || 0) + parentNode.__depth + 1;\n } else {\n currentNode.__depth = 1;\n }\n }\n\n /*\n * Remove an element if nested too deeply to avoid mXSS\n * or if the __depth might have been tampered with\n */\n if (currentNode.__depth >= MAX_NESTING_DEPTH || currentNode.__depth < 0 || numberIsNaN(currentNode.__depth)) {\n _forceRemove(currentNode);\n }\n\n /* Shadow DOM detected, sanitize it */\n if (currentNode.content instanceof DocumentFragment) {\n currentNode.content.__depth = currentNode.__depth;\n _sanitizeShadowDOM(currentNode.content);\n }\n\n /* Check attributes, sanitize if necessary */\n _sanitizeAttributes(currentNode);\n }\n\n /* If we sanitized `dirty` in-place, return it. */\n if (IN_PLACE) {\n return dirty;\n }\n\n /* Return sanitized string or DOM */\n if (RETURN_DOM) {\n if (RETURN_DOM_FRAGMENT) {\n returnNode = createDocumentFragment.call(body.ownerDocument);\n while (body.firstChild) {\n // eslint-disable-next-line unicorn/prefer-dom-node-append\n returnNode.appendChild(body.firstChild);\n }\n } else {\n returnNode = body;\n }\n if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmode) {\n /*\n AdoptNode() is not used because internal state is not reset\n (e.g. the past names map of a HTMLFormElement), this is safe\n in theory but we would rather not risk another attack vector.\n The state that is cloned by importNode() is explicitly defined\n by the specs.\n */\n returnNode = importNode.call(originalDocument, returnNode, true);\n }\n return returnNode;\n }\n let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;\n\n /* Serialize doctype if allowed */\n if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {\n serializedHTML = '<!DOCTYPE ' + body.ownerDocument.doctype.name + '>\\n' + serializedHTML;\n }\n\n /* Sanitize final string template-safe */\n if (SAFE_FOR_TEMPLATES) {\n arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {\n serializedHTML = stringReplace(serializedHTML, expr, ' ');\n });\n }\n return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;\n };\n\n /**\n * Public method to set the configuration once\n * setConfig\n *\n * @param {Object} cfg configuration object\n */\n DOMPurify.setConfig = function () {\n let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n _parseConfig(cfg);\n SET_CONFIG = true;\n };\n\n /**\n * Public method to remove the configuration\n * clearConfig\n *\n */\n DOMPurify.clearConfig = function () {\n CONFIG = null;\n SET_CONFIG = false;\n };\n\n /**\n * Public method to check if an attribute value is valid.\n * Uses last set config, if any. Otherwise, uses config defaults.\n * isValidAttribute\n *\n * @param {String} tag Tag name of containing element.\n * @param {String} attr Attribute name.\n * @param {String} value Attribute value.\n * @return {Boolean} Returns true if `value` is valid. Otherwise, returns false.\n */\n DOMPurify.isValidAttribute = function (tag, attr, value) {\n /* Initialize shared config vars if necessary. */\n if (!CONFIG) {\n _parseConfig({});\n }\n const lcTag = transformCaseFunc(tag);\n const lcName = transformCaseFunc(attr);\n return _isValidAttribute(lcTag, lcName, value);\n };\n\n /**\n * AddHook\n * Public method to add DOMPurify hooks\n *\n * @param {String} entryPoint entry point for the hook to add\n * @param {Function} hookFunction function to execute\n */\n DOMPurify.addHook = function (entryPoint, hookFunction) {\n if (typeof hookFunction !== 'function') {\n return;\n }\n hooks[entryPoint] = hooks[entryPoint] || [];\n arrayPush(hooks[entryPoint], hookFunction);\n };\n\n /**\n * RemoveHook\n * Public method to remove a DOMPurify hook at a given entryPoint\n * (pops it from the stack of hooks if more are present)\n *\n * @param {String} entryPoint entry point for the hook to remove\n * @return {Function} removed(popped) hook\n */\n DOMPurify.removeHook = function (entryPoint) {\n if (hooks[entryPoint]) {\n return arrayPop(hooks[entryPoint]);\n }\n };\n\n /**\n * RemoveHooks\n * Public method to remove all DOMPurify hooks at a given entryPoint\n *\n * @param {String} entryPoint entry point for the hooks to remove\n */\n DOMPurify.removeHooks = function (entryPoint) {\n if (hooks[entryPoint]) {\n hooks[entryPoint] = [];\n }\n };\n\n /**\n * RemoveAllHooks\n * Public method to remove all DOMPurify hooks\n */\n DOMPurify.removeAllHooks = function () {\n hooks = {};\n };\n return DOMPurify;\n }\n var purify = createDOMPurify();\n\n return purify;\n\n}));\n//# sourceMappingURL=purify.js.map\n\n\n//# sourceURL=webpack://Formio/./node_modules/dompurify/dist/purify.js?");
|
|
2722
2732
|
|
|
2723
2733
|
/***/ }),
|
|
2724
2734
|
|
|
@@ -5227,7 +5237,7 @@ eval("\nvar __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5227
5237
|
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
|
|
5228
5238
|
|
|
5229
5239
|
"use strict";
|
|
5230
|
-
eval("\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nconst lodash_1 = __importDefault(__webpack_require__(/*! lodash */ \"./node_modules/lodash/lodash.js\"));\nconst moment_1 = __importDefault(__webpack_require__(/*! moment */ \"./node_modules/moment/moment.js\"));\nconst compare_versions_1 = __webpack_require__(/*! compare-versions */ \"./node_modules/compare-versions/lib/esm/index.js\");\nconst core_1 = __webpack_require__(/*! @formio/core */ \"./node_modules/@formio/core/lib/index.js\");\nconst EventEmitter_1 = __importDefault(__webpack_require__(/*! ./EventEmitter */ \"./lib/cjs/EventEmitter.js\"));\nconst i18n_1 = __importDefault(__webpack_require__(/*! ./i18n */ \"./lib/cjs/i18n.js\"));\nconst Formio_1 = __webpack_require__(/*! ./Formio */ \"./lib/cjs/Formio.js\");\nconst Components_1 = __importDefault(__webpack_require__(/*! ./components/Components */ \"./lib/cjs/components/Components.js\"));\nconst NestedDataComponent_1 = __importDefault(__webpack_require__(/*! ./components/_classes/nesteddata/NestedDataComponent */ \"./lib/cjs/components/_classes/nesteddata/NestedDataComponent.js\"));\nconst utils_1 = __webpack_require__(/*! ./utils/utils */ \"./lib/cjs/utils/utils.js\");\nconst formUtils_1 = __webpack_require__(/*! ./utils/formUtils */ \"./lib/cjs/utils/formUtils.js\");\n// Initialize the available forms.\nFormio_1.Formio.forms = {};\n// Allow people to register components.\nFormio_1.Formio.registerComponent = Components_1.default.setComponent;\nfunction getIconSet(icons) {\n if (icons === 'fontawesome') {\n return 'fa';\n }\n return icons || '';\n}\nfunction getOptions(options) {\n options = lodash_1.default.defaults(options, {\n submitOnEnter: false,\n iconset: getIconSet((options && options.icons) ? options.icons : Formio_1.Formio.icons),\n i18next: null,\n saveDraft: false,\n alwaysDirty: false,\n saveDraftThrottle: 5000,\n display: 'form',\n cdnUrl: Formio_1.Formio.cdn.baseUrl\n });\n if (!options.events) {\n options.events = new EventEmitter_1.default();\n }\n return options;\n}\n/**\n * Represents a JSON value.\n * @typedef {(string | number | boolean | null | JSONArray | JSONObject)} JSON\n */\n/**\n * Represents a JSON array.\n * @typedef {Array<JSON>} JSONArray\n */\n/**\n * Represents a JSON object.\n * @typedef {{[key: string]: JSON}} JSONObject\n */\n/**\n * @typedef {Object} FormioHooks\n * @property {function} [beforeSubmit]\n * @property {function} [beforeCancel]\n * @property {function} [beforeNext]\n * @property {function} [beforePrev]\n * @property {function} [attachComponent]\n * @property {function} [setDataValue]\n * @property {function} [addComponents]\n * @property {function} [addComponent]\n * @property {function} [customValidation]\n * @property {function} [attachWebform]\n */\n/**\n * @typedef {Object} SanitizeConfig\n * @property {string[]} [addAttr]\n * @property {string[]} [addTags]\n * @property {string[]} [allowedAttrs]\n * @property {string[]} [allowedTags]\n * @property {string[]} [allowedUriRegex]\n * @property {string[]} [addUriSafeAttr]\n */\n/**\n * @typedef {Object} ButtonSettings\n * @property {boolean} [showPrevious]\n * @property {boolean} [showNext]\n * @property {boolean} [showCancel]\n * @property {boolean} [showSubmit]\n */\n/**\n * @typedef {Object} FormOptions\n * @property {boolean} [saveDraft] - Enable the save draft feature.\n * @property {number} [saveDraftThrottle] - The throttle for the save draft feature.\n * @property {boolean} [readOnly] - Set this form to readOnly.\n * @property {boolean} [noAlerts] - Disable the alerts dialog.\n * @property {{[key: string]: string}} [i18n] - The translation file for this rendering.\n * @property {string} [template] - Custom logic for creation of elements.\n * @property {boolean} [noDefaults] - Exclude default values from the settings.\n * @property {any} [fileService] - The file service for this form.\n * @property {EventEmitter} [events] - The EventEmitter for this form.\n * @property {string} [language] - The language to render this form in.\n * @property {{[key: string]: string}} [i18next] - The i18next configuration for this form.\n * @property {boolean} [viewAsHtml] - View the form as raw HTML.\n * @property {'form' | 'html' | 'flat' | 'builder' | 'pdf'} [renderMode] - The render mode for this form.\n * @property {boolean} [highlightErrors] - Highlight any errors on the form.\n * @property {string} [componentErrorClass] - The error class for components.\n * @property {any} [templates] - The templates for this form.\n * @property {string} [iconset] - The iconset for this form.\n * @property {Component[]} [components] - The components for this form.\n * @property {{[key: string]: boolean}} [disabled] - Disabled components for this form.\n * @property {boolean} [showHiddenFields] - Show hidden fields.\n * @property {{[key: string]: boolean}} [hide] - Hidden components for this form.\n * @property {{[key: string]: boolean}} [show] - Components to show for this form.\n * @property {Formio} [formio] - The Formio instance for this form.\n * @property {string} [decimalSeparator] - The decimal separator for this form.\n * @property {string} [thousandsSeparator] - The thousands separator for this form.\n * @property {FormioHooks} [hooks] - The hooks for this form.\n * @property {boolean} [alwaysDirty] - Always be dirty.\n * @property {boolean} [skipDraftRestore] - Skip restoring a draft.\n * @property {'form' | 'wizard' | 'pdf'} [display] - The display for this form.\n * @property {string} [cdnUrl] - The CDN url for this form.\n * @property {boolean} [flatten] - Flatten the form.\n * @property {boolean} [sanitize] - Sanitize the form.\n * @property {SanitizeConfig} [sanitizeConfig] - The sanitize configuration for this form.\n * @property {ButtonSettings} [buttonSettings] - The button settings for this form.\n * @property {Object} [breadCrumbSettings] - The breadcrumb settings for this form.\n * @property {boolean} [allowPrevious] - Allow the previous button (for Wizard forms).\n * @property {string[]} [wizardButtonOrder] - The order of the buttons (for Wizard forms).\n * @property {boolean} [showCheckboxBackground] - Show the checkbox background.\n * @property {number} [zoom] - The zoom for PDF forms.\n */\n/**\n * Renders a Form.io form within the webpage.\n */\nclass Webform extends NestedDataComponent_1.default {\n /**\n * Creates a new Form instance.\n *\n * @param {HTMLElement | Object | FormOptions} [elementOrOptions] - The DOM element to render this form within or the options to create this form instance.\n * @param {FormOptions} [options] - The options to create a new form instance.\n */\n constructor(elementOrOptions, options) {\n let element, formOptions;\n if (elementOrOptions instanceof HTMLElement || options) {\n element = elementOrOptions;\n formOptions = options;\n }\n else {\n formOptions = elementOrOptions;\n }\n super(null, getOptions(formOptions));\n this.executeShortcuts = (event) => {\n const { target } = event;\n if (!this.keyboardCatchableElement(target)) {\n return;\n }\n const ctrl = event.ctrlKey || event.metaKey;\n const keyCode = event.keyCode;\n let char = '';\n if (65 <= keyCode && keyCode <= 90) {\n char = String.fromCharCode(keyCode);\n }\n else if (keyCode === 13) {\n char = 'Enter';\n }\n else if (keyCode === 27) {\n char = 'Esc';\n }\n lodash_1.default.each(this.shortcuts, (shortcut) => {\n if (shortcut.ctrl && !ctrl) {\n return;\n }\n if (shortcut.shortcut === char) {\n shortcut.element.click();\n event.preventDefault();\n }\n });\n };\n this.setElement(element);\n // Keep track of all available forms globally.\n Formio_1.Formio.forms[this.id] = this;\n // Set the base url.\n if (this.options.baseUrl) {\n Formio_1.Formio.setBaseUrl(this.options.baseUrl);\n }\n /**\n * The type of this element.\n * @type {string}\n */\n this.type = 'form';\n this._src = '';\n this._loading = false;\n this._form = {};\n this.draftEnabled = false;\n this.savingDraft = true;\n if (this.options.saveDraftThrottle) {\n this.triggerSaveDraft = lodash_1.default.throttle(this.saveDraft.bind(this), this.options.saveDraftThrottle);\n }\n else {\n this.triggerSaveDraft = this.saveDraft.bind(this);\n }\n /**\n * Determines if this form should submit the API on submit.\n * @type {boolean}\n */\n this.nosubmit = false;\n /**\n * Determines if the form has tried to be submitted, error or not.\n *\n * @type {boolean}\n */\n this.submitted = false;\n /**\n * Determines if the form is being submitted at the moment.\n *\n * @type {boolean}\n */\n this.submitting = false;\n /**\n * The Formio instance for this form.\n * @type {Formio}\n */\n this.formio = null;\n /**\n * The loader HTML element.\n * @type {HTMLElement}\n */\n this.loader = null;\n /**\n * The alert HTML element\n * @type {HTMLElement}\n */\n this.alert = null;\n /**\n * Promise that is triggered when the submission is done loading.\n * @type {Promise}\n */\n this.onSubmission = null;\n /**\n * Determines if this submission is explicitly set.\n * @type {boolean}\n */\n this.submissionSet = false;\n /**\n * Promise that executes when the form is ready and rendered.\n * @type {Promise}\n *\n * @example\n * import Webform from '@formio/js/Webform';\n * let form = new Webform(document.getElementById('formio'));\n * form.formReady.then(() => {\n * console.log('The form is ready!');\n * });\n * form.src = 'https://examples.form.io/example';\n */\n this.formReady = new Promise((resolve, reject) => {\n /**\n * Called when the formReady state of this form has been resolved.\n *\n * @type {function}\n */\n this.formReadyResolve = resolve;\n /**\n * Called when this form could not load and is rejected.\n *\n * @type {function}\n */\n this.formReadyReject = reject;\n });\n /**\n * Promise that executes when the submission is ready and rendered.\n * @type {Promise}\n *\n * @example\n * import Webform from '@formio/js/Webform';\n * let form = new Webform(document.getElementById('formio'));\n * form.submissionReady.then(() => {\n * console.log('The submission is ready!');\n * });\n * form.src = 'https://examples.form.io/example/submission/234234234234234243';\n */\n this.submissionReady = new Promise((resolve, reject) => {\n /**\n * Called when the formReady state of this form has been resolved.\n *\n * @type {function}\n */\n this.submissionReadyResolve = resolve;\n /**\n * Called when this form could not load and is rejected.\n *\n * @type {function}\n */\n this.submissionReadyReject = reject;\n });\n this.shortcuts = [];\n // Set language after everything is established.\n this.language = this.i18next.language;\n // See if we need to restore the draft from a user.\n if (this.options.saveDraft && !this.options.skipDraftRestore) {\n this.formReady.then(() => {\n const user = Formio_1.Formio.getUser();\n // Only restore a draft if the submission isn't explicitly set.\n if (user && !this.submissionSet) {\n this.restoreDraft(user._id);\n }\n });\n }\n this.component.clearOnHide = false;\n // Ensure the root is set to this component.\n this.root = this;\n this.localRoot = this;\n }\n /* eslint-enable max-statements */\n get language() {\n return this.options.language;\n }\n get emptyValue() {\n return null;\n }\n componentContext() {\n return this._data;\n }\n /**\n * Sets the language for this form.\n *\n * @param lang\n * @return {Promise}\n */\n set language(lang) {\n if (!this.i18next) {\n return;\n }\n this.options.language = lang;\n if (this.i18next.language === lang) {\n return;\n }\n this.i18next.changeLanguage(lang, (err) => {\n if (err) {\n return;\n }\n this.rebuild();\n this.emit('languageChanged');\n });\n }\n get componentComponents() {\n return this.form.components;\n }\n get shadowRoot() {\n return this.options.shadowRoot;\n }\n /**\n * Add a language for translations\n *\n * @param code\n * @param lang\n * @param active\n * @return {*}\n */\n addLanguage(code, lang, active = false) {\n if (this.i18next) {\n var translations = lodash_1.default.assign((0, utils_1.fastCloneDeep)(i18n_1.default.resources.en.translation), lang);\n this.i18next.addResourceBundle(code, 'translation', translations, true, true);\n if (active) {\n this.language = code;\n }\n }\n }\n keyboardCatchableElement(element) {\n if (element.nodeName === 'TEXTAREA') {\n return false;\n }\n if (element.nodeName === 'INPUT') {\n return [\n 'text',\n 'email',\n 'password'\n ].indexOf(element.type) === -1;\n }\n return true;\n }\n addShortcut(element, shortcut) {\n if (!shortcut || !/^([A-Z]|Enter|Esc)$/i.test(shortcut)) {\n return;\n }\n shortcut = lodash_1.default.capitalize(shortcut);\n if (shortcut === 'Enter' || shortcut === 'Esc') {\n // Restrict Enter and Esc only for buttons\n if (element.tagName !== 'BUTTON') {\n return;\n }\n this.shortcuts.push({\n shortcut,\n element\n });\n }\n else {\n this.shortcuts.push({\n ctrl: true,\n shortcut,\n element\n });\n }\n }\n removeShortcut(element, shortcut) {\n if (!shortcut || !/^([A-Z]|Enter|Esc)$/i.test(shortcut)) {\n return;\n }\n lodash_1.default.remove(this.shortcuts, {\n shortcut,\n element\n });\n }\n /**\n * Get the embed source of the form.\n *\n * @returns {string}\n */\n get src() {\n return this._src;\n }\n /**\n * Loads the submission if applicable.\n */\n loadSubmission() {\n this.loadingSubmission = true;\n if (this.formio.submissionId) {\n this.onSubmission = this.formio.loadSubmission().then((submission) => this.setSubmission(submission), (err) => this.submissionReadyReject(err)).catch((err) => this.submissionReadyReject(err));\n }\n else {\n this.submissionReadyResolve();\n }\n return this.submissionReady;\n }\n /**\n * Set the src of the form renderer.\n *\n * @param value\n * @param options\n */\n setSrc(value, options) {\n if (this.setUrl(value, options)) {\n this.nosubmit = false;\n return this.formio.loadForm({ params: { live: 1 } }).then((form) => {\n const setForm = this.setForm(form);\n this.loadSubmission();\n return setForm;\n }).catch((err) => {\n console.warn(err);\n this.formReadyReject(err);\n });\n }\n return Promise.resolve();\n }\n /**\n * Set the Form source, which is typically the Form.io embed URL.\n *\n * @param {string} value - The value of the form embed url.\n *\n * @example\n * import Webform from '@formio/js/Webform';\n * let form = new Webform(document.getElementById('formio'));\n * form.formReady.then(() => {\n * console.log('The form is formReady!');\n * });\n * form.src = 'https://examples.form.io/example';\n */\n set src(value) {\n this.setSrc(value);\n }\n /**\n * Get the embed source of the form.\n *\n * @returns {string}\n */\n get url() {\n return this._src;\n }\n /**\n * Sets the url of the form renderer.\n *\n * @param value\n * @param options\n */\n setUrl(value, options) {\n if (!value ||\n (typeof value !== 'string') ||\n (value === this._src)) {\n return false;\n }\n this._src = value;\n this.nosubmit = true;\n this.formio = this.options.formio = new Formio_1.Formio(value, options);\n if (this.type === 'form') {\n // Set the options source so this can be passed to other components.\n this.options.src = value;\n }\n return true;\n }\n /**\n * Set the form source but don't initialize the form and submission from the url.\n *\n * @param {string} value - The value of the form embed url.\n */\n set url(value) {\n this.setUrl(value);\n }\n /**\n * Called when both the form and submission have been loaded.\n *\n * @returns {Promise} - The promise to trigger when both form and submission have loaded.\n */\n get ready() {\n return this.formReady.then(() => {\n return super.ready.then(() => {\n return this.loadingSubmission ? this.submissionReady : true;\n });\n });\n }\n /**\n * Returns if this form is loading.\n *\n * @returns {boolean} - TRUE means the form is loading, FALSE otherwise.\n */\n get loading() {\n return this._loading;\n }\n /**\n * Set the loading state for this form, and also show the loader spinner.\n *\n * @param {boolean} loading - If this form should be \"loading\" or not.\n */\n set loading(loading) {\n if (this._loading !== loading) {\n this._loading = loading;\n if (!this.loader && loading) {\n this.loader = this.ce('div', {\n class: 'loader-wrapper'\n });\n const spinner = this.ce('div', {\n class: 'loader text-center'\n });\n this.loader.appendChild(spinner);\n }\n /* eslint-disable max-depth */\n if (this.loader) {\n try {\n if (loading) {\n this.prependTo(this.loader, this.wrapper);\n }\n else {\n this.removeChildFrom(this.loader, this.wrapper);\n }\n }\n catch (err) {\n // ingore\n }\n }\n /* eslint-enable max-depth */\n }\n }\n /**\n * Sets the JSON schema for the form to be rendered.\n *\n * @example\n * import Webform from '@formio/js/Webform';\n * let form = new Webform(document.getElementById('formio'));\n * form.setForm({\n * components: [\n * {\n * type: 'textfield',\n * key: 'firstName',\n * label: 'First Name',\n * placeholder: 'Enter your first name.',\n * input: true\n * },\n * {\n * type: 'textfield',\n * key: 'lastName',\n * label: 'Last Name',\n * placeholder: 'Enter your last name',\n * input: true\n * },\n * {\n * type: 'button',\n * action: 'submit',\n * label: 'Submit',\n * theme: 'primary'\n * }\n * ]\n * });\n *\n * @param {Object} form - The JSON schema of the form @see https://examples.form.io/example for an example JSON schema.\n * @param flags\n * @returns {*}\n */\n setForm(form, flags) {\n var _a, _b, _c;\n const isFormAlreadySet = this._form && ((_a = this._form.components) === null || _a === void 0 ? void 0 : _a.length);\n try {\n // Do not set the form again if it has been already set\n if (isFormAlreadySet && JSON.stringify(this._form) === JSON.stringify(form)) {\n return Promise.resolve();\n }\n // Create the form.\n this._form = (flags === null || flags === void 0 ? void 0 : flags.keepAsReference) ? form : lodash_1.default.cloneDeep(form);\n if (this.onSetForm) {\n this.onSetForm(lodash_1.default.cloneDeep(this._form), form);\n }\n if ((_c = (_b = this.parent) === null || _b === void 0 ? void 0 : _b.component) === null || _c === void 0 ? void 0 : _c.modalEdit) {\n return Promise.resolve();\n }\n }\n catch (err) {\n console.warn(err);\n // If provided form is not a valid JSON object, do not set it too\n return Promise.resolve();\n }\n // Allow the form to provide component overrides.\n if (form && form.settings && form.settings.components) {\n this.options.components = form.settings.components;\n }\n if (form && form.properties) {\n this.options.properties = form.properties;\n }\n // Use the sanitize config from the form settings or the global sanitize config if it is not provided in the options\n if (!this.options.sanitizeConfig && !this.builderMode) {\n this.options.sanitizeConfig = lodash_1.default.get(form, 'settings.sanitizeConfig') || lodash_1.default.get(form, 'globalSettings.sanitizeConfig');\n }\n if ('schema' in form && (0, compare_versions_1.compareVersions)(form.schema, '1.x') > 0) {\n this.ready.then(() => {\n this.setAlert('alert alert-danger', 'Form schema is for a newer version, please upgrade your renderer. Some functionality may not work.');\n });\n }\n // See if they pass a module, and evaluate it if so.\n if (form && form.module) {\n let formModule = null;\n if (typeof form.module === 'string') {\n try {\n formModule = this.evaluate(`return ${form.module}`);\n }\n catch (err) {\n console.warn(err);\n }\n }\n else {\n formModule = form.module;\n }\n if (formModule) {\n Formio_1.Formio.use(formModule);\n // Since we got here after instantiation, we need to manually apply form options.\n if (formModule.options && formModule.options.form) {\n this.options = Object.assign(this.options, formModule.options.form);\n }\n }\n }\n this.initialized = false;\n const rebuild = this.rebuild() || Promise.resolve();\n return rebuild.then(() => {\n this.emit('formLoad', form);\n this.triggerRecaptcha();\n // Make sure to trigger onChange after a render event occurs to speed up form rendering.\n setTimeout(() => {\n this.onChange(flags);\n this.formReadyResolve();\n }, 0);\n return this.formReady;\n });\n }\n /**\n * Gets the form object.\n *\n * @returns {Object} - The form JSON schema.\n */\n get form() {\n if (!this._form) {\n this._form = {\n components: []\n };\n }\n return this._form;\n }\n /**\n * Sets the form value.\n *\n * @alias setForm\n * @param {Object} form - The form schema object.\n */\n set form(form) {\n this.setForm(form);\n }\n /**\n * Returns the submission object that was set within this form.\n *\n * @returns {Object}\n */\n get submission() {\n return this.getValue();\n }\n /**\n * Sets the submission of a form.\n *\n * @example\n * import Webform from '@formio/js/Webform';\n * let form = new Webform(document.getElementById('formio'));\n * form.src = 'https://examples.form.io/example';\n * form.submission = {data: {\n * firstName: 'Joe',\n * lastName: 'Smith',\n * email: 'joe@example.com'\n * }};\n *\n * @param {Object} submission - The Form.io submission object.\n */\n set submission(submission) {\n this.setSubmission(submission);\n }\n /**\n * Sets a submission and returns the promise when it is ready.\n * @param submission\n * @param flags\n * @return {Promise.<TResult>}\n */\n setSubmission(submission, flags = {}) {\n flags = Object.assign(Object.assign({}, flags), { fromSubmission: lodash_1.default.has(flags, 'fromSubmission') ? flags.fromSubmission : true });\n return this.onSubmission = this.formReady.then((resolveFlags) => {\n if (resolveFlags) {\n flags = Object.assign(Object.assign({}, flags), resolveFlags);\n }\n this.submissionSet = true;\n this.triggerChange(flags);\n this.emit('beforeSetSubmission', submission);\n this.setValue(submission, flags);\n return this.submissionReadyResolve(submission);\n }, (err) => this.submissionReadyReject(err)).catch((err) => this.submissionReadyReject(err));\n }\n handleDraftError(errName, errDetails, restoreDraft) {\n const errorMessage = lodash_1.default.trim(`${this.t(errName)} ${errDetails || ''}`);\n console.warn(errorMessage);\n this.emit(restoreDraft ? 'restoreDraftError' : 'saveDraftError', errDetails || errorMessage);\n }\n /**\n * Saves a submission draft.\n */\n saveDraft() {\n if (!this.draftEnabled) {\n return;\n }\n if (!this.formio) {\n this.handleDraftError('saveDraftInstanceError');\n return;\n }\n if (!Formio_1.Formio.getUser()) {\n this.handleDraftError('saveDraftAuthError');\n return;\n }\n const draft = (0, utils_1.fastCloneDeep)(this.submission);\n draft.state = 'draft';\n if (!this.savingDraft) {\n this.emit('saveDraftBegin');\n this.savingDraft = true;\n this.formio.saveSubmission(draft).then((sub) => {\n // Set id to submission to avoid creating new draft submission\n this.submission._id = sub._id;\n this.savingDraft = false;\n this.emit('saveDraft', sub);\n })\n .catch(err => {\n this.savingDraft = false;\n this.handleDraftError('saveDraftError', err);\n });\n }\n }\n /**\n * Restores a draft submission based on the user who is authenticated.\n *\n * @param {userId} - The user id where we need to restore the draft from.\n */\n restoreDraft(userId) {\n const formio = this.formio || this.options.formio;\n if (!formio) {\n this.handleDraftError('restoreDraftInstanceError', null, true);\n return;\n }\n this.savingDraft = true;\n formio.loadSubmissions({\n params: {\n state: 'draft',\n owner: userId\n }\n }).then(submissions => {\n if (submissions.length > 0 && !this.options.skipDraftRestore) {\n const draft = (0, utils_1.fastCloneDeep)(submissions[0]);\n return this.setSubmission(draft).then(() => {\n this.draftEnabled = true;\n this.savingDraft = false;\n this.emit('restoreDraft', draft);\n });\n }\n // Enable drafts so that we can keep track of changes.\n this.draftEnabled = true;\n this.savingDraft = false;\n this.emit('restoreDraft', null);\n })\n .catch(err => {\n this.draftEnabled = true;\n this.savingDraft = false;\n this.handleDraftError('restoreDraftError', err, true);\n });\n }\n get schema() {\n const schema = (0, utils_1.fastCloneDeep)(lodash_1.default.omit(this._form, ['components']));\n schema.components = [];\n this.eachComponent((component) => schema.components.push(component.schema));\n return schema;\n }\n mergeData(_this, _that) {\n lodash_1.default.mergeWith(_this, _that, (thisValue, thatValue) => {\n if (Array.isArray(thisValue) && Array.isArray(thatValue) && thisValue.length !== thatValue.length) {\n return thatValue;\n }\n });\n }\n setValue(submission, flags = {}) {\n if (!submission || !submission.data) {\n submission = {\n data: {},\n metadata: submission.metadata,\n };\n }\n // Metadata needs to be available before setValue\n this._submission.metadata = submission.metadata || {};\n this.editing = !!submission._id;\n // Set the timezone in the options if available.\n if (!this.options.submissionTimezone &&\n submission.metadata &&\n submission.metadata.timezone) {\n this.options.submissionTimezone = submission.metadata.timezone;\n }\n const changed = super.setValue(submission.data, flags);\n if (!flags.sanitize) {\n this.mergeData(this.data, submission.data);\n }\n submission.data = this.data;\n this._submission = submission;\n return changed;\n }\n getValue() {\n if (!this._submission.data) {\n this._submission.data = {};\n }\n if (this.viewOnly) {\n return this._submission;\n }\n const submission = this._submission;\n submission.data = this.data;\n return this._submission;\n }\n /**\n * Build the form.\n */\n init() {\n if (this.options.submission) {\n const submission = lodash_1.default.extend({}, this.options.submission);\n this._submission = submission;\n this._data = submission.data;\n }\n else {\n this._submission = this._submission || { data: {} };\n }\n // Remove any existing components.\n if (this.components && this.components.length) {\n this.destroyComponents();\n this.components = [];\n }\n if (this.component) {\n this.component.components = this.form ? this.form.components : [];\n }\n else {\n this.component = this.form;\n }\n this.component.type = 'form';\n this.component.input = false;\n this.addComponents();\n this.on('submitButton', options => {\n this.submit(false, options).catch(e => {\n options.instance.loading = false;\n return e !== false && e !== undefined && console.log(e);\n });\n }, true);\n this.on('checkValidity', (data) => this.validate(data, { dirty: true, process: 'change' }), true);\n this.on('requestUrl', (args) => (this.submitUrl(args.url, args.headers)), true);\n this.on('resetForm', () => this.resetValue(), true);\n this.on('deleteSubmission', () => this.deleteSubmission(), true);\n this.on('refreshData', () => this.updateValue(), true);\n this.executeFormController();\n return this.formReady;\n }\n executeFormController() {\n // If no controller value or\n // hidden and set to clearOnHide (Don't calculate a value for a hidden field set to clear when hidden)\n if (!this.form || !this.form.controller\n || ((!this.visible || this.component.hidden) && this.component.clearOnHide && !this.rootPristine)) {\n return false;\n }\n this.formReady.then(() => {\n this.evaluate(this.form.controller, {\n components: this.components,\n instance: this,\n });\n });\n }\n teardown() {\n this.emit('formDelete', this.id);\n delete Formio_1.Formio.forms[this.id];\n delete this.executeShortcuts;\n delete this.triggerSaveDraft;\n super.teardown();\n }\n destroy(all = false) {\n this.off('submitButton');\n this.off('checkValidity');\n this.off('requestUrl');\n this.off('resetForm');\n this.off('deleteSubmission');\n this.off('refreshData');\n return super.destroy(all);\n }\n build(element) {\n if (element || this.element) {\n return this.ready.then(() => {\n element = element || this.element;\n super.build(element);\n });\n }\n return this.ready;\n }\n getClassName() {\n let classes = 'formio-form';\n if (this.options.readOnly) {\n classes += ' formio-read-only';\n }\n return classes;\n }\n render() {\n return super.render(this.renderTemplate('webform', {\n classes: this.getClassName(),\n children: this.renderComponents(),\n }), this.builderMode ? 'builder' : 'form', true);\n }\n redraw() {\n // Don't bother if we have not built yet.\n if (!this.element) {\n return Promise.resolve();\n }\n this.clear();\n this.setContent(this.element, this.render());\n return this.attach(this.element);\n }\n attach(element) {\n this.setElement(element);\n this.loadRefs(element, { webform: 'single' });\n const childPromise = this.attachComponents(this.refs.webform);\n this.addEventListener(document, 'keydown', this.executeShortcuts);\n this.currentForm = this;\n this.hook('attachWebform', element, this);\n return childPromise.then(() => {\n this.emit('render', this.element);\n return this.setValue(this._submission, {\n noUpdateEvent: true,\n });\n });\n }\n hasRequiredFields() {\n let result = false;\n (0, formUtils_1.eachComponent)(this.form.components, (component) => {\n if (component.validate.required) {\n result = true;\n return true;\n }\n }, true);\n return result;\n }\n resetValue() {\n lodash_1.default.each(this.getComponents(), (comp) => (comp.resetValue()));\n this.setPristine(true);\n this.onChange({ resetValue: true });\n }\n /**\n * Sets a new alert to display in the error dialog of the form.\n *\n * @param {string} type - The type of alert to display. \"danger\", \"success\", \"warning\", etc.\n * @param {string} message - The message to show in the alert.\n * @param {Object} options\n */\n setAlert(type, message, options) {\n if (!type && this.submitted) {\n if (this.alert) {\n if (this.refs.errorRef && this.refs.errorRef.length) {\n this.refs.errorRef.forEach(el => {\n this.removeEventListener(el, 'click');\n this.removeEventListener(el, 'keypress');\n });\n }\n this.removeChild(this.alert);\n this.alert = null;\n }\n return;\n }\n if (this.options.noAlerts) {\n if (!message) {\n this.emit('error', false);\n }\n return;\n }\n if (this.alert) {\n try {\n if (this.refs.errorRef && this.refs.errorRef.length) {\n this.refs.errorRef.forEach(el => {\n this.removeEventListener(el, 'click');\n this.removeEventListener(el, 'keypress');\n });\n }\n this.removeChild(this.alert);\n this.alert = null;\n }\n catch (err) {\n // ignore\n }\n }\n if (message) {\n const attrs = {\n class: (options && options.classes) || `alert alert-${type}`,\n id: `error-list-${this.id}`,\n };\n const templateOptions = {\n message: message instanceof HTMLElement ? message.outerHTML : message,\n attrs: attrs,\n type\n };\n this.alert = (0, utils_1.convertStringToHTMLElement)(this.renderTemplate('alert', templateOptions), `#${attrs.id}`);\n }\n if (!this.alert) {\n return;\n }\n this.loadRefs(this.alert, { errorRef: 'multiple' });\n if (this.refs.errorRef && this.refs.errorRef.length) {\n this.refs.errorRef.forEach(el => {\n this.addEventListener(el, 'click', (e) => {\n const key = e.currentTarget.dataset.componentKey;\n this.focusOnComponent(key);\n });\n this.addEventListener(el, 'keydown', (e) => {\n if (e.keyCode === 13) {\n e.preventDefault();\n const key = e.currentTarget.dataset.componentKey;\n this.focusOnComponent(key);\n }\n });\n });\n }\n this.prepend(this.alert);\n }\n /**\n * Focus on selected component.\n *\n * @param {string} key - The key of selected component.\n * @returns {*}\n */\n focusOnComponent(key) {\n if (key) {\n const component = this.getComponent(key);\n if (component) {\n component.focus();\n }\n }\n }\n /**\n * Show the errors of this form within the alert dialog.\n *\n * @param {Object} error - An optional additional error to display along with the component errors.\n * @returns {*}\n */\n /* eslint-disable no-unused-vars */\n showErrors(errors, triggerEvent) {\n this.loading = false;\n if (!Array.isArray(errors)) {\n errors = [errors];\n }\n errors = errors.concat(this.customErrors).filter((err) => !!err);\n if (!errors.length) {\n this.setAlert(false);\n return;\n }\n // Mark any components as invalid if in a custom message.\n errors.forEach((err) => {\n const { components = [] } = err;\n if (err.component) {\n components.push(err.component);\n }\n if (err.path) {\n components.push(err.path);\n }\n components.forEach((path) => {\n const originalPath = (0, utils_1.getStringFromComponentPath)(path);\n const component = this.getComponent(path, lodash_1.default.identity, originalPath);\n if (err.fromServer) {\n if (component.serverErrors) {\n component.serverErrors.push(err);\n }\n else {\n component.serverErrors = [err];\n }\n }\n const components = lodash_1.default.compact(Array.isArray(component) ? component : [component]);\n components.forEach((component) => component.setCustomValidity(err.message, true));\n });\n });\n const displayedErrors = [];\n if (errors.length) {\n errors = lodash_1.default.uniqBy(errors, error => error.message);\n const createListItem = (message, index) => {\n var _a, _b, _c;\n const err = errors[index];\n const messageFromIndex = !lodash_1.default.isUndefined(index) && errors && errors[index];\n const keyOrPath = ((messageFromIndex === null || messageFromIndex === void 0 ? void 0 : messageFromIndex.formattedKeyOrPath) || (messageFromIndex === null || messageFromIndex === void 0 ? void 0 : messageFromIndex.path) || ((_a = messageFromIndex === null || messageFromIndex === void 0 ? void 0 : messageFromIndex.context) === null || _a === void 0 ? void 0 : _a.path)) || (((_b = err.context) === null || _b === void 0 ? void 0 : _b.component) && ((_c = err.context) === null || _c === void 0 ? void 0 : _c.component.key)) || (err.component && err.component.key) || err.fromServer && err.path;\n const formattedKeyOrPath = keyOrPath ? (0, utils_1.getStringFromComponentPath)(keyOrPath) : '';\n if (typeof err !== 'string' && !err.formattedKeyOrPath) {\n err.formattedKeyOrPath = formattedKeyOrPath;\n }\n return {\n message: (0, utils_1.unescapeHTML)(message),\n keyOrPath: formattedKeyOrPath\n };\n };\n errors.forEach(({ message, context, fromServer, component }, index) => {\n const text = !(component === null || component === void 0 ? void 0 : component.label) || (context === null || context === void 0 ? void 0 : context.hasLabel) || fromServer\n ? this.t('alertMessage', { message: this.t(message) })\n : this.t('alertMessageWithLabel', {\n label: this.t(component === null || component === void 0 ? void 0 : component.label),\n message: this.t(message),\n });\n displayedErrors.push(createListItem(text, index));\n });\n }\n const errorsList = this.renderTemplate('errorsList', { errors: displayedErrors });\n this.root.setAlert('danger', errorsList);\n if (triggerEvent) {\n this.emit('error', errors);\n }\n return errors;\n }\n /* eslint-enable no-unused-vars */\n /**\n * Called when the submission has completed, or if the submission needs to be sent to an external library.\n *\n * @param {Object} submission - The submission object.\n * @param {boolean} saved - Whether or not this submission was saved to the server.\n * @returns {object} - The submission object.\n */\n onSubmit(submission, saved) {\n var _a;\n this.loading = false;\n this.submitting = false;\n this.setPristine(true);\n // We want to return the submitted submission and setValue will mutate the submission so cloneDeep it here.\n this.setValue((0, utils_1.fastCloneDeep)(submission), {\n noValidate: true,\n noCheck: true\n });\n this.setAlert('success', `<p>${this.t('complete')}</p>`);\n // Cancel triggered saveDraft to prevent overriding the submitted state\n if (this.draftEnabled && ((_a = this.triggerSaveDraft) === null || _a === void 0 ? void 0 : _a.cancel)) {\n this.triggerSaveDraft.cancel();\n }\n this.emit('submit', submission, saved);\n if (saved) {\n this.emit('submitDone', submission);\n }\n return submission;\n }\n normalizeError(error) {\n if (error) {\n if (typeof error === 'object' && 'details' in error) {\n error = error.details;\n }\n if (typeof error === 'string') {\n error = { message: error };\n }\n }\n return error;\n }\n /**\n * Called when an error occurs during the submission.\n *\n * @param {Object} error - The error that occured.\n */\n onSubmissionError(error) {\n error = this.normalizeError(error);\n this.submitting = false;\n this.setPristine(false);\n this.emit('submitError', error || this.errors);\n // Allow for silent cancellations (no error message, no submit button error state)\n if (error && error.silent) {\n this.emit('change', { isValid: true }, { silent: true });\n return false;\n }\n const errors = this.showErrors(error, true);\n if (this.root && this.root.alert) {\n this.scrollIntoView(this.root.alert);\n }\n return errors;\n }\n /**\n * Trigger the change event for this form.\n *\n * @param changed\n * @param flags\n */\n onChange(flags, changed, modified, changes) {\n flags = flags || {};\n let isChangeEventEmitted = false;\n super.onChange(flags, true);\n const value = lodash_1.default.clone(this.submission);\n flags.changed = value.changed = changed;\n flags.changes = changes;\n if (modified && this.pristine) {\n this.pristine = false;\n }\n this.checkData(value.data, flags);\n const shouldValidate = !flags.noValidate || flags.fromIFrame || (flags.fromSubmission && this.rootPristine && this.pristine && flags.changed);\n const errors = shouldValidate ? this.validate(value.data, Object.assign(Object.assign({}, flags), { process: 'change' })) : [];\n value.isValid = errors.length === 0;\n this.loading = false;\n if (this.submitted) {\n // show server errors while they are not cleaned/fixed\n const nonComponentServerErrors = lodash_1.default.filter(this.serverErrors || [], err => !err.component && !err.path);\n this.showErrors(nonComponentServerErrors.length ? nonComponentServerErrors : errors);\n }\n // See if we need to save the draft of the form.\n if (modified && this.options.saveDraft) {\n this.triggerSaveDraft();\n }\n if (!flags || !flags.noEmit) {\n this.emit('change', value, flags, modified);\n isChangeEventEmitted = true;\n }\n // The form is initialized after the first change event occurs.\n if (isChangeEventEmitted && !this.initialized) {\n this.emit('initialized');\n this.initialized = true;\n }\n }\n /**\n * Send a delete request to the server.\n */\n deleteSubmission() {\n return this.formio.deleteSubmission()\n .then(() => {\n this.emit('submissionDeleted', this.submission);\n this.resetValue();\n });\n }\n /**\n * Cancels the submission.\n *\n * @alias reset\n */\n cancel(noconfirm) {\n const shouldReset = this.hook('beforeCancel', true);\n if (shouldReset && (noconfirm || confirm(this.t('confirmCancel')))) {\n this.resetValue();\n return true;\n }\n else {\n this.emit('cancelSubmit');\n return false;\n }\n }\n setMetadata(submission) {\n // Add in metadata about client submitting the form\n submission.metadata = submission.metadata || {};\n lodash_1.default.defaults(submission.metadata, {\n timezone: lodash_1.default.get(this, '_submission.metadata.timezone', (0, utils_1.currentTimezone)()),\n offset: parseInt(lodash_1.default.get(this, '_submission.metadata.offset', (0, moment_1.default)().utcOffset()), 10),\n origin: document.location.origin,\n referrer: document.referrer,\n browserName: navigator.appName,\n userAgent: navigator.userAgent,\n pathName: window.location.pathname,\n onLine: navigator.onLine\n });\n }\n submitForm(options = {}) {\n this.clearServerErrors();\n return new Promise((resolve, reject) => {\n // Read-only forms should never submit.\n if (this.options.readOnly) {\n return resolve({\n submission: this.submission,\n saved: false\n });\n }\n const submission = (0, utils_1.fastCloneDeep)(this.submission || {});\n this.setMetadata(submission);\n submission.state = options.state || submission.state || 'submitted';\n const isDraft = (submission.state === 'draft');\n this.hook('beforeSubmit', Object.assign(Object.assign({}, submission), { component: options.component }), (err, data) => {\n var _a;\n if (err) {\n return reject(err);\n }\n submission._vnote = data && data._vnote ? data._vnote : '';\n try {\n if (!isDraft && !options.noValidate) {\n if (!submission.data) {\n return reject('Invalid Submission');\n }\n const errors = this.validate(submission.data, {\n dirty: true,\n silentCheck: false,\n process: 'submit'\n });\n if (errors.length || ((_a = options.beforeSubmitResults) === null || _a === void 0 ? void 0 : _a.some((result) => result.status === 'rejected'))) {\n return reject(errors);\n }\n }\n }\n catch (err) {\n console.error(err);\n }\n this.everyComponent((comp) => {\n if (submission._vnote && comp.type === 'form' && comp.component.reference) {\n lodash_1.default.get(submission.data, comp.path, {})._vnote = submission._vnote;\n }\n const { persistent } = comp.component;\n if (persistent === 'client-only') {\n lodash_1.default.unset(submission.data, comp.path);\n }\n });\n this.hook('customValidation', Object.assign(Object.assign({}, submission), { component: options.component }), (err) => {\n if (err) {\n // If string is returned, cast to object.\n if (typeof err === 'string') {\n err = {\n message: err\n };\n }\n // Ensure err is an array.\n err = Array.isArray(err) ? err : [err];\n return reject(err);\n }\n this.loading = true;\n // Use the form action to submit the form if available.\n if (this._form && this._form.action) {\n const method = (submission.data._id && this._form.action.includes(submission.data._id)) ? 'PUT' : 'POST';\n return Formio_1.Formio.makeStaticRequest(this._form.action, method, submission, this.formio ? this.formio.options : {})\n .then((result) => resolve({\n submission: result,\n saved: true,\n }))\n .catch((error) => {\n this.setServerErrors(error);\n return reject(error);\n });\n }\n const submitFormio = this.formio;\n if (this.nosubmit || !submitFormio) {\n return resolve({\n submission,\n saved: false,\n });\n }\n // If this is an actionUrl, then make sure to save the action and not the submission.\n const submitMethod = submitFormio.actionUrl ? 'saveAction' : 'saveSubmission';\n submitFormio[submitMethod](submission)\n .then((result) => resolve({\n submission: result,\n saved: true,\n }))\n .catch((error) => {\n this.setServerErrors(error);\n return reject(error);\n });\n });\n });\n });\n }\n setServerErrors(error) {\n if (error.details) {\n this.serverErrors = error.details.filter((err) => err.level ? err.level === 'error' : err).map((err) => {\n err.fromServer = true;\n return err;\n });\n }\n else if (typeof error === 'string') {\n this.serverErrors = [{ fromServer: true, level: 'error', message: error }];\n }\n }\n executeSubmit(options) {\n this.submitted = true;\n this.submitting = true;\n return this.submitForm(options)\n .then(({ submission, saved }) => this.onSubmit(submission, saved))\n .then((results) => {\n this.submissionInProcess = false;\n return results;\n })\n .catch((err) => {\n this.submissionInProcess = false;\n return Promise.reject(this.onSubmissionError(err));\n });\n }\n clearServerErrors() {\n var _a;\n (_a = this.serverErrors) === null || _a === void 0 ? void 0 : _a.forEach((error) => {\n if (error.path) {\n const pathArray = (0, utils_1.getArrayFromComponentPath)(error.path);\n const component = this.getComponent(pathArray, lodash_1.default.identity, error.formattedKeyOrPath);\n if (component) {\n component.serverErrors = [];\n }\n }\n });\n this.serverErrors = [];\n }\n /**\n * Submits the form.\n *\n * @example\n * import Webform from '@formio/js/Webform';\n * let form = new Webform(document.getElementById('formio'));\n * form.src = 'https://examples.form.io/example';\n * form.submission = {data: {\n * firstName: 'Joe',\n * lastName: 'Smith',\n * email: 'joe@example.com'\n * }};\n * form.submit().then((submission) => {\n * console.log(submission);\n * });\n *\n * @param {boolean} before - If this submission occured from the before handlers.\n *\n * @returns {Promise} - A promise when the form is done submitting.\n */\n submit(before, options = {}) {\n this.submissionInProcess = true;\n if (!before) {\n return this.beforeSubmit(options).then(() => this.executeSubmit(options));\n }\n else {\n return this.executeSubmit(options);\n }\n }\n submitUrl(URL, headers) {\n if (!URL) {\n return console.warn('Missing URL argument');\n }\n const submission = this.submission || {};\n const API_URL = URL;\n const settings = {\n method: 'POST',\n headers: {}\n };\n if (headers && headers.length > 0) {\n headers.map((e) => {\n if (e.header !== '' && e.value !== '') {\n settings.headers[e.header] = this.interpolate(e.value, submission);\n }\n });\n }\n if (API_URL && settings) {\n Formio_1.Formio.makeStaticRequest(API_URL, settings.method, submission, { headers: settings.headers }).then(() => {\n this.emit('requestDone');\n this.setAlert('success', '<p> Success </p>');\n }).catch((e) => {\n const message = `${e.statusText ? e.statusText : ''} ${e.status ? e.status : e}`;\n this.emit('error', message);\n console.error(message);\n this.setAlert('danger', `<p> ${message} </p>`);\n return Promise.reject(this.onSubmissionError(e));\n });\n }\n else {\n this.emit('error', 'You should add a URL to this button.');\n this.setAlert('warning', 'You should add a URL to this button.');\n return console.warn('You should add a URL to this button.');\n }\n }\n triggerRecaptcha() {\n if (!this || !this.components) {\n return;\n }\n const recaptchaComponent = (0, utils_1.searchComponents)(this.components, {\n 'component.type': 'recaptcha',\n 'component.eventType': 'formLoad'\n });\n if (recaptchaComponent.length > 0) {\n recaptchaComponent[0].verify(`${this.form.name ? this.form.name : 'form'}Load`);\n }\n }\n set nosubmit(value) {\n this._nosubmit = !!value;\n this.emit('nosubmit', this._nosubmit);\n }\n get nosubmit() {\n return this._nosubmit || false;\n }\n get conditions() {\n var _a, _b;\n return (_b = (_a = this.schema.settings) === null || _a === void 0 ? void 0 : _a.conditions) !== null && _b !== void 0 ? _b : [];\n }\n get variables() {\n var _a, _b;\n return (_b = (_a = this.schema.settings) === null || _a === void 0 ? void 0 : _a.variables) !== null && _b !== void 0 ? _b : [];\n }\n}\nexports[\"default\"] = Webform;\nWebform.setBaseUrl = Formio_1.Formio.setBaseUrl;\nWebform.setApiUrl = Formio_1.Formio.setApiUrl;\nWebform.setAppUrl = Formio_1.Formio.setAppUrl;\n\n\n//# sourceURL=webpack://Formio/./lib/cjs/Webform.js?");
|
|
5240
|
+
eval("\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nconst lodash_1 = __importDefault(__webpack_require__(/*! lodash */ \"./node_modules/lodash/lodash.js\"));\nconst moment_1 = __importDefault(__webpack_require__(/*! moment */ \"./node_modules/moment/moment.js\"));\nconst compare_versions_1 = __webpack_require__(/*! compare-versions */ \"./node_modules/compare-versions/lib/esm/index.js\");\nconst core_1 = __webpack_require__(/*! @formio/core */ \"./node_modules/@formio/core/lib/index.js\");\nconst EventEmitter_1 = __importDefault(__webpack_require__(/*! ./EventEmitter */ \"./lib/cjs/EventEmitter.js\"));\nconst i18n_1 = __importDefault(__webpack_require__(/*! ./i18n */ \"./lib/cjs/i18n.js\"));\nconst Formio_1 = __webpack_require__(/*! ./Formio */ \"./lib/cjs/Formio.js\");\nconst Components_1 = __importDefault(__webpack_require__(/*! ./components/Components */ \"./lib/cjs/components/Components.js\"));\nconst NestedDataComponent_1 = __importDefault(__webpack_require__(/*! ./components/_classes/nesteddata/NestedDataComponent */ \"./lib/cjs/components/_classes/nesteddata/NestedDataComponent.js\"));\nconst utils_1 = __webpack_require__(/*! ./utils/utils */ \"./lib/cjs/utils/utils.js\");\nconst formUtils_1 = __webpack_require__(/*! ./utils/formUtils */ \"./lib/cjs/utils/formUtils.js\");\n// Initialize the available forms.\nFormio_1.Formio.forms = {};\n// Allow people to register components.\nFormio_1.Formio.registerComponent = Components_1.default.setComponent;\nfunction getIconSet(icons) {\n if (icons === 'fontawesome') {\n return 'fa';\n }\n return icons || '';\n}\nfunction getOptions(options) {\n options = lodash_1.default.defaults(options, {\n submitOnEnter: false,\n iconset: getIconSet((options && options.icons) ? options.icons : Formio_1.Formio.icons),\n i18next: null,\n saveDraft: false,\n alwaysDirty: false,\n saveDraftThrottle: 5000,\n display: 'form',\n cdnUrl: Formio_1.Formio.cdn.baseUrl\n });\n if (!options.events) {\n options.events = new EventEmitter_1.default();\n }\n return options;\n}\n/**\n * Represents a JSON value.\n * @typedef {(string | number | boolean | null | JSONArray | JSONObject)} JSON\n */\n/**\n * Represents a JSON array.\n * @typedef {Array<JSON>} JSONArray\n */\n/**\n * Represents a JSON object.\n * @typedef {{[key: string]: JSON}} JSONObject\n */\n/**\n * @typedef {Object} FormioHooks\n * @property {function} [beforeSubmit]\n * @property {function} [beforeCancel]\n * @property {function} [beforeNext]\n * @property {function} [beforePrev]\n * @property {function} [attachComponent]\n * @property {function} [setDataValue]\n * @property {function} [addComponents]\n * @property {function} [addComponent]\n * @property {function} [customValidation]\n * @property {function} [attachWebform]\n */\n/**\n * @typedef {Object} SanitizeConfig\n * @property {string[]} [addAttr]\n * @property {string[]} [addTags]\n * @property {string[]} [allowedAttrs]\n * @property {string[]} [allowedTags]\n * @property {string[]} [allowedUriRegex]\n * @property {string[]} [addUriSafeAttr]\n */\n/**\n * @typedef {Object} ButtonSettings\n * @property {boolean} [showPrevious]\n * @property {boolean} [showNext]\n * @property {boolean} [showCancel]\n * @property {boolean} [showSubmit]\n */\n/**\n * @typedef {Object} FormOptions\n * @property {boolean} [saveDraft] - Enable the save draft feature.\n * @property {number} [saveDraftThrottle] - The throttle for the save draft feature.\n * @property {boolean} [readOnly] - Set this form to readOnly.\n * @property {boolean} [noAlerts] - Disable the alerts dialog.\n * @property {{[key: string]: string}} [i18n] - The translation file for this rendering.\n * @property {string} [template] - Custom logic for creation of elements.\n * @property {boolean} [noDefaults] - Exclude default values from the settings.\n * @property {any} [fileService] - The file service for this form.\n * @property {EventEmitter} [events] - The EventEmitter for this form.\n * @property {string} [language] - The language to render this form in.\n * @property {{[key: string]: string}} [i18next] - The i18next configuration for this form.\n * @property {boolean} [viewAsHtml] - View the form as raw HTML.\n * @property {'form' | 'html' | 'flat' | 'builder' | 'pdf'} [renderMode] - The render mode for this form.\n * @property {boolean} [highlightErrors] - Highlight any errors on the form.\n * @property {string} [componentErrorClass] - The error class for components.\n * @property {any} [templates] - The templates for this form.\n * @property {string} [iconset] - The iconset for this form.\n * @property {Component[]} [components] - The components for this form.\n * @property {{[key: string]: boolean}} [disabled] - Disabled components for this form.\n * @property {boolean} [showHiddenFields] - Show hidden fields.\n * @property {{[key: string]: boolean}} [hide] - Hidden components for this form.\n * @property {{[key: string]: boolean}} [show] - Components to show for this form.\n * @property {Formio} [formio] - The Formio instance for this form.\n * @property {string} [decimalSeparator] - The decimal separator for this form.\n * @property {string} [thousandsSeparator] - The thousands separator for this form.\n * @property {FormioHooks} [hooks] - The hooks for this form.\n * @property {boolean} [alwaysDirty] - Always be dirty.\n * @property {boolean} [skipDraftRestore] - Skip restoring a draft.\n * @property {'form' | 'wizard' | 'pdf'} [display] - The display for this form.\n * @property {string} [cdnUrl] - The CDN url for this form.\n * @property {boolean} [flatten] - Flatten the form.\n * @property {boolean} [sanitize] - Sanitize the form.\n * @property {SanitizeConfig} [sanitizeConfig] - The sanitize configuration for this form.\n * @property {ButtonSettings} [buttonSettings] - The button settings for this form.\n * @property {Object} [breadCrumbSettings] - The breadcrumb settings for this form.\n * @property {boolean} [allowPrevious] - Allow the previous button (for Wizard forms).\n * @property {string[]} [wizardButtonOrder] - The order of the buttons (for Wizard forms).\n * @property {boolean} [showCheckboxBackground] - Show the checkbox background.\n * @property {number} [zoom] - The zoom for PDF forms.\n */\n/**\n * Renders a Form.io form within the webpage.\n */\nclass Webform extends NestedDataComponent_1.default {\n /**\n * Creates a new Form instance.\n *\n * @param {HTMLElement | Object | FormOptions} [elementOrOptions] - The DOM element to render this form within or the options to create this form instance.\n * @param {FormOptions} [options] - The options to create a new form instance.\n */\n constructor(elementOrOptions, options) {\n let element, formOptions;\n if (elementOrOptions instanceof HTMLElement || options) {\n element = elementOrOptions;\n formOptions = options;\n }\n else {\n formOptions = elementOrOptions;\n }\n super(null, getOptions(formOptions));\n this.executeShortcuts = (event) => {\n const { target } = event;\n if (!this.keyboardCatchableElement(target)) {\n return;\n }\n const ctrl = event.ctrlKey || event.metaKey;\n const keyCode = event.keyCode;\n let char = '';\n if (65 <= keyCode && keyCode <= 90) {\n char = String.fromCharCode(keyCode);\n }\n else if (keyCode === 13) {\n char = 'Enter';\n }\n else if (keyCode === 27) {\n char = 'Esc';\n }\n lodash_1.default.each(this.shortcuts, (shortcut) => {\n if (shortcut.ctrl && !ctrl) {\n return;\n }\n if (shortcut.shortcut === char) {\n shortcut.element.click();\n event.preventDefault();\n }\n });\n };\n this.setElement(element);\n // Keep track of all available forms globally.\n Formio_1.Formio.forms[this.id] = this;\n // Set the base url.\n if (this.options.baseUrl) {\n Formio_1.Formio.setBaseUrl(this.options.baseUrl);\n }\n /**\n * The type of this element.\n * @type {string}\n */\n this.type = 'form';\n this._src = '';\n this._loading = false;\n this._form = {};\n this.draftEnabled = false;\n this.savingDraft = true;\n if (this.options.saveDraftThrottle) {\n this.triggerSaveDraft = lodash_1.default.throttle(this.saveDraft.bind(this), this.options.saveDraftThrottle);\n }\n else {\n this.triggerSaveDraft = this.saveDraft.bind(this);\n }\n /**\n * Determines if this form should submit the API on submit.\n * @type {boolean}\n */\n this.nosubmit = false;\n /**\n * Determines if the form has tried to be submitted, error or not.\n *\n * @type {boolean}\n */\n this.submitted = false;\n /**\n * Determines if the form is being submitted at the moment.\n *\n * @type {boolean}\n */\n this.submitting = false;\n /**\n * The Formio instance for this form.\n * @type {Formio}\n */\n this.formio = null;\n /**\n * The loader HTML element.\n * @type {HTMLElement}\n */\n this.loader = null;\n /**\n * The alert HTML element\n * @type {HTMLElement}\n */\n this.alert = null;\n /**\n * Promise that is triggered when the submission is done loading.\n * @type {Promise}\n */\n this.onSubmission = null;\n /**\n * Determines if this submission is explicitly set.\n * @type {boolean}\n */\n this.submissionSet = false;\n /**\n * Promise that executes when the form is ready and rendered.\n * @type {Promise}\n *\n * @example\n * import Webform from '@formio/js/Webform';\n * let form = new Webform(document.getElementById('formio'));\n * form.formReady.then(() => {\n * console.log('The form is ready!');\n * });\n * form.src = 'https://examples.form.io/example';\n */\n this.formReady = new Promise((resolve, reject) => {\n /**\n * Called when the formReady state of this form has been resolved.\n *\n * @type {function}\n */\n this.formReadyResolve = resolve;\n /**\n * Called when this form could not load and is rejected.\n *\n * @type {function}\n */\n this.formReadyReject = reject;\n });\n /**\n * Promise that executes when the submission is ready and rendered.\n * @type {Promise}\n *\n * @example\n * import Webform from '@formio/js/Webform';\n * let form = new Webform(document.getElementById('formio'));\n * form.submissionReady.then(() => {\n * console.log('The submission is ready!');\n * });\n * form.src = 'https://examples.form.io/example/submission/234234234234234243';\n */\n this.submissionReady = new Promise((resolve, reject) => {\n /**\n * Called when the formReady state of this form has been resolved.\n *\n * @type {function}\n */\n this.submissionReadyResolve = resolve;\n /**\n * Called when this form could not load and is rejected.\n *\n * @type {function}\n */\n this.submissionReadyReject = reject;\n });\n this.shortcuts = [];\n // Set language after everything is established.\n this.language = this.i18next.language;\n // See if we need to restore the draft from a user.\n if (this.options.saveDraft) {\n this.formReady.then(() => {\n if (!this.options.skipDraftRestore) {\n const user = Formio_1.Formio.getUser();\n // Only restore a draft if the submission isn't explicitly set.\n if (user && !this.submissionSet) {\n this.restoreDraft(user._id);\n }\n }\n else {\n // Enable drafts\n this.draftEnabled = true;\n this.savingDraft = false;\n }\n });\n }\n this.component.clearOnHide = false;\n // Ensure the root is set to this component.\n this.root = this;\n this.localRoot = this;\n }\n /* eslint-enable max-statements */\n get language() {\n return this.options.language;\n }\n get emptyValue() {\n return null;\n }\n componentContext() {\n return this._data;\n }\n /**\n * Sets the language for this form.\n *\n * @param lang\n * @return {Promise}\n */\n set language(lang) {\n if (!this.i18next) {\n return;\n }\n this.options.language = lang;\n if (this.i18next.language === lang) {\n return;\n }\n this.i18next.changeLanguage(lang, (err) => {\n if (err) {\n return;\n }\n this.rebuild();\n this.emit('languageChanged');\n });\n }\n get componentComponents() {\n return this.form.components;\n }\n get shadowRoot() {\n return this.options.shadowRoot;\n }\n /**\n * Add a language for translations\n *\n * @param code\n * @param lang\n * @param active\n * @return {*}\n */\n addLanguage(code, lang, active = false) {\n if (this.i18next) {\n var translations = lodash_1.default.assign((0, utils_1.fastCloneDeep)(i18n_1.default.resources.en.translation), lang);\n this.i18next.addResourceBundle(code, 'translation', translations, true, true);\n if (active) {\n this.language = code;\n }\n }\n }\n keyboardCatchableElement(element) {\n if (element.nodeName === 'TEXTAREA') {\n return false;\n }\n if (element.nodeName === 'INPUT') {\n return [\n 'text',\n 'email',\n 'password'\n ].indexOf(element.type) === -1;\n }\n return true;\n }\n addShortcut(element, shortcut) {\n if (!shortcut || !/^([A-Z]|Enter|Esc)$/i.test(shortcut)) {\n return;\n }\n shortcut = lodash_1.default.capitalize(shortcut);\n if (shortcut === 'Enter' || shortcut === 'Esc') {\n // Restrict Enter and Esc only for buttons\n if (element.tagName !== 'BUTTON') {\n return;\n }\n this.shortcuts.push({\n shortcut,\n element\n });\n }\n else {\n this.shortcuts.push({\n ctrl: true,\n shortcut,\n element\n });\n }\n }\n removeShortcut(element, shortcut) {\n if (!shortcut || !/^([A-Z]|Enter|Esc)$/i.test(shortcut)) {\n return;\n }\n lodash_1.default.remove(this.shortcuts, {\n shortcut,\n element\n });\n }\n /**\n * Get the embed source of the form.\n *\n * @returns {string}\n */\n get src() {\n return this._src;\n }\n /**\n * Loads the submission if applicable.\n */\n loadSubmission() {\n this.loadingSubmission = true;\n if (this.formio.submissionId) {\n this.onSubmission = this.formio.loadSubmission().then((submission) => this.setSubmission(submission), (err) => this.submissionReadyReject(err)).catch((err) => this.submissionReadyReject(err));\n }\n else {\n this.submissionReadyResolve();\n }\n return this.submissionReady;\n }\n /**\n * Set the src of the form renderer.\n *\n * @param value\n * @param options\n */\n setSrc(value, options) {\n if (this.setUrl(value, options)) {\n this.nosubmit = false;\n return this.formio.loadForm({ params: { live: 1 } }).then((form) => {\n const setForm = this.setForm(form);\n this.loadSubmission();\n return setForm;\n }).catch((err) => {\n console.warn(err);\n this.formReadyReject(err);\n });\n }\n return Promise.resolve();\n }\n /**\n * Set the Form source, which is typically the Form.io embed URL.\n *\n * @param {string} value - The value of the form embed url.\n *\n * @example\n * import Webform from '@formio/js/Webform';\n * let form = new Webform(document.getElementById('formio'));\n * form.formReady.then(() => {\n * console.log('The form is formReady!');\n * });\n * form.src = 'https://examples.form.io/example';\n */\n set src(value) {\n this.setSrc(value);\n }\n /**\n * Get the embed source of the form.\n *\n * @returns {string}\n */\n get url() {\n return this._src;\n }\n /**\n * Sets the url of the form renderer.\n *\n * @param value\n * @param options\n */\n setUrl(value, options) {\n if (!value ||\n (typeof value !== 'string') ||\n (value === this._src)) {\n return false;\n }\n this._src = value;\n this.nosubmit = true;\n this.formio = this.options.formio = new Formio_1.Formio(value, options);\n if (this.type === 'form') {\n // Set the options source so this can be passed to other components.\n this.options.src = value;\n }\n return true;\n }\n /**\n * Set the form source but don't initialize the form and submission from the url.\n *\n * @param {string} value - The value of the form embed url.\n */\n set url(value) {\n this.setUrl(value);\n }\n /**\n * Called when both the form and submission have been loaded.\n *\n * @returns {Promise} - The promise to trigger when both form and submission have loaded.\n */\n get ready() {\n return this.formReady.then(() => {\n return super.ready.then(() => {\n return this.loadingSubmission ? this.submissionReady : true;\n });\n });\n }\n /**\n * Returns if this form is loading.\n *\n * @returns {boolean} - TRUE means the form is loading, FALSE otherwise.\n */\n get loading() {\n return this._loading;\n }\n /**\n * Set the loading state for this form, and also show the loader spinner.\n *\n * @param {boolean} loading - If this form should be \"loading\" or not.\n */\n set loading(loading) {\n if (this._loading !== loading) {\n this._loading = loading;\n if (!this.loader && loading) {\n this.loader = this.ce('div', {\n class: 'loader-wrapper'\n });\n const spinner = this.ce('div', {\n class: 'loader text-center'\n });\n this.loader.appendChild(spinner);\n }\n /* eslint-disable max-depth */\n if (this.loader) {\n try {\n if (loading) {\n this.prependTo(this.loader, this.wrapper);\n }\n else {\n this.removeChildFrom(this.loader, this.wrapper);\n }\n }\n catch (err) {\n // ingore\n }\n }\n /* eslint-enable max-depth */\n }\n }\n /**\n * Sets the JSON schema for the form to be rendered.\n *\n * @example\n * import Webform from '@formio/js/Webform';\n * let form = new Webform(document.getElementById('formio'));\n * form.setForm({\n * components: [\n * {\n * type: 'textfield',\n * key: 'firstName',\n * label: 'First Name',\n * placeholder: 'Enter your first name.',\n * input: true\n * },\n * {\n * type: 'textfield',\n * key: 'lastName',\n * label: 'Last Name',\n * placeholder: 'Enter your last name',\n * input: true\n * },\n * {\n * type: 'button',\n * action: 'submit',\n * label: 'Submit',\n * theme: 'primary'\n * }\n * ]\n * });\n *\n * @param {Object} form - The JSON schema of the form @see https://examples.form.io/example for an example JSON schema.\n * @param flags\n * @returns {*}\n */\n setForm(form, flags) {\n var _a, _b, _c;\n const isFormAlreadySet = this._form && ((_a = this._form.components) === null || _a === void 0 ? void 0 : _a.length);\n try {\n // Do not set the form again if it has been already set\n if (isFormAlreadySet && JSON.stringify(this._form) === JSON.stringify(form)) {\n return Promise.resolve();\n }\n // Create the form.\n this._form = (flags === null || flags === void 0 ? void 0 : flags.keepAsReference) ? form : lodash_1.default.cloneDeep(form);\n if (this.onSetForm) {\n this.onSetForm(lodash_1.default.cloneDeep(this._form), form);\n }\n if ((_c = (_b = this.parent) === null || _b === void 0 ? void 0 : _b.component) === null || _c === void 0 ? void 0 : _c.modalEdit) {\n return Promise.resolve();\n }\n }\n catch (err) {\n console.warn(err);\n // If provided form is not a valid JSON object, do not set it too\n return Promise.resolve();\n }\n // Allow the form to provide component overrides.\n if (form && form.settings && form.settings.components) {\n this.options.components = form.settings.components;\n }\n if (form && form.properties) {\n this.options.properties = form.properties;\n }\n // Use the sanitize config from the form settings or the global sanitize config if it is not provided in the options\n if (!this.options.sanitizeConfig && !this.builderMode) {\n this.options.sanitizeConfig = lodash_1.default.get(form, 'settings.sanitizeConfig') || lodash_1.default.get(form, 'globalSettings.sanitizeConfig');\n }\n if ('schema' in form && (0, compare_versions_1.compareVersions)(form.schema, '1.x') > 0) {\n this.ready.then(() => {\n this.setAlert('alert alert-danger', 'Form schema is for a newer version, please upgrade your renderer. Some functionality may not work.');\n });\n }\n // See if they pass a module, and evaluate it if so.\n if (form && form.module) {\n let formModule = null;\n if (typeof form.module === 'string') {\n try {\n formModule = this.evaluate(`return ${form.module}`);\n }\n catch (err) {\n console.warn(err);\n }\n }\n else {\n formModule = form.module;\n }\n if (formModule) {\n Formio_1.Formio.use(formModule);\n // Since we got here after instantiation, we need to manually apply form options.\n if (formModule.options && formModule.options.form) {\n this.options = Object.assign(this.options, formModule.options.form);\n }\n }\n }\n this.initialized = false;\n const rebuild = this.rebuild() || Promise.resolve();\n return rebuild.then(() => {\n this.emit('formLoad', form);\n this.triggerRecaptcha();\n // Make sure to trigger onChange after a render event occurs to speed up form rendering.\n setTimeout(() => {\n this.onChange(flags);\n this.formReadyResolve();\n }, 0);\n return this.formReady;\n });\n }\n /**\n * Gets the form object.\n *\n * @returns {Object} - The form JSON schema.\n */\n get form() {\n if (!this._form) {\n this._form = {\n components: []\n };\n }\n return this._form;\n }\n /**\n * Sets the form value.\n *\n * @alias setForm\n * @param {Object} form - The form schema object.\n */\n set form(form) {\n this.setForm(form);\n }\n /**\n * Returns the submission object that was set within this form.\n *\n * @returns {Object}\n */\n get submission() {\n return this.getValue();\n }\n /**\n * Sets the submission of a form.\n *\n * @example\n * import Webform from '@formio/js/Webform';\n * let form = new Webform(document.getElementById('formio'));\n * form.src = 'https://examples.form.io/example';\n * form.submission = {data: {\n * firstName: 'Joe',\n * lastName: 'Smith',\n * email: 'joe@example.com'\n * }};\n *\n * @param {Object} submission - The Form.io submission object.\n */\n set submission(submission) {\n this.setSubmission(submission);\n }\n /**\n * Sets a submission and returns the promise when it is ready.\n * @param submission\n * @param flags\n * @return {Promise.<TResult>}\n */\n setSubmission(submission, flags = {}) {\n flags = Object.assign(Object.assign({}, flags), { fromSubmission: lodash_1.default.has(flags, 'fromSubmission') ? flags.fromSubmission : true });\n return this.onSubmission = this.formReady.then((resolveFlags) => {\n if (resolveFlags) {\n flags = Object.assign(Object.assign({}, flags), resolveFlags);\n }\n this.submissionSet = true;\n this.triggerChange(flags);\n this.emit('beforeSetSubmission', submission);\n this.setValue(submission, flags);\n return this.submissionReadyResolve(submission);\n }, (err) => this.submissionReadyReject(err)).catch((err) => this.submissionReadyReject(err));\n }\n handleDraftError(errName, errDetails, restoreDraft) {\n const errorMessage = lodash_1.default.trim(`${this.t(errName)} ${errDetails || ''}`);\n console.warn(errorMessage);\n this.emit(restoreDraft ? 'restoreDraftError' : 'saveDraftError', errDetails || errorMessage);\n }\n /**\n * Saves a submission draft.\n */\n saveDraft() {\n if (!this.draftEnabled) {\n return;\n }\n if (!this.formio) {\n this.handleDraftError('saveDraftInstanceError');\n return;\n }\n if (!Formio_1.Formio.getUser()) {\n this.handleDraftError('saveDraftAuthError');\n return;\n }\n const draft = (0, utils_1.fastCloneDeep)(this.submission);\n draft.state = 'draft';\n if (!this.savingDraft && !this.submitting) {\n this.emit('saveDraftBegin');\n this.savingDraft = true;\n this.formio.saveSubmission(draft).then((sub) => {\n // Set id to submission to avoid creating new draft submission\n this.submission._id = sub._id;\n this.savingDraft = false;\n this.emit('saveDraft', sub);\n })\n .catch(err => {\n this.savingDraft = false;\n this.handleDraftError('saveDraftError', err);\n });\n }\n }\n /**\n * Restores a draft submission based on the user who is authenticated.\n *\n * @param {userId} - The user id where we need to restore the draft from.\n */\n restoreDraft(userId) {\n const formio = this.formio || this.options.formio;\n if (!formio) {\n this.handleDraftError('restoreDraftInstanceError', null, true);\n return;\n }\n this.savingDraft = true;\n formio.loadSubmissions({\n params: {\n state: 'draft',\n owner: userId\n }\n }).then(submissions => {\n if (submissions.length > 0 && !this.options.skipDraftRestore) {\n const draft = (0, utils_1.fastCloneDeep)(submissions[0]);\n return this.setSubmission(draft).then(() => {\n this.draftEnabled = true;\n this.savingDraft = false;\n this.emit('restoreDraft', draft);\n });\n }\n // Enable drafts so that we can keep track of changes.\n this.draftEnabled = true;\n this.savingDraft = false;\n this.emit('restoreDraft', null);\n })\n .catch(err => {\n this.draftEnabled = true;\n this.savingDraft = false;\n this.handleDraftError('restoreDraftError', err, true);\n });\n }\n get schema() {\n const schema = (0, utils_1.fastCloneDeep)(lodash_1.default.omit(this._form, ['components']));\n schema.components = [];\n this.eachComponent((component) => schema.components.push(component.schema));\n return schema;\n }\n mergeData(_this, _that) {\n lodash_1.default.mergeWith(_this, _that, (thisValue, thatValue) => {\n if (Array.isArray(thisValue) && Array.isArray(thatValue) && thisValue.length !== thatValue.length) {\n return thatValue;\n }\n });\n }\n setValue(submission, flags = {}) {\n if (!submission || !submission.data) {\n submission = {\n data: {},\n metadata: submission.metadata,\n };\n }\n // Metadata needs to be available before setValue\n this._submission.metadata = submission.metadata || {};\n this.editing = !!submission._id;\n // Set the timezone in the options if available.\n if (!this.options.submissionTimezone &&\n submission.metadata &&\n submission.metadata.timezone) {\n this.options.submissionTimezone = submission.metadata.timezone;\n }\n const changed = super.setValue(submission.data, flags);\n if (!flags.sanitize) {\n this.mergeData(this.data, submission.data);\n }\n submission.data = this.data;\n this._submission = submission;\n return changed;\n }\n getValue() {\n if (!this._submission.data) {\n this._submission.data = {};\n }\n if (this.viewOnly) {\n return this._submission;\n }\n const submission = this._submission;\n submission.data = this.data;\n return this._submission;\n }\n /**\n * Build the form.\n */\n init() {\n if (this.options.submission) {\n const submission = lodash_1.default.extend({}, this.options.submission);\n this._submission = submission;\n this._data = submission.data;\n }\n else {\n this._submission = this._submission || { data: {} };\n }\n // Remove any existing components.\n if (this.components && this.components.length) {\n this.destroyComponents();\n this.components = [];\n }\n if (this.component) {\n this.component.components = this.form ? this.form.components : [];\n }\n else {\n this.component = this.form;\n }\n this.component.type = 'form';\n this.component.input = false;\n this.addComponents();\n this.on('submitButton', options => {\n this.submit(false, options).catch(e => {\n options.instance.loading = false;\n return e !== false && e !== undefined && console.log(e);\n });\n }, true);\n this.on('checkValidity', (data) => this.validate(data, { dirty: true, process: 'change' }), true);\n this.on('requestUrl', (args) => (this.submitUrl(args.url, args.headers)), true);\n this.on('resetForm', () => this.resetValue(), true);\n this.on('deleteSubmission', () => this.deleteSubmission(), true);\n this.on('refreshData', () => this.updateValue(), true);\n this.executeFormController();\n return this.formReady;\n }\n executeFormController() {\n // If no controller value or\n // hidden and set to clearOnHide (Don't calculate a value for a hidden field set to clear when hidden)\n if (!this.form || !this.form.controller\n || ((!this.visible || this.component.hidden) && this.component.clearOnHide && !this.rootPristine)) {\n return false;\n }\n this.formReady.then(() => {\n this.evaluate(this.form.controller, {\n components: this.components,\n instance: this,\n });\n });\n }\n teardown() {\n this.emit('formDelete', this.id);\n delete Formio_1.Formio.forms[this.id];\n delete this.executeShortcuts;\n delete this.triggerSaveDraft;\n super.teardown();\n }\n destroy(all = false) {\n this.off('submitButton');\n this.off('checkValidity');\n this.off('requestUrl');\n this.off('resetForm');\n this.off('deleteSubmission');\n this.off('refreshData');\n return super.destroy(all);\n }\n build(element) {\n if (element || this.element) {\n return this.ready.then(() => {\n element = element || this.element;\n super.build(element);\n });\n }\n return this.ready;\n }\n getClassName() {\n let classes = 'formio-form';\n if (this.options.readOnly) {\n classes += ' formio-read-only';\n }\n return classes;\n }\n render() {\n return super.render(this.renderTemplate('webform', {\n classes: this.getClassName(),\n children: this.renderComponents(),\n }), this.builderMode ? 'builder' : 'form', true);\n }\n redraw() {\n // Don't bother if we have not built yet.\n if (!this.element) {\n return Promise.resolve();\n }\n this.clear();\n this.setContent(this.element, this.render());\n return this.attach(this.element);\n }\n attach(element) {\n this.setElement(element);\n this.loadRefs(element, { webform: 'single' });\n const childPromise = this.attachComponents(this.refs.webform);\n this.addEventListener(document, 'keydown', this.executeShortcuts);\n this.currentForm = this;\n this.hook('attachWebform', element, this);\n return childPromise.then(() => {\n this.emit('render', this.element);\n return this.setValue(this._submission, {\n noUpdateEvent: true,\n });\n });\n }\n hasRequiredFields() {\n let result = false;\n (0, formUtils_1.eachComponent)(this.form.components, (component) => {\n if (component.validate.required) {\n result = true;\n return true;\n }\n }, true);\n return result;\n }\n resetValue() {\n lodash_1.default.each(this.getComponents(), (comp) => (comp.resetValue()));\n this.setPristine(true);\n this.onChange({ resetValue: true });\n }\n /**\n * Sets a new alert to display in the error dialog of the form.\n *\n * @param {string} type - The type of alert to display. \"danger\", \"success\", \"warning\", etc.\n * @param {string} message - The message to show in the alert.\n * @param {Object} options\n */\n setAlert(type, message, options) {\n if (!type && this.submitted) {\n if (this.alert) {\n if (this.refs.errorRef && this.refs.errorRef.length) {\n this.refs.errorRef.forEach(el => {\n this.removeEventListener(el, 'click');\n this.removeEventListener(el, 'keypress');\n });\n }\n this.removeChild(this.alert);\n this.alert = null;\n }\n return;\n }\n if (this.options.noAlerts) {\n if (!message) {\n this.emit('error', false);\n }\n return;\n }\n if (this.alert) {\n try {\n if (this.refs.errorRef && this.refs.errorRef.length) {\n this.refs.errorRef.forEach(el => {\n this.removeEventListener(el, 'click');\n this.removeEventListener(el, 'keypress');\n });\n }\n this.removeChild(this.alert);\n this.alert = null;\n }\n catch (err) {\n // ignore\n }\n }\n if (message) {\n const attrs = {\n class: (options && options.classes) || `alert alert-${type}`,\n id: `error-list-${this.id}`,\n };\n const templateOptions = {\n message: message instanceof HTMLElement ? message.outerHTML : message,\n attrs: attrs,\n type\n };\n this.alert = (0, utils_1.convertStringToHTMLElement)(this.renderTemplate('alert', templateOptions), `#${attrs.id}`);\n }\n if (!this.alert) {\n return;\n }\n this.loadRefs(this.alert, { errorRef: 'multiple' });\n if (this.refs.errorRef && this.refs.errorRef.length) {\n this.refs.errorRef.forEach(el => {\n this.addEventListener(el, 'click', (e) => {\n const key = e.currentTarget.dataset.componentKey;\n this.focusOnComponent(key);\n });\n this.addEventListener(el, 'keydown', (e) => {\n if (e.keyCode === 13) {\n e.preventDefault();\n const key = e.currentTarget.dataset.componentKey;\n this.focusOnComponent(key);\n }\n });\n });\n }\n this.prepend(this.alert);\n }\n /**\n * Focus on selected component.\n *\n * @param {string} key - The key of selected component.\n * @returns {*}\n */\n focusOnComponent(key) {\n if (key) {\n const component = this.getComponent(key);\n if (component) {\n component.focus();\n }\n }\n }\n /**\n * Show the errors of this form within the alert dialog.\n *\n * @param {Object} error - An optional additional error to display along with the component errors.\n * @returns {*}\n */\n /* eslint-disable no-unused-vars */\n showErrors(errors, triggerEvent) {\n this.loading = false;\n if (!Array.isArray(errors)) {\n errors = [errors];\n }\n errors = errors.concat(this.customErrors).filter((err) => !!err);\n if (!errors.length) {\n this.setAlert(false);\n return;\n }\n // Mark any components as invalid if in a custom message.\n errors.forEach((err) => {\n const { components = [] } = err;\n if (err.component) {\n components.push(err.component);\n }\n if (err.path) {\n components.push(err.path);\n }\n components.forEach((path) => {\n const originalPath = (0, utils_1.getStringFromComponentPath)(path);\n const component = this.getComponent(path, lodash_1.default.identity, originalPath);\n if (err.fromServer) {\n if (component.serverErrors) {\n component.serverErrors.push(err);\n }\n else {\n component.serverErrors = [err];\n }\n }\n const components = lodash_1.default.compact(Array.isArray(component) ? component : [component]);\n components.forEach((component) => component.setCustomValidity(err.message, true));\n });\n });\n const displayedErrors = [];\n if (errors.length) {\n errors = lodash_1.default.uniqBy(errors, error => error.message);\n const createListItem = (message, index) => {\n var _a, _b, _c;\n const err = errors[index];\n const messageFromIndex = !lodash_1.default.isUndefined(index) && errors && errors[index];\n const keyOrPath = ((messageFromIndex === null || messageFromIndex === void 0 ? void 0 : messageFromIndex.formattedKeyOrPath) || (messageFromIndex === null || messageFromIndex === void 0 ? void 0 : messageFromIndex.path) || ((_a = messageFromIndex === null || messageFromIndex === void 0 ? void 0 : messageFromIndex.context) === null || _a === void 0 ? void 0 : _a.path)) || (((_b = err.context) === null || _b === void 0 ? void 0 : _b.component) && ((_c = err.context) === null || _c === void 0 ? void 0 : _c.component.key)) || (err.component && err.component.key) || err.fromServer && err.path;\n const formattedKeyOrPath = keyOrPath ? (0, utils_1.getStringFromComponentPath)(keyOrPath) : '';\n if (typeof err !== 'string' && !err.formattedKeyOrPath) {\n err.formattedKeyOrPath = formattedKeyOrPath;\n }\n return {\n message: (0, utils_1.unescapeHTML)(message),\n keyOrPath: formattedKeyOrPath\n };\n };\n errors.forEach(({ message, context, fromServer, component }, index) => {\n const text = !(component === null || component === void 0 ? void 0 : component.label) || (context === null || context === void 0 ? void 0 : context.hasLabel) || fromServer\n ? this.t('alertMessage', { message: this.t(message) })\n : this.t('alertMessageWithLabel', {\n label: this.t(component === null || component === void 0 ? void 0 : component.label),\n message: this.t(message),\n });\n displayedErrors.push(createListItem(text, index));\n });\n }\n const errorsList = this.renderTemplate('errorsList', { errors: displayedErrors });\n this.root.setAlert('danger', errorsList);\n if (triggerEvent) {\n this.emit('error', errors);\n }\n return errors;\n }\n /* eslint-enable no-unused-vars */\n /**\n * Called when the submission has completed, or if the submission needs to be sent to an external library.\n *\n * @param {Object} submission - The submission object.\n * @param {boolean} saved - Whether or not this submission was saved to the server.\n * @returns {object} - The submission object.\n */\n onSubmit(submission, saved) {\n var _a;\n this.loading = false;\n this.submitting = false;\n this.setPristine(true);\n // We want to return the submitted submission and setValue will mutate the submission so cloneDeep it here.\n this.setValue((0, utils_1.fastCloneDeep)(submission), {\n noValidate: true,\n noCheck: true\n });\n this.setAlert('success', `<p>${this.t('complete')}</p>`);\n // Cancel triggered saveDraft to prevent overriding the submitted state\n if (this.draftEnabled && ((_a = this.triggerSaveDraft) === null || _a === void 0 ? void 0 : _a.cancel)) {\n this.triggerSaveDraft.cancel();\n }\n this.emit('submit', submission, saved);\n if (saved) {\n this.emit('submitDone', submission);\n }\n return submission;\n }\n normalizeError(error) {\n if (error) {\n if (typeof error === 'object' && 'details' in error) {\n error = error.details;\n }\n if (typeof error === 'string') {\n error = { message: error };\n }\n }\n return error;\n }\n /**\n * Called when an error occurs during the submission.\n *\n * @param {Object} error - The error that occured.\n */\n onSubmissionError(error) {\n error = this.normalizeError(error);\n this.submitting = false;\n this.setPristine(false);\n this.emit('submitError', error || this.errors);\n // Allow for silent cancellations (no error message, no submit button error state)\n if (error && error.silent) {\n this.emit('change', { isValid: true }, { silent: true });\n return false;\n }\n const errors = this.showErrors(error, true);\n if (this.root && this.root.alert) {\n this.scrollIntoView(this.root.alert);\n }\n return errors;\n }\n /**\n * Trigger the change event for this form.\n *\n * @param changed\n * @param flags\n */\n onChange(flags, changed, modified, changes) {\n flags = flags || {};\n let isChangeEventEmitted = false;\n super.onChange(flags, true);\n const value = lodash_1.default.clone(this.submission);\n flags.changed = value.changed = changed;\n flags.changes = changes;\n if (modified && this.pristine) {\n this.pristine = false;\n }\n this.checkData(value.data, flags);\n const shouldValidate = !flags.noValidate || flags.fromIFrame || (flags.fromSubmission && this.rootPristine && this.pristine && flags.changed);\n const errors = shouldValidate ? this.validate(value.data, Object.assign(Object.assign({}, flags), { process: 'change' })) : [];\n value.isValid = errors.length === 0;\n this.loading = false;\n if (this.submitted) {\n // show server errors while they are not cleaned/fixed\n const nonComponentServerErrors = lodash_1.default.filter(this.serverErrors || [], err => !err.component && !err.path);\n this.showErrors(nonComponentServerErrors.length ? nonComponentServerErrors : errors);\n }\n // See if we need to save the draft of the form.\n if (modified && this.options.saveDraft) {\n this.triggerSaveDraft();\n }\n if (!flags || !flags.noEmit) {\n this.emit('change', value, flags, modified);\n isChangeEventEmitted = true;\n }\n // The form is initialized after the first change event occurs.\n if (isChangeEventEmitted && !this.initialized) {\n this.emit('initialized');\n this.initialized = true;\n }\n }\n /**\n * Send a delete request to the server.\n */\n deleteSubmission() {\n return this.formio.deleteSubmission()\n .then(() => {\n this.emit('submissionDeleted', this.submission);\n this.resetValue();\n });\n }\n /**\n * Cancels the submission.\n *\n * @alias reset\n */\n cancel(noconfirm) {\n const shouldReset = this.hook('beforeCancel', true);\n if (shouldReset && (noconfirm || confirm(this.t('confirmCancel')))) {\n this.resetValue();\n return true;\n }\n else {\n this.emit('cancelSubmit');\n return false;\n }\n }\n setMetadata(submission) {\n // Add in metadata about client submitting the form\n submission.metadata = submission.metadata || {};\n lodash_1.default.defaults(submission.metadata, {\n timezone: lodash_1.default.get(this, '_submission.metadata.timezone', (0, utils_1.currentTimezone)()),\n offset: parseInt(lodash_1.default.get(this, '_submission.metadata.offset', (0, moment_1.default)().utcOffset()), 10),\n origin: document.location.origin,\n referrer: document.referrer,\n browserName: navigator.appName,\n userAgent: navigator.userAgent,\n pathName: window.location.pathname,\n onLine: navigator.onLine\n });\n }\n submitForm(options = {}) {\n this.clearServerErrors();\n return new Promise((resolve, reject) => {\n // Read-only forms should never submit.\n if (this.options.readOnly) {\n return resolve({\n submission: this.submission,\n saved: false\n });\n }\n const submission = (0, utils_1.fastCloneDeep)(this.submission || {});\n this.setMetadata(submission);\n submission.state = options.state || submission.state || 'submitted';\n const isDraft = (submission.state === 'draft');\n this.hook('beforeSubmit', Object.assign(Object.assign({}, submission), { component: options.component }), (err, data) => {\n var _a;\n if (err) {\n return reject(err);\n }\n submission._vnote = data && data._vnote ? data._vnote : '';\n try {\n if (!isDraft && !options.noValidate) {\n if (!submission.data) {\n return reject('Invalid Submission');\n }\n const errors = this.validate(submission.data, {\n dirty: true,\n silentCheck: false,\n process: 'submit'\n });\n if (errors.length || ((_a = options.beforeSubmitResults) === null || _a === void 0 ? void 0 : _a.some((result) => result.status === 'rejected'))) {\n return reject(errors);\n }\n }\n }\n catch (err) {\n console.error(err);\n }\n this.everyComponent((comp) => {\n if (submission._vnote && comp.type === 'form' && comp.component.reference) {\n lodash_1.default.get(submission.data, comp.path, {})._vnote = submission._vnote;\n }\n const { persistent } = comp.component;\n if (persistent === 'client-only') {\n lodash_1.default.unset(submission.data, comp.path);\n }\n });\n this.hook('customValidation', Object.assign(Object.assign({}, submission), { component: options.component }), (err) => {\n if (err) {\n // If string is returned, cast to object.\n if (typeof err === 'string') {\n err = {\n message: err\n };\n }\n // Ensure err is an array.\n err = Array.isArray(err) ? err : [err];\n return reject(err);\n }\n this.loading = true;\n // Use the form action to submit the form if available.\n if (this._form && this._form.action) {\n const method = (submission.data._id && this._form.action.includes(submission.data._id)) ? 'PUT' : 'POST';\n return Formio_1.Formio.makeStaticRequest(this._form.action, method, submission, this.formio ? this.formio.options : {})\n .then((result) => resolve({\n submission: result,\n saved: true,\n }))\n .catch((error) => {\n this.setServerErrors(error);\n return reject(error);\n });\n }\n const submitFormio = this.formio;\n if (this.nosubmit || !submitFormio) {\n return resolve({\n submission,\n saved: false,\n });\n }\n // If this is an actionUrl, then make sure to save the action and not the submission.\n const submitMethod = submitFormio.actionUrl ? 'saveAction' : 'saveSubmission';\n submitFormio[submitMethod](submission)\n .then((result) => resolve({\n submission: result,\n saved: true,\n }))\n .catch((error) => {\n this.setServerErrors(error);\n return reject(error);\n });\n });\n });\n });\n }\n setServerErrors(error) {\n if (error.details) {\n this.serverErrors = error.details.filter((err) => err.level ? err.level === 'error' : err).map((err) => {\n err.fromServer = true;\n return err;\n });\n }\n else if (typeof error === 'string') {\n this.serverErrors = [{ fromServer: true, level: 'error', message: error }];\n }\n }\n executeSubmit(options) {\n this.submitted = true;\n this.submitting = true;\n return this.submitForm(options)\n .then(({ submission, saved }) => this.onSubmit(submission, saved))\n .then((results) => {\n this.submissionInProcess = false;\n return results;\n })\n .catch((err) => {\n this.submissionInProcess = false;\n return Promise.reject(this.onSubmissionError(err));\n });\n }\n clearServerErrors() {\n var _a;\n (_a = this.serverErrors) === null || _a === void 0 ? void 0 : _a.forEach((error) => {\n if (error.path) {\n const pathArray = (0, utils_1.getArrayFromComponentPath)(error.path);\n const component = this.getComponent(pathArray, lodash_1.default.identity, error.formattedKeyOrPath);\n if (component) {\n component.serverErrors = [];\n }\n }\n });\n this.serverErrors = [];\n }\n /**\n * Submits the form.\n *\n * @example\n * import Webform from '@formio/js/Webform';\n * let form = new Webform(document.getElementById('formio'));\n * form.src = 'https://examples.form.io/example';\n * form.submission = {data: {\n * firstName: 'Joe',\n * lastName: 'Smith',\n * email: 'joe@example.com'\n * }};\n * form.submit().then((submission) => {\n * console.log(submission);\n * });\n *\n * @param {boolean} before - If this submission occured from the before handlers.\n *\n * @returns {Promise} - A promise when the form is done submitting.\n */\n submit(before, options = {}) {\n this.submissionInProcess = true;\n if (!before) {\n return this.beforeSubmit(options).then(() => this.executeSubmit(options));\n }\n else {\n return this.executeSubmit(options);\n }\n }\n submitUrl(URL, headers) {\n if (!URL) {\n return console.warn('Missing URL argument');\n }\n const submission = this.submission || {};\n const API_URL = URL;\n const settings = {\n method: 'POST',\n headers: {}\n };\n if (headers && headers.length > 0) {\n headers.map((e) => {\n if (e.header !== '' && e.value !== '') {\n settings.headers[e.header] = this.interpolate(e.value, submission);\n }\n });\n }\n if (API_URL && settings) {\n Formio_1.Formio.makeStaticRequest(API_URL, settings.method, submission, { headers: settings.headers }).then(() => {\n this.emit('requestDone');\n this.setAlert('success', '<p> Success </p>');\n }).catch((e) => {\n const message = `${e.statusText ? e.statusText : ''} ${e.status ? e.status : e}`;\n this.emit('error', message);\n console.error(message);\n this.setAlert('danger', `<p> ${message} </p>`);\n return Promise.reject(this.onSubmissionError(e));\n });\n }\n else {\n this.emit('error', 'You should add a URL to this button.');\n this.setAlert('warning', 'You should add a URL to this button.');\n return console.warn('You should add a URL to this button.');\n }\n }\n triggerRecaptcha() {\n if (!this || !this.components) {\n return;\n }\n const recaptchaComponent = (0, utils_1.searchComponents)(this.components, {\n 'component.type': 'recaptcha',\n 'component.eventType': 'formLoad'\n });\n if (recaptchaComponent.length > 0) {\n recaptchaComponent[0].verify(`${this.form.name ? this.form.name : 'form'}Load`);\n }\n }\n set nosubmit(value) {\n this._nosubmit = !!value;\n this.emit('nosubmit', this._nosubmit);\n }\n get nosubmit() {\n return this._nosubmit || false;\n }\n get conditions() {\n var _a, _b;\n return (_b = (_a = this.schema.settings) === null || _a === void 0 ? void 0 : _a.conditions) !== null && _b !== void 0 ? _b : [];\n }\n get variables() {\n var _a, _b;\n return (_b = (_a = this.schema.settings) === null || _a === void 0 ? void 0 : _a.variables) !== null && _b !== void 0 ? _b : [];\n }\n}\nexports[\"default\"] = Webform;\nWebform.setBaseUrl = Formio_1.Formio.setBaseUrl;\nWebform.setApiUrl = Formio_1.Formio.setApiUrl;\nWebform.setAppUrl = Formio_1.Formio.setAppUrl;\n\n\n//# sourceURL=webpack://Formio/./lib/cjs/Webform.js?");
|
|
5231
5241
|
|
|
5232
5242
|
/***/ }),
|
|
5233
5243
|
|
|
@@ -5315,7 +5325,7 @@ eval("\nvar __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5315
5325
|
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
|
|
5316
5326
|
|
|
5317
5327
|
"use strict";
|
|
5318
|
-
eval("\nvar __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n var desc = Object.getOwnPropertyDescriptor(m, k);\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\n desc = { enumerable: true, get: function() { return m[k]; } };\n }\n Object.defineProperty(o, k2, desc);\n}) : (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n o[k2] = m[k];\n}));\nvar __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\n}) : function(o, v) {\n o[\"default\"] = v;\n});\nvar __importStar = (this && this.__importStar) || function (mod) {\n if (mod && mod.__esModule) return mod;\n var result = {};\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\n __setModuleDefault(result, mod);\n return result;\n};\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\n/* globals Quill, ClassicEditor, CKEDITOR */\nconst vanilla_text_mask_1 = __webpack_require__(/*! @formio/vanilla-text-mask */ \"./node_modules/@formio/vanilla-text-mask/dist/vanillaTextMask.js\");\nconst tippy_js_1 = __importDefault(__webpack_require__(/*! tippy.js */ \"./node_modules/tippy.js/dist/tippy.esm.js\"));\nconst lodash_1 = __importDefault(__webpack_require__(/*! lodash */ \"./node_modules/lodash/lodash.js\"));\nconst ismobilejs_1 = __importDefault(__webpack_require__(/*! ismobilejs */ \"./node_modules/ismobilejs/esm/index.js\"));\nconst process_1 = __webpack_require__(/*! @formio/core/process */ \"./node_modules/@formio/core/lib/process/index.js\");\nconst Formio_1 = __webpack_require__(/*! ../../../Formio */ \"./lib/cjs/Formio.js\");\nconst FormioUtils = __importStar(__webpack_require__(/*! ../../../utils/utils */ \"./lib/cjs/utils/utils.js\"));\nconst utils_1 = __webpack_require__(/*! ../../../utils/utils */ \"./lib/cjs/utils/utils.js\");\nconst Element_1 = __importDefault(__webpack_require__(/*! ../../../Element */ \"./lib/cjs/Element.js\"));\nconst ComponentModal_1 = __importDefault(__webpack_require__(/*! ../componentModal/ComponentModal */ \"./lib/cjs/components/_classes/componentModal/ComponentModal.js\"));\nconst widgets_1 = __importDefault(__webpack_require__(/*! ../../../widgets */ \"./lib/cjs/widgets/index.js\"));\nconst addons_1 = __importDefault(__webpack_require__(/*! ../../../addons */ \"./lib/cjs/addons/index.js\"));\nconst uploadAdapter_1 = __webpack_require__(/*! ../../../providers/storage/uploadAdapter */ \"./lib/cjs/providers/storage/uploadAdapter.js\");\nconst en_1 = __importDefault(__webpack_require__(/*! ../../../translations/en */ \"./lib/cjs/translations/en.js\"));\nconst Templates_1 = __importDefault(__webpack_require__(/*! ../../../templates/Templates */ \"./lib/cjs/templates/Templates.js\"));\nconst isIEBrowser = FormioUtils.getBrowserInfo().ie;\n/**\n * This is the Component class\n which all elements within the FormioForm derive from.\n */\nclass Component extends Element_1.default {\n static schema(...sources) {\n return lodash_1.default.merge({\n /**\n * Determines if this component provides an input.\n */\n input: true,\n /**\n * The data key for this component (how the data is stored in the database).\n */\n key: '',\n /**\n * The input placeholder for this component.\n */\n placeholder: '',\n /**\n * The input prefix\n */\n prefix: '',\n /**\n * The custom CSS class to provide to this component.\n */\n customClass: '',\n /**\n * The input suffix.\n */\n suffix: '',\n /**\n * If this component should allow an array of values to be captured.\n */\n multiple: false,\n /**\n * The default value of this component.\n */\n defaultValue: null,\n /**\n * If the data of this component should be protected (no GET api requests can see the data)\n */\n protected: false,\n /**\n * Validate if the value of this component should be unique within the form.\n */\n unique: false,\n /**\n * If the value of this component should be persisted within the backend api database.\n */\n persistent: true,\n /**\n * Determines if the component should be within the form, but not visible.\n */\n hidden: false,\n /**\n * If the component should be cleared when hidden.\n */\n clearOnHide: true,\n /**\n * This will refresh this component options when this field changes.\n */\n refreshOn: '',\n /**\n * This will redraw the component when this field changes.\n */\n redrawOn: '',\n /**\n * If this component should be included as a column within a submission table.\n */\n tableView: false,\n /**\n * If this component should be rendering in modal.\n */\n modalEdit: false,\n /**\n * The input label provided to this component.\n */\n label: '',\n dataGridLabel: false,\n labelPosition: 'top',\n description: '',\n errorLabel: '',\n tooltip: '',\n hideLabel: false,\n tabindex: '',\n disabled: false,\n autofocus: false,\n dbIndex: false,\n customDefaultValue: '',\n calculateValue: '',\n calculateServer: false,\n widget: null,\n /**\n * Attributes that will be assigned to the input elements of this component.\n */\n attributes: {},\n /**\n * This will perform the validation on either \"change\" or \"blur\" of the input element.\n */\n validateOn: 'change',\n /**\n * The validation criteria for this component.\n */\n validate: {\n /**\n * If this component is required.\n */\n required: false,\n /**\n * Custom JavaScript validation.\n */\n custom: '',\n /**\n * If the custom validation should remain private (only the backend will see it and execute it).\n */\n customPrivate: false,\n /**\n * If this component should implement a strict date validation if the Calendar widget is implemented.\n */\n strictDateValidation: false,\n multiple: false,\n unique: false\n },\n /**\n * The simple conditional settings for a component.\n */\n conditional: {\n show: null,\n when: null,\n eq: ''\n },\n overlay: {\n style: '',\n left: '',\n top: '',\n width: '',\n height: '',\n },\n allowCalculateOverride: false,\n encrypted: false,\n showCharCount: false,\n showWordCount: false,\n properties: {},\n allowMultipleMasks: false,\n addons: [],\n }, ...sources);\n }\n /**\n * Return the simple condition settings as part of the component.\n *\n * @return {Object}\n *\n */\n static get conditionOperatorsSettings() {\n return {\n operators: ['isEqual', 'isNotEqual', 'isEmpty', 'isNotEmpty'],\n valueComponent() {\n return {\n type: 'textfield',\n widget: {\n type: 'input'\n }\n };\n }\n };\n }\n /**\n * Return the array of possible types of component value absed on its schema.\n *\n * @param schema\n * @return {Array}\n *\n */\n static savedValueTypes(schema) {\n schema = schema || {};\n return FormioUtils.getComponentSavedTypes(schema) || [FormioUtils.componentValueTypes.any];\n }\n /**\n * Provides a table view for this component. Override if you wish to do something different than using getView\n * method of your instance.\n *\n * @param value\n * @param options\n */\n /* eslint-disable no-unused-vars */\n static tableView(value, options) { }\n /* eslint-enable no-unused-vars */\n /**\n * Initialize a new Component.\n *\n * @param {Object} component - The component JSON you wish to initialize.\n * @param {Object} options - The options for this component.\n * @param {Object} data - The global data submission object this component will belong.\n */\n /* eslint-disable max-statements */\n constructor(component, options, data) {\n super(Object.assign({\n renderMode: 'form',\n attachMode: 'full',\n noDefaults: false\n }, options || {}));\n // Restore the component id.\n if (component && component.id) {\n this.id = component.id;\n }\n /**\n * Determines if this component has a condition assigned to it.\n * @type {null}\n * @private\n */\n this._hasCondition = null;\n /**\n * References to dom elements\n */\n this.refs = {};\n // Allow global override for any component JSON.\n if (component &&\n this.options.components &&\n this.options.components[component.type]) {\n lodash_1.default.merge(component, this.options.components[component.type]);\n }\n /**\n * The data path to this specific component instance.\n *\n * @type {string}\n */\n this.path = (component === null || component === void 0 ? void 0 : component.key) || '';\n /**\n * An array of all the children components errors.\n */\n this.childErrors = [];\n /**\n * Last validation errors that have occured.\n */\n this._errors = [];\n this._visibleErrors = [];\n /**\n * The Form.io component JSON schema.\n * @type {*}\n */\n this.component = this.mergeSchema(component || {});\n // Add the id to the component.\n this.component.id = this.id;\n this.afterComponentAssign();\n // Save off the original component to be used in logic.\n this.originalComponent = (0, utils_1.fastCloneDeep)(this.component);\n /**\n * If the component has been attached\n */\n this.attached = false;\n /**\n * If the component has been rendered\n */\n this.rendered = false;\n /**\n * The data object in which this component resides.\n * @type {*}\n */\n this._data = data || {};\n /**\n * Tool tip text after processing\n * @type {string}\n */\n this.tooltip = '';\n /**\n * The row path of this component.\n * @type {number}\n */\n this.row = this.options.row;\n /**\n * Points to a flat map of child components (if applicable).\n *\n * @type {Object}\n */\n this.childComponentsMap = {};\n /**\n * Determines if this component is disabled, or not.\n *\n * @type {boolean}\n */\n this._disabled = (0, utils_1.boolValue)(this.component.disabled) ? this.component.disabled : false;\n /**\n * Points to the root component, usually the FormComponent.\n *\n * @type {Component}\n */\n this.root = this.options.root || this;\n this.localRoot = this.options.localRoot || this;\n /**\n * If this input has been input and provided value.\n *\n * @type {boolean}\n */\n this.pristine = true;\n /**\n * Points to the parent component.\n *\n * @type {Component}\n */\n this.parent = this.options.parent;\n this.options.name = this.options.name || 'data';\n this._path = '';\n // Needs for Nextgen Rules Engine\n this.resetCaches();\n /**\n * Determines if this component is visible, or not.\n */\n this._parentVisible = this.options.hasOwnProperty('parentVisible') ? this.options.parentVisible : true;\n this._visible = this._parentVisible && this.conditionallyVisible(null, data);\n this._parentDisabled = false;\n /**\n * The reference attribute name for this component\n */\n this._referenceAttributeName = 'ref';\n /**\n * Used to trigger a new change in this component.\n * @type {function} - Call to trigger a change in this component.\n */\n let changes = [];\n let lastChanged = null;\n let triggerArgs = [];\n const _triggerChange = lodash_1.default.debounce((...args) => {\n if (this.root) {\n this.root.changing = false;\n }\n triggerArgs = [];\n if (!args[1] && lastChanged) {\n // Set the changed component if one isn't provided.\n args[1] = lastChanged;\n }\n if (lodash_1.default.isEmpty(args[0]) && lastChanged) {\n // Set the flags if it is empty and lastChanged exists.\n args[0] = lastChanged.flags;\n }\n lastChanged = null;\n args[3] = changes;\n const retVal = this.onChange(...args);\n changes = [];\n return retVal;\n }, 100);\n this.triggerChange = (...args) => {\n if (args[1]) {\n // Make sure that during the debounce that we always track lastChanged component, even if they\n // don't provide one later.\n lastChanged = args[1];\n changes.push(lastChanged);\n }\n if (this.root) {\n this.root.changing = true;\n }\n if (args.length) {\n triggerArgs = args;\n }\n return _triggerChange(...triggerArgs);\n };\n /**\n * Used to trigger a redraw event within this component.\n *\n * @type {Function}\n */\n this.triggerRedraw = lodash_1.default.debounce(this.redraw.bind(this), 100);\n /**\n * list of attached tooltips\n * @type {Array}\n */\n this.tooltips = [];\n /**\n * List of attached addons\n * @type {Array}\n */\n this.addons = [];\n // To force this component to be invalid.\n this.invalid = false;\n if (this.component) {\n this.type = this.component.type;\n if (this.allowData && this.key) {\n this.options.name += `[${this.key}]`;\n // If component is visible or not set to clear on hide, set the default value.\n if (this.visible || !this.component.clearOnHide) {\n if (!this.hasValue()) {\n if (this.shouldAddDefaultValue) {\n this.dataValue = this.defaultValue;\n }\n }\n else {\n // Ensure the dataValue is set.\n /* eslint-disable no-self-assign */\n this.dataValue = this.dataValue;\n /* eslint-enable no-self-assign */\n }\n }\n }\n /**\n * The element information for creating the input element.\n * @type {*}\n */\n this.info = this.elementInfo();\n }\n // Allow anyone to hook into the component creation.\n this.hook('component');\n if (!this.options.skipInit) {\n this.init();\n }\n }\n /* eslint-enable max-statements */\n get componentsMap() {\n var _a;\n if ((_a = this.localRoot) === null || _a === void 0 ? void 0 : _a.childComponentsMap) {\n return this.localRoot.childComponentsMap;\n }\n const localMap = {};\n localMap[this.path] = this;\n return localMap;\n }\n get data() {\n return this._data;\n }\n set data(value) {\n this._data = value;\n }\n mergeSchema(component = {}) {\n return lodash_1.default.defaultsDeep(component, this.defaultSchema);\n }\n // Allow componets to notify when ready.\n get ready() {\n return Promise.resolve(this);\n }\n get isPDFReadOnlyMode() {\n return this.parent &&\n this.parent.form &&\n (this.parent.form.display === 'pdf') &&\n this.options.readOnly;\n }\n get labelInfo() {\n const label = {};\n label.hidden = this.labelIsHidden();\n label.className = '';\n label.labelPosition = this.component.labelPosition;\n label.tooltipClass = `${this.iconClass('question-sign')} text-muted`;\n const isPDFReadOnlyMode = this.isPDFReadOnlyMode;\n if (this.hasInput && this.component.validate && (0, utils_1.boolValue)(this.component.validate.required) && !isPDFReadOnlyMode) {\n label.className += ' field-required';\n }\n if (label.hidden) {\n label.className += ' control-label--hidden';\n }\n if (this.info.attr.id) {\n label.for = this.info.attr.id;\n }\n return label;\n }\n init() {\n var _a;\n this.disabled = this.shouldDisabled;\n this._visible = this.conditionallyVisible(null, null);\n if ((_a = this.component.addons) === null || _a === void 0 ? void 0 : _a.length) {\n this.component.addons.forEach((addon) => this.createAddon(addon));\n }\n }\n afterComponentAssign() {\n //implement in extended classes\n }\n createAddon(addonConfiguration) {\n var _a;\n const name = addonConfiguration.name;\n if (!name) {\n return;\n }\n const settings = ((_a = addonConfiguration.settings) === null || _a === void 0 ? void 0 : _a.data) || {};\n const Addon = addons_1.default[name.value];\n let addon = null;\n if (Addon) {\n const supportedComponents = Addon.info.supportedComponents;\n const supportsThisComponentType = !(supportedComponents === null || supportedComponents === void 0 ? void 0 : supportedComponents.length) ||\n supportedComponents.indexOf(this.component.type) !== -1;\n if (supportsThisComponentType) {\n addon = new Addon(settings, this);\n this.addons.push(addon);\n }\n else {\n console.warn(`Addon ${name.label} does not support component of type ${this.component.type}.`);\n }\n }\n return addon;\n }\n teardown() {\n if (this.element) {\n delete this.element.component;\n delete this.element;\n }\n delete this._currentForm;\n delete this.parent;\n delete this.root;\n delete this.triggerChange;\n delete this.triggerRedraw;\n if (this.options) {\n delete this.options.root;\n delete this.options.parent;\n delete this.options.i18next;\n }\n super.teardown();\n }\n destroy(all = false) {\n super.destroy(all);\n this.detach();\n this.addons.forEach((addon) => addon.destroy());\n if (all) {\n this.teardown();\n }\n }\n get shouldDisabled() {\n return this.options.readOnly || this.component.disabled || (this.options.hasOwnProperty('disabled') && this.options.disabled[this.key]);\n }\n get isInputComponent() {\n return !this.component.hasOwnProperty('input') || this.component.input;\n }\n get allowData() {\n return this.hasInput;\n }\n get hasInput() {\n return this.isInputComponent || (this.refs.input && this.refs.input.length);\n }\n get defaultSchema() {\n return Component.schema();\n }\n get key() {\n return lodash_1.default.get(this.component, 'key', '');\n }\n set parentVisible(value) {\n this._parentVisible = value;\n }\n get parentVisible() {\n return this._parentVisible;\n }\n set parentDisabled(value) {\n this._parentDisabled = value;\n }\n get parentDisabled() {\n return this._parentDisabled;\n }\n shouldForceVisibility(component, visibility) {\n if (!this.options[visibility]) {\n return false;\n }\n if (!component) {\n component = this.component;\n }\n if (lodash_1.default.isArray(this.options[visibility])) {\n return this.options[visibility].includes(component.key);\n }\n return this.options[visibility][component.key];\n }\n shouldForceHide(component) {\n return this.shouldForceVisibility(component, 'hide');\n }\n shouldForceShow(component) {\n return this.shouldForceVisibility(component, 'show');\n }\n /**\n *\n * @param value {boolean}\n */\n set visible(value) {\n if (this._visible !== value) {\n // Skip if this component is set to visible and is supposed to be hidden.\n if (value && this.shouldForceHide()) {\n return;\n }\n // Skip if this component is set to hidden and is supposed to be shown.\n if (!value && this.shouldForceShow()) {\n return;\n }\n this._visible = value;\n this.clearOnHide();\n this.redraw();\n }\n }\n /**\n *\n * @returns {boolean}\n */\n get visible() {\n // Show only if visibility changes or if we are in builder mode or if hidden fields should be shown.\n if (this.builderMode || this.previewMode || this.options.showHiddenFields) {\n return true;\n }\n if (this.shouldForceHide()) {\n return false;\n }\n if (this.shouldForceShow()) {\n return true;\n }\n return this._visible && this._parentVisible;\n }\n get currentForm() {\n return this._currentForm;\n }\n set currentForm(instance) {\n this._currentForm = instance;\n }\n get fullMode() {\n return this.options.attachMode === 'full';\n }\n get builderMode() {\n return this.options.attachMode === 'builder';\n }\n get calculatedPath() {\n console.error('component.calculatedPath was deprecated, use component.path instead.');\n return this.path;\n }\n get labelPosition() {\n return this.component.labelPosition;\n }\n get labelWidth() {\n const width = this.component.labelWidth;\n return width >= 0 ? width : 30;\n }\n get labelMargin() {\n const margin = this.component.labelMargin;\n return margin >= 0 ? margin : 3;\n }\n get isAdvancedLabel() {\n return [\n 'left-left',\n 'left-right',\n 'right-left',\n 'right-right'\n ].includes(this.labelPosition);\n }\n get labelPositions() {\n return this.labelPosition.split('-');\n }\n get skipInEmail() {\n return false;\n }\n rightDirection(direction) {\n if (this.options.condensedMode) {\n return false;\n }\n return direction === 'right';\n }\n getLabelInfo(isCondensed = false) {\n const isRightPosition = this.rightDirection(this.labelPositions[0]);\n const isLeftPosition = this.labelPositions[0] === 'left' || isCondensed;\n const isRightAlign = this.rightDirection(this.labelPositions[1]);\n let contentMargin = '';\n if (this.component.hideLabel) {\n const margin = isCondensed ? 0 : this.labelWidth + this.labelMargin;\n contentMargin = isRightPosition ? `margin-right: ${margin}%` : '';\n contentMargin = isLeftPosition ? `margin-left: ${margin}%` : '';\n }\n const labelStyles = `\n flex: ${this.labelWidth};\n ${isRightPosition ? 'margin-left' : 'margin-right'}: ${this.labelMargin}%;\n `;\n const contentStyles = `\n flex: ${100 - this.labelWidth - this.labelMargin};\n ${contentMargin};\n ${this.component.hideLabel ? `max-width: ${100 - this.labelWidth - this.labelMargin}` : ''};\n `;\n return {\n isRightPosition,\n isRightAlign,\n labelStyles,\n contentStyles\n };\n }\n /**\n * Returns only the schema that is different from the default.\n *\n * @param schema\n * @param defaultSchema\n */\n getModifiedSchema(schema, defaultSchema, recursion) {\n const modified = {};\n if (!defaultSchema) {\n return schema;\n }\n lodash_1.default.each(schema, (val, key) => {\n if (!lodash_1.default.isArray(val) && lodash_1.default.isObject(val) && defaultSchema.hasOwnProperty(key)) {\n const subModified = this.getModifiedSchema(val, defaultSchema[key], true);\n if (!lodash_1.default.isEmpty(subModified)) {\n modified[key] = subModified;\n }\n }\n else if (lodash_1.default.isArray(val)) {\n if (val.length !== 0 && !lodash_1.default.isEqual(val, defaultSchema[key])) {\n modified[key] = val;\n }\n }\n else if ((!recursion && (key === 'type')) ||\n (!recursion && (key === 'key')) ||\n (!recursion && (key === 'label')) ||\n (!recursion && (key === 'input')) ||\n (!recursion && (key === 'tableView')) ||\n (val !== '' && !defaultSchema.hasOwnProperty(key)) ||\n (val !== '' && val !== defaultSchema[key]) ||\n (defaultSchema[key] && val !== defaultSchema[key])) {\n modified[key] = val;\n }\n });\n return modified;\n }\n /**\n * Returns the JSON schema for this component.\n */\n get schema() {\n return (0, utils_1.fastCloneDeep)(this.getModifiedSchema(lodash_1.default.omit(this.component, 'id'), this.defaultSchema));\n }\n /**\n * Returns true if component is inside DataGrid\n */\n get isInDataGrid() {\n return this.inDataGrid;\n }\n /**\n * Translate a text using the i18n system.\n *\n * @param {string} text - The i18n identifier.\n * @param {Object} params - The i18n parameters to use for translation.\n */\n t(text, params = {}, ...args) {\n if (!text) {\n return '';\n }\n // Use _userInput: true to ignore translations from defaults\n if (text in en_1.default && params._userInput) {\n return text;\n }\n params.data = params.data || this.rootValue;\n params.row = params.row || this.data;\n params.component = params.component || this.component;\n return super.t(text, params, ...args);\n }\n labelIsHidden() {\n return !this.component.label ||\n ((!this.isInDataGrid && this.component.hideLabel) ||\n (this.isInDataGrid && !this.component.dataGridLabel) ||\n this.options.floatingLabels ||\n this.options.inputsOnly) && !this.builderMode;\n }\n transform(type, value) {\n const frameworkTemplates = this.options.template ? Templates_1.default.templates[this.options.template] : Templates_1.default.current;\n return frameworkTemplates.hasOwnProperty('transform')\n ? frameworkTemplates.transform(type, value, this)\n : (type, value) => value;\n }\n getTemplate(names, modes) {\n modes = Array.isArray(modes) ? modes : [modes];\n names = Array.isArray(names) ? names : [names];\n if (!modes.includes('form')) {\n modes.push('form');\n }\n let result = null;\n if (this.options.templates) {\n result = this.checkTemplate(this.options.templates, names, modes);\n if (result) {\n return result;\n }\n }\n const frameworkTemplates = this.options.template ? Templates_1.default.templates[this.options.template] : Templates_1.default.current;\n result = this.checkTemplate(frameworkTemplates, names, modes);\n if (result) {\n return result;\n }\n // Default back to bootstrap if not defined.\n const name = names[names.length - 1];\n const templatesByName = Templates_1.default.defaultTemplates[name];\n if (!templatesByName) {\n return { template: `Unknown template: ${name}` };\n }\n const templateByMode = this.checkTemplateMode(templatesByName, modes);\n if (templateByMode) {\n return { template: templateByMode };\n }\n return { template: templatesByName.form };\n }\n checkTemplate(templates, names, modes) {\n for (const name of names) {\n const templatesByName = templates[name];\n if (templatesByName) {\n const { referenceAttributeName } = templatesByName;\n const templateByMode = this.checkTemplateMode(templatesByName, modes);\n if (templateByMode) {\n return { template: templateByMode, referenceAttributeName };\n }\n }\n }\n return null;\n }\n checkTemplateMode(templatesByName, modes) {\n for (const mode of modes) {\n const templateByMode = templatesByName[mode];\n if (templateByMode) {\n return templateByMode;\n }\n }\n return null;\n }\n getFormattedAttribute(attr) {\n return attr ? this.t(attr, { _userInput: true }).replace(/\"/g, '"') : '';\n }\n getFormattedTooltip(tooltipValue) {\n const tooltip = this.interpolate(tooltipValue || '').replace(/(?:\\r\\n|\\r|\\n)/g, '<br />');\n return this.getFormattedAttribute(tooltip);\n }\n isHtmlRenderMode() {\n return this.options.renderMode === 'html';\n }\n renderTemplate(name, data = {}, modeOption) {\n // Need to make this fall back to form if renderMode is not found similar to how we search templates.\n const mode = modeOption || this.options.renderMode || 'form';\n data.component = this.component;\n data.self = this;\n data.options = this.options;\n data.readOnly = this.options.readOnly;\n data.iconClass = this.iconClass.bind(this);\n data.size = this.size.bind(this);\n data.t = this.t.bind(this);\n data.transform = this.transform.bind(this);\n data.id = data.id || this.id;\n data.key = data.key || this.key;\n data.value = data.value || this.dataValue;\n data.disabled = this.disabled;\n data.builder = this.builderMode;\n data.render = (...args) => {\n console.warn(`Form.io 'render' template function is deprecated.\n If you need to render template (template A) inside of another template (template B),\n pass pre-compiled template A (use this.renderTemplate('template_A_name') as template context variable for template B`);\n return this.renderTemplate(...args);\n };\n data.label = data.labelInfo || this.labelInfo;\n data.tooltip = this.getFormattedTooltip(this.component.tooltip);\n // Allow more specific template names\n const names = [\n `${name}-${this.component.type}-${this.key}`,\n `${name}-${this.component.type}`,\n `${name}-${this.key}`,\n `${name}`,\n ];\n // Allow template alters.\n const { referenceAttributeName, template } = this.getTemplate(names, mode);\n if (referenceAttributeName) {\n this._referenceAttributeName = referenceAttributeName;\n }\n return this.hook(`render${name.charAt(0).toUpperCase() + name.substring(1, name.length)}`, this.interpolate(template, data), data, mode);\n }\n /**\n * Sanitize an html string.\n *\n * @param string\n * @returns {*}\n */\n sanitize(dirty, forceSanitize, options) {\n var _a;\n if (!this.shouldSanitizeValue && !forceSanitize) {\n return dirty;\n }\n return FormioUtils.sanitize(dirty, {\n sanitizeConfig: lodash_1.default.merge(((_a = this.options) === null || _a === void 0 ? void 0 : _a.sanitizeConfig) || {}, options || {}),\n });\n }\n /**\n * Render a template string into html.\n *\n * @param template\n * @param data\n * @param actions\n *\n * @return {HTMLElement|String} - The created element or an empty string if template is not specified.\n */\n renderString(template, data) {\n if (!template) {\n return '';\n }\n // Interpolate the template and populate\n return this.interpolate(template, data);\n }\n performInputMapping(input) {\n return input;\n }\n get widget() {\n var _a;\n const settings = this.component.widget;\n if (settings && ((_a = this.root) === null || _a === void 0 ? void 0 : _a.shadowRoot)) {\n settings.shadowRoot = this.root.shadowRoot;\n }\n const widget = settings && widgets_1.default[settings.type] ? new widgets_1.default[settings.type](settings, this.component, this) : null;\n return widget;\n }\n getBrowserLanguage() {\n const nav = window.navigator;\n const browserLanguagePropertyKeys = ['language', 'browserLanguage', 'systemLanguage', 'userLanguage'];\n let language;\n // support for HTML 5.1 \"navigator.languages\"\n if (Array.isArray(nav.languages)) {\n for (let i = 0; i < nav.languages.length; i++) {\n language = nav.languages[i];\n if (language && language.length) {\n return language.split(';')[0];\n }\n }\n }\n // support for other well known properties in browsers\n for (let i = 0; i < browserLanguagePropertyKeys.length; i++) {\n language = nav[browserLanguagePropertyKeys[i]];\n if (language && language.length) {\n return language.split(';')[0];\n }\n }\n return null;\n }\n /**\n * Called before a next and previous page is triggered allowing the components\n * to perform special functions.\n *\n * @return {*}\n */\n beforePage() {\n return Promise.resolve(true);\n }\n beforeNext() {\n return this.beforePage(true);\n }\n /**\n * Called before a submission is triggered allowing the components\n * to perform special async functions.\n *\n * @return {*}\n */\n beforeSubmit() {\n return Promise.resolve(true);\n }\n /**\n * Return the submission timezone.\n *\n * @return {*}\n */\n get submissionTimezone() {\n this.options.submissionTimezone = this.options.submissionTimezone || lodash_1.default.get(this.root, 'options.submissionTimezone');\n return this.options.submissionTimezone;\n }\n get timezone() {\n return this.getTimezone(this.component);\n }\n getTimezone(settings) {\n if (settings.timezone) {\n return settings.timezone;\n }\n if (settings.displayInTimezone === 'utc') {\n return 'UTC';\n }\n const submissionTimezone = this.submissionTimezone;\n if (submissionTimezone &&\n ((settings.displayInTimezone === 'submission') ||\n ((this.options.pdf || this.options.server) && (settings.displayInTimezone === 'viewer')))) {\n return submissionTimezone;\n }\n // Return current timezone if none are provided.\n return (0, utils_1.currentTimezone)();\n }\n /**\n *\n * @param {HTMLElement} element - The containing DOM element to query for the ref value.\n * @param {object} refs - The references to load.\n * @param {string} [referenceAttributeName] - The attribute name to use for the reference.\n */\n loadRefs(element, refs, referenceAttributeName) {\n for (const ref in refs) {\n const refType = refs[ref];\n const isString = typeof refType === 'string';\n const selector = isString && refType.includes('scope')\n ? `:scope > [${referenceAttributeName || this._referenceAttributeName || 'ref'}=\"${ref}\"]`\n : `[${referenceAttributeName || this._referenceAttributeName || 'ref'}=\"${ref}\"]`;\n if (isString && refType.startsWith('single')) {\n this.refs[ref] = element.querySelector(selector);\n }\n else {\n this.refs[ref] = element.querySelectorAll(selector);\n }\n }\n }\n setOpenModalElement(template) {\n this.componentModal.setOpenModalElement(template || this.getModalPreviewTemplate());\n }\n getModalPreviewTemplate() {\n var _a;\n const dataValue = this.component.type === 'password' ? this.dataValue.replace(/./g, '•') : this.dataValue;\n let modalLabel;\n if (this.hasInput && ((_a = this.component.validate) === null || _a === void 0 ? void 0 : _a.required) && !this.isPDFReadOnlyMode) {\n modalLabel = { className: 'field-required' };\n }\n return this.renderTemplate('modalPreview', {\n previewText: this.getValueAsString(dataValue, { modalPreview: true }) || this.t('Click to set value'),\n messages: '',\n labelInfo: modalLabel,\n });\n }\n build(element) {\n element = element || this.element;\n this.empty(element);\n this.setContent(element, this.render());\n return this.attach(element);\n }\n get hasModalSaveButton() {\n return true;\n }\n render(children = `Unknown component: ${this.component.type}`, topLevel = false) {\n const isVisible = this.visible;\n this.rendered = true;\n if (!this.builderMode && !this.previewMode && this.component.modalEdit) {\n return ComponentModal_1.default.render(this, {\n visible: isVisible,\n showSaveButton: this.hasModalSaveButton,\n id: this.id,\n classes: this.className,\n styles: this.customStyle,\n children\n }, topLevel);\n }\n else {\n return this.renderTemplate('component', {\n visible: isVisible,\n id: this.id,\n classes: this.className,\n styles: this.customStyle,\n children\n }, topLevel);\n }\n }\n attachTooltips(toolTipsRefs) {\n toolTipsRefs === null || toolTipsRefs === void 0 ? void 0 : toolTipsRefs.forEach((tooltip, index) => {\n if (tooltip) {\n const tooltipAttribute = tooltip.getAttribute('data-tooltip');\n const tooltipDataTitle = tooltip.getAttribute('data-title');\n const tooltipText = this.interpolate(tooltipDataTitle || tooltipAttribute)\n .replace(/(?:\\r\\n|\\r|\\n)/g, '<br />');\n this.tooltips[index] = (0, tippy_js_1.default)(tooltip, {\n allowHTML: true,\n trigger: 'mouseenter click focus',\n placement: 'right',\n zIndex: 10000,\n interactive: true,\n content: this.t(this.sanitize(tooltipText), { _userInput: true }),\n });\n }\n });\n }\n createComponentModal(element, modalShouldBeOpened, currentValue) {\n return new ComponentModal_1.default(this, element, modalShouldBeOpened, currentValue, this._referenceAttributeName);\n }\n attach(element) {\n if (!this.builderMode && !this.previewMode && this.component.modalEdit) {\n const modalShouldBeOpened = this.componentModal ? this.componentModal.isOpened : false;\n const currentValue = modalShouldBeOpened ? this.componentModal.currentValue : this.dataValue;\n const openModalTemplate = this.componentModal && modalShouldBeOpened\n ? this.componentModal.openModalTemplate\n : null;\n this.componentModal = this.createComponentModal(element, modalShouldBeOpened, currentValue);\n this.setOpenModalElement(openModalTemplate);\n }\n this.attached = true;\n this.setElement(element);\n element.component = this;\n // If this already has an id, get it from the dom. If SSR, it could be different from the initiated id.\n if (this.element.id) {\n this.id = this.element.id;\n this.component.id = this.id;\n }\n this.loadRefs(element, {\n messageContainer: 'single',\n tooltip: 'multiple'\n });\n this.attachTooltips(this.refs.tooltip);\n // Attach logic.\n this.attachLogic();\n this.autofocus();\n // Allow global attach.\n this.hook('attachComponent', element, this);\n // Allow attach per component type.\n const type = this.component.type;\n if (type) {\n this.hook(`attach${type.charAt(0).toUpperCase() + type.substring(1, type.length)}`, element, this);\n }\n this.restoreFocus();\n this.addons.forEach((addon) => addon.attach(element));\n return Promise.resolve();\n }\n restoreFocus() {\n var _a, _b, _c;\n const isFocused = ((_b = (_a = this.root) === null || _a === void 0 ? void 0 : _a.focusedComponent) === null || _b === void 0 ? void 0 : _b.path) === this.path;\n if (isFocused) {\n this.loadRefs(this.element, { input: 'multiple' });\n this.focus((_c = this.root.currentSelection) === null || _c === void 0 ? void 0 : _c.index);\n this.restoreCaretPosition();\n }\n }\n addShortcut(element, shortcut) {\n // Avoid infinite recursion.\n if (!element || !this.root || (this.root === this)) {\n return;\n }\n if (!shortcut) {\n shortcut = this.component.shortcut;\n }\n this.root.addShortcut(element, shortcut);\n }\n removeShortcut(element, shortcut) {\n // Avoid infinite recursion.\n if (!element || (this.root === this)) {\n return;\n }\n if (!shortcut) {\n shortcut = this.component.shortcut;\n }\n this.root.removeShortcut(element, shortcut);\n }\n /**\n * Remove all event handlers.\n */\n detach() {\n // First iterate through each ref and delete the component so there are no dangling component references.\n lodash_1.default.each(this.refs, (ref) => {\n if (typeof ref === NodeList) {\n ref.forEach((elem) => {\n delete elem.component;\n });\n }\n else if (ref) {\n delete ref.component;\n }\n });\n this.refs = {};\n this.removeEventListeners();\n this.detachLogic();\n if (this.tooltip) {\n this.tooltip.destroy();\n }\n }\n checkRefresh(refreshData, changed, flags) {\n const changePath = lodash_1.default.get(changed, 'instance.path', false);\n // Don't let components change themselves.\n if (changePath && this.path === changePath) {\n return;\n }\n if (refreshData === 'data') {\n this.refresh(this.data, changed, flags);\n }\n else if ((changePath && (0, utils_1.getComponentPath)(changed.instance) === refreshData) && changed && changed.instance &&\n // Make sure the changed component is not in a different \"context\". Solves issues where refreshOn being set\n // in fields inside EditGrids could alter their state from other rows (which is bad).\n this.inContext(changed.instance)) {\n this.refresh(changed.value, changed, flags);\n }\n }\n checkRefreshOn(changes, flags = {}) {\n changes = changes || [];\n if (flags.noRefresh) {\n return;\n }\n if (!changes.length && flags.changed) {\n changes = [flags.changed];\n }\n const refreshOn = flags.fromBlur ? this.component.refreshOnBlur : this.component.refreshOn || this.component.redrawOn;\n // If they wish to refresh on a value, then add that here.\n if (refreshOn) {\n if (Array.isArray(refreshOn)) {\n refreshOn.forEach(refreshData => changes.forEach(changed => this.checkRefresh(refreshData, changed, flags)));\n }\n else {\n changes.forEach(changed => this.checkRefresh(refreshOn, changed, flags));\n }\n }\n }\n /**\n * Refreshes the component with a new value.\n *\n * @param value\n */\n refresh(value) {\n if (this.hasOwnProperty('refreshOnValue')) {\n this.refreshOnChanged = !lodash_1.default.isEqual(value, this.refreshOnValue);\n }\n else {\n this.refreshOnChanged = true;\n }\n this.refreshOnValue = (0, utils_1.fastCloneDeep)(value);\n if (this.refreshOnChanged) {\n if (this.component.clearOnRefresh) {\n this.setValue(null);\n }\n this.triggerRedraw();\n }\n }\n /**\n * Checks to see if a separate component is in the \"context\" of this component. This is determined by first checking\n * if they share the same \"data\" object. It will then walk up the parent tree and compare its parents data objects\n * with the components data and returns true if they are in the same context.\n *\n * Different rows of the same EditGrid, for example, are in different contexts.\n *\n * @param component\n */\n inContext(component) {\n if (component.data === this.data) {\n return true;\n }\n let parent = this.parent;\n while (parent) {\n if (parent.data === component.data) {\n return true;\n }\n parent = parent.parent;\n }\n return false;\n }\n get viewOnly() {\n return this.options.readOnly && this.options.viewAsHtml;\n }\n setElement(element) {\n if (this.element) {\n delete this.element.component;\n delete this.element;\n }\n this.element = element;\n }\n createViewOnlyElement() {\n this.setElement(this.ce('dl', {\n id: this.id\n }));\n if (this.element) {\n // Ensure you can get the component info from the element.\n this.element.component = this;\n }\n return this.element;\n }\n get defaultViewOnlyValue() {\n return '-';\n }\n /**\n * Uses the widget to determine the output string.\n *\n * @param value\n * @return {*}\n */\n getWidgetValueAsString(value, options) {\n const noInputWidget = !this.refs.input || !this.refs.input[0] || !this.refs.input[0].widget;\n if (!value || noInputWidget) {\n if (!this.widget || !value) {\n return value;\n }\n else {\n return this.widget.getValueAsString(value);\n }\n }\n if (Array.isArray(value)) {\n const values = [];\n value.forEach((val, index) => {\n const widget = this.refs.input[index] && this.refs.input[index].widget;\n if (widget) {\n values.push(widget.getValueAsString(val, options));\n }\n });\n return values;\n }\n const widget = this.refs.input[0].widget;\n return widget.getValueAsString(value, options);\n }\n getValueAsString(value, options) {\n if (!value) {\n return '';\n }\n value = this.getWidgetValueAsString(value, options);\n if (Array.isArray(value)) {\n return value.join(', ');\n }\n if (lodash_1.default.isPlainObject(value)) {\n return JSON.stringify(value);\n }\n if (value === null || value === undefined) {\n return '';\n }\n const stringValue = value.toString();\n return this.sanitize(stringValue);\n }\n getView(value, options) {\n if (this.component.protected) {\n return '--- PROTECTED ---';\n }\n return this.getValueAsString(value, options);\n }\n updateItems(...args) {\n this.restoreValue();\n this.onChange(...args);\n }\n /**\n * @param {*} data\n * @param {boolean} [forceUseValue=false] - if true, return 'value' property of the data\n * @return {*}\n */\n itemValue(data, forceUseValue = false) {\n if (lodash_1.default.isObject(data) && !lodash_1.default.isArray(data)) {\n if (this.valueProperty) {\n return lodash_1.default.get(data, this.valueProperty);\n }\n if (forceUseValue) {\n return data.value;\n }\n }\n return data;\n }\n itemValueForHTMLMode(value) {\n if (Array.isArray(value)) {\n const values = value.map(item => Array.isArray(item) ? this.itemValueForHTMLMode(item) : this.itemValue(item));\n return values.join(', ');\n }\n return this.itemValue(value);\n }\n createModal(element, attr, confirm) {\n const dialog = this.ce('div', attr || {});\n this.setContent(dialog, this.renderTemplate('dialog'));\n // Add refs to dialog, not \"this\".\n dialog.refs = {};\n this.loadRefs.call(dialog, dialog, {\n dialogOverlay: 'single',\n dialogContents: 'single',\n dialogClose: 'single',\n });\n dialog.refs.dialogContents.appendChild(element);\n document.body.appendChild(dialog);\n document.body.classList.add('modal-open');\n dialog.close = () => {\n document.body.classList.remove('modal-open');\n dialog.dispatchEvent(new CustomEvent('close'));\n };\n this.addEventListener(dialog, 'close', () => this.removeChildFrom(dialog, document.body));\n const close = (event) => {\n event.preventDefault();\n dialog.close();\n };\n const handleCloseClick = (e) => {\n if (confirm) {\n confirm().then(() => close(e))\n .catch(() => { });\n }\n else {\n close(e);\n }\n };\n this.addEventListener(dialog.refs.dialogOverlay, 'click', handleCloseClick);\n this.addEventListener(dialog.refs.dialogClose, 'click', handleCloseClick);\n return dialog;\n }\n get optimizeRedraw() {\n if (this.options.optimizeRedraw && this.element && !this.visible) {\n this.addClass(this.element, 'formio-removed');\n return true;\n }\n return false;\n }\n /**\n * Retrieves the CSS class name of this component.\n * @returns {string} - The class name of this component.\n */\n get className() {\n let className = this.hasInput ? `${this.transform('class', 'form-group')} has-feedback ` : '';\n className += `formio-component formio-component-${this.component.type} `;\n // TODO: find proper way to avoid overriding of default type-based component styles\n if (this.key && this.key !== 'form') {\n className += `formio-component-${this.key} `;\n }\n if (this.component.multiple) {\n className += 'formio-component-multiple ';\n }\n if (this.component.customClass) {\n className += this.component.customClass;\n }\n if (this.hasInput && this.component.validate && (0, utils_1.boolValue)(this.component.validate.required)) {\n className += ' required';\n }\n if (this.labelIsHidden()) {\n className += ' formio-component-label-hidden';\n }\n if (!this.visible) {\n className += ' formio-hidden';\n }\n return className;\n }\n /**\n * Build the custom style from the layout values\n * @return {string} - The custom style\n */\n get customStyle() {\n let customCSS = '';\n lodash_1.default.each(this.component.style, (value, key) => {\n if (value !== '') {\n customCSS += `${key}:${value};`;\n }\n });\n return customCSS;\n }\n static get serverConditionSettings() {\n return Component.conditionOperatorsSettings;\n }\n get isMobile() {\n return (0, ismobilejs_1.default)();\n }\n /**\n * Returns the outside wrapping element of this component.\n * @returns {HTMLElement}\n */\n getElement() {\n return this.element;\n }\n /**\n * Create an evaluation context for all script executions and interpolations.\n *\n * @param additional\n * @return {*}\n */\n evalContext(additional) {\n return super.evalContext(Object.assign({\n component: this.component,\n row: this.data,\n rowIndex: this.rowIndex,\n data: this.rootValue,\n iconClass: this.iconClass.bind(this),\n // Bind the translate function to the data context of any interpolated string.\n // It is useful to translate strings in different scenarions (eg: custom edit grid templates, custom error messages etc.)\n // and desirable to be publicly available rather than calling the internal {instance.t} function in the template string.\n t: this.t.bind(this),\n submission: (this.root ? this.root._submission : {\n data: this.rootValue\n }),\n form: this.root ? this.root._form : {},\n options: this.options,\n }, additional));\n }\n /**\n * Sets the pristine flag for this component.\n *\n * @param pristine {boolean} - TRUE to make pristine, FALSE not pristine.\n */\n setPristine(pristine) {\n this.pristine = pristine;\n }\n get isPristine() {\n return this.pristine;\n }\n setDirty(dirty) {\n this.dirty = dirty;\n }\n get isDirty() {\n return this.dirty;\n }\n /**\n * Removes a value out of the data array and rebuild the rows.\n * @param {number} index - The index of the data element to remove.\n */\n removeValue(index) {\n this.splice(index);\n this.redraw();\n this.restoreValue();\n this.triggerRootChange();\n }\n iconClass(name, spinning) {\n const iconset = this.options.iconset || Templates_1.default.current.defaultIconset || 'fa';\n return Templates_1.default.current.hasOwnProperty('iconClass')\n ? Templates_1.default.current.iconClass(iconset, name, spinning)\n : this.options.iconset === 'fa' ? Templates_1.default.defaultTemplates.iconClass(iconset, name, spinning) : name;\n }\n size(size) {\n return Templates_1.default.current.hasOwnProperty('size')\n ? Templates_1.default.current.size(size)\n : size;\n }\n /**\n * The readible name for this component.\n * @returns {string} - The name of the component.\n */\n get name() {\n return this.t(this.component.label || this.component.placeholder || this.key, { _userInput: true });\n }\n get visibleErrors() {\n return this._visibleErrors;\n }\n get errors() {\n return this._errors;\n }\n /**\n * Returns the error label for this component.\n * @return {*}\n */\n get errorLabel() {\n return this.t(this.component.errorLabel\n || this.component.label\n || this.component.placeholder\n || this.key);\n }\n /**\n * Get the error message provided a certain type of error.\n * @param type\n * @return {*}\n */\n errorMessage(type) {\n return (this.component.errors && this.component.errors[type]) ? this.component.errors[type] : type;\n }\n setContent(element, content, forceSanitize, sanitizeOptions) {\n if (element instanceof HTMLElement) {\n element.innerHTML = this.sanitize(content, forceSanitize, sanitizeOptions);\n return true;\n }\n return false;\n }\n restoreCaretPosition() {\n var _a, _b, _c;\n if ((_a = this.root) === null || _a === void 0 ? void 0 : _a.currentSelection) {\n if ((_b = this.refs.input) === null || _b === void 0 ? void 0 : _b.length) {\n const { selection, index } = this.root.currentSelection;\n let input = this.refs.input[index];\n const isInputRangeSelectable = (i) => /text|search|password|tel|url/i.test((i === null || i === void 0 ? void 0 : i.type) || '');\n if (input) {\n if (isInputRangeSelectable(input)) {\n input.setSelectionRange(...selection);\n }\n }\n else {\n input = this.refs.input[this.refs.input.length];\n const lastCharacter = ((_c = input.value) === null || _c === void 0 ? void 0 : _c.length) || 0;\n if (isInputRangeSelectable(input)) {\n input.setSelectionRange(lastCharacter, lastCharacter);\n }\n }\n }\n }\n }\n redraw() {\n // Don't bother if we have not built yet.\n if (!this.element || !this.element.parentNode || this.optimizeRedraw) {\n // Return a non-resolving promise.\n return Promise.resolve();\n }\n this.detach();\n this.emit('redraw');\n // Since we are going to replace the element, we need to know it's position so we can find it in the parent's children.\n const parent = this.element.parentNode;\n const index = Array.prototype.indexOf.call(parent.children, this.element);\n this.element.outerHTML = this.sanitize(this.render());\n this.setElement(parent.children[index]);\n return this.attach(this.element);\n }\n rebuild() {\n this.destroy();\n this.init();\n this.visible = this.conditionallyVisible(null, null);\n return this.redraw();\n }\n removeEventListeners() {\n super.removeEventListeners();\n this.tooltips.forEach(tooltip => tooltip.destroy());\n this.tooltips = [];\n }\n hasClass(element, className) {\n if (!element) {\n return;\n }\n return super.hasClass(element, this.transform('class', className));\n }\n addClass(element, className) {\n if (!element) {\n return;\n }\n return super.addClass(element, this.transform('class', className));\n }\n removeClass(element, className) {\n if (!element) {\n return;\n }\n return super.removeClass(element, this.transform('class', className));\n }\n /**\n * Determines if this component has a condition defined.\n *\n * @return {null}\n */\n hasCondition() {\n if (this._hasCondition !== null) {\n return this._hasCondition;\n }\n this._hasCondition = FormioUtils.hasCondition(this.component);\n return this._hasCondition;\n }\n /**\n * Check if this component is conditionally visible.\n *\n * @param data\n * @return {boolean}\n */\n conditionallyVisible(data, row) {\n data = data || this.rootValue;\n row = row || this.data;\n if (this.builderMode || this.previewMode || !this.hasCondition()) {\n return !this.component.hidden;\n }\n data = data || (this.root ? this.root.data : {});\n return this.checkCondition(row, data);\n }\n /**\n * Checks the condition of this component.\n *\n * TODO: Switch row and data parameters to be consistent with other methods.\n *\n * @param row - The row contextual data.\n * @param data - The global data object.\n * @return {boolean} - True if the condition applies to this component.\n */\n checkCondition(row, data) {\n return FormioUtils.checkCondition(this.component, row || this.data, data || this.rootValue, this.root ? this.root._form : {}, this);\n }\n /**\n * Check for conditionals and hide/show the element based on those conditions.\n */\n checkComponentConditions(data, flags, row) {\n data = data || this.rootValue;\n flags = flags || {};\n row = row || this.data;\n if (!this.builderMode & !this.previewMode && this.fieldLogic(data, row)) {\n this.redraw();\n }\n // Check advanced conditions\n const visible = this.conditionallyVisible(data, row);\n if (this.visible !== visible) {\n this.visible = visible;\n }\n return visible;\n }\n /**\n * Checks conditions for this component and any sub components.\n * @param args\n * @return {boolean}\n */\n checkConditions(data, flags, row) {\n data = data || this.rootValue;\n flags = flags || {};\n row = row || this.data;\n return this.checkComponentConditions(data, flags, row);\n }\n get logic() {\n return this.component.logic || [];\n }\n /**\n * Check all triggers and apply necessary actions.\n *\n * @param data\n */\n fieldLogic(data, row) {\n data = data || this.rootValue;\n row = row || this.data;\n const logics = this.logic;\n // If there aren't logic, don't go further.\n if (logics.length === 0) {\n return;\n }\n const newComponent = (0, utils_1.fastCloneDeep)(this.originalComponent);\n let changed = logics.reduce((changed, logic) => {\n const result = FormioUtils.checkTrigger(newComponent, logic.trigger, row, data, this.root ? this.root._form : {}, this);\n return (result ? this.applyActions(newComponent, logic.actions, result, row, data) : false) || changed;\n }, false);\n // If component definition changed, replace and mark as changed.\n if (!lodash_1.default.isEqual(this.component, newComponent)) {\n this.component = newComponent;\n changed = true;\n const disabled = this.shouldDisabled;\n // Change disabled state if it has changed\n if (this.disabled !== disabled) {\n this.disabled = disabled;\n }\n }\n return changed;\n }\n isIE() {\n if (typeof window === 'undefined') {\n return false;\n }\n const userAgent = window.navigator.userAgent;\n const msie = userAgent.indexOf('MSIE ');\n if (msie > 0) {\n // IE 10 or older => return version number\n return parseInt(userAgent.substring(msie + 5, userAgent.indexOf('.', msie)), 10);\n }\n const trident = userAgent.indexOf('Trident/');\n if (trident > 0) {\n // IE 11 => return version number\n const rv = userAgent.indexOf('rv:');\n return parseInt(userAgent.substring(rv + 3, userAgent.indexOf('.', rv)), 10);\n }\n const edge = userAgent.indexOf('Edge/');\n if (edge > 0) {\n // IE 12 (aka Edge) => return version number\n return parseInt(userAgent.substring(edge + 5, userAgent.indexOf('.', edge)), 10);\n }\n // other browser\n return false;\n }\n defineActionValue(action, argsObject) {\n return this.evaluate(action.value, argsObject, 'value');\n }\n applyActions(newComponent, actions, result, row, data) {\n data = data || this.rootValue;\n row = row || this.data;\n return actions.reduce((changed, action) => {\n switch (action.type) {\n case 'property': {\n FormioUtils.setActionProperty(newComponent, action, result, row, data, this);\n const property = action.property.value;\n if (!lodash_1.default.isEqual(lodash_1.default.get(this.component, property), lodash_1.default.get(newComponent, property))) {\n changed = true;\n }\n break;\n }\n case 'value': {\n const oldValue = this.getValue();\n const newValue = this.defineActionValue(action, {\n value: lodash_1.default.clone(oldValue),\n data,\n row,\n component: newComponent,\n result,\n });\n if (!lodash_1.default.isEqual(oldValue, newValue) && !(this.component.clearOnHide && !this.visible)) {\n this.setValue(newValue);\n if (this.viewOnly) {\n this.dataValue = newValue;\n }\n changed = true;\n }\n break;\n }\n case 'mergeComponentSchema': {\n const schema = this.evaluate(action.schemaDefinition, {\n value: lodash_1.default.clone(this.getValue()),\n data,\n row,\n component: newComponent,\n result,\n }, 'schema');\n lodash_1.default.assign(newComponent, schema);\n if (!lodash_1.default.isEqual(this.component, newComponent)) {\n changed = true;\n }\n break;\n }\n case 'customAction': {\n const oldValue = this.getValue();\n const newValue = this.evaluate(action.customAction, {\n value: lodash_1.default.clone(oldValue),\n data,\n row,\n input: oldValue,\n component: newComponent,\n result,\n }, 'value');\n if (!lodash_1.default.isEqual(oldValue, newValue) && !(this.component.clearOnHide && !this.visible)) {\n this.setValue(newValue);\n if (this.viewOnly) {\n this.dataValue = newValue;\n }\n changed = true;\n }\n break;\n }\n }\n return changed;\n }, false);\n }\n // Deprecated\n addInputError(message, dirty, elements) {\n this.addMessages(message);\n this.setErrorClasses(elements, dirty, !!message);\n }\n // Deprecated\n removeInputError(elements) {\n this.setErrorClasses(elements, true, false);\n }\n /**\n * Add a new input error to this element.\n *\n * @param message\n * @param dirty\n */\n addMessages(messages) {\n if (!messages) {\n return;\n }\n // Standardize on array of objects for message.\n if (typeof messages === 'string') {\n messages = {\n messages,\n level: 'error',\n };\n }\n if (!Array.isArray(messages)) {\n messages = [messages];\n }\n messages = lodash_1.default.uniqBy(messages, message => message.message);\n if (this.refs.messageContainer) {\n this.setContent(this.refs.messageContainer, messages.map((message) => {\n if (message.message && typeof message.message === 'string') {\n message.message = message.message.replaceAll('<', '<').replaceAll('>', '>');\n }\n return this.renderTemplate('message', Object.assign({}, message));\n }).join(''));\n }\n }\n setErrorClasses(elements, dirty, hasErrors, hasMessages, element = this.element) {\n this.clearErrorClasses();\n elements.forEach((element) => {\n this.setElementInvalid(this.performInputMapping(element), false);\n });\n this.setInputWidgetErrorClasses(elements, hasErrors);\n // do not set error classes for hidden components\n if (!this.visible) {\n return;\n }\n if (hasErrors) {\n // Add error classes\n elements.forEach((input) => {\n this.setElementInvalid(this.performInputMapping(input), true);\n });\n if (dirty && this.options.highlightErrors) {\n this.addClass(element, this.options.componentErrorClass);\n }\n else {\n this.addClass(element, 'has-error');\n }\n }\n if (hasMessages) {\n this.addClass(element, 'has-message');\n }\n }\n setElementInvalid(element, invalid) {\n if (!element)\n return;\n if (invalid) {\n this.addClass(element, 'is-invalid');\n }\n else {\n this.removeClass(element, 'is-invalid');\n }\n element.setAttribute('aria-invalid', invalid ? 'true' : 'false');\n }\n clearOnHide() {\n // clearOnHide defaults to true for old forms (without the value set) so only trigger if the value is false.\n if (\n // if change happens inside EditGrid's row, it doesn't trigger change on the root level, so rootPristine will be true\n (!this.rootPristine || this.options.server || (0, utils_1.isInsideScopingComponent)(this)) &&\n this.component.clearOnHide !== false &&\n !this.options.readOnly &&\n !this.options.showHiddenFields) {\n if (!this.visible) {\n this.deleteValue();\n }\n else if (!this.hasValue() && this.shouldAddDefaultValue) {\n // If shown, ensure the default is set.\n this.setValue(this.defaultValue, {\n noUpdateEvent: true\n });\n }\n }\n }\n triggerRootChange(...args) {\n if (this.options.onChange) {\n this.options.onChange(...args);\n }\n else if (this.root && this.root.triggerChange) {\n this.root.triggerChange(...args);\n }\n }\n onChange(flags, fromRoot) {\n flags = flags || {};\n if (flags.modified) {\n if (!flags.noPristineChangeOnModified) {\n this.pristine = false;\n }\n this.addClass(this.getElement(), 'formio-modified');\n }\n // If we are supposed to validate on blur, then don't trigger validation yet.\n if (this.component.validateOn === 'blur') {\n flags.noValidate = true;\n }\n if (this.component.onChange) {\n this.evaluate(this.component.onChange, {\n flags\n });\n }\n // Set the changed variable.\n const changed = {\n instance: this,\n component: this.component,\n value: this.dataValue,\n flags: flags\n };\n // Emit the change.\n this.emit('componentChange', changed);\n // Do not propogate the modified flag.\n let modified = false;\n if (flags.modified) {\n modified = true;\n delete flags.modified;\n }\n // Bubble this change up to the top.\n if (!fromRoot) {\n this.triggerRootChange(flags, changed, modified);\n }\n return changed;\n }\n get wysiwygDefault() {\n return {\n quill: {\n theme: 'snow',\n placeholder: this.t(this.component.placeholder, { _userInput: true }),\n modules: {\n toolbar: [\n [{ 'size': ['small', false, 'large', 'huge'] }], // custom dropdown\n [{ 'header': [1, 2, 3, 4, 5, 6, false] }],\n [{ 'font': [] }],\n ['bold', 'italic', 'underline', 'strike', { 'script': 'sub' }, { 'script': 'super' }, 'clean'],\n [{ 'color': [] }, { 'background': [] }],\n [{ 'list': 'ordered' }, { 'list': 'bullet' }, { 'indent': '-1' }, { 'indent': '+1' }, { 'align': [] }],\n ['blockquote', 'code-block'],\n ['link', 'image', 'video', 'formula', 'source']\n ]\n }\n },\n ace: {\n theme: 'ace/theme/xcode',\n maxLines: 12,\n minLines: 12,\n tabSize: 2,\n mode: 'ace/mode/javascript',\n placeholder: this.t(this.component.placeholder, { _userInput: true })\n },\n ckeditor: {\n image: {\n toolbar: [\n 'imageTextAlternative',\n '|',\n 'imageStyle:full',\n 'imageStyle:alignLeft',\n 'imageStyle:alignCenter',\n 'imageStyle:alignRight'\n ],\n styles: [\n 'full',\n 'alignLeft',\n 'alignCenter',\n 'alignRight'\n ]\n },\n extraPlugins: []\n },\n default: {}\n };\n }\n addCKE(element, settings, onChange) {\n settings = lodash_1.default.isEmpty(settings) ? {} : settings;\n settings.base64Upload = this.component.isUploadEnabled ? false : true;\n settings.mediaEmbed = { previewsInData: true };\n settings = lodash_1.default.merge(this.wysiwygDefault.ckeditor, lodash_1.default.get(this.options, 'editors.ckeditor.settings', {}), settings);\n if (this.component.isUploadEnabled) {\n settings.extraPlugins.push((0, uploadAdapter_1.getFormioUploadAdapterPlugin)(this.fileService, this));\n }\n return Formio_1.Formio.requireLibrary('ckeditor', isIEBrowser ? 'CKEDITOR' : 'ClassicEditor', lodash_1.default.get(this.options, 'editors.ckeditor.src', `${Formio_1.Formio.cdn.ckeditor}/ckeditor.js`), true)\n .then(() => {\n if (!element.parentNode) {\n return Promise.reject();\n }\n if (isIEBrowser) {\n const editor = CKEDITOR.replace(element);\n editor.on('change', () => onChange(editor.getData()));\n return Promise.resolve(editor);\n }\n else {\n return ClassicEditor.create(element, settings).then(editor => {\n editor.model.document.on('change', () => onChange(editor.data.get()));\n return editor;\n });\n }\n });\n }\n addQuill(element, settings, onChange) {\n settings = lodash_1.default.isEmpty(settings) ? this.wysiwygDefault.quill : settings;\n settings = lodash_1.default.merge(this.wysiwygDefault.quill, lodash_1.default.get(this.options, 'editors.quill.settings', {}), settings);\n settings = Object.assign(Object.assign({}, settings), { modules: Object.assign({ table: true }, settings.modules) });\n // Lazy load the quill css.\n Formio_1.Formio.requireLibrary(`quill-css-${settings.theme}`, 'Quill', [\n { type: 'styles', src: `${Formio_1.Formio.cdn.quill}/quill.${settings.theme}.css` }\n ], true);\n // Lazy load the quill library.\n return Formio_1.Formio.requireLibrary('quill', 'Quill', lodash_1.default.get(this.options, 'editors.quill.src', `${Formio_1.Formio.cdn.quill}/quill.min.js`), true)\n .then(() => {\n return Formio_1.Formio.requireLibrary('quill-table', 'Quill', `${Formio_1.Formio.cdn.baseUrl}/quill/quill-table.js`, true)\n .then(() => {\n if (!element.parentNode) {\n return Promise.reject();\n }\n this.quill = new Quill(element, isIEBrowser ? Object.assign(Object.assign({}, settings), { modules: {} }) : settings);\n /** This block of code adds the [source] capabilities. See https://codepen.io/anon/pen/ZyEjrQ **/\n const txtArea = document.createElement('textarea');\n txtArea.setAttribute('class', 'quill-source-code');\n this.quill.addContainer('ql-custom').appendChild(txtArea);\n const qlSource = element.parentNode.querySelector('.ql-source');\n if (qlSource) {\n this.addEventListener(qlSource, 'click', (event) => {\n event.preventDefault();\n if (txtArea.style.display === 'inherit') {\n this.quill.setContents(this.quill.clipboard.convert({ html: txtArea.value }));\n }\n txtArea.style.display = (txtArea.style.display === 'none') ? 'inherit' : 'none';\n });\n }\n /** END CODEBLOCK **/\n // Make sure to select cursor when they click on the element.\n this.addEventListener(element, 'click', () => this.quill.focus());\n // Allows users to skip toolbar items when tabbing though form\n const elm = document.querySelectorAll('.ql-formats > button');\n for (let i = 0; i < elm.length; i++) {\n elm[i].setAttribute('tabindex', '-1');\n }\n this.quill.on('text-change', () => {\n txtArea.value = this.quill.root.innerHTML;\n onChange(txtArea);\n });\n return this.quill;\n });\n });\n }\n get shouldSanitizeValue() {\n var _a;\n // Sanitize value if sanitizing for thw whole content is turned off\n return (((_a = this.options) === null || _a === void 0 ? void 0 : _a.sanitize) !== false);\n }\n addAce(element, settings, onChange) {\n if (!settings || (settings.theme === 'snow')) {\n const mode = settings ? settings.mode : '';\n settings = {};\n if (mode) {\n settings.mode = mode;\n }\n }\n settings = lodash_1.default.merge(this.wysiwygDefault.ace, lodash_1.default.get(this.options, 'editors.ace.settings', {}), settings || {});\n return Formio_1.Formio.requireLibrary('ace', 'ace', lodash_1.default.get(this.options, 'editors.ace.src', `${Formio_1.Formio.cdn.ace}/ace.js`), true)\n .then((editor) => {\n editor = editor.edit(element);\n editor.removeAllListeners('change');\n editor.setOptions(settings);\n editor.getSession().setMode(settings.mode);\n editor.on('change', () => onChange(editor.getValue()));\n if (settings.isUseWorkerDisabled) {\n editor.session.setUseWorker(false);\n }\n return editor;\n });\n }\n get tree() {\n return this.component.tree || false;\n }\n /**\n * The empty value for this component.\n *\n * @return {null}\n */\n get emptyValue() {\n return null;\n }\n /**\n * Returns if this component has a value set.\n *\n */\n hasValue(data) {\n return !lodash_1.default.isUndefined(lodash_1.default.get(data || this.data, this.key));\n }\n /**\n * Get the data value at the root level.\n *\n * @return {*}\n */\n get rootValue() {\n return this.root ? this.root.data : this.data;\n }\n get rootPristine() {\n return lodash_1.default.get(this, 'root.pristine', false);\n }\n /**\n * Get the static value of this component.\n * @return {*}\n */\n get dataValue() {\n if (!this.key ||\n (!this.visible && this.component.clearOnHide && !this.rootPristine)) {\n return this.emptyValue;\n }\n if (!this.hasValue() && this.shouldAddDefaultValue) {\n const empty = this.component.multiple ? [] : this.emptyValue;\n if (!this.rootPristine) {\n this.dataValue = empty;\n }\n return empty;\n }\n return lodash_1.default.get(this._data, this.key);\n }\n /**\n * Sets the static value of this component.\n *\n * @param value\n */\n set dataValue(value) {\n if (!this.allowData ||\n !this.key ||\n (!this.visible && this.component.clearOnHide && !this.rootPristine)) {\n return;\n }\n if ((value !== null) && (value !== undefined)) {\n value = this.hook('setDataValue', value, this.key, this._data);\n }\n if ((value === null) || (value === undefined)) {\n this.unset();\n return;\n }\n lodash_1.default.set(this._data, this.key, value);\n return;\n }\n /**\n * Splice a value from the dataValue.\n *\n * @param index\n */\n splice(index, flags = {}) {\n if (this.hasValue()) {\n const dataValue = this.dataValue || [];\n if (lodash_1.default.isArray(dataValue) && dataValue.hasOwnProperty(index)) {\n dataValue.splice(index, 1);\n this.dataValue = dataValue;\n this.triggerChange(flags);\n }\n }\n }\n unset() {\n lodash_1.default.unset(this._data, this.key);\n }\n /**\n * Deletes the value of the component.\n */\n deleteValue() {\n this.setValue(null, {\n noUpdateEvent: true,\n noDefault: true\n });\n this.unset();\n }\n getCustomDefaultValue(defaultValue) {\n if (this.component.customDefaultValue && !this.options.preview) {\n defaultValue = this.evaluate(this.component.customDefaultValue, { value: '' }, 'value');\n }\n return defaultValue;\n }\n get shouldAddDefaultValue() {\n return !this.options.noDefaults || (this.component.defaultValue && !this.isEmpty(this.component.defaultValue)) || this.component.customDefaultValue;\n }\n get defaultValue() {\n let defaultValue = this.emptyValue;\n if (this.component.defaultValue) {\n defaultValue = this.component.defaultValue;\n }\n defaultValue = this.getCustomDefaultValue(defaultValue);\n const checkMask = (value) => {\n if (typeof value === 'string') {\n if (this.component.type !== 'textfield') {\n const placeholderChar = this.placeholderChar;\n value = (0, vanilla_text_mask_1.conformToMask)(value, this.defaultMask, { placeholderChar }).conformedValue;\n if (!FormioUtils.matchInputMask(value, this.defaultMask)) {\n value = '';\n }\n }\n }\n else {\n value = '';\n }\n return value;\n };\n if (this.defaultMask) {\n if (Array.isArray(defaultValue)) {\n defaultValue = defaultValue.map(checkMask);\n }\n else {\n defaultValue = checkMask(defaultValue);\n }\n }\n // Clone so that it creates a new instance.\n return lodash_1.default.cloneDeep(defaultValue);\n }\n /**\n * Get the input value of this component.\n *\n * @return {*}\n */\n getValue() {\n if (!this.hasInput || this.viewOnly || !this.refs.input || !this.refs.input.length) {\n return this.dataValue;\n }\n const values = [];\n for (const i in this.refs.input) {\n if (this.refs.input.hasOwnProperty(i)) {\n if (!this.component.multiple) {\n return this.getValueAt(i);\n }\n values.push(this.getValueAt(i));\n }\n }\n if (values.length === 0 && !this.component.multiple) {\n return '';\n }\n return values;\n }\n /**\n * Get the value at a specific index.\n *\n * @param index\n * @returns {*}\n */\n getValueAt(index) {\n const input = this.performInputMapping(this.refs.input[index]);\n return input ? input.value : undefined;\n }\n /**\n * Set the value of this component.\n *\n * @param value\n * @param flags\n *\n * @return {boolean} - If the value changed.\n */\n setValue(value, flags = {}) {\n const changed = this.updateValue(value, flags);\n value = this.dataValue;\n if (!this.hasInput) {\n return changed;\n }\n const isArray = Array.isArray(value);\n const valueInput = this.refs.fileLink || this.refs.input;\n if (isArray &&\n Array.isArray(this.defaultValue) &&\n this.refs.hasOwnProperty('input') &&\n valueInput &&\n (valueInput.length !== value.length) &&\n this.visible) {\n this.redraw();\n }\n if (this.isHtmlRenderMode() && flags && flags.fromSubmission && changed) {\n this.redraw();\n return changed;\n }\n for (const i in this.refs.input) {\n if (this.refs.input.hasOwnProperty(i)) {\n this.setValueAt(i, isArray ? value[i] : value, flags);\n }\n }\n return changed;\n }\n /**\n * Set the value at a specific index.\n *\n * @param index\n * @param value\n */\n setValueAt(index, value, flags = {}) {\n if (!flags.noDefault && (value === null || value === undefined) && !this.component.multiple) {\n value = this.defaultValue;\n }\n const input = this.performInputMapping(this.refs.input[index]);\n const valueMaskInput = this.refs.valueMaskInput;\n if ((valueMaskInput === null || valueMaskInput === void 0 ? void 0 : valueMaskInput.mask) && valueMaskInput.mask.textMaskInputElement) {\n valueMaskInput.mask.textMaskInputElement.update(value);\n }\n if (input.mask && input.mask.textMaskInputElement) {\n input.mask.textMaskInputElement.update(value);\n }\n else if (input.widget && input.widget.setValue) {\n input.widget.setValue(value);\n }\n else {\n input.value = value;\n }\n }\n get hasSetValue() {\n return this.hasValue() && !this.isEmpty(this.dataValue);\n }\n setDefaultValue() {\n if (this.defaultValue && this.shouldAddDefaultValue) {\n const defaultValue = (this.component.multiple && !this.dataValue.length) ? [] : this.defaultValue;\n this.setValue(defaultValue, {\n noUpdateEvent: true\n });\n }\n }\n /**\n * Restore the value of a control.\n */\n restoreValue() {\n if (this.hasSetValue) {\n this.setValue(this.dataValue, {\n noUpdateEvent: true\n });\n }\n else {\n this.setDefaultValue();\n }\n }\n /**\n * Normalize values coming into updateValue.\n *\n * @param value\n * @return {*}\n */\n normalizeValue(value) {\n if (this.component.multiple && !Array.isArray(value)) {\n value = value ? [value] : [];\n }\n return value;\n }\n /**\n * Update a value of this component.\n *\n * @param flags\n */\n updateComponentValue(value, flags = {}) {\n let newValue = (!flags.resetValue && (value === undefined || value === null)) ? this.getValue() : value;\n newValue = this.normalizeValue(newValue, flags);\n const oldValue = this.dataValue;\n let changed = ((newValue !== undefined) ? this.hasChanged(newValue, oldValue) : false);\n if (changed) {\n this.dataValue = newValue;\n changed = this.dataValue !== oldValue;\n this.updateOnChange(flags, changed);\n }\n if (this.componentModal && flags && flags.fromSubmission) {\n this.componentModal.setValue(value);\n }\n return changed;\n }\n /**\n * Updates the value of this component plus all sub-components.\n *\n * @param args\n * @return {boolean}\n */\n updateValue(...args) {\n return this.updateComponentValue(...args);\n }\n getIcon(name, content, styles, ref = 'icon') {\n return this.renderTemplate('icon', {\n className: this.iconClass(name),\n ref,\n styles,\n content\n });\n }\n /**\n * Resets the value of this component.\n */\n resetValue() {\n this.unset();\n this.setValue(this.emptyValue, {\n noUpdateEvent: true,\n noValidate: true,\n resetValue: true\n });\n }\n /**\n * Determine if the value of this component has changed.\n *\n * @param newValue\n * @param oldValue\n * @return {boolean}\n */\n hasChanged(newValue, oldValue) {\n if (((newValue === undefined) || (newValue === null)) &&\n ((oldValue === undefined) || (oldValue === null) || this.isEmpty(oldValue))) {\n return false;\n }\n // If we do not have a value and are getting set to anything other than undefined or null, then we changed.\n if (newValue !== undefined &&\n newValue !== null &&\n this.allowData &&\n !this.hasValue()) {\n return true;\n }\n return !lodash_1.default.isEqual(newValue, oldValue);\n }\n /**\n * Update the value on change.\n *\n * @param flags\n */\n updateOnChange(flags = {}, changed = false) {\n if (!flags.noUpdateEvent && changed) {\n if (flags.fromSubmission) {\n // Reset the errors when a submission has been made and allow it to revalidate.\n this._errors = [];\n }\n this.triggerChange(flags);\n return true;\n }\n return false;\n }\n /**\n * Perform a calculated value operation.\n *\n * @param data - The global data object.\n *\n * @return {boolean} - If the value changed during calculation.\n */\n convertNumberOrBoolToString(value) {\n if (typeof value === 'number' || typeof value === 'boolean') {\n return value.toString();\n }\n return value;\n }\n doValueCalculation(dataValue, data, row) {\n var _a;\n return this.evaluate(this.component.calculateValue, {\n value: dataValue,\n data,\n row: row || this.data,\n submission: ((_a = this.root) === null || _a === void 0 ? void 0 : _a._submission) || {\n data: this.rootValue\n }\n }, 'value');\n }\n /* eslint-disable max-statements */\n calculateComponentValue(data, flags, row) {\n // Skip value calculation for the component if we don't have entire form data set or in builder mode\n if (this.builderMode || lodash_1.default.isUndefined(lodash_1.default.get(this, 'root.data'))) {\n return false;\n }\n // If no calculated value or\n // hidden and set to clearOnHide (Don't calculate a value for a hidden field set to clear when hidden)\n const { clearOnHide } = this.component;\n const shouldBeCleared = !this.visible && clearOnHide;\n const allowOverride = lodash_1.default.get(this.component, 'allowCalculateOverride', false);\n if (shouldBeCleared) {\n // remove calculated value so that the value is recalculated once component becomes visible\n if (this.hasOwnProperty('calculatedValue') && allowOverride) {\n lodash_1.default.unset(this, 'calculatedValue');\n }\n return false;\n }\n // Handle all cases when calculated values should not fire.\n if ((this.options.readOnly && !this.options.pdf && !this.component.calculateValue) ||\n !(this.component.calculateValue || this.component.calculateValueVariable) ||\n (this.options.server && !this.component.calculateServer) ||\n (flags.dataSourceInitialLoading && allowOverride)) {\n return false;\n }\n const dataValue = this.dataValue;\n // Calculate the new value.\n let calculatedValue = this.doValueCalculation(dataValue, data, row, flags);\n if (this.options.readOnly && dataValue && !calculatedValue) {\n return false;\n }\n if (lodash_1.default.isNil(calculatedValue)) {\n calculatedValue = this.emptyValue;\n }\n const changed = !lodash_1.default.isEqual(dataValue, calculatedValue);\n // Do not override calculations on server if they have calculateServer set.\n if (allowOverride) {\n // The value is considered locked if it is not empty and comes from a submission value.\n const fromSubmission = (flags.fromSubmission && this.component.persistent === true);\n if (this.isEmpty(dataValue)) {\n // Reset the calculation lock if ever the data is cleared.\n this.calculationLocked = false;\n }\n else if (this.calculationLocked || fromSubmission) {\n this.calculationLocked = true;\n return false;\n }\n const firstPass = (this.calculatedValue === undefined) || flags.resetValue;\n if (firstPass) {\n this.calculatedValue = null;\n }\n const newCalculatedValue = this.normalizeValue(this.convertNumberOrBoolToString(calculatedValue));\n const previousCalculatedValue = this.normalizeValue(this.convertNumberOrBoolToString(this.calculatedValue));\n const normalizedDataValue = this.normalizeValue(this.convertNumberOrBoolToString(dataValue));\n const calculationChanged = !lodash_1.default.isEqual(previousCalculatedValue, newCalculatedValue);\n const previousChanged = !lodash_1.default.isEqual(normalizedDataValue, previousCalculatedValue);\n if (calculationChanged && previousChanged && !firstPass) {\n return false;\n }\n // Check to ensure that the calculated value is different than the previously calculated value.\n if (previousCalculatedValue && previousChanged && !calculationChanged) {\n this.calculatedValue = null;\n return false;\n }\n if (flags.isReordered || !calculationChanged) {\n return false;\n }\n if (fromSubmission) {\n // If we set value from submission and it differs from calculated one, set the calculated value to prevent overriding dataValue in the next pass\n this.calculatedValue = (0, utils_1.fastCloneDeep)(calculatedValue);\n return false;\n }\n // If this is the firstPass, and the dataValue is different than to the calculatedValue.\n if (firstPass && !this.isEmpty(dataValue) && changed && calculationChanged) {\n // Return that we have a change so it will perform another pass.\n return true;\n }\n }\n this.calculatedValue = (0, utils_1.fastCloneDeep)(calculatedValue);\n if (changed) {\n if (!flags.noPristineChangeOnModified) {\n this.pristine = false;\n }\n flags.triggeredComponentId = this.id;\n return this.setValue(calculatedValue, flags);\n }\n return false;\n }\n /* eslint-enable max-statements */\n /**\n * Performs calculations in this component plus any child components.\n *\n * @param args\n * @return {boolean}\n */\n calculateValue(data, flags, row) {\n data = data || this.rootValue;\n flags = flags || {};\n row = row || this.data;\n return this.calculateComponentValue(data, flags, row);\n }\n /**\n * Get this component's label text.\n *\n */\n get label() {\n return this.component.label;\n }\n /**\n * Set this component's label text and render it.\n *\n * @param value - The new label text.\n */\n set label(value) {\n this.component.label = value;\n if (this.labelElement) {\n this.labelElement.innerText = value;\n }\n }\n /**\n * Get FormioForm element at the root of this component tree.\n *\n */\n getRoot() {\n return this.root;\n }\n /**\n * Returns the invalid message, or empty string if the component is valid.\n *\n * @param data\n * @param dirty\n * @return {*}\n */\n invalidMessage(data, dirty, ignoreCondition, row) {\n if (!ignoreCondition && !this.checkCondition(row, data)) {\n return '';\n }\n // See if this is forced invalid.\n if (this.invalid) {\n return this.invalid;\n }\n // No need to check for errors if there is no input or if it is pristine.\n if (!this.hasInput || (!dirty && this.pristine)) {\n return '';\n }\n const validationScope = { errors: [] };\n (0, process_1.processOneSync)({\n component: this.component,\n data,\n row,\n path: this.path || this.component.key,\n scope: validationScope,\n instance: this,\n processors: [\n process_1.validateProcessInfo\n ]\n });\n const errors = validationScope.errors;\n const interpolatedErrors = FormioUtils.interpolateErrors(this.component, errors, this.t.bind(this));\n return lodash_1.default.map(interpolatedErrors, 'message').join('\\n\\n');\n }\n /**\n * Returns if the component is valid or not.\n *\n * @param data\n * @param dirty\n * @return {boolean}\n */\n isValid(data, dirty) {\n return !this.invalidMessage(data, dirty);\n }\n setComponentValidity(errors, dirty, silentCheck) {\n if (silentCheck) {\n return [];\n }\n const messages = errors.filter(message => !message.fromServer);\n if (errors.length && !!messages.length && (!this.isEmpty(this.defaultValue) || dirty || !this.pristine)) {\n return this.setCustomValidity(messages, dirty);\n }\n else {\n return this.setCustomValidity('');\n }\n }\n /**\n * Interpolate errors from the validation methods.\n * @param {*} errors\n * @returns\n */\n interpolateErrors(errors) {\n var _a;\n const interpolatedErrors = FormioUtils.interpolateErrors(this.component, errors, this.t.bind(this));\n return ((_a = this.serverErrors) === null || _a === void 0 ? void 0 : _a.length) ? [...interpolatedErrors, ...this.serverErrors] : interpolatedErrors;\n }\n /**\n * Show component validation errors.\n * @param {*} errors - An array of errors that have occured.\n * @param {*} data - The root submission data.\n * @param {*} row - The contextual row data.\n * @param {*} flags - The flags to perform validation.\n * @returns\n */\n showValidationErrors(errors, data, row, flags) {\n if (flags.silentCheck) {\n return [];\n }\n if (this.options.alwaysDirty) {\n flags.dirty = true;\n }\n if (flags.fromSubmission && this.hasValue(data)) {\n flags.dirty = true;\n }\n this.setDirty(flags.dirty);\n return this.setComponentValidity(errors, flags.dirty, flags.silentCheck, flags.fromSubmission);\n }\n /**\n * Perform a component validation.\n * @param {*} data - The root data you wish to use for this component.\n * @param {*} row - The contextual row data you wish to use for this component.\n * @param {*} flags - The flags to control the behavior of the validation.\n * @returns\n */\n validateComponent(data, row, flags = {}) {\n data = data || this.rootValue;\n row = row || this.data;\n const { async = false } = flags;\n if (this.shouldSkipValidation(data, row, flags)) {\n return async ? Promise.resolve([]) : [];\n }\n const processContext = {\n component: this.component,\n data,\n row,\n value: this.validationValue,\n path: this.path || this.component.key,\n instance: this,\n scope: { errors: [] },\n processors: [\n process_1.validateProcessInfo\n ]\n };\n if (async) {\n return (0, process_1.processOne)(processContext).then(() => {\n this._errors = this.interpolateErrors(processContext.scope.errors);\n return this._errors;\n });\n }\n (0, process_1.processOneSync)(processContext);\n this._errors = this.interpolateErrors(processContext.scope.errors);\n return this._errors;\n }\n /**\n * Checks the validity of this component and sets the error message if it is invalid.\n *\n * @param data\n * @param dirty\n * @param row\n * @return {boolean}\n */\n checkComponentValidity(data, dirty, row, flags = {}, allErrors = []) {\n data = data || this.rootValue;\n row = row || this.data;\n flags.dirty = dirty || false;\n if (flags.async) {\n return this.validateComponent(data, row, flags).then((errors) => {\n allErrors.push(...errors);\n if (this.parent && this.parent.childErrors) {\n if (errors.length) {\n this.parent.childErrors.push(...errors);\n }\n else {\n lodash_1.default.remove(this.parent.childErrors, (err) => err.component.key === this.component.key);\n }\n }\n this.showValidationErrors(errors, data, row, flags);\n return errors.length === 0;\n });\n }\n else {\n const errors = this.validateComponent(data, row, flags);\n this.showValidationErrors(errors, data, row, flags);\n allErrors.push(...errors);\n if (this.parent && this.parent.childErrors) {\n if (errors.length) {\n this.parent.childErrors.push(...errors);\n }\n else {\n lodash_1.default.remove(this.parent.childErrors, (err) => err.component.key === this.component.key);\n }\n }\n return errors.length === 0;\n }\n }\n /**\n * Checks the validity of the component.\n * @param {*} data\n * @param {*} dirty\n * @param {*} row\n * @param {*} silentCheck\n * @returns\n */\n checkValidity(data, dirty, row, silentCheck, errors = []) {\n data = data || this.rootValue;\n row = row || this.data;\n console.log('Deprecation warning: Component.checkValidity() will be deprecated in 6.x version of renderer. Use Component.validateComponent instead.');\n return this.checkComponentValidity(data, dirty, row, { silentCheck }, errors);\n }\n checkAsyncValidity(data, dirty, row, silentCheck, errors = []) {\n console.log('Deprecation warning: Component.checkAsyncValidity() will be deprecated in 6.x version of renderer. Use Component.validateComponent instead.');\n return this.checkComponentValidity(data, dirty, row, { async: true, silentCheck }, errors);\n }\n /**\n * Check the conditions, calculations, and validity of a single component and triggers an update if\n * something changed.\n *\n * @param data - The root data of the change event.\n * @param flags - The flags from this change event.\n *\n * @return boolean - If component is valid or not.\n */\n checkData(data, flags, row) {\n data = data || this.rootValue;\n flags = flags || {};\n row = row || this.data;\n // Needs for Nextgen Rules Engine\n this.resetCaches();\n // Do not trigger refresh if change was triggered on blur event since components with Refresh on Blur have their own listeners\n if (!flags.fromBlur) {\n this.checkRefreshOn(flags.changes, flags);\n }\n if (flags.noCheck) {\n return true;\n }\n this.checkComponentConditions(data, flags, row);\n if (this.id !== flags.triggeredComponentId) {\n this.calculateComponentValue(data, flags, row);\n }\n }\n checkModal(errors = [], dirty = false) {\n const messages = errors.filter(error => !error.fromServer);\n const isValid = errors.length === 0;\n if (!this.component.modalEdit || !this.componentModal) {\n return;\n }\n if (dirty && !isValid) {\n this.setErrorClasses([this.refs.openModal], dirty, !isValid, !!messages.length, this.refs.openModalWrapper);\n }\n else {\n this.clearErrorClasses(this.refs.openModalWrapper);\n }\n }\n get validationValue() {\n return this.dataValue;\n }\n isEmpty(value = this.dataValue) {\n const isEmptyArray = (lodash_1.default.isArray(value) && value.length === 1) ? lodash_1.default.isEqual(value[0], this.emptyValue) : false;\n return value == null || value.length === 0 || lodash_1.default.isEqual(value, this.emptyValue) || isEmptyArray;\n }\n isEqual(valueA, valueB = this.dataValue) {\n return (this.isEmpty(valueA) && this.isEmpty(valueB)) || lodash_1.default.isEqual(valueA, valueB);\n }\n /**\n * Check if a component is eligible for multiple validation\n *\n * @return {boolean}\n */\n validateMultiple() {\n return true;\n }\n clearErrorClasses(element = this.element) {\n this.removeClass(element, this.options.componentErrorClass);\n this.removeClass(element, 'alert alert-danger');\n this.removeClass(element, 'has-error');\n this.removeClass(element, 'has-message');\n }\n setInputWidgetErrorClasses(inputRefs, hasErrors) {\n if (!this.isInputComponent || !this.component.widget || !(inputRefs === null || inputRefs === void 0 ? void 0 : inputRefs.length)) {\n return;\n }\n inputRefs.forEach((input) => {\n if ((input === null || input === void 0 ? void 0 : input.widget) && input.widget.setErrorClasses) {\n input.widget.setErrorClasses(hasErrors);\n }\n });\n }\n addFocusBlurEvents(element) {\n this.addEventListener(element, 'focus', () => {\n if (this.root.focusedComponent !== this) {\n if (this.root.pendingBlur) {\n this.root.pendingBlur();\n }\n this.root.focusedComponent = this;\n this.emit('focus', this);\n }\n else if (this.root.focusedComponent === this && this.root.pendingBlur) {\n this.root.pendingBlur.cancel();\n this.root.pendingBlur = null;\n }\n });\n this.addEventListener(element, 'blur', () => {\n this.root.pendingBlur = FormioUtils.delay(() => {\n this.emit('blur', this);\n if (this.component.validateOn === 'blur') {\n this.root.triggerChange({ fromBlur: true }, {\n instance: this,\n component: this.component,\n value: this.dataValue,\n flags: { fromBlur: true }\n });\n }\n this.root.focusedComponent = null;\n this.root.pendingBlur = null;\n });\n });\n }\n // eslint-disable-next-line max-statements\n setCustomValidity(messages, dirty, external) {\n const inputRefs = this.isInputComponent ? this.refs.input || [] : null;\n if (typeof messages === 'string' && messages) {\n messages = {\n level: 'error',\n message: messages,\n component: this.component,\n };\n }\n if (!Array.isArray(messages)) {\n if (messages) {\n messages = [messages];\n }\n else {\n messages = [];\n }\n }\n const errors = messages.filter(message => message.level === 'error');\n let invalidInputRefs = inputRefs;\n // Filter the invalid input refs in multiple components\n if (this.component.multiple) {\n const refsArray = Array.from(inputRefs);\n refsArray.forEach((input) => {\n this.setElementInvalid(this.performInputMapping(input), false);\n });\n this.setInputWidgetErrorClasses(refsArray, false);\n invalidInputRefs = refsArray.filter((ref, index) => {\n var _a;\n return (_a = messages.some) === null || _a === void 0 ? void 0 : _a.call(messages, (msg) => {\n var _a;\n return ((_a = msg === null || msg === void 0 ? void 0 : msg.context) === null || _a === void 0 ? void 0 : _a.index) === index;\n });\n });\n }\n if (messages.length) {\n if (this.refs.messageContainer) {\n this.empty(this.refs.messageContainer);\n }\n this.emit('componentError', {\n instance: this,\n component: this.component,\n message: messages[0].message,\n messages,\n external: !!external,\n });\n this.addMessages(messages, dirty, invalidInputRefs);\n if (invalidInputRefs) {\n this.setErrorClasses(invalidInputRefs, dirty, !!errors.length, !!messages.length);\n }\n }\n else if (!errors.length || (errors[0].external === !!external)) {\n if (this.refs.messageContainer) {\n this.empty(this.refs.messageContainer);\n }\n if (this.refs.modalMessageContainer) {\n this.empty(this.refs.modalMessageContainer);\n }\n if (invalidInputRefs) {\n this.setErrorClasses(invalidInputRefs, dirty, !!errors.length, !!messages.length);\n }\n this.clearErrorClasses();\n }\n this._visibleErrors = messages;\n return messages;\n }\n /**\n * Determines if the value of this component is hidden from the user as if it is coming from the server, but is\n * protected.\n *\n * @return {boolean|*}\n */\n isValueHidden() {\n if (this.component.protected && this.root.editing) {\n return false;\n }\n if (!this.root || !this.root.hasOwnProperty('editing')) {\n return false;\n }\n if (!this.root || !this.root.editing) {\n return false;\n }\n return (this.component.protected || !this.component.persistent || (this.component.persistent === 'client-only'));\n }\n shouldSkipValidation(data, row, flags = {}) {\n const { validateWhenHidden = false } = this.component || {};\n const forceValidOnHidden = (!this.visible || !this.checkCondition(row, data)) && !validateWhenHidden;\n if (forceValidOnHidden) {\n // If this component is forced valid when it is hidden, then we also need to reset the errors for this component.\n this._errors = [];\n }\n const rules = [\n // Do not validate if the flags say not too.\n () => flags.noValidate,\n // Force valid if component is read-only\n () => this.options.readOnly,\n // Do not check validations if component is not an input component.\n () => !this.hasInput,\n // Check to see if we are editing and if so, check component persistence.\n () => this.isValueHidden(),\n // Force valid if component is hidden.\n () => forceValidOnHidden\n ];\n return rules.some(pred => pred());\n }\n // Maintain reverse compatibility.\n whenReady() {\n console.warn('The whenReady() method has been deprecated. Please use the dataReady property instead.');\n return this.dataReady;\n }\n get dataReady() {\n return Promise.resolve();\n }\n /**\n * Prints out the value of this component as a string value.\n */\n asString(value) {\n value = value || this.getValue();\n return (Array.isArray(value) ? value : [value]).map(lodash_1.default.toString).join(', ');\n }\n /**\n * Return if the component is disabled.\n * @return {boolean}\n */\n get disabled() {\n return this._disabled || this.parentDisabled;\n }\n /**\n * Disable this component.\n *\n * @param {boolean} disabled\n */\n set disabled(disabled) {\n this._disabled = disabled;\n }\n setDisabled(element, disabled) {\n if (!element) {\n return;\n }\n element.disabled = disabled;\n if (disabled) {\n element.setAttribute('disabled', 'disabled');\n }\n else {\n element.removeAttribute('disabled');\n }\n }\n setLoading(element, loading) {\n if (!element || (element.loading === loading)) {\n return;\n }\n element.loading = loading;\n if (!element.loader && loading) {\n element.loader = this.ce('i', {\n class: `${this.iconClass('refresh', true)} button-icon-right`\n });\n }\n if (element.loader) {\n if (loading) {\n this.appendTo(element.loader, element);\n }\n else {\n this.removeChildFrom(element.loader, element);\n }\n }\n }\n selectOptions(select, tag, options, defaultValue) {\n lodash_1.default.each(options, (option) => {\n const attrs = {\n value: option.value\n };\n if (defaultValue !== undefined && (option.value === defaultValue)) {\n attrs.selected = 'selected';\n }\n const optionElement = this.ce('option', attrs);\n optionElement.appendChild(this.text(option.label));\n select.appendChild(optionElement);\n });\n }\n setSelectValue(select, value) {\n const options = select.querySelectorAll('option');\n lodash_1.default.each(options, (option) => {\n if (option.value === value) {\n option.setAttribute('selected', 'selected');\n }\n else {\n option.removeAttribute('selected');\n }\n });\n if (select.onchange) {\n select.onchange();\n }\n if (select.onselect) {\n select.onselect();\n }\n }\n getRelativePath(path) {\n const keyPart = `.${this.key}`;\n const thisPath = this.isInputComponent ? this.path\n : this.path.slice(0).replace(keyPart, '');\n return path.replace(thisPath, '');\n }\n clear() {\n this.detach();\n this.empty(this.getElement());\n }\n append(element) {\n this.appendTo(element, this.element);\n }\n prepend(element) {\n this.prependTo(element, this.element);\n }\n removeChild(element) {\n this.removeChildFrom(element, this.element);\n }\n detachLogic() {\n this.logic.forEach(logic => {\n if (logic.trigger.type === 'event') {\n const event = this.interpolate(logic.trigger.event);\n this.off(event); // only applies to callbacks on this component\n }\n });\n }\n attachLogic() {\n // Do not attach logic during builder mode.\n if (this.builderMode) {\n return;\n }\n this.logic.forEach((logic) => {\n if (logic.trigger.type === 'event') {\n const event = this.interpolate(logic.trigger.event);\n this.on(event, (...args) => {\n const newComponent = (0, utils_1.fastCloneDeep)(this.originalComponent);\n if (this.applyActions(newComponent, logic.actions, args)) {\n // If component definition changed, replace it.\n if (!lodash_1.default.isEqual(this.component, newComponent)) {\n this.component = newComponent;\n const visible = this.conditionallyVisible(null, null);\n const disabled = this.shouldDisabled;\n // Change states which won't be recalculated during redrawing\n if (this.visible !== visible) {\n this.visible = visible;\n }\n if (this.disabled !== disabled) {\n this.disabled = disabled;\n }\n this.redraw();\n }\n }\n }, true);\n }\n });\n }\n /**\n * Get the element information.\n */\n elementInfo() {\n const attributes = {\n name: this.options.name,\n type: this.component.inputType || 'text',\n class: 'form-control',\n lang: this.options.language\n };\n if (this.component.placeholder) {\n attributes.placeholder = this.t(this.component.placeholder, { _userInput: true });\n }\n if (this.component.tabindex) {\n attributes.tabindex = this.component.tabindex;\n }\n if (this.disabled) {\n attributes.disabled = 'disabled';\n }\n lodash_1.default.defaults(attributes, this.component.attributes);\n return {\n type: 'input',\n component: this.component,\n changeEvent: 'change',\n attr: attributes\n };\n }\n autofocus() {\n const hasAutofocus = this.component.autofocus && !this.builderMode && !this.options.preview;\n if (hasAutofocus) {\n this.on('render', () => this.focus(), true);\n }\n }\n scrollIntoView(element = this.element) {\n if (!element) {\n return;\n }\n const { left, top } = element.getBoundingClientRect();\n window.scrollTo(left + window.scrollX, top + window.scrollY);\n }\n focus(index) {\n var _a, _b;\n if ('beforeFocus' in this.parent) {\n this.parent.beforeFocus(this);\n }\n if ((_a = this.refs.input) === null || _a === void 0 ? void 0 : _a.length) {\n const focusingInput = typeof index === 'number' && this.refs.input[index]\n ? this.refs.input[index]\n : this.refs.input[this.refs.input.length - 1];\n if (((_b = this.component.widget) === null || _b === void 0 ? void 0 : _b.type) === 'calendar') {\n const sibling = focusingInput.nextSibling;\n if (sibling) {\n sibling.focus();\n }\n }\n else {\n focusingInput.focus();\n }\n }\n if (this.refs.openModal) {\n this.refs.openModal.focus();\n }\n if (this.parent.refs.openModal) {\n this.parent.refs.openModal.focus();\n }\n }\n /**\n * Get `Formio` instance for working with files\n */\n get fileService() {\n if (this.options.fileService) {\n return this.options.fileService;\n }\n if (this.options.formio) {\n return this.options.formio;\n }\n if (this.root && this.root.formio) {\n return this.root.formio;\n }\n const formio = new Formio_1.Formio();\n // If a form is loaded, then make sure to set the correct formUrl.\n if (this.root && this.root._form && this.root._form._id) {\n formio.formUrl = `${formio.projectUrl}/form/${this.root._form._id}`;\n }\n return formio;\n }\n resetCaches() { }\n get previewMode() {\n return false;\n }\n}\nexports[\"default\"] = Component;\nComponent.externalLibraries = {};\nComponent.requireLibrary = function (name, property, src, polling) {\n if (!Component.externalLibraries.hasOwnProperty(name)) {\n Component.externalLibraries[name] = {};\n Component.externalLibraries[name].ready = new Promise((resolve, reject) => {\n Component.externalLibraries[name].resolve = resolve;\n Component.externalLibraries[name].reject = reject;\n });\n const callbackName = `${name}Callback`;\n if (!polling && !window[callbackName]) {\n window[callbackName] = function () {\n this.resolve();\n }.bind(Component.externalLibraries[name]);\n }\n // See if the plugin already exists.\n const plugin = (0, utils_1.getScriptPlugin)(property);\n if (plugin) {\n Component.externalLibraries[name].resolve(plugin);\n }\n else {\n src = Array.isArray(src) ? src : [src];\n src.forEach((lib) => {\n let attrs = {};\n let elementType = '';\n if (typeof lib === 'string') {\n lib = {\n type: 'script',\n src: lib\n };\n }\n switch (lib.type) {\n case 'script':\n elementType = 'script';\n attrs = {\n src: lib.src,\n type: 'text/javascript',\n defer: true,\n async: true\n };\n break;\n case 'styles':\n elementType = 'link';\n attrs = {\n href: lib.src,\n rel: 'stylesheet'\n };\n break;\n }\n // Add the script to the top page.\n const script = document.createElement(elementType);\n for (const attr in attrs) {\n script.setAttribute(attr, attrs[attr]);\n }\n document.getElementsByTagName('head')[0].appendChild(script);\n });\n // if no callback is provided, then check periodically for the script.\n if (polling) {\n setTimeout(function checkLibrary() {\n const plugin = (0, utils_1.getScriptPlugin)(property);\n if (plugin) {\n Component.externalLibraries[name].resolve(plugin);\n }\n else {\n // check again after 200 ms.\n setTimeout(checkLibrary, 200);\n }\n }, 200);\n }\n }\n }\n return Component.externalLibraries[name].ready;\n};\nComponent.libraryReady = function (name) {\n if (Component.externalLibraries.hasOwnProperty(name) &&\n Component.externalLibraries[name].ready) {\n return Component.externalLibraries[name].ready;\n }\n return Promise.reject(`${name} library was not required.`);\n};\n\n\n//# sourceURL=webpack://Formio/./lib/cjs/components/_classes/component/Component.js?");
|
|
5328
|
+
eval("\nvar __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n var desc = Object.getOwnPropertyDescriptor(m, k);\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\n desc = { enumerable: true, get: function() { return m[k]; } };\n }\n Object.defineProperty(o, k2, desc);\n}) : (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n o[k2] = m[k];\n}));\nvar __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\n}) : function(o, v) {\n o[\"default\"] = v;\n});\nvar __importStar = (this && this.__importStar) || function (mod) {\n if (mod && mod.__esModule) return mod;\n var result = {};\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\n __setModuleDefault(result, mod);\n return result;\n};\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\n/* globals Quill, ClassicEditor, CKEDITOR */\nconst vanilla_text_mask_1 = __webpack_require__(/*! @formio/vanilla-text-mask */ \"./node_modules/@formio/vanilla-text-mask/dist/vanillaTextMask.js\");\nconst tippy_js_1 = __importDefault(__webpack_require__(/*! tippy.js */ \"./node_modules/tippy.js/dist/tippy.esm.js\"));\nconst lodash_1 = __importDefault(__webpack_require__(/*! lodash */ \"./node_modules/lodash/lodash.js\"));\nconst ismobilejs_1 = __importDefault(__webpack_require__(/*! ismobilejs */ \"./node_modules/ismobilejs/esm/index.js\"));\nconst process_1 = __webpack_require__(/*! @formio/core/process */ \"./node_modules/@formio/core/lib/process/index.js\");\nconst Formio_1 = __webpack_require__(/*! ../../../Formio */ \"./lib/cjs/Formio.js\");\nconst FormioUtils = __importStar(__webpack_require__(/*! ../../../utils/utils */ \"./lib/cjs/utils/utils.js\"));\nconst utils_1 = __webpack_require__(/*! ../../../utils/utils */ \"./lib/cjs/utils/utils.js\");\nconst Element_1 = __importDefault(__webpack_require__(/*! ../../../Element */ \"./lib/cjs/Element.js\"));\nconst ComponentModal_1 = __importDefault(__webpack_require__(/*! ../componentModal/ComponentModal */ \"./lib/cjs/components/_classes/componentModal/ComponentModal.js\"));\nconst widgets_1 = __importDefault(__webpack_require__(/*! ../../../widgets */ \"./lib/cjs/widgets/index.js\"));\nconst addons_1 = __importDefault(__webpack_require__(/*! ../../../addons */ \"./lib/cjs/addons/index.js\"));\nconst uploadAdapter_1 = __webpack_require__(/*! ../../../providers/storage/uploadAdapter */ \"./lib/cjs/providers/storage/uploadAdapter.js\");\nconst en_1 = __importDefault(__webpack_require__(/*! ../../../translations/en */ \"./lib/cjs/translations/en.js\"));\nconst Templates_1 = __importDefault(__webpack_require__(/*! ../../../templates/Templates */ \"./lib/cjs/templates/Templates.js\"));\nconst isIEBrowser = FormioUtils.getBrowserInfo().ie;\n/**\n * This is the Component class\n which all elements within the FormioForm derive from.\n */\nclass Component extends Element_1.default {\n static schema(...sources) {\n return lodash_1.default.merge({\n /**\n * Determines if this component provides an input.\n */\n input: true,\n /**\n * The data key for this component (how the data is stored in the database).\n */\n key: '',\n /**\n * The input placeholder for this component.\n */\n placeholder: '',\n /**\n * The input prefix\n */\n prefix: '',\n /**\n * The custom CSS class to provide to this component.\n */\n customClass: '',\n /**\n * The input suffix.\n */\n suffix: '',\n /**\n * If this component should allow an array of values to be captured.\n */\n multiple: false,\n /**\n * The default value of this component.\n */\n defaultValue: null,\n /**\n * If the data of this component should be protected (no GET api requests can see the data)\n */\n protected: false,\n /**\n * Validate if the value of this component should be unique within the form.\n */\n unique: false,\n /**\n * If the value of this component should be persisted within the backend api database.\n */\n persistent: true,\n /**\n * Determines if the component should be within the form, but not visible.\n */\n hidden: false,\n /**\n * If the component should be cleared when hidden.\n */\n clearOnHide: true,\n /**\n * This will refresh this component options when this field changes.\n */\n refreshOn: '',\n /**\n * This will redraw the component when this field changes.\n */\n redrawOn: '',\n /**\n * If this component should be included as a column within a submission table.\n */\n tableView: false,\n /**\n * If this component should be rendering in modal.\n */\n modalEdit: false,\n /**\n * The input label provided to this component.\n */\n label: '',\n dataGridLabel: false,\n labelPosition: 'top',\n description: '',\n errorLabel: '',\n tooltip: '',\n hideLabel: false,\n tabindex: '',\n disabled: false,\n autofocus: false,\n dbIndex: false,\n customDefaultValue: '',\n calculateValue: '',\n calculateServer: false,\n widget: null,\n /**\n * Attributes that will be assigned to the input elements of this component.\n */\n attributes: {},\n /**\n * This will perform the validation on either \"change\" or \"blur\" of the input element.\n */\n validateOn: 'change',\n /**\n * The validation criteria for this component.\n */\n validate: {\n /**\n * If this component is required.\n */\n required: false,\n /**\n * Custom JavaScript validation.\n */\n custom: '',\n /**\n * If the custom validation should remain private (only the backend will see it and execute it).\n */\n customPrivate: false,\n /**\n * If this component should implement a strict date validation if the Calendar widget is implemented.\n */\n strictDateValidation: false,\n multiple: false,\n unique: false\n },\n /**\n * The simple conditional settings for a component.\n */\n conditional: {\n show: null,\n when: null,\n eq: ''\n },\n overlay: {\n style: '',\n left: '',\n top: '',\n width: '',\n height: '',\n },\n allowCalculateOverride: false,\n encrypted: false,\n showCharCount: false,\n showWordCount: false,\n properties: {},\n allowMultipleMasks: false,\n addons: [],\n }, ...sources);\n }\n /**\n * Return the simple condition settings as part of the component.\n *\n * @return {Object}\n *\n */\n static get conditionOperatorsSettings() {\n return {\n operators: ['isEqual', 'isNotEqual', 'isEmpty', 'isNotEmpty'],\n valueComponent() {\n return {\n type: 'textfield',\n widget: {\n type: 'input'\n }\n };\n }\n };\n }\n /**\n * Return the array of possible types of component value absed on its schema.\n *\n * @param schema\n * @return {Array}\n *\n */\n static savedValueTypes(schema) {\n schema = schema || {};\n return FormioUtils.getComponentSavedTypes(schema) || [FormioUtils.componentValueTypes.any];\n }\n /**\n * Provides a table view for this component. Override if you wish to do something different than using getView\n * method of your instance.\n *\n * @param value\n * @param options\n */\n /* eslint-disable no-unused-vars */\n static tableView(value, options) { }\n /* eslint-enable no-unused-vars */\n /**\n * Initialize a new Component.\n *\n * @param {Object} component - The component JSON you wish to initialize.\n * @param {Object} options - The options for this component.\n * @param {Object} data - The global data submission object this component will belong.\n */\n /* eslint-disable max-statements */\n constructor(component, options, data) {\n super(Object.assign({\n renderMode: 'form',\n attachMode: 'full',\n noDefaults: false\n }, options || {}));\n // Restore the component id.\n if (component && component.id) {\n this.id = component.id;\n }\n /**\n * Determines if this component has a condition assigned to it.\n * @type {null}\n * @private\n */\n this._hasCondition = null;\n /**\n * References to dom elements\n */\n this.refs = {};\n // Allow global override for any component JSON.\n if (component &&\n this.options.components &&\n this.options.components[component.type]) {\n lodash_1.default.merge(component, this.options.components[component.type]);\n }\n /**\n * The data path to this specific component instance.\n *\n * @type {string}\n */\n this.path = (component === null || component === void 0 ? void 0 : component.key) || '';\n /**\n * An array of all the children components errors.\n */\n this.childErrors = [];\n /**\n * Last validation errors that have occured.\n */\n this._errors = [];\n this._visibleErrors = [];\n /**\n * The Form.io component JSON schema.\n * @type {*}\n */\n this.component = this.mergeSchema(component || {});\n // Add the id to the component.\n this.component.id = this.id;\n this.afterComponentAssign();\n // Save off the original component to be used in logic.\n this.originalComponent = (0, utils_1.fastCloneDeep)(this.component);\n /**\n * If the component has been attached\n */\n this.attached = false;\n /**\n * If the component has been rendered\n */\n this.rendered = false;\n /**\n * The data object in which this component resides.\n * @type {*}\n */\n this._data = data || {};\n /**\n * Tool tip text after processing\n * @type {string}\n */\n this.tooltip = '';\n /**\n * The row path of this component.\n * @type {number}\n */\n this.row = this.options.row;\n /**\n * Points to a flat map of child components (if applicable).\n *\n * @type {Object}\n */\n this.childComponentsMap = {};\n /**\n * Determines if this component is disabled, or not.\n *\n * @type {boolean}\n */\n this._disabled = (0, utils_1.boolValue)(this.component.disabled) ? this.component.disabled : false;\n /**\n * Points to the root component, usually the FormComponent.\n *\n * @type {Component}\n */\n this.root = this.options.root || this;\n this.localRoot = this.options.localRoot || this;\n /**\n * If this input has been input and provided value.\n *\n * @type {boolean}\n */\n this.pristine = true;\n /**\n * Points to the parent component.\n *\n * @type {Component}\n */\n this.parent = this.options.parent;\n this.options.name = this.options.name || 'data';\n this._path = '';\n // Needs for Nextgen Rules Engine\n this.resetCaches();\n /**\n * Determines if this component is visible, or not.\n */\n this._parentVisible = this.options.hasOwnProperty('parentVisible') ? this.options.parentVisible : true;\n this._visible = this._parentVisible && this.conditionallyVisible(null, data);\n this._parentDisabled = false;\n /**\n * The reference attribute name for this component\n */\n this._referenceAttributeName = 'ref';\n /**\n * Used to trigger a new change in this component.\n * @type {function} - Call to trigger a change in this component.\n */\n let changes = [];\n let lastChanged = null;\n let triggerArgs = [];\n const _triggerChange = lodash_1.default.debounce((...args) => {\n if (this.root) {\n this.root.changing = false;\n }\n triggerArgs = [];\n if (!args[1] && lastChanged) {\n // Set the changed component if one isn't provided.\n args[1] = lastChanged;\n }\n if (lodash_1.default.isEmpty(args[0]) && lastChanged) {\n // Set the flags if it is empty and lastChanged exists.\n args[0] = lastChanged.flags;\n }\n lastChanged = null;\n args[3] = changes;\n const retVal = this.onChange(...args);\n changes = [];\n return retVal;\n }, 100);\n this.triggerChange = (...args) => {\n if (args[1]) {\n // Make sure that during the debounce that we always track lastChanged component, even if they\n // don't provide one later.\n lastChanged = args[1];\n changes.push(lastChanged);\n }\n if (this.root) {\n this.root.changing = true;\n }\n if (args.length) {\n triggerArgs = args;\n }\n return _triggerChange(...triggerArgs);\n };\n /**\n * Used to trigger a redraw event within this component.\n *\n * @type {Function}\n */\n this.triggerRedraw = lodash_1.default.debounce(this.redraw.bind(this), 100);\n /**\n * list of attached tooltips\n * @type {Array}\n */\n this.tooltips = [];\n /**\n * List of attached addons\n * @type {Array}\n */\n this.addons = [];\n // To force this component to be invalid.\n this.invalid = false;\n if (this.component) {\n this.type = this.component.type;\n if (this.allowData && this.key) {\n this.options.name += `[${this.key}]`;\n // If component is visible or not set to clear on hide, set the default value.\n if (this.visible || !this.component.clearOnHide) {\n if (!this.hasValue()) {\n if (this.shouldAddDefaultValue) {\n this.dataValue = this.defaultValue;\n }\n }\n else {\n // Ensure the dataValue is set.\n /* eslint-disable no-self-assign */\n this.dataValue = this.dataValue;\n /* eslint-enable no-self-assign */\n }\n }\n }\n /**\n * The element information for creating the input element.\n * @type {*}\n */\n this.info = this.elementInfo();\n }\n // Allow anyone to hook into the component creation.\n this.hook('component');\n if (!this.options.skipInit) {\n this.init();\n }\n }\n /* eslint-enable max-statements */\n get componentsMap() {\n var _a;\n if ((_a = this.localRoot) === null || _a === void 0 ? void 0 : _a.childComponentsMap) {\n return this.localRoot.childComponentsMap;\n }\n const localMap = {};\n localMap[this.path] = this;\n return localMap;\n }\n get data() {\n return this._data;\n }\n set data(value) {\n this._data = value;\n }\n mergeSchema(component = {}) {\n return lodash_1.default.defaultsDeep(component, this.defaultSchema);\n }\n // Allow componets to notify when ready.\n get ready() {\n return Promise.resolve(this);\n }\n get isPDFReadOnlyMode() {\n return this.parent &&\n this.parent.form &&\n (this.parent.form.display === 'pdf') &&\n this.options.readOnly;\n }\n get labelInfo() {\n const label = {};\n label.hidden = this.labelIsHidden();\n label.className = '';\n label.labelPosition = this.component.labelPosition;\n label.tooltipClass = `${this.iconClass('question-sign')} text-muted`;\n const isPDFReadOnlyMode = this.isPDFReadOnlyMode;\n if (this.hasInput && this.component.validate && (0, utils_1.boolValue)(this.component.validate.required) && !isPDFReadOnlyMode) {\n label.className += ' field-required';\n }\n if (label.hidden) {\n label.className += ' control-label--hidden';\n }\n if (this.info.attr.id) {\n label.for = this.info.attr.id;\n }\n return label;\n }\n init() {\n var _a;\n this.disabled = this.shouldDisabled;\n this._visible = this.conditionallyVisible(null, null);\n if ((_a = this.component.addons) === null || _a === void 0 ? void 0 : _a.length) {\n this.component.addons.forEach((addon) => this.createAddon(addon));\n }\n }\n afterComponentAssign() {\n //implement in extended classes\n }\n createAddon(addonConfiguration) {\n var _a;\n const name = addonConfiguration.name;\n if (!name) {\n return;\n }\n const settings = ((_a = addonConfiguration.settings) === null || _a === void 0 ? void 0 : _a.data) || {};\n const Addon = addons_1.default[name.value];\n let addon = null;\n if (Addon) {\n const supportedComponents = Addon.info.supportedComponents;\n const supportsThisComponentType = !(supportedComponents === null || supportedComponents === void 0 ? void 0 : supportedComponents.length) ||\n supportedComponents.indexOf(this.component.type) !== -1;\n if (supportsThisComponentType) {\n addon = new Addon(settings, this);\n this.addons.push(addon);\n }\n else {\n console.warn(`Addon ${name.label} does not support component of type ${this.component.type}.`);\n }\n }\n return addon;\n }\n teardown() {\n if (this.element) {\n delete this.element.component;\n delete this.element;\n }\n delete this._currentForm;\n delete this.parent;\n delete this.root;\n delete this.triggerChange;\n delete this.triggerRedraw;\n if (this.options) {\n delete this.options.root;\n delete this.options.parent;\n delete this.options.i18next;\n }\n super.teardown();\n }\n destroy(all = false) {\n super.destroy(all);\n this.detach();\n this.addons.forEach((addon) => addon.destroy());\n if (all) {\n this.teardown();\n }\n }\n get shouldDisabled() {\n return this.options.readOnly || this.component.disabled || (this.options.hasOwnProperty('disabled') && this.options.disabled[this.key]);\n }\n get isInputComponent() {\n return !this.component.hasOwnProperty('input') || this.component.input;\n }\n get allowData() {\n return this.hasInput;\n }\n get hasInput() {\n return this.isInputComponent || (this.refs.input && this.refs.input.length);\n }\n get defaultSchema() {\n return Component.schema();\n }\n get key() {\n return lodash_1.default.get(this.component, 'key', '');\n }\n set parentVisible(value) {\n this._parentVisible = value;\n }\n get parentVisible() {\n return this._parentVisible;\n }\n set parentDisabled(value) {\n this._parentDisabled = value;\n }\n get parentDisabled() {\n return this._parentDisabled;\n }\n shouldForceVisibility(component, visibility) {\n if (!this.options[visibility]) {\n return false;\n }\n if (!component) {\n component = this.component;\n }\n if (lodash_1.default.isArray(this.options[visibility])) {\n return this.options[visibility].includes(component.key);\n }\n return this.options[visibility][component.key];\n }\n shouldForceHide(component) {\n return this.shouldForceVisibility(component, 'hide');\n }\n shouldForceShow(component) {\n return this.shouldForceVisibility(component, 'show');\n }\n /**\n *\n * @param value {boolean}\n */\n set visible(value) {\n if (this._visible !== value) {\n // Skip if this component is set to visible and is supposed to be hidden.\n if (value && this.shouldForceHide()) {\n return;\n }\n // Skip if this component is set to hidden and is supposed to be shown.\n if (!value && this.shouldForceShow()) {\n return;\n }\n this._visible = value;\n this.clearOnHide();\n this.redraw();\n }\n }\n /**\n *\n * @returns {boolean}\n */\n get visible() {\n // Show only if visibility changes or if we are in builder mode or if hidden fields should be shown.\n if (this.builderMode || this.previewMode || this.options.showHiddenFields) {\n return true;\n }\n if (this.shouldForceHide()) {\n return false;\n }\n if (this.shouldForceShow()) {\n return true;\n }\n return this._visible && this._parentVisible;\n }\n get currentForm() {\n return this._currentForm;\n }\n set currentForm(instance) {\n this._currentForm = instance;\n }\n get fullMode() {\n return this.options.attachMode === 'full';\n }\n get builderMode() {\n return this.options.attachMode === 'builder';\n }\n get calculatedPath() {\n console.error('component.calculatedPath was deprecated, use component.path instead.');\n return this.path;\n }\n get labelPosition() {\n return this.component.labelPosition;\n }\n get labelWidth() {\n const width = this.component.labelWidth;\n return width >= 0 ? width : 30;\n }\n get labelMargin() {\n const margin = this.component.labelMargin;\n return margin >= 0 ? margin : 3;\n }\n get isAdvancedLabel() {\n return [\n 'left-left',\n 'left-right',\n 'right-left',\n 'right-right'\n ].includes(this.labelPosition);\n }\n get labelPositions() {\n return this.labelPosition.split('-');\n }\n get skipInEmail() {\n return false;\n }\n rightDirection(direction) {\n if (this.options.condensedMode) {\n return false;\n }\n return direction === 'right';\n }\n getLabelInfo(isCondensed = false) {\n const isRightPosition = this.rightDirection(this.labelPositions[0]);\n const isLeftPosition = this.labelPositions[0] === 'left' || isCondensed;\n const isRightAlign = this.rightDirection(this.labelPositions[1]);\n let contentMargin = '';\n if (this.component.hideLabel) {\n const margin = isCondensed ? 0 : this.labelWidth + this.labelMargin;\n contentMargin = isRightPosition ? `margin-right: ${margin}%` : '';\n contentMargin = isLeftPosition ? `margin-left: ${margin}%` : '';\n }\n const labelStyles = `\n flex: ${this.labelWidth};\n ${isRightPosition ? 'margin-left' : 'margin-right'}: ${this.labelMargin}%;\n `;\n const contentStyles = `\n flex: ${100 - this.labelWidth - this.labelMargin};\n ${contentMargin};\n ${this.component.hideLabel ? `max-width: ${100 - this.labelWidth - this.labelMargin}` : ''};\n `;\n return {\n isRightPosition,\n isRightAlign,\n labelStyles,\n contentStyles\n };\n }\n /**\n * Returns only the schema that is different from the default.\n *\n * @param schema\n * @param defaultSchema\n */\n getModifiedSchema(schema, defaultSchema, recursion) {\n const modified = {};\n if (!defaultSchema) {\n return schema;\n }\n lodash_1.default.each(schema, (val, key) => {\n if (!lodash_1.default.isArray(val) && lodash_1.default.isObject(val) && defaultSchema.hasOwnProperty(key)) {\n const subModified = this.getModifiedSchema(val, defaultSchema[key], true);\n if (!lodash_1.default.isEmpty(subModified)) {\n modified[key] = subModified;\n }\n }\n else if (lodash_1.default.isArray(val)) {\n if (val.length !== 0 && !lodash_1.default.isEqual(val, defaultSchema[key])) {\n modified[key] = val;\n }\n }\n else if ((!recursion && (key === 'type')) ||\n (!recursion && (key === 'key')) ||\n (!recursion && (key === 'label')) ||\n (!recursion && (key === 'input')) ||\n (!recursion && (key === 'tableView')) ||\n (val !== '' && !defaultSchema.hasOwnProperty(key)) ||\n (val !== '' && val !== defaultSchema[key]) ||\n (defaultSchema[key] && val !== defaultSchema[key])) {\n modified[key] = val;\n }\n });\n return modified;\n }\n /**\n * Returns the JSON schema for this component.\n */\n get schema() {\n return (0, utils_1.fastCloneDeep)(this.getModifiedSchema(lodash_1.default.omit(this.component, 'id'), this.defaultSchema));\n }\n /**\n * Returns true if component is inside DataGrid\n */\n get isInDataGrid() {\n return this.inDataGrid;\n }\n /**\n * Translate a text using the i18n system.\n *\n * @param {string} text - The i18n identifier.\n * @param {Object} params - The i18n parameters to use for translation.\n */\n t(text, params = {}, ...args) {\n if (!text) {\n return '';\n }\n // Use _userInput: true to ignore translations from defaults\n if (text in en_1.default && params._userInput) {\n return text;\n }\n params.data = params.data || this.rootValue;\n params.row = params.row || this.data;\n params.component = params.component || this.component;\n return super.t(text, params, ...args);\n }\n labelIsHidden() {\n return !this.component.label ||\n ((!this.isInDataGrid && this.component.hideLabel) ||\n (this.isInDataGrid && !this.component.dataGridLabel) ||\n this.options.floatingLabels ||\n this.options.inputsOnly) && !this.builderMode;\n }\n transform(type, value) {\n const frameworkTemplates = this.options.template ? Templates_1.default.templates[this.options.template] : Templates_1.default.current;\n return frameworkTemplates.hasOwnProperty('transform')\n ? frameworkTemplates.transform(type, value, this)\n : (type, value) => value;\n }\n getTemplate(names, modes) {\n modes = Array.isArray(modes) ? modes : [modes];\n names = Array.isArray(names) ? names : [names];\n if (!modes.includes('form')) {\n modes.push('form');\n }\n let result = null;\n if (this.options.templates) {\n result = this.checkTemplate(this.options.templates, names, modes);\n if (result) {\n return result;\n }\n }\n const frameworkTemplates = this.options.template ? Templates_1.default.templates[this.options.template] : Templates_1.default.current;\n result = this.checkTemplate(frameworkTemplates, names, modes);\n if (result) {\n return result;\n }\n // Default back to bootstrap if not defined.\n const name = names[names.length - 1];\n const templatesByName = Templates_1.default.defaultTemplates[name];\n if (!templatesByName) {\n return { template: `Unknown template: ${name}` };\n }\n const templateByMode = this.checkTemplateMode(templatesByName, modes);\n if (templateByMode) {\n return { template: templateByMode };\n }\n return { template: templatesByName.form };\n }\n checkTemplate(templates, names, modes) {\n for (const name of names) {\n const templatesByName = templates[name];\n if (templatesByName) {\n const { referenceAttributeName } = templatesByName;\n const templateByMode = this.checkTemplateMode(templatesByName, modes);\n if (templateByMode) {\n return { template: templateByMode, referenceAttributeName };\n }\n }\n }\n return null;\n }\n checkTemplateMode(templatesByName, modes) {\n for (const mode of modes) {\n const templateByMode = templatesByName[mode];\n if (templateByMode) {\n return templateByMode;\n }\n }\n return null;\n }\n getFormattedAttribute(attr) {\n return attr ? this.t(attr, { _userInput: true }).replace(/\"/g, '"') : '';\n }\n getFormattedTooltip(tooltipValue) {\n const tooltip = this.interpolate(tooltipValue || '').replace(/(?:\\r\\n|\\r|\\n)/g, '<br />');\n return this.getFormattedAttribute(tooltip);\n }\n isHtmlRenderMode() {\n return this.options.renderMode === 'html';\n }\n renderTemplate(name, data = {}, modeOption) {\n // Need to make this fall back to form if renderMode is not found similar to how we search templates.\n const mode = modeOption || this.options.renderMode || 'form';\n data.component = this.component;\n data.self = this;\n data.options = this.options;\n data.readOnly = this.options.readOnly;\n data.iconClass = this.iconClass.bind(this);\n data.size = this.size.bind(this);\n data.t = this.t.bind(this);\n data.transform = this.transform.bind(this);\n data.id = data.id || this.id;\n data.key = data.key || this.key;\n data.value = data.value || this.dataValue;\n data.disabled = this.disabled;\n data.builder = this.builderMode;\n data.render = (...args) => {\n console.warn(`Form.io 'render' template function is deprecated.\n If you need to render template (template A) inside of another template (template B),\n pass pre-compiled template A (use this.renderTemplate('template_A_name') as template context variable for template B`);\n return this.renderTemplate(...args);\n };\n data.label = data.labelInfo || this.labelInfo;\n data.tooltip = this.getFormattedTooltip(this.component.tooltip);\n // Allow more specific template names\n const names = [\n `${name}-${this.component.type}-${this.key}`,\n `${name}-${this.component.type}`,\n `${name}-${this.key}`,\n `${name}`,\n ];\n // Allow template alters.\n const { referenceAttributeName, template } = this.getTemplate(names, mode);\n if (referenceAttributeName) {\n this._referenceAttributeName = referenceAttributeName;\n }\n return this.hook(`render${name.charAt(0).toUpperCase() + name.substring(1, name.length)}`, this.interpolate(template, data), data, mode);\n }\n /**\n * Sanitize an html string.\n *\n * @param string\n * @returns {*}\n */\n sanitize(dirty, forceSanitize, options) {\n var _a;\n if (!this.shouldSanitizeValue && !forceSanitize) {\n return dirty;\n }\n return FormioUtils.sanitize(dirty, {\n sanitizeConfig: lodash_1.default.merge(((_a = this.options) === null || _a === void 0 ? void 0 : _a.sanitizeConfig) || {}, options || {}),\n });\n }\n /**\n * Render a template string into html.\n *\n * @param template\n * @param data\n * @param actions\n *\n * @return {HTMLElement|String} - The created element or an empty string if template is not specified.\n */\n renderString(template, data) {\n if (!template) {\n return '';\n }\n // Interpolate the template and populate\n return this.interpolate(template, data);\n }\n performInputMapping(input) {\n return input;\n }\n get widget() {\n var _a;\n const settings = this.component.widget;\n if (settings && ((_a = this.root) === null || _a === void 0 ? void 0 : _a.shadowRoot)) {\n settings.shadowRoot = this.root.shadowRoot;\n }\n const widget = settings && widgets_1.default[settings.type] ? new widgets_1.default[settings.type](settings, this.component, this) : null;\n return widget;\n }\n getBrowserLanguage() {\n const nav = window.navigator;\n const browserLanguagePropertyKeys = ['language', 'browserLanguage', 'systemLanguage', 'userLanguage'];\n let language;\n // support for HTML 5.1 \"navigator.languages\"\n if (Array.isArray(nav.languages)) {\n for (let i = 0; i < nav.languages.length; i++) {\n language = nav.languages[i];\n if (language && language.length) {\n return language.split(';')[0];\n }\n }\n }\n // support for other well known properties in browsers\n for (let i = 0; i < browserLanguagePropertyKeys.length; i++) {\n language = nav[browserLanguagePropertyKeys[i]];\n if (language && language.length) {\n return language.split(';')[0];\n }\n }\n return null;\n }\n /**\n * Called before a next and previous page is triggered allowing the components\n * to perform special functions.\n *\n * @return {*}\n */\n beforePage() {\n return Promise.resolve(true);\n }\n beforeNext() {\n return this.beforePage(true);\n }\n /**\n * Called before a submission is triggered allowing the components\n * to perform special async functions.\n *\n * @return {*}\n */\n beforeSubmit() {\n return Promise.resolve(true);\n }\n /**\n * Return the submission timezone.\n *\n * @return {*}\n */\n get submissionTimezone() {\n this.options.submissionTimezone = this.options.submissionTimezone || lodash_1.default.get(this.root, 'options.submissionTimezone');\n return this.options.submissionTimezone;\n }\n get timezone() {\n return this.getTimezone(this.component);\n }\n getTimezone(settings) {\n if (settings.timezone) {\n return settings.timezone;\n }\n if (settings.displayInTimezone === 'utc') {\n return 'UTC';\n }\n const submissionTimezone = this.submissionTimezone;\n if (submissionTimezone &&\n ((settings.displayInTimezone === 'submission') ||\n ((this.options.pdf || this.options.server) && (settings.displayInTimezone === 'viewer')))) {\n return submissionTimezone;\n }\n // Return current timezone if none are provided.\n return (0, utils_1.currentTimezone)();\n }\n /**\n *\n * @param {HTMLElement} element - The containing DOM element to query for the ref value.\n * @param {object} refs - The references to load.\n * @param {string} [referenceAttributeName] - The attribute name to use for the reference.\n */\n loadRefs(element, refs, referenceAttributeName) {\n for (const ref in refs) {\n const refType = refs[ref];\n const isString = typeof refType === 'string';\n const selector = isString && refType.includes('scope')\n ? `:scope > [${referenceAttributeName || this._referenceAttributeName || 'ref'}=\"${ref}\"]`\n : `[${referenceAttributeName || this._referenceAttributeName || 'ref'}=\"${ref}\"]`;\n if (isString && refType.startsWith('single')) {\n this.refs[ref] = element.querySelector(selector);\n }\n else {\n this.refs[ref] = element.querySelectorAll(selector);\n }\n }\n }\n setOpenModalElement(template) {\n this.componentModal.setOpenModalElement(template || this.getModalPreviewTemplate());\n }\n getModalPreviewTemplate() {\n var _a;\n const dataValue = this.component.type === 'password' ? this.dataValue.replace(/./g, '•') : this.dataValue;\n let modalLabel;\n if (this.hasInput && ((_a = this.component.validate) === null || _a === void 0 ? void 0 : _a.required) && !this.isPDFReadOnlyMode) {\n modalLabel = { className: 'field-required' };\n }\n return this.renderTemplate('modalPreview', {\n previewText: this.getValueAsString(dataValue, { modalPreview: true }) || this.t('Click to set value'),\n messages: '',\n labelInfo: modalLabel,\n });\n }\n build(element) {\n element = element || this.element;\n this.empty(element);\n this.setContent(element, this.render());\n return this.attach(element);\n }\n get hasModalSaveButton() {\n return true;\n }\n render(children = `Unknown component: ${this.component.type}`, topLevel = false) {\n const isVisible = this.visible;\n this.rendered = true;\n if (!this.builderMode && !this.previewMode && this.component.modalEdit) {\n return ComponentModal_1.default.render(this, {\n visible: isVisible,\n showSaveButton: this.hasModalSaveButton,\n id: this.id,\n classes: this.className,\n styles: this.customStyle,\n children\n }, topLevel);\n }\n else {\n return this.renderTemplate('component', {\n visible: isVisible,\n id: this.id,\n classes: this.className,\n styles: this.customStyle,\n children\n }, topLevel);\n }\n }\n attachTooltips(toolTipsRefs) {\n toolTipsRefs === null || toolTipsRefs === void 0 ? void 0 : toolTipsRefs.forEach((tooltip, index) => {\n if (tooltip) {\n const tooltipAttribute = tooltip.getAttribute('data-tooltip');\n const tooltipDataTitle = tooltip.getAttribute('data-title');\n const tooltipText = this.interpolate(tooltipDataTitle || tooltipAttribute)\n .replace(/(?:\\r\\n|\\r|\\n)/g, '<br />');\n this.tooltips[index] = (0, tippy_js_1.default)(tooltip, {\n allowHTML: true,\n trigger: 'mouseenter click focus',\n placement: 'right',\n zIndex: 10000,\n interactive: true,\n content: this.t(this.sanitize(tooltipText), { _userInput: true }),\n });\n }\n });\n }\n createComponentModal(element, modalShouldBeOpened, currentValue) {\n return new ComponentModal_1.default(this, element, modalShouldBeOpened, currentValue, this._referenceAttributeName);\n }\n attach(element) {\n if (!this.builderMode && !this.previewMode && this.component.modalEdit) {\n const modalShouldBeOpened = this.componentModal ? this.componentModal.isOpened : false;\n const currentValue = modalShouldBeOpened ? this.componentModal.currentValue : this.dataValue;\n const openModalTemplate = this.componentModal && modalShouldBeOpened\n ? this.componentModal.openModalTemplate\n : null;\n this.componentModal = this.createComponentModal(element, modalShouldBeOpened, currentValue);\n this.setOpenModalElement(openModalTemplate);\n }\n this.attached = true;\n this.setElement(element);\n element.component = this;\n // If this already has an id, get it from the dom. If SSR, it could be different from the initiated id.\n if (this.element.id) {\n this.id = this.element.id;\n this.component.id = this.id;\n }\n this.loadRefs(element, {\n messageContainer: 'single',\n tooltip: 'multiple'\n });\n this.attachTooltips(this.refs.tooltip);\n // Attach logic.\n this.attachLogic();\n this.autofocus();\n // Allow global attach.\n this.hook('attachComponent', element, this);\n // Allow attach per component type.\n const type = this.component.type;\n if (type) {\n this.hook(`attach${type.charAt(0).toUpperCase() + type.substring(1, type.length)}`, element, this);\n }\n this.restoreFocus();\n this.addons.forEach((addon) => addon.attach(element));\n return Promise.resolve();\n }\n restoreFocus() {\n var _a, _b, _c;\n const isFocused = ((_b = (_a = this.root) === null || _a === void 0 ? void 0 : _a.focusedComponent) === null || _b === void 0 ? void 0 : _b.path) === this.path;\n if (isFocused) {\n this.loadRefs(this.element, { input: 'multiple' });\n this.focus((_c = this.root.currentSelection) === null || _c === void 0 ? void 0 : _c.index);\n this.restoreCaretPosition();\n }\n }\n addShortcut(element, shortcut) {\n // Avoid infinite recursion.\n if (!element || !this.root || (this.root === this)) {\n return;\n }\n if (!shortcut) {\n shortcut = this.component.shortcut;\n }\n this.root.addShortcut(element, shortcut);\n }\n removeShortcut(element, shortcut) {\n // Avoid infinite recursion.\n if (!element || (this.root === this)) {\n return;\n }\n if (!shortcut) {\n shortcut = this.component.shortcut;\n }\n this.root.removeShortcut(element, shortcut);\n }\n /**\n * Remove all event handlers.\n */\n detach() {\n // First iterate through each ref and delete the component so there are no dangling component references.\n lodash_1.default.each(this.refs, (ref) => {\n if (typeof ref === NodeList) {\n ref.forEach((elem) => {\n delete elem.component;\n });\n }\n else if (ref) {\n delete ref.component;\n }\n });\n this.refs = {};\n this.removeEventListeners();\n this.detachLogic();\n if (this.tooltip) {\n this.tooltip.destroy();\n }\n }\n checkRefresh(refreshData, changed, flags) {\n const changePath = lodash_1.default.get(changed, 'instance.path', false);\n // Don't let components change themselves.\n if (changePath && this.path === changePath) {\n return;\n }\n if (refreshData === 'data') {\n this.refresh(this.data, changed, flags);\n }\n else if ((changePath && (0, utils_1.getComponentPath)(changed.instance) === refreshData) && changed && changed.instance &&\n // Make sure the changed component is not in a different \"context\". Solves issues where refreshOn being set\n // in fields inside EditGrids could alter their state from other rows (which is bad).\n this.inContext(changed.instance)) {\n this.refresh(changed.value, changed, flags);\n }\n }\n checkRefreshOn(changes, flags = {}) {\n changes = changes || [];\n if (flags.noRefresh) {\n return;\n }\n if (!changes.length && flags.changed) {\n changes = [flags.changed];\n }\n const refreshOn = flags.fromBlur ? this.component.refreshOnBlur : this.component.refreshOn || this.component.redrawOn;\n // If they wish to refresh on a value, then add that here.\n if (refreshOn) {\n if (Array.isArray(refreshOn)) {\n refreshOn.forEach(refreshData => changes.forEach(changed => this.checkRefresh(refreshData, changed, flags)));\n }\n else {\n changes.forEach(changed => this.checkRefresh(refreshOn, changed, flags));\n }\n }\n }\n /**\n * Refreshes the component with a new value.\n *\n * @param value\n */\n refresh(value) {\n if (this.hasOwnProperty('refreshOnValue')) {\n this.refreshOnChanged = !lodash_1.default.isEqual(value, this.refreshOnValue);\n }\n else {\n this.refreshOnChanged = true;\n }\n this.refreshOnValue = (0, utils_1.fastCloneDeep)(value);\n if (this.refreshOnChanged) {\n if (this.component.clearOnRefresh) {\n this.setValue(null);\n }\n this.triggerRedraw();\n }\n }\n /**\n * Checks to see if a separate component is in the \"context\" of this component. This is determined by first checking\n * if they share the same \"data\" object. It will then walk up the parent tree and compare its parents data objects\n * with the components data and returns true if they are in the same context.\n *\n * Different rows of the same EditGrid, for example, are in different contexts.\n *\n * @param component\n */\n inContext(component) {\n if (component.data === this.data) {\n return true;\n }\n let parent = this.parent;\n while (parent) {\n if (parent.data === component.data) {\n return true;\n }\n parent = parent.parent;\n }\n return false;\n }\n get viewOnly() {\n return this.options.readOnly && this.options.viewAsHtml;\n }\n setElement(element) {\n if (this.element) {\n delete this.element.component;\n delete this.element;\n }\n this.element = element;\n }\n createViewOnlyElement() {\n this.setElement(this.ce('dl', {\n id: this.id\n }));\n if (this.element) {\n // Ensure you can get the component info from the element.\n this.element.component = this;\n }\n return this.element;\n }\n get defaultViewOnlyValue() {\n return '-';\n }\n /**\n * Uses the widget to determine the output string.\n *\n * @param value\n * @return {*}\n */\n getWidgetValueAsString(value, options) {\n const noInputWidget = !this.refs.input || !this.refs.input[0] || !this.refs.input[0].widget;\n if (!value || noInputWidget) {\n if (!this.widget || !value) {\n return value;\n }\n else {\n return this.widget.getValueAsString(value);\n }\n }\n if (Array.isArray(value)) {\n const values = [];\n value.forEach((val, index) => {\n const widget = this.refs.input[index] && this.refs.input[index].widget;\n if (widget) {\n values.push(widget.getValueAsString(val, options));\n }\n });\n return values;\n }\n const widget = this.refs.input[0].widget;\n return widget.getValueAsString(value, options);\n }\n getValueAsString(value, options) {\n if (!value) {\n return '';\n }\n value = this.getWidgetValueAsString(value, options);\n if (Array.isArray(value)) {\n return value.join(', ');\n }\n if (lodash_1.default.isPlainObject(value)) {\n return JSON.stringify(value);\n }\n if (value === null || value === undefined) {\n return '';\n }\n const stringValue = value.toString();\n return this.sanitize(stringValue);\n }\n getView(value, options) {\n if (this.component.protected) {\n return '--- PROTECTED ---';\n }\n return this.getValueAsString(value, options);\n }\n updateItems(...args) {\n this.restoreValue();\n this.onChange(...args);\n }\n /**\n * @param {*} data\n * @param {boolean} [forceUseValue=false] - if true, return 'value' property of the data\n * @return {*}\n */\n itemValue(data, forceUseValue = false) {\n if (lodash_1.default.isObject(data) && !lodash_1.default.isArray(data)) {\n if (this.valueProperty) {\n return lodash_1.default.get(data, this.valueProperty);\n }\n if (forceUseValue) {\n return data.value;\n }\n }\n return data;\n }\n itemValueForHTMLMode(value) {\n if (Array.isArray(value)) {\n const values = value.map(item => Array.isArray(item) ? this.itemValueForHTMLMode(item) : this.itemValue(item));\n return values.join(', ');\n }\n return this.itemValue(value);\n }\n createModal(element, attr, confirm) {\n const dialog = this.ce('div', attr || {});\n this.setContent(dialog, this.renderTemplate('dialog'));\n // Add refs to dialog, not \"this\".\n dialog.refs = {};\n this.loadRefs.call(dialog, dialog, {\n dialogOverlay: 'single',\n dialogContents: 'single',\n dialogClose: 'single',\n });\n dialog.refs.dialogContents.appendChild(element);\n document.body.appendChild(dialog);\n document.body.classList.add('modal-open');\n dialog.close = () => {\n document.body.classList.remove('modal-open');\n dialog.dispatchEvent(new CustomEvent('close'));\n };\n this.addEventListener(dialog, 'close', () => this.removeChildFrom(dialog, document.body));\n const close = (event) => {\n event.preventDefault();\n dialog.close();\n };\n const handleCloseClick = (e) => {\n if (confirm) {\n confirm().then(() => close(e))\n .catch(() => { });\n }\n else {\n close(e);\n }\n };\n this.addEventListener(dialog.refs.dialogOverlay, 'click', handleCloseClick);\n this.addEventListener(dialog.refs.dialogClose, 'click', handleCloseClick);\n return dialog;\n }\n get optimizeRedraw() {\n if (this.options.optimizeRedraw && this.element && !this.visible) {\n this.addClass(this.element, 'formio-removed');\n return true;\n }\n return false;\n }\n /**\n * Retrieves the CSS class name of this component.\n * @returns {string} - The class name of this component.\n */\n get className() {\n let className = this.hasInput ? `${this.transform('class', 'form-group')} has-feedback ` : '';\n className += `formio-component formio-component-${this.component.type} `;\n // TODO: find proper way to avoid overriding of default type-based component styles\n if (this.key && this.key !== 'form') {\n className += `formio-component-${this.key} `;\n }\n if (this.component.multiple) {\n className += 'formio-component-multiple ';\n }\n if (this.component.customClass) {\n className += this.component.customClass;\n }\n if (this.hasInput && this.component.validate && (0, utils_1.boolValue)(this.component.validate.required)) {\n className += ' required';\n }\n if (this.labelIsHidden()) {\n className += ' formio-component-label-hidden';\n }\n if (!this.visible) {\n className += ' formio-hidden';\n }\n return className;\n }\n /**\n * Build the custom style from the layout values\n * @return {string} - The custom style\n */\n get customStyle() {\n let customCSS = '';\n lodash_1.default.each(this.component.style, (value, key) => {\n if (value !== '') {\n customCSS += `${key}:${value};`;\n }\n });\n return customCSS;\n }\n static get serverConditionSettings() {\n return Component.conditionOperatorsSettings;\n }\n get isMobile() {\n return (0, ismobilejs_1.default)();\n }\n /**\n * Returns the outside wrapping element of this component.\n * @returns {HTMLElement}\n */\n getElement() {\n return this.element;\n }\n /**\n * Create an evaluation context for all script executions and interpolations.\n *\n * @param additional\n * @return {*}\n */\n evalContext(additional) {\n return super.evalContext(Object.assign({\n component: this.component,\n row: this.data,\n rowIndex: this.rowIndex,\n data: this.rootValue,\n iconClass: this.iconClass.bind(this),\n // Bind the translate function to the data context of any interpolated string.\n // It is useful to translate strings in different scenarions (eg: custom edit grid templates, custom error messages etc.)\n // and desirable to be publicly available rather than calling the internal {instance.t} function in the template string.\n t: this.t.bind(this),\n submission: (this.root ? this.root._submission : {\n data: this.rootValue\n }),\n form: this.root ? this.root._form : {},\n options: this.options,\n }, additional));\n }\n /**\n * Sets the pristine flag for this component.\n *\n * @param pristine {boolean} - TRUE to make pristine, FALSE not pristine.\n */\n setPristine(pristine) {\n this.pristine = pristine;\n }\n get isPristine() {\n return this.pristine;\n }\n setDirty(dirty) {\n this.dirty = dirty;\n }\n get isDirty() {\n return this.dirty;\n }\n /**\n * Removes a value out of the data array and rebuild the rows.\n * @param {number} index - The index of the data element to remove.\n */\n removeValue(index) {\n this.splice(index);\n this.redraw();\n this.restoreValue();\n this.triggerRootChange();\n }\n iconClass(name, spinning) {\n const iconset = this.options.iconset || Templates_1.default.current.defaultIconset || 'fa';\n return Templates_1.default.current.hasOwnProperty('iconClass')\n ? Templates_1.default.current.iconClass(iconset, name, spinning)\n : this.options.iconset === 'fa' ? Templates_1.default.defaultTemplates.iconClass(iconset, name, spinning) : name;\n }\n size(size) {\n return Templates_1.default.current.hasOwnProperty('size')\n ? Templates_1.default.current.size(size)\n : size;\n }\n /**\n * The readible name for this component.\n * @returns {string} - The name of the component.\n */\n get name() {\n return this.t(this.component.label || this.component.placeholder || this.key, { _userInput: true });\n }\n get visibleErrors() {\n return this._visibleErrors;\n }\n get errors() {\n return this._errors;\n }\n /**\n * Returns the error label for this component.\n * @return {*}\n */\n get errorLabel() {\n return this.t(this.component.errorLabel\n || this.component.label\n || this.component.placeholder\n || this.key);\n }\n /**\n * Get the error message provided a certain type of error.\n * @param type\n * @return {*}\n */\n errorMessage(type) {\n return (this.component.errors && this.component.errors[type]) ? this.component.errors[type] : type;\n }\n setContent(element, content, forceSanitize, sanitizeOptions) {\n if (element instanceof HTMLElement) {\n element.innerHTML = this.sanitize(content, forceSanitize, sanitizeOptions);\n return true;\n }\n return false;\n }\n restoreCaretPosition() {\n var _a, _b, _c;\n if ((_a = this.root) === null || _a === void 0 ? void 0 : _a.currentSelection) {\n if ((_b = this.refs.input) === null || _b === void 0 ? void 0 : _b.length) {\n const { selection, index } = this.root.currentSelection;\n let input = this.refs.input[index];\n const isInputRangeSelectable = (i) => /text|search|password|tel|url/i.test((i === null || i === void 0 ? void 0 : i.type) || '');\n if (input) {\n if (isInputRangeSelectable(input)) {\n input.setSelectionRange(...selection);\n }\n }\n else {\n input = this.refs.input[this.refs.input.length];\n const lastCharacter = ((_c = input.value) === null || _c === void 0 ? void 0 : _c.length) || 0;\n if (isInputRangeSelectable(input)) {\n input.setSelectionRange(lastCharacter, lastCharacter);\n }\n }\n }\n }\n }\n redraw() {\n // Don't bother if we have not built yet.\n if (!this.element || !this.element.parentNode || this.optimizeRedraw) {\n // Return a non-resolving promise.\n return Promise.resolve();\n }\n this.detach();\n this.emit('redraw');\n // Since we are going to replace the element, we need to know it's position so we can find it in the parent's children.\n const parent = this.element.parentNode;\n const index = Array.prototype.indexOf.call(parent.children, this.element);\n this.element.outerHTML = this.sanitize(this.render());\n this.setElement(parent.children[index]);\n return this.attach(this.element);\n }\n rebuild() {\n this.destroy();\n this.init();\n this.visible = this.conditionallyVisible(null, null);\n return this.redraw();\n }\n removeEventListeners() {\n super.removeEventListeners();\n this.tooltips.forEach(tooltip => tooltip.destroy());\n this.tooltips = [];\n }\n hasClass(element, className) {\n if (!element) {\n return;\n }\n return super.hasClass(element, this.transform('class', className));\n }\n addClass(element, className) {\n if (!element) {\n return;\n }\n return super.addClass(element, this.transform('class', className));\n }\n removeClass(element, className) {\n if (!element) {\n return;\n }\n return super.removeClass(element, this.transform('class', className));\n }\n /**\n * Determines if this component has a condition defined.\n *\n * @return {null}\n */\n hasCondition() {\n if (this._hasCondition !== null) {\n return this._hasCondition;\n }\n this._hasCondition = FormioUtils.hasCondition(this.component);\n return this._hasCondition;\n }\n /**\n * Check if this component is conditionally visible.\n *\n * @param data\n * @return {boolean}\n */\n conditionallyVisible(data, row) {\n data = data || this.rootValue;\n row = row || this.data;\n if (this.builderMode || this.previewMode || !this.hasCondition()) {\n return !this.component.hidden;\n }\n data = data || (this.root ? this.root.data : {});\n return this.checkCondition(row, data);\n }\n /**\n * Checks the condition of this component.\n *\n * TODO: Switch row and data parameters to be consistent with other methods.\n *\n * @param row - The row contextual data.\n * @param data - The global data object.\n * @return {boolean} - True if the condition applies to this component.\n */\n checkCondition(row, data) {\n return FormioUtils.checkCondition(this.component, row || this.data, data || this.rootValue, this.root ? this.root._form : {}, this);\n }\n /**\n * Check for conditionals and hide/show the element based on those conditions.\n */\n checkComponentConditions(data, flags, row) {\n data = data || this.rootValue;\n flags = flags || {};\n row = row || this.data;\n if (!this.builderMode & !this.previewMode && this.fieldLogic(data, row)) {\n this.redraw();\n }\n // Check advanced conditions\n const visible = this.conditionallyVisible(data, row);\n if (this.visible !== visible) {\n this.visible = visible;\n }\n return visible;\n }\n /**\n * Checks conditions for this component and any sub components.\n * @param args\n * @return {boolean}\n */\n checkConditions(data, flags, row) {\n data = data || this.rootValue;\n flags = flags || {};\n row = row || this.data;\n return this.checkComponentConditions(data, flags, row);\n }\n get logic() {\n return this.component.logic || [];\n }\n /**\n * Check all triggers and apply necessary actions.\n *\n * @param data\n */\n fieldLogic(data, row) {\n data = data || this.rootValue;\n row = row || this.data;\n const logics = this.logic;\n // If there aren't logic, don't go further.\n if (logics.length === 0) {\n return;\n }\n const newComponent = (0, utils_1.fastCloneDeep)(this.originalComponent);\n let changed = logics.reduce((changed, logic) => {\n const result = FormioUtils.checkTrigger(newComponent, logic.trigger, row, data, this.root ? this.root._form : {}, this);\n return (result ? this.applyActions(newComponent, logic.actions, result, row, data) : false) || changed;\n }, false);\n // If component definition changed, replace and mark as changed.\n if (!lodash_1.default.isEqual(this.component, newComponent)) {\n this.component = newComponent;\n changed = true;\n const disabled = this.shouldDisabled;\n // Change disabled state if it has changed\n if (this.disabled !== disabled) {\n this.disabled = disabled;\n }\n }\n return changed;\n }\n isIE() {\n if (typeof window === 'undefined') {\n return false;\n }\n const userAgent = window.navigator.userAgent;\n const msie = userAgent.indexOf('MSIE ');\n if (msie > 0) {\n // IE 10 or older => return version number\n return parseInt(userAgent.substring(msie + 5, userAgent.indexOf('.', msie)), 10);\n }\n const trident = userAgent.indexOf('Trident/');\n if (trident > 0) {\n // IE 11 => return version number\n const rv = userAgent.indexOf('rv:');\n return parseInt(userAgent.substring(rv + 3, userAgent.indexOf('.', rv)), 10);\n }\n const edge = userAgent.indexOf('Edge/');\n if (edge > 0) {\n // IE 12 (aka Edge) => return version number\n return parseInt(userAgent.substring(edge + 5, userAgent.indexOf('.', edge)), 10);\n }\n // other browser\n return false;\n }\n defineActionValue(action, argsObject) {\n return this.evaluate(action.value, argsObject, 'value');\n }\n applyActions(newComponent, actions, result, row, data) {\n data = data || this.rootValue;\n row = row || this.data;\n return actions.reduce((changed, action) => {\n switch (action.type) {\n case 'property': {\n FormioUtils.setActionProperty(newComponent, action, result, row, data, this);\n const property = action.property.value;\n if (!lodash_1.default.isEqual(lodash_1.default.get(this.component, property), lodash_1.default.get(newComponent, property))) {\n changed = true;\n }\n break;\n }\n case 'value': {\n const oldValue = this.getValue();\n const newValue = this.defineActionValue(action, {\n value: lodash_1.default.clone(oldValue),\n data,\n row,\n component: newComponent,\n result,\n });\n if (!lodash_1.default.isEqual(oldValue, newValue) && !(this.component.clearOnHide && !this.visible)) {\n this.setValue(newValue);\n if (this.viewOnly) {\n this.dataValue = newValue;\n }\n changed = true;\n }\n break;\n }\n case 'mergeComponentSchema': {\n const schema = this.evaluate(action.schemaDefinition, {\n value: lodash_1.default.clone(this.getValue()),\n data,\n row,\n component: newComponent,\n result,\n }, 'schema');\n lodash_1.default.assign(newComponent, schema);\n if (!lodash_1.default.isEqual(this.component, newComponent)) {\n changed = true;\n }\n break;\n }\n case 'customAction': {\n const oldValue = this.getValue();\n const newValue = this.evaluate(action.customAction, {\n value: lodash_1.default.clone(oldValue),\n data,\n row,\n input: oldValue,\n component: newComponent,\n result,\n }, 'value');\n if (!lodash_1.default.isEqual(oldValue, newValue) && !(this.component.clearOnHide && !this.visible)) {\n this.setValue(newValue);\n if (this.viewOnly) {\n this.dataValue = newValue;\n }\n changed = true;\n }\n break;\n }\n }\n return changed;\n }, false);\n }\n // Deprecated\n addInputError(message, dirty, elements) {\n this.addMessages(message);\n this.setErrorClasses(elements, dirty, !!message);\n }\n // Deprecated\n removeInputError(elements) {\n this.setErrorClasses(elements, true, false);\n }\n /**\n * Add a new input error to this element.\n *\n * @param {{level: string, message: string}[]} messages\n */\n addMessages(messages) {\n if (!messages) {\n return;\n }\n // Standardize on array of objects for message.\n if (typeof messages === 'string') {\n messages = {\n messages,\n level: 'error',\n };\n }\n if (!Array.isArray(messages)) {\n messages = [messages];\n }\n messages = lodash_1.default.uniqBy(messages, message => message.message);\n if (this.refs.messageContainer) {\n this.setContent(this.refs.messageContainer, messages.map((message) => {\n if (message.message && typeof message.message === 'string') {\n message.message = message.message.replaceAll('<', '<').replaceAll('>', '>');\n }\n return this.renderTemplate('message', Object.assign({}, message));\n }).join(''));\n }\n }\n setErrorClasses(elements, dirty, hasErrors, hasMessages, element = this.element) {\n this.clearErrorClasses();\n elements.forEach((element) => {\n this.setElementInvalid(this.performInputMapping(element), false);\n });\n this.setInputWidgetErrorClasses(elements, hasErrors);\n // do not set error classes for hidden components\n if (!this.visible) {\n return;\n }\n if (hasErrors) {\n // Add error classes\n elements.forEach((input) => {\n this.setElementInvalid(this.performInputMapping(input), true);\n });\n if (dirty && this.options.highlightErrors) {\n this.addClass(element, this.options.componentErrorClass);\n }\n else {\n this.addClass(element, 'has-error');\n }\n }\n if (hasMessages) {\n this.addClass(element, 'has-message');\n }\n }\n setElementInvalid(element, invalid) {\n if (!element)\n return;\n if (invalid) {\n this.addClass(element, 'is-invalid');\n }\n else {\n this.removeClass(element, 'is-invalid');\n }\n element.setAttribute('aria-invalid', invalid ? 'true' : 'false');\n }\n clearOnHide() {\n // clearOnHide defaults to true for old forms (without the value set) so only trigger if the value is false.\n if (\n // if change happens inside EditGrid's row, it doesn't trigger change on the root level, so rootPristine will be true\n (!this.rootPristine || this.options.server || (0, utils_1.isInsideScopingComponent)(this)) &&\n this.component.clearOnHide !== false &&\n !this.options.readOnly &&\n !this.options.showHiddenFields) {\n if (!this.visible) {\n this.deleteValue();\n }\n else if (!this.hasValue() && this.shouldAddDefaultValue) {\n // If shown, ensure the default is set.\n this.setValue(this.defaultValue, {\n noUpdateEvent: true\n });\n }\n }\n }\n triggerRootChange(...args) {\n if (this.options.onChange) {\n this.options.onChange(...args);\n }\n else if (this.root && this.root.triggerChange) {\n this.root.triggerChange(...args);\n }\n }\n onChange(flags, fromRoot) {\n flags = flags || {};\n if (flags.modified) {\n if (!flags.noPristineChangeOnModified) {\n this.pristine = false;\n }\n this.addClass(this.getElement(), 'formio-modified');\n }\n // If we are supposed to validate on blur, then don't trigger validation yet.\n if (this.component.validateOn === 'blur') {\n flags.noValidate = true;\n }\n if (this.component.onChange) {\n this.evaluate(this.component.onChange, {\n flags\n });\n }\n // Set the changed variable.\n const changed = {\n instance: this,\n component: this.component,\n value: this.dataValue,\n flags: flags\n };\n // Emit the change.\n this.emit('componentChange', changed);\n // Do not propogate the modified flag.\n let modified = false;\n if (flags.modified) {\n modified = true;\n delete flags.modified;\n }\n // Bubble this change up to the top.\n if (!fromRoot) {\n this.triggerRootChange(flags, changed, modified);\n }\n return changed;\n }\n get wysiwygDefault() {\n return {\n quill: {\n theme: 'snow',\n placeholder: this.t(this.component.placeholder, { _userInput: true }),\n modules: {\n toolbar: [\n [{ 'size': ['small', false, 'large', 'huge'] }], // custom dropdown\n [{ 'header': [1, 2, 3, 4, 5, 6, false] }],\n [{ 'font': [] }],\n ['bold', 'italic', 'underline', 'strike', { 'script': 'sub' }, { 'script': 'super' }, 'clean'],\n [{ 'color': [] }, { 'background': [] }],\n [{ 'list': 'ordered' }, { 'list': 'bullet' }, { 'indent': '-1' }, { 'indent': '+1' }, { 'align': [] }],\n ['blockquote', 'code-block'],\n ['link', 'image', 'video', 'formula', 'source']\n ]\n }\n },\n ace: {\n theme: 'ace/theme/xcode',\n maxLines: 12,\n minLines: 12,\n tabSize: 2,\n mode: 'ace/mode/javascript',\n placeholder: this.t(this.component.placeholder, { _userInput: true })\n },\n ckeditor: {\n image: {\n toolbar: [\n 'imageTextAlternative',\n '|',\n 'imageStyle:full',\n 'imageStyle:alignLeft',\n 'imageStyle:alignCenter',\n 'imageStyle:alignRight'\n ],\n styles: [\n 'full',\n 'alignLeft',\n 'alignCenter',\n 'alignRight'\n ]\n },\n extraPlugins: []\n },\n default: {}\n };\n }\n addCKE(element, settings, onChange) {\n settings = lodash_1.default.isEmpty(settings) ? {} : settings;\n settings.base64Upload = this.component.isUploadEnabled ? false : true;\n settings.mediaEmbed = { previewsInData: true };\n settings = lodash_1.default.merge(this.wysiwygDefault.ckeditor, lodash_1.default.get(this.options, 'editors.ckeditor.settings', {}), settings);\n if (this.component.isUploadEnabled) {\n settings.extraPlugins.push((0, uploadAdapter_1.getFormioUploadAdapterPlugin)(this.fileService, this));\n }\n return Formio_1.Formio.requireLibrary('ckeditor', isIEBrowser ? 'CKEDITOR' : 'ClassicEditor', lodash_1.default.get(this.options, 'editors.ckeditor.src', `${Formio_1.Formio.cdn.ckeditor}/ckeditor.js`), true)\n .then(() => {\n if (!element.parentNode) {\n return Promise.reject();\n }\n if (isIEBrowser) {\n const editor = CKEDITOR.replace(element);\n editor.on('change', () => onChange(editor.getData()));\n return Promise.resolve(editor);\n }\n else {\n return ClassicEditor.create(element, settings).then(editor => {\n editor.model.document.on('change', () => onChange(editor.data.get()));\n return editor;\n });\n }\n });\n }\n addQuill(element, settings, onChange) {\n settings = lodash_1.default.isEmpty(settings) ? this.wysiwygDefault.quill : settings;\n settings = lodash_1.default.merge(this.wysiwygDefault.quill, lodash_1.default.get(this.options, 'editors.quill.settings', {}), settings);\n settings = Object.assign(Object.assign({}, settings), { modules: Object.assign({ table: true }, settings.modules) });\n // Lazy load the quill css.\n Formio_1.Formio.requireLibrary(`quill-css-${settings.theme}`, 'Quill', [\n { type: 'styles', src: `${Formio_1.Formio.cdn.quill}/quill.${settings.theme}.css` }\n ], true);\n // Lazy load the quill library.\n return Formio_1.Formio.requireLibrary('quill', 'Quill', lodash_1.default.get(this.options, 'editors.quill.src', `${Formio_1.Formio.cdn.quill}/quill.min.js`), true)\n .then(() => {\n return Formio_1.Formio.requireLibrary('quill-table', 'Quill', `${Formio_1.Formio.cdn.baseUrl}/quill/quill-table.js`, true)\n .then(() => {\n if (!element.parentNode) {\n return Promise.reject();\n }\n this.quill = new Quill(element, isIEBrowser ? Object.assign(Object.assign({}, settings), { modules: {} }) : settings);\n /** This block of code adds the [source] capabilities. See https://codepen.io/anon/pen/ZyEjrQ **/\n const txtArea = document.createElement('textarea');\n txtArea.setAttribute('class', 'quill-source-code');\n this.quill.addContainer('ql-custom').appendChild(txtArea);\n const qlSource = element.parentNode.querySelector('.ql-source');\n if (qlSource) {\n this.addEventListener(qlSource, 'click', (event) => {\n event.preventDefault();\n if (txtArea.style.display === 'inherit') {\n this.quill.setContents(this.quill.clipboard.convert({ html: txtArea.value }));\n }\n txtArea.style.display = (txtArea.style.display === 'none') ? 'inherit' : 'none';\n });\n }\n /** END CODEBLOCK **/\n // Make sure to select cursor when they click on the element.\n this.addEventListener(element, 'click', () => this.quill.focus());\n // Allows users to skip toolbar items when tabbing though form\n const elm = document.querySelectorAll('.ql-formats > button');\n for (let i = 0; i < elm.length; i++) {\n elm[i].setAttribute('tabindex', '-1');\n }\n this.quill.on('text-change', () => {\n txtArea.value = this.quill.root.innerHTML;\n onChange(txtArea);\n });\n return this.quill;\n });\n });\n }\n get shouldSanitizeValue() {\n var _a;\n // Sanitize value if sanitizing for thw whole content is turned off\n return (((_a = this.options) === null || _a === void 0 ? void 0 : _a.sanitize) !== false);\n }\n addAce(element, settings, onChange) {\n if (!settings || (settings.theme === 'snow')) {\n const mode = settings ? settings.mode : '';\n settings = {};\n if (mode) {\n settings.mode = mode;\n }\n }\n settings = lodash_1.default.merge(this.wysiwygDefault.ace, lodash_1.default.get(this.options, 'editors.ace.settings', {}), settings || {});\n return Formio_1.Formio.requireLibrary('ace', 'ace', lodash_1.default.get(this.options, 'editors.ace.src', `${Formio_1.Formio.cdn.ace}/ace.js`), true)\n .then((editor) => {\n editor = editor.edit(element);\n editor.removeAllListeners('change');\n editor.setOptions(settings);\n editor.getSession().setMode(settings.mode);\n editor.on('change', () => onChange(editor.getValue()));\n if (settings.isUseWorkerDisabled) {\n editor.session.setUseWorker(false);\n }\n return editor;\n });\n }\n get tree() {\n return this.component.tree || false;\n }\n /**\n * The empty value for this component.\n *\n * @return {null}\n */\n get emptyValue() {\n return null;\n }\n /**\n * Returns if this component has a value set.\n *\n */\n hasValue(data) {\n return !lodash_1.default.isUndefined(lodash_1.default.get(data || this.data, this.key));\n }\n /**\n * Get the data value at the root level.\n *\n * @return {*}\n */\n get rootValue() {\n return this.root ? this.root.data : this.data;\n }\n get rootPristine() {\n return lodash_1.default.get(this, 'root.pristine', false);\n }\n /**\n * Get the static value of this component.\n * @return {*}\n */\n get dataValue() {\n if (!this.key ||\n (!this.visible && this.component.clearOnHide && !this.rootPristine)) {\n return this.emptyValue;\n }\n if (!this.hasValue() && this.shouldAddDefaultValue) {\n const empty = this.component.multiple ? [] : this.emptyValue;\n if (!this.rootPristine) {\n this.dataValue = empty;\n }\n return empty;\n }\n return lodash_1.default.get(this._data, this.key);\n }\n /**\n * Sets the static value of this component.\n *\n * @param value\n */\n set dataValue(value) {\n if (!this.allowData ||\n !this.key ||\n (!this.visible && this.component.clearOnHide && !this.rootPristine)) {\n return;\n }\n if ((value !== null) && (value !== undefined)) {\n value = this.hook('setDataValue', value, this.key, this._data);\n }\n if ((value === null) || (value === undefined)) {\n this.unset();\n return;\n }\n lodash_1.default.set(this._data, this.key, value);\n return;\n }\n /**\n * Splice a value from the dataValue.\n *\n * @param index\n */\n splice(index, flags = {}) {\n if (this.hasValue()) {\n const dataValue = this.dataValue || [];\n if (lodash_1.default.isArray(dataValue) && dataValue.hasOwnProperty(index)) {\n dataValue.splice(index, 1);\n this.dataValue = dataValue;\n this.triggerChange(flags);\n }\n }\n }\n unset() {\n lodash_1.default.unset(this._data, this.key);\n }\n /**\n * Deletes the value of the component.\n */\n deleteValue() {\n this.setValue(null, {\n noUpdateEvent: true,\n noDefault: true\n });\n this.unset();\n }\n getCustomDefaultValue(defaultValue) {\n if (this.component.customDefaultValue && !this.options.preview) {\n defaultValue = this.evaluate(this.component.customDefaultValue, { value: '' }, 'value');\n }\n return defaultValue;\n }\n get shouldAddDefaultValue() {\n return !this.options.noDefaults || (this.component.defaultValue && !this.isEmpty(this.component.defaultValue)) || this.component.customDefaultValue;\n }\n get defaultValue() {\n let defaultValue = this.emptyValue;\n if (this.component.defaultValue) {\n defaultValue = this.component.defaultValue;\n }\n defaultValue = this.getCustomDefaultValue(defaultValue);\n const checkMask = (value) => {\n if (typeof value === 'string') {\n if (this.component.type !== 'textfield') {\n const placeholderChar = this.placeholderChar;\n value = (0, vanilla_text_mask_1.conformToMask)(value, this.defaultMask, { placeholderChar }).conformedValue;\n if (!FormioUtils.matchInputMask(value, this.defaultMask)) {\n value = '';\n }\n }\n }\n else {\n value = '';\n }\n return value;\n };\n if (this.defaultMask) {\n if (Array.isArray(defaultValue)) {\n defaultValue = defaultValue.map(checkMask);\n }\n else {\n defaultValue = checkMask(defaultValue);\n }\n }\n // Clone so that it creates a new instance.\n return lodash_1.default.cloneDeep(defaultValue);\n }\n /**\n * Get the input value of this component.\n *\n * @return {*}\n */\n getValue() {\n if (!this.hasInput || this.viewOnly || !this.refs.input || !this.refs.input.length) {\n return this.dataValue;\n }\n const values = [];\n for (const i in this.refs.input) {\n if (this.refs.input.hasOwnProperty(i)) {\n if (!this.component.multiple) {\n return this.getValueAt(i);\n }\n values.push(this.getValueAt(i));\n }\n }\n if (values.length === 0 && !this.component.multiple) {\n return '';\n }\n return values;\n }\n /**\n * Get the value at a specific index.\n *\n * @param index\n * @returns {*}\n */\n getValueAt(index) {\n const input = this.performInputMapping(this.refs.input[index]);\n return input ? input.value : undefined;\n }\n /**\n * Set the value of this component.\n *\n * @param value\n * @param flags\n *\n * @return {boolean} - If the value changed.\n */\n setValue(value, flags = {}) {\n const changed = this.updateValue(value, flags);\n value = this.dataValue;\n if (!this.hasInput) {\n return changed;\n }\n const isArray = Array.isArray(value);\n const valueInput = this.refs.fileLink || this.refs.input;\n if (isArray &&\n Array.isArray(this.defaultValue) &&\n this.refs.hasOwnProperty('input') &&\n valueInput &&\n (valueInput.length !== value.length) &&\n this.visible) {\n this.redraw();\n }\n if (this.isHtmlRenderMode() && flags && flags.fromSubmission && changed) {\n this.redraw();\n return changed;\n }\n for (const i in this.refs.input) {\n if (this.refs.input.hasOwnProperty(i)) {\n this.setValueAt(i, isArray ? value[i] : value, flags);\n }\n }\n return changed;\n }\n /**\n * Set the value at a specific index.\n *\n * @param index\n * @param value\n */\n setValueAt(index, value, flags = {}) {\n if (!flags.noDefault && (value === null || value === undefined) && !this.component.multiple) {\n value = this.defaultValue;\n }\n const input = this.performInputMapping(this.refs.input[index]);\n const valueMaskInput = this.refs.valueMaskInput;\n if ((valueMaskInput === null || valueMaskInput === void 0 ? void 0 : valueMaskInput.mask) && valueMaskInput.mask.textMaskInputElement) {\n valueMaskInput.mask.textMaskInputElement.update(value);\n }\n if (input.mask && input.mask.textMaskInputElement) {\n input.mask.textMaskInputElement.update(value);\n }\n else if (input.widget && input.widget.setValue) {\n input.widget.setValue(value);\n }\n else {\n input.value = value;\n }\n }\n get hasSetValue() {\n return this.hasValue() && !this.isEmpty(this.dataValue);\n }\n setDefaultValue() {\n if (this.defaultValue && this.shouldAddDefaultValue) {\n const defaultValue = (this.component.multiple && !this.dataValue.length) ? [] : this.defaultValue;\n this.setValue(defaultValue, {\n noUpdateEvent: true\n });\n }\n }\n /**\n * Restore the value of a control.\n */\n restoreValue() {\n if (this.hasSetValue) {\n this.setValue(this.dataValue, {\n noUpdateEvent: true\n });\n }\n else {\n this.setDefaultValue();\n }\n }\n /**\n * Normalize values coming into updateValue.\n *\n * @param value\n * @return {*}\n */\n normalizeValue(value) {\n if (this.component.multiple && !Array.isArray(value)) {\n value = value ? [value] : [];\n }\n return value;\n }\n /**\n * Update a value of this component.\n *\n * @param flags\n */\n updateComponentValue(value, flags = {}) {\n let newValue = (!flags.resetValue && (value === undefined || value === null)) ? this.getValue() : value;\n newValue = this.normalizeValue(newValue, flags);\n const oldValue = this.dataValue;\n let changed = ((newValue !== undefined) ? this.hasChanged(newValue, oldValue) : false);\n if (changed) {\n this.dataValue = newValue;\n changed = this.dataValue !== oldValue;\n this.updateOnChange(flags, changed);\n }\n if (this.componentModal && flags && flags.fromSubmission) {\n this.componentModal.setValue(value);\n }\n return changed;\n }\n /**\n * Updates the value of this component plus all sub-components.\n *\n * @param args\n * @return {boolean}\n */\n updateValue(...args) {\n return this.updateComponentValue(...args);\n }\n getIcon(name, content, styles, ref = 'icon') {\n return this.renderTemplate('icon', {\n className: this.iconClass(name),\n ref,\n styles,\n content\n });\n }\n /**\n * Resets the value of this component.\n */\n resetValue() {\n this.unset();\n this.setValue(this.emptyValue, {\n noUpdateEvent: true,\n noValidate: true,\n resetValue: true\n });\n }\n /**\n * Determine if the value of this component has changed.\n *\n * @param newValue\n * @param oldValue\n * @return {boolean}\n */\n hasChanged(newValue, oldValue) {\n if (((newValue === undefined) || (newValue === null)) &&\n ((oldValue === undefined) || (oldValue === null) || this.isEmpty(oldValue))) {\n return false;\n }\n // If we do not have a value and are getting set to anything other than undefined or null, then we changed.\n if (newValue !== undefined &&\n newValue !== null &&\n this.allowData &&\n !this.hasValue()) {\n return true;\n }\n return !lodash_1.default.isEqual(newValue, oldValue);\n }\n /**\n * Update the value on change.\n *\n * @param flags\n */\n updateOnChange(flags = {}, changed = false) {\n if (!flags.noUpdateEvent && changed) {\n if (flags.fromSubmission) {\n // Reset the errors when a submission has been made and allow it to revalidate.\n this._errors = [];\n }\n this.triggerChange(flags);\n return true;\n }\n return false;\n }\n /**\n * Perform a calculated value operation.\n *\n * @param data - The global data object.\n *\n * @return {boolean} - If the value changed during calculation.\n */\n convertNumberOrBoolToString(value) {\n if (typeof value === 'number' || typeof value === 'boolean') {\n return value.toString();\n }\n return value;\n }\n doValueCalculation(dataValue, data, row) {\n var _a;\n return this.evaluate(this.component.calculateValue, {\n value: dataValue,\n data,\n row: row || this.data,\n submission: ((_a = this.root) === null || _a === void 0 ? void 0 : _a._submission) || {\n data: this.rootValue\n }\n }, 'value');\n }\n /* eslint-disable max-statements */\n calculateComponentValue(data, flags, row) {\n // Skip value calculation for the component if we don't have entire form data set or in builder mode\n if (this.builderMode || lodash_1.default.isUndefined(lodash_1.default.get(this, 'root.data'))) {\n return false;\n }\n // If no calculated value or\n // hidden and set to clearOnHide (Don't calculate a value for a hidden field set to clear when hidden)\n const { clearOnHide } = this.component;\n const shouldBeCleared = !this.visible && clearOnHide;\n const allowOverride = lodash_1.default.get(this.component, 'allowCalculateOverride', false);\n if (shouldBeCleared) {\n // remove calculated value so that the value is recalculated once component becomes visible\n if (this.hasOwnProperty('calculatedValue') && allowOverride) {\n lodash_1.default.unset(this, 'calculatedValue');\n }\n return false;\n }\n // Handle all cases when calculated values should not fire.\n if ((this.options.readOnly && !this.options.pdf && !this.component.calculateValue) ||\n !(this.component.calculateValue || this.component.calculateValueVariable) ||\n (this.options.server && !this.component.calculateServer) ||\n (flags.dataSourceInitialLoading && allowOverride)) {\n return false;\n }\n const dataValue = this.dataValue;\n // Calculate the new value.\n let calculatedValue = this.doValueCalculation(dataValue, data, row, flags);\n if (this.options.readOnly && dataValue && !calculatedValue) {\n return false;\n }\n if (lodash_1.default.isNil(calculatedValue)) {\n calculatedValue = this.emptyValue;\n }\n const changed = !lodash_1.default.isEqual(dataValue, calculatedValue);\n // Do not override calculations on server if they have calculateServer set.\n if (allowOverride) {\n // The value is considered locked if it is not empty and comes from a submission value.\n const fromSubmission = (flags.fromSubmission && this.component.persistent === true);\n if (this.isEmpty(dataValue)) {\n // Reset the calculation lock if ever the data is cleared.\n this.calculationLocked = false;\n }\n else if (this.calculationLocked || fromSubmission) {\n this.calculationLocked = true;\n return false;\n }\n const firstPass = (this.calculatedValue === undefined) || flags.resetValue;\n if (firstPass) {\n this.calculatedValue = null;\n }\n const newCalculatedValue = this.normalizeValue(this.convertNumberOrBoolToString(calculatedValue));\n const previousCalculatedValue = this.normalizeValue(this.convertNumberOrBoolToString(this.calculatedValue));\n const normalizedDataValue = this.normalizeValue(this.convertNumberOrBoolToString(dataValue));\n const calculationChanged = !lodash_1.default.isEqual(previousCalculatedValue, newCalculatedValue);\n const previousChanged = !lodash_1.default.isEqual(normalizedDataValue, previousCalculatedValue);\n if (calculationChanged && previousChanged && !firstPass) {\n return false;\n }\n // Check to ensure that the calculated value is different than the previously calculated value.\n if (previousCalculatedValue && previousChanged && !calculationChanged) {\n this.calculatedValue = null;\n return false;\n }\n if (flags.isReordered || !calculationChanged) {\n return false;\n }\n if (fromSubmission) {\n // If we set value from submission and it differs from calculated one, set the calculated value to prevent overriding dataValue in the next pass\n this.calculatedValue = (0, utils_1.fastCloneDeep)(calculatedValue);\n return false;\n }\n // If this is the firstPass, and the dataValue is different than to the calculatedValue.\n if (firstPass && !this.isEmpty(dataValue) && changed && calculationChanged) {\n // Return that we have a change so it will perform another pass.\n return true;\n }\n }\n this.calculatedValue = (0, utils_1.fastCloneDeep)(calculatedValue);\n if (changed) {\n if (!flags.noPristineChangeOnModified) {\n this.pristine = false;\n }\n flags.triggeredComponentId = this.id;\n return this.setValue(calculatedValue, flags);\n }\n return false;\n }\n /* eslint-enable max-statements */\n /**\n * Performs calculations in this component plus any child components.\n *\n * @param args\n * @return {boolean}\n */\n calculateValue(data, flags, row) {\n data = data || this.rootValue;\n flags = flags || {};\n row = row || this.data;\n return this.calculateComponentValue(data, flags, row);\n }\n /**\n * Get this component's label text.\n *\n */\n get label() {\n return this.component.label;\n }\n /**\n * Set this component's label text and render it.\n *\n * @param value - The new label text.\n */\n set label(value) {\n this.component.label = value;\n if (this.labelElement) {\n this.labelElement.innerText = value;\n }\n }\n /**\n * Get FormioForm element at the root of this component tree.\n *\n */\n getRoot() {\n return this.root;\n }\n /**\n * Returns the invalid message, or empty string if the component is valid.\n *\n * @param data\n * @param dirty\n * @return {*}\n */\n invalidMessage(data, dirty, ignoreCondition, row) {\n if (!ignoreCondition && !this.checkCondition(row, data)) {\n return '';\n }\n // See if this is forced invalid.\n if (this.invalid) {\n return this.invalid;\n }\n // No need to check for errors if there is no input or if it is pristine.\n if (!this.hasInput || (!dirty && this.pristine)) {\n return '';\n }\n const validationScope = { errors: [] };\n (0, process_1.processOneSync)({\n component: this.component,\n data,\n row,\n path: this.path || this.component.key,\n scope: validationScope,\n instance: this,\n processors: [\n process_1.validateProcessInfo\n ]\n });\n const errors = validationScope.errors;\n const interpolatedErrors = FormioUtils.interpolateErrors(this.component, errors, this.t.bind(this));\n return lodash_1.default.map(interpolatedErrors, 'message').join('\\n\\n');\n }\n /**\n * Returns if the component is valid or not.\n *\n * @param data\n * @param dirty\n * @return {boolean}\n */\n isValid(data, dirty) {\n return !this.invalidMessage(data, dirty);\n }\n setComponentValidity(errors, dirty, silentCheck) {\n if (silentCheck) {\n return [];\n }\n const messages = errors.filter(message => !message.fromServer);\n if (errors.length && !!messages.length && (!this.isEmpty(this.defaultValue) || dirty || !this.pristine)) {\n return this.setCustomValidity(messages, dirty);\n }\n else {\n return this.setCustomValidity('');\n }\n }\n /**\n * Interpolate errors from the validation methods.\n * @param {*} errors\n * @returns\n */\n interpolateErrors(errors) {\n var _a;\n const interpolatedErrors = FormioUtils.interpolateErrors(this.component, errors, this.t.bind(this));\n return ((_a = this.serverErrors) === null || _a === void 0 ? void 0 : _a.length) ? [...interpolatedErrors, ...this.serverErrors] : interpolatedErrors;\n }\n /**\n * Show component validation errors.\n * @param {*} errors - An array of errors that have occured.\n * @param {*} data - The root submission data.\n * @param {*} row - The contextual row data.\n * @param {*} flags - The flags to perform validation.\n * @returns\n */\n showValidationErrors(errors, data, row, flags) {\n if (flags.silentCheck) {\n return [];\n }\n if (this.options.alwaysDirty) {\n flags.dirty = true;\n }\n if (flags.fromSubmission && this.hasValue(data)) {\n flags.dirty = true;\n }\n this.setDirty(flags.dirty);\n return this.setComponentValidity(errors, flags.dirty, flags.silentCheck, flags.fromSubmission);\n }\n /**\n * Perform a component validation.\n * @param {*} data - The root data you wish to use for this component.\n * @param {*} row - The contextual row data you wish to use for this component.\n * @param {*} flags - The flags to control the behavior of the validation.\n * @returns\n */\n validateComponent(data, row, flags = {}) {\n data = data || this.rootValue;\n row = row || this.data;\n const { async = false } = flags;\n if (this.shouldSkipValidation(data, row, flags)) {\n return async ? Promise.resolve([]) : [];\n }\n const processContext = {\n component: this.component,\n data,\n row,\n value: this.validationValue,\n path: this.path || this.component.key,\n instance: this,\n scope: { errors: [] },\n processors: [\n process_1.validateProcessInfo\n ]\n };\n if (async) {\n return (0, process_1.processOne)(processContext).then(() => {\n this._errors = this.interpolateErrors(processContext.scope.errors);\n return this._errors;\n });\n }\n (0, process_1.processOneSync)(processContext);\n this._errors = this.interpolateErrors(processContext.scope.errors);\n return this._errors;\n }\n /**\n * Checks the validity of this component and sets the error message if it is invalid.\n *\n * @param data\n * @param dirty\n * @param row\n * @return {boolean}\n */\n checkComponentValidity(data, dirty, row, flags = {}, allErrors = []) {\n data = data || this.rootValue;\n row = row || this.data;\n flags.dirty = dirty || false;\n if (flags.async) {\n return this.validateComponent(data, row, flags).then((errors) => {\n allErrors.push(...errors);\n if (this.parent && this.parent.childErrors) {\n if (errors.length) {\n this.parent.childErrors.push(...errors);\n }\n else {\n lodash_1.default.remove(this.parent.childErrors, (err) => err.component.key === this.component.key);\n }\n }\n this.showValidationErrors(errors, data, row, flags);\n return errors.length === 0;\n });\n }\n else {\n const errors = this.validateComponent(data, row, flags);\n this.showValidationErrors(errors, data, row, flags);\n allErrors.push(...errors);\n if (this.parent && this.parent.childErrors) {\n if (errors.length) {\n this.parent.childErrors.push(...errors);\n }\n else {\n lodash_1.default.remove(this.parent.childErrors, (err) => err.component.key === this.component.key);\n }\n }\n return errors.length === 0;\n }\n }\n /**\n * Checks the validity of the component.\n * @param {*} data\n * @param {*} dirty\n * @param {*} row\n * @param {*} silentCheck\n * @returns\n */\n checkValidity(data, dirty, row, silentCheck, errors = []) {\n data = data || this.rootValue;\n row = row || this.data;\n console.log('Deprecation warning: Component.checkValidity() will be deprecated in 6.x version of renderer. Use Component.validateComponent instead.');\n return this.checkComponentValidity(data, dirty, row, { silentCheck }, errors);\n }\n checkAsyncValidity(data, dirty, row, silentCheck, errors = []) {\n console.log('Deprecation warning: Component.checkAsyncValidity() will be deprecated in 6.x version of renderer. Use Component.validateComponent instead.');\n return this.checkComponentValidity(data, dirty, row, { async: true, silentCheck }, errors);\n }\n /**\n * Check the conditions, calculations, and validity of a single component and triggers an update if\n * something changed.\n *\n * @param data - The root data of the change event.\n * @param flags - The flags from this change event.\n *\n * @return boolean - If component is valid or not.\n */\n checkData(data, flags, row) {\n data = data || this.rootValue;\n flags = flags || {};\n row = row || this.data;\n // Needs for Nextgen Rules Engine\n this.resetCaches();\n // Do not trigger refresh if change was triggered on blur event since components with Refresh on Blur have their own listeners\n if (!flags.fromBlur) {\n this.checkRefreshOn(flags.changes, flags);\n }\n if (flags.noCheck) {\n return true;\n }\n this.checkComponentConditions(data, flags, row);\n if (this.id !== flags.triggeredComponentId) {\n this.calculateComponentValue(data, flags, row);\n }\n }\n checkModal(errors = [], dirty = false) {\n const messages = errors.filter(error => !error.fromServer);\n const isValid = errors.length === 0;\n if (!this.component.modalEdit || !this.componentModal) {\n return;\n }\n if (dirty && !isValid) {\n this.setErrorClasses([this.refs.openModal], dirty, !isValid, !!messages.length, this.refs.openModalWrapper);\n }\n else {\n this.clearErrorClasses(this.refs.openModalWrapper);\n }\n }\n get validationValue() {\n return this.dataValue;\n }\n isEmpty(value = this.dataValue) {\n const isEmptyArray = (lodash_1.default.isArray(value) && value.length === 1) ? lodash_1.default.isEqual(value[0], this.emptyValue) : false;\n return value == null || value.length === 0 || lodash_1.default.isEqual(value, this.emptyValue) || isEmptyArray;\n }\n isEqual(valueA, valueB = this.dataValue) {\n return (this.isEmpty(valueA) && this.isEmpty(valueB)) || lodash_1.default.isEqual(valueA, valueB);\n }\n /**\n * Check if a component is eligible for multiple validation\n *\n * @return {boolean}\n */\n validateMultiple() {\n return true;\n }\n clearErrorClasses(element = this.element) {\n this.removeClass(element, this.options.componentErrorClass);\n this.removeClass(element, 'alert alert-danger');\n this.removeClass(element, 'has-error');\n this.removeClass(element, 'has-message');\n }\n setInputWidgetErrorClasses(inputRefs, hasErrors) {\n if (!this.isInputComponent || !this.component.widget || !(inputRefs === null || inputRefs === void 0 ? void 0 : inputRefs.length)) {\n return;\n }\n inputRefs.forEach((input) => {\n if ((input === null || input === void 0 ? void 0 : input.widget) && input.widget.setErrorClasses) {\n input.widget.setErrorClasses(hasErrors);\n }\n });\n }\n addFocusBlurEvents(element) {\n this.addEventListener(element, 'focus', () => {\n if (this.root.focusedComponent !== this) {\n if (this.root.pendingBlur) {\n this.root.pendingBlur();\n }\n this.root.focusedComponent = this;\n this.emit('focus', this);\n }\n else if (this.root.focusedComponent === this && this.root.pendingBlur) {\n this.root.pendingBlur.cancel();\n this.root.pendingBlur = null;\n }\n });\n this.addEventListener(element, 'blur', () => {\n this.root.pendingBlur = FormioUtils.delay(() => {\n this.emit('blur', this);\n if (this.component.validateOn === 'blur') {\n this.root.triggerChange({ fromBlur: true }, {\n instance: this,\n component: this.component,\n value: this.dataValue,\n flags: { fromBlur: true }\n });\n }\n this.root.focusedComponent = null;\n this.root.pendingBlur = null;\n });\n });\n }\n // eslint-disable-next-line max-statements\n setCustomValidity(messages, dirty, external) {\n const inputRefs = this.isInputComponent ? this.refs.input || [] : null;\n if (typeof messages === 'string' && messages) {\n messages = {\n level: 'error',\n message: messages,\n component: this.component,\n };\n }\n if (!Array.isArray(messages)) {\n if (messages) {\n messages = [messages];\n }\n else {\n messages = [];\n }\n }\n const errors = messages.filter(message => message.level === 'error');\n let invalidInputRefs = inputRefs;\n // Filter the invalid input refs in multiple components\n if (this.component.multiple) {\n const refsArray = Array.from(inputRefs);\n refsArray.forEach((input) => {\n this.setElementInvalid(this.performInputMapping(input), false);\n });\n this.setInputWidgetErrorClasses(refsArray, false);\n invalidInputRefs = refsArray.filter((ref, index) => {\n var _a;\n return (_a = messages.some) === null || _a === void 0 ? void 0 : _a.call(messages, (msg) => {\n var _a;\n return ((_a = msg === null || msg === void 0 ? void 0 : msg.context) === null || _a === void 0 ? void 0 : _a.index) === index;\n });\n });\n }\n if (messages.length) {\n if (this.refs.messageContainer) {\n this.empty(this.refs.messageContainer);\n }\n this.emit('componentError', {\n instance: this,\n component: this.component,\n message: messages[0].message,\n messages,\n external: !!external,\n });\n this.addMessages(messages, dirty, invalidInputRefs);\n if (invalidInputRefs) {\n this.setErrorClasses(invalidInputRefs, dirty, !!errors.length, !!messages.length);\n }\n }\n else if (!errors.length || (errors[0].external === !!external)) {\n if (this.refs.messageContainer) {\n this.empty(this.refs.messageContainer);\n }\n if (this.refs.modalMessageContainer) {\n this.empty(this.refs.modalMessageContainer);\n }\n if (invalidInputRefs) {\n this.setErrorClasses(invalidInputRefs, dirty, !!errors.length, !!messages.length);\n }\n this.clearErrorClasses();\n }\n this._visibleErrors = messages;\n return messages;\n }\n /**\n * Determines if the value of this component is hidden from the user as if it is coming from the server, but is\n * protected.\n *\n * @return {boolean|*}\n */\n isValueHidden() {\n if (this.component.protected && this.root.editing) {\n return false;\n }\n if (!this.root || !this.root.hasOwnProperty('editing')) {\n return false;\n }\n if (!this.root || !this.root.editing) {\n return false;\n }\n return (this.component.protected || !this.component.persistent || (this.component.persistent === 'client-only'));\n }\n shouldSkipValidation(data, row, flags = {}) {\n const { validateWhenHidden = false } = this.component || {};\n const forceValidOnHidden = (!this.visible || !this.checkCondition(row, data)) && !validateWhenHidden;\n if (forceValidOnHidden) {\n // If this component is forced valid when it is hidden, then we also need to reset the errors for this component.\n this._errors = [];\n }\n const rules = [\n // Do not validate if the flags say not too.\n () => flags.noValidate,\n // Force valid if component is read-only\n () => this.options.readOnly,\n // Do not check validations if component is not an input component.\n () => !this.hasInput,\n // Check to see if we are editing and if so, check component persistence.\n () => this.isValueHidden(),\n // Force valid if component is hidden.\n () => forceValidOnHidden\n ];\n return rules.some(pred => pred());\n }\n // Maintain reverse compatibility.\n whenReady() {\n console.warn('The whenReady() method has been deprecated. Please use the dataReady property instead.');\n return this.dataReady;\n }\n get dataReady() {\n return Promise.resolve();\n }\n /**\n * Prints out the value of this component as a string value.\n */\n asString(value) {\n value = value || this.getValue();\n return (Array.isArray(value) ? value : [value]).map(lodash_1.default.toString).join(', ');\n }\n /**\n * Return if the component is disabled.\n * @return {boolean}\n */\n get disabled() {\n return this._disabled || this.parentDisabled;\n }\n /**\n * Disable this component.\n *\n * @param {boolean} disabled\n */\n set disabled(disabled) {\n this._disabled = disabled;\n }\n setDisabled(element, disabled) {\n if (!element) {\n return;\n }\n element.disabled = disabled;\n if (disabled) {\n element.setAttribute('disabled', 'disabled');\n }\n else {\n element.removeAttribute('disabled');\n }\n }\n setLoading(element, loading) {\n if (!element || (element.loading === loading)) {\n return;\n }\n element.loading = loading;\n if (!element.loader && loading) {\n element.loader = this.ce('i', {\n class: `${this.iconClass('refresh', true)} button-icon-right`\n });\n }\n if (element.loader) {\n if (loading) {\n this.appendTo(element.loader, element);\n }\n else {\n this.removeChildFrom(element.loader, element);\n }\n }\n }\n selectOptions(select, tag, options, defaultValue) {\n lodash_1.default.each(options, (option) => {\n const attrs = {\n value: option.value\n };\n if (defaultValue !== undefined && (option.value === defaultValue)) {\n attrs.selected = 'selected';\n }\n const optionElement = this.ce('option', attrs);\n optionElement.appendChild(this.text(option.label));\n select.appendChild(optionElement);\n });\n }\n setSelectValue(select, value) {\n const options = select.querySelectorAll('option');\n lodash_1.default.each(options, (option) => {\n if (option.value === value) {\n option.setAttribute('selected', 'selected');\n }\n else {\n option.removeAttribute('selected');\n }\n });\n if (select.onchange) {\n select.onchange();\n }\n if (select.onselect) {\n select.onselect();\n }\n }\n getRelativePath(path) {\n const keyPart = `.${this.key}`;\n const thisPath = this.isInputComponent ? this.path\n : this.path.slice(0).replace(keyPart, '');\n return path.replace(thisPath, '');\n }\n clear() {\n this.detach();\n this.empty(this.getElement());\n }\n append(element) {\n this.appendTo(element, this.element);\n }\n prepend(element) {\n this.prependTo(element, this.element);\n }\n removeChild(element) {\n this.removeChildFrom(element, this.element);\n }\n detachLogic() {\n this.logic.forEach(logic => {\n if (logic.trigger.type === 'event') {\n const event = this.interpolate(logic.trigger.event);\n this.off(event); // only applies to callbacks on this component\n }\n });\n }\n attachLogic() {\n // Do not attach logic during builder mode.\n if (this.builderMode) {\n return;\n }\n this.logic.forEach((logic) => {\n if (logic.trigger.type === 'event') {\n const event = this.interpolate(logic.trigger.event);\n this.on(event, (...args) => {\n const newComponent = (0, utils_1.fastCloneDeep)(this.originalComponent);\n if (this.applyActions(newComponent, logic.actions, args)) {\n // If component definition changed, replace it.\n if (!lodash_1.default.isEqual(this.component, newComponent)) {\n this.component = newComponent;\n const visible = this.conditionallyVisible(null, null);\n const disabled = this.shouldDisabled;\n // Change states which won't be recalculated during redrawing\n if (this.visible !== visible) {\n this.visible = visible;\n }\n if (this.disabled !== disabled) {\n this.disabled = disabled;\n }\n this.redraw();\n }\n }\n }, true);\n }\n });\n }\n /**\n * Get the element information.\n */\n elementInfo() {\n const attributes = {\n name: this.options.name,\n type: this.component.inputType || 'text',\n class: 'form-control',\n lang: this.options.language\n };\n if (this.component.placeholder) {\n attributes.placeholder = this.t(this.component.placeholder, { _userInput: true });\n }\n if (this.component.tabindex) {\n attributes.tabindex = this.component.tabindex;\n }\n if (this.disabled) {\n attributes.disabled = 'disabled';\n }\n lodash_1.default.defaults(attributes, this.component.attributes);\n return {\n type: 'input',\n component: this.component,\n changeEvent: 'change',\n attr: attributes\n };\n }\n autofocus() {\n const hasAutofocus = this.component.autofocus && !this.builderMode && !this.options.preview;\n if (hasAutofocus) {\n this.on('render', () => this.focus(), true);\n }\n }\n scrollIntoView(element = this.element) {\n if (!element) {\n return;\n }\n const { left, top } = element.getBoundingClientRect();\n window.scrollTo(left + window.scrollX, top + window.scrollY);\n }\n focus(index) {\n var _a, _b;\n if ('beforeFocus' in this.parent) {\n this.parent.beforeFocus(this);\n }\n if ((_a = this.refs.input) === null || _a === void 0 ? void 0 : _a.length) {\n const focusingInput = typeof index === 'number' && this.refs.input[index]\n ? this.refs.input[index]\n : this.refs.input[this.refs.input.length - 1];\n if (((_b = this.component.widget) === null || _b === void 0 ? void 0 : _b.type) === 'calendar') {\n const sibling = focusingInput.nextSibling;\n if (sibling) {\n sibling.focus();\n }\n }\n else {\n focusingInput.focus();\n }\n }\n if (this.refs.openModal) {\n this.refs.openModal.focus();\n }\n if (this.parent.refs.openModal) {\n this.parent.refs.openModal.focus();\n }\n }\n /**\n * Get `Formio` instance for working with files\n */\n get fileService() {\n if (this.options.fileService) {\n return this.options.fileService;\n }\n if (this.options.formio) {\n return this.options.formio;\n }\n if (this.root && this.root.formio) {\n return this.root.formio;\n }\n const formio = new Formio_1.Formio();\n // If a form is loaded, then make sure to set the correct formUrl.\n if (this.root && this.root._form && this.root._form._id) {\n formio.formUrl = `${formio.projectUrl}/form/${this.root._form._id}`;\n }\n return formio;\n }\n resetCaches() { }\n get previewMode() {\n return false;\n }\n}\nexports[\"default\"] = Component;\nComponent.externalLibraries = {};\nComponent.requireLibrary = function (name, property, src, polling) {\n if (!Component.externalLibraries.hasOwnProperty(name)) {\n Component.externalLibraries[name] = {};\n Component.externalLibraries[name].ready = new Promise((resolve, reject) => {\n Component.externalLibraries[name].resolve = resolve;\n Component.externalLibraries[name].reject = reject;\n });\n const callbackName = `${name}Callback`;\n if (!polling && !window[callbackName]) {\n window[callbackName] = function () {\n this.resolve();\n }.bind(Component.externalLibraries[name]);\n }\n // See if the plugin already exists.\n const plugin = (0, utils_1.getScriptPlugin)(property);\n if (plugin) {\n Component.externalLibraries[name].resolve(plugin);\n }\n else {\n src = Array.isArray(src) ? src : [src];\n src.forEach((lib) => {\n let attrs = {};\n let elementType = '';\n if (typeof lib === 'string') {\n lib = {\n type: 'script',\n src: lib\n };\n }\n switch (lib.type) {\n case 'script':\n elementType = 'script';\n attrs = {\n src: lib.src,\n type: 'text/javascript',\n defer: true,\n async: true\n };\n break;\n case 'styles':\n elementType = 'link';\n attrs = {\n href: lib.src,\n rel: 'stylesheet'\n };\n break;\n }\n // Add the script to the top page.\n const script = document.createElement(elementType);\n for (const attr in attrs) {\n script.setAttribute(attr, attrs[attr]);\n }\n document.getElementsByTagName('head')[0].appendChild(script);\n });\n // if no callback is provided, then check periodically for the script.\n if (polling) {\n setTimeout(function checkLibrary() {\n const plugin = (0, utils_1.getScriptPlugin)(property);\n if (plugin) {\n Component.externalLibraries[name].resolve(plugin);\n }\n else {\n // check again after 200 ms.\n setTimeout(checkLibrary, 200);\n }\n }, 200);\n }\n }\n }\n return Component.externalLibraries[name].ready;\n};\nComponent.libraryReady = function (name) {\n if (Component.externalLibraries.hasOwnProperty(name) &&\n Component.externalLibraries[name].ready) {\n return Component.externalLibraries[name].ready;\n }\n return Promise.reject(`${name} library was not required.`);\n};\n\n\n//# sourceURL=webpack://Formio/./lib/cjs/components/_classes/component/Component.js?");
|
|
5319
5329
|
|
|
5320
5330
|
/***/ }),
|
|
5321
5331
|
|
|
@@ -5535,7 +5545,7 @@ eval("\nvar __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5535
5545
|
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
|
|
5536
5546
|
|
|
5537
5547
|
"use strict";
|
|
5538
|
-
eval("\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nconst lodash_1 = __importDefault(__webpack_require__(/*! lodash */ \"./node_modules/lodash/lodash.js\"));\nconst utils_1 = __webpack_require__(/*! ../../utils/utils */ \"./lib/cjs/utils/utils.js\");\nconst Field_1 = __importDefault(__webpack_require__(/*! ../_classes/field/Field */ \"./lib/cjs/components/_classes/field/Field.js\"));\nclass CheckBoxComponent extends Field_1.default {\n static schema(...extend) {\n return Field_1.default.schema({\n type: 'checkbox',\n inputType: 'checkbox',\n label: 'Checkbox',\n key: 'checkbox',\n dataGridLabel: true,\n labelPosition: 'right',\n value: '',\n name: ''\n }, ...extend);\n }\n static get builderInfo() {\n return {\n title: 'Checkbox',\n group: 'basic',\n icon: 'check-square',\n documentation: '/userguide/form-building/form-components#check-box',\n weight: 50,\n schema: CheckBoxComponent.schema()\n };\n }\n static get serverConditionSettings() {\n return CheckBoxComponent.conditionOperatorsSettings;\n }\n static get conditionOperatorsSettings() {\n return Object.assign(Object.assign({}, super.conditionOperatorsSettings), { operators: ['isEqual'], valueComponent() {\n return {\n valueType: 'boolean',\n data: {\n values: [\n { label: 'Checked', value: 'true' },\n { label: 'Not Checked', value: 'false' },\n ]\n },\n type: 'select'\n };\n } });\n }\n static savedValueTypes(schema) {\n schema = schema || {};\n const types = (0, utils_1.getComponentSavedTypes)(schema);\n if (lodash_1.default.isArray(types)) {\n return types;\n }\n if (schema.inputType === 'radio') {\n return [utils_1.componentValueTypes.string];\n }\n return [utils_1.componentValueTypes.boolean];\n }\n get defaultSchema() {\n return CheckBoxComponent.schema();\n }\n get labelClass() {\n let className = '';\n if (this.isInputComponent\n && !this.options.inputsOnly\n && this.component.validate\n && this.component.validate.required) {\n className += ' field-required';\n }\n return `${className}`;\n }\n get hasSetValue() {\n return this.hasValue();\n }\n get inputInfo() {\n const info = super.elementInfo();\n info.type = 'input';\n info.changeEvent = 'click';\n info.attr.type = this.component.inputType || 'checkbox';\n info.attr.class = 'form-check-input';\n if (this.component.name) {\n info.attr.name = `data[${this.component.name}]`;\n }\n info.attr.value = this.component.value ? this.component.value : 0;\n info.label = this.t(this.component.label, { _userInput: true });\n info.labelClass = this.labelClass;\n return info;\n }\n get labelInfo() {\n return {\n hidden: true\n };\n }\n render() {\n return super.render(this.renderTemplate('checkbox', {\n input: this.inputInfo,\n checked: this.checked,\n tooltip: this.interpolate(this.t(this.component.tooltip) || '', { _userInput: true }).replace(/(?:\\r\\n|\\r|\\n)/g, '<br />')\n }));\n }\n attach(element) {\n this.loadRefs(element, { input: 'multiple' });\n this.input = this.refs.input[0];\n if (this.refs.input) {\n this.addEventListener(this.input, this.inputInfo.changeEvent, () => this.updateValue(null, {\n modified: true\n }));\n this.addShortcut(this.input);\n }\n return super.attach(element);\n }\n detach(element) {\n if (element && this.input) {\n this.removeShortcut(this.input);\n }\n super.detach();\n }\n get emptyValue() {\n return this.component.inputType === 'radio' ? null : false;\n }\n isEmpty(value = this.dataValue) {\n return super.isEmpty(value) || value === false;\n }\n get key() {\n return this.component.name ? this.component.name : super.key;\n }\n getValueAt(index) {\n if (this.component.name) {\n return this.refs.input[index].checked ? this.component.value : '';\n }\n return !!this.refs.input[index].checked;\n }\n getValue() {\n const value = super.getValue();\n if (this.component.name) {\n return value ? this.setCheckedState(value) : this.setCheckedState(this.dataValue);\n }\n else {\n return (value === '') ? this.dataValue : !!value;\n }\n }\n get checked() {\n if (this.component.name) {\n return (this.dataValue === this.component.value);\n }\n return !!this.dataValue;\n }\n setCheckedState(value) {\n if (!this.input) {\n return;\n }\n if (this.component.name) {\n this.input.value = (value === this.component.value) ? this.component.value : 0;\n this.input.checked = (value === this.component.value) ? 1 : 0;\n }\n else if (value === 'on') {\n this.input.value = 1;\n this.input.checked = 1;\n }\n else if (value === 'off') {\n this.input.value = 0;\n this.input.checked = 0;\n }\n else if (value) {\n this.input.value = 1;\n this.input.checked = 1;\n }\n else {\n this.input.value = 0;\n this.input.checked = 0;\n }\n if (this.input.checked) {\n this.input.setAttribute('checked', true);\n }\n else {\n this.input.removeAttribute('checked');\n }\n return value;\n }\n setValue(value, flags = {}) {\n
|
|
5548
|
+
eval("\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nconst lodash_1 = __importDefault(__webpack_require__(/*! lodash */ \"./node_modules/lodash/lodash.js\"));\nconst utils_1 = __webpack_require__(/*! ../../utils/utils */ \"./lib/cjs/utils/utils.js\");\nconst Field_1 = __importDefault(__webpack_require__(/*! ../_classes/field/Field */ \"./lib/cjs/components/_classes/field/Field.js\"));\nclass CheckBoxComponent extends Field_1.default {\n static schema(...extend) {\n return Field_1.default.schema({\n type: 'checkbox',\n inputType: 'checkbox',\n label: 'Checkbox',\n key: 'checkbox',\n dataGridLabel: true,\n labelPosition: 'right',\n value: '',\n name: ''\n }, ...extend);\n }\n static get builderInfo() {\n return {\n title: 'Checkbox',\n group: 'basic',\n icon: 'check-square',\n documentation: '/userguide/form-building/form-components#check-box',\n weight: 50,\n schema: CheckBoxComponent.schema()\n };\n }\n static get serverConditionSettings() {\n return CheckBoxComponent.conditionOperatorsSettings;\n }\n static get conditionOperatorsSettings() {\n return Object.assign(Object.assign({}, super.conditionOperatorsSettings), { operators: ['isEqual'], valueComponent() {\n return {\n valueType: 'boolean',\n data: {\n values: [\n { label: 'Checked', value: 'true' },\n { label: 'Not Checked', value: 'false' },\n ]\n },\n type: 'select'\n };\n } });\n }\n static savedValueTypes(schema) {\n schema = schema || {};\n const types = (0, utils_1.getComponentSavedTypes)(schema);\n if (lodash_1.default.isArray(types)) {\n return types;\n }\n if (schema.inputType === 'radio') {\n return [utils_1.componentValueTypes.string];\n }\n return [utils_1.componentValueTypes.boolean];\n }\n get defaultSchema() {\n return CheckBoxComponent.schema();\n }\n get labelClass() {\n let className = '';\n if (this.isInputComponent\n && !this.options.inputsOnly\n && this.component.validate\n && this.component.validate.required) {\n className += ' field-required';\n }\n return `${className}`;\n }\n get hasSetValue() {\n return this.hasValue();\n }\n get inputInfo() {\n const info = super.elementInfo();\n info.type = 'input';\n info.changeEvent = 'click';\n info.attr.type = this.component.inputType || 'checkbox';\n info.attr.class = 'form-check-input';\n if (this.component.name) {\n info.attr.name = `data[${this.component.name}]`;\n }\n info.attr.value = this.component.value ? this.component.value : 0;\n info.label = this.t(this.component.label, { _userInput: true });\n info.labelClass = this.labelClass;\n return info;\n }\n get labelInfo() {\n return {\n hidden: true\n };\n }\n render() {\n return super.render(this.renderTemplate('checkbox', {\n input: this.inputInfo,\n checked: this.checked,\n tooltip: this.interpolate(this.t(this.component.tooltip) || '', { _userInput: true }).replace(/(?:\\r\\n|\\r|\\n)/g, '<br />')\n }));\n }\n attach(element) {\n this.loadRefs(element, { input: 'multiple' });\n this.input = this.refs.input[0];\n if (this.refs.input) {\n this.addEventListener(this.input, this.inputInfo.changeEvent, () => this.updateValue(null, {\n modified: true\n }));\n this.addShortcut(this.input);\n }\n return super.attach(element);\n }\n detach(element) {\n if (element && this.input) {\n this.removeShortcut(this.input);\n }\n super.detach();\n }\n get emptyValue() {\n return this.component.inputType === 'radio' ? null : false;\n }\n isEmpty(value = this.dataValue) {\n return super.isEmpty(value) || value === false;\n }\n get key() {\n return this.component.name ? this.component.name : super.key;\n }\n getValueAt(index) {\n if (this.component.name) {\n return this.refs.input[index].checked ? this.component.value : '';\n }\n return !!this.refs.input[index].checked;\n }\n getValue() {\n const value = super.getValue();\n if (this.component.name) {\n return value ? this.setCheckedState(value) : this.setCheckedState(this.dataValue);\n }\n else {\n return (value === '') ? this.dataValue : !!value;\n }\n }\n get checked() {\n if (this.component.name) {\n return (this.dataValue === this.component.value);\n }\n return !!this.dataValue;\n }\n setCheckedState(value) {\n if (!this.input) {\n return;\n }\n if (this.component.name) {\n this.input.value = (value === this.component.value) ? this.component.value : 0;\n this.input.checked = (value === this.component.value) ? 1 : 0;\n }\n else if (value === 'on') {\n this.input.value = 1;\n this.input.checked = 1;\n }\n else if (value === 'off') {\n this.input.value = 0;\n this.input.checked = 0;\n }\n else if (value) {\n this.input.value = 1;\n this.input.checked = 1;\n }\n else {\n this.input.value = 0;\n this.input.checked = 0;\n }\n if (this.input.checked) {\n this.input.setAttribute('checked', true);\n }\n else {\n this.input.removeAttribute('checked');\n }\n return value;\n }\n setValue(value, flags = {}) {\n this.setCheckedState(value);\n return super.setValue(value, flags);\n }\n getValueAsString(value) {\n const { name: componentName, value: componentValue } = this.component;\n const hasValue = componentName ? lodash_1.default.isEqual(value, componentValue) : value;\n if (lodash_1.default.isUndefined(value) && this.inDataTable) {\n return '';\n }\n return this.t(hasValue ? 'Yes' : 'No');\n }\n updateValue(value, flags) {\n // If this is a radio and is alredy checked, uncheck it.\n if (this.component.name && flags.modified && (this.dataValue === this.component.value)) {\n this.input.checked = 0;\n this.input.value = 0;\n this.dataValue = '';\n this.updateOnChange(flags, true);\n }\n const changed = super.updateValue(value, flags);\n // Update attributes of the input element\n if (changed && this.input) {\n if (this.input.checked) {\n this.input.setAttribute('checked', 'true');\n }\n else {\n this.input.removeAttribute('checked');\n }\n }\n return changed;\n }\n}\nexports[\"default\"] = CheckBoxComponent;\n\n\n//# sourceURL=webpack://Formio/./lib/cjs/components/checkbox/Checkbox.js?");
|
|
5539
5549
|
|
|
5540
5550
|
/***/ }),
|
|
5541
5551
|
|
|
@@ -5678,7 +5688,7 @@ eval("\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _argument
|
|
|
5678
5688
|
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
|
|
5679
5689
|
|
|
5680
5690
|
"use strict";
|
|
5681
|
-
eval("\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\n/* eslint-disable max-statements */\nconst lodash_1 = __importDefault(__webpack_require__(/*! lodash */ \"./node_modules/lodash/lodash.js\"));\nconst Component_1 = __importDefault(__webpack_require__(/*! ../_classes/component/Component */ \"./lib/cjs/components/_classes/component/Component.js\"));\nconst ComponentModal_1 = __importDefault(__webpack_require__(/*! ../_classes/componentModal/ComponentModal */ \"./lib/cjs/components/_classes/componentModal/ComponentModal.js\"));\nconst eventemitter3_1 = __importDefault(__webpack_require__(/*! eventemitter3 */ \"./node_modules/eventemitter3/index.js\"));\nconst utils_1 = __webpack_require__(/*! ../../utils/utils */ \"./lib/cjs/utils/utils.js\");\nconst Formio_1 = __webpack_require__(/*! ../../Formio */ \"./lib/cjs/Formio.js\");\nconst Form_1 = __importDefault(__webpack_require__(/*! ../../Form */ \"./lib/cjs/Form.js\"));\nclass FormComponent extends Component_1.default {\n static schema(...extend) {\n return Component_1.default.schema({\n label: 'Form',\n type: 'form',\n key: 'form',\n src: '',\n reference: true,\n form: '',\n path: '',\n tableView: true,\n }, ...extend);\n }\n static get builderInfo() {\n return {\n title: 'Nested Form',\n icon: 'wpforms',\n group: 'premium',\n documentation: '/userguide/form-building/premium-components#nested-form',\n weight: 110,\n schema: FormComponent.schema()\n };\n }\n static savedValueTypes() {\n return [utils_1.componentValueTypes.object];\n }\n init() {\n super.init();\n this.formObj = {\n display: this.component.display,\n settings: this.component.settings,\n components: this.component.components\n };\n this.valueChanged = false;\n this.subForm = null;\n this.formSrc = '';\n if (this.component.src) {\n this.formSrc = this.component.src;\n }\n if (!this.component.src &&\n !this.options.formio &&\n (this.component.form || this.component.path)) {\n if (this.component.project) {\n this.formSrc = Formio_1.Formio.getBaseUrl();\n // Check to see if it is a MongoID.\n if ((0, utils_1.isMongoId)(this.component.project)) {\n this.formSrc += '/project';\n }\n this.formSrc += `/${this.component.project}`;\n this.options.project = this.formSrc;\n }\n else {\n this.formSrc = Formio_1.Formio.getProjectUrl();\n this.options.project = this.formSrc;\n }\n if (this.component.form) {\n if ((0, utils_1.isMongoId)(this.component.form)) {\n this.formSrc += `/form/${this.component.form}`;\n }\n else {\n this.formSrc += `/${this.component.form}`;\n }\n }\n else if (this.component.path) {\n this.formSrc += `/${this.component.path}`;\n }\n }\n // Build the source based on the root src path.\n if (!this.formSrc && this.options.formio) {\n const rootSrc = this.options.formio.formsUrl;\n if (this.component.form && (0, utils_1.isMongoId)(this.component.form)) {\n this.formSrc = `${rootSrc}/${this.component.form}`;\n }\n else {\n const formPath = this.component.path || this.component.form;\n this.formSrc = `${rootSrc.replace(/\\/form$/, '')}/${formPath}`;\n }\n }\n if (this.builderMode && this.component.hasOwnProperty('formRevision')) {\n this.component.revision = this.component.formRevision;\n delete this.component.formRevision;\n }\n // Add revision version if set.\n if (this.component.revision || this.component.revision === 0 ||\n this.component.formRevision || this.component.formRevision === 0\n || this.component.revisionId) {\n this.setFormRevision(this.component.revisionId || this.component.revision || this.component.formRevision);\n }\n return this.createSubForm();\n }\n get dataReady() {\n return this.subFormReady || Promise.resolve();\n }\n get defaultValue() {\n // Not not provide a default value unless the subform is ready so that it will initialize correctly.\n return this.subForm ? super.defaultValue : null;\n }\n get defaultSchema() {\n return FormComponent.schema();\n }\n get emptyValue() {\n return { data: {} };\n }\n get ready() {\n return this.subFormReady || Promise.resolve();\n }\n get useOriginalRevision() {\n var _a, _b;\n return ((_a = this.component) === null || _a === void 0 ? void 0 : _a.useOriginalRevision) && !!((_b = this.formObj) === null || _b === void 0 ? void 0 : _b.revisions);\n }\n setFormRevision(rev) {\n // Remove current revisions from src if it is\n this.formSrc = this.formSrc.replace(/\\/v\\/[0-9a-z]+/, '');\n const revNumber = Number.parseInt(rev);\n if (!isNaN(revNumber)) {\n this.subFormRevision = rev;\n this.formSrc += `/v/${rev}`;\n }\n else {\n this.subFormRevision = undefined;\n }\n }\n getComponent(path, fn) {\n path = (0, utils_1.getArrayFromComponentPath)(path);\n if (path[0] === 'data') {\n path.shift();\n }\n const originalPathStr = `${this.path}.data.${(0, utils_1.getStringFromComponentPath)(path)}`;\n if (this.subForm) {\n return this.subForm.getComponent(path, fn, originalPathStr);\n }\n }\n /* eslint-disable max-statements */\n getSubOptions(options = {}) {\n options.events = this.createEmitter();\n // Make sure to not show the submit button in wizards in the nested forms.\n lodash_1.default.set(options, 'buttonSettings.showSubmit', false);\n if (!this.options) {\n return options;\n }\n if (this.options.base) {\n options.base = this.options.base;\n }\n if (this.options.project) {\n options.project = this.options.project;\n }\n if (this.options.readOnly || this.component.disabled) {\n options.readOnly = this.options.readOnly || this.component.disabled;\n }\n if (this.options.breadcrumbSettings) {\n options.breadcrumbSettings = this.options.breadcrumbSettings;\n }\n if (this.options.buttonSettings) {\n options.buttonSettings = lodash_1.default.clone(this.options.buttonSettings);\n }\n if (this.options.viewAsHtml) {\n options.viewAsHtml = this.options.viewAsHtml;\n }\n if (this.options.language) {\n options.language = this.options.language;\n }\n if (this.options.template) {\n options.template = this.options.template;\n }\n if (this.options.templates) {\n options.templates = this.options.templates;\n }\n if (this.options.renderMode) {\n options.renderMode = this.options.renderMode;\n }\n if (this.options.attachMode) {\n options.attachMode = this.options.attachMode;\n }\n if (this.options.iconset) {\n options.iconset = this.options.iconset;\n }\n if (this.options.fileService) {\n options.fileService = this.options.fileService;\n }\n if (this.options.onChange) {\n options.onChange = this.options.onChange;\n }\n if (this.options.preview) {\n options.preview = this.options.preview;\n }\n if (this.options.inEditGrid) {\n options.inEditGrid = this.options.inEditGrid;\n }\n if (this.options.saveDraft) {\n options.saveDraft = this.options.saveDraft;\n options.formio = new Formio_1.Formio(this.formSrc);\n }\n if (this.options.saveDraftThrottle) {\n options.saveDraftThrottle = this.options.saveDraftThrottle;\n }\n return options;\n }\n /* eslint-enable max-statements */\n render() {\n if (this.builderMode) {\n return super.render(this.component.label || 'Nested form');\n }\n const subform = this.subForm ? this.subForm.render() : this.renderTemplate('loading');\n return super.render(subform);\n }\n asString(value) {\n return this.getValueAsString(value);\n }\n /**\n * Prints out the value of form components as a datagrid value.\n */\n getValueAsString(value, options) {\n if (!value) {\n return 'No data provided';\n }\n if (!value.data && value._id) {\n return value._id;\n }\n if (!value.data || !Object.keys(value.data).length) {\n return 'No data provided';\n }\n if (options === null || options === void 0 ? void 0 : options.email) {\n let result = (`\n <table border=\"1\" style=\"width:100%\">\n <tbody>\n `);\n this.everyComponent((component) => {\n if (component.isInputComponent && component.visible && !component.skipInEmail) {\n result += (`\n <tr>\n <th style=\"padding: 5px 10px;\">${component.label}</th>\n <td style=\"width:100%;padding:5px 10px;\">${component.getView(component.dataValue, options)}</td>\n </tr>\n `);\n }\n }, Object.assign(Object.assign({}, options), { fromRoot: true }));\n result += (`\n </tbody>\n </table>\n `);\n return result;\n }\n if (lodash_1.default.isEmpty(value)) {\n return '';\n }\n return '[Complex Data]';\n }\n attach(element) {\n // Don't attach in builder.\n if (this.builderMode) {\n return super.attach(element);\n }\n return super.attach(element)\n .then(() => {\n if (this.isSubFormLazyLoad() && !this.hasLoadedForm && !this.subFormLoading) {\n this.createSubForm(true);\n }\n return this.subFormReady.then(() => {\n this.empty(element);\n if (this.options.builder) {\n this.setContent(element, this.ce('div', {\n class: 'text-muted text-center p-2'\n }, this.text(this.formObj.title)));\n return;\n }\n this.setContent(element, this.render());\n if (this.subForm) {\n if (this.isNestedWizard) {\n element = this.root.element;\n }\n this.subForm.attach(element);\n this.valueChanged = this.hasSetValue;\n if (!this.valueChanged && this.dataValue.state !== 'submitted') {\n this.setDefaultValue();\n }\n else {\n this.restoreValue();\n }\n }\n if (!this.builderMode && this.component.modalEdit) {\n const modalShouldBeOpened = this.componentModal ? this.componentModal.isOpened : false;\n const currentValue = modalShouldBeOpened ? this.componentModal.currentValue : this.dataValue;\n this.componentModal = new ComponentModal_1.default(this, element, modalShouldBeOpened, currentValue, this._referenceAttributeName);\n this.setOpenModalElement();\n }\n this.calculateValue();\n });\n });\n }\n detach() {\n if (this.subForm) {\n this.subForm.detach();\n }\n super.detach();\n }\n get currentForm() {\n return this._currentForm;\n }\n get hasLoadedForm() {\n return this.formObj\n && this.formObj.components\n && Array.isArray(this.formObj.components)\n && this.formObj.components.length;\n }\n set currentForm(instance) {\n this._currentForm = instance;\n if (!this.subForm) {\n return;\n }\n this.subForm.getComponents().forEach(component => {\n component.currentForm = this;\n });\n }\n get isRevisionChanged() {\n return lodash_1.default.isNumber(this.subFormRevision)\n && lodash_1.default.isNumber(this.formObj._vid)\n && this.formObj._vid !== this.subFormRevision;\n }\n destroy(all = false) {\n if (this.subForm) {\n this.subForm.destroy(all);\n this.subForm = null;\n this.subFormReady = null;\n }\n super.destroy(all);\n }\n redraw() {\n if (this.subForm) {\n this.subForm.form = this.formObj;\n this.setSubFormDisabled(this.subForm);\n }\n return super.redraw();\n }\n /**\n * Pass everyComponent to subform.\n * @param args\n * @returns {*|void}\n */\n everyComponent(...args) {\n if (this.subForm) {\n this.subForm.everyComponent(...args);\n }\n }\n setSubFormDisabled(subForm) {\n subForm.disabled = this.disabled; // When the Nested Form is disabled make the subForm disabled\n }\n updateSubWizards(subForm) {\n var _a, _b;\n if (this.isNestedWizard && ((_a = this.root) === null || _a === void 0 ? void 0 : _a.subWizards) && ((_b = subForm === null || subForm === void 0 ? void 0 : subForm._form) === null || _b === void 0 ? void 0 : _b.display) === 'wizard') {\n const existedForm = this.root.subWizards.findIndex(form => form.component.form === this.component.form);\n if (existedForm !== -1) {\n this.root.subWizards[existedForm] = this;\n }\n else {\n this.root.subWizards.push(this);\n }\n this.emit('subWizardsUpdated', subForm);\n }\n }\n /**\n * Create a subform instance.\n *\n * @return {*}\n */\n createSubForm(fromAttach) {\n this.subFormReady = this.loadSubForm(fromAttach).then((form) => {\n if (!form) {\n return;\n }\n // Iterate through every component and hide the submit button.\n (0, utils_1.eachComponent)(form.components, (component) => {\n this.hideSubmitButton(component);\n });\n // If the subform is already created then destroy the old one.\n if (this.subForm) {\n this.subForm.destroy();\n }\n // Render the form.\n return (new Form_1.default(form, this.getSubOptions())).ready.then((instance) => {\n this.subForm = instance;\n this.subForm.currentForm = this;\n this.subForm.parent = this;\n this.subForm.parentVisible = this.visible;\n this.subForm.on('change', () => {\n if (this.subForm) {\n this.dataValue = this.subForm.getValue();\n this.triggerChange({\n noEmit: true\n });\n }\n });\n this.subForm.url = this.formSrc;\n this.subForm.nosubmit = true;\n this.subForm.root = this.root;\n this.subForm.localRoot = this.isNestedWizard ? this.localRoot : this.subForm;\n this.restoreValue();\n this.valueChanged = this.hasSetValue;\n this.onChange();\n return this.subForm;\n });\n }).then((subForm) => {\n this.updateSubWizards(subForm);\n return subForm;\n });\n return this.subFormReady;\n }\n hideSubmitButton(component) {\n const isSubmitButton = (component.type === 'button') &&\n ((component.action === 'submit') || !component.action);\n if (isSubmitButton) {\n component.hidden = true;\n }\n }\n /**\n * Load the subform.\n */\n loadSubForm(fromAttach) {\n var _a, _b, _c;\n if (this.builderMode || this.isHidden() || (this.isSubFormLazyLoad() && !fromAttach)) {\n return Promise.resolve();\n }\n if (this.hasLoadedForm && !this.isRevisionChanged &&\n !(this.options.pdf && ((_a = this.component) === null || _a === void 0 ? void 0 : _a.useOriginalRevision) && lodash_1.default.isNull(this.subForm) && !this.subFormLoading)) {\n // Pass config down to sub forms.\n if (this.root && this.root.form && this.root.form.config && !this.formObj.config) {\n this.formObj.config = this.root.form.config;\n }\n return Promise.resolve(this.formObj);\n }\n else if (this.formSrc) {\n this.subFormLoading = true;\n const options = ((_b = this.root.formio) === null || _b === void 0 ? void 0 : _b.base) && ((_c = this.root.formio) === null || _c === void 0 ? void 0 : _c.projectUrl)\n ? {\n base: this.root.formio.base,\n project: this.root.formio.projectUrl,\n }\n : {};\n return (new Formio_1.Formio(this.formSrc, options)).loadForm({ params: { live: 1 } })\n .then((formObj) => {\n this.formObj = formObj;\n if (this.options.pdf && this.component.useOriginalRevision) {\n this.formObj.display = 'form';\n }\n this.subFormLoading = false;\n return formObj;\n })\n .catch((err) => {\n console.log(err);\n return null;\n });\n }\n return Promise.resolve();\n }\n get subFormData() {\n var _a;\n return ((_a = this.dataValue) === null || _a === void 0 ? void 0 : _a.data) || {};\n }\n checkComponentValidity(data, dirty, row, options, errors = []) {\n options = options || {};\n const silentCheck = options.silentCheck || false;\n if (this.subForm) {\n return this.subForm.checkValidity(this.subFormData, dirty, null, silentCheck, errors);\n }\n return super.checkComponentValidity(data, dirty, row, options, errors);\n }\n checkComponentConditions(data, flags, row) {\n const visible = super.checkComponentConditions(data, flags, row);\n // Return if already hidden\n if (!visible) {\n return visible;\n }\n if (this.subForm) {\n return this.subForm.checkConditions(this.subFormData);\n }\n // There are few cases when subForm is not loaded when a change is triggered,\n // so we need to perform checkConditions after it is ready, or some conditional fields might be hidden in View mode\n else if (this.subFormReady) {\n this.subFormReady.then(() => {\n if (this.subForm) {\n return this.subForm.checkConditions(this.subFormData);\n }\n });\n }\n return visible;\n }\n calculateValue(data, flags, row) {\n if (this.subForm) {\n return this.subForm.calculateValue(this.subFormData, flags);\n }\n return super.calculateValue(data, flags, row);\n }\n setPristine(pristine) {\n super.setPristine(pristine);\n if (this.subForm) {\n this.subForm.setPristine(pristine);\n }\n }\n /**\n * Determine if the subform should be submitted.\n * @return {*|boolean}\n */\n get shouldSubmit() {\n return this.subFormReady && (!this.component.hasOwnProperty('reference') || this.component.reference) && !this.isHidden();\n }\n /**\n * Returns the data for the subform.\n *\n * @return {*}\n */\n getSubFormData() {\n if (lodash_1.default.get(this.subForm, 'form.display') === 'pdf') {\n return this.subForm.getSubmission();\n }\n else {\n return Promise.resolve(this.dataValue);\n }\n }\n /**\n * Submit the subform if configured to do so.\n *\n * @return {*}\n */\n submitSubForm() {\n // If we wish to submit the form on next page, then do that here.\n if (this.shouldSubmit) {\n return this.subFormReady.then(() => {\n if (!this.subForm) {\n return this.dataValue;\n }\n this.subForm.nosubmit = false;\n this.subForm.submitted = true;\n return this.subForm.submitForm().then(result => {\n this.subForm.loading = false;\n this.subForm.showAllErrors = false;\n this.dataValue = result.submission;\n return this.dataValue;\n }).catch(err => {\n this.subForm.showAllErrors = true;\n this.subForm.onSubmissionError(err);\n return Promise.reject(err);\n });\n });\n }\n return this.getSubFormData();\n }\n /**\n * Submit the form before the next page is triggered.\n */\n beforePage(next) {\n // Should not submit child forms if we are going to the previous page\n if (!next) {\n return super.beforePage(next);\n }\n return this.submitSubForm(true).then(() => super.beforePage(next));\n }\n /**\n * Submit the form before the whole form is triggered.\n */\n beforeSubmit() {\n var _a, _b, _c;\n const submission = this.dataValue;\n // Cancel triggered saveDraft\n if (((_a = this.subForm) === null || _a === void 0 ? void 0 : _a.draftEnabled) && ((_b = this.subForm.triggerSaveDraft) === null || _b === void 0 ? void 0 : _b.cancel)) {\n this.subForm.triggerSaveDraft.cancel();\n }\n const isAlreadySubmitted = submission && submission._id && submission.form;\n // This submission has already been submitted, so just return the reference data.\n if (isAlreadySubmitted && !((_c = this.subForm) === null || _c === void 0 ? void 0 : _c.wizard)) {\n this.dataValue = submission;\n return Promise.resolve(this.dataValue);\n }\n return this.submitSubForm(false)\n .then(() => {\n return this.dataValue;\n })\n .then(() => super.beforeSubmit());\n }\n isSubFormLazyLoad() {\n var _a, _b;\n return ((_b = (_a = this.root) === null || _a === void 0 ? void 0 : _a._form) === null || _b === void 0 ? void 0 : _b.display) === 'wizard' && this.component.lazyLoad;\n }\n isHidden() {\n if (!this.visible) {\n return true;\n }\n return !super.checkConditions(this.rootValue);\n }\n setValue(submission, flags = {}) {\n var _a;\n const changed = super.setValue(submission, flags);\n this.valueChanged = true;\n if (this.subForm) {\n const revisionPath = submission._frid ? '_frid' : '_vid';\n const shouldLoadOriginalRevision = this.useOriginalRevision\n && (lodash_1.default.isNumber(submission[revisionPath]) || lodash_1.default.isNumber(submission._fvid))\n && lodash_1.default.isNumber((_a = this.subForm.form) === null || _a === void 0 ? void 0 : _a[revisionPath])\n && submission._fvid !== this.subForm.form[revisionPath];\n if (shouldLoadOriginalRevision) {\n this.setFormRevision(submission._frid || submission._fvid);\n this.createSubForm().then(() => {\n this.attach(this.element);\n });\n }\n else {\n this.setSubFormValue(submission, flags);\n }\n }\n return changed;\n }\n setSubFormValue(submission, flags) {\n var _a, _b;\n const shouldLoadSubmissionById = submission\n && submission._id\n && this.subForm.formio\n && lodash_1.default.isEmpty(submission.data);\n if (shouldLoadSubmissionById) {\n const formId = submission.form || this.formObj.form || this.component.form;\n const submissionUrl = `${this.subForm.formio.formsUrl}/${formId}/submission/${submission._id}`;\n const options = ((_a = this.root.formio) === null || _a === void 0 ? void 0 : _a.base) && ((_b = this.root.formio) === null || _b === void 0 ? void 0 : _b.projectUrl)\n ? {\n base: this.root.formio.base,\n project: this.root.formio.projectUrl,\n }\n : {};\n this.subForm.setUrl(submissionUrl, Object.assign(Object.assign({}, this.options), options));\n this.subForm.loadSubmission().catch((err) => {\n console.error(`Unable to load subform submission ${submission._id}:`, err);\n });\n }\n else {\n this.subForm.setValue(submission, flags);\n }\n }\n isEmpty(value = this.dataValue) {\n return value === null || lodash_1.default.isEqual(value, this.emptyValue) || (this.areAllComponentsEmpty(value === null || value === void 0 ? void 0 : value.data) && !(value === null || value === void 0 ? void 0 : value._id));\n }\n areAllComponentsEmpty(data) {\n let res = true;\n if (this.subForm) {\n this.subForm.everyComponent((comp) => {\n const componentValue = lodash_1.default.get(data, comp.key);\n res &= comp.isEmpty(componentValue);\n });\n }\n else {\n res = false;\n }\n return res;\n }\n getValue() {\n if (this.subForm) {\n return this.subForm.getValue();\n }\n return this.dataValue;\n }\n get errors() {\n let errors = super.errors;\n if (this.subForm) {\n errors = errors.concat(this.subForm.errors);\n }\n return errors;\n }\n updateSubFormVisibility() {\n if (this.subForm) {\n this.subForm.parentVisible = this.visible;\n }\n }\n /**\n * Determines if this form is a Nested Wizard\n * which means it should be a Wizard itself and should be a direct child of a Wizard's page\n * @returns {boolean}\n */\n get isNestedWizard() {\n var _a, _b, _c, _d, _e;\n return ((_b = (_a = this.subForm) === null || _a === void 0 ? void 0 : _a._form) === null || _b === void 0 ? void 0 : _b.display) === 'wizard' && ((_e = (_d = (_c = this.parent) === null || _c === void 0 ? void 0 : _c.parent) === null || _d === void 0 ? void 0 : _d._form) === null || _e === void 0 ? void 0 : _e.display) === 'wizard';\n }\n get visible() {\n return super.visible;\n }\n set visible(value) {\n const isNestedWizard = this.isNestedWizard;\n if (this._visible !== value) {\n this._visible = value;\n // Form doesn't load if hidden. If it becomes visible, create the form.\n if (!this.subForm && value) {\n this.createSubForm();\n this.subFormReady.then(() => {\n this.updateSubFormVisibility();\n this.clearOnHide();\n });\n this.redraw();\n return;\n }\n this.updateSubFormVisibility();\n this.clearOnHide();\n isNestedWizard ? this.rebuild() : this.redraw();\n }\n if (!value && isNestedWizard) {\n this.root.redraw();\n }\n }\n get parentVisible() {\n return super.parentVisible;\n }\n set parentVisible(value) {\n if (this._parentVisible !== value) {\n this._parentVisible = value;\n this.clearOnHide();\n // Form doesn't load if hidden. If it becomes visible, create the form.\n if (!this.subForm && value) {\n this.createSubForm();\n this.subFormReady.then(() => {\n this.updateSubFormVisibility();\n });\n this.redraw();\n return;\n }\n this.updateSubFormVisibility();\n this.redraw();\n }\n }\n isInternalEvent(event) {\n switch (event) {\n case 'focus':\n case 'blur':\n case 'componentChange':\n case 'componentError':\n case 'error':\n case 'formLoad':\n case 'languageChanged':\n case 'render':\n case 'checkValidity':\n case 'initialized':\n case 'submit':\n case 'submitButton':\n case 'nosubmit':\n case 'updateComponent':\n case 'submitDone':\n case 'submissionDeleted':\n case 'requestDone':\n case 'nextPage':\n case 'prevPage':\n case 'wizardNavigationClicked':\n case 'updateWizardNav':\n case 'restoreDraft':\n case 'saveDraft':\n case 'saveComponent':\n case 'pdfUploaded':\n return true;\n default:\n return false;\n }\n }\n createEmitter() {\n const emitter = new eventemitter3_1.default();\n const nativeEmit = emitter.emit;\n const that = this;\n emitter.emit = function (event, ...args) {\n const eventType = event.replace(`${that.options.namespace}.`, '');\n nativeEmit.call(this, event, ...args);\n if (!that.isInternalEvent(eventType)) {\n that.emit(eventType, ...args);\n }\n };\n return emitter;\n }\n deleteValue() {\n super.setValue(null, {\n noUpdateEvent: true,\n noDefault: true\n });\n this.unset();\n }\n}\nexports[\"default\"] = FormComponent;\n\n\n//# sourceURL=webpack://Formio/./lib/cjs/components/form/Form.js?");
|
|
5691
|
+
eval("\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\n/* eslint-disable max-statements */\nconst lodash_1 = __importDefault(__webpack_require__(/*! lodash */ \"./node_modules/lodash/lodash.js\"));\nconst Component_1 = __importDefault(__webpack_require__(/*! ../_classes/component/Component */ \"./lib/cjs/components/_classes/component/Component.js\"));\nconst ComponentModal_1 = __importDefault(__webpack_require__(/*! ../_classes/componentModal/ComponentModal */ \"./lib/cjs/components/_classes/componentModal/ComponentModal.js\"));\nconst eventemitter3_1 = __importDefault(__webpack_require__(/*! eventemitter3 */ \"./node_modules/eventemitter3/index.js\"));\nconst utils_1 = __webpack_require__(/*! ../../utils/utils */ \"./lib/cjs/utils/utils.js\");\nconst Formio_1 = __webpack_require__(/*! ../../Formio */ \"./lib/cjs/Formio.js\");\nconst Form_1 = __importDefault(__webpack_require__(/*! ../../Form */ \"./lib/cjs/Form.js\"));\nclass FormComponent extends Component_1.default {\n static schema(...extend) {\n return Component_1.default.schema({\n label: 'Form',\n type: 'form',\n key: 'form',\n src: '',\n reference: true,\n form: '',\n path: '',\n tableView: true,\n }, ...extend);\n }\n static get builderInfo() {\n return {\n title: 'Nested Form',\n icon: 'wpforms',\n group: 'premium',\n documentation: '/userguide/form-building/premium-components#nested-form',\n weight: 110,\n schema: FormComponent.schema()\n };\n }\n static savedValueTypes() {\n return [utils_1.componentValueTypes.object];\n }\n init() {\n super.init();\n this.formObj = {\n display: this.component.display,\n settings: this.component.settings,\n components: this.component.components\n };\n this.valueChanged = false;\n this.subForm = null;\n this.formSrc = '';\n if (this.component.src) {\n this.formSrc = this.component.src;\n }\n if (!this.component.src &&\n !this.options.formio &&\n (this.component.form || this.component.path)) {\n if (this.component.project) {\n this.formSrc = Formio_1.Formio.getBaseUrl();\n // Check to see if it is a MongoID.\n if ((0, utils_1.isMongoId)(this.component.project)) {\n this.formSrc += '/project';\n }\n this.formSrc += `/${this.component.project}`;\n this.options.project = this.formSrc;\n }\n else {\n this.formSrc = Formio_1.Formio.getProjectUrl();\n this.options.project = this.formSrc;\n }\n if (this.component.form) {\n if ((0, utils_1.isMongoId)(this.component.form)) {\n this.formSrc += `/form/${this.component.form}`;\n }\n else {\n this.formSrc += `/${this.component.form}`;\n }\n }\n else if (this.component.path) {\n this.formSrc += `/${this.component.path}`;\n }\n }\n // Build the source based on the root src path.\n if (!this.formSrc && this.options.formio) {\n const rootSrc = this.options.formio.formsUrl;\n if (this.component.form && (0, utils_1.isMongoId)(this.component.form)) {\n this.formSrc = `${rootSrc}/${this.component.form}`;\n }\n else {\n const formPath = this.component.path || this.component.form;\n this.formSrc = `${rootSrc.replace(/\\/form$/, '')}/${formPath}`;\n }\n }\n if (this.builderMode && this.component.hasOwnProperty('formRevision')) {\n this.component.revision = this.component.formRevision;\n delete this.component.formRevision;\n }\n // Add revision version if set.\n if (this.component.revision || this.component.revision === 0 ||\n this.component.formRevision || this.component.formRevision === 0\n || this.component.revisionId) {\n this.setFormRevision(this.component.revisionId || this.component.revision || this.component.formRevision);\n }\n return this.createSubForm();\n }\n get dataReady() {\n return this.subFormReady || Promise.resolve();\n }\n get defaultValue() {\n // Not not provide a default value unless the subform is ready so that it will initialize correctly.\n return this.subForm ? super.defaultValue : null;\n }\n get defaultSchema() {\n return FormComponent.schema();\n }\n get emptyValue() {\n return { data: {} };\n }\n get ready() {\n return this.subFormReady || Promise.resolve();\n }\n get useOriginalRevision() {\n var _a, _b;\n return ((_a = this.component) === null || _a === void 0 ? void 0 : _a.useOriginalRevision) && !!((_b = this.formObj) === null || _b === void 0 ? void 0 : _b.revisions);\n }\n setFormRevision(rev) {\n // Remove current revisions from src if it is\n this.formSrc = this.formSrc.replace(/\\/v\\/[0-9a-z]+/, '');\n const revNumber = Number.parseInt(rev);\n if (!isNaN(revNumber)) {\n this.subFormRevision = rev;\n this.formSrc += `/v/${rev}`;\n }\n else {\n this.subFormRevision = undefined;\n }\n }\n getComponent(path, fn) {\n path = (0, utils_1.getArrayFromComponentPath)(path);\n if (path[0] === 'data') {\n path.shift();\n }\n const originalPathStr = `${this.path}.data.${(0, utils_1.getStringFromComponentPath)(path)}`;\n if (this.subForm) {\n return this.subForm.getComponent(path, fn, originalPathStr);\n }\n }\n /* eslint-disable max-statements */\n getSubOptions(options = {}) {\n options.events = this.createEmitter();\n // Make sure to not show the submit button in wizards in the nested forms.\n lodash_1.default.set(options, 'buttonSettings.showSubmit', false);\n if (!this.options) {\n return options;\n }\n if (this.options.base) {\n options.base = this.options.base;\n }\n if (this.options.project) {\n options.project = this.options.project;\n }\n if (this.options.readOnly || this.component.disabled) {\n options.readOnly = this.options.readOnly || this.component.disabled;\n }\n if (this.options.breadcrumbSettings) {\n options.breadcrumbSettings = this.options.breadcrumbSettings;\n }\n if (this.options.buttonSettings) {\n options.buttonSettings = lodash_1.default.clone(this.options.buttonSettings);\n }\n if (this.options.viewAsHtml) {\n options.viewAsHtml = this.options.viewAsHtml;\n }\n if (this.options.language) {\n options.language = this.options.language;\n }\n if (this.options.template) {\n options.template = this.options.template;\n }\n if (this.options.templates) {\n options.templates = this.options.templates;\n }\n if (this.options.renderMode) {\n options.renderMode = this.options.renderMode;\n }\n if (this.options.attachMode) {\n options.attachMode = this.options.attachMode;\n }\n if (this.options.iconset) {\n options.iconset = this.options.iconset;\n }\n if (this.options.fileService) {\n options.fileService = this.options.fileService;\n }\n if (this.options.onChange) {\n options.onChange = this.options.onChange;\n }\n if (this.options.preview) {\n options.preview = this.options.preview;\n }\n if (this.options.inEditGrid) {\n options.inEditGrid = this.options.inEditGrid;\n }\n if (this.options.saveDraft) {\n options.saveDraft = this.options.saveDraft;\n options.formio = new Formio_1.Formio(this.formSrc);\n }\n if (this.options.saveDraftThrottle) {\n options.saveDraftThrottle = this.options.saveDraftThrottle;\n }\n if (this.options.skipDraftRestore) {\n options.skipDraftRestore = this.options.skipDraftRestore;\n }\n return options;\n }\n /* eslint-enable max-statements */\n render() {\n if (this.builderMode) {\n return super.render(this.component.label || 'Nested form');\n }\n const subform = this.subForm ? this.subForm.render() : this.renderTemplate('loading');\n return super.render(subform);\n }\n asString(value) {\n return this.getValueAsString(value);\n }\n /**\n * Prints out the value of form components as a datagrid value.\n */\n getValueAsString(value, options) {\n if (!value) {\n return 'No data provided';\n }\n if (!value.data && value._id) {\n return value._id;\n }\n if (!value.data || !Object.keys(value.data).length) {\n return 'No data provided';\n }\n if (options === null || options === void 0 ? void 0 : options.email) {\n let result = (`\n <table border=\"1\" style=\"width:100%\">\n <tbody>\n `);\n this.everyComponent((component) => {\n if (component.isInputComponent && component.visible && !component.skipInEmail) {\n result += (`\n <tr>\n <th style=\"padding: 5px 10px;\">${component.label}</th>\n <td style=\"width:100%;padding:5px 10px;\">${component.getView(component.dataValue, options)}</td>\n </tr>\n `);\n }\n }, Object.assign(Object.assign({}, options), { fromRoot: true }));\n result += (`\n </tbody>\n </table>\n `);\n return result;\n }\n if (lodash_1.default.isEmpty(value)) {\n return '';\n }\n return '[Complex Data]';\n }\n attach(element) {\n // Don't attach in builder.\n if (this.builderMode) {\n return super.attach(element);\n }\n return super.attach(element)\n .then(() => {\n if (this.isSubFormLazyLoad() && !this.hasLoadedForm && !this.subFormLoading) {\n this.createSubForm(true);\n }\n return this.subFormReady.then(() => {\n this.empty(element);\n if (this.options.builder) {\n this.setContent(element, this.ce('div', {\n class: 'text-muted text-center p-2'\n }, this.text(this.formObj.title)));\n return;\n }\n this.setContent(element, this.render());\n if (this.subForm) {\n if (this.isNestedWizard) {\n element = this.root.element;\n }\n this.subForm.attach(element);\n this.valueChanged = this.hasSetValue;\n if (!this.valueChanged && this.dataValue.state !== 'submitted') {\n this.setDefaultValue();\n }\n else {\n this.restoreValue();\n }\n }\n if (!this.builderMode && this.component.modalEdit) {\n const modalShouldBeOpened = this.componentModal ? this.componentModal.isOpened : false;\n const currentValue = modalShouldBeOpened ? this.componentModal.currentValue : this.dataValue;\n this.componentModal = new ComponentModal_1.default(this, element, modalShouldBeOpened, currentValue, this._referenceAttributeName);\n this.setOpenModalElement();\n }\n this.calculateValue();\n });\n });\n }\n detach() {\n if (this.subForm) {\n this.subForm.detach();\n }\n super.detach();\n }\n get currentForm() {\n return this._currentForm;\n }\n get hasLoadedForm() {\n return this.formObj\n && this.formObj.components\n && Array.isArray(this.formObj.components)\n && this.formObj.components.length;\n }\n set currentForm(instance) {\n this._currentForm = instance;\n if (!this.subForm) {\n return;\n }\n this.subForm.getComponents().forEach(component => {\n component.currentForm = this;\n });\n }\n get isRevisionChanged() {\n return lodash_1.default.isNumber(this.subFormRevision)\n && lodash_1.default.isNumber(this.formObj._vid)\n && this.formObj._vid !== this.subFormRevision;\n }\n destroy(all = false) {\n if (this.subForm) {\n this.subForm.destroy(all);\n this.subForm = null;\n this.subFormReady = null;\n }\n super.destroy(all);\n }\n redraw() {\n if (this.subForm) {\n this.subForm.form = this.formObj;\n this.setSubFormDisabled(this.subForm);\n }\n return super.redraw();\n }\n /**\n * Pass everyComponent to subform.\n * @param args\n * @returns {*|void}\n */\n everyComponent(...args) {\n if (this.subForm) {\n this.subForm.everyComponent(...args);\n }\n }\n setSubFormDisabled(subForm) {\n subForm.disabled = this.disabled; // When the Nested Form is disabled make the subForm disabled\n }\n updateSubWizards(subForm) {\n var _a, _b;\n if (this.isNestedWizard && ((_a = this.root) === null || _a === void 0 ? void 0 : _a.subWizards) && ((_b = subForm === null || subForm === void 0 ? void 0 : subForm._form) === null || _b === void 0 ? void 0 : _b.display) === 'wizard') {\n const existedForm = this.root.subWizards.findIndex(form => form.component.form === this.component.form);\n if (existedForm !== -1) {\n this.root.subWizards[existedForm] = this;\n }\n else {\n this.root.subWizards.push(this);\n }\n this.emit('subWizardsUpdated', subForm);\n }\n }\n /**\n * Create a subform instance.\n *\n * @return {*}\n */\n createSubForm(fromAttach) {\n this.subFormReady = this.loadSubForm(fromAttach).then((form) => {\n if (!form) {\n return;\n }\n // Iterate through every component and hide the submit button.\n (0, utils_1.eachComponent)(form.components, (component) => {\n this.hideSubmitButton(component);\n });\n // If the subform is already created then destroy the old one.\n if (this.subForm) {\n this.subForm.destroy();\n }\n // Render the form.\n return (new Form_1.default(form, this.getSubOptions())).ready.then((instance) => {\n this.subForm = instance;\n this.subForm.currentForm = this;\n this.subForm.parent = this;\n this.subForm.parentVisible = this.visible;\n this.subForm.on('change', () => {\n if (this.subForm) {\n this.dataValue = this.subForm.getValue();\n this.triggerChange({\n noEmit: true\n });\n }\n });\n this.subForm.url = this.formSrc;\n this.subForm.nosubmit = true;\n this.subForm.root = this.root;\n this.subForm.localRoot = this.isNestedWizard ? this.localRoot : this.subForm;\n this.restoreValue();\n this.valueChanged = this.hasSetValue;\n this.onChange();\n return this.subForm;\n });\n }).then((subForm) => {\n this.updateSubWizards(subForm);\n return subForm;\n });\n return this.subFormReady;\n }\n hideSubmitButton(component) {\n const isSubmitButton = (component.type === 'button') &&\n ((component.action === 'submit') || !component.action);\n if (isSubmitButton) {\n component.hidden = true;\n }\n }\n /**\n * Load the subform.\n */\n loadSubForm(fromAttach) {\n var _a, _b, _c;\n if (this.builderMode || this.isHidden() || (this.isSubFormLazyLoad() && !fromAttach)) {\n return Promise.resolve();\n }\n if (this.hasLoadedForm && !this.isRevisionChanged &&\n !(this.options.pdf && ((_a = this.component) === null || _a === void 0 ? void 0 : _a.useOriginalRevision) && lodash_1.default.isNull(this.subForm) && !this.subFormLoading)) {\n // Pass config down to sub forms.\n if (this.root && this.root.form && this.root.form.config && !this.formObj.config) {\n this.formObj.config = this.root.form.config;\n }\n return Promise.resolve(this.formObj);\n }\n else if (this.formSrc) {\n this.subFormLoading = true;\n const options = ((_b = this.root.formio) === null || _b === void 0 ? void 0 : _b.base) && ((_c = this.root.formio) === null || _c === void 0 ? void 0 : _c.projectUrl)\n ? {\n base: this.root.formio.base,\n project: this.root.formio.projectUrl,\n }\n : {};\n return (new Formio_1.Formio(this.formSrc, options)).loadForm({ params: { live: 1 } })\n .then((formObj) => {\n this.formObj = formObj;\n if (this.options.pdf && this.component.useOriginalRevision) {\n this.formObj.display = 'form';\n }\n this.subFormLoading = false;\n return formObj;\n })\n .catch((err) => {\n console.log(err);\n return null;\n });\n }\n return Promise.resolve();\n }\n get subFormData() {\n var _a;\n return ((_a = this.dataValue) === null || _a === void 0 ? void 0 : _a.data) || {};\n }\n checkComponentValidity(data, dirty, row, options, errors = []) {\n options = options || {};\n const silentCheck = options.silentCheck || false;\n if (this.subForm) {\n return this.subForm.checkValidity(this.subFormData, dirty, null, silentCheck, errors);\n }\n return super.checkComponentValidity(data, dirty, row, options, errors);\n }\n checkComponentConditions(data, flags, row) {\n const visible = super.checkComponentConditions(data, flags, row);\n // Return if already hidden\n if (!visible) {\n return visible;\n }\n if (this.subForm) {\n return this.subForm.checkConditions(this.subFormData);\n }\n // There are few cases when subForm is not loaded when a change is triggered,\n // so we need to perform checkConditions after it is ready, or some conditional fields might be hidden in View mode\n else if (this.subFormReady) {\n this.subFormReady.then(() => {\n if (this.subForm) {\n return this.subForm.checkConditions(this.subFormData);\n }\n });\n }\n return visible;\n }\n calculateValue(data, flags, row) {\n if (this.subForm) {\n return this.subForm.calculateValue(this.subFormData, flags);\n }\n return super.calculateValue(data, flags, row);\n }\n setPristine(pristine) {\n super.setPristine(pristine);\n if (this.subForm) {\n this.subForm.setPristine(pristine);\n }\n }\n /**\n * Determine if the subform should be submitted.\n * @return {*|boolean}\n */\n get shouldSubmit() {\n return this.subFormReady && (!this.component.hasOwnProperty('reference') || this.component.reference) && !this.isHidden();\n }\n /**\n * Returns the data for the subform.\n *\n * @return {*}\n */\n getSubFormData() {\n if (lodash_1.default.get(this.subForm, 'form.display') === 'pdf') {\n return this.subForm.getSubmission();\n }\n else {\n return Promise.resolve(this.dataValue);\n }\n }\n /**\n * Submit the subform if configured to do so.\n *\n * @return {*}\n */\n submitSubForm() {\n // If we wish to submit the form on next page, then do that here.\n if (this.shouldSubmit) {\n return this.subFormReady.then(() => {\n if (!this.subForm) {\n return this.dataValue;\n }\n this.subForm.nosubmit = false;\n this.subForm.submitted = true;\n return this.subForm.submitForm().then(result => {\n this.subForm.loading = false;\n this.subForm.showAllErrors = false;\n this.dataValue = result.submission;\n return this.dataValue;\n }).catch(err => {\n this.subForm.showAllErrors = true;\n this.subForm.onSubmissionError(err);\n return Promise.reject(err);\n });\n });\n }\n return this.getSubFormData();\n }\n /**\n * Submit the form before the next page is triggered.\n */\n beforePage(next) {\n // Should not submit child forms if we are going to the previous page\n if (!next) {\n return super.beforePage(next);\n }\n return this.submitSubForm(true).then(() => super.beforePage(next));\n }\n /**\n * Submit the form before the whole form is triggered.\n */\n beforeSubmit() {\n var _a, _b, _c;\n const submission = this.dataValue;\n // Cancel triggered saveDraft\n if (((_a = this.subForm) === null || _a === void 0 ? void 0 : _a.draftEnabled) && ((_b = this.subForm.triggerSaveDraft) === null || _b === void 0 ? void 0 : _b.cancel)) {\n this.subForm.triggerSaveDraft.cancel();\n }\n const isAlreadySubmitted = submission && submission._id && submission.form;\n const isDraftSubmission = this.options.saveDraft && submission.state === 'draft';\n // This submission has already been submitted, so just return the reference data.\n if (isAlreadySubmitted && !((_c = this.subForm) === null || _c === void 0 ? void 0 : _c.wizard) && !isDraftSubmission) {\n this.dataValue = submission;\n return Promise.resolve(this.dataValue);\n }\n return this.submitSubForm(false)\n .then(() => {\n return this.dataValue;\n })\n .then(() => super.beforeSubmit());\n }\n isSubFormLazyLoad() {\n var _a, _b;\n return ((_b = (_a = this.root) === null || _a === void 0 ? void 0 : _a._form) === null || _b === void 0 ? void 0 : _b.display) === 'wizard' && this.component.lazyLoad;\n }\n isHidden() {\n if (!this.visible) {\n return true;\n }\n return !super.checkConditions(this.rootValue);\n }\n setValue(submission, flags = {}) {\n var _a;\n const changed = super.setValue(submission, flags);\n this.valueChanged = true;\n if (this.subForm) {\n const revisionPath = submission._frid ? '_frid' : '_vid';\n const shouldLoadOriginalRevision = this.useOriginalRevision\n && (lodash_1.default.isNumber(submission[revisionPath]) || lodash_1.default.isNumber(submission._fvid))\n && lodash_1.default.isNumber((_a = this.subForm.form) === null || _a === void 0 ? void 0 : _a[revisionPath])\n && submission._fvid !== this.subForm.form[revisionPath];\n if (shouldLoadOriginalRevision) {\n this.setFormRevision(submission._frid || submission._fvid);\n this.createSubForm().then(() => {\n this.attach(this.element);\n });\n }\n else {\n this.setSubFormValue(submission, flags);\n }\n }\n return changed;\n }\n setSubFormValue(submission, flags) {\n var _a, _b;\n const shouldLoadSubmissionById = submission\n && submission._id\n && this.subForm.formio\n && lodash_1.default.isEmpty(submission.data);\n if (shouldLoadSubmissionById) {\n const formId = submission.form || this.formObj.form || this.component.form;\n const submissionUrl = `${this.subForm.formio.formsUrl}/${formId}/submission/${submission._id}`;\n const options = ((_a = this.root.formio) === null || _a === void 0 ? void 0 : _a.base) && ((_b = this.root.formio) === null || _b === void 0 ? void 0 : _b.projectUrl)\n ? {\n base: this.root.formio.base,\n project: this.root.formio.projectUrl,\n }\n : {};\n this.subForm.setUrl(submissionUrl, Object.assign(Object.assign({}, this.options), options));\n this.subForm.loadSubmission().catch((err) => {\n console.error(`Unable to load subform submission ${submission._id}:`, err);\n });\n }\n else {\n this.subForm.setValue(submission, flags);\n }\n }\n isEmpty(value = this.dataValue) {\n return value === null || lodash_1.default.isEqual(value, this.emptyValue) || (this.areAllComponentsEmpty(value === null || value === void 0 ? void 0 : value.data) && !(value === null || value === void 0 ? void 0 : value._id));\n }\n areAllComponentsEmpty(data) {\n let res = true;\n if (this.subForm) {\n this.subForm.everyComponent((comp) => {\n const componentValue = lodash_1.default.get(data, comp.key);\n res &= comp.isEmpty(componentValue);\n });\n }\n else {\n res = false;\n }\n return res;\n }\n getValue() {\n if (this.subForm) {\n return this.subForm.getValue();\n }\n return this.dataValue;\n }\n get errors() {\n let errors = super.errors;\n if (this.subForm) {\n errors = errors.concat(this.subForm.errors);\n }\n return errors;\n }\n updateSubFormVisibility() {\n if (this.subForm) {\n this.subForm.parentVisible = this.visible;\n }\n }\n /**\n * Determines if this form is a Nested Wizard\n * which means it should be a Wizard itself and should be a direct child of a Wizard's page\n * @returns {boolean}\n */\n get isNestedWizard() {\n var _a, _b, _c, _d, _e;\n return ((_b = (_a = this.subForm) === null || _a === void 0 ? void 0 : _a._form) === null || _b === void 0 ? void 0 : _b.display) === 'wizard' && ((_e = (_d = (_c = this.parent) === null || _c === void 0 ? void 0 : _c.parent) === null || _d === void 0 ? void 0 : _d._form) === null || _e === void 0 ? void 0 : _e.display) === 'wizard';\n }\n get visible() {\n return super.visible;\n }\n set visible(value) {\n const isNestedWizard = this.isNestedWizard;\n if (this._visible !== value) {\n this._visible = value;\n // Form doesn't load if hidden. If it becomes visible, create the form.\n if (!this.subForm && value) {\n this.createSubForm();\n this.subFormReady.then(() => {\n this.updateSubFormVisibility();\n this.clearOnHide();\n });\n this.redraw();\n return;\n }\n this.updateSubFormVisibility();\n this.clearOnHide();\n isNestedWizard ? this.rebuild() : this.redraw();\n }\n if (!value && isNestedWizard) {\n this.root.redraw();\n }\n }\n get parentVisible() {\n return super.parentVisible;\n }\n set parentVisible(value) {\n if (this._parentVisible !== value) {\n this._parentVisible = value;\n this.clearOnHide();\n // Form doesn't load if hidden. If it becomes visible, create the form.\n if (!this.subForm && value) {\n this.createSubForm();\n this.subFormReady.then(() => {\n this.updateSubFormVisibility();\n });\n this.redraw();\n return;\n }\n this.updateSubFormVisibility();\n this.redraw();\n }\n }\n isInternalEvent(event) {\n switch (event) {\n case 'focus':\n case 'blur':\n case 'componentChange':\n case 'componentError':\n case 'error':\n case 'formLoad':\n case 'languageChanged':\n case 'render':\n case 'checkValidity':\n case 'initialized':\n case 'submit':\n case 'submitButton':\n case 'nosubmit':\n case 'updateComponent':\n case 'submitDone':\n case 'submissionDeleted':\n case 'requestDone':\n case 'nextPage':\n case 'prevPage':\n case 'wizardNavigationClicked':\n case 'updateWizardNav':\n case 'restoreDraft':\n case 'saveDraft':\n case 'saveComponent':\n case 'pdfUploaded':\n return true;\n default:\n return false;\n }\n }\n createEmitter() {\n const emitter = new eventemitter3_1.default();\n const nativeEmit = emitter.emit;\n const that = this;\n emitter.emit = function (event, ...args) {\n const eventType = event.replace(`${that.options.namespace}.`, '');\n nativeEmit.call(this, event, ...args);\n if (!that.isInternalEvent(eventType)) {\n that.emit(eventType, ...args);\n }\n };\n return emitter;\n }\n deleteValue() {\n super.setValue(null, {\n noUpdateEvent: true,\n noDefault: true\n });\n this.unset();\n }\n}\nexports[\"default\"] = FormComponent;\n\n\n//# sourceURL=webpack://Formio/./lib/cjs/components/form/Form.js?");
|
|
5682
5692
|
|
|
5683
5693
|
/***/ }),
|
|
5684
5694
|
|
|
@@ -5766,7 +5776,7 @@ eval("\nvar __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5766
5776
|
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
|
|
5767
5777
|
|
|
5768
5778
|
"use strict";
|
|
5769
|
-
eval("\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nconst lodash_1 = __importDefault(__webpack_require__(/*! lodash */ \"./node_modules/lodash/lodash.js\"));\nconst ListComponent_1 = __importDefault(__webpack_require__(/*! ../_classes/list/ListComponent */ \"./lib/cjs/components/_classes/list/ListComponent.js\"));\nconst Formio_1 = __webpack_require__(/*! ../../Formio */ \"./lib/cjs/Formio.js\");\nconst utils_1 = __webpack_require__(/*! ../../utils/utils */ \"./lib/cjs/utils/utils.js\");\nclass RadioComponent extends ListComponent_1.default {\n static schema(...extend) {\n return ListComponent_1.default.schema({\n type: 'radio',\n inputType: 'radio',\n label: 'Radio',\n key: 'radio',\n values: [{ label: '', value: '' }],\n data: {\n url: '',\n },\n fieldSet: false\n }, ...extend);\n }\n static get builderInfo() {\n return {\n title: 'Radio',\n group: 'basic',\n icon: 'dot-circle-o',\n weight: 80,\n documentation: '/userguide/form-building/form-components#radio',\n schema: RadioComponent.schema()\n };\n }\n static get conditionOperatorsSettings() {\n return Object.assign(Object.assign({}, super.conditionOperatorsSettings), { valueComponent(classComp) {\n return {\n type: 'select',\n dataSrc: 'custom',\n valueProperty: 'value',\n dataType: classComp.dataType || '',\n data: {\n custom() {\n return classComp.values;\n }\n },\n };\n } });\n }\n static get serverConditionSettings() {\n return Object.assign(Object.assign({}, super.serverConditionSettings), { valueComponent(classComp) {\n return {\n type: 'select',\n dataSrc: 'custom',\n valueProperty: 'value',\n dataType: classComp.dataType || '',\n data: {\n custom: `values = ${classComp && classComp.values ? JSON.stringify(classComp.values) : []}`,\n },\n };\n } });\n }\n static savedValueTypes(schema) {\n const { boolean, string, number, object, array } = utils_1.componentValueTypes;\n const { dataType } = schema;\n const types = (0, utils_1.getComponentSavedTypes)(schema);\n if (types) {\n return types;\n }\n if (dataType === 'object') {\n return [object, array];\n }\n if (utils_1.componentValueTypes[dataType]) {\n return [utils_1.componentValueTypes[dataType]];\n }\n return [boolean, string, number, object, array];\n }\n constructor(component, options, data) {\n super(component, options, data);\n this.previousValue = this.dataValue || null;\n }\n get defaultSchema() {\n return RadioComponent.schema();\n }\n get defaultValue() {\n let defaultValue = super.defaultValue;\n if (!defaultValue && this.component.defaultValue === false) {\n defaultValue = this.component.defaultValue;\n }\n return defaultValue;\n }\n get inputInfo() {\n var _a;\n const info = super.elementInfo();\n info.type = 'input';\n info.changeEvent = 'click';\n info.attr.class = 'form-check-input';\n info.attr.name = info.attr.name += `[${(_a = this.root) === null || _a === void 0 ? void 0 : _a.id}-${this.id}]`;\n return info;\n }\n get emptyValue() {\n return '';\n }\n get isRadio() {\n return this.component.inputType === 'radio';\n }\n get optionSelectedClass() {\n return 'radio-selected';\n }\n get listData() {\n const listData = lodash_1.default.get(this.root, 'submission.metadata.listData', {});\n return lodash_1.default.get(listData, this.path);\n }\n init() {\n super.init();\n this.templateData = {};\n // Trigger an update.//\n let updateArgs = [];\n const triggerUpdate = lodash_1.default.debounce((...args) => {\n updateArgs = [];\n return this.updateItems.apply(this, args);\n }, 100);\n this.triggerUpdate = (...args) => {\n // Make sure we always resolve the previous promise before reassign it\n if (typeof this.itemsLoadedResolve === 'function') {\n this.itemsLoadedResolve();\n }\n this.itemsLoaded = new Promise((resolve) => {\n this.itemsLoadedResolve = resolve;\n });\n if (args.length) {\n updateArgs = args;\n }\n return triggerUpdate(...updateArgs);\n };\n this.itemsLoaded = new Promise((resolve) => {\n this.itemsLoadedResolve = resolve;\n });\n this.optionsLoaded = false;\n this.loadedOptions = [];\n // Get the template keys for this radio component.\n this.getTemplateKeys();\n }\n render() {\n return super.render(this.renderTemplate('radio', {\n input: this.inputInfo,\n inline: this.component.inline,\n values: this.component.dataSrc === 'values' ? this.component.values : this.loadedOptions,\n value: this.dataValue,\n row: this.row,\n }));\n }\n attach(element) {\n this.loadRefs(element, { input: 'multiple', wrapper: 'multiple' });\n this.refs.input.forEach((input, index) => {\n this.addEventListener(input, this.inputInfo.changeEvent, () => {\n this.updateValue(null, {\n modified: true,\n });\n });\n if (this.component.values[index]) {\n this.addShortcut(input, this.component.values[index].shortcut);\n }\n if (this.isRadio) {\n let dataValue = this.dataValue;\n if (!lodash_1.default.isString(this.dataValue)) {\n dataValue = lodash_1.default.toString(this.dataValue);\n }\n if (this.isSelectURL && lodash_1.default.isObject(this.loadedOptions[index].value)) {\n const optionValue = this.component.dataType === 'string' ? JSON.stringify(this.loadedOptions[index].value) : this.loadedOptions[index].value;\n input.checked = lodash_1.default.isEqual(optionValue, this.dataValue);\n }\n else {\n input.checked = (dataValue === input.value && (input.value || this.component.dataSrc !== 'url'));\n }\n this.addEventListener(input, 'keyup', (event) => {\n if (event.key === ' ' && dataValue === input.value) {\n event.preventDefault();\n this.updateValue(null, {\n modified: true,\n });\n }\n });\n }\n });\n this.triggerUpdate();\n this.setSelectedClasses();\n return super.attach(element);\n }\n detach(element) {\n if (element && this.refs.input) {\n this.refs.input.forEach((input, index) => {\n if (this.component.values[index]) {\n this.removeShortcut(input, this.component.values[index].shortcut);\n }\n });\n }\n super.detach();\n }\n getValue() {\n if (this.viewOnly || !this.refs.input || !this.refs.input.length) {\n return this.dataValue;\n }\n let value = this.dataValue;\n this.refs.input.forEach((input, index) => {\n if (input.checked) {\n value = (this.isSelectURL && lodash_1.default.isObject(this.loadedOptions[index].value)) ?\n this.loadedOptions[index].value :\n input.value;\n }\n });\n return value;\n }\n validateValueProperty() {\n if (this.component.dataSrc === 'values') {\n return true;\n }\n return !lodash_1.default.some(this.refs.wrapper, (wrapper, index) => this.refs.input[index].checked && this.loadedOptions[index].invalid);\n }\n validateValueAvailability(setting, value) {\n if (!(0, utils_1.boolValue)(setting) || !value) {\n return true;\n }\n const values = this.component.values;\n if (values) {\n return values.findIndex(({ value: optionValue }) => this.normalizeValue(optionValue) === value) !== -1;\n }\n return false;\n }\n getValueAsString(value) {\n if (lodash_1.default.isObject(value)) {\n value = JSON.stringify(value);\n }\n else if (!lodash_1.default.isString(value)) {\n value = lodash_1.default.toString(value);\n }\n if (this.component.dataSrc !== 'values') {\n return value;\n }\n const option = lodash_1.default.find(this.component.values, (v) => v.value === value);\n if (!value) {\n return lodash_1.default.get(option, 'label', '');\n }\n return lodash_1.default.get(option, 'label', '');\n }\n setValueAt(index, value) {\n if (this.refs.input && this.refs.input[index] && value !== null && value !== undefined) {\n const inputValue = this.refs.input[index].value;\n this.refs.input[index].checked = (inputValue === value.toString());\n }\n }\n loadItems(url, search, headers, options, method, body) {\n if (this.optionsLoaded) {\n return;\n }\n if (!this.shouldLoad && this.listData) {\n this.loadItemsFromMetadata();\n return;\n }\n // Ensure we have a method and remove any body if method is get\n method = method || 'GET';\n if (method.toUpperCase() === 'GET') {\n body = null;\n }\n // Set ignoreCache if it is\n options.ignoreCache = this.component.ignoreCache;\n // Make the request.\n options.header = headers;\n this.loading = true;\n Formio_1.Formio.makeRequest(this.options.formio, 'select', url, method, body, options)\n .then((response) => {\n this.loading = false;\n this.setItems(response);\n this.optionsLoaded = true;\n this.redraw();\n })\n .catch((err) => {\n this.handleLoadingError(err);\n });\n }\n loadItemsFromMetadata() {\n this.listData.forEach((item, i) => {\n this.loadedOptions[i] = {\n label: this.itemTemplate(item)\n };\n if (lodash_1.default.isEqual(item, this.selectData || lodash_1.default.pick(this.dataValue, lodash_1.default.keys(item)))) {\n this.loadedOptions[i].value = this.dataValue;\n }\n });\n this.optionsLoaded = true;\n this.redraw();\n }\n setItems(items) {\n const listData = [];\n items === null || items === void 0 ? void 0 : items.forEach((item, i) => {\n this.loadedOptions[i] = {\n value: this.component.valueProperty ? item[this.component.valueProperty] : item,\n label: this.component.valueProperty ? this.itemTemplate(item, item[this.component.valueProperty]) : this.itemTemplate(item, item, i)\n };\n listData.push(this.templateData[this.component.valueProperty ? item[this.component.valueProperty] : i]);\n if ((this.component.valueProperty || !this.isRadio) && (lodash_1.default.isUndefined(item[this.component.valueProperty]) ||\n (!this.isRadio && lodash_1.default.isObject(item[this.component.valueProperty])) ||\n (!this.isRadio && lodash_1.default.isBoolean(item[this.component.valueProperty])))) {\n this.loadedOptions[i].invalid = true;\n }\n });\n if (this.isSelectURL) {\n const submission = this.root.submission;\n if (!submission.metadata) {\n submission.metadata = {};\n }\n if (!submission.metadata.listData) {\n submission.metadata.listData = {};\n }\n lodash_1.default.set(submission.metadata.listData, this.path, listData);\n }\n }\n setSelectedClasses() {\n if (this.refs.wrapper) {\n //add/remove selected option class\n const value = this.dataValue;\n this.refs.wrapper.forEach((wrapper, index) => {\n const input = this.refs.input[index];\n const checked = (input.type === 'checkbox') ? value[input.value] : (input.value.toString() === value.toString());\n if (checked) {\n //add class to container when selected\n this.addClass(wrapper, this.optionSelectedClass);\n //change \"checked\" attribute\n input.setAttribute('checked', 'true');\n }\n else {\n this.removeClass(wrapper, this.optionSelectedClass);\n input.removeAttribute('checked');\n }\n });\n }\n }\n updateValue(value, flags) {\n const changed = super.updateValue(value, flags);\n if (changed) {\n this.setSelectedClasses();\n }\n if (!flags || !flags.modified || !this.isRadio) {\n if (changed) {\n this.previousValue = this.dataValue;\n }\n return changed;\n }\n // If they clicked on the radio that is currently selected, it needs to reset the value.\n this.currentValue = this.dataValue;\n const shouldResetValue = flags && flags.modified && !flags.noUpdateEvent && this.previousValue === this.currentValue;\n if (shouldResetValue) {\n this.resetValue();\n this.triggerChange(flags);\n this.setSelectedClasses();\n }\n this.previousValue = this.dataValue;\n return changed;\n }\n /**\n * Normalize values coming into updateValue.\n *\n * @param value\n * @return {*}\n */\n normalizeValue(value) {\n const dataType = this.component.dataType || 'auto';\n if (value === this.emptyValue) {\n return value;\n }\n switch (dataType) {\n case 'auto':\n if (!isNaN(parseFloat(value)) && isFinite(value) && lodash_1.default.toString(value) === Number(value).toString()) {\n value = +value;\n }\n if (value === 'true') {\n value = true;\n }\n if (value === 'false') {\n value = false;\n }\n break;\n case 'number':\n value = +value;\n break;\n case 'string':\n if (typeof value === 'object') {\n value = JSON.stringify(value);\n }\n else {\n value = String(value);\n }\n break;\n case 'boolean':\n value = !(!value || value.toString() === 'false');\n break;\n }\n if (this.isSelectURL && this.templateData && this.templateData[value]) {\n const submission = this.root.submission;\n if (!submission.metadata.selectData) {\n submission.metadata.selectData = {};\n }\n lodash_1.default.set(submission.metadata.selectData, this.path, this.templateData[value]);\n }\n return super.normalizeValue(value);\n }\n}\nexports[\"default\"] = RadioComponent;\n\n\n//# sourceURL=webpack://Formio/./lib/cjs/components/radio/Radio.js?");
|
|
5779
|
+
eval("\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nconst lodash_1 = __importDefault(__webpack_require__(/*! lodash */ \"./node_modules/lodash/lodash.js\"));\nconst ListComponent_1 = __importDefault(__webpack_require__(/*! ../_classes/list/ListComponent */ \"./lib/cjs/components/_classes/list/ListComponent.js\"));\nconst Formio_1 = __webpack_require__(/*! ../../Formio */ \"./lib/cjs/Formio.js\");\nconst utils_1 = __webpack_require__(/*! ../../utils/utils */ \"./lib/cjs/utils/utils.js\");\nclass RadioComponent extends ListComponent_1.default {\n static schema(...extend) {\n return ListComponent_1.default.schema({\n type: 'radio',\n inputType: 'radio',\n label: 'Radio',\n key: 'radio',\n values: [{ label: '', value: '' }],\n data: {\n url: '',\n },\n fieldSet: false\n }, ...extend);\n }\n static get builderInfo() {\n return {\n title: 'Radio',\n group: 'basic',\n icon: 'dot-circle-o',\n weight: 80,\n documentation: '/userguide/form-building/form-components#radio',\n schema: RadioComponent.schema()\n };\n }\n static get conditionOperatorsSettings() {\n return Object.assign(Object.assign({}, super.conditionOperatorsSettings), { valueComponent(classComp) {\n return {\n type: 'select',\n dataSrc: 'custom',\n valueProperty: 'value',\n dataType: classComp.dataType || '',\n data: {\n custom() {\n return classComp.values;\n }\n },\n };\n } });\n }\n static get serverConditionSettings() {\n return Object.assign(Object.assign({}, super.serverConditionSettings), { valueComponent(classComp) {\n return {\n type: 'select',\n dataSrc: 'custom',\n valueProperty: 'value',\n dataType: classComp.dataType || '',\n data: {\n custom: `values = ${classComp && classComp.values ? JSON.stringify(classComp.values) : []}`,\n },\n };\n } });\n }\n static savedValueTypes(schema) {\n const { boolean, string, number, object, array } = utils_1.componentValueTypes;\n const { dataType } = schema;\n const types = (0, utils_1.getComponentSavedTypes)(schema);\n if (types) {\n return types;\n }\n if (dataType === 'object') {\n return [object, array];\n }\n if (utils_1.componentValueTypes[dataType]) {\n return [utils_1.componentValueTypes[dataType]];\n }\n return [boolean, string, number, object, array];\n }\n constructor(component, options, data) {\n super(component, options, data);\n this.previousValue = this.dataValue || null;\n }\n get defaultSchema() {\n return RadioComponent.schema();\n }\n get defaultValue() {\n let defaultValue = super.defaultValue;\n if (!defaultValue && this.component.defaultValue === false) {\n defaultValue = this.component.defaultValue;\n }\n return defaultValue;\n }\n get inputInfo() {\n var _a;\n const info = super.elementInfo();\n info.type = 'input';\n info.changeEvent = 'click';\n info.attr.class = 'form-check-input';\n info.attr.name = info.attr.name += `[${(_a = this.root) === null || _a === void 0 ? void 0 : _a.id}-${this.id}]`;\n return info;\n }\n get emptyValue() {\n return '';\n }\n get isRadio() {\n return this.component.inputType === 'radio';\n }\n get optionSelectedClass() {\n return 'radio-selected';\n }\n get listData() {\n const listData = lodash_1.default.get(this.root, 'submission.metadata.listData', {});\n return lodash_1.default.get(listData, this.path);\n }\n init() {\n super.init();\n this.templateData = {};\n // Trigger an update.//\n let updateArgs = [];\n const triggerUpdate = lodash_1.default.debounce((...args) => {\n updateArgs = [];\n return this.updateItems.apply(this, args);\n }, 100);\n this.triggerUpdate = (...args) => {\n // Make sure we always resolve the previous promise before reassign it\n if (typeof this.itemsLoadedResolve === 'function') {\n this.itemsLoadedResolve();\n }\n this.itemsLoaded = new Promise((resolve) => {\n this.itemsLoadedResolve = resolve;\n });\n if (args.length) {\n updateArgs = args;\n }\n return triggerUpdate(...updateArgs);\n };\n this.itemsLoaded = new Promise((resolve) => {\n this.itemsLoadedResolve = resolve;\n });\n this.optionsLoaded = false;\n this.loadedOptions = [];\n // Get the template keys for this radio component.\n this.getTemplateKeys();\n }\n render() {\n return super.render(this.renderTemplate('radio', {\n input: this.inputInfo,\n inline: this.component.inline,\n values: this.component.dataSrc === 'values' ? this.component.values : this.loadedOptions,\n value: this.dataValue,\n row: this.row,\n }));\n }\n attach(element) {\n this.loadRefs(element, { input: 'multiple', wrapper: 'multiple' });\n this.refs.input.forEach((input, index) => {\n this.addEventListener(input, this.inputInfo.changeEvent, () => {\n this.updateValue(null, {\n modified: true,\n });\n });\n if (this.component.values[index]) {\n this.addShortcut(input, this.component.values[index].shortcut);\n }\n if (this.isRadio) {\n let dataValue = this.dataValue;\n if (!lodash_1.default.isString(this.dataValue)) {\n dataValue = lodash_1.default.toString(this.dataValue);\n }\n if (this.isSelectURL && lodash_1.default.isObject(this.loadedOptions[index].value)) {\n const optionValue = this.component.dataType === 'string' ? JSON.stringify(this.loadedOptions[index].value) : this.loadedOptions[index].value;\n input.checked = lodash_1.default.isEqual(optionValue, this.dataValue);\n }\n else {\n input.checked = (dataValue === input.value && (input.value || this.component.dataSrc !== 'url'));\n }\n this.addEventListener(input, 'keyup', (event) => {\n if (event.key === ' ' && dataValue === input.value) {\n event.preventDefault();\n this.updateValue(null, {\n modified: true,\n });\n }\n });\n }\n });\n this.triggerUpdate();\n this.setSelectedClasses();\n return super.attach(element);\n }\n detach(element) {\n if (element && this.refs.input) {\n this.refs.input.forEach((input, index) => {\n if (this.component.values[index]) {\n this.removeShortcut(input, this.component.values[index].shortcut);\n }\n });\n }\n super.detach();\n }\n getValue() {\n if (this.viewOnly || !this.refs.input || !this.refs.input.length) {\n return this.dataValue;\n }\n let value = this.dataValue;\n this.refs.input.forEach((input, index) => {\n if (input.checked) {\n value = (this.isSelectURL && lodash_1.default.isObject(this.loadedOptions[index].value)) ?\n this.loadedOptions[index].value :\n input.value;\n }\n });\n return value;\n }\n validateValueProperty() {\n if (this.component.dataSrc === 'values') {\n return true;\n }\n return !lodash_1.default.some(this.refs.wrapper, (wrapper, index) => this.refs.input[index].checked && this.loadedOptions[index].invalid);\n }\n validateValueAvailability(setting, value) {\n if (!(0, utils_1.boolValue)(setting) || !value) {\n return true;\n }\n const values = this.component.values;\n if (values) {\n return values.findIndex(({ value: optionValue }) => this.normalizeValue(optionValue) === value) !== -1;\n }\n return false;\n }\n getValueAsString(value, options = {}) {\n if (lodash_1.default.isObject(value)) {\n value = JSON.stringify(value);\n }\n else if (!lodash_1.default.isString(value)) {\n value = lodash_1.default.toString(value);\n }\n const isModalPreviewWithUrlDataSource = options.modalPreview && this.component.dataSrc === 'url';\n if (this.component.dataSrc !== 'values' && !isModalPreviewWithUrlDataSource) {\n return value;\n }\n const values = isModalPreviewWithUrlDataSource ? this.loadedOptions : this.component.values;\n const option = lodash_1.default.find(values, (v) => v.value === value);\n if (!value) {\n return lodash_1.default.get(option, 'label', '');\n }\n return lodash_1.default.get(option, 'label', '');\n }\n setValueAt(index, value) {\n if (this.refs.input && this.refs.input[index] && value !== null && value !== undefined) {\n const inputValue = this.refs.input[index].value;\n this.refs.input[index].checked = (inputValue === value.toString());\n }\n }\n loadItems(url, search, headers, options, method, body) {\n if (this.optionsLoaded) {\n return;\n }\n if (!this.shouldLoad && this.listData) {\n this.loadItemsFromMetadata();\n return;\n }\n // Ensure we have a method and remove any body if method is get\n method = method || 'GET';\n if (method.toUpperCase() === 'GET') {\n body = null;\n }\n // Set ignoreCache if it is\n options.ignoreCache = this.component.ignoreCache;\n // Make the request.\n options.header = headers;\n this.loading = true;\n Formio_1.Formio.makeRequest(this.options.formio, 'select', url, method, body, options)\n .then((response) => {\n this.loading = false;\n this.setItems(response);\n this.optionsLoaded = true;\n this.redraw();\n })\n .catch((err) => {\n this.handleLoadingError(err);\n });\n }\n loadItemsFromMetadata() {\n this.listData.forEach((item, i) => {\n this.loadedOptions[i] = {\n label: this.itemTemplate(item)\n };\n if (lodash_1.default.isEqual(item, this.selectData || lodash_1.default.pick(this.dataValue, lodash_1.default.keys(item)))) {\n this.loadedOptions[i].value = this.dataValue;\n }\n });\n this.optionsLoaded = true;\n this.redraw();\n }\n setItems(items) {\n const listData = [];\n items === null || items === void 0 ? void 0 : items.forEach((item, i) => {\n this.loadedOptions[i] = {\n value: this.component.valueProperty ? item[this.component.valueProperty] : item,\n label: this.component.valueProperty ? this.itemTemplate(item, item[this.component.valueProperty]) : this.itemTemplate(item, item, i)\n };\n listData.push(this.templateData[this.component.valueProperty ? item[this.component.valueProperty] : i]);\n if ((this.component.valueProperty || !this.isRadio) && (lodash_1.default.isUndefined(item[this.component.valueProperty]) ||\n (!this.isRadio && lodash_1.default.isObject(item[this.component.valueProperty])) ||\n (!this.isRadio && lodash_1.default.isBoolean(item[this.component.valueProperty])))) {\n this.loadedOptions[i].invalid = true;\n }\n });\n if (this.isSelectURL) {\n const submission = this.root.submission;\n if (!submission.metadata) {\n submission.metadata = {};\n }\n if (!submission.metadata.listData) {\n submission.metadata.listData = {};\n }\n lodash_1.default.set(submission.metadata.listData, this.path, listData);\n }\n }\n setSelectedClasses() {\n if (this.refs.wrapper) {\n //add/remove selected option class\n const value = this.dataValue;\n this.refs.wrapper.forEach((wrapper, index) => {\n const input = this.refs.input[index];\n const checked = (input.type === 'checkbox') ? value[input.value] : (input.value.toString() === value.toString());\n if (checked) {\n //add class to container when selected\n this.addClass(wrapper, this.optionSelectedClass);\n //change \"checked\" attribute\n input.setAttribute('checked', 'true');\n }\n else {\n this.removeClass(wrapper, this.optionSelectedClass);\n input.removeAttribute('checked');\n }\n });\n }\n }\n updateValue(value, flags) {\n const changed = super.updateValue(value, flags);\n if (changed) {\n this.setSelectedClasses();\n }\n if (!flags || !flags.modified || !this.isRadio) {\n if (changed) {\n this.previousValue = this.dataValue;\n }\n return changed;\n }\n // If they clicked on the radio that is currently selected, it needs to reset the value.\n this.currentValue = this.dataValue;\n const shouldResetValue = flags && flags.modified && !flags.noUpdateEvent && this.previousValue === this.currentValue;\n if (shouldResetValue) {\n this.resetValue();\n this.triggerChange(flags);\n this.setSelectedClasses();\n }\n this.previousValue = this.dataValue;\n return changed;\n }\n /**\n * Normalize values coming into updateValue.\n *\n * @param value\n * @return {*}\n */\n normalizeValue(value) {\n const dataType = this.component.dataType || 'auto';\n if (value === this.emptyValue) {\n return value;\n }\n switch (dataType) {\n case 'auto':\n if (!isNaN(parseFloat(value)) && isFinite(value) && lodash_1.default.toString(value) === Number(value).toString()) {\n value = +value;\n }\n if (value === 'true') {\n value = true;\n }\n if (value === 'false') {\n value = false;\n }\n break;\n case 'number':\n value = +value;\n break;\n case 'string':\n if (typeof value === 'object') {\n value = JSON.stringify(value);\n }\n else {\n value = String(value);\n }\n break;\n case 'boolean':\n value = !(!value || value.toString() === 'false');\n break;\n }\n if (this.isSelectURL && this.templateData && this.templateData[value]) {\n const submission = this.root.submission;\n if (!submission.metadata.selectData) {\n submission.metadata.selectData = {};\n }\n lodash_1.default.set(submission.metadata.selectData, this.path, this.templateData[value]);\n }\n return super.normalizeValue(value);\n }\n}\nexports[\"default\"] = RadioComponent;\n\n\n//# sourceURL=webpack://Formio/./lib/cjs/components/radio/Radio.js?");
|
|
5770
5780
|
|
|
5771
5781
|
/***/ }),
|
|
5772
5782
|
|
|
@@ -5788,7 +5798,7 @@ eval("\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _argument
|
|
|
5788
5798
|
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
|
|
5789
5799
|
|
|
5790
5800
|
"use strict";
|
|
5791
|
-
eval("\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nconst lodash_1 = __importDefault(__webpack_require__(/*! lodash */ \"./node_modules/lodash/lodash.js\"));\nconst Formio_1 = __webpack_require__(/*! ../../Formio */ \"./lib/cjs/Formio.js\");\nconst ListComponent_1 = __importDefault(__webpack_require__(/*! ../_classes/list/ListComponent */ \"./lib/cjs/components/_classes/list/ListComponent.js\"));\nconst Input_1 = __importDefault(__webpack_require__(/*! ../_classes/input/Input */ \"./lib/cjs/components/_classes/input/Input.js\"));\nconst Form_1 = __importDefault(__webpack_require__(/*! ../../Form */ \"./lib/cjs/Form.js\"));\nconst utils_1 = __webpack_require__(/*! ../../utils/utils */ \"./lib/cjs/utils/utils.js\");\nconst ChoicesWrapper_1 = __importDefault(__webpack_require__(/*! ../../utils/ChoicesWrapper */ \"./lib/cjs/utils/ChoicesWrapper.js\"));\nclass SelectComponent extends ListComponent_1.default {\n static schema(...extend) {\n return ListComponent_1.default.schema({\n type: 'select',\n label: 'Select',\n key: 'select',\n idPath: 'id',\n data: {\n values: [{ label: '', value: '' }],\n json: '',\n url: '',\n resource: '',\n custom: ''\n },\n clearOnRefresh: false,\n limit: 100,\n valueProperty: '',\n lazyLoad: true,\n filter: '',\n searchEnabled: true,\n searchDebounce: 0.3,\n searchField: '',\n minSearch: 0,\n readOnlyValue: false,\n selectFields: '',\n selectThreshold: 0.3,\n uniqueOptions: false,\n tableView: true,\n fuseOptions: {\n include: 'score',\n threshold: 0.3,\n },\n indexeddb: {\n filter: {}\n },\n customOptions: {},\n useExactSearch: false,\n }, ...extend);\n }\n static get builderInfo() {\n return {\n title: 'Select',\n group: 'basic',\n icon: 'th-list',\n weight: 70,\n documentation: '/userguide/form-building/form-components#select',\n schema: SelectComponent.schema()\n };\n }\n static get serverConditionSettings() {\n return SelectComponent.conditionOperatorsSettings;\n }\n static get conditionOperatorsSettings() {\n return Object.assign(Object.assign({}, super.conditionOperatorsSettings), { valueComponent(classComp) {\n const valueComp = Object.assign(Object.assign({}, classComp), { type: 'select' });\n if ((0, utils_1.isSelectResourceWithObjectValue)(classComp)) {\n valueComp.reference = false;\n valueComp.onSetItems = `\n var templateKeys = utils.getItemTemplateKeys(component.template) || [];\n items = _.map(items || [], i => {\n var item = {};\n _.each(templateKeys, k => _.set(item, k, _.get(i, k)));\n return item;\n })\n `;\n }\n return valueComp;\n } });\n }\n static savedValueTypes(schema) {\n const { boolean, string, number, object, array } = utils_1.componentValueTypes;\n const { dataType, reference } = schema;\n const types = (0, utils_1.getComponentSavedTypes)(schema);\n if (types) {\n return types;\n }\n if (reference) {\n return [object];\n }\n if (dataType === 'object') {\n return [object, array];\n }\n if (utils_1.componentValueTypes[dataType]) {\n return [utils_1.componentValueTypes[dataType]];\n }\n return [boolean, string, number, object, array];\n }\n init() {\n super.init();\n this.templateData = {};\n // Trigger an update.\n let updateArgs = [];\n const triggerUpdate = lodash_1.default.debounce((...args) => {\n updateArgs = [];\n return this.updateItems.apply(this, args);\n }, 100);\n this.triggerUpdate = (...args) => {\n // Make sure we always resolve the previous promise before reassign it\n if (typeof this.itemsLoadedResolve === 'function') {\n this.itemsLoadedResolve();\n }\n this.itemsLoaded = new Promise((resolve) => {\n this.itemsLoadedResolve = resolve;\n });\n if (args.length) {\n updateArgs = args;\n }\n return triggerUpdate(...updateArgs);\n };\n // Keep track of the select options.\n this.selectOptions = [];\n if (this.itemsFromUrl) {\n this.isFromSearch = false;\n this.searchServerCount = null;\n this.defaultServerCount = null;\n this.isScrollLoading = false;\n this.searchDownloadedResources = [];\n this.defaultDownloadedResources = [];\n }\n // If this component has been activated.//\n this.activated = false;\n this.itemsLoaded = new Promise((resolve) => {\n this.itemsLoadedResolve = resolve;\n });\n this.shouldPositionDropdown = this.hasDataGridAncestor();\n if (this.isHtmlRenderMode()) {\n this.activate();\n }\n // Get the template keys for this select component.\n this.getTemplateKeys();\n }\n get dataReady() {\n // If the root submission has been set, and we are still not attached, then assume\n // that our data is ready.\n if (this.root &&\n this.root.submissionSet &&\n !this.attached) {\n return Promise.resolve();\n }\n return this.itemsLoaded;\n }\n get defaultSchema() {\n return SelectComponent.schema();\n }\n get emptyValue() {\n if (this.component.multiple) {\n return [];\n }\n // if select has JSON data source type, we are defining if empty value would be an object or a string by checking JSON's first item\n if (this.component.dataSrc === 'json' && this.component.data.json) {\n const firstItem = this.component.data.json[0];\n let firstValue;\n if (this.valueProperty) {\n firstValue = lodash_1.default.get(firstItem, this.valueProperty);\n }\n else {\n firstValue = firstItem;\n }\n if (firstValue && typeof firstValue === 'string') {\n return '';\n }\n else {\n return {};\n }\n }\n if (this.valueProperty) {\n return '';\n }\n return {};\n }\n get valueProperty() {\n if (this.component.valueProperty) {\n return this.component.valueProperty;\n }\n // Force values datasource to use values without actually setting it on the component settings.\n if (this.component.dataSrc === 'values') {\n return 'value';\n }\n return '';\n }\n get inputInfo() {\n const info = super.elementInfo();\n info.type = 'select';\n info.changeEvent = 'change';\n return info;\n }\n get isSelectResource() {\n return this.component.dataSrc === 'resource';\n }\n get itemsFromUrl() {\n return this.isSelectResource || this.isSelectURL;\n }\n get isInfiniteScrollProvided() {\n return this.itemsFromUrl;\n }\n get shouldDisabled() {\n return super.shouldDisabled || this.parentDisabled;\n }\n get shouldInitialLoad() {\n if (this.component.widget === 'html5' &&\n this.isEntireObjectDisplay() &&\n this.component.searchField &&\n this.dataValue) {\n return false;\n }\n return super.shouldLoad;\n }\n get selectMetadata() {\n return super.selectData;\n }\n get selectData() {\n return this.selectMetadata || this.component.selectData;\n }\n isEntireObjectDisplay() {\n return this.component.dataSrc === 'resource' && this.valueProperty === 'data';\n }\n selectValueAndLabel(data) {\n const value = this.getOptionValue((this.isEntireObjectDisplay() && !this.itemValue(data)) ? data : this.itemValue(data));\n return {\n value,\n label: this.itemTemplate((this.isEntireObjectDisplay() && !lodash_1.default.isObject(data.data)) ? { data: data } : data, value)\n };\n }\n itemTemplate(data, value) {\n if (!lodash_1.default.isNumber(data) && lodash_1.default.isEmpty(data)) {\n return '';\n }\n // If they wish to show the value in read only mode, then just return the itemValue here.\n if (this.options.readOnly && this.component.readOnlyValue) {\n return this.itemValue(data);\n }\n // Perform a fast interpretation if we should not use the template.\n if (data && !this.component.template) {\n const itemLabel = data.label || data;\n const value = (typeof itemLabel === 'string') ? this.t(itemLabel, { _userInput: true }) : itemLabel;\n return this.sanitize(value, this.shouldSanitizeValue);\n }\n if (this.component.multiple && lodash_1.default.isArray(this.dataValue) ? this.dataValue.find((val) => value === val) : (this.dataValue === value)) {\n const selectData = this.selectData;\n if (selectData) {\n const templateValue = this.component.reference && (value === null || value === void 0 ? void 0 : value._id) ? value._id.toString() : value;\n if (!this.templateData || !this.templateData[templateValue]) {\n this.getOptionTemplate(data, value);\n }\n if (this.component.multiple) {\n if (selectData[templateValue]) {\n data = selectData[templateValue];\n }\n }\n else {\n data = selectData;\n }\n }\n }\n if (typeof data === 'string' || typeof data === 'number') {\n return this.sanitize(this.t(data, { _userInput: true }), this.shouldSanitizeValue);\n }\n if (Array.isArray(data)) {\n return data.map((val) => {\n if (typeof val === 'string' || typeof val === 'number') {\n return this.sanitize(this.t(val, { _userInput: true }), this.shouldSanitizeValue);\n }\n return val;\n });\n }\n if (data.data) {\n // checking additional fields in the template for the selected Entire Object option\n const hasNestedFields = /item\\.data\\.\\w*/g.test(this.component.template);\n data.data = this.isEntireObjectDisplay() && lodash_1.default.isObject(data.data) && !hasNestedFields\n ? JSON.stringify(data.data)\n : data.data;\n }\n return super.itemTemplate(data, value);\n }\n /**\n * Adds an option to the select dropdown.\n *\n * @param value\n * @param label\n */\n addOption(value, label, attrs = {}, id = (0, utils_1.getRandomComponentId)()) {\n if (lodash_1.default.isNil(label))\n return;\n const idPath = this.component.idPath\n ? this.component.idPath.split('.').reduceRight((obj, key) => ({ [key]: obj }), id)\n : {};\n const option = Object.assign({ value: this.getOptionValue(value), label }, idPath);\n const skipOption = this.component.uniqueOptions\n ? !!this.selectOptions.find((selectOption) => lodash_1.default.isEqual(selectOption.value, option.value))\n : false;\n if (skipOption) {\n return;\n }\n if (value) {\n this.selectOptions.push(option);\n }\n if (this.refs.selectContainer && (this.component.widget === 'html5')) {\n // Replace an empty Object value to an empty String.\n if (option.value && lodash_1.default.isObject(option.value) && lodash_1.default.isEmpty(option.value)) {\n option.value = '';\n }\n // Add element to option so we can reference it later.\n const div = document.createElement('div');\n div.innerHTML = this.sanitize(this.renderTemplate('selectOption', {\n selected: lodash_1.default.isEqual(this.getOptionValue(this.dataValue), option.value),\n option,\n attrs,\n id,\n useId: (this.valueProperty === '' || this.isEntireObjectDisplay()) && lodash_1.default.isObject(value) && id,\n }), this.shouldSanitizeValue).trim();\n option.element = div.firstChild;\n this.refs.selectContainer.appendChild(option.element);\n }\n }\n addValueOptions(items) {\n items = items || [];\n let added = false;\n let data = this.dataValue;\n // preset submission value with value property before request.\n if (this.options.pdf && !items.length && this.component.dataSrc === 'url' && this.valueProperty) {\n data = Array.isArray(data)\n ? data.map(item => lodash_1.default.set({}, this.valueProperty, item))\n : lodash_1.default.set({}, this.valueProperty, data);\n }\n if (!this.selectOptions.length) {\n // Add the currently selected choices if they don't already exist.\n const currentChoices = Array.isArray(data) && this.component.multiple ? data : [data];\n added = this.addCurrentChoices(currentChoices, items);\n if (!added && !this.component.multiple) {\n this.addPlaceholder();\n }\n }\n return added;\n }\n disableInfiniteScroll() {\n if (!this.downloadedResources) {\n return;\n }\n this.downloadedResources.serverCount = this.downloadedResources.length;\n this.serverCount = this.downloadedResources.length;\n }\n /* eslint-disable max-statements */\n setItems(items, fromSearch) {\n var _a, _b;\n this.selectItems = items;\n // If the items is a string, then parse as JSON.\n if (typeof items == 'string') {\n try {\n items = JSON.parse(items);\n }\n catch (err) {\n console.warn(err.message);\n items = [];\n }\n }\n // Allow js processing (needed for form builder)\n if (this.component.onSetItems) {\n const newItems = typeof this.component.onSetItems === 'function'\n ? this.component.onSetItems(this, items)\n : this.evaluate(this.component.onSetItems, { items: items }, 'items');\n if (newItems) {\n items = newItems;\n }\n }\n if (!this.choices && this.refs.selectContainer) {\n this.empty(this.refs.selectContainer);\n }\n // If they provided select values, then we need to get them instead.\n if (this.component.selectValues) {\n items = lodash_1.default.get(items, this.component.selectValues, items) || [];\n }\n let areItemsEqual;\n if (this.itemsFromUrl) {\n areItemsEqual = this.isSelectURL ? lodash_1.default.isEqual(items, this.downloadedResources) : false;\n const areItemsEnded = this.component.limit > items.length;\n const areItemsDownloaded = areItemsEqual\n && this.downloadedResources\n && this.downloadedResources.length === items.length;\n if (areItemsEnded) {\n this.disableInfiniteScroll();\n }\n else if (areItemsDownloaded) {\n this.selectOptions = [];\n }\n else {\n this.serverCount = items.serverCount;\n }\n }\n if (this.isScrollLoading && items) {\n if (!areItemsEqual) {\n this.downloadedResources = this.downloadedResources\n ? this.downloadedResources.concat(items)\n : items;\n }\n this.downloadedResources.serverCount = items.serverCount || this.downloadedResources.serverCount;\n }\n else {\n this.downloadedResources = items || [];\n this.selectOptions = [];\n // If there is new select option with same id as already selected, set the new one\n if (!lodash_1.default.isEmpty(this.dataValue) && this.component.idPath) {\n const selectedOptionId = lodash_1.default.get(this.dataValue, this.component.idPath, null);\n const newOptionWithSameId = !lodash_1.default.isNil(selectedOptionId) && items.find(item => {\n const itemId = lodash_1.default.get(item, this.component.idPath);\n return itemId === selectedOptionId;\n });\n if (newOptionWithSameId) {\n this.setValue(newOptionWithSameId);\n }\n }\n }\n // Add the value options.\n if (!fromSearch) {\n this.addValueOptions(items);\n }\n if (this.component.widget === 'html5' && !this.component.placeholder) {\n this.addOption(null, '');\n }\n // Iterate through each of the items.\n lodash_1.default.each(items, (item, index) => {\n // preventing references of the components inside the form to the parent form when building forms\n if (this.root && this.root.options.editForm && this.root.options.editForm._id && this.root.options.editForm._id === item._id)\n return;\n const itemValueAndLabel = this.selectValueAndLabel(item);\n this.addOption(itemValueAndLabel.value, itemValueAndLabel.label, {}, lodash_1.default.get(item, this.component.idPath, String(index)));\n });\n if (this.choices) {\n this.choices.setChoices(this.selectOptions, 'value', 'label', true);\n }\n else if (this.loading) {\n // Re-attach select input.\n // this.appendTo(this.refs.input[0], this.selectContainer);\n }\n // We are no longer loading.\n this.isScrollLoading = false;\n this.loading = false;\n const searching = fromSearch && ((_b = (_a = this.choices) === null || _a === void 0 ? void 0 : _a.input) === null || _b === void 0 ? void 0 : _b.isFocussed);\n if (!searching) {\n // If a value is provided, then select it.\n if (!this.isEmpty() || this.isRemoveButtonPressed) {\n this.setValue(this.dataValue, {\n noUpdateEvent: true\n });\n }\n else if (this.shouldAddDefaultValue && !this.options.readOnly) {\n // If a default value is provided then select it.\n const defaultValue = this.defaultValue;\n if (!this.isEmpty(defaultValue)) {\n this.setValue(defaultValue);\n }\n }\n }\n // Say we are done loading the items.\n this.itemsLoadedResolve();\n }\n getSingleItemValueForHTMLMode(data) {\n var _a;\n const option = (_a = this.selectOptions) === null || _a === void 0 ? void 0 : _a.find(({ value }) => lodash_1.default.isEqual(value, data));\n if (option) {\n return option.label || data;\n }\n return data;\n }\n itemValueForHTMLMode(value) {\n if (!this.isHtmlRenderMode()) {\n return super.itemValueForHTMLMode(value);\n }\n if (Array.isArray(value)) {\n const values = value.map(item => Array.isArray(item)\n ? this.itemValueForHTMLMode(item)\n : this.getSingleItemValueForHTMLMode(item));\n return values.join(', ');\n }\n return this.getSingleItemValueForHTMLMode(value);\n }\n /* eslint-enable max-statements */\n get defaultValue() {\n let defaultValue = super.defaultValue;\n if (!defaultValue && (this.component.defaultValue === false || this.component.defaultValue === 0)) {\n defaultValue = this.component.defaultValue;\n }\n return defaultValue;\n }\n get loadingError() {\n return !this.component.refreshOn && !this.component.refreshOnBlur && this.networkError;\n }\n loadItems(url, search, headers, options, method, body) {\n options = options || {};\n // See if we should load items or not.\n if (!this.shouldLoad || (!this.itemsFromUrl && this.options.readOnly)) {\n this.isScrollLoading = false;\n this.loading = false;\n this.itemsLoadedResolve();\n return;\n }\n // See if they have not met the minimum search requirements.\n const minSearch = parseInt(this.component.minSearch, 10);\n if (this.component.searchField &&\n (minSearch > 0) &&\n (!search || (search.length < minSearch))) {\n // Set empty items.\n return this.setItems([]);\n }\n // Ensure we have a method and remove any body if method is get\n method = method || 'GET';\n if (method.toUpperCase() === 'GET') {\n body = null;\n }\n const limit = this.component.limit || 100;\n const skip = this.isScrollLoading ? this.selectOptions.length : 0;\n const query = this.component.disableLimit ? {} : {\n limit,\n skip,\n };\n // Allow for url interpolation.\n url = this.interpolate(url, {\n formioBase: Formio_1.Formio.getBaseUrl(),\n search,\n limit,\n skip,\n page: Math.abs(Math.floor(skip / limit))\n });\n // Add search capability.\n if (this.component.searchField && search) {\n const searchValue = Array.isArray(search)\n ? search.join(',')\n : typeof search === 'object'\n ? JSON.stringify(search)\n : search;\n query[this.component.searchField] = this.component.searchField.endsWith('__regex')\n ? lodash_1.default.escapeRegExp(searchValue)\n : searchValue;\n }\n // If they wish to return only some fields.\n if (this.component.selectFields) {\n query.select = this.component.selectFields;\n }\n // Add sort capability\n if (this.component.sort) {\n query.sort = this.component.sort;\n }\n if (!lodash_1.default.isEmpty(query)) {\n // Add the query string.\n url += (!url.includes('?') ? '?' : '&') + Formio_1.Formio.serialize(query, (item) => this.interpolate(item));\n }\n // Add filter capability\n if (this.component.filter) {\n url += (!url.includes('?') ? '?' : '&') + this.interpolate(this.component.filter);\n }\n // Set ignoreCache if it is\n options.ignoreCache = this.component.ignoreCache;\n // Make the request.\n options.header = headers;\n this.loading = true;\n Formio_1.Formio.makeRequest(this.options.formio, 'select', url, method, body, options)\n .then((response) => {\n this.loading = false;\n this.setItems(response, !!search);\n })\n .catch((err) => {\n if (this.itemsFromUrl) {\n this.setItems([]);\n this.disableInfiniteScroll();\n }\n this.isScrollLoading = false;\n this.handleLoadingError(err);\n });\n }\n handleLoadingError(err) {\n this.loading = false;\n if (err.networkError) {\n this.networkError = true;\n }\n this.itemsLoadedResolve();\n this.emit('componentError', {\n component: this.component,\n message: err.toString(),\n });\n console.warn(`Unable to load resources for ${this.key}`);\n }\n /**\n * Get the request headers for this select dropdown.\n */\n get requestHeaders() {\n // Create the headers object.\n const headers = new Formio_1.Formio.Headers();\n // Add custom headers to the url.\n if (this.component.data && this.component.data.headers) {\n try {\n lodash_1.default.each(this.component.data.headers, (header) => {\n if (header.key) {\n headers.set(header.key, this.interpolate(header.value));\n }\n });\n }\n catch (err) {\n console.warn(err.message);\n }\n }\n return headers;\n }\n getCustomItems() {\n const customItems = this.evaluate(this.component.data.custom, {\n values: []\n }, 'values');\n this.asyncValues = (0, utils_1.isPromise)(customItems);\n return customItems;\n }\n asyncCustomValues() {\n if (!lodash_1.default.isBoolean(this.asyncValues)) {\n this.getCustomItems();\n }\n return this.asyncValues;\n }\n updateCustomItems(forceUpdate) {\n if (this.asyncCustomValues()) {\n if (!forceUpdate && !this.active) {\n this.itemsLoadedResolve();\n return;\n }\n this.loading = true;\n this.getCustomItems()\n .then(items => {\n this.loading = false;\n this.setItems(items || []);\n })\n .catch(err => {\n this.handleLoadingError(err);\n });\n }\n else {\n this.setItems(this.getCustomItems() || []);\n }\n }\n isEmpty(value = this.dataValue) {\n return super.isEmpty(value) || value === undefined;\n }\n refresh(value, { instance }) {\n if (this.component.clearOnRefresh && (instance && !instance.pristine)) {\n this.setValue(this.emptyValue);\n }\n this.updateItems(null, true);\n }\n get additionalResourcesAvailable() {\n return lodash_1.default.isNil(this.serverCount) || (this.serverCount > this.downloadedResources.length);\n }\n get serverCount() {\n if (this.isFromSearch) {\n return this.searchServerCount;\n }\n return this.defaultServerCount;\n }\n set serverCount(value) {\n if (this.isFromSearch) {\n this.searchServerCount = value;\n }\n else {\n this.defaultServerCount = value;\n }\n }\n get downloadedResources() {\n if (this.isFromSearch) {\n return this.searchDownloadedResources;\n }\n return this.defaultDownloadedResources;\n }\n set downloadedResources(value) {\n if (this.isFromSearch) {\n this.searchDownloadedResources = value;\n }\n else {\n this.defaultDownloadedResources = value;\n }\n }\n addPlaceholder() {\n if (!this.component.placeholder) {\n return;\n }\n this.addOption('', this.component.placeholder, { placeholder: true });\n }\n /**\n * Activate this select control.\n */\n activate() {\n if (this.loading || !this.active) {\n this.setLoadingItem();\n }\n if (this.active) {\n return;\n }\n this.activated = true;\n this.triggerUpdate();\n }\n setLoadingItem(addToCurrentList = false) {\n if (this.choices) {\n if (addToCurrentList) {\n this.choices.setChoices([{\n value: `${this.id}-loading`,\n label: 'Loading...',\n disabled: true,\n }], 'value', 'label');\n }\n else {\n this.choices.setChoices([{\n value: '',\n label: `<i class=\"${this.iconClass('refresh')}\" style=\"font-size:1.3em;\"></i>`,\n disabled: true,\n }], 'value', 'label', true);\n }\n }\n else if (this.component.dataSrc === 'url' || this.component.dataSrc === 'resource') {\n this.addOption('', this.t('loading...'));\n }\n }\n get active() {\n return !this.component.lazyLoad || this.activated;\n }\n render() {\n const info = this.inputInfo;\n info.attr = info.attr || {};\n info.multiple = this.component.multiple;\n return super.render(this.wrapElement(this.renderTemplate('select', {\n input: info,\n selectOptions: '',\n index: null,\n })));\n }\n wrapElement(element) {\n return this.component.addResource && !this.options.readOnly\n ? (this.renderTemplate('resourceAdd', {\n element\n }))\n : element;\n }\n choicesOptions() {\n const useSearch = this.component.hasOwnProperty('searchEnabled') ? this.component.searchEnabled : true;\n const placeholderValue = this.t(this.component.placeholder, { _userInput: true });\n let customOptions = this.component.customOptions || {};\n if (typeof customOptions == 'string') {\n try {\n customOptions = JSON.parse(customOptions);\n }\n catch (err) {\n console.warn(err.message);\n customOptions = {};\n }\n }\n const commonFuseOptions = {\n maxPatternLength: 1000,\n distance: 1000,\n };\n return Object.assign({ removeItemButton: this.component.disabled ? false : lodash_1.default.get(this.component, 'removeItemButton', true), itemSelectText: '', classNames: {\n containerOuter: 'choices form-group formio-choices',\n containerInner: this.transform('class', 'form-control ui fluid selection dropdown')\n }, addItemText: false, allowHTML: true, placeholder: !!this.component.placeholder, placeholderValue: placeholderValue, noResultsText: this.t('No results found'), noChoicesText: this.t('No choices to choose from'), searchPlaceholderValue: this.t('Type to search'), shouldSort: false, position: (this.component.dropdown || 'auto'), searchEnabled: useSearch, searchChoices: !this.component.searchField, searchFields: lodash_1.default.get(this, 'component.searchFields', ['label']), shadowRoot: this.root ? this.root.shadowRoot : null, fuseOptions: this.component.useExactSearch\n ? Object.assign({ tokenize: true, matchAllTokens: true }, commonFuseOptions) : Object.assign({}, lodash_1.default.get(this, 'component.fuseOptions', {}), Object.assign({ include: 'score', threshold: lodash_1.default.get(this, 'component.selectThreshold', 0.3) }, commonFuseOptions)), valueComparer: lodash_1.default.isEqual, resetScrollPosition: false }, customOptions);\n }\n /* eslint-disable max-statements */\n attach(element) {\n var _a, _b, _c;\n const superAttach = super.attach(element);\n this.loadRefs(element, {\n selectContainer: 'single',\n addResource: 'single',\n autocompleteInput: 'single'\n });\n //enable autocomplete for select\n const autocompleteInput = this.refs.autocompleteInput;\n if (autocompleteInput) {\n this.addEventListener(autocompleteInput, 'change', (event) => {\n this.setValue(event.target.value);\n });\n }\n const input = this.refs.selectContainer;\n if (!input) {\n return;\n }\n this.addEventListener(input, this.inputInfo.changeEvent, () => this.updateValue(null, {\n modified: true\n }));\n this.attachRefreshOnBlur();\n if (this.component.widget === 'html5') {\n this.addFocusBlurEvents(input);\n this.triggerUpdate(null, true);\n if (this.visible) {\n this.setItems(this.selectItems || []);\n }\n this.focusableElement = input;\n if (this.component.dataSrc === 'custom') {\n this.addEventListener(input, 'focus', () => this.updateCustomItems());\n }\n this.addEventListener(input, 'keydown', (event) => {\n const { key } = event;\n if (['Backspace', 'Delete'].includes(key)) {\n this.setValue(this.emptyValue);\n }\n });\n return;\n }\n const tabIndex = input.tabIndex;\n this.addPlaceholder();\n if (this.i18next) {\n input.setAttribute('dir', this.i18next.dir());\n }\n if ((_c = (_b = (_a = this.choices) === null || _a === void 0 ? void 0 : _a.containerOuter) === null || _b === void 0 ? void 0 : _b.element) === null || _c === void 0 ? void 0 : _c.parentNode) {\n this.choices.destroy();\n }\n const choicesOptions = this.choicesOptions();\n if (ChoicesWrapper_1.default) {\n this.choices = new ChoicesWrapper_1.default(input, choicesOptions);\n if (this.selectOptions && this.selectOptions.length) {\n this.choices.setChoices(this.selectOptions, 'value', 'label', true);\n }\n if (this.component.multiple) {\n this.focusableElement = this.choices.input.element;\n }\n else {\n this.focusableElement = this.choices.containerInner.element;\n this.choices.containerOuter.element.setAttribute('tabIndex', '-1');\n this.addEventListener(this.choices.containerOuter.element, 'focus', () => this.focusableElement.focus());\n }\n Input_1.default.prototype.addFocusBlurEvents.call(this, this.focusableElement);\n if (this.itemsFromUrl && !this.component.noRefreshOnScroll) {\n this.scrollList = this.choices.choiceList.element;\n this.addEventListener(this.scrollList, 'scroll', () => this.onScroll());\n }\n if (choicesOptions.removeItemButton) {\n this.addEventListener(input, 'removeItem', () => {\n this.isRemoveButtonPressed = true;\n });\n }\n }\n if (window && this.choices && this.shouldPositionDropdown) {\n this.addEventListener(window.document, 'scroll', () => {\n this.positionDropdown(true);\n }, false, true);\n }\n this.focusableElement.setAttribute('tabIndex', tabIndex);\n // If a search field is provided, then add an event listener to update items on search.\n if (this.component.searchField) {\n // Make sure to clear the search when no value is provided.\n if (this.choices && this.choices.input && this.choices.input.element) {\n this.addEventListener(this.choices.input.element, 'input', (event) => {\n this.isFromSearch = !!event.target.value;\n if (!event.target.value) {\n this.triggerUpdate();\n }\n else {\n this.serverCount = null;\n this.downloadedResources = [];\n }\n });\n }\n this.addEventListener(input, 'choice', () => {\n if (this.component.multiple && this.component.dataSrc === 'resource' && this.isFromSearch) {\n this.triggerUpdate();\n }\n this.isFromSearch = false;\n });\n // avoid spamming the resource/url endpoint when we have server side filtering enabled.\n const debounceTimeout = this.component.searchField && (this.isSelectResource || this.isSelectURL) ?\n (this.component.searchDebounce === 0 ? 0 : this.component.searchDebounce || this.defaultSchema.searchDebounce) * 1000\n : 0;\n const updateComponent = (evt) => {\n this.triggerUpdate(evt.detail.value);\n };\n this.addEventListener(input, 'search', lodash_1.default.debounce((e) => {\n updateComponent(e);\n this.positionDropdown();\n }, debounceTimeout));\n this.addEventListener(input, 'stopSearch', () => this.triggerUpdate());\n this.addEventListener(input, 'hideDropdown', () => {\n if (this.choices && this.choices.input && this.choices.input.element) {\n this.choices.input.element.value = '';\n }\n this.updateItems(null, true);\n });\n }\n this.addEventListener(input, 'showDropdown', () => {\n this.update();\n this.positionDropdown();\n });\n if (this.shouldPositionDropdown) {\n this.addEventListener(input, 'highlightChoice', () => {\n this.positionDropdown();\n });\n }\n if (this.choices && choicesOptions.placeholderValue && this.choices._isSelectOneElement) {\n this.addPlaceholderItem(choicesOptions.placeholderValue);\n this.addEventListener(input, 'removeItem', () => {\n this.addPlaceholderItem(choicesOptions.placeholderValue);\n });\n }\n // Add value options.\n this.addValueOptions();\n this.setChoicesValue(this.dataValue);\n if (this.isSelectResource && this.refs.addResource) {\n this.addEventListener(this.refs.addResource, 'click', (event) => {\n event.preventDefault();\n const formioForm = this.ce('div');\n const dialog = this.createModal(formioForm);\n const projectUrl = lodash_1.default.get(this.root, 'formio.projectUrl', Formio_1.Formio.getProjectUrl());\n const formUrl = `${projectUrl}/form/${this.component.data.resource}`;\n new Form_1.default(formioForm, formUrl, {}).ready\n .then((form) => {\n form.on('submit', (submission) => {\n // If valueProperty is set, replace the submission with the corresponding value\n let value = this.valueProperty ? lodash_1.default.get(submission, this.valueProperty) : submission;\n if (this.component.multiple) {\n value = [...this.dataValue, value];\n }\n this.setValue(value);\n this.triggerUpdate();\n dialog.close();\n });\n });\n });\n }\n // Force the disabled state with getters and setters.\n this.disabled = this.shouldDisabled;\n this.triggerUpdate();\n return superAttach;\n }\n setDropdownPosition() {\n var _a, _b, _c, _d;\n const dropdown = (_b = (_a = this.choices) === null || _a === void 0 ? void 0 : _a.dropdown) === null || _b === void 0 ? void 0 : _b.element;\n const container = (_d = (_c = this.choices) === null || _c === void 0 ? void 0 : _c.containerOuter) === null || _d === void 0 ? void 0 : _d.element;\n if (!dropdown || !container) {\n return;\n }\n const containerPosition = container.getBoundingClientRect();\n const isFlipped = container.classList.contains('is-flipped');\n lodash_1.default.assign(dropdown.style, {\n top: `${isFlipped ? containerPosition.top - dropdown.offsetHeight : containerPosition.top + containerPosition.height}px`,\n left: `${containerPosition.left}px`,\n width: `${containerPosition.width}px`,\n position: 'fixed',\n bottom: 'unset',\n right: 'unset',\n });\n }\n hasDataGridAncestor(comp) {\n comp = comp || this;\n if (comp.inDataGrid || comp.type === 'datagrid') {\n return true;\n }\n else if (comp.parent) {\n return this.hasDataGridAncestor(comp.parent);\n }\n else {\n return false;\n }\n }\n positionDropdown(scroll) {\n var _a;\n if (!this.shouldPositionDropdown || !this.choices || (!((_a = this.choices.dropdown) === null || _a === void 0 ? void 0 : _a.isActive) && scroll)) {\n return;\n }\n this.setDropdownPosition();\n this.itemsLoaded.then(() => {\n this.setDropdownPosition();\n });\n }\n get isLoadingAvailable() {\n return !this.isScrollLoading && this.additionalResourcesAvailable;\n }\n onScroll() {\n if (this.isLoadingAvailable) {\n this.isScrollLoading = true;\n this.setLoadingItem(true);\n this.triggerUpdate(this.choices.input.element.value);\n }\n }\n attachRefreshOnBlur() {\n if (this.component.refreshOnBlur) {\n this.on('blur', (instance) => {\n this.checkRefreshOn([{ instance, value: instance.dataValue }], { fromBlur: true });\n });\n }\n }\n addPlaceholderItem(placeholderValue) {\n const items = this.choices._store.activeItems;\n if (!items.length) {\n this.choices._addItem({\n value: '',\n label: placeholderValue,\n choiceId: 0,\n groupId: -1,\n customProperties: null,\n placeholder: true,\n keyCode: null\n });\n }\n }\n /* eslint-enable max-statements */\n update() {\n if (this.component.dataSrc === 'custom') {\n this.updateCustomItems();\n }\n // Activate the control.\n this.activate();\n }\n set disabled(disabled) {\n super.disabled = disabled;\n if (!this.choices) {\n return;\n }\n if (disabled) {\n this.setDisabled(this.choices.containerInner.element, true);\n this.focusableElement.removeAttribute('tabIndex');\n this.choices.disable();\n }\n else {\n this.setDisabled(this.choices.containerInner.element, false);\n this.focusableElement.setAttribute('tabIndex', this.component.tabindex || 0);\n this.choices.enable();\n }\n }\n get disabled() {\n return super.disabled;\n }\n set visible(value) {\n // If we go from hidden to visible, trigger a refresh.\n if (value && (!this._visible !== !value)) {\n this.triggerUpdate();\n }\n super.visible = value;\n }\n get visible() {\n return super.visible;\n }\n /**\n * @param {*} value\n * @param {Array} items\n */\n addCurrentChoices(values, items, keyValue) {\n if (!values) {\n return false;\n }\n const notFoundValuesToAdd = [];\n const added = values.reduce((defaultAdded, value) => {\n if (!value || lodash_1.default.isEmpty(value)) {\n return defaultAdded;\n }\n let found = false;\n // Make sure that `items` and `this.selectOptions` points\n // to the same reference. Because `this.selectOptions` is\n // internal property and all items are populated by\n // `this.addOption` method, we assume that items has\n // 'label' and 'value' properties. This assumption allows\n // us to read correct value from the item.\n const isSelectOptions = items === this.selectOptions;\n if (items && items.length) {\n lodash_1.default.each(items, (choice) => {\n if (choice._id && value._id && (choice._id === value._id)) {\n found = true;\n return false;\n }\n const itemValue = keyValue ? choice.value : this.itemValue(choice, isSelectOptions);\n found |= lodash_1.default.isEqual(itemValue, value);\n return found ? false : true;\n });\n }\n // Add the default option if no item is found.\n if (!found) {\n notFoundValuesToAdd.push(this.selectValueAndLabel(value));\n return true;\n }\n return found || defaultAdded;\n }, false);\n if (notFoundValuesToAdd.length) {\n if (this.choices) {\n this.choices.setChoices(notFoundValuesToAdd, 'value', 'label');\n }\n notFoundValuesToAdd.map(notFoundValue => {\n this.addOption(notFoundValue.value, notFoundValue.label);\n });\n }\n return added;\n }\n getValueAsString(data, options) {\n return (this.component.multiple && Array.isArray(data))\n ? data.map((v) => this.asString(v, options)).join(', ')\n : this.asString(data, options);\n }\n getValue() {\n // If the widget isn't active.\n if (this.viewOnly || this.loading\n || (!this.component.lazyLoad && !this.selectOptions.length)\n || !this.element) {\n return this.dataValue;\n }\n let value = this.emptyValue;\n if (this.choices) {\n value = this.choices.getValue(true);\n // Make sure we don't get the placeholder\n if (!this.component.multiple &&\n this.component.placeholder &&\n (value === this.t(this.component.placeholder, { _userInput: true }))) {\n value = this.emptyValue;\n }\n }\n else if (this.refs.selectContainer) {\n value = this.refs.selectContainer.value;\n if (this.valueProperty === '' || this.isEntireObjectDisplay()) {\n if (value === '') {\n return {};\n }\n const option = this.selectOptions[value] ||\n this.selectOptions.find(option => option.id === value);\n if (option && lodash_1.default.isObject(option.value)) {\n value = option.value;\n }\n }\n }\n else {\n value = this.dataValue;\n }\n // Choices will return undefined if nothing is selected. We really want '' to be empty.\n if (value === undefined || value === null) {\n value = '';\n }\n return value;\n }\n redraw() {\n const done = super.redraw();\n this.triggerUpdate();\n return done;\n }\n normalizeSingleValue(value) {\n if (lodash_1.default.isNil(value)) {\n return;\n }\n const valueIsObject = lodash_1.default.isObject(value);\n //check if value equals to default emptyValue\n if (valueIsObject && Object.keys(value).length === 0) {\n return value;\n }\n const dataType = this.component.dataType || 'auto';\n const normalize = {\n value,\n number() {\n const numberValue = Number(this.value);\n const isEquivalent = value.toString() === numberValue.toString();\n if (!Number.isNaN(numberValue) && Number.isFinite(numberValue) && value !== '' && isEquivalent) {\n this.value = numberValue;\n }\n return this;\n },\n boolean() {\n if (lodash_1.default.isString(this.value)\n && (this.value.toLowerCase() === 'true'\n || this.value.toLowerCase() === 'false')) {\n this.value = (this.value.toLowerCase() === 'true');\n }\n return this;\n },\n string() {\n this.value = String(this.value);\n return this;\n },\n object() {\n return this;\n },\n auto() {\n if (lodash_1.default.isObject(this.value)) {\n this.value = this.object().value;\n }\n else {\n this.value = this.string().number().boolean().value;\n }\n return this;\n }\n };\n try {\n return normalize[dataType]().value;\n }\n catch (err) {\n console.warn('Failed to normalize value', err);\n return value;\n }\n }\n /**\n * Normalize values coming into updateValue.\n *\n * @param value\n * @return {*}\n */\n normalizeValue(value) {\n if (this.component.multiple && Array.isArray(value)) {\n return value.map((singleValue) => this.normalizeSingleValue(singleValue));\n }\n return super.normalizeValue(this.normalizeSingleValue(value));\n }\n setMetadata(value) {\n var _a;\n if (lodash_1.default.isNil(value)) {\n return;\n }\n const valueIsObject = lodash_1.default.isObject(value);\n //check if value equals to default emptyValue\n if (valueIsObject && Object.keys(value).length === 0) {\n return value;\n }\n // Check to see if we need to save off the template data into our metadata.\n const templateValue = this.component.reference && (value === null || value === void 0 ? void 0 : value._id) ? value._id.toString() : value;\n const shouldSaveData = !valueIsObject || this.component.reference;\n if (templateValue && shouldSaveData && this.templateData && this.templateData[templateValue] && ((_a = this.root) === null || _a === void 0 ? void 0 : _a.submission)) {\n const submission = this.root.submission;\n if (!submission.metadata) {\n submission.metadata = {};\n }\n if (!submission.metadata.selectData) {\n submission.metadata.selectData = {};\n }\n let templateData = this.templateData[templateValue];\n if (this.component.multiple) {\n templateData = {};\n const dataValue = this.dataValue;\n if (dataValue && lodash_1.default.isArray(dataValue) && dataValue.length) {\n dataValue.forEach((dataValueItem) => {\n const dataValueItemValue = this.component.reference ? dataValueItem._id.toString() : dataValueItem;\n templateData[dataValueItemValue] = this.templateData[dataValueItemValue];\n });\n }\n templateData[value] = this.templateData[value];\n }\n lodash_1.default.set(submission.metadata.selectData, this.path, templateData);\n }\n }\n updateValue(value, flags) {\n const changed = super.updateValue(value, flags);\n if (changed || !this.selectMetadata) {\n if (this.component.multiple && Array.isArray(this.dataValue)) {\n this.dataValue.forEach(singleValue => this.setMetadata(singleValue));\n }\n else {\n this.setMetadata(this.dataValue);\n }\n }\n return changed;\n }\n setValue(value, flags = {}) {\n const previousValue = this.dataValue;\n const changed = this.updateValue(value, flags);\n if (this.component.widget === 'html5' && (lodash_1.default.isEqual(value, previousValue) || lodash_1.default.isEqual(previousValue, {}) && lodash_1.default.isEqual(flags, {})) && !flags.fromSubmission) {\n return false;\n }\n value = this.dataValue;\n const hasPreviousValue = !this.isEmpty(previousValue);\n const hasValue = !this.isEmpty(value);\n // Undo typing when searching to set the value.\n if (this.component.multiple && Array.isArray(value)) {\n value = value.map(value => {\n if (typeof value === 'boolean' || typeof value === 'number') {\n return value.toString();\n }\n return value;\n });\n }\n else {\n if (typeof value === 'boolean' || typeof value === 'number') {\n value = value.toString();\n }\n }\n if (this.isHtmlRenderMode() && flags && flags.fromSubmission && changed) {\n this.itemsLoaded.then(() => {\n this.redraw();\n });\n return changed;\n }\n // Do not set the value if we are loading... that will happen after it is done.\n if (this.loading) {\n return changed;\n }\n // Determine if we need to perform an initial lazyLoad api call if searchField is provided.\n if (this.isInitApiCallNeeded(hasValue)) {\n this.loading = true;\n this.lazyLoadInit = true;\n const searchProperty = this.component.searchField || this.component.valueProperty;\n this.triggerUpdate(lodash_1.default.get(value.data || value, searchProperty, value), true);\n return changed;\n }\n // Add the value options.\n this.itemsLoaded.then(() => {\n this.addValueOptions();\n this.setChoicesValue(value, hasPreviousValue, flags);\n });\n return changed;\n }\n isInitApiCallNeeded(hasValue) {\n return this.component.lazyLoad &&\n !this.lazyLoadInit &&\n !this.active &&\n !this.selectOptions.length &&\n hasValue &&\n this.shouldInitialLoad &&\n this.visible && (this.component.searchField || this.component.valueProperty);\n }\n setChoicesValue(value, hasPreviousValue, flags = {}) {\n const hasValue = !this.isEmpty(value) || flags.fromSubmission;\n hasPreviousValue = (hasPreviousValue === undefined) ? true : hasPreviousValue;\n if (this.choices) {\n // Now set the value.\n if (hasValue) {\n this.choices.removeActiveItems();\n // Add the currently selected choices if they don't already exist.\n const currentChoices = Array.isArray(value) && this.component.multiple ? value : [value];\n if (!this.addCurrentChoices(currentChoices, this.selectOptions, true)) {\n this.choices.setChoices(this.selectOptions, 'value', 'label', true);\n }\n this.choices.setChoiceByValue(currentChoices);\n }\n else if (hasPreviousValue || flags.resetValue) {\n this.choices.removeActiveItems();\n }\n }\n else {\n if (hasValue) {\n const values = Array.isArray(value) ? value : [value];\n if (!lodash_1.default.isEqual(this.dataValue, this.defaultValue) && this.selectOptions.length < 2\n || (this.selectData && flags.fromSubmission)) {\n const { value, label } = this.selectValueAndLabel(this.dataValue);\n this.addOption(value, label);\n }\n lodash_1.default.each(this.selectOptions, (selectOption) => {\n lodash_1.default.each(values, (val) => {\n if (selectOption.value === '') {\n selectOption.value = {};\n }\n if (lodash_1.default.isEqual(val, selectOption.value) && selectOption.element) {\n selectOption.element.selected = true;\n selectOption.element.setAttribute('selected', 'selected');\n return false;\n }\n });\n });\n }\n else {\n lodash_1.default.each(this.selectOptions, (selectOption) => {\n if (selectOption.element) {\n selectOption.element.selected = false;\n selectOption.element.removeAttribute('selected');\n }\n });\n }\n }\n }\n get itemsLoaded() {\n return this._itemsLoaded || Promise.resolve();\n }\n set itemsLoaded(promise) {\n this._itemsLoaded = promise;\n }\n validateValueAvailability(setting, value) {\n if (!(0, utils_1.boolValue)(setting) || !value) {\n return true;\n }\n const values = this.getOptionsValues();\n if (values) {\n if (lodash_1.default.isObject(value)) {\n const compareComplexValues = (optionValue) => {\n const normalizedOptionValue = this.normalizeSingleValue(optionValue);\n if (!lodash_1.default.isObject(normalizedOptionValue)) {\n return false;\n }\n try {\n return (JSON.stringify(normalizedOptionValue) === JSON.stringify(value));\n }\n catch (err) {\n console.warn.error('Error while comparing items', err);\n return false;\n }\n };\n return values.findIndex((optionValue) => compareComplexValues(optionValue)) !== -1;\n }\n return values.findIndex((optionValue) => this.normalizeSingleValue(optionValue) === value) !== -1;\n }\n return false;\n }\n /**\n * Performs required transformations on the initial value to use in selectOptions\n * @param {*} value\n */\n getOptionValue(value) {\n return lodash_1.default.isObject(value) && this.isEntireObjectDisplay()\n ? this.normalizeSingleValue(value)\n : lodash_1.default.isObject(value) && (this.valueProperty || this.component.key !== 'resource')\n ? value\n : lodash_1.default.isObject(value) && !this.valueProperty\n ? this.interpolate(this.component.template, { item: value }).replace(/<\\/?[^>]+(>|$)/g, '')\n : lodash_1.default.isNull(value)\n ? this.emptyValue\n : String(this.normalizeSingleValue(value));\n }\n /**\n * If component has static values (values, json) or custom values, returns an array of them\n * @returns {Array<*>|undefined}\n */\n getOptionsValues() {\n let rawItems = [];\n switch (this.component.dataSrc) {\n case 'values':\n rawItems = this.component.data.values;\n break;\n case 'json':\n rawItems = this.component.data.json;\n break;\n case 'custom':\n rawItems = this.getCustomItems();\n break;\n }\n if (typeof rawItems === 'string') {\n try {\n rawItems = JSON.parse(rawItems);\n }\n catch (err) {\n console.warn(err.message);\n rawItems = [];\n }\n }\n if (!Array.isArray(rawItems)) {\n return;\n }\n return rawItems.map((item) => this.getOptionValue(this.itemValue(item)));\n }\n /**\n * Deletes the value of the component.\n */\n deleteValue() {\n this.setValue('', {\n noUpdateEvent: true\n });\n this.unset();\n }\n /**\n * Check if a component is eligible for multiple validation\n *\n * @return {boolean}\n */\n validateMultiple() {\n // Select component will contain one input when flagged as multiple.\n return false;\n }\n /**\n * Output this select dropdown as a string value.\n * @return {*}\n */\n isBooleanOrNumber(value) {\n return typeof value === 'number' || typeof value === 'boolean';\n }\n getNormalizedValues() {\n if (!this.component || !this.component.data || !this.component.data.values) {\n return;\n }\n return this.component.data.values.map(value => ({ label: value.label, value: String(this.normalizeSingleValue(value.value)) }));\n }\n asString(value, options = {}) {\n var _a;\n value = value !== null && value !== void 0 ? value : this.getValue();\n //need to convert values to strings to be able to compare values with available options that are strings\n const convertToString = (data, valueProperty) => {\n if (valueProperty) {\n if (Array.isArray(data)) {\n data.forEach((item) => item[valueProperty] = item[valueProperty].toString());\n }\n else {\n data[valueProperty] = data[valueProperty].toString();\n }\n return data;\n }\n if (this.isBooleanOrNumber(data)) {\n data = data.toString();\n }\n if (Array.isArray(data) && data.some(item => this.isBooleanOrNumber(item))) {\n data = data.map(item => {\n if (this.isBooleanOrNumber(item)) {\n item = item.toString();\n }\n });\n }\n return data;\n };\n value = convertToString(value);\n if (['values', 'custom'].includes(this.component.dataSrc) && !this.asyncCustomValues()) {\n const { items, valueProperty, } = this.component.dataSrc === 'values'\n ? {\n items: convertToString(this.getNormalizedValues(), 'value'),\n valueProperty: 'value',\n }\n : {\n items: convertToString(this.getCustomItems(), this.valueProperty),\n valueProperty: this.valueProperty,\n };\n const getFromValues = () => {\n const initialValue = lodash_1.default.find(items, [valueProperty, value]);\n const values = this.defaultSchema.data.values || [];\n return lodash_1.default.isEqual(initialValue, values[0]) ? '-' : initialValue;\n };\n value = (this.component.multiple && Array.isArray(value))\n ? lodash_1.default.filter(items, (item) => value.includes(item.value))\n : valueProperty\n ? (_a = getFromValues()) !== null && _a !== void 0 ? _a : { value, label: value }\n : value;\n }\n if (lodash_1.default.isString(value)) {\n return value;\n }\n const getTemplateValue = (v) => {\n const itemTemplate = this.itemTemplate(v);\n return options.csv && itemTemplate\n ? (0, utils_1.unescapeHTML)(itemTemplate)\n : itemTemplate;\n };\n if (Array.isArray(value)) {\n const items = [];\n value.forEach(item => items.push(getTemplateValue(item)));\n if (this.component.dataSrc === 'resource' && items.length > 0) {\n return items.join(', ');\n }\n else if (items.length > 0) {\n return items.join('<br />');\n }\n else {\n return '-';\n }\n }\n if (this.isEntireObjectDisplay() && lodash_1.default.isObject(value)) {\n return JSON.stringify(value);\n }\n return !lodash_1.default.isNil(value)\n ? getTemplateValue(value)\n : '-';\n }\n detach() {\n var _a, _b;\n this.off('blur');\n if (this.choices) {\n if ((_b = (_a = this.choices.containerOuter) === null || _a === void 0 ? void 0 : _a.element) === null || _b === void 0 ? void 0 : _b.parentNode) {\n this.choices.destroy();\n }\n this.choices = null;\n }\n super.detach();\n }\n focus() {\n if (this.focusableElement) {\n super.focus.call(this);\n this.focusableElement.focus();\n }\n }\n setErrorClasses(elements, dirty, hasError, hasMessages, element = this.element) {\n super.setErrorClasses(elements, dirty, hasError, hasMessages, element);\n if (this.choices) {\n super.setErrorClasses([this.choices.containerInner.element], dirty, hasError, hasMessages, element);\n }\n else {\n super.setErrorClasses([this.refs.selectContainer], dirty, hasError, hasMessages, element);\n }\n }\n}\nexports[\"default\"] = SelectComponent;\n\n\n//# sourceURL=webpack://Formio/./lib/cjs/components/select/Select.js?");
|
|
5801
|
+
eval("\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nconst lodash_1 = __importDefault(__webpack_require__(/*! lodash */ \"./node_modules/lodash/lodash.js\"));\nconst Formio_1 = __webpack_require__(/*! ../../Formio */ \"./lib/cjs/Formio.js\");\nconst ListComponent_1 = __importDefault(__webpack_require__(/*! ../_classes/list/ListComponent */ \"./lib/cjs/components/_classes/list/ListComponent.js\"));\nconst Input_1 = __importDefault(__webpack_require__(/*! ../_classes/input/Input */ \"./lib/cjs/components/_classes/input/Input.js\"));\nconst Form_1 = __importDefault(__webpack_require__(/*! ../../Form */ \"./lib/cjs/Form.js\"));\nconst utils_1 = __webpack_require__(/*! ../../utils/utils */ \"./lib/cjs/utils/utils.js\");\nconst ChoicesWrapper_1 = __importDefault(__webpack_require__(/*! ../../utils/ChoicesWrapper */ \"./lib/cjs/utils/ChoicesWrapper.js\"));\nclass SelectComponent extends ListComponent_1.default {\n static schema(...extend) {\n return ListComponent_1.default.schema({\n type: 'select',\n label: 'Select',\n key: 'select',\n idPath: 'id',\n data: {\n values: [{ label: '', value: '' }],\n json: '',\n url: '',\n resource: '',\n custom: ''\n },\n clearOnRefresh: false,\n limit: 100,\n valueProperty: '',\n lazyLoad: true,\n filter: '',\n searchEnabled: true,\n searchDebounce: 0.3,\n searchField: '',\n minSearch: 0,\n readOnlyValue: false,\n selectFields: '',\n selectThreshold: 0.3,\n uniqueOptions: false,\n tableView: true,\n fuseOptions: {\n include: 'score',\n threshold: 0.3,\n },\n indexeddb: {\n filter: {}\n },\n customOptions: {},\n useExactSearch: false,\n }, ...extend);\n }\n static get builderInfo() {\n return {\n title: 'Select',\n group: 'basic',\n icon: 'th-list',\n weight: 70,\n documentation: '/userguide/form-building/form-components#select',\n schema: SelectComponent.schema()\n };\n }\n static get serverConditionSettings() {\n return SelectComponent.conditionOperatorsSettings;\n }\n static get conditionOperatorsSettings() {\n return Object.assign(Object.assign({}, super.conditionOperatorsSettings), { valueComponent(classComp) {\n const valueComp = Object.assign(Object.assign({}, classComp), { type: 'select' });\n if ((0, utils_1.isSelectResourceWithObjectValue)(classComp)) {\n valueComp.reference = false;\n valueComp.onSetItems = `\n var templateKeys = utils.getItemTemplateKeys(component.template) || [];\n items = _.map(items || [], i => {\n var item = {};\n _.each(templateKeys, k => _.set(item, k, _.get(i, k)));\n return item;\n })\n `;\n }\n return valueComp;\n } });\n }\n static savedValueTypes(schema) {\n const { boolean, string, number, object, array } = utils_1.componentValueTypes;\n const { dataType, reference } = schema;\n const types = (0, utils_1.getComponentSavedTypes)(schema);\n if (types) {\n return types;\n }\n if (reference) {\n return [object];\n }\n if (dataType === 'object') {\n return [object, array];\n }\n if (utils_1.componentValueTypes[dataType]) {\n return [utils_1.componentValueTypes[dataType]];\n }\n return [boolean, string, number, object, array];\n }\n init() {\n super.init();\n this.templateData = {};\n // Trigger an update.\n let updateArgs = [];\n const triggerUpdate = lodash_1.default.debounce((...args) => {\n updateArgs = [];\n return this.updateItems.apply(this, args);\n }, 100);\n this.triggerUpdate = (...args) => {\n // Make sure we always resolve the previous promise before reassign it\n if (typeof this.itemsLoadedResolve === 'function') {\n this.itemsLoadedResolve();\n }\n this.itemsLoaded = new Promise((resolve) => {\n this.itemsLoadedResolve = resolve;\n });\n if (args.length) {\n updateArgs = args;\n }\n return triggerUpdate(...updateArgs);\n };\n // Keep track of the select options.\n this.selectOptions = [];\n if (this.itemsFromUrl) {\n this.isFromSearch = false;\n this.searchServerCount = null;\n this.defaultServerCount = null;\n this.isScrollLoading = false;\n this.searchDownloadedResources = [];\n this.defaultDownloadedResources = [];\n }\n // If this component has been activated.//\n this.activated = false;\n this.itemsLoaded = new Promise((resolve) => {\n this.itemsLoadedResolve = resolve;\n });\n this.shouldPositionDropdown = this.hasDataGridAncestor();\n if (this.isHtmlRenderMode()) {\n this.activate();\n }\n // Get the template keys for this select component.\n this.getTemplateKeys();\n }\n get dataReady() {\n // If the root submission has been set, and we are still not attached, then assume\n // that our data is ready.\n if (this.root &&\n this.root.submissionSet &&\n !this.attached) {\n return Promise.resolve();\n }\n return this.itemsLoaded;\n }\n get defaultSchema() {\n return SelectComponent.schema();\n }\n get emptyValue() {\n if (this.component.multiple) {\n return [];\n }\n // if select has JSON data source type, we are defining if empty value would be an object or a string by checking JSON's first item\n if (this.component.dataSrc === 'json' && this.component.data.json) {\n const firstItem = this.component.data.json[0];\n let firstValue;\n if (this.valueProperty) {\n firstValue = lodash_1.default.get(firstItem, this.valueProperty);\n }\n else {\n firstValue = firstItem;\n }\n if (firstValue && typeof firstValue === 'string') {\n return '';\n }\n else {\n return {};\n }\n }\n if (this.valueProperty) {\n return '';\n }\n return {};\n }\n get valueProperty() {\n if (this.component.valueProperty) {\n return this.component.valueProperty;\n }\n // Force values datasource to use values without actually setting it on the component settings.\n if (this.component.dataSrc === 'values') {\n return 'value';\n }\n return '';\n }\n get inputInfo() {\n const info = super.elementInfo();\n info.type = 'select';\n info.changeEvent = 'change';\n return info;\n }\n get isSelectResource() {\n return this.component.dataSrc === 'resource';\n }\n get itemsFromUrl() {\n return this.isSelectResource || this.isSelectURL;\n }\n get isInfiniteScrollProvided() {\n return this.itemsFromUrl;\n }\n get shouldDisabled() {\n return super.shouldDisabled || this.parentDisabled;\n }\n get shouldInitialLoad() {\n if (this.component.widget === 'html5' &&\n this.isEntireObjectDisplay() &&\n this.component.searchField &&\n this.dataValue) {\n return false;\n }\n return super.shouldLoad;\n }\n get selectMetadata() {\n return super.selectData;\n }\n get selectData() {\n return this.selectMetadata || this.component.selectData;\n }\n isEntireObjectDisplay() {\n return this.component.dataSrc === 'resource' && this.valueProperty === 'data';\n }\n selectValueAndLabel(data) {\n const value = this.getOptionValue((this.isEntireObjectDisplay() && !this.itemValue(data)) ? data : this.itemValue(data));\n const readOnlyResourceLabelData = this.options.readOnly && (this.component.dataSrc === 'resource' || this.component.dataSrc === 'url') && this.selectData;\n return {\n value,\n label: this.itemTemplate((this.isEntireObjectDisplay() && !lodash_1.default.isObject(data.data)) ? { data: data } : readOnlyResourceLabelData || data, value)\n };\n }\n itemTemplate(data, value) {\n if (!lodash_1.default.isNumber(data) && lodash_1.default.isEmpty(data)) {\n return '';\n }\n // If they wish to show the value in read only mode, then just return the itemValue here.\n if (this.options.readOnly && this.component.readOnlyValue) {\n return this.itemValue(data);\n }\n // Perform a fast interpretation if we should not use the template.\n if (data && !this.component.template) {\n const itemLabel = data.label || data;\n const value = (typeof itemLabel === 'string') ? this.t(itemLabel, { _userInput: true }) : itemLabel;\n return this.sanitize(value, this.shouldSanitizeValue);\n }\n if (this.component.multiple && lodash_1.default.isArray(this.dataValue) ? this.dataValue.find((val) => value === val) : (this.dataValue === value)) {\n const selectData = this.selectData;\n if (selectData) {\n const templateValue = this.component.reference && (value === null || value === void 0 ? void 0 : value._id) ? value._id.toString() : value;\n if (!this.templateData || !this.templateData[templateValue]) {\n this.getOptionTemplate(data, value);\n }\n if (this.component.multiple) {\n if (selectData[templateValue]) {\n data = selectData[templateValue];\n }\n }\n else {\n data = selectData;\n }\n }\n }\n if (typeof data === 'string' || typeof data === 'number') {\n return this.sanitize(this.t(data, { _userInput: true }), this.shouldSanitizeValue);\n }\n if (Array.isArray(data)) {\n return data.map((val) => {\n if (typeof val === 'string' || typeof val === 'number') {\n return this.sanitize(this.t(val, { _userInput: true }), this.shouldSanitizeValue);\n }\n return val;\n });\n }\n if (data.data) {\n // checking additional fields in the template for the selected Entire Object option\n const hasNestedFields = /item\\.data\\.\\w*/g.test(this.component.template);\n data.data = this.isEntireObjectDisplay() && lodash_1.default.isObject(data.data) && !hasNestedFields\n ? JSON.stringify(data.data)\n : data.data;\n }\n return super.itemTemplate(data, value);\n }\n /**\n * Adds an option to the select dropdown.\n *\n * @param value\n * @param label\n */\n addOption(value, label, attrs = {}, id = (0, utils_1.getRandomComponentId)()) {\n if (lodash_1.default.isNil(label))\n return;\n const idPath = this.component.idPath\n ? this.component.idPath.split('.').reduceRight((obj, key) => ({ [key]: obj }), id)\n : {};\n const option = Object.assign({ value: this.getOptionValue(value), label }, idPath);\n const skipOption = this.component.uniqueOptions\n ? !!this.selectOptions.find((selectOption) => lodash_1.default.isEqual(selectOption.value, option.value))\n : false;\n if (skipOption) {\n return;\n }\n if (value) {\n this.selectOptions.push(option);\n }\n if (this.refs.selectContainer && (this.component.widget === 'html5')) {\n // Replace an empty Object value to an empty String.\n if (option.value && lodash_1.default.isObject(option.value) && lodash_1.default.isEmpty(option.value)) {\n option.value = '';\n }\n // Add element to option so we can reference it later.\n const div = document.createElement('div');\n div.innerHTML = this.sanitize(this.renderTemplate('selectOption', {\n selected: lodash_1.default.isEqual(this.getOptionValue(this.dataValue), option.value),\n option,\n attrs,\n id,\n useId: (this.valueProperty === '' || this.isEntireObjectDisplay()) && lodash_1.default.isObject(value) && id,\n }), this.shouldSanitizeValue).trim();\n option.element = div.firstChild;\n this.refs.selectContainer.appendChild(option.element);\n }\n }\n addValueOptions(items) {\n items = items || [];\n let added = false;\n let data = this.dataValue;\n // preset submission value with value property before request.\n if (this.options.pdf && !items.length && this.component.dataSrc === 'url' && this.valueProperty) {\n data = Array.isArray(data)\n ? data.map(item => lodash_1.default.set({}, this.valueProperty, item))\n : lodash_1.default.set({}, this.valueProperty, data);\n }\n if (!this.selectOptions.length) {\n // Add the currently selected choices if they don't already exist.\n const currentChoices = Array.isArray(data) && this.component.multiple ? data : [data];\n added = this.addCurrentChoices(currentChoices, items);\n if (!added && !this.component.multiple) {\n this.addPlaceholder();\n }\n }\n return added;\n }\n disableInfiniteScroll() {\n if (!this.downloadedResources) {\n return;\n }\n this.downloadedResources.serverCount = this.downloadedResources.length;\n this.serverCount = this.downloadedResources.length;\n }\n /* eslint-disable max-statements */\n setItems(items, fromSearch) {\n var _a, _b;\n this.selectItems = items;\n // If the items is a string, then parse as JSON.\n if (typeof items == 'string') {\n try {\n items = JSON.parse(items);\n }\n catch (err) {\n console.warn(err.message);\n items = [];\n }\n }\n // Allow js processing (needed for form builder)\n if (this.component.onSetItems) {\n const newItems = typeof this.component.onSetItems === 'function'\n ? this.component.onSetItems(this, items)\n : this.evaluate(this.component.onSetItems, { items: items }, 'items');\n if (newItems) {\n items = newItems;\n }\n }\n if (!this.choices && this.refs.selectContainer) {\n this.empty(this.refs.selectContainer);\n }\n // If they provided select values, then we need to get them instead.\n if (this.component.selectValues) {\n items = lodash_1.default.get(items, this.component.selectValues, items) || [];\n }\n let areItemsEqual;\n if (this.itemsFromUrl) {\n areItemsEqual = this.isSelectURL ? lodash_1.default.isEqual(items, this.downloadedResources) : false;\n const areItemsEnded = this.component.limit > items.length;\n const areItemsDownloaded = areItemsEqual\n && this.downloadedResources\n && this.downloadedResources.length === items.length;\n if (areItemsEnded) {\n this.disableInfiniteScroll();\n }\n else if (areItemsDownloaded) {\n this.selectOptions = [];\n }\n else {\n this.serverCount = items.serverCount;\n }\n }\n if (this.isScrollLoading && items) {\n if (!areItemsEqual) {\n this.downloadedResources = this.downloadedResources\n ? this.downloadedResources.concat(items)\n : items;\n }\n this.downloadedResources.serverCount = items.serverCount || this.downloadedResources.serverCount;\n }\n else {\n this.downloadedResources = items || [];\n this.selectOptions = [];\n // If there is new select option with same id as already selected, set the new one\n if (!lodash_1.default.isEmpty(this.dataValue) && this.component.idPath) {\n const selectedOptionId = lodash_1.default.get(this.dataValue, this.component.idPath, null);\n const newOptionWithSameId = !lodash_1.default.isNil(selectedOptionId) && items.find(item => {\n const itemId = lodash_1.default.get(item, this.component.idPath);\n return itemId === selectedOptionId;\n });\n if (newOptionWithSameId) {\n this.setValue(newOptionWithSameId);\n }\n }\n }\n // Add the value options.\n if (!fromSearch) {\n this.addValueOptions(items);\n }\n if (this.component.widget === 'html5' && !this.component.placeholder) {\n this.addOption(null, '');\n }\n // Iterate through each of the items.\n lodash_1.default.each(items, (item, index) => {\n // preventing references of the components inside the form to the parent form when building forms\n if (this.root && this.root.options.editForm && this.root.options.editForm._id && this.root.options.editForm._id === item._id)\n return;\n const itemValueAndLabel = this.selectValueAndLabel(item);\n this.addOption(itemValueAndLabel.value, itemValueAndLabel.label, {}, lodash_1.default.get(item, this.component.idPath, String(index)));\n });\n if (this.choices) {\n this.choices.setChoices(this.selectOptions, 'value', 'label', true);\n }\n else if (this.loading) {\n // Re-attach select input.\n // this.appendTo(this.refs.input[0], this.selectContainer);\n }\n // We are no longer loading.\n this.isScrollLoading = false;\n this.loading = false;\n const searching = fromSearch && ((_b = (_a = this.choices) === null || _a === void 0 ? void 0 : _a.input) === null || _b === void 0 ? void 0 : _b.isFocussed);\n if (!searching) {\n // If a value is provided, then select it.\n if (!this.isEmpty() || this.isRemoveButtonPressed) {\n this.setValue(this.dataValue, {\n noUpdateEvent: true\n });\n }\n else if (this.shouldAddDefaultValue && !this.options.readOnly) {\n // If a default value is provided then select it.\n const defaultValue = this.defaultValue;\n if (!this.isEmpty(defaultValue)) {\n this.setValue(defaultValue);\n }\n }\n }\n // Say we are done loading the items.\n this.itemsLoadedResolve();\n }\n getSingleItemValueForHTMLMode(data) {\n var _a;\n const option = (_a = this.selectOptions) === null || _a === void 0 ? void 0 : _a.find(({ value }) => lodash_1.default.isEqual(value, data));\n if (option) {\n return option.label || data;\n }\n return data;\n }\n itemValueForHTMLMode(value) {\n if (!this.isHtmlRenderMode()) {\n return super.itemValueForHTMLMode(value);\n }\n if (Array.isArray(value)) {\n const values = value.map(item => Array.isArray(item)\n ? this.itemValueForHTMLMode(item)\n : this.getSingleItemValueForHTMLMode(item));\n return values.join(', ');\n }\n return this.getSingleItemValueForHTMLMode(value);\n }\n /* eslint-enable max-statements */\n get defaultValue() {\n let defaultValue = super.defaultValue;\n if (!defaultValue && (this.component.defaultValue === false || this.component.defaultValue === 0)) {\n defaultValue = this.component.defaultValue;\n }\n return defaultValue;\n }\n get loadingError() {\n return !this.component.refreshOn && !this.component.refreshOnBlur && this.networkError;\n }\n loadItems(url, search, headers, options, method, body) {\n options = options || {};\n // See if we should load items or not.\n if (!this.shouldLoad || (!this.itemsFromUrl && this.options.readOnly)) {\n this.isScrollLoading = false;\n this.loading = false;\n this.itemsLoadedResolve();\n return;\n }\n // See if they have not met the minimum search requirements.\n const minSearch = parseInt(this.component.minSearch, 10);\n if (this.component.searchField &&\n (minSearch > 0) &&\n (!search || (search.length < minSearch))) {\n // Set empty items.\n return this.setItems([]);\n }\n // Ensure we have a method and remove any body if method is get\n method = method || 'GET';\n if (method.toUpperCase() === 'GET') {\n body = null;\n }\n const limit = this.component.limit || 100;\n const skip = this.isScrollLoading ? this.selectOptions.length : 0;\n const query = this.component.disableLimit ? {} : {\n limit,\n skip,\n };\n // Allow for url interpolation.\n url = this.interpolate(url, {\n formioBase: Formio_1.Formio.getBaseUrl(),\n search,\n limit,\n skip,\n page: Math.abs(Math.floor(skip / limit))\n });\n // Add search capability.\n if (this.component.searchField && search) {\n const searchValue = Array.isArray(search)\n ? search.join(',')\n : typeof search === 'object'\n ? JSON.stringify(search)\n : search;\n query[this.component.searchField] = this.component.searchField.endsWith('__regex')\n ? lodash_1.default.escapeRegExp(searchValue)\n : searchValue;\n }\n // If they wish to return only some fields.\n if (this.component.selectFields) {\n query.select = this.component.selectFields;\n }\n // Add sort capability\n if (this.component.sort) {\n query.sort = this.component.sort;\n }\n if (!lodash_1.default.isEmpty(query)) {\n // Add the query string.\n url += (!url.includes('?') ? '?' : '&') + Formio_1.Formio.serialize(query, (item) => this.interpolate(item));\n }\n // Add filter capability\n if (this.component.filter) {\n url += (!url.includes('?') ? '?' : '&') + this.interpolate(this.component.filter);\n }\n // Set ignoreCache if it is\n options.ignoreCache = this.component.ignoreCache;\n // Make the request.\n options.header = headers;\n this.loading = true;\n Formio_1.Formio.makeRequest(this.options.formio, 'select', url, method, body, options)\n .then((response) => {\n this.loading = false;\n this.setItems(response, !!search);\n })\n .catch((err) => {\n if (this.itemsFromUrl) {\n this.setItems([]);\n this.disableInfiniteScroll();\n }\n this.isScrollLoading = false;\n this.handleLoadingError(err);\n });\n }\n handleLoadingError(err) {\n this.loading = false;\n if (err.networkError) {\n this.networkError = true;\n }\n this.itemsLoadedResolve();\n this.emit('componentError', {\n component: this.component,\n message: err.toString(),\n });\n console.warn(`Unable to load resources for ${this.key}`);\n }\n /**\n * Get the request headers for this select dropdown.\n */\n get requestHeaders() {\n // Create the headers object.\n const headers = new Formio_1.Formio.Headers();\n // Add custom headers to the url.\n if (this.component.data && this.component.data.headers) {\n try {\n lodash_1.default.each(this.component.data.headers, (header) => {\n if (header.key) {\n headers.set(header.key, this.interpolate(header.value));\n }\n });\n }\n catch (err) {\n console.warn(err.message);\n }\n }\n return headers;\n }\n getCustomItems() {\n const customItems = this.evaluate(this.component.data.custom, {\n values: []\n }, 'values');\n this.asyncValues = (0, utils_1.isPromise)(customItems);\n return customItems;\n }\n asyncCustomValues() {\n if (!lodash_1.default.isBoolean(this.asyncValues)) {\n this.getCustomItems();\n }\n return this.asyncValues;\n }\n updateCustomItems(forceUpdate) {\n if (this.asyncCustomValues()) {\n if (!forceUpdate && !this.active) {\n this.itemsLoadedResolve();\n return;\n }\n this.loading = true;\n this.getCustomItems()\n .then(items => {\n this.loading = false;\n this.setItems(items || []);\n })\n .catch(err => {\n this.handleLoadingError(err);\n });\n }\n else {\n this.setItems(this.getCustomItems() || []);\n }\n }\n isEmpty(value = this.dataValue) {\n return super.isEmpty(value) || value === undefined;\n }\n refresh(value, { instance }) {\n if (this.component.clearOnRefresh && (instance && !instance.pristine)) {\n this.setValue(this.emptyValue);\n }\n this.updateItems(null, true);\n }\n get additionalResourcesAvailable() {\n return lodash_1.default.isNil(this.serverCount) || (this.serverCount > this.downloadedResources.length);\n }\n get serverCount() {\n if (this.isFromSearch) {\n return this.searchServerCount;\n }\n return this.defaultServerCount;\n }\n set serverCount(value) {\n if (this.isFromSearch) {\n this.searchServerCount = value;\n }\n else {\n this.defaultServerCount = value;\n }\n }\n get downloadedResources() {\n if (this.isFromSearch) {\n return this.searchDownloadedResources;\n }\n return this.defaultDownloadedResources;\n }\n set downloadedResources(value) {\n if (this.isFromSearch) {\n this.searchDownloadedResources = value;\n }\n else {\n this.defaultDownloadedResources = value;\n }\n }\n addPlaceholder() {\n if (!this.component.placeholder) {\n return;\n }\n this.addOption('', this.component.placeholder, { placeholder: true });\n }\n /**\n * Activate this select control.\n */\n activate() {\n if (this.loading || !this.active) {\n this.setLoadingItem();\n }\n if (this.active) {\n return;\n }\n this.activated = true;\n this.triggerUpdate();\n }\n setLoadingItem(addToCurrentList = false) {\n if (this.choices) {\n if (addToCurrentList) {\n this.choices.setChoices([{\n value: `${this.id}-loading`,\n label: 'Loading...',\n disabled: true,\n }], 'value', 'label');\n }\n else {\n this.choices.setChoices([{\n value: '',\n label: `<i class=\"${this.iconClass('refresh')}\" style=\"font-size:1.3em;\"></i>`,\n disabled: true,\n }], 'value', 'label', true);\n }\n }\n else if (this.component.dataSrc === 'url' || this.component.dataSrc === 'resource') {\n this.addOption('', this.t('loading...'));\n }\n }\n get active() {\n return !this.component.lazyLoad || this.activated;\n }\n render() {\n const info = this.inputInfo;\n info.attr = info.attr || {};\n info.multiple = this.component.multiple;\n return super.render(this.wrapElement(this.renderTemplate('select', {\n input: info,\n selectOptions: '',\n index: null,\n })));\n }\n wrapElement(element) {\n return this.component.addResource && !this.options.readOnly\n ? (this.renderTemplate('resourceAdd', {\n element\n }))\n : element;\n }\n choicesOptions() {\n const useSearch = this.component.hasOwnProperty('searchEnabled') ? this.component.searchEnabled : true;\n const placeholderValue = this.t(this.component.placeholder, { _userInput: true });\n let customOptions = this.component.customOptions || {};\n if (typeof customOptions == 'string') {\n try {\n customOptions = JSON.parse(customOptions);\n }\n catch (err) {\n console.warn(err.message);\n customOptions = {};\n }\n }\n const commonFuseOptions = {\n maxPatternLength: 1000,\n distance: 1000,\n };\n return Object.assign({ removeItemButton: this.component.disabled ? false : lodash_1.default.get(this.component, 'removeItemButton', true), itemSelectText: '', classNames: {\n containerOuter: 'choices form-group formio-choices',\n containerInner: this.transform('class', 'form-control ui fluid selection dropdown')\n }, addItemText: false, allowHTML: true, placeholder: !!this.component.placeholder, placeholderValue: placeholderValue, noResultsText: this.t('No results found'), noChoicesText: this.t('No choices to choose from'), searchPlaceholderValue: this.t('Type to search'), shouldSort: false, position: (this.component.dropdown || 'auto'), searchEnabled: useSearch, searchChoices: !this.component.searchField, searchFields: lodash_1.default.get(this, 'component.searchFields', ['label']), shadowRoot: this.root ? this.root.shadowRoot : null, fuseOptions: this.component.useExactSearch\n ? Object.assign({ tokenize: true, matchAllTokens: true }, commonFuseOptions) : Object.assign({}, lodash_1.default.get(this, 'component.fuseOptions', {}), Object.assign({ include: 'score', threshold: lodash_1.default.get(this, 'component.selectThreshold', 0.3) }, commonFuseOptions)), valueComparer: lodash_1.default.isEqual, resetScrollPosition: false }, customOptions);\n }\n /* eslint-disable max-statements */\n attach(element) {\n var _a, _b, _c;\n const superAttach = super.attach(element);\n this.loadRefs(element, {\n selectContainer: 'single',\n addResource: 'single',\n autocompleteInput: 'single'\n });\n //enable autocomplete for select\n const autocompleteInput = this.refs.autocompleteInput;\n if (autocompleteInput) {\n this.addEventListener(autocompleteInput, 'change', (event) => {\n this.setValue(event.target.value);\n });\n }\n const input = this.refs.selectContainer;\n if (!input) {\n return;\n }\n this.addEventListener(input, this.inputInfo.changeEvent, () => this.updateValue(null, {\n modified: true\n }));\n this.attachRefreshOnBlur();\n if (this.component.widget === 'html5') {\n this.addFocusBlurEvents(input);\n this.triggerUpdate(null, true);\n if (this.visible) {\n this.setItems(this.selectItems || []);\n }\n this.focusableElement = input;\n if (this.component.dataSrc === 'custom') {\n this.addEventListener(input, 'focus', () => this.updateCustomItems());\n }\n this.addEventListener(input, 'keydown', (event) => {\n const { key } = event;\n if (['Backspace', 'Delete'].includes(key)) {\n this.setValue(this.emptyValue);\n }\n });\n return;\n }\n const tabIndex = input.tabIndex;\n this.addPlaceholder();\n if (this.i18next) {\n input.setAttribute('dir', this.i18next.dir());\n }\n if ((_c = (_b = (_a = this.choices) === null || _a === void 0 ? void 0 : _a.containerOuter) === null || _b === void 0 ? void 0 : _b.element) === null || _c === void 0 ? void 0 : _c.parentNode) {\n this.choices.destroy();\n }\n const choicesOptions = this.choicesOptions();\n if (ChoicesWrapper_1.default) {\n this.choices = new ChoicesWrapper_1.default(input, choicesOptions);\n if (this.selectOptions && this.selectOptions.length) {\n this.choices.setChoices(this.selectOptions, 'value', 'label', true);\n }\n if (this.component.multiple) {\n this.focusableElement = this.choices.input.element;\n }\n else {\n this.focusableElement = this.choices.containerInner.element;\n this.choices.containerOuter.element.setAttribute('tabIndex', '-1');\n this.addEventListener(this.choices.containerOuter.element, 'focus', () => this.focusableElement.focus());\n }\n Input_1.default.prototype.addFocusBlurEvents.call(this, this.focusableElement);\n if (this.itemsFromUrl && !this.component.noRefreshOnScroll) {\n this.scrollList = this.choices.choiceList.element;\n this.addEventListener(this.scrollList, 'scroll', () => this.onScroll());\n }\n if (choicesOptions.removeItemButton) {\n this.addEventListener(input, 'removeItem', () => {\n this.isRemoveButtonPressed = true;\n });\n }\n }\n if (window && this.choices && this.shouldPositionDropdown) {\n this.addEventListener(window.document, 'scroll', () => {\n this.positionDropdown(true);\n }, false, true);\n }\n this.focusableElement.setAttribute('tabIndex', tabIndex);\n // If a search field is provided, then add an event listener to update items on search.\n if (this.component.searchField) {\n // Make sure to clear the search when no value is provided.\n if (this.choices && this.choices.input && this.choices.input.element) {\n this.addEventListener(this.choices.input.element, 'input', (event) => {\n this.isFromSearch = !!event.target.value;\n if (!event.target.value) {\n this.triggerUpdate();\n }\n else {\n this.serverCount = null;\n this.downloadedResources = [];\n }\n });\n }\n this.addEventListener(input, 'choice', () => {\n if (this.component.multiple && this.component.dataSrc === 'resource' && this.isFromSearch) {\n this.triggerUpdate();\n }\n this.isFromSearch = false;\n });\n // avoid spamming the resource/url endpoint when we have server side filtering enabled.\n const debounceTimeout = this.component.searchField && (this.isSelectResource || this.isSelectURL) ?\n (this.component.searchDebounce === 0 ? 0 : this.component.searchDebounce || this.defaultSchema.searchDebounce) * 1000\n : 0;\n const updateComponent = (evt) => {\n this.triggerUpdate(evt.detail.value);\n };\n this.addEventListener(input, 'search', lodash_1.default.debounce((e) => {\n updateComponent(e);\n this.positionDropdown();\n }, debounceTimeout));\n this.addEventListener(input, 'stopSearch', () => this.triggerUpdate());\n this.addEventListener(input, 'hideDropdown', () => {\n if (this.choices && this.choices.input && this.choices.input.element) {\n this.choices.input.element.value = '';\n }\n this.updateItems(null, true);\n });\n }\n this.addEventListener(input, 'showDropdown', () => {\n this.update();\n this.positionDropdown();\n });\n if (this.shouldPositionDropdown) {\n this.addEventListener(input, 'highlightChoice', () => {\n this.positionDropdown();\n });\n }\n if (this.choices && choicesOptions.placeholderValue && this.choices._isSelectOneElement) {\n this.addPlaceholderItem(choicesOptions.placeholderValue);\n this.addEventListener(input, 'removeItem', () => {\n this.addPlaceholderItem(choicesOptions.placeholderValue);\n });\n }\n // Add value options.\n this.addValueOptions();\n this.setChoicesValue(this.dataValue);\n if (this.isSelectResource && this.refs.addResource) {\n this.addEventListener(this.refs.addResource, 'click', (event) => {\n event.preventDefault();\n const formioForm = this.ce('div');\n const dialog = this.createModal(formioForm);\n const projectUrl = lodash_1.default.get(this.root, 'formio.projectUrl', Formio_1.Formio.getProjectUrl());\n const formUrl = `${projectUrl}/form/${this.component.data.resource}`;\n new Form_1.default(formioForm, formUrl, {}).ready\n .then((form) => {\n form.on('submit', (submission) => {\n // If valueProperty is set, replace the submission with the corresponding value\n let value = this.valueProperty ? lodash_1.default.get(submission, this.valueProperty) : submission;\n if (this.component.multiple) {\n value = [...this.dataValue, value];\n }\n this.setValue(value);\n this.triggerUpdate();\n dialog.close();\n });\n });\n });\n }\n // Force the disabled state with getters and setters.\n this.disabled = this.shouldDisabled;\n this.triggerUpdate();\n return superAttach;\n }\n setDropdownPosition() {\n var _a, _b, _c, _d;\n const dropdown = (_b = (_a = this.choices) === null || _a === void 0 ? void 0 : _a.dropdown) === null || _b === void 0 ? void 0 : _b.element;\n const container = (_d = (_c = this.choices) === null || _c === void 0 ? void 0 : _c.containerOuter) === null || _d === void 0 ? void 0 : _d.element;\n if (!dropdown || !container) {\n return;\n }\n const containerPosition = container.getBoundingClientRect();\n const isFlipped = container.classList.contains('is-flipped');\n lodash_1.default.assign(dropdown.style, {\n top: `${isFlipped ? containerPosition.top - dropdown.offsetHeight : containerPosition.top + containerPosition.height}px`,\n left: `${containerPosition.left}px`,\n width: `${containerPosition.width}px`,\n position: 'fixed',\n bottom: 'unset',\n right: 'unset',\n });\n }\n hasDataGridAncestor(comp) {\n comp = comp || this;\n if (comp.inDataGrid || comp.type === 'datagrid') {\n return true;\n }\n else if (comp.parent) {\n return this.hasDataGridAncestor(comp.parent);\n }\n else {\n return false;\n }\n }\n positionDropdown(scroll) {\n var _a;\n if (!this.shouldPositionDropdown || !this.choices || (!((_a = this.choices.dropdown) === null || _a === void 0 ? void 0 : _a.isActive) && scroll)) {\n return;\n }\n this.setDropdownPosition();\n this.itemsLoaded.then(() => {\n this.setDropdownPosition();\n });\n }\n get isLoadingAvailable() {\n return !this.isScrollLoading && this.additionalResourcesAvailable;\n }\n onScroll() {\n if (this.isLoadingAvailable) {\n this.isScrollLoading = true;\n this.setLoadingItem(true);\n this.triggerUpdate(this.choices.input.element.value);\n }\n }\n attachRefreshOnBlur() {\n if (this.component.refreshOnBlur) {\n this.on('blur', (instance) => {\n this.checkRefreshOn([{ instance, value: instance.dataValue }], { fromBlur: true });\n });\n }\n }\n addPlaceholderItem(placeholderValue) {\n const items = this.choices._store.activeItems;\n if (!items.length) {\n this.choices._addItem({\n value: '',\n label: placeholderValue,\n choiceId: 0,\n groupId: -1,\n customProperties: null,\n placeholder: true,\n keyCode: null\n });\n }\n }\n /* eslint-enable max-statements */\n update() {\n if (this.component.dataSrc === 'custom') {\n this.updateCustomItems();\n }\n // Activate the control.\n this.activate();\n }\n set disabled(disabled) {\n super.disabled = disabled;\n if (!this.choices) {\n return;\n }\n if (disabled) {\n this.setDisabled(this.choices.containerInner.element, true);\n this.focusableElement.removeAttribute('tabIndex');\n this.choices.disable();\n }\n else {\n this.setDisabled(this.choices.containerInner.element, false);\n this.focusableElement.setAttribute('tabIndex', this.component.tabindex || 0);\n this.choices.enable();\n }\n }\n get disabled() {\n return super.disabled;\n }\n set visible(value) {\n // If we go from hidden to visible, trigger a refresh.\n if (value && (!this._visible !== !value)) {\n this.triggerUpdate();\n }\n super.visible = value;\n }\n get visible() {\n return super.visible;\n }\n /**\n * @param {*} value\n * @param {Array} items\n */\n addCurrentChoices(values, items, keyValue) {\n if (!values) {\n return false;\n }\n const notFoundValuesToAdd = [];\n const added = values.reduce((defaultAdded, value) => {\n if (!value || lodash_1.default.isEmpty(value)) {\n return defaultAdded;\n }\n let found = false;\n // Make sure that `items` and `this.selectOptions` points\n // to the same reference. Because `this.selectOptions` is\n // internal property and all items are populated by\n // `this.addOption` method, we assume that items has\n // 'label' and 'value' properties. This assumption allows\n // us to read correct value from the item.\n const isSelectOptions = items === this.selectOptions;\n if (items && items.length) {\n lodash_1.default.each(items, (choice) => {\n if (choice._id && value._id && (choice._id === value._id)) {\n found = true;\n return false;\n }\n const itemValue = keyValue ? choice.value : this.itemValue(choice, isSelectOptions);\n found |= lodash_1.default.isEqual(itemValue, value);\n return found ? false : true;\n });\n }\n // Add the default option if no item is found.\n if (!found) {\n notFoundValuesToAdd.push(this.selectValueAndLabel(value));\n return true;\n }\n return found || defaultAdded;\n }, false);\n if (notFoundValuesToAdd.length) {\n if (this.choices) {\n this.choices.setChoices(notFoundValuesToAdd, 'value', 'label');\n }\n notFoundValuesToAdd.map(notFoundValue => {\n this.addOption(notFoundValue.value, notFoundValue.label);\n });\n }\n return added;\n }\n getValueAsString(data, options) {\n return (this.component.multiple && Array.isArray(data))\n ? data.map((v) => this.asString(v, options)).join(', ')\n : this.asString(data, options);\n }\n getValue() {\n // If the widget isn't active.\n if (this.viewOnly || this.loading\n || (!this.component.lazyLoad && !this.selectOptions.length)\n || !this.element) {\n return this.dataValue;\n }\n let value = this.emptyValue;\n if (this.choices) {\n value = this.choices.getValue(true);\n // Make sure we don't get the placeholder\n if (!this.component.multiple &&\n this.component.placeholder &&\n (value === this.t(this.component.placeholder, { _userInput: true }))) {\n value = this.emptyValue;\n }\n }\n else if (this.refs.selectContainer) {\n value = this.refs.selectContainer.value;\n if (this.valueProperty === '' || this.isEntireObjectDisplay()) {\n if (value === '') {\n return {};\n }\n const option = this.selectOptions[value] ||\n this.selectOptions.find(option => option.id === value);\n if (option && lodash_1.default.isObject(option.value)) {\n value = option.value;\n }\n }\n }\n else {\n value = this.dataValue;\n }\n // Choices will return undefined if nothing is selected. We really want '' to be empty.\n if (value === undefined || value === null) {\n value = '';\n }\n return value;\n }\n redraw() {\n const done = super.redraw();\n this.triggerUpdate();\n return done;\n }\n normalizeSingleValue(value) {\n if (lodash_1.default.isNil(value)) {\n return;\n }\n const valueIsObject = lodash_1.default.isObject(value);\n //check if value equals to default emptyValue\n if (valueIsObject && Object.keys(value).length === 0) {\n return value;\n }\n const dataType = this.component.dataType || 'auto';\n const normalize = {\n value,\n number() {\n const numberValue = Number(this.value);\n const isEquivalent = value.toString() === numberValue.toString();\n if (!Number.isNaN(numberValue) && Number.isFinite(numberValue) && value !== '' && isEquivalent) {\n this.value = numberValue;\n }\n return this;\n },\n boolean() {\n if (lodash_1.default.isString(this.value)\n && (this.value.toLowerCase() === 'true'\n || this.value.toLowerCase() === 'false')) {\n this.value = (this.value.toLowerCase() === 'true');\n }\n return this;\n },\n string() {\n this.value = String(this.value);\n return this;\n },\n object() {\n return this;\n },\n auto() {\n if (lodash_1.default.isObject(this.value)) {\n this.value = this.object().value;\n }\n else {\n this.value = this.string().number().boolean().value;\n }\n return this;\n }\n };\n try {\n return normalize[dataType]().value;\n }\n catch (err) {\n console.warn('Failed to normalize value', err);\n return value;\n }\n }\n /**\n * Normalize values coming into updateValue.\n *\n * @param value\n * @return {*}\n */\n normalizeValue(value) {\n if (this.component.multiple && Array.isArray(value)) {\n return value.map((singleValue) => this.normalizeSingleValue(singleValue));\n }\n return super.normalizeValue(this.normalizeSingleValue(value));\n }\n setMetadata(value) {\n var _a;\n if (lodash_1.default.isNil(value)) {\n return;\n }\n const valueIsObject = lodash_1.default.isObject(value);\n //check if value equals to default emptyValue\n if (valueIsObject && Object.keys(value).length === 0) {\n return value;\n }\n // Check to see if we need to save off the template data into our metadata.\n const templateValue = this.component.reference && (value === null || value === void 0 ? void 0 : value._id) ? value._id.toString() : value;\n const shouldSaveData = !valueIsObject || this.component.reference;\n if (templateValue && shouldSaveData && this.templateData && this.templateData[templateValue] && ((_a = this.root) === null || _a === void 0 ? void 0 : _a.submission)) {\n const submission = this.root.submission;\n if (!submission.metadata) {\n submission.metadata = {};\n }\n if (!submission.metadata.selectData) {\n submission.metadata.selectData = {};\n }\n let templateData = this.templateData[templateValue];\n if (this.component.multiple) {\n templateData = {};\n const dataValue = this.dataValue;\n if (dataValue && lodash_1.default.isArray(dataValue) && dataValue.length) {\n dataValue.forEach((dataValueItem) => {\n const dataValueItemValue = this.component.reference ? dataValueItem._id.toString() : dataValueItem;\n templateData[dataValueItemValue] = this.templateData[dataValueItemValue];\n });\n }\n templateData[value] = this.templateData[value];\n }\n lodash_1.default.set(submission.metadata.selectData, this.path, templateData);\n }\n }\n updateValue(value, flags) {\n const changed = super.updateValue(value, flags);\n if (changed || !this.selectMetadata) {\n if (this.component.multiple && Array.isArray(this.dataValue)) {\n this.dataValue.forEach(singleValue => this.setMetadata(singleValue));\n }\n else {\n this.setMetadata(this.dataValue);\n }\n }\n return changed;\n }\n setValue(value, flags = {}) {\n const previousValue = this.dataValue;\n const changed = this.updateValue(value, flags);\n if (this.component.widget === 'html5' && (lodash_1.default.isEqual(value, previousValue) || lodash_1.default.isEqual(previousValue, {}) && lodash_1.default.isEqual(flags, {})) && !flags.fromSubmission) {\n return false;\n }\n value = this.dataValue;\n const hasPreviousValue = !this.isEmpty(previousValue);\n const hasValue = !this.isEmpty(value);\n // Undo typing when searching to set the value.\n if (this.component.multiple && Array.isArray(value)) {\n value = value.map(value => {\n if (typeof value === 'boolean' || typeof value === 'number') {\n return value.toString();\n }\n return value;\n });\n }\n else {\n if (typeof value === 'boolean' || typeof value === 'number') {\n value = value.toString();\n }\n }\n if (this.isHtmlRenderMode() && flags && flags.fromSubmission && changed) {\n this.itemsLoaded.then(() => {\n this.redraw();\n });\n return changed;\n }\n // Do not set the value if we are loading... that will happen after it is done.\n if (this.loading) {\n return changed;\n }\n // Determine if we need to perform an initial lazyLoad api call if searchField is provided.\n if (this.isInitApiCallNeeded(hasValue)) {\n this.loading = true;\n this.lazyLoadInit = true;\n const searchProperty = this.component.searchField || this.component.valueProperty;\n this.triggerUpdate(lodash_1.default.get(value.data || value, searchProperty, value), true);\n return changed;\n }\n // Add the value options.\n this.itemsLoaded.then(() => {\n this.addValueOptions();\n this.setChoicesValue(value, hasPreviousValue, flags);\n });\n return changed;\n }\n isInitApiCallNeeded(hasValue) {\n return this.component.lazyLoad &&\n !this.lazyLoadInit &&\n !this.active &&\n !this.selectOptions.length &&\n hasValue &&\n this.shouldInitialLoad &&\n this.visible && (this.component.searchField || this.component.valueProperty);\n }\n setChoicesValue(value, hasPreviousValue, flags = {}) {\n const hasValue = !this.isEmpty(value) || flags.fromSubmission;\n hasPreviousValue = (hasPreviousValue === undefined) ? true : hasPreviousValue;\n if (this.choices) {\n // Now set the value.\n if (hasValue) {\n this.choices.removeActiveItems();\n // Add the currently selected choices if they don't already exist.\n const currentChoices = Array.isArray(value) && this.component.multiple ? value : [value];\n if (!this.addCurrentChoices(currentChoices, this.selectOptions, true)) {\n this.choices.setChoices(this.selectOptions, 'value', 'label', true);\n }\n this.choices.setChoiceByValue(currentChoices);\n }\n else if (hasPreviousValue || flags.resetValue) {\n this.choices.removeActiveItems();\n }\n }\n else {\n if (hasValue) {\n const values = Array.isArray(value) ? value : [value];\n if (!lodash_1.default.isEqual(this.dataValue, this.defaultValue) && this.selectOptions.length < 2\n || (this.selectData && flags.fromSubmission)) {\n const { value, label } = this.selectValueAndLabel(this.dataValue);\n this.addOption(value, label);\n }\n lodash_1.default.each(this.selectOptions, (selectOption) => {\n lodash_1.default.each(values, (val) => {\n if (selectOption.value === '') {\n selectOption.value = {};\n }\n if (lodash_1.default.isEqual(val, selectOption.value) && selectOption.element) {\n selectOption.element.selected = true;\n selectOption.element.setAttribute('selected', 'selected');\n return false;\n }\n });\n });\n }\n else {\n lodash_1.default.each(this.selectOptions, (selectOption) => {\n if (selectOption.element) {\n selectOption.element.selected = false;\n selectOption.element.removeAttribute('selected');\n }\n });\n }\n }\n }\n get itemsLoaded() {\n return this._itemsLoaded || Promise.resolve();\n }\n set itemsLoaded(promise) {\n this._itemsLoaded = promise;\n }\n validateValueAvailability(setting, value) {\n if (!(0, utils_1.boolValue)(setting) || !value) {\n return true;\n }\n const values = this.getOptionsValues();\n if (values) {\n if (lodash_1.default.isObject(value)) {\n const compareComplexValues = (optionValue) => {\n const normalizedOptionValue = this.normalizeSingleValue(optionValue);\n if (!lodash_1.default.isObject(normalizedOptionValue)) {\n return false;\n }\n try {\n return (JSON.stringify(normalizedOptionValue) === JSON.stringify(value));\n }\n catch (err) {\n console.warn.error('Error while comparing items', err);\n return false;\n }\n };\n return values.findIndex((optionValue) => compareComplexValues(optionValue)) !== -1;\n }\n return values.findIndex((optionValue) => this.normalizeSingleValue(optionValue) === value) !== -1;\n }\n return false;\n }\n /**\n * Performs required transformations on the initial value to use in selectOptions\n * @param {*} value\n */\n getOptionValue(value) {\n return lodash_1.default.isObject(value) && this.isEntireObjectDisplay()\n ? this.normalizeSingleValue(value)\n : lodash_1.default.isObject(value) && (this.valueProperty || this.component.key !== 'resource')\n ? value\n : lodash_1.default.isObject(value) && !this.valueProperty\n ? this.interpolate(this.component.template, { item: value }).replace(/<\\/?[^>]+(>|$)/g, '')\n : lodash_1.default.isNull(value)\n ? this.emptyValue\n : String(this.normalizeSingleValue(value));\n }\n /**\n * If component has static values (values, json) or custom values, returns an array of them\n * @returns {Array<*>|undefined}\n */\n getOptionsValues() {\n let rawItems = [];\n switch (this.component.dataSrc) {\n case 'values':\n rawItems = this.component.data.values;\n break;\n case 'json':\n rawItems = this.component.data.json;\n break;\n case 'custom':\n rawItems = this.getCustomItems();\n break;\n }\n if (typeof rawItems === 'string') {\n try {\n rawItems = JSON.parse(rawItems);\n }\n catch (err) {\n console.warn(err.message);\n rawItems = [];\n }\n }\n if (!Array.isArray(rawItems)) {\n return;\n }\n return rawItems.map((item) => this.getOptionValue(this.itemValue(item)));\n }\n /**\n * Deletes the value of the component.\n */\n deleteValue() {\n this.setValue('', {\n noUpdateEvent: true\n });\n this.unset();\n }\n /**\n * Check if a component is eligible for multiple validation\n *\n * @return {boolean}\n */\n validateMultiple() {\n // Select component will contain one input when flagged as multiple.\n return false;\n }\n /**\n * Output this select dropdown as a string value.\n * @return {*}\n */\n isBooleanOrNumber(value) {\n return typeof value === 'number' || typeof value === 'boolean';\n }\n getNormalizedValues() {\n if (!this.component || !this.component.data || !this.component.data.values) {\n return;\n }\n return this.component.data.values.map(value => ({ label: value.label, value: String(this.normalizeSingleValue(value.value)) }));\n }\n asString(value, options = {}) {\n var _a;\n value = value !== null && value !== void 0 ? value : this.getValue();\n if (options.modalPreview && this.selectData) {\n const { label } = this.selectValueAndLabel(value);\n return label;\n }\n //need to convert values to strings to be able to compare values with available options that are strings\n const convertToString = (data, valueProperty) => {\n if (valueProperty) {\n if (Array.isArray(data)) {\n data.forEach((item) => item[valueProperty] = item[valueProperty].toString());\n }\n else {\n data[valueProperty] = data[valueProperty].toString();\n }\n return data;\n }\n if (this.isBooleanOrNumber(data)) {\n data = data.toString();\n }\n if (Array.isArray(data) && data.some(item => this.isBooleanOrNumber(item))) {\n data = data.map(item => {\n if (this.isBooleanOrNumber(item)) {\n item = item.toString();\n }\n });\n }\n return data;\n };\n value = convertToString(value);\n if (['values', 'custom'].includes(this.component.dataSrc) && !this.asyncCustomValues()) {\n const { items, valueProperty, } = this.component.dataSrc === 'values'\n ? {\n items: convertToString(this.getNormalizedValues(), 'value'),\n valueProperty: 'value',\n }\n : {\n items: convertToString(this.getCustomItems(), this.valueProperty),\n valueProperty: this.valueProperty,\n };\n const getFromValues = () => {\n const initialValue = lodash_1.default.find(items, [valueProperty, value]);\n const values = this.defaultSchema.data.values || [];\n return lodash_1.default.isEqual(initialValue, values[0]) ? '-' : initialValue;\n };\n value = (this.component.multiple && Array.isArray(value))\n ? lodash_1.default.filter(items, (item) => value.includes(item.value))\n : valueProperty\n ? (_a = getFromValues()) !== null && _a !== void 0 ? _a : { value, label: value }\n : value;\n }\n if (lodash_1.default.isString(value)) {\n return value;\n }\n const getTemplateValue = (v) => {\n const itemTemplate = this.itemTemplate(v);\n return options.csv && itemTemplate\n ? (0, utils_1.unescapeHTML)(itemTemplate)\n : itemTemplate;\n };\n if (Array.isArray(value)) {\n const items = [];\n value.forEach(item => items.push(getTemplateValue(item)));\n if (this.component.dataSrc === 'resource' && items.length > 0) {\n return items.join(', ');\n }\n else if (items.length > 0) {\n return items.join('<br />');\n }\n else {\n return '-';\n }\n }\n if (this.isEntireObjectDisplay() && lodash_1.default.isObject(value)) {\n return JSON.stringify(value);\n }\n return !lodash_1.default.isNil(value)\n ? getTemplateValue(value)\n : '-';\n }\n detach() {\n var _a, _b;\n this.off('blur');\n if (this.choices) {\n if ((_b = (_a = this.choices.containerOuter) === null || _a === void 0 ? void 0 : _a.element) === null || _b === void 0 ? void 0 : _b.parentNode) {\n this.choices.destroy();\n }\n this.choices = null;\n }\n super.detach();\n }\n focus() {\n if (this.focusableElement) {\n super.focus.call(this);\n this.focusableElement.focus();\n }\n }\n setErrorClasses(elements, dirty, hasError, hasMessages, element = this.element) {\n super.setErrorClasses(elements, dirty, hasError, hasMessages, element);\n if (this.choices) {\n super.setErrorClasses([this.choices.containerInner.element], dirty, hasError, hasMessages, element);\n }\n else {\n super.setErrorClasses([this.refs.selectContainer], dirty, hasError, hasMessages, element);\n }\n }\n}\nexports[\"default\"] = SelectComponent;\n\n\n//# sourceURL=webpack://Formio/./lib/cjs/components/select/Select.js?");
|
|
5792
5802
|
|
|
5793
5803
|
/***/ }),
|
|
5794
5804
|
|
|
@@ -5799,7 +5809,7 @@ eval("\nvar __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5799
5809
|
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
|
|
5800
5810
|
|
|
5801
5811
|
"use strict";
|
|
5802
|
-
eval("\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nconst lodash_1 = __importDefault(__webpack_require__(/*! lodash */ \"./node_modules/lodash/lodash.js\"));\nconst utils_1 = __webpack_require__(/*! ../../utils/utils */ \"./lib/cjs/utils/utils.js\");\nconst Radio_1 = __importDefault(__webpack_require__(/*! ../radio/Radio */ \"./lib/cjs/components/radio/Radio.js\"));\nclass SelectBoxesComponent extends Radio_1.default {\n static schema(...extend) {\n return Radio_1.default.schema({\n type: 'selectboxes',\n label: 'Select Boxes',\n key: 'selectBoxes',\n inline: false\n }, ...extend);\n }\n static get builderInfo() {\n return {\n title: 'Select Boxes',\n group: 'basic',\n icon: 'plus-square',\n weight: 60,\n documentation: '/userguide/form-building/form-components#select-box',\n schema: SelectBoxesComponent.schema()\n };\n }\n static get serverConditionSettings() {\n return SelectBoxesComponent.conditionOperatorsSettings;\n }\n static get conditionOperatorsSettings() {\n return Object.assign(Object.assign({}, super.conditionOperatorsSettings), { valueComponent(classComp) {\n return {\n type: 'select',\n dataSrc: 'custom',\n valueProperty: 'value',\n dataType: 'string',\n data: {\n custom: `values = ${classComp && classComp.values ? JSON.stringify(classComp.values) : []}`\n },\n };\n } });\n }\n static savedValueTypes(schema) {\n return (0, utils_1.getComponentSavedTypes)(schema) || [utils_1.componentValueTypes.object];\n }\n constructor(...args) {\n super(...args);\n }\n init() {\n super.init();\n this.component.inputType = 'checkbox';\n }\n get defaultSchema() {\n return SelectBoxesComponent.schema();\n }\n get inputInfo() {\n const info = super.elementInfo();\n info.attr.name += '[]';\n info.attr.type = 'checkbox';\n info.attr.class = 'form-check-input';\n return info;\n }\n get emptyValue() {\n return this.component.values.reduce((prev, value) => {\n if (value.value) {\n prev[value.value] = false;\n }\n return prev;\n }, {});\n }\n get defaultValue() {\n let defaultValue = this.emptyValue;\n if (!lodash_1.default.isEmpty(this.component.defaultValue)) {\n defaultValue = this.component.defaultValue;\n }\n if (this.component.customDefaultValue && !this.options.preview) {\n defaultValue = this.evaluate(this.component.customDefaultValue, { value: '' }, 'value');\n }\n return defaultValue;\n }\n /**\n * Only empty if the values are all false.\n *\n * @param value\n * @return {boolean}\n */\n isEmpty(value = this.dataValue) {\n let empty = true;\n for (const key in value) {\n if (value.hasOwnProperty(key) && value[key]) {\n empty = false;\n break;\n }\n }\n return empty;\n }\n getValue() {\n if (this.viewOnly || !this.refs.input || !this.refs.input.length) {\n return this.dataValue;\n }\n const value = {};\n lodash_1.default.each(this.refs.input, (input) => {\n value[input.value] = !!input.checked;\n });\n return value;\n }\n /**\n * Normalize values coming into updateValue.\n *\n * @param value\n * @return {*}\n */\n normalizeValue(value) {\n value = value || {};\n if (typeof value !== 'object') {\n if (typeof value === 'string') {\n value = {\n [value]: true\n };\n }\n else {\n value = {};\n }\n }\n if (Array.isArray(value)) {\n lodash_1.default.each(value, (val) => {\n value[val] = true;\n });\n }\n const checkedValues = lodash_1.default.keys(lodash_1.default.pickBy(value, (val) => val));\n if (this.isSelectURL && this.templateData && lodash_1.default.every(checkedValues, (val) => this.templateData[val])) {\n const submission = this.root.submission;\n if (!submission.metadata.selectData) {\n submission.metadata.selectData = {};\n }\n const selectData = [];\n checkedValues.forEach((value) => selectData.push(this.templateData[value]));\n lodash_1.default.set(submission.metadata.selectData, this.path, selectData);\n }\n return value;\n }\n /**\n * Set the value of this component.\n *\n * @param value\n * @param flags\n */\n setValue(value, flags = {}) {\n const changed = this.updateValue(value, flags);\n value = this.dataValue;\n if (this.isHtmlRenderMode()) {\n if (changed) {\n this.redraw();\n }\n }\n else {\n lodash_1.default.each(this.refs.input, (input) => {\n if (lodash_1.default.isUndefined(value[input.value])) {\n value[input.value] = false;\n }\n input.checked = !!value[input.value];\n });\n }\n return changed;\n }\n getValueAsString(value) {\n if (!value) {\n return '';\n }\n if (this.isSelectURL) {\n return (0, lodash_1.default)(value).pickBy((val) => val).keys().join(', ');\n }\n return (0, lodash_1.default)(this.component.values || [])\n .filter((v) => value[v.value])\n .map('label')\n .join(', ');\n }\n setSelectedClasses() {\n if (this.refs.wrapper) {\n //add/remove selected option class\n const value = this.dataValue;\n const valuesKeys = Object.keys(value);\n this.refs.wrapper.forEach((wrapper, index) => {\n let key = valuesKeys[index];\n const input = this.refs.input[index];\n if ((input === null || input === void 0 ? void 0 : input.value.toString()) !== key) {\n key = valuesKeys.find((k) => (input === null || input === void 0 ? void 0 : input.value.toString()) === k);\n }\n const isChecked = value[key];\n if ((isChecked && key) || (this.isSelectURL && !this.shouldLoad && this.listData && lodash_1.default.findIndex(this.selectData, this.listData[index]) !== -1)) {\n //add class to container when selected\n this.addClass(wrapper, this.optionSelectedClass);\n //change \"checked\" attribute\n input.setAttribute('checked', 'true');\n }\n else if (!isChecked && key) {\n this.removeClass(wrapper, this.optionSelectedClass);\n input.removeAttribute('checked');\n }\n });\n }\n }\n setInputsDisabled(value, onlyUnchecked) {\n if (this.refs.input) {\n this.refs.input.forEach(item => {\n if (onlyUnchecked && !item.checked || !onlyUnchecked) {\n item.disabled = value;\n }\n });\n }\n }\n checkComponentValidity(data, dirty, rowData, options, errors = []) {\n const minCount = this.component.validate.minSelectedCount;\n const maxCount = this.component.validate.maxSelectedCount;\n if (!this.shouldSkipValidation(data, rowData, options)) {\n const isValid = this.isValid(data, dirty);\n if ((maxCount || minCount)) {\n const count = Object.keys(this.validationValue).reduce((total, key) => {\n if (this.validationValue[key]) {\n total++;\n }\n return total;\n }, 0);\n // Disable the rest of inputs if the max amount is already checked\n if (maxCount && count >= maxCount) {\n this.setInputsDisabled(true, true);\n }\n else if (maxCount && !this.shouldDisabled) {\n this.setInputsDisabled(false);\n }\n if (!isValid && maxCount && count > maxCount) {\n const message = this.t(this.component.maxSelectedCountMessage || 'You may only select up to {{maxCount}} items', { maxCount });\n this.errors.push({ message });\n this.setCustomValidity(message, dirty);\n return false;\n }\n else if (!isValid && minCount && count < minCount) {\n this.setInputsDisabled(false);\n const message = this.t(this.component.minSelectedCountMessage || 'You must select at least {{minCount}} items', { minCount });\n this.errors.push({ message });\n this.setCustomValidity(message, dirty);\n return false;\n }\n }\n }\n return super.checkComponentValidity(data, dirty, rowData, options, errors);\n }\n validateValueAvailability(setting, value) {\n if (!(0, utils_1.boolValue)(setting) || !value) {\n return true;\n }\n const values = this.component.values;\n const availableValueKeys = (values || []).map(({ value: optionValue }) => optionValue);\n const valueKeys = Object.keys(value);\n return valueKeys.every((key) => availableValueKeys.includes(key));\n }\n}\nexports[\"default\"] = SelectBoxesComponent;\n\n\n//# sourceURL=webpack://Formio/./lib/cjs/components/selectboxes/SelectBoxes.js?");
|
|
5812
|
+
eval("\nvar __importDefault = (this && this.__importDefault) || function (mod) {\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\n};\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nconst lodash_1 = __importDefault(__webpack_require__(/*! lodash */ \"./node_modules/lodash/lodash.js\"));\nconst utils_1 = __webpack_require__(/*! ../../utils/utils */ \"./lib/cjs/utils/utils.js\");\nconst Radio_1 = __importDefault(__webpack_require__(/*! ../radio/Radio */ \"./lib/cjs/components/radio/Radio.js\"));\nclass SelectBoxesComponent extends Radio_1.default {\n static schema(...extend) {\n return Radio_1.default.schema({\n type: 'selectboxes',\n label: 'Select Boxes',\n key: 'selectBoxes',\n inline: false\n }, ...extend);\n }\n static get builderInfo() {\n return {\n title: 'Select Boxes',\n group: 'basic',\n icon: 'plus-square',\n weight: 60,\n documentation: '/userguide/form-building/form-components#select-box',\n schema: SelectBoxesComponent.schema()\n };\n }\n static get serverConditionSettings() {\n return SelectBoxesComponent.conditionOperatorsSettings;\n }\n static get conditionOperatorsSettings() {\n return Object.assign(Object.assign({}, super.conditionOperatorsSettings), { valueComponent(classComp) {\n return {\n type: 'select',\n dataSrc: 'custom',\n valueProperty: 'value',\n dataType: 'string',\n data: {\n custom: `values = ${classComp && classComp.values ? JSON.stringify(classComp.values) : []}`\n },\n };\n } });\n }\n static savedValueTypes(schema) {\n return (0, utils_1.getComponentSavedTypes)(schema) || [utils_1.componentValueTypes.object];\n }\n constructor(...args) {\n super(...args);\n }\n init() {\n super.init();\n this.component.inputType = 'checkbox';\n }\n get defaultSchema() {\n return SelectBoxesComponent.schema();\n }\n get inputInfo() {\n const info = super.elementInfo();\n info.attr.name += '[]';\n info.attr.type = 'checkbox';\n info.attr.class = 'form-check-input';\n return info;\n }\n get emptyValue() {\n return this.component.values.reduce((prev, value) => {\n if (value.value) {\n prev[value.value] = false;\n }\n return prev;\n }, {});\n }\n get defaultValue() {\n let defaultValue = this.emptyValue;\n if (!lodash_1.default.isEmpty(this.component.defaultValue)) {\n defaultValue = this.component.defaultValue;\n }\n if (this.component.customDefaultValue && !this.options.preview) {\n defaultValue = this.evaluate(this.component.customDefaultValue, { value: '' }, 'value');\n }\n return defaultValue;\n }\n /**\n * Only empty if the values are all false.\n *\n * @param value\n * @return {boolean}\n */\n isEmpty(value = this.dataValue) {\n let empty = true;\n for (const key in value) {\n if (value.hasOwnProperty(key) && value[key]) {\n empty = false;\n break;\n }\n }\n return empty;\n }\n getValue() {\n if (this.viewOnly || !this.refs.input || !this.refs.input.length) {\n return this.dataValue;\n }\n const value = {};\n lodash_1.default.each(this.refs.input, (input) => {\n value[input.value] = !!input.checked;\n });\n return value;\n }\n /**\n * Normalize values coming into updateValue.\n *\n * @param value\n * @return {*}\n */\n normalizeValue(value) {\n value = value || {};\n if (typeof value !== 'object') {\n if (typeof value === 'string') {\n value = {\n [value]: true\n };\n }\n else {\n value = {};\n }\n }\n if (Array.isArray(value)) {\n lodash_1.default.each(value, (val) => {\n value[val] = true;\n });\n }\n const checkedValues = lodash_1.default.keys(lodash_1.default.pickBy(value, (val) => val));\n if (this.isSelectURL && this.templateData && lodash_1.default.every(checkedValues, (val) => this.templateData[val])) {\n const submission = this.root.submission;\n if (!submission.metadata.selectData) {\n submission.metadata.selectData = {};\n }\n const selectData = [];\n checkedValues.forEach((value) => selectData.push(this.templateData[value]));\n lodash_1.default.set(submission.metadata.selectData, this.path, selectData);\n }\n return value;\n }\n /**\n * Set the value of this component.\n *\n * @param value\n * @param flags\n */\n setValue(value, flags = {}) {\n const changed = this.updateValue(value, flags);\n value = this.dataValue;\n if (this.isHtmlRenderMode()) {\n if (changed) {\n this.redraw();\n }\n }\n else {\n lodash_1.default.each(this.refs.input, (input) => {\n if (lodash_1.default.isUndefined(value[input.value])) {\n value[input.value] = false;\n }\n input.checked = !!value[input.value];\n });\n }\n return changed;\n }\n getValueAsString(value, options = {}) {\n if (!value) {\n return '';\n }\n if (this.isSelectURL) {\n if (options.modalPreview && this.loadedOptions) {\n return this.loadedOptions.filter((option) => value[option.value]).map((option) => option.label).join(', ');\n }\n return (0, lodash_1.default)(value).pickBy((val) => val).keys().join(', ');\n }\n return (0, lodash_1.default)(this.component.values || [])\n .filter((v) => value[v.value])\n .map('label')\n .join(', ');\n }\n setSelectedClasses() {\n if (this.refs.wrapper) {\n //add/remove selected option class\n const value = this.dataValue;\n const valuesKeys = Object.keys(value);\n this.refs.wrapper.forEach((wrapper, index) => {\n let key = valuesKeys[index];\n const input = this.refs.input[index];\n if ((input === null || input === void 0 ? void 0 : input.value.toString()) !== key) {\n key = valuesKeys.find((k) => (input === null || input === void 0 ? void 0 : input.value.toString()) === k);\n }\n const isChecked = value[key];\n if ((isChecked && key) || (this.isSelectURL && !this.shouldLoad && this.listData && lodash_1.default.findIndex(this.selectData, this.listData[index]) !== -1)) {\n //add class to container when selected\n this.addClass(wrapper, this.optionSelectedClass);\n //change \"checked\" attribute\n input.setAttribute('checked', 'true');\n }\n else if (!isChecked && key) {\n this.removeClass(wrapper, this.optionSelectedClass);\n input.removeAttribute('checked');\n }\n });\n }\n }\n setInputsDisabled(value, onlyUnchecked) {\n if (this.refs.input) {\n this.refs.input.forEach(item => {\n if (onlyUnchecked && !item.checked || !onlyUnchecked) {\n item.disabled = value;\n }\n });\n }\n }\n checkComponentValidity(data, dirty, rowData, options, errors = []) {\n const minCount = this.component.validate.minSelectedCount;\n const maxCount = this.component.validate.maxSelectedCount;\n if (!this.shouldSkipValidation(data, rowData, options)) {\n const isValid = this.isValid(data, dirty);\n if ((maxCount || minCount)) {\n const count = Object.keys(this.validationValue).reduce((total, key) => {\n if (this.validationValue[key]) {\n total++;\n }\n return total;\n }, 0);\n // Disable the rest of inputs if the max amount is already checked\n if (maxCount && count >= maxCount) {\n this.setInputsDisabled(true, true);\n }\n else if (maxCount && !this.shouldDisabled) {\n this.setInputsDisabled(false);\n }\n if (!isValid && maxCount && count > maxCount) {\n const message = this.t(this.component.maxSelectedCountMessage || 'You may only select up to {{maxCount}} items', { maxCount });\n this.errors.push({ message });\n this.setCustomValidity(message, dirty);\n return false;\n }\n else if (!isValid && minCount && count < minCount) {\n this.setInputsDisabled(false);\n const message = this.t(this.component.minSelectedCountMessage || 'You must select at least {{minCount}} items', { minCount });\n this.errors.push({ message });\n this.setCustomValidity(message, dirty);\n return false;\n }\n }\n }\n return super.checkComponentValidity(data, dirty, rowData, options, errors);\n }\n validateValueAvailability(setting, value) {\n if (!(0, utils_1.boolValue)(setting) || !value) {\n return true;\n }\n const values = this.component.values;\n const availableValueKeys = (values || []).map(({ value: optionValue }) => optionValue);\n const valueKeys = Object.keys(value);\n return valueKeys.every((key) => availableValueKeys.includes(key));\n }\n}\nexports[\"default\"] = SelectBoxesComponent;\n\n\n//# sourceURL=webpack://Formio/./lib/cjs/components/selectboxes/SelectBoxes.js?");
|
|
5803
5813
|
|
|
5804
5814
|
/***/ }),
|
|
5805
5815
|
|
|
@@ -6239,7 +6249,7 @@ eval("\nvar __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
6239
6249
|
/***/ (function(__unused_webpack_module, exports) {
|
|
6240
6250
|
|
|
6241
6251
|
"use strict";
|
|
6242
|
-
eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports[\"default\"] = {\n unsavedRowsError: 'Please save all rows before proceeding.',\n invalidRowsError: 'Please correct invalid rows before proceeding.',\n invalidRowError: 'Invalid row. Please correct it or delete.',\n invalidOption: '{{field}} is an invalid value.',\n invalidDay: '{{field}} is not a valid day.',\n alertMessageWithLabel: '{{label}}: {{message}}',\n alertMessage: '{{message}}',\n complete: 'Submission Complete',\n error: 'Please fix the following errors before submitting.',\n errorListHotkey: 'Press Ctrl + Alt + X to go back to the error list.',\n errorsListNavigationMessage: 'Click to navigate to the field with following error.',\n submitError: 'Please check the form and correct all errors before submitting.',\n required: '{{field}} is required',\n unique: '{{field}} must be unique',\n array: '{{field}} must be an array',\n array_nonempty: '{{field}} must be a non-empty array', // eslint-disable-line camelcase\n nonarray: '{{field}} must not be an array',\n select: '{{field}} contains an invalid selection',\n pattern: '{{field}} does not match the pattern {{pattern}}',\n minLength: '{{field}} must have at least {{length}} characters.',\n maxLength: '{{field}} must have no more than {{length}} characters.',\n minWords: '{{field}} must have at least {{length}} words.',\n maxWords: '{{field}} must have no more than {{length}} words.',\n min: '{{field}} cannot be less than {{min}}.',\n max: '{{field}} cannot be greater than {{max}}.',\n maxDate: '{{field}} should not contain date after {{- maxDate}}',\n minDate: '{{field}} should not contain date before {{- minDate}}',\n maxYear: '{{field}} should not contain year greater than {{maxYear}}',\n minYear: '{{field}} should not contain year less than {{minYear}}',\n minSelectedCount: 'You must select at least {{minCount}} items',\n maxSelectedCount: 'You may only select up to {{maxCount}} items',\n invalid_email: '{{field}} must be a valid email.', // eslint-disable-line camelcase\n invalid_url: '{{field}} must be a valid url.', // eslint-disable-line camelcase\n invalid_regex: '{{field}} does not match the pattern {{regex}}.', // eslint-disable-line camelcase\n invalid_date: '{{field}} is not a valid date.', // eslint-disable-line camelcase\n invalid_day: '{{field}} is not a valid day.', // eslint-disable-line camelcase\n invalidValueProperty: 'Invalid Value Property',\n mask: '{{field}} does not match the mask.',\n valueIsNotAvailable: '{{ field }} is an invalid value.',\n stripe: '{{stripe}}',\n month: 'Month',\n day: 'Day',\n year: 'Year',\n january: 'January',\n february: 'February',\n march: 'March',\n april: 'April',\n may: 'May',\n june: 'June',\n july: 'July',\n august: 'August',\n september: 'September',\n october: 'October',\n november: 'November',\n december: 'December',\n next: 'Next',\n previous: 'Previous',\n cancel: 'Cancel',\n submit: 'Submit Form',\n confirmCancel: 'Are you sure you want to cancel?',\n saveDraftInstanceError: 'Cannot save draft because there is no formio instance.',\n saveDraftAuthError: 'Cannot save draft unless a user is authenticated.',\n restoreDraftInstanceError: 'Cannot restore draft because there is no formio instance.',\n saveDraftError: 'Unable to save draft.',\n restoreDraftError: 'Unable to restore draft.',\n time: 'Invalid time',\n cancelButtonAriaLabel: 'Cancel button. Click to reset the form',\n previousButtonAriaLabel: 'Previous button. Click to go back to the previous tab',\n nextButtonAriaLabel: 'Next button. Click to go to the next tab',\n submitButtonAriaLabel: 'Submit Form button. Click to submit the form',\n reCaptchaTokenValidationError: 'ReCAPTCHA: Token validation error',\n reCaptchaTokenNotSpecifiedError: 'ReCAPTCHA: Token is not specified in submission',\n};\n\n\n//# sourceURL=webpack://Formio/./lib/cjs/translations/en.js?");
|
|
6252
|
+
eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports[\"default\"] = {\n unsavedRowsError: 'Please save all rows before proceeding.',\n invalidRowsError: 'Please correct invalid rows before proceeding.',\n invalidRowError: 'Invalid row. Please correct it or delete.',\n invalidOption: '{{field}} is an invalid value.',\n invalidDay: '{{field}} is not a valid day.',\n alertMessageWithLabel: '{{label}}: {{message}}',\n alertMessage: '{{message}}',\n complete: 'Submission Complete',\n error: 'Please fix the following errors before submitting.',\n errorListHotkey: 'Press Ctrl + Alt + X to go back to the error list.',\n errorsListNavigationMessage: 'Click to navigate to the field with following error.',\n submitError: 'Please check the form and correct all errors before submitting.',\n required: '{{field}} is required',\n unique: '{{field}} must be unique',\n array: '{{field}} must be an array',\n array_nonempty: '{{field}} must be a non-empty array', // eslint-disable-line camelcase\n nonarray: '{{field}} must not be an array',\n select: '{{field}} contains an invalid selection',\n pattern: '{{field}} does not match the pattern {{pattern}}',\n minLength: '{{field}} must have at least {{length}} characters.',\n maxLength: '{{field}} must have no more than {{length}} characters.',\n minWords: '{{field}} must have at least {{length}} words.',\n maxWords: '{{field}} must have no more than {{length}} words.',\n min: '{{field}} cannot be less than {{min}}.',\n max: '{{field}} cannot be greater than {{max}}.',\n maxDate: '{{field}} should not contain date after {{- maxDate}}',\n minDate: '{{field}} should not contain date before {{- minDate}}',\n maxYear: '{{field}} should not contain year greater than {{maxYear}}',\n minYear: '{{field}} should not contain year less than {{minYear}}',\n minSelectedCount: 'You must select at least {{minCount}} items',\n maxSelectedCount: 'You may only select up to {{maxCount}} items',\n invalid_email: '{{field}} must be a valid email.', // eslint-disable-line camelcase\n invalid_url: '{{field}} must be a valid url.', // eslint-disable-line camelcase\n invalid_regex: '{{field}} does not match the pattern {{regex}}.', // eslint-disable-line camelcase\n invalid_date: '{{field}} is not a valid date.', // eslint-disable-line camelcase\n invalid_day: '{{field}} is not a valid day.', // eslint-disable-line camelcase\n invalidValueProperty: 'Invalid Value Property',\n mask: '{{field}} does not match the mask.',\n valueIsNotAvailable: '{{ field }} is an invalid value.',\n stripe: '{{stripe}}',\n month: 'Month',\n day: 'Day',\n year: 'Year',\n january: 'January',\n february: 'February',\n march: 'March',\n april: 'April',\n may: 'May',\n june: 'June',\n july: 'July',\n august: 'August',\n september: 'September',\n october: 'October',\n november: 'November',\n december: 'December',\n next: 'Next',\n previous: 'Previous',\n cancel: 'Cancel',\n submit: 'Submit Form',\n confirmCancel: 'Are you sure you want to cancel?',\n saveDraftInstanceError: 'Cannot save draft because there is no formio instance.',\n saveDraftAuthError: 'Cannot save draft unless a user is authenticated.',\n restoreDraftInstanceError: 'Cannot restore draft because there is no formio instance.',\n saveDraftError: 'Unable to save draft.',\n restoreDraftError: 'Unable to restore draft.',\n time: 'Invalid time',\n cancelButtonAriaLabel: 'Cancel button. Click to reset the form',\n previousButtonAriaLabel: 'Previous button. Click to go back to the previous tab',\n nextButtonAriaLabel: 'Next button. Click to go to the next tab',\n submitButtonAriaLabel: 'Submit Form button. Click to submit the form',\n reCaptchaTokenValidationError: 'ReCAPTCHA: Token validation error',\n reCaptchaTokenNotSpecifiedError: 'ReCAPTCHA: Token is not specified in submission',\n apiKey: 'API Key is not unique: {{key}}'\n};\n\n\n//# sourceURL=webpack://Formio/./lib/cjs/translations/en.js?");
|
|
6243
6253
|
|
|
6244
6254
|
/***/ }),
|
|
6245
6255
|
|