pcai_client_side_validations 3.1.5
Sign up to get free protection for your applications and to get access to all the features.
- data/client_side_validations.gemspec +42 -0
- data/lib/client_side_validations.rb +13 -0
- data/lib/client_side_validations/action_view.rb +14 -0
- data/lib/client_side_validations/action_view/form_builder.rb +157 -0
- data/lib/client_side_validations/action_view/form_helper.rb +86 -0
- data/lib/client_side_validations/action_view/form_tag_helper.rb +12 -0
- data/lib/client_side_validations/active_model.rb +60 -0
- data/lib/client_side_validations/active_model/acceptance.rb +10 -0
- data/lib/client_side_validations/active_model/exclusion.rb +15 -0
- data/lib/client_side_validations/active_model/format.rb +10 -0
- data/lib/client_side_validations/active_model/inclusion.rb +15 -0
- data/lib/client_side_validations/active_model/length.rb +24 -0
- data/lib/client_side_validations/active_model/numericality.rb +31 -0
- data/lib/client_side_validations/active_model/presence.rb +10 -0
- data/lib/client_side_validations/active_record.rb +11 -0
- data/lib/client_side_validations/active_record/middleware.rb +33 -0
- data/lib/client_side_validations/active_record/uniqueness.rb +28 -0
- data/lib/client_side_validations/core_ext.rb +3 -0
- data/lib/client_side_validations/core_ext/range.rb +10 -0
- data/lib/client_side_validations/core_ext/regexp.rb +14 -0
- data/lib/client_side_validations/engine.rb +6 -0
- data/lib/client_side_validations/files.rb +8 -0
- data/lib/client_side_validations/formtastic.rb +21 -0
- data/lib/client_side_validations/middleware.rb +81 -0
- data/lib/client_side_validations/mongo_mapper.rb +9 -0
- data/lib/client_side_validations/mongo_mapper/middleware.rb +20 -0
- data/lib/client_side_validations/mongo_mapper/uniqueness.rb +28 -0
- data/lib/client_side_validations/mongoid.rb +9 -0
- data/lib/client_side_validations/mongoid/middleware.rb +20 -0
- data/lib/client_side_validations/mongoid/uniqueness.rb +28 -0
- data/lib/client_side_validations/simple_form.rb +24 -0
- data/lib/client_side_validations/version.rb +3 -0
- data/lib/generators/client_side_validations/copy_asset_generator.rb +36 -0
- data/lib/generators/client_side_validations/install_generator.rb +45 -0
- data/lib/generators/templates/client_side_validations/README.rails.3.0 +6 -0
- data/lib/generators/templates/client_side_validations/README.rails.3.1 +7 -0
- data/lib/generators/templates/client_side_validations/initializer.rb +14 -0
- data/vendor/assets/javascripts/rails.validations.js +410 -0
- 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
|
+
|