Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: thedersen/backbone.validation
base: v0.8.0
...
head fork: thedersen/backbone.validation
compare: v0.8.1
Checking mergeability… Don't worry, you can still create the pull request.
  • 5 commits
  • 12 files changed
  • 2 commit comments
  • 1 contributor
View
8 README.md
@@ -1,4 +1,4 @@
-# Backbone.Validation v0.8.0
+# Backbone.Validation v0.8.1
A validation plugin for [Backbone.js](http://documentcloud.github.com/backbone) that validates both your model as well as form input.
@@ -774,6 +774,12 @@ Basic behaviour:
## Release notes
+#### v0.8.1 [commits](https://github.com/thedersen/backbone.validation/compare/v0.8.0...v0.8.1)
+
+* No longer flattens arrays
+* Added required validator test for empty and non-empty arrays
+* Replaces all the underscores in sentenceCase formatter
+
#### v0.8.0 [commits](https://github.com/thedersen/backbone.validation/compare/v0.7.1...v0.8.0)
* All tests pass Backbone v1.0
View
4 dist/backbone-validation-amd-min.js
@@ -1,8 +1,8 @@
-// Backbone.Validation v0.8.0
+// Backbone.Validation v0.8.1
//
// Copyright (c) 2011-2013 Thomas Pedersen
// Distributed under MIT License
//
// Documentation and full license available at:
// http://thedersen.com/projects/backbone-validation
-(function(e){typeof exports=="object"?module.exports=e(require("backbone"),require("underscore")):typeof define=="function"&&define.amd&&define(["backbone","underscore"],e)})(function(e,t){return e.Validation=function(t){"use strict";var n={forceUpdate:!1,selector:"name",labelFormatter:"sentenceCase",valid:Function.prototype,invalid:Function.prototype},r={formatLabel:function(e,t){return f[n.labelFormatter](e,t)},format:function(){var e=Array.prototype.slice.call(arguments),t=e.shift();return t.replace(/\{(\d+)\}/g,function(t,n){return typeof e[n]!="undefined"?e[n]:t})}},i=function(n,r,s){return r=r||{},s=s||"",t.each(n,function(t,o){n.hasOwnProperty(o)&&(!t||typeof t!="object"||t instanceof Date||t instanceof RegExp||t instanceof e.Model||t instanceof e.Collection?r[s+o]=t:i(t,r,s+o+"."))}),r},s=function(){var e=function(e){return t.reduce(t.keys(e.validation||{}),function(e,t){return e[t]=void 0,e},{})},s=function(e,n){var r=e.validation?e.validation[n]||{}:{};if(t.isFunction(r)||t.isString(r))r={fn:r};return t.isArray(r)||(r=[r]),t.reduce(r,function(e,n){return t.each(t.without(t.keys(n),"msg"),function(t){e.push({fn:l[t],val:n[t],msg:n.msg})}),e},[])},u=function(e,n,i,o){return t.reduce(s(e,n),function(s,u){var a=t.extend({},r,l),f=u.fn.call(a,i,n,u.val,e,o);return f===!1||s===!1?!1:f&&!s?u.msg||f:s},"")},a=function(e,n){var r,s={},o=!0,a=t.clone(n),f=i(n);return t.each(f,function(t,n){r=u(e,n,t,a),r&&(s[n]=r,o=!1)}),{invalidAttrs:s,isValid:o}},f=function(n,r){return{preValidate:function(e,n){return u(this,e,n,t.extend({},this.attributes))},isValid:function(e){var n=i(this.attributes);return t.isString(e)?!u(this,e,n[e],t.extend({},this.attributes)):t.isArray(e)?t.reduce(e,function(e,r){return e&&!u(this,r,n[r],t.extend({},this.attributes))},!0,this):(e===!0&&this.validate(),this.validation?this._isValid:!0)},validate:function(s,o){var u=this,f=!s,l=t.extend({},r,o),c=e(u),h=t.extend({},c,u.attributes,s),p=i(s||h),d=a(u,h);u._isValid=d.isValid,t.each(c,function(e,t){var r=d.invalidAttrs.hasOwnProperty(t);r||l.valid(n,t,l.selector)}),t.each(c,function(e,t){var r=d.invalidAttrs.hasOwnProperty(t),i=p.hasOwnProperty(t);r&&(i||f)&&l.invalid(n,t,d.invalidAttrs[t],l.selector)}),t.defer(function(){u.trigger("validated",u._isValid,u,d.invalidAttrs),u.trigger("validated:"+(u._isValid?"valid":"invalid"),u,d.invalidAttrs)});if(!l.forceUpdate&&t.intersection(t.keys(d.invalidAttrs),t.keys(p)).length>0)return d.invalidAttrs}}},c=function(e,n,r){t.extend(n,f(e,r))},h=function(e){delete e.validate,delete e.preValidate,delete e.isValid},p=function(e){c(this.view,e,this.options)},d=function(e){h(e)};return{version:"0.8.0",configure:function(e){t.extend(n,e)},bind:function(e,r){var i=e.model,s=e.collection;r=t.extend({},n,o,r);if(typeof i=="undefined"&&typeof s=="undefined")throw"Before you execute the binding your view must have a model or a collection.\nSee http://thedersen.com/projects/backbone-validation/#using-form-model-validation for more information.";i?c(e,i,r):s&&(s.each(function(t){c(e,t,r)}),s.bind("add",p,{view:e,options:r}),s.bind("remove",d))},unbind:function(e){var t=e.model,n=e.collection;t&&h(e.model),n&&(n.each(function(e){h(e)}),n.unbind("add",p),n.unbind("remove",d))},mixin:f(null,n)}}(),o=s.callbacks={valid:function(e,t,n){e.$("["+n+'~="'+t+'"]').removeClass("invalid").removeAttr("data-error")},invalid:function(e,t,n,r){e.$("["+r+'~="'+t+'"]').addClass("invalid").attr("data-error",n)}},u=s.patterns={digits:/^\d+$/,number:/^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/,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,url:/^(https?|ftp):\/\/(((([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},a=s.messages={required:"{0} is required",acceptance:"{0} must be accepted",min:"{0} must be greater than or equal to {1}",max:"{0} must be less than or equal to {1}",range:"{0} must be between {1} and {2}",length:"{0} must be {1} characters",minLength:"{0} must be at least {1} characters",maxLength:"{0} must be at most {1} characters",rangeLength:"{0} must be between {1} and {2} characters",oneOf:"{0} must be one of: {1}",equalTo:"{0} must be the same as {1}",pattern:"{0} must be a valid {1}"},f=s.labelFormatters={none:function(e){return e},sentenceCase:function(e){return e.replace(/(?:^\w|[A-Z]|\b\w)/g,function(e,t){return t===0?e.toUpperCase():" "+e.toLowerCase()}).replace("_"," ")},label:function(e,t){return t.labels&&t.labels[e]||f.sentenceCase(e,t)}},l=s.validators=function(){var e=String.prototype.trim?function(e){return e===null?"":String.prototype.trim.call(e)}:function(e){var t=/^\s+/,n=/\s+$/;return e===null?"":e.toString().replace(t,"").replace(n,"")},n=function(e){return t.isNumber(e)||t.isString(e)&&e.match(u.number)},r=function(n){return!(t.isNull(n)||t.isUndefined(n)||t.isString(n)&&e(n)==="")};return{fn:function(e,n,r,i,s){return t.isString(r)&&(r=i[r]),r.call(i,e,n,s)},required:function(e,n,i,s,o){var u=t.isFunction(i)?i.call(s,e,n,o):i;if(!u&&!r(e))return!1;if(u&&!r(e))return this.format(a.required,this.formatLabel(n,s))},acceptance:function(e,n,r,i){if(e!=="true"&&(!t.isBoolean(e)||e===!1))return this.format(a.acceptance,this.formatLabel(n,i))},min:function(e,t,r,i){if(!n(e)||e<r)return this.format(a.min,this.formatLabel(t,i),r)},max:function(e,t,r,i){if(!n(e)||e>r)return this.format(a.max,this.formatLabel(t,i),r)},range:function(e,t,r,i){if(!n(e)||e<r[0]||e>r[1])return this.format(a.range,this.formatLabel(t,i),r[0],r[1])},length:function(t,n,i,s){if(!r(t)||e(t).length!==i)return this.format(a.length,this.formatLabel(n,s),i)},minLength:function(t,n,i,s){if(!r(t)||e(t).length<i)return this.format(a.minLength,this.formatLabel(n,s),i)},maxLength:function(t,n,i,s){if(!r(t)||e(t).length>i)return this.format(a.maxLength,this.formatLabel(n,s),i)},rangeLength:function(t,n,i,s){if(!r(t)||e(t).length<i[0]||e(t).length>i[1])return this.format(a.rangeLength,this.formatLabel(n,s),i[0],i[1])},oneOf:function(e,n,r,i){if(!t.include(r,e))return this.format(a.oneOf,this.formatLabel(n,i),r.join(", "))},equalTo:function(e,t,n,r,i){if(e!==i[n])return this.format(a.equalTo,this.formatLabel(t,r),this.formatLabel(n,r))},pattern:function(e,t,n,i){if(!r(e)||!e.toString().match(u[n]||n))return this.format(a.pattern,this.formatLabel(t,i),n)}}}();return s}(t),e.Validation});
+!function(a){"object"==typeof exports?module.exports=a(require("backbone"),require("underscore")):"function"==typeof define&&define.amd&&define(["backbone","underscore"],a)}(function(a,b){return a.Validation=function(b){"use strict";var c={forceUpdate:!1,selector:"name",labelFormatter:"sentenceCase",valid:Function.prototype,invalid:Function.prototype},d={formatLabel:function(a,b){return j[c.labelFormatter](a,b)},format:function(){var a=Array.prototype.slice.call(arguments),b=a.shift();return b.replace(/\{(\d+)\}/g,function(b,c){return"undefined"!=typeof a[c]?a[c]:b})}},e=function(c,d,f){return d=d||{},f=f||"",b.each(c,function(b,g){c.hasOwnProperty(g)&&(!b||"object"!=typeof b||b instanceof Array||b instanceof Date||b instanceof RegExp||b instanceof a.Model||b instanceof a.Collection?d[f+g]=b:e(b,d,f+g+"."))}),d},f=function(){var a=function(a){return b.reduce(b.keys(a.validation||{}),function(a,b){return a[b]=void 0,a},{})},f=function(a,c){var d=a.validation?a.validation[c]||{}:{};return(b.isFunction(d)||b.isString(d))&&(d={fn:d}),b.isArray(d)||(d=[d]),b.reduce(d,function(a,c){return b.each(b.without(b.keys(c),"msg"),function(b){a.push({fn:k[b],val:c[b],msg:c.msg})}),a},[])},h=function(a,c,e,g){return b.reduce(f(a,c),function(f,h){var i=b.extend({},d,k),j=h.fn.call(i,e,c,h.val,a,g);return j===!1||f===!1?!1:j&&!f?h.msg||j:f},"")},i=function(a,c){var d,f={},g=!0,i=b.clone(c),j=e(c);return b.each(j,function(b,c){d=h(a,c,b,i),d&&(f[c]=d,g=!1)}),{invalidAttrs:f,isValid:g}},j=function(c,d){return{preValidate:function(a,c){return h(this,a,c,b.extend({},this.attributes))},isValid:function(a){var c=e(this.attributes);return b.isString(a)?!h(this,a,c[a],b.extend({},this.attributes)):b.isArray(a)?b.reduce(a,function(a,d){return a&&!h(this,d,c[d],b.extend({},this.attributes))},!0,this):(a===!0&&this.validate(),this.validation?this._isValid:!0)},validate:function(f,g){var h=this,j=!f,k=b.extend({},d,g),l=a(h),m=b.extend({},l,h.attributes,f),n=e(f||m),o=i(h,m);return h._isValid=o.isValid,b.each(l,function(a,b){var d=o.invalidAttrs.hasOwnProperty(b);d||k.valid(c,b,k.selector)}),b.each(l,function(a,b){var d=o.invalidAttrs.hasOwnProperty(b),e=n.hasOwnProperty(b);d&&(e||j)&&k.invalid(c,b,o.invalidAttrs[b],k.selector)}),b.defer(function(){h.trigger("validated",h._isValid,h,o.invalidAttrs),h.trigger("validated:"+(h._isValid?"valid":"invalid"),h,o.invalidAttrs)}),!k.forceUpdate&&b.intersection(b.keys(o.invalidAttrs),b.keys(n)).length>0?o.invalidAttrs:void 0}}},l=function(a,c,d){b.extend(c,j(a,d))},m=function(a){delete a.validate,delete a.preValidate,delete a.isValid},n=function(a){l(this.view,a,this.options)},o=function(a){m(a)};return{version:"0.8.1",configure:function(a){b.extend(c,a)},bind:function(a,d){var e=a.model,f=a.collection;if(d=b.extend({},c,g,d),"undefined"==typeof e&&"undefined"==typeof f)throw"Before you execute the binding your view must have a model or a collection.\nSee http://thedersen.com/projects/backbone-validation/#using-form-model-validation for more information.";e?l(a,e,d):f&&(f.each(function(b){l(a,b,d)}),f.bind("add",n,{view:a,options:d}),f.bind("remove",o))},unbind:function(a){var b=a.model,c=a.collection;b&&m(a.model),c&&(c.each(function(a){m(a)}),c.unbind("add",n),c.unbind("remove",o))},mixin:j(null,c)}}(),g=f.callbacks={valid:function(a,b,c){a.$("["+c+'~="'+b+'"]').removeClass("invalid").removeAttr("data-error")},invalid:function(a,b,c,d){a.$("["+d+'~="'+b+'"]').addClass("invalid").attr("data-error",c)}},h=f.patterns={digits:/^\d+$/,number:/^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/,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,url:/^(https?|ftp):\/\/(((([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},i=f.messages={required:"{0} is required",acceptance:"{0} must be accepted",min:"{0} must be greater than or equal to {1}",max:"{0} must be less than or equal to {1}",range:"{0} must be between {1} and {2}",length:"{0} must be {1} characters",minLength:"{0} must be at least {1} characters",maxLength:"{0} must be at most {1} characters",rangeLength:"{0} must be between {1} and {2} characters",oneOf:"{0} must be one of: {1}",equalTo:"{0} must be the same as {1}",pattern:"{0} must be a valid {1}"},j=f.labelFormatters={none:function(a){return a},sentenceCase:function(a){return a.replace(/(?:^\w|[A-Z]|\b\w)/g,function(a,b){return 0===b?a.toUpperCase():" "+a.toLowerCase()}).replace(/_/g," ")},label:function(a,b){return b.labels&&b.labels[a]||j.sentenceCase(a,b)}},k=f.validators=function(){var a=String.prototype.trim?function(a){return null===a?"":String.prototype.trim.call(a)}:function(a){var b=/^\s+/,c=/\s+$/;return null===a?"":a.toString().replace(b,"").replace(c,"")},c=function(a){return b.isNumber(a)||b.isString(a)&&a.match(h.number)},d=function(c){return!(b.isNull(c)||b.isUndefined(c)||b.isString(c)&&""===a(c)||b.isArray(c)&&b.isEmpty(c))};return{fn:function(a,c,d,e,f){return b.isString(d)&&(d=e[d]),d.call(e,a,c,f)},required:function(a,c,e,f,g){var h=b.isFunction(e)?e.call(f,a,c,g):e;return h||d(a)?h&&!d(a)?this.format(i.required,this.formatLabel(c,f)):void 0:!1},acceptance:function(a,c,d,e){return"true"===a||b.isBoolean(a)&&a!==!1?void 0:this.format(i.acceptance,this.formatLabel(c,e))},min:function(a,b,d,e){return!c(a)||d>a?this.format(i.min,this.formatLabel(b,e),d):void 0},max:function(a,b,d,e){return!c(a)||a>d?this.format(i.max,this.formatLabel(b,e),d):void 0},range:function(a,b,d,e){return!c(a)||a<d[0]||a>d[1]?this.format(i.range,this.formatLabel(b,e),d[0],d[1]):void 0},length:function(b,c,e,f){return d(b)&&a(b).length===e?void 0:this.format(i.length,this.formatLabel(c,f),e)},minLength:function(b,c,e,f){return!d(b)||a(b).length<e?this.format(i.minLength,this.formatLabel(c,f),e):void 0},maxLength:function(b,c,e,f){return!d(b)||a(b).length>e?this.format(i.maxLength,this.formatLabel(c,f),e):void 0},rangeLength:function(b,c,e,f){return!d(b)||a(b).length<e[0]||a(b).length>e[1]?this.format(i.rangeLength,this.formatLabel(c,f),e[0],e[1]):void 0},oneOf:function(a,c,d,e){return b.include(d,a)?void 0:this.format(i.oneOf,this.formatLabel(c,e),d.join(", "))},equalTo:function(a,b,c,d,e){return a!==e[c]?this.format(i.equalTo,this.formatLabel(b,d),this.formatLabel(c,d)):void 0},pattern:function(a,b,c,e){return d(a)&&a.toString().match(h[c]||c)?void 0:this.format(i.pattern,this.formatLabel(b,e),c)}}}();return f}(b),a.Validation});
View
12 dist/backbone-validation-amd.js
@@ -1,4 +1,4 @@
-// Backbone.Validation v0.8.0
+// Backbone.Validation v0.8.1
//
// Copyright (c) 2011-2013 Thomas Pedersen
// Distributed under MIT License
@@ -72,6 +72,7 @@
_.each(obj, function(val, key) {
if(obj.hasOwnProperty(key)) {
if (val && typeof val === 'object' && !(
+ val instanceof Array ||
val instanceof Date ||
val instanceof RegExp ||
val instanceof Backbone.Model ||
@@ -295,7 +296,7 @@
return {
// Current version of the library
- version: '0.8.0',
+ version: '0.8.1',
// Called to configure the default options
configure: function(options) {
@@ -437,7 +438,7 @@
sentenceCase: function(attrName) {
return attrName.replace(/(?:^\w|[A-Z]|\b\w)/g, function(match, index) {
return index === 0 ? match.toUpperCase() : ' ' + match.toLowerCase();
- }).replace('_', ' ');
+ }).replace(/_/g, ' ');
},
// Looks for a label configured on the model and returns it
@@ -480,9 +481,9 @@
return _.isNumber(value) || (_.isString(value) && value.match(defaultPatterns.number));
};
- // Determines whether or not not a value is empty
+ // Determines whether or not a value is empty
var hasValue = function(value) {
- return !(_.isNull(value) || _.isUndefined(value) || (_.isString(value) && trim(value) === ''));
+ return !(_.isNull(value) || _.isUndefined(value) || (_.isString(value) && trim(value) === '') || (_.isArray(value) && _.isEmpty(value)));
};
return {
@@ -610,6 +611,5 @@
return Validation;
}(_));
-
return Backbone.Validation;
}));
View
4 dist/backbone-validation-min.js
@@ -1,8 +1,8 @@
-// Backbone.Validation v0.8.0
+// Backbone.Validation v0.8.1
//
// Copyright (c) 2011-2013 Thomas Pedersen
// Distributed under MIT License
//
// Documentation and full license available at:
// http://thedersen.com/projects/backbone-validation
-Backbone.Validation=function(e){"use strict";var t={forceUpdate:!1,selector:"name",labelFormatter:"sentenceCase",valid:Function.prototype,invalid:Function.prototype},n={formatLabel:function(e,n){return a[t.labelFormatter](e,n)},format:function(){var e=Array.prototype.slice.call(arguments),t=e.shift();return t.replace(/\{(\d+)\}/g,function(t,n){return typeof e[n]!="undefined"?e[n]:t})}},r=function(t,n,i){return n=n||{},i=i||"",e.each(t,function(e,s){t.hasOwnProperty(s)&&(!e||typeof e!="object"||e instanceof Date||e instanceof RegExp||e instanceof Backbone.Model||e instanceof Backbone.Collection?n[i+s]=e:r(e,n,i+s+"."))}),n},i=function(){var i=function(t){return e.reduce(e.keys(t.validation||{}),function(e,t){return e[t]=void 0,e},{})},o=function(t,n){var r=t.validation?t.validation[n]||{}:{};if(e.isFunction(r)||e.isString(r))r={fn:r};return e.isArray(r)||(r=[r]),e.reduce(r,function(t,n){return e.each(e.without(e.keys(n),"msg"),function(e){t.push({fn:f[e],val:n[e],msg:n.msg})}),t},[])},u=function(t,r,i,s){return e.reduce(o(t,r),function(o,u){var a=e.extend({},n,f),l=u.fn.call(a,i,r,u.val,t,s);return l===!1||o===!1?!1:l&&!o?u.msg||l:o},"")},a=function(t,n){var i,s={},o=!0,a=e.clone(n),f=r(n);return e.each(f,function(e,n){i=u(t,n,e,a),i&&(s[n]=i,o=!1)}),{invalidAttrs:s,isValid:o}},l=function(t,n){return{preValidate:function(t,n){return u(this,t,n,e.extend({},this.attributes))},isValid:function(t){var n=r(this.attributes);return e.isString(t)?!u(this,t,n[t],e.extend({},this.attributes)):e.isArray(t)?e.reduce(t,function(t,r){return t&&!u(this,r,n[r],e.extend({},this.attributes))},!0,this):(t===!0&&this.validate(),this.validation?this._isValid:!0)},validate:function(s,o){var u=this,f=!s,l=e.extend({},n,o),c=i(u),h=e.extend({},c,u.attributes,s),p=r(s||h),d=a(u,h);u._isValid=d.isValid,e.each(c,function(e,n){var r=d.invalidAttrs.hasOwnProperty(n);r||l.valid(t,n,l.selector)}),e.each(c,function(e,n){var r=d.invalidAttrs.hasOwnProperty(n),i=p.hasOwnProperty(n);r&&(i||f)&&l.invalid(t,n,d.invalidAttrs[n],l.selector)}),e.defer(function(){u.trigger("validated",u._isValid,u,d.invalidAttrs),u.trigger("validated:"+(u._isValid?"valid":"invalid"),u,d.invalidAttrs)});if(!l.forceUpdate&&e.intersection(e.keys(d.invalidAttrs),e.keys(p)).length>0)return d.invalidAttrs}}},c=function(t,n,r){e.extend(n,l(t,r))},h=function(e){delete e.validate,delete e.preValidate,delete e.isValid},p=function(e){c(this.view,e,this.options)},d=function(e){h(e)};return{version:"0.8.0",configure:function(n){e.extend(t,n)},bind:function(n,r){var i=n.model,o=n.collection;r=e.extend({},t,s,r);if(typeof i=="undefined"&&typeof o=="undefined")throw"Before you execute the binding your view must have a model or a collection.\nSee http://thedersen.com/projects/backbone-validation/#using-form-model-validation for more information.";i?c(n,i,r):o&&(o.each(function(e){c(n,e,r)}),o.bind("add",p,{view:n,options:r}),o.bind("remove",d))},unbind:function(e){var t=e.model,n=e.collection;t&&h(e.model),n&&(n.each(function(e){h(e)}),n.unbind("add",p),n.unbind("remove",d))},mixin:l(null,t)}}(),s=i.callbacks={valid:function(e,t,n){e.$("["+n+'~="'+t+'"]').removeClass("invalid").removeAttr("data-error")},invalid:function(e,t,n,r){e.$("["+r+'~="'+t+'"]').addClass("invalid").attr("data-error",n)}},o=i.patterns={digits:/^\d+$/,number:/^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/,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,url:/^(https?|ftp):\/\/(((([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},u=i.messages={required:"{0} is required",acceptance:"{0} must be accepted",min:"{0} must be greater than or equal to {1}",max:"{0} must be less than or equal to {1}",range:"{0} must be between {1} and {2}",length:"{0} must be {1} characters",minLength:"{0} must be at least {1} characters",maxLength:"{0} must be at most {1} characters",rangeLength:"{0} must be between {1} and {2} characters",oneOf:"{0} must be one of: {1}",equalTo:"{0} must be the same as {1}",pattern:"{0} must be a valid {1}"},a=i.labelFormatters={none:function(e){return e},sentenceCase:function(e){return e.replace(/(?:^\w|[A-Z]|\b\w)/g,function(e,t){return t===0?e.toUpperCase():" "+e.toLowerCase()}).replace("_"," ")},label:function(e,t){return t.labels&&t.labels[e]||a.sentenceCase(e,t)}},f=i.validators=function(){var t=String.prototype.trim?function(e){return e===null?"":String.prototype.trim.call(e)}:function(e){var t=/^\s+/,n=/\s+$/;return e===null?"":e.toString().replace(t,"").replace(n,"")},n=function(t){return e.isNumber(t)||e.isString(t)&&t.match(o.number)},r=function(n){return!(e.isNull(n)||e.isUndefined(n)||e.isString(n)&&t(n)==="")};return{fn:function(t,n,r,i,s){return e.isString(r)&&(r=i[r]),r.call(i,t,n,s)},required:function(t,n,i,s,o){var a=e.isFunction(i)?i.call(s,t,n,o):i;if(!a&&!r(t))return!1;if(a&&!r(t))return this.format(u.required,this.formatLabel(n,s))},acceptance:function(t,n,r,i){if(t!=="true"&&(!e.isBoolean(t)||t===!1))return this.format(u.acceptance,this.formatLabel(n,i))},min:function(e,t,r,i){if(!n(e)||e<r)return this.format(u.min,this.formatLabel(t,i),r)},max:function(e,t,r,i){if(!n(e)||e>r)return this.format(u.max,this.formatLabel(t,i),r)},range:function(e,t,r,i){if(!n(e)||e<r[0]||e>r[1])return this.format(u.range,this.formatLabel(t,i),r[0],r[1])},length:function(e,n,i,s){if(!r(e)||t(e).length!==i)return this.format(u.length,this.formatLabel(n,s),i)},minLength:function(e,n,i,s){if(!r(e)||t(e).length<i)return this.format(u.minLength,this.formatLabel(n,s),i)},maxLength:function(e,n,i,s){if(!r(e)||t(e).length>i)return this.format(u.maxLength,this.formatLabel(n,s),i)},rangeLength:function(e,n,i,s){if(!r(e)||t(e).length<i[0]||t(e).length>i[1])return this.format(u.rangeLength,this.formatLabel(n,s),i[0],i[1])},oneOf:function(t,n,r,i){if(!e.include(r,t))return this.format(u.oneOf,this.formatLabel(n,i),r.join(", "))},equalTo:function(e,t,n,r,i){if(e!==i[n])return this.format(u.equalTo,this.formatLabel(t,r),this.formatLabel(n,r))},pattern:function(e,t,n,i){if(!r(e)||!e.toString().match(o[n]||n))return this.format(u.pattern,this.formatLabel(t,i),n)}}}();return i}(_);
+Backbone.Validation=function(a){"use strict";var b={forceUpdate:!1,selector:"name",labelFormatter:"sentenceCase",valid:Function.prototype,invalid:Function.prototype},c={formatLabel:function(a,c){return i[b.labelFormatter](a,c)},format:function(){var a=Array.prototype.slice.call(arguments),b=a.shift();return b.replace(/\{(\d+)\}/g,function(b,c){return"undefined"!=typeof a[c]?a[c]:b})}},d=function(b,c,e){return c=c||{},e=e||"",a.each(b,function(a,f){b.hasOwnProperty(f)&&(!a||"object"!=typeof a||a instanceof Array||a instanceof Date||a instanceof RegExp||a instanceof Backbone.Model||a instanceof Backbone.Collection?c[e+f]=a:d(a,c,e+f+"."))}),c},e=function(){var e=function(b){return a.reduce(a.keys(b.validation||{}),function(a,b){return a[b]=void 0,a},{})},g=function(b,c){var d=b.validation?b.validation[c]||{}:{};return(a.isFunction(d)||a.isString(d))&&(d={fn:d}),a.isArray(d)||(d=[d]),a.reduce(d,function(b,c){return a.each(a.without(a.keys(c),"msg"),function(a){b.push({fn:j[a],val:c[a],msg:c.msg})}),b},[])},h=function(b,d,e,f){return a.reduce(g(b,d),function(g,h){var i=a.extend({},c,j),k=h.fn.call(i,e,d,h.val,b,f);return k===!1||g===!1?!1:k&&!g?h.msg||k:g},"")},i=function(b,c){var e,f={},g=!0,i=a.clone(c),j=d(c);return a.each(j,function(a,c){e=h(b,c,a,i),e&&(f[c]=e,g=!1)}),{invalidAttrs:f,isValid:g}},k=function(b,c){return{preValidate:function(b,c){return h(this,b,c,a.extend({},this.attributes))},isValid:function(b){var c=d(this.attributes);return a.isString(b)?!h(this,b,c[b],a.extend({},this.attributes)):a.isArray(b)?a.reduce(b,function(b,d){return b&&!h(this,d,c[d],a.extend({},this.attributes))},!0,this):(b===!0&&this.validate(),this.validation?this._isValid:!0)},validate:function(f,g){var h=this,j=!f,k=a.extend({},c,g),l=e(h),m=a.extend({},l,h.attributes,f),n=d(f||m),o=i(h,m);return h._isValid=o.isValid,a.each(l,function(a,c){var d=o.invalidAttrs.hasOwnProperty(c);d||k.valid(b,c,k.selector)}),a.each(l,function(a,c){var d=o.invalidAttrs.hasOwnProperty(c),e=n.hasOwnProperty(c);d&&(e||j)&&k.invalid(b,c,o.invalidAttrs[c],k.selector)}),a.defer(function(){h.trigger("validated",h._isValid,h,o.invalidAttrs),h.trigger("validated:"+(h._isValid?"valid":"invalid"),h,o.invalidAttrs)}),!k.forceUpdate&&a.intersection(a.keys(o.invalidAttrs),a.keys(n)).length>0?o.invalidAttrs:void 0}}},l=function(b,c,d){a.extend(c,k(b,d))},m=function(a){delete a.validate,delete a.preValidate,delete a.isValid},n=function(a){l(this.view,a,this.options)},o=function(a){m(a)};return{version:"0.8.1",configure:function(c){a.extend(b,c)},bind:function(c,d){var e=c.model,g=c.collection;if(d=a.extend({},b,f,d),"undefined"==typeof e&&"undefined"==typeof g)throw"Before you execute the binding your view must have a model or a collection.\nSee http://thedersen.com/projects/backbone-validation/#using-form-model-validation for more information.";e?l(c,e,d):g&&(g.each(function(a){l(c,a,d)}),g.bind("add",n,{view:c,options:d}),g.bind("remove",o))},unbind:function(a){var b=a.model,c=a.collection;b&&m(a.model),c&&(c.each(function(a){m(a)}),c.unbind("add",n),c.unbind("remove",o))},mixin:k(null,b)}}(),f=e.callbacks={valid:function(a,b,c){a.$("["+c+'~="'+b+'"]').removeClass("invalid").removeAttr("data-error")},invalid:function(a,b,c,d){a.$("["+d+'~="'+b+'"]').addClass("invalid").attr("data-error",c)}},g=e.patterns={digits:/^\d+$/,number:/^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/,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,url:/^(https?|ftp):\/\/(((([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},h=e.messages={required:"{0} is required",acceptance:"{0} must be accepted",min:"{0} must be greater than or equal to {1}",max:"{0} must be less than or equal to {1}",range:"{0} must be between {1} and {2}",length:"{0} must be {1} characters",minLength:"{0} must be at least {1} characters",maxLength:"{0} must be at most {1} characters",rangeLength:"{0} must be between {1} and {2} characters",oneOf:"{0} must be one of: {1}",equalTo:"{0} must be the same as {1}",pattern:"{0} must be a valid {1}"},i=e.labelFormatters={none:function(a){return a},sentenceCase:function(a){return a.replace(/(?:^\w|[A-Z]|\b\w)/g,function(a,b){return 0===b?a.toUpperCase():" "+a.toLowerCase()}).replace(/_/g," ")},label:function(a,b){return b.labels&&b.labels[a]||i.sentenceCase(a,b)}},j=e.validators=function(){var b=String.prototype.trim?function(a){return null===a?"":String.prototype.trim.call(a)}:function(a){var b=/^\s+/,c=/\s+$/;return null===a?"":a.toString().replace(b,"").replace(c,"")},c=function(b){return a.isNumber(b)||a.isString(b)&&b.match(g.number)},d=function(c){return!(a.isNull(c)||a.isUndefined(c)||a.isString(c)&&""===b(c)||a.isArray(c)&&a.isEmpty(c))};return{fn:function(b,c,d,e,f){return a.isString(d)&&(d=e[d]),d.call(e,b,c,f)},required:function(b,c,e,f,g){var i=a.isFunction(e)?e.call(f,b,c,g):e;return i||d(b)?i&&!d(b)?this.format(h.required,this.formatLabel(c,f)):void 0:!1},acceptance:function(b,c,d,e){return"true"===b||a.isBoolean(b)&&b!==!1?void 0:this.format(h.acceptance,this.formatLabel(c,e))},min:function(a,b,d,e){return!c(a)||d>a?this.format(h.min,this.formatLabel(b,e),d):void 0},max:function(a,b,d,e){return!c(a)||a>d?this.format(h.max,this.formatLabel(b,e),d):void 0},range:function(a,b,d,e){return!c(a)||a<d[0]||a>d[1]?this.format(h.range,this.formatLabel(b,e),d[0],d[1]):void 0},length:function(a,c,e,f){return d(a)&&b(a).length===e?void 0:this.format(h.length,this.formatLabel(c,f),e)},minLength:function(a,c,e,f){return!d(a)||b(a).length<e?this.format(h.minLength,this.formatLabel(c,f),e):void 0},maxLength:function(a,c,e,f){return!d(a)||b(a).length>e?this.format(h.maxLength,this.formatLabel(c,f),e):void 0},rangeLength:function(a,c,e,f){return!d(a)||b(a).length<e[0]||b(a).length>e[1]?this.format(h.rangeLength,this.formatLabel(c,f),e[0],e[1]):void 0},oneOf:function(b,c,d,e){return a.include(d,b)?void 0:this.format(h.oneOf,this.formatLabel(c,e),d.join(", "))},equalTo:function(a,b,c,d,e){return a!==e[c]?this.format(h.equalTo,this.formatLabel(b,d),this.formatLabel(c,d)):void 0},pattern:function(a,b,c,e){return d(a)&&a.toString().match(g[c]||c)?void 0:this.format(h.pattern,this.formatLabel(b,e),c)}}}();return e}(_);
View
11 dist/backbone-validation.js
@@ -1,4 +1,4 @@
-// Backbone.Validation v0.8.0
+// Backbone.Validation v0.8.1
//
// Copyright (c) 2011-2013 Thomas Pedersen
// Distributed under MIT License
@@ -65,6 +65,7 @@ Backbone.Validation = (function(_){
_.each(obj, function(val, key) {
if(obj.hasOwnProperty(key)) {
if (val && typeof val === 'object' && !(
+ val instanceof Array ||
val instanceof Date ||
val instanceof RegExp ||
val instanceof Backbone.Model ||
@@ -288,7 +289,7 @@ Backbone.Validation = (function(_){
return {
// Current version of the library
- version: '0.8.0',
+ version: '0.8.1',
// Called to configure the default options
configure: function(options) {
@@ -430,7 +431,7 @@ Backbone.Validation = (function(_){
sentenceCase: function(attrName) {
return attrName.replace(/(?:^\w|[A-Z]|\b\w)/g, function(match, index) {
return index === 0 ? match.toUpperCase() : ' ' + match.toLowerCase();
- }).replace('_', ' ');
+ }).replace(/_/g, ' ');
},
// Looks for a label configured on the model and returns it
@@ -473,9 +474,9 @@ Backbone.Validation = (function(_){
return _.isNumber(value) || (_.isString(value) && value.match(defaultPatterns.number));
};
- // Determines whether or not not a value is empty
+ // Determines whether or not a value is empty
var hasValue = function(value) {
- return !(_.isNull(value) || _.isUndefined(value) || (_.isString(value) && trim(value) === ''));
+ return !(_.isNull(value) || _.isUndefined(value) || (_.isString(value) && trim(value) === '') || (_.isArray(value) && _.isEmpty(value)));
};
return {
View
84 grunt.js → gruntfile.js
@@ -1,40 +1,47 @@
-
module.exports = function(grunt) {
-
- // Project configuration.
grunt.initConfig({
- pkg: '<json:package.json>',
+ pkg: grunt.file.readJSON('package.json'),
meta: {
- banner: '// <%= pkg.title %> v<%= pkg.version %>\n' +
- '//\n' +
- '// Copyright (c) 2011-<%= grunt.template.today("yyyy") %> <%= pkg.author.name %>\n' +
- '// Distributed under MIT License\n' +
- '//\n' +
- '// Documentation and full license available at:\n' +
- '// <%= pkg.homepage %>'
+ banner: '// <%= pkg.title %> v<%= pkg.version %>\n' + '//\n' + '// Copyright (c) 2011-<%= grunt.template.today("yyyy") %> <%= pkg.author.name %>\n' + '// Distributed under MIT License\n' + '//\n' + '// Documentation and full license available at:\n' + '// <%= pkg.homepage %>\n'
},
rig: {
browser: {
- src: ['<banner:meta.banner>', '<file_strip_banner:src/<%= pkg.name %>.js>'],
- dest: 'dist/<%= pkg.name %>.js'
+ options: {
+ banner: '<%=grunt.config.get("meta").banner%>'
+ },
+ files: {
+ 'dist/<%= pkg.name %>.js': ['src/<%= pkg.name %>.js']
+ }
},
amd: {
- src: ['<banner:meta.banner>', '<file_strip_banner:src/<%= pkg.name %>-amd.js>'],
- dest: 'dist/<%= pkg.name %>-amd.js'
+ options: {
+ banner: '<%=grunt.config.get("meta").banner%>'
+ },
+ files: {
+ 'dist/<%= pkg.name %>-amd.js': ['src/<%= pkg.name %>-amd.js']
+ }
}
},
- min: {
+ uglify: {
browser: {
- src: ['<banner:meta.banner>', '<config:rig.browser.dest>'],
- dest: 'dist/<%= pkg.name %>-min.js'
+ options: {
+ banner: '<%=grunt.config.get("meta").banner%>'
+ },
+ files: {
+ 'dist/<%= pkg.name %>-min.js': ['dist/<%= pkg.name %>.js']
+ }
},
amd: {
- src: ['<banner:meta.banner>', '<config:rig.amd.dest>'],
- dest: 'dist/<%= pkg.name %>-amd-min.js'
+ options: {
+ banner: '<%=grunt.config.get("meta").banner%>'
+ },
+ files: {
+ 'dist/<%= pkg.name %>-amd-min.js': ['dist/<%= pkg.name %>-amd.js']
+ }
}
},
watch: {
- files: '<config:lint.files>',
+ files: '<%=grunt.config.get("lint").files%>',
tasks: 'default'
},
buster: {
@@ -47,36 +54,9 @@ module.exports = function(grunt) {
'port': '1111'
}
},
- lint: {
- files: ['grunt.js', 'src/**/*.js', 'tests/**/*.js']
- },
jshint: {
- options: {
- curly: true,
- eqeqeq: true,
- immed: true,
- latedef: true,
- newcap: true,
- noarg: true,
- sub: true,
- undef: true,
- boss: true,
- eqnull: true,
- browser: true,
- node: true
- },
- globals: {
- Backbone: true,
- _: true,
- jQuery: true,
- $: true,
- buster: true,
- assert: true,
- refute: true,
- define: true
- }
+ all: ['grunt.js', 'src/**/*.js', 'tests/**/*.js']
},
- uglify: {},
docco: {
app: {
src: ['dist/backbone-validation.js'],
@@ -128,11 +108,13 @@ module.exports = function(grunt) {
}
});
- grunt.registerTask('default', 'rig lint buster min');
+ grunt.registerTask('default', ['rig', 'jshint', 'buster', 'uglify']);
grunt.registerTask('publish', 'docco shell');
+ grunt.loadNpmTasks('grunt-contrib-jshint');
+ grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-buster');
grunt.loadNpmTasks('grunt-docco');
grunt.loadNpmTasks('grunt-shell');
grunt.loadNpmTasks('grunt-rigger');
-};
+};
View
7 package.json
@@ -1,7 +1,7 @@
{
"name": "backbone-validation",
"title": "Backbone.Validation",
- "version": "0.8.0",
+ "version": "0.8.1",
"author": {
"name": "Thomas Pedersen",
"url": "http://thedersen.com/"
@@ -31,10 +31,13 @@
"underscore": ">=1.3.1"
},
"devDependencies": {
+ "grunt": "~0.4.1",
"buster": ">=0.6.2",
"grunt-docco": ">=0.1.2",
"grunt-shell": ">=0.1.3",
"grunt-rigger": ">=0.3.0",
- "grunt-buster": ">=0.1.1"
+ "grunt-buster": ">=0.1.1",
+ "grunt-contrib-jshint": "~0.6.0",
+ "grunt-contrib-uglify": "~0.2.2"
}
}
View
9 src/backbone-validation.js
@@ -58,6 +58,7 @@ Backbone.Validation = (function(_){
_.each(obj, function(val, key) {
if(obj.hasOwnProperty(key)) {
if (val && typeof val === 'object' && !(
+ val instanceof Array ||
val instanceof Date ||
val instanceof RegExp ||
val instanceof Backbone.Model ||
@@ -281,7 +282,7 @@ Backbone.Validation = (function(_){
return {
// Current version of the library
- version: '0.8.0',
+ version: '0.8.1',
// Called to configure the default options
configure: function(options) {
@@ -423,7 +424,7 @@ Backbone.Validation = (function(_){
sentenceCase: function(attrName) {
return attrName.replace(/(?:^\w|[A-Z]|\b\w)/g, function(match, index) {
return index === 0 ? match.toUpperCase() : ' ' + match.toLowerCase();
- }).replace('_', ' ');
+ }).replace(/_/g, ' ');
},
// Looks for a label configured on the model and returns it
@@ -466,9 +467,9 @@ Backbone.Validation = (function(_){
return _.isNumber(value) || (_.isString(value) && value.match(defaultPatterns.number));
};
- // Determines whether or not not a value is empty
+ // Determines whether or not a value is empty
var hasValue = function(value) {
- return !(_.isNull(value) || _.isUndefined(value) || (_.isString(value) && trim(value) === ''));
+ return !(_.isNull(value) || _.isUndefined(value) || (_.isString(value) && trim(value) === '') || (_.isArray(value) && _.isEmpty(value)));
};
return {
View
73 tests/collections.js → tests/binding.js
@@ -1,3 +1,68 @@
+buster.testCase('Binding to view with model', {
+ setUp: function() {
+ var View = Backbone.View.extend({
+ render: function() {
+ Backbone.Validation.bind(this);
+ }
+ });
+ var Model = Backbone.Model.extend({
+ validation: {
+ name: function(val) {
+ if (!val) {
+ return 'Name is invalid';
+ }
+ }
+ }
+ });
+ this.model = new Model();
+ this.view = new View({
+ model: this.model
+ });
+
+ this.view.render();
+ },
+
+ tearDown: function() {
+ this.view.remove();
+ },
+
+ "the model's validate function is defined": function() {
+ assert.defined(this.model.validate);
+ },
+
+ "the model's isValid function is overridden": function() {
+ refute.same(this.model.isValid, Backbone.Model.prototype.isValid);
+ },
+
+ "and passing custom callbacks with the options": {
+ setUp: function(){
+ this.valid = this.spy();
+ this.invalid = this.spy();
+
+ Backbone.Validation.bind(this.view, {
+ valid: this.valid,
+ invalid: this.invalid
+ });
+ },
+
+ "should call valid callback passed with options": function() {
+ this.model.set({
+ name: 'Ben'
+ }, {validate: true});
+
+ assert.called(this.valid);
+ },
+
+ "should call invalid callback passed with options": function() {
+ this.model.set({
+ name: ''
+ }, {validate: true});
+
+ assert.called(this.invalid);
+ }
+ }
+});
+
buster.testCase('Binding to view with collection', {
setUp: function() {
var View = Backbone.View.extend({
@@ -80,4 +145,12 @@ buster.testCase('Binding to view with collection', {
refute.exception(function() { that.collection.trigger('add'); });
refute.exception(function() { that.collection.trigger('remove'); });
}
+});
+
+buster.testCase('Binding to view with model or collection', {
+ "throws exception": function(){
+ assert.exception(function(){
+ Backbone.Validation.bind(new Backbone.View());
+ });
+ }
});
View
48 tests/general.js
@@ -36,54 +36,6 @@ buster.testCase("Backbone.Validation", {
this.view.remove();
},
- "when binding": {
- setUp: function() {
- Backbone.Validation.bind(this.view);
- },
-
- "the model's validate function is defined": function() {
- assert.defined(this.model.validate);
- },
-
- "the model's isValid function is overridden": function() {
- refute.same(this.model.isValid, Backbone.Model.prototype.isValid);
- },
-
- "and passing custom callbacks with the options": {
- setUp: function(){
- this.valid = this.spy();
- this.invalid = this.spy();
-
- Backbone.Validation.bind(this.view, {
- valid: this.valid,
- invalid: this.invalid
- });
- },
-
- "should call valid callback passed with options": function() {
- this.model.set({
- age: 1
- }, {validate: true});
-
- assert.called(this.valid);
- },
-
- "should call invalid callback passed with options": function() {
- this.model.set({
- age: 0
- }, {validate: true});
-
- assert.called(this.invalid);
- }
- }
- },
-
- "when binding to view without model or collection": function(){
- assert.exception(function(){
- Backbone.Validation.bind(new Backbone.View());
- });
- },
-
"when unbinding":{
setUp: function(){
Backbone.Validation.bind(this.view);
View
7 tests/labelFormatter.js
@@ -8,6 +8,9 @@ buster.testCase('Label formatters', {
},
some_attribute: {
required: true
+ },
+ some_other_attribute: {
+ required: true
}
},
@@ -83,6 +86,10 @@ buster.testCase('Label formatters', {
"sentence cases underscore named attribute name": function(){
assert.equals('Some attribute is required', this.model.preValidate('some_attribute', ''));
+ },
+
+ "sentence cases underscore named attribute name with multiple underscores": function(){
+ assert.equals('Some other attribute is required', this.model.preValidate('some_other_attribute', ''));
}
}
}
View
19 tests/validators/required.js
@@ -9,6 +9,9 @@ buster.testCase("required validator", {
agree: {
required: true
},
+ posts: {
+ required: true
+ },
dependsOnName: {
required: function(val, attr, computed) {
that.ctx = this;
@@ -23,6 +26,7 @@ buster.testCase("required validator", {
this.model = new Model({
name: 'name',
agree: true,
+ posts: ['post'],
dependsOnName: 'depends'
});
this.view = new Backbone.View({
@@ -85,6 +89,18 @@ buster.testCase("required validator", {
}, {validate: true}));
},
+ "empty array is invalid": function() {
+ refute(this.model.set({
+ posts: []
+ }, {validate: true}));
+ },
+
+ "non-empty array is valid": function() {
+ assert(this.model.set({
+ posts: ['post']
+ }, {validate: true}));
+ },
+
"required can be specified as a method returning true or false": function() {
this.model.set({name:'aaa'}, {validate: true});
@@ -115,9 +131,10 @@ buster.testCase("required validator", {
this.model.set({attr: 'attr'});
this.model.set({
name: 'name',
+ posts: ['post'],
dependsOnName: 'value'
}, {validate: true});
- assert.equals({agree:true, attr:'attr', dependsOnName:'value', name:'name'}, this.computed);
+ assert.equals({agree:true, attr:'attr', dependsOnName:'value', name:'name', posts: ['post']}, this.computed);
}
});

Showing you all comments on commits in this comparison.

@4download

Hi Thomas:

Firstly and fore mostly thank you so much for backbone-validation. Today I took the 0.8.1 update having been on 0.8 before. With 0.8.1 update, the new line 75 broke array validation for me :(

My model object logically looks like this:

Person {
firstName: "John",
lastName: "Smith",
addresses: [{addressLine: "123 Main Street", city: "My City", zip: "12345"}]
}

with validation setup as such for zip attribute in address:

validation: {

...
"addresses.0.zip" : {
length: 5
}
...
}

This worked fine in 0.8, only error-ing out when the zip was not of length 5. However, now with 0.8.1, the object is always failing validation with this message:

"Addresses. 0. zip must be 5 characters"

This occurs regardless of whether the zip is 5 characters or not.

If I comment out line 75 in version 0.8.1, then all works well again, with the above messaging only when the zip is not 5 chars.

Wondering what was the driver for the addition of line 75. More so, given the above use case, is it possible to rollback the change and delete line 75? Alternatively, any guidance you could provide to validate a nested array objects with backbone-validation would be sincerely appreciated.

Thanks again for backbone-validation.

@rayqian

oh, no.

because this line of code won't flatten the array.

when array contains object, your validation will not work.

may be this #141 pull request is not good enough.

Something went wrong with that request. Please try again.