formtastic 3.0.0 → 5.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 +5 -13
- data/.gitattributes +1 -0
- data/.github/workflows/test.yml +61 -0
- data/.gitignore +3 -2
- data/CHANGELOG.md +61 -0
- data/Gemfile.lock +140 -0
- data/MIT-LICENSE +1 -1
- data/{README.textile → README.md} +191 -168
- data/RELEASE_PROCESS +3 -1
- data/Rakefile +24 -8
- data/app/assets/stylesheets/formtastic.css +1 -1
- data/bin/appraisal +8 -0
- data/formtastic.gemspec +13 -17
- data/gemfiles/rails_6.0/Gemfile +5 -0
- data/gemfiles/rails_6.1/Gemfile +5 -0
- data/gemfiles/rails_7.0/Gemfile +5 -0
- data/gemfiles/rails_7.1/Gemfile +5 -0
- data/gemfiles/rails_edge/Gemfile +13 -0
- data/lib/formtastic/action_class_finder.rb +19 -0
- data/lib/formtastic/actions/base.rb +1 -0
- data/lib/formtastic/actions/button_action.rb +56 -53
- data/lib/formtastic/actions/buttonish.rb +1 -0
- data/lib/formtastic/actions/input_action.rb +60 -57
- data/lib/formtastic/actions/link_action.rb +69 -67
- data/lib/formtastic/actions.rb +7 -3
- data/lib/formtastic/deprecation.rb +6 -0
- data/lib/formtastic/engine.rb +4 -1
- data/lib/formtastic/form_builder.rb +32 -25
- data/lib/formtastic/helpers/action_helper.rb +22 -31
- data/lib/formtastic/helpers/actions_helper.rb +1 -0
- data/lib/formtastic/helpers/enum.rb +14 -0
- data/lib/formtastic/helpers/errors_helper.rb +3 -2
- data/lib/formtastic/helpers/fieldset_wrapper.rb +16 -11
- data/lib/formtastic/helpers/file_column_detection.rb +1 -0
- data/lib/formtastic/helpers/form_helper.rb +4 -3
- data/lib/formtastic/helpers/input_helper.rb +59 -80
- data/lib/formtastic/helpers/inputs_helper.rb +33 -27
- data/lib/formtastic/helpers/reflection.rb +5 -4
- data/lib/formtastic/helpers.rb +2 -2
- data/lib/formtastic/html_attributes.rb +13 -1
- data/lib/formtastic/i18n.rb +2 -1
- data/lib/formtastic/input_class_finder.rb +19 -0
- data/lib/formtastic/inputs/base/associations.rb +1 -0
- data/lib/formtastic/inputs/base/choices.rb +4 -3
- data/lib/formtastic/inputs/base/collections.rb +47 -11
- data/lib/formtastic/inputs/base/database.rb +8 -5
- data/lib/formtastic/inputs/base/datetime_pickerish.rb +1 -0
- data/lib/formtastic/inputs/base/errors.rb +7 -6
- data/lib/formtastic/inputs/base/fileish.rb +1 -0
- data/lib/formtastic/inputs/base/hints.rb +2 -1
- data/lib/formtastic/inputs/base/html.rb +12 -10
- data/lib/formtastic/inputs/base/labelling.rb +3 -2
- data/lib/formtastic/inputs/base/naming.rb +5 -4
- data/lib/formtastic/inputs/base/numeric.rb +1 -0
- data/lib/formtastic/inputs/base/options.rb +3 -3
- data/lib/formtastic/inputs/base/placeholder.rb +1 -0
- data/lib/formtastic/inputs/base/stringish.rb +1 -0
- data/lib/formtastic/inputs/base/timeish.rb +9 -4
- data/lib/formtastic/inputs/base/validations.rb +39 -12
- data/lib/formtastic/inputs/base/wrapping.rb +2 -3
- data/lib/formtastic/inputs/base.rb +17 -12
- data/lib/formtastic/inputs/boolean_input.rb +2 -1
- data/lib/formtastic/inputs/check_boxes_input.rb +16 -24
- data/lib/formtastic/inputs/color_input.rb +1 -1
- data/lib/formtastic/inputs/country_input.rb +4 -1
- data/lib/formtastic/inputs/datalist_input.rb +42 -0
- data/lib/formtastic/inputs/date_picker_input.rb +1 -0
- data/lib/formtastic/inputs/date_select_input.rb +1 -0
- data/lib/formtastic/inputs/datetime_picker_input.rb +1 -0
- data/lib/formtastic/inputs/datetime_select_input.rb +1 -0
- data/lib/formtastic/inputs/email_input.rb +1 -0
- data/lib/formtastic/inputs/file_input.rb +3 -2
- data/lib/formtastic/inputs/hidden_input.rb +3 -2
- data/lib/formtastic/inputs/number_input.rb +1 -0
- data/lib/formtastic/inputs/password_input.rb +1 -0
- data/lib/formtastic/inputs/phone_input.rb +1 -0
- data/lib/formtastic/inputs/radio_input.rb +26 -21
- data/lib/formtastic/inputs/range_input.rb +1 -0
- data/lib/formtastic/inputs/search_input.rb +1 -0
- data/lib/formtastic/inputs/select_input.rb +32 -10
- data/lib/formtastic/inputs/string_input.rb +1 -0
- data/lib/formtastic/inputs/text_input.rb +1 -0
- data/lib/formtastic/inputs/time_picker_input.rb +1 -0
- data/lib/formtastic/inputs/time_select_input.rb +1 -0
- data/lib/formtastic/inputs/time_zone_input.rb +17 -6
- data/lib/formtastic/inputs/url_input.rb +1 -0
- data/lib/formtastic/inputs.rb +33 -28
- data/lib/formtastic/localized_string.rb +2 -1
- data/lib/formtastic/localizer.rb +23 -24
- data/lib/formtastic/namespaced_class_finder.rb +98 -0
- data/lib/formtastic/version.rb +2 -1
- data/lib/formtastic.rb +19 -14
- data/lib/generators/formtastic/form/form_generator.rb +8 -2
- data/lib/generators/formtastic/input/input_generator.rb +47 -0
- data/lib/generators/formtastic/install/install_generator.rb +2 -0
- data/lib/generators/templates/formtastic.rb +29 -7
- data/lib/generators/templates/input.rb +19 -0
- data/sample/basic_inputs.html +1 -1
- data/script/integration-template.rb +73 -0
- data/script/integration.sh +19 -0
- data/spec/action_class_finder_spec.rb +13 -0
- data/spec/actions/button_action_spec.rb +21 -20
- data/spec/actions/generic_action_spec.rb +134 -133
- data/spec/actions/input_action_spec.rb +20 -19
- data/spec/actions/link_action_spec.rb +30 -29
- data/spec/builder/custom_builder_spec.rb +39 -22
- data/spec/builder/error_proc_spec.rb +6 -5
- data/spec/builder/semantic_fields_for_spec.rb +46 -45
- data/spec/fast_spec_helper.rb +13 -0
- data/spec/generators/formtastic/form/form_generator_spec.rb +33 -32
- data/spec/generators/formtastic/input/input_generator_spec.rb +125 -0
- data/spec/generators/formtastic/install/install_generator_spec.rb +10 -9
- data/spec/helpers/action_helper_spec.rb +70 -97
- data/spec/helpers/actions_helper_spec.rb +43 -42
- data/spec/helpers/form_helper_spec.rb +56 -39
- data/spec/helpers/input_helper_spec.rb +314 -255
- data/spec/helpers/inputs_helper_spec.rb +217 -202
- data/spec/helpers/reflection_helper_spec.rb +7 -6
- data/spec/helpers/semantic_errors_helper_spec.rb +26 -25
- data/spec/i18n_spec.rb +30 -29
- data/spec/input_class_finder_spec.rb +11 -0
- data/spec/inputs/base/collections_spec.rb +78 -0
- data/spec/inputs/base/validations_spec.rb +481 -0
- data/spec/inputs/boolean_input_spec.rb +73 -72
- data/spec/inputs/check_boxes_input_spec.rb +174 -123
- data/spec/inputs/color_input_spec.rb +53 -64
- data/spec/inputs/country_input_spec.rb +23 -22
- data/spec/inputs/custom_input_spec.rb +3 -6
- data/spec/inputs/datalist_input_spec.rb +62 -0
- data/spec/inputs/date_picker_input_spec.rb +114 -113
- data/spec/inputs/date_select_input_spec.rb +76 -61
- data/spec/inputs/datetime_picker_input_spec.rb +123 -122
- data/spec/inputs/datetime_select_input_spec.rb +85 -68
- data/spec/inputs/email_input_spec.rb +17 -16
- data/spec/inputs/file_input_spec.rb +18 -17
- data/spec/inputs/hidden_input_spec.rb +32 -31
- data/spec/inputs/include_blank_spec.rb +10 -9
- data/spec/inputs/label_spec.rb +36 -31
- data/spec/inputs/number_input_spec.rb +212 -211
- data/spec/inputs/password_input_spec.rb +17 -16
- data/spec/inputs/phone_input_spec.rb +17 -16
- data/spec/inputs/placeholder_spec.rb +18 -17
- data/spec/inputs/radio_input_spec.rb +92 -65
- data/spec/inputs/range_input_spec.rb +136 -135
- data/spec/inputs/readonly_spec.rb +51 -0
- data/spec/inputs/search_input_spec.rb +16 -15
- data/spec/inputs/select_input_spec.rb +209 -102
- data/spec/inputs/string_input_spec.rb +51 -50
- data/spec/inputs/text_input_spec.rb +34 -33
- data/spec/inputs/time_picker_input_spec.rb +115 -114
- data/spec/inputs/time_select_input_spec.rb +84 -70
- data/spec/inputs/time_zone_input_spec.rb +58 -31
- data/spec/inputs/url_input_spec.rb +17 -16
- data/spec/inputs/with_options_spec.rb +9 -8
- data/spec/localizer_spec.rb +18 -17
- data/spec/namespaced_class_finder_spec.rb +91 -0
- data/spec/schema.rb +22 -0
- data/spec/spec_helper.rb +180 -249
- data/spec/support/custom_macros.rb +128 -98
- data/spec/support/deprecation.rb +2 -1
- data/spec/support/shared_examples.rb +13 -0
- data/spec/support/specialized_class_finder_shared_example.rb +28 -0
- data/spec/support/test_environment.rb +25 -10
- metadata +95 -136
- data/.travis.yml +0 -28
- data/Appraisals +0 -25
- data/CHANGELOG +0 -27
- data/gemfiles/rails_3.2.gemfile +0 -7
- data/gemfiles/rails_4.0.4.gemfile +0 -7
- data/gemfiles/rails_4.1.gemfile +0 -7
- data/gemfiles/rails_4.gemfile +0 -7
- data/gemfiles/rails_edge.gemfile +0 -10
- data/lib/formtastic/util.rb +0 -53
- data/spec/support/deferred_garbage_collection.rb +0 -21
- data/spec/util_spec.rb +0 -52
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module Formtastic
|
|
2
3
|
module Inputs
|
|
3
4
|
module Base
|
|
@@ -85,6 +86,9 @@ module Formtastic
|
|
|
85
86
|
# <%= f.input :publish_at, :as => :time_select, :include_blank => true %>
|
|
86
87
|
# <%= f.input :publish_at, :as => :time_select, :include_blank => false %>
|
|
87
88
|
#
|
|
89
|
+
# @example Provide a value for the field via selected
|
|
90
|
+
# <%= f.input :publish_at, :as => :datetime_select, :selected => DateTime.new(2018, 10, 4, 12, 00)
|
|
91
|
+
#
|
|
88
92
|
# @todo Document i18n
|
|
89
93
|
# @todo Check what other Rails options are supported (`start_year`, `end_year`, `use_month_numbers`, `use_short_month`, `add_month_numbers`, `prompt`), write tests for them, and otherwise support them
|
|
90
94
|
# @todo Could we take the rendering from Rails' helpers and inject better HTML in and around it rather than re-inventing the whee?
|
|
@@ -153,10 +157,11 @@ module Formtastic
|
|
|
153
157
|
|
|
154
158
|
def fragment_label_html(fragment)
|
|
155
159
|
text = fragment_label(fragment)
|
|
156
|
-
text.blank? ? "".html_safe : template.content_tag(:label, text, :for => fragment_id(fragment))
|
|
160
|
+
text.blank? ? +"".html_safe : template.content_tag(:label, text, :for => fragment_id(fragment))
|
|
157
161
|
end
|
|
158
162
|
|
|
159
163
|
def value
|
|
164
|
+
return input_options[:selected] if options.key?(:selected)
|
|
160
165
|
object.send(method) if object && object.respond_to?(method)
|
|
161
166
|
end
|
|
162
167
|
|
|
@@ -213,7 +218,7 @@ module Formtastic
|
|
|
213
218
|
:class => "label"
|
|
214
219
|
)
|
|
215
220
|
else
|
|
216
|
-
"".html_safe
|
|
221
|
+
+"".html_safe
|
|
217
222
|
end
|
|
218
223
|
end
|
|
219
224
|
|
|
@@ -224,7 +229,7 @@ module Formtastic
|
|
|
224
229
|
end
|
|
225
230
|
|
|
226
231
|
def hidden_fragments
|
|
227
|
-
"".html_safe
|
|
232
|
+
+"".html_safe
|
|
228
233
|
end
|
|
229
234
|
|
|
230
235
|
def hidden_field_name(fragment)
|
|
@@ -238,4 +243,4 @@ module Formtastic
|
|
|
238
243
|
end
|
|
239
244
|
end
|
|
240
245
|
end
|
|
241
|
-
end
|
|
246
|
+
end
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module Formtastic
|
|
2
3
|
module Inputs
|
|
3
4
|
module Base
|
|
@@ -73,13 +74,11 @@ module Formtastic
|
|
|
73
74
|
raise IndeterminableMinimumAttributeError if validation.options[:greater_than] && column? && [:float, :decimal].include?(column.type)
|
|
74
75
|
|
|
75
76
|
if validation.options[:greater_than_or_equal_to]
|
|
76
|
-
return (validation.options[:greater_than_or_equal_to]
|
|
77
|
-
return (validation.options[:greater_than_or_equal_to])
|
|
77
|
+
return option_value(validation.options[:greater_than_or_equal_to], object)
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
if validation.options[:greater_than]
|
|
81
|
-
return (validation.options[:greater_than]
|
|
82
|
-
return (validation.options[:greater_than] + 1)
|
|
81
|
+
return option_value(validation.options[:greater_than], object) + 1
|
|
83
82
|
end
|
|
84
83
|
end
|
|
85
84
|
end
|
|
@@ -94,13 +93,11 @@ module Formtastic
|
|
|
94
93
|
raise IndeterminableMaximumAttributeError if validation.options[:less_than] && column? && [:float, :decimal].include?(column.type)
|
|
95
94
|
|
|
96
95
|
if validation.options[:less_than_or_equal_to]
|
|
97
|
-
return (validation.options[:less_than_or_equal_to]
|
|
98
|
-
return (validation.options[:less_than_or_equal_to])
|
|
96
|
+
return option_value(validation.options[:less_than_or_equal_to], object)
|
|
99
97
|
end
|
|
100
98
|
|
|
101
99
|
if validation.options[:less_than]
|
|
102
|
-
return (
|
|
103
|
-
return (validation.options[:less_than] - 1)
|
|
100
|
+
return option_value(validation.options[:less_than], object) - 1
|
|
104
101
|
end
|
|
105
102
|
end
|
|
106
103
|
end
|
|
@@ -136,9 +133,10 @@ module Formtastic
|
|
|
136
133
|
return true if options[:required] == true
|
|
137
134
|
return false if not_required_through_negated_validation?
|
|
138
135
|
if validations?
|
|
139
|
-
validations.
|
|
136
|
+
validations.any? { |validator|
|
|
140
137
|
if validator.options.key?(:on)
|
|
141
|
-
|
|
138
|
+
validator_on = Array(validator.options[:on])
|
|
139
|
+
next false if (validator_on.exclude?(:save)) && ((object.new_record? && validator_on.exclude?(:create)) || (!object.new_record? && validator_on.exclude?(:update)))
|
|
142
140
|
end
|
|
143
141
|
case validator.kind
|
|
144
142
|
when :presence
|
|
@@ -152,7 +150,7 @@ module Formtastic
|
|
|
152
150
|
else
|
|
153
151
|
false
|
|
154
152
|
end
|
|
155
|
-
}
|
|
153
|
+
}
|
|
156
154
|
else
|
|
157
155
|
return responds_to_global_required? && !!builder.all_fields_required_by_default
|
|
158
156
|
end
|
|
@@ -192,8 +190,37 @@ module Formtastic
|
|
|
192
190
|
validation_limit || column_limit
|
|
193
191
|
end
|
|
194
192
|
|
|
193
|
+
def readonly?
|
|
194
|
+
readonly_from_options? || readonly_attribute?
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def readonly_attribute?
|
|
198
|
+
object_class = self.object.class
|
|
199
|
+
object_class.respond_to?(:readonly_attributes) &&
|
|
200
|
+
self.object.persisted? &&
|
|
201
|
+
column.respond_to?(:name) &&
|
|
202
|
+
object_class.readonly_attributes.include?(column.name.to_s)
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def readonly_from_options?
|
|
206
|
+
options[:input_html] && options[:input_html][:readonly]
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
private
|
|
210
|
+
|
|
211
|
+
# Loosely based on
|
|
212
|
+
# https://github.com/rails/rails/blob/459e7cf62252558bbf65f582a230562ab1a76c5e/activemodel/lib/active_model/validations/numericality.rb#L65-L70
|
|
213
|
+
def option_value(option, object)
|
|
214
|
+
case option
|
|
215
|
+
when Symbol
|
|
216
|
+
object.send(option)
|
|
217
|
+
when Proc
|
|
218
|
+
option.call(object)
|
|
219
|
+
else
|
|
220
|
+
option
|
|
221
|
+
end
|
|
222
|
+
end
|
|
195
223
|
end
|
|
196
224
|
end
|
|
197
225
|
end
|
|
198
226
|
end
|
|
199
|
-
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module Formtastic
|
|
2
3
|
module Inputs
|
|
3
4
|
module Base
|
|
@@ -25,9 +26,7 @@ module Formtastic
|
|
|
25
26
|
end
|
|
26
27
|
|
|
27
28
|
def wrapper_classes_raw
|
|
28
|
-
|
|
29
|
-
return classes.dup if classes.is_a?(Array)
|
|
30
|
-
return [classes]
|
|
29
|
+
[*wrapper_html_options_raw[:class]]
|
|
31
30
|
end
|
|
32
31
|
|
|
33
32
|
def wrapper_classes
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module Formtastic
|
|
2
3
|
module Inputs
|
|
3
4
|
module Base
|
|
4
|
-
|
|
5
|
+
|
|
5
6
|
attr_accessor :builder, :template, :object, :object_name, :method, :options
|
|
6
|
-
|
|
7
|
+
|
|
7
8
|
def initialize(builder, template, object, object_name, method, options)
|
|
8
9
|
@builder = builder
|
|
9
10
|
@template = template
|
|
@@ -11,30 +12,35 @@ module Formtastic
|
|
|
11
12
|
@object_name = object_name
|
|
12
13
|
@method = method
|
|
13
14
|
@options = options.dup
|
|
15
|
+
|
|
16
|
+
# Deprecate :member_label and :member_value, remove v4.0
|
|
17
|
+
member_deprecation_message = "passing an Array of label/value pairs like [['Justin', 2], ['Kate', 3]] into :collection directly (consider building the array in your model using Model.pluck)"
|
|
18
|
+
warn_deprecated_option!(:member_label, member_deprecation_message)
|
|
19
|
+
warn_deprecated_option!(:member_value, member_deprecation_message)
|
|
14
20
|
end
|
|
15
|
-
|
|
21
|
+
|
|
16
22
|
# Usefull for deprecating options.
|
|
17
23
|
def warn_and_correct_option!(old_option_name, new_option_name)
|
|
18
24
|
if options.key?(old_option_name)
|
|
19
|
-
|
|
25
|
+
Deprecation.warn("The :#{old_option_name} option is deprecated in favour of :#{new_option_name} and will be removed from Formtastic in the next version", caller(6))
|
|
20
26
|
options[new_option_name] = options.delete(old_option_name)
|
|
21
27
|
end
|
|
22
28
|
end
|
|
23
|
-
|
|
29
|
+
|
|
24
30
|
# Usefull for deprecating options.
|
|
25
31
|
def warn_deprecated_option!(old_option_name, instructions)
|
|
26
32
|
if options.key?(old_option_name)
|
|
27
|
-
|
|
33
|
+
Deprecation.warn("The :#{old_option_name} option is deprecated in favour of `#{instructions}`. :#{old_option_name} will be removed in the next version", caller(6))
|
|
28
34
|
end
|
|
29
35
|
end
|
|
30
|
-
|
|
36
|
+
|
|
31
37
|
# Usefull for raising an error on previously supported option.
|
|
32
38
|
def removed_option!(old_option_name)
|
|
33
39
|
raise ArgumentError, ":#{old_option_name} is no longer available" if options.key?(old_option_name)
|
|
34
40
|
end
|
|
35
|
-
|
|
41
|
+
|
|
36
42
|
extend ActiveSupport::Autoload
|
|
37
|
-
|
|
43
|
+
|
|
38
44
|
autoload :DatetimePickerish
|
|
39
45
|
autoload :Associations
|
|
40
46
|
autoload :Collections
|
|
@@ -53,7 +59,7 @@ module Formtastic
|
|
|
53
59
|
autoload :Timeish
|
|
54
60
|
autoload :Validations
|
|
55
61
|
autoload :Wrapping
|
|
56
|
-
|
|
62
|
+
|
|
57
63
|
include Html
|
|
58
64
|
include Options
|
|
59
65
|
include Database
|
|
@@ -65,8 +71,7 @@ module Formtastic
|
|
|
65
71
|
include Associations
|
|
66
72
|
include Labelling
|
|
67
73
|
include Wrapping
|
|
68
|
-
|
|
74
|
+
|
|
69
75
|
end
|
|
70
76
|
end
|
|
71
77
|
end
|
|
72
|
-
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module Formtastic
|
|
2
3
|
module Inputs
|
|
3
4
|
# Boolean inputs are used to render an input for a single checkbox, typically for attributes
|
|
@@ -59,7 +60,7 @@ module Formtastic
|
|
|
59
60
|
end
|
|
60
61
|
|
|
61
62
|
def label_text_with_embedded_checkbox
|
|
62
|
-
check_box_html << "" << label_text
|
|
63
|
+
check_box_html << +"" << label_text
|
|
63
64
|
end
|
|
64
65
|
|
|
65
66
|
def check_box_html
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module Formtastic
|
|
2
3
|
module Inputs
|
|
3
4
|
|
|
@@ -39,6 +40,7 @@ module Formtastic
|
|
|
39
40
|
# <%= f.input :categories, :as => :check_boxes, :collection => @categories %>
|
|
40
41
|
# <%= f.input :categories, :as => :check_boxes, :collection => Category.all %>
|
|
41
42
|
# <%= f.input :categories, :as => :check_boxes, :collection => Category.some_named_scope %>
|
|
43
|
+
# <%= f.input :categories, :as => :check_boxes, :collection => Category.pluck(:label, :id) %>
|
|
42
44
|
# <%= f.input :categories, :as => :check_boxes, :collection => [Category.find_by_name("Ruby"), Category.find_by_name("Rails")] %>
|
|
43
45
|
# <%= f.input :categories, :as => :check_boxes, :collection => ["Ruby", "Rails"] %>
|
|
44
46
|
# <%= f.input :categories, :as => :check_boxes, :collection => [["Ruby", "ruby"], ["Rails", "rails"]] %>
|
|
@@ -56,24 +58,6 @@ module Formtastic
|
|
|
56
58
|
# @example `:disabled` can be used to disable any checkboxes with a value found in the given Array
|
|
57
59
|
# <%= f.input :categories, :as => :check_boxes, :collection => ["a", "b"], :disabled => ["a"] %>
|
|
58
60
|
#
|
|
59
|
-
# @example `:member_label` can be used to call a different method (or a Proc) on each object in the collection for rendering the label text (it'll try the methods like `to_s` in `collection_label_methods` config by default)
|
|
60
|
-
# <%= f.input :categories, :as => :check_boxes, :member_label => :name %>
|
|
61
|
-
# <%= f.input :categories, :as => :check_boxes, :member_label => :name_with_post_count
|
|
62
|
-
# <%= f.input :categories, :as => :check_boxes, :member_label => { |c| "#{c.name} (#{pluralize("post", c.posts.count)})" }
|
|
63
|
-
#
|
|
64
|
-
# @example `:member_label` can be used with a helper method (both examples have the same result)
|
|
65
|
-
# <%= f.input :categories, :as => :check_boxes, :member_label => method(:fancy_label)
|
|
66
|
-
# <%= f.input :categories, :as => :check_boxes, :member_label => Proc.new { |category| fancy_label(category) }
|
|
67
|
-
#
|
|
68
|
-
# @example `:member_value` can be used to call a different method (or a Proc) on each object in the collection for rendering the value for each checkbox (it'll try the methods like `id` in `collection_value_methods` config by default)
|
|
69
|
-
# <%= f.input :categories, :as => :check_boxes, :member_value => :code %>
|
|
70
|
-
# <%= f.input :categories, :as => :check_boxes, :member_value => :isbn
|
|
71
|
-
# <%= f.input :categories, :as => :check_boxes, :member_value => Proc.new { |c| c.name.downcase.underscore }
|
|
72
|
-
#
|
|
73
|
-
# @example `:member_value` can be used with a helper method (both examples have the same result)
|
|
74
|
-
# <%= f.input :categories, :as => :check_boxes, :member_value => method(:some_helper)
|
|
75
|
-
# <%= f.input :categories, :as => :check_boxes, :member_value => Proc.new { |category| some_helper(category) }
|
|
76
|
-
#
|
|
77
61
|
# @example `:value_as_class` can be used to add a class to the `<li>` wrapped around each choice using the checkbox value for custom styling of each choice
|
|
78
62
|
# <%= f.input :categories, :as => :check_boxes, :value_as_class => true %>
|
|
79
63
|
#
|
|
@@ -86,6 +70,11 @@ module Formtastic
|
|
|
86
70
|
include Base::Collections
|
|
87
71
|
include Base::Choices
|
|
88
72
|
|
|
73
|
+
def initialize(*args)
|
|
74
|
+
super
|
|
75
|
+
raise Formtastic::UnsupportedEnumCollection if collection_from_enum?
|
|
76
|
+
end
|
|
77
|
+
|
|
89
78
|
def to_html
|
|
90
79
|
input_wrapping do
|
|
91
80
|
choices_wrapping do
|
|
@@ -111,8 +100,8 @@ module Formtastic
|
|
|
111
100
|
end
|
|
112
101
|
|
|
113
102
|
def hidden_field_for_all
|
|
114
|
-
if
|
|
115
|
-
''
|
|
103
|
+
if hidden_fields_for_every?
|
|
104
|
+
+''
|
|
116
105
|
else
|
|
117
106
|
options = {}
|
|
118
107
|
options[:class] = [method.to_s.singularize, 'default'].join('_') if value_as_class?
|
|
@@ -121,7 +110,7 @@ module Formtastic
|
|
|
121
110
|
end
|
|
122
111
|
end
|
|
123
112
|
|
|
124
|
-
def
|
|
113
|
+
def hidden_fields_for_every?
|
|
125
114
|
options[:hidden_fields]
|
|
126
115
|
end
|
|
127
116
|
|
|
@@ -182,7 +171,7 @@ module Formtastic
|
|
|
182
171
|
protected
|
|
183
172
|
|
|
184
173
|
def checkbox_input(choice)
|
|
185
|
-
if
|
|
174
|
+
if hidden_fields_for_every?
|
|
186
175
|
check_box_with_hidden_input(choice)
|
|
187
176
|
else
|
|
188
177
|
check_box_without_hidden_input(choice)
|
|
@@ -192,11 +181,14 @@ module Formtastic
|
|
|
192
181
|
def make_selected_values
|
|
193
182
|
if object.respond_to?(method)
|
|
194
183
|
selected_items = object.send(method)
|
|
195
|
-
|
|
196
184
|
# Construct an array from the return value, regardless of the return type
|
|
197
185
|
selected_items = [*selected_items].compact.flatten
|
|
198
186
|
|
|
199
|
-
|
|
187
|
+
selected = []
|
|
188
|
+
selected_items.map do |selected_item|
|
|
189
|
+
selected_item_id = selected_item.id if selected_item.respond_to? :id
|
|
190
|
+
item = send_or_call_or_object(value_method, selected_item) || selected_item_id
|
|
191
|
+
end.compact
|
|
200
192
|
else
|
|
201
193
|
[]
|
|
202
194
|
end
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module Formtastic
|
|
2
3
|
module Inputs
|
|
3
4
|
|
|
@@ -31,7 +32,6 @@ module Formtastic
|
|
|
31
32
|
include Base::Placeholder
|
|
32
33
|
|
|
33
34
|
def to_html
|
|
34
|
-
raise "The :color input requires the color_field form helper, which is only available in Rails 4+" unless builder.respond_to?(:color_field)
|
|
35
35
|
input_wrapping do
|
|
36
36
|
label_html <<
|
|
37
37
|
builder.color_field(method, input_html_options)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module Formtastic
|
|
2
3
|
module Inputs
|
|
3
4
|
# Outputs a country select input, wrapping around a regular country_select helper.
|
|
@@ -67,8 +68,10 @@ module Formtastic
|
|
|
67
68
|
class CountryInput
|
|
68
69
|
include Base
|
|
69
70
|
|
|
71
|
+
CountrySelectPluginMissing = Class.new(StandardError)
|
|
72
|
+
|
|
70
73
|
def to_html
|
|
71
|
-
raise "To use the :country input, please install a country_select plugin, like this one: https://github.com/stefanpenner/country_select" unless builder.respond_to?(:country_select)
|
|
74
|
+
raise CountrySelectPluginMissing, "To use the :country input, please install a country_select plugin, like this one: https://github.com/stefanpenner/country_select" unless builder.respond_to?(:country_select)
|
|
72
75
|
input_wrapping do
|
|
73
76
|
label_html <<
|
|
74
77
|
builder.country_select(method, priority_countries, input_options, input_html_options)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Formtastic
|
|
3
|
+
module Inputs
|
|
4
|
+
# Outputs a label and a text field, along with a datalist tag
|
|
5
|
+
# datalist tag provides a list of options which drives a simple autocomplete
|
|
6
|
+
# on the text field. This is a HTML5 feature, more info can be found at
|
|
7
|
+
# {https://developer.mozilla.org/en/docs/Web/HTML/Element/datalist <datalist> at MDN}
|
|
8
|
+
# This input accepts a :collection option which takes data in all the usual formats accepted by
|
|
9
|
+
# {http://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/options_for_select options_for_select}
|
|
10
|
+
#
|
|
11
|
+
# @example Input is used as follows
|
|
12
|
+
# f.input :fav_book, :as => :datalist, :collection => Book.pluck(:name)
|
|
13
|
+
#
|
|
14
|
+
class DatalistInput
|
|
15
|
+
include Base
|
|
16
|
+
include Base::Stringish
|
|
17
|
+
include Base::Collections
|
|
18
|
+
|
|
19
|
+
def to_html
|
|
20
|
+
@name = input_html_options[:id].gsub(/_id$/, "")
|
|
21
|
+
input_wrapping do
|
|
22
|
+
label_html <<
|
|
23
|
+
builder.text_field(method, input_html_options) << # standard input
|
|
24
|
+
data_list_html # append new datalist element
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def input_html_options
|
|
29
|
+
super.merge(:list => html_id_of_datalist)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def html_id_of_datalist
|
|
33
|
+
"#{@name}_datalist"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def data_list_html
|
|
37
|
+
html = builder.template.options_for_select(collection)
|
|
38
|
+
builder.template.content_tag(:datalist,html, { :id => html_id_of_datalist }, false)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module Formtastic
|
|
2
3
|
module Inputs
|
|
3
4
|
|
|
@@ -20,7 +21,7 @@ module Formtastic
|
|
|
20
21
|
# <form...>
|
|
21
22
|
# <fieldset>
|
|
22
23
|
# <ol>
|
|
23
|
-
# <li class="
|
|
24
|
+
# <li class="file">
|
|
24
25
|
# <label for="user_avatar">Avatar</label>
|
|
25
26
|
# <input type="file" id="user_avatar" name="user[avatar]">
|
|
26
27
|
# </li>
|
|
@@ -29,7 +30,7 @@ module Formtastic
|
|
|
29
30
|
# </form>
|
|
30
31
|
#
|
|
31
32
|
# @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
|
|
32
|
-
class FileInput
|
|
33
|
+
class FileInput
|
|
33
34
|
include Base
|
|
34
35
|
def to_html
|
|
35
36
|
input_wrapping do
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module Formtastic
|
|
2
3
|
module Inputs
|
|
3
4
|
|
|
@@ -42,7 +43,7 @@ module Formtastic
|
|
|
42
43
|
end
|
|
43
44
|
|
|
44
45
|
def error_html
|
|
45
|
-
""
|
|
46
|
+
+""
|
|
46
47
|
end
|
|
47
48
|
|
|
48
49
|
def errors?
|
|
@@ -50,7 +51,7 @@ module Formtastic
|
|
|
50
51
|
end
|
|
51
52
|
|
|
52
53
|
def hint_html
|
|
53
|
-
""
|
|
54
|
+
+""
|
|
54
55
|
end
|
|
55
56
|
|
|
56
57
|
def hint?
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module Formtastic
|
|
2
3
|
module Inputs
|
|
3
4
|
|
|
@@ -31,10 +32,13 @@ module Formtastic
|
|
|
31
32
|
# `Section.all` for a `Post` form with an input for a `belongs_to :section` association.
|
|
32
33
|
# You can override or customise this collection through the `:collection` option (see examples).
|
|
33
34
|
#
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
#
|
|
37
|
-
#
|
|
35
|
+
# For radio inputs that map to ActiveRecord `enum` attributes, Formtastic will automatically
|
|
36
|
+
# load in your enum options to be used as the radio button choices. This can be overridden with
|
|
37
|
+
# the `:collection` option, or augmented with I18n translations. See examples below.
|
|
38
|
+
#
|
|
39
|
+
# The way on which Formtastic renders the `value` attribute and label for each choice in the `:collection` is
|
|
40
|
+
# customisable (see examples below). When not provided, we fall back to a list of methods to try on each
|
|
41
|
+
# object such as `:to_label`, `:name` and `:to_s`, which are defined in the configurations
|
|
38
42
|
# `collection_label_methods` and `collection_value_methods`.
|
|
39
43
|
#
|
|
40
44
|
# @example Basic `belongs_to` example with full form context
|
|
@@ -78,6 +82,8 @@ module Formtastic
|
|
|
78
82
|
# <%= f.input :author, :as => :radio, :collection => @authors %>
|
|
79
83
|
# <%= f.input :author, :as => :radio, :collection => Author.all %>
|
|
80
84
|
# <%= f.input :author, :as => :radio, :collection => Author.some_named_scope %>
|
|
85
|
+
# <%= f.input :author, :as => :radio, :collection => Author.pluck(:full_name, :id) %>
|
|
86
|
+
# <%= f.input :author, :as => :radio, :collection => Author.pluck(Arel.sql("CONCAT(`first_name`, ' ', `last_name`)"), :id)) %>
|
|
81
87
|
# <%= f.input :author, :as => :radio, :collection => [Author.find_by_login("justin"), Category.find_by_name("kate")] %>
|
|
82
88
|
# <%= f.input :author, :as => :radio, :collection => ["Justin", "Kate"] %>
|
|
83
89
|
# <%= f.input :author, :as => :radio, :collection => [["Justin", "justin"], ["Kate", "kate"]] %>
|
|
@@ -87,23 +93,6 @@ module Formtastic
|
|
|
87
93
|
# <%= f.input :author, :as => :radio, :collection => [:justin, :kate] %>
|
|
88
94
|
# <%= f.input :author, :as => :radio, :collection => 1..5 %>
|
|
89
95
|
#
|
|
90
|
-
# @example The `:member_label` can be used to call a different method (or a Proc) on each object in the collection for rendering the label text (it'll try the methods like `to_s` in `collection_label_methods` config by default)
|
|
91
|
-
# <%= f.input :author, :as => :radio, :member_label => :name %>
|
|
92
|
-
# <%= f.input :author, :as => :radio, :member_label => :name_with_post_count
|
|
93
|
-
# <%= f.input :author, :as => :radio, :member_label => Proc.new { |a| "#{c.name} (#{pluralize("post", a.posts.count)})" }
|
|
94
|
-
#
|
|
95
|
-
# @example `:member_label` can be used with a helper method (both examples have the same result)
|
|
96
|
-
# <%= f.input :author, :as => :radio, :member_label => method(:fancy_label)
|
|
97
|
-
# <%= f.input :author, :as => :radio, :member_label => Proc.new { |author| fancy_label(author) }
|
|
98
|
-
#
|
|
99
|
-
# @example The `:member_value` can be used to call a different method (or a Proc) on each object in the collection for rendering the value for each checkbox (it'll try the methods like `id` in `collection_value_methods` config by default)
|
|
100
|
-
# <%= f.input :author, :as => :radio, :member_value => :login %>
|
|
101
|
-
# <%= f.input :author, :as => :radio, :member_value => Proc.new { |c| c.full_name.downcase.underscore }
|
|
102
|
-
#
|
|
103
|
-
# @example `:member_value` can be used with a helper method (both examples have the same result)
|
|
104
|
-
# <%= f.input :author, :as => :radio, :member_value => method(:some_helper)
|
|
105
|
-
# <%= f.input :author, :as => :radio, :member_value => Proc.new { |author| some_helper(author) }
|
|
106
|
-
#
|
|
107
96
|
# @example Set HTML attributes on each `<input type="radio">` tag with `:input_html`
|
|
108
97
|
# <%= f.input :author, :as => :radio, :input_html => { :size => 20, :multiple => true, :class => "special" } %>
|
|
109
98
|
#
|
|
@@ -116,6 +105,22 @@ module Formtastic
|
|
|
116
105
|
# @example Set HTML options on a specific radio input option with a 3rd element in the array for a collection member
|
|
117
106
|
# <%= f.input :author, :as => :radio, :collection => [["Test", 'test'], ["Try", "try", {:disabled => true}]]
|
|
118
107
|
#
|
|
108
|
+
# @example Using ActiveRecord enum attribute with i18n translation:
|
|
109
|
+
# # post.rb
|
|
110
|
+
# class Post < ActiveRecord::Base
|
|
111
|
+
# enum :status => [ :active, :archived ]
|
|
112
|
+
# end
|
|
113
|
+
# # en.yml
|
|
114
|
+
# en:
|
|
115
|
+
# activerecord:
|
|
116
|
+
# attributes:
|
|
117
|
+
# post:
|
|
118
|
+
# statuses:
|
|
119
|
+
# active: I am active!
|
|
120
|
+
# archived: I am archived!
|
|
121
|
+
# # form
|
|
122
|
+
# <%= f.input :status, :as => :radio %>
|
|
123
|
+
#
|
|
119
124
|
# @see Formtastic::Helpers::InputsHelper#input InputsHelper#input for full documentation of all possible options.
|
|
120
125
|
# @see Formtastic::Inputs::RadioInput as an alternative for `belongs_to` associations
|
|
121
126
|
#
|