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