simple_form 3.0.1 → 3.1.0.rc1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +33 -27
- data/MIT-LICENSE +1 -1
- data/README.md +146 -71
- data/lib/generators/simple_form/install_generator.rb +2 -2
- data/lib/generators/simple_form/templates/README +3 -4
- data/lib/generators/simple_form/templates/config/initializers/simple_form.rb +19 -3
- data/lib/generators/simple_form/templates/config/initializers/simple_form_bootstrap.rb +83 -22
- data/lib/generators/simple_form/templates/config/initializers/simple_form_foundation.rb +1 -1
- data/lib/generators/simple_form/templates/config/locales/simple_form.en.yml +7 -2
- data/lib/simple_form/action_view_extensions/form_helper.rb +1 -1
- data/lib/simple_form/components/errors.rb +30 -2
- data/lib/simple_form/components/hints.rb +2 -2
- data/lib/simple_form/components/html5.rb +1 -1
- data/lib/simple_form/components/label_input.rb +20 -2
- data/lib/simple_form/components/labels.rb +9 -5
- data/lib/simple_form/components/maxlength.rb +1 -1
- data/lib/simple_form/components/min_max.rb +1 -1
- data/lib/simple_form/components/pattern.rb +1 -1
- data/lib/simple_form/components/placeholders.rb +2 -2
- data/lib/simple_form/components/readonly.rb +1 -1
- data/lib/simple_form/form_builder.rb +92 -57
- data/lib/simple_form/helpers.rb +5 -5
- data/lib/simple_form/inputs/base.rb +33 -11
- data/lib/simple_form/inputs/block_input.rb +1 -1
- data/lib/simple_form/inputs/boolean_input.rb +23 -13
- data/lib/simple_form/inputs/collection_input.rb +32 -9
- data/lib/simple_form/inputs/collection_radio_buttons_input.rb +6 -11
- data/lib/simple_form/inputs/collection_select_input.rb +4 -2
- data/lib/simple_form/inputs/date_time_input.rb +12 -2
- data/lib/simple_form/inputs/file_input.rb +4 -2
- data/lib/simple_form/inputs/grouped_collection_select_input.rb +15 -3
- data/lib/simple_form/inputs/hidden_input.rb +4 -2
- data/lib/simple_form/inputs/numeric_input.rb +5 -4
- data/lib/simple_form/inputs/password_input.rb +4 -2
- data/lib/simple_form/inputs/priority_input.rb +4 -2
- data/lib/simple_form/inputs/range_input.rb +1 -1
- data/lib/simple_form/inputs/string_input.rb +4 -2
- data/lib/simple_form/inputs/text_input.rb +4 -2
- data/lib/simple_form/railtie.rb +7 -0
- data/lib/simple_form/tags.rb +7 -0
- data/lib/simple_form/version.rb +1 -1
- data/lib/simple_form/wrappers/builder.rb +5 -5
- data/lib/simple_form/wrappers/leaf.rb +28 -0
- data/lib/simple_form/wrappers/many.rb +5 -6
- data/lib/simple_form/wrappers/root.rb +1 -1
- data/lib/simple_form/wrappers/single.rb +5 -3
- data/lib/simple_form/wrappers.rb +1 -0
- data/lib/simple_form.rb +38 -6
- data/test/action_view_extensions/builder_test.rb +2 -2
- data/test/components/label_test.rb +1 -1
- data/test/form_builder/association_test.rb +17 -0
- data/test/form_builder/error_notification_test.rb +1 -1
- data/test/form_builder/error_test.rb +61 -0
- data/test/form_builder/input_field_test.rb +25 -1
- data/test/form_builder/label_test.rb +24 -1
- data/test/form_builder/wrapper_test.rb +67 -0
- data/test/generators/simple_form_generator_test.rb +2 -2
- data/test/inputs/boolean_input_test.rb +50 -2
- data/test/inputs/collection_check_boxes_input_test.rb +40 -11
- data/test/inputs/collection_radio_buttons_input_test.rb +76 -17
- data/test/inputs/collection_select_input_test.rb +108 -3
- data/test/inputs/datetime_input_test.rb +105 -38
- data/test/inputs/discovery_test.rb +12 -1
- data/test/inputs/grouped_collection_select_input_test.rb +36 -0
- data/test/inputs/string_input_test.rb +20 -0
- data/test/simple_form_test.rb +8 -0
- data/test/support/discovery_inputs.rb +12 -2
- data/test/support/misc_helpers.rb +49 -5
- data/test/support/models.rb +49 -24
- data/test/test_helper.rb +2 -0
- metadata +23 -34
data/lib/simple_form/helpers.rb
CHANGED
|
@@ -3,10 +3,10 @@ module SimpleForm
|
|
|
3
3
|
# For instance, disabled cannot be turned on automatically, it requires the
|
|
4
4
|
# user to explicitly pass the option disabled: true so it may work.
|
|
5
5
|
module Helpers
|
|
6
|
-
autoload :Autofocus,
|
|
7
|
-
autoload :Disabled,
|
|
8
|
-
autoload :Readonly,
|
|
9
|
-
autoload :Required,
|
|
10
|
-
autoload :Validators,
|
|
6
|
+
autoload :Autofocus, 'simple_form/helpers/autofocus'
|
|
7
|
+
autoload :Disabled, 'simple_form/helpers/disabled'
|
|
8
|
+
autoload :Readonly, 'simple_form/helpers/readonly'
|
|
9
|
+
autoload :Required, 'simple_form/helpers/required'
|
|
10
|
+
autoload :Validators, 'simple_form/helpers/validators'
|
|
11
11
|
end
|
|
12
12
|
end
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
require 'simple_form/i18n_cache'
|
|
2
2
|
require 'active_support/core_ext/string/output_safety'
|
|
3
|
+
require 'action_view/helpers'
|
|
3
4
|
|
|
4
5
|
module SimpleForm
|
|
5
6
|
module Inputs
|
|
6
7
|
class Base
|
|
7
8
|
include ERB::Util
|
|
9
|
+
include ActionView::Helpers::TranslationHelper
|
|
8
10
|
|
|
9
11
|
extend I18nCache
|
|
10
12
|
|
|
@@ -53,14 +55,14 @@ module SimpleForm
|
|
|
53
55
|
def initialize(builder, attribute_name, column, input_type, options = {})
|
|
54
56
|
super
|
|
55
57
|
|
|
56
|
-
options
|
|
57
|
-
@builder
|
|
58
|
-
@attribute_name
|
|
59
|
-
@column
|
|
60
|
-
@input_type
|
|
61
|
-
@reflection
|
|
62
|
-
@options
|
|
63
|
-
@required
|
|
58
|
+
options = options.dup
|
|
59
|
+
@builder = builder
|
|
60
|
+
@attribute_name = attribute_name
|
|
61
|
+
@column = column
|
|
62
|
+
@input_type = input_type
|
|
63
|
+
@reflection = options.delete(:reflection)
|
|
64
|
+
@options = options.reverse_merge!(self.class.default_options)
|
|
65
|
+
@required = calculate_required
|
|
64
66
|
|
|
65
67
|
# Notice that html_options_for receives a reference to input_html_classes.
|
|
66
68
|
# This means that classes added dynamically to input_html_classes will
|
|
@@ -79,7 +81,7 @@ module SimpleForm
|
|
|
79
81
|
end
|
|
80
82
|
end
|
|
81
83
|
|
|
82
|
-
def input
|
|
84
|
+
def input(wrapper_options = nil)
|
|
83
85
|
raise NotImplementedError
|
|
84
86
|
end
|
|
85
87
|
|
|
@@ -167,7 +169,7 @@ module SimpleForm
|
|
|
167
169
|
# email: 'E-mail.'
|
|
168
170
|
#
|
|
169
171
|
# Take a look at our locale example file.
|
|
170
|
-
def
|
|
172
|
+
def translate_from_namespace(namespace, default = '')
|
|
171
173
|
model_names = lookup_model_names.dup
|
|
172
174
|
lookups = []
|
|
173
175
|
|
|
@@ -176,13 +178,33 @@ module SimpleForm
|
|
|
176
178
|
model_names.shift
|
|
177
179
|
|
|
178
180
|
lookups << :"#{joined_model_names}.#{lookup_action}.#{reflection_or_attribute_name}"
|
|
181
|
+
lookups << :"#{joined_model_names}.#{lookup_action}.#{reflection_or_attribute_name}_html"
|
|
179
182
|
lookups << :"#{joined_model_names}.#{reflection_or_attribute_name}"
|
|
183
|
+
lookups << :"#{joined_model_names}.#{reflection_or_attribute_name}_html"
|
|
180
184
|
end
|
|
181
185
|
lookups << :"defaults.#{lookup_action}.#{reflection_or_attribute_name}"
|
|
186
|
+
lookups << :"defaults.#{lookup_action}.#{reflection_or_attribute_name}_html"
|
|
182
187
|
lookups << :"defaults.#{reflection_or_attribute_name}"
|
|
188
|
+
lookups << :"defaults.#{reflection_or_attribute_name}_html"
|
|
183
189
|
lookups << default
|
|
184
190
|
|
|
185
|
-
|
|
191
|
+
t(lookups.shift, scope: :"#{i18n_scope}.#{namespace}", default: lookups).presence
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def merge_wrapper_options(options, wrapper_options)
|
|
195
|
+
if wrapper_options
|
|
196
|
+
options.merge(wrapper_options) do |_, oldval, newval|
|
|
197
|
+
if Array === oldval
|
|
198
|
+
oldval + Array(newval)
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
else
|
|
202
|
+
options
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def i18n_scope
|
|
207
|
+
SimpleForm.i18n_scope
|
|
186
208
|
end
|
|
187
209
|
end
|
|
188
210
|
end
|
|
@@ -1,31 +1,36 @@
|
|
|
1
1
|
module SimpleForm
|
|
2
2
|
module Inputs
|
|
3
3
|
class BooleanInput < Base
|
|
4
|
-
def input
|
|
4
|
+
def input(wrapper_options = nil)
|
|
5
|
+
merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
|
|
6
|
+
|
|
5
7
|
if nested_boolean_style?
|
|
6
8
|
build_hidden_field_for_checkbox +
|
|
7
|
-
template.label_tag(nil, class:
|
|
8
|
-
build_check_box_without_hidden_field +
|
|
9
|
+
template.label_tag(nil, class: SimpleForm.boolean_label_class) {
|
|
10
|
+
build_check_box_without_hidden_field(merged_input_options) +
|
|
11
|
+
inline_label
|
|
9
12
|
}
|
|
10
13
|
else
|
|
11
|
-
build_check_box
|
|
14
|
+
build_check_box(unchecked_value, merged_input_options)
|
|
12
15
|
end
|
|
13
16
|
end
|
|
14
17
|
|
|
15
|
-
def label_input
|
|
18
|
+
def label_input(wrapper_options = nil)
|
|
16
19
|
if options[:label] == false
|
|
17
|
-
input
|
|
20
|
+
input(wrapper_options)
|
|
18
21
|
elsif nested_boolean_style?
|
|
19
22
|
html_options = label_html_options.dup
|
|
20
23
|
html_options[:class] ||= []
|
|
21
|
-
html_options[:class].push(
|
|
24
|
+
html_options[:class].push(SimpleForm.boolean_label_class) if SimpleForm.boolean_label_class
|
|
25
|
+
|
|
26
|
+
merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
|
|
22
27
|
|
|
23
28
|
build_hidden_field_for_checkbox +
|
|
24
29
|
@builder.label(label_target, html_options) {
|
|
25
|
-
build_check_box_without_hidden_field + label_text
|
|
30
|
+
build_check_box_without_hidden_field(merged_input_options) + label_text
|
|
26
31
|
}
|
|
27
32
|
else
|
|
28
|
-
input + label
|
|
33
|
+
input(wrapper_options) + label(wrapper_options)
|
|
29
34
|
end
|
|
30
35
|
end
|
|
31
36
|
|
|
@@ -35,14 +40,14 @@ module SimpleForm
|
|
|
35
40
|
# reuse the method for nested boolean style, but with no unchecked value,
|
|
36
41
|
# which won't generate the hidden checkbox. This is the default functionality
|
|
37
42
|
# in Rails > 3.2.1, and is backported in SimpleForm AV helpers.
|
|
38
|
-
def build_check_box(unchecked_value
|
|
43
|
+
def build_check_box(unchecked_value, options)
|
|
39
44
|
@builder.check_box(attribute_name, input_html_options, checked_value, unchecked_value)
|
|
40
45
|
end
|
|
41
46
|
|
|
42
47
|
# Build a checkbox without generating the hidden field. See
|
|
43
48
|
# #build_hidden_field_for_checkbox for more info.
|
|
44
|
-
def build_check_box_without_hidden_field
|
|
45
|
-
build_check_box(nil)
|
|
49
|
+
def build_check_box_without_hidden_field(options)
|
|
50
|
+
build_check_box(nil, options)
|
|
46
51
|
end
|
|
47
52
|
|
|
48
53
|
# Create a hidden field for the current checkbox, so we can simulate Rails
|
|
@@ -58,7 +63,12 @@ module SimpleForm
|
|
|
58
63
|
|
|
59
64
|
def inline_label
|
|
60
65
|
inline_option = options[:inline_label]
|
|
61
|
-
|
|
66
|
+
|
|
67
|
+
if inline_option
|
|
68
|
+
label = inline_option == true ? " #{label_text}" : " #{html_escape(inline_option)}"
|
|
69
|
+
|
|
70
|
+
label.html_safe
|
|
71
|
+
end
|
|
62
72
|
end
|
|
63
73
|
|
|
64
74
|
# Booleans are not required by default because in most of the cases
|
|
@@ -12,14 +12,20 @@ module SimpleForm
|
|
|
12
12
|
end
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
def input
|
|
15
|
+
def input(wrapper_options = nil)
|
|
16
16
|
raise NotImplementedError,
|
|
17
17
|
"input should be implemented by classes inheriting from CollectionInput"
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def input_options
|
|
21
21
|
options = super
|
|
22
|
+
|
|
22
23
|
options[:include_blank] = true unless skip_include_blank?
|
|
24
|
+
|
|
25
|
+
[:prompt, :include_blank].each do |key|
|
|
26
|
+
translate_option options, key
|
|
27
|
+
end
|
|
28
|
+
|
|
23
29
|
options
|
|
24
30
|
end
|
|
25
31
|
|
|
@@ -33,7 +39,7 @@ module SimpleForm
|
|
|
33
39
|
end
|
|
34
40
|
|
|
35
41
|
def has_required?
|
|
36
|
-
super && (input_options[:include_blank] || multiple?)
|
|
42
|
+
super && (input_options[:include_blank] || input_options[:prompt] || multiple?)
|
|
37
43
|
end
|
|
38
44
|
|
|
39
45
|
# Check if :include_blank must be included by default.
|
|
@@ -70,13 +76,17 @@ module SimpleForm
|
|
|
70
76
|
elsif collection_includes_basic_objects?(collection_classes)
|
|
71
77
|
{ label: :to_s, value: :to_s }
|
|
72
78
|
else
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
{ label: SimpleForm.collection_label_methods.find { |m| sample.respond_to?(m) },
|
|
76
|
-
value: SimpleForm.collection_value_methods.find { |m| sample.respond_to?(m) } }
|
|
79
|
+
detect_method_from_class(collection_classes)
|
|
77
80
|
end
|
|
78
81
|
end
|
|
79
82
|
|
|
83
|
+
def detect_method_from_class(collection_classes)
|
|
84
|
+
sample = collection.first || collection.last
|
|
85
|
+
|
|
86
|
+
{ label: SimpleForm.collection_label_methods.find { |m| sample.respond_to?(m) },
|
|
87
|
+
value: SimpleForm.collection_value_methods.find { |m| sample.respond_to?(m) } }
|
|
88
|
+
end
|
|
89
|
+
|
|
80
90
|
def detect_collection_classes(some_collection = collection)
|
|
81
91
|
some_collection.map { |e| e.class }.uniq
|
|
82
92
|
end
|
|
@@ -88,14 +98,27 @@ module SimpleForm
|
|
|
88
98
|
end
|
|
89
99
|
|
|
90
100
|
def translate_collection
|
|
91
|
-
if translated_collection =
|
|
101
|
+
if translated_collection = translate_from_namespace(:options)
|
|
92
102
|
@collection = collection.map do |key|
|
|
93
|
-
|
|
103
|
+
html_key = "#{key}_html".to_sym
|
|
104
|
+
|
|
105
|
+
if translated_collection[html_key]
|
|
106
|
+
[translated_collection[html_key].html_safe || key, key.to_s]
|
|
107
|
+
else
|
|
108
|
+
[translated_collection[key] || key, key.to_s]
|
|
109
|
+
end
|
|
94
110
|
end
|
|
95
111
|
true
|
|
96
112
|
end
|
|
97
113
|
end
|
|
114
|
+
|
|
115
|
+
def translate_option(options, key)
|
|
116
|
+
if options[key] == :translate
|
|
117
|
+
namespace = key.to_s.pluralize
|
|
118
|
+
|
|
119
|
+
options[key] = translate_from_namespace(namespace, true)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
98
122
|
end
|
|
99
123
|
end
|
|
100
124
|
end
|
|
101
|
-
|
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
module SimpleForm
|
|
2
2
|
module Inputs
|
|
3
3
|
class CollectionRadioButtonsInput < CollectionInput
|
|
4
|
-
def input
|
|
4
|
+
def input(wrapper_options = nil)
|
|
5
5
|
label_method, value_method = detect_collection_methods
|
|
6
6
|
|
|
7
|
+
merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
|
|
8
|
+
|
|
7
9
|
@builder.send("collection_#{input_type}",
|
|
8
10
|
attribute_name, collection, value_method, label_method,
|
|
9
|
-
input_options,
|
|
11
|
+
input_options, merged_input_options,
|
|
12
|
+
&collection_block_for_nested_boolean_style
|
|
10
13
|
)
|
|
11
14
|
end
|
|
12
15
|
|
|
13
16
|
def input_options
|
|
14
17
|
options = super
|
|
15
18
|
apply_default_collection_options!(options)
|
|
16
|
-
apply_nested_boolean_collection_options!(options) if nested_boolean_style?
|
|
17
19
|
options
|
|
18
20
|
end
|
|
19
21
|
|
|
@@ -23,7 +25,7 @@ module SimpleForm
|
|
|
23
25
|
options[:item_wrapper_tag] ||= options.fetch(:item_wrapper_tag, SimpleForm.item_wrapper_tag)
|
|
24
26
|
options[:item_wrapper_class] = [
|
|
25
27
|
item_wrapper_class, options[:item_wrapper_class], SimpleForm.item_wrapper_class
|
|
26
|
-
].compact.presence
|
|
28
|
+
].compact.presence if SimpleForm.include_default_input_wrapper_class
|
|
27
29
|
|
|
28
30
|
options[:collection_wrapper_tag] ||= options.fetch(:collection_wrapper_tag, SimpleForm.collection_wrapper_tag)
|
|
29
31
|
options[:collection_wrapper_class] = [
|
|
@@ -31,13 +33,6 @@ module SimpleForm
|
|
|
31
33
|
].compact.presence
|
|
32
34
|
end
|
|
33
35
|
|
|
34
|
-
# Force item wrapper to be a label when using nested boolean, to support
|
|
35
|
-
# configuring classes through :item_wrapper_class, and to maintain
|
|
36
|
-
# compatibility with :inline style and default :item_wrapper_tag.
|
|
37
|
-
def apply_nested_boolean_collection_options!(options)
|
|
38
|
-
options[:item_wrapper_tag] = :label
|
|
39
|
-
end
|
|
40
|
-
|
|
41
36
|
def collection_block_for_nested_boolean_style
|
|
42
37
|
return unless nested_boolean_style?
|
|
43
38
|
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
module SimpleForm
|
|
2
2
|
module Inputs
|
|
3
3
|
class CollectionSelectInput < CollectionInput
|
|
4
|
-
def input
|
|
4
|
+
def input(wrapper_options = nil)
|
|
5
5
|
label_method, value_method = detect_collection_methods
|
|
6
6
|
|
|
7
|
+
merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
|
|
8
|
+
|
|
7
9
|
@builder.collection_select(
|
|
8
10
|
attribute_name, collection, value_method, label_method,
|
|
9
|
-
input_options,
|
|
11
|
+
input_options, merged_input_options
|
|
10
12
|
)
|
|
11
13
|
end
|
|
12
14
|
end
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
module SimpleForm
|
|
2
2
|
module Inputs
|
|
3
3
|
class DateTimeInput < Base
|
|
4
|
-
def input
|
|
5
|
-
|
|
4
|
+
def input(wrapper_options = nil)
|
|
5
|
+
merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
|
|
6
|
+
|
|
7
|
+
if use_html5_inputs?
|
|
8
|
+
@builder.send(:"#{input_type}_field", attribute_name, merged_input_options)
|
|
9
|
+
else
|
|
10
|
+
@builder.send(:"#{input_type}_select", attribute_name, input_options, merged_input_options)
|
|
11
|
+
end
|
|
6
12
|
end
|
|
7
13
|
|
|
8
14
|
private
|
|
@@ -19,6 +25,10 @@ module SimpleForm
|
|
|
19
25
|
position = ActionView::Helpers::DateTimeSelector::POSITION[position]
|
|
20
26
|
"#{attribute_name}_#{position}i"
|
|
21
27
|
end
|
|
28
|
+
|
|
29
|
+
def use_html5_inputs?
|
|
30
|
+
input_options[:html5]
|
|
31
|
+
end
|
|
22
32
|
end
|
|
23
33
|
end
|
|
24
34
|
end
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
module SimpleForm
|
|
2
2
|
module Inputs
|
|
3
3
|
class FileInput < Base
|
|
4
|
-
def input
|
|
5
|
-
|
|
4
|
+
def input(wrapper_options = nil)
|
|
5
|
+
merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
|
|
6
|
+
|
|
7
|
+
@builder.file_field(attribute_name, merged_input_options)
|
|
6
8
|
end
|
|
7
9
|
end
|
|
8
10
|
end
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
module SimpleForm
|
|
2
2
|
module Inputs
|
|
3
3
|
class GroupedCollectionSelectInput < CollectionInput
|
|
4
|
-
def input
|
|
4
|
+
def input(wrapper_options = nil)
|
|
5
5
|
label_method, value_method = detect_collection_methods
|
|
6
|
+
|
|
7
|
+
merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
|
|
8
|
+
|
|
6
9
|
@builder.grouped_collection_select(attribute_name, grouped_collection,
|
|
7
10
|
group_method, group_label_method, value_method, label_method,
|
|
8
|
-
input_options,
|
|
11
|
+
input_options, merged_input_options)
|
|
9
12
|
end
|
|
10
13
|
|
|
11
14
|
private
|
|
@@ -19,7 +22,7 @@ module SimpleForm
|
|
|
19
22
|
|
|
20
23
|
# Sample collection
|
|
21
24
|
def collection
|
|
22
|
-
@collection ||= grouped_collection.
|
|
25
|
+
@collection ||= grouped_collection.map { |collection| collection.try(:send, group_method) }.detect(&:present?) || []
|
|
23
26
|
end
|
|
24
27
|
|
|
25
28
|
def group_method
|
|
@@ -36,6 +39,15 @@ module SimpleForm
|
|
|
36
39
|
|
|
37
40
|
label
|
|
38
41
|
end
|
|
42
|
+
|
|
43
|
+
def detect_method_from_class(collection_classes)
|
|
44
|
+
return {} if collection_classes.empty?
|
|
45
|
+
|
|
46
|
+
sample = collection_classes.first
|
|
47
|
+
|
|
48
|
+
{ label: SimpleForm.collection_label_methods.find { |m| sample.instance_methods.include?(m) },
|
|
49
|
+
value: SimpleForm.collection_value_methods.find { |m| sample.instance_methods.include?(m) } }
|
|
50
|
+
end
|
|
39
51
|
end
|
|
40
52
|
end
|
|
41
53
|
end
|
|
@@ -3,8 +3,10 @@ module SimpleForm
|
|
|
3
3
|
class HiddenInput < Base
|
|
4
4
|
disable :label, :errors, :hint, :required
|
|
5
5
|
|
|
6
|
-
def input
|
|
7
|
-
|
|
6
|
+
def input(wrapper_options = nil)
|
|
7
|
+
merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
|
|
8
|
+
|
|
9
|
+
@builder.hidden_field(attribute_name, merged_input_options)
|
|
8
10
|
end
|
|
9
11
|
|
|
10
12
|
private
|
|
@@ -3,16 +3,17 @@ module SimpleForm
|
|
|
3
3
|
class NumericInput < Base
|
|
4
4
|
enable :placeholder, :min_max
|
|
5
5
|
|
|
6
|
-
def input
|
|
6
|
+
def input(wrapper_options = nil)
|
|
7
7
|
input_html_classes.unshift("numeric")
|
|
8
8
|
if html5?
|
|
9
9
|
input_html_options[:type] ||= "number"
|
|
10
10
|
input_html_options[:step] ||= integer? ? 1 : "any"
|
|
11
11
|
end
|
|
12
|
-
@builder.text_field(attribute_name, input_html_options)
|
|
13
|
-
end
|
|
14
12
|
|
|
15
|
-
|
|
13
|
+
merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
|
|
14
|
+
|
|
15
|
+
@builder.text_field(attribute_name, merged_input_options)
|
|
16
|
+
end
|
|
16
17
|
end
|
|
17
18
|
end
|
|
18
19
|
end
|
|
@@ -3,8 +3,10 @@ module SimpleForm
|
|
|
3
3
|
class PasswordInput < Base
|
|
4
4
|
enable :placeholder, :maxlength
|
|
5
5
|
|
|
6
|
-
def input
|
|
7
|
-
|
|
6
|
+
def input(wrapper_options = nil)
|
|
7
|
+
merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
|
|
8
|
+
|
|
9
|
+
@builder.password_field(attribute_name, merged_input_options)
|
|
8
10
|
end
|
|
9
11
|
end
|
|
10
12
|
end
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
module SimpleForm
|
|
2
2
|
module Inputs
|
|
3
3
|
class PriorityInput < CollectionSelectInput
|
|
4
|
-
def input
|
|
4
|
+
def input(wrapper_options = nil)
|
|
5
|
+
merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
|
|
6
|
+
|
|
5
7
|
@builder.send(:"#{input_type}_select", attribute_name, input_priority,
|
|
6
|
-
input_options,
|
|
8
|
+
input_options, merged_input_options)
|
|
7
9
|
end
|
|
8
10
|
|
|
9
11
|
def input_priority
|
|
@@ -3,13 +3,15 @@ module SimpleForm
|
|
|
3
3
|
class StringInput < Base
|
|
4
4
|
enable :placeholder, :maxlength, :pattern
|
|
5
5
|
|
|
6
|
-
def input
|
|
6
|
+
def input(wrapper_options = nil)
|
|
7
7
|
unless string?
|
|
8
8
|
input_html_classes.unshift("string")
|
|
9
9
|
input_html_options[:type] ||= input_type if html5?
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
|
|
13
|
+
|
|
14
|
+
@builder.text_field(attribute_name, merged_input_options)
|
|
13
15
|
end
|
|
14
16
|
|
|
15
17
|
private
|
|
@@ -3,8 +3,10 @@ module SimpleForm
|
|
|
3
3
|
class TextInput < Base
|
|
4
4
|
enable :placeholder, :maxlength
|
|
5
5
|
|
|
6
|
-
def input
|
|
7
|
-
|
|
6
|
+
def input(wrapper_options = nil)
|
|
7
|
+
merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
|
|
8
|
+
|
|
9
|
+
@builder.text_area(attribute_name, merged_input_options)
|
|
8
10
|
end
|
|
9
11
|
end
|
|
10
12
|
end
|
data/lib/simple_form/railtie.rb
CHANGED
|
@@ -3,5 +3,12 @@ require 'rails/railtie'
|
|
|
3
3
|
module SimpleForm
|
|
4
4
|
class Railtie < Rails::Railtie
|
|
5
5
|
config.eager_load_namespaces << SimpleForm
|
|
6
|
+
|
|
7
|
+
config.after_initialize do
|
|
8
|
+
unless SimpleForm.configured?
|
|
9
|
+
warn '[Simple Form] Simple Form is not configured in the application and will use the default values.' +
|
|
10
|
+
' Use `rails generate simple_form:install` to generate the Simple Form configuration.'
|
|
11
|
+
end
|
|
12
|
+
end
|
|
6
13
|
end
|
|
7
14
|
end
|
data/lib/simple_form/tags.rb
CHANGED
|
@@ -15,6 +15,13 @@ module SimpleForm
|
|
|
15
15
|
|
|
16
16
|
rendered_item = yield item, value, text, default_html_options.merge(additional_html_options)
|
|
17
17
|
|
|
18
|
+
if @options.fetch(:boolean_style, SimpleForm.boolean_style) == :nested
|
|
19
|
+
label_options = {}
|
|
20
|
+
add_default_name_and_id_for_value(value, label_options)
|
|
21
|
+
label_options['for'] = label_options.delete('id')
|
|
22
|
+
rendered_item = content_tag(:label, rendered_item, label_options)
|
|
23
|
+
end
|
|
24
|
+
|
|
18
25
|
item_wrapper_tag ? @template_object.content_tag(item_wrapper_tag, rendered_item, class: item_wrapper_class) : rendered_item
|
|
19
26
|
end.join.html_safe
|
|
20
27
|
end
|
data/lib/simple_form/version.rb
CHANGED
|
@@ -45,20 +45,20 @@ module SimpleForm
|
|
|
45
45
|
@components = []
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
-
def use(name, options=
|
|
48
|
+
def use(name, options = {}, &block)
|
|
49
49
|
if options && wrapper = options[:wrap_with]
|
|
50
|
-
@components << Single.new(name, wrapper)
|
|
50
|
+
@components << Single.new(name, wrapper, options.except(:wrap_with))
|
|
51
51
|
else
|
|
52
|
-
@components << name
|
|
52
|
+
@components << Leaf.new(name, options)
|
|
53
53
|
end
|
|
54
54
|
end
|
|
55
55
|
|
|
56
|
-
def optional(name, options=
|
|
56
|
+
def optional(name, options = {}, &block)
|
|
57
57
|
@options[name] = false
|
|
58
58
|
use(name, options, &block)
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
-
def wrapper(name, options=nil)
|
|
61
|
+
def wrapper(name, options = nil)
|
|
62
62
|
if block_given?
|
|
63
63
|
name, options = nil, name if name.is_a?(Hash)
|
|
64
64
|
builder = self.class.new(@options)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module SimpleForm
|
|
2
|
+
module Wrappers
|
|
3
|
+
class Leaf
|
|
4
|
+
attr_reader :namespace
|
|
5
|
+
|
|
6
|
+
def initialize(namespace, options = {})
|
|
7
|
+
@namespace = namespace
|
|
8
|
+
@options = options
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def render(input)
|
|
12
|
+
method = input.method(@namespace)
|
|
13
|
+
|
|
14
|
+
if method.arity == 0
|
|
15
|
+
ActiveSupport::Deprecation.warn(SimpleForm::CUSTOM_INPUT_DEPRECATION_WARN % { name: @namespace })
|
|
16
|
+
|
|
17
|
+
method.call
|
|
18
|
+
else
|
|
19
|
+
method.call(@options)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def find(name)
|
|
24
|
+
self if @namespace == name
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module SimpleForm
|
|
2
2
|
module Wrappers
|
|
3
3
|
# A wrapper is an object that holds several components and render them.
|
|
4
|
-
# A component may
|
|
4
|
+
# A component may be any object that responds to `render`.
|
|
5
5
|
# This API allows inputs/components to be easily wrapped, removing the
|
|
6
6
|
# need to modify the code only to wrap input in an extra tag.
|
|
7
7
|
#
|
|
@@ -10,9 +10,8 @@ module SimpleForm
|
|
|
10
10
|
# on demand on input generation.
|
|
11
11
|
class Many
|
|
12
12
|
attr_reader :namespace, :defaults, :components
|
|
13
|
-
alias :to_sym :namespace
|
|
14
13
|
|
|
15
|
-
def initialize(namespace, components, defaults={})
|
|
14
|
+
def initialize(namespace, components, defaults = {})
|
|
16
15
|
@namespace = namespace
|
|
17
16
|
@components = components
|
|
18
17
|
@defaults = defaults
|
|
@@ -25,8 +24,8 @@ module SimpleForm
|
|
|
25
24
|
options = input.options
|
|
26
25
|
|
|
27
26
|
components.each do |component|
|
|
28
|
-
next if options[component] == false
|
|
29
|
-
rendered = component.
|
|
27
|
+
next if options[component.namespace] == false
|
|
28
|
+
rendered = component.render(input)
|
|
30
29
|
content.safe_concat rendered.to_s if rendered
|
|
31
30
|
end
|
|
32
31
|
|
|
@@ -62,7 +61,7 @@ module SimpleForm
|
|
|
62
61
|
end
|
|
63
62
|
|
|
64
63
|
def html_options(options)
|
|
65
|
-
options[:"#{namespace}_html"] || {}
|
|
64
|
+
(@defaults[:html] || {}).merge(options[:"#{namespace}_html"] || {})
|
|
66
65
|
end
|
|
67
66
|
|
|
68
67
|
def html_classes(input, options)
|