actionview 7.0.8 → 7.1.0
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 +255 -346
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/app/assets/javascripts/rails-ujs.esm.js +668 -0
- data/app/assets/javascripts/rails-ujs.js +606 -0
- data/lib/action_view/base.rb +33 -12
- data/lib/action_view/buffers.rb +106 -8
- data/lib/action_view/cache_expiry.rb +40 -43
- data/lib/action_view/context.rb +1 -1
- data/lib/action_view/deprecator.rb +7 -0
- data/lib/action_view/digestor.rb +1 -1
- data/lib/action_view/gem_version.rb +3 -3
- data/lib/action_view/helpers/active_model_helper.rb +1 -1
- data/lib/action_view/helpers/asset_tag_helper.rb +130 -46
- data/lib/action_view/helpers/asset_url_helper.rb +6 -5
- data/lib/action_view/helpers/atom_feed_helper.rb +5 -5
- data/lib/action_view/helpers/cache_helper.rb +3 -9
- data/lib/action_view/helpers/capture_helper.rb +24 -10
- data/lib/action_view/helpers/content_exfiltration_prevention_helper.rb +70 -0
- data/lib/action_view/helpers/controller_helper.rb +6 -0
- data/lib/action_view/helpers/csp_helper.rb +2 -2
- data/lib/action_view/helpers/csrf_helper.rb +2 -2
- data/lib/action_view/helpers/date_helper.rb +17 -19
- data/lib/action_view/helpers/debug_helper.rb +3 -3
- data/lib/action_view/helpers/form_helper.rb +44 -19
- data/lib/action_view/helpers/form_options_helper.rb +2 -1
- data/lib/action_view/helpers/form_tag_helper.rb +43 -9
- data/lib/action_view/helpers/javascript_helper.rb +1 -0
- data/lib/action_view/helpers/number_helper.rb +2 -1
- data/lib/action_view/helpers/output_safety_helper.rb +2 -2
- data/lib/action_view/helpers/rendering_helper.rb +1 -1
- data/lib/action_view/helpers/sanitize_helper.rb +33 -14
- data/lib/action_view/helpers/tag_helper.rb +5 -27
- data/lib/action_view/helpers/tags/base.rb +11 -52
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +1 -0
- data/lib/action_view/helpers/tags/collection_radio_buttons.rb +1 -0
- data/lib/action_view/helpers/tags/collection_select.rb +3 -0
- data/lib/action_view/helpers/tags/date_field.rb +1 -1
- data/lib/action_view/helpers/tags/date_select.rb +2 -0
- data/lib/action_view/helpers/tags/datetime_field.rb +14 -6
- data/lib/action_view/helpers/tags/datetime_local_field.rb +11 -2
- data/lib/action_view/helpers/tags/grouped_collection_select.rb +3 -0
- data/lib/action_view/helpers/tags/month_field.rb +1 -1
- data/lib/action_view/helpers/tags/select.rb +3 -0
- data/lib/action_view/helpers/tags/select_renderer.rb +56 -0
- data/lib/action_view/helpers/tags/time_field.rb +1 -1
- data/lib/action_view/helpers/tags/time_zone_select.rb +3 -0
- data/lib/action_view/helpers/tags/week_field.rb +1 -1
- data/lib/action_view/helpers/tags/weekday_select.rb +3 -0
- data/lib/action_view/helpers/tags.rb +2 -0
- data/lib/action_view/helpers/text_helper.rb +32 -16
- data/lib/action_view/helpers/translation_helper.rb +3 -3
- data/lib/action_view/helpers/url_helper.rb +41 -14
- data/lib/action_view/helpers.rb +2 -0
- data/lib/action_view/layouts.rb +6 -4
- data/lib/action_view/log_subscriber.rb +49 -32
- data/lib/action_view/lookup_context.rb +29 -13
- data/lib/action_view/path_registry.rb +57 -0
- data/lib/action_view/path_set.rb +13 -14
- data/lib/action_view/railtie.rb +26 -3
- data/lib/action_view/record_identifier.rb +15 -8
- data/lib/action_view/renderer/abstract_renderer.rb +1 -1
- data/lib/action_view/renderer/collection_renderer.rb +9 -1
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +2 -1
- data/lib/action_view/renderer/partial_renderer.rb +2 -1
- data/lib/action_view/renderer/renderer.rb +2 -0
- data/lib/action_view/renderer/streaming_template_renderer.rb +3 -2
- data/lib/action_view/renderer/template_renderer.rb +3 -2
- data/lib/action_view/rendering.rb +22 -4
- data/lib/action_view/ripper_ast_parser.rb +6 -6
- data/lib/action_view/template/error.rb +14 -1
- data/lib/action_view/template/handlers/builder.rb +4 -4
- data/lib/action_view/template/handlers/erb/erubi.rb +23 -27
- data/lib/action_view/template/handlers/erb.rb +73 -1
- data/lib/action_view/template/handlers.rb +1 -1
- data/lib/action_view/template/html.rb +1 -1
- data/lib/action_view/template/raw_file.rb +1 -1
- data/lib/action_view/template/renderable.rb +1 -1
- data/lib/action_view/template/resolver.rb +10 -2
- data/lib/action_view/template/text.rb +1 -1
- data/lib/action_view/template/types.rb +25 -34
- data/lib/action_view/template.rb +227 -53
- data/lib/action_view/template_path.rb +2 -0
- data/lib/action_view/test_case.rb +174 -21
- data/lib/action_view/unbound_template.rb +15 -5
- data/lib/action_view/version.rb +1 -1
- data/lib/action_view/view_paths.rb +15 -24
- data/lib/action_view.rb +4 -1
- metadata +23 -23
|
@@ -7,8 +7,9 @@ require "action_view/helpers/capture_helper"
|
|
|
7
7
|
require "action_view/helpers/output_safety_helper"
|
|
8
8
|
|
|
9
9
|
module ActionView
|
|
10
|
-
# = Action View Tag Helpers
|
|
11
10
|
module Helpers # :nodoc:
|
|
11
|
+
# = Action View Tag \Helpers
|
|
12
|
+
#
|
|
12
13
|
# Provides methods to generate HTML tags programmatically both as a modern
|
|
13
14
|
# HTML5 compliant builder style and legacy XHTML compliant tags.
|
|
14
15
|
module TagHelper
|
|
@@ -65,9 +66,7 @@ module ActionView
|
|
|
65
66
|
tag_string(:p, *arguments, **options, &block)
|
|
66
67
|
end
|
|
67
68
|
|
|
68
|
-
def tag_string(name, content = nil, **options, &block)
|
|
69
|
-
escape = handle_deprecated_escape_options(options)
|
|
70
|
-
|
|
69
|
+
def tag_string(name, content = nil, escape: true, **options, &block)
|
|
71
70
|
content = @view_context.capture(self, &block) if block_given?
|
|
72
71
|
self_closing = SVG_SELF_CLOSING_ELEMENTS.include?(name)
|
|
73
72
|
if (HTML_VOID_ELEMENTS.include?(name) || self_closing) && content.nil?
|
|
@@ -164,27 +163,6 @@ module ActionView
|
|
|
164
163
|
true
|
|
165
164
|
end
|
|
166
165
|
|
|
167
|
-
def handle_deprecated_escape_options(options)
|
|
168
|
-
# The option :escape_attributes has been merged into the options hash to be
|
|
169
|
-
# able to warn when it is used, so we need to handle default values here.
|
|
170
|
-
escape_option_provided = options.has_key?(:escape)
|
|
171
|
-
escape_attributes_option_provided = options.has_key?(:escape_attributes)
|
|
172
|
-
|
|
173
|
-
if escape_attributes_option_provided
|
|
174
|
-
ActiveSupport::Deprecation.warn(<<~MSG)
|
|
175
|
-
Use of the option :escape_attributes is deprecated. It currently \
|
|
176
|
-
escapes both names and values of tags and attributes and it is \
|
|
177
|
-
equivalent to :escape. If any of them are enabled, the escaping \
|
|
178
|
-
is fully enabled.
|
|
179
|
-
MSG
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
return true unless escape_option_provided || escape_attributes_option_provided
|
|
183
|
-
escape_option = options.delete(:escape)
|
|
184
|
-
escape_attributes_option = options.delete(:escape_attributes)
|
|
185
|
-
escape_option || escape_attributes_option
|
|
186
|
-
end
|
|
187
|
-
|
|
188
166
|
def method_missing(called, *args, **options, &block)
|
|
189
167
|
tag_string(called, *args, **options, &block)
|
|
190
168
|
end
|
|
@@ -283,7 +261,7 @@ module ActionView
|
|
|
283
261
|
#
|
|
284
262
|
# === Legacy syntax
|
|
285
263
|
#
|
|
286
|
-
# The following format is for legacy syntax support. It will be deprecated in future versions of Rails.
|
|
264
|
+
# The following format is for legacy syntax support. It will be deprecated in future versions of \Rails.
|
|
287
265
|
#
|
|
288
266
|
# tag(name, options = nil, open = false, escape = true)
|
|
289
267
|
#
|
|
@@ -386,7 +364,7 @@ module ActionView
|
|
|
386
364
|
# token_list(nil, false, 123, "", "foo", { bar: true })
|
|
387
365
|
# # => "123 foo bar"
|
|
388
366
|
def token_list(*args)
|
|
389
|
-
tokens = build_tag_values(*args).flat_map { |value| value.to_s.split(/\s+/) }.uniq
|
|
367
|
+
tokens = build_tag_values(*args).flat_map { |value| CGI.unescape_html(value.to_s).split(/\s+/) }.uniq
|
|
390
368
|
|
|
391
369
|
safe_join(tokens, " ")
|
|
392
370
|
end
|
|
@@ -5,7 +5,6 @@ module ActionView
|
|
|
5
5
|
module Tags # :nodoc:
|
|
6
6
|
class Base # :nodoc:
|
|
7
7
|
include Helpers::ActiveModelInstanceTag, Helpers::TagHelper, Helpers::FormTagHelper
|
|
8
|
-
include FormOptionsHelper
|
|
9
8
|
|
|
10
9
|
attr_reader :object
|
|
11
10
|
|
|
@@ -35,22 +34,24 @@ module ActionView
|
|
|
35
34
|
|
|
36
35
|
private
|
|
37
36
|
def value
|
|
37
|
+
return unless object
|
|
38
|
+
|
|
38
39
|
if @allow_method_names_outside_object
|
|
39
|
-
object.public_send @method_name if object
|
|
40
|
+
object.public_send @method_name if object.respond_to?(@method_name)
|
|
40
41
|
else
|
|
41
|
-
object.public_send @method_name
|
|
42
|
+
object.public_send @method_name
|
|
42
43
|
end
|
|
43
44
|
end
|
|
44
45
|
|
|
45
46
|
def value_before_type_cast
|
|
46
|
-
unless object
|
|
47
|
-
method_before_type_cast = @method_name + "_before_type_cast"
|
|
47
|
+
return unless object
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
method_before_type_cast = @method_name + "_before_type_cast"
|
|
50
|
+
|
|
51
|
+
if value_came_from_user? && object.respond_to?(method_before_type_cast)
|
|
52
|
+
object.public_send(method_before_type_cast)
|
|
53
|
+
else
|
|
54
|
+
value
|
|
54
55
|
end
|
|
55
56
|
end
|
|
56
57
|
|
|
@@ -120,48 +121,6 @@ module ActionView
|
|
|
120
121
|
value.to_s.gsub(/[\s.]/, "_").gsub(/[^-[[:word:]]]/, "").downcase
|
|
121
122
|
end
|
|
122
123
|
|
|
123
|
-
def select_content_tag(option_tags, options, html_options)
|
|
124
|
-
html_options = html_options.stringify_keys
|
|
125
|
-
add_default_name_and_id(html_options)
|
|
126
|
-
|
|
127
|
-
if placeholder_required?(html_options)
|
|
128
|
-
raise ArgumentError, "include_blank cannot be false for a required field." if options[:include_blank] == false
|
|
129
|
-
options[:include_blank] ||= true unless options[:prompt]
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
value = options.fetch(:selected) { value() }
|
|
133
|
-
select = content_tag("select", add_options(option_tags, options, value), html_options)
|
|
134
|
-
|
|
135
|
-
if html_options["multiple"] && options.fetch(:include_hidden, true)
|
|
136
|
-
tag("input", disabled: html_options["disabled"], name: html_options["name"], type: "hidden", value: "", autocomplete: "off") + select
|
|
137
|
-
else
|
|
138
|
-
select
|
|
139
|
-
end
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
def placeholder_required?(html_options)
|
|
143
|
-
# See https://html.spec.whatwg.org/multipage/forms.html#attr-select-required
|
|
144
|
-
html_options["required"] && !html_options["multiple"] && html_options.fetch("size", 1).to_i == 1
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
def add_options(option_tags, options, value = nil)
|
|
148
|
-
if options[:include_blank]
|
|
149
|
-
content = (options[:include_blank] if options[:include_blank].is_a?(String))
|
|
150
|
-
label = (" " unless content)
|
|
151
|
-
option_tags = tag_builder.content_tag_string("option", content, value: "", label: label) + "\n" + option_tags
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
if value.blank? && options[:prompt]
|
|
155
|
-
tag_options = { value: "" }.tap do |prompt_opts|
|
|
156
|
-
prompt_opts[:disabled] = true if options[:disabled] == ""
|
|
157
|
-
prompt_opts[:selected] = true if options[:selected] == ""
|
|
158
|
-
end
|
|
159
|
-
option_tags = tag_builder.content_tag_string("option", prompt_text(options[:prompt]), tag_options) + "\n" + option_tags
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
option_tags
|
|
163
|
-
end
|
|
164
|
-
|
|
165
124
|
def name_and_id_index(options)
|
|
166
125
|
if options.key?("index")
|
|
167
126
|
options.delete("index") || ""
|
|
@@ -4,6 +4,9 @@ module ActionView
|
|
|
4
4
|
module Helpers
|
|
5
5
|
module Tags # :nodoc:
|
|
6
6
|
class CollectionSelect < Base # :nodoc:
|
|
7
|
+
include SelectRenderer
|
|
8
|
+
include FormOptionsHelper
|
|
9
|
+
|
|
7
10
|
def initialize(object_name, method_name, template_object, collection, value_method, text_method, options, html_options)
|
|
8
11
|
@collection = collection
|
|
9
12
|
@value_method = value_method
|
|
@@ -6,20 +6,28 @@ module ActionView
|
|
|
6
6
|
class DatetimeField < TextField # :nodoc:
|
|
7
7
|
def render
|
|
8
8
|
options = @options.stringify_keys
|
|
9
|
-
options["value"]
|
|
10
|
-
options["min"] =
|
|
11
|
-
options["max"] =
|
|
9
|
+
options["value"] = datetime_value(options["value"] || value)
|
|
10
|
+
options["min"] = format_datetime(parse_datetime(options["min"]))
|
|
11
|
+
options["max"] = format_datetime(parse_datetime(options["max"]))
|
|
12
12
|
@options = options
|
|
13
13
|
super
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
private
|
|
17
|
-
def
|
|
17
|
+
def datetime_value(value)
|
|
18
|
+
if value.is_a?(String)
|
|
19
|
+
value
|
|
20
|
+
else
|
|
21
|
+
format_datetime(value)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def format_datetime(value)
|
|
18
26
|
raise NotImplementedError
|
|
19
27
|
end
|
|
20
28
|
|
|
21
|
-
def
|
|
22
|
-
if value.is_a?
|
|
29
|
+
def parse_datetime(value)
|
|
30
|
+
if value.is_a?(String)
|
|
23
31
|
DateTime.parse(value) rescue nil
|
|
24
32
|
else
|
|
25
33
|
value
|
|
@@ -4,6 +4,11 @@ module ActionView
|
|
|
4
4
|
module Helpers
|
|
5
5
|
module Tags # :nodoc:
|
|
6
6
|
class DatetimeLocalField < DatetimeField # :nodoc:
|
|
7
|
+
def initialize(object_name, method_name, template_object, options = {})
|
|
8
|
+
@include_seconds = options.delete(:include_seconds) { true }
|
|
9
|
+
super
|
|
10
|
+
end
|
|
11
|
+
|
|
7
12
|
class << self
|
|
8
13
|
def field_type
|
|
9
14
|
@field_type ||= "datetime-local"
|
|
@@ -11,8 +16,12 @@ module ActionView
|
|
|
11
16
|
end
|
|
12
17
|
|
|
13
18
|
private
|
|
14
|
-
def
|
|
15
|
-
|
|
19
|
+
def format_datetime(value)
|
|
20
|
+
if @include_seconds
|
|
21
|
+
value&.strftime("%Y-%m-%dT%T")
|
|
22
|
+
else
|
|
23
|
+
value&.strftime("%Y-%m-%dT%H:%M")
|
|
24
|
+
end
|
|
16
25
|
end
|
|
17
26
|
end
|
|
18
27
|
end
|
|
@@ -4,6 +4,9 @@ module ActionView
|
|
|
4
4
|
module Helpers
|
|
5
5
|
module Tags # :nodoc:
|
|
6
6
|
class GroupedCollectionSelect < Base # :nodoc:
|
|
7
|
+
include SelectRenderer
|
|
8
|
+
include FormOptionsHelper
|
|
9
|
+
|
|
7
10
|
def initialize(object_name, method_name, template_object, collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options)
|
|
8
11
|
@collection = collection
|
|
9
12
|
@group_method = group_method
|
|
@@ -4,6 +4,9 @@ module ActionView
|
|
|
4
4
|
module Helpers
|
|
5
5
|
module Tags # :nodoc:
|
|
6
6
|
class Select < Base # :nodoc:
|
|
7
|
+
include SelectRenderer
|
|
8
|
+
include FormOptionsHelper
|
|
9
|
+
|
|
7
10
|
def initialize(object_name, method_name, template_object, choices, options, html_options)
|
|
8
11
|
@choices = block_given? ? template_object.capture { yield || "" } : choices
|
|
9
12
|
@choices = @choices.to_a if @choices.is_a?(Range)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActionView
|
|
4
|
+
module Helpers
|
|
5
|
+
module Tags # :nodoc:
|
|
6
|
+
module SelectRenderer # :nodoc:
|
|
7
|
+
private
|
|
8
|
+
def select_content_tag(option_tags, options, html_options)
|
|
9
|
+
html_options = html_options.stringify_keys
|
|
10
|
+
[:required, :multiple, :size].each do |prop|
|
|
11
|
+
html_options[prop.to_s] = options.delete(prop) if options.key?(prop) && !html_options.key?(prop.to_s)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
add_default_name_and_id(html_options)
|
|
15
|
+
|
|
16
|
+
if placeholder_required?(html_options)
|
|
17
|
+
raise ArgumentError, "include_blank cannot be false for a required field." if options[:include_blank] == false
|
|
18
|
+
options[:include_blank] ||= true unless options[:prompt]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
value = options.fetch(:selected) { value() }
|
|
22
|
+
select = content_tag("select", add_options(option_tags, options, value), html_options)
|
|
23
|
+
|
|
24
|
+
if html_options["multiple"] && options.fetch(:include_hidden, true)
|
|
25
|
+
tag("input", disabled: html_options["disabled"], name: html_options["name"], type: "hidden", value: "", autocomplete: "off") + select
|
|
26
|
+
else
|
|
27
|
+
select
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def placeholder_required?(html_options)
|
|
32
|
+
# See https://html.spec.whatwg.org/multipage/forms.html#attr-select-required
|
|
33
|
+
html_options["required"] && !html_options["multiple"] && html_options.fetch("size", 1).to_i == 1
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def add_options(option_tags, options, value = nil)
|
|
37
|
+
if options[:include_blank]
|
|
38
|
+
content = (options[:include_blank] if options[:include_blank].is_a?(String))
|
|
39
|
+
label = (" " unless content)
|
|
40
|
+
option_tags = tag_builder.content_tag_string("option", content, value: "", label: label) + "\n" + option_tags
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
if value.blank? && options[:prompt]
|
|
44
|
+
tag_options = { value: "" }.tap do |prompt_opts|
|
|
45
|
+
prompt_opts[:disabled] = true if options[:disabled] == ""
|
|
46
|
+
prompt_opts[:selected] = true if options[:selected] == ""
|
|
47
|
+
end
|
|
48
|
+
option_tags = tag_builder.content_tag_string("option", prompt_text(options[:prompt]), tag_options) + "\n" + option_tags
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
option_tags
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -4,6 +4,9 @@ module ActionView
|
|
|
4
4
|
module Helpers
|
|
5
5
|
module Tags # :nodoc:
|
|
6
6
|
class TimeZoneSelect < Base # :nodoc:
|
|
7
|
+
include SelectRenderer
|
|
8
|
+
include FormOptionsHelper
|
|
9
|
+
|
|
7
10
|
def initialize(object_name, method_name, template_object, priority_zones, options, html_options)
|
|
8
11
|
@priority_zones = priority_zones
|
|
9
12
|
@html_options = html_options
|
|
@@ -4,6 +4,9 @@ module ActionView
|
|
|
4
4
|
module Helpers
|
|
5
5
|
module Tags # :nodoc:
|
|
6
6
|
class WeekdaySelect < Base # :nodoc:
|
|
7
|
+
include SelectRenderer
|
|
8
|
+
include FormOptionsHelper
|
|
9
|
+
|
|
7
10
|
def initialize(object_name, method_name, template_object, options, html_options)
|
|
8
11
|
@html_options = html_options
|
|
9
12
|
|
|
@@ -8,8 +8,9 @@ require "action_view/helpers/tag_helper"
|
|
|
8
8
|
require "action_view/helpers/output_safety_helper"
|
|
9
9
|
|
|
10
10
|
module ActionView
|
|
11
|
-
# = Action View Text Helpers
|
|
12
11
|
module Helpers # :nodoc:
|
|
12
|
+
# = Action View Text \Helpers
|
|
13
|
+
#
|
|
13
14
|
# The TextHelper module provides a set of methods for filtering, formatting
|
|
14
15
|
# and transforming strings, which can reduce the amount of inline Ruby code in
|
|
15
16
|
# your views. These helper methods extend Action View making them callable
|
|
@@ -139,16 +140,19 @@ module ActionView
|
|
|
139
140
|
if text.blank? || phrases.blank?
|
|
140
141
|
text || ""
|
|
141
142
|
else
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
143
|
+
patterns = Array(phrases).map { |phrase| Regexp === phrase ? phrase : Regexp.escape(phrase) }
|
|
144
|
+
pattern = /(#{patterns.join("|")})/i
|
|
145
|
+
highlighter = options.fetch(:highlighter, '<mark>\1</mark>') unless block
|
|
146
|
+
|
|
147
|
+
text.scan(/<[^>]*|[^<]+/).each do |segment|
|
|
148
|
+
if !segment.start_with?("<")
|
|
149
|
+
if block
|
|
150
|
+
segment.gsub!(pattern, &block)
|
|
151
|
+
else
|
|
152
|
+
segment.gsub!(pattern, highlighter)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end.join
|
|
152
156
|
end.html_safe
|
|
153
157
|
end
|
|
154
158
|
|
|
@@ -262,9 +266,17 @@ module ActionView
|
|
|
262
266
|
# word_wrap('Once upon a time', line_width: 1, break_sequence: "\r\n")
|
|
263
267
|
# # => Once\r\nupon\r\na\r\ntime
|
|
264
268
|
def word_wrap(text, line_width: 80, break_sequence: "\n")
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
end
|
|
269
|
+
# Match up to `line_width` characters, followed by one of
|
|
270
|
+
# (1) non-newline whitespace plus an optional newline
|
|
271
|
+
# (2) the end of the string, ignoring any trailing newlines
|
|
272
|
+
# (3) a newline
|
|
273
|
+
#
|
|
274
|
+
# -OR-
|
|
275
|
+
#
|
|
276
|
+
# Match an empty line
|
|
277
|
+
pattern = /(.{1,#{line_width}})(?:[^\S\n]+\n?|\n*\Z|\n)|\n/
|
|
278
|
+
|
|
279
|
+
text.gsub(pattern, "\\1#{break_sequence}").chomp!(break_sequence)
|
|
268
280
|
end
|
|
269
281
|
|
|
270
282
|
# Returns +text+ transformed into HTML using simple formatting rules.
|
|
@@ -279,6 +291,7 @@ module ActionView
|
|
|
279
291
|
#
|
|
280
292
|
# ==== Options
|
|
281
293
|
# * <tt>:sanitize</tt> - If +false+, does not sanitize +text+.
|
|
294
|
+
# * <tt>:sanitize_options</tt> - Any extra options you want appended to the sanitize.
|
|
282
295
|
# * <tt>:wrapper_tag</tt> - String representing the wrapper tag, defaults to <tt>"p"</tt>
|
|
283
296
|
#
|
|
284
297
|
# ==== Examples
|
|
@@ -303,10 +316,13 @@ module ActionView
|
|
|
303
316
|
#
|
|
304
317
|
# simple_format("<blink>Blinkable!</blink> It's true.", {}, sanitize: false)
|
|
305
318
|
# # => "<p><blink>Blinkable!</blink> It's true.</p>"
|
|
319
|
+
#
|
|
320
|
+
# simple_format("<a target=\"_blank\" href=\"http://example.com\">Continue</a>", {}, { sanitize_options: { attributes: %w[target href] } })
|
|
321
|
+
# # => "<p><a target=\"_blank\" href=\"http://example.com\">Continue</a></p>"
|
|
306
322
|
def simple_format(text, html_options = {}, options = {})
|
|
307
|
-
wrapper_tag = options
|
|
323
|
+
wrapper_tag = options[:wrapper_tag] || "p"
|
|
308
324
|
|
|
309
|
-
text = sanitize(text) if options.fetch(:sanitize, true)
|
|
325
|
+
text = sanitize(text, options.fetch(:sanitize_options, {})) if options.fetch(:sanitize, true)
|
|
310
326
|
paragraphs = split_paragraphs(text)
|
|
311
327
|
|
|
312
328
|
if paragraphs.empty?
|
|
@@ -4,14 +4,14 @@ require "action_view/helpers/tag_helper"
|
|
|
4
4
|
require "active_support/html_safe_translation"
|
|
5
5
|
|
|
6
6
|
module ActionView
|
|
7
|
-
# = Action View Translation Helpers
|
|
8
7
|
module Helpers # :nodoc:
|
|
8
|
+
# = Action View Translation \Helpers
|
|
9
9
|
module TranslationHelper
|
|
10
10
|
extend ActiveSupport::Concern
|
|
11
11
|
|
|
12
12
|
include TagHelper
|
|
13
13
|
|
|
14
|
-
# Specify whether an error should be raised for missing translations
|
|
14
|
+
# Specify whether an error should be raised for missing translations.
|
|
15
15
|
singleton_class.attr_accessor :raise_on_missing_translations
|
|
16
16
|
|
|
17
17
|
included do
|
|
@@ -93,7 +93,7 @@ module ActionView
|
|
|
93
93
|
break translated unless translated == MISSING_TRANSLATION
|
|
94
94
|
|
|
95
95
|
if alternatives.present? && !alternatives.first.is_a?(Symbol)
|
|
96
|
-
break alternatives.first && I18n.translate(**options, default: alternatives)
|
|
96
|
+
break alternatives.first && I18n.translate(nil, **options, default: alternatives)
|
|
97
97
|
end
|
|
98
98
|
|
|
99
99
|
first_key ||= key
|