From a7163e4b86f5e55500040a050ae039af7faa17fe Mon Sep 17 00:00:00 2001 From: David Konsumer Date: Fri, 23 Jan 2015 07:03:45 -0800 Subject: [PATCH 1/5] browserify & uglify build tools --- package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 58de5c5..9a1ea39 100644 --- a/package.json +++ b/package.json @@ -13,14 +13,15 @@ "url": "http://github.com/flatiron/revalidator.git" }, "devDependencies": { + "browserify": "^8.1.1", "vows": "0.8.x" }, "main": "./lib/revalidator", "scripts": { - "test": "vows test/*-test.js --spec" + "test": "vows test/*-test.js --spec", + "browser": "browserify --standalone revalidator ./lib/revalidator.js -o dist/revalidator.js && uglifyjs --compress --mangle -o dist/revalidator.min.js dist/revalidator.js" }, "engines": { "node": ">= 0.8.0" } } - From 840c695aa0d569b7d0b8f49dcca28cf44a44bdc4 Mon Sep 17 00:00:00 2001 From: David Konsumer Date: Fri, 23 Jan 2015 07:04:36 -0800 Subject: [PATCH 2/5] browser demo --- example/clientside.html | 95 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 example/clientside.html diff --git a/example/clientside.html b/example/clientside.html new file mode 100644 index 0000000..da8f2e7 --- /dev/null +++ b/example/clientside.html @@ -0,0 +1,95 @@ + + + + + + + revalidator demo + + + + + + + +
+
+

revalidator

+

This is a client-side demo of revalidator.

+
+
+ +
+
+
+
+ +
+ + + + + + + + + \ No newline at end of file From 8bee6d8de508deee12f3a5140e6e3d185b212dec Mon Sep 17 00:00:00 2001 From: David Konsumer Date: Fri, 23 Jan 2015 07:05:18 -0800 Subject: [PATCH 3/5] checking built files for rawgit use & easy download for browser peeps --- dist/revalidator.js | 448 ++++++++++++++++++++++++++++++++++++++++ dist/revalidator.min.js | 1 + 2 files changed, 449 insertions(+) create mode 100644 dist/revalidator.js create mode 100644 dist/revalidator.min.js diff --git a/dist/revalidator.js b/dist/revalidator.js new file mode 100644 index 0000000..9efe235 --- /dev/null +++ b/dist/revalidator.js @@ -0,0 +1,448 @@ +!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.revalidator=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;oobject against a JSON Schema. + // If object is self-describing (i.e. has a + // $schema property), it will also be validated + // against the referenced schema. [TODO]: This behaviour bay be + // suppressed by setting the {@link #validate.options.???} + // option to ???.[/TODO] + // + // If schema is not specified, and object + // is not self-describing, validation always passes. + // + // Note: in order to pass options but no schema, + // schema must be specified in the call to + // validate(); otherwise, options will + // be interpreted as the schema. schema may be passed + // as null, undefinded, or the empty object + // ({}) in this case. + // + function validate(object, schema, options) { + options = mixin({}, validate.defaults, options); + var errors = []; + + if (schema.type === 'array') + validateProperty(object, object, '', schema, options, errors); + else + validateObject(object, schema, options, errors); + + // + // TODO: self-described validation + // if (! options.selfDescribing) { ... } + // + + return { + valid: !(errors.length), + errors: errors + }; + }; + + /** + * Default validation options. Defaults can be overridden by + * passing an 'options' hash to {@link #validate}. They can + * also be set globally be changing the values in + * validate.defaults directly. + */ + validate.defaults = { + /** + *

+ * Enforce 'format' constraints. + *

+ * Default: true + *

+ */ + validateFormats: true, + /** + *

+ * When {@link #validateFormats} is true, + * treat unrecognized formats as validation errors. + *

+ * Default: false + *

+ * + * @see validation.formats for default supported formats. + */ + validateFormatsStrict: false, + /** + *

+ * When {@link #validateFormats} is true, + * also validate formats defined in {@link #validate.formatExtensions}. + *

+ * Default: true + *

+ */ + validateFormatExtensions: true, + /** + *

+ * When {@link #additionalProperties} is true, + * allow additional unvisited properties on the object. + *

+ * Default: true + *

+ */ + additionalProperties: true + }; + + /** + * Default messages to include with validation errors. + */ + validate.messages = { + required: "is required", + allowEmpty: "must not be empty", + minLength: "is too short (minimum is %{expected} characters)", + maxLength: "is too long (maximum is %{expected} characters)", + pattern: "invalid input", + minimum: "must be greater than or equal to %{expected}", + maximum: "must be less than or equal to %{expected}", + exclusiveMinimum: "must be greater than %{expected}", + exclusiveMaximum: "must be less than %{expected}", + divisibleBy: "must be divisible by %{expected}", + minItems: "must contain more than %{expected} items", + maxItems: "must contain less than %{expected} items", + uniqueItems: "must hold a unique set of values", + format: "is not a valid %{expected}", + conform: "must conform to given constraint", + type: "must be of %{expected} type", + additionalProperties: "must not exist" + }; + validate.messages['enum'] = "must be present in given enumerator"; + + /** + * + */ + validate.formats = { + 'email': /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i, + 'ip-address': /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/i, + 'ipv6': /^([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}$/, + 'date-time': /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:.\d{1,3})?Z$/, + 'date': /^\d{4}-\d{2}-\d{2}$/, + 'time': /^\d{2}:\d{2}:\d{2}$/, + 'color': /^#[a-z0-9]{6}|#[a-z0-9]{3}|(?:rgb\(\s*(?:[+-]?\d+%?)\s*,\s*(?:[+-]?\d+%?)\s*,\s*(?:[+-]?\d+%?)\s*\))aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|orange|purple|red|silver|teal|white|yellow$/i, + //'style': (not supported) + //'phone': (not supported) + //'uri': (not supported) + 'host-name': /^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])/, + 'utc-millisec': { + test: function (value) { + return typeof(value) === 'number' && value >= 0; + } + }, + 'regex': { + test: function (value) { + try { new RegExp(value) } + catch (e) { return false } + + return true; + } + } + }; + + /** + * + */ + validate.formatExtensions = { + 'url': /^(https?|ftp|git):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i + }; + + function mixin(obj) { + var sources = Array.prototype.slice.call(arguments, 1); + while (sources.length) { + var source = sources.shift(); + if (!source) { continue } + + if (typeof(source) !== 'object') { + throw new TypeError('mixin non-object'); + } + + for (var p in source) { + if (source.hasOwnProperty(p)) { + obj[p] = source[p]; + } + } + } + + return obj; + } + + function validateObject(object, schema, options, errors) { + var props, allProps = Object.keys(object), + visitedProps = []; + + // see 5.2 + if (schema.properties) { + props = schema.properties; + for (var p in props) { + if (props.hasOwnProperty(p)) { + visitedProps.push(p); + validateProperty(object, object[p], p, props[p], options, errors); + } + } + } + + // see 5.3 + if (schema.patternProperties) { + props = schema.patternProperties; + for (var p in props) { + if (props.hasOwnProperty(p)) { + var re = new RegExp(p); + + // Find all object properties that are matching `re` + for (var k in object) { + if (object.hasOwnProperty(k)) { + if (re.exec(k) !== null) { + validateProperty(object, object[k], k, props[p], options, errors); + visitedProps.push(k); + } + } + } + } + } + } + + //if additionalProperties is not defined set default value + if (schema.additionalProperties === undefined) { + schema.additionalProperties = options.additionalProperties; + } + + // see 5.4 + if (undefined !== schema.additionalProperties) { + var i, l; + + var unvisitedProps = allProps.filter(function(k){ + return -1 === visitedProps.indexOf(k); + }); + + // Prevent additional properties; each unvisited property is therefore an error + if (schema.additionalProperties === false && unvisitedProps.length > 0) { + for (i = 0, l = unvisitedProps.length; i < l; i++) { + error("additionalProperties", unvisitedProps[i], object[unvisitedProps[i]], false, errors); + } + } + // additionalProperties is a schema and validate unvisited properties against that schema + else if (typeof schema.additionalProperties == "object" && unvisitedProps.length > 0) { + for (i = 0, l = unvisitedProps.length; i < l; i++) { + validateProperty(object, object[unvisitedProps[i]], unvisitedProps[i], schema.unvisitedProperties, options, errors); + } + } + } + + } + + function validateProperty(object, value, property, schema, options, errors) { + var format, + valid, + spec, + type; + + function constrain(name, value, assert) { + if (schema[name] !== undefined && !assert(value, schema[name])) { + error(name, property, value, schema, errors); + } + } + + if (value === undefined) { + if (schema.required && schema.type !== 'any') { + return error('required', property, undefined, schema, errors); + } else { + return; + } + } + + if (options.cast) { + if (('integer' === schema.type || 'number' === schema.type) && value == +value) { + value = +value; + object[property] = value; + } + + if ('boolean' === schema.type) { + if ('true' === value || '1' === value || 1 === value) { + value = true; + object[property] = value; + } + + if ('false' === value || '0' === value || 0 === value) { + value = false; + object[property] = value; + } + } + } + + if (schema.format && options.validateFormats) { + format = schema.format; + + if (options.validateFormatExtensions) { spec = validate.formatExtensions[format] } + if (!spec) { spec = validate.formats[format] } + if (!spec) { + if (options.validateFormatsStrict) { + return error('format', property, value, schema, errors); + } + } + else { + if (!spec.test(value)) { + return error('format', property, value, schema, errors); + } + } + } + + if (schema['enum'] && schema['enum'].indexOf(value) === -1) { + error('enum', property, value, schema, errors); + } + + // Dependencies (see 5.8) + if (typeof schema.dependencies === 'string' && + object[schema.dependencies] === undefined) { + error('dependencies', property, null, schema, errors); + } + + if (isArray(schema.dependencies)) { + for (var i = 0, l = schema.dependencies.length; i < l; i++) { + if (object[schema.dependencies[i]] === undefined) { + error('dependencies', property, null, schema, errors); + } + } + } + + if (typeof schema.dependencies === 'object') { + validateObject(object, schema.dependencies, options, errors); + } + + checkType(value, schema.type, function(err, type) { + if (err) return error('type', property, typeof value, schema, errors); + + constrain('conform', value, function (a, e) { return e(a, object) }); + + switch (type || (isArray(value) ? 'array' : typeof value)) { + case 'string': + constrain('allowEmpty', value, function (a, e) { return e ? e : a !== '' }); + constrain('minLength', value.length, function (a, e) { return a >= e }); + constrain('maxLength', value.length, function (a, e) { return a <= e }); + constrain('pattern', value, function (a, e) { + e = typeof e === 'string' + ? e = new RegExp(e) + : e; + return e.test(a) + }); + break; + case 'integer': + case 'number': + constrain('minimum', value, function (a, e) { return a >= e }); + constrain('maximum', value, function (a, e) { return a <= e }); + constrain('exclusiveMinimum', value, function (a, e) { return a > e }); + constrain('exclusiveMaximum', value, function (a, e) { return a < e }); + constrain('divisibleBy', value, function (a, e) { + var multiplier = Math.max((a - Math.floor(a)).toString().length - 2, (e - Math.floor(e)).toString().length - 2); + multiplier = multiplier > 0 ? Math.pow(10, multiplier) : 1; + return (a * multiplier) % (e * multiplier) === 0 + }); + break; + case 'array': + constrain('items', value, function (a, e) { + var nestedErrors; + for (var i = 0, l = a.length; i < l; i++) { + nestedErrors = []; + validateProperty(object, a[i], property, e, options, nestedErrors); + nestedErrors.forEach(function (err) { + err.property = + (property ? property + '.' : '') + + i + + (err.property ? '.' + err.property.replace(property + '.', '') : ''); + }); + nestedErrors.unshift(0, 0); + Array.prototype.splice.apply(errors, nestedErrors); + } + return true; + }); + constrain('minItems', value, function (a, e) { return a.length >= e }); + constrain('maxItems', value, function (a, e) { return a.length <= e }); + constrain('uniqueItems', value, function (a, e) { + if (!e) return true; + + var h = {}; + + for (var i = 0, l = a.length; i < l; i++) { + var key = JSON.stringify(a[i]); + if (h[key]) return false; + h[key] = true; + } + + return true; + }); + break; + case 'object': + // Recursive validation + if (schema.properties || schema.patternProperties || schema.additionalProperties) { + var nestedErrors = []; + validateObject(value, schema, options, nestedErrors); + nestedErrors.forEach(function (e) { + e.property = property + '.' + e.property + }); + nestedErrors.unshift(0, 0); + Array.prototype.splice.apply(errors, nestedErrors); + } + break; + } + }); + } + + function checkType(val, type, callback) { + var result = false, + types = isArray(type) ? type : [type]; + + // No type - no check + if (type === undefined) return callback(null, type); + + // Go through available types + // And fine first matching + for (var i = 0, l = types.length; i < l; i++) { + type = types[i].toLowerCase().trim(); + if (type === 'string' ? typeof val === 'string' : + type === 'array' ? isArray(val) : + type === 'object' ? val && typeof val === 'object' && + !isArray(val) : + type === 'number' ? typeof val === 'number' : + type === 'integer' ? typeof val === 'number' && Math.floor(val) === val : + type === 'null' ? val === null : + type === 'boolean'? typeof val === 'boolean' : + type === 'date' ? isDate(val) : + type === 'any' ? typeof val !== 'undefined' : false) { + return callback(null, type); + } + } + + callback(true); + } + + function error(attribute, property, actual, schema, errors) { + var lookup = { expected: schema[attribute], actual: actual, attribute: attribute, property: property }; + var message = schema.messages && schema.messages[attribute] || schema.message || validate.messages[attribute] || "no default message"; + message = message.replace(/%\{([a-z]+)\}/ig, function (_, match) { return lookup[match.toLowerCase()] || ''; }); + errors.push({ + attribute: attribute, + property: property, + expected: schema[attribute], + actual: actual, + message: message + }); + } + + function isArray(value) { + return Object.prototype.toString.call(value) === '[object Array]'; + } + + function isDate(value) { + return Object.prototype.toString.call(value) === '[object Date]'; + } + +})(typeof module === 'object' && module && module.exports ? module.exports : window); + +},{}]},{},[1])(1) +}); \ No newline at end of file diff --git a/dist/revalidator.min.js b/dist/revalidator.min.js new file mode 100644 index 0000000..cb8d740 --- /dev/null +++ b/dist/revalidator.min.js @@ -0,0 +1 @@ +!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;"undefined"!=typeof window?t=window:"undefined"!=typeof global?t=global:"undefined"!=typeof self&&(t=self),t.revalidator=e()}}(function(){return function e(t,u,r){function n(F,o){if(!u[F]){if(!t[F]){var a="function"==typeof require&&require;if(!o&&a)return a(F,!0);if(i)return i(F,!0);var d=new Error("Cannot find module '"+F+"'");throw d.code="MODULE_NOT_FOUND",d}var s=u[F]={exports:{}};t[F][0].call(s.exports,function(e){var u=t[F][1][e];return n(u?u:e)},s,s.exports,e,t,u,r)}return u[F].exports}for(var i="function"==typeof require&&require,F=0;F0)for(p=0,l=c.length;l>p;p++)F("additionalProperties",c[p],e[c[p]],!1,r);else if("object"==typeof t.additionalProperties&&c.length>0)for(p=0,l=c.length;l>p;p++)n(e,e[c[p]],c[p],t.unvisitedProperties,u,r)}}function n(e,u,a,d,s,f){function p(e,t,u){void 0===d[e]||u(t,d[e])||F(e,a,t,d,f)}var l,c;if(void 0===u)return d.required&&"any"!==d.type?F("required",a,void 0,d,f):void 0;if(s.cast&&("integer"!==d.type&&"number"!==d.type||u!=+u||(u=+u,e[a]=u),"boolean"===d.type&&(("true"===u||"1"===u||1===u)&&(u=!0,e[a]=u),("false"===u||"0"===u||0===u)&&(u=!1,e[a]=u))),d.format&&s.validateFormats)if(l=d.format,s.validateFormatExtensions&&(c=t.formatExtensions[l]),c||(c=t.formats[l]),c){if(!c.test(u))return F("format",a,u,d,f)}else if(s.validateFormatsStrict)return F("format",a,u,d,f);if(d["enum"]&&-1===d["enum"].indexOf(u)&&F("enum",a,u,d,f),"string"==typeof d.dependencies&&void 0===e[d.dependencies]&&F("dependencies",a,null,d,f),o(d.dependencies))for(var m=0,x=d.dependencies.length;x>m;m++)void 0===e[d.dependencies[m]]&&F("dependencies",a,null,d,f);"object"==typeof d.dependencies&&r(e,d.dependencies,s,f),i(u,d.type,function(t,i){if(t)return F("type",a,typeof u,d,f);switch(p("conform",u,function(t,u){return u(t,e)}),i||(o(u)?"array":typeof u)){case"string":p("allowEmpty",u,function(e,t){return t?t:""!==e}),p("minLength",u.length,function(e,t){return e>=t}),p("maxLength",u.length,function(e,t){return t>=e}),p("pattern",u,function(e,t){return t="string"==typeof t?t=new RegExp(t):t,t.test(e)});break;case"integer":case"number":p("minimum",u,function(e,t){return e>=t}),p("maximum",u,function(e,t){return t>=e}),p("exclusiveMinimum",u,function(e,t){return e>t}),p("exclusiveMaximum",u,function(e,t){return t>e}),p("divisibleBy",u,function(e,t){var u=Math.max((e-Math.floor(e)).toString().length-2,(t-Math.floor(t)).toString().length-2);return u=u>0?Math.pow(10,u):1,e*u%(t*u)===0});break;case"array":p("items",u,function(t,u){for(var r,i=0,F=t.length;F>i;i++)r=[],n(e,t[i],a,u,s,r),r.forEach(function(e){e.property=(a?a+".":"")+i+(e.property?"."+e.property.replace(a+".",""):"")}),r.unshift(0,0),Array.prototype.splice.apply(f,r);return!0}),p("minItems",u,function(e,t){return e.length>=t}),p("maxItems",u,function(e,t){return e.length<=t}),p("uniqueItems",u,function(e,t){if(!t)return!0;for(var u={},r=0,n=e.length;n>r;r++){var i=JSON.stringify(e[r]);if(u[i])return!1;u[i]=!0}return!0});break;case"object":if(d.properties||d.patternProperties||d.additionalProperties){var l=[];r(u,d,s,l),l.forEach(function(e){e.property=a+"."+e.property}),l.unshift(0,0),Array.prototype.splice.apply(f,l)}}})}function i(e,t,u){var r=o(t)?t:[t];if(void 0===t)return u(null,t);for(var n=0,i=r.length;i>n;n++)if(t=r[n].toLowerCase().trim(),"string"===t?"string"==typeof e:"array"===t?o(e):"object"===t?e&&"object"==typeof e&&!o(e):"number"===t?"number"==typeof e:"integer"===t?"number"==typeof e&&Math.floor(e)===e:"null"===t?null===e:"boolean"===t?"boolean"==typeof e:"date"===t?a(e):"any"===t?"undefined"!=typeof e:!1)return u(null,t);u(!0)}function F(e,u,r,n,i){var F={expected:n[e],actual:r,attribute:e,property:u},o=n.messages&&n.messages[e]||n.message||t.messages[e]||"no default message";o=o.replace(/%\{([a-z]+)\}/gi,function(e,t){return F[t.toLowerCase()]||""}),i.push({attribute:e,property:u,expected:n[e],actual:r,message:o})}function o(e){return"[object Array]"===Object.prototype.toString.call(e)}function a(e){return"[object Date]"===Object.prototype.toString.call(e)}e.validate=t,e.mixin=u,t.defaults={validateFormats:!0,validateFormatsStrict:!1,validateFormatExtensions:!0,additionalProperties:!0},t.messages={required:"is required",allowEmpty:"must not be empty",minLength:"is too short (minimum is %{expected} characters)",maxLength:"is too long (maximum is %{expected} characters)",pattern:"invalid input",minimum:"must be greater than or equal to %{expected}",maximum:"must be less than or equal to %{expected}",exclusiveMinimum:"must be greater than %{expected}",exclusiveMaximum:"must be less than %{expected}",divisibleBy:"must be divisible by %{expected}",minItems:"must contain more than %{expected} items",maxItems:"must contain less than %{expected} items",uniqueItems:"must hold a unique set of values",format:"is not a valid %{expected}",conform:"must conform to given constraint",type:"must be of %{expected} type",additionalProperties:"must not exist"},t.messages["enum"]="must be present in given enumerator",t.formats={email:/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i,"ip-address":/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/i,ipv6:/^([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}$/,"date-time":/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:.\d{1,3})?Z$/,date:/^\d{4}-\d{2}-\d{2}$/,time:/^\d{2}:\d{2}:\d{2}$/,color:/^#[a-z0-9]{6}|#[a-z0-9]{3}|(?:rgb\(\s*(?:[+-]?\d+%?)\s*,\s*(?:[+-]?\d+%?)\s*,\s*(?:[+-]?\d+%?)\s*\))aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|orange|purple|red|silver|teal|white|yellow$/i,"host-name":/^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])/,"utc-millisec":{test:function(e){return"number"==typeof e&&e>=0}},regex:{test:function(e){try{new RegExp(e)}catch(t){return!1}return!0}}},t.formatExtensions={url:/^(https?|ftp|git):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i}}("object"==typeof t&&t&&t.exports?t.exports:window)},{}]},{},[1])(1)}); \ No newline at end of file From 6bdffaf4ea3d3c10f97d6f2635f7737eb881699d Mon Sep 17 00:00:00 2001 From: David Konsumer Date: Fri, 23 Jan 2015 07:20:03 -0800 Subject: [PATCH 4/5] more efficient class/message toggle --- example/clientside.html | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/example/clientside.html b/example/clientside.html index da8f2e7..03f5b1e 100644 --- a/example/clientside.html +++ b/example/clientside.html @@ -68,21 +68,29 @@

This is a client-side demo of This is a client-side demo of