actionview 6.0.0 → 6.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 +4 -4
- data/CHANGELOG.md +169 -162
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/action_view/base.rb +21 -52
- data/lib/action_view/cache_expiry.rb +1 -3
- data/lib/action_view/context.rb +0 -1
- data/lib/action_view/dependency_tracker.rb +10 -4
- data/lib/action_view/digestor.rb +3 -2
- data/lib/action_view/flows.rb +0 -1
- data/lib/action_view/gem_version.rb +1 -1
- data/lib/action_view/helpers/active_model_helper.rb +0 -1
- data/lib/action_view/helpers/asset_tag_helper.rb +41 -16
- data/lib/action_view/helpers/asset_url_helper.rb +6 -4
- data/lib/action_view/helpers/atom_feed_helper.rb +2 -1
- data/lib/action_view/helpers/cache_helper.rb +11 -18
- data/lib/action_view/helpers/date_helper.rb +5 -6
- data/lib/action_view/helpers/form_helper.rb +61 -19
- data/lib/action_view/helpers/form_options_helper.rb +7 -16
- data/lib/action_view/helpers/form_tag_helper.rb +9 -7
- data/lib/action_view/helpers/javascript_helper.rb +7 -5
- data/lib/action_view/helpers/number_helper.rb +9 -8
- data/lib/action_view/helpers/rendering_helper.rb +11 -3
- data/lib/action_view/helpers/sanitize_helper.rb +2 -2
- data/lib/action_view/helpers/tag_helper.rb +94 -19
- data/lib/action_view/helpers/tags/base.rb +9 -6
- data/lib/action_view/helpers/tags/check_box.rb +0 -1
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +0 -1
- data/lib/action_view/helpers/tags/collection_helpers.rb +0 -1
- data/lib/action_view/helpers/tags/collection_radio_buttons.rb +0 -1
- data/lib/action_view/helpers/tags/color_field.rb +0 -1
- data/lib/action_view/helpers/tags/date_field.rb +1 -2
- data/lib/action_view/helpers/tags/date_select.rb +2 -3
- data/lib/action_view/helpers/tags/datetime_field.rb +0 -1
- data/lib/action_view/helpers/tags/datetime_local_field.rb +1 -2
- data/lib/action_view/helpers/tags/label.rb +4 -1
- data/lib/action_view/helpers/tags/month_field.rb +1 -2
- data/lib/action_view/helpers/tags/radio_button.rb +0 -1
- data/lib/action_view/helpers/tags/select.rb +1 -2
- data/lib/action_view/helpers/tags/text_field.rb +0 -1
- data/lib/action_view/helpers/tags/time_field.rb +1 -2
- data/lib/action_view/helpers/tags/week_field.rb +1 -2
- data/lib/action_view/helpers/text_helper.rb +1 -2
- data/lib/action_view/helpers/translation_helper.rb +98 -53
- data/lib/action_view/helpers/url_helper.rb +107 -13
- data/lib/action_view/layouts.rb +3 -5
- data/lib/action_view/log_subscriber.rb +26 -11
- data/lib/action_view/lookup_context.rb +7 -21
- data/lib/action_view/path_set.rb +0 -4
- data/lib/action_view/railtie.rb +35 -46
- data/lib/action_view/record_identifier.rb +0 -1
- data/lib/action_view/renderer/abstract_renderer.rb +92 -14
- data/lib/action_view/renderer/collection_renderer.rb +192 -0
- data/lib/action_view/renderer/object_renderer.rb +34 -0
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +25 -26
- data/lib/action_view/renderer/partial_renderer.rb +20 -283
- data/lib/action_view/renderer/renderer.rb +44 -1
- data/lib/action_view/renderer/streaming_template_renderer.rb +5 -3
- data/lib/action_view/renderer/template_renderer.rb +16 -14
- data/lib/action_view/rendering.rb +3 -2
- data/lib/action_view/routing_url_for.rb +1 -1
- data/lib/action_view/template/error.rb +9 -14
- data/lib/action_view/template/handlers/erb/erubi.rb +9 -7
- data/lib/action_view/template/handlers/erb.rb +10 -15
- data/lib/action_view/template/handlers.rb +0 -26
- data/lib/action_view/template/html.rb +1 -11
- data/lib/action_view/template/raw_file.rb +0 -3
- data/lib/action_view/template/renderable.rb +24 -0
- data/lib/action_view/template/resolver.rb +83 -45
- data/lib/action_view/template/text.rb +0 -3
- data/lib/action_view/template.rb +9 -50
- data/lib/action_view/test_case.rb +20 -28
- data/lib/action_view/testing/resolvers.rb +10 -32
- data/lib/action_view/unbound_template.rb +4 -5
- data/lib/action_view/view_paths.rb +34 -37
- data/lib/action_view.rb +5 -1
- data/lib/assets/compiled/rails-ujs.js +3 -3
- metadata +17 -11
|
@@ -21,7 +21,7 @@ module ActionView
|
|
|
21
21
|
# could become:
|
|
22
22
|
#
|
|
23
23
|
# <select name="post[category]" id="post_category">
|
|
24
|
-
# <option value=""></option>
|
|
24
|
+
# <option value="" label=" "></option>
|
|
25
25
|
# <option value="joke">joke</option>
|
|
26
26
|
# <option value="poem">poem</option>
|
|
27
27
|
# </select>
|
|
@@ -74,7 +74,6 @@ module ActionView
|
|
|
74
74
|
# could become:
|
|
75
75
|
#
|
|
76
76
|
# <select name="post[category]" id="post_category">
|
|
77
|
-
# <option value=""></option>
|
|
78
77
|
# <option value="joke">joke</option>
|
|
79
78
|
# <option value="poem">poem</option>
|
|
80
79
|
# <option disabled="disabled" value="restricted">restricted</option>
|
|
@@ -112,7 +111,7 @@ module ActionView
|
|
|
112
111
|
# would become:
|
|
113
112
|
#
|
|
114
113
|
# <select name="post[person_id]" id="post_person_id">
|
|
115
|
-
# <option value=""></option>
|
|
114
|
+
# <option value="" label=" "></option>
|
|
116
115
|
# <option value="1" selected="selected">David</option>
|
|
117
116
|
# <option value="2">Eileen</option>
|
|
118
117
|
# <option value="3">Rafael</option>
|
|
@@ -143,7 +142,7 @@ module ActionView
|
|
|
143
142
|
#
|
|
144
143
|
# The HTML specification says when +multiple+ parameter passed to select and all options got deselected
|
|
145
144
|
# web browsers do not send any value to server. Unfortunately this introduces a gotcha:
|
|
146
|
-
# if
|
|
145
|
+
# if a +User+ model has many +roles+ and have +role_ids+ accessor, and in the form that edits roles of the user
|
|
147
146
|
# the user deselects all roles from +role_ids+ multiple select box, no +role_ids+ parameter is sent. So,
|
|
148
147
|
# any mass-assignment idiom like
|
|
149
148
|
#
|
|
@@ -569,7 +568,7 @@ module ActionView
|
|
|
569
568
|
# be obtained in Active Record as a value object). The +model+ parameter
|
|
570
569
|
# must respond to +all+ and return an array of objects that represent time
|
|
571
570
|
# zones; each object must respond to +name+. If a Regexp is given it will
|
|
572
|
-
# attempt to match the zones using
|
|
571
|
+
# attempt to match the zones using <code>match?</code> method.
|
|
573
572
|
#
|
|
574
573
|
# NOTE: Only the option tags are returned, you have to wrap this call in
|
|
575
574
|
# a regular HTML select tag.
|
|
@@ -581,7 +580,7 @@ module ActionView
|
|
|
581
580
|
|
|
582
581
|
if priority_zones
|
|
583
582
|
if priority_zones.is_a?(Regexp)
|
|
584
|
-
priority_zones = zones.select { |z| z
|
|
583
|
+
priority_zones = zones.select { |z| z.match?(priority_zones) }
|
|
585
584
|
end
|
|
586
585
|
|
|
587
586
|
zone_options.safe_concat options_for_select(convert_zones[priority_zones], selected)
|
|
@@ -795,7 +794,7 @@ module ActionView
|
|
|
795
794
|
def extract_values_from_collection(collection, value_method, selected)
|
|
796
795
|
if selected.is_a?(Proc)
|
|
797
796
|
collection.map do |element|
|
|
798
|
-
|
|
797
|
+
element.public_send(value_method) if selected.call(element)
|
|
799
798
|
end.compact
|
|
800
799
|
else
|
|
801
800
|
selected
|
|
@@ -803,15 +802,7 @@ module ActionView
|
|
|
803
802
|
end
|
|
804
803
|
|
|
805
804
|
def value_for_collection(item, value)
|
|
806
|
-
value.respond_to?(:call) ? value.call(item) :
|
|
807
|
-
end
|
|
808
|
-
|
|
809
|
-
def public_or_deprecated_send(item, value)
|
|
810
|
-
item.public_send(value)
|
|
811
|
-
rescue NoMethodError
|
|
812
|
-
raise unless item.respond_to?(value, true) && !item.respond_to?(value)
|
|
813
|
-
ActiveSupport::Deprecation.warn "Using private methods from view helpers is deprecated (calling private #{item.class}##{value})"
|
|
814
|
-
item.send(value)
|
|
805
|
+
value.respond_to?(:call) ? value.call(item) : item.public_send(value)
|
|
815
806
|
end
|
|
816
807
|
|
|
817
808
|
def prompt_text(prompt)
|
|
@@ -4,6 +4,7 @@ require "cgi"
|
|
|
4
4
|
require "action_view/helpers/tag_helper"
|
|
5
5
|
require "active_support/core_ext/string/output_safety"
|
|
6
6
|
require "active_support/core_ext/module/attribute_accessors"
|
|
7
|
+
require "active_support/core_ext/symbol/starts_ends_with"
|
|
7
8
|
|
|
8
9
|
module ActionView
|
|
9
10
|
# = Action View Form Tag Helpers
|
|
@@ -134,7 +135,7 @@ module ActionView
|
|
|
134
135
|
# # <option selected="selected">MasterCard</option></select>
|
|
135
136
|
def select_tag(name, option_tags = nil, options = {})
|
|
136
137
|
option_tags ||= ""
|
|
137
|
-
html_name = (options[:multiple] == true && !name.
|
|
138
|
+
html_name = (options[:multiple] == true && !name.end_with?("[]")) ? "#{name}[]" : name
|
|
138
139
|
|
|
139
140
|
if options.include?(:include_blank)
|
|
140
141
|
include_blank = options[:include_blank]
|
|
@@ -166,6 +167,8 @@ module ActionView
|
|
|
166
167
|
# * <tt>:size</tt> - The number of visible characters that will fit in the input.
|
|
167
168
|
# * <tt>:maxlength</tt> - The maximum number of characters that the browser will allow the user to enter.
|
|
168
169
|
# * <tt>:placeholder</tt> - The text contained in the field by default which is removed when the field receives focus.
|
|
170
|
+
# If set to true, use a translation is found in the current I18n locale
|
|
171
|
+
# (through helpers.placeholders.<modelname>.<attribute>).
|
|
169
172
|
# * Any other key creates standard HTML attributes for the tag.
|
|
170
173
|
#
|
|
171
174
|
# ==== Examples
|
|
@@ -894,16 +897,15 @@ module ActionView
|
|
|
894
897
|
end
|
|
895
898
|
|
|
896
899
|
def set_default_disable_with(value, tag_options)
|
|
897
|
-
|
|
898
|
-
data = tag_options["data"]
|
|
900
|
+
data = tag_options.fetch("data", {})
|
|
899
901
|
|
|
900
|
-
|
|
902
|
+
if tag_options["data-disable-with"] == false || data["disable_with"] == false
|
|
903
|
+
data.delete("disable_with")
|
|
904
|
+
elsif ActionView::Base.automatically_disable_submit_tag
|
|
901
905
|
disable_with_text = tag_options["data-disable-with"]
|
|
902
|
-
disable_with_text ||= data["disable_with"]
|
|
906
|
+
disable_with_text ||= data["disable_with"]
|
|
903
907
|
disable_with_text ||= value.to_s.clone
|
|
904
908
|
tag_options.deep_merge!("data" => { "disable_with" => disable_with_text })
|
|
905
|
-
else
|
|
906
|
-
data.delete("disable_with") if data
|
|
907
909
|
end
|
|
908
910
|
|
|
909
911
|
tag_options.delete("data-disable-with")
|
|
@@ -12,7 +12,9 @@ module ActionView
|
|
|
12
12
|
"\n" => '\n',
|
|
13
13
|
"\r" => '\n',
|
|
14
14
|
'"' => '\\"',
|
|
15
|
-
"'" => "\\'"
|
|
15
|
+
"'" => "\\'",
|
|
16
|
+
"`" => "\\`",
|
|
17
|
+
"$" => "\\$"
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
JS_ESCAPE_MAP[(+"\342\200\250").force_encoding(Encoding::UTF_8).encode!] = "
"
|
|
@@ -29,7 +31,7 @@ module ActionView
|
|
|
29
31
|
if javascript.empty?
|
|
30
32
|
result = ""
|
|
31
33
|
else
|
|
32
|
-
result = javascript.gsub(/(\\|<\/|\r\n|\342\200\250|\342\200\251|[\n\r"'])/u
|
|
34
|
+
result = javascript.gsub(/(\\|<\/|\r\n|\342\200\250|\342\200\251|[\n\r"']|[`]|[$])/u, JS_ESCAPE_MAP)
|
|
33
35
|
end
|
|
34
36
|
javascript.html_safe? ? result.html_safe : result
|
|
35
37
|
end
|
|
@@ -49,10 +51,10 @@ module ActionView
|
|
|
49
51
|
# +html_options+ may be a hash of attributes for the <tt>\<script></tt>
|
|
50
52
|
# tag.
|
|
51
53
|
#
|
|
52
|
-
# javascript_tag "alert('All is good')",
|
|
54
|
+
# javascript_tag "alert('All is good')", type: 'application/javascript'
|
|
53
55
|
#
|
|
54
56
|
# Returns:
|
|
55
|
-
# <script
|
|
57
|
+
# <script type="application/javascript">
|
|
56
58
|
# //<![CDATA[
|
|
57
59
|
# alert('All is good')
|
|
58
60
|
# //]]>
|
|
@@ -61,7 +63,7 @@ module ActionView
|
|
|
61
63
|
# Instead of passing the content as an argument, you can also use a block
|
|
62
64
|
# in which case, you pass your +html_options+ as the first parameter.
|
|
63
65
|
#
|
|
64
|
-
# <%= javascript_tag
|
|
66
|
+
# <%= javascript_tag type: 'application/javascript' do -%>
|
|
65
67
|
# alert('All is good')
|
|
66
68
|
# <% end -%>
|
|
67
69
|
#
|
|
@@ -57,7 +57,7 @@ module ActionView
|
|
|
57
57
|
#
|
|
58
58
|
# number_to_phone(75561234567, pattern: /(\d{1,4})(\d{4})(\d{4})$/, area_code: true)
|
|
59
59
|
# # => "(755) 6123-4567"
|
|
60
|
-
# number_to_phone(13312345678, pattern: /(\d{3})(\d{4})(\d{4})$/)
|
|
60
|
+
# number_to_phone(13312345678, pattern: /(\d{3})(\d{4})(\d{4})$/)
|
|
61
61
|
# # => "133-1234-5678"
|
|
62
62
|
def number_to_phone(number, options = {})
|
|
63
63
|
return unless number
|
|
@@ -114,6 +114,8 @@ module ActionView
|
|
|
114
114
|
#
|
|
115
115
|
# number_to_currency("123a456", raise: true) # => InvalidNumberError
|
|
116
116
|
#
|
|
117
|
+
# number_to_currency(-0.456789, precision: 0)
|
|
118
|
+
# # => "$0"
|
|
117
119
|
# number_to_currency(-1234567890.50, negative_format: "(%u%n)")
|
|
118
120
|
# # => ($1,234,567,890.50)
|
|
119
121
|
# number_to_currency(1234567890.50, unit: "R$", separator: ",", delimiter: "")
|
|
@@ -251,7 +253,7 @@ module ActionView
|
|
|
251
253
|
end
|
|
252
254
|
|
|
253
255
|
# Formats the bytes in +number+ into a more understandable
|
|
254
|
-
# representation (e.g., giving it 1500 yields 1.
|
|
256
|
+
# representation (e.g., giving it 1500 yields 1.46 KB). This
|
|
255
257
|
# method is useful for reporting file sizes to users. You can
|
|
256
258
|
# customize the format in the +options+ hash.
|
|
257
259
|
#
|
|
@@ -297,7 +299,7 @@ module ActionView
|
|
|
297
299
|
end
|
|
298
300
|
|
|
299
301
|
# Pretty prints (formats and approximates) a number in a way it
|
|
300
|
-
# is more readable by humans (
|
|
302
|
+
# is more readable by humans (e.g.: 1200000000 becomes "1.2
|
|
301
303
|
# Billion"). This is useful for numbers that can get very large
|
|
302
304
|
# (and too hard to read).
|
|
303
305
|
#
|
|
@@ -305,7 +307,7 @@ module ActionView
|
|
|
305
307
|
# size.
|
|
306
308
|
#
|
|
307
309
|
# You can also define your own unit-quantifier names if you want
|
|
308
|
-
# to use other decimal units (
|
|
310
|
+
# to use other decimal units (e.g.: 1500 becomes "1.5
|
|
309
311
|
# kilometers", 0.150 becomes "150 milliliters", etc). You may
|
|
310
312
|
# define a wide range of unit quantifiers, even fractional ones
|
|
311
313
|
# (centi, deci, mili, etc).
|
|
@@ -403,7 +405,6 @@ module ActionView
|
|
|
403
405
|
end
|
|
404
406
|
|
|
405
407
|
private
|
|
406
|
-
|
|
407
408
|
def delegate_number_helper_method(method, number, options)
|
|
408
409
|
return unless number
|
|
409
410
|
options = escape_unsafe_options(options.symbolize_keys)
|
|
@@ -424,9 +425,9 @@ module ActionView
|
|
|
424
425
|
end
|
|
425
426
|
|
|
426
427
|
def escape_units(units)
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
end
|
|
428
|
+
units.transform_values do |v|
|
|
429
|
+
ERB::Util.html_escape(v)
|
|
430
|
+
end
|
|
430
431
|
end
|
|
431
432
|
|
|
432
433
|
def wrap_with_output_safety_handling(number, raise_on_invalid, &block)
|
|
@@ -22,8 +22,12 @@ module ActionView
|
|
|
22
22
|
# type of <tt>text/plain</tt> from <tt>ActionDispatch::Response</tt>
|
|
23
23
|
# object.
|
|
24
24
|
#
|
|
25
|
-
# If no options hash is passed or
|
|
26
|
-
#
|
|
25
|
+
# If no <tt>options</tt> hash is passed or if <tt>:update</tt> is specified, then:
|
|
26
|
+
#
|
|
27
|
+
# If an object responding to `render_in` is passed, `render_in` is called on the object,
|
|
28
|
+
# passing in the current view context.
|
|
29
|
+
#
|
|
30
|
+
# Otherwise, a partial is rendered using the second parameter as the locals hash.
|
|
27
31
|
def render(options = {}, locals = {}, &block)
|
|
28
32
|
case options
|
|
29
33
|
when Hash
|
|
@@ -35,7 +39,11 @@ module ActionView
|
|
|
35
39
|
end
|
|
36
40
|
end
|
|
37
41
|
else
|
|
38
|
-
|
|
42
|
+
if options.respond_to?(:render_in)
|
|
43
|
+
options.render_in(self, &block)
|
|
44
|
+
else
|
|
45
|
+
view_renderer.render_partial(self, partial: options, locals: locals, &block)
|
|
46
|
+
end
|
|
39
47
|
end
|
|
40
48
|
end
|
|
41
49
|
|
|
@@ -129,11 +129,11 @@ module ActionView
|
|
|
129
129
|
end
|
|
130
130
|
|
|
131
131
|
def sanitized_allowed_tags
|
|
132
|
-
safe_list_sanitizer.allowed_tags
|
|
132
|
+
sanitizer_vendor.safe_list_sanitizer.allowed_tags
|
|
133
133
|
end
|
|
134
134
|
|
|
135
135
|
def sanitized_allowed_attributes
|
|
136
|
-
safe_list_sanitizer.allowed_attributes
|
|
136
|
+
sanitizer_vendor.safe_list_sanitizer.allowed_attributes
|
|
137
137
|
end
|
|
138
138
|
|
|
139
139
|
# Gets the Rails::Html::FullSanitizer instance used by +strip_tags+. Replace with
|
|
@@ -13,19 +13,27 @@ module ActionView
|
|
|
13
13
|
include CaptureHelper
|
|
14
14
|
include OutputSafetyHelper
|
|
15
15
|
|
|
16
|
-
BOOLEAN_ATTRIBUTES = %w(allowfullscreen async autofocus
|
|
17
|
-
compact controls declare default
|
|
18
|
-
defaultmuted defaultselected defer
|
|
19
|
-
enabled formnovalidate hidden indeterminate
|
|
20
|
-
ismap itemscope loop multiple muted nohref
|
|
21
|
-
noresize noshade novalidate nowrap open
|
|
22
|
-
pauseonexit readonly required reversed
|
|
23
|
-
seamless selected sortable truespeed
|
|
24
|
-
visible).to_set
|
|
16
|
+
BOOLEAN_ATTRIBUTES = %w(allowfullscreen allowpaymentrequest async autofocus
|
|
17
|
+
autoplay checked compact controls declare default
|
|
18
|
+
defaultchecked defaultmuted defaultselected defer
|
|
19
|
+
disabled enabled formnovalidate hidden indeterminate
|
|
20
|
+
inert ismap itemscope loop multiple muted nohref
|
|
21
|
+
nomodule noresize noshade novalidate nowrap open
|
|
22
|
+
pauseonexit playsinline readonly required reversed
|
|
23
|
+
scoped seamless selected sortable truespeed
|
|
24
|
+
typemustmatch visible).to_set
|
|
25
25
|
|
|
26
26
|
BOOLEAN_ATTRIBUTES.merge(BOOLEAN_ATTRIBUTES.map(&:to_sym))
|
|
27
|
+
BOOLEAN_ATTRIBUTES.freeze
|
|
27
28
|
|
|
28
|
-
|
|
29
|
+
ARIA_PREFIXES = ["aria", :aria].to_set.freeze
|
|
30
|
+
DATA_PREFIXES = ["data", :data].to_set.freeze
|
|
31
|
+
|
|
32
|
+
TAG_TYPES = {}
|
|
33
|
+
TAG_TYPES.merge! BOOLEAN_ATTRIBUTES.index_with(:boolean)
|
|
34
|
+
TAG_TYPES.merge! DATA_PREFIXES.index_with(:data)
|
|
35
|
+
TAG_TYPES.merge! ARIA_PREFIXES.index_with(:aria)
|
|
36
|
+
TAG_TYPES.freeze
|
|
29
37
|
|
|
30
38
|
PRE_CONTENT_STRINGS = Hash.new { "" }
|
|
31
39
|
PRE_CONTENT_STRINGS[:textarea] = "\n"
|
|
@@ -41,6 +49,10 @@ module ActionView
|
|
|
41
49
|
@view_context = view_context
|
|
42
50
|
end
|
|
43
51
|
|
|
52
|
+
def p(*arguments, **options, &block)
|
|
53
|
+
tag_string(:p, *arguments, **options, &block)
|
|
54
|
+
end
|
|
55
|
+
|
|
44
56
|
def tag_string(name, content = nil, escape_attributes: true, **options, &block)
|
|
45
57
|
content = @view_context.capture(self, &block) if block_given?
|
|
46
58
|
if VOID_ELEMENTS.include?(name) && content.nil?
|
|
@@ -61,13 +73,31 @@ module ActionView
|
|
|
61
73
|
output = +""
|
|
62
74
|
sep = " "
|
|
63
75
|
options.each_pair do |key, value|
|
|
64
|
-
|
|
76
|
+
type = TAG_TYPES[key]
|
|
77
|
+
if type == :data && value.is_a?(Hash)
|
|
78
|
+
value.each_pair do |k, v|
|
|
79
|
+
next if v.nil?
|
|
80
|
+
output << sep
|
|
81
|
+
output << prefix_tag_option(key, k, v, escape)
|
|
82
|
+
end
|
|
83
|
+
elsif type == :aria && value.is_a?(Hash)
|
|
65
84
|
value.each_pair do |k, v|
|
|
66
85
|
next if v.nil?
|
|
86
|
+
|
|
87
|
+
case v
|
|
88
|
+
when Array, Hash
|
|
89
|
+
tokens = TagHelper.build_tag_values(v)
|
|
90
|
+
next if tokens.none?
|
|
91
|
+
|
|
92
|
+
v = safe_join(tokens, " ")
|
|
93
|
+
else
|
|
94
|
+
v = v.to_s
|
|
95
|
+
end
|
|
96
|
+
|
|
67
97
|
output << sep
|
|
68
98
|
output << prefix_tag_option(key, k, v, escape)
|
|
69
99
|
end
|
|
70
|
-
elsif
|
|
100
|
+
elsif type == :boolean
|
|
71
101
|
if value
|
|
72
102
|
output << sep
|
|
73
103
|
output << boolean_tag_option(key)
|
|
@@ -85,12 +115,14 @@ module ActionView
|
|
|
85
115
|
end
|
|
86
116
|
|
|
87
117
|
def tag_option(key, value, escape)
|
|
88
|
-
|
|
118
|
+
case value
|
|
119
|
+
when Array, Hash
|
|
120
|
+
value = TagHelper.build_tag_values(value) if key.to_s == "class"
|
|
89
121
|
value = escape ? safe_join(value, " ") : value.join(" ")
|
|
90
122
|
else
|
|
91
|
-
value = escape ? ERB::Util.unwrapped_html_escape(value) : value.to_s
|
|
123
|
+
value = escape ? ERB::Util.unwrapped_html_escape(value) : value.to_s
|
|
92
124
|
end
|
|
93
|
-
value.gsub
|
|
125
|
+
value = value.gsub('"', """) if value.include?('"')
|
|
94
126
|
%(#{key}="#{value}")
|
|
95
127
|
end
|
|
96
128
|
|
|
@@ -107,8 +139,8 @@ module ActionView
|
|
|
107
139
|
true
|
|
108
140
|
end
|
|
109
141
|
|
|
110
|
-
def method_missing(called, *args, &block)
|
|
111
|
-
tag_string(called, *args, &block)
|
|
142
|
+
def method_missing(called, *args, **options, &block)
|
|
143
|
+
tag_string(called, *args, **options, &block)
|
|
112
144
|
end
|
|
113
145
|
end
|
|
114
146
|
|
|
@@ -152,8 +184,8 @@ module ActionView
|
|
|
152
184
|
# tag.input type: 'text', disabled: true
|
|
153
185
|
# # => <input type="text" disabled="disabled">
|
|
154
186
|
#
|
|
155
|
-
# HTML5 <tt>data-*</tt> attributes can be set with a
|
|
156
|
-
# pointing to a hash of sub-attributes.
|
|
187
|
+
# HTML5 <tt>data-*</tt> and <tt>aria-*</tt> attributes can be set with a
|
|
188
|
+
# single +data+ or +aria+ key pointing to a hash of sub-attributes.
|
|
157
189
|
#
|
|
158
190
|
# To play nicely with JavaScript conventions, sub-attributes are dasherized.
|
|
159
191
|
#
|
|
@@ -233,6 +265,9 @@ module ActionView
|
|
|
233
265
|
#
|
|
234
266
|
# tag("div", data: { name: 'Stephen', city_state: %w(Chicago IL) })
|
|
235
267
|
# # => <div data-name="Stephen" data-city-state="["Chicago","IL"]" />
|
|
268
|
+
#
|
|
269
|
+
# tag("div", class: { highlight: current_user.admin? })
|
|
270
|
+
# # => <div class="highlight" />
|
|
236
271
|
def tag(name = nil, options = nil, open = false, escape = true)
|
|
237
272
|
if name.nil?
|
|
238
273
|
tag_builder
|
|
@@ -260,6 +295,8 @@ module ActionView
|
|
|
260
295
|
# # => <div class="strong"><p>Hello world!</p></div>
|
|
261
296
|
# content_tag(:div, "Hello world!", class: ["strong", "highlight"])
|
|
262
297
|
# # => <div class="strong highlight">Hello world!</div>
|
|
298
|
+
# content_tag(:div, "Hello world!", class: ["strong", { highlight: current_user.admin? }])
|
|
299
|
+
# # => <div class="strong highlight">Hello world!</div>
|
|
263
300
|
# content_tag("select", options, multiple: true)
|
|
264
301
|
# # => <select multiple="multiple">...options...</select>
|
|
265
302
|
#
|
|
@@ -276,6 +313,24 @@ module ActionView
|
|
|
276
313
|
end
|
|
277
314
|
end
|
|
278
315
|
|
|
316
|
+
# Returns a string of tokens built from +args+.
|
|
317
|
+
#
|
|
318
|
+
# ==== Examples
|
|
319
|
+
# token_list("foo", "bar")
|
|
320
|
+
# # => "foo bar"
|
|
321
|
+
# token_list("foo", "foo bar")
|
|
322
|
+
# # => "foo bar"
|
|
323
|
+
# token_list({ foo: true, bar: false })
|
|
324
|
+
# # => "foo"
|
|
325
|
+
# token_list(nil, false, 123, "", "foo", { bar: true })
|
|
326
|
+
# # => "123 foo bar"
|
|
327
|
+
def token_list(*args)
|
|
328
|
+
tokens = build_tag_values(*args).flat_map { |value| value.to_s.split(/\s+/) }.uniq
|
|
329
|
+
|
|
330
|
+
safe_join(tokens, " ")
|
|
331
|
+
end
|
|
332
|
+
alias_method :class_names, :token_list
|
|
333
|
+
|
|
279
334
|
# Returns a CDATA section with the given +content+. CDATA sections
|
|
280
335
|
# are used to escape blocks of text containing characters which would
|
|
281
336
|
# otherwise be recognized as markup. CDATA sections begin with the string
|
|
@@ -306,6 +361,26 @@ module ActionView
|
|
|
306
361
|
end
|
|
307
362
|
|
|
308
363
|
private
|
|
364
|
+
def build_tag_values(*args)
|
|
365
|
+
tag_values = []
|
|
366
|
+
|
|
367
|
+
args.each do |tag_value|
|
|
368
|
+
case tag_value
|
|
369
|
+
when Hash
|
|
370
|
+
tag_value.each do |key, val|
|
|
371
|
+
tag_values << key.to_s if val && key.present?
|
|
372
|
+
end
|
|
373
|
+
when Array
|
|
374
|
+
tag_values.concat build_tag_values(*tag_value)
|
|
375
|
+
else
|
|
376
|
+
tag_values << tag_value.to_s if tag_value.present?
|
|
377
|
+
end
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
tag_values
|
|
381
|
+
end
|
|
382
|
+
module_function :build_tag_values
|
|
383
|
+
|
|
309
384
|
def tag_builder
|
|
310
385
|
@tag_builder ||= TagBuilder.new(self)
|
|
311
386
|
end
|
|
@@ -34,7 +34,6 @@ module ActionView
|
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
private
|
|
37
|
-
|
|
38
37
|
def value
|
|
39
38
|
if @allow_method_names_outside_object
|
|
40
39
|
object.public_send @method_name if object && object.respond_to?(@method_name)
|
|
@@ -106,7 +105,7 @@ module ActionView
|
|
|
106
105
|
end
|
|
107
106
|
|
|
108
107
|
def tag_name(multiple = false, index = nil)
|
|
109
|
-
# a little duplication to construct
|
|
108
|
+
# a little duplication to construct fewer strings
|
|
110
109
|
case
|
|
111
110
|
when @object_name.empty?
|
|
112
111
|
"#{sanitized_method_name}#{multiple ? "[]" : ""}"
|
|
@@ -118,7 +117,7 @@ module ActionView
|
|
|
118
117
|
end
|
|
119
118
|
|
|
120
119
|
def tag_id(index = nil)
|
|
121
|
-
# a little duplication to construct
|
|
120
|
+
# a little duplication to construct fewer strings
|
|
122
121
|
case
|
|
123
122
|
when @object_name.empty?
|
|
124
123
|
sanitized_method_name.dup
|
|
@@ -130,11 +129,11 @@ module ActionView
|
|
|
130
129
|
end
|
|
131
130
|
|
|
132
131
|
def sanitized_object_name
|
|
133
|
-
@sanitized_object_name ||= @object_name.gsub(/\]\[|[^-a-zA-Z0-9:.]/, "_").
|
|
132
|
+
@sanitized_object_name ||= @object_name.gsub(/\]\[|[^-a-zA-Z0-9:.]/, "_").delete_suffix("_")
|
|
134
133
|
end
|
|
135
134
|
|
|
136
135
|
def sanitized_method_name
|
|
137
|
-
@sanitized_method_name ||= @method_name.
|
|
136
|
+
@sanitized_method_name ||= @method_name.delete_suffix("?")
|
|
138
137
|
end
|
|
139
138
|
|
|
140
139
|
def sanitized_value(value)
|
|
@@ -167,8 +166,11 @@ module ActionView
|
|
|
167
166
|
|
|
168
167
|
def add_options(option_tags, options, value = nil)
|
|
169
168
|
if options[:include_blank]
|
|
170
|
-
|
|
169
|
+
content = (options[:include_blank] if options[:include_blank].is_a?(String))
|
|
170
|
+
label = (" " unless content)
|
|
171
|
+
option_tags = tag_builder.content_tag_string("option", content, value: "", label: label) + "\n" + option_tags
|
|
171
172
|
end
|
|
173
|
+
|
|
172
174
|
if value.blank? && options[:prompt]
|
|
173
175
|
tag_options = { value: "" }.tap do |prompt_opts|
|
|
174
176
|
prompt_opts[:disabled] = true if options[:disabled] == ""
|
|
@@ -176,6 +178,7 @@ module ActionView
|
|
|
176
178
|
end
|
|
177
179
|
option_tags = tag_builder.content_tag_string("option", prompt_text(options[:prompt]), tag_options) + "\n" + option_tags
|
|
178
180
|
end
|
|
181
|
+
|
|
179
182
|
option_tags
|
|
180
183
|
end
|
|
181
184
|
|
|
@@ -13,7 +13,7 @@ module ActionView
|
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
def render
|
|
16
|
-
error_wrapping(datetime_selector(@options, @html_options).
|
|
16
|
+
error_wrapping(datetime_selector(@options, @html_options).public_send("select_#{select_type}").html_safe)
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
class << self
|
|
@@ -23,7 +23,6 @@ module ActionView
|
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
private
|
|
26
|
-
|
|
27
26
|
def select_type
|
|
28
27
|
self.class.select_type
|
|
29
28
|
end
|
|
@@ -59,7 +58,7 @@ module ActionView
|
|
|
59
58
|
time = Time.current
|
|
60
59
|
|
|
61
60
|
[:year, :month, :day, :hour, :min, :sec].each do |key|
|
|
62
|
-
default[key] ||= time.
|
|
61
|
+
default[key] ||= time.public_send(key)
|
|
63
62
|
end
|
|
64
63
|
|
|
65
64
|
Time.utc(
|
|
@@ -25,6 +25,10 @@ module ActionView
|
|
|
25
25
|
|
|
26
26
|
content
|
|
27
27
|
end
|
|
28
|
+
|
|
29
|
+
def to_s
|
|
30
|
+
translation
|
|
31
|
+
end
|
|
28
32
|
end
|
|
29
33
|
|
|
30
34
|
def initialize(object_name, method_name, template_object, content_or_options = nil, options = nil)
|
|
@@ -71,7 +75,6 @@ module ActionView
|
|
|
71
75
|
end
|
|
72
76
|
|
|
73
77
|
private
|
|
74
|
-
|
|
75
78
|
def render_component(builder)
|
|
76
79
|
builder.translation
|
|
77
80
|
end
|