pcai_client_side_validations 3.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/client_side_validations.gemspec +42 -0
  2. data/lib/client_side_validations.rb +13 -0
  3. data/lib/client_side_validations/action_view.rb +14 -0
  4. data/lib/client_side_validations/action_view/form_builder.rb +157 -0
  5. data/lib/client_side_validations/action_view/form_helper.rb +86 -0
  6. data/lib/client_side_validations/action_view/form_tag_helper.rb +12 -0
  7. data/lib/client_side_validations/active_model.rb +60 -0
  8. data/lib/client_side_validations/active_model/acceptance.rb +10 -0
  9. data/lib/client_side_validations/active_model/exclusion.rb +15 -0
  10. data/lib/client_side_validations/active_model/format.rb +10 -0
  11. data/lib/client_side_validations/active_model/inclusion.rb +15 -0
  12. data/lib/client_side_validations/active_model/length.rb +24 -0
  13. data/lib/client_side_validations/active_model/numericality.rb +31 -0
  14. data/lib/client_side_validations/active_model/presence.rb +10 -0
  15. data/lib/client_side_validations/active_record.rb +11 -0
  16. data/lib/client_side_validations/active_record/middleware.rb +33 -0
  17. data/lib/client_side_validations/active_record/uniqueness.rb +28 -0
  18. data/lib/client_side_validations/core_ext.rb +3 -0
  19. data/lib/client_side_validations/core_ext/range.rb +10 -0
  20. data/lib/client_side_validations/core_ext/regexp.rb +14 -0
  21. data/lib/client_side_validations/engine.rb +6 -0
  22. data/lib/client_side_validations/files.rb +8 -0
  23. data/lib/client_side_validations/formtastic.rb +21 -0
  24. data/lib/client_side_validations/middleware.rb +81 -0
  25. data/lib/client_side_validations/mongo_mapper.rb +9 -0
  26. data/lib/client_side_validations/mongo_mapper/middleware.rb +20 -0
  27. data/lib/client_side_validations/mongo_mapper/uniqueness.rb +28 -0
  28. data/lib/client_side_validations/mongoid.rb +9 -0
  29. data/lib/client_side_validations/mongoid/middleware.rb +20 -0
  30. data/lib/client_side_validations/mongoid/uniqueness.rb +28 -0
  31. data/lib/client_side_validations/simple_form.rb +24 -0
  32. data/lib/client_side_validations/version.rb +3 -0
  33. data/lib/generators/client_side_validations/copy_asset_generator.rb +36 -0
  34. data/lib/generators/client_side_validations/install_generator.rb +45 -0
  35. data/lib/generators/templates/client_side_validations/README.rails.3.0 +6 -0
  36. data/lib/generators/templates/client_side_validations/README.rails.3.1 +7 -0
  37. data/lib/generators/templates/client_side_validations/initializer.rb +14 -0
  38. data/vendor/assets/javascripts/rails.validations.js +410 -0
  39. metadata +226 -0
@@ -0,0 +1,42 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "client_side_validations/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "pcai_client_side_validations"
7
+ s.version = ClientSideValidations::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Brian Cardarella"]
10
+ s.email = ["bcardarella@gmail.com"]
11
+ s.homepage = "https://github.com/bcardarella/client_side_validations"
12
+ s.summary = %q{Client Side Validations}
13
+ s.description = %q{Client Side Validations}
14
+
15
+ s.files = Dir.glob("{lib}/**/*") + Dir.glob("{vendor}/**/*") + Dir.glob("*.gemspec")
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
+ s.require_paths = ["lib"]
19
+
20
+ s.add_development_dependency 'rails', '~> 3.1.0'
21
+ s.add_development_dependency 'sqlite3'
22
+ s.add_development_dependency 'bson_ext'
23
+ s.add_development_dependency 'mongoid', '~> 2.0.0'
24
+ s.add_development_dependency 'mongo_mapper','~> 0.9.0'
25
+ 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
+
29
+ # For QUnit testing
30
+ s.add_development_dependency 'sinatra', '~> 1.0'
31
+ s.add_development_dependency 'shotgun'
32
+ s.add_development_dependency 'thin'
33
+ s.add_development_dependency 'json'
34
+
35
+ ruby_minor_version = RUBY_VERSION.split('.')[1].to_i
36
+ if ruby_minor_version == 8
37
+ s.add_development_dependency 'minitest'
38
+ s.add_development_dependency 'ruby-debug'
39
+ elsif ruby_minor_version == 9
40
+ s.add_development_dependency 'ruby-debug19'
41
+ end
42
+ end
@@ -0,0 +1,13 @@
1
+ module ClientSideValidations
2
+ end
3
+
4
+ require 'client_side_validations/active_model' if defined?(::ActiveModel)
5
+ 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
+ require 'client_side_validations/action_view' if defined?(::ActionView)
9
+ if defined?(::Rails)
10
+ require 'client_side_validations/middleware'
11
+ require 'client_side_validations/engine'
12
+ end
13
+
@@ -0,0 +1,14 @@
1
+ module ClientSideValidations::ActionView
2
+ module Helpers
3
+ end
4
+ end
5
+
6
+ require 'client_side_validations/core_ext'
7
+ require 'client_side_validations/action_view/form_helper'
8
+ require 'client_side_validations/action_view/form_tag_helper'
9
+ require 'client_side_validations/action_view/form_builder'
10
+
11
+ ActionView::Base.send(:include, ClientSideValidations::ActionView::Helpers::FormHelper)
12
+ ActionView::Base.send(:include, ClientSideValidations::ActionView::Helpers::FormTagHelper)
13
+ ActionView::Helpers::FormBuilder.send(:include, ClientSideValidations::ActionView::Helpers::FormBuilder)
14
+
@@ -0,0 +1,157 @@
1
+ module ClientSideValidations::ActionView::Helpers
2
+ module FormBuilder
3
+
4
+ def self.included(base)
5
+ (base.field_helpers.map(&:to_s) - %w(apply_form_for_options! label check_box radio_button fields_for hidden_field)).each do |selector|
6
+ base.class_eval <<-RUBY_EVAL
7
+ def #{selector}_with_client_side_validations(method, options = {})
8
+ apply_client_side_validators(method, options)
9
+ options.delete(:validate)
10
+ #{selector}_without_client_side_validations(method, options)
11
+ end
12
+ RUBY_EVAL
13
+
14
+ base.class_eval { alias_method_chain selector, :client_side_validations }
15
+ end
16
+
17
+ base.class_eval do
18
+ alias_method_chain :initialize, :client_side_validations
19
+ alias_method_chain :fields_for, :client_side_validations
20
+ alias_method_chain :check_box, :client_side_validations
21
+ alias_method_chain :radio_button, :client_side_validations
22
+ alias_method_chain :select, :client_side_validations
23
+ alias_method_chain :collection_select, :client_side_validations
24
+ alias_method_chain :grouped_collection_select, :client_side_validations
25
+ alias_method_chain :time_zone_select, :client_side_validations
26
+
27
+ def self.client_side_form_settings(options, form_helper)
28
+ {
29
+ :type => self.to_s,
30
+ :input_tag => form_helper.class.field_error_proc.call(%{<span id="input_tag" />}, Struct.new(:error_message, :tag_id).new([], "")),
31
+ :label_tag => form_helper.class.field_error_proc.call(%{<label id="label_tag" />}, Struct.new(:error_message, :tag_id).new([], ""))
32
+ }
33
+ end
34
+ end
35
+ end
36
+
37
+ def initialize_with_client_side_validations(object_name, object, template, options, proc)
38
+ initialize_without_client_side_validations(object_name, object, template, options, proc)
39
+ @options[:validators] = {}
40
+ end
41
+
42
+ def fields_for_with_client_side_validations(record_or_name_or_array, *args, &block)
43
+ options = args.extract_options!
44
+ options[:validate] ||= @options[:validate] if @options[:validate] && !options.key?(:validate)
45
+ fields_for_without_client_side_validations(record_or_name_or_array, *(args << options), &block)
46
+ end
47
+
48
+ def check_box_with_client_side_validations(method, options = {}, checked_value = "1", unchecked_value = "0")
49
+ apply_client_side_validators(method, options)
50
+ check_box_without_client_side_validations(method, options, checked_value, unchecked_value)
51
+ end
52
+
53
+ def radio_button_with_client_side_validations(method, tag_value, options = {})
54
+ apply_client_side_validators(method, options)
55
+ radio_button_without_client_side_validations(method, tag_value, options)
56
+ end
57
+
58
+ def select_with_client_side_validations(method, choices, options = {}, html_options = {})
59
+ apply_client_side_validators(method, html_options)
60
+ select_without_client_side_validations(method, choices, options, html_options)
61
+ end
62
+
63
+ def collection_select_with_client_side_validations(method, collection, value_method, text_method, options = {}, html_options = {})
64
+ apply_client_side_validators(method, html_options)
65
+ collection_select_without_client_side_validations(method, collection, value_method, text_method, options, html_options)
66
+ end
67
+
68
+ def grouped_collection_select_with_client_side_validations(method, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, html_options = {})
69
+ apply_client_side_validators(method, html_options)
70
+ grouped_collection_select_without_client_side_validations(method, collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options)
71
+ end
72
+
73
+ def time_zone_select_with_client_side_validations(method, priority_zones = nil, options = {}, html_options = {})
74
+ apply_client_side_validators(method, html_options)
75
+ time_zone_select_without_client_side_validations(method, priority_zones = nil, options, html_options)
76
+ end
77
+
78
+ private
79
+
80
+ def apply_client_side_validators(method, options = {})
81
+ if @options[:validate] && options[:validate] != false && validators = filter_validators(method, options[:validate])
82
+ options.merge!("data-validate" => true)
83
+ @options[:validators].merge!("#{@object_name}[#{method}]#{options[:multiple] ? "[]" : nil}" => validators)
84
+ end
85
+ end
86
+
87
+ def filter_validators(method, filters)
88
+ if validators = @object.client_side_validation_hash[method]
89
+ unfiltered_validators = validators.inject({}) do |unfiltered_validators, validator|
90
+ unfiltered_validators[validator.first] = validator.last
91
+ if has_filter_for_validator?(validator, filters)
92
+ if filter_validator?(validator, filters)
93
+ unfiltered_validators.delete(validator.first)
94
+ elsif force_validator_despite_conditional?(validator, filters) && !can_run_validator?(validator, method)
95
+ unfiltered_validators.delete(validator.first)
96
+ end
97
+ else
98
+ if (conditional = (validator.last[:if] || validator.last[:unless])) && conditional.is_a?(Symbol) && !conditional_method_is_change_method?(conditional, method)
99
+ unfiltered_validators.delete(validator.first)
100
+ end
101
+ end
102
+ unfiltered_validators[validator.first].delete(:if) if unfiltered_validators[validator.first]
103
+ unfiltered_validators[validator.first].delete(:unless) if unfiltered_validators[validator.first]
104
+ unfiltered_validators
105
+ end
106
+
107
+ unfiltered_validators.empty? ? nil : unfiltered_validators
108
+ end
109
+ end
110
+
111
+ def has_filter_for_validator?(validator, filters)
112
+ filters && (filters == true || filters.key?(validator.first))
113
+ end
114
+
115
+ def filter_validator?(validator, filters)
116
+ filters != true && filters[validator.first] == false
117
+ end
118
+
119
+ def force_validator_despite_conditional?(validator, filters)
120
+ filters == true || filters[validator.first] == true
121
+ end
122
+
123
+ def can_run_validator?(validator, method)
124
+ result = true
125
+ if_result = run_if_validator(validator.last[:if], method)
126
+ unless_result = run_unless_validator(validator.last[:unless], method)
127
+ result = result && if_result unless if_result.nil?
128
+ result = result && unless_result unless unless_result.nil?
129
+ result
130
+ end
131
+
132
+ def run_if_validator(conditional, method)
133
+ if conditional
134
+ if conditional.is_a?(Symbol)
135
+ conditional_method_is_change_method?(conditional, method) ? true : !!@object.send(conditional)
136
+ else
137
+ !!conditional.call(@object)
138
+ end
139
+ end
140
+ end
141
+
142
+ def run_unless_validator(conditional, method)
143
+ if conditional
144
+ if conditional.is_a?(Symbol)
145
+ conditional_method_is_change_method?(conditional, method) ? true : !@object.send(conditional)
146
+ else
147
+ !conditional.call(@object)
148
+ end
149
+ end
150
+ end
151
+
152
+ def conditional_method_is_change_method?(conditional, method)
153
+ conditional.to_sym == "#{method}_changed?".to_sym
154
+ end
155
+ end
156
+ end
157
+
@@ -0,0 +1,86 @@
1
+ module ClientSideValidations::ActionView::Helpers
2
+ module FormHelper
3
+ class Error < StandardError; end
4
+
5
+ def form_for(record_or_name_or_array, *args, &proc)
6
+ options = args.extract_options!
7
+ if options[:validate]
8
+
9
+ content_for_name = options[:validate] unless options[:validate] == true
10
+
11
+ # Always turn off HTML5 Validations
12
+ options[:html] ||= {}
13
+ options[:html][:novalidate] = 'novalidate'
14
+
15
+ case record_or_name_or_array
16
+ when String, Symbol
17
+ raise ClientSideValidations::ActionView::Helpers::FormHelper::Error, 'Using form_for(:name, @resource) is deprecated in Rails and is not supported with ClientSideValidations. Please use form_for(@resource, :as => :name) instead.'
18
+ when Array
19
+ object = record_or_name_or_array.last
20
+ else
21
+ object = record_or_name_or_array
22
+ end
23
+ end
24
+
25
+ @validators = {}
26
+ # Order matters here. Rails mutates the options object
27
+ script = client_side_form_settings(object, options)
28
+ form = super(record_or_name_or_array, *(args << options), &proc)
29
+ # Because of the load order requirement above this sub is necessary
30
+ # Would be nice to not do this
31
+ script = insert_validators_into_script(script)
32
+ if content_for_name
33
+ content_for(content_for_name) { script.html_safe }
34
+ script = nil
35
+ end
36
+ "#{form}#{script}".html_safe
37
+ end
38
+
39
+ def apply_form_for_options!(object_or_array, options)
40
+ super
41
+ options[:html][:validate] = true if options[:validate]
42
+ end
43
+
44
+ def fields_for(record_or_name_or_array, *args, &block)
45
+ output = super
46
+ @validators.merge!(args.last ? args.last[:validators] : {}) if @validators
47
+ output
48
+ end
49
+
50
+ private
51
+
52
+ def insert_validators_into_script(script)
53
+ # There is probably a more performant way of doing this
54
+ # But using String#sub has some issues. Undocumented "features"
55
+ if script
56
+ script = script.split(/"validator_hash"/)
57
+ script = "#{script[0]}#{@validators.to_json}#{script[1]}"
58
+ end
59
+
60
+ script
61
+ end
62
+
63
+ def client_side_form_settings(object, options)
64
+ if options[:validate]
65
+ builder = options[:builder] || ActionView::Base.default_form_builder
66
+
67
+ if options[:html] && options[:html][:id]
68
+ var_name = options[:html][:id]
69
+ else
70
+ var_name = if object.respond_to?(:persisted?) && object.persisted?
71
+ options[:as] ? "#{options[:as]}_edit" : dom_id(object, :edit)
72
+ else
73
+ options[:as] ? "#{options[:as]}_new" : dom_id(object)
74
+ end
75
+ end
76
+
77
+ content_tag(:script) do
78
+ "window['#{var_name}'] = #{builder.client_side_form_settings(options, self).merge(:validators => 'validator_hash').to_json};".html_safe
79
+ end
80
+
81
+ end
82
+ end
83
+
84
+ end
85
+ end
86
+
@@ -0,0 +1,12 @@
1
+ module ClientSideValidations::ActionView::Helpers
2
+ module FormTagHelper
3
+ private
4
+ def html_options_for_form(url_for_options, options, *parameters_for_url)
5
+ options.stringify_keys!
6
+ html_options = {}
7
+ html_options['data-validate'] = options.delete('validate') if options['validate']
8
+ html_options.merge!(super(url_for_options, options, *parameters_for_url))
9
+ end
10
+ end
11
+ end
12
+
@@ -0,0 +1,60 @@
1
+ require 'client_side_validations/core_ext'
2
+
3
+ module ClientSideValidations::ActiveModel
4
+ module Validator
5
+
6
+ def client_side_hash(model, attribute)
7
+ options = self.options.dup
8
+ { :message => model.errors.generate_message(attribute, message_type, options) }.merge(options.except(*::ActiveModel::Errors::CALLBACKS_OPTIONS - [:allow_blank, :if, :unless]))
9
+ end
10
+
11
+ private
12
+
13
+ def message_type
14
+ kind
15
+ end
16
+ end
17
+
18
+ module Validations
19
+ def client_side_validation_hash
20
+ @client_side_validation_hash ||= _validators.inject({}) do |attr_hash, attr|
21
+ unless [nil, :block].include?(attr[0])
22
+
23
+ validator_hash = attr[1].inject({}) do |kind_hash, validator|
24
+ client_side_hash = validator.client_side_hash(self, attr[0])
25
+ # Yeah yeah, #new_record? is not part of ActiveModel :p
26
+ if (can_use_for_client_side_validation?(client_side_hash, validator))
27
+ kind_hash.merge!(validator.kind => client_side_hash.except(:on))
28
+ else
29
+ kind_hash.merge!({})
30
+ end
31
+ end
32
+
33
+ if validator_hash.present?
34
+ attr_hash.merge!(attr[0] => validator_hash)
35
+ else
36
+ attr_hash
37
+ end
38
+ else
39
+ attr_hash
40
+ end
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def can_use_for_client_side_validation?(client_side_hash, validator)
47
+ ((self.respond_to?(:new_record?) && validator.options[:on] == (self.new_record? ? :create : :update)) || validator.options[:on].nil?) && validator.kind != :block
48
+ end
49
+ end
50
+ end
51
+
52
+ ActiveModel::Validator.send(:include, ClientSideValidations::ActiveModel::Validator)
53
+ ActiveModel::Validations.send(:include, ClientSideValidations::ActiveModel::Validations)
54
+
55
+ %w{acceptance exclusion inclusion length format numericality presence}.each do |validator|
56
+ require "client_side_validations/active_model/#{validator}"
57
+ validator.capitalize!
58
+ eval "ActiveModel::Validations::#{validator}Validator.send(:include, ClientSideValidations::ActiveModel::#{validator})"
59
+ end
60
+
@@ -0,0 +1,10 @@
1
+ module ClientSideValidations::ActiveModel
2
+ module Acceptance
3
+ private
4
+
5
+ def message_type
6
+ :accepted
7
+ end
8
+ end
9
+ end
10
+
@@ -0,0 +1,15 @@
1
+ module ClientSideValidations::ActiveModel
2
+ module Exclusion
3
+
4
+ def client_side_hash(model, attribute)
5
+ hash = super
6
+ if hash[:in].is_a?(Range)
7
+ hash[:range] = hash[:in]
8
+ hash.delete(:in)
9
+ end
10
+ hash
11
+ end
12
+
13
+ end
14
+ end
15
+
@@ -0,0 +1,10 @@
1
+ module ClientSideValidations::ActiveModel
2
+ module Format
3
+ private
4
+
5
+ def message_type
6
+ :invalid
7
+ end
8
+ end
9
+ end
10
+
@@ -0,0 +1,15 @@
1
+ module ClientSideValidations::ActiveModel
2
+ module Inclusion
3
+
4
+ def client_side_hash(model, attribute)
5
+ hash = super
6
+ if hash[:in].is_a?(Range)
7
+ hash[:range] = hash[:in]
8
+ hash.delete(:in)
9
+ end
10
+ hash
11
+ end
12
+
13
+ end
14
+ end
15
+