simple_form 2.1.3 → 3.0.0.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of simple_form might be problematic. Click here for more details.
- data/CHANGELOG.md +6 -54
- data/README.md +129 -111
- data/lib/generators/simple_form/install_generator.rb +4 -4
- data/lib/generators/simple_form/templates/README +2 -2
- data/lib/generators/simple_form/templates/config/initializers/simple_form.rb +8 -11
- data/lib/generators/simple_form/templates/config/initializers/simple_form_bootstrap.rb +16 -16
- data/lib/generators/simple_form/templates/config/initializers/simple_form_foundation.rb +3 -3
- data/lib/simple_form.rb +31 -47
- data/lib/simple_form/action_view_extensions/builder.rb +0 -319
- data/lib/simple_form/action_view_extensions/builder.rb.orig +247 -0
- data/lib/simple_form/action_view_extensions/form_helper.rb +1 -1
- data/lib/simple_form/components.rb +1 -1
- data/lib/simple_form/components/errors.rb +1 -7
- data/lib/simple_form/components/hints.rb +2 -7
- data/lib/simple_form/components/html5.rb +1 -1
- data/lib/simple_form/components/labels.rb +4 -4
- data/lib/simple_form/components/maxlength.rb +1 -8
- data/lib/simple_form/error_notification.rb +2 -2
- data/lib/simple_form/form_builder.rb +144 -46
- data/lib/simple_form/form_builder.rb.orig +486 -0
- data/lib/simple_form/helpers.rb +1 -1
- data/lib/simple_form/inputs/base.rb +3 -10
- data/lib/simple_form/inputs/block_input.rb +1 -1
- data/lib/simple_form/inputs/boolean_input.rb +6 -6
- data/lib/simple_form/inputs/collection_input.rb +7 -7
- data/lib/simple_form/inputs/numeric_input.rb +0 -6
- data/lib/simple_form/inputs/password_input.rb +0 -1
- data/lib/simple_form/inputs/string_input.rb +0 -1
- data/lib/simple_form/railtie.rb +7 -0
- data/lib/simple_form/tags.rb +61 -0
- data/lib/simple_form/version.rb +1 -1
- data/lib/simple_form/version.rb.orig +7 -0
- data/lib/simple_form/wrappers.rb +1 -1
- data/lib/simple_form/wrappers/builder.rb +5 -29
- data/lib/simple_form/wrappers/many.rb +1 -1
- data/lib/simple_form/wrappers/root.rb +1 -1
- data/test/action_view_extensions/builder_test.rb +67 -87
- data/test/action_view_extensions/form_helper_test.rb +16 -16
- data/test/components/label_test.rb +46 -46
- data/test/form_builder/association_test.rb +23 -23
- data/test/form_builder/button_test.rb +4 -4
- data/test/form_builder/error_notification_test.rb +8 -8
- data/test/form_builder/error_test.rb +18 -65
- data/test/form_builder/general_test.rb +45 -65
- data/test/form_builder/hint_test.rb +23 -29
- data/test/form_builder/input_field_test.rb +12 -12
- data/test/form_builder/label_test.rb +6 -16
- data/test/form_builder/wrapper_test.rb +21 -21
- data/test/inputs/boolean_input_test.rb +23 -35
- data/test/inputs/collection_check_boxes_input_test.rb +55 -55
- data/test/inputs/collection_radio_buttons_input_test.rb +70 -79
- data/test/inputs/collection_select_input_test.rb +45 -51
- data/test/inputs/datetime_input_test.rb +11 -11
- data/test/inputs/disabled_test.rb +10 -10
- data/test/inputs/discovery_test.rb +4 -4
- data/test/inputs/file_input_test.rb +1 -1
- data/test/inputs/general_test.rb +12 -12
- data/test/inputs/grouped_collection_select_input_test.rb +20 -20
- data/test/inputs/hidden_input_test.rb +1 -1
- data/test/inputs/numeric_input_test.rb +3 -3
- data/test/inputs/priority_input_test.rb +3 -3
- data/test/inputs/readonly_test.rb +12 -12
- data/test/inputs/required_test.rb +5 -5
- data/test/inputs/string_input_test.rb +10 -25
- data/test/inputs/text_input_test.rb +1 -1
- data/test/support/misc_helpers.rb +24 -24
- data/test/support/mock_controller.rb +6 -6
- data/test/support/models.rb +37 -46
- data/test/test_helper.rb +20 -20
- metadata +49 -24
- checksums.yaml +0 -7
- data/lib/simple_form/core_ext/hash.rb +0 -16
@@ -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
|
@@ -2,7 +2,7 @@ module SimpleForm
|
|
2
2
|
# Components are a special type of helpers that can work on their own.
|
3
3
|
# For example, by using a component, it will automatically change the
|
4
4
|
# output under given circumstances without user input. For example,
|
5
|
-
# the disabled helper always need a :
|
5
|
+
# the disabled helper always need a disabled: true option given
|
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
|
@@ -12,9 +12,7 @@ module SimpleForm
|
|
12
12
|
protected
|
13
13
|
|
14
14
|
def error_text
|
15
|
-
|
16
|
-
|
17
|
-
"#{html_escape(options[:error_prefix])} #{html_escape(text)}".lstrip.html_safe
|
15
|
+
"#{options[:error_prefix]} #{errors.send(error_method)}".lstrip.html_safe
|
18
16
|
end
|
19
17
|
|
20
18
|
def error_method
|
@@ -32,10 +30,6 @@ module SimpleForm
|
|
32
30
|
def errors_on_association
|
33
31
|
reflection ? object.errors[reflection.name] : []
|
34
32
|
end
|
35
|
-
|
36
|
-
def has_error_in_options?
|
37
|
-
options[:error] && !options[:error].nil?
|
38
|
-
end
|
39
33
|
end
|
40
34
|
end
|
41
35
|
end
|
@@ -5,13 +5,8 @@ module SimpleForm
|
|
5
5
|
def hint
|
6
6
|
@hint ||= begin
|
7
7
|
hint = options[:hint]
|
8
|
-
|
9
|
-
if
|
10
|
-
html_escape(hint)
|
11
|
-
else
|
12
|
-
content = translate(:hints)
|
13
|
-
content.html_safe if content
|
14
|
-
end
|
8
|
+
hint_content = hint.is_a?(String) ? hint : translate(:hints)
|
9
|
+
hint_content.html_safe if hint_content
|
15
10
|
end
|
16
11
|
end
|
17
12
|
|
@@ -6,18 +6,18 @@ module SimpleForm
|
|
6
6
|
module ClassMethods #:nodoc:
|
7
7
|
def translate_required_html
|
8
8
|
i18n_cache :translate_required_html do
|
9
|
-
I18n.t(:"simple_form.required.html", :
|
9
|
+
I18n.t(:"simple_form.required.html", default:
|
10
10
|
%[<abbr title="#{translate_required_text}">#{translate_required_mark}</abbr>]
|
11
11
|
)
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
15
|
def translate_required_text
|
16
|
-
I18n.t(:"simple_form.required.text", :
|
16
|
+
I18n.t(:"simple_form.required.text", default: 'required')
|
17
17
|
end
|
18
18
|
|
19
19
|
def translate_required_mark
|
20
|
-
I18n.t(:"simple_form.required.mark", :
|
20
|
+
I18n.t(:"simple_form.required.mark", default: '*')
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
@@ -30,7 +30,7 @@ module SimpleForm
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def label_text
|
33
|
-
SimpleForm.label_text.call(
|
33
|
+
SimpleForm.label_text.call(raw_label_text, required_label_text).strip.html_safe
|
34
34
|
end
|
35
35
|
|
36
36
|
def label_target
|
@@ -27,14 +27,7 @@ module SimpleForm
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def has_tokenizer?(length_validator)
|
30
|
-
|
31
|
-
|
32
|
-
# TODO: Remove this check when we drop Rails 3.0 support
|
33
|
-
if ActiveModel::Validations::LengthValidator.const_defined?(:DEFAULT_TOKENIZER)
|
34
|
-
tokenizer && tokenizer != ActiveModel::Validations::LengthValidator::DEFAULT_TOKENIZER
|
35
|
-
else
|
36
|
-
tokenizer
|
37
|
-
end
|
30
|
+
length_validator.options[:tokenizer]
|
38
31
|
end
|
39
32
|
end
|
40
33
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module SimpleForm
|
2
2
|
class ErrorNotification
|
3
|
-
delegate :object, :object_name, :template, :
|
3
|
+
delegate :object, :object_name, :template, to: :@builder
|
4
4
|
|
5
5
|
def initialize(builder, options)
|
6
6
|
@builder = builder
|
@@ -42,7 +42,7 @@ module SimpleForm
|
|
42
42
|
lookups << :"#{object_name}"
|
43
43
|
lookups << :default_message
|
44
44
|
lookups << "Please review the problems below:"
|
45
|
-
I18n.t(lookups.shift, :
|
45
|
+
I18n.t(lookups.shift, scope: :"simple_form.error_notification", default: lookups)
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
@@ -1,5 +1,6 @@
|
|
1
|
-
require '
|
1
|
+
require 'active_support/core_ext/object/deep_dup'
|
2
2
|
require 'simple_form/map_type'
|
3
|
+
require 'simple_form/tags'
|
3
4
|
|
4
5
|
module SimpleForm
|
5
6
|
class FormBuilder < ActionView::Helpers::FormBuilder
|
@@ -7,26 +8,26 @@ module SimpleForm
|
|
7
8
|
|
8
9
|
# When action is create or update, we still should use new and edit
|
9
10
|
ACTIONS = {
|
10
|
-
:
|
11
|
-
:
|
11
|
+
create: :new,
|
12
|
+
update: :edit
|
12
13
|
}
|
13
14
|
|
14
15
|
extend MapType
|
15
16
|
include SimpleForm::Inputs
|
16
17
|
|
17
|
-
map_type :text, :
|
18
|
-
map_type :file, :
|
19
|
-
map_type :string, :email, :search, :tel, :url, :
|
20
|
-
map_type :password, :
|
21
|
-
map_type :integer, :decimal, :float, :
|
22
|
-
map_type :range, :
|
23
|
-
map_type :check_boxes, :
|
24
|
-
map_type :radio_buttons, :
|
25
|
-
map_type :select, :
|
26
|
-
map_type :grouped_select, :
|
27
|
-
map_type :date, :time, :datetime, :
|
28
|
-
map_type :country, :time_zone, :
|
29
|
-
map_type :boolean, :
|
18
|
+
map_type :text, to: SimpleForm::Inputs::TextInput
|
19
|
+
map_type :file, to: SimpleForm::Inputs::FileInput
|
20
|
+
map_type :string, :email, :search, :tel, :url, to: SimpleForm::Inputs::StringInput
|
21
|
+
map_type :password, to: SimpleForm::Inputs::PasswordInput
|
22
|
+
map_type :integer, :decimal, :float, to: SimpleForm::Inputs::NumericInput
|
23
|
+
map_type :range, to: SimpleForm::Inputs::RangeInput
|
24
|
+
map_type :check_boxes, to: SimpleForm::Inputs::CollectionCheckBoxesInput
|
25
|
+
map_type :radio_buttons, to: SimpleForm::Inputs::CollectionRadioButtonsInput
|
26
|
+
map_type :select, to: SimpleForm::Inputs::CollectionSelectInput
|
27
|
+
map_type :grouped_select, to: SimpleForm::Inputs::GroupedCollectionSelectInput
|
28
|
+
map_type :date, :time, :datetime, to: SimpleForm::Inputs::DateTimeInput
|
29
|
+
map_type :country, :time_zone, to: SimpleForm::Inputs::PriorityInput
|
30
|
+
map_type :boolean, to: SimpleForm::Inputs::BooleanInput
|
30
31
|
|
31
32
|
def self.discovery_cache
|
32
33
|
@discovery_cache ||= {}
|
@@ -48,7 +49,7 @@ module SimpleForm
|
|
48
49
|
#
|
49
50
|
# # Imagine @user has error "can't be blank" on name
|
50
51
|
# simple_form_for @user do |f|
|
51
|
-
# f.input :name, :
|
52
|
+
# f.input :name, hint: 'My hint'
|
52
53
|
# end
|
53
54
|
#
|
54
55
|
# This is the output html (only the input portion, not the form):
|
@@ -57,7 +58,7 @@ module SimpleForm
|
|
57
58
|
# <abbr title="required">*</abbr> Super User Name!
|
58
59
|
# </label>
|
59
60
|
# <input class="string required" id="user_name" maxlength="100"
|
60
|
-
# name="user[name]"
|
61
|
+
# name="user[name]" type="text" value="Carlos" />
|
61
62
|
# <span class="hint">My hint</span>
|
62
63
|
# <span class="error">can't be blank</span>
|
63
64
|
#
|
@@ -66,15 +67,15 @@ module SimpleForm
|
|
66
67
|
#
|
67
68
|
# You have some options for the input to enable/disable some functions:
|
68
69
|
#
|
69
|
-
# :
|
70
|
+
# as: allows you to define the input type you want, for instance you
|
70
71
|
# can use it to generate a text field for a date column.
|
71
72
|
#
|
72
|
-
# :
|
73
|
+
# required: defines whether this attribute is required or not. True
|
73
74
|
# by default.
|
74
75
|
#
|
75
76
|
# The fact SimpleForm is built in components allow the interface to be unified.
|
76
77
|
# So, for instance, if you need to disable :hint for a given input, you can pass
|
77
|
-
# :
|
78
|
+
# hint: false. The same works for :error, :label and :wrapper.
|
78
79
|
#
|
79
80
|
# Besides the html for any component can be changed. So, if you want to change
|
80
81
|
# the label html you just need to give a hash to :label_html. To configure the
|
@@ -85,18 +86,18 @@ module SimpleForm
|
|
85
86
|
# Some inputs, as datetime, time and select allow you to give extra options, like
|
86
87
|
# prompt and/or include blank. Such options are given in plainly:
|
87
88
|
#
|
88
|
-
# f.input :created_at, :
|
89
|
+
# f.input :created_at, include_blank: true
|
89
90
|
#
|
90
91
|
# == Collection
|
91
92
|
#
|
92
93
|
# When playing with collections (:radio_buttons, :check_boxes and :select
|
93
94
|
# inputs), you have three extra options:
|
94
95
|
#
|
95
|
-
# :
|
96
|
+
# collection: use to determine the collection to generate the radio or select
|
96
97
|
#
|
97
|
-
# :
|
98
|
+
# label_method: the method to apply on the array collection to get the label
|
98
99
|
#
|
99
|
-
# :
|
100
|
+
# value_method: the method to apply on the array collection to get the value
|
100
101
|
#
|
101
102
|
# == Priority
|
102
103
|
#
|
@@ -130,14 +131,14 @@ module SimpleForm
|
|
130
131
|
# This is the output html (only the input portion, not the form):
|
131
132
|
#
|
132
133
|
# <input class="string required" id="user_name" maxlength="100"
|
133
|
-
# name="user[name]"
|
134
|
+
# name="user[name]" type="text" value="Carlos" />
|
134
135
|
#
|
135
136
|
def input_field(attribute_name, options={})
|
136
137
|
options = options.dup
|
137
138
|
options[:input_html] = options.except(:as, :collection, :label_method, :value_method)
|
138
139
|
options = @defaults.deep_dup.deep_merge(options) if @defaults
|
139
140
|
|
140
|
-
SimpleForm::Wrappers::Root.new([:min_max, :maxlength, :placeholder, :pattern, :readonly, :input], :
|
141
|
+
SimpleForm::Wrappers::Root.new([:min_max, :maxlength, :placeholder, :pattern, :readonly, :input], wrapper: false).render find_input(attribute_name, options)
|
141
142
|
end
|
142
143
|
|
143
144
|
# Helper for dealing with association selects/radios, generating the
|
@@ -151,7 +152,7 @@ module SimpleForm
|
|
151
152
|
# f.association :company # Company.all
|
152
153
|
# end
|
153
154
|
#
|
154
|
-
# f.association :company, :
|
155
|
+
# f.association :company, collection: Company.all(order: 'name')
|
155
156
|
# # Same as using :order option, but overriding collection
|
156
157
|
#
|
157
158
|
# == Block
|
@@ -190,7 +191,6 @@ module SimpleForm
|
|
190
191
|
else
|
191
192
|
if options[:as] == :select
|
192
193
|
html_options = options[:input_html] ||= {}
|
193
|
-
html_options[:size] ||= 5
|
194
194
|
html_options[:multiple] = true unless html_options.key?(:multiple)
|
195
195
|
end
|
196
196
|
|
@@ -203,7 +203,7 @@ module SimpleForm
|
|
203
203
|
:"#{reflection.name.to_s.singularize}_ids"
|
204
204
|
end
|
205
205
|
|
206
|
-
input(attribute, options.merge(:
|
206
|
+
input(attribute, options.merge(reflection: reflection))
|
207
207
|
end
|
208
208
|
|
209
209
|
# Creates a button:
|
@@ -216,8 +216,7 @@ module SimpleForm
|
|
216
216
|
# button implementation (3.2 forward (to delegate to the original when
|
217
217
|
# calling `f.button :button`.
|
218
218
|
#
|
219
|
-
|
220
|
-
alias_method :button_button, :button if method_defined?(:button)
|
219
|
+
alias_method :button_button, :button
|
221
220
|
def button(type, *args, &block)
|
222
221
|
options = args.extract_options!.dup
|
223
222
|
options[:class] = [SimpleForm.button_class, options[:class]].compact
|
@@ -235,7 +234,7 @@ module SimpleForm
|
|
235
234
|
# == Examples
|
236
235
|
#
|
237
236
|
# f.error :name
|
238
|
-
# f.error :name, :
|
237
|
+
# f.error :name, id: "cool_error"
|
239
238
|
#
|
240
239
|
def error(attribute_name, options={})
|
241
240
|
options = options.dup
|
@@ -273,7 +272,7 @@ module SimpleForm
|
|
273
272
|
# == Examples
|
274
273
|
#
|
275
274
|
# f.hint :name # Do I18n lookup
|
276
|
-
# f.hint :name, :
|
275
|
+
# f.hint :name, id: "cool_hint"
|
277
276
|
# f.hint "Don't forget to accept this"
|
278
277
|
#
|
279
278
|
def hint(attribute_name, options={})
|
@@ -300,10 +299,10 @@ module SimpleForm
|
|
300
299
|
#
|
301
300
|
# f.label :name # Do I18n lookup
|
302
301
|
# f.label :name, "Name" # Same behavior as Rails, do not add required tag
|
303
|
-
# f.label :name, :
|
302
|
+
# f.label :name, label: "Name" # Same as above, but adds required tag
|
304
303
|
#
|
305
|
-
# f.label :name, :
|
306
|
-
# f.label :name, :
|
304
|
+
# f.label :name, required: false
|
305
|
+
# f.label :name, id: "cool_label"
|
307
306
|
#
|
308
307
|
def label(attribute_name, *args)
|
309
308
|
return super if args.first.is_a?(String) || block_given?
|
@@ -324,13 +323,118 @@ module SimpleForm
|
|
324
323
|
# == Examples
|
325
324
|
#
|
326
325
|
# f.error_notification
|
327
|
-
# f.error_notification :
|
328
|
-
# f.error_notification :
|
326
|
+
# f.error_notification message: 'Something went wrong'
|
327
|
+
# f.error_notification id: 'user_error_message', class: 'form_error'
|
329
328
|
#
|
330
329
|
def error_notification(options={})
|
331
330
|
SimpleForm::ErrorNotification.new(self, options).render
|
332
331
|
end
|
333
332
|
|
333
|
+
# Create a collection of radio inputs for the attribute. Basically this
|
334
|
+
# helper will create a radio input associated with a label for each
|
335
|
+
# text/value option in the collection, using value_method and text_method
|
336
|
+
# to convert these text/value. You can give a symbol or a proc to both
|
337
|
+
# value_method and text_method, that will be evaluated for each item in
|
338
|
+
# the collection.
|
339
|
+
#
|
340
|
+
# == Examples
|
341
|
+
#
|
342
|
+
# form_for @user do |f|
|
343
|
+
# f.collection_radio_buttons :options, [[true, 'Yes'] ,[false, 'No']], :first, :last
|
344
|
+
# end
|
345
|
+
#
|
346
|
+
# <input id="user_options_true" name="user[options]" type="radio" value="true" />
|
347
|
+
# <label class="collection_radio_buttons" for="user_options_true">Yes</label>
|
348
|
+
# <input id="user_options_false" name="user[options]" type="radio" value="false" />
|
349
|
+
# <label class="collection_radio_buttons" for="user_options_false">No</label>
|
350
|
+
#
|
351
|
+
# It is also possible to give a block that should generate the radio +
|
352
|
+
# label. To wrap the radio with the label, for instance:
|
353
|
+
#
|
354
|
+
# form_for @user do |f|
|
355
|
+
# f.collection_radio_buttons(
|
356
|
+
# :options, [[true, 'Yes'] ,[false, 'No']], :first, :last
|
357
|
+
# ) do |b|
|
358
|
+
# b.label { b.radio_button + b.text }
|
359
|
+
# end
|
360
|
+
# end
|
361
|
+
#
|
362
|
+
# == Options
|
363
|
+
#
|
364
|
+
# Collection radio accepts some extra options:
|
365
|
+
#
|
366
|
+
# * checked => the value that should be checked initially.
|
367
|
+
#
|
368
|
+
# * disabled => the value or values that should be disabled. Accepts a single
|
369
|
+
# item or an array of items.
|
370
|
+
#
|
371
|
+
# * collection_wrapper_tag => the tag to wrap the entire collection.
|
372
|
+
#
|
373
|
+
# * collection_wrapper_class => the CSS class to use for collection_wrapper_tag
|
374
|
+
#
|
375
|
+
# * item_wrapper_tag => the tag to wrap each item in the collection.
|
376
|
+
#
|
377
|
+
# * item_wrapper_class => the CSS class to use for item_wrapper_tag
|
378
|
+
#
|
379
|
+
# * a block => to generate the label + radio or any other component.
|
380
|
+
def collection_radio_buttons(method, collection, value_method, text_method, options = {}, html_options = {}, &block)
|
381
|
+
SimpleForm::Tags::CollectionRadioButtons.new(@object_name, method, @template, collection, value_method, text_method, objectify_options(options), @default_options.merge(html_options)).render(&block)
|
382
|
+
end
|
383
|
+
|
384
|
+
# Creates a collection of check boxes for each item in the collection,
|
385
|
+
# associated with a clickable label. Use value_method and text_method to
|
386
|
+
# convert items in the collection for use as text/value in check boxes.
|
387
|
+
# You can give a symbol or a proc to both value_method and text_method,
|
388
|
+
# that will be evaluated for each item in the collection.
|
389
|
+
#
|
390
|
+
# == Examples
|
391
|
+
#
|
392
|
+
# form_for @user do |f|
|
393
|
+
# f.collection_check_boxes :options, [[true, 'Yes'] ,[false, 'No']], :first, :last
|
394
|
+
# end
|
395
|
+
#
|
396
|
+
# <input name="user[options][]" type="hidden" value="" />
|
397
|
+
# <input id="user_options_true" name="user[options][]" type="checkbox" value="true" />
|
398
|
+
# <label class="collection_check_boxes" for="user_options_true">Yes</label>
|
399
|
+
# <input name="user[options][]" type="hidden" value="" />
|
400
|
+
# <input id="user_options_false" name="user[options][]" type="checkbox" value="false" />
|
401
|
+
# <label class="collection_check_boxes" for="user_options_false">No</label>
|
402
|
+
#
|
403
|
+
# It is also possible to give a block that should generate the check box +
|
404
|
+
# label. To wrap the check box with the label, for instance:
|
405
|
+
#
|
406
|
+
# form_for @user do |f|
|
407
|
+
# f.collection_check_boxes(
|
408
|
+
# :options, [[true, 'Yes'] ,[false, 'No']], :first, :last
|
409
|
+
# ) do |b|
|
410
|
+
# b.label { b.check_box + b.text }
|
411
|
+
# end
|
412
|
+
# end
|
413
|
+
#
|
414
|
+
# == Options
|
415
|
+
#
|
416
|
+
# Collection check box accepts some extra options:
|
417
|
+
#
|
418
|
+
# * checked => the value or values that should be checked initially. Accepts
|
419
|
+
# a single item or an array of items. It overrides existing associations.
|
420
|
+
#
|
421
|
+
# * disabled => the value or values that should be disabled. Accepts a single
|
422
|
+
# item or an array of items.
|
423
|
+
#
|
424
|
+
# * collection_wrapper_tag => the tag to wrap the entire collection.
|
425
|
+
#
|
426
|
+
# * collection_wrapper_class => the CSS class to use for collection_wrapper_tag. This option
|
427
|
+
# is ignored if the :collection_wrapper_tag option is blank.
|
428
|
+
#
|
429
|
+
# * item_wrapper_tag => the tag to wrap each item in the collection.
|
430
|
+
#
|
431
|
+
# * item_wrapper_class => the CSS class to use for item_wrapper_tag
|
432
|
+
#
|
433
|
+
# * a block => to generate the label + check box or any other component.
|
434
|
+
def collection_check_boxes(method, collection, value_method, text_method, options = {}, html_options = {}, &block)
|
435
|
+
SimpleForm::Tags::CollectionCheckBoxes.new(@object_name, method, @template, collection, value_method, text_method, objectify_options(options), @default_options.merge(html_options)).render(&block)
|
436
|
+
end
|
437
|
+
|
334
438
|
# Extract the model names from the object_name mess, ignoring numeric and
|
335
439
|
# explicit child indexes.
|
336
440
|
#
|
@@ -342,7 +446,7 @@ module SimpleForm
|
|
342
446
|
def lookup_model_names
|
343
447
|
@lookup_model_names ||= begin
|
344
448
|
child_index = options[:child_index]
|
345
|
-
names = object_name.to_s.scan(/(
|
449
|
+
names = object_name.to_s.scan(/([a-zA-Z_]+)/).flatten
|
346
450
|
names.delete(child_index) if child_index
|
347
451
|
names.each { |name| name.gsub!('_attributes', '') }
|
348
452
|
names.freeze
|
@@ -366,12 +470,6 @@ module SimpleForm
|
|
366
470
|
column = find_attribute_column(attribute_name)
|
367
471
|
input_type = default_input_type(attribute_name, column, options)
|
368
472
|
|
369
|
-
if input_type == :radio
|
370
|
-
SimpleForm.deprecation_warn "Using `:as => :radio` as input type is " \
|
371
|
-
"deprecated, please change it to `:as => :radio_buttons`."
|
372
|
-
input_type = :radio_buttons
|
373
|
-
end
|
374
|
-
|
375
473
|
if block_given?
|
376
474
|
SimpleForm::Inputs::BlockInput.new(self, attribute_name, column, input_type, options, &block)
|
377
475
|
else
|