simple_form 2.0.4 → 2.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 (36) hide show
  1. data/CHANGELOG.md +33 -301
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +30 -12
  4. data/lib/generators/simple_form/install_generator.rb +7 -4
  5. data/lib/generators/simple_form/templates/config/initializers/simple_form_foundation.rb +26 -0
  6. data/lib/simple_form.rb +11 -8
  7. data/lib/simple_form/action_view_extensions/builder.rb +32 -18
  8. data/lib/simple_form/action_view_extensions/builder.rb.orig +247 -0
  9. data/lib/simple_form/components.rb +12 -10
  10. data/lib/simple_form/components/hints.rb +1 -1
  11. data/lib/simple_form/components/label_input.rb +1 -1
  12. data/lib/simple_form/components/maxlength.rb +1 -1
  13. data/lib/simple_form/components/min_max.rb +1 -1
  14. data/lib/simple_form/components/pattern.rb +1 -1
  15. data/lib/simple_form/form_builder.rb +6 -3
  16. data/lib/simple_form/form_builder.rb.orig +486 -0
  17. data/lib/simple_form/helpers/validators.rb +2 -2
  18. data/lib/simple_form/inputs.rb +19 -17
  19. data/lib/simple_form/inputs/base.rb +8 -2
  20. data/lib/simple_form/inputs/date_time_input.rb +0 -4
  21. data/lib/simple_form/version.rb +1 -1
  22. data/lib/simple_form/version.rb.orig +7 -0
  23. data/lib/simple_form/wrappers/root.rb +3 -1
  24. data/test/action_view_extensions/builder_test.rb +113 -67
  25. data/test/action_view_extensions/form_helper_test.rb +5 -0
  26. data/test/components/label_test.rb +27 -17
  27. data/test/form_builder/association_test.rb +10 -7
  28. data/test/form_builder/general_test.rb +48 -25
  29. data/test/form_builder/input_field_test.rb +45 -0
  30. data/test/form_builder/wrapper_test.rb +22 -0
  31. data/test/generators/simple_form_generator_test.rb +8 -0
  32. data/test/inputs/datetime_input_test.rb +2 -2
  33. data/test/inputs/grouped_collection_select_input_test.rb +15 -0
  34. data/test/support/misc_helpers.rb +6 -0
  35. data/test/test_helper.rb +6 -1
  36. metadata +12 -2
@@ -0,0 +1,26 @@
1
+ # Use this setup block to configure all options available in SimpleForm.
2
+ SimpleForm.setup do |config|
3
+ config.wrappers :foundation, :class => :input, :hint_class => :field_with_hint, :error_class => :error do |b|
4
+ b.use :html5
5
+ b.use :placeholder
6
+ b.optional :maxlength
7
+ b.optional :pattern
8
+ b.optional :min_max
9
+ b.optional :readonly
10
+ b.use :label_input
11
+ b.use :error, :wrap_with => { :tag => :small }
12
+
13
+ # Uncomment the following line to enable hints. The line is commented out by default since Foundation
14
+ # does't provide styles for hints. You will need to provide your own CSS styles for hints.
15
+ # b.use :hint, :wrap_with => { :tag => :span, :class => :hint }
16
+ end
17
+
18
+ # CSS class for buttons
19
+ config.button_class = 'button'
20
+
21
+ # CSS class to add for error notification helper.
22
+ config.error_notification_class = 'alert-box alert'
23
+
24
+ # The default wrapper to be used by the FormBuilder.
25
+ config.default_wrapper = :foundation
26
+ end
data/lib/simple_form.rb CHANGED
@@ -6,14 +6,17 @@ require 'active_support/core_ext/hash/except'
6
6
  require 'active_support/core_ext/hash/reverse_merge'
7
7
 
8
8
  module SimpleForm
9
- autoload :Components, 'simple_form/components'
10
- autoload :ErrorNotification, 'simple_form/error_notification'
11
- autoload :FormBuilder, 'simple_form/form_builder'
12
- autoload :Helpers, 'simple_form/helpers'
13
- autoload :I18nCache, 'simple_form/i18n_cache'
14
- autoload :Inputs, 'simple_form/inputs'
15
- autoload :MapType, 'simple_form/map_type'
16
- autoload :Wrappers, 'simple_form/wrappers'
9
+ extend ActiveSupport::Autoload
10
+
11
+ autoload :Helpers
12
+ autoload :Wrappers
13
+
14
+ eager_autoload do
15
+ autoload :Components
16
+ autoload :ErrorNotification
17
+ autoload :FormBuilder
18
+ autoload :Inputs
19
+ end
17
20
 
18
21
  ## CONFIGURATION OPTIONS
19
22
 
@@ -92,7 +92,7 @@ module SimpleForm
92
92
  rendered_collection = render_collection(
93
93
  collection, value_method, text_method, options, html_options
94
94
  ) do |item, value, text, default_html_options|
95
- builder = instantiate_builder(RadioButtonBuilder, attribute, item, value, text, default_html_options)
95
+ builder = instantiate_collection_builder(RadioButtonBuilder, attribute, item, value, text, default_html_options)
96
96
 
97
97
  if block_given?
98
98
  yield builder
@@ -167,7 +167,7 @@ module SimpleForm
167
167
  collection, value_method, text_method, options, html_options
168
168
  ) do |item, value, text, default_html_options|
169
169
  default_html_options[:multiple] = true
170
- builder = instantiate_builder(CheckBoxBuilder, attribute, item, value, text, default_html_options)
170
+ builder = instantiate_collection_builder(CheckBoxBuilder, attribute, item, value, text, default_html_options)
171
171
 
172
172
  if block_given?
173
173
  yield builder
@@ -194,7 +194,7 @@ module SimpleForm
194
194
  # end
195
195
  def simple_fields_for(*args, &block)
196
196
  options = args.extract_options!
197
- options[:wrapper] ||= self.options[:wrapper]
197
+ options[:wrapper] = self.options[:wrapper] if options[:wrapper].nil?
198
198
  options[:defaults] ||= self.options[:defaults]
199
199
 
200
200
  if self.class < ActionView::Helpers::FormBuilder
@@ -207,7 +207,7 @@ module SimpleForm
207
207
 
208
208
  private
209
209
 
210
- def instantiate_builder(builder_class, attribute, item, value, text, html_options)
210
+ def instantiate_collection_builder(builder_class, attribute, item, value, text, html_options)
211
211
  builder_class.new(self, attribute, item,
212
212
  sanitize_attribute_name(attribute, value), text, value, html_options)
213
213
  end
@@ -277,34 +277,48 @@ end
277
277
  module ActionView::Helpers
278
278
  class FormBuilder
279
279
  include SimpleForm::ActionViewExtensions::Builder
280
+ end
280
281
 
281
- # Override default Rails collection_select helper to handle lambdas/procs in
282
+ module FormOptionsHelper
283
+ # Override Rails options_from_collection_for_select to handle lambdas/procs in
282
284
  # text and value methods, so it works the same way as collection_radio_buttons
283
285
  # and collection_check_boxes in SimpleForm. If none of text/value methods is a
284
286
  # callable object, then it just delegates back to original collection select.
285
- #
286
- alias :original_collection_select :collection_select
287
- def collection_select(attribute, collection, value_method, text_method, options={}, html_options={})
287
+ # FIXME: remove when support only Rails 4.0 forward
288
+ # https://github.com/rails/rails/commit/9035324367526af0300477a58b6d3efc15d1a5a8
289
+ alias :original_options_from_collection_for_select :options_from_collection_for_select
290
+ def options_from_collection_for_select(collection, value_method, text_method, selected = nil)
288
291
  if value_method.respond_to?(:call) || text_method.respond_to?(:call)
289
292
  collection = collection.map do |item|
290
293
  value = value_for_collection(item, value_method)
291
294
  text = value_for_collection(item, text_method)
292
295
 
293
- default_html_options = default_html_options_for_collection(item, value, options, html_options)
294
- disabled = value if default_html_options[:disabled]
295
- selected = value if default_html_options[:selected]
296
-
297
- [value, text, selected, disabled]
296
+ [value, text]
298
297
  end
299
298
 
300
- [:disabled, :selected].each do |option|
301
- option_value = collection.map(&:pop).compact
302
- options[option] = option_value if option_value.present?
303
- end
304
299
  value_method, text_method = :first, :last
300
+ selected = extract_selected_and_disabled_and_call_procs selected, collection
301
+ end
302
+
303
+ original_options_from_collection_for_select collection, value_method, text_method, selected
304
+ end
305
+
306
+ private
307
+
308
+ def extract_selected_and_disabled_and_call_procs(selected, collection)
309
+ selected, disabled = extract_selected_and_disabled selected
310
+ selected_disabled = { :selected => selected, :disabled => disabled }
311
+
312
+ selected_disabled.each do |key, check|
313
+ if check.is_a? Proc
314
+ values = collection.map { |option| option.first if check.call(option.first) }
315
+ selected_disabled[key] = values
316
+ end
305
317
  end
318
+ end
306
319
 
307
- original_collection_select(attribute, collection, value_method, text_method, options, html_options)
320
+ def value_for_collection(item, value) #:nodoc:
321
+ value.respond_to?(:call) ? value.call(item) : item.send(value)
308
322
  end
309
323
  end
310
324
 
@@ -0,0 +1,247 @@
1
+ module SimpleForm
2
+ module ActionViewExtensions
3
+ # A collection of methods required by simple_form but added to rails default form.
4
+ # This means that you can use such methods outside simple_form context.
5
+ module Builder
6
+
7
+ # Wrapper for using SimpleForm inside a default rails form.
8
+ # Example:
9
+ #
10
+ # form_for @user do |f|
11
+ # f.simple_fields_for :posts do |posts_form|
12
+ # # Here you have all simple_form methods available
13
+ # posts_form.input :title
14
+ # end
15
+ # end
16
+ def simple_fields_for(*args, &block)
17
+ options = args.extract_options!
18
+ options[:wrapper] = self.options[:wrapper] if options[:wrapper].nil?
19
+ options[:defaults] ||= self.options[:defaults]
20
+
21
+ if self.class < ActionView::Helpers::FormBuilder
22
+ options[:builder] ||= self.class
23
+ else
24
+ options[:builder] ||= SimpleForm::FormBuilder
25
+ end
26
+ fields_for(*(args << options), &block)
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ module SimpleForm
33
+ module Tags
34
+ module CollectionExtensions
35
+ private
36
+
37
+ def render_collection
38
+ item_wrapper_tag = @options.fetch(:item_wrapper_tag, :span)
39
+ item_wrapper_class = @options[:item_wrapper_class]
40
+
41
+ @collection.map do |item|
42
+ value = value_for_collection(item, @value_method)
43
+ text = value_for_collection(item, @text_method)
44
+ default_html_options = default_html_options_for_collection(item, value)
45
+
46
+ rendered_item = yield item, value, text, default_html_options
47
+
48
+ item_wrapper_tag ? @template_object.content_tag(item_wrapper_tag, rendered_item, :class => item_wrapper_class) : rendered_item
49
+ end.join.html_safe
50
+ end
51
+
52
+ def wrap_rendered_collection(collection)
53
+ wrapper_tag = @options[:collection_wrapper_tag]
54
+
55
+ if wrapper_tag
56
+ wrapper_class = @options[:collection_wrapper_class]
57
+ @template_object.content_tag(wrapper_tag, collection, :class => wrapper_class)
58
+ else
59
+ collection
60
+ end
61
+ end
62
+ end
63
+
64
+ class CollectionRadioButtons < ActionView::Helpers::Tags::CollectionRadioButtons
65
+ include CollectionExtensions
66
+
67
+ def render
68
+ wrap_rendered_collection(super)
69
+ end
70
+
71
+ private
72
+
73
+ def render_component(builder)
74
+ builder.radio_button + builder.label(:class => "collection_radio_buttons")
75
+ end
76
+ end
77
+
78
+ class CollectionCheckBoxes < ActionView::Helpers::Tags::CollectionCheckBoxes
79
+ include CollectionExtensions
80
+
81
+ def render
82
+ wrap_rendered_collection(super)
83
+ end
84
+
85
+ private
86
+
87
+ def render_component(builder)
88
+ builder.check_box + builder.label(:class => "collection_check_boxes")
89
+ end
90
+ end
91
+ end
92
+ end
93
+
94
+ module ActionView::Helpers
95
+ class FormBuilder
96
+ include SimpleForm::ActionViewExtensions::Builder
97
+ end
98
+
99
+ <<<<<<< HEAD
100
+ # Create a collection of radio inputs for the attribute. Basically this
101
+ # helper will create a radio input associated with a label for each
102
+ # text/value option in the collection, using value_method and text_method
103
+ # to convert these text/value. You can give a symbol or a proc to both
104
+ # value_method and text_method, that will be evaluated for each item in
105
+ # the collection.
106
+ #
107
+ # == Examples
108
+ #
109
+ # form_for @user do |f|
110
+ # f.collection_radio_buttons :options, [[true, 'Yes'] ,[false, 'No']], :first, :last
111
+ # end
112
+ #
113
+ # <input id="user_options_true" name="user[options]" type="radio" value="true" />
114
+ # <label class="collection_radio_buttons" for="user_options_true">Yes</label>
115
+ # <input id="user_options_false" name="user[options]" type="radio" value="false" />
116
+ # <label class="collection_radio_buttons" for="user_options_false">No</label>
117
+ #
118
+ # It is also possible to give a block that should generate the radio +
119
+ # label. To wrap the radio with the label, for instance:
120
+ #
121
+ # form_for @user do |f|
122
+ # f.collection_radio_buttons(
123
+ # :options, [[true, 'Yes'] ,[false, 'No']], :first, :last
124
+ # ) do |b|
125
+ # b.label { b.radio_button + b.text }
126
+ # end
127
+ # end
128
+ #
129
+ # == Options
130
+ #
131
+ # Collection radio accepts some extra options:
132
+ #
133
+ # * checked => the value that should be checked initially.
134
+ #
135
+ # * disabled => the value or values that should be disabled. Accepts a single
136
+ # item or an array of items.
137
+ #
138
+ # * collection_wrapper_tag => the tag to wrap the entire collection.
139
+ #
140
+ # * collection_wrapper_class => the CSS class to use for collection_wrapper_tag
141
+ #
142
+ # * item_wrapper_tag => the tag to wrap each item in the collection.
143
+ #
144
+ # * item_wrapper_class => the CSS class to use for item_wrapper_tag
145
+ #
146
+ # * a block => to generate the label + radio or any other component.
147
+ def collection_radio_buttons(method, collection, value_method, text_method, options = {}, html_options = {}, &block)
148
+ SimpleForm::Tags::CollectionRadioButtons.new(@object_name, method, @template, collection, value_method, text_method, objectify_options(options), @default_options.merge(html_options)).render(&block)
149
+ =======
150
+ module FormOptionsHelper
151
+ # Override Rails options_from_collection_for_select to handle lambdas/procs in
152
+ # text and value methods, so it works the same way as collection_radio_buttons
153
+ # and collection_check_boxes in SimpleForm. If none of text/value methods is a
154
+ # callable object, then it just delegates back to original collection select.
155
+ # FIXME: remove when support only Rails 4.0 forward
156
+ # https://github.com/rails/rails/commit/9035324367526af0300477a58b6d3efc15d1a5a8
157
+ alias :original_options_from_collection_for_select :options_from_collection_for_select
158
+ def options_from_collection_for_select(collection, value_method, text_method, selected = nil)
159
+ if value_method.respond_to?(:call) || text_method.respond_to?(:call)
160
+ collection = collection.map do |item|
161
+ value = value_for_collection(item, value_method)
162
+ text = value_for_collection(item, text_method)
163
+
164
+ [value, text]
165
+ end
166
+
167
+ value_method, text_method = :first, :last
168
+ selected = extract_selected_and_disabled_and_call_procs selected, collection
169
+ end
170
+
171
+ original_options_from_collection_for_select collection, value_method, text_method, selected
172
+ end
173
+
174
+ private
175
+
176
+ def extract_selected_and_disabled_and_call_procs(selected, collection)
177
+ selected, disabled = extract_selected_and_disabled selected
178
+ selected_disabled = { :selected => selected, :disabled => disabled }
179
+
180
+ selected_disabled.each do |key, check|
181
+ if check.is_a? Proc
182
+ values = collection.map { |option| option.first if check.call(option.first) }
183
+ selected_disabled[key] = values
184
+ end
185
+ end
186
+ end
187
+
188
+ def value_for_collection(item, value) #:nodoc:
189
+ value.respond_to?(:call) ? value.call(item) : item.send(value)
190
+ >>>>>>> master
191
+ end
192
+
193
+ # Creates a collection of check boxes for each item in the collection,
194
+ # associated with a clickable label. Use value_method and text_method to
195
+ # convert items in the collection for use as text/value in check boxes.
196
+ # You can give a symbol or a proc to both value_method and text_method,
197
+ # that will be evaluated for each item in the collection.
198
+ #
199
+ # == Examples
200
+ #
201
+ # form_for @user do |f|
202
+ # f.collection_check_boxes :options, [[true, 'Yes'] ,[false, 'No']], :first, :last
203
+ # end
204
+ #
205
+ # <input name="user[options][]" type="hidden" value="" />
206
+ # <input id="user_options_true" name="user[options][]" type="checkbox" value="true" />
207
+ # <label class="collection_check_boxes" for="user_options_true">Yes</label>
208
+ # <input name="user[options][]" type="hidden" value="" />
209
+ # <input id="user_options_false" name="user[options][]" type="checkbox" value="false" />
210
+ # <label class="collection_check_boxes" for="user_options_false">No</label>
211
+ #
212
+ # It is also possible to give a block that should generate the check box +
213
+ # label. To wrap the check box with the label, for instance:
214
+ #
215
+ # form_for @user do |f|
216
+ # f.collection_check_boxes(
217
+ # :options, [[true, 'Yes'] ,[false, 'No']], :first, :last
218
+ # ) do |b|
219
+ # b.label { b.check_box + b.text }
220
+ # end
221
+ # end
222
+ #
223
+ # == Options
224
+ #
225
+ # Collection check box accepts some extra options:
226
+ #
227
+ # * checked => the value or values that should be checked initially. Accepts
228
+ # a single item or an array of items. It overrides existing associations.
229
+ #
230
+ # * disabled => the value or values that should be disabled. Accepts a single
231
+ # item or an array of items.
232
+ #
233
+ # * collection_wrapper_tag => the tag to wrap the entire collection.
234
+ #
235
+ # * collection_wrapper_class => the CSS class to use for collection_wrapper_tag. This option
236
+ # is ignored if the :collection_wrapper_tag option is blank.
237
+ #
238
+ # * item_wrapper_tag => the tag to wrap each item in the collection.
239
+ #
240
+ # * item_wrapper_class => the CSS class to use for item_wrapper_tag
241
+ #
242
+ # * a block => to generate the label + check box or any other component.
243
+ def collection_check_boxes(method, collection, value_method, text_method, options = {}, html_options = {}, &block)
244
+ SimpleForm::Tags::CollectionCheckBoxes.new(@object_name, method, @template, collection, value_method, text_method, objectify_options(options), @default_options.merge(html_options)).render(&block)
245
+ end
246
+ end
247
+ end
@@ -6,15 +6,17 @@ module SimpleForm
6
6
  # to the input in order to be enabled. On the other hand, things like
7
7
  # hints can generate output automatically by doing I18n lookups.
8
8
  module Components
9
- autoload :Errors, 'simple_form/components/errors'
10
- autoload :Hints, 'simple_form/components/hints'
11
- autoload :HTML5, 'simple_form/components/html5'
12
- autoload :LabelInput, 'simple_form/components/label_input'
13
- autoload :Labels, 'simple_form/components/labels'
14
- autoload :MinMax, 'simple_form/components/min_max'
15
- autoload :Maxlength, 'simple_form/components/maxlength'
16
- autoload :Pattern, 'simple_form/components/pattern'
17
- autoload :Placeholders, 'simple_form/components/placeholders'
18
- autoload :Readonly, 'simple_form/components/readonly'
9
+ extend ActiveSupport::Autoload
10
+
11
+ autoload :Errors
12
+ autoload :Hints
13
+ autoload :HTML5
14
+ autoload :LabelInput
15
+ autoload :Labels
16
+ autoload :MinMax
17
+ autoload :Maxlength
18
+ autoload :Pattern
19
+ autoload :Placeholders
20
+ autoload :Readonly
19
21
  end
20
22
  end
@@ -11,7 +11,7 @@ module SimpleForm
11
11
  end
12
12
 
13
13
  def has_hint?
14
- hint.present?
14
+ options[:hint] != false && hint.present?
15
15
  end
16
16
  end
17
17
  end
@@ -8,7 +8,7 @@ module SimpleForm
8
8
  end
9
9
 
10
10
  def label_input
11
- (options[:label] == false ? "" : label) + input
11
+ options[:label] == false ? input : (label + input)
12
12
  end
13
13
  end
14
14
  end
@@ -23,7 +23,7 @@ module SimpleForm
23
23
  end
24
24
 
25
25
  def find_length_validator
26
- find_validator(ActiveModel::Validations::LengthValidator)
26
+ find_validator(:length)
27
27
  end
28
28
 
29
29
  def has_tokenizer?(length_validator)