diff --git a/dist/aspnet-validation.js b/dist/aspnet-validation.js index 2233d3f..f508ead 100644 --- a/dist/aspnet-validation.js +++ b/dist/aspnet-validation.js @@ -108,10 +108,11 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MvcValidationProviders", function() { return MvcValidationProviders; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ValidationService", function() { return ValidationService; }); var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; @@ -790,7 +791,7 @@ var ValidationService = /** @class */ (function () { ValidationService.prototype.createValidator = function (input, directives) { var _this = this; return function () { return __awaiter(_this, void 0, void 0, function () { - var _a, _b, _i, key, directive, provider, result, valid, error, resolution; + var _a, _b, _i, key, directive, provider, result, valid, error, resolution, ex_1; return __generator(this, function (_c) { switch (_c.label) { case 0: @@ -800,26 +801,28 @@ var ValidationService = /** @class */ (function () { _i = 0; _c.label = 1; case 1: - if (!(_i < _a.length)) return [3 /*break*/, 7]; + if (!(_i < _a.length)) return [3 /*break*/, 8]; key = _a[_i]; directive = directives[key]; provider = this.providers[key]; if (!provider) { console.log('aspnet-validation provider not implemented: ' + key); - return [3 /*break*/, 6]; + return [3 /*break*/, 7]; } result = provider(input.value, input, directive.params); valid = false; error = directive.error; if (!(typeof result === 'boolean')) return [3 /*break*/, 2]; valid = result; - return [3 /*break*/, 5]; + return [3 /*break*/, 6]; case 2: if (!(typeof result === 'string')) return [3 /*break*/, 3]; valid = false; error = result; - return [3 /*break*/, 5]; - case 3: return [4 /*yield*/, result]; + return [3 /*break*/, 6]; + case 3: + _c.trys.push([3, 5, , 6]); + return [4 /*yield*/, result]; case 4: resolution = _c.sent(); if (typeof resolution === 'boolean') { @@ -829,17 +832,26 @@ var ValidationService = /** @class */ (function () { valid = false; error = resolution; } - _c.label = 5; + return [3 /*break*/, 6]; case 5: + ex_1 = _c.sent(); + if (ex_1 instanceof Error) { + error = ex_1.message; + } + else + error = ex_1; + valid = false; + return [3 /*break*/, 6]; + case 6: if (!valid) { this.addError(input, error); return [2 /*return*/, false]; } - _c.label = 6; - case 6: + _c.label = 7; + case 7: _i++; return [3 /*break*/, 1]; - case 7: + case 8: this.removeError(input); return [2 /*return*/, true]; } diff --git a/dist/aspnet-validation.min.js b/dist/aspnet-validation.min.js index e442df5..414f5e7 100644 --- a/dist/aspnet-validation.min.js +++ b/dist/aspnet-validation.min.js @@ -1,2 +1,2 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.aspnetValidation=t():e.aspnetValidation=t()}(window,function(){return function(e){var t={};function r(n){if(t[n])return t[n].exports;var a=t[n]={i:n,l:!1,exports:{}};return e[n].call(a.exports,a,a.exports,r),a.l=!0,a.exports}return r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var a in e)r.d(n,a,function(t){return e[t]}.bind(null,a));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=0)}([function(e,t,r){"use strict";r.r(t),r.d(t,"MvcValidationProviders",function(){return o}),r.d(t,"ValidationService",function(){return s});var n=function(e,t,r,n){return new(r||(r=Promise))(function(a,i){function o(e){try{u(n.next(e))}catch(e){i(e)}}function s(e){try{u(n.throw(e))}catch(e){i(e)}}function u(e){e.done?a(e.value):new r(function(t){t(e.value)}).then(o,s)}u((n=n.apply(e,t||[])).next())})},a=function(e,t){var r,n,a,i,o={label:0,sent:function(){if(1&a[0])throw a[1];return a[1]},trys:[],ops:[]};return i={next:s(0),throw:s(1),return:s(2)},"function"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function s(i){return function(s){return function(i){if(r)throw new TypeError("Generator is already executing.");for(;o;)try{if(r=1,n&&(a=2&i[0]?n.return:i[0]?n.throw||((a=n.return)&&a.call(n),0):n.next)&&!(a=a.call(n,i[1])).done)return a;switch(n=0,a&&(i=[2&i[0],a.value]),i[0]){case 0:case 1:a=i;break;case 4:return o.label++,{value:i[1],done:!1};case 5:o.label++,n=i[1],i=[0];continue;case 7:i=o.ops.pop(),o.trys.pop();continue;default:if(!(a=(a=o.trys).length>0&&a[a.length-1])&&(6===i[0]||2===i[0])){o=0;continue}if(3===i[0]&&(!a||i[1]>a[0]&&i[1]-1){var a=e.substr(0,n)+"."+r,i=document.getElementsByName(a)[0];if(i)return i}return document.getElementsByName(r)[0]}var o=function(){return function(){this.required=function(e,t,r){return Boolean(e)},this.stringLength=function(e,t,r){if(!e)return!0;if(r.min){var n=parseInt(r.min);if(e.lengtha)return!1}return!0},this.compare=function(e,t,r){if(!r.other)return!0;var n=i(t.name,r.other);return!n||n.value===e},this.range=function(e,t,r){if(!e)return!0;var n=parseFloat(e);return!isNaN(n)&&(!(r.min&&nparseFloat(r.max)))},this.regex=function(e,t,r){return!e||!r.pattern||new RegExp(r.pattern).test(e)},this.email=function(e,t,r){return!e||/^([^\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,})+$/.test(e)},this.creditcard=function(e,t,r){if(!e)return!0;if(/[^0-9 \-]+/.test(e))return!1;var n,a,i=0,o=0,s=!1;if((e=e.replace(/\D/g,"")).length<13||e.length>19)return!1;for(n=e.length-1;n>=0;n--)a=e.charAt(n),o=parseInt(a,10),s&&(o*=2)>9&&(o-=9),i+=o,s=!s;return i%10==0},this.url=function(e,t,r){return!e||new RegExp("^(?:(?:https?|ftp)://)(?:\\S+(?::\\S*)?@)?(?:(?!(?:10|127)(?:\\.\\d{1,3}){3})(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))\\.?)(?::\\d{2,5})?(?:[/?#]\\S*)?$","i").test(e)},this.phone=function(e,t,r){return!e||!/[\+\-\s][\-\s]/g.test(e)&&/^\+?[0-9\-\s]+$/.test(e)},this.remote=function(e,t,r){if(!e)return!0;for(var n=r.additionalfields.split(","),a={},o=0,s=n;o=200&&n.status<300){var a=JSON.parse(n.responseText);e(a)}else t({status:n.status,statusText:n.statusText,data:n.responseText})},n.onerror=function(e){t({status:n.status,statusText:n.statusText,data:n.responseText})}})}}}(),s=function(){function e(){this.providers={},this.messageFor={},this.elementUIDs=[],this.elementByUID={},this.formInputs={},this.validators={},this.elementEvents={},this.summary={},this.debounce=300}return e.prototype.addProvider=function(e,t){this.providers[e]||(this.providers[e]=t)},e.prototype.addMvcProviders=function(){var e=new o;this.addProvider("required",e.required),this.addProvider("length",e.stringLength),this.addProvider("maxlength",e.stringLength),this.addProvider("minlength",e.stringLength),this.addProvider("equalto",e.compare),this.addProvider("range",e.range),this.addProvider("regex",e.regex),this.addProvider("creditcard",e.creditcard),this.addProvider("email",e.email),this.addProvider("url",e.url),this.addProvider("phone",e.phone),this.addProvider("remote",e.remote)},e.prototype.scanMessages=function(){for(var e=document.querySelectorAll("[data-valmsg-for]"),t=0;t0&&a[a.length-1])||6!==i[0]&&2!==i[0])){o=0;continue}if(3===i[0]&&(!a||i[1]>a[0]&&i[1]-1){var a=e.substr(0,n)+"."+r,i=document.getElementsByName(a)[0];if(i)return i}return document.getElementsByName(r)[0]}var o=function(){this.required=function(e,t,r){return Boolean(e)},this.stringLength=function(e,t,r){if(!e)return!0;if(r.min){var n=parseInt(r.min);if(e.lengtha)return!1}return!0},this.compare=function(e,t,r){if(!r.other)return!0;var n=i(t.name,r.other);return!n||n.value===e},this.range=function(e,t,r){if(!e)return!0;var n=parseFloat(e);return!isNaN(n)&&(!(r.min&&nparseFloat(r.max)))},this.regex=function(e,t,r){return!e||!r.pattern||new RegExp(r.pattern).test(e)},this.email=function(e,t,r){return!e||/^([^\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,})+$/.test(e)},this.creditcard=function(e,t,r){if(!e)return!0;if(/[^0-9 \-]+/.test(e))return!1;var n,a,i=0,o=0,s=!1;if((e=e.replace(/\D/g,"")).length<13||e.length>19)return!1;for(n=e.length-1;n>=0;n--)a=e.charAt(n),o=parseInt(a,10),s&&(o*=2)>9&&(o-=9),i+=o,s=!s;return i%10==0},this.url=function(e,t,r){return!e||new RegExp("^(?:(?:https?|ftp)://)(?:\\S+(?::\\S*)?@)?(?:(?!(?:10|127)(?:\\.\\d{1,3}){3})(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))\\.?)(?::\\d{2,5})?(?:[/?#]\\S*)?$","i").test(e)},this.phone=function(e,t,r){return!e||!/[\+\-\s][\-\s]/g.test(e)&&/^\+?[0-9\-\s]+$/.test(e)},this.remote=function(e,t,r){if(!e)return!0;for(var n=r.additionalfields.split(","),a={},o=0,s=n;o=200&&n.status<300){var a=JSON.parse(n.responseText);e(a)}else t({status:n.status,statusText:n.statusText,data:n.responseText})},n.onerror=function(e){t({status:n.status,statusText:n.statusText,data:n.responseText})}}))}},s=function(){function e(){this.providers={},this.messageFor={},this.elementUIDs=[],this.elementByUID={},this.formInputs={},this.validators={},this.elementEvents={},this.summary={},this.debounce=300}return e.prototype.addProvider=function(e,t){this.providers[e]||(this.providers[e]=t)},e.prototype.addMvcProviders=function(){var e=new o;this.addProvider("required",e.required),this.addProvider("length",e.stringLength),this.addProvider("maxlength",e.stringLength),this.addProvider("minlength",e.stringLength),this.addProvider("equalto",e.compare),this.addProvider("range",e.range),this.addProvider("regex",e.regex),this.addProvider("creditcard",e.creditcard),this.addProvider("email",e.email),this.addProvider("url",e.url),this.addProvider("phone",e.phone),this.addProvider("remote",e.remote)},e.prototype.scanMessages=function(){for(var e=document.querySelectorAll("[data-valmsg-for]"),t=0;t\r\n */\r\nexport interface StringKeyValuePair {\r\n [key: string]: string\r\n}\r\n\r\n/**\r\n * A duplex key-value pair for an element, by GUID or its DOM object reference.\r\n */\r\ninterface ElementUID {\r\n node: Element,\r\n uid: string;\r\n}\r\n\r\n/**\r\n * Parameters passed into validation providers from the element attributes.\r\n * error property is read from data-val-[Provider Name] attribute.\r\n * params property is populated from data-val-[Provider Name]-[Parameter Name] attributes.\r\n */\r\nexport interface ValidationDirectiveBindings {\r\n error: string,\r\n params: StringKeyValuePair\r\n}\r\n\r\n/**\r\n * A key-value pair describing what validations to enforce to an input element, with respective parameters.\r\n */\r\nexport type ValidationDirective = {\r\n [key: string]: ValidationDirectiveBindings\r\n};\r\n\r\n/**\r\n * Validation plugin signature with multitype return.\r\n * Boolean return signifies the validation result, which uses the default validation error message read from the element attribute.\r\n * String return signifies failed validation, which then will be used as the validation error message.\r\n * Promise return signifies asynchronous plugin behavior, with same behavior as Boolean or String.\r\n */\r\nexport type ValidationProvider = (value: string, element: HTMLInputElement, params: StringKeyValuePair) => boolean | string | Promise;\r\n\r\n/**\r\n * A callback method signature that kickstarts a new validation task for an input element, as a Boolean Promise.\r\n */\r\ntype Validator = () => Promise;\r\n\r\n/**\r\n * Resolves and returns the element referred by original element using ASP.NET selector logic.\r\n * @param elementName \r\n */\r\nfunction getRelativeFormElement(elementName: string, selector: string) {\r\n // example elementName: Form.PasswordConfirm, Form.Email\r\n // example selector (dafuq): *.Password, *.__RequestVerificationToken\r\n // example result element name: Form.Password, __RequestVerificationToken\r\n\r\n let realSelector = selector.substr(2); // Password, __RequestVerificationToken\r\n let objectName = '';\r\n\r\n let dotLocation = elementName.lastIndexOf('.');\r\n if (dotLocation > -1) {\r\n // Form\r\n objectName = elementName.substr(0, dotLocation);\r\n\r\n // Form.Password\r\n let relativeElementName = objectName + '.' + realSelector;\r\n let relativeElement = document.getElementsByName(relativeElementName)[0];\r\n if (relativeElement) {\r\n return relativeElement;\r\n }\r\n }\r\n\r\n // __RequestVerificationToken\r\n return document.getElementsByName(realSelector)[0];\r\n}\r\n\r\n/**\r\n * Contains default implementations for ASP.NET Core MVC validation attributes.\r\n */\r\nexport class MvcValidationProviders {\r\n /**\r\n * Validates whether the input has a value.\r\n */\r\n required: ValidationProvider = (value, element, params) => {\r\n return Boolean(value);\r\n }\r\n\r\n /**\r\n * Validates whether the input value satisfies the length contstraint.\r\n */\r\n stringLength: ValidationProvider = (value, element, params) => {\r\n if (!value) {\r\n return true;\r\n }\r\n\r\n if (params.min) {\r\n let min = parseInt(params.min);\r\n if (value.length < min) {\r\n return false;\r\n }\r\n }\r\n\r\n if (params.max) {\r\n let max = parseInt(params.max);\r\n if (value.length > max) {\r\n return false;\r\n }\r\n }\r\n\r\n return true;\r\n }\r\n\r\n /**\r\n * Validates whether the input value is equal to another input value.\r\n */\r\n compare: ValidationProvider = (value, element, params) => {\r\n if (!params.other) {\r\n return true;\r\n }\r\n\r\n let otherElement = getRelativeFormElement(element.name, params.other) as HTMLInputElement;\r\n if (!otherElement) {\r\n return true;\r\n }\r\n\r\n return (otherElement.value === value);\r\n }\r\n\r\n /**\r\n * Validates whether the input value is a number within a given range.\r\n */\r\n range: ValidationProvider = (value, element, params) => {\r\n if (!value) {\r\n return true;\r\n }\r\n\r\n let val = parseFloat(value);\r\n if (isNaN(val)) {\r\n return false;\r\n }\r\n\r\n if (params.min) {\r\n let min = parseFloat(params.min);\r\n if (val < min) {\r\n return false;\r\n }\r\n }\r\n\r\n if (params.max) {\r\n let max = parseFloat(params.max);\r\n if (val > max) {\r\n return false;\r\n }\r\n }\r\n\r\n return true;\r\n }\r\n\r\n /**\r\n * Validates whether the input value satisfies a regular expression pattern.\r\n */\r\n regex: ValidationProvider = (value, element, params) => {\r\n if (!value || !params.pattern) {\r\n return true;\r\n }\r\n\r\n let r = new RegExp(params.pattern);\r\n return r.test(value);\r\n }\r\n\r\n /**\r\n * Validates whether the input value is an email in accordance to RFC822 specification, with a top level domain.\r\n */\r\n email: ValidationProvider = (value, element, params) => {\r\n if (!value) {\r\n return true;\r\n }\r\n\r\n // RFC822 email address with .TLD validation\r\n // (c) Richard Willis, Chris Ferdinandi, MIT Licensed\r\n // https://gist.github.com/badsyntax/719800\r\n // https://gist.github.com/cferdinandi/d04aad4ce064b8da3edf21e26f8944c4\r\n\r\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,})+$/;\r\n return r.test(value);\r\n }\r\n\r\n /**\r\n * Validates whether the input value is a credit card number, with Luhn's Algorithm.\r\n */\r\n creditcard: ValidationProvider = (value, element, params) => {\r\n if (!value) {\r\n return true;\r\n }\r\n\r\n // (c) jquery-validation, MIT Licensed\r\n // https://github.com/jquery-validation/jquery-validation/blob/master/src/additional/creditcard.js\r\n // based on https://en.wikipedia.org/wiki/Luhn_algorithm\r\n\r\n // Accept only spaces, digits and dashes\r\n if (/[^0-9 \\-]+/.test(value)) {\r\n return false;\r\n }\r\n\r\n var nCheck = 0,\r\n nDigit = 0,\r\n bEven = false,\r\n n, cDigit;\r\n\r\n value = value.replace(/\\D/g, \"\");\r\n\r\n // Basing min and max length on https://developer.ean.com/general_info/Valid_Credit_Card_Types\r\n if (value.length < 13 || value.length > 19) {\r\n return false;\r\n }\r\n\r\n for (n = value.length - 1; n >= 0; n--) {\r\n cDigit = value.charAt(n);\r\n nDigit = parseInt(cDigit, 10);\r\n if (bEven) {\r\n if ((nDigit *= 2) > 9) {\r\n nDigit -= 9;\r\n }\r\n }\r\n\r\n nCheck += nDigit;\r\n bEven = !bEven;\r\n }\r\n\r\n return (nCheck % 10) === 0;\r\n }\r\n\r\n /**\r\n * Validates whether the input value is a URL.\r\n */\r\n url: ValidationProvider = (value, element, params) => {\r\n if (!value) {\r\n return true;\r\n }\r\n\r\n // (c) Diego Perini, MIT Licensed\r\n // https://gist.github.com/dperini/729294\r\n\r\n var r = new RegExp(\r\n \"^\" +\r\n // protocol identifier\r\n \"(?:(?:https?|ftp)://)\" +\r\n // user:pass authentication\r\n \"(?:\\\\S+(?::\\\\S*)?@)?\" +\r\n \"(?:\" +\r\n // IP address exclusion\r\n // private & local networks\r\n \"(?!(?:10|127)(?:\\\\.\\\\d{1,3}){3})\" +\r\n \"(?!(?:169\\\\.254|192\\\\.168)(?:\\\\.\\\\d{1,3}){2})\" +\r\n \"(?!172\\\\.(?:1[6-9]|2\\\\d|3[0-1])(?:\\\\.\\\\d{1,3}){2})\" +\r\n // IP address dotted notation octets\r\n // excludes loopback network 0.0.0.0\r\n // excludes reserved space >= 224.0.0.0\r\n // excludes network & broacast addresses\r\n // (first & last IP address of each class)\r\n \"(?:[1-9]\\\\d?|1\\\\d\\\\d|2[01]\\\\d|22[0-3])\" +\r\n \"(?:\\\\.(?:1?\\\\d{1,2}|2[0-4]\\\\d|25[0-5])){2}\" +\r\n \"(?:\\\\.(?:[1-9]\\\\d?|1\\\\d\\\\d|2[0-4]\\\\d|25[0-4]))\" +\r\n \"|\" +\r\n // host name\r\n \"(?:(?:[a-z\\\\u00a1-\\\\uffff0-9]-*)*[a-z\\\\u00a1-\\\\uffff0-9]+)\" +\r\n // domain name\r\n \"(?:\\\\.(?:[a-z\\\\u00a1-\\\\uffff0-9]-*)*[a-z\\\\u00a1-\\\\uffff0-9]+)*\" +\r\n // TLD identifier\r\n \"(?:\\\\.(?:[a-z\\\\u00a1-\\\\uffff]{2,}))\" +\r\n // TLD may end with dot\r\n \"\\\\.?\" +\r\n \")\" +\r\n // port number\r\n \"(?::\\\\d{2,5})?\" +\r\n // resource path\r\n \"(?:[/?#]\\\\S*)?\" +\r\n \"$\", \"i\"\r\n );\r\n\r\n return r.test(value);\r\n }\r\n\r\n /**\r\n * Validates whether the input value is a phone number.\r\n */\r\n phone: ValidationProvider = (value, element, params) => {\r\n if (!value) {\r\n return true;\r\n }\r\n\r\n // Allows whitespace or dash as number separator because some people like to do that...\r\n let consecutiveSeparator = /[\\+\\-\\s][\\-\\s]/g;\r\n if (consecutiveSeparator.test(value)) {\r\n return false;\r\n }\r\n\r\n let r = /^\\+?[0-9\\-\\s]+$/;\r\n return r.test(value);\r\n }\r\n\r\n /**\r\n * Asynchronously validates the input value to a JSON GET API endpoint. \r\n */\r\n remote: ValidationProvider = (value, element, params) => {\r\n if (!value) {\r\n return true;\r\n }\r\n\r\n // params.additionalfields: *.Email,*.Username\r\n let fieldSelectors: string[] = (params.additionalfields as string).split(',');\r\n let fields: StringKeyValuePair = {};\r\n\r\n for (let fieldSelector of fieldSelectors) {\r\n let fieldName = fieldSelector.substr(2);\r\n let fieldElement = getRelativeFormElement(element.name, fieldSelector) as HTMLInputElement;\r\n\r\n let hasValue = Boolean(fieldElement && fieldElement.value);\r\n if (!hasValue) {\r\n continue;\r\n }\r\n\r\n fields[fieldName] = fieldElement.value;\r\n }\r\n\r\n let url: string = params['url'];\r\n // console.log(fields);\r\n\r\n let encodedParams: string[] = [];\r\n for (let fieldName in fields) {\r\n let encodedParam = encodeURIComponent(fieldName) + '=' + encodeURIComponent(fields[fieldName]);\r\n encodedParams.push(encodedParam);\r\n }\r\n let payload = encodedParams.join('&');\r\n // console.log(payload);\r\n\r\n return new Promise((ok, reject) => {\r\n let request = new XMLHttpRequest();\r\n\r\n if (params.type === 'Post') {\r\n let postData = new FormData();\r\n for (let fieldName in fields) {\r\n postData.append(fieldName, fields[fieldName]);\r\n }\r\n request.open('post', url);\r\n request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');\r\n request.send(payload);\r\n } else {\r\n request.open('get', url + '?' + payload);\r\n request.send();\r\n }\r\n\r\n request.onload = e => {\r\n if (request.status >= 200 && request.status < 300) {\r\n let data = JSON.parse(request.responseText);\r\n ok(data);\r\n } else {\r\n reject({\r\n status: request.status,\r\n statusText: request.statusText,\r\n data: request.responseText\r\n });\r\n }\r\n };\r\n\r\n request.onerror = e => {\r\n reject({\r\n status: request.status,\r\n statusText: request.statusText,\r\n data: request.responseText\r\n });\r\n };\r\n });\r\n }\r\n}\r\n\r\n/**\r\n * Responsibles for managing the DOM elements and running the validation providers.\r\n */\r\nexport class ValidationService {\r\n /**\r\n * A key-value collection of loaded validation plugins. \r\n */\r\n private providers: { [name: string]: ValidationProvider } = {};\r\n\r\n /**\r\n * A key-value collection of elements for displaying validation messages for an input (by DOM ID).\r\n */\r\n private messageFor: { [id: string]: Element[] } = {};\r\n\r\n /**\r\n * A list of managed elements, each having a randomly assigned unique identifier (UID).\r\n */\r\n private elementUIDs: ElementUID[] = [];\r\n\r\n /**\r\n * A key-value collection of UID to Element for quick lookup. \r\n */\r\n private elementByUID: { [uid: string]: Element } = {};\r\n\r\n /**\r\n * A key-value collection of input UIDs for a
UID.\r\n */\r\n private formInputs: { [formUID: string]: string[] } = {};\r\n\r\n /**\r\n * A key-value map for input UID to its validator factory.\r\n */\r\n private validators: { [inputUID: string]: Validator } = {};\r\n\r\n /**\r\n * A key-value map for element UID to its trigger element (submit event for , input event for