simple_form_awesome 2.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.
Files changed (103) hide show
  1. data/CHANGELOG.md +327 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +25 -0
  4. data/lib/generators/simple_form/USAGE +3 -0
  5. data/lib/generators/simple_form/install_generator.rb +48 -0
  6. data/lib/generators/simple_form/templates/AUI_README +19 -0
  7. data/lib/generators/simple_form/templates/README +12 -0
  8. data/lib/generators/simple_form/templates/_form.html.erb +13 -0
  9. data/lib/generators/simple_form/templates/_form.html.haml +10 -0
  10. data/lib/generators/simple_form/templates/_form.html.slim +10 -0
  11. data/lib/generators/simple_form/templates/config/initializers/simple_form.rb +142 -0
  12. data/lib/generators/simple_form/templates/config/initializers/simple_form_aui.rb +21 -0
  13. data/lib/generators/simple_form/templates/config/initializers/simple_form_bootstrap.rb +45 -0
  14. data/lib/generators/simple_form/templates/config/initializers/simple_form_foundation.rb +26 -0
  15. data/lib/generators/simple_form/templates/config/locales/simple_form.en.yml +26 -0
  16. data/lib/simple_form/action_view_extensions/builder.rb +340 -0
  17. data/lib/simple_form/action_view_extensions/form_helper.rb +72 -0
  18. data/lib/simple_form/components/errors.rb +35 -0
  19. data/lib/simple_form/components/hints.rb +18 -0
  20. data/lib/simple_form/components/html5.rb +26 -0
  21. data/lib/simple_form/components/label_input.rb +15 -0
  22. data/lib/simple_form/components/labels.rb +79 -0
  23. data/lib/simple_form/components/maxlength.rb +41 -0
  24. data/lib/simple_form/components/min_max.rb +50 -0
  25. data/lib/simple_form/components/pattern.rb +34 -0
  26. data/lib/simple_form/components/placeholders.rb +16 -0
  27. data/lib/simple_form/components/readonly.rb +22 -0
  28. data/lib/simple_form/components.rb +20 -0
  29. data/lib/simple_form/core_ext/hash.rb +16 -0
  30. data/lib/simple_form/error_notification.rb +48 -0
  31. data/lib/simple_form/form_builder.rb +482 -0
  32. data/lib/simple_form/helpers/autofocus.rb +11 -0
  33. data/lib/simple_form/helpers/disabled.rb +15 -0
  34. data/lib/simple_form/helpers/readonly.rb +15 -0
  35. data/lib/simple_form/helpers/required.rb +35 -0
  36. data/lib/simple_form/helpers/validators.rb +44 -0
  37. data/lib/simple_form/helpers.rb +12 -0
  38. data/lib/simple_form/i18n_cache.rb +22 -0
  39. data/lib/simple_form/inputs/aui_string_input.rb +10 -0
  40. data/lib/simple_form/inputs/base.rb +184 -0
  41. data/lib/simple_form/inputs/block_input.rb +14 -0
  42. data/lib/simple_form/inputs/boolean_input.rb +78 -0
  43. data/lib/simple_form/inputs/collection_check_boxes_input.rb +21 -0
  44. data/lib/simple_form/inputs/collection_input.rb +101 -0
  45. data/lib/simple_form/inputs/collection_radio_buttons_input.rb +63 -0
  46. data/lib/simple_form/inputs/collection_select_input.rb +14 -0
  47. data/lib/simple_form/inputs/date_time_input.rb +28 -0
  48. data/lib/simple_form/inputs/file_input.rb +9 -0
  49. data/lib/simple_form/inputs/grouped_collection_select_input.rb +41 -0
  50. data/lib/simple_form/inputs/hidden_input.rb +17 -0
  51. data/lib/simple_form/inputs/numeric_input.rb +24 -0
  52. data/lib/simple_form/inputs/password_input.rb +12 -0
  53. data/lib/simple_form/inputs/priority_input.rb +24 -0
  54. data/lib/simple_form/inputs/range_input.rb +14 -0
  55. data/lib/simple_form/inputs/string_input.rb +23 -0
  56. data/lib/simple_form/inputs/text_area_input.rb +12 -0
  57. data/lib/simple_form/inputs/text_input.rb +11 -0
  58. data/lib/simple_form/inputs.rb +23 -0
  59. data/lib/simple_form/map_type.rb +16 -0
  60. data/lib/simple_form/version.rb +3 -0
  61. data/lib/simple_form/wrappers/builder.rb +103 -0
  62. data/lib/simple_form/wrappers/many.rb +73 -0
  63. data/lib/simple_form/wrappers/root.rb +36 -0
  64. data/lib/simple_form/wrappers/single.rb +24 -0
  65. data/lib/simple_form/wrappers.rb +8 -0
  66. data/lib/simple_form.rb +221 -0
  67. data/test/action_view_extensions/builder_test.rb +583 -0
  68. data/test/action_view_extensions/form_helper_test.rb +143 -0
  69. data/test/components/label_test.rb +327 -0
  70. data/test/form_builder/association_test.rb +186 -0
  71. data/test/form_builder/button_test.rb +47 -0
  72. data/test/form_builder/error_notification_test.rb +79 -0
  73. data/test/form_builder/error_test.rb +121 -0
  74. data/test/form_builder/general_test.rb +402 -0
  75. data/test/form_builder/hint_test.rb +138 -0
  76. data/test/form_builder/input_field_test.rb +63 -0
  77. data/test/form_builder/label_test.rb +71 -0
  78. data/test/form_builder/wrapper_test.rb +203 -0
  79. data/test/generators/simple_form_generator_test.rb +42 -0
  80. data/test/inputs/boolean_input_test.rb +140 -0
  81. data/test/inputs/collection_check_boxes_input_test.rb +224 -0
  82. data/test/inputs/collection_radio_buttons_input_test.rb +326 -0
  83. data/test/inputs/collection_select_input_test.rb +241 -0
  84. data/test/inputs/datetime_input_test.rb +99 -0
  85. data/test/inputs/disabled_test.rb +78 -0
  86. data/test/inputs/discovery_test.rb +69 -0
  87. data/test/inputs/file_input_test.rb +16 -0
  88. data/test/inputs/general_test.rb +116 -0
  89. data/test/inputs/grouped_collection_select_input_test.rb +118 -0
  90. data/test/inputs/hidden_input_test.rb +30 -0
  91. data/test/inputs/numeric_input_test.rb +173 -0
  92. data/test/inputs/priority_input_test.rb +43 -0
  93. data/test/inputs/readonly_test.rb +101 -0
  94. data/test/inputs/required_test.rb +113 -0
  95. data/test/inputs/string_input_test.rb +146 -0
  96. data/test/inputs/text_input_test.rb +24 -0
  97. data/test/simple_form_test.rb +9 -0
  98. data/test/support/discovery_inputs.rb +27 -0
  99. data/test/support/misc_helpers.rb +138 -0
  100. data/test/support/mock_controller.rb +24 -0
  101. data/test/support/models.rb +216 -0
  102. data/test/test_helper.rb +95 -0
  103. metadata +217 -0
@@ -0,0 +1,45 @@
1
+ # Use this setup block to configure all options available in SimpleForm.
2
+ SimpleForm.setup do |config|
3
+ config.wrappers :bootstrap, :tag => 'div', :class => 'control-group', :error_class => 'error' do |b|
4
+ b.use :html5
5
+ b.use :placeholder
6
+ b.use :label
7
+ b.wrapper :tag => 'div', :class => 'controls' do |ba|
8
+ ba.use :input
9
+ ba.use :error, :wrap_with => { :tag => 'span', :class => 'help-inline' }
10
+ ba.use :hint, :wrap_with => { :tag => 'p', :class => 'help-block' }
11
+ end
12
+ end
13
+
14
+ config.wrappers :prepend, :tag => 'div', :class => "control-group", :error_class => 'error' do |b|
15
+ b.use :html5
16
+ b.use :placeholder
17
+ b.use :label
18
+ b.wrapper :tag => 'div', :class => 'controls' do |input|
19
+ input.wrapper :tag => 'div', :class => 'input-prepend' do |prepend|
20
+ prepend.use :input
21
+ end
22
+ input.use :hint, :wrap_with => { :tag => 'span', :class => 'help-block' }
23
+ input.use :error, :wrap_with => { :tag => 'span', :class => 'help-inline' }
24
+ end
25
+ end
26
+
27
+ config.wrappers :append, :tag => 'div', :class => "control-group", :error_class => 'error' do |b|
28
+ b.use :html5
29
+ b.use :placeholder
30
+ b.use :label
31
+ b.wrapper :tag => 'div', :class => 'controls' do |input|
32
+ input.wrapper :tag => 'div', :class => 'input-append' do |append|
33
+ append.use :input
34
+ end
35
+ input.use :hint, :wrap_with => { :tag => 'span', :class => 'help-block' }
36
+ input.use :error, :wrap_with => { :tag => 'span', :class => 'help-inline' }
37
+ end
38
+ end
39
+
40
+ # Wrappers for forms and inputs using the Twitter Bootstrap toolkit.
41
+ # Check the Bootstrap docs (http://twitter.github.com/bootstrap)
42
+ # to learn about the different styles for forms and inputs,
43
+ # buttons and other elements.
44
+ config.default_wrapper = :bootstrap
45
+ end
@@ -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
@@ -0,0 +1,26 @@
1
+ en:
2
+ simple_form:
3
+ "yes": 'Yes'
4
+ "no": 'No'
5
+ required:
6
+ text: 'required'
7
+ mark: '*'
8
+ # You can uncomment the line below if you need to overwrite the whole required html.
9
+ # When using html, text and mark won't be used.
10
+ # html: '<abbr title="required">*</abbr>'
11
+ error_notification:
12
+ default_message: "Please review the problems below:"
13
+ # Labels and hints examples
14
+ # labels:
15
+ # defaults:
16
+ # password: 'Password'
17
+ # user:
18
+ # new:
19
+ # email: 'E-mail to sign in.'
20
+ # edit:
21
+ # email: 'E-mail.'
22
+ # hints:
23
+ # defaults:
24
+ # username: 'User name to sign in.'
25
+ # password: 'No special characters, please.'
26
+
@@ -0,0 +1,340 @@
1
+ module SimpleForm
2
+ module ActionViewExtensions
3
+ # Base builder to handle each instance of a collection of radio buttons / check boxes.
4
+ # Based on (at this time upcoming) Rails 4 collection builders.
5
+ class BuilderBase #:nodoc:
6
+ attr_reader :object, :text, :value
7
+
8
+ def initialize(form_builder, method_name, object, sanitized_attribute_name, text,
9
+ value, input_html_options)
10
+ @form_builder = form_builder
11
+ @method_name = method_name
12
+ @object = object
13
+ @sanitized_attribute_name = sanitized_attribute_name
14
+ @text = text
15
+ @value = value
16
+ @input_html_options = input_html_options
17
+ end
18
+
19
+ def label(label_html_options={}, &block)
20
+ @form_builder.label(@sanitized_attribute_name, @text, label_html_options, &block)
21
+ end
22
+ end
23
+
24
+ # Handles generating an instance of radio + label for collection_radio_buttons.
25
+ class RadioButtonBuilder < BuilderBase #:nodoc:
26
+ def radio_button(extra_html_options={})
27
+ html_options = extra_html_options.merge(@input_html_options)
28
+ @form_builder.radio_button(@method_name, @value, html_options)
29
+ end
30
+ end
31
+
32
+ # Handles generating an instance of check box + label for collection_check_boxes.
33
+ class CheckBoxBuilder < BuilderBase #:nodoc:
34
+ def check_box(extra_html_options={})
35
+ html_options = extra_html_options.merge(@input_html_options)
36
+ @form_builder.check_box(@method_name, html_options, @value, nil)
37
+ end
38
+ end
39
+
40
+ # A collection of methods required by simple_form but added to rails default form.
41
+ # This means that you can use such methods outside simple_form context.
42
+ module Builder
43
+ # Create a collection of radio inputs for the attribute. Basically this
44
+ # helper will create a radio input associated with a label for each
45
+ # text/value option in the collection, using value_method and text_method
46
+ # to convert these text/value. You can give a symbol or a proc to both
47
+ # value_method and text_method, that will be evaluated for each item in
48
+ # the collection.
49
+ #
50
+ # == Examples
51
+ #
52
+ # form_for @user do |f|
53
+ # f.collection_radio_buttons :options, [[true, 'Yes'] ,[false, 'No']], :first, :last
54
+ # end
55
+ #
56
+ # <input id="user_options_true" name="user[options]" type="radio" value="true" />
57
+ # <label class="collection_radio_buttons" for="user_options_true">Yes</label>
58
+ # <input id="user_options_false" name="user[options]" type="radio" value="false" />
59
+ # <label class="collection_radio_buttons" for="user_options_false">No</label>
60
+ #
61
+ # It is also possible to give a block that should generate the radio +
62
+ # label. To wrap the radio with the label, for instance:
63
+ #
64
+ # form_for @user do |f|
65
+ # f.collection_radio_buttons(
66
+ # :options, [[true, 'Yes'] ,[false, 'No']], :first, :last
67
+ # ) do |b|
68
+ # b.label { b.radio_button + b.text }
69
+ # end
70
+ # end
71
+ #
72
+ # == Options
73
+ #
74
+ # Collection radio accepts some extra options:
75
+ #
76
+ # * checked => the value that should be checked initially.
77
+ #
78
+ # * disabled => the value or values that should be disabled. Accepts a single
79
+ # item or an array of items.
80
+ #
81
+ # * collection_wrapper_tag => the tag to wrap the entire collection.
82
+ #
83
+ # * collection_wrapper_class => the CSS class to use for collection_wrapper_tag
84
+ #
85
+ # * item_wrapper_tag => the tag to wrap each item in the collection.
86
+ #
87
+ # * item_wrapper_class => the CSS class to use for item_wrapper_tag
88
+ #
89
+ # * a block => to generate the label + radio or any other component.
90
+ #
91
+ def collection_radio_buttons(attribute, collection, value_method, text_method, options={}, html_options={})
92
+ rendered_collection = render_collection(
93
+ collection, value_method, text_method, options, html_options
94
+ ) do |item, value, text, default_html_options|
95
+ builder = instantiate_collection_builder(RadioButtonBuilder, attribute, item, value, text, default_html_options)
96
+
97
+ if block_given?
98
+ yield builder
99
+ else
100
+ builder.radio_button + builder.label(:class => "collection_radio_buttons")
101
+ end
102
+ end
103
+
104
+ wrap_rendered_collection(rendered_collection, options)
105
+ end
106
+
107
+ # deprecated
108
+ def collection_radio(*args, &block)
109
+ SimpleForm.deprecation_warn "The `collection_radio` helper is deprecated, " \
110
+ "please use `collection_radio_buttons` instead."
111
+ collection_radio_buttons(*args, &block)
112
+ end
113
+
114
+ # Creates a collection of check boxes for each item in the collection,
115
+ # associated with a clickable label. Use value_method and text_method to
116
+ # convert items in the collection for use as text/value in check boxes.
117
+ # You can give a symbol or a proc to both value_method and text_method,
118
+ # that will be evaluated for each item in the collection.
119
+ #
120
+ # == Examples
121
+ #
122
+ # form_for @user do |f|
123
+ # f.collection_check_boxes :options, [[true, 'Yes'] ,[false, 'No']], :first, :last
124
+ # end
125
+ #
126
+ # <input name="user[options][]" type="hidden" value="" />
127
+ # <input id="user_options_true" name="user[options][]" type="checkbox" value="true" />
128
+ # <label class="collection_check_boxes" for="user_options_true">Yes</label>
129
+ # <input name="user[options][]" type="hidden" value="" />
130
+ # <input id="user_options_false" name="user[options][]" type="checkbox" value="false" />
131
+ # <label class="collection_check_boxes" for="user_options_false">No</label>
132
+ #
133
+ # It is also possible to give a block that should generate the check box +
134
+ # label. To wrap the check box with the label, for instance:
135
+ #
136
+ # form_for @user do |f|
137
+ # f.collection_check_boxes(
138
+ # :options, [[true, 'Yes'] ,[false, 'No']], :first, :last
139
+ # ) do |b|
140
+ # b.label { b.check_box + b.text }
141
+ # end
142
+ # end
143
+ #
144
+ # == Options
145
+ #
146
+ # Collection check box accepts some extra options:
147
+ #
148
+ # * checked => the value or values that should be checked initially. Accepts
149
+ # a single item or an array of items. It overrides existing associations.
150
+ #
151
+ # * disabled => the value or values that should be disabled. Accepts a single
152
+ # item or an array of items.
153
+ #
154
+ # * collection_wrapper_tag => the tag to wrap the entire collection.
155
+ #
156
+ # * collection_wrapper_class => the CSS class to use for collection_wrapper_tag. This option
157
+ # is ignored if the :collection_wrapper_tag option is blank.
158
+ #
159
+ # * item_wrapper_tag => the tag to wrap each item in the collection.
160
+ #
161
+ # * item_wrapper_class => the CSS class to use for item_wrapper_tag
162
+ #
163
+ # * a block => to generate the label + check box or any other component.
164
+ #
165
+ def collection_check_boxes(attribute, collection, value_method, text_method, options={}, html_options={})
166
+ rendered_collection = render_collection(
167
+ collection, value_method, text_method, options, html_options
168
+ ) do |item, value, text, default_html_options|
169
+ default_html_options[:multiple] = true
170
+ builder = instantiate_collection_builder(CheckBoxBuilder, attribute, item, value, text, default_html_options)
171
+
172
+ if block_given?
173
+ yield builder
174
+ else
175
+ builder.check_box + builder.label(:class => "collection_check_boxes")
176
+ end
177
+ end
178
+
179
+ # Append a hidden field to make sure something will be sent back to the
180
+ # server if all checkboxes are unchecked.
181
+ hidden = @template.hidden_field_tag("#{object_name}[#{attribute}][]", "", :id => nil)
182
+
183
+ wrap_rendered_collection(rendered_collection + hidden, options)
184
+ end
185
+
186
+ # Wrapper for using SimpleForm inside a default rails form.
187
+ # Example:
188
+ #
189
+ # form_for @user do |f|
190
+ # f.simple_fields_for :posts do |posts_form|
191
+ # # Here you have all simple_form methods available
192
+ # posts_form.input :title
193
+ # end
194
+ # end
195
+ def simple_fields_for(*args, &block)
196
+ options = args.extract_options!
197
+ options[:wrapper] ||= self.options[:wrapper]
198
+ options[:defaults] ||= self.options[:defaults]
199
+
200
+ if self.class < ActionView::Helpers::FormBuilder
201
+ options[:builder] ||= self.class
202
+ else
203
+ options[:builder] ||= SimpleForm::FormBuilder
204
+ end
205
+ fields_for(*(args << options), &block)
206
+ end
207
+
208
+ private
209
+
210
+ def instantiate_collection_builder(builder_class, attribute, item, value, text, html_options)
211
+ builder_class.new(self, attribute, item,
212
+ sanitize_attribute_name(attribute, value), text, value, html_options)
213
+ end
214
+
215
+ # Generate default options for collection helpers, such as :checked and
216
+ # :disabled.
217
+ def default_html_options_for_collection(item, value, options, html_options) #:nodoc:
218
+ html_options = html_options.dup
219
+
220
+ [:checked, :selected, :disabled].each do |option|
221
+ current_option = options[option]
222
+ next if current_option.nil?
223
+
224
+ accept = if current_option.respond_to?(:call)
225
+ current_option.call(item)
226
+ else
227
+ Array(current_option).map(&:to_s).include?(value.to_s)
228
+ end
229
+
230
+ if accept
231
+ html_options[option] = true
232
+ elsif option == :checked
233
+ html_options[option] = false
234
+ end
235
+ end
236
+
237
+ html_options
238
+ end
239
+
240
+ def sanitize_attribute_name(attribute, value) #:nodoc:
241
+ "#{attribute}_#{value.to_s.gsub(/\s/, "_").gsub(/[^-\w]/, "").downcase}"
242
+ end
243
+
244
+ def render_collection(collection, value_method, text_method, options={}, html_options={}) #:nodoc:
245
+ item_wrapper_tag = options.fetch(:item_wrapper_tag, :span)
246
+ item_wrapper_class = options[:item_wrapper_class]
247
+
248
+ collection.map do |item|
249
+ value = value_for_collection(item, value_method)
250
+ text = value_for_collection(item, text_method)
251
+ default_html_options = default_html_options_for_collection(item, value, options, html_options)
252
+
253
+ rendered_item = yield item, value, text, default_html_options
254
+
255
+ item_wrapper_tag ? @template.content_tag(item_wrapper_tag, rendered_item, :class => item_wrapper_class) : rendered_item
256
+ end.join.html_safe
257
+ end
258
+
259
+ def value_for_collection(item, value) #:nodoc:
260
+ value.respond_to?(:call) ? value.call(item) : item.send(value)
261
+ end
262
+
263
+ def wrap_rendered_collection(collection, options)
264
+ wrapper_tag = options[:collection_wrapper_tag]
265
+
266
+ if wrapper_tag
267
+ wrapper_class = options[:collection_wrapper_class]
268
+ @template.content_tag(wrapper_tag, collection, :class => wrapper_class)
269
+ else
270
+ collection
271
+ end
272
+ end
273
+ end
274
+ end
275
+ end
276
+
277
+ module ActionView::Helpers
278
+ class FormBuilder
279
+ include SimpleForm::ActionViewExtensions::Builder
280
+
281
+ # Override default Rails collection_select helper to handle lambdas/procs in
282
+ # text and value methods, so it works the same way as collection_radio_buttons
283
+ # and collection_check_boxes in SimpleForm. If none of text/value methods is a
284
+ # 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={})
288
+ if value_method.respond_to?(:call) || text_method.respond_to?(:call)
289
+ collection = collection.map do |item|
290
+ value = value_for_collection(item, value_method)
291
+ text = value_for_collection(item, text_method)
292
+
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]
298
+ end
299
+
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
+ value_method, text_method = :first, :last
305
+ end
306
+
307
+ original_collection_select(attribute, collection, value_method, text_method, options, html_options)
308
+ end
309
+ end
310
+
311
+ # Backport Rails fix to checkbox tag element, which does not generate the
312
+ # hidden input when given nil as unchecked value. This is to make SimpleForm
313
+ # collection check boxes helper to work fine with nested boolean style, when
314
+ # they are wrapped in labels. Without that, clicking in the label would
315
+ # actually change the hidden input, instead of the checkbox.
316
+ # FIXME: remove when support only Rails >= 3.2.2.
317
+ class InstanceTag
318
+ def to_check_box_tag(options = {}, checked_value = "1", unchecked_value = "0")
319
+ options = options.stringify_keys
320
+ options["type"] = "checkbox"
321
+ options["value"] = checked_value
322
+ if options.has_key?("checked")
323
+ cv = options.delete "checked"
324
+ checked = cv == true || cv == "checked"
325
+ else
326
+ checked = self.class.check_box_checked?(value(object), checked_value)
327
+ end
328
+ options["checked"] = "checked" if checked
329
+ if options["multiple"]
330
+ add_default_name_and_id_for_value(checked_value, options)
331
+ options.delete("multiple")
332
+ else
333
+ add_default_name_and_id(options)
334
+ end
335
+ hidden = unchecked_value ? tag("input", "name" => options["name"], "type" => "hidden", "value" => unchecked_value, "disabled" => options["disabled"]) : "".html_safe
336
+ checkbox = tag("input", options)
337
+ hidden + checkbox
338
+ end
339
+ end
340
+ end
@@ -0,0 +1,72 @@
1
+ module SimpleForm
2
+ module ActionViewExtensions
3
+ # This module creates SimpleForm wrappers around default form_for and fields_for.
4
+ #
5
+ # Example:
6
+ #
7
+ # simple_form_for @user do |f|
8
+ # f.input :name, :hint => 'My hint'
9
+ # end
10
+ #
11
+ module FormHelper
12
+ # Override the default ActiveRecordHelper behaviour of wrapping the input.
13
+ # This gets taken care of semantically by adding an error class to the wrapper tag
14
+ # containing the input.
15
+ #
16
+ FIELD_ERROR_PROC = proc do |html_tag, instance_tag|
17
+ html_tag
18
+ end
19
+
20
+ def simple_form_for(record, options={}, &block)
21
+ options[:builder] ||= SimpleForm::FormBuilder
22
+ options[:html] ||= {}
23
+ unless options[:html].key?(:novalidate)
24
+ options[:html][:novalidate] = !SimpleForm.browser_validations
25
+ end
26
+ options[:html][:class] = [SimpleForm.form_class, simple_form_css_class(record, options)].compact.join(" ")
27
+
28
+ with_simple_form_field_error_proc do
29
+ form_for(record, options, &block)
30
+ end
31
+ end
32
+
33
+ def simple_fields_for(record_name, record_object = nil, options = {}, &block)
34
+ options, record_object = record_object, nil if record_object.is_a?(Hash) && record_object.extractable_options?
35
+ options[:builder] ||= SimpleForm::FormBuilder
36
+
37
+ with_simple_form_field_error_proc do
38
+ fields_for(record_name, record_object, options, &block)
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def with_simple_form_field_error_proc
45
+ default_field_error_proc = ::ActionView::Base.field_error_proc
46
+ begin
47
+ ::ActionView::Base.field_error_proc = FIELD_ERROR_PROC
48
+ yield
49
+ ensure
50
+ ::ActionView::Base.field_error_proc = default_field_error_proc
51
+ end
52
+ end
53
+
54
+ def simple_form_css_class(record, options)
55
+ html_options = options[:html]
56
+ as = options[:as]
57
+
58
+ if html_options.key?(:class)
59
+ html_options[:class]
60
+ elsif record.is_a?(String) || record.is_a?(Symbol)
61
+ as || record
62
+ else
63
+ record = record.last if record.is_a?(Array)
64
+ action = record.respond_to?(:persisted?) && record.persisted? ? :edit : :new
65
+ as ? "#{action}_#{as}" : dom_class(record, action)
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ ActionView::Base.send :include, SimpleForm::ActionViewExtensions::FormHelper
@@ -0,0 +1,35 @@
1
+ module SimpleForm
2
+ module Components
3
+ module Errors
4
+ def error
5
+ error_text if has_errors?
6
+ end
7
+
8
+ def has_errors?
9
+ object && object.respond_to?(:errors) && errors.present?
10
+ end
11
+
12
+ protected
13
+
14
+ def error_text
15
+ "#{options[:error_prefix]} #{errors.send(error_method)}".lstrip.html_safe
16
+ end
17
+
18
+ def error_method
19
+ options[:error_method] || SimpleForm.error_method
20
+ end
21
+
22
+ def errors
23
+ @errors ||= (errors_on_attribute + errors_on_association).compact
24
+ end
25
+
26
+ def errors_on_attribute
27
+ object.errors[attribute_name]
28
+ end
29
+
30
+ def errors_on_association
31
+ reflection ? object.errors[reflection.name] : []
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,18 @@
1
+ module SimpleForm
2
+ module Components
3
+ # Needs to be enabled in order to do automatic lookups.
4
+ module Hints
5
+ def hint
6
+ @hint ||= begin
7
+ hint = options[:hint]
8
+ hint_content = hint.is_a?(String) ? hint : translate(:hints)
9
+ hint_content.html_safe if hint_content
10
+ end
11
+ end
12
+
13
+ def has_hint?
14
+ options[:hint] != false && hint.present?
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,26 @@
1
+ module SimpleForm
2
+ module Components
3
+ module HTML5
4
+ def initialize(*)
5
+ @html5 = false
6
+ end
7
+
8
+ def html5
9
+ @html5 = true
10
+ input_html_options[:required] = true if has_required?
11
+ nil
12
+ end
13
+
14
+ def html5?
15
+ @html5
16
+ end
17
+
18
+ def has_required?
19
+ # We need to check browser_validations because
20
+ # some browsers are still checking required even
21
+ # if novalidate was given.
22
+ required_field? && SimpleForm.browser_validations
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,15 @@
1
+ module SimpleForm
2
+ module Components
3
+ module LabelInput
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ include SimpleForm::Components::Labels
8
+ end
9
+
10
+ def label_input
11
+ options[:label] == false ? input : (label + input)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,79 @@
1
+ module SimpleForm
2
+ module Components
3
+ module Labels
4
+ extend ActiveSupport::Concern
5
+
6
+ module ClassMethods #:nodoc:
7
+ def translate_required_html
8
+ i18n_cache :translate_required_html do
9
+ I18n.t(:"simple_form.required.html", :default =>
10
+ %[<abbr title="#{translate_required_text}">#{translate_required_mark}</abbr>]
11
+ )
12
+ end
13
+ end
14
+
15
+ def translate_required_text
16
+ I18n.t(:"simple_form.required.text", :default => 'required')
17
+ end
18
+
19
+ def translate_required_mark
20
+ I18n.t(:"simple_form.required.mark", :default => '*')
21
+ end
22
+ end
23
+
24
+ def label
25
+ if generate_label_for_attribute?
26
+ @builder.label(label_target, label_text, label_html_options)
27
+ else
28
+ template.label_tag(nil, label_text, label_html_options)
29
+ end
30
+ end
31
+
32
+ def label_text
33
+ SimpleForm.label_text.call(raw_label_text, required_label_text).strip.html_safe
34
+ end
35
+
36
+ def label_target
37
+ attribute_name
38
+ end
39
+
40
+ def label_html_options
41
+ label_html_classes = SimpleForm.additional_classes_for(:label) {
42
+ [input_type, required_class, SimpleForm.label_class].compact
43
+ }
44
+
45
+ label_options = html_options_for(:label, label_html_classes)
46
+ if options.key?(:input_html) && options[:input_html].key?(:id)
47
+ label_options[:for] = options[:input_html][:id]
48
+ end
49
+ label_options
50
+ end
51
+
52
+ protected
53
+
54
+ def raw_label_text #:nodoc:
55
+ options[:label] || label_translation
56
+ end
57
+
58
+ # Default required text when attribute is required.
59
+ def required_label_text #:nodoc:
60
+ required_field? ? self.class.translate_required_html.dup : ''
61
+ end
62
+
63
+ # First check labels translation and then human attribute name.
64
+ def label_translation #:nodoc:
65
+ if SimpleForm.translate_labels && (translated_label = translate(:labels))
66
+ translated_label
67
+ elsif object.class.respond_to?(:human_attribute_name)
68
+ object.class.human_attribute_name(reflection_or_attribute_name.to_s)
69
+ else
70
+ attribute_name.to_s.humanize
71
+ end
72
+ end
73
+
74
+ def generate_label_for_attribute?
75
+ true
76
+ end
77
+ end
78
+ end
79
+ end