pcai_client_side_validations 3.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+