actionview 5.1.7 → 5.2.4.3
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 +87 -224
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -4
- data/lib/action_view.rb +4 -3
- 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.rb +4 -0
- 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 +2 -2
- data/lib/action_view/helpers/tags.rb +3 -1
- 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/text_helper.rb +9 -7
- data/lib/action_view/helpers/translation_helper.rb +5 -4
- data/lib/action_view/helpers/url_helper.rb +28 -4
- 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.rb +13 -11
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +4 -2
- 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.rb +6 -4
- data/lib/action_view/template/error.rb +2 -3
- data/lib/action_view/template/handlers.rb +3 -1
- data/lib/action_view/template/handlers/builder.rb +3 -4
- data/lib/action_view/template/handlers/erb.rb +5 -9
- data/lib/action_view/template/handlers/erb/erubi.rb +2 -0
- 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/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/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/assets/compiled/rails-ujs.js +52 -15
- metadata +12 -13
- data/lib/action_view/template/handlers/erb/deprecated_erubis.rb +0 -9
- data/lib/action_view/template/handlers/erb/erubis.rb +0 -81
data/lib/action_view/base.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require "active_support/core_ext/module/attr_internal"
|
|
2
4
|
require "active_support/core_ext/module/attribute_accessors"
|
|
3
5
|
require "active_support/ordered_options"
|
|
@@ -140,30 +142,25 @@ module ActionView #:nodoc:
|
|
|
140
142
|
include Helpers, ::ERB::Util, Context
|
|
141
143
|
|
|
142
144
|
# Specify the proc used to decorate input tags that refer to attributes with errors.
|
|
143
|
-
cattr_accessor :field_error_proc
|
|
144
|
-
@@field_error_proc = Proc.new { |html_tag, instance| "<div class=\"field_with_errors\">#{html_tag}</div>".html_safe }
|
|
145
|
+
cattr_accessor :field_error_proc, default: Proc.new { |html_tag, instance| "<div class=\"field_with_errors\">#{html_tag}</div>".html_safe }
|
|
145
146
|
|
|
146
147
|
# How to complete the streaming when an exception occurs.
|
|
147
148
|
# This is our best guess: first try to close the attribute, then the tag.
|
|
148
|
-
cattr_accessor :streaming_completion_on_exception
|
|
149
|
-
@@streaming_completion_on_exception = %("><script>window.location = "/500.html"</script></html>)
|
|
149
|
+
cattr_accessor :streaming_completion_on_exception, default: %("><script>window.location = "/500.html"</script></html>)
|
|
150
150
|
|
|
151
151
|
# Specify whether rendering within namespaced controllers should prefix
|
|
152
152
|
# the partial paths for ActiveModel objects with the namespace.
|
|
153
153
|
# (e.g., an Admin::PostsController would render @post using /admin/posts/_post.erb)
|
|
154
|
-
cattr_accessor :prefix_partial_path_with_controller_namespace
|
|
155
|
-
@@prefix_partial_path_with_controller_namespace = true
|
|
154
|
+
cattr_accessor :prefix_partial_path_with_controller_namespace, default: true
|
|
156
155
|
|
|
157
156
|
# Specify default_formats that can be rendered.
|
|
158
157
|
cattr_accessor :default_formats
|
|
159
158
|
|
|
160
159
|
# Specify whether an error should be raised for missing translations
|
|
161
|
-
cattr_accessor :raise_on_missing_translations
|
|
162
|
-
@@raise_on_missing_translations = false
|
|
160
|
+
cattr_accessor :raise_on_missing_translations, default: false
|
|
163
161
|
|
|
164
162
|
# Specify whether submit_tag should automatically disable on click
|
|
165
|
-
cattr_accessor :automatically_disable_submit_tag
|
|
166
|
-
@@automatically_disable_submit_tag = true
|
|
163
|
+
cattr_accessor :automatically_disable_submit_tag, default: true
|
|
167
164
|
|
|
168
165
|
class_attribute :_routes
|
|
169
166
|
class_attribute :logger
|
|
@@ -207,6 +204,7 @@ module ActionView #:nodoc:
|
|
|
207
204
|
@view_renderer = ActionView::Renderer.new(lookup_context)
|
|
208
205
|
end
|
|
209
206
|
|
|
207
|
+
@cache_hit = {}
|
|
210
208
|
assign(assigns)
|
|
211
209
|
assign_controller(controller)
|
|
212
210
|
_prepare_context
|
data/lib/action_view/buffers.rb
CHANGED
data/lib/action_view/context.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module ActionView
|
|
2
4
|
module CompiledTemplates #:nodoc:
|
|
3
5
|
# holds compiled template code
|
|
@@ -17,7 +19,6 @@ module ActionView
|
|
|
17
19
|
attr_accessor :output_buffer, :view_flow
|
|
18
20
|
|
|
19
21
|
# Prepares the context by setting the appropriate instance variables.
|
|
20
|
-
# :api: plugin
|
|
21
22
|
def _prepare_context
|
|
22
23
|
@view_flow = OutputFlow.new
|
|
23
24
|
@output_buffer = nil
|
|
@@ -27,7 +28,6 @@ module ActionView
|
|
|
27
28
|
# Encapsulates the interaction with the view flow so it
|
|
28
29
|
# returns the correct buffer on +yield+. This is usually
|
|
29
30
|
# overwritten by helpers to add more behavior.
|
|
30
|
-
# :api: plugin
|
|
31
31
|
def _layout_for(name = nil)
|
|
32
32
|
name ||= :layout
|
|
33
33
|
view_flow.get(name).html_safe
|
data/lib/action_view/digestor.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require "concurrent/map"
|
|
2
4
|
require "action_view/dependency_tracker"
|
|
3
5
|
require "monitor"
|
|
@@ -68,13 +70,11 @@ module ActionView
|
|
|
68
70
|
end
|
|
69
71
|
|
|
70
72
|
private
|
|
71
|
-
def find_template(finder,
|
|
73
|
+
def find_template(finder, name, prefixes, partial, keys)
|
|
72
74
|
finder.disable_cache do
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
finder.find_all(*args).first
|
|
77
|
-
end
|
|
75
|
+
format = finder.rendered_format
|
|
76
|
+
result = finder.find_all(name, prefixes, partial, keys, formats: [format]).first if format
|
|
77
|
+
result || finder.find_all(name, prefixes, partial, keys).first
|
|
78
78
|
end
|
|
79
79
|
end
|
|
80
80
|
end
|
|
@@ -95,7 +95,7 @@ module ActionView
|
|
|
95
95
|
end
|
|
96
96
|
|
|
97
97
|
def digest(finder, stack = [])
|
|
98
|
-
Digest
|
|
98
|
+
ActiveSupport::Digest.hexdigest("#{template.source}-#{dependency_digest(finder, stack)}")
|
|
99
99
|
end
|
|
100
100
|
|
|
101
101
|
def dependency_digest(finder, stack)
|
data/lib/action_view/flows.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module ActionView
|
|
2
4
|
# Returns the version of the currently loaded Action View as a <tt>Gem::Version</tt>
|
|
3
5
|
def self.gem_version
|
|
@@ -6,9 +8,9 @@ module ActionView
|
|
|
6
8
|
|
|
7
9
|
module VERSION
|
|
8
10
|
MAJOR = 5
|
|
9
|
-
MINOR =
|
|
10
|
-
TINY =
|
|
11
|
-
PRE =
|
|
11
|
+
MINOR = 2
|
|
12
|
+
TINY = 4
|
|
13
|
+
PRE = "3"
|
|
12
14
|
|
|
13
15
|
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
|
|
14
16
|
end
|
data/lib/action_view/helpers.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require "active_support/benchmarkable"
|
|
2
4
|
|
|
3
5
|
module ActionView #:nodoc:
|
|
@@ -11,6 +13,7 @@ module ActionView #:nodoc:
|
|
|
11
13
|
autoload :CacheHelper
|
|
12
14
|
autoload :CaptureHelper
|
|
13
15
|
autoload :ControllerHelper
|
|
16
|
+
autoload :CspHelper
|
|
14
17
|
autoload :CsrfHelper
|
|
15
18
|
autoload :DateHelper
|
|
16
19
|
autoload :DebugHelper
|
|
@@ -44,6 +47,7 @@ module ActionView #:nodoc:
|
|
|
44
47
|
include CacheHelper
|
|
45
48
|
include CaptureHelper
|
|
46
49
|
include ControllerHelper
|
|
50
|
+
include CspHelper
|
|
47
51
|
include CsrfHelper
|
|
48
52
|
include DateHelper
|
|
49
53
|
include DebugHelper
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require "active_support/core_ext/module/attribute_accessors"
|
|
2
4
|
require "active_support/core_ext/enumerable"
|
|
3
5
|
|
|
4
6
|
module ActionView
|
|
5
7
|
# = Active Model Helpers
|
|
6
|
-
module Helpers
|
|
8
|
+
module Helpers #:nodoc:
|
|
7
9
|
module ActiveModelHelper
|
|
8
10
|
end
|
|
9
11
|
|
|
@@ -15,8 +17,8 @@ module ActionView
|
|
|
15
17
|
end
|
|
16
18
|
end
|
|
17
19
|
|
|
18
|
-
def content_tag(*)
|
|
19
|
-
error_wrapping(super)
|
|
20
|
+
def content_tag(type, options, *)
|
|
21
|
+
select_markup_helper?(type) ? super : error_wrapping(super)
|
|
20
22
|
end
|
|
21
23
|
|
|
22
24
|
def tag(type, options, *)
|
|
@@ -41,6 +43,10 @@ module ActionView
|
|
|
41
43
|
object.respond_to?(:errors) && object.errors.respond_to?(:[]) && error_message.present?
|
|
42
44
|
end
|
|
43
45
|
|
|
46
|
+
def select_markup_helper?(type)
|
|
47
|
+
["optgroup", "option"].include?(type)
|
|
48
|
+
end
|
|
49
|
+
|
|
44
50
|
def tag_generate_errors?(options)
|
|
45
51
|
options["type"] != "hidden"
|
|
46
52
|
end
|
|
@@ -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
|