simple_form 2.1.0 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of simple_form might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/CHANGELOG.md +77 -33
- data/MIT-LICENSE +1 -1
- data/README.md +387 -187
- data/lib/generators/simple_form/install_generator.rb +4 -4
- data/lib/generators/simple_form/templates/README +3 -4
- data/lib/generators/simple_form/templates/config/initializers/simple_form.rb +45 -22
- data/lib/generators/simple_form/templates/config/initializers/simple_form_bootstrap.rb +128 -24
- data/lib/generators/simple_form/templates/config/initializers/simple_form_foundation.rb +87 -6
- data/lib/generators/simple_form/templates/config/locales/simple_form.en.yml +7 -2
- data/lib/simple_form/action_view_extensions/builder.rb +2 -319
- data/lib/simple_form/action_view_extensions/form_helper.rb +8 -11
- data/lib/simple_form/components/errors.rb +28 -2
- data/lib/simple_form/components/hints.rb +8 -3
- data/lib/simple_form/components/html5.rb +6 -3
- data/lib/simple_form/components/label_input.rb +20 -2
- data/lib/simple_form/components/labels.rb +14 -10
- data/lib/simple_form/components/maxlength.rb +2 -9
- data/lib/simple_form/components/min_max.rb +1 -1
- data/lib/simple_form/components/pattern.rb +3 -3
- data/lib/simple_form/components/placeholders.rb +2 -2
- data/lib/simple_form/components/readonly.rb +1 -1
- data/lib/simple_form/components.rb +1 -1
- data/lib/simple_form/error_notification.rb +2 -2
- data/lib/simple_form/form_builder.rb +262 -107
- data/lib/simple_form/helpers.rb +6 -6
- data/lib/simple_form/inputs/base.rb +37 -16
- data/lib/simple_form/inputs/block_input.rb +2 -2
- data/lib/simple_form/inputs/boolean_input.rb +33 -18
- data/lib/simple_form/inputs/collection_input.rb +34 -13
- data/lib/simple_form/inputs/collection_radio_buttons_input.rb +7 -12
- data/lib/simple_form/inputs/collection_select_input.rb +4 -2
- data/lib/simple_form/inputs/date_time_input.rb +23 -9
- 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 +3 -8
- data/lib/simple_form/inputs/password_input.rb +4 -3
- 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 -3
- data/lib/simple_form/inputs/text_input.rb +4 -2
- data/lib/simple_form/railtie.rb +14 -0
- data/lib/simple_form/tags.rb +68 -0
- data/lib/simple_form/version.rb +1 -1
- data/lib/simple_form/wrappers/builder.rb +11 -35
- data/lib/simple_form/wrappers/leaf.rb +28 -0
- data/lib/simple_form/wrappers/many.rb +7 -7
- data/lib/simple_form/wrappers/root.rb +2 -2
- data/lib/simple_form/wrappers/single.rb +5 -3
- data/lib/simple_form/wrappers.rb +2 -1
- data/lib/simple_form.rb +99 -52
- data/test/action_view_extensions/builder_test.rb +113 -127
- data/test/action_view_extensions/form_helper_test.rb +58 -30
- data/test/components/label_test.rb +83 -83
- data/test/form_builder/association_test.rb +96 -61
- data/test/form_builder/button_test.rb +14 -14
- data/test/form_builder/error_notification_test.rb +9 -9
- data/test/form_builder/error_test.rb +159 -34
- data/test/form_builder/general_test.rb +176 -121
- data/test/form_builder/hint_test.rb +43 -37
- data/test/form_builder/input_field_test.rb +99 -52
- data/test/form_builder/label_test.rb +67 -15
- data/test/form_builder/wrapper_test.rb +157 -41
- data/test/generators/simple_form_generator_test.rb +4 -4
- data/test/inputs/boolean_input_test.rb +92 -24
- data/test/inputs/collection_check_boxes_input_test.rb +150 -71
- data/test/inputs/collection_radio_buttons_input_test.rb +213 -113
- data/test/inputs/collection_select_input_test.rb +221 -85
- data/test/inputs/datetime_input_test.rb +125 -47
- data/test/inputs/disabled_test.rb +25 -25
- data/test/inputs/discovery_test.rb +60 -10
- data/test/inputs/file_input_test.rb +3 -3
- data/test/inputs/general_test.rb +48 -32
- data/test/inputs/grouped_collection_select_input_test.rb +76 -27
- data/test/inputs/hidden_input_test.rb +6 -5
- data/test/inputs/numeric_input_test.rb +46 -46
- data/test/inputs/priority_input_test.rb +21 -15
- data/test/inputs/readonly_test.rb +31 -31
- data/test/inputs/required_test.rb +30 -18
- data/test/inputs/string_input_test.rb +53 -52
- data/test/inputs/text_input_test.rb +15 -8
- data/test/simple_form_test.rb +8 -0
- data/test/support/discovery_inputs.rb +32 -2
- data/test/support/misc_helpers.rb +130 -29
- data/test/support/mock_controller.rb +6 -6
- data/test/support/models.rb +125 -71
- data/test/test_helper.rb +28 -35
- metadata +17 -29
- data/lib/simple_form/action_view_extensions/builder.rb.orig +0 -247
- data/lib/simple_form/core_ext/hash.rb +0 -16
- data/lib/simple_form/form_builder.rb.orig +0 -486
- data/lib/simple_form/version.rb.orig +0 -7
@@ -1,8 +1,13 @@
|
|
1
1
|
require 'simple_form/i18n_cache'
|
2
|
+
require 'active_support/core_ext/string/output_safety'
|
3
|
+
require 'action_view/helpers'
|
2
4
|
|
3
5
|
module SimpleForm
|
4
6
|
module Inputs
|
5
7
|
class Base
|
8
|
+
include ERB::Util
|
9
|
+
include ActionView::Helpers::TranslationHelper
|
10
|
+
|
6
11
|
extend I18nCache
|
7
12
|
|
8
13
|
include SimpleForm::Helpers::Autofocus
|
@@ -24,7 +29,7 @@ module SimpleForm
|
|
24
29
|
attr_reader :attribute_name, :column, :input_type, :reflection,
|
25
30
|
:options, :input_html_options, :input_html_classes, :html_classes
|
26
31
|
|
27
|
-
delegate :template, :object, :object_name, :lookup_model_names, :lookup_action, :
|
32
|
+
delegate :template, :object, :object_name, :lookup_model_names, :lookup_action, to: :@builder
|
28
33
|
|
29
34
|
class_attribute :default_options
|
30
35
|
self.default_options = {}
|
@@ -50,14 +55,14 @@ module SimpleForm
|
|
50
55
|
def initialize(builder, attribute_name, column, input_type, options = {})
|
51
56
|
super
|
52
57
|
|
53
|
-
options
|
54
|
-
@builder
|
55
|
-
@attribute_name
|
56
|
-
@column
|
57
|
-
@input_type
|
58
|
-
@reflection
|
59
|
-
@options
|
60
|
-
@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
|
61
66
|
|
62
67
|
# Notice that html_options_for receives a reference to input_html_classes.
|
63
68
|
# This means that classes added dynamically to input_html_classes will
|
@@ -65,6 +70,10 @@ module SimpleForm
|
|
65
70
|
@html_classes = SimpleForm.additional_classes_for(:input) { additional_classes }
|
66
71
|
|
67
72
|
@input_html_classes = @html_classes.dup
|
73
|
+
if SimpleForm.input_class && !input_html_classes.empty?
|
74
|
+
input_html_classes << SimpleForm.input_class
|
75
|
+
end
|
76
|
+
|
68
77
|
@input_html_options = html_options_for(:input, input_html_classes).tap do |o|
|
69
78
|
o[:readonly] = true if has_readonly?
|
70
79
|
o[:disabled] = true if has_disabled?
|
@@ -72,7 +81,7 @@ module SimpleForm
|
|
72
81
|
end
|
73
82
|
end
|
74
83
|
|
75
|
-
def input
|
84
|
+
def input(wrapper_options = nil)
|
76
85
|
raise NotImplementedError
|
77
86
|
end
|
78
87
|
|
@@ -90,10 +99,6 @@ module SimpleForm
|
|
90
99
|
|
91
100
|
private
|
92
101
|
|
93
|
-
def add_size!
|
94
|
-
input_html_options[:size] ||= [limit, SimpleForm.default_input_size].compact.min
|
95
|
-
end
|
96
|
-
|
97
102
|
def limit
|
98
103
|
if column
|
99
104
|
decimal_or_float? ? decimal_limit : column_limit
|
@@ -164,7 +169,7 @@ module SimpleForm
|
|
164
169
|
# email: 'E-mail.'
|
165
170
|
#
|
166
171
|
# Take a look at our locale example file.
|
167
|
-
def
|
172
|
+
def translate_from_namespace(namespace, default = '')
|
168
173
|
model_names = lookup_model_names.dup
|
169
174
|
lookups = []
|
170
175
|
|
@@ -179,7 +184,23 @@ module SimpleForm
|
|
179
184
|
lookups << :"defaults.#{reflection_or_attribute_name}"
|
180
185
|
lookups << default
|
181
186
|
|
182
|
-
I18n.t(lookups.shift, :
|
187
|
+
I18n.t(lookups.shift, scope: :"#{i18n_scope}.#{namespace}", default: lookups).presence
|
188
|
+
end
|
189
|
+
|
190
|
+
def merge_wrapper_options(options, wrapper_options)
|
191
|
+
if wrapper_options
|
192
|
+
options.merge(wrapper_options) do |_, oldval, newval|
|
193
|
+
if Array === oldval
|
194
|
+
oldval + Array(newval)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
else
|
198
|
+
options
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def i18n_scope
|
203
|
+
SimpleForm.i18n_scope
|
183
204
|
end
|
184
205
|
end
|
185
206
|
end
|
@@ -1,30 +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, :
|
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
|
16
|
-
if options[:label] == false
|
17
|
-
input
|
18
|
+
def label_input(wrapper_options = nil)
|
19
|
+
if options[:label] == false || inline_label?
|
20
|
+
input(wrapper_options)
|
18
21
|
elsif nested_boolean_style?
|
19
22
|
html_options = label_html_options.dup
|
20
|
-
html_options[:class]
|
23
|
+
html_options[:class] ||= []
|
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)
|
21
27
|
|
22
28
|
build_hidden_field_for_checkbox +
|
23
29
|
@builder.label(label_target, html_options) {
|
24
|
-
build_check_box_without_hidden_field + label_text
|
30
|
+
build_check_box_without_hidden_field(merged_input_options) + label_text
|
25
31
|
}
|
26
32
|
else
|
27
|
-
input + label
|
33
|
+
input(wrapper_options) + label(wrapper_options)
|
28
34
|
end
|
29
35
|
end
|
30
36
|
|
@@ -34,14 +40,14 @@ module SimpleForm
|
|
34
40
|
# reuse the method for nested boolean style, but with no unchecked value,
|
35
41
|
# which won't generate the hidden checkbox. This is the default functionality
|
36
42
|
# in Rails > 3.2.1, and is backported in SimpleForm AV helpers.
|
37
|
-
def build_check_box(unchecked_value
|
38
|
-
@builder.check_box(attribute_name,
|
43
|
+
def build_check_box(unchecked_value, options)
|
44
|
+
@builder.check_box(attribute_name, options, checked_value, unchecked_value)
|
39
45
|
end
|
40
46
|
|
41
47
|
# Build a checkbox without generating the hidden field. See
|
42
48
|
# #build_hidden_field_for_checkbox for more info.
|
43
|
-
def build_check_box_without_hidden_field
|
44
|
-
build_check_box(nil)
|
49
|
+
def build_check_box_without_hidden_field(options)
|
50
|
+
build_check_box(nil, options)
|
45
51
|
end
|
46
52
|
|
47
53
|
# Create a hidden field for the current checkbox, so we can simulate Rails
|
@@ -49,14 +55,23 @@ module SimpleForm
|
|
49
55
|
# we need the hidden field to be *outside* the label (otherwise it
|
50
56
|
# generates invalid html - html5 only).
|
51
57
|
def build_hidden_field_for_checkbox
|
52
|
-
|
53
|
-
|
54
|
-
|
58
|
+
options = { value: unchecked_value, id: nil, disabled: input_html_options[:disabled] }
|
59
|
+
options[:name] = input_html_options[:name] if input_html_options.has_key?(:name)
|
60
|
+
|
61
|
+
@builder.hidden_field(attribute_name, options)
|
62
|
+
end
|
63
|
+
|
64
|
+
def inline_label?
|
65
|
+
nested_boolean_style? && options[:inline_label]
|
55
66
|
end
|
56
67
|
|
57
68
|
def inline_label
|
58
69
|
inline_option = options[:inline_label]
|
59
|
-
|
70
|
+
|
71
|
+
if inline_option
|
72
|
+
label = inline_option == true ? label_text : html_escape(inline_option)
|
73
|
+
" #{label}".html_safe
|
74
|
+
end
|
60
75
|
end
|
61
76
|
|
62
77
|
# Booleans are not required by default because in most of the cases
|
@@ -7,19 +7,23 @@ module SimpleForm
|
|
7
7
|
# "simple_form.no" keys. See the example locale file.
|
8
8
|
def self.boolean_collection
|
9
9
|
i18n_cache :boolean_collection do
|
10
|
-
[ [I18n.t(:"simple_form.yes", :
|
11
|
-
[I18n.t(:"simple_form.no", :
|
10
|
+
[ [I18n.t(:"simple_form.yes", default: 'Yes'), true],
|
11
|
+
[I18n.t(:"simple_form.no", default: 'No'), false] ]
|
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
|
+
translate_option options, :prompt
|
25
|
+
translate_option options, :include_blank
|
26
|
+
|
23
27
|
options
|
24
28
|
end
|
25
29
|
|
@@ -33,7 +37,7 @@ module SimpleForm
|
|
33
37
|
end
|
34
38
|
|
35
39
|
def has_required?
|
36
|
-
super && (input_options[:include_blank] || multiple?)
|
40
|
+
super && (input_options[:include_blank] || input_options[:prompt] || multiple?)
|
37
41
|
end
|
38
42
|
|
39
43
|
# Check if :include_blank must be included by default.
|
@@ -66,17 +70,21 @@ module SimpleForm
|
|
66
70
|
collection_translated = translate_collection if collection_classes == [Symbol]
|
67
71
|
|
68
72
|
if collection_translated || collection_classes.include?(Array)
|
69
|
-
{ :
|
73
|
+
{ label: :first, value: :second }
|
70
74
|
elsif collection_includes_basic_objects?(collection_classes)
|
71
|
-
{ :
|
75
|
+
{ label: :to_s, value: :to_s }
|
72
76
|
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) } }
|
77
|
+
detect_method_from_class(collection_classes)
|
77
78
|
end
|
78
79
|
end
|
79
80
|
|
81
|
+
def detect_method_from_class(collection_classes)
|
82
|
+
sample = collection.first || collection.last
|
83
|
+
|
84
|
+
{ label: SimpleForm.collection_label_methods.find { |m| sample.respond_to?(m) },
|
85
|
+
value: SimpleForm.collection_value_methods.find { |m| sample.respond_to?(m) } }
|
86
|
+
end
|
87
|
+
|
80
88
|
def detect_collection_classes(some_collection = collection)
|
81
89
|
some_collection.map { |e| e.class }.uniq
|
82
90
|
end
|
@@ -88,14 +96,27 @@ module SimpleForm
|
|
88
96
|
end
|
89
97
|
|
90
98
|
def translate_collection
|
91
|
-
if translated_collection =
|
99
|
+
if translated_collection = translate_from_namespace(:options)
|
92
100
|
@collection = collection.map do |key|
|
93
|
-
|
101
|
+
html_key = "#{key}_html".to_sym
|
102
|
+
|
103
|
+
if translated_collection[html_key]
|
104
|
+
[translated_collection[html_key].html_safe || key, key.to_s]
|
105
|
+
else
|
106
|
+
[translated_collection[key] || key, key.to_s]
|
107
|
+
end
|
94
108
|
end
|
95
109
|
true
|
96
110
|
end
|
97
111
|
end
|
112
|
+
|
113
|
+
def translate_option(options, key)
|
114
|
+
if options[key] == :translate
|
115
|
+
namespace = key.to_s.pluralize
|
116
|
+
|
117
|
+
options[key] = translate_from_namespace(namespace, true)
|
118
|
+
end
|
119
|
+
end
|
98
120
|
end
|
99
121
|
end
|
100
122
|
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
|
-
|
7
|
+
merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
|
8
|
+
|
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,23 +1,37 @@
|
|
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
|
9
15
|
|
10
16
|
def label_target
|
11
|
-
|
12
|
-
|
13
|
-
date_order = input_options[:order] || I18n.t('date.order')
|
14
|
-
date_order.first
|
17
|
+
if use_html5_inputs?
|
18
|
+
attribute_name
|
15
19
|
else
|
16
|
-
|
20
|
+
position = case input_type
|
21
|
+
when :date, :datetime
|
22
|
+
date_order = input_options[:order] || I18n.t('date.order')
|
23
|
+
date_order.first.to_sym
|
24
|
+
else
|
25
|
+
:hour
|
26
|
+
end
|
27
|
+
|
28
|
+
position = ActionView::Helpers::DateTimeSelector::POSITION[position]
|
29
|
+
"#{attribute_name}_#{position}i"
|
17
30
|
end
|
31
|
+
end
|
18
32
|
|
19
|
-
|
20
|
-
|
33
|
+
def use_html5_inputs?
|
34
|
+
input_options[:html5]
|
21
35
|
end
|
22
36
|
end
|
23
37
|
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,21 +3,16 @@ module SimpleForm
|
|
3
3
|
class NumericInput < Base
|
4
4
|
enable :placeholder, :min_max
|
5
5
|
|
6
|
-
def input
|
7
|
-
add_size!
|
6
|
+
def input(wrapper_options = nil)
|
8
7
|
input_html_classes.unshift("numeric")
|
9
8
|
if html5?
|
10
9
|
input_html_options[:type] ||= "number"
|
11
10
|
input_html_options[:step] ||= integer? ? 1 : "any"
|
12
11
|
end
|
13
|
-
@builder.text_field(attribute_name, input_html_options)
|
14
|
-
end
|
15
12
|
|
16
|
-
|
13
|
+
merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
|
17
14
|
|
18
|
-
|
19
|
-
def add_size!
|
20
|
-
input_html_options[:size] ||= nil
|
15
|
+
@builder.text_field(attribute_name, merged_input_options)
|
21
16
|
end
|
22
17
|
end
|
23
18
|
end
|
@@ -3,9 +3,10 @@ module SimpleForm
|
|
3
3
|
class PasswordInput < Base
|
4
4
|
enable :placeholder, :maxlength
|
5
5
|
|
6
|
-
def input
|
7
|
-
|
8
|
-
|
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)
|
9
10
|
end
|
10
11
|
end
|
11
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,14 +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
|
-
|
13
|
-
|
12
|
+
merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
|
13
|
+
|
14
|
+
@builder.text_field(attribute_name, merged_input_options)
|
14
15
|
end
|
15
16
|
|
16
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
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rails/railtie'
|
2
|
+
|
3
|
+
module SimpleForm
|
4
|
+
class Railtie < Rails::Railtie
|
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
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module SimpleForm
|
2
|
+
module Tags
|
3
|
+
module CollectionExtensions
|
4
|
+
private
|
5
|
+
|
6
|
+
def render_collection
|
7
|
+
item_wrapper_tag = @options.fetch(:item_wrapper_tag, :span)
|
8
|
+
item_wrapper_class = @options[:item_wrapper_class]
|
9
|
+
|
10
|
+
@collection.map do |item|
|
11
|
+
value = value_for_collection(item, @value_method)
|
12
|
+
text = value_for_collection(item, @text_method)
|
13
|
+
default_html_options = default_html_options_for_collection(item, value)
|
14
|
+
additional_html_options = option_html_attributes(item)
|
15
|
+
|
16
|
+
rendered_item = yield item, value, text, default_html_options.merge(additional_html_options)
|
17
|
+
|
18
|
+
if @options.fetch(:boolean_style, SimpleForm.boolean_style) == :nested
|
19
|
+
label_options = default_html_options.slice(:index, :namespace)
|
20
|
+
label_options['class'] = @options[:item_label_class]
|
21
|
+
rendered_item = @template_object.label(@object_name, sanitize_attribute_name(value), rendered_item, label_options)
|
22
|
+
end
|
23
|
+
|
24
|
+
item_wrapper_tag ? @template_object.content_tag(item_wrapper_tag, rendered_item, class: item_wrapper_class) : rendered_item
|
25
|
+
end.join.html_safe
|
26
|
+
end
|
27
|
+
|
28
|
+
def wrap_rendered_collection(collection)
|
29
|
+
wrapper_tag = @options[:collection_wrapper_tag]
|
30
|
+
|
31
|
+
if wrapper_tag
|
32
|
+
wrapper_class = @options[:collection_wrapper_class]
|
33
|
+
@template_object.content_tag(wrapper_tag, collection, class: wrapper_class)
|
34
|
+
else
|
35
|
+
collection
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class CollectionRadioButtons < ActionView::Helpers::Tags::CollectionRadioButtons
|
41
|
+
include CollectionExtensions
|
42
|
+
|
43
|
+
def render
|
44
|
+
wrap_rendered_collection(super)
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def render_component(builder)
|
50
|
+
builder.radio_button + builder.label(class: "collection_radio_buttons")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class CollectionCheckBoxes < ActionView::Helpers::Tags::CollectionCheckBoxes
|
55
|
+
include CollectionExtensions
|
56
|
+
|
57
|
+
def render
|
58
|
+
wrap_rendered_collection(super)
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def render_component(builder)
|
64
|
+
builder.check_box + builder.label(class: "collection_check_boxes")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|