simple_form 3.0.1 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +149 -25
- data/MIT-LICENSE +1 -1
- data/README.md +441 -107
- data/lib/generators/simple_form/install_generator.rb +4 -3
- data/lib/generators/simple_form/templates/README +4 -5
- data/lib/generators/simple_form/templates/_form.html.erb +2 -0
- data/lib/generators/simple_form/templates/_form.html.haml +2 -0
- data/lib/generators/simple_form/templates/_form.html.slim +1 -0
- data/lib/generators/simple_form/templates/config/initializers/simple_form.rb +48 -11
- data/lib/generators/simple_form/templates/config/initializers/simple_form_bootstrap.rb +417 -23
- data/lib/generators/simple_form/templates/config/initializers/simple_form_foundation.rb +101 -5
- data/lib/generators/simple_form/templates/config/locales/simple_form.en.yml +7 -2
- data/lib/simple_form/action_view_extensions/builder.rb +2 -0
- data/lib/simple_form/action_view_extensions/form_helper.rb +10 -3
- data/lib/simple_form/components/errors.rb +38 -3
- data/lib/simple_form/components/hints.rb +3 -2
- data/lib/simple_form/components/html5.rb +16 -5
- data/lib/simple_form/components/label_input.rb +21 -2
- data/lib/simple_form/components/labels.rb +22 -11
- data/lib/simple_form/components/maxlength.rb +9 -5
- data/lib/simple_form/components/min_max.rb +2 -1
- data/lib/simple_form/components/minlength.rb +38 -0
- data/lib/simple_form/components/pattern.rb +2 -1
- data/lib/simple_form/components/placeholders.rb +4 -3
- data/lib/simple_form/components/readonly.rb +2 -1
- data/lib/simple_form/components.rb +2 -0
- data/lib/simple_form/error_notification.rb +1 -0
- data/lib/simple_form/form_builder.rb +193 -80
- 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 +2 -1
- data/lib/simple_form/helpers.rb +6 -5
- data/lib/simple_form/i18n_cache.rb +1 -0
- data/lib/simple_form/inputs/base.rb +57 -14
- data/lib/simple_form/inputs/block_input.rb +2 -1
- data/lib/simple_form/inputs/boolean_input.rb +39 -16
- data/lib/simple_form/inputs/collection_check_boxes_input.rb +2 -1
- data/lib/simple_form/inputs/collection_input.rb +37 -14
- data/lib/simple_form/inputs/collection_radio_buttons_input.rb +9 -13
- data/lib/simple_form/inputs/collection_select_input.rb +5 -2
- data/lib/simple_form/inputs/date_time_input.rb +24 -9
- 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 +6 -4
- data/lib/simple_form/inputs/password_input.rb +6 -3
- 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 -3
- data/lib/simple_form/inputs/text_input.rb +6 -3
- data/lib/simple_form/inputs.rb +1 -0
- data/lib/simple_form/map_type.rb +1 -0
- data/lib/simple_form/railtie.rb +8 -0
- data/lib/simple_form/tags.rb +7 -0
- data/lib/simple_form/version.rb +2 -1
- data/lib/simple_form/wrappers/builder.rb +7 -6
- data/lib/simple_form/wrappers/leaf.rb +29 -0
- data/lib/simple_form/wrappers/many.rb +7 -6
- data/lib/simple_form/wrappers/root.rb +3 -1
- data/lib/simple_form/wrappers/single.rb +7 -4
- data/lib/simple_form/wrappers.rb +2 -0
- data/lib/simple_form.rb +117 -18
- data/test/action_view_extensions/builder_test.rb +42 -41
- data/test/action_view_extensions/form_helper_test.rb +36 -16
- data/test/components/custom_components_test.rb +62 -0
- data/test/components/label_test.rb +70 -41
- data/test/form_builder/association_test.rb +79 -37
- data/test/form_builder/button_test.rb +11 -10
- data/test/form_builder/error_notification_test.rb +2 -1
- data/test/form_builder/error_test.rb +173 -24
- data/test/form_builder/general_test.rb +171 -73
- data/test/form_builder/hint_test.rb +24 -18
- data/test/form_builder/input_field_test.rb +132 -56
- data/test/form_builder/label_test.rb +68 -13
- data/test/form_builder/wrapper_test.rb +190 -22
- data/test/generators/simple_form_generator_test.rb +8 -7
- data/test/inputs/boolean_input_test.rb +89 -6
- data/test/inputs/collection_check_boxes_input_test.rb +109 -25
- data/test/inputs/collection_radio_buttons_input_test.rb +168 -54
- data/test/inputs/collection_select_input_test.rb +183 -77
- data/test/inputs/datetime_input_test.rb +131 -50
- data/test/inputs/disabled_test.rb +16 -15
- data/test/inputs/discovery_test.rb +58 -6
- data/test/inputs/file_input_test.rb +3 -2
- data/test/inputs/general_test.rb +23 -22
- data/test/inputs/grouped_collection_select_input_test.rb +54 -17
- data/test/inputs/hidden_input_test.rb +5 -4
- data/test/inputs/numeric_input_test.rb +48 -44
- data/test/inputs/priority_input_test.rb +23 -14
- data/test/inputs/readonly_test.rb +20 -19
- data/test/inputs/required_test.rb +58 -13
- data/test/inputs/string_input_test.rb +62 -33
- data/test/inputs/text_input_test.rb +20 -7
- data/test/simple_form_test.rb +9 -0
- data/test/support/discovery_inputs.rb +33 -2
- data/test/support/misc_helpers.rb +113 -5
- data/test/support/mock_controller.rb +7 -1
- data/test/support/models.rb +137 -37
- data/test/test_helper.rb +15 -1
- metadata +25 -33
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module SimpleForm
|
|
2
3
|
module Wrappers
|
|
3
4
|
# A wrapper is an object that holds several components and render them.
|
|
4
|
-
# A component may
|
|
5
|
+
# A component may be any object that responds to `render`.
|
|
5
6
|
# This API allows inputs/components to be easily wrapped, removing the
|
|
6
7
|
# need to modify the code only to wrap input in an extra tag.
|
|
7
8
|
#
|
|
@@ -10,9 +11,8 @@ module SimpleForm
|
|
|
10
11
|
# on demand on input generation.
|
|
11
12
|
class Many
|
|
12
13
|
attr_reader :namespace, :defaults, :components
|
|
13
|
-
alias :to_sym :namespace
|
|
14
14
|
|
|
15
|
-
def initialize(namespace, components, defaults={})
|
|
15
|
+
def initialize(namespace, components, defaults = {})
|
|
16
16
|
@namespace = namespace
|
|
17
17
|
@components = components
|
|
18
18
|
@defaults = defaults
|
|
@@ -25,8 +25,8 @@ module SimpleForm
|
|
|
25
25
|
options = input.options
|
|
26
26
|
|
|
27
27
|
components.each do |component|
|
|
28
|
-
next if options[component] == false
|
|
29
|
-
rendered = component.
|
|
28
|
+
next if options[component.namespace] == false
|
|
29
|
+
rendered = component.render(input)
|
|
30
30
|
content.safe_concat rendered.to_s if rendered
|
|
31
31
|
end
|
|
32
32
|
|
|
@@ -51,6 +51,7 @@ module SimpleForm
|
|
|
51
51
|
|
|
52
52
|
def wrap(input, options, content)
|
|
53
53
|
return content if options[namespace] == false
|
|
54
|
+
return if defaults[:unless_blank] && content.empty?
|
|
54
55
|
|
|
55
56
|
tag = (namespace && options[:"#{namespace}_tag"]) || @defaults[:tag]
|
|
56
57
|
return content unless tag
|
|
@@ -62,7 +63,7 @@ module SimpleForm
|
|
|
62
63
|
end
|
|
63
64
|
|
|
64
65
|
def html_options(options)
|
|
65
|
-
options[:"#{namespace}_html"] || {}
|
|
66
|
+
(@defaults[:html] || {}).merge(options[:"#{namespace}_html"] || {})
|
|
66
67
|
end
|
|
67
68
|
|
|
68
69
|
def html_classes(input, options)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module SimpleForm
|
|
2
3
|
module Wrappers
|
|
3
4
|
# `Root` is the root wrapper for all components. It is special cased to
|
|
@@ -17,7 +18,7 @@ module SimpleForm
|
|
|
17
18
|
|
|
18
19
|
# Provide a fallback if name cannot be found.
|
|
19
20
|
def find(name)
|
|
20
|
-
super || SimpleForm::Wrappers::Many.new(name, [name])
|
|
21
|
+
super || SimpleForm::Wrappers::Many.new(name, [Leaf.new(name)])
|
|
21
22
|
end
|
|
22
23
|
|
|
23
24
|
private
|
|
@@ -29,6 +30,7 @@ module SimpleForm
|
|
|
29
30
|
end
|
|
30
31
|
css << (options[:wrapper_error_class] || @defaults[:error_class]) if input.has_errors?
|
|
31
32
|
css << (options[:wrapper_hint_class] || @defaults[:hint_class]) if input.has_hint?
|
|
33
|
+
css << (options[:wrapper_valid_class] || @defaults[:valid_class]) if input.valid?
|
|
32
34
|
css.compact
|
|
33
35
|
end
|
|
34
36
|
end
|
|
@@ -1,15 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module SimpleForm
|
|
2
3
|
module Wrappers
|
|
3
4
|
# `Single` is an optimization for a wrapper that has only one component.
|
|
4
5
|
class Single < Many
|
|
5
|
-
def initialize(name, options={})
|
|
6
|
-
|
|
6
|
+
def initialize(name, wrapper_options = {}, options = {})
|
|
7
|
+
@component = Leaf.new(name, options)
|
|
8
|
+
|
|
9
|
+
super(name, [@component], wrapper_options)
|
|
7
10
|
end
|
|
8
11
|
|
|
9
12
|
def render(input)
|
|
10
13
|
options = input.options
|
|
11
14
|
if options[namespace] != false
|
|
12
|
-
content =
|
|
15
|
+
content = @component.render(input)
|
|
13
16
|
wrap(input, options, content) if content
|
|
14
17
|
end
|
|
15
18
|
end
|
|
@@ -17,7 +20,7 @@ module SimpleForm
|
|
|
17
20
|
private
|
|
18
21
|
|
|
19
22
|
def html_options(options)
|
|
20
|
-
[
|
|
23
|
+
%i[label input].include?(namespace) ? {} : super
|
|
21
24
|
end
|
|
22
25
|
end
|
|
23
26
|
end
|
data/lib/simple_form/wrappers.rb
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module SimpleForm
|
|
2
3
|
module Wrappers
|
|
3
4
|
autoload :Builder, 'simple_form/wrappers/builder'
|
|
4
5
|
autoload :Many, 'simple_form/wrappers/many'
|
|
5
6
|
autoload :Root, 'simple_form/wrappers/root'
|
|
6
7
|
autoload :Single, 'simple_form/wrappers/single'
|
|
8
|
+
autoload :Leaf, 'simple_form/wrappers/leaf'
|
|
7
9
|
end
|
|
8
10
|
end
|
data/lib/simple_form.rb
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
require 'action_view'
|
|
3
|
+
require 'action_pack'
|
|
2
4
|
require 'simple_form/action_view_extensions/form_helper'
|
|
3
5
|
require 'simple_form/action_view_extensions/builder'
|
|
4
6
|
require 'active_support/core_ext/hash/slice'
|
|
@@ -24,6 +26,24 @@ module SimpleForm
|
|
|
24
26
|
SimpleForm::Components.eager_load!
|
|
25
27
|
end
|
|
26
28
|
|
|
29
|
+
CUSTOM_INPUT_DEPRECATION_WARN = <<-WARN
|
|
30
|
+
%{name} method now accepts a `wrapper_options` argument. The method definition without the argument is deprecated and will be removed in the next Simple Form version. Change your code from:
|
|
31
|
+
|
|
32
|
+
def %{name}
|
|
33
|
+
|
|
34
|
+
to
|
|
35
|
+
|
|
36
|
+
def %{name}(wrapper_options)
|
|
37
|
+
|
|
38
|
+
See https://github.com/plataformatec/simple_form/pull/997 for more information.
|
|
39
|
+
WARN
|
|
40
|
+
|
|
41
|
+
@@configured = false
|
|
42
|
+
|
|
43
|
+
def self.configured? #:nodoc:
|
|
44
|
+
@@configured
|
|
45
|
+
end
|
|
46
|
+
|
|
27
47
|
## CONFIGURATION OPTIONS
|
|
28
48
|
|
|
29
49
|
# Method used to tidy up errors.
|
|
@@ -40,11 +60,11 @@ module SimpleForm
|
|
|
40
60
|
|
|
41
61
|
# Series of attemps to detect a default label method for collection.
|
|
42
62
|
mattr_accessor :collection_label_methods
|
|
43
|
-
@@collection_label_methods = [
|
|
63
|
+
@@collection_label_methods = %i[to_label name title to_s]
|
|
44
64
|
|
|
45
65
|
# Series of attemps to detect a default value method for collection.
|
|
46
66
|
mattr_accessor :collection_value_methods
|
|
47
|
-
@@collection_value_methods = [
|
|
67
|
+
@@collection_value_methods = %i[id to_s]
|
|
48
68
|
|
|
49
69
|
# You can wrap a collection of radio/check boxes in a pre-defined tag, defaulting to none.
|
|
50
70
|
mattr_accessor :collection_wrapper_tag
|
|
@@ -66,7 +86,7 @@ module SimpleForm
|
|
|
66
86
|
|
|
67
87
|
# How the label text should be generated altogether with the required text.
|
|
68
88
|
mattr_accessor :label_text
|
|
69
|
-
@@label_text =
|
|
89
|
+
@@label_text = ->(label, required, explicit_label) { "#{required} #{label}" }
|
|
70
90
|
|
|
71
91
|
# You can define the class to be used on all labels. Defaults to none.
|
|
72
92
|
mattr_accessor :label_class
|
|
@@ -78,13 +98,19 @@ module SimpleForm
|
|
|
78
98
|
mattr_accessor :boolean_style
|
|
79
99
|
@@boolean_style = :inline
|
|
80
100
|
|
|
81
|
-
# You can define the class to be used on all forms. Default is
|
|
82
|
-
|
|
101
|
+
# DEPRECATED: You can define the class to be used on all forms. Default is
|
|
102
|
+
# simple_form.
|
|
103
|
+
mattr_reader :form_class
|
|
83
104
|
@@form_class = :simple_form
|
|
84
105
|
|
|
106
|
+
# You can define the default class to be used on all forms. Can be overriden
|
|
107
|
+
# with `html: { :class }`. Defaults to none.
|
|
108
|
+
mattr_accessor :default_form_class
|
|
109
|
+
@@default_form_class = nil
|
|
110
|
+
|
|
85
111
|
# You can define which elements should obtain additional classes.
|
|
86
112
|
mattr_accessor :generate_additional_classes_for
|
|
87
|
-
@@generate_additional_classes_for = [
|
|
113
|
+
@@generate_additional_classes_for = %i[wrapper label input]
|
|
88
114
|
|
|
89
115
|
# Whether attributes are required by default or not.
|
|
90
116
|
mattr_accessor :required_by_default
|
|
@@ -96,7 +122,7 @@ module SimpleForm
|
|
|
96
122
|
|
|
97
123
|
# Collection of methods to detect if a file type was given.
|
|
98
124
|
mattr_accessor :file_methods
|
|
99
|
-
@@file_methods = [
|
|
125
|
+
@@file_methods = %i[mounted_as file? public_filename attached?]
|
|
100
126
|
|
|
101
127
|
# Custom mappings for input types. This should be a hash containing a regexp
|
|
102
128
|
# to match as key, and the input type that will be used when the field name
|
|
@@ -107,9 +133,19 @@ module SimpleForm
|
|
|
107
133
|
# Custom wrappers for input types. This should be a hash containing an input
|
|
108
134
|
# type as key and the wrapper that will be used for all inputs with specified type.
|
|
109
135
|
# e.g { string: :string_wrapper, boolean: :boolean_wrapper }
|
|
136
|
+
# You can also set a wrapper mapping per form basis.
|
|
137
|
+
# e.g simple_form_for(@foo, wrapper_mappings: { check_boxes: :bootstrap_checkbox })
|
|
110
138
|
mattr_accessor :wrapper_mappings
|
|
111
139
|
@@wrapper_mappings = nil
|
|
112
140
|
|
|
141
|
+
# Namespaces where SimpleForm should look for custom input classes that override
|
|
142
|
+
# default inputs. Namespaces are given as string to allow lazy loading inputs.
|
|
143
|
+
# e.g. config.custom_inputs_namespaces << "CustomInputs"
|
|
144
|
+
# will try to find CustomInputs::NumericInput when an :integer
|
|
145
|
+
# field is called.
|
|
146
|
+
mattr_accessor :custom_inputs_namespaces
|
|
147
|
+
@@custom_inputs_namespaces = []
|
|
148
|
+
|
|
113
149
|
# Default priority for time_zone inputs.
|
|
114
150
|
mattr_accessor :time_zone_priority
|
|
115
151
|
@@time_zone_priority = nil
|
|
@@ -118,10 +154,6 @@ module SimpleForm
|
|
|
118
154
|
mattr_accessor :country_priority
|
|
119
155
|
@@country_priority = nil
|
|
120
156
|
|
|
121
|
-
# DEPRECATED: Maximum size allowed for inputs.
|
|
122
|
-
mattr_accessor :default_input_size
|
|
123
|
-
@@default_input_size = nil
|
|
124
|
-
|
|
125
157
|
# When off, do not use translations in labels. Disabling translation in
|
|
126
158
|
# hints and placeholders can be done manually in the wrapper API.
|
|
127
159
|
mattr_accessor :translate_labels
|
|
@@ -133,7 +165,7 @@ module SimpleForm
|
|
|
133
165
|
|
|
134
166
|
# Cache SimpleForm inputs discovery.
|
|
135
167
|
mattr_accessor :cache_discovery
|
|
136
|
-
@@cache_discovery = defined?(Rails) && !Rails.env.development?
|
|
168
|
+
@@cache_discovery = defined?(Rails.env) && !Rails.env.development?
|
|
137
169
|
|
|
138
170
|
# Adds a class to each generated button, mostly for compatiblity.
|
|
139
171
|
mattr_accessor :button_class
|
|
@@ -151,15 +183,32 @@ module SimpleForm
|
|
|
151
183
|
mattr_accessor :input_class
|
|
152
184
|
@@input_class = nil
|
|
153
185
|
|
|
186
|
+
# Defines if an input wrapper class should be included or not
|
|
187
|
+
mattr_accessor :include_default_input_wrapper_class
|
|
188
|
+
@@include_default_input_wrapper_class = true
|
|
189
|
+
|
|
190
|
+
# Define the default class of the input wrapper of the boolean input.
|
|
191
|
+
mattr_accessor :boolean_label_class
|
|
192
|
+
@@boolean_label_class = 'checkbox'
|
|
193
|
+
|
|
154
194
|
## WRAPPER CONFIGURATION
|
|
155
195
|
# The default wrapper to be used by the FormBuilder.
|
|
156
196
|
mattr_accessor :default_wrapper
|
|
157
197
|
@@default_wrapper = :default
|
|
158
|
-
@@wrappers = {}
|
|
198
|
+
@@wrappers = {} #:nodoc:
|
|
199
|
+
|
|
200
|
+
mattr_accessor :i18n_scope
|
|
201
|
+
@@i18n_scope = 'simple_form'
|
|
202
|
+
|
|
203
|
+
mattr_accessor :input_field_error_class
|
|
204
|
+
@@input_field_error_class = nil
|
|
205
|
+
|
|
206
|
+
mattr_accessor :input_field_valid_class
|
|
207
|
+
@@input_field_valid_class = nil
|
|
159
208
|
|
|
160
209
|
# Retrieves a given wrapper
|
|
161
210
|
def self.wrapper(name)
|
|
162
|
-
@@wrappers[name.
|
|
211
|
+
@@wrappers[name.to_s] or raise WrapperNotFound, "Couldn't find wrapper with name #{name}"
|
|
163
212
|
end
|
|
164
213
|
|
|
165
214
|
# Raised when fails to find a given wrapper name
|
|
@@ -172,25 +221,26 @@ module SimpleForm
|
|
|
172
221
|
if block_given?
|
|
173
222
|
options = args.extract_options!
|
|
174
223
|
name = args.first || :default
|
|
175
|
-
@@wrappers[name.
|
|
224
|
+
@@wrappers[name.to_s] = build(options, &block)
|
|
176
225
|
else
|
|
177
226
|
@@wrappers
|
|
178
227
|
end
|
|
179
228
|
end
|
|
180
229
|
|
|
181
230
|
# Builds a new wrapper using SimpleForm::Wrappers::Builder.
|
|
182
|
-
def self.build(options={})
|
|
231
|
+
def self.build(options = {})
|
|
183
232
|
options[:tag] = :div if options[:tag].nil?
|
|
184
233
|
builder = SimpleForm::Wrappers::Builder.new(options)
|
|
185
234
|
yield builder
|
|
186
235
|
SimpleForm::Wrappers::Root.new(builder.to_a, options)
|
|
187
236
|
end
|
|
188
237
|
|
|
189
|
-
wrappers class: :input, hint_class: :field_with_hint, error_class: :field_with_errors do |b|
|
|
238
|
+
wrappers class: :input, hint_class: :field_with_hint, error_class: :field_with_errors, valid_class: :field_without_errors do |b|
|
|
190
239
|
b.use :html5
|
|
191
240
|
|
|
192
241
|
b.use :min_max
|
|
193
242
|
b.use :maxlength
|
|
243
|
+
b.use :minlength
|
|
194
244
|
b.use :placeholder
|
|
195
245
|
b.optional :pattern
|
|
196
246
|
b.optional :readonly
|
|
@@ -210,11 +260,60 @@ module SimpleForm
|
|
|
210
260
|
ActiveSupport::Deprecation.warn "[SIMPLE_FORM] SimpleForm.default_input_size= is deprecated and has no effect", caller
|
|
211
261
|
end
|
|
212
262
|
|
|
213
|
-
|
|
263
|
+
def self.form_class=(value)
|
|
264
|
+
ActiveSupport::Deprecation.warn "[SIMPLE_FORM] SimpleForm.form_class= is deprecated and will be removed in 4.x. Use SimpleForm.default_form_class= instead", caller
|
|
265
|
+
@@form_class = value
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
# Default way to setup Simple Form. Run rails generate simple_form:install
|
|
214
269
|
# to create a fresh initializer with all configuration values.
|
|
215
270
|
def self.setup
|
|
271
|
+
@@configured = true
|
|
216
272
|
yield self
|
|
217
273
|
end
|
|
274
|
+
|
|
275
|
+
# Includes a component to be used by Simple Form. Methods defined in a
|
|
276
|
+
# component will be exposed to be used in the wrapper as Simple::Components
|
|
277
|
+
#
|
|
278
|
+
# Examples
|
|
279
|
+
#
|
|
280
|
+
# # The application needs to tell where the components will be.
|
|
281
|
+
# Dir[Rails.root.join('lib/components/**/*.rb')].each { |f| require f }
|
|
282
|
+
#
|
|
283
|
+
# # Create a custom component in the path specified above.
|
|
284
|
+
# # lib/components/input_group_component.rb
|
|
285
|
+
# module InputGroupComponent
|
|
286
|
+
# def prepend
|
|
287
|
+
# ...
|
|
288
|
+
# end
|
|
289
|
+
#
|
|
290
|
+
# def append
|
|
291
|
+
# ...
|
|
292
|
+
# end
|
|
293
|
+
# end
|
|
294
|
+
#
|
|
295
|
+
# SimpleForm.setup do |config|
|
|
296
|
+
# # Create a wrapper using the custom component.
|
|
297
|
+
# config.wrappers :input_group, tag: :div, error_class: :error do |b|
|
|
298
|
+
# b.use :label
|
|
299
|
+
# b.optional :prepend
|
|
300
|
+
# b.use :input
|
|
301
|
+
# b.use :append
|
|
302
|
+
# end
|
|
303
|
+
# end
|
|
304
|
+
#
|
|
305
|
+
# # Using the custom component in the form.
|
|
306
|
+
# <%= simple_form_for @blog, wrapper: input_group do |f| %>
|
|
307
|
+
# <%= f.input :title, prepend: true %>
|
|
308
|
+
# <% end %>
|
|
309
|
+
#
|
|
310
|
+
def self.include_component(component)
|
|
311
|
+
if Module === component
|
|
312
|
+
SimpleForm::Inputs::Base.include(component)
|
|
313
|
+
else
|
|
314
|
+
raise TypeError, "SimpleForm.include_component expects a module but got: #{component.class}"
|
|
315
|
+
end
|
|
316
|
+
end
|
|
218
317
|
end
|
|
219
318
|
|
|
220
319
|
require 'simple_form/railtie' if defined?(Rails)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
require 'test_helper'
|
|
2
3
|
|
|
3
4
|
class BuilderTest < ActionView::TestCase
|
|
@@ -8,13 +9,13 @@ class BuilderTest < ActionView::TestCase
|
|
|
8
9
|
end
|
|
9
10
|
end
|
|
10
11
|
|
|
11
|
-
def with_collection_radio_buttons(object, attribute, collection, value_method, text_method, options={}, html_options={}, &block)
|
|
12
|
+
def with_collection_radio_buttons(object, attribute, collection, value_method, text_method, options = {}, html_options = {}, &block)
|
|
12
13
|
with_concat_form_for(object) do |f|
|
|
13
14
|
f.collection_radio_buttons attribute, collection, value_method, text_method, options, html_options, &block
|
|
14
15
|
end
|
|
15
16
|
end
|
|
16
17
|
|
|
17
|
-
def with_collection_check_boxes(object, attribute, collection, value_method, text_method, options={}, html_options={}, &block)
|
|
18
|
+
def with_collection_check_boxes(object, attribute, collection, value_method, text_method, options = {}, html_options = {}, &block)
|
|
18
19
|
with_concat_form_for(object) do |f|
|
|
19
20
|
f.collection_check_boxes attribute, collection, value_method, text_method, options, html_options, &block
|
|
20
21
|
end
|
|
@@ -36,13 +37,13 @@ class BuilderTest < ActionView::TestCase
|
|
|
36
37
|
end
|
|
37
38
|
|
|
38
39
|
test "collection radio handles camelized collection values for labels correctly" do
|
|
39
|
-
with_collection_radio_buttons @user, :active, [
|
|
40
|
+
with_collection_radio_buttons @user, :active, %w[Yes No], :to_s, :to_s
|
|
40
41
|
|
|
41
42
|
assert_select 'form label.collection_radio_buttons[for=user_active_yes]', 'Yes'
|
|
42
43
|
assert_select 'form label.collection_radio_buttons[for=user_active_no]', 'No'
|
|
43
44
|
end
|
|
44
45
|
|
|
45
|
-
test "collection radio
|
|
46
|
+
test "collection radio sanitizes collection values for labels correctly" do
|
|
46
47
|
with_collection_radio_buttons @user, :name, ['$0.99', '$1.99'], :to_s, :to_s
|
|
47
48
|
assert_select 'label.collection_radio_buttons[for=user_name_099]', '$0.99'
|
|
48
49
|
assert_select 'label.collection_radio_buttons[for=user_name_199]', '$1.99'
|
|
@@ -243,7 +244,7 @@ class BuilderTest < ActionView::TestCase
|
|
|
243
244
|
|
|
244
245
|
test "collection radio with block helpers does not leak the template" do
|
|
245
246
|
with_concat_form_for(@user) do |f|
|
|
246
|
-
collection_input =
|
|
247
|
+
collection_input = f.collection_radio_buttons :active, [true, false], :to_s, :to_s do |b|
|
|
247
248
|
b.label(class: b.object) { b.radio_button + b.text }
|
|
248
249
|
end
|
|
249
250
|
concat collection_input
|
|
@@ -263,15 +264,15 @@ class BuilderTest < ActionView::TestCase
|
|
|
263
264
|
collection = [Tag.new(1, 'Tag 1'), Tag.new(2, 'Tag 2')]
|
|
264
265
|
with_collection_check_boxes @user, :tag_ids, collection, :id, :name
|
|
265
266
|
|
|
266
|
-
assert_select 'form input#user_tag_ids_1[type=checkbox][value=1]'
|
|
267
|
-
assert_select 'form input#user_tag_ids_2[type=checkbox][value=2]'
|
|
267
|
+
assert_select 'form input#user_tag_ids_1[type=checkbox][value="1"]'
|
|
268
|
+
assert_select 'form input#user_tag_ids_2[type=checkbox][value="2"]'
|
|
268
269
|
end
|
|
269
270
|
|
|
270
271
|
test "collection check box generates only one hidden field for the entire collection, to ensure something will be sent back to the server when posting an empty collection" do
|
|
271
272
|
collection = [Tag.new(1, 'Tag 1'), Tag.new(2, 'Tag 2')]
|
|
272
273
|
with_collection_check_boxes @user, :tag_ids, collection, :id, :name
|
|
273
274
|
|
|
274
|
-
assert_select "form input[type=hidden][name='user[tag_ids][]'][value=]", count: 1
|
|
275
|
+
assert_select "form input[type=hidden][name='user[tag_ids][]'][value='']", count: 1
|
|
275
276
|
end
|
|
276
277
|
|
|
277
278
|
test "collection check box accepts a collection and generate a serie of checkboxes with labels for label method" do
|
|
@@ -283,13 +284,13 @@ class BuilderTest < ActionView::TestCase
|
|
|
283
284
|
end
|
|
284
285
|
|
|
285
286
|
test "collection check box handles camelized collection values for labels correctly" do
|
|
286
|
-
with_collection_check_boxes @user, :active, [
|
|
287
|
+
with_collection_check_boxes @user, :active, %w[Yes No], :to_s, :to_s
|
|
287
288
|
|
|
288
289
|
assert_select 'form label.collection_check_boxes[for=user_active_yes]', 'Yes'
|
|
289
290
|
assert_select 'form label.collection_check_boxes[for=user_active_no]', 'No'
|
|
290
291
|
end
|
|
291
292
|
|
|
292
|
-
test "collection check box
|
|
293
|
+
test "collection check box sanitizes collection values for labels correctly" do
|
|
293
294
|
with_collection_check_boxes @user, :name, ['$0.99', '$1.99'], :to_s, :to_s
|
|
294
295
|
assert_select 'label.collection_check_boxes[for=user_name_099]', '$0.99'
|
|
295
296
|
assert_select 'label.collection_check_boxes[for=user_name_199]', '$1.99'
|
|
@@ -301,36 +302,36 @@ class BuilderTest < ActionView::TestCase
|
|
|
301
302
|
|
|
302
303
|
with_collection_check_boxes user, :tag_ids, collection, :first, :last
|
|
303
304
|
|
|
304
|
-
assert_select 'form input[type=checkbox][value=1][checked=checked]'
|
|
305
|
-
assert_select 'form input[type=checkbox][value=3][checked=checked]'
|
|
306
|
-
assert_no_select 'form input[type=checkbox][value=2][checked=checked]'
|
|
305
|
+
assert_select 'form input[type=checkbox][value="1"][checked=checked]'
|
|
306
|
+
assert_select 'form input[type=checkbox][value="3"][checked=checked]'
|
|
307
|
+
assert_no_select 'form input[type=checkbox][value="2"][checked=checked]'
|
|
307
308
|
end
|
|
308
309
|
|
|
309
310
|
test "collection check box accepts selected values as :checked option" do
|
|
310
311
|
collection = (1..3).map { |i| [i, "Tag #{i}"] }
|
|
311
312
|
with_collection_check_boxes @user, :tag_ids, collection, :first, :last, checked: [1, 3]
|
|
312
313
|
|
|
313
|
-
assert_select 'form input[type=checkbox][value=1][checked=checked]'
|
|
314
|
-
assert_select 'form input[type=checkbox][value=3][checked=checked]'
|
|
315
|
-
assert_no_select 'form input[type=checkbox][value=2][checked=checked]'
|
|
314
|
+
assert_select 'form input[type=checkbox][value="1"][checked=checked]'
|
|
315
|
+
assert_select 'form input[type=checkbox][value="3"][checked=checked]'
|
|
316
|
+
assert_no_select 'form input[type=checkbox][value="2"][checked=checked]'
|
|
316
317
|
end
|
|
317
318
|
|
|
318
319
|
test "collection check boxes accepts selected string values as :checked option" do
|
|
319
320
|
collection = (1..3).map { |i| [i, "Category #{i}"] }
|
|
320
|
-
with_collection_check_boxes :user, :category_ids, collection, :first, :last, checked: [
|
|
321
|
+
with_collection_check_boxes :user, :category_ids, collection, :first, :last, checked: %w[1 3]
|
|
321
322
|
|
|
322
|
-
assert_select 'input[type=checkbox][value=1][checked=checked]'
|
|
323
|
-
assert_select 'input[type=checkbox][value=3][checked=checked]'
|
|
324
|
-
assert_no_select 'input[type=checkbox][value=2][checked=checked]'
|
|
323
|
+
assert_select 'input[type=checkbox][value="1"][checked=checked]'
|
|
324
|
+
assert_select 'input[type=checkbox][value="3"][checked=checked]'
|
|
325
|
+
assert_no_select 'input[type=checkbox][value="2"][checked=checked]'
|
|
325
326
|
end
|
|
326
327
|
|
|
327
328
|
test "collection check box accepts a single checked value" do
|
|
328
329
|
collection = (1..3).map { |i| [i, "Tag #{i}"] }
|
|
329
330
|
with_collection_check_boxes @user, :tag_ids, collection, :first, :last, checked: 3
|
|
330
331
|
|
|
331
|
-
assert_select 'form input[type=checkbox][value=3][checked=checked]'
|
|
332
|
-
assert_no_select 'form input[type=checkbox][value=1][checked=checked]'
|
|
333
|
-
assert_no_select 'form input[type=checkbox][value=2][checked=checked]'
|
|
332
|
+
assert_select 'form input[type=checkbox][value="3"][checked=checked]'
|
|
333
|
+
assert_no_select 'form input[type=checkbox][value="1"][checked=checked]'
|
|
334
|
+
assert_no_select 'form input[type=checkbox][value="2"][checked=checked]'
|
|
334
335
|
end
|
|
335
336
|
|
|
336
337
|
test "collection check box accepts selected values as :checked option and override the model values" do
|
|
@@ -338,44 +339,44 @@ class BuilderTest < ActionView::TestCase
|
|
|
338
339
|
@user.tag_ids = [2]
|
|
339
340
|
with_collection_check_boxes @user, :tag_ids, collection, :first, :last, checked: [1, 3]
|
|
340
341
|
|
|
341
|
-
assert_select 'form input[type=checkbox][value=1][checked=checked]'
|
|
342
|
-
assert_select 'form input[type=checkbox][value=3][checked=checked]'
|
|
343
|
-
assert_no_select 'form input[type=checkbox][value=2][checked=checked]'
|
|
342
|
+
assert_select 'form input[type=checkbox][value="1"][checked=checked]'
|
|
343
|
+
assert_select 'form input[type=checkbox][value="3"][checked=checked]'
|
|
344
|
+
assert_no_select 'form input[type=checkbox][value="2"][checked=checked]'
|
|
344
345
|
end
|
|
345
346
|
|
|
346
347
|
test "collection check box accepts multiple disabled items" do
|
|
347
348
|
collection = (1..3).map { |i| [i, "Tag #{i}"] }
|
|
348
349
|
with_collection_check_boxes @user, :tag_ids, collection, :first, :last, disabled: [1, 3]
|
|
349
350
|
|
|
350
|
-
assert_select 'form input[type=checkbox][value=1][disabled=disabled]'
|
|
351
|
-
assert_select 'form input[type=checkbox][value=3][disabled=disabled]'
|
|
352
|
-
assert_no_select 'form input[type=checkbox][value=2][disabled=disabled]'
|
|
351
|
+
assert_select 'form input[type=checkbox][value="1"][disabled=disabled]'
|
|
352
|
+
assert_select 'form input[type=checkbox][value="3"][disabled=disabled]'
|
|
353
|
+
assert_no_select 'form input[type=checkbox][value="2"][disabled=disabled]'
|
|
353
354
|
end
|
|
354
355
|
|
|
355
356
|
test "collection check box accepts single disable item" do
|
|
356
357
|
collection = (1..3).map { |i| [i, "Tag #{i}"] }
|
|
357
358
|
with_collection_check_boxes @user, :tag_ids, collection, :first, :last, disabled: 1
|
|
358
359
|
|
|
359
|
-
assert_select 'form input[type=checkbox][value=1][disabled=disabled]'
|
|
360
|
-
assert_no_select 'form input[type=checkbox][value=3][disabled=disabled]'
|
|
361
|
-
assert_no_select 'form input[type=checkbox][value=2][disabled=disabled]'
|
|
360
|
+
assert_select 'form input[type=checkbox][value="1"][disabled=disabled]'
|
|
361
|
+
assert_no_select 'form input[type=checkbox][value="3"][disabled=disabled]'
|
|
362
|
+
assert_no_select 'form input[type=checkbox][value="2"][disabled=disabled]'
|
|
362
363
|
end
|
|
363
364
|
|
|
364
365
|
test "collection check box accepts a proc to disabled items" do
|
|
365
366
|
collection = (1..3).map { |i| [i, "Tag #{i}"] }
|
|
366
367
|
with_collection_check_boxes @user, :tag_ids, collection, :first, :last, disabled: proc { |i| i.first == 1 }
|
|
367
368
|
|
|
368
|
-
assert_select 'form input[type=checkbox][value=1][disabled=disabled]'
|
|
369
|
-
assert_no_select 'form input[type=checkbox][value=3][disabled=disabled]'
|
|
370
|
-
assert_no_select 'form input[type=checkbox][value=2][disabled=disabled]'
|
|
369
|
+
assert_select 'form input[type=checkbox][value="1"][disabled=disabled]'
|
|
370
|
+
assert_no_select 'form input[type=checkbox][value="3"][disabled=disabled]'
|
|
371
|
+
assert_no_select 'form input[type=checkbox][value="2"][disabled=disabled]'
|
|
371
372
|
end
|
|
372
373
|
|
|
373
374
|
test "collection check box accepts html options" do
|
|
374
375
|
collection = [[1, 'Tag 1'], [2, 'Tag 2']]
|
|
375
376
|
with_collection_check_boxes @user, :tag_ids, collection, :first, :last, {}, class: 'check'
|
|
376
377
|
|
|
377
|
-
assert_select 'form input.check[type=checkbox][value=1]'
|
|
378
|
-
assert_select 'form input.check[type=checkbox][value=2]'
|
|
378
|
+
assert_select 'form input.check[type=checkbox][value="1"]'
|
|
379
|
+
assert_select 'form input.check[type=checkbox][value="2"]'
|
|
379
380
|
end
|
|
380
381
|
|
|
381
382
|
test "collection check box with fields for" do
|
|
@@ -386,8 +387,8 @@ class BuilderTest < ActionView::TestCase
|
|
|
386
387
|
end
|
|
387
388
|
end
|
|
388
389
|
|
|
389
|
-
assert_select 'form input#user_post_tag_ids_1[type=checkbox][value=1]'
|
|
390
|
-
assert_select 'form input#user_post_tag_ids_2[type=checkbox][value=2]'
|
|
390
|
+
assert_select 'form input#user_post_tag_ids_1[type=checkbox][value="1"]'
|
|
391
|
+
assert_select 'form input#user_post_tag_ids_2[type=checkbox][value="2"]'
|
|
391
392
|
|
|
392
393
|
assert_select 'form label.collection_check_boxes[for=user_post_tag_ids_1]', 'Tag 1'
|
|
393
394
|
assert_select 'form label.collection_check_boxes[for=user_post_tag_ids_2]', 'Tag 2'
|
|
@@ -541,7 +542,7 @@ class BuilderTest < ActionView::TestCase
|
|
|
541
542
|
|
|
542
543
|
test "collection check boxes with block helpers does not leak the template" do
|
|
543
544
|
with_concat_form_for(@user) do |f|
|
|
544
|
-
collection_input =
|
|
545
|
+
collection_input = f.collection_check_boxes :active, [true, false], :to_s, :to_s do |b|
|
|
545
546
|
b.label(class: b.object) { b.check_box + b.text }
|
|
546
547
|
end
|
|
547
548
|
concat collection_input
|
|
@@ -593,7 +594,7 @@ class BuilderTest < ActionView::TestCase
|
|
|
593
594
|
end
|
|
594
595
|
end
|
|
595
596
|
|
|
596
|
-
test "fields
|
|
597
|
+
test "fields inherits wrapper option from the parent form" do
|
|
597
598
|
swap_wrapper :another do
|
|
598
599
|
simple_form_for(:user, wrapper: :another) do |f|
|
|
599
600
|
f.simple_fields_for(:company) do |company|
|