actionview 7.1.2 → 8.0.2
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 +51 -382
- data/lib/action_view/base.rb +25 -11
- data/lib/action_view/cache_expiry.rb +9 -3
- data/lib/action_view/dependency_tracker/erb_tracker.rb +36 -27
- data/lib/action_view/dependency_tracker/ruby_tracker.rb +43 -0
- data/lib/action_view/dependency_tracker/wildcard_resolver.rb +32 -0
- data/lib/action_view/dependency_tracker.rb +2 -1
- data/lib/action_view/digestor.rb +6 -2
- data/lib/action_view/gem_version.rb +2 -2
- data/lib/action_view/helpers/asset_tag_helper.rb +18 -6
- data/lib/action_view/helpers/atom_feed_helper.rb +0 -2
- data/lib/action_view/helpers/cache_helper.rb +14 -6
- data/lib/action_view/helpers/csrf_helper.rb +1 -1
- data/lib/action_view/helpers/date_helper.rb +3 -3
- data/lib/action_view/helpers/form_helper.rb +282 -273
- data/lib/action_view/helpers/form_options_helper.rb +23 -21
- data/lib/action_view/helpers/form_tag_helper.rb +104 -69
- data/lib/action_view/helpers/number_helper.rb +35 -329
- data/lib/action_view/helpers/output_safety_helper.rb +5 -6
- data/lib/action_view/helpers/rendering_helper.rb +160 -50
- data/lib/action_view/helpers/sanitize_helper.rb +31 -14
- data/lib/action_view/helpers/tag_helper.rb +196 -19
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +4 -3
- data/lib/action_view/helpers/tags/collection_helpers.rb +2 -1
- data/lib/action_view/helpers/text_helper.rb +125 -69
- data/lib/action_view/helpers/url_helper.rb +6 -80
- data/lib/action_view/layouts.rb +11 -13
- data/lib/action_view/log_subscriber.rb +8 -4
- data/lib/action_view/railtie.rb +0 -1
- data/lib/action_view/record_identifier.rb +1 -1
- data/lib/action_view/render_parser/prism_render_parser.rb +139 -0
- data/lib/action_view/{ripper_ast_parser.rb → render_parser/ripper_render_parser.rb} +162 -10
- data/lib/action_view/render_parser.rb +21 -169
- data/lib/action_view/renderer/abstract_renderer.rb +1 -1
- data/lib/action_view/renderer/partial_renderer.rb +2 -2
- data/lib/action_view/renderer/renderer.rb +32 -38
- data/lib/action_view/renderer/streaming_template_renderer.rb +0 -1
- data/lib/action_view/renderer/template_renderer.rb +3 -3
- data/lib/action_view/rendering.rb +6 -7
- data/lib/action_view/template/error.rb +11 -0
- data/lib/action_view/template/handlers/erb.rb +45 -37
- data/lib/action_view/template/renderable.rb +7 -1
- data/lib/action_view/template/resolver.rb +0 -3
- data/lib/action_view/template.rb +46 -12
- data/lib/action_view/test_case.rb +14 -16
- data/lib/action_view/unbound_template.rb +4 -4
- data/lib/action_view.rb +1 -1
- metadata +17 -19
- data/lib/action_view/dependency_tracker/ripper_tracker.rb +0 -59
- data/lib/assets/compiled/rails-ujs.js +0 -777
|
@@ -1,32 +1,140 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
module ActionView
|
|
4
6
|
module Helpers # :nodoc:
|
|
5
|
-
#
|
|
7
|
+
# # Action View Rendering Helpers
|
|
6
8
|
#
|
|
7
|
-
# Implements methods that allow rendering from a view context.
|
|
8
|
-
#
|
|
9
|
-
#
|
|
9
|
+
# Implements methods that allow rendering from a view context. In order to use
|
|
10
|
+
# this module, all you need is to implement view_renderer that returns an
|
|
11
|
+
# ActionView::Renderer object.
|
|
10
12
|
module RenderingHelper
|
|
11
|
-
#
|
|
13
|
+
# Renders a template and returns the result.
|
|
14
|
+
#
|
|
15
|
+
# Pass the template to render as the first argument. This is shorthand
|
|
16
|
+
# syntax for partial rendering, so the template filename should be
|
|
17
|
+
# prefixed with an underscore. The partial renderer looks for the partial
|
|
18
|
+
# template in the directory of the calling template first.
|
|
19
|
+
#
|
|
20
|
+
# <% # app/views/posts/new.html.erb %>
|
|
21
|
+
# <%= render "form" %>
|
|
22
|
+
# # => renders app/views/posts/_form.html.erb
|
|
23
|
+
#
|
|
24
|
+
# Use the complete view path to render a partial from another directory.
|
|
25
|
+
#
|
|
26
|
+
# <% # app/views/posts/show.html.erb %>
|
|
27
|
+
# <%= render "comments/form" %>
|
|
28
|
+
# # => renders app/views/comments/_form.html.erb
|
|
29
|
+
#
|
|
30
|
+
# Without the rendering mode, the second argument can be a Hash of local
|
|
31
|
+
# variable assignments for the template.
|
|
32
|
+
#
|
|
33
|
+
# <% # app/views/posts/new.html.erb %>
|
|
34
|
+
# <%= render "form", post: Post.new %>
|
|
35
|
+
# # => renders app/views/posts/_form.html.erb
|
|
36
|
+
#
|
|
37
|
+
# If the first argument responds to `render_in`, the template will be rendered
|
|
38
|
+
# by calling `render_in` with the current view context.
|
|
39
|
+
#
|
|
40
|
+
# class Greeting
|
|
41
|
+
# def render_in(view_context)
|
|
42
|
+
# view_context.render html: "<h1>Hello, World</h1>"
|
|
43
|
+
# end
|
|
44
|
+
#
|
|
45
|
+
# def format
|
|
46
|
+
# :html
|
|
47
|
+
# end
|
|
48
|
+
# end
|
|
49
|
+
#
|
|
50
|
+
# <%= render Greeting.new %>
|
|
51
|
+
# # => "<h1>Hello, World</h1>"
|
|
52
|
+
#
|
|
53
|
+
# #### Rendering Mode
|
|
54
|
+
#
|
|
55
|
+
# Pass the rendering mode as first argument to override it.
|
|
56
|
+
#
|
|
57
|
+
# `:partial`
|
|
58
|
+
# : See ActionView::PartialRenderer for details.
|
|
59
|
+
#
|
|
60
|
+
# <%= render partial: "form", locals: { post: Post.new } %>
|
|
61
|
+
# # => renders app/views/posts/_form.html.erb
|
|
62
|
+
#
|
|
63
|
+
# `:file`
|
|
64
|
+
# : Renders the contents of a file. This option should **not** be used with
|
|
65
|
+
# unsanitized user input.
|
|
66
|
+
#
|
|
67
|
+
# <%= render file: "/path/to/some/file" %>
|
|
68
|
+
# # => renders /path/to/some/file
|
|
69
|
+
#
|
|
70
|
+
# `:inline`
|
|
71
|
+
# : Renders an ERB template string.
|
|
72
|
+
#
|
|
73
|
+
# <% name = "World" %>
|
|
74
|
+
# <%= render inline: "<h1>Hello, <%= name %>!</h1>" %>
|
|
75
|
+
# # => renders "<h1>Hello, World!</h1>"
|
|
76
|
+
#
|
|
77
|
+
# `:body`
|
|
78
|
+
# : Renders the provided text, and sets the format as `:text`.
|
|
79
|
+
#
|
|
80
|
+
# <%= render body: "Hello, World!" %>
|
|
81
|
+
# # => renders "Hello, World!"
|
|
82
|
+
#
|
|
83
|
+
# `:plain`
|
|
84
|
+
# : Renders the provided text, and sets the format as `:text`.
|
|
85
|
+
#
|
|
86
|
+
# <%= render plain: "Hello, World!" %>
|
|
87
|
+
# # => renders "Hello, World!"
|
|
88
|
+
#
|
|
89
|
+
# `:html`
|
|
90
|
+
# : Renders the provided HTML string, and sets the format as
|
|
91
|
+
# `:html`. If the string is not `html_safe?`, performs HTML escaping on
|
|
92
|
+
# the string before rendering.
|
|
93
|
+
#
|
|
94
|
+
# <%= render html: "<h1>Hello, World!</h1>".html_safe %>
|
|
95
|
+
# # => renders "<h1>Hello, World!</h1>"
|
|
96
|
+
#
|
|
97
|
+
# <%= render html: "<h1>Hello, World!</h1>" %>
|
|
98
|
+
# # => renders "<h1>Hello, World!</h1>"
|
|
99
|
+
#
|
|
100
|
+
# `:renderable`
|
|
101
|
+
# : Renders the provided object by calling `render_in` with the current view
|
|
102
|
+
# context. The format is determined by calling `format` on the
|
|
103
|
+
# renderable if it responds to `format`, falling back to `:html` by
|
|
104
|
+
# default.
|
|
105
|
+
#
|
|
106
|
+
# <%= render renderable: Greeting.new %>
|
|
107
|
+
# # => renders "<h1>Hello, World</h1>"
|
|
108
|
+
#
|
|
109
|
+
#
|
|
110
|
+
# #### Options
|
|
111
|
+
#
|
|
112
|
+
# `:locals`
|
|
113
|
+
# : Hash of local variable assignments for the template.
|
|
114
|
+
#
|
|
115
|
+
# <%= render inline: "<h1>Hello, <%= name %>!</h1>", locals: { name: "World" } %>
|
|
116
|
+
# # => renders "<h1>Hello, World!</h1>"
|
|
117
|
+
#
|
|
118
|
+
# `:formats`
|
|
119
|
+
# : Override the current format to render a template for a different format.
|
|
120
|
+
#
|
|
121
|
+
# <% # app/views/posts/show.html.erb %>
|
|
122
|
+
# <%= render template: "posts/content", formats: [:text] %>
|
|
123
|
+
# # => renders app/views/posts/content.text.erb
|
|
12
124
|
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
# * <tt>:inline</tt> - Renders an inline template similar to how it's done in the controller.
|
|
16
|
-
# * <tt>:plain</tt> - Renders the text passed in out. Setting the content
|
|
17
|
-
# type as <tt>text/plain</tt>.
|
|
18
|
-
# * <tt>:html</tt> - Renders the HTML safe string passed in out, otherwise
|
|
19
|
-
# performs HTML escape on the string first. Setting the content type as
|
|
20
|
-
# <tt>text/html</tt>.
|
|
21
|
-
# * <tt>:body</tt> - Renders the text passed in, and inherits the content
|
|
22
|
-
# type of <tt>text/plain</tt> from ActionDispatch::Response object.
|
|
125
|
+
# `:variants`
|
|
126
|
+
# : Render a template for a different variant.
|
|
23
127
|
#
|
|
24
|
-
#
|
|
128
|
+
# <% # app/views/posts/show.html.erb %>
|
|
129
|
+
# <%= render template: "posts/content", variants: [:tablet] %>
|
|
130
|
+
# # => renders app/views/posts/content.html+tablet.erb
|
|
25
131
|
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
132
|
+
# `:handlers`
|
|
133
|
+
# : Render a template for a different handler.
|
|
28
134
|
#
|
|
29
|
-
#
|
|
135
|
+
# <% # app/views/posts/show.html.erb %>
|
|
136
|
+
# <%= render template: "posts/content", handlers: [:builder] %>
|
|
137
|
+
# # => renders app/views/posts/content.html.builder
|
|
30
138
|
def render(options = {}, locals = {}, &block)
|
|
31
139
|
case options
|
|
32
140
|
when Hash
|
|
@@ -47,52 +155,54 @@ module ActionView
|
|
|
47
155
|
end
|
|
48
156
|
|
|
49
157
|
# Overrides _layout_for in the context object so it supports the case a block is
|
|
50
|
-
# passed to a partial. Returns the contents that are yielded to a layout, given
|
|
51
|
-
# name or a block.
|
|
158
|
+
# passed to a partial. Returns the contents that are yielded to a layout, given
|
|
159
|
+
# a name or a block.
|
|
52
160
|
#
|
|
53
|
-
# You can think of a layout as a method that is called with a block. If the user
|
|
54
|
-
#
|
|
55
|
-
# If the user calls simply
|
|
161
|
+
# You can think of a layout as a method that is called with a block. If the user
|
|
162
|
+
# calls `yield :some_name`, the block, by default, returns
|
|
163
|
+
# `content_for(:some_name)`. If the user calls simply `yield`, the default block
|
|
164
|
+
# returns `content_for(:layout)`.
|
|
56
165
|
#
|
|
57
166
|
# The user can override this default by passing a block to the layout:
|
|
58
167
|
#
|
|
59
|
-
#
|
|
60
|
-
#
|
|
61
|
-
#
|
|
62
|
-
#
|
|
168
|
+
# # The template
|
|
169
|
+
# <%= render layout: "my_layout" do %>
|
|
170
|
+
# Content
|
|
171
|
+
# <% end %>
|
|
63
172
|
#
|
|
64
|
-
#
|
|
65
|
-
#
|
|
66
|
-
#
|
|
67
|
-
#
|
|
173
|
+
# # The layout
|
|
174
|
+
# <html>
|
|
175
|
+
# <%= yield %>
|
|
176
|
+
# </html>
|
|
68
177
|
#
|
|
69
|
-
# In this case, instead of the default block, which would return
|
|
70
|
-
# this method returns the block that was passed in to
|
|
178
|
+
# In this case, instead of the default block, which would return `content_for(:layout)`,
|
|
179
|
+
# this method returns the block that was passed in to `render :layout`, and the response
|
|
71
180
|
# would be
|
|
72
181
|
#
|
|
73
|
-
#
|
|
74
|
-
#
|
|
75
|
-
#
|
|
182
|
+
# <html>
|
|
183
|
+
# Content
|
|
184
|
+
# </html>
|
|
76
185
|
#
|
|
77
|
-
# Finally, the block can take block arguments, which can be passed in by
|
|
186
|
+
# Finally, the block can take block arguments, which can be passed in by
|
|
187
|
+
# `yield`:
|
|
78
188
|
#
|
|
79
|
-
#
|
|
80
|
-
#
|
|
81
|
-
#
|
|
82
|
-
#
|
|
189
|
+
# # The template
|
|
190
|
+
# <%= render layout: "my_layout" do |customer| %>
|
|
191
|
+
# Hello <%= customer.name %>
|
|
192
|
+
# <% end %>
|
|
83
193
|
#
|
|
84
|
-
#
|
|
85
|
-
#
|
|
86
|
-
#
|
|
87
|
-
#
|
|
194
|
+
# # The layout
|
|
195
|
+
# <html>
|
|
196
|
+
# <%= yield Struct.new(:name).new("David") %>
|
|
197
|
+
# </html>
|
|
88
198
|
#
|
|
89
|
-
# In this case, the layout would receive the block passed into
|
|
199
|
+
# In this case, the layout would receive the block passed into `render :layout`,
|
|
90
200
|
# and the struct specified would be passed into the block as an argument. The result
|
|
91
201
|
# would be
|
|
92
202
|
#
|
|
93
|
-
#
|
|
94
|
-
#
|
|
95
|
-
#
|
|
203
|
+
# <html>
|
|
204
|
+
# Hello David
|
|
205
|
+
# </html>
|
|
96
206
|
#
|
|
97
207
|
def _layout_for(*args, &block)
|
|
98
208
|
name = args.first
|
|
@@ -15,38 +15,49 @@ module ActionView
|
|
|
15
15
|
|
|
16
16
|
# Sanitizes HTML input, stripping all but known-safe tags and attributes.
|
|
17
17
|
#
|
|
18
|
-
# It also strips href/src attributes with unsafe protocols like
|
|
18
|
+
# It also strips +href+ / +src+ attributes with unsafe protocols like +javascript:+, while
|
|
19
19
|
# also protecting against attempts to use Unicode, ASCII, and hex character references to work
|
|
20
20
|
# around these protocol filters.
|
|
21
21
|
#
|
|
22
|
-
# The default sanitizer is Rails::HTML5::SafeListSanitizer
|
|
22
|
+
# The default sanitizer is +Rails::HTML5::SafeListSanitizer+. See {Rails HTML
|
|
23
23
|
# Sanitizers}[https://github.com/rails/rails-html-sanitizer] for more information.
|
|
24
24
|
#
|
|
25
25
|
# Custom sanitization rules can also be provided.
|
|
26
26
|
#
|
|
27
|
+
# <b>Warning</b>: Adding disallowed tags or attributes to the allowlists may introduce
|
|
28
|
+
# vulnerabilities into your application. Please rely on the default allowlists whenever
|
|
29
|
+
# possible, because they are curated to maintain security and safety. If you think that the
|
|
30
|
+
# default allowlists should be expanded, please {open an issue on the rails-html-sanitizer
|
|
31
|
+
# project}[https://github.com/rails/rails-html-sanitizer/issues].
|
|
32
|
+
#
|
|
27
33
|
# Please note that sanitizing user-provided text does not guarantee that the
|
|
28
34
|
# resulting markup is valid or even well-formed.
|
|
29
35
|
#
|
|
30
36
|
# ==== Options
|
|
31
37
|
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
38
|
+
# [+:tags+]
|
|
39
|
+
# An array of allowed tags.
|
|
40
|
+
#
|
|
41
|
+
# [+:attributes+]
|
|
42
|
+
# An array of allowed attributes.
|
|
43
|
+
#
|
|
44
|
+
# [+:scrubber+]
|
|
45
|
+
# A {Rails::HTML scrubber}[https://github.com/rails/rails-html-sanitizer]
|
|
35
46
|
# or {Loofah::Scrubber}[https://github.com/flavorjones/loofah] object that
|
|
36
47
|
# defines custom sanitization rules. A custom scrubber takes precedence over
|
|
37
48
|
# custom tags and attributes.
|
|
38
49
|
#
|
|
39
50
|
# ==== Examples
|
|
40
51
|
#
|
|
41
|
-
# Normal use
|
|
52
|
+
# ===== Normal use
|
|
42
53
|
#
|
|
43
54
|
# <%= sanitize @comment.body %>
|
|
44
55
|
#
|
|
45
|
-
# Providing custom lists of permitted tags and attributes
|
|
56
|
+
# ===== Providing custom lists of permitted tags and attributes
|
|
46
57
|
#
|
|
47
58
|
# <%= sanitize @comment.body, tags: %w(strong em a), attributes: %w(href) %>
|
|
48
59
|
#
|
|
49
|
-
# Providing a custom Rails::HTML scrubber
|
|
60
|
+
# ===== Providing a custom +Rails::HTML+ scrubber
|
|
50
61
|
#
|
|
51
62
|
# class CommentScrubber < Rails::HTML::PermitScrubber
|
|
52
63
|
# def initialize
|
|
@@ -60,21 +71,27 @@ module ActionView
|
|
|
60
71
|
# end
|
|
61
72
|
# end
|
|
62
73
|
#
|
|
74
|
+
# <code></code>
|
|
75
|
+
#
|
|
63
76
|
# <%= sanitize @comment.body, scrubber: CommentScrubber.new %>
|
|
64
77
|
#
|
|
65
78
|
# See {Rails HTML Sanitizer}[https://github.com/rails/rails-html-sanitizer] for
|
|
66
|
-
# documentation about Rails::HTML scrubbers.
|
|
79
|
+
# documentation about +Rails::HTML+ scrubbers.
|
|
67
80
|
#
|
|
68
|
-
# Providing a custom Loofah::Scrubber
|
|
81
|
+
# ===== Providing a custom +Loofah::Scrubber+
|
|
69
82
|
#
|
|
70
83
|
# scrubber = Loofah::Scrubber.new do |node|
|
|
71
84
|
# node.remove if node.name == 'script'
|
|
72
85
|
# end
|
|
73
86
|
#
|
|
87
|
+
# <code></code>
|
|
88
|
+
#
|
|
74
89
|
# <%= sanitize @comment.body, scrubber: scrubber %>
|
|
75
90
|
#
|
|
76
91
|
# See {Loofah's documentation}[https://github.com/flavorjones/loofah] for more
|
|
77
|
-
# information about defining custom Loofah::Scrubber objects.
|
|
92
|
+
# information about defining custom +Loofah::Scrubber+ objects.
|
|
93
|
+
#
|
|
94
|
+
# ==== Global Configuration
|
|
78
95
|
#
|
|
79
96
|
# To set the default allowed tags or attributes across your application:
|
|
80
97
|
#
|
|
@@ -95,13 +112,13 @@ module ActionView
|
|
|
95
112
|
# # In config/application.rb
|
|
96
113
|
# config.action_view.sanitizer_vendor = Rails::HTML5::Sanitizer
|
|
97
114
|
#
|
|
98
|
-
# NOTE: Rails::HTML5::Sanitizer is not supported on JRuby, so on JRuby platforms \Rails will
|
|
99
|
-
# fall back to
|
|
115
|
+
# NOTE: +Rails::HTML5::Sanitizer+ is not supported on JRuby, so on JRuby platforms \Rails will
|
|
116
|
+
# fall back to using +Rails::HTML4::Sanitizer+.
|
|
100
117
|
def sanitize(html, options = {})
|
|
101
118
|
self.class.safe_list_sanitizer.sanitize(html, options)&.html_safe
|
|
102
119
|
end
|
|
103
120
|
|
|
104
|
-
# Sanitizes a block of CSS code. Used by
|
|
121
|
+
# Sanitizes a block of CSS code. Used by #sanitize when it comes across a style attribute.
|
|
105
122
|
def sanitize_css(style)
|
|
106
123
|
self.class.safe_list_sanitizer.sanitize_css(style)
|
|
107
124
|
end
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "active_support/code_generator"
|
|
3
4
|
require "active_support/core_ext/enumerable"
|
|
4
5
|
require "active_support/core_ext/string/output_safety"
|
|
5
|
-
require "
|
|
6
|
+
require "active_support/core_ext/string/inflections"
|
|
6
7
|
require "action_view/helpers/capture_helper"
|
|
7
8
|
require "action_view/helpers/output_safety_helper"
|
|
8
9
|
|
|
@@ -46,8 +47,171 @@ module ActionView
|
|
|
46
47
|
include CaptureHelper
|
|
47
48
|
include OutputSafetyHelper
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
def self.define_element(name, code_generator:, method_name: name)
|
|
51
|
+
return if method_defined?(name)
|
|
52
|
+
|
|
53
|
+
code_generator.class_eval do |batch|
|
|
54
|
+
batch << "\n" <<
|
|
55
|
+
"def #{method_name}(content = nil, escape: true, **options, &block)" <<
|
|
56
|
+
" tag_string(#{name.inspect}, content, options, escape: escape, &block)" <<
|
|
57
|
+
"end"
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def self.define_void_element(name, code_generator:, method_name: name)
|
|
62
|
+
code_generator.class_eval do |batch|
|
|
63
|
+
batch << "\n" <<
|
|
64
|
+
"def #{method_name}(escape: true, **options, &block)" <<
|
|
65
|
+
" self_closing_tag_string(#{name.inspect}, options, escape, '>')" <<
|
|
66
|
+
"end"
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def self.define_self_closing_element(name, code_generator:, method_name: name)
|
|
71
|
+
code_generator.class_eval do |batch|
|
|
72
|
+
batch << "\n" <<
|
|
73
|
+
"def #{method_name}(content = nil, escape: true, **options, &block)" <<
|
|
74
|
+
" if content || block" <<
|
|
75
|
+
" tag_string(#{name.inspect}, content, options, escape: escape, &block)" <<
|
|
76
|
+
" else" <<
|
|
77
|
+
" self_closing_tag_string(#{name.inspect}, options, escape)" <<
|
|
78
|
+
" end" <<
|
|
79
|
+
"end"
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
ActiveSupport::CodeGenerator.batch(self, __FILE__, __LINE__) do |code_generator|
|
|
84
|
+
define_void_element :area, code_generator: code_generator
|
|
85
|
+
define_void_element :base, code_generator: code_generator
|
|
86
|
+
define_void_element :br, code_generator: code_generator
|
|
87
|
+
define_void_element :col, code_generator: code_generator
|
|
88
|
+
define_void_element :embed, code_generator: code_generator
|
|
89
|
+
define_void_element :hr, code_generator: code_generator
|
|
90
|
+
define_void_element :img, code_generator: code_generator
|
|
91
|
+
define_void_element :input, code_generator: code_generator
|
|
92
|
+
define_void_element :keygen, code_generator: code_generator
|
|
93
|
+
define_void_element :link, code_generator: code_generator
|
|
94
|
+
define_void_element :meta, code_generator: code_generator
|
|
95
|
+
define_void_element :source, code_generator: code_generator
|
|
96
|
+
define_void_element :track, code_generator: code_generator
|
|
97
|
+
define_void_element :wbr, code_generator: code_generator
|
|
98
|
+
|
|
99
|
+
define_self_closing_element :animate, code_generator: code_generator
|
|
100
|
+
define_self_closing_element :animateMotion, code_generator: code_generator, method_name: :animate_motion
|
|
101
|
+
define_self_closing_element :animateTransform, code_generator: code_generator, method_name: :animate_transform
|
|
102
|
+
define_self_closing_element :circle, code_generator: code_generator
|
|
103
|
+
define_self_closing_element :ellipse, code_generator: code_generator
|
|
104
|
+
define_self_closing_element :line, code_generator: code_generator
|
|
105
|
+
define_self_closing_element :path, code_generator: code_generator
|
|
106
|
+
define_self_closing_element :polygon, code_generator: code_generator
|
|
107
|
+
define_self_closing_element :polyline, code_generator: code_generator
|
|
108
|
+
define_self_closing_element :rect, code_generator: code_generator
|
|
109
|
+
define_self_closing_element :set, code_generator: code_generator
|
|
110
|
+
define_self_closing_element :stop, code_generator: code_generator
|
|
111
|
+
define_self_closing_element :use, code_generator: code_generator
|
|
112
|
+
define_self_closing_element :view, code_generator: code_generator
|
|
113
|
+
|
|
114
|
+
define_element :a, code_generator: code_generator
|
|
115
|
+
define_element :abbr, code_generator: code_generator
|
|
116
|
+
define_element :address, code_generator: code_generator
|
|
117
|
+
define_element :article, code_generator: code_generator
|
|
118
|
+
define_element :aside, code_generator: code_generator
|
|
119
|
+
define_element :audio, code_generator: code_generator
|
|
120
|
+
define_element :b, code_generator: code_generator
|
|
121
|
+
define_element :bdi, code_generator: code_generator
|
|
122
|
+
define_element :bdo, code_generator: code_generator
|
|
123
|
+
define_element :blockquote, code_generator: code_generator
|
|
124
|
+
define_element :body, code_generator: code_generator
|
|
125
|
+
define_element :button, code_generator: code_generator
|
|
126
|
+
define_element :canvas, code_generator: code_generator
|
|
127
|
+
define_element :caption, code_generator: code_generator
|
|
128
|
+
define_element :cite, code_generator: code_generator
|
|
129
|
+
define_element :code, code_generator: code_generator
|
|
130
|
+
define_element :colgroup, code_generator: code_generator
|
|
131
|
+
define_element :data, code_generator: code_generator
|
|
132
|
+
define_element :datalist, code_generator: code_generator
|
|
133
|
+
define_element :dd, code_generator: code_generator
|
|
134
|
+
define_element :del, code_generator: code_generator
|
|
135
|
+
define_element :details, code_generator: code_generator
|
|
136
|
+
define_element :dfn, code_generator: code_generator
|
|
137
|
+
define_element :dialog, code_generator: code_generator
|
|
138
|
+
define_element :div, code_generator: code_generator
|
|
139
|
+
define_element :dl, code_generator: code_generator
|
|
140
|
+
define_element :dt, code_generator: code_generator
|
|
141
|
+
define_element :em, code_generator: code_generator
|
|
142
|
+
define_element :fieldset, code_generator: code_generator
|
|
143
|
+
define_element :figcaption, code_generator: code_generator
|
|
144
|
+
define_element :figure, code_generator: code_generator
|
|
145
|
+
define_element :footer, code_generator: code_generator
|
|
146
|
+
define_element :form, code_generator: code_generator
|
|
147
|
+
define_element :h1, code_generator: code_generator
|
|
148
|
+
define_element :h2, code_generator: code_generator
|
|
149
|
+
define_element :h3, code_generator: code_generator
|
|
150
|
+
define_element :h4, code_generator: code_generator
|
|
151
|
+
define_element :h5, code_generator: code_generator
|
|
152
|
+
define_element :h6, code_generator: code_generator
|
|
153
|
+
define_element :head, code_generator: code_generator
|
|
154
|
+
define_element :header, code_generator: code_generator
|
|
155
|
+
define_element :hgroup, code_generator: code_generator
|
|
156
|
+
define_element :html, code_generator: code_generator
|
|
157
|
+
define_element :i, code_generator: code_generator
|
|
158
|
+
define_element :iframe, code_generator: code_generator
|
|
159
|
+
define_element :ins, code_generator: code_generator
|
|
160
|
+
define_element :kbd, code_generator: code_generator
|
|
161
|
+
define_element :label, code_generator: code_generator
|
|
162
|
+
define_element :legend, code_generator: code_generator
|
|
163
|
+
define_element :li, code_generator: code_generator
|
|
164
|
+
define_element :main, code_generator: code_generator
|
|
165
|
+
define_element :map, code_generator: code_generator
|
|
166
|
+
define_element :mark, code_generator: code_generator
|
|
167
|
+
define_element :menu, code_generator: code_generator
|
|
168
|
+
define_element :meter, code_generator: code_generator
|
|
169
|
+
define_element :nav, code_generator: code_generator
|
|
170
|
+
define_element :noscript, code_generator: code_generator
|
|
171
|
+
define_element :object, code_generator: code_generator
|
|
172
|
+
define_element :ol, code_generator: code_generator
|
|
173
|
+
define_element :optgroup, code_generator: code_generator
|
|
174
|
+
define_element :option, code_generator: code_generator
|
|
175
|
+
define_element :output, code_generator: code_generator
|
|
176
|
+
define_element :p, code_generator: code_generator
|
|
177
|
+
define_element :picture, code_generator: code_generator
|
|
178
|
+
define_element :portal, code_generator: code_generator
|
|
179
|
+
define_element :pre, code_generator: code_generator
|
|
180
|
+
define_element :progress, code_generator: code_generator
|
|
181
|
+
define_element :q, code_generator: code_generator
|
|
182
|
+
define_element :rp, code_generator: code_generator
|
|
183
|
+
define_element :rt, code_generator: code_generator
|
|
184
|
+
define_element :ruby, code_generator: code_generator
|
|
185
|
+
define_element :s, code_generator: code_generator
|
|
186
|
+
define_element :samp, code_generator: code_generator
|
|
187
|
+
define_element :script, code_generator: code_generator
|
|
188
|
+
define_element :search, code_generator: code_generator
|
|
189
|
+
define_element :section, code_generator: code_generator
|
|
190
|
+
define_element :select, code_generator: code_generator
|
|
191
|
+
define_element :slot, code_generator: code_generator
|
|
192
|
+
define_element :small, code_generator: code_generator
|
|
193
|
+
define_element :span, code_generator: code_generator
|
|
194
|
+
define_element :strong, code_generator: code_generator
|
|
195
|
+
define_element :style, code_generator: code_generator
|
|
196
|
+
define_element :sub, code_generator: code_generator
|
|
197
|
+
define_element :summary, code_generator: code_generator
|
|
198
|
+
define_element :sup, code_generator: code_generator
|
|
199
|
+
define_element :table, code_generator: code_generator
|
|
200
|
+
define_element :tbody, code_generator: code_generator
|
|
201
|
+
define_element :td, code_generator: code_generator
|
|
202
|
+
define_element :template, code_generator: code_generator
|
|
203
|
+
define_element :textarea, code_generator: code_generator
|
|
204
|
+
define_element :tfoot, code_generator: code_generator
|
|
205
|
+
define_element :th, code_generator: code_generator
|
|
206
|
+
define_element :thead, code_generator: code_generator
|
|
207
|
+
define_element :time, code_generator: code_generator
|
|
208
|
+
define_element :title, code_generator: code_generator
|
|
209
|
+
define_element :tr, code_generator: code_generator
|
|
210
|
+
define_element :u, code_generator: code_generator
|
|
211
|
+
define_element :ul, code_generator: code_generator
|
|
212
|
+
define_element :var, code_generator: code_generator
|
|
213
|
+
define_element :video, code_generator: code_generator
|
|
214
|
+
end
|
|
51
215
|
|
|
52
216
|
def initialize(view_context)
|
|
53
217
|
@view_context = view_context
|
|
@@ -62,28 +226,22 @@ module ActionView
|
|
|
62
226
|
tag_options(attributes.to_h).to_s.strip.html_safe
|
|
63
227
|
end
|
|
64
228
|
|
|
65
|
-
def
|
|
66
|
-
|
|
229
|
+
def tag_string(name, content = nil, options, escape: true, &block)
|
|
230
|
+
content = @view_context.capture(self, &block) if block
|
|
231
|
+
|
|
232
|
+
content_tag_string(name, content, options, escape)
|
|
67
233
|
end
|
|
68
234
|
|
|
69
|
-
def
|
|
70
|
-
|
|
71
|
-
self_closing = SVG_SELF_CLOSING_ELEMENTS.include?(name)
|
|
72
|
-
if (HTML_VOID_ELEMENTS.include?(name) || self_closing) && content.nil?
|
|
73
|
-
"<#{name.to_s.dasherize}#{tag_options(options, escape)}#{self_closing ? " />" : ">"}".html_safe
|
|
74
|
-
else
|
|
75
|
-
content_tag_string(name.to_s.dasherize, content || "", options, escape)
|
|
76
|
-
end
|
|
235
|
+
def self_closing_tag_string(name, options, escape = true, tag_suffix = " />")
|
|
236
|
+
"<#{name}#{tag_options(options, escape)}#{tag_suffix}".html_safe
|
|
77
237
|
end
|
|
78
238
|
|
|
79
239
|
def content_tag_string(name, content, options, escape = true)
|
|
80
240
|
tag_options = tag_options(options, escape) if options
|
|
81
241
|
|
|
82
|
-
if escape
|
|
83
|
-
name = ERB::Util.xml_name_escape(name)
|
|
242
|
+
if escape && content.present?
|
|
84
243
|
content = ERB::Util.unwrapped_html_escape(content)
|
|
85
244
|
end
|
|
86
|
-
|
|
87
245
|
"<#{name}#{tag_options}>#{PRE_CONTENT_STRINGS[name]}#{content}</#{name}>".html_safe
|
|
88
246
|
end
|
|
89
247
|
|
|
@@ -163,8 +321,12 @@ module ActionView
|
|
|
163
321
|
true
|
|
164
322
|
end
|
|
165
323
|
|
|
166
|
-
def method_missing(called, *args, **options, &block)
|
|
167
|
-
|
|
324
|
+
def method_missing(called, *args, escape: true, **options, &block)
|
|
325
|
+
name = called.name.dasherize
|
|
326
|
+
|
|
327
|
+
TagHelper.ensure_valid_html5_tag_name(name)
|
|
328
|
+
|
|
329
|
+
tag_string(name, *args, options, escape: escape, &block)
|
|
168
330
|
end
|
|
169
331
|
end
|
|
170
332
|
|
|
@@ -245,6 +407,14 @@ module ActionView
|
|
|
245
407
|
# # A void element:
|
|
246
408
|
# tag.br # => <br>
|
|
247
409
|
#
|
|
410
|
+
# Note that when using the block form options should be wrapped in
|
|
411
|
+
# parenthesis.
|
|
412
|
+
#
|
|
413
|
+
# <%= tag.a(href: "/about", class: "font-bold") do %>
|
|
414
|
+
# About the author
|
|
415
|
+
# <% end %>
|
|
416
|
+
# # => <a href="/about" class="font-bold">About the author</a>
|
|
417
|
+
#
|
|
248
418
|
# === Building HTML attributes
|
|
249
419
|
#
|
|
250
420
|
# Transforms a Hash into HTML attributes, ready to be interpolated into
|
|
@@ -310,7 +480,7 @@ module ActionView
|
|
|
310
480
|
if name.nil?
|
|
311
481
|
tag_builder
|
|
312
482
|
else
|
|
313
|
-
|
|
483
|
+
ensure_valid_html5_tag_name(name)
|
|
314
484
|
"<#{name}#{tag_builder.tag_options(options, escape) if options}#{open ? ">" : " />"}".html_safe
|
|
315
485
|
end
|
|
316
486
|
end
|
|
@@ -344,6 +514,8 @@ module ActionView
|
|
|
344
514
|
# <% end -%>
|
|
345
515
|
# # => <div class="strong">Hello world!</div>
|
|
346
516
|
def content_tag(name, content_or_options_with_block = nil, options = nil, escape = true, &block)
|
|
517
|
+
ensure_valid_html5_tag_name(name)
|
|
518
|
+
|
|
347
519
|
if block_given?
|
|
348
520
|
options = content_or_options_with_block if content_or_options_with_block.is_a?(Hash)
|
|
349
521
|
tag_builder.content_tag_string(name, capture(&block), options, escape)
|
|
@@ -400,6 +572,11 @@ module ActionView
|
|
|
400
572
|
end
|
|
401
573
|
|
|
402
574
|
private
|
|
575
|
+
def ensure_valid_html5_tag_name(name)
|
|
576
|
+
raise ArgumentError, "Invalid HTML5 tag name: #{name.inspect}" unless /\A[a-zA-Z][^\s\/>]*\z/.match?(name)
|
|
577
|
+
end
|
|
578
|
+
module_function :ensure_valid_html5_tag_name
|
|
579
|
+
|
|
403
580
|
def build_tag_values(*args)
|
|
404
581
|
tag_values = []
|
|
405
582
|
|
|
@@ -10,12 +10,13 @@ module ActionView
|
|
|
10
10
|
include FormOptionsHelper
|
|
11
11
|
|
|
12
12
|
class CheckBoxBuilder < Builder # :nodoc:
|
|
13
|
-
def
|
|
13
|
+
def checkbox(extra_html_options = {})
|
|
14
14
|
html_options = extra_html_options.merge(@input_html_options)
|
|
15
15
|
html_options[:multiple] = true
|
|
16
16
|
html_options[:skip_default_ids] = false
|
|
17
|
-
@template_object.
|
|
17
|
+
@template_object.checkbox(@object_name, @method_name, html_options, @value, nil)
|
|
18
18
|
end
|
|
19
|
+
alias_method :check_box, :checkbox
|
|
19
20
|
end
|
|
20
21
|
|
|
21
22
|
def render(&block)
|
|
@@ -24,7 +25,7 @@ module ActionView
|
|
|
24
25
|
|
|
25
26
|
private
|
|
26
27
|
def render_component(builder)
|
|
27
|
-
builder.
|
|
28
|
+
builder.checkbox + builder.label
|
|
28
29
|
end
|
|
29
30
|
|
|
30
31
|
def hidden_field_name
|
|
@@ -106,7 +106,8 @@ module ActionView
|
|
|
106
106
|
|
|
107
107
|
def hidden_field
|
|
108
108
|
hidden_name = @html_options[:name] || hidden_field_name
|
|
109
|
-
|
|
109
|
+
options = { id: nil, form: @html_options[:form] }
|
|
110
|
+
@template_object.hidden_field_tag(hidden_name, "", options)
|
|
110
111
|
end
|
|
111
112
|
|
|
112
113
|
def hidden_field_name
|