client_side_validations 3.1.5 → 3.2.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. data/client_side_validations.gemspec +1 -9
  2. data/lib/client_side_validations.rb +6 -2
  3. data/lib/client_side_validations/action_view/form_builder.rb +4 -2
  4. data/lib/client_side_validations/action_view/form_helper.rb +15 -7
  5. data/lib/client_side_validations/active_model.rb +5 -2
  6. data/lib/client_side_validations/active_record.rb +2 -1
  7. data/lib/client_side_validations/active_record/middleware.rb +15 -2
  8. data/lib/client_side_validations/active_record/uniqueness.rb +0 -1
  9. data/lib/client_side_validations/core_ext/regexp.rb +1 -1
  10. data/lib/client_side_validations/middleware.rb +40 -16
  11. data/lib/client_side_validations/version.rb +1 -1
  12. data/lib/generators/templates/client_side_validations/initializer.rb +0 -3
  13. data/vendor/assets/javascripts/rails.validations.js +135 -170
  14. metadata +22 -329
  15. data/lib/client_side_validations/formtastic.rb +0 -21
  16. data/lib/client_side_validations/mongo_mapper.rb +0 -9
  17. data/lib/client_side_validations/mongo_mapper/middleware.rb +0 -20
  18. data/lib/client_side_validations/mongo_mapper/uniqueness.rb +0 -29
  19. data/lib/client_side_validations/mongoid.rb +0 -9
  20. data/lib/client_side_validations/mongoid/format.rb +0 -10
  21. data/lib/client_side_validations/mongoid/length.rb +0 -24
  22. data/lib/client_side_validations/mongoid/middleware.rb +0 -20
  23. data/lib/client_side_validations/mongoid/presence.rb +0 -10
  24. data/lib/client_side_validations/mongoid/uniqueness.rb +0 -29
  25. data/lib/client_side_validations/simple_form.rb +0 -24
  26. data/lib/generators/templates/client_side_validations/README.rails.3.0 +0 -6
  27. data/test/action_view/cases/helper.rb +0 -176
  28. data/test/action_view/cases/test_helpers.rb +0 -635
  29. data/test/action_view/cases/test_legacy_helpers.rb +0 -217
  30. data/test/action_view/models.rb +0 -3
  31. data/test/action_view/models/comment.rb +0 -35
  32. data/test/action_view/models/post.rb +0 -35
  33. data/test/active_model/cases/helper.rb +0 -4
  34. data/test/active_model/cases/test_acceptance_validator.rb +0 -16
  35. data/test/active_model/cases/test_base.rb +0 -11
  36. data/test/active_model/cases/test_confirmation_validator.rb +0 -16
  37. data/test/active_model/cases/test_exclusion_validator.rb +0 -20
  38. data/test/active_model/cases/test_format_validator.rb +0 -21
  39. data/test/active_model/cases/test_inclusion_validator.rb +0 -21
  40. data/test/active_model/cases/test_length_validator.rb +0 -61
  41. data/test/active_model/cases/test_numericality_validator.rb +0 -46
  42. data/test/active_model/cases/test_presence_validator.rb +0 -16
  43. data/test/active_model/cases/test_validations.rb +0 -175
  44. data/test/active_model/models/person.rb +0 -17
  45. data/test/active_record/cases/helper.rb +0 -12
  46. data/test/active_record/cases/test_base.rb +0 -11
  47. data/test/active_record/cases/test_middleware.rb +0 -175
  48. data/test/active_record/cases/test_uniqueness_validator.rb +0 -56
  49. data/test/active_record/models/guid.rb +0 -7
  50. data/test/active_record/models/user.rb +0 -14
  51. data/test/base_helper.rb +0 -21
  52. data/test/core_ext/cases/test_core_ext.rb +0 -46
  53. data/test/formtastic/cases/helper.rb +0 -7
  54. data/test/formtastic/cases/test_form_builder.rb +0 -11
  55. data/test/formtastic/cases/test_form_helper.rb +0 -21
  56. data/test/generators/cases/test_generators.rb +0 -70
  57. data/test/javascript/config.ru +0 -3
  58. data/test/javascript/public/test/callbacks/elementAfter.js +0 -54
  59. data/test/javascript/public/test/callbacks/elementBefore.js +0 -54
  60. data/test/javascript/public/test/callbacks/elementFail.js +0 -70
  61. data/test/javascript/public/test/callbacks/elementPass.js +0 -70
  62. data/test/javascript/public/test/callbacks/formAfter.js +0 -45
  63. data/test/javascript/public/test/callbacks/formBefore.js +0 -45
  64. data/test/javascript/public/test/callbacks/formFail.js +0 -51
  65. data/test/javascript/public/test/callbacks/formPass.js +0 -50
  66. data/test/javascript/public/test/form_builders/validateForm.js +0 -66
  67. data/test/javascript/public/test/form_builders/validateFormtastic.js +0 -54
  68. data/test/javascript/public/test/form_builders/validateNestedForm.js +0 -66
  69. data/test/javascript/public/test/form_builders/validateSimpleForm.js +0 -57
  70. data/test/javascript/public/test/settings.js +0 -15
  71. data/test/javascript/public/test/validateElement.js +0 -179
  72. data/test/javascript/public/test/validators/acceptance.js +0 -42
  73. data/test/javascript/public/test/validators/confirmation.js +0 -25
  74. data/test/javascript/public/test/validators/exclusion.js +0 -41
  75. data/test/javascript/public/test/validators/format.js +0 -27
  76. data/test/javascript/public/test/validators/inclusion.js +0 -42
  77. data/test/javascript/public/test/validators/length.js +0 -76
  78. data/test/javascript/public/test/validators/numericality.js +0 -158
  79. data/test/javascript/public/test/validators/presence.js +0 -21
  80. data/test/javascript/public/test/validators/uniqueness.js +0 -107
  81. data/test/javascript/public/vendor/jquery.metadata.js +0 -122
  82. data/test/javascript/public/vendor/qunit.css +0 -196
  83. data/test/javascript/public/vendor/qunit.js +0 -1374
  84. data/test/javascript/server.rb +0 -84
  85. data/test/javascript/views/index.erb +0 -20
  86. data/test/javascript/views/layout.erb +0 -21
  87. data/test/middleware/cases/helper.rb +0 -7
  88. data/test/middleware/cases/test_middleware.rb +0 -8
  89. data/test/mongo_mapper/cases/helper.rb +0 -9
  90. data/test/mongo_mapper/cases/test_base.rb +0 -15
  91. data/test/mongo_mapper/cases/test_middleware.rb +0 -77
  92. data/test/mongo_mapper/cases/test_uniqueness_validator.rb +0 -55
  93. data/test/mongo_mapper/models/magazine.rb +0 -11
  94. data/test/mongoid/cases/helper.rb +0 -12
  95. data/test/mongoid/cases/test_base.rb +0 -15
  96. data/test/mongoid/cases/test_format_validator.rb +0 -21
  97. data/test/mongoid/cases/test_length_validator.rb +0 -60
  98. data/test/mongoid/cases/test_middleware.rb +0 -77
  99. data/test/mongoid/cases/test_presence_validator.rb +0 -16
  100. data/test/mongoid/cases/test_uniqueness_validator.rb +0 -54
  101. data/test/mongoid/models/book.rb +0 -12
  102. data/test/simple_form/cases/helper.rb +0 -5
  103. data/test/simple_form/cases/test_form_builder.rb +0 -14
  104. data/test/simple_form/cases/test_form_helper.rb +0 -24
  105. data/test/test_loader.rb +0 -6
@@ -13,19 +13,11 @@ Gem::Specification.new do |s|
13
13
  s.description = %q{Client Side Validations}
14
14
 
15
15
  s.files = `git ls-files -- {lib/*,vendor/*,*.gemspec}`.split("\n")
16
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
16
  s.require_paths = ["lib"]
19
17
 
20
- s.add_development_dependency 'rails', '~> 3.1.0'
18
+ s.add_development_dependency 'rails', '~> 3.2.0'
21
19
  s.add_development_dependency 'sqlite3'
22
- s.add_development_dependency 'bson_ext'
23
- s.add_development_dependency 'mongoid', '~> 2.4.0'
24
- s.add_development_dependency 'mongo_mapper','~> 0.9.0'
25
20
  s.add_development_dependency 'mocha'
26
- s.add_development_dependency 'simple_form', '~> 1.5.0'
27
- s.add_development_dependency 'formtastic', '~> 2.0.0'
28
- s.add_development_dependency 'm'
29
21
 
30
22
  # For QUnit testing
31
23
  s.add_development_dependency 'sinatra', '~> 1.0'
@@ -1,10 +1,14 @@
1
1
  module ClientSideValidations
2
+ module Config
3
+ class << self
4
+ attr_accessor :uniqueness_validator_disabled
5
+ @uniqueness_validator_disabled = false
6
+ end
7
+ end
2
8
  end
3
9
 
4
10
  require 'client_side_validations/active_model' if defined?(::ActiveModel)
5
11
  require 'client_side_validations/active_record' if defined?(::ActiveRecord)
6
- require 'client_side_validations/mongoid' if defined?(::Mongoid)
7
- require 'client_side_validations/mongo_mapper' if defined?(::MongoMapper)
8
12
  require 'client_side_validations/action_view' if defined?(::ActionView)
9
13
  if defined?(::Rails)
10
14
  require 'client_side_validations/middleware'
@@ -72,7 +72,7 @@ module ClientSideValidations::ActionView::Helpers
72
72
 
73
73
  def time_zone_select_with_client_side_validations(method, priority_zones = nil, options = {}, html_options = {})
74
74
  apply_client_side_validators(method, html_options)
75
- time_zone_select_without_client_side_validations(method, priority_zones, options, html_options)
75
+ time_zone_select_without_client_side_validations(method, priority_zones = nil, options, html_options)
76
76
  end
77
77
 
78
78
  private
@@ -80,7 +80,9 @@ module ClientSideValidations::ActionView::Helpers
80
80
  def apply_client_side_validators(method, options = {})
81
81
  if @options[:validate] && options[:validate] != false && validators = filter_validators(method, options[:validate])
82
82
  options.merge!("data-validate" => true)
83
- @options[:validators].merge!("#{@object_name}[#{method}]#{options[:multiple] ? "[]" : nil}" => validators)
83
+ name = options[:name] || "#{@object_name}[#{method}]"
84
+
85
+ @options[:validators].merge!("#{name}#{options[:multiple] ? "[]" : nil}" => validators)
84
86
  end
85
87
  end
86
88
 
@@ -6,8 +6,6 @@ module ClientSideValidations::ActionView::Helpers
6
6
  options = args.extract_options!
7
7
  if options[:validate]
8
8
 
9
- content_for_name = options[:validate] unless options[:validate] == true
10
-
11
9
  # Always turn off HTML5 Validations
12
10
  options[:html] ||= {}
13
11
  options[:html][:novalidate] = 'novalidate'
@@ -23,17 +21,27 @@ module ClientSideValidations::ActionView::Helpers
23
21
  end
24
22
 
25
23
  @validators = {}
24
+
26
25
  # Order matters here. Rails mutates the options object
27
26
  script = client_side_form_settings(object, options)
28
27
  form = super(record_or_name_or_array, *(args << options), &proc)
28
+
29
29
  # Because of the load order requirement above this sub is necessary
30
30
  # Would be nice to not do this
31
31
  script = insert_validators_into_script(script)
32
- if content_for_name
33
- content_for(content_for_name) { script.html_safe }
34
- script = nil
32
+
33
+ if assign_script_to_content_for(options[:validate], script)
34
+ form.html_safe
35
+ else
36
+ "#{form}#{script}".html_safe
37
+ end
38
+ end
39
+
40
+ def assign_script_to_content_for(name, script)
41
+ if name && name != true
42
+ content_for(name) { script.html_safe }
43
+ true
35
44
  end
36
- "#{form}#{script}".html_safe
37
45
  end
38
46
 
39
47
  def apply_form_for_options!(object_or_array, options)
@@ -75,7 +83,7 @@ module ClientSideValidations::ActionView::Helpers
75
83
  end
76
84
 
77
85
  content_tag(:script) do
78
- "window['#{var_name}'] = #{builder.client_side_form_settings(options, self).merge(:validators => 'validator_hash').to_json};".html_safe
86
+ "window.ClientSideValidations.forms['#{var_name}'] = #{builder.client_side_form_settings(options, self).merge(:validators => 'validator_hash').to_json};".html_safe
79
87
  end
80
88
 
81
89
  end
@@ -5,7 +5,6 @@ module ClientSideValidations::ActiveModel
5
5
 
6
6
  def client_side_hash(model, attribute)
7
7
  options = self.options.dup
8
- # debugger
9
8
  { :message => model.errors.generate_message(attribute, message_type, options) }.merge(options.except(*::ActiveModel::Errors::CALLBACKS_OPTIONS - [:allow_blank, :if, :unless]))
10
9
  end
11
10
 
@@ -24,7 +23,7 @@ module ClientSideValidations::ActiveModel
24
23
  validator_hash = attr[1].inject({}) do |kind_hash, validator|
25
24
  client_side_hash = validator.client_side_hash(self, attr[0])
26
25
  # Yeah yeah, #new_record? is not part of ActiveModel :p
27
- if (can_use_for_client_side_validation?(client_side_hash, validator))
26
+ if can_use_for_client_side_validation?(client_side_hash, validator) && uniqueness_validations_allowed_or_not_applicable?(validator)
28
27
  kind_hash.merge!(validator.kind => client_side_hash.except(:on))
29
28
  else
30
29
  kind_hash.merge!({})
@@ -47,6 +46,10 @@ module ClientSideValidations::ActiveModel
47
46
  def can_use_for_client_side_validation?(client_side_hash, validator)
48
47
  ((self.respond_to?(:new_record?) && validator.options[:on] == (self.new_record? ? :create : :update)) || validator.options[:on].nil?) && validator.kind != :block
49
48
  end
49
+
50
+ def uniqueness_validations_allowed_or_not_applicable?(validator)
51
+ validator.kind != :uniqueness || !ClientSideValidations::Config.uniqueness_validator_disabled
52
+ end
50
53
  end
51
54
  end
52
55
 
@@ -1,4 +1,5 @@
1
1
  require 'client_side_validations/active_model'
2
+ require 'client_side_validations/middleware'
2
3
  require 'client_side_validations/active_record/middleware'
3
4
 
4
5
  %w{uniqueness}.each do |validator|
@@ -8,4 +9,4 @@ require 'client_side_validations/active_record/middleware'
8
9
  end
9
10
 
10
11
  ActiveRecord::Base.send(:include, ClientSideValidations::ActiveModel::Validations)
11
-
12
+ ClientSideValidations::Middleware::Uniqueness.register_orm(ClientSideValidations::ActiveRecord::Middleware)
@@ -1,7 +1,12 @@
1
1
  module ClientSideValidations::ActiveRecord
2
2
  class Middleware
3
3
 
4
+ def self.is_class?(klass)
5
+ klass < ::ActiveRecord::Base
6
+ end
7
+
4
8
  def self.is_unique?(klass, attribute, value, params)
9
+ value = type_cast_value(klass, attribute, value)
5
10
  column = klass.columns_hash[attribute.to_s]
6
11
  value = column.limit ? value.to_s.mb_chars[0, column.limit] : value.to_s if column.text?
7
12
 
@@ -23,11 +28,19 @@ module ClientSideValidations::ActiveRecord
23
28
  relation = relation.and(t.primary_key.not_eq(params[:id])) if params[:id]
24
29
  end
25
30
 
26
- (params[:scope] || {}).each do |key, value|
27
- relation = relation.and(t[key].eq(value))
31
+ (params[:scope] || {}).each do |attribute, value|
32
+ value = type_cast_value(klass, attribute, value)
33
+ relation = relation.and(t[attribute].eq(value))
28
34
  end
29
35
 
30
36
  !klass.where(relation).exists?
31
37
  end
38
+
39
+ private
40
+
41
+ def self.type_cast_value(klass, attribute, value)
42
+ klass.columns_hash[attribute].type_cast(value)
43
+ end
44
+
32
45
  end
33
46
  end
@@ -4,7 +4,6 @@ module ClientSideValidations::ActiveRecord
4
4
  hash = {}
5
5
  hash[:message] = model.errors.generate_message(attribute, message_type, options.except(:scope))
6
6
  hash[:case_sensitive] = options[:case_sensitive]
7
- hash[:allow_blank] = options[:allow_blank] if options.key?(:allow_blank)
8
7
  hash[:id] = model.id unless model.new_record?
9
8
  if options.key?(:scope) && options[:scope].present?
10
9
  hash[:scope] = Array.wrap(options[:scope]).inject({}) do |scope_hash, scope_item|
@@ -1,6 +1,6 @@
1
1
  class Regexp
2
2
  def as_json(options = nil)
3
- Regexp.new inspect.sub("\\A","^").sub("\\Z","$").sub("\\z","$").sub(/^\//,"").sub(/\/[a-z]*$/,""), self.options
3
+ Regexp.new inspect.sub('\\A','^').sub('\\Z','$').sub('\\z','$').sub(/^\//,'').sub(/\/[a-z]*$/,'').gsub(/\(\?#.+\)/, '').gsub(/\(\?-\w+:/,'('), self.options
4
4
  end
5
5
 
6
6
  def to_json(options = nil)
@@ -11,11 +11,11 @@ module ClientSideValidations
11
11
  end
12
12
 
13
13
  def call(env)
14
- case env['PATH_INFO']
15
- when %r{\/validators\/(\w+)}
16
- "::ClientSideValidations::Middleware::#{$1.camelize}".constantize.new(env).response
17
- else
14
+ matches = /^\/validators\/(\w+)$/.match(env['PATH_INFO'])
15
+ if !matches || (matches[1] == 'uniqueness' && Config.uniqueness_validator_disabled)
18
16
  @app.call(env)
17
+ else
18
+ "::ClientSideValidations::Middleware::#{matches[1].camelize}".constantize.new(env).response
19
19
  end
20
20
  end
21
21
  end
@@ -40,6 +40,7 @@ module ClientSideValidations
40
40
 
41
41
  class Uniqueness < Base
42
42
  IGNORE_PARAMS = %w{case_sensitive id scope}
43
+ REGISTERED_ORMS = []
43
44
 
44
45
  def response
45
46
  if is_unique?
@@ -52,23 +53,46 @@ module ClientSideValidations
52
53
  super
53
54
  end
54
55
 
56
+ def self.register_orm(orm)
57
+ registered_orms << orm
58
+ end
59
+
60
+ def self.registered_orms
61
+ REGISTERED_ORMS
62
+ end
63
+
64
+ def registered_orms
65
+ self.class.registered_orms
66
+ end
67
+
55
68
  private
56
69
 
57
70
  def is_unique?
58
- resource = extract_resource
59
- klass = resource.classify.constantize
60
- attribute = request.params[resource].keys.first
61
- value = request.params[resource][attribute]
62
-
63
- if (defined?(::ActiveRecord::Base) && klass < ::ActiveRecord::Base)
64
- middleware_klass = ClientSideValidations::ActiveRecord::Middleware
65
- elsif (defined?(::Mongoid::Document) && klass.included_modules.include?(::Mongoid::Document))
66
- middleware_klass = ClientSideValidations::Mongoid::Middleware
67
- elsif (defined?(::MongoMapper::Document) && klass.included_modules.include?(::MongoMapper::Document))
68
- middleware_klass = ClientSideValidations::MongoMapper::Middleware
71
+ convert_scope_value_from_null_to_nil
72
+ resource = extract_resource
73
+ klass = resource.classify.constantize
74
+ attribute = request.params[resource].keys.first
75
+ value = request.params[resource][attribute]
76
+ middleware_class = nil
77
+
78
+ registered_orms.each do |orm|
79
+ if orm.is_class?(klass)
80
+ middleware_class = orm
81
+ break
82
+ end
69
83
  end
70
84
 
71
- middleware_klass.is_unique?(klass, attribute, value, request.params)
85
+ middleware_class.is_unique?(klass, attribute, value, request.params)
86
+ end
87
+
88
+ def convert_scope_value_from_null_to_nil
89
+ if request.params['scope']
90
+ request.params['scope'].each do |key, value|
91
+ if value == 'null'
92
+ request.params['scope'][key] = nil
93
+ end
94
+ end
95
+ end
72
96
  end
73
97
 
74
98
  def extract_resource
@@ -1,3 +1,3 @@
1
1
  module ClientSideValidations
2
- VERSION = '3.1.5'
2
+ VERSION = '3.2.0.beta.1'
3
3
  end
@@ -1,8 +1,5 @@
1
1
  # ClientSideValidations Initializer
2
2
 
3
- require 'client_side_validations/simple_form' if defined?(::SimpleForm)
4
- require 'client_side_validations/formtastic' if defined?(::Formtastic)
5
-
6
3
  # Uncomment the following block if you want each input field to have the validation messages attached.
7
4
  # ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
8
5
  # unless html_tag =~ /^<label/
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Rails 3 Client Side Validations - v3.1.4
2
+ * Rails 3 Client Side Validations - v3.2.0.beta.1
3
3
  * https://github.com/bcardarella/client_side_validations
4
4
  *
5
5
  * Copyright (c) 2011 Brian Cardarella
@@ -7,80 +7,79 @@
7
7
  * http://www.opensource.org/licenses/mit-license.php
8
8
  */
9
9
 
10
- (function($) {
11
- $.fn.validate = function() {
12
- return this.filter('form[data-validate]').each(function() {
13
- var form = $(this);
14
- var settings = window[form.attr('id')];
10
+ (function ($) {
11
+ $.fn.validate = function () {
12
+ return this.filter('form[data-validate]').each(function () {
13
+ var form = $(this),
14
+ settings = window['ClientSideValidations']['forms'][form.attr('id')],
15
+ addError = function (element, message) {
16
+ ClientSideValidations.formBuilders[settings.type].add(element, settings, message);
17
+ },
18
+ removeError = function (element) {
19
+ ClientSideValidations.formBuilders[settings.type].remove(element, settings);
20
+ };
15
21
 
16
22
  // Set up the events for the form
17
23
  form
18
- .submit( function() { return form.isValid(settings.validators); })
19
- .bind('ajax:beforeSend', function(eventData) { if(eventData.target == this) return form.isValid(settings.validators); })
24
+ .submit( function () { return form.isValid(settings.validators); })
25
+ .bind('ajax:beforeSend', function (eventData) { if(eventData.target == this) return form.isValid(settings.validators); })
20
26
  // Callbacks
21
- .bind('form:validate:after', function(eventData) { clientSideValidations.callbacks.form.after( form, eventData); })
22
- .bind('form:validate:before', function(eventData) { clientSideValidations.callbacks.form.before(form, eventData); })
23
- .bind('form:validate:fail', function(eventData) { clientSideValidations.callbacks.form.fail( form, eventData); })
24
- .bind('form:validate:pass', function(eventData) { clientSideValidations.callbacks.form.pass( form, eventData); })
27
+ .bind('form:validate:after', function (eventData) { ClientSideValidations.callbacks.form.after( form, eventData); } )
28
+ .bind('form:validate:before', function (eventData) { ClientSideValidations.callbacks.form.before(form, eventData); } )
29
+ .bind('form:validate:fail', function (eventData) { ClientSideValidations.callbacks.form.fail( form, eventData); } )
30
+ .bind('form:validate:pass', function (eventData) { ClientSideValidations.callbacks.form.pass( form, eventData); } )
25
31
 
26
32
  // Set up the events for each validatable form element
27
- .find('[data-validate]:input:not(:radio)')
28
- .live('focusout', function() { $(this).isValid(settings.validators); })
29
- .live('change', function() { $(this).data('changed', true); })
33
+ .find('[data-validate="true"]:input:enabled:not(:radio)')
34
+ .live('focusout', function () { $(this).isValid(settings.validators); })
35
+ .live('change', function () { $(this).data('changed', true); })
30
36
  // Callbacks
31
- .live('element:validate:after', function(eventData) { clientSideValidations.callbacks.element.after( $(this), eventData); })
32
- .live('element:validate:before', function(eventData) { clientSideValidations.callbacks.element.before($(this), eventData); })
33
- .live('element:validate:fail', function(eventData, message) {
37
+ .live('element:validate:after', function (eventData) { ClientSideValidations.callbacks.element.after( $(this), eventData); })
38
+ .live('element:validate:before', function (eventData) { ClientSideValidations.callbacks.element.before($(this), eventData); })
39
+ .live('element:validate:fail', function (eventData, message) {
34
40
  var element = $(this);
35
- clientSideValidations.callbacks.element.fail(element, message, function() {
41
+ ClientSideValidations.callbacks.element.fail(element, message, function () {
36
42
  addError(element, message);
37
- }, eventData) })
38
- .live('element:validate:pass', function(eventData) {
43
+ }, eventData); })
44
+ .live('element:validate:pass', function (eventData) {
39
45
  var element = $(this);
40
- clientSideValidations.callbacks.element.pass(element, function() {
46
+ ClientSideValidations.callbacks.element.pass(element, function () {
41
47
  removeError(element);
42
- }, eventData) })
48
+ }, eventData); })
43
49
  // Checkboxes - Live events don't support filter
44
- .end().find('[data-validate]:checkbox')
45
- .live('click', function() { $(this).isValid(settings.validators); })
50
+ .end().find('[data-validate="true"]:checkbox')
51
+ .live('click', function () { $(this).isValid(settings.validators); })
46
52
  // Inputs for confirmations
47
- .end().find('[id*=_confirmation]').each(function() {
53
+ .end().find('[id*=_confirmation]').each(function () {
48
54
  var confirmationElement = $(this),
49
- element = form.find('#' + this.id.match(/(.+)_confirmation/)[1] + '[data-validate]:input');
55
+ element = form.find('#' + this.id.match(/(.+)_confirmation/)[1] + '[data-validate="true"]:input');
50
56
 
51
57
  if (element[0]) {
52
58
  $('#' + confirmationElement.attr('id'))
53
- .live('focusout', function() {
59
+ .live('focusout', function () {
54
60
  element.data('changed', true).isValid(settings.validators);
55
61
  })
56
- .live('keyup', function() {
62
+ .live('keyup', function () {
57
63
  element.data('changed', true).isValid(settings.validators);
58
- })
64
+ });
59
65
  }
60
66
  });
61
67
 
62
- var addError = function(element, message) {
63
- clientSideValidations.formBuilders[settings.type].add(element, settings, message);
64
- }
65
-
66
- var removeError = function(element) {
67
- clientSideValidations.formBuilders[settings.type].remove(element, settings);
68
- }
69
68
  });
70
- }
69
+ };
71
70
 
72
- $.fn.isValid = function(validators) {
71
+ $.fn.isValid = function (validators) {
73
72
  if ($(this[0]).is('form')) {
74
73
  return validateForm($(this[0]), validators);
75
74
  } else {
76
75
  return validateElement($(this[0]), validators[this[0].name]);
77
76
  }
78
- }
77
+ };
79
78
 
80
- var validateForm = function(form, validators) {
79
+ var validateForm = function (form, validators) {
81
80
  var valid = true;
82
81
 
83
- form.trigger('form:validate:before').find('[data-validate]:input').each(function() {
82
+ form.trigger('form:validate:before').find('[data-validate="true"]:input:enabled').each(function() {
84
83
  if (!$(this).isValid(validators)) { valid = false; }
85
84
  });
86
85
 
@@ -92,48 +91,57 @@
92
91
 
93
92
  form.trigger('form:validate:after');
94
93
  return valid;
95
- }
96
-
97
- var validateElement = function(element, validators) {
98
- element.trigger('element:validate:before');
99
-
100
- if (element.data('changed') !== false) {
101
- var valid = true;
102
- element.data('changed', false);
94
+ },
95
+ validateElement = function (element, validators) {
96
+ element.trigger('element:validate:before');
97
+
98
+ if (element.data('changed') !== false) {
99
+ var valid = true;
100
+ element.data('changed', false);
101
+
102
+ // Because 'length' is defined on the list of validators we cannot call jQuery.each on
103
+ for (kind in ClientSideValidations.validators.local) {
104
+ if (validators[kind] && (message = ClientSideValidations.validators.all()[kind](element, validators[kind]))) {
105
+ element.trigger('element:validate:fail', message).data('valid', false);
106
+ valid = false;
107
+ break;
108
+ }
109
+ }
103
110
 
104
- // Because 'length' is defined on the list of validators we cannot call jQuery.each on
105
- // the clientSideValidations.validators.all() object
106
- for (kind in clientSideValidations.validators.all()) {
107
- if (validators[kind] && (message = clientSideValidations.validators.all()[kind](element, validators[kind]))) {
108
- element.trigger('element:validate:fail', message).data('valid', false);
109
- valid = false;
110
- break;
111
+ if (valid) {
112
+ for (kind in ClientSideValidations.validators.remote) {
113
+ if (validators[kind] && (message = ClientSideValidations.validators.all()[kind](element, validators[kind]))) {
114
+ element.trigger('element:validate:fail', message).data('valid', false);
115
+ valid = false;
116
+ break;
117
+ }
118
+ }
111
119
  }
112
- }
113
120
 
114
- if (valid) { element.data('valid', null); element.trigger('element:validate:pass'); }
115
- }
121
+ if (valid) { element.data('valid', null); element.trigger('element:validate:pass'); }
122
+ }
116
123
 
117
- element.trigger('element:validate:after');
118
- return element.data('valid') === false ? false : true;
119
- }
124
+ element.trigger('element:validate:after');
125
+ return element.data('valid') === false ? false : true;
126
+ };
120
127
 
121
128
  // Main hook
122
129
  // If new forms are dynamically introduced into the DOM the .validate() method
123
130
  // must be invoked on that form
124
- $(function() { $('form[data-validate]').validate(); })
131
+ $(function () { $('form[data-validate]').validate(); });
125
132
  })(jQuery);
126
133
 
127
- var clientSideValidations = {
134
+ var ClientSideValidations = {
135
+ forms: {},
128
136
  validators: {
129
- all: function() { return jQuery.extend({}, clientSideValidations.validators.local, clientSideValidations.validators.remote) },
137
+ all: function() { return jQuery.extend({}, ClientSideValidations.validators.local, ClientSideValidations.validators.remote); },
130
138
  local: {
131
- presence: function(element, options) {
139
+ presence: function (element, options) {
132
140
  if (/^\s*$/.test(element.val() || "")) {
133
141
  return options.message;
134
142
  }
135
143
  },
136
- acceptance: function(element, options) {
144
+ acceptance: function (element, options) {
137
145
  switch (element.attr('type')) {
138
146
  case 'checkbox':
139
147
  if (!element.attr('checked')) {
@@ -147,8 +155,8 @@ var clientSideValidations = {
147
155
  break;
148
156
  }
149
157
  },
150
- format: function(element, options) {
151
- if ((message = this.presence(element, options)) && options.allow_blank == true) {
158
+ format: function (element, options) {
159
+ if ((message = this.presence(element, options)) && options.allow_blank === true) {
152
160
  return;
153
161
  } else if (message) {
154
162
  return message;
@@ -160,8 +168,8 @@ var clientSideValidations = {
160
168
  }
161
169
  }
162
170
  },
163
- numericality: function(element, options) {
164
- if (!/^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d*)?$/.test(element.val()) && element.val() != '') {
171
+ numericality: function (element, options) {
172
+ if (!/^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d*)?$/.test(element.val())) {
165
173
  return options.messages.numericality;
166
174
  }
167
175
 
@@ -170,82 +178,83 @@ var clientSideValidations = {
170
178
  }
171
179
 
172
180
  var CHECKS = { greater_than: '>', greater_than_or_equal_to: '>=',
173
- equal_to: '==', less_than: '<', less_than_or_equal_to: '<=' }
181
+ equal_to: '==', less_than: '<', less_than_or_equal_to: '<=' };
174
182
 
175
- for (var check in CHECKS) {
176
- if (options[check] != undefined && !(new Function("return " + element.val() + CHECKS[check] + options[check])())) {
183
+ for (check in CHECKS) {
184
+ if (options[check] !== undefined && !(new Function("return " + element.val() + CHECKS[check] + options[check])())) {
177
185
  return options.messages[check];
178
186
  }
179
187
  }
180
188
 
181
- if (options.odd && !(parseInt(element.val()) % 2)) {
189
+ if (options.odd && !(parseInt(element.val(), 10) % 2)) {
182
190
  return options.messages.odd;
183
191
  }
184
192
 
185
- if (options.even && (parseInt(element.val()) % 2)) {
193
+ if (options.even && (parseInt(element.val(), 10) % 2)) {
186
194
  return options.messages.even;
187
195
  }
188
196
  },
189
- length: function(element, options) {
190
- var blankOptions = {};
197
+ length: function (element, options) {
198
+ var blankOptions = {},
199
+ CHECKS = { is: '==', minimum: '>=', maximum: '<=' },
200
+ tokenizer = options.js_tokenizer || "split('')",
201
+ tokenized_length = new Function("element", "return (element.val()." + tokenizer + " || '').length;")(element);
191
202
  if (options.is) {
192
203
  blankOptions.message = options.messages.is;
193
204
  } else if (options.minimum) {
194
205
  blankOptions.message = options.messages.minimum;
195
206
  }
196
- if ((message = this.presence(element, blankOptions)) && options.allow_blank == true) {
207
+ if ((message = this.presence(element, blankOptions)) && options.allow_blank === true) {
197
208
  return;
198
209
  } else if (message) {
199
210
  return message;
200
211
  } else {
201
- var CHECKS = { is: '==', minimum: '>=', maximum: '<=' }
202
- var tokenizer = options.js_tokenizer || "split('')";
203
- var tokenized_length = new Function("element", "return (element.val()." + tokenizer + " || '').length;")(element);
204
-
205
- for (var check in CHECKS) {
212
+ for (check in CHECKS) {
206
213
  if (options[check] && !(new Function("return " + tokenized_length + CHECKS[check] + options[check])())) {
207
214
  return options.messages[check];
208
215
  }
209
216
  }
210
217
  }
211
218
  },
212
- exclusion: function(element, options) {
213
- if ((message = this.presence(element, options)) && options.allow_blank == true) {
219
+ exclusion: function (element, options) {
220
+ var lower = null, upper = null;
221
+ if ((message = this.presence(element, options)) && options.allow_blank === true) {
214
222
  return;
215
223
  } else if (message) {
216
224
  return message;
217
225
  } else {
218
226
  if (options['in']) {
219
- for (var i = 0; i < options['in'].length; i++) {
227
+ for (i = 0; i < options['in'].length; i = i + 1) {
220
228
  if (options['in'][i] == element.val()) {
221
229
  return options.message;
222
230
  }
223
231
  }
224
- } else if (options['range']) {
225
- var lower = options['range'][0],
226
- upper = options['range'][1];
232
+ } else if (options.range) {
233
+ lower = options.range[0];
234
+ upper = options.range[1];
227
235
  if (element.val() >= lower && element.val() <= upper) {
228
236
  return options.message;
229
237
  }
230
238
  }
231
239
  }
232
240
  },
233
- inclusion: function(element, options) {
234
- if ((message = this.presence(element, options)) && options.allow_blank == true) {
241
+ inclusion: function (element, options) {
242
+ var lower = null, upper = null;
243
+ if ((message = this.presence(element, options)) && options.allow_blank === true) {
235
244
  return;
236
245
  } else if (message) {
237
246
  return message;
238
247
  } else {
239
248
  if (options['in']) {
240
- for (var i = 0; i < options['in'].length; i++) {
249
+ for (i = 0; i < options['in'].length; i = i + 1) {
241
250
  if (options['in'][i] == element.val()) {
242
251
  return;
243
252
  }
244
253
  }
245
254
  return options.message;
246
- } else if (options['range']) {
247
- var lower = options['range'][0],
248
- upper = options['range'][1];
255
+ } else if (options.range) {
256
+ lower = options.range[0];
257
+ upper = options.range[1];
249
258
 
250
259
  if (element.val() >= lower && element.val() <= upper) {
251
260
  return;
@@ -255,30 +264,31 @@ var clientSideValidations = {
255
264
  }
256
265
  }
257
266
  },
258
- confirmation: function(element, options) {
259
- if (element.val() != jQuery('#' + element.attr('id') + '_confirmation').val()) {
267
+ confirmation: function (element, options) {
268
+ if (element.val() !== jQuery('#' + element.attr('id') + '_confirmation').val()) {
260
269
  return options.message;
261
270
  }
262
271
  }
263
272
  },
264
273
  remote: {
265
- uniqueness: function(element, options) {
266
- if ((message = clientSideValidations.validators.local.presence(element, options)) && options.allow_blank === true) {
274
+ uniqueness: function (element, options) {
275
+ if ((message = ClientSideValidations.validators.local.presence(element, options)) && options.allow_blank === true) {
267
276
  return;
268
277
  } else if (message) {
269
278
  return message;
270
279
  } else {
271
- var data = {};
272
- data['case_sensitive'] = !!options.case_sensitive;
280
+ var data = {},
281
+ name = null;
282
+ data.case_sensitive = !!options.case_sensitive;
273
283
  if (options.id) {
274
- data['id'] = options.id;
284
+ data.id = options.id;
275
285
  }
276
286
 
277
287
  if (options.scope) {
278
- data.scope = {}
288
+ data.scope = {};
279
289
  for (key in options.scope) {
280
- var scoped_element = jQuery('[name="' + element.attr('name').replace(/\[\w+]$/, '[' + key + ']' + '"]'));
281
- if (scoped_element[0] && scoped_element.val() != options.scope[key]) {
290
+ var scoped_element = jQuery('[name="' + element.attr('name').replace(/\[\w+\]$/, '[' + key + ']' + '"]'));
291
+ if (scoped_element[0] && scoped_element.val() !== options.scope[key]) {
282
292
  data.scope[key] = scoped_element.val();
283
293
  scoped_element.unbind('change.' + element.id).bind('change.' + element.id, function() { element.trigger('change'); element.trigger('focusout'); });
284
294
  } else {
@@ -291,16 +301,16 @@ var clientSideValidations = {
291
301
  // e.g. user[records_attributes][0][title] => records[title]
292
302
  // e.g. user[record_attributes][title] => record[title]
293
303
  // Server side handles classifying the resource properly
294
- if (/_attributes]/.test(element.attr('name'))) {
295
- var name = element.attr('name').match(/\[\w+_attributes]/g).pop().match(/\[(\w+)_attributes]/).pop();
296
- name += /(\[\w+])$/.exec(element.attr('name'))[1];
304
+ if (/_attributes\]/.test(element.attr('name'))) {
305
+ name = element.attr('name').match(/\[\w+_attributes\]/g).pop().match(/\[(\w+)_attributes\]/).pop();
306
+ name += /(\[\w+\])$/.exec(element.attr('name'))[1];
297
307
  } else {
298
- var name = element.attr('name');
308
+ name = element.attr('name');
299
309
  }
300
310
 
301
311
  // Override the name if a nested module class is passed
302
312
  if (options['class']) {
303
- name = options['class'] + '[' + name.split('[')[1]
313
+ name = options['class'] + '[' + name.split('[')[1];
304
314
  }
305
315
  data[name] = element.val();
306
316
 
@@ -308,7 +318,7 @@ var clientSideValidations = {
308
318
  url: '/validators/uniqueness',
309
319
  data: data,
310
320
  async: false
311
- }).status == 200) {
321
+ }).status === 200) {
312
322
  return options.message;
313
323
  }
314
324
  }
@@ -317,13 +327,13 @@ var clientSideValidations = {
317
327
  },
318
328
  formBuilders: {
319
329
  'ActionView::Helpers::FormBuilder': {
320
- add: function(element, settings, message) {
321
- if (element.data('valid') !== false && jQuery('label.message[for="' + element.attr('id') + '"]')[0] == undefined) {
330
+ add: function (element, settings, message) {
331
+ if (element.data('valid') !== false && jQuery('label.message[for="' + element.attr('id') + '"]')[0] === undefined) {
322
332
  var inputErrorField = jQuery(settings.input_tag),
323
333
  labelErrorField = jQuery(settings.label_tag),
324
334
  label = jQuery('label[for="' + element.attr('id') + '"]:not(.message)');
325
335
 
326
- if (element.attr('autofocus')) { element.attr('autofocus', false) };
336
+ if (element.attr('autofocus')) { element.attr('autofocus', false); }
327
337
  element.before(inputErrorField);
328
338
  inputErrorField.find('span#input_tag').replaceWith(element);
329
339
  inputErrorField.find('label.message').attr('for', element.attr('id'));
@@ -333,7 +343,7 @@ var clientSideValidations = {
333
343
  }
334
344
  jQuery('label.message[for="' + element.attr('id') + '"]').text(message);
335
345
  },
336
- remove: function(element, settings) {
346
+ remove: function (element, settings) {
337
347
  var errorFieldClass = jQuery(settings.input_tag).attr('class'),
338
348
  inputErrorField = element.closest('.' + errorFieldClass),
339
349
  label = jQuery('label[for="' + element.attr('id') + '"]:not(.message)'),
@@ -347,64 +357,19 @@ var clientSideValidations = {
347
357
  }
348
358
  }
349
359
  },
350
- 'SimpleForm::FormBuilder': {
351
- add: function(element, settings, message) {
352
- if (element.data('valid') !== false) {
353
- var wrapper = element.closest(settings.wrapper_tag);
354
- wrapper.addClass(settings.wrapper_error_class);
355
- var errorElement = $('<' + settings.error_tag + ' class="' + settings.error_class + '">' + message + '</' + settings.error_tag + '>');
356
- wrapper.append(errorElement);
357
- } else {
358
- element.parent().find(settings.error_tag + '.' + settings.error_class).text(message);
359
- }
360
- },
361
- remove: function(element, settings) {
362
- var wrapper = element.closest(settings.wrapper_tag + '.' + settings.wrapper_error_class);
363
- wrapper.removeClass(settings.wrapper_error_class);
364
- var errorElement = wrapper.find(settings.error_tag + '.' + settings.error_class);
365
- errorElement.remove();
366
- }
367
-
368
- },
369
- 'Formtastic::FormBuilder': {
370
- add: function(element, settings, message) {
371
- if (element.data('valid') !== false) {
372
- var wrapper = element.closest('li');
373
- wrapper.addClass('error');
374
- var errorElement = $('<p class="' + settings.inline_error_class + '">' + message + '</p>');
375
- wrapper.append(errorElement);
376
- } else {
377
- element.parent().find('p.' + settings.inline_error_class).text(message);
378
- }
379
- },
380
- remove: function(element, settings) {
381
- var wrapper = element.closest('li.error');
382
- wrapper.removeClass('error');
383
- var errorElement = wrapper.find('p.' + settings.inline_error_class);
384
- errorElement.remove();
385
- }
386
- },
387
- 'NestedForm::Builder': {
388
- add: function(element, settings, message) {
389
- clientSideValidations.formBuilders['ActionView::Helpers::FormBuilder'].add(element, settings, message);
390
- },
391
- remove: function(element, settings, message) {
392
- clientSideValidations.formBuilders['ActionView::Helpers::FormBuilder'].remove(element, settings, message);
393
- }
394
- }
395
360
  },
396
361
  callbacks: {
397
362
  element: {
398
- after: function(element, eventData) { },
399
- before: function(element, eventData) { },
400
- fail: function(element, message, addError, eventData) { addError() },
401
- pass: function(element, removeError, eventData) { removeError() }
363
+ after: function (element, eventData) { },
364
+ before: function (element, eventData) { },
365
+ fail: function (element, message, addError, eventData) { addError(); },
366
+ pass: function (element, removeError, eventData) { removeError(); }
402
367
  },
403
368
  form: {
404
- after: function(form, eventData) { },
405
- before: function(form, eventData) { },
406
- fail: function(form, eventData) { },
407
- pass: function(form, eventData) { }
369
+ after: function (form, eventData) { },
370
+ before: function (form, eventData) { },
371
+ fail: function (form, eventData) { },
372
+ pass: function (form, eventData) { }
408
373
  }
409
374
  }
410
375
  };