simple_form 2.1.0 → 3.2.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.

Potentially problematic release.


This version of simple_form might be problematic. Click here for more details.

Files changed (93) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +77 -33
  3. data/MIT-LICENSE +1 -1
  4. data/README.md +387 -187
  5. data/lib/generators/simple_form/install_generator.rb +4 -4
  6. data/lib/generators/simple_form/templates/README +3 -4
  7. data/lib/generators/simple_form/templates/config/initializers/simple_form.rb +45 -22
  8. data/lib/generators/simple_form/templates/config/initializers/simple_form_bootstrap.rb +128 -24
  9. data/lib/generators/simple_form/templates/config/initializers/simple_form_foundation.rb +87 -6
  10. data/lib/generators/simple_form/templates/config/locales/simple_form.en.yml +7 -2
  11. data/lib/simple_form/action_view_extensions/builder.rb +2 -319
  12. data/lib/simple_form/action_view_extensions/form_helper.rb +8 -11
  13. data/lib/simple_form/components/errors.rb +28 -2
  14. data/lib/simple_form/components/hints.rb +8 -3
  15. data/lib/simple_form/components/html5.rb +6 -3
  16. data/lib/simple_form/components/label_input.rb +20 -2
  17. data/lib/simple_form/components/labels.rb +14 -10
  18. data/lib/simple_form/components/maxlength.rb +2 -9
  19. data/lib/simple_form/components/min_max.rb +1 -1
  20. data/lib/simple_form/components/pattern.rb +3 -3
  21. data/lib/simple_form/components/placeholders.rb +2 -2
  22. data/lib/simple_form/components/readonly.rb +1 -1
  23. data/lib/simple_form/components.rb +1 -1
  24. data/lib/simple_form/error_notification.rb +2 -2
  25. data/lib/simple_form/form_builder.rb +262 -107
  26. data/lib/simple_form/helpers.rb +6 -6
  27. data/lib/simple_form/inputs/base.rb +37 -16
  28. data/lib/simple_form/inputs/block_input.rb +2 -2
  29. data/lib/simple_form/inputs/boolean_input.rb +33 -18
  30. data/lib/simple_form/inputs/collection_input.rb +34 -13
  31. data/lib/simple_form/inputs/collection_radio_buttons_input.rb +7 -12
  32. data/lib/simple_form/inputs/collection_select_input.rb +4 -2
  33. data/lib/simple_form/inputs/date_time_input.rb +23 -9
  34. data/lib/simple_form/inputs/file_input.rb +4 -2
  35. data/lib/simple_form/inputs/grouped_collection_select_input.rb +15 -3
  36. data/lib/simple_form/inputs/hidden_input.rb +4 -2
  37. data/lib/simple_form/inputs/numeric_input.rb +3 -8
  38. data/lib/simple_form/inputs/password_input.rb +4 -3
  39. data/lib/simple_form/inputs/priority_input.rb +4 -2
  40. data/lib/simple_form/inputs/range_input.rb +1 -1
  41. data/lib/simple_form/inputs/string_input.rb +4 -3
  42. data/lib/simple_form/inputs/text_input.rb +4 -2
  43. data/lib/simple_form/railtie.rb +14 -0
  44. data/lib/simple_form/tags.rb +68 -0
  45. data/lib/simple_form/version.rb +1 -1
  46. data/lib/simple_form/wrappers/builder.rb +11 -35
  47. data/lib/simple_form/wrappers/leaf.rb +28 -0
  48. data/lib/simple_form/wrappers/many.rb +7 -7
  49. data/lib/simple_form/wrappers/root.rb +2 -2
  50. data/lib/simple_form/wrappers/single.rb +5 -3
  51. data/lib/simple_form/wrappers.rb +2 -1
  52. data/lib/simple_form.rb +99 -52
  53. data/test/action_view_extensions/builder_test.rb +113 -127
  54. data/test/action_view_extensions/form_helper_test.rb +58 -30
  55. data/test/components/label_test.rb +83 -83
  56. data/test/form_builder/association_test.rb +96 -61
  57. data/test/form_builder/button_test.rb +14 -14
  58. data/test/form_builder/error_notification_test.rb +9 -9
  59. data/test/form_builder/error_test.rb +159 -34
  60. data/test/form_builder/general_test.rb +176 -121
  61. data/test/form_builder/hint_test.rb +43 -37
  62. data/test/form_builder/input_field_test.rb +99 -52
  63. data/test/form_builder/label_test.rb +67 -15
  64. data/test/form_builder/wrapper_test.rb +157 -41
  65. data/test/generators/simple_form_generator_test.rb +4 -4
  66. data/test/inputs/boolean_input_test.rb +92 -24
  67. data/test/inputs/collection_check_boxes_input_test.rb +150 -71
  68. data/test/inputs/collection_radio_buttons_input_test.rb +213 -113
  69. data/test/inputs/collection_select_input_test.rb +221 -85
  70. data/test/inputs/datetime_input_test.rb +125 -47
  71. data/test/inputs/disabled_test.rb +25 -25
  72. data/test/inputs/discovery_test.rb +60 -10
  73. data/test/inputs/file_input_test.rb +3 -3
  74. data/test/inputs/general_test.rb +48 -32
  75. data/test/inputs/grouped_collection_select_input_test.rb +76 -27
  76. data/test/inputs/hidden_input_test.rb +6 -5
  77. data/test/inputs/numeric_input_test.rb +46 -46
  78. data/test/inputs/priority_input_test.rb +21 -15
  79. data/test/inputs/readonly_test.rb +31 -31
  80. data/test/inputs/required_test.rb +30 -18
  81. data/test/inputs/string_input_test.rb +53 -52
  82. data/test/inputs/text_input_test.rb +15 -8
  83. data/test/simple_form_test.rb +8 -0
  84. data/test/support/discovery_inputs.rb +32 -2
  85. data/test/support/misc_helpers.rb +130 -29
  86. data/test/support/mock_controller.rb +6 -6
  87. data/test/support/models.rb +125 -71
  88. data/test/test_helper.rb +28 -35
  89. metadata +17 -29
  90. data/lib/simple_form/action_view_extensions/builder.rb.orig +0 -247
  91. data/lib/simple_form/core_ext/hash.rb +0 -16
  92. data/lib/simple_form/form_builder.rb.orig +0 -486
  93. data/lib/simple_form/version.rb.orig +0 -7
@@ -1,8 +1,13 @@
1
1
  require 'simple_form/i18n_cache'
2
+ require 'active_support/core_ext/string/output_safety'
3
+ require 'action_view/helpers'
2
4
 
3
5
  module SimpleForm
4
6
  module Inputs
5
7
  class Base
8
+ include ERB::Util
9
+ include ActionView::Helpers::TranslationHelper
10
+
6
11
  extend I18nCache
7
12
 
8
13
  include SimpleForm::Helpers::Autofocus
@@ -24,7 +29,7 @@ module SimpleForm
24
29
  attr_reader :attribute_name, :column, :input_type, :reflection,
25
30
  :options, :input_html_options, :input_html_classes, :html_classes
26
31
 
27
- delegate :template, :object, :object_name, :lookup_model_names, :lookup_action, :to => :@builder
32
+ delegate :template, :object, :object_name, :lookup_model_names, :lookup_action, to: :@builder
28
33
 
29
34
  class_attribute :default_options
30
35
  self.default_options = {}
@@ -50,14 +55,14 @@ module SimpleForm
50
55
  def initialize(builder, attribute_name, column, input_type, options = {})
51
56
  super
52
57
 
53
- options = options.dup
54
- @builder = builder
55
- @attribute_name = attribute_name
56
- @column = column
57
- @input_type = input_type
58
- @reflection = options.delete(:reflection)
59
- @options = options.reverse_merge!(self.class.default_options)
60
- @required = calculate_required
58
+ options = options.dup
59
+ @builder = builder
60
+ @attribute_name = attribute_name
61
+ @column = column
62
+ @input_type = input_type
63
+ @reflection = options.delete(:reflection)
64
+ @options = options.reverse_merge!(self.class.default_options)
65
+ @required = calculate_required
61
66
 
62
67
  # Notice that html_options_for receives a reference to input_html_classes.
63
68
  # This means that classes added dynamically to input_html_classes will
@@ -65,6 +70,10 @@ module SimpleForm
65
70
  @html_classes = SimpleForm.additional_classes_for(:input) { additional_classes }
66
71
 
67
72
  @input_html_classes = @html_classes.dup
73
+ if SimpleForm.input_class && !input_html_classes.empty?
74
+ input_html_classes << SimpleForm.input_class
75
+ end
76
+
68
77
  @input_html_options = html_options_for(:input, input_html_classes).tap do |o|
69
78
  o[:readonly] = true if has_readonly?
70
79
  o[:disabled] = true if has_disabled?
@@ -72,7 +81,7 @@ module SimpleForm
72
81
  end
73
82
  end
74
83
 
75
- def input
84
+ def input(wrapper_options = nil)
76
85
  raise NotImplementedError
77
86
  end
78
87
 
@@ -90,10 +99,6 @@ module SimpleForm
90
99
 
91
100
  private
92
101
 
93
- def add_size!
94
- input_html_options[:size] ||= [limit, SimpleForm.default_input_size].compact.min
95
- end
96
-
97
102
  def limit
98
103
  if column
99
104
  decimal_or_float? ? decimal_limit : column_limit
@@ -164,7 +169,7 @@ module SimpleForm
164
169
  # email: 'E-mail.'
165
170
  #
166
171
  # Take a look at our locale example file.
167
- def translate(namespace, default='')
172
+ def translate_from_namespace(namespace, default = '')
168
173
  model_names = lookup_model_names.dup
169
174
  lookups = []
170
175
 
@@ -179,7 +184,23 @@ module SimpleForm
179
184
  lookups << :"defaults.#{reflection_or_attribute_name}"
180
185
  lookups << default
181
186
 
182
- I18n.t(lookups.shift, :scope => :"simple_form.#{namespace}", :default => lookups).presence
187
+ I18n.t(lookups.shift, scope: :"#{i18n_scope}.#{namespace}", default: lookups).presence
188
+ end
189
+
190
+ def merge_wrapper_options(options, wrapper_options)
191
+ if wrapper_options
192
+ options.merge(wrapper_options) do |_, oldval, newval|
193
+ if Array === oldval
194
+ oldval + Array(newval)
195
+ end
196
+ end
197
+ else
198
+ options
199
+ end
200
+ end
201
+
202
+ def i18n_scope
203
+ SimpleForm.i18n_scope
183
204
  end
184
205
  end
185
206
  end
@@ -6,9 +6,9 @@ module SimpleForm
6
6
  @block = block
7
7
  end
8
8
 
9
- def input
9
+ def input(wrapper_options = nil)
10
10
  template.capture(&@block)
11
11
  end
12
12
  end
13
13
  end
14
- end
14
+ end
@@ -1,30 +1,36 @@
1
1
  module SimpleForm
2
2
  module Inputs
3
3
  class BooleanInput < Base
4
- def input
4
+ def input(wrapper_options = nil)
5
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
6
+
5
7
  if nested_boolean_style?
6
8
  build_hidden_field_for_checkbox +
7
- template.label_tag(nil, :class => "checkbox") {
8
- build_check_box_without_hidden_field + inline_label
9
+ template.label_tag(nil, class: SimpleForm.boolean_label_class) {
10
+ build_check_box_without_hidden_field(merged_input_options) +
11
+ inline_label
9
12
  }
10
13
  else
11
- build_check_box
14
+ build_check_box(unchecked_value, merged_input_options)
12
15
  end
13
16
  end
14
17
 
15
- def label_input
16
- if options[:label] == false
17
- input
18
+ def label_input(wrapper_options = nil)
19
+ if options[:label] == false || inline_label?
20
+ input(wrapper_options)
18
21
  elsif nested_boolean_style?
19
22
  html_options = label_html_options.dup
20
- html_options[:class].push(:checkbox)
23
+ html_options[:class] ||= []
24
+ html_options[:class].push(SimpleForm.boolean_label_class) if SimpleForm.boolean_label_class
25
+
26
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
21
27
 
22
28
  build_hidden_field_for_checkbox +
23
29
  @builder.label(label_target, html_options) {
24
- build_check_box_without_hidden_field + label_text
30
+ build_check_box_without_hidden_field(merged_input_options) + label_text
25
31
  }
26
32
  else
27
- input + label
33
+ input(wrapper_options) + label(wrapper_options)
28
34
  end
29
35
  end
30
36
 
@@ -34,14 +40,14 @@ module SimpleForm
34
40
  # reuse the method for nested boolean style, but with no unchecked value,
35
41
  # which won't generate the hidden checkbox. This is the default functionality
36
42
  # in Rails > 3.2.1, and is backported in SimpleForm AV helpers.
37
- def build_check_box(unchecked_value = unchecked_value)
38
- @builder.check_box(attribute_name, input_html_options, checked_value, unchecked_value)
43
+ def build_check_box(unchecked_value, options)
44
+ @builder.check_box(attribute_name, options, checked_value, unchecked_value)
39
45
  end
40
46
 
41
47
  # Build a checkbox without generating the hidden field. See
42
48
  # #build_hidden_field_for_checkbox for more info.
43
- def build_check_box_without_hidden_field
44
- build_check_box(nil)
49
+ def build_check_box_without_hidden_field(options)
50
+ build_check_box(nil, options)
45
51
  end
46
52
 
47
53
  # Create a hidden field for the current checkbox, so we can simulate Rails
@@ -49,14 +55,23 @@ module SimpleForm
49
55
  # we need the hidden field to be *outside* the label (otherwise it
50
56
  # generates invalid html - html5 only).
51
57
  def build_hidden_field_for_checkbox
52
- @builder.hidden_field(attribute_name, :value => unchecked_value, :id => nil,
53
- :disabled => input_html_options[:disabled],
54
- :name => input_html_options[:name])
58
+ options = { value: unchecked_value, id: nil, disabled: input_html_options[:disabled] }
59
+ options[:name] = input_html_options[:name] if input_html_options.has_key?(:name)
60
+
61
+ @builder.hidden_field(attribute_name, options)
62
+ end
63
+
64
+ def inline_label?
65
+ nested_boolean_style? && options[:inline_label]
55
66
  end
56
67
 
57
68
  def inline_label
58
69
  inline_option = options[:inline_label]
59
- inline_option == true ? label_text : inline_option
70
+
71
+ if inline_option
72
+ label = inline_option == true ? label_text : html_escape(inline_option)
73
+ " #{label}".html_safe
74
+ end
60
75
  end
61
76
 
62
77
  # Booleans are not required by default because in most of the cases
@@ -7,19 +7,23 @@ module SimpleForm
7
7
  # "simple_form.no" keys. See the example locale file.
8
8
  def self.boolean_collection
9
9
  i18n_cache :boolean_collection do
10
- [ [I18n.t(:"simple_form.yes", :default => 'Yes'), true],
11
- [I18n.t(:"simple_form.no", :default => 'No'), false] ]
10
+ [ [I18n.t(:"simple_form.yes", default: 'Yes'), true],
11
+ [I18n.t(:"simple_form.no", default: 'No'), false] ]
12
12
  end
13
13
  end
14
14
 
15
- def input
15
+ def input(wrapper_options = nil)
16
16
  raise NotImplementedError,
17
17
  "input should be implemented by classes inheriting from CollectionInput"
18
18
  end
19
19
 
20
20
  def input_options
21
21
  options = super
22
+
22
23
  options[:include_blank] = true unless skip_include_blank?
24
+ translate_option options, :prompt
25
+ translate_option options, :include_blank
26
+
23
27
  options
24
28
  end
25
29
 
@@ -33,7 +37,7 @@ module SimpleForm
33
37
  end
34
38
 
35
39
  def has_required?
36
- super && (input_options[:include_blank] || multiple?)
40
+ super && (input_options[:include_blank] || input_options[:prompt] || multiple?)
37
41
  end
38
42
 
39
43
  # Check if :include_blank must be included by default.
@@ -66,17 +70,21 @@ module SimpleForm
66
70
  collection_translated = translate_collection if collection_classes == [Symbol]
67
71
 
68
72
  if collection_translated || collection_classes.include?(Array)
69
- { :label => :first, :value => :last }
73
+ { label: :first, value: :second }
70
74
  elsif collection_includes_basic_objects?(collection_classes)
71
- { :label => :to_s, :value => :to_s }
75
+ { label: :to_s, value: :to_s }
72
76
  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) } }
77
+ detect_method_from_class(collection_classes)
77
78
  end
78
79
  end
79
80
 
81
+ def detect_method_from_class(collection_classes)
82
+ sample = collection.first || collection.last
83
+
84
+ { label: SimpleForm.collection_label_methods.find { |m| sample.respond_to?(m) },
85
+ value: SimpleForm.collection_value_methods.find { |m| sample.respond_to?(m) } }
86
+ end
87
+
80
88
  def detect_collection_classes(some_collection = collection)
81
89
  some_collection.map { |e| e.class }.uniq
82
90
  end
@@ -88,14 +96,27 @@ module SimpleForm
88
96
  end
89
97
 
90
98
  def translate_collection
91
- if translated_collection = translate(:options)
99
+ if translated_collection = translate_from_namespace(:options)
92
100
  @collection = collection.map do |key|
93
- [translated_collection[key] || key, key]
101
+ html_key = "#{key}_html".to_sym
102
+
103
+ if translated_collection[html_key]
104
+ [translated_collection[html_key].html_safe || key, key.to_s]
105
+ else
106
+ [translated_collection[key] || key, key.to_s]
107
+ end
94
108
  end
95
109
  true
96
110
  end
97
111
  end
112
+
113
+ def translate_option(options, key)
114
+ if options[key] == :translate
115
+ namespace = key.to_s.pluralize
116
+
117
+ options[key] = translate_from_namespace(namespace, true)
118
+ end
119
+ end
98
120
  end
99
121
  end
100
122
  end
101
-
@@ -1,19 +1,21 @@
1
1
  module SimpleForm
2
2
  module Inputs
3
3
  class CollectionRadioButtonsInput < CollectionInput
4
- def input
4
+ def input(wrapper_options = nil)
5
5
  label_method, value_method = detect_collection_methods
6
6
 
7
- @builder.send("collection_#{input_type}",
7
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
8
+
9
+ @builder.send(:"collection_#{input_type}",
8
10
  attribute_name, collection, value_method, label_method,
9
- input_options, input_html_options, &collection_block_for_nested_boolean_style
11
+ input_options, merged_input_options,
12
+ &collection_block_for_nested_boolean_style
10
13
  )
11
14
  end
12
15
 
13
16
  def input_options
14
17
  options = super
15
18
  apply_default_collection_options!(options)
16
- apply_nested_boolean_collection_options!(options) if nested_boolean_style?
17
19
  options
18
20
  end
19
21
 
@@ -23,7 +25,7 @@ module SimpleForm
23
25
  options[:item_wrapper_tag] ||= options.fetch(:item_wrapper_tag, SimpleForm.item_wrapper_tag)
24
26
  options[:item_wrapper_class] = [
25
27
  item_wrapper_class, options[:item_wrapper_class], SimpleForm.item_wrapper_class
26
- ].compact.presence
28
+ ].compact.presence if SimpleForm.include_default_input_wrapper_class
27
29
 
28
30
  options[:collection_wrapper_tag] ||= options.fetch(:collection_wrapper_tag, SimpleForm.collection_wrapper_tag)
29
31
  options[:collection_wrapper_class] = [
@@ -31,13 +33,6 @@ module SimpleForm
31
33
  ].compact.presence
32
34
  end
33
35
 
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
36
  def collection_block_for_nested_boolean_style
42
37
  return unless nested_boolean_style?
43
38
 
@@ -1,12 +1,14 @@
1
1
  module SimpleForm
2
2
  module Inputs
3
3
  class CollectionSelectInput < CollectionInput
4
- def input
4
+ def input(wrapper_options = nil)
5
5
  label_method, value_method = detect_collection_methods
6
6
 
7
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
8
+
7
9
  @builder.collection_select(
8
10
  attribute_name, collection, value_method, label_method,
9
- input_options, input_html_options
11
+ input_options, merged_input_options
10
12
  )
11
13
  end
12
14
  end
@@ -1,23 +1,37 @@
1
1
  module SimpleForm
2
2
  module Inputs
3
3
  class DateTimeInput < Base
4
- def input
5
- @builder.send(:"#{input_type}_select", attribute_name, input_options, input_html_options)
4
+ def input(wrapper_options = nil)
5
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
6
+
7
+ if use_html5_inputs?
8
+ @builder.send(:"#{input_type}_field", attribute_name, merged_input_options)
9
+ else
10
+ @builder.send(:"#{input_type}_select", attribute_name, input_options, merged_input_options)
11
+ end
6
12
  end
7
13
 
8
14
  private
9
15
 
10
16
  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
17
+ if use_html5_inputs?
18
+ attribute_name
15
19
  else
16
- :hour
20
+ position = case input_type
21
+ when :date, :datetime
22
+ date_order = input_options[:order] || I18n.t('date.order')
23
+ date_order.first.to_sym
24
+ else
25
+ :hour
26
+ end
27
+
28
+ position = ActionView::Helpers::DateTimeSelector::POSITION[position]
29
+ "#{attribute_name}_#{position}i"
17
30
  end
31
+ end
18
32
 
19
- position = ActionView::Helpers::DateTimeSelector::POSITION[position]
20
- "#{attribute_name}_#{position}i"
33
+ def use_html5_inputs?
34
+ input_options[:html5]
21
35
  end
22
36
  end
23
37
  end
@@ -1,8 +1,10 @@
1
1
  module SimpleForm
2
2
  module Inputs
3
3
  class FileInput < Base
4
- def input
5
- @builder.file_field(attribute_name, input_html_options)
4
+ def input(wrapper_options = nil)
5
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
6
+
7
+ @builder.file_field(attribute_name, merged_input_options)
6
8
  end
7
9
  end
8
10
  end
@@ -1,11 +1,14 @@
1
1
  module SimpleForm
2
2
  module Inputs
3
3
  class GroupedCollectionSelectInput < CollectionInput
4
- def input
4
+ def input(wrapper_options = nil)
5
5
  label_method, value_method = detect_collection_methods
6
+
7
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
8
+
6
9
  @builder.grouped_collection_select(attribute_name, grouped_collection,
7
10
  group_method, group_label_method, value_method, label_method,
8
- input_options, input_html_options)
11
+ input_options, merged_input_options)
9
12
  end
10
13
 
11
14
  private
@@ -19,7 +22,7 @@ module SimpleForm
19
22
 
20
23
  # Sample collection
21
24
  def collection
22
- @collection ||= grouped_collection.first.try(:send, group_method) || []
25
+ @collection ||= grouped_collection.map { |collection| collection.try(:send, group_method) }.detect(&:present?) || []
23
26
  end
24
27
 
25
28
  def group_method
@@ -36,6 +39,15 @@ module SimpleForm
36
39
 
37
40
  label
38
41
  end
42
+
43
+ def detect_method_from_class(collection_classes)
44
+ return {} if collection_classes.empty?
45
+
46
+ sample = collection_classes.first
47
+
48
+ { label: SimpleForm.collection_label_methods.find { |m| sample.instance_methods.include?(m) },
49
+ value: SimpleForm.collection_value_methods.find { |m| sample.instance_methods.include?(m) } }
50
+ end
39
51
  end
40
52
  end
41
53
  end
@@ -3,8 +3,10 @@ module SimpleForm
3
3
  class HiddenInput < Base
4
4
  disable :label, :errors, :hint, :required
5
5
 
6
- def input
7
- @builder.hidden_field(attribute_name, input_html_options)
6
+ def input(wrapper_options = nil)
7
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
8
+
9
+ @builder.hidden_field(attribute_name, merged_input_options)
8
10
  end
9
11
 
10
12
  private
@@ -3,21 +3,16 @@ module SimpleForm
3
3
  class NumericInput < Base
4
4
  enable :placeholder, :min_max
5
5
 
6
- def input
7
- add_size!
6
+ def input(wrapper_options = nil)
8
7
  input_html_classes.unshift("numeric")
9
8
  if html5?
10
9
  input_html_options[:type] ||= "number"
11
10
  input_html_options[:step] ||= integer? ? 1 : "any"
12
11
  end
13
- @builder.text_field(attribute_name, input_html_options)
14
- end
15
12
 
16
- private
13
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
17
14
 
18
- # Rails adds the size attr by default, if the :size key does not exist.
19
- def add_size!
20
- input_html_options[:size] ||= nil
15
+ @builder.text_field(attribute_name, merged_input_options)
21
16
  end
22
17
  end
23
18
  end
@@ -3,9 +3,10 @@ module SimpleForm
3
3
  class PasswordInput < Base
4
4
  enable :placeholder, :maxlength
5
5
 
6
- def input
7
- add_size!
8
- @builder.password_field(attribute_name, input_html_options)
6
+ def input(wrapper_options = nil)
7
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
8
+
9
+ @builder.password_field(attribute_name, merged_input_options)
9
10
  end
10
11
  end
11
12
  end
@@ -1,9 +1,11 @@
1
1
  module SimpleForm
2
2
  module Inputs
3
3
  class PriorityInput < CollectionSelectInput
4
- def input
4
+ def input(wrapper_options = nil)
5
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
6
+
5
7
  @builder.send(:"#{input_type}_select", attribute_name, input_priority,
6
- input_options, input_html_options)
8
+ input_options, merged_input_options)
7
9
  end
8
10
 
9
11
  def input_priority
@@ -1,7 +1,7 @@
1
1
  module SimpleForm
2
2
  module Inputs
3
3
  class RangeInput < NumericInput
4
- def input
4
+ def input(wrapper_options = nil)
5
5
  if html5?
6
6
  input_html_options[:type] ||= "range"
7
7
  input_html_options[:step] ||= 1
@@ -3,14 +3,15 @@ module SimpleForm
3
3
  class StringInput < Base
4
4
  enable :placeholder, :maxlength, :pattern
5
5
 
6
- def input
6
+ def input(wrapper_options = nil)
7
7
  unless string?
8
8
  input_html_classes.unshift("string")
9
9
  input_html_options[:type] ||= input_type if html5?
10
10
  end
11
11
 
12
- add_size!
13
- @builder.text_field(attribute_name, input_html_options)
12
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
13
+
14
+ @builder.text_field(attribute_name, merged_input_options)
14
15
  end
15
16
 
16
17
  private
@@ -3,8 +3,10 @@ module SimpleForm
3
3
  class TextInput < Base
4
4
  enable :placeholder, :maxlength
5
5
 
6
- def input
7
- @builder.text_area(attribute_name, input_html_options)
6
+ def input(wrapper_options = nil)
7
+ merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
8
+
9
+ @builder.text_area(attribute_name, merged_input_options)
8
10
  end
9
11
  end
10
12
  end
@@ -0,0 +1,14 @@
1
+ require 'rails/railtie'
2
+
3
+ module SimpleForm
4
+ class Railtie < Rails::Railtie
5
+ config.eager_load_namespaces << SimpleForm
6
+
7
+ config.after_initialize do
8
+ unless SimpleForm.configured?
9
+ warn '[Simple Form] Simple Form is not configured in the application and will use the default values.' +
10
+ ' Use `rails generate simple_form:install` to generate the Simple Form configuration.'
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,68 @@
1
+ module SimpleForm
2
+ module Tags
3
+ module CollectionExtensions
4
+ private
5
+
6
+ def render_collection
7
+ item_wrapper_tag = @options.fetch(:item_wrapper_tag, :span)
8
+ item_wrapper_class = @options[:item_wrapper_class]
9
+
10
+ @collection.map do |item|
11
+ value = value_for_collection(item, @value_method)
12
+ text = value_for_collection(item, @text_method)
13
+ default_html_options = default_html_options_for_collection(item, value)
14
+ additional_html_options = option_html_attributes(item)
15
+
16
+ rendered_item = yield item, value, text, default_html_options.merge(additional_html_options)
17
+
18
+ if @options.fetch(:boolean_style, SimpleForm.boolean_style) == :nested
19
+ label_options = default_html_options.slice(:index, :namespace)
20
+ label_options['class'] = @options[:item_label_class]
21
+ rendered_item = @template_object.label(@object_name, sanitize_attribute_name(value), rendered_item, label_options)
22
+ end
23
+
24
+ item_wrapper_tag ? @template_object.content_tag(item_wrapper_tag, rendered_item, class: item_wrapper_class) : rendered_item
25
+ end.join.html_safe
26
+ end
27
+
28
+ def wrap_rendered_collection(collection)
29
+ wrapper_tag = @options[:collection_wrapper_tag]
30
+
31
+ if wrapper_tag
32
+ wrapper_class = @options[:collection_wrapper_class]
33
+ @template_object.content_tag(wrapper_tag, collection, class: wrapper_class)
34
+ else
35
+ collection
36
+ end
37
+ end
38
+ end
39
+
40
+ class CollectionRadioButtons < ActionView::Helpers::Tags::CollectionRadioButtons
41
+ include CollectionExtensions
42
+
43
+ def render
44
+ wrap_rendered_collection(super)
45
+ end
46
+
47
+ private
48
+
49
+ def render_component(builder)
50
+ builder.radio_button + builder.label(class: "collection_radio_buttons")
51
+ end
52
+ end
53
+
54
+ class CollectionCheckBoxes < ActionView::Helpers::Tags::CollectionCheckBoxes
55
+ include CollectionExtensions
56
+
57
+ def render
58
+ wrap_rendered_collection(super)
59
+ end
60
+
61
+ private
62
+
63
+ def render_component(builder)
64
+ builder.check_box + builder.label(class: "collection_check_boxes")
65
+ end
66
+ end
67
+ end
68
+ end