actionview 7.0.8.6 → 7.1.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|