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.
- data/CHANGELOG.md +327 -0
- data/MIT-LICENSE +20 -0
- data/README.md +25 -0
- data/lib/generators/simple_form/USAGE +3 -0
- data/lib/generators/simple_form/install_generator.rb +48 -0
- data/lib/generators/simple_form/templates/AUI_README +19 -0
- data/lib/generators/simple_form/templates/README +12 -0
- data/lib/generators/simple_form/templates/_form.html.erb +13 -0
- data/lib/generators/simple_form/templates/_form.html.haml +10 -0
- data/lib/generators/simple_form/templates/_form.html.slim +10 -0
- data/lib/generators/simple_form/templates/config/initializers/simple_form.rb +142 -0
- data/lib/generators/simple_form/templates/config/initializers/simple_form_aui.rb +21 -0
- data/lib/generators/simple_form/templates/config/initializers/simple_form_bootstrap.rb +45 -0
- data/lib/generators/simple_form/templates/config/initializers/simple_form_foundation.rb +26 -0
- data/lib/generators/simple_form/templates/config/locales/simple_form.en.yml +26 -0
- data/lib/simple_form/action_view_extensions/builder.rb +340 -0
- data/lib/simple_form/action_view_extensions/form_helper.rb +72 -0
- data/lib/simple_form/components/errors.rb +35 -0
- data/lib/simple_form/components/hints.rb +18 -0
- data/lib/simple_form/components/html5.rb +26 -0
- data/lib/simple_form/components/label_input.rb +15 -0
- data/lib/simple_form/components/labels.rb +79 -0
- data/lib/simple_form/components/maxlength.rb +41 -0
- data/lib/simple_form/components/min_max.rb +50 -0
- data/lib/simple_form/components/pattern.rb +34 -0
- data/lib/simple_form/components/placeholders.rb +16 -0
- data/lib/simple_form/components/readonly.rb +22 -0
- data/lib/simple_form/components.rb +20 -0
- data/lib/simple_form/core_ext/hash.rb +16 -0
- data/lib/simple_form/error_notification.rb +48 -0
- data/lib/simple_form/form_builder.rb +482 -0
- data/lib/simple_form/helpers/autofocus.rb +11 -0
- data/lib/simple_form/helpers/disabled.rb +15 -0
- data/lib/simple_form/helpers/readonly.rb +15 -0
- data/lib/simple_form/helpers/required.rb +35 -0
- data/lib/simple_form/helpers/validators.rb +44 -0
- data/lib/simple_form/helpers.rb +12 -0
- data/lib/simple_form/i18n_cache.rb +22 -0
- data/lib/simple_form/inputs/aui_string_input.rb +10 -0
- data/lib/simple_form/inputs/base.rb +184 -0
- data/lib/simple_form/inputs/block_input.rb +14 -0
- data/lib/simple_form/inputs/boolean_input.rb +78 -0
- data/lib/simple_form/inputs/collection_check_boxes_input.rb +21 -0
- data/lib/simple_form/inputs/collection_input.rb +101 -0
- data/lib/simple_form/inputs/collection_radio_buttons_input.rb +63 -0
- data/lib/simple_form/inputs/collection_select_input.rb +14 -0
- data/lib/simple_form/inputs/date_time_input.rb +28 -0
- data/lib/simple_form/inputs/file_input.rb +9 -0
- data/lib/simple_form/inputs/grouped_collection_select_input.rb +41 -0
- data/lib/simple_form/inputs/hidden_input.rb +17 -0
- data/lib/simple_form/inputs/numeric_input.rb +24 -0
- data/lib/simple_form/inputs/password_input.rb +12 -0
- data/lib/simple_form/inputs/priority_input.rb +24 -0
- data/lib/simple_form/inputs/range_input.rb +14 -0
- data/lib/simple_form/inputs/string_input.rb +23 -0
- data/lib/simple_form/inputs/text_area_input.rb +12 -0
- data/lib/simple_form/inputs/text_input.rb +11 -0
- data/lib/simple_form/inputs.rb +23 -0
- data/lib/simple_form/map_type.rb +16 -0
- data/lib/simple_form/version.rb +3 -0
- data/lib/simple_form/wrappers/builder.rb +103 -0
- data/lib/simple_form/wrappers/many.rb +73 -0
- data/lib/simple_form/wrappers/root.rb +36 -0
- data/lib/simple_form/wrappers/single.rb +24 -0
- data/lib/simple_form/wrappers.rb +8 -0
- data/lib/simple_form.rb +221 -0
- data/test/action_view_extensions/builder_test.rb +583 -0
- data/test/action_view_extensions/form_helper_test.rb +143 -0
- data/test/components/label_test.rb +327 -0
- data/test/form_builder/association_test.rb +186 -0
- data/test/form_builder/button_test.rb +47 -0
- data/test/form_builder/error_notification_test.rb +79 -0
- data/test/form_builder/error_test.rb +121 -0
- data/test/form_builder/general_test.rb +402 -0
- data/test/form_builder/hint_test.rb +138 -0
- data/test/form_builder/input_field_test.rb +63 -0
- data/test/form_builder/label_test.rb +71 -0
- data/test/form_builder/wrapper_test.rb +203 -0
- data/test/generators/simple_form_generator_test.rb +42 -0
- data/test/inputs/boolean_input_test.rb +140 -0
- data/test/inputs/collection_check_boxes_input_test.rb +224 -0
- data/test/inputs/collection_radio_buttons_input_test.rb +326 -0
- data/test/inputs/collection_select_input_test.rb +241 -0
- data/test/inputs/datetime_input_test.rb +99 -0
- data/test/inputs/disabled_test.rb +78 -0
- data/test/inputs/discovery_test.rb +69 -0
- data/test/inputs/file_input_test.rb +16 -0
- data/test/inputs/general_test.rb +116 -0
- data/test/inputs/grouped_collection_select_input_test.rb +118 -0
- data/test/inputs/hidden_input_test.rb +30 -0
- data/test/inputs/numeric_input_test.rb +173 -0
- data/test/inputs/priority_input_test.rb +43 -0
- data/test/inputs/readonly_test.rb +101 -0
- data/test/inputs/required_test.rb +113 -0
- data/test/inputs/string_input_test.rb +146 -0
- data/test/inputs/text_input_test.rb +24 -0
- data/test/simple_form_test.rb +9 -0
- data/test/support/discovery_inputs.rb +27 -0
- data/test/support/misc_helpers.rb +138 -0
- data/test/support/mock_controller.rb +24 -0
- data/test/support/models.rb +216 -0
- data/test/test_helper.rb +95 -0
- 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
|