1 rio.Form = { 2 3 build: function(options) { 4 var attributes = options.attributes || {}; 5 var attr = rio.Attr.create({ 6 attrAccessors: Object.keys(attributes), 7 methods: { 8 reset: function() { 9 Object.keys(attributes).each(function(attribute) { 10 var initialValue = attributes[attribute].initialValue || ""; 11 initialValue = initialValue.constructor == rio.Binding ? initialValue.value() : initialValue; 12 this[attribute].update(initialValue || ""); 13 this.errors[attribute].update(""); 14 }.bind(this)); 15 }, 16 17 values: function() { 18 var values = {}; 19 Object.keys(attributes).each(function(attribute) { 20 values[attribute] = this[attribute].value(); 21 }.bind(this)); 22 return values; 23 }, 24 25 commit: function() { 26 if (this.valid()) { 27 (options.onCommit || Prototype.emptyFunction)(this.values()); 28 } 29 }, 30 31 errorsFor: function(field) { 32 return this.errors[field]; 33 }, 34 35 valid: function() { 36 return this.validate(); 37 }, 38 39 validate: function() { 40 var valid = true; 41 Object.keys(attributes).each(function(attribute) { 42 var errorMessage = ""; 43 (attributes[attribute].validates || []).uniq().each(function(validate) { 44 var newErrorMessage = ""; 45 if (Object.isString(validate)) { 46 newErrorMessage = rio.Validators[validate](this[attribute].value()); 47 } else if (Object.isArray(validate)) { 48 newErrorMessage = rio.Validators[validate[0]](this[attribute].value(), validate[1]); 49 } else { 50 newErrorMessage = validate(this.values()); 51 } 52 53 if (!(newErrorMessage || "").blank()) { 54 valid = false; 55 errorMessage = newErrorMessage; 56 } 57 }.bind(this)); 58 59 this.errors[attribute].update(errorMessage); 60 }.bind(this)); 61 return valid; 62 } 63 } 64 }); 65 var form = new attr(); 66 67 68 var errorAttr = rio.Attr.create({ 69 attrAccessors: Object.keys(attributes).map(function(attribute) { return [attribute, ""]; }) 70 }); 71 form.errors = new errorAttr(); 72 form.reset(); 73 74 Object.keys(attributes).each(function(attribute) { 75 form[attribute].bind(form.validate.bind(form), true); 76 }); 77 78 79 return form; 80 } 81 82 83 }; 84 rio.Form.toString = function() { return "Form"; }; 85 86 rio.Validators = { 87 email: function(value) { 88 return value.validEmail() ? "" : "not a valid email address"; 89 }, 90 91 presence: function(value) { 92 return value && !value.blank() ? "" : "cannot be blank"; 93 }, 94 95 length: function(value, options) { 96 var blank = value == undefined || value.blank(); 97 98 if (options.allowBlank && blank) { return ""; } 99 100 if (blank) { return this.presence(value); } 101 102 if (options.minimum && value.length < options.minimum) { 103 return "must be at least " + options.minimum + " characters long"; 104 } 105 if (options.maximum && value.length > options.maximum) { 106 return "can't be more than " + options.maximum + " characters long"; 107 } 108 109 return ""; 110 }, 111 112 toString: function() { return "Validators"; } 113 };