simple_form 3.0.1 → 4.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 (103) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +149 -25
  3. data/MIT-LICENSE +1 -1
  4. data/README.md +441 -107
  5. data/lib/generators/simple_form/install_generator.rb +4 -3
  6. data/lib/generators/simple_form/templates/README +4 -5
  7. data/lib/generators/simple_form/templates/_form.html.erb +2 -0
  8. data/lib/generators/simple_form/templates/_form.html.haml +2 -0
  9. data/lib/generators/simple_form/templates/_form.html.slim +1 -0
  10. data/lib/generators/simple_form/templates/config/initializers/simple_form.rb +48 -11
  11. data/lib/generators/simple_form/templates/config/initializers/simple_form_bootstrap.rb +417 -23
  12. data/lib/generators/simple_form/templates/config/initializers/simple_form_foundation.rb +101 -5
  13. data/lib/generators/simple_form/templates/config/locales/simple_form.en.yml +7 -2
  14. data/lib/simple_form/action_view_extensions/builder.rb +2 -0
  15. data/lib/simple_form/action_view_extensions/form_helper.rb +10 -3
  16. data/lib/simple_form/components/errors.rb +38 -3
  17. data/lib/simple_form/components/hints.rb +3 -2
  18. data/lib/simple_form/components/html5.rb +16 -5
  19. data/lib/simple_form/components/label_input.rb +21 -2
  20. data/lib/simple_form/components/labels.rb +22 -11
  21. data/lib/simple_form/components/maxlength.rb +9 -5
  22. data/lib/simple_form/components/min_max.rb +2 -1
  23. data/lib/simple_form/components/minlength.rb +38 -0
  24. data/lib/simple_form/components/pattern.rb +2 -1
  25. data/lib/simple_form/components/placeholders.rb +4 -3
  26. data/lib/simple_form/components/readonly.rb +2 -1
  27. data/lib/simple_form/components.rb +2 -0
  28. data/lib/simple_form/error_notification.rb +1 -0
  29. data/lib/simple_form/form_builder.rb +193 -80
  30. data/lib/simple_form/helpers/autofocus.rb +1 -0
  31. data/lib/simple_form/helpers/disabled.rb +1 -0
  32. data/lib/simple_form/helpers/readonly.rb +1 -0
  33. data/lib/simple_form/helpers/required.rb +1 -0
  34. data/lib/simple_form/helpers/validators.rb +2 -1
  35. data/lib/simple_form/helpers.rb +6 -5
  36. data/lib/simple_form/i18n_cache.rb +1 -0
  37. data/lib/simple_form/inputs/base.rb +57 -14
  38. data/lib/simple_form/inputs/block_input.rb +2 -1
  39. data/lib/simple_form/inputs/boolean_input.rb +39 -16
  40. data/lib/simple_form/inputs/collection_check_boxes_input.rb +2 -1
  41. data/lib/simple_form/inputs/collection_input.rb +37 -14
  42. data/lib/simple_form/inputs/collection_radio_buttons_input.rb +9 -13
  43. data/lib/simple_form/inputs/collection_select_input.rb +5 -2
  44. data/lib/simple_form/inputs/date_time_input.rb +24 -9
  45. data/lib/simple_form/inputs/file_input.rb +5 -2
  46. data/lib/simple_form/inputs/grouped_collection_select_input.rb +16 -3
  47. data/lib/simple_form/inputs/hidden_input.rb +5 -2
  48. data/lib/simple_form/inputs/numeric_input.rb +6 -4
  49. data/lib/simple_form/inputs/password_input.rb +6 -3
  50. data/lib/simple_form/inputs/priority_input.rb +5 -2
  51. data/lib/simple_form/inputs/range_input.rb +2 -1
  52. data/lib/simple_form/inputs/string_input.rb +6 -3
  53. data/lib/simple_form/inputs/text_input.rb +6 -3
  54. data/lib/simple_form/inputs.rb +1 -0
  55. data/lib/simple_form/map_type.rb +1 -0
  56. data/lib/simple_form/railtie.rb +8 -0
  57. data/lib/simple_form/tags.rb +7 -0
  58. data/lib/simple_form/version.rb +2 -1
  59. data/lib/simple_form/wrappers/builder.rb +7 -6
  60. data/lib/simple_form/wrappers/leaf.rb +29 -0
  61. data/lib/simple_form/wrappers/many.rb +7 -6
  62. data/lib/simple_form/wrappers/root.rb +3 -1
  63. data/lib/simple_form/wrappers/single.rb +7 -4
  64. data/lib/simple_form/wrappers.rb +2 -0
  65. data/lib/simple_form.rb +117 -18
  66. data/test/action_view_extensions/builder_test.rb +42 -41
  67. data/test/action_view_extensions/form_helper_test.rb +36 -16
  68. data/test/components/custom_components_test.rb +62 -0
  69. data/test/components/label_test.rb +70 -41
  70. data/test/form_builder/association_test.rb +79 -37
  71. data/test/form_builder/button_test.rb +11 -10
  72. data/test/form_builder/error_notification_test.rb +2 -1
  73. data/test/form_builder/error_test.rb +173 -24
  74. data/test/form_builder/general_test.rb +171 -73
  75. data/test/form_builder/hint_test.rb +24 -18
  76. data/test/form_builder/input_field_test.rb +132 -56
  77. data/test/form_builder/label_test.rb +68 -13
  78. data/test/form_builder/wrapper_test.rb +190 -22
  79. data/test/generators/simple_form_generator_test.rb +8 -7
  80. data/test/inputs/boolean_input_test.rb +89 -6
  81. data/test/inputs/collection_check_boxes_input_test.rb +109 -25
  82. data/test/inputs/collection_radio_buttons_input_test.rb +168 -54
  83. data/test/inputs/collection_select_input_test.rb +183 -77
  84. data/test/inputs/datetime_input_test.rb +131 -50
  85. data/test/inputs/disabled_test.rb +16 -15
  86. data/test/inputs/discovery_test.rb +58 -6
  87. data/test/inputs/file_input_test.rb +3 -2
  88. data/test/inputs/general_test.rb +23 -22
  89. data/test/inputs/grouped_collection_select_input_test.rb +54 -17
  90. data/test/inputs/hidden_input_test.rb +5 -4
  91. data/test/inputs/numeric_input_test.rb +48 -44
  92. data/test/inputs/priority_input_test.rb +23 -14
  93. data/test/inputs/readonly_test.rb +20 -19
  94. data/test/inputs/required_test.rb +58 -13
  95. data/test/inputs/string_input_test.rb +62 -33
  96. data/test/inputs/text_input_test.rb +20 -7
  97. data/test/simple_form_test.rb +9 -0
  98. data/test/support/discovery_inputs.rb +33 -2
  99. data/test/support/misc_helpers.rb +113 -5
  100. data/test/support/mock_controller.rb +7 -1
  101. data/test/support/models.rb +137 -37
  102. data/test/test_helper.rb +15 -1
  103. metadata +25 -33
@@ -1,48 +1,58 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
3
  module Inputs
3
4
  class BooleanInput < Base
4
- def input
5
+ def input(wrapper_options = nil)
6
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
7
+
5
8
  if nested_boolean_style?
6
9
  build_hidden_field_for_checkbox +
7
- template.label_tag(nil, class: "checkbox") {
8
- build_check_box_without_hidden_field + inline_label
10
+ template.label_tag(nil, class: boolean_label_class) {
11
+ build_check_box_without_hidden_field(merged_input_options) +
12
+ inline_label
9
13
  }
10
14
  else
11
- build_check_box
15
+ build_check_box(unchecked_value, merged_input_options)
12
16
  end
13
17
  end
14
18
 
15
- def label_input
16
- if options[:label] == false
17
- input
19
+ def label_input(wrapper_options = nil)
20
+ if options[:label] == false || inline_label?
21
+ input(wrapper_options)
18
22
  elsif nested_boolean_style?
19
23
  html_options = label_html_options.dup
20
24
  html_options[:class] ||= []
21
- html_options[:class].push(:checkbox)
25
+ html_options[:class].push(boolean_label_class) if boolean_label_class
26
+
27
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
22
28
 
23
29
  build_hidden_field_for_checkbox +
24
30
  @builder.label(label_target, html_options) {
25
- build_check_box_without_hidden_field + label_text
31
+ build_check_box_without_hidden_field(merged_input_options) + label_text
26
32
  }
27
33
  else
28
- input + label
34
+ input(wrapper_options) + label(wrapper_options)
29
35
  end
30
36
  end
31
37
 
32
38
  private
33
39
 
40
+ def boolean_label_class
41
+ options[:boolean_label_class] || SimpleForm.boolean_label_class
42
+ end
43
+
34
44
  # Build a checkbox tag using default unchecked value. This allows us to
35
45
  # reuse the method for nested boolean style, but with no unchecked value,
36
46
  # which won't generate the hidden checkbox. This is the default functionality
37
47
  # in Rails > 3.2.1, and is backported in SimpleForm AV helpers.
38
- def build_check_box(unchecked_value = unchecked_value)
39
- @builder.check_box(attribute_name, input_html_options, checked_value, unchecked_value)
48
+ def build_check_box(unchecked_value, options)
49
+ @builder.check_box(attribute_name, options, checked_value, unchecked_value)
40
50
  end
41
51
 
42
52
  # Build a checkbox without generating the hidden field. See
43
53
  # #build_hidden_field_for_checkbox for more info.
44
- def build_check_box_without_hidden_field
45
- build_check_box(nil)
54
+ def build_check_box_without_hidden_field(options)
55
+ build_check_box(nil, options)
46
56
  end
47
57
 
48
58
  # Create a hidden field for the current checkbox, so we can simulate Rails
@@ -50,15 +60,24 @@ module SimpleForm
50
60
  # we need the hidden field to be *outside* the label (otherwise it
51
61
  # generates invalid html - html5 only).
52
62
  def build_hidden_field_for_checkbox
63
+ return "" if !include_hidden? || !unchecked_value
53
64
  options = { value: unchecked_value, id: nil, disabled: input_html_options[:disabled] }
54
- options[:name] = input_html_options[:name] if input_html_options.has_key?(:name)
65
+ options[:name] = input_html_options[:name] if input_html_options.key?(:name)
55
66
 
56
67
  @builder.hidden_field(attribute_name, options)
57
68
  end
58
69
 
70
+ def inline_label?
71
+ nested_boolean_style? && options[:inline_label]
72
+ end
73
+
59
74
  def inline_label
60
75
  inline_option = options[:inline_label]
61
- inline_option == true ? label_text : inline_option
76
+
77
+ if inline_option
78
+ label = inline_option == true ? label_text : html_escape(inline_option)
79
+ " #{label}".html_safe
80
+ end
62
81
  end
63
82
 
64
83
  # Booleans are not required by default because in most of the cases
@@ -68,6 +87,10 @@ module SimpleForm
68
87
  false
69
88
  end
70
89
 
90
+ def include_hidden?
91
+ options.fetch(:include_hidden, true)
92
+ end
93
+
71
94
  def checked_value
72
95
  options.fetch(:checked_value, '1')
73
96
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
3
  module Inputs
3
4
  class CollectionCheckBoxesInput < CollectionRadioButtonsInput
@@ -10,7 +11,7 @@ module SimpleForm
10
11
  end
11
12
 
12
13
  def build_nested_boolean_style_item_tag(collection_builder)
13
- collection_builder.check_box + collection_builder.text
14
+ collection_builder.check_box + collection_builder.text.to_s
14
15
  end
15
16
 
16
17
  def item_wrapper_class
@@ -1,6 +1,10 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
3
  module Inputs
3
4
  class CollectionInput < Base
5
+ BASIC_OBJECT_CLASSES = [String, Integer, Float, NilClass, Symbol, TrueClass, FalseClass]
6
+ BASIC_OBJECT_CLASSES.push(Fixnum, Bignum) unless 1.class == Integer
7
+
4
8
  # Default boolean collection for use with selects/radios when no
5
9
  # collection is given. Always fallback to this boolean collection.
6
10
  # Texts can be translated using i18n in "simple_form.yes" and
@@ -12,14 +16,18 @@ module SimpleForm
12
16
  end
13
17
  end
14
18
 
15
- def input
19
+ def input(wrapper_options = nil)
16
20
  raise NotImplementedError,
17
21
  "input should be implemented by classes inheriting from CollectionInput"
18
22
  end
19
23
 
20
24
  def input_options
21
25
  options = super
26
+
22
27
  options[:include_blank] = true unless skip_include_blank?
28
+ translate_option options, :prompt
29
+ translate_option options, :include_blank
30
+
23
31
  options
24
32
  end
25
33
 
@@ -33,12 +41,12 @@ module SimpleForm
33
41
  end
34
42
 
35
43
  def has_required?
36
- super && (input_options[:include_blank] || multiple?)
44
+ super && (input_options[:include_blank] || input_options[:prompt] || multiple?)
37
45
  end
38
46
 
39
47
  # Check if :include_blank must be included by default.
40
48
  def skip_include_blank?
41
- (options.keys & [:prompt, :include_blank, :default, :selected]).any? || multiple?
49
+ (options.keys & %i[prompt include_blank default selected]).any? || multiple?
42
50
  end
43
51
 
44
52
  def multiple?
@@ -70,32 +78,47 @@ module SimpleForm
70
78
  elsif collection_includes_basic_objects?(collection_classes)
71
79
  { label: :to_s, value: :to_s }
72
80
  else
73
- sample = collection.first || collection.last
74
-
75
- { label: SimpleForm.collection_label_methods.find { |m| sample.respond_to?(m) },
76
- value: SimpleForm.collection_value_methods.find { |m| sample.respond_to?(m) } }
81
+ detect_method_from_class(collection_classes)
77
82
  end
78
83
  end
79
84
 
85
+ def detect_method_from_class(collection_classes)
86
+ sample = collection.first || collection.last
87
+
88
+ { label: SimpleForm.collection_label_methods.find { |m| sample.respond_to?(m) },
89
+ value: SimpleForm.collection_value_methods.find { |m| sample.respond_to?(m) } }
90
+ end
91
+
80
92
  def detect_collection_classes(some_collection = collection)
81
- some_collection.map { |e| e.class }.uniq
93
+ some_collection.map(&:class).uniq
82
94
  end
83
95
 
84
96
  def collection_includes_basic_objects?(collection_classes)
85
- (collection_classes & [
86
- String, Integer, Fixnum, Bignum, Float, NilClass, Symbol, TrueClass, FalseClass
87
- ]).any?
97
+ (collection_classes & BASIC_OBJECT_CLASSES).any?
88
98
  end
89
99
 
90
100
  def translate_collection
91
- if translated_collection = translate(:options)
101
+ if translated_collection = translate_from_namespace(:options)
92
102
  @collection = collection.map do |key|
93
- [translated_collection[key] || key, key]
103
+ html_key = "#{key}_html".to_sym
104
+
105
+ if translated_collection[html_key]
106
+ [translated_collection[html_key].html_safe || key, key.to_s]
107
+ else
108
+ [translated_collection[key] || key, key.to_s]
109
+ end
94
110
  end
95
111
  true
96
112
  end
97
113
  end
114
+
115
+ def translate_option(options, key)
116
+ if options[key] == :translate
117
+ namespace = key.to_s.pluralize
118
+
119
+ options[key] = translate_from_namespace(namespace, true)
120
+ end
121
+ end
98
122
  end
99
123
  end
100
124
  end
101
-
@@ -1,19 +1,22 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
3
  module Inputs
3
4
  class CollectionRadioButtonsInput < CollectionInput
4
- def input
5
+ def input(wrapper_options = nil)
5
6
  label_method, value_method = detect_collection_methods
6
7
 
7
- @builder.send("collection_#{input_type}",
8
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
9
+
10
+ @builder.send(:"collection_#{input_type}",
8
11
  attribute_name, collection, value_method, label_method,
9
- input_options, input_html_options, &collection_block_for_nested_boolean_style
12
+ input_options, merged_input_options,
13
+ &collection_block_for_nested_boolean_style
10
14
  )
11
15
  end
12
16
 
13
17
  def input_options
14
18
  options = super
15
19
  apply_default_collection_options!(options)
16
- apply_nested_boolean_collection_options!(options) if nested_boolean_style?
17
20
  options
18
21
  end
19
22
 
@@ -23,7 +26,7 @@ module SimpleForm
23
26
  options[:item_wrapper_tag] ||= options.fetch(:item_wrapper_tag, SimpleForm.item_wrapper_tag)
24
27
  options[:item_wrapper_class] = [
25
28
  item_wrapper_class, options[:item_wrapper_class], SimpleForm.item_wrapper_class
26
- ].compact.presence
29
+ ].compact.presence if SimpleForm.include_default_input_wrapper_class
27
30
 
28
31
  options[:collection_wrapper_tag] ||= options.fetch(:collection_wrapper_tag, SimpleForm.collection_wrapper_tag)
29
32
  options[:collection_wrapper_class] = [
@@ -31,13 +34,6 @@ module SimpleForm
31
34
  ].compact.presence
32
35
  end
33
36
 
34
- # Force item wrapper to be a label when using nested boolean, to support
35
- # configuring classes through :item_wrapper_class, and to maintain
36
- # compatibility with :inline style and default :item_wrapper_tag.
37
- def apply_nested_boolean_collection_options!(options)
38
- options[:item_wrapper_tag] = :label
39
- end
40
-
41
37
  def collection_block_for_nested_boolean_style
42
38
  return unless nested_boolean_style?
43
39
 
@@ -45,7 +41,7 @@ module SimpleForm
45
41
  end
46
42
 
47
43
  def build_nested_boolean_style_item_tag(collection_builder)
48
- collection_builder.radio_button + collection_builder.text
44
+ collection_builder.radio_button + collection_builder.text.to_s
49
45
  end
50
46
 
51
47
  def item_wrapper_class
@@ -1,12 +1,15 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
3
  module Inputs
3
4
  class CollectionSelectInput < CollectionInput
4
- def input
5
+ def input(wrapper_options = nil)
5
6
  label_method, value_method = detect_collection_methods
6
7
 
8
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
9
+
7
10
  @builder.collection_select(
8
11
  attribute_name, collection, value_method, label_method,
9
- input_options, input_html_options
12
+ input_options, merged_input_options
10
13
  )
11
14
  end
12
15
  end
@@ -1,23 +1,38 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
3
  module Inputs
3
4
  class DateTimeInput < Base
4
- def input
5
- @builder.send(:"#{input_type}_select", attribute_name, input_options, input_html_options)
5
+ def input(wrapper_options = nil)
6
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
7
+
8
+ if use_html5_inputs?
9
+ @builder.send(:"#{input_type}_field", attribute_name, merged_input_options)
10
+ else
11
+ @builder.send(:"#{input_type}_select", attribute_name, input_options, merged_input_options)
12
+ end
6
13
  end
7
14
 
8
15
  private
9
16
 
10
17
  def label_target
11
- position = case input_type
12
- when :date, :datetime
13
- date_order = input_options[:order] || I18n.t('date.order')
14
- date_order.first.to_sym
18
+ if use_html5_inputs?
19
+ attribute_name
15
20
  else
16
- :hour
21
+ position = case input_type
22
+ when :date, :datetime
23
+ date_order = input_options[:order] || I18n.t('date.order')
24
+ date_order.first.to_sym
25
+ else
26
+ :hour
27
+ end
28
+
29
+ position = ActionView::Helpers::DateTimeSelector::POSITION[position]
30
+ "#{attribute_name}_#{position}i"
17
31
  end
32
+ end
18
33
 
19
- position = ActionView::Helpers::DateTimeSelector::POSITION[position]
20
- "#{attribute_name}_#{position}i"
34
+ def use_html5_inputs?
35
+ input_options[:html5]
21
36
  end
22
37
  end
23
38
  end
@@ -1,8 +1,11 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
3
  module Inputs
3
4
  class FileInput < Base
4
- def input
5
- @builder.file_field(attribute_name, input_html_options)
5
+ def input(wrapper_options = nil)
6
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
7
+
8
+ @builder.file_field(attribute_name, merged_input_options)
6
9
  end
7
10
  end
8
11
  end
@@ -1,11 +1,15 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
3
  module Inputs
3
4
  class GroupedCollectionSelectInput < CollectionInput
4
- def input
5
+ def input(wrapper_options = nil)
5
6
  label_method, value_method = detect_collection_methods
7
+
8
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
9
+
6
10
  @builder.grouped_collection_select(attribute_name, grouped_collection,
7
11
  group_method, group_label_method, value_method, label_method,
8
- input_options, input_html_options)
12
+ input_options, merged_input_options)
9
13
  end
10
14
 
11
15
  private
@@ -19,7 +23,7 @@ module SimpleForm
19
23
 
20
24
  # Sample collection
21
25
  def collection
22
- @collection ||= grouped_collection.first.try(:send, group_method) || []
26
+ @collection ||= grouped_collection.map { |collection| collection.try(:send, group_method) }.detect(&:present?) || []
23
27
  end
24
28
 
25
29
  def group_method
@@ -36,6 +40,15 @@ module SimpleForm
36
40
 
37
41
  label
38
42
  end
43
+
44
+ def detect_method_from_class(collection_classes)
45
+ return {} if collection_classes.empty?
46
+
47
+ sample = collection_classes.first
48
+
49
+ { label: SimpleForm.collection_label_methods.find { |m| sample.instance_methods.include?(m) },
50
+ value: SimpleForm.collection_value_methods.find { |m| sample.instance_methods.include?(m) } }
51
+ end
39
52
  end
40
53
  end
41
54
  end
@@ -1,10 +1,13 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
3
  module Inputs
3
4
  class HiddenInput < Base
4
5
  disable :label, :errors, :hint, :required
5
6
 
6
- def input
7
- @builder.hidden_field(attribute_name, input_html_options)
7
+ def input(wrapper_options = nil)
8
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
9
+
10
+ @builder.hidden_field(attribute_name, merged_input_options)
8
11
  end
9
12
 
10
13
  private
@@ -1,18 +1,20 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
3
  module Inputs
3
4
  class NumericInput < Base
4
5
  enable :placeholder, :min_max
5
6
 
6
- def input
7
+ def input(wrapper_options = nil)
7
8
  input_html_classes.unshift("numeric")
8
9
  if html5?
9
10
  input_html_options[:type] ||= "number"
10
11
  input_html_options[:step] ||= integer? ? 1 : "any"
11
12
  end
12
- @builder.text_field(attribute_name, input_html_options)
13
- end
14
13
 
15
- private
14
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
15
+
16
+ @builder.text_field(attribute_name, merged_input_options)
17
+ end
16
18
  end
17
19
  end
18
20
  end
@@ -1,10 +1,13 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
3
  module Inputs
3
4
  class PasswordInput < Base
4
- enable :placeholder, :maxlength
5
+ enable :placeholder, :maxlength, :minlength
5
6
 
6
- def input
7
- @builder.password_field(attribute_name, input_html_options)
7
+ def input(wrapper_options = nil)
8
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
9
+
10
+ @builder.password_field(attribute_name, merged_input_options)
8
11
  end
9
12
  end
10
13
  end
@@ -1,9 +1,12 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
3
  module Inputs
3
4
  class PriorityInput < CollectionSelectInput
4
- def input
5
+ def input(wrapper_options = nil)
6
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
7
+
5
8
  @builder.send(:"#{input_type}_select", attribute_name, input_priority,
6
- input_options, input_html_options)
9
+ input_options, merged_input_options)
7
10
  end
8
11
 
9
12
  def input_priority
@@ -1,7 +1,8 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
3
  module Inputs
3
4
  class RangeInput < NumericInput
4
- def input
5
+ def input(wrapper_options = nil)
5
6
  if html5?
6
7
  input_html_options[:type] ||= "range"
7
8
  input_html_options[:step] ||= 1
@@ -1,15 +1,18 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
3
  module Inputs
3
4
  class StringInput < Base
4
- enable :placeholder, :maxlength, :pattern
5
+ enable :placeholder, :maxlength, :minlength, :pattern
5
6
 
6
- def input
7
+ def input(wrapper_options = nil)
7
8
  unless string?
8
9
  input_html_classes.unshift("string")
9
10
  input_html_options[:type] ||= input_type if html5?
10
11
  end
11
12
 
12
- @builder.text_field(attribute_name, input_html_options)
13
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
14
+
15
+ @builder.text_field(attribute_name, merged_input_options)
13
16
  end
14
17
 
15
18
  private
@@ -1,10 +1,13 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
3
  module Inputs
3
4
  class TextInput < Base
4
- enable :placeholder, :maxlength
5
+ enable :placeholder, :maxlength, :minlength
5
6
 
6
- def input
7
- @builder.text_area(attribute_name, input_html_options)
7
+ def input(wrapper_options = nil)
8
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
9
+
10
+ @builder.text_area(attribute_name, merged_input_options)
8
11
  end
9
12
  end
10
13
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
3
  module Inputs
3
4
  extend ActiveSupport::Autoload
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'active_support/core_ext/class/attribute'
2
3
 
3
4
  module SimpleForm
@@ -1,7 +1,15 @@
1
+ # frozen_string_literal: true
1
2
  require 'rails/railtie'
2
3
 
3
4
  module SimpleForm
4
5
  class Railtie < Rails::Railtie
5
6
  config.eager_load_namespaces << SimpleForm
7
+
8
+ config.after_initialize do
9
+ unless SimpleForm.configured?
10
+ warn '[Simple Form] Simple Form is not configured in the application and will use the default values.' +
11
+ ' Use `rails generate simple_form:install` to generate the Simple Form configuration.'
12
+ end
13
+ end
6
14
  end
7
15
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
3
  module Tags
3
4
  module CollectionExtensions
@@ -15,6 +16,12 @@ module SimpleForm
15
16
 
16
17
  rendered_item = yield item, value, text, default_html_options.merge(additional_html_options)
17
18
 
19
+ if @options.fetch(:boolean_style, SimpleForm.boolean_style) == :nested
20
+ label_options = default_html_options.slice(:index, :namespace)
21
+ label_options['class'] = @options[:item_label_class]
22
+ rendered_item = @template_object.label(@object_name, sanitize_attribute_name(value), rendered_item, label_options)
23
+ end
24
+
18
25
  item_wrapper_tag ? @template_object.content_tag(item_wrapper_tag, rendered_item, class: item_wrapper_class) : rendered_item
19
26
  end.join.html_safe
20
27
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
- VERSION = "3.0.1".freeze
3
+ VERSION = "4.0.0".freeze
3
4
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
3
  module Wrappers
3
4
  # Provides the builder syntax for components. The builder provides
@@ -45,20 +46,20 @@ module SimpleForm
45
46
  @components = []
46
47
  end
47
48
 
48
- def use(name, options=nil, &block)
49
+ def use(name, options = {})
49
50
  if options && wrapper = options[:wrap_with]
50
- @components << Single.new(name, wrapper)
51
+ @components << Single.new(name, wrapper, options.except(:wrap_with))
51
52
  else
52
- @components << name
53
+ @components << Leaf.new(name, options)
53
54
  end
54
55
  end
55
56
 
56
- def optional(name, options=nil, &block)
57
+ def optional(name, options = {}, &block)
57
58
  @options[name] = false
58
- use(name, options, &block)
59
+ use(name, options)
59
60
  end
60
61
 
61
- def wrapper(name, options=nil)
62
+ def wrapper(name, options = nil)
62
63
  if block_given?
63
64
  name, options = nil, name if name.is_a?(Hash)
64
65
  builder = self.class.new(@options)
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+ module SimpleForm
3
+ module Wrappers
4
+ class Leaf
5
+ attr_reader :namespace
6
+
7
+ def initialize(namespace, options = {})
8
+ @namespace = namespace
9
+ @options = options
10
+ end
11
+
12
+ def render(input)
13
+ method = input.method(@namespace)
14
+
15
+ if method.arity.zero?
16
+ ActiveSupport::Deprecation.warn(SimpleForm::CUSTOM_INPUT_DEPRECATION_WARN % { name: @namespace })
17
+
18
+ method.call
19
+ else
20
+ method.call(@options)
21
+ end
22
+ end
23
+
24
+ def find(name)
25
+ self if @namespace == name
26
+ end
27
+ end
28
+ end
29
+ end