actionview 7.0.8.1 → 7.2.2.1
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 +60 -425
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/app/assets/javascripts/rails-ujs.esm.js +686 -0
- data/app/assets/javascripts/rails-ujs.js +630 -0
- data/lib/action_view/base.rb +52 -14
- data/lib/action_view/buffers.rb +106 -8
- data/lib/action_view/cache_expiry.rb +44 -41
- data/lib/action_view/context.rb +1 -1
- data/lib/action_view/dependency_tracker/{ripper_tracker.rb → ruby_tracker.rb} +4 -3
- data/lib/action_view/dependency_tracker.rb +1 -1
- data/lib/action_view/deprecator.rb +7 -0
- data/lib/action_view/digestor.rb +1 -1
- data/lib/action_view/gem_version.rb +3 -3
- data/lib/action_view/helpers/active_model_helper.rb +1 -1
- data/lib/action_view/helpers/asset_tag_helper.rb +151 -55
- data/lib/action_view/helpers/asset_url_helper.rb +6 -5
- data/lib/action_view/helpers/atom_feed_helper.rb +5 -5
- data/lib/action_view/helpers/cache_helper.rb +7 -13
- data/lib/action_view/helpers/capture_helper.rb +30 -10
- data/lib/action_view/helpers/content_exfiltration_prevention_helper.rb +70 -0
- data/lib/action_view/helpers/controller_helper.rb +6 -0
- data/lib/action_view/helpers/csp_helper.rb +2 -2
- data/lib/action_view/helpers/csrf_helper.rb +3 -3
- data/lib/action_view/helpers/date_helper.rb +17 -19
- data/lib/action_view/helpers/debug_helper.rb +3 -3
- data/lib/action_view/helpers/form_helper.rb +248 -214
- data/lib/action_view/helpers/form_options_helper.rb +2 -1
- data/lib/action_view/helpers/form_tag_helper.rb +125 -58
- data/lib/action_view/helpers/javascript_helper.rb +1 -0
- data/lib/action_view/helpers/number_helper.rb +37 -330
- data/lib/action_view/helpers/output_safety_helper.rb +6 -6
- data/lib/action_view/helpers/rendering_helper.rb +1 -1
- data/lib/action_view/helpers/sanitize_helper.rb +51 -21
- data/lib/action_view/helpers/tag_helper.rb +210 -42
- data/lib/action_view/helpers/tags/base.rb +11 -52
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +1 -0
- data/lib/action_view/helpers/tags/collection_radio_buttons.rb +1 -0
- data/lib/action_view/helpers/tags/collection_select.rb +3 -0
- data/lib/action_view/helpers/tags/date_field.rb +1 -1
- data/lib/action_view/helpers/tags/date_select.rb +2 -0
- data/lib/action_view/helpers/tags/datetime_field.rb +14 -6
- data/lib/action_view/helpers/tags/datetime_local_field.rb +11 -2
- data/lib/action_view/helpers/tags/grouped_collection_select.rb +3 -0
- data/lib/action_view/helpers/tags/month_field.rb +1 -1
- data/lib/action_view/helpers/tags/select.rb +3 -0
- data/lib/action_view/helpers/tags/select_renderer.rb +56 -0
- data/lib/action_view/helpers/tags/time_field.rb +1 -1
- data/lib/action_view/helpers/tags/time_zone_select.rb +3 -0
- data/lib/action_view/helpers/tags/week_field.rb +1 -1
- data/lib/action_view/helpers/tags/weekday_select.rb +3 -0
- data/lib/action_view/helpers/tags.rb +2 -0
- data/lib/action_view/helpers/text_helper.rb +157 -85
- data/lib/action_view/helpers/translation_helper.rb +3 -3
- data/lib/action_view/helpers/url_helper.rb +35 -80
- data/lib/action_view/helpers.rb +2 -0
- data/lib/action_view/layouts.rb +8 -8
- data/lib/action_view/log_subscriber.rb +57 -36
- data/lib/action_view/lookup_context.rb +29 -13
- data/lib/action_view/path_registry.rb +57 -0
- data/lib/action_view/path_set.rb +13 -14
- data/lib/action_view/railtie.rb +25 -3
- data/lib/action_view/record_identifier.rb +15 -8
- data/lib/action_view/render_parser/prism_render_parser.rb +127 -0
- data/lib/action_view/render_parser/ripper_render_parser.rb +341 -0
- data/lib/action_view/render_parser.rb +21 -169
- data/lib/action_view/renderer/abstract_renderer.rb +2 -2
- data/lib/action_view/renderer/collection_renderer.rb +10 -2
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +2 -1
- data/lib/action_view/renderer/partial_renderer.rb +2 -1
- data/lib/action_view/renderer/renderer.rb +34 -38
- data/lib/action_view/renderer/streaming_template_renderer.rb +3 -2
- data/lib/action_view/renderer/template_renderer.rb +3 -2
- data/lib/action_view/rendering.rb +26 -8
- data/lib/action_view/template/error.rb +14 -1
- data/lib/action_view/template/handlers/builder.rb +4 -4
- data/lib/action_view/template/handlers/erb/erubi.rb +23 -27
- data/lib/action_view/template/handlers/erb.rb +73 -1
- data/lib/action_view/template/handlers.rb +1 -1
- data/lib/action_view/template/html.rb +1 -1
- data/lib/action_view/template/raw_file.rb +1 -1
- data/lib/action_view/template/renderable.rb +8 -2
- data/lib/action_view/template/resolver.rb +9 -3
- data/lib/action_view/template/text.rb +1 -1
- data/lib/action_view/template/types.rb +25 -34
- data/lib/action_view/template.rb +278 -55
- data/lib/action_view/template_path.rb +2 -0
- data/lib/action_view/test_case.rb +181 -28
- data/lib/action_view/unbound_template.rb +17 -7
- data/lib/action_view/version.rb +1 -1
- data/lib/action_view/view_paths.rb +15 -24
- data/lib/action_view.rb +4 -1
- metadata +31 -31
- data/lib/action_view/ripper_ast_parser.rb +0 -198
- data/lib/assets/compiled/rails-ujs.js +0 -777
@@ -7,8 +7,9 @@ require "action_view/helpers/asset_url_helper"
|
|
7
7
|
require "action_view/helpers/tag_helper"
|
8
8
|
|
9
9
|
module ActionView
|
10
|
-
# = Action View Asset Tag Helpers
|
11
10
|
module Helpers # :nodoc:
|
11
|
+
# = Action View Asset Tag \Helpers
|
12
|
+
#
|
12
13
|
# This module provides methods for generating HTML that links views to assets such
|
13
14
|
# as images, JavaScripts, stylesheets, and feeds. These methods do not verify
|
14
15
|
# the assets exist before linking to them:
|
@@ -41,13 +42,14 @@ module ActionView
|
|
41
42
|
# When the Asset Pipeline is enabled, you can pass the name of your manifest as
|
42
43
|
# source, and include other JavaScript or CoffeeScript files inside the manifest.
|
43
44
|
#
|
44
|
-
# If the server supports Early Hints,
|
45
|
-
#
|
45
|
+
# If the server supports HTTP Early Hints, and the +defer+ option is not
|
46
|
+
# enabled, \Rails will push a <tt>103 Early Hints</tt> response that links
|
47
|
+
# to the assets.
|
46
48
|
#
|
47
49
|
# ==== Options
|
48
50
|
#
|
49
51
|
# When the last parameter is a hash you can add HTML attributes using that
|
50
|
-
# parameter.
|
52
|
+
# parameter. This includes but is not limited to the following options:
|
51
53
|
#
|
52
54
|
# * <tt>:extname</tt> - Append an extension to the generated URL unless the extension
|
53
55
|
# already exists. This only applies for relative URLs.
|
@@ -59,6 +61,22 @@ module ActionView
|
|
59
61
|
# when it is set to true.
|
60
62
|
# * <tt>:nonce</tt> - When set to true, adds an automatic nonce value if
|
61
63
|
# you have Content Security Policy enabled.
|
64
|
+
# * <tt>:async</tt> - When set to +true+, adds the +async+ HTML
|
65
|
+
# attribute, allowing the script to be fetched in parallel to be parsed
|
66
|
+
# and evaluated as soon as possible.
|
67
|
+
# * <tt>:defer</tt> - When set to +true+, adds the +defer+ HTML
|
68
|
+
# attribute, which indicates to the browser that the script is meant to
|
69
|
+
# be executed after the document has been parsed. Additionally, prevents
|
70
|
+
# sending the Preload Links header.
|
71
|
+
# * <tt>:nopush</tt> - Specify if the use of server push is not desired
|
72
|
+
# for the script. Defaults to +true+.
|
73
|
+
#
|
74
|
+
# Any other specified options will be treated as HTML attributes for the
|
75
|
+
# +script+ tag.
|
76
|
+
#
|
77
|
+
# For more information regarding how the <tt>:async</tt> and <tt>:defer</tt>
|
78
|
+
# options affect the <tt><script></tt> tag, please refer to the
|
79
|
+
# {MDN docs}[https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script].
|
62
80
|
#
|
63
81
|
# ==== Examples
|
64
82
|
#
|
@@ -86,10 +104,17 @@ module ActionView
|
|
86
104
|
#
|
87
105
|
# javascript_include_tag "http://www.example.com/xmlhr.js", nonce: true
|
88
106
|
# # => <script src="http://www.example.com/xmlhr.js" nonce="..."></script>
|
107
|
+
#
|
108
|
+
# javascript_include_tag "http://www.example.com/xmlhr.js", async: true
|
109
|
+
# # => <script src="http://www.example.com/xmlhr.js" async="async"></script>
|
110
|
+
#
|
111
|
+
# javascript_include_tag "http://www.example.com/xmlhr.js", defer: true
|
112
|
+
# # => <script src="http://www.example.com/xmlhr.js" defer="defer"></script>
|
89
113
|
def javascript_include_tag(*sources)
|
90
114
|
options = sources.extract_options!.stringify_keys
|
91
115
|
path_options = options.extract!("protocol", "extname", "host", "skip_pipeline").symbolize_keys
|
92
116
|
preload_links = []
|
117
|
+
use_preload_links_header = options["preload_links_header"].nil? ? preload_links_header : options.delete("preload_links_header")
|
93
118
|
nopush = options["nopush"].nil? ? true : options.delete("nopush")
|
94
119
|
crossorigin = options.delete("crossorigin")
|
95
120
|
crossorigin = "anonymous" if crossorigin == true
|
@@ -98,7 +123,7 @@ module ActionView
|
|
98
123
|
|
99
124
|
sources_tags = sources.uniq.map { |source|
|
100
125
|
href = path_to_javascript(source, path_options)
|
101
|
-
if
|
126
|
+
if use_preload_links_header && !options["defer"] && href.present? && !href.start_with?("data:")
|
102
127
|
preload_link = "<#{href}>; rel=#{rel}; as=script"
|
103
128
|
preload_link += "; crossorigin=#{crossorigin}" unless crossorigin.nil?
|
104
129
|
preload_link += "; integrity=#{integrity}" unless integrity.nil?
|
@@ -115,7 +140,7 @@ module ActionView
|
|
115
140
|
content_tag("script", "", tag_options)
|
116
141
|
}.join("\n").html_safe
|
117
142
|
|
118
|
-
if
|
143
|
+
if use_preload_links_header
|
119
144
|
send_preload_links_header(preload_links)
|
120
145
|
end
|
121
146
|
|
@@ -130,8 +155,8 @@ module ActionView
|
|
130
155
|
# set <tt>extname: false</tt> in the options.
|
131
156
|
# You can modify the link attributes by passing a hash as the last argument.
|
132
157
|
#
|
133
|
-
# If the server supports Early Hints,
|
134
|
-
#
|
158
|
+
# If the server supports HTTP Early Hints, \Rails will push a <tt>103 Early
|
159
|
+
# Hints</tt> response that links to the assets.
|
135
160
|
#
|
136
161
|
# ==== Options
|
137
162
|
#
|
@@ -143,6 +168,10 @@ module ActionView
|
|
143
168
|
# that path.
|
144
169
|
# * <tt>:skip_pipeline</tt> - This option is used to bypass the asset pipeline
|
145
170
|
# when it is set to true.
|
171
|
+
# * <tt>:nonce</tt> - When set to true, adds an automatic nonce value if
|
172
|
+
# you have Content Security Policy enabled.
|
173
|
+
# * <tt>:nopush</tt> - Specify if the use of server push is not desired
|
174
|
+
# for the stylesheet. Defaults to +true+.
|
146
175
|
#
|
147
176
|
# ==== Examples
|
148
177
|
#
|
@@ -167,9 +196,13 @@ module ActionView
|
|
167
196
|
# stylesheet_link_tag "random.styles", "/css/stylish"
|
168
197
|
# # => <link href="/assets/random.styles" rel="stylesheet" />
|
169
198
|
# # <link href="/css/stylish.css" rel="stylesheet" />
|
199
|
+
#
|
200
|
+
# stylesheet_link_tag "style", nonce: true
|
201
|
+
# # => <link href="/assets/style.css" rel="stylesheet" nonce="..." />
|
170
202
|
def stylesheet_link_tag(*sources)
|
171
203
|
options = sources.extract_options!.stringify_keys
|
172
204
|
path_options = options.extract!("protocol", "extname", "host", "skip_pipeline").symbolize_keys
|
205
|
+
use_preload_links_header = options["preload_links_header"].nil? ? preload_links_header : options.delete("preload_links_header")
|
173
206
|
preload_links = []
|
174
207
|
crossorigin = options.delete("crossorigin")
|
175
208
|
crossorigin = "anonymous" if crossorigin == true
|
@@ -178,7 +211,7 @@ module ActionView
|
|
178
211
|
|
179
212
|
sources_tags = sources.uniq.map { |source|
|
180
213
|
href = path_to_stylesheet(source, path_options)
|
181
|
-
if
|
214
|
+
if use_preload_links_header && href.present? && !href.start_with?("data:")
|
182
215
|
preload_link = "<#{href}>; rel=preload; as=style"
|
183
216
|
preload_link += "; crossorigin=#{crossorigin}" unless crossorigin.nil?
|
184
217
|
preload_link += "; integrity=#{integrity}" unless integrity.nil?
|
@@ -190,6 +223,9 @@ module ActionView
|
|
190
223
|
"crossorigin" => crossorigin,
|
191
224
|
"href" => href
|
192
225
|
}.merge!(options)
|
226
|
+
if tag_options["nonce"] == true
|
227
|
+
tag_options["nonce"] = content_security_policy_nonce
|
228
|
+
end
|
193
229
|
|
194
230
|
if apply_stylesheet_media_default && tag_options["media"].blank?
|
195
231
|
tag_options["media"] = "screen"
|
@@ -198,7 +234,7 @@ module ActionView
|
|
198
234
|
tag(:link, tag_options)
|
199
235
|
}.join("\n").html_safe
|
200
236
|
|
201
|
-
if
|
237
|
+
if use_preload_links_header
|
202
238
|
send_preload_links_header(preload_links)
|
203
239
|
end
|
204
240
|
|
@@ -327,13 +363,13 @@ module ActionView
|
|
327
363
|
nopush = options.delete(:nopush) || false
|
328
364
|
rel = mime_type == "module" ? "modulepreload" : "preload"
|
329
365
|
|
330
|
-
link_tag = tag.link(
|
366
|
+
link_tag = tag.link(
|
331
367
|
rel: rel,
|
332
368
|
href: href,
|
333
369
|
as: as_type,
|
334
370
|
type: mime_type,
|
335
|
-
crossorigin: crossorigin
|
336
|
-
|
371
|
+
crossorigin: crossorigin,
|
372
|
+
**options.symbolize_keys)
|
337
373
|
|
338
374
|
preload_link = "<#{href}>; rel=#{rel}; as=#{as_type}"
|
339
375
|
preload_link += "; type=#{mime_type}" if mime_type
|
@@ -354,8 +390,8 @@ module ActionView
|
|
354
390
|
# You can add HTML attributes using the +options+. The +options+ supports
|
355
391
|
# additional keys for convenience and conformance:
|
356
392
|
#
|
357
|
-
# * <tt>:size</tt> - Supplied as "{
|
358
|
-
# width="30"
|
393
|
+
# * <tt>:size</tt> - Supplied as <tt>"#{width}x#{height}"</tt> or <tt>"#{number}"</tt>, so <tt>"30x45"</tt> becomes
|
394
|
+
# <tt>width="30" height="45"</tt>, and <tt>"50"</tt> becomes <tt>width="50" height="50"</tt>.
|
359
395
|
# <tt>:size</tt> will be ignored if the value is not in the correct format.
|
360
396
|
# * <tt>:srcset</tt> - If supplied as a hash or array of <tt>[source, descriptor]</tt>
|
361
397
|
# pairs, each image path will be expanded before the list is formatted as a string.
|
@@ -396,7 +432,7 @@ module ActionView
|
|
396
432
|
check_for_image_tag_errors(options)
|
397
433
|
skip_pipeline = options.delete(:skip_pipeline)
|
398
434
|
|
399
|
-
options[:src] =
|
435
|
+
options[:src] = resolve_asset_source("image", source, skip_pipeline)
|
400
436
|
|
401
437
|
if options[:srcset] && !options[:srcset].is_a?(String)
|
402
438
|
options[:srcset] = options[:srcset].map do |src_path, size|
|
@@ -413,11 +449,72 @@ module ActionView
|
|
413
449
|
tag("img", options)
|
414
450
|
end
|
415
451
|
|
452
|
+
# Returns an HTML picture tag for the +sources+. If +sources+ is a string,
|
453
|
+
# a single picture tag will be returned. If +sources+ is an array, a picture
|
454
|
+
# tag with nested source tags for each source will be returned. The
|
455
|
+
# +sources+ can be full paths, files that exist in your public images
|
456
|
+
# directory, or Active Storage attachments. Since the picture tag requires
|
457
|
+
# an img tag, the last element you provide will be used for the img tag.
|
458
|
+
# For complete control over the picture tag, a block can be passed, which
|
459
|
+
# will populate the contents of the tag accordingly.
|
460
|
+
#
|
461
|
+
# ==== Options
|
462
|
+
#
|
463
|
+
# When the last parameter is a hash you can add HTML attributes using that
|
464
|
+
# parameter. Apart from all the HTML supported options, the following are supported:
|
465
|
+
#
|
466
|
+
# * <tt>:image</tt> - Hash of options that are passed directly to the +image_tag+ helper.
|
467
|
+
#
|
468
|
+
# ==== Examples
|
469
|
+
#
|
470
|
+
# picture_tag("picture.webp")
|
471
|
+
# # => <picture><img src="/images/picture.webp" /></picture>
|
472
|
+
# picture_tag("gold.png", :image => { :size => "20" })
|
473
|
+
# # => <picture><img height="20" src="/images/gold.png" width="20" /></picture>
|
474
|
+
# picture_tag("gold.png", :image => { :size => "45x70" })
|
475
|
+
# # => <picture><img height="70" src="/images/gold.png" width="45" /></picture>
|
476
|
+
# picture_tag("picture.webp", "picture.png")
|
477
|
+
# # => <picture><source srcset="/images/picture.webp" /><source srcset="/images/picture.png" /><img src="/images/picture.png" /></picture>
|
478
|
+
# picture_tag("picture.webp", "picture.png", :image => { alt: "Image" })
|
479
|
+
# # => <picture><source srcset="/images/picture.webp" /><source srcset="/images/picture.png" /><img alt="Image" src="/images/picture.png" /></picture>
|
480
|
+
# picture_tag(["picture.webp", "picture.png"], :image => { alt: "Image" })
|
481
|
+
# # => <picture><source srcset="/images/picture.webp" /><source srcset="/images/picture.png" /><img alt="Image" src="/images/picture.png" /></picture>
|
482
|
+
# picture_tag(:class => "my-class") { tag(:source, :srcset => image_path("picture.webp")) + image_tag("picture.png", :alt => "Image") }
|
483
|
+
# # => <picture class="my-class"><source srcset="/images/picture.webp" /><img alt="Image" src="/images/picture.png" /></picture>
|
484
|
+
# picture_tag { tag(:source, :srcset => image_path("picture-small.webp"), :media => "(min-width: 600px)") + tag(:source, :srcset => image_path("picture-big.webp")) + image_tag("picture.png", :alt => "Image") }
|
485
|
+
# # => <picture><source srcset="/images/picture-small.webp" media="(min-width: 600px)" /><source srcset="/images/picture-big.webp" /><img alt="Image" src="/images/picture.png" /></picture>
|
486
|
+
#
|
487
|
+
# Active Storage blobs (images that are uploaded by the users of your app):
|
488
|
+
#
|
489
|
+
# picture_tag(user.profile_picture)
|
490
|
+
# # => <picture><img src="/rails/active_storage/blobs/.../profile_picture.webp" /></picture>
|
491
|
+
def picture_tag(*sources, &block)
|
492
|
+
sources.flatten!
|
493
|
+
options = sources.extract_options!.symbolize_keys
|
494
|
+
image_options = options.delete(:image) || {}
|
495
|
+
skip_pipeline = options.delete(:skip_pipeline)
|
496
|
+
|
497
|
+
content_tag("picture", options) do
|
498
|
+
if block.present?
|
499
|
+
capture(&block).html_safe
|
500
|
+
elsif sources.size <= 1
|
501
|
+
image_tag(sources.last, image_options)
|
502
|
+
else
|
503
|
+
source_tags = sources.map do |source|
|
504
|
+
tag("source",
|
505
|
+
srcset: resolve_asset_source("image", source, skip_pipeline),
|
506
|
+
type: Template::Types[File.extname(source)[1..]]&.to_s)
|
507
|
+
end
|
508
|
+
safe_join(source_tags << image_tag(sources.last, image_options))
|
509
|
+
end
|
510
|
+
end
|
511
|
+
end
|
512
|
+
|
416
513
|
# Returns an HTML video tag for the +sources+. If +sources+ is a string,
|
417
514
|
# a single video tag will be returned. If +sources+ is an array, a video
|
418
515
|
# tag with nested source tags for each source will be returned. The
|
419
|
-
# +sources+ can be full paths
|
420
|
-
# directory.
|
516
|
+
# +sources+ can be full paths, files that exist in your public videos
|
517
|
+
# directory, or Active Storage attachments.
|
421
518
|
#
|
422
519
|
# ==== Options
|
423
520
|
#
|
@@ -426,8 +523,8 @@ module ActionView
|
|
426
523
|
#
|
427
524
|
# * <tt>:poster</tt> - Set an image (like a screenshot) to be shown
|
428
525
|
# before the video loads. The path is calculated like the +src+ of +image_tag+.
|
429
|
-
# * <tt>:size</tt> - Supplied as "{
|
430
|
-
# width="30"
|
526
|
+
# * <tt>:size</tt> - Supplied as <tt>"#{width}x#{height}"</tt> or <tt>"#{number}"</tt>, so <tt>"30x45"</tt> becomes
|
527
|
+
# <tt>width="30" height="45"</tt>, and <tt>"50"</tt> becomes <tt>width="50" height="50"</tt>.
|
431
528
|
# <tt>:size</tt> will be ignored if the value is not in the correct format.
|
432
529
|
# * <tt>:poster_skip_pipeline</tt> will bypass the asset pipeline when using
|
433
530
|
# the <tt>:poster</tt> option instead using an asset in the public folder.
|
@@ -456,6 +553,11 @@ module ActionView
|
|
456
553
|
# # => <video><source src="/videos/trailer.ogg" /><source src="/videos/trailer.flv" /></video>
|
457
554
|
# video_tag(["trailer.ogg", "trailer.flv"], size: "160x120")
|
458
555
|
# # => <video height="120" width="160"><source src="/videos/trailer.ogg" /><source src="/videos/trailer.flv" /></video>
|
556
|
+
#
|
557
|
+
# Active Storage blobs (videos that are uploaded by the users of your app):
|
558
|
+
#
|
559
|
+
# video_tag(user.intro_video)
|
560
|
+
# # => <video src="/rails/active_storage/blobs/.../intro_video.mp4"></video>
|
459
561
|
def video_tag(*sources)
|
460
562
|
options = sources.extract_options!.symbolize_keys
|
461
563
|
public_poster_folder = options.delete(:poster_skip_pipeline)
|
@@ -469,8 +571,8 @@ module ActionView
|
|
469
571
|
# Returns an HTML audio tag for the +sources+. If +sources+ is a string,
|
470
572
|
# a single audio tag will be returned. If +sources+ is an array, an audio
|
471
573
|
# tag with nested source tags for each source will be returned. The
|
472
|
-
# +sources+ can be full paths
|
473
|
-
# directory.
|
574
|
+
# +sources+ can be full paths, files that exist in your public audios
|
575
|
+
# directory, or Active Storage attachments.
|
474
576
|
#
|
475
577
|
# When the last parameter is a hash you can add HTML attributes using that
|
476
578
|
# parameter.
|
@@ -483,6 +585,11 @@ module ActionView
|
|
483
585
|
# # => <audio autoplay="autoplay" controls="controls" src="/audios/sound.wav"></audio>
|
484
586
|
# audio_tag("sound.wav", "sound.mid")
|
485
587
|
# # => <audio><source src="/audios/sound.wav" /><source src="/audios/sound.mid" /></audio>
|
588
|
+
#
|
589
|
+
# Active Storage blobs (audios that are uploaded by the users of your app):
|
590
|
+
#
|
591
|
+
# audio_tag(user.name_pronunciation_audio)
|
592
|
+
# # => <audio src="/rails/active_storage/blobs/.../name_pronunciation_audio.mp3"></audio>
|
486
593
|
def audio_tag(*sources)
|
487
594
|
multiple_sources_tag_builder("audio", sources)
|
488
595
|
end
|
@@ -497,29 +604,29 @@ module ActionView
|
|
497
604
|
|
498
605
|
if sources.size > 1
|
499
606
|
content_tag(type, options) do
|
500
|
-
safe_join sources.map { |source| tag("source", src:
|
607
|
+
safe_join sources.map { |source| tag("source", src: resolve_asset_source(type, source, skip_pipeline)) }
|
501
608
|
end
|
502
609
|
else
|
503
|
-
options[:src] =
|
610
|
+
options[:src] = resolve_asset_source(type, sources.first, skip_pipeline)
|
504
611
|
content_tag(type, nil, options)
|
505
612
|
end
|
506
613
|
end
|
507
614
|
|
508
|
-
def
|
615
|
+
def resolve_asset_source(asset_type, source, skip_pipeline)
|
509
616
|
if source.is_a?(Symbol) || source.is_a?(String)
|
510
|
-
|
617
|
+
path_to_asset(source, type: asset_type.to_sym, skip_pipeline: skip_pipeline)
|
511
618
|
else
|
512
619
|
polymorphic_url(source)
|
513
620
|
end
|
514
621
|
rescue NoMethodError => e
|
515
|
-
raise ArgumentError, "Can't resolve
|
622
|
+
raise ArgumentError, "Can't resolve #{asset_type} into URL: #{e}"
|
516
623
|
end
|
517
624
|
|
518
625
|
def extract_dimensions(size)
|
519
626
|
size = size.to_s
|
520
|
-
if /\A
|
627
|
+
if /\A\d+(?:\.\d+)?x\d+(?:\.\d+)?\z/.match?(size)
|
521
628
|
size.split("x")
|
522
|
-
elsif /\A
|
629
|
+
elsif /\A\d+(?:\.\d+)?\z/.match?(size)
|
523
630
|
[size, size]
|
524
631
|
end
|
525
632
|
end
|
@@ -540,43 +647,32 @@ module ActionView
|
|
540
647
|
end
|
541
648
|
end
|
542
649
|
|
543
|
-
|
650
|
+
# Some HTTP client and proxies have a 4kiB header limit, but more importantly
|
651
|
+
# including preload links has diminishing returns so it's best to not go overboard
|
652
|
+
MAX_HEADER_SIZE = 1_000 # :nodoc:
|
653
|
+
|
544
654
|
def send_preload_links_header(preload_links, max_header_size: MAX_HEADER_SIZE)
|
545
655
|
return if preload_links.empty?
|
546
|
-
|
656
|
+
response_present = respond_to?(:response) && response
|
657
|
+
return if response_present && response.sending?
|
547
658
|
|
548
659
|
if respond_to?(:request) && request
|
549
|
-
request.send_early_hints("
|
660
|
+
request.send_early_hints("link" => preload_links.join(","))
|
550
661
|
end
|
551
662
|
|
552
|
-
if
|
553
|
-
header = response.headers["
|
554
|
-
header = header ? header.dup : +""
|
555
|
-
|
556
|
-
# rindex count characters not bytes, but we assume non-ascii characters
|
557
|
-
# are rare in urls, and we have a 192 bytes margin.
|
558
|
-
last_line_offset = header.rindex("\n")
|
559
|
-
last_line_size = if last_line_offset
|
560
|
-
header.bytesize - last_line_offset
|
561
|
-
else
|
562
|
-
header.bytesize
|
563
|
-
end
|
564
|
-
|
663
|
+
if response_present
|
664
|
+
header = +response.headers["link"].to_s
|
565
665
|
preload_links.each do |link|
|
566
|
-
if
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
end
|
666
|
+
break if header.bytesize + link.bytesize > max_header_size
|
667
|
+
|
668
|
+
if header.empty?
|
669
|
+
header << link
|
571
670
|
else
|
572
|
-
header << "
|
573
|
-
last_line_size = 0
|
671
|
+
header << "," << link
|
574
672
|
end
|
575
|
-
header << link
|
576
|
-
last_line_size += link.bytesize
|
577
673
|
end
|
578
674
|
|
579
|
-
response.headers["
|
675
|
+
response.headers["link"] = header
|
580
676
|
end
|
581
677
|
end
|
582
678
|
end
|
@@ -3,8 +3,9 @@
|
|
3
3
|
require "zlib"
|
4
4
|
|
5
5
|
module ActionView
|
6
|
-
# = Action View Asset URL Helpers
|
7
6
|
module Helpers # :nodoc:
|
7
|
+
# = Action View Asset URL \Helpers
|
8
|
+
#
|
8
9
|
# This module provides methods for generating asset paths and
|
9
10
|
# URLs.
|
10
11
|
#
|
@@ -16,8 +17,8 @@ module ActionView
|
|
16
17
|
#
|
17
18
|
# === Using asset hosts
|
18
19
|
#
|
19
|
-
# By default, Rails links to these assets on the current host in the public
|
20
|
-
# folder, but you can direct Rails to link to assets from a dedicated asset
|
20
|
+
# By default, \Rails links to these assets on the current host in the public
|
21
|
+
# folder, but you can direct \Rails to link to assets from a dedicated asset
|
21
22
|
# server by setting <tt>ActionController::Base.asset_host</tt> in the application
|
22
23
|
# configuration, typically in <tt>config/environments/production.rb</tt>.
|
23
24
|
# For example, you'd define <tt>assets.example.com</tt> to be your asset
|
@@ -196,7 +197,7 @@ module ActionView
|
|
196
197
|
source = "#{source}#{extname}"
|
197
198
|
end
|
198
199
|
|
199
|
-
|
200
|
+
unless source.start_with?(?/)
|
200
201
|
if options[:skip_pipeline]
|
201
202
|
source = public_compute_asset_path(source, options)
|
202
203
|
else
|
@@ -372,7 +373,7 @@ module ActionView
|
|
372
373
|
# image_path("http://www.example.com/img/edit.png") # => "http://www.example.com/img/edit.png"
|
373
374
|
#
|
374
375
|
# If you have images as application resources this method may conflict with their named routes.
|
375
|
-
# The alias +path_to_image+ is provided to avoid that. Rails uses the alias internally, and
|
376
|
+
# The alias +path_to_image+ is provided to avoid that. \Rails uses the alias internally, and
|
376
377
|
# plugin authors are encouraged to do so.
|
377
378
|
def image_path(source, options = {})
|
378
379
|
path_to_asset(source, { type: :image }.merge!(options))
|
@@ -3,8 +3,8 @@
|
|
3
3
|
require "set"
|
4
4
|
|
5
5
|
module ActionView
|
6
|
-
# = Action View Atom Feed Helpers
|
7
6
|
module Helpers # :nodoc:
|
7
|
+
# = Action View Atom Feed \Helpers
|
8
8
|
module AtomFeedHelper
|
9
9
|
# Adds easy defaults to writing Atom feeds with the Builder template engine (this does not work on ERB or any other
|
10
10
|
# template languages).
|
@@ -82,9 +82,9 @@ module ActionView
|
|
82
82
|
# end
|
83
83
|
#
|
84
84
|
# The Atom spec defines five elements (content rights title subtitle
|
85
|
-
# summary) which may directly contain
|
85
|
+
# summary) which may directly contain XHTML content if type: 'xhtml'
|
86
86
|
# is specified as an attribute. If so, this helper will take care of
|
87
|
-
# the enclosing div and
|
87
|
+
# the enclosing div and XHTML namespace declaration. Example usage:
|
88
88
|
#
|
89
89
|
# entry.summary type: 'xhtml' do |xhtml|
|
90
90
|
# xhtml.p pluralize(order.line_items.count, "line item")
|
@@ -102,7 +102,7 @@ module ActionView
|
|
102
102
|
options[:schema_date] = "2005" # The Atom spec copyright date
|
103
103
|
end
|
104
104
|
|
105
|
-
xml = options.delete(:xml) ||
|
105
|
+
xml = options.delete(:xml) || block.binding.local_variable_get(:xml)
|
106
106
|
xml.instruct!
|
107
107
|
if options[:instruct]
|
108
108
|
options[:instruct].each do |target, attrs|
|
@@ -134,7 +134,7 @@ module ActionView
|
|
134
134
|
end
|
135
135
|
|
136
136
|
private
|
137
|
-
# Delegate to
|
137
|
+
# Delegate to XML Builder, first wrapping the element in an XHTML
|
138
138
|
# namespaced div element if the method and arguments indicate
|
139
139
|
# that an xhtml_block? is desired.
|
140
140
|
def method_missing(method, *arguments, &block)
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActionView
|
4
|
-
# = Action View Cache Helper
|
5
4
|
module Helpers # :nodoc:
|
5
|
+
# = Action View Cache \Helpers
|
6
6
|
module CacheHelper
|
7
7
|
class UncacheableFragmentError < StandardError; end
|
8
8
|
|
@@ -76,11 +76,11 @@ module ActionView
|
|
76
76
|
# render 'comments/comments'
|
77
77
|
# render('comments/comments')
|
78
78
|
#
|
79
|
-
# render "header" translates to render("comments/header")
|
79
|
+
# render "header" # translates to render("comments/header")
|
80
80
|
#
|
81
|
-
# render(@topic) translates to render("topics/topic")
|
82
|
-
# render(topics) translates to render("topics/topic")
|
83
|
-
# render(message.topics) translates to render("topics/topic")
|
81
|
+
# render(@topic) # translates to render("topics/topic")
|
82
|
+
# render(topics) # translates to render("topics/topic")
|
83
|
+
# render(message.topics) # translates to render("topics/topic")
|
84
84
|
#
|
85
85
|
# It's not possible to derive all render calls like that, though.
|
86
86
|
# Here are a few examples of things that can't be derived:
|
@@ -281,14 +281,8 @@ module ActionView
|
|
281
281
|
controller.read_fragment(name, options)
|
282
282
|
end
|
283
283
|
|
284
|
-
def write_fragment_for(name, options)
|
285
|
-
|
286
|
-
yield
|
287
|
-
output_safe = output_buffer.html_safe?
|
288
|
-
fragment = output_buffer.slice!(pos..-1)
|
289
|
-
if output_safe
|
290
|
-
self.output_buffer = output_buffer.class.new(output_buffer)
|
291
|
-
end
|
284
|
+
def write_fragment_for(name, options, &block)
|
285
|
+
fragment = output_buffer.capture(&block)
|
292
286
|
controller.write_fragment(name, fragment, options)
|
293
287
|
end
|
294
288
|
|
@@ -3,18 +3,22 @@
|
|
3
3
|
require "active_support/core_ext/string/output_safety"
|
4
4
|
|
5
5
|
module ActionView
|
6
|
-
# = Action View Capture Helper
|
7
6
|
module Helpers # :nodoc:
|
8
|
-
#
|
7
|
+
# = Action View Capture \Helpers
|
8
|
+
#
|
9
|
+
# \CaptureHelper exposes methods to let you extract generated markup which
|
9
10
|
# can be used in other parts of a template or layout file.
|
10
11
|
#
|
11
|
-
# It provides a method to capture blocks into variables through capture and
|
12
|
-
# a way to capture a block of markup for use in a layout through
|
12
|
+
# It provides a method to capture blocks into variables through #capture and
|
13
|
+
# a way to capture a block of markup for use in a layout through #content_for.
|
14
|
+
#
|
15
|
+
# As well as provides a method when using streaming responses through #provide.
|
16
|
+
# See ActionController::Streaming for more information.
|
13
17
|
module CaptureHelper
|
14
|
-
# The capture method extracts part of a template as a
|
18
|
+
# The capture method extracts part of a template as a string object.
|
15
19
|
# You can then use this object anywhere in your templates, layout, or helpers.
|
16
20
|
#
|
17
|
-
# The capture method can be used in ERB templates...
|
21
|
+
# The capture method can be used in \ERB templates...
|
18
22
|
#
|
19
23
|
# <% @greeting = capture do %>
|
20
24
|
# Welcome to my shiny new web page! The date and time is
|
@@ -40,11 +44,24 @@ module ActionView
|
|
40
44
|
#
|
41
45
|
# @greeting # => "Welcome to my shiny new web page! The date and time is 2018-09-06 11:09:16 -0500"
|
42
46
|
#
|
43
|
-
def capture(*args)
|
47
|
+
def capture(*args, &block)
|
44
48
|
value = nil
|
45
|
-
|
46
|
-
|
47
|
-
|
49
|
+
@output_buffer ||= ActionView::OutputBuffer.new
|
50
|
+
buffer = @output_buffer.capture { value = yield(*args) }
|
51
|
+
|
52
|
+
string = if @output_buffer.equal?(value)
|
53
|
+
buffer
|
54
|
+
else
|
55
|
+
buffer.presence || value
|
56
|
+
end
|
57
|
+
|
58
|
+
case string
|
59
|
+
when OutputBuffer
|
60
|
+
string.to_s
|
61
|
+
when ActiveSupport::SafeBuffer
|
62
|
+
string
|
63
|
+
when String
|
64
|
+
ERB::Util.html_escape(string)
|
48
65
|
end
|
49
66
|
end
|
50
67
|
|
@@ -172,6 +189,8 @@ module ActionView
|
|
172
189
|
# concatenate several times to the same buffer when rendering a given
|
173
190
|
# template, you should use +content_for+, if not, use +provide+ to tell
|
174
191
|
# the layout to stop looking for more contents.
|
192
|
+
#
|
193
|
+
# See ActionController::Streaming for more information.
|
175
194
|
def provide(name, content = nil, &block)
|
176
195
|
content = capture(&block) if block_given?
|
177
196
|
result = @view_flow.append!(name, content) if content
|
@@ -179,6 +198,7 @@ module ActionView
|
|
179
198
|
end
|
180
199
|
|
181
200
|
# <tt>content_for?</tt> checks whether any content has been captured yet using <tt>content_for</tt>.
|
201
|
+
#
|
182
202
|
# Useful to render parts of your layout differently based on what is in your views.
|
183
203
|
#
|
184
204
|
# <%# This is the layout %>
|