actionview 5.0.7.2 → 5.1.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionview might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +92 -384
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/action_view.rb +5 -5
- data/lib/action_view/base.rb +19 -19
- data/lib/action_view/buffers.rb +1 -1
- data/lib/action_view/context.rb +1 -1
- data/lib/action_view/dependency_tracker.rb +4 -5
- data/lib/action_view/digestor.rb +6 -7
- data/lib/action_view/flows.rb +5 -6
- data/lib/action_view/gem_version.rb +3 -3
- data/lib/action_view/helpers.rb +1 -1
- data/lib/action_view/helpers/active_model_helper.rb +8 -8
- data/lib/action_view/helpers/asset_tag_helper.rb +62 -36
- data/lib/action_view/helpers/asset_url_helper.rb +111 -49
- data/lib/action_view/helpers/atom_feed_helper.rb +12 -13
- data/lib/action_view/helpers/cache_helper.rb +34 -20
- data/lib/action_view/helpers/capture_helper.rb +2 -2
- data/lib/action_view/helpers/controller_helper.rb +3 -11
- data/lib/action_view/helpers/csrf_helper.rb +3 -3
- data/lib/action_view/helpers/date_helper.rb +109 -107
- data/lib/action_view/helpers/debug_helper.rb +2 -3
- data/lib/action_view/helpers/form_helper.rb +406 -31
- data/lib/action_view/helpers/form_options_helper.rb +12 -12
- data/lib/action_view/helpers/form_tag_helper.rb +19 -18
- data/lib/action_view/helpers/javascript_helper.rb +6 -6
- data/lib/action_view/helpers/number_helper.rb +48 -46
- data/lib/action_view/helpers/output_safety_helper.rb +8 -8
- data/lib/action_view/helpers/rendering_helper.rb +2 -2
- data/lib/action_view/helpers/sanitize_helper.rb +6 -8
- data/lib/action_view/helpers/tag_helper.rb +194 -77
- data/lib/action_view/helpers/tags/base.rb +121 -102
- data/lib/action_view/helpers/tags/check_box.rb +17 -17
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +8 -8
- data/lib/action_view/helpers/tags/collection_helpers.rb +60 -60
- data/lib/action_view/helpers/tags/collection_radio_buttons.rb +2 -2
- data/lib/action_view/helpers/tags/collection_select.rb +2 -2
- data/lib/action_view/helpers/tags/date_select.rb +36 -36
- data/lib/action_view/helpers/tags/grouped_collection_select.rb +2 -2
- data/lib/action_view/helpers/tags/label.rb +4 -0
- data/lib/action_view/helpers/tags/password_field.rb +1 -1
- data/lib/action_view/helpers/tags/radio_button.rb +4 -4
- data/lib/action_view/helpers/tags/select.rb +9 -9
- data/lib/action_view/helpers/tags/text_area.rb +1 -1
- data/lib/action_view/helpers/tags/text_field.rb +5 -5
- data/lib/action_view/helpers/tags/translator.rb +14 -12
- data/lib/action_view/helpers/text_helper.rb +20 -19
- data/lib/action_view/helpers/translation_helper.rb +6 -6
- data/lib/action_view/helpers/url_helper.rb +42 -38
- data/lib/action_view/layouts.rb +51 -47
- data/lib/action_view/log_subscriber.rb +24 -9
- data/lib/action_view/lookup_context.rb +19 -25
- data/lib/action_view/path_set.rb +19 -19
- data/lib/action_view/railtie.rb +3 -3
- data/lib/action_view/record_identifier.rb +6 -6
- data/lib/action_view/renderer/abstract_renderer.rb +17 -17
- data/lib/action_view/renderer/partial_renderer.rb +188 -187
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +7 -1
- data/lib/action_view/renderer/streaming_template_renderer.rb +45 -47
- data/lib/action_view/renderer/template_renderer.rb +64 -66
- data/lib/action_view/rendering.rb +4 -5
- data/lib/action_view/routing_url_for.rb +9 -13
- data/lib/action_view/tasks/cache_digests.rake +7 -7
- data/lib/action_view/template.rb +26 -27
- data/lib/action_view/template/error.rb +5 -15
- data/lib/action_view/template/handlers.rb +4 -4
- data/lib/action_view/template/handlers/builder.rb +7 -7
- data/lib/action_view/template/handlers/erb.rb +9 -76
- data/lib/action_view/template/handlers/erb/deprecated_erubis.rb +9 -0
- data/lib/action_view/template/handlers/erb/erubi.rb +81 -0
- data/lib/action_view/template/handlers/erb/erubis.rb +81 -0
- data/lib/action_view/template/html.rb +2 -4
- data/lib/action_view/template/resolver.rb +107 -90
- data/lib/action_view/template/text.rb +5 -8
- data/lib/action_view/template/types.rb +1 -1
- data/lib/action_view/test_case.rb +20 -21
- data/lib/action_view/testing/resolvers.rb +29 -30
- data/lib/action_view/version.rb +1 -1
- data/lib/action_view/view_paths.rb +20 -8
- data/lib/assets/compiled/rails-ujs.js +648 -0
- metadata +19 -14
@@ -11,8 +11,10 @@ module ActionView
|
|
11
11
|
@object_name, @method_name = object_name.to_s.dup, method_name.to_s.dup
|
12
12
|
@template_object = template_object
|
13
13
|
|
14
|
-
@object_name.sub!(/\[\]$/,"") || @object_name.sub!(/\[\]\]$/,"]")
|
14
|
+
@object_name.sub!(/\[\]$/, "") || @object_name.sub!(/\[\]\]$/, "]")
|
15
15
|
@object = retrieve_object(options.delete(:object))
|
16
|
+
@skip_default_ids = options.delete(:skip_default_ids)
|
17
|
+
@allow_method_names_outside_object = options.delete(:allow_method_names_outside_object)
|
16
18
|
@options = options
|
17
19
|
|
18
20
|
if Regexp.last_match
|
@@ -31,140 +33,157 @@ module ActionView
|
|
31
33
|
|
32
34
|
private
|
33
35
|
|
34
|
-
|
35
|
-
|
36
|
-
|
36
|
+
def value(object)
|
37
|
+
if @allow_method_names_outside_object
|
38
|
+
object.public_send @method_name if object && object.respond_to?(@method_name)
|
39
|
+
else
|
40
|
+
object.public_send @method_name if object
|
41
|
+
end
|
42
|
+
end
|
37
43
|
|
38
|
-
|
39
|
-
|
40
|
-
|
44
|
+
def value_before_type_cast(object)
|
45
|
+
unless object.nil?
|
46
|
+
method_before_type_cast = @method_name + "_before_type_cast"
|
41
47
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
48
|
+
if value_came_from_user?(object) && object.respond_to?(method_before_type_cast)
|
49
|
+
object.public_send(method_before_type_cast)
|
50
|
+
else
|
51
|
+
value(object)
|
52
|
+
end
|
46
53
|
end
|
47
54
|
end
|
48
|
-
end
|
49
55
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
56
|
+
def value_came_from_user?(object)
|
57
|
+
method_name = "#{@method_name}_came_from_user?"
|
58
|
+
!object.respond_to?(method_name) || object.public_send(method_name)
|
59
|
+
end
|
54
60
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
61
|
+
def retrieve_object(object)
|
62
|
+
if object
|
63
|
+
object
|
64
|
+
elsif @template_object.instance_variable_defined?("@#{@object_name}")
|
65
|
+
@template_object.instance_variable_get("@#{@object_name}")
|
66
|
+
end
|
67
|
+
rescue NameError
|
68
|
+
# As @object_name may contain the nested syntax (item[subobject]) we need to fallback to nil.
|
69
|
+
nil
|
60
70
|
end
|
61
|
-
rescue NameError
|
62
|
-
# As @object_name may contain the nested syntax (item[subobject]) we need to fallback to nil.
|
63
|
-
nil
|
64
|
-
end
|
65
71
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
+
def retrieve_autoindex(pre_match)
|
73
|
+
object = self.object || @template_object.instance_variable_get("@#{pre_match}")
|
74
|
+
if object && object.respond_to?(:to_param)
|
75
|
+
object.to_param
|
76
|
+
else
|
77
|
+
raise ArgumentError, "object[] naming but object param and @object var don't exist or don't respond to to_param: #{object.inspect}"
|
78
|
+
end
|
72
79
|
end
|
73
|
-
end
|
74
80
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
+
def add_default_name_and_id_for_value(tag_value, options)
|
82
|
+
if tag_value.nil?
|
83
|
+
add_default_name_and_id(options)
|
84
|
+
else
|
85
|
+
specified_id = options["id"]
|
86
|
+
add_default_name_and_id(options)
|
81
87
|
|
82
|
-
|
83
|
-
|
88
|
+
if specified_id.blank? && options["id"].present?
|
89
|
+
options["id"] += "_#{sanitized_value(tag_value)}"
|
90
|
+
end
|
84
91
|
end
|
85
92
|
end
|
86
|
-
end
|
87
93
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
+
def add_default_name_and_id(options)
|
95
|
+
index = name_and_id_index(options)
|
96
|
+
options["name"] = options.fetch("name") { tag_name(options["multiple"], index) }
|
97
|
+
|
98
|
+
unless skip_default_ids?
|
99
|
+
options["id"] = options.fetch("id") { tag_id(index) }
|
100
|
+
if namespace = options.delete("namespace")
|
101
|
+
options["id"] = options["id"] ? "#{namespace}_#{options['id']}" : namespace
|
102
|
+
end
|
103
|
+
end
|
94
104
|
end
|
95
|
-
end
|
96
105
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
106
|
+
def tag_name(multiple = false, index = nil)
|
107
|
+
# a little duplication to construct less strings
|
108
|
+
case
|
109
|
+
when @object_name.empty?
|
110
|
+
"#{sanitized_method_name}#{"[]" if multiple}"
|
111
|
+
when index
|
112
|
+
"#{@object_name}[#{index}][#{sanitized_method_name}]#{"[]" if multiple}"
|
113
|
+
else
|
114
|
+
"#{@object_name}[#{sanitized_method_name}]#{"[]" if multiple}"
|
115
|
+
end
|
103
116
|
end
|
104
|
-
end
|
105
117
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
118
|
+
def tag_id(index = nil)
|
119
|
+
# a little duplication to construct less strings
|
120
|
+
case
|
121
|
+
when @object_name.empty?
|
122
|
+
sanitized_method_name.dup
|
123
|
+
when index
|
124
|
+
"#{sanitized_object_name}_#{index}_#{sanitized_method_name}"
|
125
|
+
else
|
126
|
+
"#{sanitized_object_name}_#{sanitized_method_name}"
|
127
|
+
end
|
112
128
|
end
|
113
|
-
end
|
114
129
|
|
115
|
-
|
116
|
-
|
117
|
-
|
130
|
+
def sanitized_object_name
|
131
|
+
@sanitized_object_name ||= @object_name.gsub(/\]\[|[^-a-zA-Z0-9:.]/, "_").sub(/_$/, "")
|
132
|
+
end
|
118
133
|
|
119
|
-
|
120
|
-
|
121
|
-
|
134
|
+
def sanitized_method_name
|
135
|
+
@sanitized_method_name ||= @method_name.sub(/\?$/, "")
|
136
|
+
end
|
122
137
|
|
123
|
-
|
124
|
-
|
125
|
-
|
138
|
+
def sanitized_value(value)
|
139
|
+
value.to_s.gsub(/\s/, "_").gsub(/[^-\w]/, "").downcase
|
140
|
+
end
|
126
141
|
|
127
|
-
|
128
|
-
|
129
|
-
|
142
|
+
def select_content_tag(option_tags, options, html_options)
|
143
|
+
html_options = html_options.stringify_keys
|
144
|
+
add_default_name_and_id(html_options)
|
130
145
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
146
|
+
if placeholder_required?(html_options)
|
147
|
+
raise ArgumentError, "include_blank cannot be false for a required field." if options[:include_blank] == false
|
148
|
+
options[:include_blank] ||= true unless options[:prompt]
|
149
|
+
end
|
135
150
|
|
136
|
-
|
137
|
-
|
151
|
+
value = options.fetch(:selected) { value(object) }
|
152
|
+
select = content_tag("select", add_options(option_tags, options, value), html_options)
|
138
153
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
154
|
+
if html_options["multiple"] && options.fetch(:include_hidden, true)
|
155
|
+
tag("input", disabled: html_options["disabled"], name: html_options["name"], type: "hidden", value: "") + select
|
156
|
+
else
|
157
|
+
select
|
158
|
+
end
|
143
159
|
end
|
144
|
-
end
|
145
160
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
161
|
+
def placeholder_required?(html_options)
|
162
|
+
# See https://html.spec.whatwg.org/multipage/forms.html#attr-select-required
|
163
|
+
html_options["required"] && !html_options["multiple"] && html_options.fetch("size", 1).to_i == 1
|
164
|
+
end
|
150
165
|
|
151
|
-
|
152
|
-
|
153
|
-
|
166
|
+
def add_options(option_tags, options, value = nil)
|
167
|
+
if options[:include_blank]
|
168
|
+
option_tags = tag_builder.content_tag_string("option", options[:include_blank].kind_of?(String) ? options[:include_blank] : nil, value: "") + "\n" + option_tags
|
169
|
+
end
|
170
|
+
if value.blank? && options[:prompt]
|
171
|
+
option_tags = tag_builder.content_tag_string("option", prompt_text(options[:prompt]), value: "") + "\n" + option_tags
|
172
|
+
end
|
173
|
+
option_tags
|
154
174
|
end
|
155
|
-
|
156
|
-
|
175
|
+
|
176
|
+
def name_and_id_index(options)
|
177
|
+
if options.key?("index")
|
178
|
+
options.delete("index") || ""
|
179
|
+
elsif @generate_indexed_names
|
180
|
+
@auto_index || ""
|
181
|
+
end
|
157
182
|
end
|
158
|
-
option_tags
|
159
|
-
end
|
160
183
|
|
161
|
-
|
162
|
-
|
163
|
-
options.delete("index") || ""
|
164
|
-
elsif @generate_indexed_names
|
165
|
-
@auto_index || ""
|
184
|
+
def skip_default_ids?
|
185
|
+
@skip_default_ids
|
166
186
|
end
|
167
|
-
end
|
168
187
|
end
|
169
188
|
end
|
170
189
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "action_view/helpers/tags/checkable"
|
2
2
|
|
3
3
|
module ActionView
|
4
4
|
module Helpers
|
@@ -38,26 +38,26 @@ module ActionView
|
|
38
38
|
|
39
39
|
private
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
else
|
50
|
-
if value.respond_to?(:include?)
|
51
|
-
value.include?(@checked_value)
|
41
|
+
def checked?(value)
|
42
|
+
case value
|
43
|
+
when TrueClass, FalseClass
|
44
|
+
value == !!@checked_value
|
45
|
+
when NilClass
|
46
|
+
false
|
47
|
+
when String
|
48
|
+
value == @checked_value
|
52
49
|
else
|
53
|
-
value.
|
50
|
+
if value.respond_to?(:include?)
|
51
|
+
value.include?(@checked_value)
|
52
|
+
else
|
53
|
+
value.to_i == @checked_value.to_i
|
54
|
+
end
|
54
55
|
end
|
55
56
|
end
|
56
|
-
end
|
57
57
|
|
58
|
-
|
59
|
-
|
60
|
-
|
58
|
+
def hidden_field_for_checkbox(options)
|
59
|
+
@unchecked_value ? tag("input", options.slice("name", "disabled", "form").merge!("type" => "hidden", "value" => @unchecked_value)) : "".html_safe
|
60
|
+
end
|
61
61
|
end
|
62
62
|
end
|
63
63
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "action_view/helpers/tags/collection_helpers"
|
2
2
|
|
3
3
|
module ActionView
|
4
4
|
module Helpers
|
@@ -7,7 +7,7 @@ module ActionView
|
|
7
7
|
include CollectionHelpers
|
8
8
|
|
9
9
|
class CheckBoxBuilder < Builder # :nodoc:
|
10
|
-
def check_box(extra_html_options={})
|
10
|
+
def check_box(extra_html_options = {})
|
11
11
|
html_options = extra_html_options.merge(@input_html_options)
|
12
12
|
html_options[:multiple] = true
|
13
13
|
@template_object.check_box(@object_name, @method_name, html_options, @value, nil)
|
@@ -20,13 +20,13 @@ module ActionView
|
|
20
20
|
|
21
21
|
private
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
def render_component(builder)
|
24
|
+
builder.check_box + builder.label
|
25
|
+
end
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
def hidden_field_name
|
28
|
+
"#{super}[]"
|
29
|
+
end
|
30
30
|
end
|
31
31
|
end
|
32
32
|
end
|
@@ -17,7 +17,7 @@ module ActionView
|
|
17
17
|
@input_html_options = input_html_options
|
18
18
|
end
|
19
19
|
|
20
|
-
def label(label_html_options={}, &block)
|
20
|
+
def label(label_html_options = {}, &block)
|
21
21
|
html_options = @input_html_options.slice(:index, :namespace).merge(label_html_options)
|
22
22
|
html_options[:for] ||= @input_html_options[:id] if @input_html_options[:id]
|
23
23
|
|
@@ -36,81 +36,81 @@ module ActionView
|
|
36
36
|
|
37
37
|
private
|
38
38
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
# Generate default options for collection helpers, such as :checked and
|
45
|
-
# :disabled.
|
46
|
-
def default_html_options_for_collection(item, value) #:nodoc:
|
47
|
-
html_options = @html_options.dup
|
48
|
-
|
49
|
-
[:checked, :selected, :disabled, :readonly].each do |option|
|
50
|
-
current_value = @options[option]
|
51
|
-
next if current_value.nil?
|
39
|
+
def instantiate_builder(builder_class, item, value, text, html_options)
|
40
|
+
builder_class.new(@template_object, @object_name, @method_name, item,
|
41
|
+
sanitize_attribute_name(value), text, value, html_options)
|
42
|
+
end
|
52
43
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
44
|
+
# Generate default options for collection helpers, such as :checked and
|
45
|
+
# :disabled.
|
46
|
+
def default_html_options_for_collection(item, value)
|
47
|
+
html_options = @html_options.dup
|
48
|
+
|
49
|
+
[:checked, :selected, :disabled, :readonly].each do |option|
|
50
|
+
current_value = @options[option]
|
51
|
+
next if current_value.nil?
|
52
|
+
|
53
|
+
accept = if current_value.respond_to?(:call)
|
54
|
+
current_value.call(item)
|
55
|
+
else
|
56
|
+
Array(current_value).map(&:to_s).include?(value.to_s)
|
57
|
+
end
|
58
|
+
|
59
|
+
if accept
|
60
|
+
html_options[option] = true
|
61
|
+
elsif option == :checked
|
62
|
+
html_options[option] = false
|
63
|
+
end
|
57
64
|
end
|
58
65
|
|
59
|
-
|
60
|
-
|
61
|
-
elsif option == :checked
|
62
|
-
html_options[option] = false
|
63
|
-
end
|
66
|
+
html_options[:object] = @object
|
67
|
+
html_options
|
64
68
|
end
|
65
69
|
|
66
|
-
|
67
|
-
|
68
|
-
|
70
|
+
def sanitize_attribute_name(value)
|
71
|
+
"#{sanitized_method_name}_#{sanitized_value(value)}"
|
72
|
+
end
|
69
73
|
|
70
|
-
|
71
|
-
|
72
|
-
|
74
|
+
def render_collection
|
75
|
+
@collection.map do |item|
|
76
|
+
value = value_for_collection(item, @value_method)
|
77
|
+
text = value_for_collection(item, @text_method)
|
78
|
+
default_html_options = default_html_options_for_collection(item, value)
|
79
|
+
additional_html_options = option_html_attributes(item)
|
73
80
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
text = value_for_collection(item, @text_method)
|
78
|
-
default_html_options = default_html_options_for_collection(item, value)
|
79
|
-
additional_html_options = option_html_attributes(item)
|
81
|
+
yield item, value, text, default_html_options.merge(additional_html_options)
|
82
|
+
end.join.html_safe
|
83
|
+
end
|
80
84
|
|
81
|
-
|
82
|
-
|
83
|
-
|
85
|
+
def render_collection_for(builder_class, &block)
|
86
|
+
options = @options.stringify_keys
|
87
|
+
rendered_collection = render_collection do |item, value, text, default_html_options|
|
88
|
+
builder = instantiate_builder(builder_class, item, value, text, default_html_options)
|
84
89
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
90
|
+
if block_given?
|
91
|
+
@template_object.capture(builder, &block)
|
92
|
+
else
|
93
|
+
render_component(builder)
|
94
|
+
end
|
95
|
+
end
|
89
96
|
|
90
|
-
|
91
|
-
|
97
|
+
# Prepend a hidden field to make sure something will be sent back to the
|
98
|
+
# server if all radio buttons are unchecked.
|
99
|
+
if options.fetch("include_hidden", true)
|
100
|
+
hidden_field + rendered_collection
|
92
101
|
else
|
93
|
-
|
102
|
+
rendered_collection
|
94
103
|
end
|
95
104
|
end
|
96
105
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
hidden_field + rendered_collection
|
101
|
-
else
|
102
|
-
rendered_collection
|
106
|
+
def hidden_field
|
107
|
+
hidden_name = @html_options[:name] || hidden_field_name
|
108
|
+
@template_object.hidden_field_tag(hidden_name, "", id: nil)
|
103
109
|
end
|
104
|
-
end
|
105
110
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
end
|
110
|
-
|
111
|
-
def hidden_field_name #:nodoc:
|
112
|
-
"#{tag_name(false, @options[:index])}"
|
113
|
-
end
|
111
|
+
def hidden_field_name
|
112
|
+
"#{tag_name(false, @options[:index])}"
|
113
|
+
end
|
114
114
|
end
|
115
115
|
end
|
116
116
|
end
|