summaryrefslogtreecommitdiff
path: root/config/initializers/leaguer_html5_autovalidation.rb
blob: 7c31bb20b1a1ed4df87a7466f9ecdf30492b359e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
module ActionView
	module Helpers
		module Tags
			class Base
				def initialize_with_html5_validators(object_name, method_name, template_object, options = {})
					initialize_without_html5_validators(object_name, method_name, template_object, options = {})

					if /(Area|Button|Box|Field|Select)$/ =~ self.class.name
						inject_html5_validators(@object._validators[@method_name.to_sym])
						if @method_name.to_s.end_with?("_confirmation")
							orig_method_name = @method_name.to_s.sub(/_confirmation$/,'').to_sym
							if @object._validators[orig_method_name].any?{|v|v.is_a?(ActiveModel::Validations::ConfirmationValidator)}
								inject_html5_validators(@object._validators[orig_method_name])
							end
						end
					end
				end
				alias_method_chain :initialize, :html5_validators

				private

				def inject_html5_validators(validators = [])
					validators.each do |v|
						# XXX: evaluate :if/:unless?
						if (v.options.keys & [:if, :unless]).empty?
							case v
							when ActiveModel::Validations::AbsenceValidator
								# The opposite of required
								# XXX: perhaps disable the input?
							when ActiveModel::Validations::AcceptanceValidator
								# XXX: If in a text-ish input, perhaps create a pattern from :accept?
								@options[:required] = :required
							when ActiveRecord::Validations::AssociatedValidator
								# Can't possibly do anything here
							when ActiveModel::Validations::ConfirmationValidator
								# Do nothing here
							when ActiveModel::Validations::ExclusionValidator
								# XXX: There is no simple way to do this.
							when ActiveModel::Validations::FormatValidator
								# XXX: Does not support :without
								if v.options[:with] and not v.options[:with].is_a?(Proc)
									pattern = v.options[:with].source.sub(/^\\A/,'').sub(/\\[Zz]$/,'')
									pattern = "(|#{pattern})" if (v.options[:allow_nil] or v.options[:allow_blank])
									@options[:pattern] = pattern
								end
							when ActiveModel::Validations::InclusionValidator
								# XXX: There is no simple way to do this.
							when ActiveModel::Validations::LengthValidator
								@options[:minlength] = v.options[:minimum] if v.options[:minimum]
								@options[:maxlength] = v.options[:maximum] if v.options[:maximum]
							when ActiveModel::Validations::NumericalityValidator
								# XXX: Does not support :other_than
								# XXX: Does not correctly handle any of these things being a Proc
								@options[:required] = :required unless v.options[:allow_nil]
								@options[:step] = 1 if v.options[:only_integer]

								if v.options[:greater_than]
									if @options[:step] or v.options[:even] or v.options[:odd]
										@options[:min] = v.options[:greater_than] + 1
									else
										# Floating point limit BS
										@options[:min] = v.options[:greater_than]
									end
								end
								if v.options[:greater_than_or_equal_to]
									@options[:min] = v.options[:greater_than_or_equal_to]
								end

								if v.options[:less_than]
									if @options[:step] or v.options[:even] or v.options[:odd]
										@options[:max] = v.options[:less_than] - 1
									else
										# Floating point limit BS
										@options[:max] = v.options[:less_than]
									end
								end
								if v.options[:less_than_or_equal_to]
									@options[:max] = v.options[:less_than_or_equal_to]
								end
								
								if v.options[:equal_to]
									@options[:min] = @options[:max] = v.options[:equal_to]
								end

								if v.options[:even] and @options[:min]
									@options[:min] = @options[:min] + @options[:min] % 2
									@options[:step] = 2
								end
								if v.options[:odd] and @options[:min]
									@options[:min] = @options[:min] + (@options[:min]+1) % 2
									@options[:step] = 2
								end
							when ActiveModel::Validations::PresenceValidator, ActiveRecord::Validations::PresenceValidator
								@options[:required] = :required
							when ActiveRecord::Validations::UniquenessValidator
								# Can't do this without making network calls
							when ActiveModel::Validations::WithValidator
								# Just here for completeness; can't possibly do anything
							end # case
						end # if
					end # each
				end # def
			end # class Base
		end # module Tags
	end # module Helpers
end # module ActionView