actionview 7.0.8.6 → 7.1.0.beta1
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 +235 -387
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/app/assets/javascripts/rails-ujs.esm.js +668 -0
- data/app/assets/javascripts/rails-ujs.js +606 -0
- data/lib/action_view/base.rb +28 -7
- data/lib/action_view/buffers.rb +106 -8
- data/lib/action_view/cache_expiry.rb +40 -43
- data/lib/action_view/context.rb +1 -1
- data/lib/action_view/deprecator.rb +7 -0
- data/lib/action_view/digestor.rb +1 -1
- data/lib/action_view/gem_version.rb +4 -4
- data/lib/action_view/helpers/active_model_helper.rb +1 -1
- data/lib/action_view/helpers/asset_tag_helper.rb +130 -46
- data/lib/action_view/helpers/asset_url_helper.rb +6 -5
- data/lib/action_view/helpers/atom_feed_helper.rb +5 -5
- data/lib/action_view/helpers/cache_helper.rb +3 -9
- data/lib/action_view/helpers/capture_helper.rb +24 -10
- data/lib/action_view/helpers/content_exfiltration_prevention_helper.rb +70 -0
- data/lib/action_view/helpers/controller_helper.rb +6 -0
- data/lib/action_view/helpers/csp_helper.rb +2 -2
- data/lib/action_view/helpers/csrf_helper.rb +2 -2
- data/lib/action_view/helpers/date_helper.rb +17 -19
- data/lib/action_view/helpers/debug_helper.rb +3 -3
- data/lib/action_view/helpers/form_helper.rb +43 -18
- data/lib/action_view/helpers/form_options_helper.rb +2 -1
- data/lib/action_view/helpers/form_tag_helper.rb +43 -9
- data/lib/action_view/helpers/javascript_helper.rb +1 -0
- data/lib/action_view/helpers/number_helper.rb +2 -1
- data/lib/action_view/helpers/output_safety_helper.rb +2 -2
- data/lib/action_view/helpers/rendering_helper.rb +1 -1
- data/lib/action_view/helpers/sanitize_helper.rb +33 -14
- data/lib/action_view/helpers/tag_helper.rb +5 -27
- data/lib/action_view/helpers/tags/base.rb +11 -52
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +1 -0
- data/lib/action_view/helpers/tags/collection_radio_buttons.rb +1 -0
- data/lib/action_view/helpers/tags/collection_select.rb +3 -0
- data/lib/action_view/helpers/tags/date_field.rb +1 -1
- data/lib/action_view/helpers/tags/date_select.rb +2 -0
- data/lib/action_view/helpers/tags/datetime_field.rb +14 -6
- data/lib/action_view/helpers/tags/datetime_local_field.rb +11 -2
- data/lib/action_view/helpers/tags/grouped_collection_select.rb +3 -0
- data/lib/action_view/helpers/tags/month_field.rb +1 -1
- data/lib/action_view/helpers/tags/select.rb +3 -0
- data/lib/action_view/helpers/tags/select_renderer.rb +56 -0
- data/lib/action_view/helpers/tags/time_field.rb +1 -1
- data/lib/action_view/helpers/tags/time_zone_select.rb +3 -0
- data/lib/action_view/helpers/tags/week_field.rb +1 -1
- data/lib/action_view/helpers/tags/weekday_select.rb +3 -0
- data/lib/action_view/helpers/tags.rb +2 -0
- data/lib/action_view/helpers/text_helper.rb +32 -16
- data/lib/action_view/helpers/translation_helper.rb +3 -3
- data/lib/action_view/helpers/url_helper.rb +41 -14
- data/lib/action_view/helpers.rb +2 -0
- data/lib/action_view/layouts.rb +4 -2
- data/lib/action_view/log_subscriber.rb +49 -32
- data/lib/action_view/lookup_context.rb +29 -13
- data/lib/action_view/path_registry.rb +57 -0
- data/lib/action_view/path_set.rb +13 -14
- data/lib/action_view/railtie.rb +26 -3
- data/lib/action_view/record_identifier.rb +15 -8
- data/lib/action_view/renderer/abstract_renderer.rb +1 -1
- data/lib/action_view/renderer/collection_renderer.rb +9 -1
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +2 -1
- data/lib/action_view/renderer/partial_renderer.rb +2 -1
- data/lib/action_view/renderer/renderer.rb +2 -0
- data/lib/action_view/renderer/streaming_template_renderer.rb +3 -2
- data/lib/action_view/renderer/template_renderer.rb +3 -2
- data/lib/action_view/rendering.rb +22 -4
- data/lib/action_view/ripper_ast_parser.rb +6 -6
- data/lib/action_view/template/error.rb +14 -1
- data/lib/action_view/template/handlers/builder.rb +4 -4
- data/lib/action_view/template/handlers/erb/erubi.rb +23 -27
- data/lib/action_view/template/handlers/erb.rb +73 -1
- data/lib/action_view/template/handlers.rb +1 -1
- data/lib/action_view/template/html.rb +1 -1
- data/lib/action_view/template/raw_file.rb +1 -1
- data/lib/action_view/template/renderable.rb +1 -1
- data/lib/action_view/template/resolver.rb +10 -2
- data/lib/action_view/template/text.rb +1 -1
- data/lib/action_view/template/types.rb +25 -34
- data/lib/action_view/template.rb +179 -52
- data/lib/action_view/template_path.rb +2 -0
- data/lib/action_view/test_case.rb +8 -5
- data/lib/action_view/unbound_template.rb +15 -5
- data/lib/action_view/version.rb +1 -1
- data/lib/action_view/view_paths.rb +15 -24
- data/lib/action_view.rb +4 -1
- metadata +29 -29
@@ -1,14 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "cgi"
|
4
|
+
require "action_view/helpers/content_exfiltration_prevention_helper"
|
4
5
|
require "action_view/helpers/url_helper"
|
5
6
|
require "action_view/helpers/text_helper"
|
6
7
|
require "active_support/core_ext/string/output_safety"
|
7
8
|
require "active_support/core_ext/module/attribute_accessors"
|
8
9
|
|
9
10
|
module ActionView
|
10
|
-
# = Action View Form Tag Helpers
|
11
11
|
module Helpers # :nodoc:
|
12
|
+
# = Action View Form Tag \Helpers
|
13
|
+
#
|
12
14
|
# Provides a number of methods for creating form tags that don't rely on an Active Record object assigned to the template like
|
13
15
|
# FormHelper does. Instead, you provide the names and values manually.
|
14
16
|
#
|
@@ -19,6 +21,7 @@ module ActionView
|
|
19
21
|
|
20
22
|
include UrlHelper
|
21
23
|
include TextHelper
|
24
|
+
include ContentExfiltrationPreventionHelper
|
22
25
|
|
23
26
|
mattr_accessor :embed_authenticity_token_in_remote_forms
|
24
27
|
self.embed_authenticity_token_in_remote_forms = nil
|
@@ -420,9 +423,17 @@ module ActionView
|
|
420
423
|
content_tag :textarea, content.to_s.html_safe, { "name" => name, "id" => sanitize_to_id(name) }.update(options)
|
421
424
|
end
|
422
425
|
|
426
|
+
##
|
427
|
+
# :call-seq:
|
428
|
+
# check_box_tag(name, options = {})
|
429
|
+
# check_box_tag(name, value, options = {})
|
430
|
+
# check_box_tag(name, value, checked, options = {})
|
431
|
+
#
|
423
432
|
# Creates a check box form input tag.
|
424
433
|
#
|
425
434
|
# ==== Options
|
435
|
+
# * <tt>:value</tt> - The value of the input. Defaults to <tt>"1"</tt>.
|
436
|
+
# * <tt>:checked</tt> - If set to true, the checkbox will be checked by default.
|
426
437
|
# * <tt>:disabled</tt> - If set to true, the user will not be able to use this input.
|
427
438
|
# * Any other key creates standard HTML options for the tag.
|
428
439
|
#
|
@@ -441,16 +452,27 @@ module ActionView
|
|
441
452
|
#
|
442
453
|
# check_box_tag 'eula', 'accepted', false, disabled: true
|
443
454
|
# # => <input disabled="disabled" id="eula" name="eula" type="checkbox" value="accepted" />
|
444
|
-
def check_box_tag(name,
|
455
|
+
def check_box_tag(name, *args)
|
456
|
+
if args.length >= 4
|
457
|
+
raise ArgumentError, "wrong number of arguments (given #{args.length + 1}, expected 1..4)"
|
458
|
+
end
|
459
|
+
options = args.extract_options!
|
460
|
+
value, checked = args.empty? ? ["1", false] : [*args, false]
|
445
461
|
html_options = { "type" => "checkbox", "name" => name, "id" => sanitize_to_id(name), "value" => value }.update(options.stringify_keys)
|
446
462
|
html_options["checked"] = "checked" if checked
|
447
463
|
tag :input, html_options
|
448
464
|
end
|
449
465
|
|
466
|
+
##
|
467
|
+
# :call-seq:
|
468
|
+
# radio_button_tag(name, value, options = {})
|
469
|
+
# radio_button_tag(name, value, checked, options = {})
|
470
|
+
#
|
450
471
|
# Creates a radio button; use groups of radio buttons named the same to allow users to
|
451
472
|
# select from a group of options.
|
452
473
|
#
|
453
474
|
# ==== Options
|
475
|
+
# * <tt>:checked</tt> - If set to true, the radio button will be selected by default.
|
454
476
|
# * <tt>:disabled</tt> - If set to true, the user will not be able to use this input.
|
455
477
|
# * Any other key creates standard HTML options for the tag.
|
456
478
|
#
|
@@ -466,7 +488,12 @@ module ActionView
|
|
466
488
|
#
|
467
489
|
# radio_button_tag 'color', "green", true, class: "color_input"
|
468
490
|
# # => <input checked="checked" class="color_input" id="color_green" name="color" type="radio" value="green" />
|
469
|
-
def radio_button_tag(name, value,
|
491
|
+
def radio_button_tag(name, value, *args)
|
492
|
+
if args.length >= 3
|
493
|
+
raise ArgumentError, "wrong number of arguments (given #{args.length + 2}, expected 2..4)"
|
494
|
+
end
|
495
|
+
options = args.extract_options!
|
496
|
+
checked = args.empty? ? false : args.first
|
470
497
|
html_options = { "type" => "radio", "name" => name, "id" => "#{sanitize_to_id(name)}_#{sanitize_to_id(value)}", "value" => value }.update(options.stringify_keys)
|
471
498
|
html_options["checked"] = "checked" if checked
|
472
499
|
tag :input, html_options
|
@@ -495,9 +522,9 @@ module ActionView
|
|
495
522
|
# submit_tag "Edit", class: "edit_button"
|
496
523
|
# # => <input class="edit_button" data-disable-with="Edit" name="commit" type="submit" value="Edit" />
|
497
524
|
#
|
498
|
-
# ==== Deprecated: Rails UJS attributes
|
525
|
+
# ==== Deprecated: \Rails UJS attributes
|
499
526
|
#
|
500
|
-
# Prior to Rails 7, Rails shipped with the JavaScript library called @rails/ujs on by default. Following Rails 7,
|
527
|
+
# Prior to \Rails 7, \Rails shipped with the JavaScript library called @rails/ujs on by default. Following \Rails 7,
|
501
528
|
# this library is no longer on by default. This library integrated with the following options:
|
502
529
|
#
|
503
530
|
# * <tt>confirm: 'question?'</tt> - If present the unobtrusive JavaScript
|
@@ -555,9 +582,9 @@ module ActionView
|
|
555
582
|
# # <strong>Ask me!</strong>
|
556
583
|
# # </button>
|
557
584
|
#
|
558
|
-
# ==== Deprecated: Rails UJS attributes
|
585
|
+
# ==== Deprecated: \Rails UJS attributes
|
559
586
|
#
|
560
|
-
# Prior to Rails 7, Rails shipped with a JavaScript library called @rails/ujs on by default. Following Rails 7,
|
587
|
+
# Prior to \Rails 7, \Rails shipped with a JavaScript library called @rails/ujs on by default. Following \Rails 7,
|
561
588
|
# this library is no longer on by default. This library integrated with the following options:
|
562
589
|
#
|
563
590
|
# * <tt>confirm: 'question?'</tt> - If present, the
|
@@ -770,6 +797,7 @@ module ActionView
|
|
770
797
|
# * <tt>:min</tt> - The minimum acceptable value.
|
771
798
|
# * <tt>:max</tt> - The maximum acceptable value.
|
772
799
|
# * <tt>:step</tt> - The acceptable value granularity.
|
800
|
+
# * <tt>:include_seconds</tt> - Include seconds in the output timestamp format (true by default).
|
773
801
|
def datetime_field_tag(name, value = nil, options = {})
|
774
802
|
text_field_tag(name, value, options.merge(type: "datetime-local"))
|
775
803
|
end
|
@@ -979,7 +1007,8 @@ module ActionView
|
|
979
1007
|
|
980
1008
|
def form_tag_html(html_options)
|
981
1009
|
extra_tags = extra_tags_for_form(html_options)
|
982
|
-
tag(:form, html_options, true) + extra_tags
|
1010
|
+
html = tag(:form, html_options, true) + extra_tags
|
1011
|
+
prevent_content_exfiltration(html)
|
983
1012
|
end
|
984
1013
|
|
985
1014
|
def form_tag_with_body(html_options, content)
|
@@ -1009,9 +1038,14 @@ module ActionView
|
|
1009
1038
|
end
|
1010
1039
|
|
1011
1040
|
def convert_direct_upload_option_to_url(options)
|
1012
|
-
|
1041
|
+
return options unless options.delete(:direct_upload)
|
1042
|
+
|
1043
|
+
if respond_to?(:rails_direct_uploads_url)
|
1013
1044
|
options["data-direct-upload-url"] = rails_direct_uploads_url
|
1045
|
+
elsif respond_to?(:main_app) && main_app.respond_to?(:rails_direct_uploads_url)
|
1046
|
+
options["data-direct-upload-url"] = main_app.rails_direct_uploads_url
|
1014
1047
|
end
|
1048
|
+
|
1015
1049
|
options
|
1016
1050
|
end
|
1017
1051
|
end
|
@@ -5,8 +5,9 @@ require "active_support/core_ext/string/output_safety"
|
|
5
5
|
require "active_support/number_helper"
|
6
6
|
|
7
7
|
module ActionView
|
8
|
-
# = Action View Number Helpers
|
9
8
|
module Helpers # :nodoc:
|
9
|
+
# = Action View Number \Helpers
|
10
|
+
#
|
10
11
|
# Provides methods for converting numbers into formatted strings.
|
11
12
|
# Methods are provided for phone numbers, currency, percentage,
|
12
13
|
# precision, positional notation, file size, and pretty printing.
|
@@ -3,11 +3,11 @@
|
|
3
3
|
require "active_support/core_ext/string/output_safety"
|
4
4
|
|
5
5
|
module ActionView # :nodoc:
|
6
|
-
# = Action View Raw Output Helper
|
7
6
|
module Helpers # :nodoc:
|
7
|
+
# = Action View Raw Output \Helpers
|
8
8
|
module OutputSafetyHelper
|
9
9
|
# This method outputs without escaping a string. Since escaping tags is
|
10
|
-
# now default, this can be used when you don't want Rails to automatically
|
10
|
+
# now default, this can be used when you don't want \Rails to automatically
|
11
11
|
# escape tags. This is not recommended if the data is coming from the user's
|
12
12
|
# input.
|
13
13
|
#
|
@@ -3,20 +3,23 @@
|
|
3
3
|
require "rails-html-sanitizer"
|
4
4
|
|
5
5
|
module ActionView
|
6
|
-
# = Action View Sanitize Helpers
|
7
6
|
module Helpers # :nodoc:
|
7
|
+
# = Action View Sanitize \Helpers
|
8
|
+
#
|
8
9
|
# The SanitizeHelper module provides a set of methods for scrubbing text of undesired HTML elements.
|
9
10
|
# These helper methods extend Action View making them callable within your template files.
|
10
11
|
module SanitizeHelper
|
12
|
+
mattr_accessor :sanitizer_vendor, default: Rails::HTML4::Sanitizer
|
13
|
+
|
11
14
|
extend ActiveSupport::Concern
|
15
|
+
|
12
16
|
# Sanitizes HTML input, stripping all but known-safe tags and attributes.
|
13
17
|
#
|
14
|
-
# It also strips href/src attributes with unsafe protocols like
|
15
|
-
#
|
16
|
-
#
|
17
|
-
# All special characters will be escaped.
|
18
|
+
# It also strips href/src attributes with unsafe protocols like <tt>javascript:</tt>, while
|
19
|
+
# also protecting against attempts to use Unicode, ASCII, and hex character references to work
|
20
|
+
# around these protocol filters.
|
18
21
|
#
|
19
|
-
# The default sanitizer is Rails::
|
22
|
+
# The default sanitizer is Rails::HTML5::SafeListSanitizer. See {Rails HTML
|
20
23
|
# Sanitizers}[https://github.com/rails/rails-html-sanitizer] for more information.
|
21
24
|
#
|
22
25
|
# Custom sanitization rules can also be provided.
|
@@ -28,7 +31,7 @@ module ActionView
|
|
28
31
|
#
|
29
32
|
# * <tt>:tags</tt> - An array of allowed tags.
|
30
33
|
# * <tt>:attributes</tt> - An array of allowed attributes.
|
31
|
-
# * <tt>:scrubber</tt> - A {Rails::
|
34
|
+
# * <tt>:scrubber</tt> - A {Rails::HTML scrubber}[https://github.com/rails/rails-html-sanitizer]
|
32
35
|
# or {Loofah::Scrubber}[https://github.com/flavorjones/loofah] object that
|
33
36
|
# defines custom sanitization rules. A custom scrubber takes precedence over
|
34
37
|
# custom tags and attributes.
|
@@ -43,9 +46,9 @@ module ActionView
|
|
43
46
|
#
|
44
47
|
# <%= sanitize @comment.body, tags: %w(strong em a), attributes: %w(href) %>
|
45
48
|
#
|
46
|
-
# Providing a custom Rails::
|
49
|
+
# Providing a custom Rails::HTML scrubber:
|
47
50
|
#
|
48
|
-
# class CommentScrubber < Rails::
|
51
|
+
# class CommentScrubber < Rails::HTML::PermitScrubber
|
49
52
|
# def initialize
|
50
53
|
# super
|
51
54
|
# self.tags = %w( form script comment blockquote )
|
@@ -60,7 +63,7 @@ module ActionView
|
|
60
63
|
# <%= sanitize @comment.body, scrubber: CommentScrubber.new %>
|
61
64
|
#
|
62
65
|
# See {Rails HTML Sanitizer}[https://github.com/rails/rails-html-sanitizer] for
|
63
|
-
# documentation about Rails::
|
66
|
+
# documentation about Rails::HTML scrubbers.
|
64
67
|
#
|
65
68
|
# Providing a custom Loofah::Scrubber:
|
66
69
|
#
|
@@ -78,6 +81,22 @@ module ActionView
|
|
78
81
|
# # In config/application.rb
|
79
82
|
# config.action_view.sanitized_allowed_tags = ['strong', 'em', 'a']
|
80
83
|
# config.action_view.sanitized_allowed_attributes = ['href', 'title']
|
84
|
+
#
|
85
|
+
# The default, starting in \Rails 7.1, is to use an HTML5 parser for sanitization (if it is
|
86
|
+
# available, see NOTE below). If you wish to revert back to the previous HTML4 behavior, you
|
87
|
+
# can do so by setting the following in your application configuration:
|
88
|
+
#
|
89
|
+
# # In config/application.rb
|
90
|
+
# config.action_view.sanitizer_vendor = Rails::HTML4::Sanitizer
|
91
|
+
#
|
92
|
+
# Or, if you're upgrading from a previous version of \Rails and wish to opt into the HTML5
|
93
|
+
# behavior:
|
94
|
+
#
|
95
|
+
# # In config/application.rb
|
96
|
+
# config.action_view.sanitizer_vendor = Rails::HTML5::Sanitizer
|
97
|
+
#
|
98
|
+
# NOTE: Rails::HTML5::Sanitizer is not supported on JRuby, so on JRuby platforms \Rails will
|
99
|
+
# fall back to use Rails::HTML4::Sanitizer.
|
81
100
|
def sanitize(html, options = {})
|
82
101
|
self.class.safe_list_sanitizer.sanitize(html, options)&.html_safe
|
83
102
|
end
|
@@ -125,7 +144,7 @@ module ActionView
|
|
125
144
|
attr_writer :full_sanitizer, :link_sanitizer, :safe_list_sanitizer
|
126
145
|
|
127
146
|
def sanitizer_vendor
|
128
|
-
|
147
|
+
ActionView::Helpers::SanitizeHelper.sanitizer_vendor
|
129
148
|
end
|
130
149
|
|
131
150
|
def sanitized_allowed_tags
|
@@ -136,7 +155,7 @@ module ActionView
|
|
136
155
|
sanitizer_vendor.safe_list_sanitizer.allowed_attributes
|
137
156
|
end
|
138
157
|
|
139
|
-
# Gets the Rails::
|
158
|
+
# Gets the Rails::HTML::FullSanitizer instance used by +strip_tags+. Replace with
|
140
159
|
# any object that responds to +sanitize+.
|
141
160
|
#
|
142
161
|
# class Application < Rails::Application
|
@@ -146,7 +165,7 @@ module ActionView
|
|
146
165
|
@full_sanitizer ||= sanitizer_vendor.full_sanitizer.new
|
147
166
|
end
|
148
167
|
|
149
|
-
# Gets the Rails::
|
168
|
+
# Gets the Rails::HTML::LinkSanitizer instance used by +strip_links+.
|
150
169
|
# Replace with any object that responds to +sanitize+.
|
151
170
|
#
|
152
171
|
# class Application < Rails::Application
|
@@ -156,7 +175,7 @@ module ActionView
|
|
156
175
|
@link_sanitizer ||= sanitizer_vendor.link_sanitizer.new
|
157
176
|
end
|
158
177
|
|
159
|
-
# Gets the Rails::
|
178
|
+
# Gets the Rails::HTML::SafeListSanitizer instance used by sanitize and +sanitize_css+.
|
160
179
|
# Replace with any object that responds to +sanitize+.
|
161
180
|
#
|
162
181
|
# class Application < Rails::Application
|
@@ -7,8 +7,9 @@ require "action_view/helpers/capture_helper"
|
|
7
7
|
require "action_view/helpers/output_safety_helper"
|
8
8
|
|
9
9
|
module ActionView
|
10
|
-
# = Action View Tag Helpers
|
11
10
|
module Helpers # :nodoc:
|
11
|
+
# = Action View Tag \Helpers
|
12
|
+
#
|
12
13
|
# Provides methods to generate HTML tags programmatically both as a modern
|
13
14
|
# HTML5 compliant builder style and legacy XHTML compliant tags.
|
14
15
|
module TagHelper
|
@@ -65,9 +66,7 @@ module ActionView
|
|
65
66
|
tag_string(:p, *arguments, **options, &block)
|
66
67
|
end
|
67
68
|
|
68
|
-
def tag_string(name, content = nil, **options, &block)
|
69
|
-
escape = handle_deprecated_escape_options(options)
|
70
|
-
|
69
|
+
def tag_string(name, content = nil, escape: true, **options, &block)
|
71
70
|
content = @view_context.capture(self, &block) if block_given?
|
72
71
|
self_closing = SVG_SELF_CLOSING_ELEMENTS.include?(name)
|
73
72
|
if (HTML_VOID_ELEMENTS.include?(name) || self_closing) && content.nil?
|
@@ -164,27 +163,6 @@ module ActionView
|
|
164
163
|
true
|
165
164
|
end
|
166
165
|
|
167
|
-
def handle_deprecated_escape_options(options)
|
168
|
-
# The option :escape_attributes has been merged into the options hash to be
|
169
|
-
# able to warn when it is used, so we need to handle default values here.
|
170
|
-
escape_option_provided = options.has_key?(:escape)
|
171
|
-
escape_attributes_option_provided = options.has_key?(:escape_attributes)
|
172
|
-
|
173
|
-
if escape_attributes_option_provided
|
174
|
-
ActiveSupport::Deprecation.warn(<<~MSG)
|
175
|
-
Use of the option :escape_attributes is deprecated. It currently \
|
176
|
-
escapes both names and values of tags and attributes and it is \
|
177
|
-
equivalent to :escape. If any of them are enabled, the escaping \
|
178
|
-
is fully enabled.
|
179
|
-
MSG
|
180
|
-
end
|
181
|
-
|
182
|
-
return true unless escape_option_provided || escape_attributes_option_provided
|
183
|
-
escape_option = options.delete(:escape)
|
184
|
-
escape_attributes_option = options.delete(:escape_attributes)
|
185
|
-
escape_option || escape_attributes_option
|
186
|
-
end
|
187
|
-
|
188
166
|
def method_missing(called, *args, **options, &block)
|
189
167
|
tag_string(called, *args, **options, &block)
|
190
168
|
end
|
@@ -283,7 +261,7 @@ module ActionView
|
|
283
261
|
#
|
284
262
|
# === Legacy syntax
|
285
263
|
#
|
286
|
-
# The following format is for legacy syntax support. It will be deprecated in future versions of Rails.
|
264
|
+
# The following format is for legacy syntax support. It will be deprecated in future versions of \Rails.
|
287
265
|
#
|
288
266
|
# tag(name, options = nil, open = false, escape = true)
|
289
267
|
#
|
@@ -386,7 +364,7 @@ module ActionView
|
|
386
364
|
# token_list(nil, false, 123, "", "foo", { bar: true })
|
387
365
|
# # => "123 foo bar"
|
388
366
|
def token_list(*args)
|
389
|
-
tokens = build_tag_values(*args).flat_map { |value| value.to_s.split(/\s+/) }.uniq
|
367
|
+
tokens = build_tag_values(*args).flat_map { |value| CGI.unescape_html(value.to_s).split(/\s+/) }.uniq
|
390
368
|
|
391
369
|
safe_join(tokens, " ")
|
392
370
|
end
|
@@ -5,7 +5,6 @@ module ActionView
|
|
5
5
|
module Tags # :nodoc:
|
6
6
|
class Base # :nodoc:
|
7
7
|
include Helpers::ActiveModelInstanceTag, Helpers::TagHelper, Helpers::FormTagHelper
|
8
|
-
include FormOptionsHelper
|
9
8
|
|
10
9
|
attr_reader :object
|
11
10
|
|
@@ -35,22 +34,24 @@ module ActionView
|
|
35
34
|
|
36
35
|
private
|
37
36
|
def value
|
37
|
+
return unless object
|
38
|
+
|
38
39
|
if @allow_method_names_outside_object
|
39
|
-
object.public_send @method_name if object
|
40
|
+
object.public_send @method_name if object.respond_to?(@method_name)
|
40
41
|
else
|
41
|
-
object.public_send @method_name
|
42
|
+
object.public_send @method_name
|
42
43
|
end
|
43
44
|
end
|
44
45
|
|
45
46
|
def value_before_type_cast
|
46
|
-
unless object
|
47
|
-
method_before_type_cast = @method_name + "_before_type_cast"
|
47
|
+
return unless object
|
48
48
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
49
|
+
method_before_type_cast = @method_name + "_before_type_cast"
|
50
|
+
|
51
|
+
if value_came_from_user? && object.respond_to?(method_before_type_cast)
|
52
|
+
object.public_send(method_before_type_cast)
|
53
|
+
else
|
54
|
+
value
|
54
55
|
end
|
55
56
|
end
|
56
57
|
|
@@ -120,48 +121,6 @@ module ActionView
|
|
120
121
|
value.to_s.gsub(/[\s.]/, "_").gsub(/[^-[[:word:]]]/, "").downcase
|
121
122
|
end
|
122
123
|
|
123
|
-
def select_content_tag(option_tags, options, html_options)
|
124
|
-
html_options = html_options.stringify_keys
|
125
|
-
add_default_name_and_id(html_options)
|
126
|
-
|
127
|
-
if placeholder_required?(html_options)
|
128
|
-
raise ArgumentError, "include_blank cannot be false for a required field." if options[:include_blank] == false
|
129
|
-
options[:include_blank] ||= true unless options[:prompt]
|
130
|
-
end
|
131
|
-
|
132
|
-
value = options.fetch(:selected) { value() }
|
133
|
-
select = content_tag("select", add_options(option_tags, options, value), html_options)
|
134
|
-
|
135
|
-
if html_options["multiple"] && options.fetch(:include_hidden, true)
|
136
|
-
tag("input", disabled: html_options["disabled"], name: html_options["name"], type: "hidden", value: "", autocomplete: "off") + select
|
137
|
-
else
|
138
|
-
select
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
def placeholder_required?(html_options)
|
143
|
-
# See https://html.spec.whatwg.org/multipage/forms.html#attr-select-required
|
144
|
-
html_options["required"] && !html_options["multiple"] && html_options.fetch("size", 1).to_i == 1
|
145
|
-
end
|
146
|
-
|
147
|
-
def add_options(option_tags, options, value = nil)
|
148
|
-
if options[:include_blank]
|
149
|
-
content = (options[:include_blank] if options[:include_blank].is_a?(String))
|
150
|
-
label = (" " unless content)
|
151
|
-
option_tags = tag_builder.content_tag_string("option", content, value: "", label: label) + "\n" + option_tags
|
152
|
-
end
|
153
|
-
|
154
|
-
if value.blank? && options[:prompt]
|
155
|
-
tag_options = { value: "" }.tap do |prompt_opts|
|
156
|
-
prompt_opts[:disabled] = true if options[:disabled] == ""
|
157
|
-
prompt_opts[:selected] = true if options[:selected] == ""
|
158
|
-
end
|
159
|
-
option_tags = tag_builder.content_tag_string("option", prompt_text(options[:prompt]), tag_options) + "\n" + option_tags
|
160
|
-
end
|
161
|
-
|
162
|
-
option_tags
|
163
|
-
end
|
164
|
-
|
165
124
|
def name_and_id_index(options)
|
166
125
|
if options.key?("index")
|
167
126
|
options.delete("index") || ""
|
@@ -4,6 +4,9 @@ module ActionView
|
|
4
4
|
module Helpers
|
5
5
|
module Tags # :nodoc:
|
6
6
|
class CollectionSelect < Base # :nodoc:
|
7
|
+
include SelectRenderer
|
8
|
+
include FormOptionsHelper
|
9
|
+
|
7
10
|
def initialize(object_name, method_name, template_object, collection, value_method, text_method, options, html_options)
|
8
11
|
@collection = collection
|
9
12
|
@value_method = value_method
|
@@ -6,20 +6,28 @@ module ActionView
|
|
6
6
|
class DatetimeField < TextField # :nodoc:
|
7
7
|
def render
|
8
8
|
options = @options.stringify_keys
|
9
|
-
options["value"]
|
10
|
-
options["min"] =
|
11
|
-
options["max"] =
|
9
|
+
options["value"] = datetime_value(options["value"] || value)
|
10
|
+
options["min"] = format_datetime(parse_datetime(options["min"]))
|
11
|
+
options["max"] = format_datetime(parse_datetime(options["max"]))
|
12
12
|
@options = options
|
13
13
|
super
|
14
14
|
end
|
15
15
|
|
16
16
|
private
|
17
|
-
def
|
17
|
+
def datetime_value(value)
|
18
|
+
if value.is_a?(String)
|
19
|
+
value
|
20
|
+
else
|
21
|
+
format_datetime(value)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def format_datetime(value)
|
18
26
|
raise NotImplementedError
|
19
27
|
end
|
20
28
|
|
21
|
-
def
|
22
|
-
if value.is_a?
|
29
|
+
def parse_datetime(value)
|
30
|
+
if value.is_a?(String)
|
23
31
|
DateTime.parse(value) rescue nil
|
24
32
|
else
|
25
33
|
value
|
@@ -4,6 +4,11 @@ module ActionView
|
|
4
4
|
module Helpers
|
5
5
|
module Tags # :nodoc:
|
6
6
|
class DatetimeLocalField < DatetimeField # :nodoc:
|
7
|
+
def initialize(object_name, method_name, template_object, options = {})
|
8
|
+
@include_seconds = options.delete(:include_seconds) { true }
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
7
12
|
class << self
|
8
13
|
def field_type
|
9
14
|
@field_type ||= "datetime-local"
|
@@ -11,8 +16,12 @@ module ActionView
|
|
11
16
|
end
|
12
17
|
|
13
18
|
private
|
14
|
-
def
|
15
|
-
|
19
|
+
def format_datetime(value)
|
20
|
+
if @include_seconds
|
21
|
+
value&.strftime("%Y-%m-%dT%T")
|
22
|
+
else
|
23
|
+
value&.strftime("%Y-%m-%dT%H:%M")
|
24
|
+
end
|
16
25
|
end
|
17
26
|
end
|
18
27
|
end
|
@@ -4,6 +4,9 @@ module ActionView
|
|
4
4
|
module Helpers
|
5
5
|
module Tags # :nodoc:
|
6
6
|
class GroupedCollectionSelect < Base # :nodoc:
|
7
|
+
include SelectRenderer
|
8
|
+
include FormOptionsHelper
|
9
|
+
|
7
10
|
def initialize(object_name, method_name, template_object, collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options)
|
8
11
|
@collection = collection
|
9
12
|
@group_method = group_method
|
@@ -4,6 +4,9 @@ module ActionView
|
|
4
4
|
module Helpers
|
5
5
|
module Tags # :nodoc:
|
6
6
|
class Select < Base # :nodoc:
|
7
|
+
include SelectRenderer
|
8
|
+
include FormOptionsHelper
|
9
|
+
|
7
10
|
def initialize(object_name, method_name, template_object, choices, options, html_options)
|
8
11
|
@choices = block_given? ? template_object.capture { yield || "" } : choices
|
9
12
|
@choices = @choices.to_a if @choices.is_a?(Range)
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActionView
|
4
|
+
module Helpers
|
5
|
+
module Tags # :nodoc:
|
6
|
+
module SelectRenderer # :nodoc:
|
7
|
+
private
|
8
|
+
def select_content_tag(option_tags, options, html_options)
|
9
|
+
html_options = html_options.stringify_keys
|
10
|
+
[:required, :multiple, :size].each do |prop|
|
11
|
+
html_options[prop.to_s] = options.delete(prop) if options.key?(prop) && !html_options.key?(prop.to_s)
|
12
|
+
end
|
13
|
+
|
14
|
+
add_default_name_and_id(html_options)
|
15
|
+
|
16
|
+
if placeholder_required?(html_options)
|
17
|
+
raise ArgumentError, "include_blank cannot be false for a required field." if options[:include_blank] == false
|
18
|
+
options[:include_blank] ||= true unless options[:prompt]
|
19
|
+
end
|
20
|
+
|
21
|
+
value = options.fetch(:selected) { value() }
|
22
|
+
select = content_tag("select", add_options(option_tags, options, value), html_options)
|
23
|
+
|
24
|
+
if html_options["multiple"] && options.fetch(:include_hidden, true)
|
25
|
+
tag("input", disabled: html_options["disabled"], name: html_options["name"], type: "hidden", value: "", autocomplete: "off") + select
|
26
|
+
else
|
27
|
+
select
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def placeholder_required?(html_options)
|
32
|
+
# See https://html.spec.whatwg.org/multipage/forms.html#attr-select-required
|
33
|
+
html_options["required"] && !html_options["multiple"] && html_options.fetch("size", 1).to_i == 1
|
34
|
+
end
|
35
|
+
|
36
|
+
def add_options(option_tags, options, value = nil)
|
37
|
+
if options[:include_blank]
|
38
|
+
content = (options[:include_blank] if options[:include_blank].is_a?(String))
|
39
|
+
label = (" " unless content)
|
40
|
+
option_tags = tag_builder.content_tag_string("option", content, value: "", label: label) + "\n" + option_tags
|
41
|
+
end
|
42
|
+
|
43
|
+
if value.blank? && options[:prompt]
|
44
|
+
tag_options = { value: "" }.tap do |prompt_opts|
|
45
|
+
prompt_opts[:disabled] = true if options[:disabled] == ""
|
46
|
+
prompt_opts[:selected] = true if options[:selected] == ""
|
47
|
+
end
|
48
|
+
option_tags = tag_builder.content_tag_string("option", prompt_text(options[:prompt]), tag_options) + "\n" + option_tags
|
49
|
+
end
|
50
|
+
|
51
|
+
option_tags
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|