livevalidation 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1 @@
1
+ pkg/
@@ -0,0 +1,21 @@
1
+ LiveValidation is a plugin which allows automatic integration of your Rails application with Javascript library [LiveValidation](http://www.livevalidation.com/). This library implements client-side form validation and you can see a demo in its site.
2
+
3
+ ## Important note
4
+
5
+ This plugin is no longer mantained, and may not work with the newest versions of Rails. I suggest you to use one of the more updated [forks](http://github.com/porras/livevalidation/network).
6
+
7
+ ## Author
8
+
9
+ [Sergio Gil](http://twitter.com/porras)
10
+
11
+ ## License
12
+
13
+ LiveValidation is licensed under the terms of the [MIT License](http://www.opensource.org/licenses/mit-license.php).
14
+
15
+ Copyright (c) 2007 Sergio Gil
16
+
17
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
18
+
19
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
20
+
21
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,35 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the live_validation plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.pattern = 'test/**/*_test.rb'
12
+ t.verbose = true
13
+ end
14
+
15
+ desc 'Generate documentation for the live_validation plugin.'
16
+ Rake::RDocTask.new(:rdoc) do |rdoc|
17
+ rdoc.rdoc_dir = 'rdoc'
18
+ rdoc.title = 'LiveValidation'
19
+ rdoc.options << '--line-numbers' << '--inline-source'
20
+ rdoc.rdoc_files.include('README')
21
+ rdoc.rdoc_files.include('lib/**/*.rb')
22
+ end
23
+
24
+ begin
25
+ require 'jeweler'
26
+ Jeweler::Tasks.new do |gemspec|
27
+ gemspec.name = "livevalidation"
28
+ gemspec.summary = "Easy client side validation for your ActiveRecord models"
29
+ gemspec.email = "sgilperez@gmail.com"
30
+ gemspec.homepage = "http://github.com/porras/livevalidation"
31
+ gemspec.description = "Easy client side validation for your ActiveRecord models"
32
+ gemspec.authors = ["Sergio Gil"]
33
+ end
34
+ rescue LoadError
35
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,4 @@
1
+ // LiveValidation 1.3 (prototype.js version)
2
+ // Copyright (c) 2007-2008 Alec Hill (www.livevalidation.com)
3
+ // LiveValidation is licensed under the terms of the MIT License
4
+ var LiveValidation=Class.create();Object.extend(LiveValidation,{VERSION:"1.3 prototype",TEXTAREA:1,TEXT:2,PASSWORD:3,CHECKBOX:4,SELECT:5,FILE:6,massValidate:function(C){var D=true;for(var B=0,A=C.length;B<A;++B){var E=C[B].validate();if(D){D=E;}}return D;}});LiveValidation.prototype={validClass:"LV_valid",invalidClass:"LV_invalid",messageClass:"LV_validation_message",validFieldClass:"LV_valid_field",invalidFieldClass:"LV_invalid_field",initialize:function(B,A){if(!B){throw new Error("LiveValidation::initialize - No element reference or element id has been provided!");}this.element=$(B);if(!this.element){throw new Error("LiveValidation::initialize - No element with reference or id of '"+B+"' exists!");}this.elementType=this.getElementType();this.validations=[];this.form=this.element.form;this.options=Object.extend({validMessage:"Thankyou!",onValid:function(){this.insertMessage(this.createMessageSpan());this.addFieldClass();},onInvalid:function(){this.insertMessage(this.createMessageSpan());this.addFieldClass();},insertAfterWhatNode:this.element,onlyOnBlur:false,wait:0,onlyOnSubmit:false},A||{});var C=this.options.insertAfterWhatNode||this.element;this.options.insertAfterWhatNode=$(C);Object.extend(this,this.options);if(this.form){this.formObj=LiveValidationForm.getInstance(this.form);this.formObj.addField(this);}this.boundFocus=this.doOnFocus.bindAsEventListener(this);Event.observe(this.element,"focus",this.boundFocus);if(!this.onlyOnSubmit){switch(this.elementType){case LiveValidation.CHECKBOX:this.boundClick=this.validate.bindAsEventListener(this);Event.observe(this.element,"click",this.boundClick);case LiveValidation.SELECT:case LiveValidation.FILE:this.boundChange=this.validate.bindAsEventListener(this);Event.observe(this.element,"change",this.boundChange);break;default:if(!this.onlyOnBlur){this.boundKeyup=this.deferValidation.bindAsEventListener(this);Event.observe(this.element,"keyup",this.boundKeyup);}this.boundBlur=this.validate.bindAsEventListener(this);Event.observe(this.element,"blur",this.boundBlur);}}},destroy:function(){if(this.formObj){this.formObj.removeField(this);this.formObj.destroy();}Event.stopObserving(this.element,"focus",this.boundFocus);if(!this.onlyOnSubmit){switch(this.elementType){case LiveValidation.CHECKBOX:Event.stopObserving(this.element,"click",this.boundClick);case LiveValidation.SELECT:case LiveValidation.FILE:Event.stopObserving(this.element,"change",this.boundChange);break;default:if(!this.onlyOnBlur){Event.stopObserving(this.element,"keyup",this.boundKeyup);}Event.stopObserving(this.element,"blur",this.boundBlur);}}this.validations=[];this.removeMessageAndFieldClass();},add:function(A,B){this.validations.push({type:A,params:B||{}});return this;},remove:function(A,B){this.validations=this.validations.reject(function(C){return(C.type==A&&C.params==B);});return this;},deferValidation:function(A){if(this.wait>=300){this.removeMessageAndFieldClass();}if(this.timeout){clearTimeout(this.timeout);}this.timeout=setTimeout(this.validate.bind(this),this.wait);},doOnBlur:function(){this.focused=false;this.validate();},doOnFocus:function(){this.focused=true;this.removeMessageAndFieldClass();},getElementType:function(){switch(true){case (this.element.nodeName.toUpperCase()=="TEXTAREA"):return LiveValidation.TEXTAREA;case (this.element.nodeName.toUpperCase()=="INPUT"&&this.element.type.toUpperCase()=="TEXT"):return LiveValidation.TEXT;case (this.element.nodeName.toUpperCase()=="INPUT"&&this.element.type.toUpperCase()=="PASSWORD"):return LiveValidation.PASSWORD;case (this.element.nodeName.toUpperCase()=="INPUT"&&this.element.type.toUpperCase()=="CHECKBOX"):return LiveValidation.CHECKBOX;case (this.element.nodeName.toUpperCase()=="INPUT"&&this.element.type.toUpperCase()=="FILE"):return LiveValidation.FILE;case (this.element.nodeName.toUpperCase()=="SELECT"):return LiveValidation.SELECT;case (this.element.nodeName.toUpperCase()=="INPUT"):throw new Error("LiveValidation::getElementType - Cannot use LiveValidation on an "+this.element.type+" input!");default:throw new Error("LiveValidation::getElementType - Element must be an input, select, or textarea!");}},doValidations:function(){this.validationFailed=false;for(var C=0,A=this.validations.length;C<A;++C){var B=this.validations[C];switch(B.type){case Validate.Presence:case Validate.Confirmation:case Validate.Acceptance:this.displayMessageWhenEmpty=true;this.validationFailed=!this.validateElement(B.type,B.params);break;default:this.validationFailed=!this.validateElement(B.type,B.params);break;}if(this.validationFailed){return false;}}this.message=this.validMessage;return true;},validateElement:function(A,C){var D=(this.elementType==LiveValidation.SELECT)?this.element.options[this.element.selectedIndex].value:this.element.value;if(A==Validate.Acceptance){if(this.elementType!=LiveValidation.CHECKBOX){throw new Error("LiveValidation::validateElement - Element to validate acceptance must be a checkbox!");}D=this.element.checked;}var E=true;try{A(D,C);}catch(B){if(B instanceof Validate.Error){if(D!==""||(D===""&&this.displayMessageWhenEmpty)){this.validationFailed=true;this.message=B.message;E=false;}}else{throw B;}}finally{return E;}},validate:function(){if(!this.element.disabled){var A=this.doValidations();if(A){this.onValid();return true;}else{this.onInvalid();return false;}}else{return true;}},enable:function(){this.element.disabled=false;return this;},disable:function(){this.element.disabled=true;this.removeMessageAndFieldClass();return this;},createMessageSpan:function(){var A=document.createElement("span");var B=document.createTextNode(this.message);A.appendChild(B);return A;},insertMessage:function(B){this.removeMessage();var A=this.validationFailed?this.invalidClass:this.validClass;if((this.displayMessageWhenEmpty&&(this.elementType==LiveValidation.CHECKBOX||this.element.value==""))||this.element.value!=""){$(B).addClassName(this.messageClass+(" "+A));if(nxtSibling=this.insertAfterWhatNode.nextSibling){this.insertAfterWhatNode.parentNode.insertBefore(B,nxtSibling);}else{this.insertAfterWhatNode.parentNode.appendChild(B);}}},addFieldClass:function(){this.removeFieldClass();if(!this.validationFailed){if(this.displayMessageWhenEmpty||this.element.value!=""){if(!this.element.hasClassName(this.validFieldClass)){this.element.addClassName(this.validFieldClass);}}}else{if(!this.element.hasClassName(this.invalidFieldClass)){this.element.addClassName(this.invalidFieldClass);}}},removeMessage:function(){if(nxtEl=this.insertAfterWhatNode.next("."+this.messageClass)){nxtEl.remove();}},removeFieldClass:function(){this.element.removeClassName(this.invalidFieldClass);this.element.removeClassName(this.validFieldClass);},removeMessageAndFieldClass:function(){this.removeMessage();this.removeFieldClass();}};var LiveValidationForm=Class.create();Object.extend(LiveValidationForm,{instances:{},getInstance:function(A){var B=Math.random()*Math.random();if(!A.id){A.id="formId_"+B.toString().replace(/\./,"")+new Date().valueOf();}if(!LiveValidationForm.instances[A.id]){LiveValidationForm.instances[A.id]=new LiveValidationForm(A);}return LiveValidationForm.instances[A.id];}});LiveValidationForm.prototype={initialize:function(A){this.element=$(A);this.fields=[];this.oldOnSubmit=this.element.onsubmit||function(){};this.element.onsubmit=function(C){var B=(LiveValidation.massValidate(this.fields))?this.oldOnSubmit.call(this.element,C)!==false:false;if(!B){Event.stop(C);}}.bindAsEventListener(this);},addField:function(A){this.fields.push(A);},removeField:function(A){this.fields=this.fields.without(A);},destroy:function(A){if(this.fields.length!=0&&!A){return false;}this.element.onsubmit=this.oldOnSubmit;LiveValidationForm.instances[this.element.id]=null;return true;}};var Validate={Presence:function(A,B){var C=Object.extend({failureMessage:"Can't be empty!"},B||{});if(A===""||A===null||A===undefined){Validate.fail(C.failureMessage);}return true;},Numericality:function(B,C){var A=B;var B=Number(B);var C=C||{};var D={notANumberMessage:C.notANumberMessage||"Must be a number!",notAnIntegerMessage:C.notAnIntegerMessage||"Must be an integer!",wrongNumberMessage:C.wrongNumberMessage||"Must be "+C.is+"!",tooLowMessage:C.tooLowMessage||"Must not be less than "+C.minimum+"!",tooHighMessage:C.tooHighMessage||"Must not be more than "+C.maximum+"!",is:((C.is)||(C.is==0))?C.is:null,minimum:((C.minimum)||(C.minimum==0))?C.minimum:null,maximum:((C.maximum)||(C.maximum==0))?C.maximum:null,onlyInteger:C.onlyInteger||false};if(!isFinite(B)){Validate.fail(D.notANumberMessage);}if(D.onlyInteger&&((/\.0+$|\.$/.test(String(A)))||(B!=parseInt(B)))){Validate.fail(D.notAnIntegerMessage);}switch(true){case (D.is!==null):if(B!=Number(D.is)){Validate.fail(D.wrongNumberMessage);}break;case (D.minimum!==null&&D.maximum!==null):Validate.Numericality(B,{tooLowMessage:D.tooLowMessage,minimum:D.minimum});Validate.Numericality(B,{tooHighMessage:D.tooHighMessage,maximum:D.maximum});break;case (D.minimum!==null):if(B<Number(D.minimum)){Validate.fail(D.tooLowMessage);}break;case (D.maximum!==null):if(B>Number(D.maximum)){Validate.fail(D.tooHighMessage);}break;}return true;},Format:function(A,B){var A=String(A);var C=Object.extend({failureMessage:"Not valid!",pattern:/./,negate:false},B||{});if(!C.negate&&!C.pattern.test(A)){Validate.fail(C.failureMessage);}if(C.negate&&C.pattern.test(A)){Validate.fail(C.failureMessage);}return true;},Email:function(A,B){var C=Object.extend({failureMessage:"Must be a valid email address!"},B||{});Validate.Format(A,{failureMessage:C.failureMessage,pattern:/^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i});return true;},Length:function(A,B){var A=String(A);var B=B||{};var C={wrongLengthMessage:B.wrongLengthMessage||"Must be "+B.is+" characters long!",tooShortMessage:B.tooShortMessage||"Must not be less than "+B.minimum+" characters long!",tooLongMessage:B.tooLongMessage||"Must not be more than "+B.maximum+" characters long!",is:((B.is)||(B.is==0))?B.is:null,minimum:((B.minimum)||(B.minimum==0))?B.minimum:null,maximum:((B.maximum)||(B.maximum==0))?B.maximum:null};switch(true){case (C.is!==null):if(A.length!=Number(C.is)){Validate.fail(C.wrongLengthMessage);}break;case (C.minimum!==null&&C.maximum!==null):Validate.Length(A,{tooShortMessage:C.tooShortMessage,minimum:C.minimum});Validate.Length(A,{tooLongMessage:C.tooLongMessage,maximum:C.maximum});break;case (C.minimum!==null):if(A.length<Number(C.minimum)){Validate.fail(C.tooShortMessage);}break;case (C.maximum!==null):if(A.length>Number(C.maximum)){Validate.fail(C.tooLongMessage);}break;default:throw new Error("Validate::Length - Length(s) to validate against must be provided!");}return true;},Inclusion:function(C,D){var E=Object.extend({failureMessage:"Must be included in the list!",within:[],allowNull:false,partialMatch:false,caseSensitive:true,negate:false},D||{});if(E.allowNull&&C==null){return true;}if(!E.allowNull&&C==null){Validate.fail(E.failureMessage);}if(!E.caseSensitive){var A=[];E.within.each(function(F){if(typeof F=="string"){F=F.toLowerCase();}A.push(F);});E.within=A;if(typeof C=="string"){C=C.toLowerCase();}}var B=(E.within.indexOf(C)==-1)?false:true;if(E.partialMatch){B=false;E.within.each(function(F){if(C.indexOf(F)!=-1){B=true;}});}if((!E.negate&&!B)||(E.negate&&B)){Validate.fail(E.failureMessage);}return true;},Exclusion:function(A,B){var C=Object.extend({failureMessage:"Must not be included in the list!",within:[],allowNull:false,partialMatch:false,caseSensitive:true},B||{});C.negate=true;Validate.Inclusion(A,C);return true;},Confirmation:function(A,B){if(!B.match){throw new Error("Validate::Confirmation - Error validating confirmation: Id of element to match must be provided!");}var C=Object.extend({failureMessage:"Does not match!",match:null},B||{});C.match=$(B.match);if(!C.match){throw new Error("Validate::Confirmation - There is no reference with name of, or element with id of '"+C.match+"'!");}if(A!=C.match.value){Validate.fail(C.failureMessage);}return true;},Acceptance:function(A,B){var C=Object.extend({failureMessage:"Must be accepted!"},B||{});if(!A){Validate.fail(C.failureMessage);}return true;},Custom:function(A,B){var C=Object.extend({against:function(){return true;},args:{},failureMessage:"Not valid!"},B||{});if(!C.against(A,C.args)){Validate.fail(C.failureMessage);}return true;},now:function(A,D,C){if(!A){throw new Error("Validate::now - Validation function must be provided!");}var E=true;try{A(D,C||{});}catch(B){if(B instanceof Validate.Error){E=false;}else{throw B;}}finally{return E;}},Error:function(A){this.message=A;this.name="ValidationError";},fail:function(A){throw new Validate.Error(A);}};
@@ -0,0 +1,28 @@
1
+ .LV_validation_message{
2
+ font-weight:bold;
3
+ margin:0 0 0 5px;
4
+ }
5
+
6
+ .LV_valid {
7
+ color:#00CC00;
8
+ }
9
+
10
+ .LV_invalid {
11
+ color:#CC0000;
12
+ }
13
+
14
+ .LV_valid_field,
15
+ input.LV_valid_field:hover,
16
+ input.LV_valid_field:active,
17
+ textarea.LV_valid_field:hover,
18
+ textarea.LV_valid_field:active {
19
+ border: 1px solid #00CC00;
20
+ }
21
+
22
+ .LV_invalid_field,
23
+ input.LV_invalid_field:hover,
24
+ input.LV_invalid_field:active,
25
+ textarea.LV_invalid_field:hover,
26
+ textarea.LV_invalid_field:active {
27
+ border: 1px solid #CC0000;
28
+ }
@@ -0,0 +1 @@
1
+ # Install hook code here
@@ -0,0 +1,49 @@
1
+ module ActionView
2
+
3
+ mattr_accessor :live_validations
4
+ ActionView::live_validations = true
5
+
6
+ module Helpers
7
+ module FormHelper
8
+ [ :text_field, :text_area, :password_field ].each do |field_type|
9
+ define_method "#{field_type}_with_live_validations" do |object_name, method, options|
10
+ live = options.delete(:live)
11
+ live = ActionView::live_validations if live.nil?
12
+ send("#{field_type}_without_live_validations", object_name, method, options) +
13
+ ( live ? live_validations_for(object_name, method) : '' )
14
+ end
15
+ alias_method_chain field_type, :live_validations
16
+ end
17
+
18
+ def live_validations_for(object_name, method)
19
+ script_tags(live_validation(object_name, method))
20
+ end
21
+
22
+ private
23
+
24
+ def live_validation(object_name, method)
25
+ if validations = self.instance_variable_get("@#{object_name.to_s}").class.live_validations[method.to_sym] rescue false
26
+ field_name = "#{object_name}_#{method}"
27
+ initialize_validator(field_name) +
28
+ validations.map do |type, configuration|
29
+ live_validation_code(field_name, type, configuration)
30
+ end.join(';')
31
+ else
32
+ ''
33
+ end
34
+ end
35
+
36
+ def initialize_validator(field_name)
37
+ "var #{field_name} = new LiveValidation('#{field_name}');"
38
+ end
39
+
40
+ def live_validation_code(field_name, type, configuration)
41
+ "#{field_name}.add(#{ActiveRecord::Validations::VALIDATION_METHODS[type]}" + ( configuration ? ", #{configuration.to_json}" : '') + ')'
42
+ end
43
+
44
+ def script_tags(js_code = '')
45
+ ( js_code.blank? ? '' : "<script>#{js_code}</script>" )
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,73 @@
1
+ module ActiveRecord
2
+ module Validations
3
+ LIVE_VALIDATIONS_OPTIONS = {
4
+ :failureMessage => :message,
5
+ :pattern => :with,
6
+ :onlyInteger => :only_integer
7
+ }
8
+ # more complicated mappings in map_configuration method
9
+
10
+ VALIDATION_METHODS = {
11
+ :presence => "Validate.Presence",
12
+ :numericality => "Validate.Numericality",
13
+ :format => "Validate.Format",
14
+ :length => "Validate.Length",
15
+ :acceptance => "Validate.Acceptance",
16
+ :confirmation => "Validate.Confirmation"
17
+ }
18
+
19
+
20
+ module ClassMethods
21
+
22
+ VALIDATION_METHODS.keys.each do |type|
23
+ define_method "validates_#{type}_of_with_live_validations".to_sym do |*attr_names|
24
+ send "validates_#{type}_of_without_live_validations".to_sym, *attr_names
25
+ define_validations(type, attr_names)
26
+ end
27
+ alias_method_chain "validates_#{type}_of".to_sym, :live_validations
28
+ end
29
+
30
+ def live_validations
31
+ @live_validations ||= {}
32
+ end
33
+
34
+ private
35
+
36
+ def define_validations(validation_type, attr_names)
37
+ conf = (attr_names.last.is_a?(Hash) ? attr_names.pop : {})
38
+ attr_names.each do |attr_name|
39
+ configuration = map_configuration(conf.dup, validation_type, attr_name)
40
+ add_live_validation(attr_name, validation_type, configuration)
41
+ end
42
+ end
43
+
44
+ def add_live_validation(attr_name, type, configuration = {})
45
+ @live_validations ||= {}
46
+ @live_validations[attr_name] ||= {}
47
+ @live_validations[attr_name][type] = configuration
48
+ end
49
+
50
+ def map_configuration(configuration, type = nil, attr_name = '')
51
+ LIVE_VALIDATIONS_OPTIONS.each do |live, rails|
52
+ configuration[live] = configuration.delete(rails)
53
+ end
54
+ if type == :numericality
55
+ if configuration[:onlyInteger]
56
+ configuration[:notAnIntegerMessage] = configuration.delete(:failureMessage)
57
+ else
58
+ configuration[:notANumberMessage] = configuration.delete(:failureMessage)
59
+ end
60
+ end
61
+ if type == :length and range = ( configuration.delete(:in) || configuration.delete(:within) )
62
+ configuration[:minimum] = range.begin
63
+ configuration[:maximum] = range.end
64
+ end
65
+ if type == :confirmation
66
+ configuration[:match] = self.to_s.underscore + '_' + attr_name.to_s + '_confirmation'
67
+ end
68
+ configuration[:validMessage] ||= ''
69
+ configuration.reject {|k, v| v.nil? }
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,59 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{livevalidation}
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Sergio Gil"]
12
+ s.date = %q{2010-08-30}
13
+ s.description = %q{Easy client side validation for your ActiveRecord models}
14
+ s.email = %q{sgilperez@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "README.md"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ "README.md",
21
+ "Rakefile",
22
+ "VERSION",
23
+ "assets/javascripts/live_validation.js",
24
+ "assets/stylesheets/live_validation.css",
25
+ "install.rb",
26
+ "lib/form_helpers.rb",
27
+ "lib/live_validations.rb",
28
+ "livevalidation.gemspec",
29
+ "rails/init.rb",
30
+ "tasks/live_validation_tasks.rake",
31
+ "test/form_helpers_test.rb",
32
+ "test/live_validations_test.rb",
33
+ "test/resource.rb",
34
+ "test/test_helper.rb",
35
+ "uninstall.rb"
36
+ ]
37
+ s.homepage = %q{http://github.com/porras/livevalidation}
38
+ s.rdoc_options = ["--charset=UTF-8"]
39
+ s.require_paths = ["lib"]
40
+ s.rubygems_version = %q{1.3.7}
41
+ s.summary = %q{Easy client side validation for your ActiveRecord models}
42
+ s.test_files = [
43
+ "test/form_helpers_test.rb",
44
+ "test/live_validations_test.rb",
45
+ "test/resource.rb",
46
+ "test/test_helper.rb"
47
+ ]
48
+
49
+ if s.respond_to? :specification_version then
50
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
51
+ s.specification_version = 3
52
+
53
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
54
+ else
55
+ end
56
+ else
57
+ end
58
+ end
59
+
@@ -0,0 +1,2 @@
1
+ require 'live_validations'
2
+ require 'form_helpers'
@@ -0,0 +1,17 @@
1
+ namespace :livevalidation do
2
+
3
+ PLUGIN_ROOT = File.dirname(__FILE__) + '/../'
4
+
5
+ desc 'Installs required javascript and stylesheet files to the public/ directory.'
6
+ task :install do
7
+ FileUtils.cp Dir[PLUGIN_ROOT + '/assets/javascripts/*.js'], RAILS_ROOT + '/public/javascripts'
8
+ FileUtils.cp Dir[PLUGIN_ROOT + '/assets/stylesheets/*.css'], RAILS_ROOT + '/public/stylesheets'
9
+ end
10
+
11
+ desc 'Removes the javascript and stylesheet for the plugin.'
12
+ task :remove do
13
+ FileUtils.rm %{live_validation.js}.collect { |f| RAILS_ROOT + "/public/javascripts/" + f }
14
+ FileUtils.rm %{live_validation.css}.collect { |f| RAILS_ROOT + "/public/stylesheets/" + f }
15
+ end
16
+
17
+ end
@@ -0,0 +1,206 @@
1
+ require File.dirname(__FILE__) + '/../test/test_helper'
2
+
3
+ class ResourcesController < ActionController::Base
4
+ def without_instance_var
5
+ render_form(:text, :name)
6
+ end
7
+
8
+ def without_live
9
+ @resource = Resource.new
10
+ render :inline => "<% form_for(:resource, :url => resources_path) do |f| %><%= f.text_field :name, :live => false %><% end %>"
11
+ end
12
+
13
+ def with_live
14
+ @resource = Resource.new
15
+ render :inline => "<% form_for(:resource, :url => resources_path) do |f| %><%= f.text_field :name, :live => true %><% end %>"
16
+ end
17
+
18
+ def with_string
19
+ @resource = Resource.new
20
+ render :inline => "<% form_for(:resource, :url => resources_path) do |f| %><%= f.text_field 'name' %><% end %>"
21
+ end
22
+
23
+ def with_text_area
24
+ @resource = Resource.new
25
+ render :inline => "<% form_for(:resource, :url => resources_path) do |f| %><%= f.text_area :name %><% end %>"
26
+ end
27
+
28
+ def name
29
+ @resource = Resource.new
30
+ render_form(:text, :name)
31
+ end
32
+
33
+ def amount
34
+ @resource = Resource.new
35
+ render_form(:text, :amount)
36
+ end
37
+
38
+ def password
39
+ @resource = Resource.new
40
+ render :inline => "<% form_for(:resource, :url => resources_path) do |f| %><%= f.password_field :password %><%= f.password_field :password_confirmation %><% end %>"
41
+ end
42
+
43
+ def rescue_action(e)
44
+ raise e
45
+ end
46
+
47
+ private
48
+
49
+ def render_form(type, method)
50
+ render :inline => "<% form_for(:resource, :url => resources_path) do |f| %><%= f.#{type}_field :#{method} %><% end %>"
51
+ end
52
+ end
53
+
54
+ ActionController::Routing::Routes.draw do |map|
55
+ map.resources :resources
56
+ map.connect ':controller/:action/:id'
57
+ end
58
+
59
+ class FormHelpersTest < ActionController::TestCase
60
+
61
+ def setup
62
+ @controller = ResourcesController.new
63
+ @request = ActionController::TestRequest.new
64
+ @response = ActionController::TestResponse.new
65
+ Resource.class_eval do # reset live validations
66
+ @live_validations = {}
67
+ end
68
+ ActionView::live_validations = true # reset default behaviour
69
+ end
70
+
71
+ def test_without_instance_var
72
+ get :without_instance_var
73
+ check_form_item :type => 'text', :name => 'name'
74
+ end
75
+
76
+ def test_without_live
77
+ Resource.class_eval do
78
+ validates_presence_of :name
79
+ end
80
+ get :without_live
81
+ check_form_item :type => 'text', :name => 'name'
82
+ end
83
+
84
+ def test_without_live_with_false_default
85
+ ActionView::live_validations = false
86
+ Resource.class_eval do
87
+ validates_presence_of :name
88
+ end
89
+ get :name
90
+ check_form_item :type => 'text', :name => 'name'
91
+ end
92
+
93
+ def test_with_live_with_false_default
94
+ ActionView::live_validations = false
95
+ Resource.class_eval do
96
+ validates_presence_of :name
97
+ end
98
+ get :with_live
99
+ check_form_item :type => 'text', :name => 'name' do |script|
100
+ assert_matches script, "var resource_name = new LiveValidation('resource_name');resource_name.add(Validate.Presence, {\"validMessage\": \"\"})"
101
+ end
102
+ end
103
+
104
+ def test_with_string
105
+ Resource.class_eval do
106
+ validates_presence_of :name
107
+ end
108
+ get :with_string
109
+ check_form_item :type => 'text', :name => 'name' do |script|
110
+ assert_matches script, "var resource_name = new LiveValidation('resource_name');resource_name.add(Validate.Presence, {\"validMessage\": \"\"})"
111
+ end
112
+ end
113
+
114
+ def test_with_text_area
115
+ Resource.class_eval do
116
+ validates_presence_of :name
117
+ end
118
+ get :with_text_area
119
+ assert_response :ok
120
+ assert_select 'form[action="/resources"]' do
121
+ assert_select "textarea[id='resource_name']"
122
+ assert_select 'script', "var resource_name = new LiveValidation('resource_name');resource_name.add(Validate.Presence, {\"validMessage\": \"\"})"
123
+ end
124
+ end
125
+
126
+ def test_presence
127
+ Resource.class_eval do
128
+ validates_presence_of :name
129
+ end
130
+ get :name
131
+ check_form_item :type => 'text', :name => 'name' do |script|
132
+ assert_matches script, "var resource_name = new LiveValidation('resource_name');resource_name.add(Validate.Presence, {\"validMessage\": \"\"})"
133
+ end
134
+ end
135
+
136
+ def test_presence_with_message
137
+ Resource.class_eval do
138
+ validates_presence_of :name, :message => 'is required'
139
+ end
140
+ get :name
141
+ check_form_item :type => 'text', :name => 'name' do |script|
142
+ assert_matches script, /var resource_name = new LiveValidation\('resource_name'\);resource_name.add\(Validate.Presence, \{(.+)\}\)/
143
+ assert_matches script, "\"validMessage\": \"\""
144
+ assert_matches script, "\"failureMessage\": \"is required\""
145
+ end
146
+ end
147
+
148
+ def test_numericality
149
+ Resource.class_eval do
150
+ validates_numericality_of :amount
151
+ end
152
+ get :amount
153
+ check_form_item :type => 'text', :name => 'amount' do |script|
154
+ assert_matches script, "var resource_amount = new LiveValidation('resource_amount');resource_amount.add(Validate.Numericality, {\"validMessage\": \"\"})"
155
+ end
156
+ end
157
+
158
+ def test_numericality_only_integer
159
+ Resource.class_eval do
160
+ validates_numericality_of :amount, :only_integer => true
161
+ end
162
+ get :amount
163
+ check_form_item :type => 'text', :name => 'amount' do |script|
164
+ assert_matches script, /var resource_amount = new LiveValidation\('resource_amount'\);resource_amount.add\(Validate.Numericality, \{(.*)\}\)/
165
+ assert_matches script, "\"onlyInteger\": true"
166
+ assert_matches script, "\"validMessage\": \"\""
167
+ end
168
+ end
169
+
170
+ def test_confirmation
171
+ Resource.class_eval do
172
+ validates_confirmation_of :password
173
+ end
174
+ get :password
175
+ check_form_item :type => 'password', :name => 'password' do |script|
176
+ assert_matches script, /var resource_password = new LiveValidation\('resource_password'\);resource_password.add\(Validate.Confirmation, \{(.*)\}\)/
177
+ assert_matches script, "\"match\": \"resource_password_confirmation\""
178
+ assert_matches script, "\"validMessage\": \"\""
179
+ end
180
+ end
181
+
182
+ private
183
+
184
+ def check_form_item(options = {}, &blk)
185
+ assert_response :ok
186
+ assert_select 'form[action="/resources"]' do
187
+ assert_select "input[type='#{options[:type]}'][id='resource_#{options[:name]}']"
188
+ if block_given?
189
+ assert_select 'script' do |element|
190
+ yield(element.to_s)
191
+ end
192
+ else
193
+ assert_select 'script', 0
194
+ end
195
+ end
196
+ end
197
+
198
+ def assert_matches(string, regexp)
199
+ if regexp.is_a?(Regexp)
200
+ assert string =~ regexp, "#{string} doesn't match #{regexp}"
201
+ else
202
+ assert string[regexp], "#{string} doesn't match #{regexp}"
203
+ end
204
+ end
205
+
206
+ end
@@ -0,0 +1,120 @@
1
+ require File.dirname(__FILE__) + '/../test/test_helper'
2
+
3
+ class LiveValidationTest < ActiveRecord::TestCase
4
+
5
+ def setup
6
+ Resource.class_eval do # reset live validations
7
+ @live_validations = {}
8
+ end
9
+ end
10
+
11
+ def test_live_validations_accessor
12
+ assert_kind_of(Hash, Resource.live_validations)
13
+ end
14
+
15
+ def test_without_validations
16
+ assert_equal({}, Resource.live_validations)
17
+ end
18
+
19
+ def test_without_ok_message
20
+ Resource.class_eval do
21
+ validates_presence_of :name, :message => "can't be blank"
22
+ end
23
+ assert_equal("", Resource.live_validations[:name][:presence][:validMessage])
24
+ end
25
+
26
+ def test_with_ok_message
27
+ Resource.class_eval do
28
+ validates_presence_of :name, :message => "can't be blank", :validMessage => 'thank you!'
29
+ end
30
+ assert_equal("thank you!", Resource.live_validations[:name][:presence][:validMessage])
31
+ end
32
+
33
+ def test_presence
34
+ Resource.class_eval do
35
+ validates_presence_of :name, :message => "can't be blank"
36
+ end
37
+ assert_equal("can't be blank", Resource.live_validations[:name][:presence][:failureMessage])
38
+ end
39
+
40
+ def test_presence_more_than_one_attribute
41
+ Resource.class_eval do
42
+ validates_presence_of :name, :amount, :message => "can't be blank"
43
+ end
44
+ assert_equal("can't be blank", Resource.live_validations[:name][:presence][:failureMessage])
45
+ assert_equal("can't be blank", Resource.live_validations[:amount][:presence][:failureMessage])
46
+ end
47
+
48
+ def test_numericality
49
+ Resource.class_eval do
50
+ validates_numericality_of :amount, :message => "isn't a valid number"
51
+ end
52
+ assert_equal("isn't a valid number", Resource.live_validations[:amount][:numericality][:notANumberMessage])
53
+ assert(!Resource.live_validations[:amount][:numericality][:onlyInteger])
54
+ end
55
+
56
+ def test_numericality_only_integer
57
+ Resource.class_eval do
58
+ validates_numericality_of :amount, :only_integer => true, :message => "isn't an integer number"
59
+ end
60
+ assert_equal("isn't an integer number", Resource.live_validations[:amount][:numericality][:notAnIntegerMessage])
61
+ assert(Resource.live_validations[:amount][:numericality][:onlyInteger])
62
+ end
63
+
64
+ def test_format
65
+ Resource.class_eval do
66
+ validates_format_of :name, :with => /^\w+$/, :message => "only letters are accepted"
67
+ end
68
+ assert_equal("only letters are accepted", Resource.live_validations[:name][:format][:failureMessage])
69
+ assert_equal(/^\w+$/, Resource.live_validations[:name][:format][:pattern])
70
+ end
71
+
72
+ def test_length_max
73
+ Resource.class_eval do
74
+ validates_length_of :name, :maximum => 10, :message => "must be under 10 characters long"
75
+ end
76
+ assert_equal("must be under 10 characters long", Resource.live_validations[:name][:length][:failureMessage])
77
+ assert_equal(10, Resource.live_validations[:name][:length][:maximum])
78
+ end
79
+
80
+ def test_length_min
81
+ Resource.class_eval do
82
+ validates_length_of :name, :minimum => 4, :message => "must be more than 4 characters long"
83
+ end
84
+ assert_equal("must be more than 4 characters long", Resource.live_validations[:name][:length][:failureMessage])
85
+ assert_equal(4, Resource.live_validations[:name][:length][:minimum])
86
+ end
87
+
88
+ def test_length_range
89
+ Resource.class_eval do
90
+ validates_length_of :name, :in => 4..10, :message => "must be between 4 and 10 characters long"
91
+ end
92
+ assert_equal("must be between 4 and 10 characters long", Resource.live_validations[:name][:length][:failureMessage])
93
+ assert_equal(4, Resource.live_validations[:name][:length][:minimum])
94
+ assert_equal(10, Resource.live_validations[:name][:length][:maximum])
95
+ assert_nil(Resource.live_validations[:name][:length][:in])
96
+ end
97
+
98
+ def test_length_exact
99
+ Resource.class_eval do
100
+ validates_length_of :name, :is => 5, :message => "must be 5 characters long"
101
+ end
102
+ assert_equal("must be 5 characters long", Resource.live_validations[:name][:length][:failureMessage])
103
+ assert_equal(5, Resource.live_validations[:name][:length][:is])
104
+ end
105
+
106
+ def test_acceptance
107
+ Resource.class_eval do
108
+ validates_acceptance_of :conditions, :message => "you must accept conditions"
109
+ end
110
+ assert_equal("you must accept conditions", Resource.live_validations[:conditions][:acceptance][:failureMessage])
111
+ end
112
+
113
+ def test_confirmation
114
+ Resource.class_eval do
115
+ validates_confirmation_of :name, :message => "doesn't match"
116
+ end
117
+ assert_equal("doesn't match", Resource.live_validations[:name][:confirmation][:failureMessage])
118
+ end
119
+
120
+ end
@@ -0,0 +1,17 @@
1
+ ActiveRecord::Base.class_eval do
2
+ alias_method :save, :valid?
3
+ def self.columns() @columns ||= []; end
4
+
5
+ def self.column(name, sql_type = nil, default = nil, null = true)
6
+ columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default, sql_type, null)
7
+ end
8
+ end
9
+
10
+ class Resource < ActiveRecord::Base
11
+ column :id, :integer
12
+ column :name, :string
13
+ column :amount, :integer
14
+ column :conditions, :boolean
15
+
16
+ attr_accessor :password
17
+ end
@@ -0,0 +1,13 @@
1
+ require 'test/unit'
2
+
3
+ require 'rubygems'
4
+ gem 'rails', '<= 2.3.0' #tests aren't passing in 2.3.2 (but it seems to work)
5
+
6
+ require 'active_record'
7
+ require 'action_controller'
8
+ require 'action_controller/test_process'
9
+ require 'action_view'
10
+
11
+ require File.dirname(__FILE__) + '/../lib/live_validations'
12
+ require File.dirname(__FILE__) + '/../lib/form_helpers'
13
+ require File.dirname(__FILE__) + '/../test/resource'
@@ -0,0 +1 @@
1
+ # Uninstall hook code here
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: livevalidation
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Sergio Gil
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-08-30 00:00:00 +02:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: Easy client side validation for your ActiveRecord models
23
+ email: sgilperez@gmail.com
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files:
29
+ - README.md
30
+ files:
31
+ - .gitignore
32
+ - README.md
33
+ - Rakefile
34
+ - VERSION
35
+ - assets/javascripts/live_validation.js
36
+ - assets/stylesheets/live_validation.css
37
+ - install.rb
38
+ - lib/form_helpers.rb
39
+ - lib/live_validations.rb
40
+ - livevalidation.gemspec
41
+ - rails/init.rb
42
+ - tasks/live_validation_tasks.rake
43
+ - test/form_helpers_test.rb
44
+ - test/live_validations_test.rb
45
+ - test/resource.rb
46
+ - test/test_helper.rb
47
+ - uninstall.rb
48
+ has_rdoc: true
49
+ homepage: http://github.com/porras/livevalidation
50
+ licenses: []
51
+
52
+ post_install_message:
53
+ rdoc_options:
54
+ - --charset=UTF-8
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ hash: 3
63
+ segments:
64
+ - 0
65
+ version: "0"
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ hash: 3
72
+ segments:
73
+ - 0
74
+ version: "0"
75
+ requirements: []
76
+
77
+ rubyforge_project:
78
+ rubygems_version: 1.3.7
79
+ signing_key:
80
+ specification_version: 3
81
+ summary: Easy client side validation for your ActiveRecord models
82
+ test_files:
83
+ - test/form_helpers_test.rb
84
+ - test/live_validations_test.rb
85
+ - test/resource.rb
86
+ - test/test_helper.rb