{"version":3,"sources":["webpack://aspnetValidation/webpack/universalModuleDefinition","webpack://aspnetValidation/webpack/bootstrap","webpack://aspnetValidation/./src/index.ts"],"names":["root","factory","exports","module","define","amd","window","installedModules","__webpack_require__","moduleId","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","nullLogger","warn","globalThis","console","log","_","isValidatable","element","HTMLInputElement","HTMLSelectElement","HTMLTextAreaElement","validatableElementTypes","validatableSelector","selector","map","join","getRelativeFormElement","elementName","selectedName","substring","dotLocation","lastIndexOf","relativeElementName","relativeElement","document","getElementsByName","form","querySelector","required","params","elementType","type","toLowerCase","Array","from","querySelectorAll","checked","checkboxHiddenInput","Boolean","stringLength","min","parseInt","length","max","compare","other","otherElement","range","val","parseFloat","isNaN","regex","pattern","RegExp","test","email","creditcard","cDigit","nCheck","nDigit","bEven","replace","charAt","url","lowerCaseValue","indexOf","phone","remote","fieldSelectors","additionalfields","split","fields","fieldSelector","fieldName","substr","fieldElement","encodedParams","encodedParam","encodeURIComponent","push","payload","Promise","ok","reject","request","XMLHttpRequest","postData","FormData","append","open","setRequestHeader","send","onload","e","status","data","JSON","parse","responseText","statusText","onerror","logger","providers","messageFor","elementUIDs","elementByUID","formInputs","validators","formEvents","inputEvents","summary","debounce","allowHiddenFields","validateForm","callback","HTMLFormElement","Error","formUID","getElementUID","formValidationEvent","undefined","validateField","field","fieldUID","fieldValidationEvent","preValidate","submitEvent","preventDefault","stopImmediatePropagation","handleValidated","success","submitValidForm","focusFirstInvalid","newEvent","SubmitEvent","dispatchEvent","submitter","initialFormAction","action","getAttribute","submitterInput","createElement","appendChild","formAction","submit","formInputUIDs","invalidFormInputUID","find","uid","firstInvalid","HTMLElement","focus","isValid","prevalidate","some","isFieldValid","options","body","watch","addNoValidate","ValidationInputCssClassName","ValidationInputValidCssClassName","ValidationMessageCssClassName","ValidationMessageValidCssClassName","ValidationSummaryCssClassName","ValidationSummaryValidCssClassName","this","addProvider","addMvcProviders","mvc","MvcValidationProviders","scanMessages","remove","span","getElementById","removeValidationMessageSpan","pushValidationMessageSpan","forms","containingForm","Element","closest","formId","spans","index","splice","parseDirectives","attributes","directives","validationAtributes","cut","a","parameters","keys","filter","Q","directive","error","pcut","pvalue","pkey","guid4","Math","random","toString","node","x","getFormValidationTask","resolve","formValidators","inputUID","validator","tasks","all","then","result","every","getMessageFor","input","shouldValidate","trackFormInput","setAttribute","validating","cb","validate","validationEvent","CustomEvent","detail","valid","setTimeout","catch","finally","addEventListener","resetField","renderSummary","reset","isDisabled","scan","classList","contains","innerHTML","untrackFormInput","indexToRemove","addInput","createValidator","debounceTimeoutID","clearTimeout","validateEvent","dataset","valEvent","eventType","removeInput","scanInputs","inputs","createSummaryDOM","renderedMessages","ul","matchingElement","className","li","summaryElements","shadow","stringify","sort","renderedSummaryJSON","listElements","j","hasChildNodes","swapClasses","cloneNode","addError","message","removeError","isHidden","provider","resolution","offsetWidth","offsetHeight","getClientRects","disabled","addClass","removeClass","add","bootstrap","assign","init","readyState","observer","MutationObserver","mutations","forEach","mutation","observed","observe","childList","subtree","addedNodes","removedNodes","target","attributeName","oldValue","newValue"],"mappings":"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","file":"aspnet-validation.min.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"aspnetValidation\"] = factory();\n\telse\n\t\troot[\"aspnetValidation\"] = factory();\n})(window, function() {\nreturn "," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n","/**\n * A simple IDictionary<string, string>\n */\nexport interface StringKeyValuePair {\n [key: string]: string\n}\n\n/**\n * A duplex key-value pair for an element, by GUID or its DOM object reference.\n */\ninterface ElementUID {\n node: Element,\n uid: string;\n}\n\n/**\n * A simple logging interface that mirrors the Console object.\n */\nexport interface Logger {\n log(message: string, ...args: any[]): void;\n warn(message: string, ...args: any[]): void;\n}\n\nconst nullLogger = new (class implements Logger {\n log(_: string, ..._args: any[]): void { }\n warn = globalThis.console.warn;\n})();\n\n/**\n * An `HTMLElement` that can be validated (`input`, `select`, `textarea`).\n */\nexport type ValidatableElement = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;\n\n/**\n * Checks if `element` is validatable (`input`, `select`, `textarea`).\n * @param element The element to check.\n * @returns `true` if validatable, otherwise `false`.\n */\nexport const isValidatable = (element: Node): element is ValidatableElement =>\n element instanceof HTMLInputElement\n || element instanceof HTMLSelectElement\n || element instanceof HTMLTextAreaElement;\n\nconst validatableElementTypes = ['input', 'select', 'textarea'];\n\n/**\n * Generates a selector to match validatable elements (`input`, `select`, `textarea`).\n * @param selector An optional selector to apply to the valid input types, e.g. `[data-val=\"true\"]`.\n * @returns The validatable elements.\n */\nconst validatableSelector = (selector?: string) =>\n validatableElementTypes.map(t => `${t}${selector || ''}`).join(',');\n\n/**\n * Parameters passed into validation providers from the element attributes.\n * error property is read from data-val-[Provider Name] attribute.\n * params property is populated from data-val-[Provider Name]-[Parameter Name] attributes.\n */\nexport interface ValidationDirectiveBindings {\n error: string,\n params: StringKeyValuePair\n}\n\n/**\n * A key-value pair describing what validations to enforce to an input element, with respective parameters.\n */\nexport type ValidationDirective = {\n [key: string]: ValidationDirectiveBindings\n};\n\n/**\n * Validation plugin signature with multitype return.\n * Boolean return signifies the validation result, which uses the default validation error message read from the element attribute.\n * String return signifies failed validation, which then will be used as the validation error message.\n * Promise return signifies asynchronous plugin behavior, with same behavior as Boolean or String.\n */\nexport type ValidationProvider = (value: string, element: ValidatableElement, params: StringKeyValuePair) => boolean | string | Promise<boolean | string>;\n\n/**\n * Callback to receive the result of validating a form.\n */\nexport type ValidatedCallback = (success: boolean) => void;\n\n/**\n * A callback method signature that kickstarts a new validation task for an input element, as a Boolean Promise.\n */\ntype Validator = () => Promise<boolean>;\n\n/**\n * Resolves and returns the element referred by original element using ASP.NET selector logic.\n * @param element - The input to validate\n * @param selector - Used to find the field. Ex. *.Password where * replaces whatever prefixes asp.net might add.\n */\nfunction getRelativeFormElement(element: ValidatableElement, selector: string): ValidatableElement {\n // example elementName: Form.PasswordConfirm, Form.Email\n // example selector (dafuq): *.Password, *.__RequestVerificationToken\n // example result element name: Form.Password, __RequestVerificationToken\n\n let elementName = element.name;\n let selectedName = selector.substring(2); // Password, __RequestVerificationToken\n let objectName = '';\n\n let dotLocation = elementName.lastIndexOf('.');\n if (dotLocation > -1) {\n // Form\n objectName = elementName.substring(0, dotLocation);\n\n // Form.Password\n const relativeElementName = objectName + '.' + selectedName;\n const relativeElement = document.getElementsByName(relativeElementName)[0];\n if (isValidatable(relativeElement)) {\n return relativeElement;\n }\n }\n\n // __RequestVerificationToken\n return element.form.querySelector(validatableSelector(`[name=${selectedName}]`));\n}\n\n/**\n * Contains default implementations for ASP.NET Core MVC validation attributes.\n */\nexport class MvcValidationProviders {\n /**\n * Validates whether the input has a value.\n */\n required: ValidationProvider = (value, element, params) => {\n // Handle single and multiple checkboxes/radio buttons.\n const elementType = element.type.toLowerCase();\n if (elementType === \"checkbox\" || elementType === \"radio\") {\n const allElementsOfThisName = Array.from(element.form.querySelectorAll(validatableSelector(`[name='${element.name}'][type='${elementType}']`)));\n for (let element of allElementsOfThisName) {\n if (element instanceof HTMLInputElement && element.checked === true) {\n return true;\n }\n }\n\n // Checkboxes do not submit a value when unchecked. To work around this, platforms such as ASP.NET render a\n // hidden input with the same name as the checkbox so that a value (\"false\") is still submitted even when\n // the checkbox is not checked. We check this special case here.\n if (elementType === \"checkbox\") {\n const checkboxHiddenInput = element.form.querySelector(`input[name='${element.name}'][type='hidden']`);\n if (checkboxHiddenInput instanceof HTMLInputElement && checkboxHiddenInput.value === \"false\") {\n return true;\n }\n }\n\n return false;\n }\n // Default behavior otherwise.\n return Boolean(value);\n }\n\n /**\n * Validates whether the input value satisfies the length contstraint.\n */\n stringLength: ValidationProvider = (value, element, params) => {\n if (!value) {\n return true;\n }\n\n if (params.min) {\n let min = parseInt(params.min);\n if (value.length < min) {\n return false;\n }\n }\n\n if (params.max) {\n let max = parseInt(params.max);\n if (value.length > max) {\n return false;\n }\n }\n\n return true;\n }\n\n /**\n * Validates whether the input value is equal to another input value.\n */\n compare: ValidationProvider = (value, element, params) => {\n if (!params.other) {\n return true;\n }\n\n let otherElement = getRelativeFormElement(element, params.other);\n if (!otherElement) {\n return true;\n }\n\n return (otherElement.value === value);\n }\n\n /**\n * Validates whether the input value is a number within a given range.\n */\n range: ValidationProvider = (value, element, params) => {\n if (!value) {\n return true;\n }\n\n let val = parseFloat(value);\n if (isNaN(val)) {\n return false;\n }\n\n if (params.min) {\n let min = parseFloat(params.min);\n if (val < min) {\n return false;\n }\n }\n\n if (params.max) {\n let max = parseFloat(params.max);\n if (val > max) {\n return false;\n }\n }\n\n return true;\n }\n\n /**\n * Validates whether the input value satisfies a regular expression pattern.\n */\n regex: ValidationProvider = (value, element, params) => {\n if (!value || !params.pattern) {\n return true;\n }\n\n let r = new RegExp(params.pattern);\n return r.test(value);\n }\n\n /**\n * Validates whether the input value is an email in accordance to RFC822 specification, with a top level domain.\n */\n email: ValidationProvider = (value, element, params) => {\n if (!value) {\n return true;\n }\n\n // RFC822 email address with .TLD validation\n // (c) Richard Willis, Chris Ferdinandi, MIT Licensed\n // https://gist.github.com/badsyntax/719800\n // https://gist.github.com/cferdinandi/d04aad4ce064b8da3edf21e26f8944c4\n\n let r = /^([^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+|\\x22([^\\x0d\\x22\\x5c\\x80-\\xff]|\\x5c[\\x00-\\x7f])*\\x22)(\\x2e([^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+|\\x22([^\\x0d\\x22\\x5c\\x80-\\xff]|\\x5c[\\x00-\\x7f])*\\x22))*\\x40([^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+|\\x5b([^\\x0d\\x5b-\\x5d\\x80-\\xff]|\\x5c[\\x00-\\x7f])*\\x5d)(\\x2e([^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+|\\x5b([^\\x0d\\x5b-\\x5d\\x80-\\xff]|\\x5c[\\x00-\\x7f])*\\x5d))*(\\.\\w{2,})+$/;\n return r.test(value);\n }\n\n /**\n * Validates whether the input value is a credit card number, with Luhn's Algorithm.\n */\n creditcard: ValidationProvider = (value, element, params) => {\n if (!value) {\n return true;\n }\n\n // (c) jquery-validation, MIT Licensed\n // https://github.com/jquery-validation/jquery-validation/blob/master/src/additional/creditcard.js\n // based on https://en.wikipedia.org/wiki/Luhn_algorithm\n\n // Accept only spaces, digits and dashes\n if (/[^0-9 \\-]+/.test(value)) {\n return false;\n }\n\n var nCheck = 0,\n nDigit = 0,\n bEven = false,\n n, cDigit;\n\n value = value.replace(/\\D/g, \"\");\n\n // Basing min and max length on https://developer.ean.com/general_info/Valid_Credit_Card_Types\n if (value.length < 13 || value.length > 19) {\n return false;\n }\n\n for (n = value.length - 1; n >= 0; n--) {\n cDigit = value.charAt(n);\n nDigit = parseInt(cDigit, 10);\n if (bEven) {\n if ((nDigit *= 2) > 9) {\n nDigit -= 9;\n }\n }\n\n nCheck += nDigit;\n bEven = !bEven;\n }\n\n return (nCheck % 10) === 0;\n }\n\n /**\n * Validates whether the input value is a URL.\n */\n url: ValidationProvider = (value, element, params) => {\n if (!value) {\n return true;\n }\n\n let lowerCaseValue = value.toLowerCase();\n\n // Match the logic in `UrlAttribute`\n return lowerCaseValue.indexOf('http://') > -1\n || lowerCaseValue.indexOf('https://') > -1\n || lowerCaseValue.indexOf('ftp://') > -1;\n }\n\n /**\n * Validates whether the input value is a phone number.\n */\n phone: ValidationProvider = (value, element, params) => {\n if (!value) {\n return true;\n }\n\n // Allows whitespace or dash as number separator because some people like to do that...\n let consecutiveSeparator = /[\\+\\-\\s][\\-\\s]/g;\n if (consecutiveSeparator.test(value)) {\n return false;\n }\n\n let r = /^\\+?[0-9\\-\\s]+$/;\n return r.test(value);\n }\n\n /**\n * Asynchronously validates the input value to a JSON GET API endpoint.\n */\n remote: ValidationProvider = (value, element, params) => {\n if (!value) {\n return true;\n }\n\n // params.additionalfields: *.Email,*.Username\n let fieldSelectors: string[] = (params.additionalfields as string).split(',');\n let fields: StringKeyValuePair = {};\n\n for (let fieldSelector of fieldSelectors) {\n let fieldName = fieldSelector.substr(2);\n let fieldElement = getRelativeFormElement(element, fieldSelector);\n\n let hasValue = Boolean(fieldElement && fieldElement.value);\n if (!hasValue) {\n continue;\n }\n\n if (fieldElement instanceof HTMLInputElement &&\n (fieldElement.type === 'checkbox' || fieldElement.type === 'radio')) {\n fields[fieldName] = fieldElement.checked ? fieldElement.value : '';\n } else {\n fields[fieldName] = fieldElement.value;\n }\n }\n\n let url: string = params['url'];\n\n let encodedParams: string[] = [];\n for (let fieldName in fields) {\n let encodedParam = encodeURIComponent(fieldName) + '=' + encodeURIComponent(fields[fieldName]);\n encodedParams.push(encodedParam);\n }\n let payload = encodedParams.join('&');\n\n return new Promise((ok, reject) => {\n let request = new XMLHttpRequest();\n\n if (params.type && params.type.toLowerCase() === 'post') {\n let postData = new FormData();\n for (let fieldName in fields) {\n postData.append(fieldName, fields[fieldName]);\n }\n request.open('post', url);\n request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');\n request.send(payload);\n } else {\n request.open('get', url + '?' + payload);\n request.send();\n }\n\n request.onload = e => {\n if (request.status >= 200 && request.status < 300) {\n let data = JSON.parse(request.responseText);\n ok(data);\n } else {\n reject({\n status: request.status,\n statusText: request.statusText,\n data: request.responseText\n });\n }\n };\n\n request.onerror = e => {\n reject({\n status: request.status,\n statusText: request.statusText,\n data: request.responseText\n });\n };\n });\n }\n}\n\n/**\n * Configuration for @type {ValidationService}.\n */\nexport interface ValidationServiceOptions {\n watch: boolean;\n root: ParentNode;\n addNoValidate: boolean;\n}\n\n/**\n * Responsible for managing the DOM elements and running the validation providers.\n */\nexport class ValidationService {\n /**\n * A key-value collection of loaded validation plugins.\n */\n private providers: { [name: string]: ValidationProvider } = {};\n\n /**\n * A key-value collection of <span> elements for displaying validation messages for an input (by DOM ID).\n */\n private messageFor: { [id: string]: Element[] } = {};\n\n /**\n * A list of managed elements, each having a randomly assigned unique identifier (UID).\n */\n private elementUIDs: ElementUID[] = [];\n\n /**\n * A key-value collection of UID to Element for quick lookup.\n */\n private elementByUID: { [uid: string]: Element } = {};\n\n /**\n * A key-value collection of input UIDs for a <form> UID.\n */\n private formInputs: { [formUID: string]: string[] } = {};\n\n /**\n * A key-value map for input UID to its validator factory.\n */\n private validators: { [inputUID: string]: Validator } = {};\n\n /**\n * A key-value map for form UID to its trigger element (submit event for <form>).\n */\n private formEvents: { [id: string]: (e?: SubmitEvent, callback?: ValidatedCallback) => void } = {};\n\n /**\n * A key-value map for element UID to its trigger element (input event for <textarea> and <input>, change event for <select>).\n */\n private inputEvents: { [id: string]: (e?: Event, callback?: ValidatedCallback) => void } = {};\n\n /**\n * A key-value map of input UID to its validation error message.\n */\n private summary: StringKeyValuePair = {};\n\n /**\n * A serialized representation of the validation error message summary rendered to the user.\n */\n private renderedSummaryJSON: string;\n\n /**\n * In milliseconds, the rate of fire of the input validation.\n */\n debounce = 300;\n\n /**\n * Allow hidden fields validation\n */\n allowHiddenFields = false;\n\n private logger: Logger;\n observer?: MutationObserver;\n\n constructor(logger?: Logger) {\n this.logger = logger || nullLogger;\n }\n\n /**\n * Registers a new validation plugin of the given name, if not registered yet.\n * Registered plugin validates inputs with data-val-[name] attribute, used as error message.\n * @param name\n * @param callback\n */\n addProvider(name: string, callback: ValidationProvider) {\n if (this.providers[name]) {\n // First-Come-First-Serve validation plugin design.\n // Allows developers to override the default MVC Providers by adding custom providers BEFORE bootstrap() is called!\n return;\n }\n this.logger.log(\"Registered provider: %s\", name);\n this.providers[name] = callback;\n }\n\n /**\n * Registers the default providers for enabling ASP.NET Core MVC client-side validation.\n */\n private addMvcProviders() {\n let mvc = new MvcValidationProviders();\n\n // [Required]\n this.addProvider('required', mvc.required);\n // [StringLength], [MinLength], [MaxLength]\n this.addProvider('length', mvc.stringLength);\n this.addProvider('maxlength', mvc.stringLength);\n this.addProvider('minlength', mvc.stringLength);\n // [Compare]\n this.addProvider('equalto', mvc.compare);\n // [Range]\n this.addProvider('range', mvc.range);\n // [RegularExpression]\n this.addProvider('regex', mvc.regex);\n // [CreditCard]\n this.addProvider('creditcard', mvc.creditcard);\n // [EmailAddress]\n this.addProvider('email', mvc.email);\n // [Url]\n this.addProvider('url', mvc.url);\n // [Phone]\n this.addProvider('phone', mvc.phone);\n // [Remote]\n this.addProvider('remote', mvc.remote);\n }\n\n /**\n * Scans document for all validation message <span> generated by ASP.NET Core MVC, then tracks them.\n */\n private scanMessages(root: ParentNode, remove: boolean = false) {\n /* If a validation span explicitly declares a form, we group the span with that form. */\n let validationMessageElements = Array.from(root.querySelectorAll<HTMLElement>('span[form]'));\n for (let span of validationMessageElements) {\n let form = document.getElementById(span.getAttribute('form'));\n if (form) {\n if (remove) {\n this.removeValidationMessageSpan(form, span);\n } else {\n this.pushValidationMessageSpan(form, span);\n }\n }\n }\n\n // Otherwise if a validation message span is inside a form, we group the span with the form it's inside.\n let forms = Array.from(root.querySelectorAll<HTMLFormElement>('form'));\n if (root instanceof HTMLFormElement) {\n // querySelectorAll does not include the root element itself.\n // we could use 'matches', but that's newer than querySelectorAll so we'll keep it simple and compatible.\n forms.push(root);\n }\n // If root is the descendant of a form, we want to include that form too.\n const containingForm = (root instanceof Element) ? root.closest('form') : null;\n if (containingForm) {\n forms.push(containingForm);\n }\n\n for (let form of forms) {\n let validationMessageElements = Array.from(form.querySelectorAll<HTMLElement>('[data-valmsg-for]'));\n\n for (let span of validationMessageElements) {\n if (remove) {\n this.removeValidationMessageSpan(form, span);\n } else {\n this.pushValidationMessageSpan(form, span);\n }\n }\n }\n }\n\n private pushValidationMessageSpan(form: HTMLElement, span: HTMLElement) {\n let formId = this.getElementUID(form);\n let name = `${formId}:${span.getAttribute('data-valmsg-for')}`;\n let spans = this.messageFor[name] || (this.messageFor[name] = []);\n if (spans.indexOf(span) < 0) {\n spans.push(span);\n }\n else {\n this.logger.log(\"Validation element for '%s' is already tracked\", name, span);\n }\n }\n\n private removeValidationMessageSpan(form: HTMLElement, span: HTMLElement) {\n let formId = this.getElementUID(form);\n let name = `${formId}:${span.getAttribute('data-valmsg-for')}`;\n let spans = this.messageFor[name];\n if (!spans) {\n return;\n }\n let index = spans.indexOf(span);\n if (index >= 0) {\n spans.splice(index, 1);\n }\n else {\n this.logger.log(\"Validation element for '%s' was already removed\", name, span);\n }\n }\n\n /**\n * Given attribute map for an HTML input, returns the validation directives to be executed.\n * @param attributes\n */\n parseDirectives(attributes: NamedNodeMap) {\n let directives: ValidationDirective = {};\n let validationAtributes: StringKeyValuePair = {};\n\n let cut = 'data-val-'.length;\n for (let i = 0; i < attributes.length; i++) {\n let a = attributes[i];\n if (a.name.indexOf('data-val-') === 0) {\n let key = a.name.substr(cut);\n validationAtributes[key] = a.value;\n }\n }\n\n for (let key in validationAtributes) {\n if (key.indexOf('-') === -1) {\n let parameters = Object.keys(validationAtributes).filter(Q => {\n return (Q !== key) && (Q.indexOf(key) === 0);\n });\n\n let directive: ValidationDirectiveBindings = {\n error: validationAtributes[key],\n params: {}\n };\n\n let pcut = (key + '-').length;\n for (let i = 0; i < parameters.length; i++) {\n let pvalue = validationAtributes[parameters[i]];\n let pkey = parameters[i].substr(pcut);\n\n directive.params[pkey] = pvalue;\n }\n\n directives[key] = directive;\n }\n }\n\n return directives;\n }\n\n /**\n * Returns an RFC4122 version 4 compliant GUID.\n */\n private guid4() {\n // (c) broofa, MIT Licensed\n // https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript/2117523#2117523\n\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {\n const r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n }\n\n /**\n * Gets a UID for an DOM element.\n * @param node\n */\n private getElementUID(node: Element) {\n let x = this.elementUIDs.filter(e => {\n return e.node === node;\n })[0];\n\n if (x) {\n return x.uid;\n }\n\n let uid = this.guid4();\n this.elementUIDs.push({\n node: node,\n uid: uid\n });\n this.elementByUID[uid] = node;\n return uid;\n }\n\n /**\n * Returns a Promise that returns validation result for each and every inputs within the form.\n * @param formUID\n */\n private getFormValidationTask(formUID: string) {\n let formInputUIDs = this.formInputs[formUID];\n if (!formInputUIDs || formInputUIDs.length === 0) {\n return Promise.resolve(true);\n }\n\n let formValidators: Validator[] = [];\n\n for (let i = 0; i < formInputUIDs.length; i++) {\n let inputUID = formInputUIDs[i];\n const validator = this.validators[inputUID];\n if (validator) {\n formValidators.push(validator);\n }\n }\n\n let tasks = formValidators.map(factory => factory());\n return Promise.all(tasks).then(result => result.every(e => e));\n }\n\n // Retrieves the validation span for the input.\n private getMessageFor(input: ValidatableElement) {\n if (!input.form) {\n return [];\n }\n let formId = this.getElementUID(input.form);\n let name = `${formId}:${input.name}`;\n return this.messageFor[name];\n }\n\n /**\n * Fires off validation for elements within the provided form and then calls the callback\n * @param form The form to validate.\n * @param callback Receives true or false indicating validity after all validation is complete.\n */\n validateForm = (form: HTMLFormElement, callback?: ValidatedCallback) => {\n if (!(form instanceof HTMLFormElement)) {\n throw new Error('validateForm() can only be called on <form> elements');\n }\n let formUID = this.getElementUID(form);\n let formValidationEvent = this.formEvents[formUID];\n if (formValidationEvent) {\n formValidationEvent(undefined, callback);\n }\n }\n\n /**\n * Fires off validation for the provided element and then calls the callback\n * @param field The element to validate.\n * @param callback Receives true or false indicating validity after all validation is complete.\n */\n validateField = (field: ValidatableElement, callback?: ValidatedCallback) => {\n let fieldUID = this.getElementUID(field);\n let fieldValidationEvent = this.inputEvents[fieldUID];\n if (fieldValidationEvent) {\n fieldValidationEvent(undefined, callback);\n }\n }\n\n /**\n * Called before validating form submit events.\n * Default calls `preventDefault()` and `stopImmediatePropagation()`.\n * @param submitEvent The `SubmitEvent`.\n */\n preValidate = (submitEvent: SubmitEvent) => {\n submitEvent.preventDefault();\n submitEvent.stopImmediatePropagation();\n }\n\n /**\n * Handler for validated form submit events.\n * Default calls `submitValidForm(form, submitEvent)` on success\n * and `focusFirstInvalid(form)` on failure.\n * @param form The form that has been validated.\n * @param success The validation result.\n * @param submitEvent The `SubmitEvent`.\n */\n handleValidated = (form: HTMLFormElement, success: boolean, submitEvent?: SubmitEvent) => {\n if (!(form instanceof HTMLFormElement)) {\n throw new Error('handleValidated() can only be called on <form> elements');\n }\n if (success) {\n if (submitEvent) {\n this.submitValidForm(form, submitEvent);\n }\n }\n else {\n this.focusFirstInvalid(form);\n }\n }\n\n /**\n * Dispatches a new `SubmitEvent` on the provided form,\n * then calls `form.submit()` unless `submitEvent` is cancelable\n * and `preventDefault()` was called by a handler that received the new event.\n *\n * This is equivalent to `form.requestSubmit()`, but more flexible.\n * @param form The validated form to submit\n * @param submitEvent The `SubmitEvent`.\n */\n submitValidForm = (form: HTMLFormElement, submitEvent: SubmitEvent) => {\n if (!(form instanceof HTMLFormElement)) {\n throw new Error('submitValidForm() can only be called on <form> elements');\n }\n const newEvent = new SubmitEvent('submit', submitEvent);\n if (form.dispatchEvent(newEvent)) {\n // Because the submitter is not propagated when calling\n // form.submit(), we recreate it here.\n const submitter = submitEvent.submitter;\n const initialFormAction = form.action;\n if (submitter) {\n const name = submitter.getAttribute('name');\n // If name is null, a submit button is not submitted.\n if (name) {\n const submitterInput = document.createElement('input');\n submitterInput.type = 'hidden';\n submitterInput.name = name;\n submitterInput.value = submitter.getAttribute('value');\n form.appendChild(submitterInput)\n }\n\n const formAction = submitter.getAttribute('formaction');\n if (formAction) {\n form.action = formAction;\n }\n }\n\n try {\n form.submit();\n } finally {\n form.action = initialFormAction;\n }\n }\n }\n\n /**\n * Focuses the first invalid element within the provided form\n * @param form\n */\n focusFirstInvalid = (form: HTMLFormElement) => {\n if (!(form instanceof HTMLFormElement)) {\n throw new Error('focusFirstInvalid() can only be called on <form> elements');\n }\n let formUID = this.getElementUID(form);\n let formInputUIDs = this.formInputs[formUID];\n let invalidFormInputUID = formInputUIDs?.find(uid => this.summary[uid]);\n\n if (invalidFormInputUID) {\n const firstInvalid = this.elementByUID[invalidFormInputUID];\n if (firstInvalid instanceof HTMLElement) {\n firstInvalid.focus();\n }\n }\n }\n\n /**\n * Returns true if the provided form is currently valid.\n * The form will be validated unless prevalidate is set to false.\n * @param form The form to validate.\n * @param prevalidate Whether the form should be validated before returning.\n * @param callback A callback that receives true or false indicating validity after all validation is complete. Ignored if prevalidate is false.\n * @returns The current state of the form. May be inaccurate if any validation is asynchronous (e.g. remote); consider using `callback` instead.\n */\n isValid = (form: HTMLFormElement, prevalidate: boolean = true, callback?: ValidatedCallback) => {\n if (!(form instanceof HTMLFormElement)) {\n throw new Error('isValid() can only be called on <form> elements');\n }\n if (prevalidate) {\n this.validateForm(form, callback);\n }\n let formUID = this.getElementUID(form);\n let formInputUIDs = this.formInputs[formUID];\n let formIsInvalid = formInputUIDs?.some(uid => this.summary[uid]) === true;\n return !formIsInvalid;\n }\n\n /**\n * Returns true if the provided field is currently valid.\n * The field will be validated unless prevalidate is set to false.\n * @param field The field to validate.\n * @param prevalidate Whether the field should be validated before returning.\n * @param callback A callback that receives true or false indicating validity after all validation is complete. Ignored if prevalidate is false.\n * @returns The current state of the field. May be inaccurate if any validation is asynchronous (e.g. remote); consider using `callback` instead.\n */\n isFieldValid = (field: ValidatableElement, prevalidate: boolean = true, callback?: ValidatedCallback) => {\n if (prevalidate) {\n this.validateField(field, callback);\n }\n\n let fieldUID = this.getElementUID(field);\n return this.summary[fieldUID] === undefined;\n }\n\n /**\n * Returns true if the event triggering the form submission indicates we should validate the form.\n * @param e\n */\n private shouldValidate(e?: Event) {\n // Skip client-side validation if the form has been submitted via a button that has the \"formnovalidate\" attribute.\n return !(e && e['submitter'] && e['submitter']['formNoValidate']);\n }\n\n /**\n * Tracks a <form> element as parent of an input UID. When the form is submitted, attempts to validate the said input asynchronously.\n * @param form\n * @param inputUID\n */\n private trackFormInput(form: HTMLFormElement, inputUID: string) {\n let formUID = this.getElementUID(form);\n if (!this.formInputs[formUID]) {\n this.formInputs[formUID] = [];\n }\n let add = (this.formInputs[formUID].indexOf(inputUID) === -1);\n if (add) {\n this.formInputs[formUID].push(inputUID);\n\n if (this.options.addNoValidate) {\n this.logger.log('Setting novalidate on form', form);\n form.setAttribute('novalidate', 'novalidate');\n }\n else {\n this.logger.log('Not setting novalidate on form', form);\n }\n }\n else {\n this.logger.log(\"Form input for UID '%s' is already tracked\", inputUID);\n }\n\n if (this.formEvents[formUID]) {\n return;\n }\n\n let validating = false;\n let cb = (e?: SubmitEvent, callback?: ValidatedCallback) => {\n // Prevent recursion\n if (validating) {\n return;\n }\n\n if (!this.shouldValidate(e)) {\n return;\n }\n\n let validate = this.getFormValidationTask(formUID);\n if (!validate) {\n return;\n }\n\n //`preValidate` typically prevents submit before validation\n if (e) {\n this.preValidate(e);\n }\n\n validating = true;\n this.logger.log('Validating', form);\n\n validate.then(async success => {\n this.logger.log('Validated (success = %s)', success, form);\n if (callback) {\n callback(success);\n return;\n }\n\n const validationEvent = new CustomEvent('validation',\n {\n detail: { valid: success }\n });\n form.dispatchEvent(validationEvent);\n\n // Firefox fix: redispatch 'submit' after finished handling this event\n await new Promise(resolve => setTimeout(resolve, 0));\n this.handleValidated(form, success, e);\n }).catch(error => {\n this.logger.log('Validation error', error);\n }).finally(() => {\n validating = false;\n });\n };\n\n form.addEventListener('submit', cb);\n form.addEventListener('reset', e => {\n const uids = this.formInputs[formUID];\n\n for (let uid of uids) {\n this.resetField(uid);\n }\n this.renderSummary();\n });\n this.formEvents[formUID] = cb;\n }\n\n /*\n Reset the state of a validatable input. This is used when it's enabled or disabled.\n */\n reset(input: HTMLElement) {\n if (this.isDisabled(input)) {\n this.resetField(this.getElementUID(input));\n }\n else {\n this.scan(input);\n }\n }\n\n private resetField(inputUID: string) {\n let input = this.elementByUID[inputUID] as ValidatableElement;\n if (input.classList.contains(this.ValidationInputCssClassName)) {\n input.classList.remove(this.ValidationInputCssClassName);\n }\n if (input.classList.contains(this.ValidationInputValidCssClassName)) {\n input.classList.remove(this.ValidationInputValidCssClassName);\n }\n\n let spans = this.getMessageFor(input);\n if (spans) {\n for (let i = 0; i < spans.length; i++) {\n spans[i].innerHTML = '';\n }\n }\n\n delete this.summary[inputUID];\n }\n\n private untrackFormInput(form: HTMLFormElement, inputUID: string) {\n let formUID = this.getElementUID(form);\n if (!this.formInputs[formUID]) {\n return;\n }\n let indexToRemove = this.formInputs[formUID].indexOf(inputUID);\n if (indexToRemove >= 0) {\n this.formInputs[formUID].splice(indexToRemove, 1);\n }\n else {\n this.logger.log(\"Form input for UID '%s' was already removed\", inputUID);\n }\n }\n\n /**\n * Adds an input element to be managed and validated by the service.\n * Triggers a debounced live validation when input value changes.\n * @param input\n */\n addInput(input: ValidatableElement) {\n let uid = this.getElementUID(input);\n\n let directives = this.parseDirectives(input.attributes);\n this.validators[uid] = this.createValidator(input, directives);\n\n if (input.form) {\n this.trackFormInput(input.form, uid);\n }\n\n if (this.inputEvents[uid]) {\n return;\n }\n\n let debounceTimeoutID = 0;\n let cb = (e: Event, callback?: ValidatedCallback) => {\n let validate = this.validators[uid];\n clearTimeout(debounceTimeoutID);\n debounceTimeoutID = setTimeout(() => {\n validate()\n .then(callback)\n .catch(error => {\n this.logger.log('Validation error', error);\n });\n }, this.debounce);\n };\n\n let validateEvent = input.dataset.valEvent;\n if (validateEvent) {\n input.addEventListener(validateEvent, cb);\n }\n else {\n let eventType = input instanceof HTMLSelectElement ? 'change' : 'input';\n input.addEventListener(eventType, cb);\n }\n\n this.inputEvents[uid] = cb;\n }\n\n removeInput(input: ValidatableElement) {\n let uid = this.getElementUID(input);\n\n delete this.summary[uid];\n delete this.inputEvents[uid];\n delete this.validators[uid];\n\n if (input.form) {\n this.untrackFormInput(input.form, uid);\n }\n }\n\n /**\n * Scans the entire document for input elements to be validated.\n */\n private scanInputs(root: ParentNode, remove: boolean = false) {\n let inputs = Array.from(root.querySelectorAll<ValidatableElement>(validatableSelector('[data-val=\"true\"]')));\n\n // querySelectorAll does not include the root element itself.\n // we could use 'matches', but that's newer than querySelectorAll so we'll keep it simple and compatible.\n if (isValidatable(root) && root.getAttribute(\"data-val\") === \"true\") {\n inputs.push(root);\n }\n\n for (let i = 0; i < inputs.length; i++) {\n let input = inputs[i];\n if (remove) {\n this.removeInput(input);\n }\n else {\n this.addInput(input);\n }\n }\n }\n\n /**\n * Returns a <ul> element as a validation errors summary.\n */\n createSummaryDOM() {\n if (!Object.keys(this.summary).length) {\n return null;\n }\n\n let renderedMessages = [];\n let ul = document.createElement('ul');\n for (let key in this.summary) {\n // It could be that the message we are rendering belongs to one of a fieldset of multiple inputs that's not selected,\n // even if another one in the fieldset is. In that case the fieldset is valid, and we shouldn't render the message.\n const matchingElement = this.elementByUID[key];\n if (matchingElement instanceof HTMLInputElement) {\n if (matchingElement.type === \"checkbox\" || matchingElement.type === \"radio\") {\n if (matchingElement.className === this.ValidationInputValidCssClassName) {\n continue;\n }\n }\n }\n\n // With required multiple inputs, such as a checkbox list, we'll have one message per input.\n // It's one from the inputs that's required, not all, so we should only have one message displayed.\n if (renderedMessages.indexOf(this.summary[key]) > -1) {\n continue;\n }\n\n let li = document.createElement('li');\n li.innerHTML = this.summary[key];\n ul.appendChild(li);\n renderedMessages.push(this.summary[key]);\n }\n return ul;\n }\n\n /**\n * Displays validation summary to ASP.NET Core MVC designated elements, when it actually gets updated.\n */\n private renderSummary() {\n let summaryElements = document.querySelectorAll('[data-valmsg-summary=\"true\"]');\n if (!summaryElements.length) {\n return;\n }\n\n // Prevents wasteful re-rendering of summary list element with identical items!\n // Using JSON.stringify for quick and painless deep compare of simple KVP. You need to sort the keys first, tho...\n let shadow = JSON.stringify(this.summary, Object.keys(this.summary).sort());\n if (shadow === this.renderedSummaryJSON) {\n return;\n }\n\n // Prevents wasteful re-rendering of summary list element with identical items!\n this.renderedSummaryJSON = shadow;\n let ul = this.createSummaryDOM();\n\n for (let i = 0; i < summaryElements.length; i++) {\n let e = summaryElements[i];\n\n // Remove existing list elements, but keep the summary's message.\n let listElements = e.querySelectorAll(\"ul\");\n for (let j = 0; j < listElements.length; j++) {\n listElements[j].remove();\n }\n\n // Style the summary element as valid/invalid depending on whether there are any messages to display.\n if (ul && ul.hasChildNodes()) {\n this.swapClasses(e,\n this.ValidationSummaryCssClassName,\n this.ValidationSummaryValidCssClassName)\n e.appendChild(ul.cloneNode(true));\n } else {\n this.swapClasses(e,\n this.ValidationSummaryValidCssClassName,\n this.ValidationSummaryCssClassName)\n }\n }\n }\n\n /**\n * Adds an error message to an input element, which also updates the validation message elements and validation summary elements.\n * @param input\n * @param message\n */\n addError(input: ValidatableElement, message: string) {\n let spans = this.getMessageFor(input);\n if (spans) {\n for (let i = 0; i < spans.length; i++) {\n const span = spans[i];\n spans[i].innerHTML = message;\n this.swapClasses(spans[i],\n this.ValidationMessageCssClassName,\n this.ValidationMessageValidCssClassName);\n }\n }\n\n this.swapClasses(input,\n this.ValidationInputCssClassName,\n this.ValidationInputValidCssClassName);\n\n if (input.form) {\n // Adding an error to one input should also add it to others with the same name (i.e. for radio button and checkbox lists).\n const inputs = input.form.querySelectorAll(validatableSelector(`[name=\"${input.name}\"]`));\n for (let i = 0; i < inputs.length; i++) {\n this.swapClasses(inputs[i],\n this.ValidationInputCssClassName,\n this.ValidationInputValidCssClassName);\n\n let uid = this.getElementUID(inputs[i]);\n this.summary[uid] = message;\n }\n }\n\n this.renderSummary();\n }\n\n /**\n * Removes an error message from an input element, which also updates the validation message elements and validation summary elements.\n * @param input\n */\n removeError(input: ValidatableElement) {\n let spans = this.getMessageFor(input);\n if (spans) {\n for (let i = 0; i < spans.length; i++) {\n spans[i].innerHTML = '';\n this.swapClasses(spans[i],\n this.ValidationMessageValidCssClassName,\n this.ValidationMessageCssClassName);\n }\n }\n\n this.swapClasses(input,\n this.ValidationInputValidCssClassName,\n this.ValidationInputCssClassName);\n\n // Removing an error from one input should also remove it from others with the same name (i.e. for radio button and checkbox lists).\n if (input.form) {\n const inputs = input.form.querySelectorAll(validatableSelector(`[name=\"${input.name}\"]`));\n for (let i = 0; i < inputs.length; i++) {\n this.swapClasses(inputs[i],\n this.ValidationInputValidCssClassName,\n this.ValidationInputCssClassName);\n\n let uid = this.getElementUID(inputs[i]);\n delete this.summary[uid];\n }\n }\n\n this.renderSummary();\n }\n\n /**\n * Returns a validation Promise factory for an input element, using given validation directives.\n * @param input\n * @param directives\n */\n createValidator(input: ValidatableElement, directives: ValidationDirective) {\n return async () => {\n // only validate visible and enabled fields\n if (!this.isHidden(input) && !this.isDisabled(input)) {\n for (let key in directives) {\n let directive = directives[key];\n let provider = this.providers[key];\n\n if (!provider) {\n this.logger.log('aspnet-validation provider not implemented: %s', key);\n continue;\n }\n this.logger.log(\"Running %s validator on element\", key, input);\n\n let result = provider(input.value, input, directive.params);\n let valid = false;\n let error = directive.error;\n\n if (typeof result === 'boolean') {\n valid = result;\n } else if (typeof result === 'string') {\n valid = false;\n error = result;\n } else {\n let resolution = await result;\n if (typeof resolution === 'boolean') {\n valid = resolution;\n } else {\n valid = false;\n error = resolution;\n }\n }\n\n if (!valid) {\n this.addError(input, error);\n return false;\n }\n }\n }\n\n this.removeError(input);\n return true;\n };\n }\n\n /**\n * Checks if the provided input is hidden from the browser\n * @param input\n * @returns\n */\n private isHidden(input: HTMLElement) {\n return !(this.allowHiddenFields || input.offsetWidth || input.offsetHeight || input.getClientRects().length);\n }\n\n /**\n * Checks if the provided input is disabled\n * @param input\n * @returns\n */\n private isDisabled(input: Element) {\n // If the input is validatable, we check the `disabled` property.\n // Otherwise the `disabled` property is undefined and this returns false.\n return (input as ValidatableElement).disabled;\n }\n\n /**\n * Adds addClass and removes removeClass\n * @param element Element to modify\n * @param addClass Class to add\n * @param removeClass Class to remove\n */\n private swapClasses(element: Element, addClass: string, removeClass: string) {\n if (addClass && !this.isDisabled(element) && !element.classList.contains(addClass)) {\n element.classList.add(addClass);\n }\n if (element.classList.contains(removeClass)) {\n element.classList.remove(removeClass);\n }\n }\n\n /**\n * Options for this instance of @type {ValidationService}.\n */\n private options: ValidationServiceOptions = {\n root: document.body,\n watch: false,\n addNoValidate: true,\n }\n\n /**\n * Load default validation providers and scans the entire document when ready.\n * @param options.watch If set to true, a MutationObserver will be used to continuously watch for new elements that provide validation directives.\n * @param options.addNoValidate If set to true (the default), a novalidate attribute will be added to the containing form in validate elements.\n */\n bootstrap(options?: Partial<ValidationServiceOptions>) {\n Object.assign(this.options, options);\n\n this.addMvcProviders();\n let document = window.document;\n const root = this.options.root;\n const init = () => {\n this.scan(root);\n\n // Watch for further mutations after initial scan\n if (this.options.watch) {\n this.watch(root);\n }\n }\n\n // If the document is done loading, scan it now.\n if (document.readyState === 'complete' || document.readyState === 'interactive') {\n init();\n }\n else {\n // Otherwise wait until the document is done loading.\n document.addEventListener('DOMContentLoaded', init);\n }\n }\n\n /**\n * Scans the provided root element for any validation directives and attaches behavior to them.\n */\n scan(root: ParentNode) {\n this.logger.log('Scanning', root);\n this.scanMessages(root);\n this.scanInputs(root);\n }\n\n /**\n * Scans the provided root element for any validation directives and removes behavior from them.\n */\n remove(root: ParentNode) {\n this.logger.log('Removing', root);\n this.scanMessages(root, true);\n this.scanInputs(root, true);\n }\n\n /**\n * Watches the provided root element for mutations, and scans for new validation directives to attach behavior.\n * @param root The root element to use, defaults to the document.documentElement.\n */\n watch(root: ParentNode) {\n this.observer = new MutationObserver(mutations => {\n mutations.forEach(mutation => {\n this.observed(mutation);\n });\n });\n this.observer.observe(root, {\n attributes: true,\n childList: true,\n subtree: true\n });\n this.logger.log(\"Watching for mutations\");\n }\n\n private observed(mutation: MutationRecord) {\n if (mutation.type === 'childList') {\n for (let i = 0; i < mutation.addedNodes.length; i++) {\n let node = mutation.addedNodes[i];\n this.logger.log('Added node', node);\n if (node instanceof HTMLElement) {\n this.scan(node);\n }\n }\n for (let i = 0; i < mutation.removedNodes.length; i++) {\n let node = mutation.removedNodes[i];\n this.logger.log('Removed node', node);\n if (node instanceof HTMLElement) {\n this.remove(node);\n }\n }\n } else if (mutation.type === 'attributes') {\n if (mutation.target instanceof HTMLElement) {\n const attributeName = mutation.attributeName;\n\n // Special case for disabled.\n if (attributeName === 'disabled') {\n const target = mutation.target as ValidatableElement;\n this.reset(target);\n }\n else {\n const oldValue = mutation.oldValue ?? '';\n const newValue = mutation.target.attributes[mutation.attributeName]?.value ?? '';\n this.logger.log(\"Attribute '%s' changed from '%s' to '%s'\",\n mutation.attributeName,\n oldValue,\n newValue,\n mutation.target);\n if (oldValue !== newValue) {\n this.scan(mutation.target);\n }\n }\n }\n }\n }\n\n /**\n * Override CSS class name for input validation error. Default: 'input-validation-error'\n */\n ValidationInputCssClassName = \"input-validation-error\";\n\n /**\n * Override CSS class name for valid input validation. Default: 'input-validation-valid'\n */\n ValidationInputValidCssClassName = \"input-validation-valid\";\n\n /**\n * Override CSS class name for field validation error. Default: 'field-validation-error'\n */\n ValidationMessageCssClassName = \"field-validation-error\";\n\n /**\n * Override CSS class name for valid field validation. Default: 'field-validation-valid'\n */\n ValidationMessageValidCssClassName = \"field-validation-valid\";\n\n /**\n * Override CSS class name for validation summary error. Default: 'validation-summary-errors'\n */\n ValidationSummaryCssClassName = \"validation-summary-errors\";\n\n /**\n * Override CSS class name for valid validation summary. Default: 'validation-summary-valid'\n */\n ValidationSummaryValidCssClassName = \"validation-summary-valid\";\n}\n"],"sourceRoot":""}