actionview 6.1.7.2 → 7.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +299 -277
  3. data/MIT-LICENSE +2 -1
  4. data/README.rdoc +3 -3
  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 +37 -19
  8. data/lib/action_view/buffers.rb +107 -9
  9. data/lib/action_view/cache_expiry.rb +48 -37
  10. data/lib/action_view/context.rb +1 -1
  11. data/lib/action_view/dependency_tracker/erb_tracker.rb +154 -0
  12. data/lib/action_view/dependency_tracker/ripper_tracker.rb +59 -0
  13. data/lib/action_view/dependency_tracker.rb +6 -147
  14. data/lib/action_view/deprecator.rb +7 -0
  15. data/lib/action_view/digestor.rb +8 -5
  16. data/lib/action_view/flows.rb +4 -4
  17. data/lib/action_view/gem_version.rb +4 -4
  18. data/lib/action_view/helpers/active_model_helper.rb +3 -3
  19. data/lib/action_view/helpers/asset_tag_helper.rb +200 -60
  20. data/lib/action_view/helpers/asset_url_helper.rb +22 -21
  21. data/lib/action_view/helpers/atom_feed_helper.rb +8 -9
  22. data/lib/action_view/helpers/cache_helper.rb +55 -12
  23. data/lib/action_view/helpers/capture_helper.rb +34 -14
  24. data/lib/action_view/helpers/content_exfiltration_prevention_helper.rb +70 -0
  25. data/lib/action_view/helpers/controller_helper.rb +8 -2
  26. data/lib/action_view/helpers/csp_helper.rb +3 -3
  27. data/lib/action_view/helpers/csrf_helper.rb +4 -4
  28. data/lib/action_view/helpers/date_helper.rb +123 -57
  29. data/lib/action_view/helpers/debug_helper.rb +6 -4
  30. data/lib/action_view/helpers/form_helper.rb +253 -97
  31. data/lib/action_view/helpers/form_options_helper.rb +72 -34
  32. data/lib/action_view/helpers/form_tag_helper.rb +189 -58
  33. data/lib/action_view/helpers/javascript_helper.rb +4 -5
  34. data/lib/action_view/helpers/number_helper.rb +43 -335
  35. data/lib/action_view/helpers/output_safety_helper.rb +6 -6
  36. data/lib/action_view/helpers/rendering_helper.rb +6 -7
  37. data/lib/action_view/helpers/sanitize_helper.rb +54 -24
  38. data/lib/action_view/helpers/tag_helper.rb +42 -35
  39. data/lib/action_view/helpers/tags/base.rb +16 -77
  40. data/lib/action_view/helpers/tags/check_box.rb +1 -1
  41. data/lib/action_view/helpers/tags/collection_check_boxes.rb +1 -0
  42. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +1 -0
  43. data/lib/action_view/helpers/tags/collection_select.rb +4 -1
  44. data/lib/action_view/helpers/tags/date_field.rb +1 -1
  45. data/lib/action_view/helpers/tags/date_select.rb +2 -0
  46. data/lib/action_view/helpers/tags/datetime_field.rb +14 -6
  47. data/lib/action_view/helpers/tags/datetime_local_field.rb +11 -2
  48. data/lib/action_view/helpers/tags/file_field.rb +16 -0
  49. data/lib/action_view/helpers/tags/grouped_collection_select.rb +3 -0
  50. data/lib/action_view/helpers/tags/month_field.rb +1 -1
  51. data/lib/action_view/helpers/tags/select.rb +4 -1
  52. data/lib/action_view/helpers/tags/select_renderer.rb +56 -0
  53. data/lib/action_view/helpers/tags/time_field.rb +11 -2
  54. data/lib/action_view/helpers/tags/time_zone_select.rb +3 -0
  55. data/lib/action_view/helpers/tags/week_field.rb +1 -1
  56. data/lib/action_view/helpers/tags/weekday_select.rb +31 -0
  57. data/lib/action_view/helpers/tags.rb +5 -2
  58. data/lib/action_view/helpers/text_helper.rb +180 -97
  59. data/lib/action_view/helpers/translation_helper.rb +14 -45
  60. data/lib/action_view/helpers/url_helper.rb +230 -132
  61. data/lib/action_view/helpers.rb +27 -25
  62. data/lib/action_view/layouts.rb +15 -10
  63. data/lib/action_view/log_subscriber.rb +49 -32
  64. data/lib/action_view/lookup_context.rb +58 -61
  65. data/lib/action_view/model_naming.rb +2 -2
  66. data/lib/action_view/path_registry.rb +57 -0
  67. data/lib/action_view/path_set.rb +28 -35
  68. data/lib/action_view/railtie.rb +44 -9
  69. data/lib/action_view/record_identifier.rb +16 -9
  70. data/lib/action_view/render_parser.rb +188 -0
  71. data/lib/action_view/renderer/abstract_renderer.rb +3 -3
  72. data/lib/action_view/renderer/collection_renderer.rb +10 -2
  73. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +21 -3
  74. data/lib/action_view/renderer/partial_renderer.rb +3 -36
  75. data/lib/action_view/renderer/renderer.rb +6 -4
  76. data/lib/action_view/renderer/streaming_template_renderer.rb +6 -5
  77. data/lib/action_view/renderer/template_renderer.rb +9 -4
  78. data/lib/action_view/rendering.rb +25 -7
  79. data/lib/action_view/ripper_ast_parser.rb +198 -0
  80. data/lib/action_view/routing_url_for.rb +8 -5
  81. data/lib/action_view/template/error.rb +122 -14
  82. data/lib/action_view/template/handlers/builder.rb +4 -4
  83. data/lib/action_view/template/handlers/erb/erubi.rb +23 -27
  84. data/lib/action_view/template/handlers/erb.rb +79 -1
  85. data/lib/action_view/template/handlers.rb +4 -4
  86. data/lib/action_view/template/html.rb +4 -4
  87. data/lib/action_view/template/inline.rb +3 -3
  88. data/lib/action_view/template/raw_file.rb +4 -4
  89. data/lib/action_view/template/renderable.rb +1 -1
  90. data/lib/action_view/template/resolver.rb +96 -313
  91. data/lib/action_view/template/text.rb +4 -4
  92. data/lib/action_view/template/types.rb +25 -32
  93. data/lib/action_view/template.rb +245 -41
  94. data/lib/action_view/template_details.rb +66 -0
  95. data/lib/action_view/template_path.rb +66 -0
  96. data/lib/action_view/test_case.rb +182 -23
  97. data/lib/action_view/testing/resolvers.rb +11 -12
  98. data/lib/action_view/unbound_template.rb +43 -7
  99. data/lib/action_view/version.rb +1 -1
  100. data/lib/action_view/view_paths.rb +19 -28
  101. data/lib/action_view.rb +6 -4
  102. data/lib/assets/compiled/rails-ujs.js +36 -5
  103. metadata +32 -25
@@ -2,21 +2,22 @@
2
2
 
3
3
  require "cgi"
4
4
  require "erb"
5
- require "action_view/helpers/form_helper"
6
5
  require "active_support/core_ext/string/output_safety"
7
6
  require "active_support/core_ext/array/extract_options"
8
7
  require "active_support/core_ext/array/wrap"
8
+ require "action_view/helpers/text_helper"
9
9
 
10
10
  module ActionView
11
- # = Action View Form Option Helpers
12
- module Helpers #:nodoc:
11
+ module Helpers # :nodoc:
12
+ # = Action View Form Option \Helpers
13
+ #
13
14
  # Provides a number of methods for turning different kinds of containers into a set of option tags.
14
15
  #
15
16
  # The <tt>collection_select</tt>, <tt>select</tt> and <tt>time_zone_select</tt> methods take an <tt>options</tt> parameter, a hash:
16
17
  #
17
18
  # * <tt>:include_blank</tt> - set to true or a prompt string if the first option element of the select element is a blank. Useful if there is not a default value required for the select element.
18
19
  #
19
- # select("post", "category", Post::CATEGORIES, { include_blank: true })
20
+ # select(:post, :category, Post::CATEGORIES, { include_blank: true })
20
21
  #
21
22
  # could become:
22
23
  #
@@ -30,7 +31,7 @@ module ActionView
30
31
  #
31
32
  # Example with <tt>@post.person_id => 2</tt>:
32
33
  #
33
- # select("post", "person_id", Person.all.collect { |p| [ p.name, p.id ] }, { include_blank: 'None' })
34
+ # select(:post, :person_id, Person.all.collect { |p| [ p.name, p.id ] }, { include_blank: "None" })
34
35
  #
35
36
  # could become:
36
37
  #
@@ -43,7 +44,7 @@ module ActionView
43
44
  #
44
45
  # * <tt>:prompt</tt> - set to true or a prompt string. When the select element doesn't have a value yet, this prepends an option with a generic prompt -- "Please select" -- or the given prompt string.
45
46
  #
46
- # select("post", "person_id", Person.all.collect { |p| [ p.name, p.id ] }, { prompt: 'Select Person' })
47
+ # select(:post, :person_id, Person.all.collect { |p| [ p.name, p.id ] }, { prompt: "Select Person" })
47
48
  #
48
49
  # could become:
49
50
  #
@@ -54,10 +55,10 @@ module ActionView
54
55
  # <option value="3">Rafael</option>
55
56
  # </select>
56
57
  #
57
- # * <tt>:index</tt> - like the other form helpers, +select+ can accept an <tt>:index</tt> option to manually set the ID used in the resulting output. Unlike other helpers, +select+ expects this
58
+ # * <tt>:index</tt> - like the other form helpers, <tt>select</tt> can accept an <tt>:index</tt> option to manually set the ID used in the resulting output. Unlike other helpers, <tt>select</tt> expects this
58
59
  # option to be in the +html_options+ parameter.
59
60
  #
60
- # select("album[]", "genre", %w[rap rock country], {}, { index: nil })
61
+ # select("album[]", :genre, %w[ rap rock country ], {}, { index: nil })
61
62
  #
62
63
  # becomes:
63
64
  #
@@ -69,7 +70,7 @@ module ActionView
69
70
  #
70
71
  # * <tt>:disabled</tt> - can be a single value or an array of values that will be disabled options in the final output.
71
72
  #
72
- # select("post", "category", Post::CATEGORIES, { disabled: 'restricted' })
73
+ # select(:post, :category, Post::CATEGORIES, { disabled: "restricted" })
73
74
  #
74
75
  # could become:
75
76
  #
@@ -90,7 +91,6 @@ module ActionView
90
91
  # <option value="3">Jokes</option>
91
92
  # <option value="4">Poems</option>
92
93
  # </select>
93
- #
94
94
  module FormOptionsHelper
95
95
  # ERB::Util can mask some helpers like textilize. Make sure to include them.
96
96
  include TextHelper
@@ -100,25 +100,22 @@ module ActionView
100
100
  #
101
101
  # There are two possible formats for the +choices+ parameter, corresponding to other helpers' output:
102
102
  #
103
- # * A flat collection (see +options_for_select+).
103
+ # * A flat collection (see <tt>options_for_select</tt>).
104
+ # * A nested collection (see <tt>grouped_options_for_select</tt>).
104
105
  #
105
- # * A nested collection (see +grouped_options_for_select+).
106
+ # Example with <tt>@post.person_id => 2</tt>:
106
107
  #
107
- # For example:
108
- #
109
- # select("post", "person_id", Person.all.collect { |p| [ p.name, p.id ] }, { include_blank: true })
108
+ # select :post, :person_id, Person.all.collect { |p| [ p.name, p.id ] }, { include_blank: true })
110
109
  #
111
110
  # would become:
112
111
  #
113
112
  # <select name="post[person_id]" id="post_person_id">
114
113
  # <option value="" label=" "></option>
115
- # <option value="1" selected="selected">David</option>
116
- # <option value="2">Eileen</option>
114
+ # <option value="1">David</option>
115
+ # <option value="2" selected="selected">Eileen</option>
117
116
  # <option value="3">Rafael</option>
118
117
  # </select>
119
118
  #
120
- # assuming the associated person has ID 1.
121
- #
122
119
  # This can be used to provide a default set of options in the standard way: before rendering the create form, a
123
120
  # new model instance is assigned the default options and bound to @model_name. Usually this model is not saved
124
121
  # to the database. Instead, a second model object is created when the create request is received.
@@ -132,9 +129,9 @@ module ActionView
132
129
  # A block can be passed to +select+ to customize how the options tags will be rendered. This
133
130
  # is useful when the options tag has complex attributes.
134
131
  #
135
- # select(report, "campaign_ids") do
132
+ # select(report, :campaign_ids) do
136
133
  # available_campaigns.each do |c|
137
- # content_tag(:option, c.name, value: c.id, data: { tags: c.tags.to_json })
134
+ # tag.option(c.name, value: c.id, data: { tags: c.tags.to_json })
138
135
  # end
139
136
  # end
140
137
  #
@@ -159,7 +156,6 @@ module ActionView
159
156
  #
160
157
  # In case if you don't want the helper to generate this hidden field you can specify
161
158
  # <tt>include_hidden: false</tt> option.
162
- #
163
159
  def select(object, method, choices = nil, options = {}, html_options = {}, &block)
164
160
  Tags::Select.new(object, method, self, choices, options, html_options, &block).render
165
161
  end
@@ -183,6 +179,7 @@ module ActionView
183
179
  #
184
180
  # class Author < ActiveRecord::Base
185
181
  # has_many :posts
182
+ #
186
183
  # def name_with_initial
187
184
  # "#{first_name.first}. #{last_name}"
188
185
  # end
@@ -227,19 +224,19 @@ module ActionView
227
224
  #
228
225
  # Example object structure for use with this method:
229
226
  #
227
+ # # attributes: id, name
230
228
  # class Continent < ActiveRecord::Base
231
229
  # has_many :countries
232
- # # attribs: id, name
233
230
  # end
234
231
  #
232
+ # # attributes: id, name, continent_id
235
233
  # class Country < ActiveRecord::Base
236
234
  # belongs_to :continent
237
- # # attribs: id, name, continent_id
238
235
  # end
239
236
  #
237
+ # # attributes: id, name, country_id
240
238
  # class City < ActiveRecord::Base
241
239
  # belongs_to :country
242
- # # attribs: id, name, country_id
243
240
  # end
244
241
  #
245
242
  # Sample usage:
@@ -258,7 +255,6 @@ module ActionView
258
255
  # <option value="2">Ireland</option>
259
256
  # </optgroup>
260
257
  # </select>
261
- #
262
258
  def grouped_collection_select(object, method, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, html_options = {})
263
259
  Tags::GroupedCollectionSelect.new(object, method, self, collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options).render
264
260
  end
@@ -282,21 +278,27 @@ module ActionView
282
278
  # Finally, this method supports a <tt>:default</tt> option, which selects
283
279
  # a default ActiveSupport::TimeZone if the object's time zone is +nil+.
284
280
  #
285
- # time_zone_select("user", "time_zone", nil, include_blank: true)
281
+ # time_zone_select(:user, :time_zone, nil, include_blank: true)
286
282
  #
287
- # time_zone_select("user", "time_zone", nil, default: "Pacific Time (US & Canada)")
283
+ # time_zone_select(:user, :time_zone, nil, default: "Pacific Time (US & Canada)")
288
284
  #
289
- # time_zone_select("user", 'time_zone', ActiveSupport::TimeZone.us_zones, default: "Pacific Time (US & Canada)")
285
+ # time_zone_select(:user, :time_zone, ActiveSupport::TimeZone.us_zones, default: "Pacific Time (US & Canada)")
290
286
  #
291
- # time_zone_select("user", 'time_zone', [ ActiveSupport::TimeZone['Alaska'], ActiveSupport::TimeZone['Hawaii'] ])
287
+ # time_zone_select(:user, :time_zone, [ ActiveSupport::TimeZone["Alaska"], ActiveSupport::TimeZone["Hawaii"] ])
292
288
  #
293
- # time_zone_select("user", 'time_zone', /Australia/)
289
+ # time_zone_select(:user, :time_zone, /Australia/)
294
290
  #
295
- # time_zone_select("user", "time_zone", ActiveSupport::TimeZone.all.sort, model: ActiveSupport::TimeZone)
291
+ # time_zone_select(:user, :time_zone, ActiveSupport::TimeZone.all.sort, model: ActiveSupport::TimeZone)
296
292
  def time_zone_select(object, method, priority_zones = nil, options = {}, html_options = {})
297
293
  Tags::TimeZoneSelect.new(object, method, self, priority_zones, options, html_options).render
298
294
  end
299
295
 
296
+ # Returns select and option tags for the given object and method, using
297
+ # <tt>weekday_options_for_select</tt> to generate the list of option tags.
298
+ def weekday_select(object, method, options = {}, html_options = {}, &block)
299
+ Tags::WeekdaySelect.new(object, method, self, options, html_options, &block).render
300
+ end
301
+
300
302
  # Accepts a container (hash, array, enumerable, your type) and returns a string of option tags. Given a container
301
303
  # where the elements respond to first and last (such as a two-element array), the "lasts" serve as option values and
302
304
  # the "firsts" as option text. Hashes are turned into this form automatically, so the keys become "firsts" and values
@@ -499,6 +501,8 @@ module ActionView
499
501
  # <tt><optgroup></tt> label while the second value must be an array of options. The second value can be a
500
502
  # nested array of text-value pairs. See <tt>options_for_select</tt> for more info.
501
503
  # Ex. ["North America",[["United States","US"],["Canada","CA"]]]
504
+ # An optional third value can be provided as HTML attributes for the <tt>optgroup</tt>.
505
+ # Ex. ["North America",[["United States","US"],["Canada","CA"]], { disabled: "disabled" }]
502
506
  # * +selected_key+ - A value equal to the +value+ attribute for one of the <tt><option></tt> tags,
503
507
  # which will have the +selected+ attribute set. Note: It is possible for this value to match multiple options
504
508
  # as you might have the same option in multiple groups. Each will then get <tt>selected="selected"</tt>.
@@ -593,6 +597,25 @@ module ActionView
593
597
  zone_options.safe_concat options_for_select(convert_zones[zones], selected)
594
598
  end
595
599
 
600
+ # Returns a string of option tags for the days of the week.
601
+ #
602
+ # Options:
603
+ # * <tt>:index_as_value</tt> - Defaults to false, set to true to use the indexes from
604
+ # <tt>I18n.translate("date.day_names")</tt> as the values. By default, Sunday is always 0.
605
+ # * <tt>:day_format</tt> - The I18n key of the array to use for the weekday options.
606
+ # Defaults to +:day_names+, set to +:abbr_day_names+ for abbreviations.
607
+ # * <tt>:beginning_of_week</tt> - Defaults to Date.beginning_of_week.
608
+ #
609
+ # NOTE: Only the option tags are returned, you have to wrap this call in
610
+ # a regular HTML select tag.
611
+ def weekday_options_for_select(selected = nil, index_as_value: false, day_format: :day_names, beginning_of_week: Date.beginning_of_week)
612
+ day_names = I18n.translate("date.#{day_format}")
613
+ day_names = day_names.map.with_index.to_a if index_as_value
614
+ day_names = day_names.rotate(Date::DAYS_INTO_WEEK.fetch(beginning_of_week))
615
+
616
+ options_for_select(day_names, selected)
617
+ end
618
+
596
619
  # Returns radio button tags for the collection of existing return values
597
620
  # of +method+ for +object+'s class. The value returned from calling
598
621
  # +method+ on the instance +object+ will be selected. If calling +method+
@@ -606,11 +629,14 @@ module ActionView
606
629
  # retrieve the value/text.
607
630
  #
608
631
  # Example object structure for use with this method:
632
+ #
609
633
  # class Post < ActiveRecord::Base
610
634
  # belongs_to :author
611
635
  # end
636
+ #
612
637
  # class Author < ActiveRecord::Base
613
638
  # has_many :posts
639
+ #
614
640
  # def name_with_initial
615
641
  # "#{first_name.first}. #{last_name}"
616
642
  # end
@@ -793,9 +819,9 @@ module ActionView
793
819
 
794
820
  def extract_values_from_collection(collection, value_method, selected)
795
821
  if selected.is_a?(Proc)
796
- collection.map do |element|
822
+ collection.filter_map do |element|
797
823
  element.public_send(value_method) if selected.call(element)
798
- end.compact
824
+ end
799
825
  else
800
826
  selected
801
827
  end
@@ -859,6 +885,18 @@ module ActionView
859
885
  @template.time_zone_select(@object_name, method, priority_zones, objectify_options(options), @default_html_options.merge(html_options))
860
886
  end
861
887
 
888
+ # Wraps ActionView::Helpers::FormOptionsHelper#weekday_select for form builders:
889
+ #
890
+ # <%= form_for @user do |f| %>
891
+ # <%= f.weekday_select :weekday, include_blank: true %>
892
+ # <%= f.submit %>
893
+ # <% end %>
894
+ #
895
+ # Please refer to the documentation of the base helper for details.
896
+ def weekday_select(method, options = {}, html_options = {})
897
+ @template.weekday_select(@object_name, method, objectify_options(options), @default_html_options.merge(html_options))
898
+ end
899
+
862
900
  # Wraps ActionView::Helpers::FormOptionsHelper#collection_check_boxes for form builders:
863
901
  #
864
902
  # <%= form_for @post do |f| %>