actionview 4.2.10 → 5.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 +141 -272
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -3
- data/lib/action_view/base.rb +33 -21
- data/lib/action_view/buffers.rb +1 -1
- data/lib/action_view/context.rb +1 -1
- data/lib/action_view/dependency_tracker.rb +52 -20
- data/lib/action_view/digestor.rb +86 -83
- data/lib/action_view/flows.rb +9 -11
- data/lib/action_view/gem_version.rb +3 -3
- data/lib/action_view/helpers/active_model_helper.rb +8 -8
- data/lib/action_view/helpers/asset_tag_helper.rb +74 -38
- data/lib/action_view/helpers/asset_url_helper.rb +160 -59
- data/lib/action_view/helpers/atom_feed_helper.rb +16 -16
- data/lib/action_view/helpers/cache_helper.rb +90 -35
- data/lib/action_view/helpers/capture_helper.rb +7 -6
- data/lib/action_view/helpers/controller_helper.rb +3 -2
- data/lib/action_view/helpers/csrf_helper.rb +3 -3
- data/lib/action_view/helpers/date_helper.rb +156 -108
- data/lib/action_view/helpers/debug_helper.rb +3 -4
- data/lib/action_view/helpers/form_helper.rb +475 -94
- data/lib/action_view/helpers/form_options_helper.rb +87 -47
- data/lib/action_view/helpers/form_tag_helper.rb +88 -57
- data/lib/action_view/helpers/javascript_helper.rb +10 -10
- data/lib/action_view/helpers/number_helper.rb +76 -59
- data/lib/action_view/helpers/output_safety_helper.rb +34 -4
- data/lib/action_view/helpers/record_tag_helper.rb +12 -99
- data/lib/action_view/helpers/rendering_helper.rb +3 -3
- data/lib/action_view/helpers/sanitize_helper.rb +17 -14
- data/lib/action_view/helpers/tag_helper.rb +198 -73
- data/lib/action_view/helpers/tags/base.rb +132 -97
- data/lib/action_view/helpers/tags/check_box.rb +17 -17
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +9 -33
- data/lib/action_view/helpers/tags/collection_helpers.rb +68 -36
- data/lib/action_view/helpers/tags/collection_radio_buttons.rb +3 -11
- data/lib/action_view/helpers/tags/collection_select.rb +2 -2
- data/lib/action_view/helpers/tags/date_select.rb +36 -36
- data/lib/action_view/helpers/tags/datetime_field.rb +1 -1
- data/lib/action_view/helpers/tags/grouped_collection_select.rb +2 -2
- data/lib/action_view/helpers/tags/label.rb +5 -1
- data/lib/action_view/helpers/tags/password_field.rb +1 -1
- data/lib/action_view/helpers/tags/placeholderable.rb +1 -1
- data/lib/action_view/helpers/tags/radio_button.rb +4 -4
- data/lib/action_view/helpers/tags/search_field.rb +12 -9
- data/lib/action_view/helpers/tags/select.rb +9 -9
- data/lib/action_view/helpers/tags/text_area.rb +1 -1
- data/lib/action_view/helpers/tags/text_field.rb +5 -6
- data/lib/action_view/helpers/tags/translator.rb +15 -13
- data/lib/action_view/helpers/text_helper.rb +47 -30
- data/lib/action_view/helpers/translation_helper.rb +60 -30
- data/lib/action_view/helpers/url_helper.rb +132 -104
- data/lib/action_view/helpers.rb +1 -1
- data/lib/action_view/layouts.rb +59 -54
- data/lib/action_view/log_subscriber.rb +56 -7
- data/lib/action_view/lookup_context.rb +76 -61
- data/lib/action_view/model_naming.rb +1 -1
- data/lib/action_view/path_set.rb +28 -19
- data/lib/action_view/railtie.rb +30 -6
- data/lib/action_view/record_identifier.rb +51 -25
- data/lib/action_view/renderer/abstract_renderer.rb +19 -15
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +55 -0
- data/lib/action_view/renderer/partial_renderer.rb +208 -206
- data/lib/action_view/renderer/renderer.rb +2 -6
- data/lib/action_view/renderer/streaming_template_renderer.rb +46 -48
- data/lib/action_view/renderer/template_renderer.rb +65 -66
- data/lib/action_view/rendering.rb +16 -9
- data/lib/action_view/routing_url_for.rb +25 -17
- data/lib/action_view/tasks/cache_digests.rake +23 -0
- data/lib/action_view/template/error.rb +14 -13
- data/lib/action_view/template/handlers/builder.rb +7 -7
- data/lib/action_view/template/handlers/erb/deprecated_erubis.rb +9 -0
- data/lib/action_view/template/handlers/erb/erubi.rb +81 -0
- data/lib/action_view/template/handlers/erb/erubis.rb +81 -0
- data/lib/action_view/template/handlers/erb.rb +9 -76
- data/lib/action_view/template/handlers/html.rb +9 -0
- data/lib/action_view/template/handlers/raw.rb +1 -3
- data/lib/action_view/template/handlers.rb +8 -6
- data/lib/action_view/template/html.rb +2 -4
- data/lib/action_view/template/resolver.rb +133 -109
- data/lib/action_view/template/text.rb +5 -8
- data/lib/action_view/template/types.rb +15 -17
- data/lib/action_view/template.rb +51 -28
- data/lib/action_view/test_case.rb +32 -27
- data/lib/action_view/testing/resolvers.rb +29 -31
- data/lib/action_view/version.rb +1 -1
- data/lib/action_view/view_paths.rb +26 -32
- data/lib/action_view.rb +5 -5
- data/lib/assets/compiled/rails-ujs.js +685 -0
- metadata +23 -23
- data/lib/action_view/tasks/dependencies.rake +0 -23
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
require
|
|
2
|
-
require
|
|
1
|
+
require "active_support/core_ext/string/filters"
|
|
2
|
+
require "active_support/core_ext/array/extract_options"
|
|
3
3
|
|
|
4
4
|
module ActionView
|
|
5
5
|
# = Action View Text Helpers
|
|
@@ -103,7 +103,9 @@ module ActionView
|
|
|
103
103
|
# Highlights one or more +phrases+ everywhere in +text+ by inserting it into
|
|
104
104
|
# a <tt>:highlighter</tt> string. The highlighter can be specialized by passing <tt>:highlighter</tt>
|
|
105
105
|
# as a single-quoted string with <tt>\1</tt> where the phrase is to be inserted (defaults to
|
|
106
|
-
# '<mark>\1</mark>') or passing a block that receives each matched term.
|
|
106
|
+
# '<mark>\1</mark>') or passing a block that receives each matched term. By default +text+
|
|
107
|
+
# is sanitized to prevent possible XSS attacks. If the input is trustworthy, passing false
|
|
108
|
+
# for <tt>:sanitize</tt> will turn sanitizing off.
|
|
107
109
|
#
|
|
108
110
|
# highlight('You searched for: rails', 'rails')
|
|
109
111
|
# # => You searched for: <mark>rails</mark>
|
|
@@ -122,6 +124,9 @@ module ActionView
|
|
|
122
124
|
#
|
|
123
125
|
# highlight('You searched for: rails', 'rails') { |match| link_to(search_path(q: match, match)) }
|
|
124
126
|
# # => You searched for: <a href="search?q=rails">rails</a>
|
|
127
|
+
#
|
|
128
|
+
# highlight('<a href="javascript:alert(\'no!\')">ruby</a> on rails', 'rails', sanitize: false)
|
|
129
|
+
# # => "<a>ruby</a> on <mark>rails</mark>"
|
|
125
130
|
def highlight(text, phrases, options = {})
|
|
126
131
|
text = sanitize(text) if options.fetch(:sanitize, true)
|
|
127
132
|
|
|
@@ -130,7 +135,7 @@ module ActionView
|
|
|
130
135
|
else
|
|
131
136
|
match = Array(phrases).map do |p|
|
|
132
137
|
Regexp === p ? p.to_s : Regexp.escape(p)
|
|
133
|
-
end.join(
|
|
138
|
+
end.join("|")
|
|
134
139
|
|
|
135
140
|
if block_given?
|
|
136
141
|
text.gsub(/(#{match})(?![^<]*?>)/i) { |found| yield found }
|
|
@@ -146,7 +151,7 @@ module ActionView
|
|
|
146
151
|
# defined in <tt>:radius</tt> (which defaults to 100). If the excerpt radius overflows the beginning or end of the +text+,
|
|
147
152
|
# then the <tt>:omission</tt> option (which defaults to "...") will be prepended/appended accordingly. Use the
|
|
148
153
|
# <tt>:separator</tt> option to choose the delimitation. The resulting string will be stripped in any case. If the +phrase+
|
|
149
|
-
# isn't found, nil is returned.
|
|
154
|
+
# isn't found, +nil+ is returned.
|
|
150
155
|
#
|
|
151
156
|
# excerpt('This is an example', 'an', radius: 5)
|
|
152
157
|
# # => ...s is an exam...
|
|
@@ -182,7 +187,7 @@ module ActionView
|
|
|
182
187
|
unless separator.empty?
|
|
183
188
|
text.split(separator).each do |value|
|
|
184
189
|
if value.match(regex)
|
|
185
|
-
|
|
190
|
+
phrase = value
|
|
186
191
|
break
|
|
187
192
|
end
|
|
188
193
|
end
|
|
@@ -199,7 +204,12 @@ module ActionView
|
|
|
199
204
|
|
|
200
205
|
# Attempts to pluralize the +singular+ word unless +count+ is 1. If
|
|
201
206
|
# +plural+ is supplied, it will use that when count is > 1, otherwise
|
|
202
|
-
# it will use the Inflector to determine the plural form
|
|
207
|
+
# it will use the Inflector to determine the plural form for the given locale,
|
|
208
|
+
# which defaults to I18n.locale
|
|
209
|
+
#
|
|
210
|
+
# The word will be pluralized using rules defined for the locale
|
|
211
|
+
# (you must define your own inflection rules for languages other than English).
|
|
212
|
+
# See ActiveSupport::Inflector.pluralize
|
|
203
213
|
#
|
|
204
214
|
# pluralize(1, 'person')
|
|
205
215
|
# # => 1 person
|
|
@@ -207,16 +217,19 @@ module ActionView
|
|
|
207
217
|
# pluralize(2, 'person')
|
|
208
218
|
# # => 2 people
|
|
209
219
|
#
|
|
210
|
-
# pluralize(3, 'person', 'users')
|
|
220
|
+
# pluralize(3, 'person', plural: 'users')
|
|
211
221
|
# # => 3 users
|
|
212
222
|
#
|
|
213
223
|
# pluralize(0, 'person')
|
|
214
224
|
# # => 0 people
|
|
215
|
-
|
|
225
|
+
#
|
|
226
|
+
# pluralize(2, 'Person', locale: :de)
|
|
227
|
+
# # => 2 Personen
|
|
228
|
+
def pluralize(count, singular, plural_arg = nil, plural: plural_arg, locale: I18n.locale)
|
|
216
229
|
word = if (count == 1 || count =~ /^1(\.0+)?$/)
|
|
217
230
|
singular
|
|
218
231
|
else
|
|
219
|
-
plural || singular.pluralize
|
|
232
|
+
plural || singular.pluralize(locale)
|
|
220
233
|
end
|
|
221
234
|
|
|
222
235
|
"#{count || 0} #{word}"
|
|
@@ -237,19 +250,23 @@ module ActionView
|
|
|
237
250
|
#
|
|
238
251
|
# word_wrap('Once upon a time', line_width: 1)
|
|
239
252
|
# # => Once\nupon\na\ntime
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
253
|
+
#
|
|
254
|
+
# You can also specify a custom +break_sequence+ ("\n" by default)
|
|
255
|
+
#
|
|
256
|
+
# word_wrap('Once upon a time', line_width: 1, break_sequence: "\r\n")
|
|
257
|
+
# # => Once\r\nupon\r\na\r\ntime
|
|
258
|
+
def word_wrap(text, line_width: 80, break_sequence: "\n")
|
|
243
259
|
text.split("\n").collect! do |line|
|
|
244
|
-
line.length > line_width ? line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1
|
|
245
|
-
end *
|
|
260
|
+
line.length > line_width ? line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1#{break_sequence}").strip : line
|
|
261
|
+
end * break_sequence
|
|
246
262
|
end
|
|
247
263
|
|
|
248
264
|
# Returns +text+ transformed into HTML using simple formatting rules.
|
|
249
|
-
# Two or more consecutive newlines(<tt>\n\n</tt>) are
|
|
250
|
-
# paragraph and wrapped in <tt><p></tt> tags. One newline
|
|
251
|
-
#
|
|
252
|
-
# method does not remove the
|
|
265
|
+
# Two or more consecutive newlines(<tt>\n\n</tt> or <tt>\r\n\r\n</tt>) are
|
|
266
|
+
# considered a paragraph and wrapped in <tt><p></tt> tags. One newline
|
|
267
|
+
# (<tt>\n</tt> or <tt>\r\n</tt>) is considered a linebreak and a
|
|
268
|
+
# <tt><br /></tt> tag is appended. This method does not remove the
|
|
269
|
+
# newlines from the +text+.
|
|
253
270
|
#
|
|
254
271
|
# You can pass any HTML attributes into <tt>html_options</tt>. These
|
|
255
272
|
# will be added to all created paragraphs.
|
|
@@ -309,7 +326,7 @@ module ActionView
|
|
|
309
326
|
# <table>
|
|
310
327
|
# <% @items.each do |item| %>
|
|
311
328
|
# <tr class="<%= cycle("odd", "even") -%>">
|
|
312
|
-
# <td
|
|
329
|
+
# <td><%= item %></td>
|
|
313
330
|
# </tr>
|
|
314
331
|
# <% end %>
|
|
315
332
|
# </table>
|
|
@@ -334,7 +351,7 @@ module ActionView
|
|
|
334
351
|
# <% end %>
|
|
335
352
|
def cycle(first_value, *values)
|
|
336
353
|
options = values.extract_options!
|
|
337
|
-
name = options.fetch(:name,
|
|
354
|
+
name = options.fetch(:name, "default")
|
|
338
355
|
|
|
339
356
|
values.unshift(*first_value)
|
|
340
357
|
|
|
@@ -408,17 +425,17 @@ module ActionView
|
|
|
408
425
|
|
|
409
426
|
private
|
|
410
427
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
428
|
+
def next_index
|
|
429
|
+
step_index(1)
|
|
430
|
+
end
|
|
414
431
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
432
|
+
def previous_index
|
|
433
|
+
step_index(-1)
|
|
434
|
+
end
|
|
418
435
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
436
|
+
def step_index(n)
|
|
437
|
+
(@index + n) % @values.size
|
|
438
|
+
end
|
|
422
439
|
end
|
|
423
440
|
|
|
424
441
|
private
|
|
@@ -1,40 +1,61 @@
|
|
|
1
|
-
require
|
|
2
|
-
require
|
|
3
|
-
require
|
|
1
|
+
require "action_view/helpers/tag_helper"
|
|
2
|
+
require "active_support/core_ext/string/access"
|
|
3
|
+
require "i18n/exceptions"
|
|
4
4
|
|
|
5
5
|
module ActionView
|
|
6
6
|
# = Action View Translation Helpers
|
|
7
7
|
module Helpers
|
|
8
8
|
module TranslationHelper
|
|
9
|
+
extend ActiveSupport::Concern
|
|
10
|
+
|
|
9
11
|
include TagHelper
|
|
10
|
-
|
|
12
|
+
|
|
13
|
+
included do
|
|
14
|
+
mattr_accessor :debug_missing_translation
|
|
15
|
+
self.debug_missing_translation = true
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Delegates to <tt>I18n#translate</tt> but also performs three additional
|
|
19
|
+
# functions.
|
|
20
|
+
#
|
|
21
|
+
# First, it will ensure that any thrown +MissingTranslation+ messages will
|
|
22
|
+
# be rendered as inline spans that:
|
|
23
|
+
#
|
|
24
|
+
# * Have a <tt>translation-missing</tt> class applied
|
|
25
|
+
# * Contain the missing key as the value of the +title+ attribute
|
|
26
|
+
# * Have a titleized version of the last key segment as text
|
|
11
27
|
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
28
|
+
# For example, the value returned for the missing translation key
|
|
29
|
+
# <tt>"blog.post.title"</tt> will be:
|
|
14
30
|
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
31
|
+
# <span
|
|
32
|
+
# class="translation_missing"
|
|
33
|
+
# title="translation missing: en.blog.post.title">Title</span>
|
|
18
34
|
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
# This way your views will display rather reasonable strings but it will still
|
|
22
|
-
# be easy to spot missing translations.
|
|
35
|
+
# This allows for views to display rather reasonable strings while still
|
|
36
|
+
# giving developers a way to find missing translations.
|
|
23
37
|
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
# <tt>
|
|
27
|
-
# <tt>
|
|
28
|
-
#
|
|
29
|
-
# for scoping them consistently. If you don't prepend the key with a period,
|
|
30
|
-
# nothing is converted.
|
|
38
|
+
# If you would prefer missing translations to raise an error, you can
|
|
39
|
+
# opt out of span-wrapping behavior globally by setting
|
|
40
|
+
# <tt>ActionView::Base.raise_on_missing_translations = true</tt> or
|
|
41
|
+
# individually by passing <tt>raise: true</tt> as an option to
|
|
42
|
+
# <tt>translate</tt>.
|
|
31
43
|
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
#
|
|
37
|
-
#
|
|
44
|
+
# Second, if the key starts with a period <tt>translate</tt> will scope
|
|
45
|
+
# the key by the current partial. Calling <tt>translate(".foo")</tt> from
|
|
46
|
+
# the <tt>people/index.html.erb</tt> template is equivalent to calling
|
|
47
|
+
# <tt>translate("people.index.foo")</tt>. This makes it less
|
|
48
|
+
# repetitive to translate many keys within the same partial and provides
|
|
49
|
+
# a convention to scope keys consistently.
|
|
50
|
+
#
|
|
51
|
+
# Third, the translation will be marked as <tt>html_safe</tt> if the key
|
|
52
|
+
# has the suffix "_html" or the last element of the key is "html". Calling
|
|
53
|
+
# <tt>translate("footer_html")</tt> or <tt>translate("footer.html")</tt>
|
|
54
|
+
# will return an HTML safe string that won't be escaped by other HTML
|
|
55
|
+
# helper methods. This naming convention helps to identify translations
|
|
56
|
+
# that include HTML tags so that you know what kind of output to expect
|
|
57
|
+
# when you call translate in a template and translators know which keys
|
|
58
|
+
# they can provide HTML values for.
|
|
38
59
|
def translate(key, options = {})
|
|
39
60
|
options = options.dup
|
|
40
61
|
has_default = options.has_key?(:default)
|
|
@@ -47,11 +68,11 @@ module ActionView
|
|
|
47
68
|
# If the user has explicitly decided to NOT raise errors, pass that option to I18n.
|
|
48
69
|
# Otherwise, tell I18n to raise an exception, which we rescue further in this method.
|
|
49
70
|
# Note: `raise_error` refers to us re-raising the error in this method. I18n is forced to raise by default.
|
|
50
|
-
if options[:raise] == false
|
|
71
|
+
if options[:raise] == false
|
|
51
72
|
raise_error = false
|
|
52
73
|
i18n_raise = false
|
|
53
74
|
else
|
|
54
|
-
raise_error = options[:raise] ||
|
|
75
|
+
raise_error = options[:raise] || ActionView::Base.raise_on_missing_translations
|
|
55
76
|
i18n_raise = true
|
|
56
77
|
end
|
|
57
78
|
|
|
@@ -75,7 +96,16 @@ module ActionView
|
|
|
75
96
|
raise e if raise_error
|
|
76
97
|
|
|
77
98
|
keys = I18n.normalize_keys(e.locale, e.key, e.options[:scope])
|
|
78
|
-
|
|
99
|
+
title = "translation missing: #{keys.join('.')}"
|
|
100
|
+
|
|
101
|
+
interpolations = options.except(:default, :scope)
|
|
102
|
+
if interpolations.any?
|
|
103
|
+
title << ", " << interpolations.map { |k, v| "#{k}: #{ERB::Util.html_escape(v)}" }.join(", ")
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
return title unless ActionView::Base.debug_missing_translation
|
|
107
|
+
|
|
108
|
+
content_tag("span", keys.last.to_s.titleize, class: "translation_missing", title: title)
|
|
79
109
|
end
|
|
80
110
|
end
|
|
81
111
|
alias :t :translate
|
|
@@ -103,7 +133,7 @@ module ActionView
|
|
|
103
133
|
end
|
|
104
134
|
|
|
105
135
|
def html_safe_translation_key?(key)
|
|
106
|
-
|
|
136
|
+
/(\b|_|\.)html$/.match?(key.to_s)
|
|
107
137
|
end
|
|
108
138
|
end
|
|
109
139
|
end
|