actionview 4.2.11.1 → 7.0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of actionview might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +229 -215
- data/MIT-LICENSE +1 -1
- data/README.rdoc +9 -8
- data/lib/action_view/base.rb +116 -43
- data/lib/action_view/buffers.rb +20 -3
- data/lib/action_view/cache_expiry.rb +66 -0
- data/lib/action_view/context.rb +8 -12
- data/lib/action_view/dependency_tracker/erb_tracker.rb +154 -0
- data/lib/action_view/dependency_tracker/ripper_tracker.rb +59 -0
- data/lib/action_view/dependency_tracker.rb +21 -122
- data/lib/action_view/digestor.rb +92 -85
- data/lib/action_view/flows.rb +15 -16
- data/lib/action_view/gem_version.rb +6 -4
- data/lib/action_view/helpers/active_model_helper.rb +17 -12
- data/lib/action_view/helpers/asset_tag_helper.rb +356 -101
- data/lib/action_view/helpers/asset_url_helper.rb +180 -74
- data/lib/action_view/helpers/atom_feed_helper.rb +21 -19
- data/lib/action_view/helpers/cache_helper.rb +156 -43
- data/lib/action_view/helpers/capture_helper.rb +21 -14
- data/lib/action_view/helpers/controller_helper.rb +16 -5
- data/lib/action_view/helpers/csp_helper.rb +26 -0
- data/lib/action_view/helpers/csrf_helper.rb +8 -6
- data/lib/action_view/helpers/date_helper.rb +288 -132
- data/lib/action_view/helpers/debug_helper.rb +9 -6
- data/lib/action_view/helpers/form_helper.rb +956 -173
- data/lib/action_view/helpers/form_options_helper.rb +178 -97
- data/lib/action_view/helpers/form_tag_helper.rb +220 -101
- data/lib/action_view/helpers/javascript_helper.rb +33 -19
- data/lib/action_view/helpers/number_helper.rb +88 -63
- data/lib/action_view/helpers/output_safety_helper.rb +38 -6
- data/lib/action_view/helpers/rendering_helper.rb +21 -10
- data/lib/action_view/helpers/sanitize_helper.rb +31 -32
- data/lib/action_view/helpers/tag_helper.rb +332 -71
- data/lib/action_view/helpers/tags/base.rb +123 -99
- data/lib/action_view/helpers/tags/check_box.rb +21 -20
- data/lib/action_view/helpers/tags/checkable.rb +4 -2
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +12 -34
- data/lib/action_view/helpers/tags/collection_helpers.rb +69 -36
- data/lib/action_view/helpers/tags/collection_radio_buttons.rb +6 -12
- data/lib/action_view/helpers/tags/collection_select.rb +5 -3
- data/lib/action_view/helpers/tags/color_field.rb +4 -3
- data/lib/action_view/helpers/tags/date_field.rb +3 -2
- data/lib/action_view/helpers/tags/date_select.rb +38 -37
- data/lib/action_view/helpers/tags/datetime_field.rb +4 -3
- data/lib/action_view/helpers/tags/datetime_local_field.rb +3 -2
- data/lib/action_view/helpers/tags/datetime_select.rb +2 -0
- data/lib/action_view/helpers/tags/email_field.rb +2 -0
- data/lib/action_view/helpers/tags/file_field.rb +18 -0
- data/lib/action_view/helpers/tags/grouped_collection_select.rb +4 -2
- data/lib/action_view/helpers/tags/hidden_field.rb +6 -0
- data/lib/action_view/helpers/tags/label.rb +7 -2
- data/lib/action_view/helpers/tags/month_field.rb +3 -2
- data/lib/action_view/helpers/tags/number_field.rb +2 -0
- data/lib/action_view/helpers/tags/password_field.rb +3 -1
- data/lib/action_view/helpers/tags/placeholderable.rb +3 -1
- data/lib/action_view/helpers/tags/radio_button.rb +7 -6
- data/lib/action_view/helpers/tags/range_field.rb +2 -0
- data/lib/action_view/helpers/tags/search_field.rb +14 -9
- data/lib/action_view/helpers/tags/select.rb +11 -10
- data/lib/action_view/helpers/tags/tel_field.rb +2 -0
- data/lib/action_view/helpers/tags/text_area.rb +4 -2
- data/lib/action_view/helpers/tags/text_field.rb +8 -8
- data/lib/action_view/helpers/tags/time_field.rb +12 -2
- data/lib/action_view/helpers/tags/time_select.rb +2 -0
- data/lib/action_view/helpers/tags/time_zone_select.rb +3 -1
- data/lib/action_view/helpers/tags/translator.rb +15 -16
- data/lib/action_view/helpers/tags/url_field.rb +2 -0
- data/lib/action_view/helpers/tags/week_field.rb +3 -2
- data/lib/action_view/helpers/tags/weekday_select.rb +28 -0
- data/lib/action_view/helpers/tags.rb +5 -2
- data/lib/action_view/helpers/text_helper.rb +80 -51
- data/lib/action_view/helpers/translation_helper.rb +120 -69
- data/lib/action_view/helpers/url_helper.rb +398 -171
- data/lib/action_view/helpers.rb +29 -27
- data/lib/action_view/layouts.rb +68 -63
- data/lib/action_view/log_subscriber.rb +77 -10
- data/lib/action_view/lookup_context.rb +137 -113
- data/lib/action_view/model_naming.rb +4 -2
- data/lib/action_view/path_set.rb +28 -32
- data/lib/action_view/railtie.rb +74 -13
- data/lib/action_view/record_identifier.rb +53 -26
- data/lib/action_view/render_parser.rb +188 -0
- data/lib/action_view/renderer/abstract_renderer.rb +152 -15
- data/lib/action_view/renderer/collection_renderer.rb +196 -0
- data/lib/action_view/renderer/object_renderer.rb +34 -0
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +102 -0
- data/lib/action_view/renderer/partial_renderer.rb +51 -333
- data/lib/action_view/renderer/renderer.rb +68 -11
- data/lib/action_view/renderer/streaming_template_renderer.rb +60 -56
- data/lib/action_view/renderer/template_renderer.rb +87 -74
- data/lib/action_view/rendering.rb +73 -47
- data/lib/action_view/ripper_ast_parser.rb +198 -0
- data/lib/action_view/routing_url_for.rb +35 -24
- data/lib/action_view/tasks/cache_digests.rake +25 -0
- data/lib/action_view/template/error.rb +151 -41
- data/lib/action_view/template/handlers/builder.rb +12 -13
- data/lib/action_view/template/handlers/erb/erubi.rb +89 -0
- data/lib/action_view/template/handlers/erb.rb +29 -89
- data/lib/action_view/template/handlers/html.rb +11 -0
- data/lib/action_view/template/handlers/raw.rb +4 -4
- data/lib/action_view/template/handlers.rb +14 -10
- data/lib/action_view/template/html.rb +12 -13
- data/lib/action_view/template/inline.rb +22 -0
- data/lib/action_view/template/raw_file.rb +25 -0
- data/lib/action_view/template/renderable.rb +24 -0
- data/lib/action_view/template/resolver.rb +139 -300
- data/lib/action_view/template/sources/file.rb +17 -0
- data/lib/action_view/template/sources.rb +13 -0
- data/lib/action_view/template/text.rb +10 -12
- data/lib/action_view/template/types.rb +28 -26
- data/lib/action_view/template.rb +123 -91
- data/lib/action_view/template_details.rb +66 -0
- data/lib/action_view/template_path.rb +64 -0
- data/lib/action_view/test_case.rb +70 -53
- data/lib/action_view/testing/resolvers.rb +25 -35
- data/lib/action_view/unbound_template.rb +57 -0
- data/lib/action_view/version.rb +3 -1
- data/lib/action_view/view_paths.rb +73 -58
- data/lib/action_view.rb +16 -11
- data/lib/assets/compiled/rails-ujs.js +746 -0
- metadata +52 -32
- data/lib/action_view/helpers/record_tag_helper.rb +0 -108
- data/lib/action_view/tasks/dependencies.rake +0 -23
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActionView
|
2
4
|
module Helpers
|
3
5
|
module Tags # :nodoc:
|
@@ -11,10 +13,19 @@ module ActionView
|
|
11
13
|
@object_name, @method_name = object_name.to_s.dup, method_name.to_s.dup
|
12
14
|
@template_object = template_object
|
13
15
|
|
14
|
-
@object_name.sub!(/\[\]$/,"") || @object_name.sub!(/\[\]\]$/,"]")
|
16
|
+
@object_name.sub!(/\[\]$/, "") || @object_name.sub!(/\[\]\]$/, "]")
|
15
17
|
@object = retrieve_object(options.delete(:object))
|
18
|
+
@skip_default_ids = options.delete(:skip_default_ids)
|
19
|
+
@allow_method_names_outside_object = options.delete(:allow_method_names_outside_object)
|
16
20
|
@options = options
|
17
|
-
|
21
|
+
|
22
|
+
if Regexp.last_match
|
23
|
+
@generate_indexed_names = true
|
24
|
+
@auto_index = retrieve_autoindex(Regexp.last_match.pre_match)
|
25
|
+
else
|
26
|
+
@generate_indexed_names = false
|
27
|
+
@auto_index = nil
|
28
|
+
end
|
18
29
|
end
|
19
30
|
|
20
31
|
# This is what child classes implement.
|
@@ -23,132 +34,145 @@ module ActionView
|
|
23
34
|
end
|
24
35
|
|
25
36
|
private
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
end
|
30
|
-
|
31
|
-
def value_before_type_cast(object)
|
32
|
-
unless object.nil?
|
33
|
-
method_before_type_cast = @method_name + "_before_type_cast"
|
34
|
-
|
35
|
-
if value_came_from_user?(object) && object.respond_to?(method_before_type_cast)
|
36
|
-
object.public_send(method_before_type_cast)
|
37
|
+
def value
|
38
|
+
if @allow_method_names_outside_object
|
39
|
+
object.public_send @method_name if object && object.respond_to?(@method_name)
|
37
40
|
else
|
38
|
-
|
41
|
+
object.public_send @method_name if object
|
39
42
|
end
|
40
43
|
end
|
41
|
-
end
|
42
44
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
end
|
45
|
+
def value_before_type_cast
|
46
|
+
unless object.nil?
|
47
|
+
method_before_type_cast = @method_name + "_before_type_cast"
|
47
48
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
49
|
+
if value_came_from_user? && object.respond_to?(method_before_type_cast)
|
50
|
+
object.public_send(method_before_type_cast)
|
51
|
+
else
|
52
|
+
value
|
53
|
+
end
|
54
|
+
end
|
53
55
|
end
|
54
|
-
rescue NameError
|
55
|
-
# As @object_name may contain the nested syntax (item[subobject]) we need to fallback to nil.
|
56
|
-
nil
|
57
|
-
end
|
58
56
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
object.to_param
|
63
|
-
else
|
64
|
-
raise ArgumentError, "object[] naming but object param and @object var don't exist or don't respond to to_param: #{object.inspect}"
|
57
|
+
def value_came_from_user?
|
58
|
+
method_name = "#{@method_name}_came_from_user?"
|
59
|
+
!object.respond_to?(method_name) || object.public_send(method_name)
|
65
60
|
end
|
66
|
-
end
|
67
61
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
62
|
+
def retrieve_object(object)
|
63
|
+
if object
|
64
|
+
object
|
65
|
+
elsif @template_object.instance_variable_defined?("@#{@object_name}")
|
66
|
+
@template_object.instance_variable_get("@#{@object_name}")
|
67
|
+
end
|
68
|
+
rescue NameError
|
69
|
+
# As @object_name may contain the nested syntax (item[subobject]) we need to fallback to nil.
|
70
|
+
nil
|
71
|
+
end
|
74
72
|
|
75
|
-
|
76
|
-
|
73
|
+
def retrieve_autoindex(pre_match)
|
74
|
+
object = self.object || @template_object.instance_variable_get("@#{pre_match}")
|
75
|
+
if object && object.respond_to?(:to_param)
|
76
|
+
object.to_param
|
77
|
+
else
|
78
|
+
raise ArgumentError, "object[] naming but object param and @object var don't exist or don't respond to to_param: #{object.inspect}"
|
77
79
|
end
|
78
80
|
end
|
79
|
-
end
|
80
81
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
82
|
+
def add_default_name_and_id_for_value(tag_value, options)
|
83
|
+
if tag_value.nil?
|
84
|
+
add_default_name_and_id(options)
|
85
|
+
else
|
86
|
+
specified_id = options["id"]
|
87
|
+
add_default_name_and_id(options)
|
88
|
+
|
89
|
+
if specified_id.blank? && options["id"].present?
|
90
|
+
options["id"] += "_#{sanitized_value(tag_value)}"
|
91
|
+
end
|
92
|
+
end
|
92
93
|
end
|
93
94
|
|
94
|
-
|
95
|
-
|
95
|
+
def add_default_name_and_id(options)
|
96
|
+
index = name_and_id_index(options)
|
97
|
+
options["name"] = options.fetch("name") { tag_name(options["multiple"], index) }
|
96
98
|
|
97
|
-
|
98
|
-
|
99
|
-
|
99
|
+
if generate_ids?
|
100
|
+
options["id"] = options.fetch("id") { tag_id(index, options.delete("namespace")) }
|
101
|
+
if namespace = options.delete("namespace")
|
102
|
+
options["id"] = options["id"] ? "#{namespace}_#{options['id']}" : namespace
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
100
106
|
|
101
|
-
|
102
|
-
|
103
|
-
|
107
|
+
def tag_name(multiple = false, index = nil)
|
108
|
+
@template_object.field_name(@object_name, sanitized_method_name, multiple: multiple, index: index)
|
109
|
+
end
|
104
110
|
|
105
|
-
|
106
|
-
|
107
|
-
|
111
|
+
def tag_id(index = nil, namespace = nil)
|
112
|
+
@template_object.field_id(@object_name, @method_name, index: index, namespace: namespace)
|
113
|
+
end
|
108
114
|
|
109
|
-
|
110
|
-
|
111
|
-
|
115
|
+
def sanitized_method_name
|
116
|
+
@sanitized_method_name ||= @method_name.delete_suffix("?")
|
117
|
+
end
|
112
118
|
|
113
|
-
|
114
|
-
|
115
|
-
|
119
|
+
def sanitized_value(value)
|
120
|
+
value.to_s.gsub(/[\s.]/, "_").gsub(/[^-[[:word:]]]/, "").downcase
|
121
|
+
end
|
116
122
|
|
117
|
-
|
118
|
-
|
119
|
-
|
123
|
+
def select_content_tag(option_tags, options, html_options)
|
124
|
+
html_options = html_options.stringify_keys
|
125
|
+
add_default_name_and_id(html_options)
|
120
126
|
|
121
|
-
|
122
|
-
|
123
|
-
|
127
|
+
if placeholder_required?(html_options)
|
128
|
+
raise ArgumentError, "include_blank cannot be false for a required field." if options[:include_blank] == false
|
129
|
+
options[:include_blank] ||= true unless options[:prompt]
|
130
|
+
end
|
124
131
|
|
125
|
-
|
126
|
-
|
127
|
-
add_default_name_and_id(html_options)
|
128
|
-
options[:include_blank] ||= true unless options[:prompt] || select_not_required?(html_options)
|
129
|
-
value = options.fetch(:selected) { value(object) }
|
130
|
-
select = content_tag("select", add_options(option_tags, options, value), html_options)
|
132
|
+
value = options.fetch(:selected) { value() }
|
133
|
+
select = content_tag("select", add_options(option_tags, options, value), html_options)
|
131
134
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
135
|
+
if html_options["multiple"] && options.fetch(:include_hidden, true)
|
136
|
+
tag("input", disabled: html_options["disabled"], name: html_options["name"], type: "hidden", value: "", autocomplete: "off") + select
|
137
|
+
else
|
138
|
+
select
|
139
|
+
end
|
136
140
|
end
|
137
|
-
end
|
138
141
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
+
def placeholder_required?(html_options)
|
143
|
+
# See https://html.spec.whatwg.org/multipage/forms.html#attr-select-required
|
144
|
+
html_options["required"] && !html_options["multiple"] && html_options.fetch("size", 1).to_i == 1
|
145
|
+
end
|
142
146
|
|
143
|
-
|
144
|
-
|
145
|
-
|
147
|
+
def add_options(option_tags, options, value = nil)
|
148
|
+
if options[:include_blank]
|
149
|
+
content = (options[:include_blank] if options[:include_blank].is_a?(String))
|
150
|
+
label = (" " unless content)
|
151
|
+
option_tags = tag_builder.content_tag_string("option", content, value: "", label: label) + "\n" + option_tags
|
152
|
+
end
|
153
|
+
|
154
|
+
if value.blank? && options[:prompt]
|
155
|
+
tag_options = { value: "" }.tap do |prompt_opts|
|
156
|
+
prompt_opts[:disabled] = true if options[:disabled] == ""
|
157
|
+
prompt_opts[:selected] = true if options[:selected] == ""
|
158
|
+
end
|
159
|
+
option_tags = tag_builder.content_tag_string("option", prompt_text(options[:prompt]), tag_options) + "\n" + option_tags
|
160
|
+
end
|
161
|
+
|
162
|
+
option_tags
|
163
|
+
end
|
164
|
+
|
165
|
+
def name_and_id_index(options)
|
166
|
+
if options.key?("index")
|
167
|
+
options.delete("index") || ""
|
168
|
+
elsif @generate_indexed_names
|
169
|
+
@auto_index || ""
|
170
|
+
end
|
146
171
|
end
|
147
|
-
|
148
|
-
|
172
|
+
|
173
|
+
def generate_ids?
|
174
|
+
!@skip_default_ids
|
149
175
|
end
|
150
|
-
option_tags
|
151
|
-
end
|
152
176
|
end
|
153
177
|
end
|
154
178
|
end
|
@@ -1,9 +1,11 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "action_view/helpers/tags/checkable"
|
2
4
|
|
3
5
|
module ActionView
|
4
6
|
module Helpers
|
5
7
|
module Tags # :nodoc:
|
6
|
-
class CheckBox < Base
|
8
|
+
class CheckBox < Base # :nodoc:
|
7
9
|
include Checkable
|
8
10
|
|
9
11
|
def initialize(object_name, method_name, template_object, checked_value, unchecked_value, options)
|
@@ -16,7 +18,7 @@ module ActionView
|
|
16
18
|
options = @options.stringify_keys
|
17
19
|
options["type"] = "checkbox"
|
18
20
|
options["value"] = @checked_value
|
19
|
-
options["checked"] = "checked" if input_checked?(
|
21
|
+
options["checked"] = "checked" if input_checked?(options)
|
20
22
|
|
21
23
|
if options["multiple"]
|
22
24
|
add_default_name_and_id_for_value(@checked_value, options)
|
@@ -37,27 +39,26 @@ module ActionView
|
|
37
39
|
end
|
38
40
|
|
39
41
|
private
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
value == @checked_value
|
49
|
-
else
|
50
|
-
if value.respond_to?(:include?)
|
51
|
-
value.include?(@checked_value)
|
42
|
+
def checked?(value)
|
43
|
+
case value
|
44
|
+
when TrueClass, FalseClass
|
45
|
+
value == !!@checked_value
|
46
|
+
when NilClass
|
47
|
+
false
|
48
|
+
when String
|
49
|
+
value == @checked_value
|
52
50
|
else
|
53
|
-
value.
|
51
|
+
if value.respond_to?(:include?)
|
52
|
+
value.include?(@checked_value)
|
53
|
+
else
|
54
|
+
value.to_i == @checked_value.to_i
|
55
|
+
end
|
54
56
|
end
|
55
57
|
end
|
56
|
-
end
|
57
58
|
|
58
|
-
|
59
|
-
|
60
|
-
|
59
|
+
def hidden_field_for_checkbox(options)
|
60
|
+
@unchecked_value ? tag("input", options.slice("name", "disabled", "form").merge!("type" => "hidden", "value" => @unchecked_value, "autocomplete" => "off")) : "".html_safe
|
61
|
+
end
|
61
62
|
end
|
62
63
|
end
|
63
64
|
end
|
@@ -1,13 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActionView
|
2
4
|
module Helpers
|
3
5
|
module Tags # :nodoc:
|
4
6
|
module Checkable # :nodoc:
|
5
|
-
def input_checked?(
|
7
|
+
def input_checked?(options)
|
6
8
|
if options.has_key?("checked")
|
7
9
|
checked = options.delete "checked"
|
8
10
|
checked == true || checked == "checked"
|
9
11
|
else
|
10
|
-
checked?(value
|
12
|
+
checked?(value)
|
11
13
|
end
|
12
14
|
end
|
13
15
|
end
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "action_view/helpers/tags/collection_helpers"
|
2
4
|
|
3
5
|
module ActionView
|
4
6
|
module Helpers
|
@@ -7,50 +9,26 @@ module ActionView
|
|
7
9
|
include CollectionHelpers
|
8
10
|
|
9
11
|
class CheckBoxBuilder < Builder # :nodoc:
|
10
|
-
def check_box(extra_html_options={})
|
12
|
+
def check_box(extra_html_options = {})
|
11
13
|
html_options = extra_html_options.merge(@input_html_options)
|
14
|
+
html_options[:multiple] = true
|
15
|
+
html_options[:skip_default_ids] = false
|
12
16
|
@template_object.check_box(@object_name, @method_name, html_options, @value, nil)
|
13
17
|
end
|
14
18
|
end
|
15
19
|
|
16
20
|
def render(&block)
|
17
|
-
|
18
|
-
default_html_options[:multiple] = true
|
19
|
-
builder = instantiate_builder(CheckBoxBuilder, item, value, text, default_html_options)
|
20
|
-
|
21
|
-
if block_given?
|
22
|
-
@template_object.capture(builder, &block)
|
23
|
-
else
|
24
|
-
render_component(builder)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
# Append a hidden field to make sure something will be sent back to the
|
29
|
-
# server if all check boxes are unchecked.
|
30
|
-
if @options.fetch(:include_hidden, true)
|
31
|
-
rendered_collection + hidden_field
|
32
|
-
else
|
33
|
-
rendered_collection
|
34
|
-
end
|
21
|
+
render_collection_for(CheckBoxBuilder, &block)
|
35
22
|
end
|
36
23
|
|
37
24
|
private
|
38
|
-
|
39
|
-
|
40
|
-
builder.check_box + builder.label
|
41
|
-
end
|
42
|
-
|
43
|
-
def hidden_field
|
44
|
-
hidden_name = @html_options[:name]
|
45
|
-
|
46
|
-
hidden_name ||= if @options.has_key?(:index)
|
47
|
-
"#{tag_name_with_index(@options[:index])}[]"
|
48
|
-
else
|
49
|
-
"#{tag_name}[]"
|
25
|
+
def render_component(builder)
|
26
|
+
builder.check_box + builder.label
|
50
27
|
end
|
51
28
|
|
52
|
-
|
53
|
-
|
29
|
+
def hidden_field_name
|
30
|
+
"#{super}[]"
|
31
|
+
end
|
54
32
|
end
|
55
33
|
end
|
56
34
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActionView
|
2
4
|
module Helpers
|
3
5
|
module Tags # :nodoc:
|
@@ -17,8 +19,10 @@ module ActionView
|
|
17
19
|
@input_html_options = input_html_options
|
18
20
|
end
|
19
21
|
|
20
|
-
def label(label_html_options={}, &block)
|
22
|
+
def label(label_html_options = {}, &block)
|
21
23
|
html_options = @input_html_options.slice(:index, :namespace).merge(label_html_options)
|
24
|
+
html_options[:for] ||= @input_html_options[:id] if @input_html_options[:id]
|
25
|
+
|
22
26
|
@template_object.label(@object_name, @sanitized_attribute_name, @text, html_options, &block)
|
23
27
|
end
|
24
28
|
end
|
@@ -33,52 +37,81 @@ module ActionView
|
|
33
37
|
end
|
34
38
|
|
35
39
|
private
|
40
|
+
def instantiate_builder(builder_class, item, value, text, html_options)
|
41
|
+
builder_class.new(@template_object, @object_name, @method_name, item,
|
42
|
+
sanitize_attribute_name(value), text, value, html_options)
|
43
|
+
end
|
36
44
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
45
|
+
# Generate default options for collection helpers, such as :checked and
|
46
|
+
# :disabled.
|
47
|
+
def default_html_options_for_collection(item, value)
|
48
|
+
html_options = @html_options.dup
|
41
49
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
html_options = @html_options.dup
|
50
|
+
[:checked, :selected, :disabled, :readonly].each do |option|
|
51
|
+
current_value = @options[option]
|
52
|
+
next if current_value.nil?
|
46
53
|
|
47
|
-
|
48
|
-
|
49
|
-
|
54
|
+
accept = if current_value.respond_to?(:call)
|
55
|
+
current_value.call(item)
|
56
|
+
else
|
57
|
+
Array(current_value).map(&:to_s).include?(value.to_s)
|
58
|
+
end
|
50
59
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
60
|
+
if accept
|
61
|
+
html_options[option] = true
|
62
|
+
elsif option == :checked
|
63
|
+
html_options[option] = false
|
64
|
+
end
|
55
65
|
end
|
56
66
|
|
57
|
-
|
58
|
-
|
59
|
-
elsif option == :checked
|
60
|
-
html_options[option] = false
|
61
|
-
end
|
67
|
+
html_options[:object] = @object
|
68
|
+
html_options
|
62
69
|
end
|
63
70
|
|
64
|
-
|
65
|
-
|
66
|
-
|
71
|
+
def sanitize_attribute_name(value)
|
72
|
+
"#{sanitized_method_name}_#{sanitized_value(value)}"
|
73
|
+
end
|
67
74
|
|
68
|
-
|
69
|
-
|
70
|
-
|
75
|
+
def render_collection
|
76
|
+
@collection.map do |item|
|
77
|
+
value = value_for_collection(item, @value_method)
|
78
|
+
text = value_for_collection(item, @text_method)
|
79
|
+
default_html_options = default_html_options_for_collection(item, value)
|
80
|
+
additional_html_options = option_html_attributes(item)
|
71
81
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
text = value_for_collection(item, @text_method)
|
76
|
-
default_html_options = default_html_options_for_collection(item, value)
|
77
|
-
additional_html_options = option_html_attributes(item)
|
82
|
+
yield item, value, text, default_html_options.merge(additional_html_options)
|
83
|
+
end.join.html_safe
|
84
|
+
end
|
78
85
|
|
79
|
-
|
80
|
-
|
81
|
-
|
86
|
+
def render_collection_for(builder_class, &block)
|
87
|
+
options = @options.stringify_keys
|
88
|
+
rendered_collection = render_collection do |item, value, text, default_html_options|
|
89
|
+
builder = instantiate_builder(builder_class, item, value, text, default_html_options)
|
90
|
+
|
91
|
+
if block_given?
|
92
|
+
@template_object.capture(builder, &block)
|
93
|
+
else
|
94
|
+
render_component(builder)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Prepend a hidden field to make sure something will be sent back to the
|
99
|
+
# server if all radio buttons are unchecked.
|
100
|
+
if options.fetch("include_hidden", true)
|
101
|
+
hidden_field + rendered_collection
|
102
|
+
else
|
103
|
+
rendered_collection
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def hidden_field
|
108
|
+
hidden_name = @html_options[:name] || hidden_field_name
|
109
|
+
@template_object.hidden_field_tag(hidden_name, "", id: nil)
|
110
|
+
end
|
111
|
+
|
112
|
+
def hidden_field_name
|
113
|
+
"#{tag_name(false, @options[:index])}"
|
114
|
+
end
|
82
115
|
end
|
83
116
|
end
|
84
117
|
end
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "action_view/helpers/tags/collection_helpers"
|
2
4
|
|
3
5
|
module ActionView
|
4
6
|
module Helpers
|
@@ -7,26 +9,18 @@ module ActionView
|
|
7
9
|
include CollectionHelpers
|
8
10
|
|
9
11
|
class RadioButtonBuilder < Builder # :nodoc:
|
10
|
-
def radio_button(extra_html_options={})
|
12
|
+
def radio_button(extra_html_options = {})
|
11
13
|
html_options = extra_html_options.merge(@input_html_options)
|
14
|
+
html_options[:skip_default_ids] = false
|
12
15
|
@template_object.radio_button(@object_name, @method_name, @value, html_options)
|
13
16
|
end
|
14
17
|
end
|
15
18
|
|
16
19
|
def render(&block)
|
17
|
-
|
18
|
-
builder = instantiate_builder(RadioButtonBuilder, item, value, text, default_html_options)
|
19
|
-
|
20
|
-
if block_given?
|
21
|
-
@template_object.capture(builder, &block)
|
22
|
-
else
|
23
|
-
render_component(builder)
|
24
|
-
end
|
25
|
-
end
|
20
|
+
render_collection_for(RadioButtonBuilder, &block)
|
26
21
|
end
|
27
22
|
|
28
23
|
private
|
29
|
-
|
30
24
|
def render_component(builder)
|
31
25
|
builder.radio_button + builder.label
|
32
26
|
end
|
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActionView
|
2
4
|
module Helpers
|
3
5
|
module Tags # :nodoc:
|
4
|
-
class CollectionSelect < Base
|
6
|
+
class CollectionSelect < Base # :nodoc:
|
5
7
|
def initialize(object_name, method_name, template_object, collection, value_method, text_method, options, html_options)
|
6
8
|
@collection = collection
|
7
9
|
@value_method = value_method
|
@@ -13,8 +15,8 @@ module ActionView
|
|
13
15
|
|
14
16
|
def render
|
15
17
|
option_tags_options = {
|
16
|
-
:
|
17
|
-
:
|
18
|
+
selected: @options.fetch(:selected) { value },
|
19
|
+
disabled: @options[:disabled]
|
18
20
|
}
|
19
21
|
|
20
22
|
select_content_tag(
|
@@ -1,19 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActionView
|
2
4
|
module Helpers
|
3
5
|
module Tags # :nodoc:
|
4
6
|
class ColorField < TextField # :nodoc:
|
5
7
|
def render
|
6
8
|
options = @options.stringify_keys
|
7
|
-
options["value"] ||= validate_color_string(value
|
9
|
+
options["value"] ||= validate_color_string(value)
|
8
10
|
@options = options
|
9
11
|
super
|
10
12
|
end
|
11
13
|
|
12
14
|
private
|
13
|
-
|
14
15
|
def validate_color_string(string)
|
15
16
|
regex = /#[0-9a-fA-F]{6}/
|
16
|
-
if regex.match(string)
|
17
|
+
if regex.match?(string)
|
17
18
|
string.downcase
|
18
19
|
else
|
19
20
|
"#000000"
|
@@ -1,11 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActionView
|
2
4
|
module Helpers
|
3
5
|
module Tags # :nodoc:
|
4
6
|
class DateField < DatetimeField # :nodoc:
|
5
7
|
private
|
6
|
-
|
7
8
|
def format_date(value)
|
8
|
-
value
|
9
|
+
value&.strftime("%Y-%m-%d")
|
9
10
|
end
|
10
11
|
end
|
11
12
|
end
|