actionview 5.1.7 → 5.2.8.1
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 +4 -4
- data/CHANGELOG.md +119 -178
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -4
- data/lib/action_view/base.rb +8 -10
- data/lib/action_view/buffers.rb +2 -0
- data/lib/action_view/context.rb +2 -2
- data/lib/action_view/dependency_tracker.rb +2 -0
- data/lib/action_view/digestor.rb +7 -7
- data/lib/action_view/flows.rb +2 -0
- data/lib/action_view/gem_version.rb +5 -3
- data/lib/action_view/helpers/active_model_helper.rb +9 -3
- data/lib/action_view/helpers/asset_tag_helper.rb +180 -34
- data/lib/action_view/helpers/asset_url_helper.rb +19 -17
- data/lib/action_view/helpers/atom_feed_helper.rb +3 -1
- data/lib/action_view/helpers/cache_helper.rb +24 -14
- data/lib/action_view/helpers/capture_helper.rb +9 -7
- data/lib/action_view/helpers/controller_helper.rb +3 -1
- data/lib/action_view/helpers/csp_helper.rb +24 -0
- data/lib/action_view/helpers/csrf_helper.rb +4 -2
- data/lib/action_view/helpers/date_helper.rb +7 -5
- data/lib/action_view/helpers/debug_helper.rb +4 -2
- data/lib/action_view/helpers/form_helper.rb +53 -70
- data/lib/action_view/helpers/form_options_helper.rb +23 -17
- data/lib/action_view/helpers/form_tag_helper.rb +23 -11
- data/lib/action_view/helpers/javascript_helper.rb +20 -5
- data/lib/action_view/helpers/number_helper.rb +2 -0
- data/lib/action_view/helpers/output_safety_helper.rb +2 -0
- data/lib/action_view/helpers/record_tag_helper.rb +3 -1
- data/lib/action_view/helpers/rendering_helper.rb +3 -1
- data/lib/action_view/helpers/sanitize_helper.rb +3 -1
- data/lib/action_view/helpers/tag_helper.rb +39 -8
- data/lib/action_view/helpers/tags/base.rb +12 -10
- data/lib/action_view/helpers/tags/check_box.rb +3 -1
- data/lib/action_view/helpers/tags/checkable.rb +4 -2
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +2 -0
- data/lib/action_view/helpers/tags/collection_helpers.rb +2 -0
- data/lib/action_view/helpers/tags/collection_radio_buttons.rb +2 -0
- data/lib/action_view/helpers/tags/collection_select.rb +3 -1
- data/lib/action_view/helpers/tags/color_field.rb +3 -1
- data/lib/action_view/helpers/tags/date_field.rb +2 -0
- data/lib/action_view/helpers/tags/date_select.rb +3 -1
- data/lib/action_view/helpers/tags/datetime_field.rb +3 -1
- data/lib/action_view/helpers/tags/datetime_local_field.rb +2 -0
- 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 +2 -0
- data/lib/action_view/helpers/tags/grouped_collection_select.rb +3 -1
- data/lib/action_view/helpers/tags/hidden_field.rb +2 -0
- data/lib/action_view/helpers/tags/label.rb +2 -4
- data/lib/action_view/helpers/tags/month_field.rb +2 -0
- data/lib/action_view/helpers/tags/number_field.rb +2 -0
- data/lib/action_view/helpers/tags/password_field.rb +2 -0
- data/lib/action_view/helpers/tags/placeholderable.rb +2 -0
- data/lib/action_view/helpers/tags/radio_button.rb +3 -1
- data/lib/action_view/helpers/tags/range_field.rb +2 -0
- data/lib/action_view/helpers/tags/search_field.rb +2 -0
- data/lib/action_view/helpers/tags/select.rb +4 -2
- data/lib/action_view/helpers/tags/tel_field.rb +2 -0
- data/lib/action_view/helpers/tags/text_area.rb +3 -1
- data/lib/action_view/helpers/tags/text_field.rb +3 -1
- data/lib/action_view/helpers/tags/time_field.rb +2 -0
- 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 +2 -0
- data/lib/action_view/helpers/tags/url_field.rb +2 -0
- data/lib/action_view/helpers/tags/week_field.rb +2 -0
- data/lib/action_view/helpers/tags.rb +3 -1
- data/lib/action_view/helpers/text_helper.rb +9 -7
- data/lib/action_view/helpers/translation_helper.rb +17 -5
- data/lib/action_view/helpers/url_helper.rb +28 -4
- data/lib/action_view/helpers.rb +4 -0
- data/lib/action_view/layouts.rb +7 -5
- data/lib/action_view/log_subscriber.rb +5 -3
- data/lib/action_view/lookup_context.rb +4 -4
- data/lib/action_view/model_naming.rb +2 -0
- data/lib/action_view/path_set.rb +2 -0
- data/lib/action_view/railtie.rb +11 -2
- data/lib/action_view/record_identifier.rb +2 -0
- data/lib/action_view/renderer/abstract_renderer.rb +2 -0
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +4 -2
- data/lib/action_view/renderer/partial_renderer.rb +13 -11
- data/lib/action_view/renderer/renderer.rb +2 -0
- data/lib/action_view/renderer/streaming_template_renderer.rb +5 -1
- data/lib/action_view/renderer/template_renderer.rb +2 -0
- data/lib/action_view/rendering.rb +3 -5
- data/lib/action_view/routing_url_for.rb +2 -0
- data/lib/action_view/tasks/cache_digests.rake +2 -0
- data/lib/action_view/template/error.rb +2 -3
- data/lib/action_view/template/handlers/builder.rb +3 -4
- data/lib/action_view/template/handlers/erb/erubi.rb +2 -0
- data/lib/action_view/template/handlers/erb.rb +5 -9
- data/lib/action_view/template/handlers/html.rb +2 -0
- data/lib/action_view/template/handlers/raw.rb +2 -0
- data/lib/action_view/template/handlers.rb +3 -1
- data/lib/action_view/template/html.rb +3 -1
- data/lib/action_view/template/resolver.rb +7 -6
- data/lib/action_view/template/text.rb +3 -1
- data/lib/action_view/template/types.rb +3 -1
- data/lib/action_view/template.rb +6 -4
- data/lib/action_view/test_case.rb +21 -5
- data/lib/action_view/testing/resolvers.rb +3 -1
- data/lib/action_view/version.rb +2 -0
- data/lib/action_view/view_paths.rb +3 -3
- data/lib/action_view.rb +4 -3
- data/lib/assets/compiled/rails-ujs.js +52 -15
- metadata +15 -16
- data/lib/action_view/template/handlers/erb/deprecated_erubis.rb +0 -9
- data/lib/action_view/template/handlers/erb/erubis.rb +0 -81
@@ -1,5 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_support/core_ext/array/extract_options"
|
2
4
|
require "active_support/core_ext/hash/keys"
|
5
|
+
require "active_support/core_ext/object/inclusion"
|
6
|
+
require "active_support/core_ext/object/try"
|
3
7
|
require "action_view/helpers/asset_url_helper"
|
4
8
|
require "action_view/helpers/tag_helper"
|
5
9
|
|
@@ -11,7 +15,7 @@ module ActionView
|
|
11
15
|
# the assets exist before linking to them:
|
12
16
|
#
|
13
17
|
# image_tag("rails.png")
|
14
|
-
# # => <img
|
18
|
+
# # => <img src="/assets/rails.png" />
|
15
19
|
# stylesheet_link_tag("application")
|
16
20
|
# # => <link href="/assets/application.css?body=1" media="screen" rel="stylesheet" />
|
17
21
|
module AssetTagHelper
|
@@ -35,19 +39,24 @@ module ActionView
|
|
35
39
|
# When the Asset Pipeline is enabled, you can pass the name of your manifest as
|
36
40
|
# source, and include other JavaScript or CoffeeScript files inside the manifest.
|
37
41
|
#
|
42
|
+
# If the server supports Early Hints header links for these assets will be
|
43
|
+
# automatically pushed.
|
44
|
+
#
|
38
45
|
# ==== Options
|
39
46
|
#
|
40
47
|
# When the last parameter is a hash you can add HTML attributes using that
|
41
48
|
# parameter. The following options are supported:
|
42
49
|
#
|
43
|
-
# * <tt>:extname</tt> - Append an extension to the generated
|
44
|
-
# already exists. This only applies for relative
|
45
|
-
# * <tt>:protocol</tt> - Sets the protocol of the generated
|
46
|
-
# applies when a relative
|
47
|
-
# * <tt>:host</tt> - When a relative
|
50
|
+
# * <tt>:extname</tt> - Append an extension to the generated URL unless the extension
|
51
|
+
# already exists. This only applies for relative URLs.
|
52
|
+
# * <tt>:protocol</tt> - Sets the protocol of the generated URL. This option only
|
53
|
+
# applies when a relative URL and +host+ options are provided.
|
54
|
+
# * <tt>:host</tt> - When a relative URL is provided the host is added to the
|
48
55
|
# that path.
|
49
56
|
# * <tt>:skip_pipeline</tt> - This option is used to bypass the asset pipeline
|
50
57
|
# when it is set to true.
|
58
|
+
# * <tt>:nonce<tt> - When set to true, adds an automatic nonce value if
|
59
|
+
# you have Content Security Policy enabled.
|
51
60
|
#
|
52
61
|
# ==== Examples
|
53
62
|
#
|
@@ -72,15 +81,29 @@ module ActionView
|
|
72
81
|
#
|
73
82
|
# javascript_include_tag "http://www.example.com/xmlhr.js"
|
74
83
|
# # => <script src="http://www.example.com/xmlhr.js"></script>
|
84
|
+
#
|
85
|
+
# javascript_include_tag "http://www.example.com/xmlhr.js", nonce: true
|
86
|
+
# # => <script src="http://www.example.com/xmlhr.js" nonce="..."></script>
|
75
87
|
def javascript_include_tag(*sources)
|
76
88
|
options = sources.extract_options!.stringify_keys
|
77
89
|
path_options = options.extract!("protocol", "extname", "host", "skip_pipeline").symbolize_keys
|
78
|
-
|
90
|
+
early_hints_links = []
|
91
|
+
|
92
|
+
sources_tags = sources.uniq.map { |source|
|
93
|
+
href = path_to_javascript(source, path_options)
|
94
|
+
early_hints_links << "<#{href}>; rel=preload; as=script"
|
79
95
|
tag_options = {
|
80
|
-
"src" =>
|
96
|
+
"src" => href
|
81
97
|
}.merge!(options)
|
98
|
+
if tag_options["nonce"] == true
|
99
|
+
tag_options["nonce"] = content_security_policy_nonce
|
100
|
+
end
|
82
101
|
content_tag("script".freeze, "", tag_options)
|
83
102
|
}.join("\n").html_safe
|
103
|
+
|
104
|
+
request.send_early_hints("Link" => early_hints_links.join("\n")) if respond_to?(:request) && request
|
105
|
+
|
106
|
+
sources_tags
|
84
107
|
end
|
85
108
|
|
86
109
|
# Returns a stylesheet link tag for the sources specified as arguments. If
|
@@ -90,6 +113,9 @@ module ActionView
|
|
90
113
|
# to "screen", so you must explicitly set it to "all" for the stylesheet(s) to
|
91
114
|
# apply to all media types.
|
92
115
|
#
|
116
|
+
# If the server supports Early Hints header links for these assets will be
|
117
|
+
# automatically pushed.
|
118
|
+
#
|
93
119
|
# stylesheet_link_tag "style"
|
94
120
|
# # => <link href="/assets/style.css" media="screen" rel="stylesheet" />
|
95
121
|
#
|
@@ -111,20 +137,28 @@ module ActionView
|
|
111
137
|
def stylesheet_link_tag(*sources)
|
112
138
|
options = sources.extract_options!.stringify_keys
|
113
139
|
path_options = options.extract!("protocol", "host", "skip_pipeline").symbolize_keys
|
114
|
-
|
140
|
+
early_hints_links = []
|
141
|
+
|
142
|
+
sources_tags = sources.uniq.map { |source|
|
143
|
+
href = path_to_stylesheet(source, path_options)
|
144
|
+
early_hints_links << "<#{href}>; rel=preload; as=style"
|
115
145
|
tag_options = {
|
116
146
|
"rel" => "stylesheet",
|
117
147
|
"media" => "screen",
|
118
|
-
"href" =>
|
148
|
+
"href" => href
|
119
149
|
}.merge!(options)
|
120
150
|
tag(:link, tag_options)
|
121
151
|
}.join("\n").html_safe
|
152
|
+
|
153
|
+
request.send_early_hints("Link" => early_hints_links.join("\n")) if respond_to?(:request) && request
|
154
|
+
|
155
|
+
sources_tags
|
122
156
|
end
|
123
157
|
|
124
158
|
# Returns a link tag that browsers and feed readers can use to auto-detect
|
125
|
-
# an RSS or
|
126
|
-
# <tt>:atom</tt>. Control the link options in url_for format
|
127
|
-
# +url_options+. You can modify the LINK tag itself in +tag_options+.
|
159
|
+
# an RSS, Atom, or JSON feed. The +type+ can be <tt>:rss</tt> (default),
|
160
|
+
# <tt>:atom</tt>, or <tt>:json</tt>. Control the link options in url_for format
|
161
|
+
# using the +url_options+. You can modify the LINK tag itself in +tag_options+.
|
128
162
|
#
|
129
163
|
# ==== Options
|
130
164
|
#
|
@@ -138,6 +172,8 @@ module ActionView
|
|
138
172
|
# # => <link rel="alternate" type="application/rss+xml" title="RSS" href="http://www.currenthost.com/controller/action" />
|
139
173
|
# auto_discovery_link_tag(:atom)
|
140
174
|
# # => <link rel="alternate" type="application/atom+xml" title="ATOM" href="http://www.currenthost.com/controller/action" />
|
175
|
+
# auto_discovery_link_tag(:json)
|
176
|
+
# # => <link rel="alternate" type="application/json" title="JSON" href="http://www.currenthost.com/controller/action" />
|
141
177
|
# auto_discovery_link_tag(:rss, {action: "feed"})
|
142
178
|
# # => <link rel="alternate" type="application/rss+xml" title="RSS" href="http://www.currenthost.com/controller/feed" />
|
143
179
|
# auto_discovery_link_tag(:rss, {action: "feed"}, {title: "My RSS"})
|
@@ -147,8 +183,8 @@ module ActionView
|
|
147
183
|
# auto_discovery_link_tag(:rss, "http://www.example.com/feed.rss", {title: "Example RSS"})
|
148
184
|
# # => <link rel="alternate" type="application/rss+xml" title="Example RSS" href="http://www.example.com/feed.rss" />
|
149
185
|
def auto_discovery_link_tag(type = :rss, url_options = {}, tag_options = {})
|
150
|
-
if !(type == :rss || type == :atom) && tag_options[:type].blank?
|
151
|
-
raise ArgumentError.new("You should pass :type tag_option key explicitly, because you have passed #{type} type other than :rss or :
|
186
|
+
if !(type == :rss || type == :atom || type == :json) && tag_options[:type].blank?
|
187
|
+
raise ArgumentError.new("You should pass :type tag_option key explicitly, because you have passed #{type} type other than :rss, :atom, or :json.")
|
152
188
|
end
|
153
189
|
|
154
190
|
tag(
|
@@ -195,44 +231,124 @@ module ActionView
|
|
195
231
|
}.merge!(options.symbolize_keys))
|
196
232
|
end
|
197
233
|
|
234
|
+
# Returns a link tag that browsers can use to preload the +source+.
|
235
|
+
# The +source+ can be the path of a resource managed by asset pipeline,
|
236
|
+
# a full path, or an URI.
|
237
|
+
#
|
238
|
+
# ==== Options
|
239
|
+
#
|
240
|
+
# * <tt>:type</tt> - Override the auto-generated mime type, defaults to the mime type for +source+ extension.
|
241
|
+
# * <tt>:as</tt> - Override the auto-generated value for as attribute, calculated using +source+ extension and mime type.
|
242
|
+
# * <tt>:crossorigin</tt> - Specify the crossorigin attribute, required to load cross-origin resources.
|
243
|
+
# * <tt>:nopush</tt> - Specify if the use of server push is not desired for the resource. Defaults to +false+.
|
244
|
+
#
|
245
|
+
# ==== Examples
|
246
|
+
#
|
247
|
+
# preload_link_tag("custom_theme.css")
|
248
|
+
# # => <link rel="preload" href="/assets/custom_theme.css" as="style" type="text/css" />
|
249
|
+
#
|
250
|
+
# preload_link_tag("/videos/video.webm")
|
251
|
+
# # => <link rel="preload" href="/videos/video.mp4" as="video" type="video/webm" />
|
252
|
+
#
|
253
|
+
# preload_link_tag(post_path(format: :json), as: "fetch")
|
254
|
+
# # => <link rel="preload" href="/posts.json" as="fetch" type="application/json" />
|
255
|
+
#
|
256
|
+
# preload_link_tag("worker.js", as: "worker")
|
257
|
+
# # => <link rel="preload" href="/assets/worker.js" as="worker" type="text/javascript" />
|
258
|
+
#
|
259
|
+
# preload_link_tag("//example.com/font.woff2")
|
260
|
+
# # => <link rel="preload" href="//example.com/font.woff2" as="font" type="font/woff2" crossorigin="anonymous"/>
|
261
|
+
#
|
262
|
+
# preload_link_tag("//example.com/font.woff2", crossorigin: "use-credentials")
|
263
|
+
# # => <link rel="preload" href="//example.com/font.woff2" as="font" type="font/woff2" crossorigin="use-credentials" />
|
264
|
+
#
|
265
|
+
# preload_link_tag("/media/audio.ogg", nopush: true)
|
266
|
+
# # => <link rel="preload" href="/media/audio.ogg" as="audio" type="audio/ogg" />
|
267
|
+
#
|
268
|
+
def preload_link_tag(source, options = {})
|
269
|
+
href = asset_path(source, skip_pipeline: options.delete(:skip_pipeline))
|
270
|
+
extname = File.extname(source).downcase.delete(".")
|
271
|
+
mime_type = options.delete(:type) || Template::Types[extname].try(:to_s)
|
272
|
+
as_type = options.delete(:as) || resolve_link_as(extname, mime_type)
|
273
|
+
crossorigin = options.delete(:crossorigin)
|
274
|
+
crossorigin = "anonymous" if crossorigin == true || (crossorigin.blank? && as_type == "font")
|
275
|
+
nopush = options.delete(:nopush) || false
|
276
|
+
|
277
|
+
link_tag = tag.link({
|
278
|
+
rel: "preload",
|
279
|
+
href: href,
|
280
|
+
as: as_type,
|
281
|
+
type: mime_type,
|
282
|
+
crossorigin: crossorigin
|
283
|
+
}.merge!(options.symbolize_keys))
|
284
|
+
|
285
|
+
early_hints_link = "<#{href}>; rel=preload; as=#{as_type}"
|
286
|
+
early_hints_link += "; type=#{mime_type}" if mime_type
|
287
|
+
early_hints_link += "; crossorigin=#{crossorigin}" if crossorigin
|
288
|
+
early_hints_link += "; nopush" if nopush
|
289
|
+
|
290
|
+
request.send_early_hints("Link" => early_hints_link) if respond_to?(:request) && request
|
291
|
+
|
292
|
+
link_tag
|
293
|
+
end
|
294
|
+
|
198
295
|
# Returns an HTML image tag for the +source+. The +source+ can be a full
|
199
|
-
# path or
|
296
|
+
# path, a file, or an Active Storage attachment.
|
200
297
|
#
|
201
298
|
# ==== Options
|
202
299
|
#
|
203
300
|
# You can add HTML attributes using the +options+. The +options+ supports
|
204
|
-
#
|
301
|
+
# additional keys for convenience and conformance:
|
205
302
|
#
|
206
|
-
# * <tt>:alt</tt> - If no alt text is given, the file name part of the
|
207
|
-
# +source+ is used (capitalized and without the extension)
|
208
303
|
# * <tt>:size</tt> - Supplied as "{Width}x{Height}" or "{Number}", so "30x45" becomes
|
209
304
|
# width="30" and height="45", and "50" becomes width="50" and height="50".
|
210
305
|
# <tt>:size</tt> will be ignored if the value is not in the correct format.
|
306
|
+
# * <tt>:srcset</tt> - If supplied as a hash or array of <tt>[source, descriptor]</tt>
|
307
|
+
# pairs, each image path will be expanded before the list is formatted as a string.
|
211
308
|
#
|
212
309
|
# ==== Examples
|
213
310
|
#
|
311
|
+
# Assets (images that are part of your app):
|
312
|
+
#
|
214
313
|
# image_tag("icon")
|
215
|
-
# # => <img
|
314
|
+
# # => <img src="/assets/icon" />
|
216
315
|
# image_tag("icon.png")
|
217
|
-
# # => <img
|
316
|
+
# # => <img src="/assets/icon.png" />
|
218
317
|
# image_tag("icon.png", size: "16x10", alt: "Edit Entry")
|
219
318
|
# # => <img src="/assets/icon.png" width="16" height="10" alt="Edit Entry" />
|
220
319
|
# image_tag("/icons/icon.gif", size: "16")
|
221
|
-
# # => <img src="/icons/icon.gif" width="16" height="16"
|
320
|
+
# # => <img src="/icons/icon.gif" width="16" height="16" />
|
222
321
|
# image_tag("/icons/icon.gif", height: '32', width: '32')
|
223
|
-
# # => <img
|
322
|
+
# # => <img height="32" src="/icons/icon.gif" width="32" />
|
224
323
|
# image_tag("/icons/icon.gif", class: "menu_icon")
|
225
|
-
# # => <img
|
324
|
+
# # => <img class="menu_icon" src="/icons/icon.gif" />
|
226
325
|
# image_tag("/icons/icon.gif", data: { title: 'Rails Application' })
|
227
326
|
# # => <img data-title="Rails Application" src="/icons/icon.gif" />
|
327
|
+
# image_tag("icon.png", srcset: { "icon_2x.png" => "2x", "icon_4x.png" => "4x" })
|
328
|
+
# # => <img src="/assets/icon.png" srcset="/assets/icon_2x.png 2x, /assets/icon_4x.png 4x">
|
329
|
+
# image_tag("pic.jpg", srcset: [["pic_1024.jpg", "1024w"], ["pic_1980.jpg", "1980w"]], sizes: "100vw")
|
330
|
+
# # => <img src="/assets/pic.jpg" srcset="/assets/pic_1024.jpg 1024w, /assets/pic_1980.jpg 1980w" sizes="100vw">
|
331
|
+
#
|
332
|
+
# Active Storage (images that are uploaded by the users of your app):
|
333
|
+
#
|
334
|
+
# image_tag(user.avatar)
|
335
|
+
# # => <img src="/rails/active_storage/blobs/.../tiger.jpg" />
|
336
|
+
# image_tag(user.avatar.variant(resize: "100x100"))
|
337
|
+
# # => <img src="/rails/active_storage/variants/.../tiger.jpg" />
|
338
|
+
# image_tag(user.avatar.variant(resize: "100x100"), size: '100')
|
339
|
+
# # => <img width="100" height="100" src="/rails/active_storage/variants/.../tiger.jpg" />
|
228
340
|
def image_tag(source, options = {})
|
229
341
|
options = options.symbolize_keys
|
230
342
|
check_for_image_tag_errors(options)
|
343
|
+
skip_pipeline = options.delete(:skip_pipeline)
|
231
344
|
|
232
|
-
|
345
|
+
options[:src] = resolve_image_source(source, skip_pipeline)
|
233
346
|
|
234
|
-
|
235
|
-
options[:
|
347
|
+
if options[:srcset] && !options[:srcset].is_a?(String)
|
348
|
+
options[:srcset] = options[:srcset].map do |src_path, size|
|
349
|
+
src_path = path_to_image(src_path, skip_pipeline: skip_pipeline)
|
350
|
+
"#{src_path} #{size}"
|
351
|
+
end.join(", ")
|
236
352
|
end
|
237
353
|
|
238
354
|
options[:width], options[:height] = extract_dimensions(options.delete(:size)) if options[:size]
|
@@ -257,18 +373,21 @@ module ActionView
|
|
257
373
|
# image_alt('underscored_file_name.png')
|
258
374
|
# # => Underscored file name
|
259
375
|
def image_alt(src)
|
376
|
+
ActiveSupport::Deprecation.warn("image_alt is deprecated and will be removed from Rails 6.0. You must explicitly set alt text on images.")
|
377
|
+
|
260
378
|
File.basename(src, ".*".freeze).sub(/-[[:xdigit:]]{32,64}\z/, "".freeze).tr("-_".freeze, " ".freeze).capitalize
|
261
379
|
end
|
262
380
|
|
263
381
|
# Returns an HTML video tag for the +sources+. If +sources+ is a string,
|
264
382
|
# a single video tag will be returned. If +sources+ is an array, a video
|
265
383
|
# tag with nested source tags for each source will be returned. The
|
266
|
-
# +sources+ can be full paths or files that
|
384
|
+
# +sources+ can be full paths or files that exist in your public videos
|
267
385
|
# directory.
|
268
386
|
#
|
269
387
|
# ==== Options
|
270
|
-
#
|
271
|
-
#
|
388
|
+
#
|
389
|
+
# When the last parameter is a hash you can add HTML attributes using that
|
390
|
+
# parameter. The following options are supported:
|
272
391
|
#
|
273
392
|
# * <tt>:poster</tt> - Set an image (like a screenshot) to be shown
|
274
393
|
# before the video loads. The path is calculated like the +src+ of +image_tag+.
|
@@ -285,7 +404,7 @@ module ActionView
|
|
285
404
|
# video_tag("trailer.ogg")
|
286
405
|
# # => <video src="/videos/trailer.ogg"></video>
|
287
406
|
# video_tag("trailer.ogg", controls: true, preload: 'none')
|
288
|
-
# # => <video preload="none" controls="controls" src="/videos/trailer.ogg"
|
407
|
+
# # => <video preload="none" controls="controls" src="/videos/trailer.ogg"></video>
|
289
408
|
# video_tag("trailer.m4v", size: "16x10", poster: "screenshot.png")
|
290
409
|
# # => <video src="/videos/trailer.m4v" width="16" height="10" poster="/assets/screenshot.png"></video>
|
291
410
|
# video_tag("trailer.m4v", size: "16x10", poster: "screenshot.png", poster_skip_pipeline: true)
|
@@ -312,9 +431,14 @@ module ActionView
|
|
312
431
|
end
|
313
432
|
end
|
314
433
|
|
315
|
-
# Returns an HTML audio tag for the +
|
316
|
-
#
|
317
|
-
#
|
434
|
+
# Returns an HTML audio tag for the +sources+. If +sources+ is a string,
|
435
|
+
# a single audio tag will be returned. If +sources+ is an array, an audio
|
436
|
+
# tag with nested source tags for each source will be returned. The
|
437
|
+
# +sources+ can be full paths or files that exist in your public audios
|
438
|
+
# directory.
|
439
|
+
#
|
440
|
+
# When the last parameter is a hash you can add HTML attributes using that
|
441
|
+
# parameter.
|
318
442
|
#
|
319
443
|
# audio_tag("sound")
|
320
444
|
# # => <audio src="/audios/sound"></audio>
|
@@ -346,6 +470,16 @@ module ActionView
|
|
346
470
|
end
|
347
471
|
end
|
348
472
|
|
473
|
+
def resolve_image_source(source, skip_pipeline)
|
474
|
+
if source.is_a?(Symbol) || source.is_a?(String)
|
475
|
+
path_to_image(source, skip_pipeline: skip_pipeline)
|
476
|
+
else
|
477
|
+
polymorphic_url(source)
|
478
|
+
end
|
479
|
+
rescue NoMethodError => e
|
480
|
+
raise ArgumentError, "Can't resolve image into URL: #{e}"
|
481
|
+
end
|
482
|
+
|
349
483
|
def extract_dimensions(size)
|
350
484
|
size = size.to_s
|
351
485
|
if /\A\d+x\d+\z/.match?(size)
|
@@ -360,6 +494,18 @@ module ActionView
|
|
360
494
|
raise ArgumentError, "Cannot pass a :size option with a :height or :width option"
|
361
495
|
end
|
362
496
|
end
|
497
|
+
|
498
|
+
def resolve_link_as(extname, mime_type)
|
499
|
+
if extname == "js"
|
500
|
+
"script"
|
501
|
+
elsif extname == "css"
|
502
|
+
"style"
|
503
|
+
elsif extname == "vtt"
|
504
|
+
"track"
|
505
|
+
elsif (type = mime_type.to_s.split("/")[0]) && type.in?(%w(audio video font))
|
506
|
+
type
|
507
|
+
end
|
508
|
+
end
|
363
509
|
end
|
364
510
|
end
|
365
511
|
end
|
@@ -1,10 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "zlib"
|
2
4
|
|
3
5
|
module ActionView
|
4
6
|
# = Action View Asset URL Helpers
|
5
|
-
module Helpers
|
7
|
+
module Helpers #:nodoc:
|
6
8
|
# This module provides methods for generating asset paths and
|
7
|
-
#
|
9
|
+
# URLs.
|
8
10
|
#
|
9
11
|
# image_path("rails.png")
|
10
12
|
# # => "/assets/rails.png"
|
@@ -27,7 +29,7 @@ module ActionView
|
|
27
29
|
# Helpers take that into account:
|
28
30
|
#
|
29
31
|
# image_tag("rails.png")
|
30
|
-
# # => <img
|
32
|
+
# # => <img src="http://assets.example.com/assets/rails.png" />
|
31
33
|
# stylesheet_link_tag("application")
|
32
34
|
# # => <link href="http://assets.example.com/assets/application.css" media="screen" rel="stylesheet" />
|
33
35
|
#
|
@@ -40,7 +42,7 @@ module ActionView
|
|
40
42
|
# "assets0.example.com", ..., "assets3.example.com".
|
41
43
|
#
|
42
44
|
# image_tag("rails.png")
|
43
|
-
# # => <img
|
45
|
+
# # => <img src="http://assets0.example.com/assets/rails.png" />
|
44
46
|
# stylesheet_link_tag("application")
|
45
47
|
# # => <link href="http://assets2.example.com/assets/application.css" media="screen" rel="stylesheet" />
|
46
48
|
#
|
@@ -55,8 +57,8 @@ module ActionView
|
|
55
57
|
# You can read more about setting up your DNS CNAME records from your ISP.
|
56
58
|
#
|
57
59
|
# Note: This is purely a browser performance optimization and is not meant
|
58
|
-
# for server load balancing. See
|
59
|
-
# for background and
|
60
|
+
# for server load balancing. See https://www.die.net/musings/page_load_time/
|
61
|
+
# for background and https://www.browserscope.org/?category=network for
|
60
62
|
# connection limit data.
|
61
63
|
#
|
62
64
|
# Alternatively, you can exert more control over the asset host by setting
|
@@ -66,7 +68,7 @@ module ActionView
|
|
66
68
|
# "http://assets#{Digest::MD5.hexdigest(source).to_i(16) % 2 + 1}.example.com"
|
67
69
|
# }
|
68
70
|
# image_tag("rails.png")
|
69
|
-
# # => <img
|
71
|
+
# # => <img src="http://assets1.example.com/assets/rails.png" />
|
70
72
|
# stylesheet_link_tag("application")
|
71
73
|
# # => <link href="http://assets2.example.com/assets/application.css" media="screen" rel="stylesheet" />
|
72
74
|
#
|
@@ -85,7 +87,7 @@ module ActionView
|
|
85
87
|
# end
|
86
88
|
# }
|
87
89
|
# image_tag("rails.png")
|
88
|
-
# # => <img
|
90
|
+
# # => <img src="http://assets.example.com/assets/rails.png" />
|
89
91
|
# stylesheet_link_tag("application")
|
90
92
|
# # => <link href="http://stylesheets.example.com/assets/application.css" media="screen" rel="stylesheet" />
|
91
93
|
#
|
@@ -95,7 +97,7 @@ module ActionView
|
|
95
97
|
# still sending assets for plain HTTP requests from asset hosts. If you don't
|
96
98
|
# have SSL certificates for each of the asset hosts this technique allows you
|
97
99
|
# to avoid warnings in the client about mixed media.
|
98
|
-
# Note that the request parameter might not be supplied, e.g. when the assets
|
100
|
+
# Note that the +request+ parameter might not be supplied, e.g. when the assets
|
99
101
|
# are precompiled via a Rake task. Make sure to use a +Proc+ instead of a lambda,
|
100
102
|
# since a +Proc+ allows missing parameters and sets them to +nil+.
|
101
103
|
#
|
@@ -147,13 +149,13 @@ module ActionView
|
|
147
149
|
# Below lists scenarios that apply to +asset_path+ whether or not you're
|
148
150
|
# using the asset pipeline.
|
149
151
|
#
|
150
|
-
# - All fully qualified
|
152
|
+
# - All fully qualified URLs are returned immediately. This bypasses the
|
151
153
|
# asset pipeline and all other behavior described.
|
152
154
|
#
|
153
155
|
# asset_path("http://www.example.com/js/xmlhr.js") # => "http://www.example.com/js/xmlhr.js"
|
154
156
|
#
|
155
157
|
# - All assets that begin with a forward slash are assumed to be full
|
156
|
-
#
|
158
|
+
# URLs and will not be expanded. This will bypass the asset pipeline.
|
157
159
|
#
|
158
160
|
# asset_path("/foo.png") # => "/foo.png"
|
159
161
|
#
|
@@ -322,7 +324,7 @@ module ActionView
|
|
322
324
|
# Since +javascript_url+ is based on +asset_url+ method you can set :host options. If :host
|
323
325
|
# options is set, it overwrites global +config.action_controller.asset_host+ setting.
|
324
326
|
#
|
325
|
-
# javascript_url "js/xmlhr.js", host: "http://stage.example.com" # => http://stage.example.com/assets/
|
327
|
+
# javascript_url "js/xmlhr.js", host: "http://stage.example.com" # => http://stage.example.com/assets/js/xmlhr.js
|
326
328
|
#
|
327
329
|
def javascript_url(source, options = {})
|
328
330
|
url_to_asset(source, { type: :javascript }.merge!(options))
|
@@ -349,7 +351,7 @@ module ActionView
|
|
349
351
|
# Since +stylesheet_url+ is based on +asset_url+ method you can set :host options. If :host
|
350
352
|
# options is set, it overwrites global +config.action_controller.asset_host+ setting.
|
351
353
|
#
|
352
|
-
# stylesheet_url "css/style.css", host: "http://stage.example.com" # => http://stage.example.com/css/style.css
|
354
|
+
# stylesheet_url "css/style.css", host: "http://stage.example.com" # => http://stage.example.com/assets/css/style.css
|
353
355
|
#
|
354
356
|
def stylesheet_url(source, options = {})
|
355
357
|
url_to_asset(source, { type: :stylesheet }.merge!(options))
|
@@ -379,7 +381,7 @@ module ActionView
|
|
379
381
|
# Since +image_url+ is based on +asset_url+ method you can set :host options. If :host
|
380
382
|
# options is set, it overwrites global +config.action_controller.asset_host+ setting.
|
381
383
|
#
|
382
|
-
# image_url "edit.png", host: "http://stage.example.com" # => http://stage.example.com/edit.png
|
384
|
+
# image_url "edit.png", host: "http://stage.example.com" # => http://stage.example.com/assets/edit.png
|
383
385
|
#
|
384
386
|
def image_url(source, options = {})
|
385
387
|
url_to_asset(source, { type: :image }.merge!(options))
|
@@ -405,7 +407,7 @@ module ActionView
|
|
405
407
|
# Since +video_url+ is based on +asset_url+ method you can set :host options. If :host
|
406
408
|
# options is set, it overwrites global +config.action_controller.asset_host+ setting.
|
407
409
|
#
|
408
|
-
# video_url "hd.avi", host: "http://stage.example.com" # => http://stage.example.com/hd.avi
|
410
|
+
# video_url "hd.avi", host: "http://stage.example.com" # => http://stage.example.com/videos/hd.avi
|
409
411
|
#
|
410
412
|
def video_url(source, options = {})
|
411
413
|
url_to_asset(source, { type: :video }.merge!(options))
|
@@ -431,7 +433,7 @@ module ActionView
|
|
431
433
|
# Since +audio_url+ is based on +asset_url+ method you can set :host options. If :host
|
432
434
|
# options is set, it overwrites global +config.action_controller.asset_host+ setting.
|
433
435
|
#
|
434
|
-
# audio_url "horse.wav", host: "http://stage.example.com" # => http://stage.example.com/horse.wav
|
436
|
+
# audio_url "horse.wav", host: "http://stage.example.com" # => http://stage.example.com/audios/horse.wav
|
435
437
|
#
|
436
438
|
def audio_url(source, options = {})
|
437
439
|
url_to_asset(source, { type: :audio }.merge!(options))
|
@@ -456,7 +458,7 @@ module ActionView
|
|
456
458
|
# Since +font_url+ is based on +asset_url+ method you can set :host options. If :host
|
457
459
|
# options is set, it overwrites global +config.action_controller.asset_host+ setting.
|
458
460
|
#
|
459
|
-
# font_url "font.ttf", host: "http://stage.example.com" # => http://stage.example.com/font.ttf
|
461
|
+
# font_url "font.ttf", host: "http://stage.example.com" # => http://stage.example.com/fonts/font.ttf
|
460
462
|
#
|
461
463
|
def font_url(source, options = {})
|
462
464
|
url_to_asset(source, { type: :font }.merge!(options))
|
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "set"
|
2
4
|
|
3
5
|
module ActionView
|
4
6
|
# = Action View Atom Feed Helpers
|
5
|
-
module Helpers
|
7
|
+
module Helpers #:nodoc:
|
6
8
|
module AtomFeedHelper
|
7
9
|
# Adds easy defaults to writing Atom feeds with the Builder template engine (this does not work on ERB or any other
|
8
10
|
# template languages).
|
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActionView
|
2
4
|
# = Action View Cache Helper
|
3
|
-
module Helpers
|
5
|
+
module Helpers #:nodoc:
|
4
6
|
module CacheHelper
|
5
7
|
# This helper exposes a method for caching fragments of a view
|
6
8
|
# rather than an entire action or page. This technique is useful
|
@@ -8,10 +10,9 @@ module ActionView
|
|
8
10
|
# fragments, and so on. This method takes a block that contains
|
9
11
|
# the content you wish to cache.
|
10
12
|
#
|
11
|
-
# The best way to use this is by doing key-based cache expiration
|
12
|
-
# on top of a cache store like Memcached that'll automatically
|
13
|
-
# kick out old entries.
|
14
|
-
# http://signalvnoise.com/posts/3113-how-key-based-cache-expiration-works
|
13
|
+
# The best way to use this is by doing recyclable key-based cache expiration
|
14
|
+
# on top of a cache store like Memcached or Redis that'll automatically
|
15
|
+
# kick out old entries.
|
15
16
|
#
|
16
17
|
# When using this method, you list the cache dependency as the name of the cache, like so:
|
17
18
|
#
|
@@ -23,10 +24,14 @@ module ActionView
|
|
23
24
|
# This approach will assume that when a new topic is added, you'll touch
|
24
25
|
# the project. The cache key generated from this call will be something like:
|
25
26
|
#
|
26
|
-
# views/projects/123
|
27
|
-
# ^
|
27
|
+
# views/template/action.html.erb:7a1156131a6928cb0026877f8b749ac9/projects/123
|
28
|
+
# ^template path ^template tree digest ^class ^id
|
28
29
|
#
|
29
|
-
#
|
30
|
+
# This cache key is stable, but it's combined with a cache version derived from the project
|
31
|
+
# record. When the project updated_at is touched, the #cache_version changes, even
|
32
|
+
# if the key stays stable. This means that unlike a traditional key-based cache expiration
|
33
|
+
# approach, you won't be generating cache trash, unused keys, simply because the dependent
|
34
|
+
# record is updated.
|
30
35
|
#
|
31
36
|
# If your template cache depends on multiple sources (try to avoid this to keep things simple),
|
32
37
|
# you can name all these dependencies as part of an array:
|
@@ -106,9 +111,9 @@ module ActionView
|
|
106
111
|
# <%= render_categorizable_events @person.events %>
|
107
112
|
#
|
108
113
|
# This marks every template in the directory as a dependency. To find those
|
109
|
-
# templates, the wildcard path must be absolutely defined from app/views or paths
|
114
|
+
# templates, the wildcard path must be absolutely defined from <tt>app/views</tt> or paths
|
110
115
|
# otherwise added with +prepend_view_path+ or +append_view_path+.
|
111
|
-
# This way the wildcard for
|
116
|
+
# This way the wildcard for <tt>app/views/recordings/events</tt> would be <tt>recordings/events/*</tt> etc.
|
112
117
|
#
|
113
118
|
# The pattern used to match explicit dependencies is <tt>/# Template Dependency: (\S+)/</tt>,
|
114
119
|
# so it's important that you type it out just so.
|
@@ -128,14 +133,14 @@ module ActionView
|
|
128
133
|
#
|
129
134
|
# === Collection Caching
|
130
135
|
#
|
131
|
-
# When rendering a collection of objects that each use the same partial, a
|
136
|
+
# When rendering a collection of objects that each use the same partial, a <tt>:cached</tt>
|
132
137
|
# option can be passed.
|
133
138
|
#
|
134
139
|
# For collections rendered such:
|
135
140
|
#
|
136
141
|
# <%= render partial: 'projects/project', collection: @projects, cached: true %>
|
137
142
|
#
|
138
|
-
# The
|
143
|
+
# The <tt>cached: true</tt> will make Action View's rendering read several templates
|
139
144
|
# from cache at once instead of one call per template.
|
140
145
|
#
|
141
146
|
# Templates in the collection not already cached are written to cache.
|
@@ -215,10 +220,15 @@ module ActionView
|
|
215
220
|
|
216
221
|
def fragment_name_with_digest(name, virtual_path)
|
217
222
|
virtual_path ||= @virtual_path
|
223
|
+
|
218
224
|
if virtual_path
|
219
225
|
name = controller.url_for(name).split("://").last if name.is_a?(Hash)
|
220
|
-
|
221
|
-
|
226
|
+
|
227
|
+
if digest = Digestor.digest(name: virtual_path, finder: lookup_context, dependencies: view_cache_dependencies).presence
|
228
|
+
[ "#{virtual_path}:#{digest}", name ]
|
229
|
+
else
|
230
|
+
[ virtual_path, name ]
|
231
|
+
end
|
222
232
|
else
|
223
233
|
name
|
224
234
|
end
|