|
|
/*! * validate.js 0.11.1 * * (c) 2013-2016 Nicklas Ansman, 2013 Wrapp * Validate.js may be freely distributed under the MIT license. * For all details and documentation: * http://validatejs.org/
*/
(function(exports, module, define) { "use strict";
// The main function that calls the validators specified by the constraints.
// The options are the following:
// - format (string) - An option that controls how the returned value is formatted
// * flat - Returns a flat array of just the error messages
// * grouped - Returns the messages grouped by attribute (default)
// * detailed - Returns an array of the raw validation data
// - fullMessages (boolean) - If `true` (default) the attribute name is prepended to the error.
//
// Please note that the options are also passed to each validator.
var validate = function(attributes, constraints, options) { options = v.extend({}, v.options, options);
var results = v.runValidations(attributes, constraints, options) , attr , validator;
for (attr in results) { for (validator in results[attr]) { if (v.isPromise(results[attr][validator])) { throw new Error("Use validate.async if you want support for promises"); } } } return validate.processValidationResults(results, options); };
var v = validate;
// Copies over attributes from one or more sources to a single destination.
// Very much similar to underscore's extend.
// The first argument is the target object and the remaining arguments will be
// used as sources.
v.extend = function(obj) { [].slice.call(arguments, 1).forEach(function(source) { for (var attr in source) { obj[attr] = source[attr]; } }); return obj; };
v.extend(validate, { // This is the version of the library as a semver.
// The toString function will allow it to be coerced into a string
version: { major: 0, minor: 11, patch: 1, metadata: "development", toString: function() { var version = v.format("%{major}.%{minor}.%{patch}", v.version); if (!v.isEmpty(v.version.metadata)) { version += "+" + v.version.metadata; } return version; } },
// Below is the dependencies that are used in validate.js
// The constructor of the Promise implementation.
// If you are using Q.js, RSVP or any other A+ compatible implementation
// override this attribute to be the constructor of that promise.
// Since jQuery promises aren't A+ compatible they won't work.
Promise: typeof Promise !== "undefined" ? Promise : /* istanbul ignore next */ null,
EMPTY_STRING_REGEXP: /^\s*$/,
// Runs the validators specified by the constraints object.
// Will return an array of the format:
// [{attribute: "<attribute name>", error: "<validation result>"}, ...]
runValidations: function(attributes, constraints, options) { var results = [] , attr , validatorName , value , validators , validator , validatorOptions , error;
if (v.isDomElement(attributes) || v.isJqueryElement(attributes)) { attributes = v.collectFormValues(attributes); }
// Loops through each constraints, finds the correct validator and run it.
for (attr in constraints) { value = v.getDeepObjectValue(attributes, attr); // This allows the constraints for an attribute to be a function.
// The function will be called with the value, attribute name, the complete dict of
// attributes as well as the options and constraints passed in.
// This is useful when you want to have different
// validations depending on the attribute value.
validators = v.result(constraints[attr], value, attributes, attr, options, constraints);
for (validatorName in validators) { validator = v.validators[validatorName];
if (!validator) { error = v.format("Unknown validator %{name}", {name: validatorName}); throw new Error(error); }
validatorOptions = validators[validatorName]; // This allows the options to be a function. The function will be
// called with the value, attribute name, the complete dict of
// attributes as well as the options and constraints passed in.
// This is useful when you want to have different
// validations depending on the attribute value.
validatorOptions = v.result(validatorOptions, value, attributes, attr, options, constraints); if (!validatorOptions) { continue; } results.push({ attribute: attr, value: value, validator: validatorName, globalOptions: options, attributes: attributes, options: validatorOptions, error: validator.call(validator, value, validatorOptions, attr, attributes, options) }); } }
return results; },
// Takes the output from runValidations and converts it to the correct
// output format.
processValidationResults: function(errors, options) { errors = v.pruneEmptyErrors(errors, options); errors = v.expandMultipleErrors(errors, options); errors = v.convertErrorMessages(errors, options);
var format = options.format || "grouped";
if (typeof v.formatters[format] === 'function') { errors = v.formatters[format](errors); } else { throw new Error(v.format("Unknown format %{format}", options)); }
return v.isEmpty(errors) ? undefined : errors; },
// Runs the validations with support for promises.
// This function will return a promise that is settled when all the
// validation promises have been completed.
// It can be called even if no validations returned a promise.
async: function(attributes, constraints, options) { options = v.extend({}, v.async.options, options);
var WrapErrors = options.wrapErrors || function(errors) { return errors; };
// Removes unknown attributes
if (options.cleanAttributes !== false) { attributes = v.cleanAttributes(attributes, constraints); }
var results = v.runValidations(attributes, constraints, options);
return new v.Promise(function(resolve, reject) { v.waitForResults(results).then(function() { var errors = v.processValidationResults(results, options); if (errors) { reject(new WrapErrors(errors, options, attributes, constraints)); } else { resolve(attributes); } }, function(err) { reject(err); }); }); },
single: function(value, constraints, options) { options = v.extend({}, v.single.options, options, { format: "flat", fullMessages: false }); return v({single: value}, {single: constraints}, options); },
// Returns a promise that is resolved when all promises in the results array
// are settled. The promise returned from this function is always resolved,
// never rejected.
// This function modifies the input argument, it replaces the promises
// with the value returned from the promise.
waitForResults: function(results) { // Create a sequence of all the results starting with a resolved promise.
return results.reduce(function(memo, result) { // If this result isn't a promise skip it in the sequence.
if (!v.isPromise(result.error)) { return memo; }
return memo.then(function() { return result.error.then(function(error) { result.error = error || null; }); }); }, new v.Promise(function(r) { r(); })); // A resolved promise
},
// If the given argument is a call: function the and: function return the value
// otherwise just return the value. Additional arguments will be passed as
// arguments to the function.
// Example:
// ```
// result('foo') // 'foo'
// result(Math.max, 1, 2) // 2
// ```
result: function(value) { var args = [].slice.call(arguments, 1); if (typeof value === 'function') { value = value.apply(null, args); } return value; },
// Checks if the value is a number. This function does not consider NaN a
// number like many other `isNumber` functions do.
isNumber: function(value) { return typeof value === 'number' && !isNaN(value); },
// Returns false if the object is not a function
isFunction: function(value) { return typeof value === 'function'; },
// A simple check to verify that the value is an integer. Uses `isNumber`
// and a simple modulo check.
isInteger: function(value) { return v.isNumber(value) && value % 1 === 0; },
// Checks if the value is a boolean
isBoolean: function(value) { return typeof value === 'boolean'; },
// Uses the `Object` function to check if the given argument is an object.
isObject: function(obj) { return obj === Object(obj); },
// Simply checks if the object is an instance of a date
isDate: function(obj) { return obj instanceof Date; },
// Returns false if the object is `null` of `undefined`
isDefined: function(obj) { return obj !== null && obj !== undefined; },
// Checks if the given argument is a promise. Anything with a `then`
// function is considered a promise.
isPromise: function(p) { return !!p && v.isFunction(p.then); },
isJqueryElement: function(o) { return o && v.isString(o.jquery); },
isDomElement: function(o) { if (!o) { return false; }
if (!o.querySelectorAll || !o.querySelector) { return false; }
if (v.isObject(document) && o === document) { return true; }
// http://stackoverflow.com/a/384380/699304
/* istanbul ignore else */ if (typeof HTMLElement === "object") { return o instanceof HTMLElement; } else { return o && typeof o === "object" && o !== null && o.nodeType === 1 && typeof o.nodeName === "string"; } },
isEmpty: function(value) { var attr;
// Null and undefined are empty
if (!v.isDefined(value)) { return true; }
// functions are non empty
if (v.isFunction(value)) { return false; }
// Whitespace only strings are empty
if (v.isString(value)) { return v.EMPTY_STRING_REGEXP.test(value); }
// For arrays we use the length property
if (v.isArray(value)) { return value.length === 0; }
// Dates have no attributes but aren't empty
if (v.isDate(value)) { return false; }
// If we find at least one property we consider it non empty
if (v.isObject(value)) { for (attr in value) { return false; } return true; }
return false; },
// Formats the specified strings with the given values like so:
// ```
// format("Foo: %{foo}", {foo: "bar"}) // "Foo bar"
// ```
// If you want to write %{...} without having it replaced simply
// prefix it with % like this `Foo: %%{foo}` and it will be returned
// as `"Foo: %{foo}"`
format: v.extend(function(str, vals) { if (!v.isString(str)) { return str; } return str.replace(v.format.FORMAT_REGEXP, function(m0, m1, m2) { if (m1 === '%') { return "%{" + m2 + "}"; } else { return String(vals[m2]); } }); }, { // Finds %{key} style patterns in the given string
FORMAT_REGEXP: /(%?)%\{([^\}]+)\}/g }),
// "Prettifies" the given string.
// Prettifying means replacing [.\_-] with spaces as well as splitting
// camel case words.
prettify: function(str) { if (v.isNumber(str)) { // If there are more than 2 decimals round it to two
if ((str * 100) % 1 === 0) { return "" + str; } else { return parseFloat(Math.round(str * 100) / 100).toFixed(2); } }
if (v.isArray(str)) { return str.map(function(s) { return v.prettify(s); }).join(", "); }
if (v.isObject(str)) { return str.toString(); }
// Ensure the string is actually a string
str = "" + str;
return str // Splits keys separated by periods
.replace(/([^\s])\.([^\s])/g, '$1 $2') // Removes backslashes
.replace(/\\+/g, '') // Replaces - and - with space
.replace(/[_-]/g, ' ') // Splits camel cased words
.replace(/([a-z])([A-Z])/g, function(m0, m1, m2) { return "" + m1 + " " + m2.toLowerCase(); }) .toLowerCase(); },
stringifyValue: function(value) { return v.prettify(value); },
isString: function(value) { return typeof value === 'string'; },
isArray: function(value) { return {}.toString.call(value) === '[object Array]'; },
// Checks if the object is a hash, which is equivalent to an object that
// is neither an array nor a function.
isHash: function(value) { return v.isObject(value) && !v.isArray(value) && !v.isFunction(value); },
contains: function(obj, value) { if (!v.isDefined(obj)) { return false; } if (v.isArray(obj)) { return obj.indexOf(value) !== -1; } return value in obj; },
unique: function(array) { if (!v.isArray(array)) { return array; } return array.filter(function(el, index, array) { return array.indexOf(el) == index; }); },
forEachKeyInKeypath: function(object, keypath, callback) { if (!v.isString(keypath)) { return undefined; }
var key = "" , i , escape = false;
for (i = 0; i < keypath.length; ++i) { switch (keypath[i]) { case '.': if (escape) { escape = false; key += '.'; } else { object = callback(object, key, false); key = ""; } break;
case '\\': if (escape) { escape = false; key += '\\'; } else { escape = true; } break;
default: escape = false; key += keypath[i]; break; } }
return callback(object, key, true); },
getDeepObjectValue: function(obj, keypath) { if (!v.isObject(obj)) { return undefined; }
return v.forEachKeyInKeypath(obj, keypath, function(obj, key) { if (v.isObject(obj)) { return obj[key]; } }); },
// This returns an object with all the values of the form.
// It uses the input name as key and the value as value
// So for example this:
// <input type="text" name="email" value="foo@bar.com" />
// would return:
// {email: "foo@bar.com"}
collectFormValues: function(form, options) { var values = {} , i , j , input , inputs , option , value;
if (v.isJqueryElement(form)) { form = form[0]; }
if (!form) { return values; }
options = options || {};
inputs = form.querySelectorAll("input[name], textarea[name]"); for (i = 0; i < inputs.length; ++i) { input = inputs.item(i);
if (v.isDefined(input.getAttribute("data-ignored"))) { continue; }
value = v.sanitizeFormValue(input.value, options); if (input.type === "number") { value = value ? +value : null; } else if (input.type === "checkbox") { if (input.attributes.value) { if (!input.checked) { value = values[input.name] || null; } } else { value = input.checked; } } else if (input.type === "radio") { if (!input.checked) { value = values[input.name] || null; } } values[input.name] = value; }
inputs = form.querySelectorAll("select[name]"); for (i = 0; i < inputs.length; ++i) { input = inputs.item(i); if (v.isDefined(input.getAttribute("data-ignored"))) { continue; }
if (input.multiple) { value = []; for (j in input.options) { option = input.options[j]; if (option.selected) { value.push(v.sanitizeFormValue(option.value, options)); } } } else { value = v.sanitizeFormValue(input.options[input.selectedIndex].value, options); } values[input.name] = value; }
return values; },
sanitizeFormValue: function(value, options) { if (options.trim && v.isString(value)) { value = value.trim(); }
if (options.nullify !== false && value === "") { return null; } return value; },
capitalize: function(str) { if (!v.isString(str)) { return str; } return str[0].toUpperCase() + str.slice(1); },
// Remove all errors who's error attribute is empty (null or undefined)
pruneEmptyErrors: function(errors) { return errors.filter(function(error) { return !v.isEmpty(error.error); }); },
// In
// [{error: ["err1", "err2"], ...}]
// Out
// [{error: "err1", ...}, {error: "err2", ...}]
//
// All attributes in an error with multiple messages are duplicated
// when expanding the errors.
expandMultipleErrors: function(errors) { var ret = []; errors.forEach(function(error) { // Removes errors without a message
if (v.isArray(error.error)) { error.error.forEach(function(msg) { ret.push(v.extend({}, error, {error: msg})); }); } else { ret.push(error); } }); return ret; },
// Converts the error mesages by prepending the attribute name unless the
// message is prefixed by ^
convertErrorMessages: function(errors, options) { options = options || {};
var ret = []; errors.forEach(function(errorInfo) { var error = v.result(errorInfo.error, errorInfo.value, errorInfo.attribute, errorInfo.options, errorInfo.attributes, errorInfo.globalOptions);
if (!v.isString(error)) { ret.push(errorInfo); return; }
if (error[0] === '^') { error = error.slice(1); } else if (options.fullMessages !== false) { error = v.capitalize(v.prettify(errorInfo.attribute)) + " " + error; } error = error.replace(/\\\^/g, "^"); error = v.format(error, {value: v.stringifyValue(errorInfo.value)}); ret.push(v.extend({}, errorInfo, {error: error})); }); return ret; },
// In:
// [{attribute: "<attributeName>", ...}]
// Out:
// {"<attributeName>": [{attribute: "<attributeName>", ...}]}
groupErrorsByAttribute: function(errors) { var ret = {}; errors.forEach(function(error) { var list = ret[error.attribute]; if (list) { list.push(error); } else { ret[error.attribute] = [error]; } }); return ret; },
// In:
// [{error: "<message 1>", ...}, {error: "<message 2>", ...}]
// Out:
// ["<message 1>", "<message 2>"]
flattenErrorsToArray: function(errors) { return errors .map(function(error) { return error.error; }) .filter(function(value, index, self) { return self.indexOf(value) === index; }); },
cleanAttributes: function(attributes, whitelist) { function whitelistCreator(obj, key, last) { if (v.isObject(obj[key])) { return obj[key]; } return (obj[key] = last ? true : {}); }
function buildObjectWhitelist(whitelist) { var ow = {} , lastObject , attr; for (attr in whitelist) { if (!whitelist[attr]) { continue; } v.forEachKeyInKeypath(ow, attr, whitelistCreator); } return ow; }
function cleanRecursive(attributes, whitelist) { if (!v.isObject(attributes)) { return attributes; }
var ret = v.extend({}, attributes) , w , attribute;
for (attribute in attributes) { w = whitelist[attribute];
if (v.isObject(w)) { ret[attribute] = cleanRecursive(ret[attribute], w); } else if (!w) { delete ret[attribute]; } } return ret; }
if (!v.isObject(whitelist) || !v.isObject(attributes)) { return {}; }
whitelist = buildObjectWhitelist(whitelist); return cleanRecursive(attributes, whitelist); },
exposeModule: function(validate, root, exports, module, define) { if (exports) { if (module && module.exports) { exports = module.exports = validate; } exports.validate = validate; } else { root.validate = validate; if (validate.isFunction(define) && define.amd) { define([], function () { return validate; }); } } },
warn: function(msg) { if (typeof console !== "undefined" && console.warn) { console.warn("[validate.js] " + msg); } },
error: function(msg) { if (typeof console !== "undefined" && console.error) { console.error("[validate.js] " + msg); } } });
validate.validators = { // Presence validates that the value isn't empty
presence: function(value, options) { options = v.extend({}, this.options, options); if (options.allowEmpty ? !v.isDefined(value) : v.isEmpty(value)) { return options.message || this.message || "can't be blank"; } }, length: function(value, options, attribute) { // Empty values are allowed
if (!v.isDefined(value)) { return; }
options = v.extend({}, this.options, options);
var is = options.is , maximum = options.maximum , minimum = options.minimum , tokenizer = options.tokenizer || function(val) { return val; } , err , errors = [];
value = tokenizer(value); var length = value.length; if(!v.isNumber(length)) { v.error(v.format("Attribute %{attr} has a non numeric value for `length`", {attr: attribute})); return options.message || this.notValid || "has an incorrect length"; }
// Is checks
if (v.isNumber(is) && length !== is) { err = options.wrongLength || this.wrongLength || "is the wrong length (should be %{count} characters)"; errors.push(v.format(err, {count: is})); }
if (v.isNumber(minimum) && length < minimum) { err = options.tooShort || this.tooShort || "is too short (minimum is %{count} characters)"; errors.push(v.format(err, {count: minimum})); }
if (v.isNumber(maximum) && length > maximum) { err = options.tooLong || this.tooLong || "is too long (maximum is %{count} characters)"; errors.push(v.format(err, {count: maximum})); }
if (errors.length > 0) { return options.message || errors; } }, numericality: function(value, options) { // Empty values are fine
if (!v.isDefined(value)) { return; }
options = v.extend({}, this.options, options);
var errors = [] , name , count , checks = { greaterThan: function(v, c) { return v > c; }, greaterThanOrEqualTo: function(v, c) { return v >= c; }, equalTo: function(v, c) { return v === c; }, lessThan: function(v, c) { return v < c; }, lessThanOrEqualTo: function(v, c) { return v <= c; }, divisibleBy: function(v, c) { return v % c === 0; } };
// Strict will check that it is a valid looking number
if (v.isString(value) && options.strict) { var pattern = "^(0|[1-9]\\d*)"; if (!options.onlyInteger) { pattern += "(\\.\\d+)?"; } pattern += "$";
if (!(new RegExp(pattern).test(value))) { return options.message || options.notValid || this.notValid || this.message || "must be a valid number"; } }
// Coerce the value to a number unless we're being strict.
if (options.noStrings !== true && v.isString(value) && !v.isEmpty(value)) { value = +value; }
// If it's not a number we shouldn't continue since it will compare it.
if (!v.isNumber(value)) { return options.message || options.notValid || this.notValid || this.message || "is not a number"; }
// Same logic as above, sort of. Don't bother with comparisons if this
// doesn't pass.
if (options.onlyInteger && !v.isInteger(value)) { return options.message || options.notInteger || this.notInteger || this.message || "must be an integer"; }
for (name in checks) { count = options[name]; if (v.isNumber(count) && !checks[name](value, count)) { // This picks the default message if specified
// For example the greaterThan check uses the message from
// this.notGreaterThan so we capitalize the name and prepend "not"
var key = "not" + v.capitalize(name); var msg = options[key] || this[key] || this.message || "must be %{type} %{count}";
errors.push(v.format(msg, { count: count, type: v.prettify(name) })); } }
if (options.odd && value % 2 !== 1) { errors.push(options.notOdd || this.notOdd || this.message || "must be odd"); } if (options.even && value % 2 !== 0) { errors.push(options.notEven || this.notEven || this.message || "must be even"); }
if (errors.length) { return options.message || errors; } }, datetime: v.extend(function(value, options) { if (!v.isFunction(this.parse) || !v.isFunction(this.format)) { throw new Error("Both the parse and format functions needs to be set to use the datetime/date validator"); }
// Empty values are fine
if (!v.isDefined(value)) { return; }
options = v.extend({}, this.options, options);
var err , errors = [] , earliest = options.earliest ? this.parse(options.earliest, options) : NaN , latest = options.latest ? this.parse(options.latest, options) : NaN;
value = this.parse(value, options);
// 86400000 is the number of seconds in a day, this is used to remove
// the time from the date
if (isNaN(value) || options.dateOnly && value % 86400000 !== 0) { err = options.notValid || options.message || this.notValid || "must be a valid date"; return v.format(err, {value: arguments[0]}); }
if (!isNaN(earliest) && value < earliest) { err = options.tooEarly || options.message || this.tooEarly || "must be no earlier than %{date}"; err = v.format(err, { value: this.format(value, options), date: this.format(earliest, options) }); errors.push(err); }
if (!isNaN(latest) && value > latest) { err = options.tooLate || options.message || this.tooLate || "must be no later than %{date}"; err = v.format(err, { date: this.format(latest, options), value: this.format(value, options) }); errors.push(err); }
if (errors.length) { return v.unique(errors); } }, { parse: null, format: null }), date: function(value, options) { options = v.extend({}, options, {dateOnly: true}); return v.validators.datetime.call(v.validators.datetime, value, options); }, format: function(value, options) { if (v.isString(options) || (options instanceof RegExp)) { options = {pattern: options}; }
options = v.extend({}, this.options, options);
var message = options.message || this.message || "is invalid" , pattern = options.pattern , match;
// Empty values are allowed
if (!v.isDefined(value)) { return; } if (!v.isString(value)) { return message; }
if (v.isString(pattern)) { pattern = new RegExp(options.pattern, options.flags); } match = pattern.exec(value); if (!match || match[0].length != value.length) { return message; } }, inclusion: function(value, options) { // Empty values are fine
if (!v.isDefined(value)) { return; } if (v.isArray(options)) { options = {within: options}; } options = v.extend({}, this.options, options); if (v.contains(options.within, value)) { return; } var message = options.message || this.message || "^%{value} is not included in the list"; return v.format(message, {value: value}); }, exclusion: function(value, options) { // Empty values are fine
if (!v.isDefined(value)) { return; } if (v.isArray(options)) { options = {within: options}; } options = v.extend({}, this.options, options); if (!v.contains(options.within, value)) { return; } var message = options.message || this.message || "^%{value} is restricted"; return v.format(message, {value: value}); }, email: v.extend(function(value, options) { options = v.extend({}, this.options, options); var message = options.message || this.message || "is not a valid email"; // Empty values are fine
if (!v.isDefined(value)) { return; } if (!v.isString(value)) { return message; } if (!this.PATTERN.exec(value)) { return message; } }, { PATTERN: /^[a-z0-9\u007F-\uffff!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9\u007F-\uffff!#$%&'*+\/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z]{2,}$/i }), equality: function(value, options, attribute, attributes) { if (!v.isDefined(value)) { return; }
if (v.isString(options)) { options = {attribute: options}; } options = v.extend({}, this.options, options); var message = options.message || this.message || "is not equal to %{attribute}";
if (v.isEmpty(options.attribute) || !v.isString(options.attribute)) { throw new Error("The attribute must be a non empty string"); }
var otherValue = v.getDeepObjectValue(attributes, options.attribute) , comparator = options.comparator || function(v1, v2) { return v1 === v2; };
if (!comparator(value, otherValue, options, attribute, attributes)) { return v.format(message, {attribute: v.prettify(options.attribute)}); } },
// A URL validator that is used to validate URLs with the ability to
// restrict schemes and some domains.
url: function(value, options) { if (!v.isDefined(value)) { return; }
options = v.extend({}, this.options, options);
var message = options.message || this.message || "is not a valid url" , schemes = options.schemes || this.schemes || ['http', 'https'] , allowLocal = options.allowLocal || this.allowLocal || false;
if (!v.isString(value)) { return message; }
// https://gist.github.com/dperini/729294
var regex = "^" + // protocol identifier
"(?:(?:" + schemes.join("|") + ")://)" + // user:pass authentication
"(?:\\S+(?::\\S*)?@)?" + "(?:";
var tld = "(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))";
if (allowLocal) { tld += "?"; } else { regex += // IP address exclusion
// private & local networks
"(?!(?: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})"; }
regex += // IP address dotted notation octets
// excludes loopback network 0.0.0.0
// excludes reserved space >= 224.0.0.0
// excludes network & broacast addresses
// (first & last IP address of each class)
"(?:[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]))" + "|" + // host name
"(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)" + // domain name
"(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*" + tld + ")" + // port number
"(?::\\d{2,5})?" + // resource path
"(?:[/?#]\\S*)?" + "$";
var PATTERN = new RegExp(regex, 'i'); if (!PATTERN.exec(value)) { return message; } } };
validate.formatters = { detailed: function(errors) {return errors;}, flat: v.flattenErrorsToArray, grouped: function(errors) { var attr;
errors = v.groupErrorsByAttribute(errors); for (attr in errors) { errors[attr] = v.flattenErrorsToArray(errors[attr]); } return errors; }, constraint: function(errors) { var attr; errors = v.groupErrorsByAttribute(errors); for (attr in errors) { errors[attr] = errors[attr].map(function(result) { return result.validator; }).sort(); } return errors; } };
validate.exposeModule(validate, this, exports, module, define);}).call(this, typeof exports !== 'undefined' ? /* istanbul ignore next */ exports : null, typeof module !== 'undefined' ? /* istanbul ignore next */ module : null, typeof define !== 'undefined' ? /* istanbul ignore next */ define : null);
|