sandbox/tmp/cache/assets/D3B/BC0/sprockets%2F19510a763bd1521ff5fc70ffe0d837d3 in iugu-ux-0.9.5 vs sandbox/tmp/cache/assets/D3B/BC0/sprockets%2F19510a763bd1521ff5fc70ffe0d837d3 in iugu-ux-0.9.8

- old
+ new

@@ -1,22 +1,78 @@ -o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1357641141.9059379úã: @value"U{I" -class:EFI"ProcessedAsset;FI"logical_path;FI""vendor/backbone.validation.js;FI" pathname;FI"h/Users/patricknegri/Desenvolvimento/iugu-ux/vendor/assets/javascripts/vendor/backbone.validation.js;FI"content_type;FI"application/javascript;FI" -mtime;FI"2013-01-08T08:29:58-02:00;FI" length;Fi¢QI" digest;F"%6a0996a61128b319cb2de9a8b8e45d4bI" source;FI"¢QBackbone.Validation = (function(_){ +o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1372441614.964292: @value"'d{I" +class:EFI"ProcessedAsset;FI"logical_path;F""vendor/backbone.validation.jsI" pathname;F"h/Users/patricknegri/Desenvolvimento/iugu-ux/vendor/assets/javascripts/vendor/backbone.validation.jsI"content_type;FI"application/javascript;FI" +mtime;FI"2013-06-27T10:44:24-03:00;FI" length;FiÜ`I" digest;F"%fcea25b898b13f1c2232be57c2eefe10I" source;FI"Ü`Backbone.Validation = (function(_){ 'use strict'; // Default options // --------------- var defaultOptions = { - forceUpdate: false, - selector: 'name', - labelFormatter: 'sentenceCase', - valid: Function.prototype, - invalid: Function.prototype + forceUpdate: false, + selector: 'name', + labelFormatter: 'sentenceCase', + valid: Function.prototype, + invalid: Function.prototype }; + // Helper functions + // ---------------- + + // Formatting functions used for formatting error messages + var formatFunctions = { + // Uses the configured label formatter to format the attribute name + // to make it more readable for the user + formatLabel: function(attrName, model) { + return defaultLabelFormatters[defaultOptions.labelFormatter](attrName, model); + }, + + // Replaces nummeric placeholders like {0} in a string with arguments + // passed to the function + format: function() { + var args = Array.prototype.slice.call(arguments), + text = args.shift(); + return text.replace(/\{(\d+)\}/g, function(match, number) { + return typeof args[number] !== 'undefined' ? args[number] : match; + }); + } + }; + + // Flattens an object + // eg: + // + // var o = { + // address: { + // street: 'Street', + // zip: 1234 + // } + // }; + // + // becomes: + // + // var o = { + // 'address.street': 'Street', + // 'address.zip': 1234 + // }; + var flatten = function (obj, into, prefix) { + into = into || {}; + prefix = prefix || ''; + + _.each(obj, function(val, key) { + if(obj.hasOwnProperty(key)) { + if (val && typeof val === 'object' && !(val instanceof Date || val instanceof RegExp || val instanceof Backbone.Collection)) { + flatten(val, into, prefix + key + '.'); + } + else { + into[prefix + key] = val; + } + } + }); + + return into; + }; + // Validation // ---------- var Validation = (function(){ @@ -70,37 +126,64 @@ var validateAttr = function(model, attr, value, computed) { // Reduces the array of validators to an error message by // applying all the validators and returning the first error // message, if any. return _.reduce(getValidators(model, attr), function(memo, validator){ - var result = validator.fn.call(defaultValidators, value, attr, validator.val, model, computed); + // Pass the format functions plus the default + // validators as the context to the validator + var ctx = _.extend({}, formatFunctions, defaultValidators), + result = validator.fn.call(ctx, value, attr, validator.val, model, computed); + if(result === false || memo === false) { return false; } if (result && !memo) { return validator.msg || result; } return memo; }, ''); }; + var validateNestedCollection = function(collection) { + var errors = {}; + + _.each(collection.models, function(model) { + var validatedAttrs = getValidatedAttrs(model); + var allAttrs = _.extend({}, validatedAttrs, model.attributes); + var error = validateModel(model, allAttrs); + + if (!error.isValid) { + errors[model.cid] = error; + } + }); + if (_.isEmpty(errors)) + errors = false; + return errors; + } + // Loops through the model's attributes and validates them all. // Returns and object containing names of invalid attributes // as well as error messages. var validateModel = function(model, attrs) { - var error, attr, + var error, invalidAttrs = {}, isValid = true, - computed = _.clone(attrs); + computed = _.clone(attrs), + flattened = flatten(attrs); - for (attr in attrs) { - error = validateAttr(model, attr, attrs[attr], computed); + _.each(flattened, function(val, attr) { + if(val instanceof Backbone.Collection) { + error = validateNestedCollection(val); + } + else { + error = validateAttr(model, attr, val, computed); + } if (error) { invalidAttrs[attr] = error; isValid = false; } - } + }); return { invalidAttrs: invalidAttrs, isValid: isValid }; @@ -118,52 +201,93 @@ // Check to see if an attribute, an array of attributes or the // entire model is valid. Passing true will force a validation // of the model. isValid: function(option) { + var flattened = flatten(this.attributes); + if(_.isString(option)){ - return !validateAttr(this, option, this.get(option), _.extend({}, this.attributes)); + return !validateAttr(this, option, flattened[option], _.extend({}, this.attributes)); } if(_.isArray(option)){ - for (var i = 0; i < option.length; i++) { - if(validateAttr(this, option[i], this.get(option[i]), _.extend({}, this.attributes))){ - return false; - } - } - return true; + return _.reduce(option, function(memo, attr) { + return memo && !validateAttr(this, attr, flattened[attr], _.extend({}, this.attributes)); + }, true, this); } if(option === true) { this.validate(); } return this.validation ? this._isValid : true; }, + callNestedValidForCollection: function(attribute, collection, opt, result) { + _.each(collection.models, function(model) { + var nestedValidatedAttrs = getValidatedAttrs(model); + _.each(nestedValidatedAttrs, function(error, attr) { + _.each(result, function(res, cid) { + var invalid = res.hasOwnProperty(attr); + if(!invalid) { + opt.valid(view, attribute + '.' + attr, opt.selector, cid); + } + }); + }); + }); + }, + + callNestedInvalidForCollection: function(attribute, collection, opt, result) { + _.each(collection.models, function(model) { + var nestedValidatedAttrs = getValidatedAttrs(model); + _.each(nestedValidatedAttrs, function(error, attr) { + _.each(result, function(res, cid) { + var invalid = res.invalidAttrs.hasOwnProperty(attr); + if(invalid) { + opt.invalid(view, attribute + '.' + attr, res.invalidAttrs[attr], opt.selector, cid); + } + }); + }); + }); + }, + // This is called by Backbone when it needs to perform validation. // You can call it manually without any parameters to validate the // entire model. validate: function(attrs, setOptions){ var model = this, validateAll = !attrs, opt = _.extend({}, options, setOptions), - allAttrs = _.extend(getValidatedAttrs(model), model.attributes, attrs), - changedAttrs = attrs || allAttrs, + validatedAttrs = getValidatedAttrs(model), + allAttrs = _.extend({}, validatedAttrs, model.attributes, attrs), + changedAttrs = flatten(attrs || allAttrs), + result = validateModel(model, allAttrs); model._isValid = result.isValid; // After validation is performed, loop through all changed attributes - // and call either the valid or invalid callback so the view is updated. - for(var attr in allAttrs) { + // 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, null); + } else if(changedAttrs[attr] instanceof Backbone.Collection) { + model.callNestedValidForCollection(attr, changedAttrs[attr], opt, result.invalidAttrs[attr]); + } + }); + + // After validation is performed, loop through all 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)){ + + if(invalid && changedAttrs[attr] instanceof Backbone.Collection) { + model.callNestedInvalidForCollection(attr, changedAttrs[attr], opt, result.invalidAttrs[attr]); + } + else if(invalid && (changed || validateAll)){ opt.invalid(view, attr, result.invalidAttrs[attr], opt.selector); } - if(!invalid){ - opt.valid(view, attr, opt.selector); - } - } + }); // Trigger validated events. // Need to defer this so the model is actually updated before // the event is triggered. _.defer(function() { @@ -207,11 +331,11 @@ // Returns the public methods on Backbone.Validation return { // Current version of the library - version: '0.6.2', + version: '0.7.1', // Called to configure the default options configure: function(options) { _.extend(defaultOptions, options); }, @@ -219,21 +343,22 @@ // Hooks up validation on a view with a model // or collection bind: function(view, options) { var model = view.model, collection = view.collection; + options = _.extend({}, defaultOptions, defaultCallbacks, options); if(typeof model === 'undefined' && typeof collection === 'undefined'){ throw 'Before you execute the binding your view must have a model or a collection.\n' + 'See http://thedersen.com/projects/backbone-validation/#using-form-model-validation for more information.'; } if(model) { bindModel(view, model, options); } - if(collection) { + else if(collection) { collection.each(function(model){ bindModel(view, model, options); }); collection.bind('add', collectionAdd, {view: view, options: options}); collection.bind('remove', collectionRemove); @@ -271,21 +396,27 @@ var defaultCallbacks = Validation.callbacks = { // Gets called when a previously invalid field in the // view becomes valid. Removes any error message. // Should be overridden with custom functionality. - valid: function(view, attr, selector) { - view.$('[' + selector + '~=' + attr + ']') + valid: function(view, attr, selector, cid) { + var sel = '[' + selector + '~="' + attr + '"]'; + if (cid) + sel = sel + '[cid="' + cid + '"]'; + view.$(sel) .removeClass('invalid') .removeAttr('data-error'); }, // Gets called when a field in the view becomes invalid. // Adds a error message. // Should be overridden with custom functionality. - invalid: function(view, attr, error, selector) { - view.$('[' + selector + '~=' + attr + ']') + invalid: function(view, attr, error, selector, cid) { + var sel = '[' + selector + '~="' + attr + '"]'; + if (cid) + sel = sel + '[cid="' + cid + '"]'; + view.$(sel) .addClass('invalid') .attr('data-error', error); } }; @@ -365,46 +496,31 @@ // labels: { // someAttribute: 'Custom label' // } // }); label: function(attrName, model) { - return model.labels[attrName] || defaultLabelFormatters.sentenceCase(attrName, model); + return (model.labels && model.labels[attrName]) || defaultLabelFormatters.sentenceCase(attrName, model); } }; + // Built in validators // ------------------- var defaultValidators = Validation.validators = (function(){ // Use native trim when defined var trim = String.prototype.trim ? - function(text) { - return text === null ? '' : String.prototype.trim.call(text); - } : - function(text) { - var trimLeft = /^\s+/, - trimRight = /\s+$/; + function(text) { + return text === null ? '' : String.prototype.trim.call(text); + } : + function(text) { + var trimLeft = /^\s+/, + trimRight = /\s+$/; - return text === null ? '' : text.toString().replace(trimLeft, '').replace(trimRight, ''); - }; + return text === null ? '' : text.toString().replace(trimLeft, '').replace(trimRight, ''); + }; - // Uses the configured label formatter to format the attribute name - // to make it more readable for the user - var formatLabel = function(attrName, model) { - return defaultLabelFormatters[defaultOptions.labelFormatter](attrName, model); - }; - - // Replaces nummeric placeholders like {0} in a string with arguments - // passed to the function - var format = function() { - var args = Array.prototype.slice.call(arguments); - var text = args.shift(); - return text.replace(/\{(\d+)\}/g, function(match, number) { - return typeof args[number] !== 'undefined' ? args[number] : match; - }); - }; - // Determines whether or not a value is a number var isNumber = function(value){ return _.isNumber(value) || (_.isString(value) && value.match(defaultPatterns.number)); }; @@ -429,114 +545,114 @@ var isRequired = _.isFunction(required) ? required.call(model, value, attr, computed) : required; if(!isRequired && !hasValue(value)) { return false; // overrides all other validators } if (isRequired && !hasValue(value)) { - return format(defaultMessages.required, formatLabel(attr, model)); + return this.format(defaultMessages.required, this.formatLabel(attr, model)); } }, // Acceptance validator // Validates that something has to be accepted, e.g. terms of use // `true` or 'true' are valid acceptance: function(value, attr, accept, model) { if(value !== 'true' && (!_.isBoolean(value) || value === false)) { - return format(defaultMessages.acceptance, formatLabel(attr, model)); + return this.format(defaultMessages.acceptance, this.formatLabel(attr, model)); } }, // Min validator // Validates that the value has to be a number and equal to or greater than // the min value specified min: function(value, attr, minValue, model) { if (!isNumber(value) || value < minValue) { - return format(defaultMessages.min, formatLabel(attr, model), minValue); + return this.format(defaultMessages.min, this.formatLabel(attr, model), minValue); } }, // Max validator // Validates that the value has to be a number and equal to or less than // the max value specified max: function(value, attr, maxValue, model) { if (!isNumber(value) || value > maxValue) { - return format(defaultMessages.max, formatLabel(attr, model), maxValue); + return this.format(defaultMessages.max, this.formatLabel(attr, model), maxValue); } }, // Range validator // Validates that the value has to be a number and equal to or between // the two numbers specified range: function(value, attr, range, model) { if(!isNumber(value) || value < range[0] || value > range[1]) { - return format(defaultMessages.range, formatLabel(attr, model), range[0], range[1]); + return this.format(defaultMessages.range, this.formatLabel(attr, model), range[0], range[1]); } }, // Length validator // Validates that the value has to be a string with length equal to // the length value specified length: function(value, attr, length, model) { if (!hasValue(value) || trim(value).length !== length) { - return format(defaultMessages.length, formatLabel(attr, model), length); + return this.format(defaultMessages.length, this.formatLabel(attr, model), length); } }, // Min length validator // Validates that the value has to be a string with length equal to or greater than // the min length value specified minLength: function(value, attr, minLength, model) { if (!hasValue(value) || trim(value).length < minLength) { - return format(defaultMessages.minLength, formatLabel(attr, model), minLength); + return this.format(defaultMessages.minLength, this.formatLabel(attr, model), minLength); } }, // Max length validator // Validates that the value has to be a string with length equal to or less than // the max length value specified maxLength: function(value, attr, maxLength, model) { if (!hasValue(value) || trim(value).length > maxLength) { - return format(defaultMessages.maxLength, formatLabel(attr, model), maxLength); + return this.format(defaultMessages.maxLength, this.formatLabel(attr, model), maxLength); } }, // Range length validator // Validates that the value has to be a string and equal to or between // the two numbers specified rangeLength: function(value, attr, range, model) { if(!hasValue(value) || trim(value).length < range[0] || trim(value).length > range[1]) { - return format(defaultMessages.rangeLength, formatLabel(attr, model), range[0], range[1]); + return this.format(defaultMessages.rangeLength, this.formatLabel(attr, model), range[0], range[1]); } }, // One of validator // Validates that the value has to be equal to one of the elements in // the specified array. Case sensitive matching oneOf: function(value, attr, values, model) { if(!_.include(values, value)){ - return format(defaultMessages.oneOf, formatLabel(attr, model), values.join(', ')); + return this.format(defaultMessages.oneOf, this.formatLabel(attr, model), values.join(', ')); } }, // Equal to validator // Validates that the value has to be equal to the value of the attribute // with the name specified equalTo: function(value, attr, equalTo, model, computed) { if(value !== computed[equalTo]) { - return format(defaultMessages.equalTo, formatLabel(attr, model), formatLabel(equalTo, model)); + return this.format(defaultMessages.equalTo, this.formatLabel(attr, model), this.formatLabel(equalTo, model)); } }, // Pattern validator // Validates that the value has to match the pattern specified. // Can be a regular expression or the name of one of the built in patterns pattern: function(value, attr, pattern, model) { if (!hasValue(value) || !value.toString().match(defaultPatterns[pattern] || pattern)) { - return format(defaultMessages.pattern, formatLabel(attr, model), pattern); + return this.format(defaultMessages.pattern, this.formatLabel(attr, model), pattern); } } }; }()); return Validation; }(_)); -;FI"dependency_digest;F"%15825a9714bafdf3c5e831a7dd1ba91eI"required_paths;F[I"h/Users/patricknegri/Desenvolvimento/iugu-ux/vendor/assets/javascripts/vendor/backbone.validation.js;FI"dependency_paths;F[{I" path;FI"h/Users/patricknegri/Desenvolvimento/iugu-ux/vendor/assets/javascripts/vendor/backbone.validation.js;FI" -mtime;FI"2013-01-08T08:29:58-02:00;FI" digest;F"%6a0996a61128b319cb2de9a8b8e45d4bI" _version;F"%9f3b95dd7ea3030dc35985c0a8020862 +;FI"dependency_digest;F"%61f3fca940453d6b3f4f8fee9615d1feI"required_paths;F["h/Users/patricknegri/Desenvolvimento/iugu-ux/vendor/assets/javascripts/vendor/backbone.validation.jsI"dependency_paths;F[{I" path;F"h/Users/patricknegri/Desenvolvimento/iugu-ux/vendor/assets/javascripts/vendor/backbone.validation.jsI" +mtime;FI"2013-06-27T10:44:24-03:00;FI" digest;F"%fcea25b898b13f1c2232be57c2eefe10I" _version;F"%6776f581a4329e299531e1d52aa59832 \ No newline at end of file