actionview 7.1.5.1 → 7.2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -522,25 +522,6 @@ module ActionView
522
522
  # submit_tag "Edit", class: "edit_button"
523
523
  # # => <input class="edit_button" data-disable-with="Edit" name="commit" type="submit" value="Edit" />
524
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
- #
541
- # submit_tag "Save", data: { confirm: "Are you sure?" }
542
- # # => <input name='commit' type='submit' value='Save' data-disable-with="Save" data-confirm="Are you sure?" />
543
- #
544
525
  def submit_tag(value = "Save changes", options = {})
545
526
  options = options.deep_stringify_keys
546
527
  tag_options = { "type" => "submit", "name" => "commit", "value" => value }.update(options)
@@ -582,26 +563,6 @@ module ActionView
582
563
  # # <strong>Ask me!</strong>
583
564
  # # </button>
584
565
  #
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
- #
599
- # button_tag "Save", data: { confirm: "Are you sure?" }
600
- # # => <button name="button" type="submit" data-confirm="Are you sure?">Save</button>
601
- #
602
- # button_tag "Checkout", data: { disable_with: "Please wait..." }
603
- # # => <button data-disable-with="Please wait..." name="button" type="submit">Checkout</button>
604
- #
605
566
  def button_tag(content_or_options = nil, options = nil, &block)
606
567
  if content_or_options.is_a? Hash
607
568
  options = content_or_options
@@ -675,11 +636,13 @@ module ActionView
675
636
  # <% end %>
676
637
  # # => <fieldset class="format"><p><input id="name" name="name" type="text" /></p></fieldset>
677
638
  def field_set_tag(legend = nil, options = nil, &block)
678
- output = tag(:fieldset, options, true)
679
- output.safe_concat(content_tag("legend", legend)) unless legend.blank?
680
- output.concat(capture(&block)) if block_given?
681
- output.safe_concat("</fieldset>")
639
+ content = []
640
+ content << content_tag("legend", legend) unless legend.blank?
641
+ content << capture(&block) if block_given?
642
+
643
+ content_tag(:fieldset, safe_join(content), options)
682
644
  end
645
+ alias_method :fieldset_tag, :field_set_tag
683
646
 
684
647
  # Creates a text field of type "color".
685
648
  #
@@ -762,14 +725,14 @@ module ActionView
762
725
  # date_field_tag 'name'
763
726
  # # => <input id="name" name="name" type="date" />
764
727
  #
765
- # date_field_tag 'date', '01/01/2014'
766
- # # => <input id="date" name="date" type="date" value="01/01/2014" />
728
+ # date_field_tag 'date', '2014-12-31'
729
+ # # => <input id="date" name="date" type="date" value="2014-12-31" />
767
730
  #
768
731
  # date_field_tag 'date', nil, class: 'special_input'
769
732
  # # => <input class="special_input" id="date" name="date" type="date" />
770
733
  #
771
- # date_field_tag 'date', '01/01/2014', class: 'special_input', disabled: true
772
- # # => <input disabled="disabled" class="special_input" id="date" name="date" type="date" value="01/01/2014" />
734
+ # date_field_tag 'date', '2014-12-31', class: 'special_input', disabled: true
735
+ # # => <input disabled="disabled" class="special_input" id="date" name="date" type="date" value="2014-12-31" />
773
736
  def date_field_tag(name, value = nil, options = {})
774
737
  text_field_tag(name, value, options.merge(type: :date))
775
738
  end
@@ -784,6 +747,23 @@ module ActionView
784
747
  # * <tt>:max</tt> - The maximum acceptable value.
785
748
  # * <tt>:step</tt> - The acceptable value granularity.
786
749
  # * <tt>:include_seconds</tt> - Include seconds and ms in the output timestamp format (true by default).
750
+ #
751
+ # ==== Examples
752
+ #
753
+ # time_field_tag 'name'
754
+ # # => <input id="name" name="name" type="time" />
755
+ #
756
+ # time_field_tag 'time', '01:01'
757
+ # # => <input id="time" name="time" type="time" value="01:01" />
758
+ #
759
+ # time_field_tag 'time', nil, class: 'special_input'
760
+ # # => <input class="special_input" id="time" name="time" type="time" />
761
+ #
762
+ # time_field_tag 'time', '01:01', include_seconds: true
763
+ # # => <input id="time" name="time" type="time" value="01:01:00.000" />
764
+ #
765
+ # time_field_tag 'time', '01:01', min: '00:00', max: '23:59', step: 1
766
+ # # => <input id="time" max="23:59" min="00:00" name="time" step="1" type="time" value="01:01" />
787
767
  def time_field_tag(name, value = nil, options = {})
788
768
  text_field_tag(name, value, options.merge(type: :time))
789
769
  end
@@ -798,6 +778,20 @@ module ActionView
798
778
  # * <tt>:max</tt> - The maximum acceptable value.
799
779
  # * <tt>:step</tt> - The acceptable value granularity.
800
780
  # * <tt>:include_seconds</tt> - Include seconds in the output timestamp format (true by default).
781
+ #
782
+ # ==== Examples
783
+ #
784
+ # datetime_field_tag 'name'
785
+ # # => <input id="name" name="name" type="datetime-local" />
786
+ #
787
+ # datetime_field_tag 'datetime', '2014-01-01T01:01'
788
+ # # => <input id="datetime" name="datetime" type="datetime-local" value="2014-01-01T01:01" />
789
+ #
790
+ # datetime_field_tag 'datetime', nil, class: 'special_input'
791
+ # # => <input class="special_input" id="datetime" name="datetime" type="datetime-local" />
792
+ #
793
+ # datetime_field_tag 'datetime', '2014-01-01T01:01', class: 'special_input', disabled: true
794
+ # # => <input disabled="disabled" class="special_input" id="datetime" name="datetime" type="datetime-local" value="2014-01-01T01:01" />
801
795
  def datetime_field_tag(name, value = nil, options = {})
802
796
  text_field_tag(name, value, options.merge(type: "datetime-local"))
803
797
  end
@@ -813,6 +807,20 @@ module ActionView
813
807
  # * <tt>:min</tt> - The minimum acceptable value.
814
808
  # * <tt>:max</tt> - The maximum acceptable value.
815
809
  # * <tt>:step</tt> - The acceptable value granularity.
810
+ #
811
+ # ==== Examples
812
+ #
813
+ # month_field_tag 'name'
814
+ # # => <input id="name" name="name" type="month" />
815
+ #
816
+ # month_field_tag 'month', '2014-01'
817
+ # # => <input id="month" name="month" type="month" value="2014-01" />
818
+ #
819
+ # month_field_tag 'month', nil, class: 'special_input'
820
+ # # => <input class="special_input" id="month" name="month" type="month" />
821
+ #
822
+ # month_field_tag 'month', '2014-01', class: 'special_input', disabled: true
823
+ # # => <input disabled="disabled" class="special_input" id="month" name="month" type="month" value="2014-01" />
816
824
  def month_field_tag(name, value = nil, options = {})
817
825
  text_field_tag(name, value, options.merge(type: :month))
818
826
  end
@@ -826,6 +834,20 @@ module ActionView
826
834
  # * <tt>:min</tt> - The minimum acceptable value.
827
835
  # * <tt>:max</tt> - The maximum acceptable value.
828
836
  # * <tt>:step</tt> - The acceptable value granularity.
837
+ #
838
+ # ==== Examples
839
+ #
840
+ # week_field_tag 'name'
841
+ # # => <input id="name" name="name" type="week" />
842
+ #
843
+ # week_field_tag 'week', '2014-W01'
844
+ # # => <input id="week" name="week" type="week" value="2014-W01" />
845
+ #
846
+ # week_field_tag 'week', nil, class: 'special_input'
847
+ # # => <input class="special_input" id="week" name="week" type="week" />
848
+ #
849
+ # week_field_tag 'week', '2014-W01', class: 'special_input', disabled: true
850
+ # # => <input disabled="disabled" class="special_input" id="week" name="week" type="week" value="2014-W01" />
829
851
  def week_field_tag(name, value = nil, options = {})
830
852
  text_field_tag(name, value, options.merge(type: :week))
831
853
  end
@@ -934,6 +956,17 @@ module ActionView
934
956
  # ==== Options
935
957
  #
936
958
  # Supports the same options as #number_field_tag.
959
+ #
960
+ # ==== Examples
961
+ #
962
+ # range_field_tag 'quantity', '1'
963
+ # # => <input id="quantity" name="quantity" type="range" value="1" />
964
+ #
965
+ # range_field_tag 'quantity', in: 1...10
966
+ # # => <input id="quantity" name="quantity" min="1" max="9" type="range" />
967
+ #
968
+ # range_field_tag 'quantity', min: 1, max: 10, step: 2
969
+ # # => <input id="quantity" name="quantity" min="1" max="10" step="2" type="range"
937
970
  def range_field_tag(name, value = nil, options = {})
938
971
  number_field_tag(name, value, options.merge(type: :range))
939
972
  end
@@ -24,11 +24,11 @@ module ActionView # :nodoc:
24
24
  # the supplied separator, are HTML escaped unless they are HTML
25
25
  # safe, and the returned string is marked as HTML safe.
26
26
  #
27
- # safe_join([raw("<p>foo</p>"), "<p>bar</p>"], "<br />")
28
- # # => "<p>foo</p>&lt;br /&gt;&lt;p&gt;bar&lt;/p&gt;"
27
+ # safe_join([tag.p("foo"), "<p>bar</p>"], "<br>")
28
+ # # => "<p>foo</p>&lt;br&gt;&lt;p&gt;bar&lt;/p&gt;"
29
29
  #
30
- # safe_join([raw("<p>foo</p>"), raw("<p>bar</p>")], raw("<br />"))
31
- # # => "<p>foo</p><br /><p>bar</p>"
30
+ # safe_join([tag.p("foo"), tag.p("bar")], tag.br)
31
+ # # => "<p>foo</p><br><p>bar</p>"
32
32
  #
33
33
  def safe_join(array, sep = $,)
34
34
  sep = ERB::Util.unwrapped_html_escape(sep)
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/code_generator"
3
4
  require "active_support/core_ext/enumerable"
4
5
  require "active_support/core_ext/string/output_safety"
6
+ require "active_support/core_ext/string/inflections"
5
7
  require "set"
6
8
  require "action_view/helpers/capture_helper"
7
9
  require "action_view/helpers/output_safety_helper"
@@ -46,8 +48,183 @@ module ActionView
46
48
  include CaptureHelper
47
49
  include OutputSafetyHelper
48
50
 
49
- HTML_VOID_ELEMENTS = %i(area base br col embed hr img input keygen link meta param source track wbr).to_set
50
- SVG_SELF_CLOSING_ELEMENTS = %i(animate animateMotion animateTransform circle ellipse line path polygon polyline rect set stop use view).to_set
51
+ def self.define_element(name, code_generator:, method_name: name.to_s.underscore)
52
+ code_generator.define_cached_method(method_name, namespace: :tag_builder) do |batch|
53
+ batch.push(<<~RUBY) unless instance_methods.include?(method_name.to_sym)
54
+ def #{method_name}(content = nil, escape: true, **options, &block)
55
+ tag_string("#{name}", content, options, escape: escape, &block)
56
+ end
57
+ RUBY
58
+ end
59
+ end
60
+
61
+ def self.define_void_element(name, code_generator:, method_name: name.to_s.underscore)
62
+ code_generator.define_cached_method(method_name, namespace: :tag_builder) do |batch|
63
+ batch.push(<<~RUBY)
64
+ def #{method_name}(content = nil, escape: true, **options, &block)
65
+ if content || block
66
+ ActionView.deprecator.warn <<~TEXT
67
+ Putting content inside a void element (#{name}) is invalid
68
+ according to the HTML5 spec, and so it is being deprecated
69
+ without replacement. In Rails 8.0, passing content as a
70
+ positional argument will raise, and using a block will have
71
+ no effect.
72
+ TEXT
73
+ tag_string("#{name}", content, options, escape: escape, &block)
74
+ else
75
+ self_closing_tag_string("#{name}", options, escape, ">")
76
+ end
77
+ end
78
+ RUBY
79
+ end
80
+ end
81
+
82
+ def self.define_self_closing_element(name, code_generator:, method_name: name.to_s.underscore)
83
+ code_generator.define_cached_method(method_name, namespace: :tag_builder) do |batch|
84
+ batch.push(<<~RUBY)
85
+ def #{method_name}(content = nil, escape: true, **options, &block)
86
+ if content || block
87
+ tag_string("#{name}", content, options, escape: escape, &block)
88
+ else
89
+ self_closing_tag_string("#{name}", options, escape)
90
+ end
91
+ end
92
+ RUBY
93
+ end
94
+ end
95
+
96
+ ActiveSupport::CodeGenerator.batch(self, __FILE__, __LINE__) do |code_generator|
97
+ define_void_element :area, code_generator: code_generator
98
+ define_void_element :base, code_generator: code_generator
99
+ define_void_element :br, code_generator: code_generator
100
+ define_void_element :col, code_generator: code_generator
101
+ define_void_element :embed, code_generator: code_generator
102
+ define_void_element :hr, code_generator: code_generator
103
+ define_void_element :img, code_generator: code_generator
104
+ define_void_element :input, code_generator: code_generator
105
+ define_void_element :keygen, code_generator: code_generator
106
+ define_void_element :link, code_generator: code_generator
107
+ define_void_element :meta, code_generator: code_generator
108
+ define_void_element :source, code_generator: code_generator
109
+ define_void_element :track, code_generator: code_generator
110
+ define_void_element :wbr, code_generator: code_generator
111
+
112
+ define_self_closing_element :animate, code_generator: code_generator
113
+ define_self_closing_element :animateMotion, code_generator: code_generator
114
+ define_self_closing_element :animateTransform, code_generator: code_generator
115
+ define_self_closing_element :circle, code_generator: code_generator
116
+ define_self_closing_element :ellipse, code_generator: code_generator
117
+ define_self_closing_element :line, code_generator: code_generator
118
+ define_self_closing_element :path, code_generator: code_generator
119
+ define_self_closing_element :polygon, code_generator: code_generator
120
+ define_self_closing_element :polyline, code_generator: code_generator
121
+ define_self_closing_element :rect, code_generator: code_generator
122
+ define_self_closing_element :set, code_generator: code_generator
123
+ define_self_closing_element :stop, code_generator: code_generator
124
+ define_self_closing_element :use, code_generator: code_generator
125
+ define_self_closing_element :view, code_generator: code_generator
126
+
127
+ define_element :a, code_generator: code_generator
128
+ define_element :abbr, code_generator: code_generator
129
+ define_element :address, code_generator: code_generator
130
+ define_element :article, code_generator: code_generator
131
+ define_element :aside, code_generator: code_generator
132
+ define_element :audio, code_generator: code_generator
133
+ define_element :b, code_generator: code_generator
134
+ define_element :bdi, code_generator: code_generator
135
+ define_element :bdo, code_generator: code_generator
136
+ define_element :blockquote, code_generator: code_generator
137
+ define_element :body, code_generator: code_generator
138
+ define_element :button, code_generator: code_generator
139
+ define_element :canvas, code_generator: code_generator
140
+ define_element :caption, code_generator: code_generator
141
+ define_element :cite, code_generator: code_generator
142
+ define_element :code, code_generator: code_generator
143
+ define_element :colgroup, code_generator: code_generator
144
+ define_element :data, code_generator: code_generator
145
+ define_element :datalist, code_generator: code_generator
146
+ define_element :dd, code_generator: code_generator
147
+ define_element :del, code_generator: code_generator
148
+ define_element :details, code_generator: code_generator
149
+ define_element :dfn, code_generator: code_generator
150
+ define_element :dialog, code_generator: code_generator
151
+ define_element :div, code_generator: code_generator
152
+ define_element :dl, code_generator: code_generator
153
+ define_element :dt, code_generator: code_generator
154
+ define_element :em, code_generator: code_generator
155
+ define_element :fieldset, code_generator: code_generator
156
+ define_element :figcaption, code_generator: code_generator
157
+ define_element :figure, code_generator: code_generator
158
+ define_element :footer, code_generator: code_generator
159
+ define_element :form, code_generator: code_generator
160
+ define_element :h1, code_generator: code_generator
161
+ define_element :h2, code_generator: code_generator
162
+ define_element :h3, code_generator: code_generator
163
+ define_element :h4, code_generator: code_generator
164
+ define_element :h5, code_generator: code_generator
165
+ define_element :h6, code_generator: code_generator
166
+ define_element :head, code_generator: code_generator
167
+ define_element :header, code_generator: code_generator
168
+ define_element :hgroup, code_generator: code_generator
169
+ define_element :html, code_generator: code_generator
170
+ define_element :i, code_generator: code_generator
171
+ define_element :iframe, code_generator: code_generator
172
+ define_element :ins, code_generator: code_generator
173
+ define_element :kbd, code_generator: code_generator
174
+ define_element :label, code_generator: code_generator
175
+ define_element :legend, code_generator: code_generator
176
+ define_element :li, code_generator: code_generator
177
+ define_element :main, code_generator: code_generator
178
+ define_element :map, code_generator: code_generator
179
+ define_element :mark, code_generator: code_generator
180
+ define_element :menu, code_generator: code_generator
181
+ define_element :meter, code_generator: code_generator
182
+ define_element :nav, code_generator: code_generator
183
+ define_element :noscript, code_generator: code_generator
184
+ define_element :object, code_generator: code_generator
185
+ define_element :ol, code_generator: code_generator
186
+ define_element :optgroup, code_generator: code_generator
187
+ define_element :option, code_generator: code_generator
188
+ define_element :output, code_generator: code_generator
189
+ define_element :p, code_generator: code_generator
190
+ define_element :picture, code_generator: code_generator
191
+ define_element :portal, code_generator: code_generator
192
+ define_element :pre, code_generator: code_generator
193
+ define_element :progress, code_generator: code_generator
194
+ define_element :q, code_generator: code_generator
195
+ define_element :rp, code_generator: code_generator
196
+ define_element :rt, code_generator: code_generator
197
+ define_element :ruby, code_generator: code_generator
198
+ define_element :s, code_generator: code_generator
199
+ define_element :samp, code_generator: code_generator
200
+ define_element :script, code_generator: code_generator
201
+ define_element :search, code_generator: code_generator
202
+ define_element :section, code_generator: code_generator
203
+ define_element :select, code_generator: code_generator
204
+ define_element :slot, code_generator: code_generator
205
+ define_element :small, code_generator: code_generator
206
+ define_element :span, code_generator: code_generator
207
+ define_element :strong, code_generator: code_generator
208
+ define_element :style, code_generator: code_generator
209
+ define_element :sub, code_generator: code_generator
210
+ define_element :summary, code_generator: code_generator
211
+ define_element :sup, code_generator: code_generator
212
+ define_element :table, code_generator: code_generator
213
+ define_element :tbody, code_generator: code_generator
214
+ define_element :td, code_generator: code_generator
215
+ define_element :template, code_generator: code_generator
216
+ define_element :textarea, code_generator: code_generator
217
+ define_element :tfoot, code_generator: code_generator
218
+ define_element :th, code_generator: code_generator
219
+ define_element :thead, code_generator: code_generator
220
+ define_element :time, code_generator: code_generator
221
+ define_element :title, code_generator: code_generator
222
+ define_element :tr, code_generator: code_generator
223
+ define_element :u, code_generator: code_generator
224
+ define_element :ul, code_generator: code_generator
225
+ define_element :var, code_generator: code_generator
226
+ define_element :video, code_generator: code_generator
227
+ end
51
228
 
52
229
  def initialize(view_context)
53
230
  @view_context = view_context
@@ -62,28 +239,22 @@ module ActionView
62
239
  tag_options(attributes.to_h).to_s.strip.html_safe
63
240
  end
64
241
 
65
- def p(*arguments, **options, &block)
66
- tag_string(:p, *arguments, **options, &block)
242
+ def tag_string(name, content = nil, options, escape: true, &block)
243
+ content = @view_context.capture(self, &block) if block
244
+
245
+ content_tag_string(name, content, options, escape)
67
246
  end
68
247
 
69
- def tag_string(name, content = nil, escape: true, **options, &block)
70
- content = @view_context.capture(self, &block) if block_given?
71
- self_closing = SVG_SELF_CLOSING_ELEMENTS.include?(name)
72
- if (HTML_VOID_ELEMENTS.include?(name) || self_closing) && content.nil?
73
- "<#{name.to_s.dasherize}#{tag_options(options, escape)}#{self_closing ? " />" : ">"}".html_safe
74
- else
75
- content_tag_string(name.to_s.dasherize, content || "", options, escape)
76
- end
248
+ def self_closing_tag_string(name, options, escape = true, tag_suffix = " />")
249
+ "<#{name}#{tag_options(options, escape)}#{tag_suffix}".html_safe
77
250
  end
78
251
 
79
252
  def content_tag_string(name, content, options, escape = true)
80
253
  tag_options = tag_options(options, escape) if options
81
254
 
82
- if escape
83
- name = ERB::Util.xml_name_escape(name)
255
+ if escape && content.present?
84
256
  content = ERB::Util.unwrapped_html_escape(content)
85
257
  end
86
-
87
258
  "<#{name}#{tag_options}>#{PRE_CONTENT_STRINGS[name]}#{content}</#{name}>".html_safe
88
259
  end
89
260
 
@@ -163,8 +334,12 @@ module ActionView
163
334
  true
164
335
  end
165
336
 
166
- def method_missing(called, *args, **options, &block)
167
- tag_string(called, *args, **options, &block)
337
+ def method_missing(called, *args, escape: true, **options, &block)
338
+ name = called.name.dasherize
339
+
340
+ TagHelper.ensure_valid_html5_tag_name(name)
341
+
342
+ tag_string(name, *args, options, escape: escape, &block)
168
343
  end
169
344
  end
170
345
 
@@ -245,6 +420,14 @@ module ActionView
245
420
  # # A void element:
246
421
  # tag.br # => <br>
247
422
  #
423
+ # Note that when using the block form options should be wrapped in
424
+ # parenthesis.
425
+ #
426
+ # <%= tag.a(href: "/about", class: "font-bold") do %>
427
+ # About the author
428
+ # <% end %>
429
+ # # => <a href="/about" class="font-bold">About the author</a>
430
+ #
248
431
  # === Building HTML attributes
249
432
  #
250
433
  # Transforms a Hash into HTML attributes, ready to be interpolated into
@@ -310,7 +493,7 @@ module ActionView
310
493
  if name.nil?
311
494
  tag_builder
312
495
  else
313
- name = ERB::Util.xml_name_escape(name) if escape
496
+ ensure_valid_html5_tag_name(name)
314
497
  "<#{name}#{tag_builder.tag_options(options, escape) if options}#{open ? ">" : " />"}".html_safe
315
498
  end
316
499
  end
@@ -344,6 +527,8 @@ module ActionView
344
527
  # <% end -%>
345
528
  # # => <div class="strong">Hello world!</div>
346
529
  def content_tag(name, content_or_options_with_block = nil, options = nil, escape = true, &block)
530
+ ensure_valid_html5_tag_name(name)
531
+
347
532
  if block_given?
348
533
  options = content_or_options_with_block if content_or_options_with_block.is_a?(Hash)
349
534
  tag_builder.content_tag_string(name, capture(&block), options, escape)
@@ -400,6 +585,11 @@ module ActionView
400
585
  end
401
586
 
402
587
  private
588
+ def ensure_valid_html5_tag_name(name)
589
+ raise ArgumentError, "Invalid HTML5 tag name: #{name.inspect}" unless /\A[a-zA-Z][^\s\/>]*\z/.match?(name)
590
+ end
591
+ module_function :ensure_valid_html5_tag_name
592
+
403
593
  def build_tag_values(*args)
404
594
  tag_values = []
405
595
 
@@ -166,7 +166,7 @@ module ActionView
166
166
  # highlight('You searched for: rails', 'rails', highlighter: '<a href="search?q=\1">\1</a>')
167
167
  # # => "You searched for: <a href=\"search?q=rails\">rails</a>"
168
168
  #
169
- # highlight('You searched for: rails', 'rails') { |match| link_to(search_path(q: match, match)) }
169
+ # highlight('You searched for: rails', 'rails') { |match| link_to(search_path(q: match)) }
170
170
  # # => "You searched for: <a href=\"search?q=rails\">rails</a>"
171
171
  #
172
172
  # highlight('<a href="javascript:alert(\'no!\')">ruby</a> on rails', 'rails', sanitize: false)
@@ -195,42 +195,6 @@ module ActionView
195
195
  # link_to "Visit Other Site", "https://rubyonrails.org/", data: { turbo_confirm: "Are you sure?" }
196
196
  # # => <a href="https://rubyonrails.org/" data-turbo-confirm="Are you sure?">Visit Other Site</a>
197
197
  #
198
- # ==== Deprecated: \Rails UJS Attributes
199
- #
200
- # Prior to \Rails 7, \Rails shipped with a JavaScript library called <tt>@rails/ujs</tt> on by default. Following \Rails 7,
201
- # this library is no longer on by default. This library integrated with the following options:
202
- #
203
- # * <tt>method: symbol of HTTP verb</tt> - This modifier will dynamically
204
- # create an HTML form and immediately submit the form for processing using
205
- # the HTTP verb specified. Useful for having links perform a POST operation
206
- # in dangerous actions like deleting a record (which search bots can follow
207
- # while spidering your site). Supported verbs are <tt>:post</tt>, <tt>:delete</tt>, <tt>:patch</tt>, and <tt>:put</tt>.
208
- # Note that if the user has JavaScript disabled, the request will fall back
209
- # to using GET. If <tt>href: '#'</tt> is used and the user has JavaScript
210
- # disabled clicking the link will have no effect. If you are relying on the
211
- # POST behavior, you should check for it in your controller's action by using
212
- # the request object's methods for <tt>post?</tt>, <tt>delete?</tt>, <tt>patch?</tt>, or <tt>put?</tt>.
213
- # * <tt>remote: true</tt> - This will allow <tt>@rails/ujs</tt>
214
- # to make an Ajax request to the URL in question instead of following
215
- # the link.
216
- #
217
- # <tt>@rails/ujs</tt> also integrated with the following +:data+ options:
218
- #
219
- # * <tt>confirm: "question?"</tt> - This will allow <tt>@rails/ujs</tt>
220
- # to prompt with the question specified (in this case, the
221
- # resulting text would be <tt>question?</tt>). If the user accepts, the
222
- # link is processed normally, otherwise no action is taken.
223
- # * <tt>:disable_with</tt> - Value of this parameter will be used as the
224
- # name for a disabled version of the link.
225
- #
226
- # ===== \Rails UJS Examples
227
- #
228
- # link_to "Remove Profile", profile_path(@profile), method: :delete
229
- # # => <a href="/profiles/1" rel="nofollow" data-method="delete">Remove Profile</a>
230
- #
231
- # link_to "Visit Other Site", "http://www.rubyonrails.org/", data: { confirm: "Are you sure?" }
232
- # # => <a href="http://www.rubyonrails.org/" data-confirm="Are you sure?">Visit Other Site</a>
233
- #
234
198
  def link_to(name = nil, options = nil, html_options = nil, &block)
235
199
  html_options, options, name = options, name, block if block_given?
236
200
  options ||= {}
@@ -256,8 +220,9 @@ module ActionView
256
220
  # +:form_class+ option within +html_options+. It defaults to
257
221
  # <tt>"button_to"</tt> to allow styling of the form and its children.
258
222
  #
259
- # The form submits a POST request by default. You can specify a different
260
- # HTTP verb via the +:method+ option within +html_options+.
223
+ # The form submits a POST request by default if the object is not persisted;
224
+ # conversely, if the object is persisted, it will submit a PATCH request.
225
+ # To specify a different HTTP verb use the +:method+ option within +html_options+.
261
226
  #
262
227
  # If the HTML button generated from +button_to+ does not work with your layout, you can
263
228
  # consider using the +link_to+ method with the +data-turbo-method+
@@ -328,32 +293,6 @@ module ActionView
328
293
  # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6" autocomplete="off"/>
329
294
  # # </form>"
330
295
  #
331
- # ==== Deprecated: \Rails UJS Attributes
332
- #
333
- # Prior to \Rails 7, \Rails shipped with a JavaScript library called <tt>@rails/ujs</tt> on by default. Following \Rails 7,
334
- # this library is no longer on by default. This library integrated with the following options:
335
- #
336
- # * <tt>:remote</tt> - If set to true, will allow <tt>@rails/ujs</tt> to control the
337
- # submit behavior. By default this behavior is an Ajax submit.
338
- #
339
- # <tt>@rails/ujs</tt> also integrated with the following +:data+ options:
340
- #
341
- # * <tt>confirm: "question?"</tt> - This will allow <tt>@rails/ujs</tt>
342
- # to prompt with the question specified (in this case, the
343
- # resulting text would be <tt>question?</tt>). If the user accepts, the
344
- # button is processed normally, otherwise no action is taken.
345
- # * <tt>:disable_with</tt> - Value of this parameter will be
346
- # used as the value for a disabled version of the submit
347
- # button when the form is submitted.
348
- #
349
- # ===== \Rails UJS Examples
350
- #
351
- # <%= button_to "Create", { action: "create" }, remote: true, form: { "data-type" => "json" } %>
352
- # # => "<form method="post" action="/images/create" class="button_to" data-remote="true" data-type="json">
353
- # # <button type="submit">Create</button>
354
- # # <input name="authenticity_token" type="hidden" value="10f2163b45388899ad4d5ae948988266befcb6c3d1b2451cf657a0c293d605a6" autocomplete="off"/>
355
- # # </form>"
356
- #
357
296
  def button_to(name = nil, options = nil, html_options = nil, &block)
358
297
  html_options, options = options, name if block_given?
359
298
  html_options ||= {}
@@ -638,19 +577,6 @@ module ActionView
638
577
  url_string == request_uri
639
578
  end
640
579
 
641
- if RUBY_VERSION.start_with?("2.7")
642
- using Module.new {
643
- refine UrlHelper do
644
- alias :_current_page? :current_page?
645
- end
646
- }
647
-
648
- def current_page?(*args) # :nodoc:
649
- options = args.pop
650
- options.is_a?(Hash) ? _current_page?(*args, **options) : _current_page?(*args, options)
651
- end
652
- end
653
-
654
580
  # Creates an SMS anchor link tag to the specified +phone_number+. When the
655
581
  # link is clicked, the default SMS messaging app is opened ready to send a
656
582
  # message to the linked phone number. If the +body+ option is specified,
@@ -209,11 +209,9 @@ module ActionView
209
209
 
210
210
  included do
211
211
  class_attribute :_layout, instance_accessor: false
212
- class_attribute :_layout_conditions, instance_accessor: false, default: {}
212
+ class_attribute :_layout_conditions, instance_accessor: false, instance_reader: true, default: {}
213
213
 
214
214
  _write_layout_method
215
-
216
- delegate :_layout_conditions, to: :class
217
215
  end
218
216
 
219
217
  module ClassMethods
@@ -430,7 +428,7 @@ module ActionView
430
428
  end
431
429
 
432
430
  def _include_layout?(options)
433
- (options.keys & [:body, :plain, :html, :inline, :partial]).empty? || options.key?(:layout)
431
+ !options.keys.intersect?([:body, :plain, :html, :inline, :partial]) || options.key?(:layout)
434
432
  end
435
433
  end
436
434
  end