simple_form 3.4.0 → 5.1.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 +5 -5
- data/CHANGELOG.md +118 -8
- data/MIT-LICENSE +2 -1
- data/README.md +235 -67
- data/lib/generators/simple_form/install_generator.rb +1 -0
- data/lib/generators/simple_form/templates/README +2 -3
- 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 +14 -7
- data/lib/generators/simple_form/templates/config/initializers/simple_form_bootstrap.rb +360 -74
- data/lib/generators/simple_form/templates/config/initializers/simple_form_foundation.rb +20 -8
- data/lib/simple_form/action_view_extensions/builder.rb +1 -0
- data/lib/simple_form/action_view_extensions/form_helper.rb +1 -0
- data/lib/simple_form/components/errors.rb +15 -2
- data/lib/simple_form/components/hints.rb +1 -0
- data/lib/simple_form/components/html5.rb +1 -0
- data/lib/simple_form/components/label_input.rb +2 -1
- data/lib/simple_form/components/labels.rb +12 -7
- data/lib/simple_form/components/maxlength.rb +4 -17
- data/lib/simple_form/components/min_max.rb +1 -0
- data/lib/simple_form/components/minlength.rb +5 -18
- data/lib/simple_form/components/pattern.rb +1 -0
- data/lib/simple_form/components/placeholders.rb +2 -1
- data/lib/simple_form/components/readonly.rb +1 -0
- data/lib/simple_form/components.rb +1 -0
- data/lib/simple_form/error_notification.rb +1 -0
- data/lib/simple_form/form_builder.rb +104 -29
- 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 +1 -0
- data/lib/simple_form/inputs/base.rb +24 -5
- data/lib/simple_form/inputs/block_input.rb +1 -0
- data/lib/simple_form/inputs/boolean_input.rb +4 -2
- data/lib/simple_form/inputs/collection_check_boxes_input.rb +3 -2
- data/lib/simple_form/inputs/collection_input.rb +6 -7
- data/lib/simple_form/inputs/collection_radio_buttons_input.rb +2 -1
- data/lib/simple_form/inputs/collection_select_input.rb +1 -0
- data/lib/simple_form/inputs/color_input.rb +14 -0
- data/lib/simple_form/inputs/date_time_input.rb +1 -0
- data/lib/simple_form/inputs/file_input.rb +1 -0
- data/lib/simple_form/inputs/grouped_collection_select_input.rb +1 -0
- data/lib/simple_form/inputs/hidden_input.rb +1 -0
- data/lib/simple_form/inputs/numeric_input.rb +1 -0
- data/lib/simple_form/inputs/password_input.rb +1 -0
- data/lib/simple_form/inputs/priority_input.rb +1 -4
- data/lib/simple_form/inputs/range_input.rb +1 -0
- data/lib/simple_form/inputs/rich_text_area_input.rb +12 -0
- data/lib/simple_form/inputs/string_input.rb +2 -1
- data/lib/simple_form/inputs/text_input.rb +1 -0
- data/lib/simple_form/inputs.rb +3 -0
- data/lib/simple_form/map_type.rb +1 -0
- data/lib/simple_form/railtie.rb +1 -0
- data/lib/simple_form/tags.rb +7 -2
- data/lib/simple_form/version.rb +2 -1
- data/lib/simple_form/wrappers/builder.rb +1 -0
- data/lib/simple_form/wrappers/leaf.rb +2 -1
- data/lib/simple_form/wrappers/many.rb +1 -0
- data/lib/simple_form/wrappers/root.rb +9 -2
- data/lib/simple_form/wrappers/single.rb +2 -1
- data/lib/simple_form/wrappers.rb +1 -0
- data/lib/simple_form.rb +79 -11
- data/test/action_view_extensions/builder_test.rb +28 -9
- data/test/action_view_extensions/form_helper_test.rb +3 -2
- data/test/components/custom_components_test.rb +62 -0
- data/test/components/label_test.rb +33 -8
- data/test/form_builder/association_test.rb +33 -2
- data/test/form_builder/button_test.rb +1 -0
- data/test/form_builder/error_notification_test.rb +1 -0
- data/test/form_builder/error_test.rb +12 -0
- data/test/form_builder/general_test.rb +75 -13
- data/test/form_builder/hint_test.rb +6 -0
- data/test/form_builder/input_field_test.rb +30 -10
- data/test/form_builder/label_test.rb +10 -4
- data/test/form_builder/wrapper_test.rb +32 -5
- data/test/generators/simple_form_generator_test.rb +4 -3
- data/test/inputs/boolean_input_test.rb +17 -0
- data/test/inputs/collection_check_boxes_input_test.rb +38 -18
- data/test/inputs/collection_radio_buttons_input_test.rb +48 -28
- data/test/inputs/collection_select_input_test.rb +46 -43
- data/test/inputs/color_input_test.rb +10 -0
- data/test/inputs/datetime_input_test.rb +7 -16
- data/test/inputs/disabled_test.rb +14 -0
- data/test/inputs/discovery_test.rb +22 -0
- data/test/inputs/file_input_test.rb +1 -0
- data/test/inputs/general_test.rb +3 -2
- data/test/inputs/grouped_collection_select_input_test.rb +11 -10
- data/test/inputs/hidden_input_test.rb +1 -0
- data/test/inputs/numeric_input_test.rb +2 -1
- data/test/inputs/priority_input_test.rb +7 -14
- data/test/inputs/readonly_test.rb +1 -0
- data/test/inputs/required_test.rb +1 -0
- data/test/inputs/rich_text_area_input_test.rb +15 -0
- data/test/inputs/string_input_test.rb +10 -16
- data/test/inputs/text_input_test.rb +1 -0
- data/test/simple_form_test.rb +1 -0
- data/test/support/discovery_inputs.rb +8 -0
- data/test/support/misc_helpers.rb +22 -1
- data/test/support/mock_controller.rb +7 -1
- data/test/support/models.rb +80 -18
- data/test/test_helper.rb +9 -4
- metadata +49 -55
- data/lib/simple_form/i18n_cache.rb +0 -22
@@ -1,13 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# Uncomment this and change the path if necessary to include your own
|
4
|
+
# components.
|
5
|
+
# See https://github.com/heartcombo/simple_form#custom-components to know
|
6
|
+
# more about custom components.
|
7
|
+
# Dir[Rails.root.join('lib/components/**/*.rb')].each { |f| require f }
|
8
|
+
#
|
1
9
|
# Use this setup block to configure all options available in SimpleForm.
|
2
10
|
SimpleForm.setup do |config|
|
3
11
|
# Don't forget to edit this file to adapt it to your needs (specially
|
4
12
|
# all the grid-related classes)
|
5
13
|
#
|
6
14
|
# Please note that hints are commented out by default since Foundation
|
7
|
-
#
|
15
|
+
# doesn't provide styles for hints. You will need to provide your own CSS styles for hints.
|
8
16
|
# Uncomment them to enable hints.
|
9
17
|
|
10
|
-
config.wrappers :vertical_form, class: :input, hint_class: :field_with_hint, error_class: :error do |b|
|
18
|
+
config.wrappers :vertical_form, class: :input, hint_class: :field_with_hint, error_class: :error, valid_class: :valid do |b|
|
11
19
|
b.use :html5
|
12
20
|
b.use :placeholder
|
13
21
|
b.optional :maxlength
|
@@ -21,7 +29,7 @@ SimpleForm.setup do |config|
|
|
21
29
|
# b.use :hint, wrap_with: { tag: :span, class: :hint }
|
22
30
|
end
|
23
31
|
|
24
|
-
config.wrappers :horizontal_form, tag: 'div', class: 'row', hint_class: :field_with_hint, error_class: :error do |b|
|
32
|
+
config.wrappers :horizontal_form, tag: 'div', class: 'row', hint_class: :field_with_hint, error_class: :error, valid_class: :valid do |b|
|
25
33
|
b.use :html5
|
26
34
|
b.use :placeholder
|
27
35
|
b.optional :maxlength
|
@@ -31,7 +39,7 @@ SimpleForm.setup do |config|
|
|
31
39
|
b.optional :readonly
|
32
40
|
|
33
41
|
b.wrapper :label_wrapper, tag: :div, class: 'small-3 columns' do |ba|
|
34
|
-
ba.use :label, class: 'right inline'
|
42
|
+
ba.use :label, class: 'text-right inline'
|
35
43
|
end
|
36
44
|
|
37
45
|
b.wrapper :right_input_wrapper, tag: :div, class: 'small-9 columns' do |ba|
|
@@ -46,7 +54,7 @@ SimpleForm.setup do |config|
|
|
46
54
|
b.optional :readonly
|
47
55
|
|
48
56
|
b.wrapper :container_wrapper, tag: 'div', class: 'small-offset-3 small-9 columns' do |ba|
|
49
|
-
ba.wrapper :
|
57
|
+
ba.wrapper tag: 'label', class: 'checkbox' do |bb|
|
50
58
|
bb.use :input
|
51
59
|
bb.use :label_text
|
52
60
|
end
|
@@ -63,7 +71,7 @@ SimpleForm.setup do |config|
|
|
63
71
|
# Note that you need to adapt this wrapper to your needs. If you need a 4
|
64
72
|
# columns form then change the wrapper class to 'small-3', if you need
|
65
73
|
# only two use 'small-6' and so on.
|
66
|
-
config.wrappers :inline_form, tag: 'div', class: 'column small-4', hint_class: :field_with_hint, error_class: :error do |b|
|
74
|
+
config.wrappers :inline_form, tag: 'div', class: 'column small-4', hint_class: :field_with_hint, error_class: :error, valid_class: :valid do |b|
|
67
75
|
b.use :html5
|
68
76
|
b.use :placeholder
|
69
77
|
b.optional :maxlength
|
@@ -82,7 +90,7 @@ SimpleForm.setup do |config|
|
|
82
90
|
# Examples of use:
|
83
91
|
# - wrapper_html: {class: 'row'}, custom_wrapper_html: {class: 'column small-12'}
|
84
92
|
# - custom_wrapper_html: {class: 'column small-3 end'}
|
85
|
-
config.wrappers :customizable_wrapper, tag: 'div', error_class: :error do |b|
|
93
|
+
config.wrappers :customizable_wrapper, tag: 'div', error_class: :error, valid_class: :valid do |b|
|
86
94
|
b.use :html5
|
87
95
|
b.optional :readonly
|
88
96
|
|
@@ -98,7 +106,7 @@ SimpleForm.setup do |config|
|
|
98
106
|
config.button_class = 'button'
|
99
107
|
|
100
108
|
# Set this to div to make the checkbox and radio properly work
|
101
|
-
# otherwise simple_form adds a label tag instead of a div
|
109
|
+
# otherwise simple_form adds a label tag instead of a div around
|
102
110
|
# the nested label
|
103
111
|
config.item_wrapper_tag = :div
|
104
112
|
|
@@ -107,4 +115,8 @@ SimpleForm.setup do |config|
|
|
107
115
|
|
108
116
|
# The default wrapper to be used by the FormBuilder.
|
109
117
|
config.default_wrapper = :vertical_form
|
118
|
+
|
119
|
+
# Defines validation classes to the input_field. By default it's nil.
|
120
|
+
# config.input_field_valid_class = 'is-valid'
|
121
|
+
# config.input_field_error_class = 'is-invalid'
|
110
122
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module SimpleForm
|
2
3
|
module Components
|
3
4
|
module Errors
|
@@ -10,7 +11,15 @@ module SimpleForm
|
|
10
11
|
end
|
11
12
|
|
12
13
|
def has_errors?
|
13
|
-
|
14
|
+
object_with_errors? || object.nil? && has_custom_error?
|
15
|
+
end
|
16
|
+
|
17
|
+
def has_value?
|
18
|
+
object && object.respond_to?(attribute_name) && object.send(attribute_name).present?
|
19
|
+
end
|
20
|
+
|
21
|
+
def valid?
|
22
|
+
!has_errors? && has_value?
|
14
23
|
end
|
15
24
|
|
16
25
|
protected
|
@@ -25,6 +34,10 @@ module SimpleForm
|
|
25
34
|
has_custom_error? ? options[:error] : full_errors.send(error_method)
|
26
35
|
end
|
27
36
|
|
37
|
+
def object_with_errors?
|
38
|
+
object && object.respond_to?(:errors) && errors.present?
|
39
|
+
end
|
40
|
+
|
28
41
|
def error_method
|
29
42
|
options[:error_method] || SimpleForm.error_method
|
30
43
|
end
|
@@ -38,7 +51,7 @@ module SimpleForm
|
|
38
51
|
end
|
39
52
|
|
40
53
|
def errors_on_attribute
|
41
|
-
object.errors[attribute_name]
|
54
|
+
object.errors[attribute_name] || []
|
42
55
|
end
|
43
56
|
|
44
57
|
def full_errors_on_attribute
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module SimpleForm
|
2
3
|
module Components
|
3
4
|
module LabelInput
|
@@ -20,7 +21,7 @@ module SimpleForm
|
|
20
21
|
def deprecated_component(namespace, wrapper_options)
|
21
22
|
method = method(namespace)
|
22
23
|
|
23
|
-
if method.arity
|
24
|
+
if method.arity.zero?
|
24
25
|
ActiveSupport::Deprecation.warn(SimpleForm::CUSTOM_INPUT_DEPRECATION_WARN % { name: namespace })
|
25
26
|
|
26
27
|
method.call
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module SimpleForm
|
2
3
|
module Components
|
3
4
|
module Labels
|
@@ -5,19 +6,23 @@ module SimpleForm
|
|
5
6
|
|
6
7
|
module ClassMethods #:nodoc:
|
7
8
|
def translate_required_html
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
)
|
12
|
-
end
|
9
|
+
I18n.t(:"required.html", scope: i18n_scope, default:
|
10
|
+
%(<abbr title="#{translate_required_text}">#{translate_required_mark}</abbr>)
|
11
|
+
)
|
13
12
|
end
|
14
13
|
|
15
14
|
def translate_required_text
|
16
|
-
I18n.t(:"
|
15
|
+
I18n.t(:"required.text", scope: i18n_scope, default: 'required')
|
17
16
|
end
|
18
17
|
|
19
18
|
def translate_required_mark
|
20
|
-
I18n.t(:"
|
19
|
+
I18n.t(:"required.mark", scope: i18n_scope, default: '*')
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def i18n_scope
|
25
|
+
SimpleForm.i18n_scope
|
21
26
|
end
|
22
27
|
end
|
23
28
|
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module SimpleForm
|
2
3
|
module Components
|
3
4
|
# Needs to be enabled in order to do automatic lookups.
|
@@ -23,23 +24,9 @@ module SimpleForm
|
|
23
24
|
find_validator(:length)
|
24
25
|
end
|
25
26
|
|
26
|
-
def
|
27
|
-
length_validator
|
28
|
-
|
29
|
-
|
30
|
-
# Use validation with tokenizer if version of Rails is less than 5,
|
31
|
-
# if not validate without the tokenizer, if version is greater than Rails 4.
|
32
|
-
if ActionPack::VERSION::STRING < '5'
|
33
|
-
def maximum_length_value_from(length_validator)
|
34
|
-
if length_validator && !has_tokenizer?(length_validator)
|
35
|
-
length_validator.options[:is] || length_validator.options[:maximum]
|
36
|
-
end
|
37
|
-
end
|
38
|
-
elsif ActionPack::VERSION::STRING >= '5'
|
39
|
-
def maximum_length_value_from(length_validator)
|
40
|
-
if length_validator
|
41
|
-
length_validator.options[:is] || length_validator.options[:maximum]
|
42
|
-
end
|
27
|
+
def maximum_length_value_from(length_validator)
|
28
|
+
if length_validator
|
29
|
+
length_validator.options[:is] || length_validator.options[:maximum]
|
43
30
|
end
|
44
31
|
end
|
45
32
|
end
|
@@ -1,9 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module SimpleForm
|
2
3
|
module Components
|
3
4
|
# Needs to be enabled in order to do automatic lookups.
|
4
5
|
module Minlength
|
5
6
|
def minlength(wrapper_options = nil)
|
6
|
-
input_html_options[:minlength] ||= minimum_length_from_validation
|
7
|
+
input_html_options[:minlength] ||= minimum_length_from_validation
|
7
8
|
nil
|
8
9
|
end
|
9
10
|
|
@@ -23,23 +24,9 @@ module SimpleForm
|
|
23
24
|
find_validator(:length)
|
24
25
|
end
|
25
26
|
|
26
|
-
def
|
27
|
-
length_validator
|
28
|
-
|
29
|
-
|
30
|
-
# Use validation with tokenizer if version of Rails is less than 5,
|
31
|
-
# if not validate without the tokenizer, if version is greater than Rails 4.
|
32
|
-
if ActionPack::VERSION::STRING < '5'
|
33
|
-
def minimum_length_value_from(length_validator)
|
34
|
-
if length_validator && !has_tokenizer?(length_validator)
|
35
|
-
length_validator.options[:is] || length_validator.options[:minimum]
|
36
|
-
end
|
37
|
-
end
|
38
|
-
elsif ActionPack::VERSION::STRING >= '5'
|
39
|
-
def minimum_length_value_from(length_validator)
|
40
|
-
if length_validator
|
41
|
-
length_validator.options[:is] || length_validator.options[:minimum]
|
42
|
-
end
|
27
|
+
def minimum_length_value_from(length_validator)
|
28
|
+
if length_validator
|
29
|
+
length_validator.options[:is] || length_validator.options[:minimum]
|
43
30
|
end
|
44
31
|
end
|
45
32
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module SimpleForm
|
2
3
|
module Components
|
3
4
|
# Needs to be enabled in order to do automatic lookups.
|
@@ -7,7 +8,7 @@ module SimpleForm
|
|
7
8
|
nil
|
8
9
|
end
|
9
10
|
|
10
|
-
def placeholder_text
|
11
|
+
def placeholder_text(wrapper_options = nil)
|
11
12
|
placeholder = options[:placeholder]
|
12
13
|
placeholder.is_a?(String) ? placeholder : translate_from_namespace(:placeholders)
|
13
14
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'active_support/core_ext/object/deep_dup'
|
2
3
|
require 'simple_form/map_type'
|
3
4
|
require 'simple_form/tags'
|
@@ -12,25 +13,26 @@ module SimpleForm
|
|
12
13
|
'update' => 'edit'
|
13
14
|
}
|
14
15
|
|
15
|
-
ATTRIBUTE_COMPONENTS = [
|
16
|
+
ATTRIBUTE_COMPONENTS = %i[html5 min_max maxlength minlength placeholder pattern readonly]
|
16
17
|
|
17
18
|
extend MapType
|
18
19
|
include SimpleForm::Inputs
|
19
20
|
|
20
|
-
map_type :text,
|
21
|
-
map_type :file,
|
22
|
-
map_type :string, :email, :search, :tel, :url, :uuid, to: SimpleForm::Inputs::StringInput
|
23
|
-
map_type :password,
|
24
|
-
map_type :integer, :decimal, :float,
|
25
|
-
map_type :range,
|
26
|
-
map_type :check_boxes,
|
27
|
-
map_type :radio_buttons,
|
28
|
-
map_type :
|
29
|
-
map_type :
|
30
|
-
map_type :
|
31
|
-
map_type :
|
32
|
-
map_type :
|
33
|
-
map_type :
|
21
|
+
map_type :text, :hstore, :json, :jsonb, to: SimpleForm::Inputs::TextInput
|
22
|
+
map_type :file, to: SimpleForm::Inputs::FileInput
|
23
|
+
map_type :string, :email, :search, :tel, :url, :uuid, :citext, to: SimpleForm::Inputs::StringInput
|
24
|
+
map_type :password, to: SimpleForm::Inputs::PasswordInput
|
25
|
+
map_type :integer, :decimal, :float, to: SimpleForm::Inputs::NumericInput
|
26
|
+
map_type :range, to: SimpleForm::Inputs::RangeInput
|
27
|
+
map_type :check_boxes, to: SimpleForm::Inputs::CollectionCheckBoxesInput
|
28
|
+
map_type :radio_buttons, to: SimpleForm::Inputs::CollectionRadioButtonsInput
|
29
|
+
map_type :rich_text_area, to: SimpleForm::Inputs::RichTextAreaInput
|
30
|
+
map_type :select, to: SimpleForm::Inputs::CollectionSelectInput
|
31
|
+
map_type :grouped_select, to: SimpleForm::Inputs::GroupedCollectionSelectInput
|
32
|
+
map_type :date, :time, :datetime, to: SimpleForm::Inputs::DateTimeInput
|
33
|
+
map_type :country, :time_zone, to: SimpleForm::Inputs::PriorityInput
|
34
|
+
map_type :boolean, to: SimpleForm::Inputs::BooleanInput
|
35
|
+
map_type :hidden, to: SimpleForm::Inputs::HiddenInput
|
34
36
|
|
35
37
|
def self.discovery_cache
|
36
38
|
@discovery_cache ||= {}
|
@@ -38,6 +40,7 @@ module SimpleForm
|
|
38
40
|
|
39
41
|
def initialize(*) #:nodoc:
|
40
42
|
super
|
43
|
+
@object = convert_to_model(@object)
|
41
44
|
@defaults = options[:defaults]
|
42
45
|
@wrapper = SimpleForm.wrapper(options[:wrapper] || SimpleForm.default_wrapper)
|
43
46
|
end
|
@@ -136,16 +139,39 @@ module SimpleForm
|
|
136
139
|
# <input class="string required" id="user_name" maxlength="100"
|
137
140
|
# name="user[name]" type="text" value="Carlos" />
|
138
141
|
#
|
142
|
+
# It also support validation classes once it is configured.
|
143
|
+
#
|
144
|
+
# # config/initializers/simple_form.rb
|
145
|
+
# SimpleForm.setup do |config|
|
146
|
+
# config.input_field_valid_class = 'is-valid'
|
147
|
+
# config.input_field_error_class = 'is-invalid'
|
148
|
+
# end
|
149
|
+
#
|
150
|
+
# simple_form_for @user do |f|
|
151
|
+
# f.input_field :name
|
152
|
+
# end
|
153
|
+
#
|
154
|
+
# When the validation happens, the input will be rendered with
|
155
|
+
# the class configured according to the validation:
|
156
|
+
#
|
157
|
+
# - when the input is valid:
|
158
|
+
#
|
159
|
+
# <input class="is-valid string required" id="user_name" value="Carlos" />
|
160
|
+
#
|
161
|
+
# - when the input is invalid:
|
162
|
+
#
|
163
|
+
# <input class="is-invalid string required" id="user_name" value="" />
|
164
|
+
#
|
139
165
|
def input_field(attribute_name, options = {})
|
140
166
|
components = (wrapper.components.map(&:namespace) & ATTRIBUTE_COMPONENTS)
|
141
167
|
|
142
168
|
options = options.dup
|
143
|
-
options[:input_html] = options.except(:as, :boolean_style, :collection, :label_method, :value_method, :prompt, *components)
|
169
|
+
options[:input_html] = options.except(:as, :boolean_style, :collection, :disabled, :label_method, :value_method, :prompt, *components)
|
144
170
|
options = @defaults.deep_dup.deep_merge(options) if @defaults
|
145
171
|
|
146
172
|
input = find_input(attribute_name, options)
|
147
173
|
wrapper = find_wrapper(input.input_type, options)
|
148
|
-
components = components.
|
174
|
+
components = build_input_field_components(components.push(:input))
|
149
175
|
|
150
176
|
SimpleForm::Wrappers::Root.new(components, wrapper.options.merge(wrapper: false)).render input
|
151
177
|
end
|
@@ -461,13 +487,17 @@ module SimpleForm
|
|
461
487
|
relation = reflection.klass.all
|
462
488
|
|
463
489
|
if reflection.respond_to?(:scope) && reflection.scope
|
464
|
-
|
490
|
+
if reflection.scope.parameters.any?
|
491
|
+
relation = reflection.klass.instance_exec(object, &reflection.scope)
|
492
|
+
else
|
493
|
+
relation = reflection.klass.instance_exec(&reflection.scope)
|
494
|
+
end
|
465
495
|
else
|
466
496
|
order = reflection.options[:order]
|
467
497
|
conditions = reflection.options[:conditions]
|
468
498
|
conditions = object.instance_exec(&conditions) if conditions.respond_to?(:call)
|
469
499
|
|
470
|
-
relation = relation.where(conditions)
|
500
|
+
relation = relation.where(conditions) if relation.respond_to?(:where)
|
471
501
|
relation = relation.order(order) if relation.respond_to?(:order)
|
472
502
|
end
|
473
503
|
|
@@ -482,7 +512,7 @@ module SimpleForm
|
|
482
512
|
when :has_one
|
483
513
|
raise ArgumentError, ":has_one associations are not supported by f.association"
|
484
514
|
else
|
485
|
-
if options[:as] == :select
|
515
|
+
if options[:as] == :select || options[:as] == :grouped_select
|
486
516
|
html_options = options[:input_html] ||= {}
|
487
517
|
html_options[:multiple] = true unless html_options.key?(:multiple)
|
488
518
|
end
|
@@ -521,14 +551,14 @@ module SimpleForm
|
|
521
551
|
case input_type
|
522
552
|
when :timestamp
|
523
553
|
:datetime
|
524
|
-
when :string, nil
|
554
|
+
when :string, :citext, nil
|
525
555
|
case attribute_name.to_s
|
526
|
-
when /password/ then :password
|
527
|
-
when /time_zone/ then :time_zone
|
528
|
-
when /country/ then :country
|
529
|
-
when /email/ then :email
|
530
|
-
when /phone/ then :tel
|
531
|
-
when /url/ then :url
|
556
|
+
when /(?:\b|\W|_)password(?:\b|\W|_)/ then :password
|
557
|
+
when /(?:\b|\W|_)time_zone(?:\b|\W|_)/ then :time_zone
|
558
|
+
when /(?:\b|\W|_)country(?:\b|\W|_)/ then :country
|
559
|
+
when /(?:\b|\W|_)email(?:\b|\W|_)/ then :email
|
560
|
+
when /(?:\b|\W|_)phone(?:\b|\W|_)/ then :tel
|
561
|
+
when /(?:\b|\W|_)url(?:\b|\W|_)/ then :url
|
532
562
|
else
|
533
563
|
file_method?(attribute_name) ? :file : (input_type || :string)
|
534
564
|
end
|
@@ -543,9 +573,28 @@ module SimpleForm
|
|
543
573
|
}.try(:last) if SimpleForm.input_mappings
|
544
574
|
end
|
545
575
|
|
576
|
+
# Internal: Try to discover whether an attribute corresponds to a file or not.
|
577
|
+
#
|
578
|
+
# Most upload Gems add some kind of attributes to the ActiveRecord's model they are included in.
|
579
|
+
# This method tries to guess if an attribute belongs to some of these Gems by checking the presence
|
580
|
+
# of their methods using `#respond_to?`.
|
581
|
+
#
|
582
|
+
# Note: This does not support multiple file upload inputs, as this is very application-specific.
|
583
|
+
#
|
584
|
+
# The order here was chosen based on the popularity of Gems:
|
585
|
+
#
|
586
|
+
# - `#{attribute_name}_attachment` - ActiveStorage >= `5.2` and Refile >= `0.2.0` <= `0.4.0`
|
587
|
+
# - `remote_#{attribute_name}_url` - Refile >= `0.3.0` and CarrierWave >= `0.2.2`
|
588
|
+
# - `#{attribute_name}_attacher` - Refile >= `0.4.0` and Shrine >= `0.9.0`
|
589
|
+
# - `#{attribute_name}_file_name` - Paperclip ~> `2.0` (added for backwards compatibility)
|
590
|
+
#
|
591
|
+
# Returns a Boolean.
|
546
592
|
def file_method?(attribute_name)
|
547
|
-
|
548
|
-
|
593
|
+
@object.respond_to?("#{attribute_name}_attachment") ||
|
594
|
+
@object.respond_to?("#{attribute_name}_attachments") ||
|
595
|
+
@object.respond_to?("remote_#{attribute_name}_url") ||
|
596
|
+
@object.respond_to?("#{attribute_name}_attacher") ||
|
597
|
+
@object.respond_to?("#{attribute_name}_file_name")
|
549
598
|
end
|
550
599
|
|
551
600
|
def find_attribute_column(attribute_name)
|
@@ -640,5 +689,31 @@ module SimpleForm
|
|
640
689
|
|
641
690
|
nil
|
642
691
|
end
|
692
|
+
|
693
|
+
def build_input_field_components(components)
|
694
|
+
components.map do |component|
|
695
|
+
if component == :input
|
696
|
+
SimpleForm::Wrappers::Leaf.new(component, build_input_field_options)
|
697
|
+
else
|
698
|
+
SimpleForm::Wrappers::Leaf.new(component)
|
699
|
+
end
|
700
|
+
end
|
701
|
+
end
|
702
|
+
|
703
|
+
def build_input_field_options
|
704
|
+
input_field_options = {}
|
705
|
+
valid_class = SimpleForm.input_field_valid_class
|
706
|
+
error_class = SimpleForm.input_field_error_class
|
707
|
+
|
708
|
+
if error_class.present?
|
709
|
+
input_field_options[:error_class] = error_class
|
710
|
+
end
|
711
|
+
|
712
|
+
if valid_class.present?
|
713
|
+
input_field_options[:valid_class] = valid_class
|
714
|
+
end
|
715
|
+
|
716
|
+
input_field_options
|
717
|
+
end
|
643
718
|
end
|
644
719
|
end
|
@@ -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
|
data/lib/simple_form/helpers.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
require 'active_support/core_ext/string/output_safety'
|
3
3
|
require 'action_view/helpers'
|
4
4
|
|
@@ -8,8 +8,6 @@ module SimpleForm
|
|
8
8
|
include ERB::Util
|
9
9
|
include ActionView::Helpers::TranslationHelper
|
10
10
|
|
11
|
-
extend I18nCache
|
12
|
-
|
13
11
|
include SimpleForm::Helpers::Autofocus
|
14
12
|
include SimpleForm::Helpers::Disabled
|
15
13
|
include SimpleForm::Helpers::Readonly
|
@@ -71,7 +69,10 @@ module SimpleForm
|
|
71
69
|
@html_classes = SimpleForm.additional_classes_for(:input) { additional_classes }
|
72
70
|
|
73
71
|
@input_html_classes = @html_classes.dup
|
74
|
-
|
72
|
+
|
73
|
+
input_html_classes = self.input_html_classes
|
74
|
+
|
75
|
+
if SimpleForm.input_class && input_html_classes.any?
|
75
76
|
input_html_classes << SimpleForm.input_class
|
76
77
|
end
|
77
78
|
|
@@ -95,7 +96,7 @@ module SimpleForm
|
|
95
96
|
end
|
96
97
|
|
97
98
|
def input_class
|
98
|
-
"#{lookup_model_names.join(
|
99
|
+
"#{lookup_model_names.join('_')}_#{reflection_or_attribute_name}"
|
99
100
|
end
|
100
101
|
|
101
102
|
private
|
@@ -190,6 +191,8 @@ module SimpleForm
|
|
190
191
|
|
191
192
|
def merge_wrapper_options(options, wrapper_options)
|
192
193
|
if wrapper_options
|
194
|
+
wrapper_options = set_input_classes(wrapper_options)
|
195
|
+
|
193
196
|
wrapper_options.merge(options) do |key, oldval, newval|
|
194
197
|
case key.to_s
|
195
198
|
when "class"
|
@@ -205,6 +208,22 @@ module SimpleForm
|
|
205
208
|
end
|
206
209
|
end
|
207
210
|
|
211
|
+
def set_input_classes(wrapper_options)
|
212
|
+
wrapper_options = wrapper_options.dup
|
213
|
+
error_class = wrapper_options.delete(:error_class)
|
214
|
+
valid_class = wrapper_options.delete(:valid_class)
|
215
|
+
|
216
|
+
if error_class.present? && has_errors?
|
217
|
+
wrapper_options[:class] = "#{wrapper_options[:class]} #{error_class}"
|
218
|
+
end
|
219
|
+
|
220
|
+
if valid_class.present? && valid?
|
221
|
+
wrapper_options[:class] = "#{wrapper_options[:class]} #{valid_class}"
|
222
|
+
end
|
223
|
+
|
224
|
+
wrapper_options
|
225
|
+
end
|
226
|
+
|
208
227
|
def i18n_scope
|
209
228
|
SimpleForm.i18n_scope
|
210
229
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module SimpleForm
|
2
3
|
module Inputs
|
3
4
|
class BooleanInput < Base
|
@@ -59,9 +60,10 @@ module SimpleForm
|
|
59
60
|
# we need the hidden field to be *outside* the label (otherwise it
|
60
61
|
# generates invalid html - html5 only).
|
61
62
|
def build_hidden_field_for_checkbox
|
62
|
-
return ""
|
63
|
+
return "" if !include_hidden? || !unchecked_value
|
63
64
|
options = { value: unchecked_value, id: nil, disabled: input_html_options[:disabled] }
|
64
|
-
options[:name] = input_html_options[:name] if input_html_options.
|
65
|
+
options[:name] = input_html_options[:name] if input_html_options.key?(:name)
|
66
|
+
options[:form] = input_html_options[:form] if input_html_options.key?(:form)
|
65
67
|
|
66
68
|
@builder.hidden_field(attribute_name, options)
|
67
69
|
end
|