backbone-validation
Advanced tools
Comparing version 0.10.1 to 0.11.0
@@ -1,2 +0,2 @@ | ||
// Backbone.Validation v0.10.1 | ||
// Backbone.Validation v0.11.0 | ||
// | ||
@@ -8,2 +8,2 @@ // Copyright (c) 2011-2015 Thomas Pedersen | ||
// http://thedersen.com/projects/backbone-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(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.constructor===Object?d(a,c,e+f+"."):c[e+f]=a)}),c},e=function(){var e=function(b){return a.reduce(a.keys(a.result(b,"validation")||{}),function(a,b){return a[b]=void 0,a},{})},g=function(b,c){var d=b.validation?a.result(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?a.result(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){var d,e=this,f={};return a.isObject(b)?(a.each(b,function(a,b){d=e.preValidate(b,a),d&&(f[b]=d)}),a.isEmpty(f)?void 0:f):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.9.1",configure:function(c){a.extend(b,c)},bind:function(c,d){d=a.extend({},b,f,d);var e=d.model||c.model,g=d.collection||c.collection;if("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(b,c){c=a.extend({},c);var d=c.model||b.model,e=c.collection||b.collection;d?m(d):e&&(e.each(function(a){m(a)}),e.unbind("add",n),e.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}",digits:"{0} must only contain digits",number:"{0} must be a number",email:"{0} must be a valid email",url:"{0} must be a valid url",inlinePattern:"{0} is invalid"},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(b,c,d,e){return a.isString(b)&&b.length===d?void 0:this.format(h.length,this.formatLabel(c,e),d)},minLength:function(b,c,d,e){return!a.isString(b)||b.length<d?this.format(h.minLength,this.formatLabel(c,e),d):void 0},maxLength:function(b,c,d,e){return!a.isString(b)||b.length>d?this.format(h.maxLength,this.formatLabel(c,e),d):void 0},rangeLength:function(b,c,d,e){return!a.isString(b)||b.length<d[0]||b.length>d[1]?this.format(h.rangeLength,this.formatLabel(c,e),d[0],d[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[c]||h.inlinePattern,this.formatLabel(b,e),c)}}}();return a.each(j,function(b,d){j[d]=a.bind(j[d],a.extend({},c,j))}),e}(b),a.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(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.constructor===Object?d(a,c,e+f+"."):c[e+f]=a)}),c},e=function(){var e=function(b,c){return c=c||a.keys(a.result(b,"validation")||{}),a.reduce(c,function(a,b){return a[b]=void 0,a},{})},g=function(b,c){var d=b.attributes;return a.isFunction(d)?d=d(c):a.isString(d)&&a.isFunction(j[d])&&(d=j[d](c)),a.isArray(d)?d:void 0},h=function(b,c){var d=b.validation?a.result(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:k[a],val:c[a],msg:c.msg})}),b},[])},i=function(b,d,e,f){return a.reduce(h(b,d),function(g,h){var i=a.extend({},c,k),j=h.fn.call(i,e,d,h.val,b,f);return j===!1||g===!1?!1:j&&!g?a.result(h,"msg")||j:g},"")},l=function(b,c,d){var e,f={},g=!0,h=a.clone(c);return a.each(d,function(a,c){e=i(b,c,a,h),e&&(f[c]=e,g=!1)}),{invalidAttrs:f,isValid:g}},m=function(b,c){return{preValidate:function(b,c){var d,e=this,f={};return a.isObject(b)?(a.each(b,function(a,b){d=e.preValidate(b,a),d&&(f[b]=d)}),a.isEmpty(f)?void 0:f):i(this,b,c,a.extend({},this.attributes))},isValid:function(e){var f=d(this.attributes);return e=e||g(c,b),a.isString(e)?!i(this,e,f[e],a.extend({},this.attributes)):a.isArray(e)?a.reduce(e,function(b,c){return b&&!i(this,c,f[c],a.extend({},this.attributes))},!0,this):(e===!0&&this.validate(),this.validation?this._isValid:!0)},validate:function(f,h){var i=this,j=!f,k=a.extend({},c,h),m=e(i,g(c,b)),n=a.extend({},m,i.attributes,f),o=d(n),p=f?d(f):o,q=l(i,n,a.pick(o,a.keys(m)));return i._isValid=q.isValid,a.each(i.associatedViews,function(b){a.each(m,function(a,c){var d=q.invalidAttrs.hasOwnProperty(c),e=p.hasOwnProperty(c);d||k.valid(b,c,k.selector),d&&(e||j)&&k.invalid(b,c,q.invalidAttrs[c],k.selector)})}),a.defer(function(){i.trigger("validated",i._isValid,i,q.invalidAttrs),i.trigger("validated:"+(i._isValid?"valid":"invalid"),i,q.invalidAttrs)}),!k.forceUpdate&&a.intersection(a.keys(q.invalidAttrs),a.keys(p)).length>0?q.invalidAttrs:void 0}}},n=function(b,c,d){c.associatedViews?c.associatedViews.push(b):c.associatedViews=[b],a.extend(c,m(b,d))},o=function(b,c){c&&b.associatedViews.length>1?b.associatedViews=a.without(b.associatedViews,c):(delete b.validate,delete b.preValidate,delete b.isValid,delete b.associatedViews)},p=function(a){n(this.view,a,this.options)},q=function(a){o(a)};return{version:"0.9.1",configure:function(c){a.extend(b,c)},bind:function(c,d){d=a.extend({},b,f,d);var e=d.model||c.model,g=d.collection||c.collection;if("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?n(c,e,d):g&&(g.each(function(a){n(c,a,d)}),g.bind("add",p,{view:c,options:d}),g.bind("remove",q))},unbind:function(b,c){c=a.extend({},c);var d=c.model||b.model,e=c.collection||b.collection;d?o(d,b):e&&(e.each(function(a){o(a,b)}),e.unbind("add",p),e.unbind("remove",q))},mixin:m(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}",digits:"{0} must only contain digits",number:"{0} must be a number",email:"{0} must be a valid email",url:"{0} must be a valid url",inlinePattern:"{0} is invalid"},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.attributeLoaders={inputNames:function(a){var b=[];return a&&a.$("form [name]").each(function(){/^(?:input|select|textarea)$/i.test(this.nodeName)&&this.name&&"submit"!==this.type&&-1===b.indexOf(this.name)&&b.push(this.name)}),b}},k=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(b,c,d,e){return a.isString(b)&&b.length===d?void 0:this.format(h.length,this.formatLabel(c,e),d)},minLength:function(b,c,d,e){return!a.isString(b)||b.length<d?this.format(h.minLength,this.formatLabel(c,e),d):void 0},maxLength:function(b,c,d,e){return!a.isString(b)||b.length>d?this.format(h.maxLength,this.formatLabel(c,e),d):void 0},rangeLength:function(b,c,d,e){return!a.isString(b)||b.length<d[0]||b.length>d[1]?this.format(h.rangeLength,this.formatLabel(c,e),d[0],d[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[c]||h.inlinePattern,this.formatLabel(b,e),c)}}}();return a.each(k,function(b,d){k[d]=a.bind(k[d],a.extend({},c,k))}),e}(b),a.Validation}); |
@@ -1,2 +0,2 @@ | ||
// Backbone.Validation v0.10.1 | ||
// Backbone.Validation v0.11.0 | ||
// | ||
@@ -17,6 +17,6 @@ // Copyright (c) 2011-2015 Thomas Pedersen | ||
'use strict'; | ||
// Default options | ||
// --------------- | ||
var defaultOptions = { | ||
@@ -29,7 +29,7 @@ forceUpdate: false, | ||
}; | ||
// Helper functions | ||
// ---------------- | ||
// Formatting functions used for formatting error messages | ||
@@ -42,3 +42,3 @@ var formatFunctions = { | ||
}, | ||
// Replaces nummeric placeholders like {0} in a string with arguments | ||
@@ -54,3 +54,3 @@ // passed to the function | ||
}; | ||
// Flattens an object | ||
@@ -75,3 +75,3 @@ // eg: | ||
prefix = prefix || ''; | ||
_.each(obj, function(val, key) { | ||
@@ -87,16 +87,17 @@ if(obj.hasOwnProperty(key)) { | ||
}); | ||
return into; | ||
}; | ||
// Validation | ||
// ---------- | ||
var Validation = (function(){ | ||
// Returns an object with undefined properties for all | ||
// attributes on the model that has defined one or more | ||
// validation rules. | ||
var getValidatedAttrs = function(model) { | ||
return _.reduce(_.keys(_.result(model, 'validation') || {}), function(memo, key) { | ||
var getValidatedAttrs = function(model, attrs) { | ||
attrs = attrs || _.keys(_.result(model, 'validation') || {}); | ||
return _.reduce(attrs, function(memo, key) { | ||
memo[key] = void 0; | ||
@@ -106,3 +107,17 @@ return memo; | ||
}; | ||
// Returns an array with attributes passed through options | ||
var getOptionsAttrs = function(options, view) { | ||
var attrs = options.attributes; | ||
if (_.isFunction(attrs)) { | ||
attrs = attrs(view); | ||
} else if (_.isString(attrs) && (_.isFunction(defaultAttributeLoaders[attrs]))) { | ||
attrs = defaultAttributeLoaders[attrs](view); | ||
} | ||
if (_.isArray(attrs)) { | ||
return attrs; | ||
} | ||
}; | ||
// Looks on the model for validations for a specified | ||
@@ -113,3 +128,3 @@ // attribute. Returns an array of any validators defined, | ||
var attrValidationSet = model.validation ? _.result(model, 'validation')[attr] || {} : {}; | ||
// If the validator is a function or a string, wrap it in a function validator | ||
@@ -121,3 +136,3 @@ if (_.isFunction(attrValidationSet) || _.isString(attrValidationSet)) { | ||
} | ||
// Stick the validator object into an array | ||
@@ -127,3 +142,3 @@ if(!_.isArray(attrValidationSet)) { | ||
} | ||
// Reduces the array of validators into a new array with objects | ||
@@ -143,3 +158,3 @@ // with a validation method to call, the value to validate against | ||
}; | ||
// Validates an attribute against all validators defined | ||
@@ -158,3 +173,3 @@ // for that attribute. If one or more errors are found, | ||
result = validator.fn.call(ctx, value, attr, validator.val, model, computed); | ||
if(result === false || memo === false) { | ||
@@ -169,14 +184,13 @@ return false; | ||
}; | ||
// Loops through the model's attributes and validates them all. | ||
// Loops through the model's attributes and validates the specified attrs. | ||
// Returns and object containing names of invalid attributes | ||
// as well as error messages. | ||
var validateModel = function(model, attrs) { | ||
var validateModel = function(model, attrs, validatedAttrs) { | ||
var error, | ||
invalidAttrs = {}, | ||
isValid = true, | ||
computed = _.clone(attrs), | ||
flattened = flatten(attrs); | ||
_.each(flattened, function(val, attr) { | ||
computed = _.clone(attrs); | ||
_.each(validatedAttrs, function(val, attr) { | ||
error = validateAttr(model, attr, val, computed); | ||
@@ -188,3 +202,3 @@ if (error) { | ||
}); | ||
return { | ||
@@ -195,7 +209,7 @@ invalidAttrs: invalidAttrs, | ||
}; | ||
// Contains the methods that are mixed in on the model when binding | ||
var mixin = function(view, options) { | ||
return { | ||
// Check whether or not a value, or a hash of values | ||
@@ -207,3 +221,3 @@ // passes validation without updating the model | ||
error; | ||
if(_.isObject(attr)){ | ||
@@ -216,3 +230,3 @@ _.each(attr, function(value, key) { | ||
}); | ||
return _.isEmpty(result) ? undefined : result; | ||
@@ -224,3 +238,3 @@ } | ||
}, | ||
// Check to see if an attribute, an array of attributes or the | ||
@@ -231,3 +245,5 @@ // entire model is valid. Passing true will force a validation | ||
var flattened = flatten(this.attributes); | ||
option = option || getOptionsAttrs(options, view); | ||
if(_.isString(option)){ | ||
@@ -246,3 +262,3 @@ return !validateAttr(this, option, flattened[option], _.extend({}, this.attributes)); | ||
}, | ||
// This is called by Backbone when it needs to perform validation. | ||
@@ -255,30 +271,28 @@ // You can call it manually without any parameters to validate the | ||
opt = _.extend({}, options, setOptions), | ||
validatedAttrs = getValidatedAttrs(model), | ||
validatedAttrs = getValidatedAttrs(model, getOptionsAttrs(options, view)), | ||
allAttrs = _.extend({}, validatedAttrs, model.attributes, attrs), | ||
changedAttrs = flatten(attrs || allAttrs), | ||
result = validateModel(model, allAttrs); | ||
flattened = flatten(allAttrs), | ||
changedAttrs = attrs ? flatten(attrs) : flattened, | ||
result = validateModel(model, allAttrs, _.pick(flattened, _.keys(validatedAttrs))); | ||
model._isValid = result.isValid; | ||
// After validation is performed, loop through all validated attributes | ||
// and call the valid callbacks so the view is updated. | ||
_.each(validatedAttrs, function(val, attr){ | ||
var invalid = result.invalidAttrs.hasOwnProperty(attr); | ||
if(!invalid){ | ||
opt.valid(view, attr, opt.selector); | ||
} | ||
//After validation is performed, loop through all associated views | ||
_.each(model.associatedViews, function(view){ | ||
// After validation is performed, loop through all validated and changed attributes | ||
// and call the valid and invalid callbacks so the view is updated. | ||
_.each(validatedAttrs, function(val, attr){ | ||
var invalid = result.invalidAttrs.hasOwnProperty(attr), | ||
changed = changedAttrs.hasOwnProperty(attr); | ||
if(!invalid){ | ||
opt.valid(view, attr, opt.selector); | ||
} | ||
if(invalid && (changed || validateAll)){ | ||
opt.invalid(view, attr, result.invalidAttrs[attr], opt.selector); | ||
} | ||
}); | ||
}); | ||
// After validation is performed, loop through all validated and changed attributes | ||
// and call the invalid callback so the view is updated. | ||
_.each(validatedAttrs, function(val, attr){ | ||
var invalid = result.invalidAttrs.hasOwnProperty(attr), | ||
changed = changedAttrs.hasOwnProperty(attr); | ||
if(invalid && (changed || validateAll)){ | ||
opt.invalid(view, attr, result.invalidAttrs[attr], opt.selector); | ||
} | ||
}); | ||
// Trigger validated events. | ||
@@ -291,3 +305,3 @@ // Need to defer this so the model is actually updated before | ||
}); | ||
// Return any error messages to Backbone, unless the forceUpdate flag is set. | ||
@@ -302,15 +316,26 @@ // Then we do not return anything and fools Backbone to believe the validation was | ||
}; | ||
// Helper to mix in validation on a model | ||
// Helper to mix in validation on a model. Stores the view in the associated views array. | ||
var bindModel = function(view, model, options) { | ||
if (model.associatedViews) { | ||
model.associatedViews.push(view); | ||
} else { | ||
model.associatedViews = [view]; | ||
} | ||
_.extend(model, mixin(view, options)); | ||
}; | ||
// Removes the methods added to a model | ||
var unbindModel = function(model) { | ||
delete model.validate; | ||
delete model.preValidate; | ||
delete model.isValid; | ||
// Removes view from associated views of the model or the methods | ||
// added to a model if no view or single view provided | ||
var unbindModel = function(model, view) { | ||
if (view && model.associatedViews.length > 1){ | ||
model.associatedViews = _.without(model.associatedViews, view); | ||
} else { | ||
delete model.validate; | ||
delete model.preValidate; | ||
delete model.isValid; | ||
delete model.associatedViews; | ||
} | ||
}; | ||
// Mix in validation on a model whenever a model is | ||
@@ -321,3 +346,3 @@ // added to a collection | ||
}; | ||
// Remove validation from a model whenever a model is | ||
@@ -328,9 +353,9 @@ // removed from a collection | ||
}; | ||
// Returns the public methods on Backbone.Validation | ||
return { | ||
// Current version of the library | ||
version: '0.9.1', | ||
// Called to configure the default options | ||
@@ -340,3 +365,3 @@ configure: function(options) { | ||
}, | ||
// Hooks up validation on a view with a model | ||
@@ -346,6 +371,6 @@ // or collection | ||
options = _.extend({}, defaultOptions, defaultCallbacks, options); | ||
var model = options.model || view.model, | ||
collection = options.collection || view.collection; | ||
if(typeof model === 'undefined' && typeof collection === 'undefined'){ | ||
@@ -355,3 +380,3 @@ throw 'Before you execute the binding your view must have a model or a collection.\n' + | ||
} | ||
if(model) { | ||
@@ -368,3 +393,3 @@ bindModel(view, model, options); | ||
}, | ||
// Removes validation from a view with a model | ||
@@ -376,9 +401,9 @@ // or collection | ||
collection = options.collection || view.collection; | ||
if(model) { | ||
unbindModel(model); | ||
unbindModel(model, view); | ||
} | ||
else if(collection) { | ||
collection.each(function(model){ | ||
unbindModel(model); | ||
unbindModel(model, view); | ||
}); | ||
@@ -389,3 +414,3 @@ collection.unbind('add', collectionAdd); | ||
}, | ||
// Used to extend the Backbone.Model.prototype | ||
@@ -396,9 +421,9 @@ // with validation | ||
}()); | ||
// Callbacks | ||
// --------- | ||
var defaultCallbacks = Validation.callbacks = { | ||
// Gets called when a previously invalid field in the | ||
@@ -412,3 +437,3 @@ // view becomes valid. Removes any error message. | ||
}, | ||
// Gets called when a field in the view becomes invalid. | ||
@@ -423,25 +448,25 @@ // Adds a error message. | ||
}; | ||
// Patterns | ||
// -------- | ||
var defaultPatterns = Validation.patterns = { | ||
// Matches any digit(s) (i.e. 0-9) | ||
digits: /^\d+$/, | ||
// Matches any number (e.g. 100.000) | ||
number: /^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/, | ||
// Matches a valid email address (e.g. mail@example.com) | ||
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, | ||
// Mathes any valid url (e.g. http://www.xample.com) | ||
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 | ||
}; | ||
// Error messages | ||
// -------------- | ||
// Error message for the build in validators. | ||
@@ -467,6 +492,6 @@ // {x} gets swapped out with arguments form the validator. | ||
}; | ||
// Label formatters | ||
// ---------------- | ||
// Label formatters are used to convert the attribute name | ||
@@ -481,3 +506,3 @@ // to a more human friendly label when using the built in | ||
var defaultLabelFormatters = Validation.labelFormatters = { | ||
// Returns the attribute name with applying any formatting | ||
@@ -487,3 +512,3 @@ none: function(attrName) { | ||
}, | ||
// Converts attributeName or attribute_name to Attribute name | ||
@@ -495,3 +520,3 @@ sentenceCase: function(attrName) { | ||
}, | ||
// Looks for a label configured on the model and returns it | ||
@@ -514,7 +539,24 @@ // | ||
}; | ||
// AttributeLoaders | ||
var defaultAttributeLoaders = Validation.attributeLoaders = { | ||
inputNames: function (view) { | ||
var attrs = []; | ||
if (view) { | ||
view.$('form [name]').each(function () { | ||
if (/^(?:input|select|textarea)$/i.test(this.nodeName) && this.name && | ||
this.type !== 'submit' && attrs.indexOf(this.name) === -1) { | ||
attrs.push(this.name); | ||
} | ||
}); | ||
} | ||
return attrs; | ||
} | ||
}; | ||
// Built in validators | ||
// ------------------- | ||
var defaultValidators = Validation.validators = (function(){ | ||
@@ -529,6 +571,6 @@ // Use native trim when defined | ||
trimRight = /\s+$/; | ||
return text === null ? '' : text.toString().replace(trimLeft, '').replace(trimRight, ''); | ||
}; | ||
// Determines whether or not a value is a number | ||
@@ -538,3 +580,3 @@ var isNumber = function(value){ | ||
}; | ||
// Determines whether or not a value is empty | ||
@@ -544,3 +586,3 @@ var hasValue = function(value) { | ||
}; | ||
return { | ||
@@ -555,3 +597,3 @@ // Function validator | ||
}, | ||
// Required validator | ||
@@ -569,3 +611,3 @@ // Validates if the attribute is required or not | ||
}, | ||
// Acceptance validator | ||
@@ -579,3 +621,3 @@ // Validates that something has to be accepted, e.g. terms of use | ||
}, | ||
// Min validator | ||
@@ -589,3 +631,3 @@ // Validates that the value has to be a number and equal to or greater than | ||
}, | ||
// Max validator | ||
@@ -599,3 +641,3 @@ // Validates that the value has to be a number and equal to or less than | ||
}, | ||
// Range validator | ||
@@ -609,3 +651,3 @@ // Validates that the value has to be a number and equal to or between | ||
}, | ||
// Length validator | ||
@@ -619,3 +661,3 @@ // Validates that the value has to be a string with length equal to | ||
}, | ||
// Min length validator | ||
@@ -629,3 +671,3 @@ // Validates that the value has to be a string with length equal to or greater than | ||
}, | ||
// Max length validator | ||
@@ -639,3 +681,3 @@ // Validates that the value has to be a string with length equal to or less than | ||
}, | ||
// Range length validator | ||
@@ -649,3 +691,3 @@ // Validates that the value has to be a string and equal to or between | ||
}, | ||
// One of validator | ||
@@ -659,3 +701,3 @@ // Validates that the value has to be equal to one of the elements in | ||
}, | ||
// Equal to validator | ||
@@ -669,3 +711,3 @@ // Validates that the value has to be equal to the value of the attribute | ||
}, | ||
// Pattern validator | ||
@@ -681,3 +723,3 @@ // Validates that the value has to match the pattern specified. | ||
}()); | ||
// Set the correct context for all validators | ||
@@ -688,6 +730,6 @@ // when used from within a method validator | ||
}); | ||
return Validation; | ||
}(_)); | ||
return Backbone.Validation; | ||
})); | ||
})); |
@@ -1,2 +0,2 @@ | ||
// Backbone.Validation v0.10.1 | ||
// Backbone.Validation v0.11.0 | ||
// | ||
@@ -8,2 +8,2 @@ // Copyright (c) 2011-2015 Thomas Pedersen | ||
// http://thedersen.com/projects/backbone-validation | ||
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.constructor===Object?d(a,c,e+f+"."):c[e+f]=a)}),c},e=function(){var e=function(b){return a.reduce(a.keys(a.result(b,"validation")||{}),function(a,b){return a[b]=void 0,a},{})},g=function(b,c){var d=b.validation?a.result(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?a.result(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){var d,e=this,f={};return a.isObject(b)?(a.each(b,function(a,b){d=e.preValidate(b,a),d&&(f[b]=d)}),a.isEmpty(f)?void 0:f):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.9.1",configure:function(c){a.extend(b,c)},bind:function(c,d){d=a.extend({},b,f,d);var e=d.model||c.model,g=d.collection||c.collection;if("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(b,c){c=a.extend({},c);var d=c.model||b.model,e=c.collection||b.collection;d?m(d):e&&(e.each(function(a){m(a)}),e.unbind("add",n),e.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}",digits:"{0} must only contain digits",number:"{0} must be a number",email:"{0} must be a valid email",url:"{0} must be a valid url",inlinePattern:"{0} is invalid"},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(b,c,d,e){return a.isString(b)&&b.length===d?void 0:this.format(h.length,this.formatLabel(c,e),d)},minLength:function(b,c,d,e){return!a.isString(b)||b.length<d?this.format(h.minLength,this.formatLabel(c,e),d):void 0},maxLength:function(b,c,d,e){return!a.isString(b)||b.length>d?this.format(h.maxLength,this.formatLabel(c,e),d):void 0},rangeLength:function(b,c,d,e){return!a.isString(b)||b.length<d[0]||b.length>d[1]?this.format(h.rangeLength,this.formatLabel(c,e),d[0],d[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[c]||h.inlinePattern,this.formatLabel(b,e),c)}}}();return a.each(j,function(b,d){j[d]=a.bind(j[d],a.extend({},c,j))}),e}(_); | ||
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.constructor===Object?d(a,c,e+f+"."):c[e+f]=a)}),c},e=function(){var e=function(b,c){return c=c||a.keys(a.result(b,"validation")||{}),a.reduce(c,function(a,b){return a[b]=void 0,a},{})},g=function(b,c){var d=b.attributes;return a.isFunction(d)?d=d(c):a.isString(d)&&a.isFunction(j[d])&&(d=j[d](c)),a.isArray(d)?d:void 0},h=function(b,c){var d=b.validation?a.result(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:k[a],val:c[a],msg:c.msg})}),b},[])},i=function(b,d,e,f){return a.reduce(h(b,d),function(g,h){var i=a.extend({},c,k),j=h.fn.call(i,e,d,h.val,b,f);return j===!1||g===!1?!1:j&&!g?a.result(h,"msg")||j:g},"")},l=function(b,c,d){var e,f={},g=!0,h=a.clone(c);return a.each(d,function(a,c){e=i(b,c,a,h),e&&(f[c]=e,g=!1)}),{invalidAttrs:f,isValid:g}},m=function(b,c){return{preValidate:function(b,c){var d,e=this,f={};return a.isObject(b)?(a.each(b,function(a,b){d=e.preValidate(b,a),d&&(f[b]=d)}),a.isEmpty(f)?void 0:f):i(this,b,c,a.extend({},this.attributes))},isValid:function(e){var f=d(this.attributes);return e=e||g(c,b),a.isString(e)?!i(this,e,f[e],a.extend({},this.attributes)):a.isArray(e)?a.reduce(e,function(b,c){return b&&!i(this,c,f[c],a.extend({},this.attributes))},!0,this):(e===!0&&this.validate(),this.validation?this._isValid:!0)},validate:function(f,h){var i=this,j=!f,k=a.extend({},c,h),m=e(i,g(c,b)),n=a.extend({},m,i.attributes,f),o=d(n),p=f?d(f):o,q=l(i,n,a.pick(o,a.keys(m)));return i._isValid=q.isValid,a.each(i.associatedViews,function(b){a.each(m,function(a,c){var d=q.invalidAttrs.hasOwnProperty(c),e=p.hasOwnProperty(c);d||k.valid(b,c,k.selector),d&&(e||j)&&k.invalid(b,c,q.invalidAttrs[c],k.selector)})}),a.defer(function(){i.trigger("validated",i._isValid,i,q.invalidAttrs),i.trigger("validated:"+(i._isValid?"valid":"invalid"),i,q.invalidAttrs)}),!k.forceUpdate&&a.intersection(a.keys(q.invalidAttrs),a.keys(p)).length>0?q.invalidAttrs:void 0}}},n=function(b,c,d){c.associatedViews?c.associatedViews.push(b):c.associatedViews=[b],a.extend(c,m(b,d))},o=function(b,c){c&&b.associatedViews.length>1?b.associatedViews=a.without(b.associatedViews,c):(delete b.validate,delete b.preValidate,delete b.isValid,delete b.associatedViews)},p=function(a){n(this.view,a,this.options)},q=function(a){o(a)};return{version:"0.9.1",configure:function(c){a.extend(b,c)},bind:function(c,d){d=a.extend({},b,f,d);var e=d.model||c.model,g=d.collection||c.collection;if("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?n(c,e,d):g&&(g.each(function(a){n(c,a,d)}),g.bind("add",p,{view:c,options:d}),g.bind("remove",q))},unbind:function(b,c){c=a.extend({},c);var d=c.model||b.model,e=c.collection||b.collection;d?o(d,b):e&&(e.each(function(a){o(a,b)}),e.unbind("add",p),e.unbind("remove",q))},mixin:m(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}",digits:"{0} must only contain digits",number:"{0} must be a number",email:"{0} must be a valid email",url:"{0} must be a valid url",inlinePattern:"{0} is invalid"},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.attributeLoaders={inputNames:function(a){var b=[];return a&&a.$("form [name]").each(function(){/^(?:input|select|textarea)$/i.test(this.nodeName)&&this.name&&"submit"!==this.type&&-1===b.indexOf(this.name)&&b.push(this.name)}),b}},k=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(b,c,d,e){return a.isString(b)&&b.length===d?void 0:this.format(h.length,this.formatLabel(c,e),d)},minLength:function(b,c,d,e){return!a.isString(b)||b.length<d?this.format(h.minLength,this.formatLabel(c,e),d):void 0},maxLength:function(b,c,d,e){return!a.isString(b)||b.length>d?this.format(h.maxLength,this.formatLabel(c,e),d):void 0},rangeLength:function(b,c,d,e){return!a.isString(b)||b.length<d[0]||b.length>d[1]?this.format(h.rangeLength,this.formatLabel(c,e),d[0],d[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[c]||h.inlinePattern,this.formatLabel(b,e),c)}}}();return a.each(k,function(b,d){k[d]=a.bind(k[d],a.extend({},c,k))}),e}(_); |
@@ -1,2 +0,2 @@ | ||
// Backbone.Validation v0.10.1 | ||
// Backbone.Validation v0.11.0 | ||
// | ||
@@ -87,4 +87,5 @@ // Copyright (c) 2011-2015 Thomas Pedersen | ||
// validation rules. | ||
var getValidatedAttrs = function(model) { | ||
return _.reduce(_.keys(_.result(model, 'validation') || {}), function(memo, key) { | ||
var getValidatedAttrs = function(model, attrs) { | ||
attrs = attrs || _.keys(_.result(model, 'validation') || {}); | ||
return _.reduce(attrs, function(memo, key) { | ||
memo[key] = void 0; | ||
@@ -95,2 +96,16 @@ return memo; | ||
// Returns an array with attributes passed through options | ||
var getOptionsAttrs = function(options, view) { | ||
var attrs = options.attributes; | ||
if (_.isFunction(attrs)) { | ||
attrs = attrs(view); | ||
} else if (_.isString(attrs) && (_.isFunction(defaultAttributeLoaders[attrs]))) { | ||
attrs = defaultAttributeLoaders[attrs](view); | ||
} | ||
if (_.isArray(attrs)) { | ||
return attrs; | ||
} | ||
}; | ||
// Looks on the model for validations for a specified | ||
@@ -153,13 +168,12 @@ // attribute. Returns an array of any validators defined, | ||
// Loops through the model's attributes and validates them all. | ||
// Loops through the model's attributes and validates the specified attrs. | ||
// Returns and object containing names of invalid attributes | ||
// as well as error messages. | ||
var validateModel = function(model, attrs) { | ||
var validateModel = function(model, attrs, validatedAttrs) { | ||
var error, | ||
invalidAttrs = {}, | ||
isValid = true, | ||
computed = _.clone(attrs), | ||
flattened = flatten(attrs); | ||
computed = _.clone(attrs); | ||
_.each(flattened, function(val, attr) { | ||
_.each(validatedAttrs, function(val, attr) { | ||
error = validateAttr(model, attr, val, computed); | ||
@@ -210,2 +224,4 @@ if (error) { | ||
option = option || getOptionsAttrs(options, view); | ||
if(_.isString(option)){ | ||
@@ -232,28 +248,26 @@ return !validateAttr(this, option, flattened[option], _.extend({}, this.attributes)); | ||
opt = _.extend({}, options, setOptions), | ||
validatedAttrs = getValidatedAttrs(model), | ||
validatedAttrs = getValidatedAttrs(model, getOptionsAttrs(options, view)), | ||
allAttrs = _.extend({}, validatedAttrs, model.attributes, attrs), | ||
changedAttrs = flatten(attrs || allAttrs), | ||
flattened = flatten(allAttrs), | ||
changedAttrs = attrs ? flatten(attrs) : flattened, | ||
result = validateModel(model, allAttrs, _.pick(flattened, _.keys(validatedAttrs))); | ||
result = validateModel(model, allAttrs); | ||
model._isValid = result.isValid; | ||
// After validation is performed, loop through all validated attributes | ||
// and call the valid callbacks so the view is updated. | ||
_.each(validatedAttrs, function(val, attr){ | ||
var invalid = result.invalidAttrs.hasOwnProperty(attr); | ||
if(!invalid){ | ||
opt.valid(view, attr, opt.selector); | ||
} | ||
}); | ||
//After validation is performed, loop through all associated views | ||
_.each(model.associatedViews, function(view){ | ||
// After validation is performed, loop through all validated and changed attributes | ||
// and call the invalid callback so the view is updated. | ||
_.each(validatedAttrs, function(val, attr){ | ||
var invalid = result.invalidAttrs.hasOwnProperty(attr), | ||
changed = changedAttrs.hasOwnProperty(attr); | ||
// After validation is performed, loop through all validated and changed attributes | ||
// and call the valid and invalid callbacks so the view is updated. | ||
_.each(validatedAttrs, function(val, attr){ | ||
var invalid = result.invalidAttrs.hasOwnProperty(attr), | ||
changed = changedAttrs.hasOwnProperty(attr); | ||
if(invalid && (changed || validateAll)){ | ||
opt.invalid(view, attr, result.invalidAttrs[attr], opt.selector); | ||
} | ||
if(!invalid){ | ||
opt.valid(view, attr, opt.selector); | ||
} | ||
if(invalid && (changed || validateAll)){ | ||
opt.invalid(view, attr, result.invalidAttrs[attr], opt.selector); | ||
} | ||
}); | ||
}); | ||
@@ -279,12 +293,23 @@ | ||
// Helper to mix in validation on a model | ||
// Helper to mix in validation on a model. Stores the view in the associated views array. | ||
var bindModel = function(view, model, options) { | ||
if (model.associatedViews) { | ||
model.associatedViews.push(view); | ||
} else { | ||
model.associatedViews = [view]; | ||
} | ||
_.extend(model, mixin(view, options)); | ||
}; | ||
// Removes the methods added to a model | ||
var unbindModel = function(model) { | ||
delete model.validate; | ||
delete model.preValidate; | ||
delete model.isValid; | ||
// Removes view from associated views of the model or the methods | ||
// added to a model if no view or single view provided | ||
var unbindModel = function(model, view) { | ||
if (view && model.associatedViews.length > 1){ | ||
model.associatedViews = _.without(model.associatedViews, view); | ||
} else { | ||
delete model.validate; | ||
delete model.preValidate; | ||
delete model.isValid; | ||
delete model.associatedViews; | ||
} | ||
}; | ||
@@ -348,7 +373,7 @@ | ||
if(model) { | ||
unbindModel(model); | ||
unbindModel(model, view); | ||
} | ||
else if(collection) { | ||
collection.each(function(model){ | ||
unbindModel(model); | ||
unbindModel(model, view); | ||
}); | ||
@@ -477,3 +502,20 @@ collection.unbind('add', collectionAdd); | ||
// AttributeLoaders | ||
var defaultAttributeLoaders = Validation.attributeLoaders = { | ||
inputNames: function (view) { | ||
var attrs = []; | ||
if (view) { | ||
view.$('form [name]').each(function () { | ||
if (/^(?:input|select|textarea)$/i.test(this.nodeName) && this.name && | ||
this.type !== 'submit' && attrs.indexOf(this.name) === -1) { | ||
attrs.push(this.name); | ||
} | ||
}); | ||
} | ||
return attrs; | ||
} | ||
}; | ||
// Built in validators | ||
@@ -636,2 +678,2 @@ // ------------------- | ||
return Validation; | ||
}(_)); | ||
}(_)); |
{ | ||
"name": "backbone-validation", | ||
"title": "Backbone.Validation", | ||
"version": "0.10.1", | ||
"version": "0.11.0", | ||
"author": { | ||
@@ -6,0 +6,0 @@ "name": "Thomas Pedersen", |
@@ -190,2 +190,10 @@ # Backbone.Validation [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/thedersen/backbone.validation?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) | ||
### Binding multiple views to same model | ||
It is possible to bind several views to the same model. This is specially useful in UI structures where forms are made with components that share models. | ||
When the model is validated all associated views with attributes from that model will validate its related elements. | ||
It is also possible to unbind each view separately without affecting other bindings. | ||
### Binding to view with a collection | ||
@@ -928,2 +936,6 @@ | ||
#### v0.11.0 [commits](https://github.com/thedersen/backbone.validation/compare/v0.10.0...v0.11.0) | ||
* Support for binding multiple views to same model | ||
#### v0.10.1 [commits](https://github.com/thedersen/backbone.validation/compare/v0.10.0...v0.10.1) | ||
@@ -930,0 +942,0 @@ |
@@ -245,20 +245,18 @@ Backbone.Validation = (function(_){ | ||
// After validation is performed, loop through all validated attributes | ||
// and call the valid callbacks so the view is updated. | ||
_.each(validatedAttrs, function(val, attr){ | ||
var invalid = result.invalidAttrs.hasOwnProperty(attr); | ||
if(!invalid){ | ||
opt.valid(view, attr, opt.selector); | ||
} | ||
}); | ||
//After validation is performed, loop through all associated views | ||
_.each(model.associatedViews, function(view){ | ||
// After validation is performed, loop through all validated and changed attributes | ||
// and call the invalid callback so the view is updated. | ||
_.each(validatedAttrs, function(val, attr){ | ||
var invalid = result.invalidAttrs.hasOwnProperty(attr), | ||
changed = changedAttrs.hasOwnProperty(attr); | ||
// After validation is performed, loop through all validated and changed attributes | ||
// and call the valid and invalid callbacks so the view is updated. | ||
_.each(validatedAttrs, function(val, attr){ | ||
var invalid = result.invalidAttrs.hasOwnProperty(attr), | ||
changed = changedAttrs.hasOwnProperty(attr); | ||
if(invalid && (changed || validateAll)){ | ||
opt.invalid(view, attr, result.invalidAttrs[attr], opt.selector); | ||
} | ||
if(!invalid){ | ||
opt.valid(view, attr, opt.selector); | ||
} | ||
if(invalid && (changed || validateAll)){ | ||
opt.invalid(view, attr, result.invalidAttrs[attr], opt.selector); | ||
} | ||
}); | ||
}); | ||
@@ -284,12 +282,23 @@ | ||
// Helper to mix in validation on a model | ||
// Helper to mix in validation on a model. Stores the view in the associated views array. | ||
var bindModel = function(view, model, options) { | ||
if (model.associatedViews) { | ||
model.associatedViews.push(view); | ||
} else { | ||
model.associatedViews = [view]; | ||
} | ||
_.extend(model, mixin(view, options)); | ||
}; | ||
// Removes the methods added to a model | ||
var unbindModel = function(model) { | ||
delete model.validate; | ||
delete model.preValidate; | ||
delete model.isValid; | ||
// Removes view from associated views of the model or the methods | ||
// added to a model if no view or single view provided | ||
var unbindModel = function(model, view) { | ||
if (view && model.associatedViews.length > 1){ | ||
model.associatedViews = _.without(model.associatedViews, view); | ||
} else { | ||
delete model.validate; | ||
delete model.preValidate; | ||
delete model.isValid; | ||
delete model.associatedViews; | ||
} | ||
}; | ||
@@ -353,7 +362,7 @@ | ||
if(model) { | ||
unbindModel(model); | ||
unbindModel(model, view); | ||
} | ||
else if(collection) { | ||
collection.each(function(model){ | ||
unbindModel(model); | ||
unbindModel(model, view); | ||
}); | ||
@@ -360,0 +369,0 @@ collection.unbind('add', collectionAdd); |
@@ -365,2 +365,93 @@ buster.testCase('Binding to view with model', { | ||
} | ||
}); | ||
buster.testCase('Binding multiple views to same model', { | ||
setUp: function() { | ||
var Model = Backbone.Model.extend({ | ||
validation: { | ||
name: function(val) { | ||
if (!val) { | ||
return 'Name is invalid'; | ||
} | ||
}, | ||
surname: function(val) { | ||
if (!val) { | ||
return 'Surname is invalid'; | ||
} | ||
} | ||
} | ||
}); | ||
var View = Backbone.View.extend({ | ||
initialize: function(data){ | ||
this.attributeName = data.attributeName; | ||
}, | ||
render: function() { | ||
var html = $('<input type="text" name="' + this.attributeName + '" />'); | ||
this.$el.append(html); | ||
Backbone.Validation.bind(this); | ||
} | ||
}); | ||
this.model = new Model(); | ||
this.view1 = new View({ | ||
attributeName: 'name', | ||
model: this.model | ||
}); | ||
this.view2 = new View({ | ||
attributeName: 'surname', | ||
model: this.model | ||
}); | ||
this.view1.render(); | ||
this.view2.render(); | ||
this.name = $(this.view1.$('[name~=name]')); | ||
this.surname = $(this.view2.$('[name~=surname]')); | ||
}, | ||
tearDown: function() { | ||
this.view1.remove(); | ||
}, | ||
"both elements receive invalid class and data-error message when validating the model": function() { | ||
this.model.validate(); | ||
assert(this.name.hasClass('invalid')); | ||
assert(this.surname.hasClass('invalid')); | ||
assert.equals(this.name.data('error'), 'Name is invalid'); | ||
assert.equals(this.surname.data('error'), 'Surname is invalid'); | ||
}, | ||
"each element validates separately": { | ||
setUp: function() { | ||
this.model.set({ | ||
name: 'Rafael' | ||
}); | ||
this.model.validate(); | ||
}, | ||
"first element should not have invalid class": function() { | ||
refute(this.name.hasClass('invalid')); | ||
}, | ||
"second element should have invalid class": function() { | ||
assert(this.surname.hasClass('invalid')); | ||
} | ||
}, | ||
"each view can be unbind separately from the same model": { | ||
setUp: function() { | ||
this.model.set('name', ''); | ||
this.view2.render(); | ||
Backbone.Validation.unbind(this.view2); | ||
this.model.validate(); | ||
}, | ||
"first element is invalid and has class invalid": function() { | ||
refute(this.model.isValid('name')); | ||
assert(this.name.hasClass('invalid')); | ||
}, | ||
"second element is invalid and has not class invalid": function() { | ||
refute(this.model.isValid('surname')); | ||
refute(this.surname.hasClass('invalid')); | ||
} | ||
} | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
873538
20304
1138