simple_form 2.0.0 → 3.5.1
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +97 -198
- data/MIT-LICENSE +1 -1
- data/README.md +572 -296
- data/lib/generators/simple_form/install_generator.rb +17 -7
- data/lib/generators/simple_form/templates/README +3 -4
- data/lib/generators/simple_form/templates/_form.html.erb +1 -0
- data/lib/generators/simple_form/templates/_form.html.haml +1 -0
- data/lib/generators/simple_form/templates/config/initializers/{simple_form.rb.tt → simple_form.rb} +57 -63
- data/lib/generators/simple_form/templates/config/initializers/simple_form_bootstrap.rb +155 -0
- data/lib/generators/simple_form/templates/config/initializers/simple_form_foundation.rb +111 -0
- data/lib/generators/simple_form/templates/config/locales/simple_form.en.yml +14 -7
- data/lib/simple_form/action_view_extensions/builder.rb +5 -305
- data/lib/simple_form/action_view_extensions/form_helper.rb +18 -20
- data/lib/simple_form/components/errors.rb +30 -3
- data/lib/simple_form/components/hints.rb +10 -3
- data/lib/simple_form/components/html5.rb +17 -3
- data/lib/simple_form/components/label_input.rb +21 -2
- data/lib/simple_form/components/labels.rb +16 -11
- data/lib/simple_form/components/maxlength.rb +19 -12
- data/lib/simple_form/components/min_max.rb +4 -2
- data/lib/simple_form/components/minlength.rb +48 -0
- data/lib/simple_form/components/pattern.rb +5 -4
- data/lib/simple_form/components/placeholders.rb +3 -2
- data/lib/simple_form/components/readonly.rb +3 -2
- data/lib/simple_form/components.rb +15 -11
- data/lib/simple_form/error_notification.rb +4 -3
- data/lib/simple_form/form_builder.rb +283 -105
- data/lib/simple_form/helpers/autofocus.rb +1 -0
- data/lib/simple_form/helpers/disabled.rb +1 -0
- data/lib/simple_form/helpers/readonly.rb +1 -0
- data/lib/simple_form/helpers/required.rb +1 -0
- data/lib/simple_form/helpers/validators.rb +4 -3
- data/lib/simple_form/helpers.rb +7 -6
- data/lib/simple_form/i18n_cache.rb +1 -0
- data/lib/simple_form/inputs/base.rb +76 -23
- data/lib/simple_form/inputs/block_input.rb +3 -2
- data/lib/simple_form/inputs/boolean_input.rb +55 -16
- data/lib/simple_form/inputs/collection_check_boxes_input.rb +2 -1
- data/lib/simple_form/inputs/collection_input.rb +41 -18
- data/lib/simple_form/inputs/collection_radio_buttons_input.rb +11 -19
- data/lib/simple_form/inputs/collection_select_input.rb +5 -2
- data/lib/simple_form/inputs/date_time_input.rb +23 -12
- data/lib/simple_form/inputs/file_input.rb +5 -2
- data/lib/simple_form/inputs/grouped_collection_select_input.rb +16 -3
- data/lib/simple_form/inputs/hidden_input.rb +5 -2
- data/lib/simple_form/inputs/numeric_input.rb +4 -8
- data/lib/simple_form/inputs/password_input.rb +6 -4
- data/lib/simple_form/inputs/priority_input.rb +5 -2
- data/lib/simple_form/inputs/range_input.rb +2 -1
- data/lib/simple_form/inputs/string_input.rb +6 -4
- data/lib/simple_form/inputs/text_input.rb +6 -3
- data/lib/simple_form/inputs.rb +20 -17
- data/lib/simple_form/map_type.rb +1 -0
- data/lib/simple_form/railtie.rb +15 -0
- data/lib/simple_form/tags.rb +69 -0
- data/lib/simple_form/version.rb +2 -1
- data/lib/simple_form/wrappers/builder.rb +12 -35
- data/lib/simple_form/wrappers/leaf.rb +29 -0
- data/lib/simple_form/wrappers/many.rb +12 -7
- data/lib/simple_form/wrappers/root.rb +7 -4
- data/lib/simple_form/wrappers/single.rb +12 -3
- data/lib/simple_form/wrappers.rb +3 -1
- data/lib/simple_form.rb +118 -63
- data/test/action_view_extensions/builder_test.rb +230 -164
- data/test/action_view_extensions/form_helper_test.rb +107 -39
- data/test/components/label_test.rb +105 -87
- data/test/form_builder/association_test.rb +131 -62
- data/test/form_builder/button_test.rb +15 -14
- data/test/form_builder/error_notification_test.rb +11 -10
- data/test/form_builder/error_test.rb +188 -34
- data/test/form_builder/general_test.rb +247 -102
- data/test/form_builder/hint_test.rb +59 -32
- data/test/form_builder/input_field_test.rb +138 -25
- data/test/form_builder/label_test.rb +84 -13
- data/test/form_builder/wrapper_test.rb +236 -33
- data/test/generators/simple_form_generator_test.rb +15 -4
- data/test/inputs/boolean_input_test.rb +147 -13
- data/test/inputs/collection_check_boxes_input_test.rb +166 -71
- data/test/inputs/collection_radio_buttons_input_test.rb +229 -113
- data/test/inputs/collection_select_input_test.rb +222 -85
- data/test/inputs/datetime_input_test.rb +134 -47
- data/test/inputs/disabled_test.rb +62 -21
- data/test/inputs/discovery_test.rb +70 -10
- data/test/inputs/file_input_test.rb +4 -3
- data/test/inputs/general_test.rb +90 -26
- data/test/inputs/grouped_collection_select_input_test.rb +88 -23
- data/test/inputs/hidden_input_test.rb +7 -5
- data/test/inputs/numeric_input_test.rb +56 -46
- data/test/inputs/priority_input_test.rb +31 -16
- data/test/inputs/readonly_test.rb +68 -27
- data/test/inputs/required_test.rb +63 -18
- data/test/inputs/string_input_test.rb +76 -51
- data/test/inputs/text_input_test.rb +21 -8
- data/test/simple_form_test.rb +9 -0
- data/test/support/discovery_inputs.rb +39 -2
- data/test/support/misc_helpers.rb +176 -20
- data/test/support/mock_controller.rb +13 -7
- data/test/support/models.rb +187 -71
- data/test/test_helper.rb +38 -39
- metadata +53 -39
- data/lib/simple_form/core_ext/hash.rb +0 -16
- data/test/support/mock_response.rb +0 -14
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module SimpleForm
|
|
2
3
|
module Helpers
|
|
3
4
|
module Validators
|
|
@@ -24,7 +25,7 @@ module SimpleForm
|
|
|
24
25
|
end
|
|
25
26
|
|
|
26
27
|
def action_validator_match?(validator)
|
|
27
|
-
return true
|
|
28
|
+
return true unless validator.options.include?(:on)
|
|
28
29
|
|
|
29
30
|
case validator.options[:on]
|
|
30
31
|
when :save
|
|
@@ -36,8 +37,8 @@ module SimpleForm
|
|
|
36
37
|
end
|
|
37
38
|
end
|
|
38
39
|
|
|
39
|
-
def find_validator(
|
|
40
|
-
attribute_validators.find { |v|
|
|
40
|
+
def find_validator(kind)
|
|
41
|
+
attribute_validators.find { |v| v.kind == kind } if has_validators?
|
|
41
42
|
end
|
|
42
43
|
end
|
|
43
44
|
end
|
data/lib/simple_form/helpers.rb
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module SimpleForm
|
|
2
3
|
# Helpers are made of several helpers that cannot be turned on automatically.
|
|
3
4
|
# For instance, disabled cannot be turned on automatically, it requires the
|
|
4
|
-
# user to explicitly pass the option :
|
|
5
|
+
# user to explicitly pass the option disabled: true so it may work.
|
|
5
6
|
module Helpers
|
|
6
|
-
autoload :Autofocus,
|
|
7
|
-
autoload :Disabled,
|
|
8
|
-
autoload :Readonly,
|
|
9
|
-
autoload :Required,
|
|
10
|
-
autoload :Validators,
|
|
7
|
+
autoload :Autofocus, 'simple_form/helpers/autofocus'
|
|
8
|
+
autoload :Disabled, 'simple_form/helpers/disabled'
|
|
9
|
+
autoload :Readonly, 'simple_form/helpers/readonly'
|
|
10
|
+
autoload :Required, 'simple_form/helpers/required'
|
|
11
|
+
autoload :Validators, 'simple_form/helpers/validators'
|
|
11
12
|
end
|
|
12
13
|
end
|
|
@@ -1,6 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'simple_form/i18n_cache'
|
|
3
|
+
require 'active_support/core_ext/string/output_safety'
|
|
4
|
+
require 'action_view/helpers'
|
|
5
|
+
|
|
1
6
|
module SimpleForm
|
|
2
7
|
module Inputs
|
|
3
8
|
class Base
|
|
9
|
+
include ERB::Util
|
|
10
|
+
include ActionView::Helpers::TranslationHelper
|
|
11
|
+
|
|
4
12
|
extend I18nCache
|
|
5
13
|
|
|
6
14
|
include SimpleForm::Helpers::Autofocus
|
|
@@ -14,6 +22,7 @@ module SimpleForm
|
|
|
14
22
|
include SimpleForm::Components::HTML5
|
|
15
23
|
include SimpleForm::Components::LabelInput
|
|
16
24
|
include SimpleForm::Components::Maxlength
|
|
25
|
+
include SimpleForm::Components::Minlength
|
|
17
26
|
include SimpleForm::Components::MinMax
|
|
18
27
|
include SimpleForm::Components::Pattern
|
|
19
28
|
include SimpleForm::Components::Placeholders
|
|
@@ -22,7 +31,7 @@ module SimpleForm
|
|
|
22
31
|
attr_reader :attribute_name, :column, :input_type, :reflection,
|
|
23
32
|
:options, :input_html_options, :input_html_classes, :html_classes
|
|
24
33
|
|
|
25
|
-
delegate :template, :object, :object_name, :lookup_model_names, :lookup_action, :
|
|
34
|
+
delegate :template, :object, :object_name, :lookup_model_names, :lookup_action, to: :@builder
|
|
26
35
|
|
|
27
36
|
class_attribute :default_options
|
|
28
37
|
self.default_options = {}
|
|
@@ -43,27 +52,30 @@ module SimpleForm
|
|
|
43
52
|
enable :hint
|
|
44
53
|
|
|
45
54
|
# Usually disabled, needs to be enabled explicitly passing true as option.
|
|
46
|
-
disable :maxlength, :placeholder, :pattern, :min_max
|
|
55
|
+
disable :maxlength, :minlength, :placeholder, :pattern, :min_max
|
|
47
56
|
|
|
48
57
|
def initialize(builder, attribute_name, column, input_type, options = {})
|
|
49
58
|
super
|
|
50
59
|
|
|
51
|
-
|
|
52
|
-
@
|
|
53
|
-
@
|
|
54
|
-
@
|
|
55
|
-
@
|
|
56
|
-
@
|
|
57
|
-
@
|
|
60
|
+
options = options.dup
|
|
61
|
+
@builder = builder
|
|
62
|
+
@attribute_name = attribute_name
|
|
63
|
+
@column = column
|
|
64
|
+
@input_type = input_type
|
|
65
|
+
@reflection = options.delete(:reflection)
|
|
66
|
+
@options = options.reverse_merge!(self.class.default_options)
|
|
67
|
+
@required = calculate_required
|
|
58
68
|
|
|
59
69
|
# Notice that html_options_for receives a reference to input_html_classes.
|
|
60
70
|
# This means that classes added dynamically to input_html_classes will
|
|
61
71
|
# still propagate to input_html_options.
|
|
62
|
-
@html_classes = SimpleForm.additional_classes_for(:input) {
|
|
63
|
-
[input_type, required_class, readonly_class, disabled_class].compact
|
|
64
|
-
}
|
|
72
|
+
@html_classes = SimpleForm.additional_classes_for(:input) { additional_classes }
|
|
65
73
|
|
|
66
74
|
@input_html_classes = @html_classes.dup
|
|
75
|
+
if SimpleForm.input_class && !input_html_classes.empty?
|
|
76
|
+
input_html_classes << SimpleForm.input_class
|
|
77
|
+
end
|
|
78
|
+
|
|
67
79
|
@input_html_options = html_options_for(:input, input_html_classes).tap do |o|
|
|
68
80
|
o[:readonly] = true if has_readonly?
|
|
69
81
|
o[:disabled] = true if has_disabled?
|
|
@@ -71,7 +83,7 @@ module SimpleForm
|
|
|
71
83
|
end
|
|
72
84
|
end
|
|
73
85
|
|
|
74
|
-
def input
|
|
86
|
+
def input(wrapper_options = nil)
|
|
75
87
|
raise NotImplementedError
|
|
76
88
|
end
|
|
77
89
|
|
|
@@ -79,14 +91,33 @@ module SimpleForm
|
|
|
79
91
|
options
|
|
80
92
|
end
|
|
81
93
|
|
|
82
|
-
|
|
94
|
+
def additional_classes
|
|
95
|
+
@additional_classes ||= [input_type, required_class, readonly_class, disabled_class].compact
|
|
96
|
+
end
|
|
83
97
|
|
|
84
|
-
def
|
|
85
|
-
|
|
98
|
+
def input_class
|
|
99
|
+
"#{lookup_model_names.join('_')}_#{reflection_or_attribute_name}"
|
|
86
100
|
end
|
|
87
101
|
|
|
102
|
+
private
|
|
103
|
+
|
|
88
104
|
def limit
|
|
89
|
-
|
|
105
|
+
if column
|
|
106
|
+
decimal_or_float? ? decimal_limit : column_limit
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def column_limit
|
|
111
|
+
column.limit
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Add one for decimal point
|
|
115
|
+
def decimal_limit
|
|
116
|
+
column_limit && (column_limit + 1)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def decimal_or_float?
|
|
120
|
+
column.type == :float || column.type == :decimal
|
|
90
121
|
end
|
|
91
122
|
|
|
92
123
|
def nested_boolean_style?
|
|
@@ -95,14 +126,15 @@ module SimpleForm
|
|
|
95
126
|
|
|
96
127
|
# Find reflection name when available, otherwise use attribute
|
|
97
128
|
def reflection_or_attribute_name
|
|
98
|
-
reflection ? reflection.name : attribute_name
|
|
129
|
+
@reflection_or_attribute_name ||= reflection ? reflection.name : attribute_name
|
|
99
130
|
end
|
|
100
131
|
|
|
101
132
|
# Retrieve options for the given namespace from the options hash
|
|
102
133
|
def html_options_for(namespace, css_classes)
|
|
103
|
-
html_options = options[:"#{namespace}_html"]
|
|
134
|
+
html_options = options[:"#{namespace}_html"]
|
|
135
|
+
html_options = html_options ? html_options.dup : {}
|
|
104
136
|
css_classes << html_options[:class] if html_options.key?(:class)
|
|
105
|
-
html_options[:class] = css_classes
|
|
137
|
+
html_options[:class] = css_classes unless css_classes.empty?
|
|
106
138
|
html_options
|
|
107
139
|
end
|
|
108
140
|
|
|
@@ -139,7 +171,7 @@ module SimpleForm
|
|
|
139
171
|
# email: 'E-mail.'
|
|
140
172
|
#
|
|
141
173
|
# Take a look at our locale example file.
|
|
142
|
-
def
|
|
174
|
+
def translate_from_namespace(namespace, default = '')
|
|
143
175
|
model_names = lookup_model_names.dup
|
|
144
176
|
lookups = []
|
|
145
177
|
|
|
@@ -151,10 +183,31 @@ module SimpleForm
|
|
|
151
183
|
lookups << :"#{joined_model_names}.#{reflection_or_attribute_name}"
|
|
152
184
|
end
|
|
153
185
|
lookups << :"defaults.#{lookup_action}.#{reflection_or_attribute_name}"
|
|
154
|
-
lookups << :"defaults.#{
|
|
186
|
+
lookups << :"defaults.#{reflection_or_attribute_name}"
|
|
155
187
|
lookups << default
|
|
156
188
|
|
|
157
|
-
I18n.t(lookups.shift, :
|
|
189
|
+
I18n.t(lookups.shift, scope: :"#{i18n_scope}.#{namespace}", default: lookups).presence
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def merge_wrapper_options(options, wrapper_options)
|
|
193
|
+
if wrapper_options
|
|
194
|
+
wrapper_options.merge(options) do |key, oldval, newval|
|
|
195
|
+
case key.to_s
|
|
196
|
+
when "class"
|
|
197
|
+
Array(oldval) + Array(newval)
|
|
198
|
+
when "data", "aria"
|
|
199
|
+
oldval.merge(newval)
|
|
200
|
+
else
|
|
201
|
+
newval
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
else
|
|
205
|
+
options
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def i18n_scope
|
|
210
|
+
SimpleForm.i18n_scope
|
|
158
211
|
end
|
|
159
212
|
end
|
|
160
213
|
end
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module SimpleForm
|
|
2
3
|
module Inputs
|
|
3
4
|
class BlockInput < Base
|
|
@@ -6,9 +7,9 @@ module SimpleForm
|
|
|
6
7
|
@block = block
|
|
7
8
|
end
|
|
8
9
|
|
|
9
|
-
def input
|
|
10
|
+
def input(wrapper_options = nil)
|
|
10
11
|
template.capture(&@block)
|
|
11
12
|
end
|
|
12
13
|
end
|
|
13
14
|
end
|
|
14
|
-
end
|
|
15
|
+
end
|
|
@@ -1,47 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module SimpleForm
|
|
2
3
|
module Inputs
|
|
3
4
|
class BooleanInput < Base
|
|
4
|
-
def input
|
|
5
|
+
def input(wrapper_options = nil)
|
|
6
|
+
merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
|
|
7
|
+
|
|
5
8
|
if nested_boolean_style?
|
|
6
9
|
build_hidden_field_for_checkbox +
|
|
7
|
-
template.label_tag(nil, :
|
|
8
|
-
build_check_box_without_hidden_field
|
|
10
|
+
template.label_tag(nil, class: boolean_label_class) {
|
|
11
|
+
build_check_box_without_hidden_field(merged_input_options) +
|
|
12
|
+
inline_label
|
|
9
13
|
}
|
|
10
14
|
else
|
|
11
|
-
build_check_box
|
|
15
|
+
build_check_box(unchecked_value, merged_input_options)
|
|
12
16
|
end
|
|
13
17
|
end
|
|
14
18
|
|
|
15
|
-
def label_input
|
|
16
|
-
if options[:label] == false
|
|
17
|
-
input
|
|
19
|
+
def label_input(wrapper_options = nil)
|
|
20
|
+
if options[:label] == false || inline_label?
|
|
21
|
+
input(wrapper_options)
|
|
18
22
|
elsif nested_boolean_style?
|
|
19
23
|
html_options = label_html_options.dup
|
|
20
|
-
html_options[:class]
|
|
24
|
+
html_options[:class] ||= []
|
|
25
|
+
html_options[:class].push(boolean_label_class) if boolean_label_class
|
|
26
|
+
|
|
27
|
+
merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
|
|
21
28
|
|
|
22
29
|
build_hidden_field_for_checkbox +
|
|
23
30
|
@builder.label(label_target, html_options) {
|
|
24
|
-
build_check_box_without_hidden_field + label_text
|
|
31
|
+
build_check_box_without_hidden_field(merged_input_options) + label_text
|
|
25
32
|
}
|
|
26
33
|
else
|
|
27
|
-
input + label
|
|
34
|
+
input(wrapper_options) + label(wrapper_options)
|
|
28
35
|
end
|
|
29
36
|
end
|
|
30
37
|
|
|
31
38
|
private
|
|
32
39
|
|
|
40
|
+
def boolean_label_class
|
|
41
|
+
options[:boolean_label_class] || SimpleForm.boolean_label_class
|
|
42
|
+
end
|
|
43
|
+
|
|
33
44
|
# Build a checkbox tag using default unchecked value. This allows us to
|
|
34
45
|
# reuse the method for nested boolean style, but with no unchecked value,
|
|
35
46
|
# which won't generate the hidden checkbox. This is the default functionality
|
|
36
47
|
# 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,
|
|
48
|
+
def build_check_box(unchecked_value, options)
|
|
49
|
+
@builder.check_box(attribute_name, options, checked_value, unchecked_value)
|
|
39
50
|
end
|
|
40
51
|
|
|
41
52
|
# Build a checkbox without generating the hidden field. See
|
|
42
53
|
# #build_hidden_field_for_checkbox for more info.
|
|
43
|
-
def build_check_box_without_hidden_field
|
|
44
|
-
build_check_box(nil)
|
|
54
|
+
def build_check_box_without_hidden_field(options)
|
|
55
|
+
build_check_box(nil, options)
|
|
45
56
|
end
|
|
46
57
|
|
|
47
58
|
# Create a hidden field for the current checkbox, so we can simulate Rails
|
|
@@ -49,8 +60,24 @@ module SimpleForm
|
|
|
49
60
|
# we need the hidden field to be *outside* the label (otherwise it
|
|
50
61
|
# generates invalid html - html5 only).
|
|
51
62
|
def build_hidden_field_for_checkbox
|
|
52
|
-
|
|
53
|
-
|
|
63
|
+
return "" if !include_hidden? || !unchecked_value
|
|
64
|
+
options = { value: unchecked_value, id: nil, disabled: input_html_options[:disabled] }
|
|
65
|
+
options[:name] = input_html_options[:name] if input_html_options.key?(:name)
|
|
66
|
+
|
|
67
|
+
@builder.hidden_field(attribute_name, options)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def inline_label?
|
|
71
|
+
nested_boolean_style? && options[:inline_label]
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def inline_label
|
|
75
|
+
inline_option = options[:inline_label]
|
|
76
|
+
|
|
77
|
+
if inline_option
|
|
78
|
+
label = inline_option == true ? label_text : html_escape(inline_option)
|
|
79
|
+
" #{label}".html_safe
|
|
80
|
+
end
|
|
54
81
|
end
|
|
55
82
|
|
|
56
83
|
# Booleans are not required by default because in most of the cases
|
|
@@ -59,6 +86,18 @@ module SimpleForm
|
|
|
59
86
|
def required_by_default?
|
|
60
87
|
false
|
|
61
88
|
end
|
|
89
|
+
|
|
90
|
+
def include_hidden?
|
|
91
|
+
options.fetch(:include_hidden, true)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def checked_value
|
|
95
|
+
options.fetch(:checked_value, '1')
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def unchecked_value
|
|
99
|
+
options.fetch(:unchecked_value, '0')
|
|
100
|
+
end
|
|
62
101
|
end
|
|
63
102
|
end
|
|
64
103
|
end
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module SimpleForm
|
|
2
3
|
module Inputs
|
|
3
4
|
class CollectionCheckBoxesInput < CollectionRadioButtonsInput
|
|
@@ -10,7 +11,7 @@ module SimpleForm
|
|
|
10
11
|
end
|
|
11
12
|
|
|
12
13
|
def build_nested_boolean_style_item_tag(collection_builder)
|
|
13
|
-
collection_builder.check_box + collection_builder.text
|
|
14
|
+
collection_builder.check_box + collection_builder.text.to_s
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
def item_wrapper_class
|
|
@@ -1,25 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module SimpleForm
|
|
2
3
|
module Inputs
|
|
3
4
|
class CollectionInput < Base
|
|
5
|
+
BASIC_OBJECT_CLASSES = [String, Integer, Float, NilClass, Symbol, TrueClass, FalseClass]
|
|
6
|
+
BASIC_OBJECT_CLASSES.push(Fixnum, Bignum) unless 1.class == Integer
|
|
7
|
+
|
|
4
8
|
# Default boolean collection for use with selects/radios when no
|
|
5
9
|
# collection is given. Always fallback to this boolean collection.
|
|
6
10
|
# Texts can be translated using i18n in "simple_form.yes" and
|
|
7
11
|
# "simple_form.no" keys. See the example locale file.
|
|
8
12
|
def self.boolean_collection
|
|
9
13
|
i18n_cache :boolean_collection do
|
|
10
|
-
[ [I18n.t(:"simple_form.yes", :
|
|
11
|
-
[I18n.t(:"simple_form.no", :
|
|
14
|
+
[ [I18n.t(:"simple_form.yes", default: 'Yes'), true],
|
|
15
|
+
[I18n.t(:"simple_form.no", default: 'No'), false] ]
|
|
12
16
|
end
|
|
13
17
|
end
|
|
14
18
|
|
|
15
|
-
def input
|
|
19
|
+
def input(wrapper_options = nil)
|
|
16
20
|
raise NotImplementedError,
|
|
17
21
|
"input should be implemented by classes inheriting from CollectionInput"
|
|
18
22
|
end
|
|
19
23
|
|
|
20
24
|
def input_options
|
|
21
25
|
options = super
|
|
26
|
+
|
|
22
27
|
options[:include_blank] = true unless skip_include_blank?
|
|
28
|
+
translate_option options, :prompt
|
|
29
|
+
translate_option options, :include_blank
|
|
30
|
+
|
|
23
31
|
options
|
|
24
32
|
end
|
|
25
33
|
|
|
@@ -33,12 +41,12 @@ module SimpleForm
|
|
|
33
41
|
end
|
|
34
42
|
|
|
35
43
|
def has_required?
|
|
36
|
-
super && (input_options[:include_blank] || multiple?)
|
|
44
|
+
super && (input_options[:include_blank] || input_options[:prompt] || multiple?)
|
|
37
45
|
end
|
|
38
46
|
|
|
39
47
|
# Check if :include_blank must be included by default.
|
|
40
48
|
def skip_include_blank?
|
|
41
|
-
(options.keys & [
|
|
49
|
+
(options.keys & %i[prompt include_blank default selected]).any? || multiple?
|
|
42
50
|
end
|
|
43
51
|
|
|
44
52
|
def multiple?
|
|
@@ -66,36 +74,51 @@ module SimpleForm
|
|
|
66
74
|
collection_translated = translate_collection if collection_classes == [Symbol]
|
|
67
75
|
|
|
68
76
|
if collection_translated || collection_classes.include?(Array)
|
|
69
|
-
{ :
|
|
77
|
+
{ label: :first, value: :second }
|
|
70
78
|
elsif collection_includes_basic_objects?(collection_classes)
|
|
71
|
-
{ :
|
|
79
|
+
{ label: :to_s, value: :to_s }
|
|
72
80
|
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) } }
|
|
81
|
+
detect_method_from_class(collection_classes)
|
|
77
82
|
end
|
|
78
83
|
end
|
|
79
84
|
|
|
85
|
+
def detect_method_from_class(collection_classes)
|
|
86
|
+
sample = collection.first || collection.last
|
|
87
|
+
|
|
88
|
+
{ label: SimpleForm.collection_label_methods.find { |m| sample.respond_to?(m) },
|
|
89
|
+
value: SimpleForm.collection_value_methods.find { |m| sample.respond_to?(m) } }
|
|
90
|
+
end
|
|
91
|
+
|
|
80
92
|
def detect_collection_classes(some_collection = collection)
|
|
81
|
-
some_collection.map
|
|
93
|
+
some_collection.map(&:class).uniq
|
|
82
94
|
end
|
|
83
95
|
|
|
84
96
|
def collection_includes_basic_objects?(collection_classes)
|
|
85
|
-
(collection_classes &
|
|
86
|
-
String, Integer, Fixnum, Bignum, Float, NilClass, Symbol, TrueClass, FalseClass
|
|
87
|
-
]).any?
|
|
97
|
+
(collection_classes & BASIC_OBJECT_CLASSES).any?
|
|
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,47 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module SimpleForm
|
|
2
3
|
module Inputs
|
|
3
4
|
class CollectionRadioButtonsInput < CollectionInput
|
|
4
|
-
def input
|
|
5
|
+
def input(wrapper_options = nil)
|
|
5
6
|
label_method, value_method = detect_collection_methods
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
|
|
9
|
+
|
|
10
|
+
@builder.send(:"collection_#{input_type}",
|
|
8
11
|
attribute_name, collection, value_method, label_method,
|
|
9
|
-
input_options,
|
|
12
|
+
input_options, merged_input_options,
|
|
13
|
+
&collection_block_for_nested_boolean_style
|
|
10
14
|
)
|
|
11
15
|
end
|
|
12
16
|
|
|
13
17
|
def input_options
|
|
14
18
|
options = super
|
|
15
19
|
apply_default_collection_options!(options)
|
|
16
|
-
apply_nested_boolean_collection_options!(options) if nested_boolean_style?
|
|
17
20
|
options
|
|
18
21
|
end
|
|
19
22
|
|
|
20
23
|
protected
|
|
21
24
|
|
|
22
25
|
def apply_default_collection_options!(options)
|
|
23
|
-
|
|
24
|
-
options[:item_wrapper_tag] = SimpleForm.item_wrapper_tag
|
|
25
|
-
end
|
|
26
|
+
options[:item_wrapper_tag] ||= options.fetch(:item_wrapper_tag, SimpleForm.item_wrapper_tag)
|
|
26
27
|
options[:item_wrapper_class] = [
|
|
27
28
|
item_wrapper_class, options[:item_wrapper_class], SimpleForm.item_wrapper_class
|
|
28
|
-
].compact.presence
|
|
29
|
+
].compact.presence if SimpleForm.include_default_input_wrapper_class
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
options[:collection_wrapper_tag] = SimpleForm.collection_wrapper_tag
|
|
32
|
-
end
|
|
31
|
+
options[:collection_wrapper_tag] ||= options.fetch(:collection_wrapper_tag, SimpleForm.collection_wrapper_tag)
|
|
33
32
|
options[:collection_wrapper_class] = [
|
|
34
33
|
options[:collection_wrapper_class], SimpleForm.collection_wrapper_class
|
|
35
34
|
].compact.presence
|
|
36
35
|
end
|
|
37
36
|
|
|
38
|
-
# Force item wrapper to be a label when using nested boolean, to support
|
|
39
|
-
# configuring classes through :item_wrapper_class, and to maintain
|
|
40
|
-
# compatibility with :inline style and default :item_wrapper_tag.
|
|
41
|
-
def apply_nested_boolean_collection_options!(options)
|
|
42
|
-
options[:item_wrapper_tag] = :label
|
|
43
|
-
end
|
|
44
|
-
|
|
45
37
|
def collection_block_for_nested_boolean_style
|
|
46
38
|
return unless nested_boolean_style?
|
|
47
39
|
|
|
@@ -49,7 +41,7 @@ module SimpleForm
|
|
|
49
41
|
end
|
|
50
42
|
|
|
51
43
|
def build_nested_boolean_style_item_tag(collection_builder)
|
|
52
|
-
collection_builder.radio_button + collection_builder.text
|
|
44
|
+
collection_builder.radio_button + collection_builder.text.to_s
|
|
53
45
|
end
|
|
54
46
|
|
|
55
47
|
def item_wrapper_class
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module SimpleForm
|
|
2
3
|
module Inputs
|
|
3
4
|
class CollectionSelectInput < CollectionInput
|
|
4
|
-
def input
|
|
5
|
+
def input(wrapper_options = nil)
|
|
5
6
|
label_method, value_method = detect_collection_methods
|
|
6
7
|
|
|
8
|
+
merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
|
|
9
|
+
|
|
7
10
|
@builder.collection_select(
|
|
8
11
|
attribute_name, collection, value_method, label_method,
|
|
9
|
-
input_options,
|
|
12
|
+
input_options, merged_input_options
|
|
10
13
|
)
|
|
11
14
|
end
|
|
12
15
|
end
|
|
@@ -1,27 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module SimpleForm
|
|
2
3
|
module Inputs
|
|
3
4
|
class DateTimeInput < Base
|
|
4
|
-
def input
|
|
5
|
-
|
|
6
|
-
end
|
|
5
|
+
def input(wrapper_options = nil)
|
|
6
|
+
merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
if use_html5_inputs?
|
|
9
|
+
@builder.send(:"#{input_type}_field", attribute_name, merged_input_options)
|
|
10
|
+
else
|
|
11
|
+
@builder.send(:"#{input_type}_select", attribute_name, input_options, merged_input_options)
|
|
12
|
+
end
|
|
10
13
|
end
|
|
11
14
|
|
|
12
15
|
private
|
|
13
16
|
|
|
14
17
|
def label_target
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
date_order = input_options[:order] || I18n.t('date.order')
|
|
18
|
-
date_order.first
|
|
18
|
+
if use_html5_inputs?
|
|
19
|
+
attribute_name
|
|
19
20
|
else
|
|
20
|
-
|
|
21
|
+
position = case input_type
|
|
22
|
+
when :date, :datetime
|
|
23
|
+
date_order = input_options[:order] || I18n.t('date.order')
|
|
24
|
+
date_order.first.to_sym
|
|
25
|
+
else
|
|
26
|
+
:hour
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
position = ActionView::Helpers::DateTimeSelector::POSITION[position]
|
|
30
|
+
"#{attribute_name}_#{position}i"
|
|
21
31
|
end
|
|
32
|
+
end
|
|
22
33
|
|
|
23
|
-
|
|
24
|
-
|
|
34
|
+
def use_html5_inputs?
|
|
35
|
+
input_options[:html5]
|
|
25
36
|
end
|
|
26
37
|
end
|
|
27
38
|
end
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module SimpleForm
|
|
2
3
|
module Inputs
|
|
3
4
|
class FileInput < Base
|
|
4
|
-
def input
|
|
5
|
-
|
|
5
|
+
def input(wrapper_options = nil)
|
|
6
|
+
merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
|
|
7
|
+
|
|
8
|
+
@builder.file_field(attribute_name, merged_input_options)
|
|
6
9
|
end
|
|
7
10
|
end
|
|
8
11
|
end
|