simple_form 3.4.0 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

Files changed (103) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +62 -0
  3. data/README.md +208 -36
  4. data/lib/generators/simple_form/install_generator.rb +1 -0
  5. data/lib/generators/simple_form/templates/README +3 -3
  6. data/lib/generators/simple_form/templates/_form.html.erb +2 -0
  7. data/lib/generators/simple_form/templates/_form.html.haml +2 -0
  8. data/lib/generators/simple_form/templates/_form.html.slim +1 -0
  9. data/lib/generators/simple_form/templates/config/initializers/simple_form.rb +15 -5
  10. data/lib/generators/simple_form/templates/config/initializers/simple_form_bootstrap.rb +358 -73
  11. data/lib/generators/simple_form/templates/config/initializers/simple_form_foundation.rb +20 -8
  12. data/lib/simple_form/action_view_extensions/builder.rb +1 -0
  13. data/lib/simple_form/action_view_extensions/form_helper.rb +1 -0
  14. data/lib/simple_form/components/errors.rb +15 -2
  15. data/lib/simple_form/components/hints.rb +1 -0
  16. data/lib/simple_form/components/html5.rb +1 -0
  17. data/lib/simple_form/components/label_input.rb +2 -1
  18. data/lib/simple_form/components/labels.rb +11 -4
  19. data/lib/simple_form/components/maxlength.rb +4 -13
  20. data/lib/simple_form/components/min_max.rb +1 -0
  21. data/lib/simple_form/components/minlength.rb +5 -14
  22. data/lib/simple_form/components/pattern.rb +1 -0
  23. data/lib/simple_form/components/placeholders.rb +2 -1
  24. data/lib/simple_form/components/readonly.rb +1 -0
  25. data/lib/simple_form/components.rb +1 -0
  26. data/lib/simple_form/error_notification.rb +1 -0
  27. data/lib/simple_form/form_builder.rb +81 -26
  28. data/lib/simple_form/helpers/autofocus.rb +1 -0
  29. data/lib/simple_form/helpers/disabled.rb +1 -0
  30. data/lib/simple_form/helpers/readonly.rb +1 -0
  31. data/lib/simple_form/helpers/required.rb +1 -0
  32. data/lib/simple_form/helpers/validators.rb +2 -1
  33. data/lib/simple_form/helpers.rb +1 -0
  34. data/lib/simple_form/i18n_cache.rb +1 -0
  35. data/lib/simple_form/inputs/base.rb +24 -2
  36. data/lib/simple_form/inputs/block_input.rb +1 -0
  37. data/lib/simple_form/inputs/boolean_input.rb +4 -2
  38. data/lib/simple_form/inputs/collection_check_boxes_input.rb +2 -1
  39. data/lib/simple_form/inputs/collection_input.rb +3 -2
  40. data/lib/simple_form/inputs/collection_radio_buttons_input.rb +2 -1
  41. data/lib/simple_form/inputs/collection_select_input.rb +1 -0
  42. data/lib/simple_form/inputs/color_input.rb +14 -0
  43. data/lib/simple_form/inputs/date_time_input.rb +1 -0
  44. data/lib/simple_form/inputs/file_input.rb +1 -0
  45. data/lib/simple_form/inputs/grouped_collection_select_input.rb +1 -0
  46. data/lib/simple_form/inputs/hidden_input.rb +1 -0
  47. data/lib/simple_form/inputs/numeric_input.rb +1 -0
  48. data/lib/simple_form/inputs/password_input.rb +1 -0
  49. data/lib/simple_form/inputs/priority_input.rb +1 -0
  50. data/lib/simple_form/inputs/range_input.rb +1 -0
  51. data/lib/simple_form/inputs/string_input.rb +2 -1
  52. data/lib/simple_form/inputs/text_input.rb +1 -0
  53. data/lib/simple_form/inputs.rb +2 -0
  54. data/lib/simple_form/map_type.rb +1 -0
  55. data/lib/simple_form/railtie.rb +1 -0
  56. data/lib/simple_form/tags.rb +1 -0
  57. data/lib/simple_form/version.rb +2 -1
  58. data/lib/simple_form/wrappers/builder.rb +1 -0
  59. data/lib/simple_form/wrappers/leaf.rb +2 -1
  60. data/lib/simple_form/wrappers/many.rb +1 -0
  61. data/lib/simple_form/wrappers/root.rb +2 -0
  62. data/lib/simple_form/wrappers/single.rb +2 -1
  63. data/lib/simple_form/wrappers.rb +1 -0
  64. data/lib/simple_form.rb +58 -7
  65. data/test/action_view_extensions/builder_test.rb +6 -5
  66. data/test/action_view_extensions/form_helper_test.rb +3 -2
  67. data/test/components/custom_components_test.rb +62 -0
  68. data/test/components/label_test.rb +33 -4
  69. data/test/form_builder/association_test.rb +27 -2
  70. data/test/form_builder/button_test.rb +1 -0
  71. data/test/form_builder/error_notification_test.rb +1 -0
  72. data/test/form_builder/error_test.rb +12 -0
  73. data/test/form_builder/general_test.rb +67 -3
  74. data/test/form_builder/hint_test.rb +6 -0
  75. data/test/form_builder/input_field_test.rb +30 -10
  76. data/test/form_builder/label_test.rb +9 -3
  77. data/test/form_builder/wrapper_test.rb +24 -4
  78. data/test/generators/simple_form_generator_test.rb +4 -3
  79. data/test/inputs/boolean_input_test.rb +17 -0
  80. data/test/inputs/collection_check_boxes_input_test.rb +30 -14
  81. data/test/inputs/collection_radio_buttons_input_test.rb +40 -24
  82. data/test/inputs/collection_select_input_test.rb +40 -39
  83. data/test/inputs/color_input_test.rb +10 -0
  84. data/test/inputs/datetime_input_test.rb +7 -16
  85. data/test/inputs/disabled_test.rb +14 -0
  86. data/test/inputs/discovery_test.rb +22 -0
  87. data/test/inputs/file_input_test.rb +1 -0
  88. data/test/inputs/general_test.rb +3 -2
  89. data/test/inputs/grouped_collection_select_input_test.rb +11 -10
  90. data/test/inputs/hidden_input_test.rb +1 -0
  91. data/test/inputs/numeric_input_test.rb +2 -1
  92. data/test/inputs/priority_input_test.rb +3 -10
  93. data/test/inputs/readonly_test.rb +1 -0
  94. data/test/inputs/required_test.rb +1 -0
  95. data/test/inputs/string_input_test.rb +10 -16
  96. data/test/inputs/text_input_test.rb +1 -0
  97. data/test/simple_form_test.rb +1 -0
  98. data/test/support/discovery_inputs.rb +8 -0
  99. data/test/support/misc_helpers.rb +22 -1
  100. data/test/support/mock_controller.rb +7 -1
  101. data/test/support/models.rb +52 -16
  102. data/test/test_helper.rb +2 -0
  103. metadata +40 -47
@@ -1,10 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Please do not make direct changes to this file!
4
+ # This generator is maintained by the community around simple_form-bootstrap:
5
+ # https://github.com/rafaelfranca/simple_form-bootstrap
6
+ # All future development, tests, and organization should happen there.
7
+ # Background history: https://github.com/plataformatec/simple_form/issues/1561
8
+
9
+ # Uncomment this and change the path if necessary to include your own
10
+ # components.
11
+ # See https://github.com/plataformatec/simple_form#custom-components
12
+ # to know more about custom components.
13
+ # Dir[Rails.root.join('lib/components/**/*.rb')].each { |f| require f }
14
+
1
15
  # Use this setup block to configure all options available in SimpleForm.
2
16
  SimpleForm.setup do |config|
17
+ # Default class for buttons
18
+ config.button_class = 'btn'
19
+
20
+ # Define the default class of the input wrapper of the boolean input.
21
+ config.boolean_label_class = 'form-check-label'
22
+
23
+ # How the label text should be generated altogether with the required text.
24
+ config.label_text = lambda { |label, required, explicit_label| "#{label} #{required}" }
25
+
26
+ # Define the way to render check boxes / radio buttons with labels.
27
+ config.boolean_style = :inline
28
+
29
+ # You can wrap each item in a collection of radio/check boxes with a tag
30
+ config.item_wrapper_tag = :div
31
+
32
+ # Defines if the default input wrapper class should be included in radio
33
+ # collection wrappers.
34
+ config.include_default_input_wrapper_class = false
35
+
36
+ # CSS class to add for error notification helper.
3
37
  config.error_notification_class = 'alert alert-danger'
4
- config.button_class = 'btn btn-default'
5
- config.boolean_label_class = nil
6
38
 
7
- config.wrappers :vertical_form, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
39
+ # Method used to tidy up errors. Specify any Rails Array method.
40
+ # :first lists the first message for each field.
41
+ # :to_sentence to list all errors for each field.
42
+ config.error_method = :to_sentence
43
+
44
+ # add validation classes to `input_field`
45
+ config.input_field_error_class = 'is-invalid'
46
+ config.input_field_valid_class = 'is-valid'
47
+
48
+
49
+ # vertical forms
50
+ #
51
+ # vertical default_wrapper
52
+ config.wrappers :vertical_form, tag: 'div', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
8
53
  b.use :html5
9
54
  b.use :placeholder
10
55
  b.optional :maxlength
@@ -12,48 +57,90 @@ SimpleForm.setup do |config|
12
57
  b.optional :pattern
13
58
  b.optional :min_max
14
59
  b.optional :readonly
15
- b.use :label, class: 'control-label'
60
+ b.use :label, class: 'form-control-label'
61
+ b.use :input, class: 'form-control', error_class: 'is-invalid', valid_class: 'is-valid'
62
+ b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
63
+ b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
64
+ end
65
+
66
+ # vertical input for boolean
67
+ config.wrappers :vertical_boolean, tag: 'fieldset', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
68
+ b.use :html5
69
+ b.optional :readonly
70
+ b.wrapper :form_check_wrapper, tag: 'div', class: 'form-check' do |bb|
71
+ bb.use :input, class: 'form-check-input', error_class: 'is-invalid', valid_class: 'is-valid'
72
+ bb.use :label, class: 'form-check-label'
73
+ bb.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
74
+ bb.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
75
+ end
76
+ end
77
+
78
+ # vertical input for radio buttons and check boxes
79
+ config.wrappers :vertical_collection, item_wrapper_class: 'form-check', tag: 'fieldset', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
80
+ b.use :html5
81
+ b.optional :readonly
82
+ b.wrapper :legend_tag, tag: 'legend', class: 'col-form-label pt-0' do |ba|
83
+ ba.use :label_text
84
+ end
85
+ b.use :input, class: 'form-check-input', error_class: 'is-invalid', valid_class: 'is-valid'
86
+ b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
87
+ b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
88
+ end
16
89
 
17
- b.use :input, class: 'form-control'
18
- b.use :error, wrap_with: { tag: 'span', class: 'help-block' }
19
- b.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
90
+ # vertical input for inline radio buttons and check boxes
91
+ config.wrappers :vertical_collection_inline, item_wrapper_class: 'form-check form-check-inline', tag: 'fieldset', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
92
+ b.use :html5
93
+ b.optional :readonly
94
+ b.wrapper :legend_tag, tag: 'legend', class: 'col-form-label pt-0' do |ba|
95
+ ba.use :label_text
96
+ end
97
+ b.use :input, class: 'form-check-input', error_class: 'is-invalid', valid_class: 'is-valid'
98
+ b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
99
+ b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
20
100
  end
21
101
 
22
- config.wrappers :vertical_file_input, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
102
+ # vertical file input
103
+ config.wrappers :vertical_file, tag: 'div', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
23
104
  b.use :html5
24
105
  b.use :placeholder
25
106
  b.optional :maxlength
26
107
  b.optional :minlength
27
108
  b.optional :readonly
28
- b.use :label, class: 'control-label'
29
-
30
- b.use :input
31
- b.use :error, wrap_with: { tag: 'span', class: 'help-block' }
32
- b.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
109
+ b.use :label
110
+ b.use :input, class: 'form-control-file', error_class: 'is-invalid', valid_class: 'is-valid'
111
+ b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
112
+ b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
33
113
  end
34
114
 
35
- config.wrappers :vertical_boolean, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
115
+ # vertical multi select
116
+ config.wrappers :vertical_multi_select, tag: 'div', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
36
117
  b.use :html5
37
118
  b.optional :readonly
38
-
39
- b.wrapper tag: 'div', class: 'checkbox' do |ba|
40
- ba.use :label_input
119
+ b.use :label, class: 'form-control-label'
120
+ b.wrapper tag: 'div', class: 'd-flex flex-row justify-content-between align-items-center' do |ba|
121
+ ba.use :input, class: 'form-control mx-1', error_class: 'is-invalid', valid_class: 'is-valid'
41
122
  end
42
-
43
- b.use :error, wrap_with: { tag: 'span', class: 'help-block' }
44
- b.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
123
+ b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
124
+ b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
45
125
  end
46
126
 
47
- config.wrappers :vertical_radio_and_checkboxes, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
127
+ # vertical range input
128
+ config.wrappers :vertical_range, tag: 'div', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
48
129
  b.use :html5
130
+ b.use :placeholder
49
131
  b.optional :readonly
50
- b.use :label, class: 'control-label'
51
- b.use :input
52
- b.use :error, wrap_with: { tag: 'span', class: 'help-block' }
53
- b.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
132
+ b.optional :step
133
+ b.use :label
134
+ b.use :input, class: 'form-control-range', error_class: 'is-invalid', valid_class: 'is-valid'
135
+ b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
136
+ b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
54
137
  end
55
138
 
56
- config.wrappers :horizontal_form, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
139
+
140
+ # horizontal forms
141
+ #
142
+ # horizontal default_wrapper
143
+ config.wrappers :horizontal_form, tag: 'div', class: 'form-group row', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
57
144
  b.use :html5
58
145
  b.use :placeholder
59
146
  b.optional :maxlength
@@ -61,58 +148,243 @@ SimpleForm.setup do |config|
61
148
  b.optional :pattern
62
149
  b.optional :min_max
63
150
  b.optional :readonly
64
- b.use :label, class: 'col-sm-3 control-label'
151
+ b.use :label, class: 'col-sm-3 col-form-label'
152
+ b.wrapper :grid_wrapper, tag: 'div', class: 'col-sm-9' do |ba|
153
+ ba.use :input, class: 'form-control', error_class: 'is-invalid', valid_class: 'is-valid'
154
+ ba.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
155
+ ba.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
156
+ end
157
+ end
158
+
159
+ # horizontal input for boolean
160
+ config.wrappers :horizontal_boolean, tag: 'div', class: 'form-group row', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
161
+ b.use :html5
162
+ b.optional :readonly
163
+ b.wrapper tag: 'label', class: 'col-sm-3' do |ba|
164
+ ba.use :label_text
165
+ end
166
+ b.wrapper :grid_wrapper, tag: 'div', class: 'col-sm-9' do |wr|
167
+ wr.wrapper :form_check_wrapper, tag: 'div', class: 'form-check' do |bb|
168
+ bb.use :input, class: 'form-check-input', error_class: 'is-invalid', valid_class: 'is-valid'
169
+ bb.use :label, class: 'form-check-label'
170
+ bb.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
171
+ bb.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
172
+ end
173
+ end
174
+ end
175
+
176
+ # horizontal input for radio buttons and check boxes
177
+ config.wrappers :horizontal_collection, item_wrapper_class: 'form-check', tag: 'div', class: 'form-group row', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
178
+ b.use :html5
179
+ b.optional :readonly
180
+ b.use :label, class: 'col-sm-3 form-control-label'
181
+ b.wrapper :grid_wrapper, tag: 'div', class: 'col-sm-9' do |ba|
182
+ ba.use :input, class: 'form-check-input', error_class: 'is-invalid', valid_class: 'is-valid'
183
+ ba.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
184
+ ba.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
185
+ end
186
+ end
65
187
 
66
- b.wrapper tag: 'div', class: 'col-sm-9' do |ba|
67
- ba.use :input, class: 'form-control'
68
- ba.use :error, wrap_with: { tag: 'span', class: 'help-block' }
69
- ba.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
188
+ # horizontal input for inline radio buttons and check boxes
189
+ config.wrappers :horizontal_collection_inline, item_wrapper_class: 'form-check form-check-inline', tag: 'div', class: 'form-group row', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
190
+ b.use :html5
191
+ b.optional :readonly
192
+ b.use :label, class: 'col-sm-3 form-control-label'
193
+ b.wrapper :grid_wrapper, tag: 'div', class: 'col-sm-9' do |ba|
194
+ ba.use :input, class: 'form-check-input', error_class: 'is-invalid', valid_class: 'is-valid'
195
+ ba.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
196
+ ba.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
70
197
  end
71
198
  end
72
199
 
73
- config.wrappers :horizontal_file_input, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
200
+ # horizontal file input
201
+ config.wrappers :horizontal_file, tag: 'div', class: 'form-group row', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
74
202
  b.use :html5
75
203
  b.use :placeholder
76
204
  b.optional :maxlength
77
205
  b.optional :minlength
78
206
  b.optional :readonly
207
+ b.use :label, class: 'col-sm-3 form-control-label'
208
+ b.wrapper :grid_wrapper, tag: 'div', class: 'col-sm-9' do |ba|
209
+ ba.use :input, error_class: 'is-invalid', valid_class: 'is-valid'
210
+ ba.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
211
+ ba.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
212
+ end
213
+ end
214
+
215
+ # horizontal multi select
216
+ config.wrappers :horizontal_multi_select, tag: 'div', class: 'form-group row', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
217
+ b.use :html5
218
+ b.optional :readonly
79
219
  b.use :label, class: 'col-sm-3 control-label'
220
+ b.wrapper :grid_wrapper, tag: 'div', class: 'col-sm-9' do |ba|
221
+ ba.wrapper tag: 'div', class: 'd-flex flex-row justify-content-between align-items-center' do |bb|
222
+ bb.use :input, class: 'form-control mx-1', error_class: 'is-invalid', valid_class: 'is-valid'
223
+ end
224
+ ba.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
225
+ ba.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
226
+ end
227
+ end
80
228
 
81
- b.wrapper tag: 'div', class: 'col-sm-9' do |ba|
82
- ba.use :input
83
- ba.use :error, wrap_with: { tag: 'span', class: 'help-block' }
84
- ba.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
229
+ # horizontal range input
230
+ config.wrappers :horizontal_range, tag: 'div', class: 'form-group row', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
231
+ b.use :html5
232
+ b.use :placeholder
233
+ b.optional :readonly
234
+ b.optional :step
235
+ b.use :label, class: 'col-sm-3 form-control-label'
236
+ b.wrapper :grid_wrapper, tag: 'div', class: 'col-sm-9' do |ba|
237
+ ba.use :input, class: 'form-control-range', error_class: 'is-invalid', valid_class: 'is-valid'
238
+ ba.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
239
+ ba.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
85
240
  end
86
241
  end
87
242
 
88
- config.wrappers :horizontal_boolean, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
243
+
244
+ # inline forms
245
+ #
246
+ # inline default_wrapper
247
+ config.wrappers :inline_form, tag: 'span', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
89
248
  b.use :html5
249
+ b.use :placeholder
250
+ b.optional :maxlength
251
+ b.optional :minlength
252
+ b.optional :pattern
253
+ b.optional :min_max
90
254
  b.optional :readonly
255
+ b.use :label, class: 'sr-only'
91
256
 
92
- b.wrapper tag: 'div', class: 'col-sm-offset-3 col-sm-9' do |wr|
93
- wr.wrapper tag: 'div', class: 'checkbox' do |ba|
94
- ba.use :label_input
95
- end
257
+ b.use :input, class: 'form-control', error_class: 'is-invalid', valid_class: 'is-valid'
258
+ b.use :error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
259
+ b.optional :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
260
+ end
261
+
262
+ # inline input for boolean
263
+ config.wrappers :inline_boolean, tag: 'span', class: 'form-check flex-wrap justify-content-start mr-sm-2', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
264
+ b.use :html5
265
+ b.optional :readonly
266
+ b.use :input, class: 'form-check-input', error_class: 'is-invalid', valid_class: 'is-valid'
267
+ b.use :label, class: 'form-check-label'
268
+ b.use :error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
269
+ b.optional :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
270
+ end
271
+
272
+
273
+ # bootstrap custom forms
274
+ #
275
+ # custom input for boolean
276
+ config.wrappers :custom_boolean, tag: 'fieldset', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
277
+ b.use :html5
278
+ b.optional :readonly
279
+ b.wrapper :form_check_wrapper, tag: 'div', class: 'custom-control custom-checkbox' do |bb|
280
+ bb.use :input, class: 'custom-control-input', error_class: 'is-invalid', valid_class: 'is-valid'
281
+ bb.use :label, class: 'custom-control-label'
282
+ bb.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
283
+ bb.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
284
+ end
285
+ end
96
286
 
97
- wr.use :error, wrap_with: { tag: 'span', class: 'help-block' }
98
- wr.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
287
+ config.wrappers :custom_boolean_switch, tag: 'fieldset', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
288
+ b.use :html5
289
+ b.optional :readonly
290
+ b.wrapper :form_check_wrapper, tag: 'div', class: 'custom-control custom-checkbox-switch' do |bb|
291
+ bb.use :input, class: 'custom-control-input', error_class: 'is-invalid', valid_class: 'is-valid'
292
+ bb.use :label, class: 'custom-control-label'
293
+ bb.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
294
+ bb.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
99
295
  end
100
296
  end
101
297
 
102
- config.wrappers :horizontal_radio_and_checkboxes, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
298
+ # custom input for radio buttons and check boxes
299
+ config.wrappers :custom_collection, item_wrapper_class: 'custom-control', tag: 'fieldset', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
103
300
  b.use :html5
104
301
  b.optional :readonly
302
+ b.wrapper :legend_tag, tag: 'legend', class: 'col-form-label pt-0' do |ba|
303
+ ba.use :label_text
304
+ end
305
+ b.use :input, class: 'custom-control-input', error_class: 'is-invalid', valid_class: 'is-valid'
306
+ b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
307
+ b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
308
+ end
105
309
 
106
- b.use :label, class: 'col-sm-3 control-label'
310
+ # custom input for inline radio buttons and check boxes
311
+ config.wrappers :custom_collection_inline, item_wrapper_class: 'custom-control custom-control-inline', tag: 'fieldset', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
312
+ b.use :html5
313
+ b.optional :readonly
314
+ b.wrapper :legend_tag, tag: 'legend', class: 'col-form-label pt-0' do |ba|
315
+ ba.use :label_text
316
+ end
317
+ b.use :input, class: 'custom-control-input', error_class: 'is-invalid', valid_class: 'is-valid'
318
+ b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
319
+ b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
320
+ end
321
+
322
+ # custom file input
323
+ config.wrappers :custom_file, tag: 'div', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
324
+ b.use :html5
325
+ b.use :placeholder
326
+ b.optional :maxlength
327
+ b.optional :minlength
328
+ b.optional :readonly
329
+ b.use :label, class: 'form-control-label'
330
+ b.wrapper :custom_file_wrapper, tag: 'div', class: 'custom-file' do |ba|
331
+ ba.use :input, class: 'custom-file-input', error_class: 'is-invalid', valid_class: 'is-valid'
332
+ ba.use :label, class: 'custom-file-label'
333
+ ba.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
334
+ end
335
+ b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
336
+ end
107
337
 
108
- b.wrapper tag: 'div', class: 'col-sm-9' do |ba|
109
- ba.use :input
110
- ba.use :error, wrap_with: { tag: 'span', class: 'help-block' }
111
- ba.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
338
+ # custom multi select
339
+ config.wrappers :custom_multi_select, tag: 'div', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
340
+ b.use :html5
341
+ b.optional :readonly
342
+ b.use :label, class: 'form-control-label'
343
+ b.wrapper tag: 'div', class: 'd-flex flex-row justify-content-between align-items-center' do |ba|
344
+ ba.use :input, class: 'custom-select mx-1', error_class: 'is-invalid', valid_class: 'is-valid'
112
345
  end
346
+ b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
347
+ b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
348
+ end
349
+
350
+ # custom range input
351
+ config.wrappers :custom_range, tag: 'div', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
352
+ b.use :html5
353
+ b.use :placeholder
354
+ b.optional :readonly
355
+ b.optional :step
356
+ b.use :label, class: 'form-control-label'
357
+ b.use :input, class: 'custom-range', error_class: 'is-invalid', valid_class: 'is-valid'
358
+ b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
359
+ b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
113
360
  end
114
361
 
115
- config.wrappers :inline_form, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
362
+
363
+ # Input Group - custom component
364
+ # see example app and config at https://github.com/rafaelfranca/simple_form-bootstrap
365
+ # config.wrappers :input_group, tag: 'div', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
366
+ # b.use :html5
367
+ # b.use :placeholder
368
+ # b.optional :maxlength
369
+ # b.optional :minlength
370
+ # b.optional :pattern
371
+ # b.optional :min_max
372
+ # b.optional :readonly
373
+ # b.use :label, class: 'form-control-label'
374
+ # b.wrapper :input_group_tag, tag: 'div', class: 'input-group' do |ba|
375
+ # ba.optional :prepend
376
+ # ba.use :input, class: 'form-control', error_class: 'is-invalid', valid_class: 'is-valid'
377
+ # ba.optional :append
378
+ # end
379
+ # b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
380
+ # b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
381
+ # end
382
+
383
+
384
+ # Floating Labels form
385
+ #
386
+ # floating labels default_wrapper
387
+ config.wrappers :floating_labels_form, tag: 'div', class: 'form-label-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
116
388
  b.use :html5
117
389
  b.use :placeholder
118
390
  b.optional :maxlength
@@ -120,35 +392,48 @@ SimpleForm.setup do |config|
120
392
  b.optional :pattern
121
393
  b.optional :min_max
122
394
  b.optional :readonly
123
- b.use :label, class: 'sr-only'
124
-
125
- b.use :input, class: 'form-control'
126
- b.use :error, wrap_with: { tag: 'span', class: 'help-block' }
127
- b.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
395
+ b.use :input, class: 'form-control', error_class: 'is-invalid', valid_class: 'is-valid'
396
+ b.use :label, class: 'form-control-label'
397
+ b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
398
+ b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
128
399
  end
129
400
 
130
- config.wrappers :multi_select, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
401
+ # custom multi select
402
+ config.wrappers :floating_labels_select, tag: 'div', class: 'form-label-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
131
403
  b.use :html5
132
404
  b.optional :readonly
133
- b.use :label, class: 'control-label'
134
- b.wrapper tag: 'div', class: 'form-inline' do |ba|
135
- ba.use :input, class: 'form-control'
136
- ba.use :error, wrap_with: { tag: 'span', class: 'help-block' }
137
- ba.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
138
- end
405
+ b.use :input, class: 'custom-select custom-select-lg', error_class: 'is-invalid', valid_class: 'is-valid'
406
+ b.use :label, class: 'form-control-label'
407
+ b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
408
+ b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
139
409
  end
140
- # Wrappers for forms and inputs using the Bootstrap toolkit.
141
- # Check the Bootstrap docs (http://getbootstrap.com)
142
- # to learn about the different styles for forms and inputs,
143
- # buttons and other elements.
410
+
411
+
412
+ # The default wrapper to be used by the FormBuilder.
144
413
  config.default_wrapper = :vertical_form
414
+
415
+ # Custom wrappers for input types. This should be a hash containing an input
416
+ # type as key and the wrapper that will be used for all inputs with specified type.
145
417
  config.wrapper_mappings = {
146
- check_boxes: :vertical_radio_and_checkboxes,
147
- radio_buttons: :vertical_radio_and_checkboxes,
148
- file: :vertical_file_input,
149
- boolean: :vertical_boolean,
150
- datetime: :multi_select,
151
- date: :multi_select,
152
- time: :multi_select
418
+ boolean: :vertical_boolean,
419
+ check_boxes: :vertical_collection,
420
+ date: :vertical_multi_select,
421
+ datetime: :vertical_multi_select,
422
+ file: :vertical_file,
423
+ radio_buttons: :vertical_collection,
424
+ range: :vertical_range,
425
+ time: :vertical_multi_select
153
426
  }
427
+
428
+ # enable custom form wrappers
429
+ # config.wrapper_mappings = {
430
+ # boolean: :custom_boolean,
431
+ # check_boxes: :custom_collection,
432
+ # date: :custom_multi_select,
433
+ # datetime: :custom_multi_select,
434
+ # file: :custom_file,
435
+ # radio_buttons: :custom_collection,
436
+ # range: :custom_range,
437
+ # time: :custom_multi_select
438
+ # }
154
439
  end
@@ -1,13 +1,21 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # Uncomment this and change the path if necessary to include your own
4
+ # components.
5
+ # See https://github.com/plataformatec/simple_form#custom-components to know
6
+ # more about custom components.
7
+ # Dir[Rails.root.join('lib/components/**/*.rb')].each { |f| require f }
8
+ #
1
9
  # Use this setup block to configure all options available in SimpleForm.
2
10
  SimpleForm.setup do |config|
3
11
  # Don't forget to edit this file to adapt it to your needs (specially
4
12
  # all the grid-related classes)
5
13
  #
6
14
  # Please note that hints are commented out by default since Foundation
7
- # does't provide styles for hints. You will need to provide your own CSS styles for hints.
15
+ # doesn't provide styles for hints. You will need to provide your own CSS styles for hints.
8
16
  # Uncomment them to enable hints.
9
17
 
10
- config.wrappers :vertical_form, class: :input, hint_class: :field_with_hint, error_class: :error do |b|
18
+ config.wrappers :vertical_form, class: :input, hint_class: :field_with_hint, error_class: :error, valid_class: :valid do |b|
11
19
  b.use :html5
12
20
  b.use :placeholder
13
21
  b.optional :maxlength
@@ -21,7 +29,7 @@ SimpleForm.setup do |config|
21
29
  # b.use :hint, wrap_with: { tag: :span, class: :hint }
22
30
  end
23
31
 
24
- config.wrappers :horizontal_form, tag: 'div', class: 'row', hint_class: :field_with_hint, error_class: :error do |b|
32
+ config.wrappers :horizontal_form, tag: 'div', class: 'row', hint_class: :field_with_hint, error_class: :error, valid_class: :valid do |b|
25
33
  b.use :html5
26
34
  b.use :placeholder
27
35
  b.optional :maxlength
@@ -31,7 +39,7 @@ SimpleForm.setup do |config|
31
39
  b.optional :readonly
32
40
 
33
41
  b.wrapper :label_wrapper, tag: :div, class: 'small-3 columns' do |ba|
34
- ba.use :label, class: 'right inline'
42
+ ba.use :label, class: 'text-right inline'
35
43
  end
36
44
 
37
45
  b.wrapper :right_input_wrapper, tag: :div, class: 'small-9 columns' do |ba|
@@ -46,7 +54,7 @@ SimpleForm.setup do |config|
46
54
  b.optional :readonly
47
55
 
48
56
  b.wrapper :container_wrapper, tag: 'div', class: 'small-offset-3 small-9 columns' do |ba|
49
- ba.wrapper :tag => 'label', :class => 'checkbox' do |bb|
57
+ ba.wrapper tag: 'label', class: 'checkbox' do |bb|
50
58
  bb.use :input
51
59
  bb.use :label_text
52
60
  end
@@ -63,7 +71,7 @@ SimpleForm.setup do |config|
63
71
  # Note that you need to adapt this wrapper to your needs. If you need a 4
64
72
  # columns form then change the wrapper class to 'small-3', if you need
65
73
  # only two use 'small-6' and so on.
66
- config.wrappers :inline_form, tag: 'div', class: 'column small-4', hint_class: :field_with_hint, error_class: :error do |b|
74
+ config.wrappers :inline_form, tag: 'div', class: 'column small-4', hint_class: :field_with_hint, error_class: :error, valid_class: :valid do |b|
67
75
  b.use :html5
68
76
  b.use :placeholder
69
77
  b.optional :maxlength
@@ -82,7 +90,7 @@ SimpleForm.setup do |config|
82
90
  # Examples of use:
83
91
  # - wrapper_html: {class: 'row'}, custom_wrapper_html: {class: 'column small-12'}
84
92
  # - custom_wrapper_html: {class: 'column small-3 end'}
85
- config.wrappers :customizable_wrapper, tag: 'div', error_class: :error do |b|
93
+ config.wrappers :customizable_wrapper, tag: 'div', error_class: :error, valid_class: :valid do |b|
86
94
  b.use :html5
87
95
  b.optional :readonly
88
96
 
@@ -98,7 +106,7 @@ SimpleForm.setup do |config|
98
106
  config.button_class = 'button'
99
107
 
100
108
  # Set this to div to make the checkbox and radio properly work
101
- # otherwise simple_form adds a label tag instead of a div arround
109
+ # otherwise simple_form adds a label tag instead of a div around
102
110
  # the nested label
103
111
  config.item_wrapper_tag = :div
104
112
 
@@ -107,4 +115,8 @@ SimpleForm.setup do |config|
107
115
 
108
116
  # The default wrapper to be used by the FormBuilder.
109
117
  config.default_wrapper = :vertical_form
118
+
119
+ # Defines validation classes to the input_field. By default it's nil.
120
+ # config.input_field_valid_class = 'is-valid'
121
+ # config.input_field_error_class = 'is-invalid'
110
122
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
3
  module ActionViewExtensions
3
4
  # A collection of methods required by simple_form but added to rails default form.
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
3
  module ActionViewExtensions
3
4
  # This module creates SimpleForm wrappers around default form_for and fields_for.
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
3
  module Components
3
4
  module Errors
@@ -10,7 +11,15 @@ module SimpleForm
10
11
  end
11
12
 
12
13
  def has_errors?
13
- object && object.respond_to?(:errors) && errors.present?
14
+ object_with_errors? || object.nil? && has_custom_error?
15
+ end
16
+
17
+ def has_value?
18
+ object && object.respond_to?(attribute_name) && object.send(attribute_name).present?
19
+ end
20
+
21
+ def valid?
22
+ !has_errors? && has_value?
14
23
  end
15
24
 
16
25
  protected
@@ -25,6 +34,10 @@ module SimpleForm
25
34
  has_custom_error? ? options[:error] : full_errors.send(error_method)
26
35
  end
27
36
 
37
+ def object_with_errors?
38
+ object && object.respond_to?(:errors) && errors.present?
39
+ end
40
+
28
41
  def error_method
29
42
  options[:error_method] || SimpleForm.error_method
30
43
  end
@@ -38,7 +51,7 @@ module SimpleForm
38
51
  end
39
52
 
40
53
  def errors_on_attribute
41
- object.errors[attribute_name]
54
+ object.errors[attribute_name] || []
42
55
  end
43
56
 
44
57
  def full_errors_on_attribute
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module SimpleForm
2
3
  module Components
3
4
  # Needs to be enabled in order to do automatic lookups.