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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +52 -435
- data/lib/action_view/base.rb +20 -2
- 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 +2 -2
- data/lib/action_view/helpers/asset_tag_helper.rb +15 -3
- 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 +80 -47
- 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/text_helper.rb +1 -1
- data/lib/action_view/helpers/url_helper.rb +3 -77
- 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 +36 -8
- data/lib/action_view/test_case.rb +7 -9
- metadata +14 -13
@@ -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
|
#
|
@@ -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', '
|
766
|
-
# # => <input id="date" name="date" type="date" value="
|
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', '
|
772
|
-
# # => <input disabled="disabled" class="special_input" id="date" name="date" type="date" value="
|
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([
|
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
|
|
@@ -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
|
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
|
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 ||= {}
|
@@ -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,
|
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
|