actionview 7.0.8.7 → 7.1.5.1

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.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +309 -321
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/app/assets/javascripts/rails-ujs.esm.js +686 -0
  6. data/app/assets/javascripts/rails-ujs.js +630 -0
  7. data/lib/action_view/base.rb +34 -14
  8. data/lib/action_view/buffers.rb +106 -8
  9. data/lib/action_view/cache_expiry.rb +40 -43
  10. data/lib/action_view/context.rb +1 -1
  11. data/lib/action_view/deprecator.rb +7 -0
  12. data/lib/action_view/digestor.rb +1 -1
  13. data/lib/action_view/gem_version.rb +4 -4
  14. data/lib/action_view/helpers/active_model_helper.rb +1 -1
  15. data/lib/action_view/helpers/asset_tag_helper.rb +136 -52
  16. data/lib/action_view/helpers/asset_url_helper.rb +6 -5
  17. data/lib/action_view/helpers/atom_feed_helper.rb +5 -5
  18. data/lib/action_view/helpers/cache_helper.rb +7 -13
  19. data/lib/action_view/helpers/capture_helper.rb +30 -10
  20. data/lib/action_view/helpers/content_exfiltration_prevention_helper.rb +70 -0
  21. data/lib/action_view/helpers/controller_helper.rb +6 -0
  22. data/lib/action_view/helpers/csp_helper.rb +2 -2
  23. data/lib/action_view/helpers/csrf_helper.rb +2 -2
  24. data/lib/action_view/helpers/date_helper.rb +17 -19
  25. data/lib/action_view/helpers/debug_helper.rb +3 -3
  26. data/lib/action_view/helpers/form_helper.rb +54 -25
  27. data/lib/action_view/helpers/form_options_helper.rb +2 -1
  28. data/lib/action_view/helpers/form_tag_helper.rb +49 -15
  29. data/lib/action_view/helpers/javascript_helper.rb +1 -0
  30. data/lib/action_view/helpers/number_helper.rb +37 -330
  31. data/lib/action_view/helpers/output_safety_helper.rb +2 -2
  32. data/lib/action_view/helpers/rendering_helper.rb +1 -1
  33. data/lib/action_view/helpers/sanitize_helper.rb +51 -21
  34. data/lib/action_view/helpers/tag_helper.rb +5 -27
  35. data/lib/action_view/helpers/tags/base.rb +11 -52
  36. data/lib/action_view/helpers/tags/collection_check_boxes.rb +1 -0
  37. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +1 -0
  38. data/lib/action_view/helpers/tags/collection_select.rb +3 -0
  39. data/lib/action_view/helpers/tags/date_field.rb +1 -1
  40. data/lib/action_view/helpers/tags/date_select.rb +2 -0
  41. data/lib/action_view/helpers/tags/datetime_field.rb +14 -6
  42. data/lib/action_view/helpers/tags/datetime_local_field.rb +11 -2
  43. data/lib/action_view/helpers/tags/grouped_collection_select.rb +3 -0
  44. data/lib/action_view/helpers/tags/month_field.rb +1 -1
  45. data/lib/action_view/helpers/tags/select.rb +3 -0
  46. data/lib/action_view/helpers/tags/select_renderer.rb +56 -0
  47. data/lib/action_view/helpers/tags/time_field.rb +1 -1
  48. data/lib/action_view/helpers/tags/time_zone_select.rb +3 -0
  49. data/lib/action_view/helpers/tags/week_field.rb +1 -1
  50. data/lib/action_view/helpers/tags/weekday_select.rb +3 -0
  51. data/lib/action_view/helpers/tags.rb +2 -0
  52. data/lib/action_view/helpers/text_helper.rb +156 -84
  53. data/lib/action_view/helpers/translation_helper.rb +3 -3
  54. data/lib/action_view/helpers/url_helper.rb +46 -17
  55. data/lib/action_view/helpers.rb +2 -0
  56. data/lib/action_view/layouts.rb +8 -6
  57. data/lib/action_view/log_subscriber.rb +49 -32
  58. data/lib/action_view/lookup_context.rb +29 -13
  59. data/lib/action_view/path_registry.rb +57 -0
  60. data/lib/action_view/path_set.rb +13 -14
  61. data/lib/action_view/railtie.rb +26 -3
  62. data/lib/action_view/record_identifier.rb +15 -8
  63. data/lib/action_view/renderer/abstract_renderer.rb +1 -1
  64. data/lib/action_view/renderer/collection_renderer.rb +10 -2
  65. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +2 -1
  66. data/lib/action_view/renderer/partial_renderer.rb +2 -1
  67. data/lib/action_view/renderer/renderer.rb +2 -0
  68. data/lib/action_view/renderer/streaming_template_renderer.rb +3 -2
  69. data/lib/action_view/renderer/template_renderer.rb +3 -2
  70. data/lib/action_view/rendering.rb +22 -4
  71. data/lib/action_view/ripper_ast_parser.rb +5 -5
  72. data/lib/action_view/template/error.rb +14 -1
  73. data/lib/action_view/template/handlers/builder.rb +4 -4
  74. data/lib/action_view/template/handlers/erb/erubi.rb +23 -27
  75. data/lib/action_view/template/handlers/erb.rb +73 -1
  76. data/lib/action_view/template/handlers.rb +1 -1
  77. data/lib/action_view/template/html.rb +1 -1
  78. data/lib/action_view/template/raw_file.rb +1 -1
  79. data/lib/action_view/template/renderable.rb +1 -1
  80. data/lib/action_view/template/resolver.rb +10 -2
  81. data/lib/action_view/template/text.rb +1 -1
  82. data/lib/action_view/template/types.rb +25 -34
  83. data/lib/action_view/template.rb +249 -54
  84. data/lib/action_view/template_path.rb +2 -0
  85. data/lib/action_view/test_case.rb +176 -21
  86. data/lib/action_view/unbound_template.rb +17 -7
  87. data/lib/action_view/version.rb +1 -1
  88. data/lib/action_view/view_paths.rb +15 -24
  89. data/lib/action_view.rb +4 -1
  90. metadata +22 -23
  91. data/lib/assets/compiled/rails-ujs.js +0 -777
@@ -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 && object.respond_to?(@method_name)
40
+ object.public_send @method_name if object.respond_to?(@method_name)
40
41
  else
41
- object.public_send @method_name if object
42
+ object.public_send @method_name
42
43
  end
43
44
  end
44
45
 
45
46
  def value_before_type_cast
46
- unless object.nil?
47
- method_before_type_cast = @method_name + "_before_type_cast"
47
+ return unless object
48
48
 
49
- if value_came_from_user? && object.respond_to?(method_before_type_cast)
50
- object.public_send(method_before_type_cast)
51
- else
52
- value
53
- end
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") || ""
@@ -7,6 +7,7 @@ module ActionView
7
7
  module Tags # :nodoc:
8
8
  class CollectionCheckBoxes < Base # :nodoc:
9
9
  include CollectionHelpers
10
+ include FormOptionsHelper
10
11
 
11
12
  class CheckBoxBuilder < Builder # :nodoc:
12
13
  def check_box(extra_html_options = {})
@@ -7,6 +7,7 @@ module ActionView
7
7
  module Tags # :nodoc:
8
8
  class CollectionRadioButtons < Base # :nodoc:
9
9
  include CollectionHelpers
10
+ include FormOptionsHelper
10
11
 
11
12
  class RadioButtonBuilder < Builder # :nodoc:
12
13
  def radio_button(extra_html_options = {})
@@ -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
@@ -5,7 +5,7 @@ module ActionView
5
5
  module Tags # :nodoc:
6
6
  class DateField < DatetimeField # :nodoc:
7
7
  private
8
- def format_date(value)
8
+ def format_datetime(value)
9
9
  value&.strftime("%Y-%m-%d")
10
10
  end
11
11
  end
@@ -6,6 +6,8 @@ module ActionView
6
6
  module Helpers
7
7
  module Tags # :nodoc:
8
8
  class DateSelect < Base # :nodoc:
9
+ include SelectRenderer
10
+
9
11
  def initialize(object_name, method_name, template_object, options, html_options)
10
12
  @html_options = html_options
11
13
 
@@ -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"] ||= format_date(value)
10
- options["min"] = format_date(datetime_value(options["min"]))
11
- options["max"] = format_date(datetime_value(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 format_date(value)
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 datetime_value(value)
22
- if value.is_a? String
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 format_date(value)
15
- value&.strftime("%Y-%m-%dT%T")
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
@@ -5,7 +5,7 @@ module ActionView
5
5
  module Tags # :nodoc:
6
6
  class MonthField < DatetimeField # :nodoc:
7
7
  private
8
- def format_date(value)
8
+ def format_datetime(value)
9
9
  value&.strftime("%Y-%m")
10
10
  end
11
11
  end
@@ -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
@@ -10,7 +10,7 @@ module ActionView
10
10
  end
11
11
 
12
12
  private
13
- def format_date(value)
13
+ def format_datetime(value)
14
14
  if @include_seconds
15
15
  value&.strftime("%T.%L")
16
16
  else
@@ -4,6 +4,9 @@ module ActionView
4
4
  module Helpers
5
5
  module Tags # :nodoc:
6
6
  class TimeZoneSelect < Base # :nodoc:
7
+ include SelectRenderer
8
+ include FormOptionsHelper
9
+
7
10
  def initialize(object_name, method_name, template_object, priority_zones, options, html_options)
8
11
  @priority_zones = priority_zones
9
12
  @html_options = html_options
@@ -5,7 +5,7 @@ module ActionView
5
5
  module Tags # :nodoc:
6
6
  class WeekField < DatetimeField # :nodoc:
7
7
  private
8
- def format_date(value)
8
+ def format_datetime(value)
9
9
  value&.strftime("%Y-W%V")
10
10
  end
11
11
  end
@@ -4,6 +4,9 @@ module ActionView
4
4
  module Helpers
5
5
  module Tags # :nodoc:
6
6
  class WeekdaySelect < Base # :nodoc:
7
+ include SelectRenderer
8
+ include FormOptionsHelper
9
+
7
10
  def initialize(object_name, method_name, template_object, options, html_options)
8
11
  @html_options = html_options
9
12
 
@@ -5,6 +5,8 @@ module ActionView
5
5
  module Tags # :nodoc:
6
6
  extend ActiveSupport::Autoload
7
7
 
8
+ autoload :SelectRenderer
9
+
8
10
  eager_autoload do
9
11
  autoload :Base
10
12
  autoload :Translator