simple_form_with_client_validation 0.0.0

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 (99) hide show
  1. data/CHANGELOG.md +6 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +783 -0
  4. data/lib/generators/simple_form_with_client_validation/USAGE +3 -0
  5. data/lib/generators/simple_form_with_client_validation/install_generator.rb +32 -0
  6. data/lib/generators/simple_form_with_client_validation/templates/README +12 -0
  7. data/lib/generators/simple_form_with_client_validation/templates/_form.html.erb +13 -0
  8. data/lib/generators/simple_form_with_client_validation/templates/_form.html.haml +10 -0
  9. data/lib/generators/simple_form_with_client_validation/templates/_form.html.slim +10 -0
  10. data/lib/generators/simple_form_with_client_validation/templates/config/initializers/simple_form.rb.tt +179 -0
  11. data/lib/generators/simple_form_with_client_validation/templates/config/locales/simple_form.en.yml +26 -0
  12. data/lib/simple_form_with_client_validation/action_view_extensions/builder.rb +331 -0
  13. data/lib/simple_form_with_client_validation/action_view_extensions/form_helper.rb +74 -0
  14. data/lib/simple_form_with_client_validation/components/errors.rb +35 -0
  15. data/lib/simple_form_with_client_validation/components/hints.rb +18 -0
  16. data/lib/simple_form_with_client_validation/components/html5.rb +26 -0
  17. data/lib/simple_form_with_client_validation/components/label_input.rb +15 -0
  18. data/lib/simple_form_with_client_validation/components/labels.rb +79 -0
  19. data/lib/simple_form_with_client_validation/components/maxlength.rb +41 -0
  20. data/lib/simple_form_with_client_validation/components/min_max.rb +50 -0
  21. data/lib/simple_form_with_client_validation/components/minlength.rb +41 -0
  22. data/lib/simple_form_with_client_validation/components/pattern.rb +34 -0
  23. data/lib/simple_form_with_client_validation/components/placeholders.rb +16 -0
  24. data/lib/simple_form_with_client_validation/components/readonly.rb +22 -0
  25. data/lib/simple_form_with_client_validation/components.rb +21 -0
  26. data/lib/simple_form_with_client_validation/core_ext/hash.rb +16 -0
  27. data/lib/simple_form_with_client_validation/error_notification.rb +48 -0
  28. data/lib/simple_form_with_client_validation/form_builder.rb +484 -0
  29. data/lib/simple_form_with_client_validation/helpers/autofocus.rb +11 -0
  30. data/lib/simple_form_with_client_validation/helpers/disabled.rb +15 -0
  31. data/lib/simple_form_with_client_validation/helpers/readonly.rb +15 -0
  32. data/lib/simple_form_with_client_validation/helpers/required.rb +35 -0
  33. data/lib/simple_form_with_client_validation/helpers/validators.rb +44 -0
  34. data/lib/simple_form_with_client_validation/helpers.rb +12 -0
  35. data/lib/simple_form_with_client_validation/i18n_cache.rb +22 -0
  36. data/lib/simple_form_with_client_validation/inputs/base.rb +162 -0
  37. data/lib/simple_form_with_client_validation/inputs/block_input.rb +14 -0
  38. data/lib/simple_form_with_client_validation/inputs/boolean_input.rb +64 -0
  39. data/lib/simple_form_with_client_validation/inputs/collection_check_boxes_input.rb +21 -0
  40. data/lib/simple_form_with_client_validation/inputs/collection_input.rb +101 -0
  41. data/lib/simple_form_with_client_validation/inputs/collection_radio_buttons_input.rb +63 -0
  42. data/lib/simple_form_with_client_validation/inputs/collection_select_input.rb +14 -0
  43. data/lib/simple_form_with_client_validation/inputs/date_time_input.rb +28 -0
  44. data/lib/simple_form_with_client_validation/inputs/file_input.rb +9 -0
  45. data/lib/simple_form_with_client_validation/inputs/grouped_collection_select_input.rb +41 -0
  46. data/lib/simple_form_with_client_validation/inputs/hidden_input.rb +17 -0
  47. data/lib/simple_form_with_client_validation/inputs/numeric_input.rb +24 -0
  48. data/lib/simple_form_with_client_validation/inputs/password_input.rb +12 -0
  49. data/lib/simple_form_with_client_validation/inputs/priority_input.rb +24 -0
  50. data/lib/simple_form_with_client_validation/inputs/range_input.rb +14 -0
  51. data/lib/simple_form_with_client_validation/inputs/string_input.rb +23 -0
  52. data/lib/simple_form_with_client_validation/inputs/text_input.rb +11 -0
  53. data/lib/simple_form_with_client_validation/inputs.rb +21 -0
  54. data/lib/simple_form_with_client_validation/map_type.rb +16 -0
  55. data/lib/simple_form_with_client_validation/version.rb +3 -0
  56. data/lib/simple_form_with_client_validation/wrappers/builder.rb +115 -0
  57. data/lib/simple_form_with_client_validation/wrappers/many.rb +78 -0
  58. data/lib/simple_form_with_client_validation/wrappers/root.rb +34 -0
  59. data/lib/simple_form_with_client_validation/wrappers/single.rb +18 -0
  60. data/lib/simple_form_with_client_validation/wrappers.rb +8 -0
  61. data/lib/simple_form_with_client_validation.rb +218 -0
  62. data/test/action_view_extensions/builder_test.rb +577 -0
  63. data/test/action_view_extensions/form_helper_test.rb +104 -0
  64. data/test/components/label_test.rb +310 -0
  65. data/test/form_builder/association_test.rb +177 -0
  66. data/test/form_builder/button_test.rb +47 -0
  67. data/test/form_builder/error_notification_test.rb +79 -0
  68. data/test/form_builder/error_test.rb +121 -0
  69. data/test/form_builder/general_test.rb +356 -0
  70. data/test/form_builder/hint_test.rb +139 -0
  71. data/test/form_builder/input_field_test.rb +63 -0
  72. data/test/form_builder/label_test.rb +71 -0
  73. data/test/form_builder/wrapper_test.rb +149 -0
  74. data/test/generators/simple_form_generator_test.rb +32 -0
  75. data/test/inputs/boolean_input_test.rb +108 -0
  76. data/test/inputs/collection_check_boxes_input_test.rb +224 -0
  77. data/test/inputs/collection_radio_buttons_input_test.rb +326 -0
  78. data/test/inputs/collection_select_input_test.rb +241 -0
  79. data/test/inputs/datetime_input_test.rb +99 -0
  80. data/test/inputs/disabled_test.rb +38 -0
  81. data/test/inputs/discovery_test.rb +61 -0
  82. data/test/inputs/file_input_test.rb +16 -0
  83. data/test/inputs/general_test.rb +69 -0
  84. data/test/inputs/grouped_collection_select_input_test.rb +118 -0
  85. data/test/inputs/hidden_input_test.rb +30 -0
  86. data/test/inputs/numeric_input_test.rb +173 -0
  87. data/test/inputs/priority_input_test.rb +43 -0
  88. data/test/inputs/readonly_test.rb +61 -0
  89. data/test/inputs/required_test.rb +113 -0
  90. data/test/inputs/string_input_test.rb +140 -0
  91. data/test/inputs/text_input_test.rb +29 -0
  92. data/test/simple_form_test.rb +9 -0
  93. data/test/support/discovery_inputs.rb +21 -0
  94. data/test/support/misc_helpers.rb +102 -0
  95. data/test/support/mock_controller.rb +24 -0
  96. data/test/support/mock_response.rb +14 -0
  97. data/test/support/models.rb +210 -0
  98. data/test/test_helper.rb +95 -0
  99. metadata +227 -0
@@ -0,0 +1,74 @@
1
+ module SimpleFormWithClientValidation
2
+ module ActionViewExtensions
3
+ # This module creates SimpleFormWithClientValidation wrappers around default form_for and fields_for.
4
+ #
5
+ # Example:
6
+ #
7
+ # simple_form_for @user do |f|
8
+ # f.input :name, :hint => 'My hint'
9
+ # end
10
+ #
11
+ module FormHelper
12
+ # based on what is done in formtastic
13
+ # http://github.com/justinfrench/formtastic/blob/master/lib/formtastic.rb#L1706
14
+ @@default_field_error_proc = nil
15
+
16
+ # Override the default ActiveRecordHelper behaviour of wrapping the input.
17
+ # This gets taken care of semantically by adding an error class to the wrapper tag
18
+ # containing the input.
19
+ #
20
+ FIELD_ERROR_PROC = proc do |html_tag, instance_tag|
21
+ html_tag
22
+ end
23
+
24
+ def simple_form_for(record, options={}, &block)
25
+ options[:builder] ||= SimpleFormWithClientValidation::FormBuilder
26
+ options[:html] ||= {}
27
+ unless options[:html].key?(:novalidate)
28
+ options[:html][:novalidate] = !SimpleFormWithClientValidation.browser_validations
29
+ end
30
+ options[:html][:class] = [SimpleFormWithClientValidation.form_class, simple_form_css_class(record, options)].compact.join(" ")
31
+
32
+ with_simple_form_field_error_proc do
33
+ form_for(record, options, &block)
34
+ end
35
+ end
36
+
37
+ def simple_fields_for(record_name, record_object = nil, options = {}, &block)
38
+ options, record_object = record_object, nil if record_object.is_a?(Hash) && record_object.extractable_options?
39
+ options[:builder] ||= SimpleFormWithClientValidation::FormBuilder
40
+
41
+ with_simple_form_field_error_proc do
42
+ fields_for(record_name, record_object, options, &block)
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ def with_simple_form_field_error_proc
49
+ @@default_field_error_proc = ::ActionView::Base.field_error_proc
50
+ ::ActionView::Base.field_error_proc = FIELD_ERROR_PROC
51
+ result = yield
52
+ ::ActionView::Base.field_error_proc = @@default_field_error_proc
53
+ result
54
+ end
55
+
56
+ def simple_form_css_class(record, options)
57
+ html_options = options[:html]
58
+ as = options[:as]
59
+
60
+ if html_options.key?(:class)
61
+ html_options[:class]
62
+ elsif record.is_a?(String) || record.is_a?(Symbol)
63
+ as || record
64
+ else
65
+ record = record.last if record.is_a?(Array)
66
+ action = record.respond_to?(:persisted?) && record.persisted? ? :edit : :new
67
+ as ? "#{action}_#{as}" : dom_class(record, action)
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ ActionView::Base.send :include, SimpleFormWithClientValidation::ActionViewExtensions::FormHelper
@@ -0,0 +1,35 @@
1
+ module SimpleFormWithClientValidation
2
+ module Components
3
+ module Errors
4
+ def error
5
+ error_text if has_errors?
6
+ end
7
+
8
+ def has_errors?
9
+ object && object.respond_to?(:errors) && errors.present?
10
+ end
11
+
12
+ protected
13
+
14
+ def error_text
15
+ "#{options[:error_prefix]} #{errors.send(error_method)}".lstrip.html_safe
16
+ end
17
+
18
+ def error_method
19
+ options[:error_method] || SimpleFormWithClientValidation.error_method
20
+ end
21
+
22
+ def errors
23
+ @errors ||= (errors_on_attribute + errors_on_association).compact
24
+ end
25
+
26
+ def errors_on_attribute
27
+ object.errors[attribute_name]
28
+ end
29
+
30
+ def errors_on_association
31
+ reflection ? object.errors[reflection.name] : []
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,18 @@
1
+ module SimpleFormWithClientValidation
2
+ module Components
3
+ # Needs to be enabled in order to do automatic lookups.
4
+ module Hints
5
+ def hint
6
+ @hint ||= begin
7
+ hint = options[:hint]
8
+ hint_content = hint.is_a?(String) ? hint : translate(:hints)
9
+ hint_content.html_safe if hint_content
10
+ end
11
+ end
12
+
13
+ def has_hint?
14
+ hint.present?
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,26 @@
1
+ module SimpleFormWithClientValidation
2
+ module Components
3
+ module HTML5
4
+ def initialize(*)
5
+ @html5 = false
6
+ end
7
+
8
+ def html5
9
+ @html5 = true
10
+ input_html_options[:required] = true if has_required?
11
+ nil
12
+ end
13
+
14
+ def html5?
15
+ @html5
16
+ end
17
+
18
+ def has_required?
19
+ # We need to check browser_validations because
20
+ # some browsers are still checking required even
21
+ # if novalidate was given.
22
+ required_field? && SimpleFormWithClientValidation.browser_validations
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,15 @@
1
+ module SimpleFormWithClientValidation
2
+ module Components
3
+ module LabelInput
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ include SimpleFormWithClientValidation::Components::Labels
8
+ end
9
+
10
+ def label_input
11
+ (options[:label] == false ? "" : label) + input
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,79 @@
1
+ module SimpleFormWithClientValidation
2
+ module Components
3
+ module Labels
4
+ extend ActiveSupport::Concern
5
+
6
+ module ClassMethods #:nodoc:
7
+ def translate_required_html
8
+ i18n_cache :translate_required_html do
9
+ I18n.t(:"simple_form.required.html", :default =>
10
+ %[<abbr title="#{translate_required_text}">#{translate_required_mark}</abbr>]
11
+ )
12
+ end
13
+ end
14
+
15
+ def translate_required_text
16
+ I18n.t(:"simple_form.required.text", :default => 'required')
17
+ end
18
+
19
+ def translate_required_mark
20
+ I18n.t(:"simple_form.required.mark", :default => '*')
21
+ end
22
+ end
23
+
24
+ def label
25
+ if generate_label_for_attribute?
26
+ @builder.label(label_target, label_text, label_html_options)
27
+ else
28
+ template.label_tag(nil, label_text, label_html_options)
29
+ end
30
+ end
31
+
32
+ def label_text
33
+ SimpleFormWithClientValidation.label_text.call(raw_label_text, required_label_text).strip.html_safe
34
+ end
35
+
36
+ def label_target
37
+ attribute_name
38
+ end
39
+
40
+ def label_html_options
41
+ label_html_classes = SimpleFormWithClientValidation.additional_classes_for(:label) {
42
+ [input_type, required_class, SimpleFormWithClientValidation.label_class].compact
43
+ }
44
+
45
+ label_options = html_options_for(:label, label_html_classes)
46
+ if options.key?(:input_html) && options[:input_html].key?(:id)
47
+ label_options[:for] = options[:input_html][:id]
48
+ end
49
+ label_options
50
+ end
51
+
52
+ protected
53
+
54
+ def raw_label_text #:nodoc:
55
+ options[:label] || label_translation
56
+ end
57
+
58
+ # Default required text when attribute is required.
59
+ def required_label_text #:nodoc:
60
+ required_field? ? self.class.translate_required_html.dup : ''
61
+ end
62
+
63
+ # First check labels translation and then human attribute name.
64
+ def label_translation #:nodoc:
65
+ if SimpleFormWithClientValidation.translate_labels && (translated_label = translate(:labels))
66
+ translated_label
67
+ elsif object.class.respond_to?(:human_attribute_name)
68
+ object.class.human_attribute_name(reflection_or_attribute_name.to_s)
69
+ else
70
+ attribute_name.to_s.humanize
71
+ end
72
+ end
73
+
74
+ def generate_label_for_attribute?
75
+ true
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,41 @@
1
+ module SimpleFormWithClientValidation
2
+ module Components
3
+ # Needs to be enabled in order to do automatic lookups.
4
+ module Maxlength
5
+ def maxlength
6
+ input_html_options[:maxlength] ||= maximum_length_from_validation || limit
7
+ nil
8
+ end
9
+
10
+ private
11
+
12
+ def maximum_length_from_validation
13
+ maxlength = options[:maxlength]
14
+ if maxlength.is_a?(String) || maxlength.is_a?(Integer)
15
+ maxlength
16
+ else
17
+ length_validator = find_length_validator
18
+
19
+ if length_validator && !has_tokenizer?(length_validator)
20
+ length_validator.options[:is] || length_validator.options[:maximum]
21
+ end
22
+ end
23
+ end
24
+
25
+ def find_length_validator
26
+ find_validator(ActiveModel::Validations::LengthValidator)
27
+ end
28
+
29
+ def has_tokenizer?(length_validator)
30
+ tokenizer = length_validator.options[:tokenizer]
31
+
32
+ # TODO: Remove this check when we drop Rails 3.0 support
33
+ if ActiveModel::Validations::LengthValidator.const_defined?(:DEFAULT_TOKENIZER)
34
+ tokenizer && tokenizer != ActiveModel::Validations::LengthValidator::DEFAULT_TOKENIZER
35
+ else
36
+ tokenizer
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,50 @@
1
+ module SimpleFormWithClientValidation
2
+ module Components
3
+ module MinMax
4
+ def min_max
5
+ if numeric_validator = find_numericality_validator
6
+ validator_options = numeric_validator.options
7
+ input_html_options[:min] ||= minimum_value(validator_options)
8
+ input_html_options[:max] ||= maximum_value(validator_options)
9
+ end
10
+ nil
11
+ end
12
+
13
+ private
14
+
15
+ def integer?
16
+ input_type == :integer
17
+ end
18
+
19
+ def minimum_value(validator_options)
20
+ if integer? && validator_options.key?(:greater_than)
21
+ evaluate_numericality_validator_option(validator_options[:greater_than]) + 1
22
+ else
23
+ evaluate_numericality_validator_option(validator_options[:greater_than_or_equal_to])
24
+ end
25
+ end
26
+
27
+ def maximum_value(validator_options)
28
+ if integer? && validator_options.key?(:less_than)
29
+ evaluate_numericality_validator_option(validator_options[:less_than]) - 1
30
+ else
31
+ evaluate_numericality_validator_option(validator_options[:less_than_or_equal_to])
32
+ end
33
+ end
34
+
35
+ def find_numericality_validator
36
+ find_validator(ActiveModel::Validations::NumericalityValidator)
37
+ end
38
+
39
+ def evaluate_numericality_validator_option(option)
40
+ if option.is_a?(Numeric)
41
+ option
42
+ elsif option.is_a?(Symbol)
43
+ object.send(option)
44
+ elsif option.respond_to?(:call)
45
+ option.call(object)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,41 @@
1
+ module SimpleFormWithClientValidation
2
+ module Components
3
+ # Needs to be enabled in order to do automatic lookups.
4
+ module Minlength
5
+ def minlength
6
+ input_html_options[:'minlength'] ||= minimum_length_from_validation || 0
7
+ nil
8
+ end
9
+
10
+ private
11
+
12
+ def minimum_length_from_validation
13
+ minlength = options[:minlength]
14
+ if minlength.is_a?(String) || minlength.is_a?(Integer)
15
+ minlength
16
+ else
17
+ length_validator = find_length_validator
18
+
19
+ if length_validator && !has_tokenizer?(length_validator)
20
+ length_validator.options[:is] || length_validator.options[:minimum]
21
+ end
22
+ end
23
+ end
24
+
25
+ def find_length_validator
26
+ find_validator(ActiveModel::Validations::LengthValidator)
27
+ end
28
+
29
+ def has_tokenizer?(length_validator)
30
+ tokenizer = length_validator.options[:tokenizer]
31
+
32
+ # TODO: Remove this check when we drop Rails 3.0 support
33
+ if ActiveModel::Validations::LengthValidator.const_defined?(:DEFAULT_TOKENIZER)
34
+ tokenizer && tokenizer != ActiveModel::Validations::LengthValidator::DEFAULT_TOKENIZER
35
+ else
36
+ tokenizer
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,34 @@
1
+ module SimpleFormWithClientValidation
2
+ module Components
3
+ # Needs to be enabled in order to do automatic lookups.
4
+ module Pattern
5
+ def pattern
6
+ input_html_options[:pattern] ||= pattern_source
7
+ nil
8
+ end
9
+
10
+ private
11
+
12
+ def pattern_source
13
+ pattern = options[:pattern]
14
+ if pattern.is_a?(String)
15
+ pattern
16
+ elsif pattern_validator = find_pattern_validator
17
+ evaluate_format_validator_option(pattern_validator.options[:with]).source
18
+ end
19
+ end
20
+
21
+ def find_pattern_validator
22
+ find_validator(ActiveModel::Validations::FormatValidator)
23
+ end
24
+
25
+ def evaluate_format_validator_option(option)
26
+ if option.respond_to?(:call)
27
+ option.call(object)
28
+ else
29
+ option
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,16 @@
1
+ module SimpleFormWithClientValidation
2
+ module Components
3
+ # Needs to be enabled in order to do automatic lookups.
4
+ module Placeholders
5
+ def placeholder
6
+ input_html_options[:placeholder] ||= placeholder_text
7
+ nil
8
+ end
9
+
10
+ def placeholder_text
11
+ placeholder = options[:placeholder]
12
+ placeholder.is_a?(String) ? placeholder : translate(:placeholders)
13
+ end
14
+ end
15
+ end
16
+ end