actionview 7.1.3.4 → 7.2.0.beta2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +43 -418
- data/lib/action_view/base.rb +20 -3
- data/lib/action_view/cache_expiry.rb +9 -3
- data/lib/action_view/dependency_tracker/{ripper_tracker.rb → ruby_tracker.rb} +4 -3
- data/lib/action_view/dependency_tracker.rb +1 -1
- data/lib/action_view/gem_version.rb +3 -3
- data/lib/action_view/helpers/asset_tag_helper.rb +18 -6
- data/lib/action_view/helpers/cache_helper.rb +4 -4
- data/lib/action_view/helpers/csrf_helper.rb +1 -1
- data/lib/action_view/helpers/form_helper.rb +197 -192
- data/lib/action_view/helpers/form_tag_helper.rb +76 -43
- data/lib/action_view/helpers/output_safety_helper.rb +4 -4
- data/lib/action_view/helpers/tag_helper.rb +208 -18
- data/lib/action_view/helpers/url_helper.rb +4 -78
- data/lib/action_view/layouts.rb +2 -4
- data/lib/action_view/log_subscriber.rb +8 -4
- data/lib/action_view/railtie.rb +0 -1
- data/lib/action_view/render_parser/prism_render_parser.rb +127 -0
- data/lib/action_view/{ripper_ast_parser.rb → render_parser/ripper_render_parser.rb} +152 -9
- data/lib/action_view/render_parser.rb +21 -169
- data/lib/action_view/renderer/abstract_renderer.rb +1 -1
- data/lib/action_view/renderer/renderer.rb +32 -38
- data/lib/action_view/rendering.rb +4 -4
- data/lib/action_view/template/renderable.rb +7 -1
- data/lib/action_view/template/resolver.rb +0 -2
- data/lib/action_view/template.rb +28 -4
- data/lib/action_view/test_case.rb +12 -14
- data/lib/action_view/unbound_template.rb +4 -4
- data/lib/action_view.rb +1 -1
- metadata +16 -15
@@ -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
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
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
|
#
|
@@ -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([
|
28
|
-
# # => "<p>foo</p><br
|
27
|
+
# safe_join([tag.p("foo"), "<p>bar</p>"], "<br>")
|
28
|
+
# # => "<p>foo</p><br><p>bar</p>"
|
29
29
|
#
|
30
|
-
# safe_join([
|
31
|
-
# # => "<p>foo</p><br
|
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
|
-
|
50
|
-
|
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
|
66
|
-
|
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
|
70
|
-
|
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
|
-
|
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
|
-
|
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
|
|
@@ -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
|
260
|
-
#
|
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 ||= {}
|
@@ -636,19 +575,6 @@ module ActionView
|
|
636
575
|
url_string == request_uri
|
637
576
|
end
|
638
577
|
|
639
|
-
if RUBY_VERSION.start_with?("2.7")
|
640
|
-
using Module.new {
|
641
|
-
refine UrlHelper do
|
642
|
-
alias :_current_page? :current_page?
|
643
|
-
end
|
644
|
-
}
|
645
|
-
|
646
|
-
def current_page?(*args) # :nodoc:
|
647
|
-
options = args.pop
|
648
|
-
options.is_a?(Hash) ? _current_page?(*args, **options) : _current_page?(*args, options)
|
649
|
-
end
|
650
|
-
end
|
651
|
-
|
652
578
|
# Creates an SMS anchor link tag to the specified +phone_number+. When the
|
653
579
|
# link is clicked, the default SMS messaging app is opened ready to send a
|
654
580
|
# message to the linked phone number. If the +body+ option is specified,
|
@@ -784,7 +710,7 @@ module ActionView
|
|
784
710
|
end
|
785
711
|
|
786
712
|
def add_method_to_attributes!(html_options, method)
|
787
|
-
if method_not_get_method?(method) && !html_options["rel"]&.
|
713
|
+
if method_not_get_method?(method) && !html_options["rel"]&.include?("nofollow")
|
788
714
|
if html_options["rel"].blank?
|
789
715
|
html_options["rel"] = "nofollow"
|
790
716
|
else
|
data/lib/action_view/layouts.rb
CHANGED
@@ -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
|
-
|
431
|
+
!options.keys.intersect?([:body, :plain, :html, :inline, :partial]) || options.key?(:layout)
|
434
432
|
end
|
435
433
|
end
|
436
434
|
end
|