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
@@ -1,14 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "cgi"
4
- require "action_view/helpers/tag_helper"
4
+ require "action_view/helpers/content_exfiltration_prevention_helper"
5
+ require "action_view/helpers/url_helper"
6
+ require "action_view/helpers/text_helper"
5
7
  require "active_support/core_ext/string/output_safety"
6
8
  require "active_support/core_ext/module/attribute_accessors"
7
- require "active_support/core_ext/symbol/starts_ends_with"
8
9
 
9
10
  module ActionView
10
- # = Action View Form Tag Helpers
11
- module Helpers #:nodoc:
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
@@ -63,6 +66,9 @@ module ActionView
63
66
  # <%= form_tag('/posts', remote: true) %>
64
67
  # # => <form action="/posts" method="post" data-remote="true">
65
68
  #
69
+ # form_tag(false, method: :get)
70
+ # # => <form method="get">
71
+ #
66
72
  # form_tag('http://far.away.com/form', authenticity_token: false)
67
73
  # # form without authenticity token
68
74
  #
@@ -78,6 +84,65 @@ module ActionView
78
84
  end
79
85
  end
80
86
 
87
+ # Generate an HTML <tt>id</tt> attribute value for the given name and
88
+ # field combination
89
+ #
90
+ # Return the value generated by the <tt>FormBuilder</tt> for the given
91
+ # attribute name.
92
+ #
93
+ # <%= label_tag :post, :title %>
94
+ # <%= text_field :post, :title, aria: { describedby: field_id(:post, :title, :error) } %>
95
+ # <%= tag.span("is blank", id: field_id(:post, :title, :error) %>
96
+ #
97
+ # In the example above, the <tt><input type="text"></tt> element built by
98
+ # the call to <tt>text_field</tt> declares an
99
+ # <tt>aria-describedby</tt> attribute referencing the <tt><span></tt>
100
+ # element, sharing a common <tt>id</tt> root (<tt>post_title</tt>, in this
101
+ # case).
102
+ def field_id(object_name, method_name, *suffixes, index: nil, namespace: nil)
103
+ if object_name.respond_to?(:model_name)
104
+ object_name = object_name.model_name.singular
105
+ end
106
+
107
+ sanitized_object_name = object_name.to_s.gsub(/\]\[|[^-a-zA-Z0-9:.]/, "_").delete_suffix("_")
108
+
109
+ sanitized_method_name = method_name.to_s.delete_suffix("?")
110
+
111
+ [
112
+ namespace,
113
+ sanitized_object_name.presence,
114
+ (index unless sanitized_object_name.empty?),
115
+ sanitized_method_name,
116
+ *suffixes,
117
+ ].tap(&:compact!).join("_")
118
+ end
119
+
120
+ # Generate an HTML <tt>name</tt> attribute value for the given name and
121
+ # field combination
122
+ #
123
+ # Return the value generated by the <tt>FormBuilder</tt> for the given
124
+ # attribute name.
125
+ #
126
+ # <%= text_field :post, :title, name: field_name(:post, :title, :subtitle) %>
127
+ # <%# => <input type="text" name="post[title][subtitle]"> %>
128
+ #
129
+ # <%= text_field :post, :tag, name: field_name(:post, :tag, multiple: true) %>
130
+ # <%# => <input type="text" name="post[tag][]"> %>
131
+ #
132
+ def field_name(object_name, method_name, *method_names, multiple: false, index: nil)
133
+ names = method_names.map! { |name| "[#{name}]" }.join
134
+
135
+ # a little duplication to construct fewer strings
136
+ case
137
+ when object_name.blank?
138
+ "#{method_name}#{names}#{multiple ? "[]" : ""}"
139
+ when index
140
+ "#{object_name}[#{index}][#{method_name}]#{names}#{multiple ? "[]" : ""}"
141
+ else
142
+ "#{object_name}[#{method_name}]#{names}#{multiple ? "[]" : ""}"
143
+ end
144
+ end
145
+
81
146
  # Creates a dropdown selection box, or if the <tt>:multiple</tt> option is set to true, a multiple
82
147
  # choice selection box.
83
148
  #
@@ -167,8 +232,8 @@ module ActionView
167
232
  # * <tt>:size</tt> - The number of visible characters that will fit in the input.
168
233
  # * <tt>:maxlength</tt> - The maximum number of characters that the browser will allow the user to enter.
169
234
  # * <tt>:placeholder</tt> - The text contained in the field by default which is removed when the field receives focus.
170
- # If set to true, use a translation is found in the current I18n locale
171
- # (through helpers.placeholders.<modelname>.<attribute>).
235
+ # If set to true, use the translation found in the current I18n locale
236
+ # (through helpers.placeholder.<modelname>.<attribute>).
172
237
  # * Any other key creates standard HTML attributes for the tag.
173
238
  #
174
239
  # ==== Examples
@@ -232,14 +297,14 @@ module ActionView
232
297
  #
233
298
  # ==== Examples
234
299
  # hidden_field_tag 'tags_list'
235
- # # => <input id="tags_list" name="tags_list" type="hidden" />
300
+ # # => <input type="hidden" name="tags_list" id="tags_list" autocomplete="off" />
236
301
  #
237
302
  # hidden_field_tag 'token', 'VUBJKB23UIVI1UU1VOBVI@'
238
- # # => <input id="token" name="token" type="hidden" value="VUBJKB23UIVI1UU1VOBVI@" />
303
+ # # => <input type="hidden" name="token" id="token" value="VUBJKB23UIVI1UU1VOBVI@" autocomplete="off" />
239
304
  #
240
305
  # hidden_field_tag 'collected_input', '', onchange: "alert('Input collected!')"
241
- # # => <input id="collected_input" name="collected_input" onchange="alert('Input collected!')"
242
- # # type="hidden" value="" />
306
+ # # => <input type="hidden" name="collected_input" id="collected_input"
307
+ # value="" onchange="alert(&#39;Input collected!&#39;)" autocomplete="off" />
243
308
  def hidden_field_tag(name, value = nil, options = {})
244
309
  text_field_tag(name, value, options.merge(type: :hidden, autocomplete: "off"))
245
310
  end
@@ -358,9 +423,17 @@ module ActionView
358
423
  content_tag :textarea, content.to_s.html_safe, { "name" => name, "id" => sanitize_to_id(name) }.update(options)
359
424
  end
360
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
+ #
361
432
  # Creates a check box form input tag.
362
433
  #
363
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.
364
437
  # * <tt>:disabled</tt> - If set to true, the user will not be able to use this input.
365
438
  # * Any other key creates standard HTML options for the tag.
366
439
  #
@@ -379,16 +452,27 @@ module ActionView
379
452
  #
380
453
  # check_box_tag 'eula', 'accepted', false, disabled: true
381
454
  # # => <input disabled="disabled" id="eula" name="eula" type="checkbox" value="accepted" />
382
- def check_box_tag(name, value = "1", checked = false, options = {})
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]
383
461
  html_options = { "type" => "checkbox", "name" => name, "id" => sanitize_to_id(name), "value" => value }.update(options.stringify_keys)
384
462
  html_options["checked"] = "checked" if checked
385
463
  tag :input, html_options
386
464
  end
387
465
 
466
+ ##
467
+ # :call-seq:
468
+ # radio_button_tag(name, value, options = {})
469
+ # radio_button_tag(name, value, checked, options = {})
470
+ #
388
471
  # Creates a radio button; use groups of radio buttons named the same to allow users to
389
472
  # select from a group of options.
390
473
  #
391
474
  # ==== Options
475
+ # * <tt>:checked</tt> - If set to true, the radio button will be selected by default.
392
476
  # * <tt>:disabled</tt> - If set to true, the user will not be able to use this input.
393
477
  # * Any other key creates standard HTML options for the tag.
394
478
  #
@@ -404,7 +488,12 @@ module ActionView
404
488
  #
405
489
  # radio_button_tag 'color', "green", true, class: "color_input"
406
490
  # # => <input checked="checked" class="color_input" id="color_green" name="color" type="radio" value="green" />
407
- def radio_button_tag(name, value, checked = false, options = {})
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
408
497
  html_options = { "type" => "radio", "name" => name, "id" => "#{sanitize_to_id(name)}_#{sanitize_to_id(value)}", "value" => value }.update(options.stringify_keys)
409
498
  html_options["checked"] = "checked" if checked
410
499
  tag :input, html_options
@@ -417,16 +506,6 @@ module ActionView
417
506
  # * <tt>:disabled</tt> - If true, the user will not be able to use this input.
418
507
  # * Any other key creates standard HTML options for the tag.
419
508
  #
420
- # ==== Data attributes
421
- #
422
- # * <tt>confirm: 'question?'</tt> - If present the unobtrusive JavaScript
423
- # drivers will provide a prompt with the question specified. If the user accepts,
424
- # the form is processed normally, otherwise no action is taken.
425
- # * <tt>:disable_with</tt> - Value of this parameter will be used as the value for a
426
- # disabled version of the submit button when the form is submitted. This feature is
427
- # provided by the unobtrusive JavaScript driver. To disable this feature for a single submit tag
428
- # pass <tt>:data => { disable_with: false }</tt> Defaults to value attribute.
429
- #
430
509
  # ==== Examples
431
510
  # submit_tag
432
511
  # # => <input name="commit" data-disable-with="Save changes" type="submit" value="Save changes" />
@@ -437,15 +516,28 @@ module ActionView
437
516
  # submit_tag "Save edits", disabled: true
438
517
  # # => <input disabled="disabled" name="commit" data-disable-with="Save edits" type="submit" value="Save edits" />
439
518
  #
440
- # submit_tag "Complete sale", data: { disable_with: "Submitting..." }
441
- # # => <input name="commit" data-disable-with="Submitting..." type="submit" value="Complete sale" />
442
- #
443
519
  # submit_tag nil, class: "form_submit"
444
520
  # # => <input class="form_submit" name="commit" type="submit" />
445
521
  #
446
522
  # submit_tag "Edit", class: "edit_button"
447
523
  # # => <input class="edit_button" data-disable-with="Edit" name="commit" type="submit" value="Edit" />
448
524
  #
525
+ # ==== Deprecated: \Rails UJS attributes
526
+ #
527
+ # Prior to \Rails 7, \Rails shipped with the JavaScript library called @rails/ujs on by default. Following \Rails 7,
528
+ # this library is no longer on by default. This library integrated with the following options:
529
+ #
530
+ # * <tt>confirm: 'question?'</tt> - If present the unobtrusive JavaScript
531
+ # drivers will provide a prompt with the question specified. If the user accepts,
532
+ # the form is processed normally, otherwise no action is taken.
533
+ # * <tt>:disable_with</tt> - Value of this parameter will be used as the value for a
534
+ # disabled version of the submit button when the form is submitted. This feature is
535
+ # provided by the unobtrusive JavaScript driver. To disable this feature for a single submit tag
536
+ # pass <tt>:data => { disable_with: false }</tt> Defaults to value attribute.
537
+ #
538
+ # submit_tag "Complete sale", data: { disable_with: "Submitting..." }
539
+ # # => <input name="commit" data-disable-with="Submitting..." type="submit" value="Complete sale" />
540
+ #
449
541
  # submit_tag "Save", data: { confirm: "Are you sure?" }
450
542
  # # => <input name='commit' type='submit' value='Save' data-disable-with="Save" data-confirm="Are you sure?" />
451
543
  #
@@ -470,17 +562,6 @@ module ActionView
470
562
  # use this input.
471
563
  # * Any other key creates standard HTML options for the tag.
472
564
  #
473
- # ==== Data attributes
474
- #
475
- # * <tt>confirm: 'question?'</tt> - If present, the
476
- # unobtrusive JavaScript drivers will provide a prompt with
477
- # the question specified. If the user accepts, the form is
478
- # processed normally, otherwise no action is taken.
479
- # * <tt>:disable_with</tt> - Value of this parameter will be
480
- # used as the value for a disabled version of the submit
481
- # button when the form is submitted. This feature is provided
482
- # by the unobtrusive JavaScript driver.
483
- #
484
565
  # ==== Examples
485
566
  # button_tag
486
567
  # # => <button name="button" type="submit">Button</button>
@@ -501,6 +582,20 @@ module ActionView
501
582
  # # <strong>Ask me!</strong>
502
583
  # # </button>
503
584
  #
585
+ # ==== Deprecated: \Rails UJS attributes
586
+ #
587
+ # Prior to \Rails 7, \Rails shipped with a JavaScript library called @rails/ujs on by default. Following \Rails 7,
588
+ # this library is no longer on by default. This library integrated with the following options:
589
+ #
590
+ # * <tt>confirm: 'question?'</tt> - If present, the
591
+ # unobtrusive JavaScript drivers will provide a prompt with
592
+ # the question specified. If the user accepts, the form is
593
+ # processed normally, otherwise no action is taken.
594
+ # * <tt>:disable_with</tt> - Value of this parameter will be
595
+ # used as the value for a disabled version of the submit
596
+ # button when the form is submitted. This feature is provided
597
+ # by the unobtrusive JavaScript driver.
598
+ #
504
599
  # button_tag "Save", data: { confirm: "Are you sure?" }
505
600
  # # => <button name="button" type="submit" data-confirm="Are you sure?">Save</button>
506
601
  #
@@ -589,9 +684,11 @@ module ActionView
589
684
  # Creates a text field of type "color".
590
685
  #
591
686
  # ==== Options
592
- # * Accepts the same options as text_field_tag.
687
+ #
688
+ # Supports the same options as #text_field_tag.
593
689
  #
594
690
  # ==== Examples
691
+ #
595
692
  # color_field_tag 'name'
596
693
  # # => <input id="name" name="name" type="color" />
597
694
  #
@@ -610,9 +707,11 @@ module ActionView
610
707
  # Creates a text field of type "search".
611
708
  #
612
709
  # ==== Options
613
- # * Accepts the same options as text_field_tag.
710
+ #
711
+ # Supports the same options as #text_field_tag.
614
712
  #
615
713
  # ==== Examples
714
+ #
616
715
  # search_field_tag 'name'
617
716
  # # => <input id="name" name="name" type="search" />
618
717
  #
@@ -631,9 +730,11 @@ module ActionView
631
730
  # Creates a text field of type "tel".
632
731
  #
633
732
  # ==== Options
634
- # * Accepts the same options as text_field_tag.
733
+ #
734
+ # Supports the same options as #text_field_tag.
635
735
  #
636
736
  # ==== Examples
737
+ #
637
738
  # telephone_field_tag 'name'
638
739
  # # => <input id="name" name="name" type="tel" />
639
740
  #
@@ -653,9 +754,11 @@ module ActionView
653
754
  # Creates a text field of type "date".
654
755
  #
655
756
  # ==== Options
656
- # * Accepts the same options as text_field_tag.
757
+ #
758
+ # Supports the same options as #text_field_tag.
657
759
  #
658
760
  # ==== Examples
761
+ #
659
762
  # date_field_tag 'name'
660
763
  # # => <input id="name" name="name" type="date" />
661
764
  #
@@ -673,22 +776,28 @@ module ActionView
673
776
 
674
777
  # Creates a text field of type "time".
675
778
  #
676
- # === Options
779
+ # ==== Options
780
+ #
781
+ # Supports the same options as #text_field_tag. Additionally, supports:
782
+ #
677
783
  # * <tt>:min</tt> - The minimum acceptable value.
678
784
  # * <tt>:max</tt> - The maximum acceptable value.
679
785
  # * <tt>:step</tt> - The acceptable value granularity.
680
- # * Otherwise accepts the same options as text_field_tag.
786
+ # * <tt>:include_seconds</tt> - Include seconds and ms in the output timestamp format (true by default).
681
787
  def time_field_tag(name, value = nil, options = {})
682
788
  text_field_tag(name, value, options.merge(type: :time))
683
789
  end
684
790
 
685
791
  # Creates a text field of type "datetime-local".
686
792
  #
687
- # === Options
793
+ # ==== Options
794
+ #
795
+ # Supports the same options as #text_field_tag. Additionally, supports:
796
+ #
688
797
  # * <tt>:min</tt> - The minimum acceptable value.
689
798
  # * <tt>:max</tt> - The maximum acceptable value.
690
799
  # * <tt>:step</tt> - The acceptable value granularity.
691
- # * Otherwise accepts the same options as text_field_tag.
800
+ # * <tt>:include_seconds</tt> - Include seconds in the output timestamp format (true by default).
692
801
  def datetime_field_tag(name, value = nil, options = {})
693
802
  text_field_tag(name, value, options.merge(type: "datetime-local"))
694
803
  end
@@ -697,22 +806,26 @@ module ActionView
697
806
 
698
807
  # Creates a text field of type "month".
699
808
  #
700
- # === Options
809
+ # ==== Options
810
+ #
811
+ # Supports the same options as #text_field_tag. Additionally, supports:
812
+ #
701
813
  # * <tt>:min</tt> - The minimum acceptable value.
702
814
  # * <tt>:max</tt> - The maximum acceptable value.
703
815
  # * <tt>:step</tt> - The acceptable value granularity.
704
- # * Otherwise accepts the same options as text_field_tag.
705
816
  def month_field_tag(name, value = nil, options = {})
706
817
  text_field_tag(name, value, options.merge(type: :month))
707
818
  end
708
819
 
709
820
  # Creates a text field of type "week".
710
821
  #
711
- # === Options
822
+ # ==== Options
823
+ #
824
+ # Supports the same options as #text_field_tag. Additionally, supports:
825
+ #
712
826
  # * <tt>:min</tt> - The minimum acceptable value.
713
827
  # * <tt>:max</tt> - The maximum acceptable value.
714
828
  # * <tt>:step</tt> - The acceptable value granularity.
715
- # * Otherwise accepts the same options as text_field_tag.
716
829
  def week_field_tag(name, value = nil, options = {})
717
830
  text_field_tag(name, value, options.merge(type: :week))
718
831
  end
@@ -720,9 +833,11 @@ module ActionView
720
833
  # Creates a text field of type "url".
721
834
  #
722
835
  # ==== Options
723
- # * Accepts the same options as text_field_tag.
836
+ #
837
+ # Supports the same options as #text_field_tag.
724
838
  #
725
839
  # ==== Examples
840
+ #
726
841
  # url_field_tag 'name'
727
842
  # # => <input id="name" name="name" type="url" />
728
843
  #
@@ -741,9 +856,11 @@ module ActionView
741
856
  # Creates a text field of type "email".
742
857
  #
743
858
  # ==== Options
744
- # * Accepts the same options as text_field_tag.
859
+ #
860
+ # Supports the same options as #text_field_tag.
745
861
  #
746
862
  # ==== Examples
863
+ #
747
864
  # email_field_tag 'name'
748
865
  # # => <input id="name" name="name" type="email" />
749
866
  #
@@ -762,15 +879,18 @@ module ActionView
762
879
  # Creates a number field.
763
880
  #
764
881
  # ==== Options
882
+ #
883
+ # Supports the same options as #text_field_tag. Additionally, supports:
884
+ #
765
885
  # * <tt>:min</tt> - The minimum acceptable value.
766
886
  # * <tt>:max</tt> - The maximum acceptable value.
767
887
  # * <tt>:in</tt> - A range specifying the <tt>:min</tt> and
768
888
  # <tt>:max</tt> values.
769
889
  # * <tt>:within</tt> - Same as <tt>:in</tt>.
770
890
  # * <tt>:step</tt> - The acceptable value granularity.
771
- # * Otherwise accepts the same options as text_field_tag.
772
891
  #
773
892
  # ==== Examples
893
+ #
774
894
  # number_field_tag 'quantity'
775
895
  # # => <input id="quantity" name="quantity" type="number" />
776
896
  #
@@ -812,12 +932,13 @@ module ActionView
812
932
  # Creates a range form element.
813
933
  #
814
934
  # ==== Options
815
- # * Accepts the same options as number_field_tag.
935
+ #
936
+ # Supports the same options as #number_field_tag.
816
937
  def range_field_tag(name, value = nil, options = {})
817
938
  number_field_tag(name, value, options.merge(type: :range))
818
939
  end
819
940
 
820
- # Creates the hidden UTF8 enforcer tag. Override this method in a helper
941
+ # Creates the hidden UTF-8 enforcer tag. Override this method in a helper
821
942
  # to customize the tag.
822
943
  def utf8_enforcer_tag
823
944
  # Use raw HTML to ensure the value is written as an HTML entity; it
@@ -832,13 +953,17 @@ module ActionView
832
953
  html_options["enctype"] = "multipart/form-data" if html_options.delete("multipart")
833
954
  # The following URL is unescaped, this is just a hash of options, and it is the
834
955
  # responsibility of the caller to escape all the values.
835
- html_options["action"] = url_for(url_for_options)
956
+ if url_for_options == false || html_options["action"] == false
957
+ html_options.delete("action")
958
+ else
959
+ html_options["action"] = url_for(url_for_options)
960
+ end
836
961
  html_options["accept-charset"] = "UTF-8"
837
962
 
838
963
  html_options["data-remote"] = true if html_options.delete("remote")
839
964
 
840
965
  if html_options["data-remote"] &&
841
- !embed_authenticity_token_in_remote_forms &&
966
+ embed_authenticity_token_in_remote_forms == false &&
842
967
  html_options["authenticity_token"].blank?
843
968
  # The authenticity token is taken from the meta tag in this case
844
969
  html_options["authenticity_token"] = false
@@ -882,12 +1007,13 @@ module ActionView
882
1007
 
883
1008
  def form_tag_html(html_options)
884
1009
  extra_tags = extra_tags_for_form(html_options)
885
- tag(:form, html_options, true) + extra_tags
1010
+ html = tag(:form, html_options, true) + extra_tags
1011
+ prevent_content_exfiltration(html)
886
1012
  end
887
1013
 
888
1014
  def form_tag_with_body(html_options, content)
889
1015
  output = form_tag_html(html_options)
890
- output << content
1016
+ output << content.to_s if content
891
1017
  output.safe_concat("</form>")
892
1018
  end
893
1019
 
@@ -912,9 +1038,14 @@ module ActionView
912
1038
  end
913
1039
 
914
1040
  def convert_direct_upload_option_to_url(options)
915
- if options.delete(:direct_upload) && respond_to?(:rails_direct_uploads_url)
1041
+ return options unless options.delete(:direct_upload)
1042
+
1043
+ if respond_to?(:rails_direct_uploads_url)
916
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
917
1047
  end
1048
+
918
1049
  options
919
1050
  end
920
1051
  end
@@ -1,12 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "action_view/helpers/tag_helper"
4
-
5
3
  module ActionView
6
- module Helpers #:nodoc:
4
+ module Helpers # :nodoc:
5
+ # = Action View JavaScript \Helpers
7
6
  module JavaScriptHelper
8
7
  JS_ESCAPE_MAP = {
9
- '\\' => '\\\\',
8
+ "\\" => "\\\\",
10
9
  "</" => '<\/',
11
10
  "\r\n" => '\n',
12
11
  "\n" => '\n',
@@ -89,7 +88,7 @@ module ActionView
89
88
  content_tag("script", javascript_cdata_section(content), html_options)
90
89
  end
91
90
 
92
- def javascript_cdata_section(content) #:nodoc:
91
+ def javascript_cdata_section(content) # :nodoc:
93
92
  "\n//#{cdata_section("\n#{content}\n//")}\n".html_safe
94
93
  end
95
94
  end