actionview 7.1.6 → 7.2.3
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 +99 -425
- data/README.rdoc +1 -1
- data/lib/action_view/base.rb +24 -9
- 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/digestor.rb +6 -2
- data/lib/action_view/gem_version.rb +2 -2
- data/lib/action_view/helpers/asset_tag_helper.rb +19 -7
- data/lib/action_view/helpers/atom_feed_helper.rb +1 -1
- data/lib/action_view/helpers/cache_helper.rb +2 -2
- data/lib/action_view/helpers/csrf_helper.rb +1 -1
- data/lib/action_view/helpers/form_helper.rb +222 -217
- data/lib/action_view/helpers/form_options_helper.rb +6 -3
- data/lib/action_view/helpers/form_tag_helper.rb +80 -47
- data/lib/action_view/helpers/output_safety_helper.rb +5 -6
- data/lib/action_view/helpers/tag_helper.rb +208 -18
- data/lib/action_view/helpers/tags/collection_helpers.rb +2 -1
- data/lib/action_view/helpers/text_helper.rb +11 -4
- data/lib/action_view/helpers/url_helper.rb +3 -77
- data/lib/action_view/layouts.rb +8 -10
- 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/partial_renderer.rb +2 -2
- data/lib/action_view/renderer/renderer.rb +32 -38
- data/lib/action_view/renderer/template_renderer.rb +3 -3
- data/lib/action_view/rendering.rb +4 -4
- data/lib/action_view/template/error.rb +11 -0
- data/lib/action_view/template/handlers/erb.rb +45 -37
- 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 -10
- data/lib/action_view.rb +1 -0
- metadata +14 -13
|
@@ -496,7 +496,8 @@ module ActionView
|
|
|
496
496
|
# <option value="France">France</option>
|
|
497
497
|
# </optgroup>
|
|
498
498
|
#
|
|
499
|
-
# Parameters
|
|
499
|
+
# ==== Parameters
|
|
500
|
+
#
|
|
500
501
|
# * +grouped_options+ - Accepts a nested array or hash of strings. The first value serves as the
|
|
501
502
|
# <tt><optgroup></tt> label while the second value must be an array of options. The second value can be a
|
|
502
503
|
# nested array of text-value pairs. See <tt>options_for_select</tt> for more info.
|
|
@@ -507,7 +508,8 @@ module ActionView
|
|
|
507
508
|
# which will have the +selected+ attribute set. Note: It is possible for this value to match multiple options
|
|
508
509
|
# as you might have the same option in multiple groups. Each will then get <tt>selected="selected"</tt>.
|
|
509
510
|
#
|
|
510
|
-
# Options
|
|
511
|
+
# ==== Options
|
|
512
|
+
#
|
|
511
513
|
# * <tt>:prompt</tt> - set to true or a prompt string. When the select element doesn't have a value yet, this
|
|
512
514
|
# prepends an option with a generic prompt - "Please select" - or the given prompt string.
|
|
513
515
|
# * <tt>:divider</tt> - the divider for the options groups.
|
|
@@ -599,7 +601,8 @@ module ActionView
|
|
|
599
601
|
|
|
600
602
|
# Returns a string of option tags for the days of the week.
|
|
601
603
|
#
|
|
602
|
-
# Options
|
|
604
|
+
# ====Options
|
|
605
|
+
#
|
|
603
606
|
# * <tt>:index_as_value</tt> - Defaults to false, set to true to use the indexes from
|
|
604
607
|
# <tt>I18n.translate("date.day_names")</tt> as the values. By default, Sunday is always 0.
|
|
605
608
|
# * <tt>:day_format</tt> - The I18n key of the array to use for the weekday options.
|
|
@@ -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)
|
|
@@ -38,8 +38,7 @@ module ActionView # :nodoc:
|
|
|
38
38
|
|
|
39
39
|
# Converts the array to a comma-separated sentence where the last element is
|
|
40
40
|
# joined by the connector word. This is the html_safe-aware version of
|
|
41
|
-
# ActiveSupport's
|
|
42
|
-
#
|
|
41
|
+
# ActiveSupport's Array#to_sentence.
|
|
43
42
|
def to_sentence(array, options = {})
|
|
44
43
|
options.assert_valid_keys(:words_connector, :two_words_connector, :last_word_connector, :locale)
|
|
45
44
|
|
|
@@ -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
|
|
|
@@ -106,7 +106,8 @@ module ActionView
|
|
|
106
106
|
|
|
107
107
|
def hidden_field
|
|
108
108
|
hidden_name = @html_options[:name] || hidden_field_name
|
|
109
|
-
|
|
109
|
+
options = { id: nil, form: @html_options[:form] }
|
|
110
|
+
@template_object.hidden_field_tag(hidden_name, "", options)
|
|
110
111
|
end
|
|
111
112
|
|
|
112
113
|
def hidden_field_name
|
|
@@ -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)
|
|
@@ -260,7 +260,14 @@ module ActionView
|
|
|
260
260
|
prefix, first_part = cut_excerpt_part(:first, first_part, separator, options)
|
|
261
261
|
postfix, second_part = cut_excerpt_part(:second, second_part, separator, options)
|
|
262
262
|
|
|
263
|
-
affix = [
|
|
263
|
+
affix = [
|
|
264
|
+
first_part,
|
|
265
|
+
!first_part.empty? ? separator : "",
|
|
266
|
+
phrase,
|
|
267
|
+
!second_part.empty? ? separator : "",
|
|
268
|
+
second_part
|
|
269
|
+
].join.strip
|
|
270
|
+
|
|
264
271
|
[prefix, affix, postfix].join
|
|
265
272
|
end
|
|
266
273
|
|
|
@@ -271,7 +278,7 @@ module ActionView
|
|
|
271
278
|
#
|
|
272
279
|
# The word will be pluralized using rules defined for the locale
|
|
273
280
|
# (you must define your own inflection rules for languages other than English).
|
|
274
|
-
# See ActiveSupport::Inflector.pluralize
|
|
281
|
+
# See ActiveSupport::Inflector.pluralize.
|
|
275
282
|
#
|
|
276
283
|
# pluralize(1, 'person')
|
|
277
284
|
# # => "1 person"
|
|
@@ -346,7 +353,7 @@ module ActionView
|
|
|
346
353
|
# ==== Options
|
|
347
354
|
# * <tt>:sanitize</tt> - If +false+, does not sanitize +text+.
|
|
348
355
|
# * <tt>:sanitize_options</tt> - Any extra options you want appended to the sanitize.
|
|
349
|
-
# * <tt>:wrapper_tag</tt> - String representing the wrapper tag, defaults to <tt>"p"</tt
|
|
356
|
+
# * <tt>:wrapper_tag</tt> - String representing the wrapper tag, defaults to <tt>"p"</tt>.
|
|
350
357
|
#
|
|
351
358
|
# ==== Examples
|
|
352
359
|
# my_text = "Here is some basic text...\n...with a line break."
|