(function() { var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; this.BackboneValidate = (function() { function BackboneValidate(attrs1, validations, model1) { this.attrs = attrs1; this.validations = validations; this.model = model1; this.validate = bind(this.validate, this); this.errors = {}; } BackboneValidate.prototype.validate = function() { var errorsKey, fieldDetails, fieldErrors, fieldName, fieldValidations, i, index, len, ref, ref1, value; if (this.validations != null) { ref = this.validations; for (fieldName in ref) { fieldValidations = ref[fieldName]; fieldDetails = this.parseName(fieldName); if (fieldDetails == null) { continue; } if (_.isArray(fieldDetails.value)) { ref1 = fieldDetails.value; for (index = i = 0, len = ref1.length; i < len; index = ++i) { value = ref1[index]; fieldErrors = this.applyValidations(value, fieldValidations); errorsKey = fieldDetails.fullName.replace(/\[\]/, "[" + index + "]"); if (!_.isEmpty(fieldErrors)) { this.errors[errorsKey] = fieldErrors; } } } else { fieldErrors = this.applyValidations(fieldDetails.value, fieldValidations); if (!_.isEmpty(fieldErrors)) { this.errors[fieldDetails.fullName] = fieldErrors; } } } if (!_.isEmpty(this.errors)) { return this.errors; } } }; BackboneValidate.prototype.parseName = function(name) { var fullName, i, index, len, ref, t, tokens, value; if (/(\.?\w+\[\]){2,}/.test(name)) { throw new Error('Backbone.Validate: Nested arrays not supported'); } if (/\[\](\.\w+){2,}/.test(name)) { throw new Error('Backbone.Validate: Nesting within an array not supported'); } fullName = name; index = (ref = /\[(\d*)\]/.exec(fullName)) != null ? ref[1] : void 0; tokens = name.split('.'); value = null; for (i = 0, len = tokens.length; i < len; i++) { t = tokens[i]; name = t.replace(/\[(\d+)?\]$/, ''); value = value == null ? this.attrs[name] : _.isArray(value) ? _.map(value, name) : value[name]; } if ((index != null) && index.length > 0 && (value != null)) { value = value[index]; } return { name: name, fullName: fullName, value: value }; }; BackboneValidate.prototype.applyValidations = function(value, fieldValidations) { var args, error, fieldErrors, option, validationName; fieldErrors = {}; for (validationName in fieldValidations) { option = fieldValidations[validationName]; args = (option === true ? [] : [option]).concat([value, this.attrs, this.model]); error = BackboneValidate.validators[validationName].apply(BackboneValidate.validators, args); if (error) { fieldErrors[validationName] = this.getDisplayMessage(error, validationName, option); } } return fieldErrors; }; BackboneValidate.validators = { hasValue: function(value) { return (value != null) && $.trim(value).length !== 0; }, required: function(value, attrs) { return !this.hasValue(value); }, min: function(minValue, value, attrs) { if (this.hasValue(value) && value < minValue) { return true; } }, max: function(maxValue, value, attrs) { if (this.hasValue(value) && value > maxValue) { return true; } }, range: function(limits, value, attrs) { return this.hasValue(value) && !((limits[0] <= value && value <= limits[1])); }, pattern: function(expr, value, attrs) { if (this.hasValue(value) && !expr.test(value)) { return true; } else { return false; } }, email: function(value, attrs) { if (/[\u00E0-\u00FC]+/i.test(value)) { return true; } return this.pattern(BackboneValidate.patterns.email, value, attrs); }, url: function(value, attrs) { return this.pattern(BackboneValidate.patterns.url, value, attrs); }, custom: function(fn, value, attrs, model) { return fn.call(model, value, attrs); }, maxLength: function(maxLength, value, attrs) { if (!this.hasValue(value)) { return false; } return value.toString().length > maxLength; }, minLength: function(minLength, value, attrs) { if (!this.hasValue(value)) { return false; } return value.toString().length < minLength; }, lengthRange: function(range, value, attrs) { if (!this.hasValue(value)) { return true; } return range[0] > value.toString().length || range[1] < value.toString().length; } }; BackboneValidate.patterns = { 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 }; BackboneValidate.messages = { required: 'is required', min: 'must be greater than or equal to {{min}}', max: 'must be less than or equal to {{max}}', range: 'must be between {{0}} and {{1}}', minLength: 'length must be greater than or equal to {{minLength}}', maxLength: 'length must be less than or equal to {{maxLength}}', lengthRange: 'length must be between {{0}} and {{1}}', pattern: 'must match {{pattern}}', email: 'must be a well-formed email address', url: 'must be a well-formed URL', past: 'must be a past date', future: 'must be a future date' }; BackboneValidate.prototype.getDisplayMessage = function(error, validationName, option) { if (_.isString(error)) { return this.getMessage(error) || error; } else { return this.getMessage(validationName, option); } }; BackboneValidate.prototype.getMessage = function(validationName, option) { var key, msg, value; msg = BackboneValidate.messages[validationName]; if (!msg) { return false; } if (!option) { return msg; } if (_.isObject(option) && !_.isRegExp(option)) { for (key in option) { value = option[key]; msg = msg.replace("{{" + key + "}}", value); } return msg; } else { return msg.replace("{{" + validationName + "}}", option); } }; return BackboneValidate; })(); if (typeof Backbone !== "undefined" && Backbone !== null) { Backbone.Model.prototype.validate = function(attrs, options) { return new BackboneValidate(attrs, this.validations, this).validate(); }; } }).call(this);