actionview 4.2.11.1 → 5.2.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionview might be problematic. Click here for more details.

Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +88 -286
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -6
  5. data/lib/action_view/base.rb +38 -28
  6. data/lib/action_view/buffers.rb +3 -1
  7. data/lib/action_view/context.rb +3 -3
  8. data/lib/action_view/dependency_tracker.rb +54 -20
  9. data/lib/action_view/digestor.rb +94 -83
  10. data/lib/action_view/flows.rb +11 -11
  11. data/lib/action_view/gem_version.rb +5 -3
  12. data/lib/action_view/helpers/active_model_helper.rb +17 -11
  13. data/lib/action_view/helpers/asset_tag_helper.rb +244 -62
  14. data/lib/action_view/helpers/asset_url_helper.rb +170 -67
  15. data/lib/action_view/helpers/atom_feed_helper.rb +19 -17
  16. data/lib/action_view/helpers/cache_helper.rb +105 -42
  17. data/lib/action_view/helpers/capture_helper.rb +16 -13
  18. data/lib/action_view/helpers/controller_helper.rb +15 -4
  19. data/lib/action_view/helpers/csp_helper.rb +24 -0
  20. data/lib/action_view/helpers/csrf_helper.rb +7 -5
  21. data/lib/action_view/helpers/date_helper.rb +170 -112
  22. data/lib/action_view/helpers/debug_helper.rb +7 -6
  23. data/lib/action_view/helpers/form_helper.rb +521 -127
  24. data/lib/action_view/helpers/form_options_helper.rb +109 -63
  25. data/lib/action_view/helpers/form_tag_helper.rb +110 -67
  26. data/lib/action_view/helpers/javascript_helper.rb +24 -11
  27. data/lib/action_view/helpers/number_helper.rb +77 -58
  28. data/lib/action_view/helpers/output_safety_helper.rb +36 -4
  29. data/lib/action_view/helpers/record_tag_helper.rb +14 -99
  30. data/lib/action_view/helpers/rendering_helper.rb +6 -5
  31. data/lib/action_view/helpers/sanitize_helper.rb +20 -15
  32. data/lib/action_view/helpers/tag_helper.rb +198 -73
  33. data/lib/action_view/helpers/tags/base.rb +134 -97
  34. data/lib/action_view/helpers/tags/check_box.rb +20 -18
  35. data/lib/action_view/helpers/tags/checkable.rb +4 -2
  36. data/lib/action_view/helpers/tags/collection_check_boxes.rb +12 -33
  37. data/lib/action_view/helpers/tags/collection_helpers.rb +70 -36
  38. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +6 -11
  39. data/lib/action_view/helpers/tags/collection_select.rb +4 -2
  40. data/lib/action_view/helpers/tags/color_field.rb +3 -1
  41. data/lib/action_view/helpers/tags/date_field.rb +2 -0
  42. data/lib/action_view/helpers/tags/date_select.rb +38 -36
  43. data/lib/action_view/helpers/tags/datetime_field.rb +4 -2
  44. data/lib/action_view/helpers/tags/datetime_local_field.rb +2 -0
  45. data/lib/action_view/helpers/tags/datetime_select.rb +2 -0
  46. data/lib/action_view/helpers/tags/email_field.rb +2 -0
  47. data/lib/action_view/helpers/tags/file_field.rb +2 -0
  48. data/lib/action_view/helpers/tags/grouped_collection_select.rb +4 -2
  49. data/lib/action_view/helpers/tags/hidden_field.rb +2 -0
  50. data/lib/action_view/helpers/tags/label.rb +3 -1
  51. data/lib/action_view/helpers/tags/month_field.rb +2 -0
  52. data/lib/action_view/helpers/tags/number_field.rb +2 -0
  53. data/lib/action_view/helpers/tags/password_field.rb +3 -1
  54. data/lib/action_view/helpers/tags/placeholderable.rb +3 -1
  55. data/lib/action_view/helpers/tags/radio_button.rb +7 -5
  56. data/lib/action_view/helpers/tags/range_field.rb +2 -0
  57. data/lib/action_view/helpers/tags/search_field.rb +14 -9
  58. data/lib/action_view/helpers/tags/select.rb +11 -9
  59. data/lib/action_view/helpers/tags/tel_field.rb +2 -0
  60. data/lib/action_view/helpers/tags/text_area.rb +4 -2
  61. data/lib/action_view/helpers/tags/text_field.rb +8 -7
  62. data/lib/action_view/helpers/tags/time_field.rb +2 -0
  63. data/lib/action_view/helpers/tags/time_select.rb +2 -0
  64. data/lib/action_view/helpers/tags/time_zone_select.rb +3 -1
  65. data/lib/action_view/helpers/tags/translator.rb +17 -13
  66. data/lib/action_view/helpers/tags/url_field.rb +2 -0
  67. data/lib/action_view/helpers/tags/week_field.rb +2 -0
  68. data/lib/action_view/helpers/tags.rb +3 -1
  69. data/lib/action_view/helpers/text_helper.rb +55 -36
  70. data/lib/action_view/helpers/translation_helper.rb +62 -31
  71. data/lib/action_view/helpers/url_helper.rb +159 -104
  72. data/lib/action_view/helpers.rb +5 -1
  73. data/lib/action_view/layouts.rb +65 -58
  74. data/lib/action_view/log_subscriber.rb +60 -8
  75. data/lib/action_view/lookup_context.rb +80 -65
  76. data/lib/action_view/model_naming.rb +3 -1
  77. data/lib/action_view/path_set.rb +30 -19
  78. data/lib/action_view/railtie.rb +39 -6
  79. data/lib/action_view/record_identifier.rb +53 -25
  80. data/lib/action_view/renderer/abstract_renderer.rb +21 -15
  81. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +57 -0
  82. data/lib/action_view/renderer/partial_renderer.rb +218 -214
  83. data/lib/action_view/renderer/renderer.rb +8 -6
  84. data/lib/action_view/renderer/streaming_template_renderer.rb +50 -48
  85. data/lib/action_view/renderer/template_renderer.rb +67 -66
  86. data/lib/action_view/rendering.rb +19 -14
  87. data/lib/action_view/routing_url_for.rb +27 -17
  88. data/lib/action_view/tasks/cache_digests.rake +25 -0
  89. data/lib/action_view/template/error.rb +16 -16
  90. data/lib/action_view/template/handlers/builder.rb +10 -11
  91. data/lib/action_view/template/handlers/erb/erubi.rb +83 -0
  92. data/lib/action_view/template/handlers/erb.rb +9 -80
  93. data/lib/action_view/template/handlers/html.rb +11 -0
  94. data/lib/action_view/template/handlers/raw.rb +3 -3
  95. data/lib/action_view/template/handlers.rb +11 -7
  96. data/lib/action_view/template/html.rb +5 -5
  97. data/lib/action_view/template/resolver.rb +140 -115
  98. data/lib/action_view/template/text.rb +8 -9
  99. data/lib/action_view/template/types.rb +18 -18
  100. data/lib/action_view/template.rb +56 -31
  101. data/lib/action_view/test_case.rb +50 -29
  102. data/lib/action_view/testing/resolvers.rb +31 -31
  103. data/lib/action_view/version.rb +3 -1
  104. data/lib/action_view/view_paths.rb +28 -34
  105. data/lib/action_view.rb +8 -7
  106. data/lib/assets/compiled/rails-ujs.js +720 -0
  107. metadata +25 -24
  108. data/lib/action_view/tasks/dependencies.rake +0 -23
@@ -1,11 +1,13 @@
1
- require 'cgi'
2
- require 'action_view/helpers/tag_helper'
3
- require 'active_support/core_ext/string/output_safety'
4
- require 'active_support/core_ext/module/attribute_accessors'
1
+ # frozen_string_literal: true
2
+
3
+ require "cgi"
4
+ require "action_view/helpers/tag_helper"
5
+ require "active_support/core_ext/string/output_safety"
6
+ require "active_support/core_ext/module/attribute_accessors"
5
7
 
6
8
  module ActionView
7
9
  # = Action View Form Tag Helpers
8
- module Helpers
10
+ module Helpers #:nodoc:
9
11
  # Provides a number of methods for creating form tags that don't rely on an Active Record object assigned to the template like
10
12
  # FormHelper does. Instead, you provide the names and values manually.
11
13
  #
@@ -18,9 +20,9 @@ module ActionView
18
20
  include TextHelper
19
21
 
20
22
  mattr_accessor :embed_authenticity_token_in_remote_forms
21
- self.embed_authenticity_token_in_remote_forms = false
23
+ self.embed_authenticity_token_in_remote_forms = nil
22
24
 
23
- # Starts a form tag that points the action to an url configured with <tt>url_for_options</tt> just like
25
+ # Starts a form tag that points the action to a url configured with <tt>url_for_options</tt> just like
24
26
  # ActionController::Base#url_for. The method for the form defaults to POST.
25
27
  #
26
28
  # ==== Options
@@ -80,7 +82,7 @@ module ActionView
80
82
  # associated records. <tt>option_tags</tt> is a string containing the option tags for the select box.
81
83
  #
82
84
  # ==== Options
83
- # * <tt>:multiple</tt> - If set to true the selection will allow multiple choices.
85
+ # * <tt>:multiple</tt> - If set to true, the selection will allow multiple choices.
84
86
  # * <tt>:disabled</tt> - If set to true, the user will not be able to use this input.
85
87
  # * <tt>:include_blank</tt> - If set to true, an empty option will be created. If set to a string, the string will be used as the option's content and the value will be empty.
86
88
  # * <tt>:prompt</tt> - Create a prompt option with blank value and the text asking user to select something.
@@ -93,27 +95,27 @@ module ActionView
93
95
  # select_tag "people", options_from_collection_for_select(@people, "id", "name", "1")
94
96
  # # <select id="people" name="people"><option value="1" selected="selected">David</option></select>
95
97
  #
96
- # select_tag "people", "<option>David</option>".html_safe
98
+ # select_tag "people", raw("<option>David</option>")
97
99
  # # => <select id="people" name="people"><option>David</option></select>
98
100
  #
99
- # select_tag "count", "<option>1</option><option>2</option><option>3</option><option>4</option>".html_safe
101
+ # select_tag "count", raw("<option>1</option><option>2</option><option>3</option><option>4</option>")
100
102
  # # => <select id="count" name="count"><option>1</option><option>2</option>
101
103
  # # <option>3</option><option>4</option></select>
102
104
  #
103
- # select_tag "colors", "<option>Red</option><option>Green</option><option>Blue</option>".html_safe, multiple: true
105
+ # select_tag "colors", raw("<option>Red</option><option>Green</option><option>Blue</option>"), multiple: true
104
106
  # # => <select id="colors" multiple="multiple" name="colors[]"><option>Red</option>
105
107
  # # <option>Green</option><option>Blue</option></select>
106
108
  #
107
- # select_tag "locations", "<option>Home</option><option selected='selected'>Work</option><option>Out</option>".html_safe
109
+ # select_tag "locations", raw("<option>Home</option><option selected='selected'>Work</option><option>Out</option>")
108
110
  # # => <select id="locations" name="locations"><option>Home</option><option selected='selected'>Work</option>
109
111
  # # <option>Out</option></select>
110
112
  #
111
- # select_tag "access", "<option>Read</option><option>Write</option>".html_safe, multiple: true, class: 'form_input', id: 'unique_id'
113
+ # select_tag "access", raw("<option>Read</option><option>Write</option>"), multiple: true, class: 'form_input', id: 'unique_id'
112
114
  # # => <select class="form_input" id="unique_id" multiple="multiple" name="access[]"><option>Read</option>
113
115
  # # <option>Write</option></select>
114
116
  #
115
117
  # select_tag "people", options_from_collection_for_select(@people, "id", "name"), include_blank: true
116
- # # => <select id="people" name="people"><option value=""></option><option value="1">David</option></select>
118
+ # # => <select id="people" name="people"><option value="" label=" "></option><option value="1">David</option></select>
117
119
  #
118
120
  # select_tag "people", options_from_collection_for_select(@people, "id", "name"), include_blank: "All"
119
121
  # # => <select id="people" name="people"><option value="">All</option><option value="1">David</option></select>
@@ -121,7 +123,7 @@ module ActionView
121
123
  # select_tag "people", options_from_collection_for_select(@people, "id", "name"), prompt: "Select something"
122
124
  # # => <select id="people" name="people"><option value="">Select something</option><option value="1">David</option></select>
123
125
  #
124
- # select_tag "destination", "<option>NYC</option><option>Paris</option><option>Rome</option>".html_safe, disabled: true
126
+ # select_tag "destination", raw("<option>NYC</option><option>Paris</option><option>Rome</option>"), disabled: true
125
127
  # # => <select disabled="disabled" id="destination" name="destination"><option>NYC</option>
126
128
  # # <option>Paris</option><option>Rome</option></select>
127
129
  #
@@ -134,21 +136,23 @@ module ActionView
134
136
 
135
137
  if options.include?(:include_blank)
136
138
  include_blank = options.delete(:include_blank)
139
+ options_for_blank_options_tag = { value: "" }
137
140
 
138
141
  if include_blank == true
139
- include_blank = ''
142
+ include_blank = ""
143
+ options_for_blank_options_tag[:label] = " "
140
144
  end
141
145
 
142
146
  if include_blank
143
- option_tags = content_tag(:option, include_blank, value: '').safe_concat(option_tags)
147
+ option_tags = content_tag("option".freeze, include_blank, options_for_blank_options_tag).safe_concat(option_tags)
144
148
  end
145
149
  end
146
150
 
147
151
  if prompt = options.delete(:prompt)
148
- option_tags = content_tag(:option, prompt, value: '').safe_concat(option_tags)
152
+ option_tags = content_tag("option".freeze, prompt, value: "").safe_concat(option_tags)
149
153
  end
150
154
 
151
- content_tag :select, option_tags, { "name" => html_name, "id" => sanitize_to_id(name) }.update(options.stringify_keys)
155
+ content_tag "select".freeze, option_tags, { "name" => html_name, "id" => sanitize_to_id(name) }.update(options.stringify_keys)
152
156
  end
153
157
 
154
158
  # Creates a standard text field; use these text fields to input smaller chunks of text like a username
@@ -159,6 +163,8 @@ module ActionView
159
163
  # * <tt>:size</tt> - The number of visible characters that will fit in the input.
160
164
  # * <tt>:maxlength</tt> - The maximum number of characters that the browser will allow the user to enter.
161
165
  # * <tt>:placeholder</tt> - The text contained in the field by default which is removed when the field receives focus.
166
+ # If set to true, use a translation is found in the current I18n locale
167
+ # (through helpers.placeholders.<modelname>.<attribute>).
162
168
  # * Any other key creates standard HTML attributes for the tag.
163
169
  #
164
170
  # ==== Examples
@@ -270,7 +276,7 @@ module ActionView
270
276
  # file_field_tag 'file', accept: 'text/html', class: 'upload', value: 'index.html'
271
277
  # # => <input accept="text/html" class="upload" id="file" name="file" type="file" value="index.html" />
272
278
  def file_field_tag(name, options = {})
273
- text_field_tag(name, nil, options.merge(type: :file))
279
+ text_field_tag(name, nil, convert_direct_upload_option_to_url(options.merge(type: :file)))
274
280
  end
275
281
 
276
282
  # Creates a password field, a masked text field that will hide the users input behind a mask character.
@@ -390,7 +396,7 @@ module ActionView
390
396
  # # => <input checked="checked" id="receive_updates_no" name="receive_updates" type="radio" value="no" />
391
397
  #
392
398
  # radio_button_tag 'time_slot', "3:00 p.m.", false, disabled: true
393
- # # => <input disabled="disabled" id="time_slot_300_pm" name="time_slot" type="radio" value="3:00 p.m." />
399
+ # # => <input disabled="disabled" id="time_slot_3:00_p.m." name="time_slot" type="radio" value="3:00 p.m." />
394
400
  #
395
401
  # radio_button_tag 'color', "green", true, class: "color_input"
396
402
  # # => <input checked="checked" class="color_input" id="color_green" name="color" type="radio" value="green" />
@@ -414,42 +420,45 @@ module ActionView
414
420
  # the form is processed normally, otherwise no action is taken.
415
421
  # * <tt>:disable_with</tt> - Value of this parameter will be used as the value for a
416
422
  # disabled version of the submit button when the form is submitted. This feature is
417
- # provided by the unobtrusive JavaScript driver.
423
+ # provided by the unobtrusive JavaScript driver. To disable this feature for a single submit tag
424
+ # pass <tt>:data => { disable_with: false }</tt> Defaults to value attribute.
418
425
  #
419
426
  # ==== Examples
420
427
  # submit_tag
421
- # # => <input name="commit" type="submit" value="Save changes" />
428
+ # # => <input name="commit" data-disable-with="Save changes" type="submit" value="Save changes" />
422
429
  #
423
430
  # submit_tag "Edit this article"
424
- # # => <input name="commit" type="submit" value="Edit this article" />
431
+ # # => <input name="commit" data-disable-with="Edit this article" type="submit" value="Edit this article" />
425
432
  #
426
433
  # submit_tag "Save edits", disabled: true
427
- # # => <input disabled="disabled" name="commit" type="submit" value="Save edits" />
434
+ # # => <input disabled="disabled" name="commit" data-disable-with="Save edits" type="submit" value="Save edits" />
428
435
  #
429
- # submit_tag "Complete sale", data: { disable_with: "Please wait..." }
430
- # # => <input name="commit" data-disable-with="Please wait..." type="submit" value="Complete sale" />
436
+ # submit_tag "Complete sale", data: { disable_with: "Submitting..." }
437
+ # # => <input name="commit" data-disable-with="Submitting..." type="submit" value="Complete sale" />
431
438
  #
432
439
  # submit_tag nil, class: "form_submit"
433
440
  # # => <input class="form_submit" name="commit" type="submit" />
434
441
  #
435
442
  # submit_tag "Edit", class: "edit_button"
436
- # # => <input class="edit_button" name="commit" type="submit" value="Edit" />
443
+ # # => <input class="edit_button" data-disable-with="Edit" name="commit" type="submit" value="Edit" />
437
444
  #
438
445
  # submit_tag "Save", data: { confirm: "Are you sure?" }
439
- # # => <input name='commit' type='submit' value='Save' data-confirm="Are you sure?" />
446
+ # # => <input name='commit' type='submit' value='Save' data-disable-with="Save" data-confirm="Are you sure?" />
440
447
  #
441
448
  def submit_tag(value = "Save changes", options = {})
442
- options = options.stringify_keys
443
-
444
- tag :input, { "type" => "submit", "name" => "commit", "value" => value }.update(options)
449
+ options = options.deep_stringify_keys
450
+ tag_options = { "type" => "submit", "name" => "commit", "value" => value }.update(options)
451
+ set_default_disable_with value, tag_options
452
+ tag :input, tag_options
445
453
  end
446
454
 
447
455
  # Creates a button element that defines a <tt>submit</tt> button,
448
- # <tt>reset</tt>button or a generic button which can be used in
456
+ # <tt>reset</tt> button or a generic button which can be used in
449
457
  # JavaScript, for example. You can use the button tag as a regular
450
458
  # submit tag but it isn't supported in legacy browsers. However,
451
- # the button tag allows richer labels such as images and emphasis,
452
- # so this helper will also accept a block.
459
+ # the button tag does allow for richer labels such as images and emphasis,
460
+ # so this helper will also accept a block. By default, it will create
461
+ # a button tag with type <tt>submit</tt>, if type is not given.
453
462
  #
454
463
  # ==== Options
455
464
  # * <tt>:data</tt> - This option can be used to add custom data attributes.
@@ -472,6 +481,15 @@ module ActionView
472
481
  # button_tag
473
482
  # # => <button name="button" type="submit">Button</button>
474
483
  #
484
+ # button_tag 'Reset', type: 'reset'
485
+ # # => <button name="button" type="reset">Reset</button>
486
+ #
487
+ # button_tag 'Button', type: 'button'
488
+ # # => <button name="button" type="button">Button</button>
489
+ #
490
+ # button_tag 'Reset', type: 'reset', disabled: true
491
+ # # => <button name="button" type="reset" disabled="disabled">Reset</button>
492
+ #
475
493
  # button_tag(type: 'button') do
476
494
  # content_tag(:strong, 'Ask me!')
477
495
  # end
@@ -479,6 +497,9 @@ module ActionView
479
497
  # # <strong>Ask me!</strong>
480
498
  # # </button>
481
499
  #
500
+ # button_tag "Save", data: { confirm: "Are you sure?" }
501
+ # # => <button name="button" type="submit" data-confirm="Are you sure?">Save</button>
502
+ #
482
503
  # button_tag "Checkout", data: { disable_with: "Please wait..." }
483
504
  # # => <button data-disable-with="Please wait..." name="button" type="submit">Checkout</button>
484
505
  #
@@ -489,12 +510,12 @@ module ActionView
489
510
  options ||= {}
490
511
  end
491
512
 
492
- options = { 'name' => 'button', 'type' => 'submit' }.merge!(options.stringify_keys)
513
+ options = { "name" => "button", "type" => "submit" }.merge!(options.stringify_keys)
493
514
 
494
515
  if block_given?
495
516
  content_tag :button, options, &block
496
517
  else
497
- content_tag :button, content_or_options || 'Button', options
518
+ content_tag :button, content_or_options || "Button", options
498
519
  end
499
520
  end
500
521
 
@@ -515,22 +536,23 @@ module ActionView
515
536
  #
516
537
  # ==== Examples
517
538
  # image_submit_tag("login.png")
518
- # # => <input alt="Login" src="/assets/login.png" type="image" />
539
+ # # => <input src="/assets/login.png" type="image" />
519
540
  #
520
541
  # image_submit_tag("purchase.png", disabled: true)
521
- # # => <input alt="Purchase" disabled="disabled" src="/assets/purchase.png" type="image" />
542
+ # # => <input disabled="disabled" src="/assets/purchase.png" type="image" />
522
543
  #
523
544
  # image_submit_tag("search.png", class: 'search_button', alt: 'Find')
524
- # # => <input alt="Find" class="search_button" src="/assets/search.png" type="image" />
545
+ # # => <input class="search_button" src="/assets/search.png" type="image" />
525
546
  #
526
547
  # image_submit_tag("agree.png", disabled: true, class: "agree_disagree_button")
527
- # # => <input alt="Agree" class="agree_disagree_button" disabled="disabled" src="/assets/agree.png" type="image" />
548
+ # # => <input class="agree_disagree_button" disabled="disabled" src="/assets/agree.png" type="image" />
528
549
  #
529
550
  # image_submit_tag("save.png", data: { confirm: "Are you sure?" })
530
- # # => <input alt="Save" src="/assets/save.png" data-confirm="Are you sure?" type="image" />
551
+ # # => <input src="/assets/save.png" data-confirm="Are you sure?" type="image" />
531
552
  def image_submit_tag(source, options = {})
532
553
  options = options.stringify_keys
533
- tag :input, { "alt" => image_alt(source), "type" => "image", "src" => path_to_image(source) }.update(options)
554
+ src = path_to_image(source, skip_pipeline: options.delete("skip_pipeline"))
555
+ tag :input, { "type" => "image", "src" => src }.update(options)
534
556
  end
535
557
 
536
558
  # Creates a field set for grouping HTML form elements.
@@ -555,7 +577,7 @@ module ActionView
555
577
  # # => <fieldset class="format"><p><input id="name" name="name" type="text" /></p></fieldset>
556
578
  def field_set_tag(legend = nil, options = nil, &block)
557
579
  output = tag(:fieldset, options, true)
558
- output.safe_concat(content_tag(:legend, legend)) unless legend.blank?
580
+ output.safe_concat(content_tag("legend".freeze, legend)) unless legend.blank?
559
581
  output.concat(capture(&block)) if block_given?
560
582
  output.safe_concat("</fieldset>")
561
583
  end
@@ -656,7 +678,7 @@ module ActionView
656
678
  text_field_tag(name, value, options.merge(type: :time))
657
679
  end
658
680
 
659
- # Creates a text field of type "datetime".
681
+ # Creates a text field of type "datetime-local".
660
682
  #
661
683
  # === Options
662
684
  # * <tt>:min</tt> - The minimum acceptable value.
@@ -664,19 +686,10 @@ module ActionView
664
686
  # * <tt>:step</tt> - The acceptable value granularity.
665
687
  # * Otherwise accepts the same options as text_field_tag.
666
688
  def datetime_field_tag(name, value = nil, options = {})
667
- text_field_tag(name, value, options.merge(type: :datetime))
689
+ text_field_tag(name, value, options.merge(type: "datetime-local"))
668
690
  end
669
691
 
670
- # Creates a text field of type "datetime-local".
671
- #
672
- # === Options
673
- # * <tt>:min</tt> - The minimum acceptable value.
674
- # * <tt>:max</tt> - The maximum acceptable value.
675
- # * <tt>:step</tt> - The acceptable value granularity.
676
- # * Otherwise accepts the same options as text_field_tag.
677
- def datetime_local_field_tag(name, value = nil, options = {})
678
- text_field_tag(name, value, options.merge(type: 'datetime-local'))
679
- end
692
+ alias datetime_local_field_tag datetime_field_tag
680
693
 
681
694
  # Creates a text field of type "month".
682
695
  #
@@ -776,10 +789,10 @@ module ActionView
776
789
  # # => <input id="quantity" name="quantity" min="1" max="9" type="number" />
777
790
  #
778
791
  # number_field_tag 'quantity', nil, min: 1, max: 10
779
- # # => <input id="quantity" name="quantity" min="1" max="9" type="number" />
792
+ # # => <input id="quantity" name="quantity" min="1" max="10" type="number" />
780
793
  #
781
794
  # number_field_tag 'quantity', nil, min: 1, max: 10, step: 2
782
- # # => <input id="quantity" name="quantity" min="1" max="9" step="2" type="number" />
795
+ # # => <input id="quantity" name="quantity" min="1" max="10" step="2" type="number" />
783
796
  #
784
797
  # number_field_tag 'quantity', '1', class: 'special_input', disabled: true
785
798
  # # => <input disabled="disabled" class="special_input" id="quantity" name="quantity" type="number" value="1" />
@@ -835,19 +848,26 @@ module ActionView
835
848
 
836
849
  def extra_tags_for_form(html_options)
837
850
  authenticity_token = html_options.delete("authenticity_token")
838
- method = html_options.delete("method").to_s
851
+ method = html_options.delete("method").to_s.downcase
839
852
 
840
- method_tag = case method
841
- when /^get$/i # must be case-insensitive, but can't use downcase as might be nil
853
+ method_tag = \
854
+ case method
855
+ when "get"
842
856
  html_options["method"] = "get"
843
- ''
844
- when /^post$/i, "", nil
857
+ ""
858
+ when "post", ""
845
859
  html_options["method"] = "post"
846
- token_tag(authenticity_token)
860
+ token_tag(authenticity_token, form_options: {
861
+ action: html_options["action"],
862
+ method: "post"
863
+ })
847
864
  else
848
865
  html_options["method"] = "post"
849
- method_tag(method) + token_tag(authenticity_token)
850
- end
866
+ method_tag(method) + token_tag(authenticity_token, form_options: {
867
+ action: html_options["action"],
868
+ method: method
869
+ })
870
+ end
851
871
 
852
872
  if html_options.delete("enforce_utf8") { true }
853
873
  utf8_enforcer_tag + method_tag
@@ -869,7 +889,30 @@ module ActionView
869
889
 
870
890
  # see http://www.w3.org/TR/html4/types.html#type-name
871
891
  def sanitize_to_id(name)
872
- name.to_s.delete(']').tr('^-a-zA-Z0-9:.', "_")
892
+ name.to_s.delete("]").tr("^-a-zA-Z0-9:.", "_")
893
+ end
894
+
895
+ def set_default_disable_with(value, tag_options)
896
+ return unless ActionView::Base.automatically_disable_submit_tag
897
+ data = tag_options["data"]
898
+
899
+ unless tag_options["data-disable-with"] == false || (data && data["disable_with"] == false)
900
+ disable_with_text = tag_options["data-disable-with"]
901
+ disable_with_text ||= data["disable_with"] if data
902
+ disable_with_text ||= value.to_s.clone
903
+ tag_options.deep_merge!("data" => { "disable_with" => disable_with_text })
904
+ else
905
+ data.delete("disable_with") if data
906
+ end
907
+
908
+ tag_options.delete("data-disable-with")
909
+ end
910
+
911
+ def convert_direct_upload_option_to_url(options)
912
+ if options.delete(:direct_upload) && respond_to?(:rails_direct_uploads_url)
913
+ options["data-direct-upload-url"] = rails_direct_uploads_url
914
+ end
915
+ options
873
916
  end
874
917
  end
875
918
  end
@@ -1,11 +1,13 @@
1
- require 'action_view/helpers/tag_helper'
1
+ # frozen_string_literal: true
2
+
3
+ require "action_view/helpers/tag_helper"
2
4
 
3
5
  module ActionView
4
- module Helpers
6
+ module Helpers #:nodoc:
5
7
  module JavaScriptHelper
6
8
  JS_ESCAPE_MAP = {
7
9
  '\\' => '\\\\',
8
- '</' => '<\/',
10
+ "</" => '<\/',
9
11
  "\r\n" => '\n',
10
12
  "\n" => '\n',
11
13
  "\r" => '\n',
@@ -13,21 +15,21 @@ module ActionView
13
15
  "'" => "\\'"
14
16
  }
15
17
 
16
- JS_ESCAPE_MAP["\342\200\250".force_encoding(Encoding::UTF_8).encode!] = '&#x2028;'
17
- JS_ESCAPE_MAP["\342\200\251".force_encoding(Encoding::UTF_8).encode!] = '&#x2029;'
18
+ JS_ESCAPE_MAP["\342\200\250".dup.force_encoding(Encoding::UTF_8).encode!] = "&#x2028;"
19
+ JS_ESCAPE_MAP["\342\200\251".dup.force_encoding(Encoding::UTF_8).encode!] = "&#x2029;"
18
20
 
19
21
  # Escapes carriage returns and single and double quotes for JavaScript segments.
20
22
  #
21
23
  # Also available through the alias j(). This is particularly helpful in JavaScript
22
24
  # responses, like:
23
25
  #
24
- # $('some_element').replaceWith('<%=j render 'some/element_template' %>');
26
+ # $('some_element').replaceWith('<%= j render 'some/element_template' %>');
25
27
  def escape_javascript(javascript)
26
28
  if javascript
27
- result = javascript.gsub(/(\\|<\/|\r\n|\342\200\250|\342\200\251|[\n\r"'])/u) {|match| JS_ESCAPE_MAP[match] }
29
+ result = javascript.gsub(/(\\|<\/|\r\n|\342\200\250|\342\200\251|[\n\r"'])/u) { |match| JS_ESCAPE_MAP[match] }
28
30
  javascript.html_safe? ? result.html_safe : result
29
31
  else
30
- ''
32
+ ""
31
33
  end
32
34
  end
33
35
 
@@ -47,8 +49,8 @@ module ActionView
47
49
  # tag.
48
50
  #
49
51
  # javascript_tag "alert('All is good')", defer: 'defer'
50
- #
51
- # Returns:
52
+ #
53
+ # Returns:
52
54
  # <script defer="defer">
53
55
  # //<![CDATA[
54
56
  # alert('All is good')
@@ -61,6 +63,13 @@ module ActionView
61
63
  # <%= javascript_tag defer: 'defer' do -%>
62
64
  # alert('All is good')
63
65
  # <% end -%>
66
+ #
67
+ # If you have a content security policy enabled then you can add an automatic
68
+ # nonce value by passing +nonce: true+ as part of +html_options+. Example:
69
+ #
70
+ # <%= javascript_tag nonce: true do -%>
71
+ # alert('All is good')
72
+ # <% end -%>
64
73
  def javascript_tag(content_or_options_with_block = nil, html_options = {}, &block)
65
74
  content =
66
75
  if block_given?
@@ -70,7 +79,11 @@ module ActionView
70
79
  content_or_options_with_block
71
80
  end
72
81
 
73
- content_tag(:script, javascript_cdata_section(content), html_options)
82
+ if html_options[:nonce] == true
83
+ html_options[:nonce] = content_security_policy_nonce
84
+ end
85
+
86
+ content_tag("script".freeze, javascript_cdata_section(content), html_options)
74
87
  end
75
88
 
76
89
  def javascript_cdata_section(content) #:nodoc: