actionpack 3.0.20 → 3.1.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- data/CHANGELOG +88 -142
- data/MIT-LICENSE +1 -1
- data/README.rdoc +5 -6
- data/lib/abstract_controller.rb +1 -0
- data/lib/abstract_controller/asset_paths.rb +2 -2
- data/lib/abstract_controller/base.rb +24 -19
- data/lib/abstract_controller/callbacks.rb +19 -19
- data/lib/abstract_controller/helpers.rb +11 -13
- data/lib/abstract_controller/layouts.rb +4 -5
- data/lib/abstract_controller/railties/routes_helpers.rb +18 -0
- data/lib/abstract_controller/rendering.rb +34 -31
- data/lib/abstract_controller/url_for.rb +27 -0
- data/lib/abstract_controller/view_paths.rb +31 -6
- data/lib/action_controller.rb +5 -3
- data/lib/action_controller/base.rb +15 -16
- data/lib/action_controller/caching.rb +2 -2
- data/lib/action_controller/caching/actions.rb +11 -12
- data/lib/action_controller/caching/fragments.rb +41 -19
- data/lib/action_controller/caching/pages.rb +3 -9
- data/lib/action_controller/caching/sweeping.rb +0 -1
- data/lib/action_controller/deprecated.rb +1 -1
- data/lib/action_controller/log_subscriber.rb +1 -1
- data/lib/action_controller/metal.rb +78 -20
- data/lib/action_controller/metal/compatibility.rb +0 -9
- data/lib/action_controller/metal/conditional_get.rb +9 -9
- data/lib/action_controller/metal/data_streaming.rb +145 -0
- data/lib/action_controller/metal/force_ssl.rb +35 -0
- data/lib/action_controller/metal/head.rb +1 -1
- data/lib/action_controller/metal/helpers.rb +37 -44
- data/lib/action_controller/metal/hide_actions.rb +2 -3
- data/lib/action_controller/metal/http_authentication.rb +41 -38
- data/lib/action_controller/metal/implicit_render.rb +13 -13
- data/lib/action_controller/metal/instrumentation.rb +2 -2
- data/lib/action_controller/metal/mime_responds.rb +25 -19
- data/lib/action_controller/metal/params_wrapper.rb +224 -0
- data/lib/action_controller/metal/redirecting.rb +6 -2
- data/lib/action_controller/metal/renderers.rb +50 -36
- data/lib/action_controller/metal/rendering.rb +34 -25
- data/lib/action_controller/metal/request_forgery_protection.rb +18 -36
- data/lib/action_controller/metal/responder.rb +47 -12
- data/lib/action_controller/metal/streaming.rb +244 -138
- data/lib/action_controller/metal/testing.rb +0 -9
- data/lib/action_controller/metal/url_for.rb +12 -14
- data/lib/action_controller/railtie.rb +19 -37
- data/lib/action_controller/railties/paths.rb +24 -0
- data/lib/action_controller/record_identifier.rb +4 -10
- data/lib/action_controller/test_case.rb +36 -19
- data/lib/action_controller/vendor/html-scanner/html/node.rb +5 -5
- data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +3 -3
- data/lib/action_controller/vendor/html-scanner/html/selector.rb +2 -0
- data/lib/action_dispatch.rb +4 -1
- data/lib/action_dispatch/http/cache.rb +5 -32
- data/lib/action_dispatch/http/filter_parameters.rb +3 -1
- data/lib/action_dispatch/http/mime_negotiation.rb +22 -3
- data/lib/action_dispatch/http/mime_type.rb +45 -5
- data/lib/action_dispatch/http/rack_cache.rb +58 -0
- data/lib/action_dispatch/http/request.rb +27 -41
- data/lib/action_dispatch/http/response.rb +56 -54
- data/lib/action_dispatch/http/upload.rb +1 -11
- data/lib/action_dispatch/http/url.rb +102 -42
- data/lib/action_dispatch/middleware/callbacks.rb +8 -25
- data/lib/action_dispatch/middleware/closed_error.rb +7 -0
- data/lib/action_dispatch/middleware/cookies.rb +37 -15
- data/lib/action_dispatch/middleware/flash.rb +80 -11
- data/lib/action_dispatch/middleware/params_parser.rb +2 -2
- data/lib/action_dispatch/middleware/reloader.rb +76 -0
- data/lib/action_dispatch/middleware/session/abstract_store.rb +56 -226
- data/lib/action_dispatch/middleware/session/cookie_store.rb +20 -44
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +7 -46
- data/lib/action_dispatch/middleware/show_exceptions.rb +15 -2
- data/lib/action_dispatch/middleware/stack.rb +50 -17
- data/lib/action_dispatch/middleware/static.rb +41 -29
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +4 -2
- data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +2 -6
- data/lib/action_dispatch/railtie.rb +8 -0
- data/lib/action_dispatch/routing.rb +13 -1
- data/lib/action_dispatch/routing/mapper.rb +345 -227
- data/lib/action_dispatch/routing/polymorphic_routes.rb +33 -13
- data/lib/action_dispatch/routing/redirection.rb +110 -0
- data/lib/action_dispatch/routing/route.rb +15 -13
- data/lib/action_dispatch/routing/route_set.rb +116 -90
- data/lib/action_dispatch/routing/routes_proxy.rb +35 -0
- data/lib/action_dispatch/routing/url_for.rb +25 -1
- data/lib/action_dispatch/testing/assertions/response.rb +8 -10
- data/lib/action_dispatch/testing/assertions/routing.rb +15 -15
- data/lib/action_dispatch/testing/assertions/selector.rb +13 -220
- data/lib/action_dispatch/testing/integration.rb +37 -28
- data/lib/action_dispatch/testing/performance_test.rb +1 -3
- data/lib/action_dispatch/testing/test_process.rb +1 -1
- data/lib/action_dispatch/testing/test_request.rb +9 -3
- data/lib/action_dispatch/testing/test_response.rb +4 -111
- data/lib/action_pack.rb +1 -1
- data/lib/action_pack/version.rb +3 -3
- data/lib/action_view.rb +39 -24
- data/lib/action_view/base.rb +61 -86
- data/lib/action_view/buffers.rb +43 -0
- data/lib/action_view/context.rb +21 -24
- data/lib/action_view/flows.rb +79 -0
- data/lib/action_view/helpers.rb +8 -6
- data/lib/action_view/helpers/active_model_helper.rb +0 -23
- data/lib/action_view/helpers/asset_paths.rb +79 -0
- data/lib/action_view/helpers/asset_tag_helper.rb +30 -500
- data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +147 -0
- data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +101 -0
- data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +200 -0
- data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +152 -0
- data/lib/action_view/helpers/atom_feed_helper.rb +2 -2
- data/lib/action_view/helpers/cache_helper.rb +11 -19
- data/lib/action_view/helpers/capture_helper.rb +19 -8
- data/lib/action_view/helpers/controller_helper.rb +21 -0
- data/lib/action_view/helpers/csrf_helper.rb +22 -4
- data/lib/action_view/helpers/date_helper.rb +36 -22
- data/lib/action_view/helpers/form_helper.rb +199 -113
- data/lib/action_view/helpers/form_options_helper.rb +10 -11
- data/lib/action_view/helpers/form_tag_helper.rb +94 -22
- data/lib/action_view/helpers/javascript_helper.rb +24 -107
- data/lib/action_view/helpers/number_helper.rb +36 -33
- data/lib/action_view/helpers/output_safety_helper.rb +38 -0
- data/lib/action_view/helpers/record_tag_helper.rb +6 -6
- data/lib/action_view/helpers/rendering_helper.rb +90 -0
- data/lib/action_view/helpers/sanitize_helper.rb +2 -2
- data/lib/action_view/helpers/sprockets_helper.rb +69 -0
- data/lib/action_view/helpers/tag_helper.rb +34 -12
- data/lib/action_view/helpers/text_helper.rb +30 -145
- data/lib/action_view/helpers/translation_helper.rb +10 -17
- data/lib/action_view/helpers/url_helper.rb +70 -67
- data/lib/action_view/locale/en.yml +1 -1
- data/lib/action_view/lookup_context.rb +36 -14
- data/lib/action_view/{paths.rb → path_set.rb} +9 -8
- data/lib/action_view/railtie.rb +12 -4
- data/lib/action_view/renderer/abstract_renderer.rb +36 -0
- data/lib/action_view/{render/partials.rb → renderer/partial_renderer.rb} +147 -146
- data/lib/action_view/renderer/renderer.rb +54 -0
- data/lib/action_view/renderer/streaming_template_renderer.rb +106 -0
- data/lib/action_view/renderer/template_renderer.rb +74 -0
- data/lib/action_view/template.rb +91 -54
- data/lib/action_view/template/error.rb +11 -8
- data/lib/action_view/template/handler.rb +9 -1
- data/lib/action_view/template/handlers.rb +9 -9
- data/lib/action_view/template/handlers/builder.rb +4 -4
- data/lib/action_view/template/handlers/erb.rb +21 -41
- data/lib/action_view/template/resolver.rb +171 -57
- data/lib/action_view/template/text.rb +0 -4
- data/lib/action_view/test_case.rb +32 -16
- data/lib/action_view/testing/resolvers.rb +16 -10
- data/lib/sprockets/railtie.rb +100 -0
- metadata +162 -140
- checksums.yaml +0 -7
- data/lib/action_controller/deprecated/base.rb +0 -143
- data/lib/action_controller/deprecated/dispatcher.rb +0 -28
- data/lib/action_controller/deprecated/url_writer.rb +0 -14
- data/lib/action_dispatch/routing/deprecated_mapper.rb +0 -525
- data/lib/action_view/helpers/prototype_helper.rb +0 -851
- data/lib/action_view/helpers/raw_output_helper.rb +0 -18
- data/lib/action_view/helpers/scriptaculous_helper.rb +0 -263
- data/lib/action_view/render/layouts.rb +0 -83
- data/lib/action_view/render/rendering.rb +0 -67
- data/lib/action_view/template/handlers/rjs.rb +0 -17
@@ -19,7 +19,7 @@ module ActionView
|
|
19
19
|
# simple_format('<a href="http://example.com/">Example</a>')
|
20
20
|
# # => "<p><a href=\"http://example.com/\">Example</a></p>"
|
21
21
|
#
|
22
|
-
# simple_format('<a href="javascript:alert('no
|
22
|
+
# simple_format('<a href="javascript:alert(\'no!\')">Example</a>')
|
23
23
|
# # => "<p><a>Example</a></p>"
|
24
24
|
#
|
25
25
|
# If you want to escape all content, you should invoke the +h+ method before
|
@@ -115,12 +115,13 @@ module ActionView
|
|
115
115
|
end
|
116
116
|
options.reverse_merge!(:highlighter => '<strong class="highlight">\1</strong>')
|
117
117
|
|
118
|
-
if text.present? && phrases.present?
|
119
|
-
match = Array(phrases).map { |p| Regexp.escape(p) }.join('|')
|
120
|
-
text = text.to_str.gsub(/(#{match})(?!(?:[^<]*?)(?:["'])[^<>]*>)/i, options[:highlighter])
|
121
|
-
end
|
122
118
|
text = sanitize(text) unless options[:sanitize] == false
|
123
|
-
text
|
119
|
+
if text.blank? || phrases.blank?
|
120
|
+
text
|
121
|
+
else
|
122
|
+
match = Array(phrases).map { |p| Regexp.escape(p) }.join('|')
|
123
|
+
text.gsub(/(#{match})(?!(?:[^<]*?)(?:["'])[^<>]*>)/i, options[:highlighter])
|
124
|
+
end.html_safe
|
124
125
|
end
|
125
126
|
|
126
127
|
# Extracts an excerpt from +text+ that matches the first instance of +phrase+.
|
@@ -151,6 +152,8 @@ module ActionView
|
|
151
152
|
# excerpt('This is an example', 'an', 5) # => ...s is an exam...
|
152
153
|
# excerpt('This is also an example', 'an', 8, '<chop> ') # => <chop> is also an example
|
153
154
|
def excerpt(text, phrase, *args)
|
155
|
+
return unless text && phrase
|
156
|
+
|
154
157
|
options = args.extract_options!
|
155
158
|
unless args.empty?
|
156
159
|
options[:radius] = args[0] || 100
|
@@ -158,21 +161,16 @@ module ActionView
|
|
158
161
|
end
|
159
162
|
options.reverse_merge!(:radius => 100, :omission => "...")
|
160
163
|
|
161
|
-
|
162
|
-
|
164
|
+
phrase = Regexp.escape(phrase)
|
165
|
+
return unless found_pos = text.mb_chars =~ /(#{phrase})/i
|
163
166
|
|
164
|
-
|
165
|
-
|
166
|
-
end_pos = [ [ found_pos + phrase.mb_chars.length + options[:radius] - 1, 0].max, text.mb_chars.length ].min
|
167
|
+
start_pos = [ found_pos - options[:radius], 0 ].max
|
168
|
+
end_pos = [ [ found_pos + phrase.mb_chars.length + options[:radius] - 1, 0].max, text.mb_chars.length ].min
|
167
169
|
|
168
|
-
|
169
|
-
|
170
|
+
prefix = start_pos > 0 ? options[:omission] : ""
|
171
|
+
postfix = end_pos < text.mb_chars.length - 1 ? options[:omission] : ""
|
170
172
|
|
171
|
-
|
172
|
-
else
|
173
|
-
nil
|
174
|
-
end
|
175
|
-
end
|
173
|
+
prefix + text.mb_chars[start_pos..end_pos].strip + postfix
|
176
174
|
end
|
177
175
|
|
178
176
|
# Attempts to pluralize the +singular+ word unless +count+ is 1. If
|
@@ -236,6 +234,10 @@ module ActionView
|
|
236
234
|
#
|
237
235
|
# You can pass any HTML attributes into <tt>html_options</tt>. These
|
238
236
|
# will be added to all created paragraphs.
|
237
|
+
#
|
238
|
+
# ==== Options
|
239
|
+
# * <tt>:sanitize</tt> - If +false+, does not sanitize +text+.
|
240
|
+
#
|
239
241
|
# ==== Examples
|
240
242
|
# my_text = "Here is some basic text...\n...with a line break."
|
241
243
|
#
|
@@ -249,71 +251,18 @@ module ActionView
|
|
249
251
|
#
|
250
252
|
# simple_format("Look ma! A class!", :class => 'description')
|
251
253
|
# # => "<p class='description'>Look ma! A class!</p>"
|
254
|
+
#
|
255
|
+
# simple_format("<span>I'm allowed!</span> It's true.", {}, :sanitize => false)
|
256
|
+
# # => "<p><span>I'm allowed!</span> It's true.</p>"
|
252
257
|
def simple_format(text, html_options={}, options={})
|
253
|
-
text =
|
254
|
-
text = text.dup if text.frozen?
|
258
|
+
text = ''.html_safe if text.nil?
|
255
259
|
start_tag = tag('p', html_options, true)
|
260
|
+
text = sanitize(text) unless options[:sanitize] == false
|
256
261
|
text.gsub!(/\r\n?/, "\n") # \r\n and \r -> \n
|
257
262
|
text.gsub!(/\n\n+/, "</p>\n\n#{start_tag}") # 2+ newline -> paragraph
|
258
263
|
text.gsub!(/([^\n]\n)(?=[^\n])/, '\1<br />') # 1 newline -> br
|
259
264
|
text.insert 0, start_tag
|
260
|
-
text.
|
261
|
-
text = sanitize(text) unless options[:sanitize] == false
|
262
|
-
text
|
263
|
-
end
|
264
|
-
|
265
|
-
# Turns all URLs and e-mail addresses into clickable links. The <tt>:link</tt> option
|
266
|
-
# will limit what should be linked. You can add HTML attributes to the links using
|
267
|
-
# <tt>:html</tt>. Possible values for <tt>:link</tt> are <tt>:all</tt> (default),
|
268
|
-
# <tt>:email_addresses</tt>, and <tt>:urls</tt>. If a block is given, each URL and
|
269
|
-
# e-mail address is yielded and the result is used as the link text.
|
270
|
-
#
|
271
|
-
# ==== Examples
|
272
|
-
# auto_link("Go to http://www.rubyonrails.org and say hello to david@loudthinking.com")
|
273
|
-
# # => "Go to <a href=\"http://www.rubyonrails.org\">http://www.rubyonrails.org</a> and
|
274
|
-
# # say hello to <a href=\"mailto:david@loudthinking.com\">david@loudthinking.com</a>"
|
275
|
-
#
|
276
|
-
# auto_link("Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com", :link => :urls)
|
277
|
-
# # => "Visit <a href=\"http://www.loudthinking.com/\">http://www.loudthinking.com/</a>
|
278
|
-
# # or e-mail david@loudthinking.com"
|
279
|
-
#
|
280
|
-
# auto_link("Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com", :link => :email_addresses)
|
281
|
-
# # => "Visit http://www.loudthinking.com/ or e-mail <a href=\"mailto:david@loudthinking.com\">david@loudthinking.com</a>"
|
282
|
-
#
|
283
|
-
# post_body = "Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com."
|
284
|
-
# auto_link(post_body, :html => { :target => '_blank' }) do |text|
|
285
|
-
# truncate(text, 15)
|
286
|
-
# end
|
287
|
-
# # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\" target=\"_blank\">http://www.m...</a>.
|
288
|
-
# Please e-mail me at <a href=\"mailto:me@email.com\">me@email.com</a>."
|
289
|
-
#
|
290
|
-
#
|
291
|
-
# You can still use <tt>auto_link</tt> with the old API that accepts the
|
292
|
-
# +link+ as its optional second parameter and the +html_options+ hash
|
293
|
-
# as its optional third parameter:
|
294
|
-
# post_body = "Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com."
|
295
|
-
# auto_link(post_body, :urls) # => Once upon\na time
|
296
|
-
# # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\">http://www.myblog.com</a>.
|
297
|
-
# Please e-mail me at me@email.com."
|
298
|
-
#
|
299
|
-
# auto_link(post_body, :all, :target => "_blank") # => Once upon\na time
|
300
|
-
# # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\" target=\"_blank\">http://www.myblog.com</a>.
|
301
|
-
# Please e-mail me at <a href=\"mailto:me@email.com\">me@email.com</a>."
|
302
|
-
def auto_link(text, *args, &block)#link = :all, html = {}, &block)
|
303
|
-
return '' if text.blank?
|
304
|
-
|
305
|
-
options = args.size == 2 ? {} : args.extract_options! # this is necessary because the old auto_link API has a Hash as its last parameter
|
306
|
-
unless args.empty?
|
307
|
-
options[:link] = args[0] || :all
|
308
|
-
options[:html] = args[1] || {}
|
309
|
-
end
|
310
|
-
options.reverse_merge!(:link => :all, :html => {})
|
311
|
-
|
312
|
-
case options[:link].to_sym
|
313
|
-
when :all then auto_link_email_addresses(auto_link_urls(text, options[:html], options, &block), options[:html], &block)
|
314
|
-
when :email_addresses then auto_link_email_addresses(text, options[:html], &block)
|
315
|
-
when :urls then auto_link_urls(text, options[:html], options, &block)
|
316
|
-
end
|
265
|
+
text.html_safe.safe_concat("</p>")
|
317
266
|
end
|
318
267
|
|
319
268
|
# Creates a Cycle object whose _to_s_ method cycles through elements of an
|
@@ -364,10 +313,10 @@ module ActionView
|
|
364
313
|
values.unshift(first_value)
|
365
314
|
|
366
315
|
cycle = get_cycle(name)
|
367
|
-
|
316
|
+
unless cycle && cycle.values == values
|
368
317
|
cycle = set_cycle(name, Cycle.new(*values))
|
369
318
|
end
|
370
|
-
|
319
|
+
cycle.to_s
|
371
320
|
end
|
372
321
|
|
373
322
|
# Returns the current cycle string after a cycle has been started. Useful
|
@@ -384,7 +333,7 @@ module ActionView
|
|
384
333
|
# <% end %>
|
385
334
|
def current_cycle(name = "default")
|
386
335
|
cycle = get_cycle(name)
|
387
|
-
cycle.current_value
|
336
|
+
cycle.current_value if cycle
|
388
337
|
end
|
389
338
|
|
390
339
|
# Resets a cycle so that it starts from the first element the next time
|
@@ -408,7 +357,7 @@ module ActionView
|
|
408
357
|
# </table>
|
409
358
|
def reset_cycle(name = "default")
|
410
359
|
cycle = get_cycle(name)
|
411
|
-
cycle.reset
|
360
|
+
cycle.reset if cycle
|
412
361
|
end
|
413
362
|
|
414
363
|
class Cycle #:nodoc:
|
@@ -461,70 +410,6 @@ module ActionView
|
|
461
410
|
@_cycles = Hash.new unless defined?(@_cycles)
|
462
411
|
@_cycles[name] = cycle_object
|
463
412
|
end
|
464
|
-
|
465
|
-
AUTO_LINK_RE = %r{
|
466
|
-
(?: ((?:ed2k|ftp|http|https|irc|mailto|news|gopher|nntp|telnet|webcal|xmpp|callto|feed|svn|urn|aim|rsync|tag|ssh|sftp|rtsp|afs):)// | www\. )
|
467
|
-
[^\s<]+
|
468
|
-
}x
|
469
|
-
|
470
|
-
# regexps for determining context, used high-volume
|
471
|
-
AUTO_LINK_CRE = [/<[^>]+$/, /^[^>]*>/, /<a\b.*?>/i, /<\/a>/i]
|
472
|
-
|
473
|
-
AUTO_EMAIL_RE = /[\w.!#\$%+-]+@[\w-]+(?:\.[\w-]+)+/
|
474
|
-
|
475
|
-
BRACKETS = { ']' => '[', ')' => '(', '}' => '{' }
|
476
|
-
|
477
|
-
# Turns all urls into clickable links. If a block is given, each url
|
478
|
-
# is yielded and the result is used as the link text.
|
479
|
-
def auto_link_urls(text, html_options = {}, options = {})
|
480
|
-
link_attributes = html_options.stringify_keys
|
481
|
-
text.to_str.gsub(AUTO_LINK_RE) do
|
482
|
-
scheme, href = $1, $&
|
483
|
-
punctuation = []
|
484
|
-
|
485
|
-
if auto_linked?($`, $')
|
486
|
-
# do not change string; URL is already linked
|
487
|
-
href
|
488
|
-
else
|
489
|
-
# don't include trailing punctuation character as part of the URL
|
490
|
-
while href.sub!(/[^\w\/-]$/, '')
|
491
|
-
punctuation.push $&
|
492
|
-
if opening = BRACKETS[punctuation.last] and href.scan(opening).size > href.scan(punctuation.last).size
|
493
|
-
href << punctuation.pop
|
494
|
-
break
|
495
|
-
end
|
496
|
-
end
|
497
|
-
|
498
|
-
link_text = block_given? ? yield(href) : href
|
499
|
-
href = 'http://' + href unless scheme
|
500
|
-
|
501
|
-
sanitize_link = options[:sanitize] != false
|
502
|
-
content_tag(:a, link_text, link_attributes.merge('href' => href), sanitize_link) + punctuation.reverse.join('')
|
503
|
-
end
|
504
|
-
end
|
505
|
-
end
|
506
|
-
|
507
|
-
# Turns all email addresses into clickable links. If a block is given,
|
508
|
-
# each email is yielded and the result is used as the link text.
|
509
|
-
def auto_link_email_addresses(text, html_options = {}, options = {})
|
510
|
-
text.to_str.gsub(AUTO_EMAIL_RE) do
|
511
|
-
text = $&
|
512
|
-
|
513
|
-
if auto_linked?($`, $')
|
514
|
-
text.html_safe
|
515
|
-
else
|
516
|
-
display_text = block_given? ? yield(text) : text
|
517
|
-
display_text = sanitize(display_text) unless options[:sanitize] == false
|
518
|
-
mail_to text, display_text, html_options
|
519
|
-
end
|
520
|
-
end
|
521
|
-
end
|
522
|
-
|
523
|
-
# Detects already linked context or position in the middle of a tag
|
524
|
-
def auto_linked?(left, right)
|
525
|
-
(left =~ AUTO_LINK_CRE[0] and right =~ AUTO_LINK_CRE[1]) or
|
526
|
-
(left.rindex(AUTO_LINK_CRE[2]) and $' !~ AUTO_LINK_CRE[3])
|
527
|
-
end
|
528
413
|
end
|
529
414
|
end
|
530
415
|
end
|
@@ -5,7 +5,7 @@ module I18n
|
|
5
5
|
class ExceptionHandler
|
6
6
|
include Module.new {
|
7
7
|
def call(exception, locale, key, options)
|
8
|
-
exception.is_a?(
|
8
|
+
exception.is_a?(MissingTranslation) ? super.html_safe : super
|
9
9
|
end
|
10
10
|
}
|
11
11
|
end
|
@@ -17,8 +17,8 @@ module ActionView
|
|
17
17
|
module TranslationHelper
|
18
18
|
# Delegates to I18n#translate but also performs three additional functions.
|
19
19
|
#
|
20
|
-
# First, it'll pass the :rescue_format => :html option to I18n so that any
|
21
|
-
#
|
20
|
+
# First, it'll pass the :rescue_format => :html option to I18n so that any
|
21
|
+
# thrown MissingTranslation messages will be turned into inline spans that
|
22
22
|
#
|
23
23
|
# * have a "translation-missing" class set,
|
24
24
|
# * contain the missing key as a title attribute and
|
@@ -26,7 +26,7 @@ module ActionView
|
|
26
26
|
#
|
27
27
|
# E.g. the value returned for a missing translation key :"blog.post.title" will be
|
28
28
|
# <span class="translation_missing" title="translation missing: blog.post.title">Title</span>.
|
29
|
-
# This way your views will display rather
|
29
|
+
# This way your views will display rather reasonable strings but it will still
|
30
30
|
# be easy to spot missing translations.
|
31
31
|
#
|
32
32
|
# Second, it'll scope the key by the current partial if the key starts
|
@@ -45,18 +45,11 @@ module ActionView
|
|
45
45
|
# you know what kind of output to expect when you call translate in a template.
|
46
46
|
def translate(key, options = {})
|
47
47
|
options.merge!(:rescue_format => :html) unless options.key?(:rescue_format)
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
unless name == :count && value.is_a?(Numeric)
|
52
|
-
html_safe_options[name] = ERB::Util.html_escape(value.to_s)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
translation = I18n.translate(scope_key_by_partial(key), html_safe_options)
|
56
|
-
|
57
|
-
translation.respond_to?(:html_safe) ? translation.html_safe : translation
|
48
|
+
translation = I18n.translate(scope_key_by_partial(key), options)
|
49
|
+
if html_safe_translation_key?(key) && translation.respond_to?(:html_safe)
|
50
|
+
translation.html_safe
|
58
51
|
else
|
59
|
-
|
52
|
+
translation
|
60
53
|
end
|
61
54
|
end
|
62
55
|
alias :t :translate
|
@@ -70,8 +63,8 @@ module ActionView
|
|
70
63
|
private
|
71
64
|
def scope_key_by_partial(key)
|
72
65
|
if key.to_s.first == "."
|
73
|
-
if @
|
74
|
-
@
|
66
|
+
if @virtual_path
|
67
|
+
@virtual_path.gsub(%r{/_?}, ".") + key.to_s
|
75
68
|
else
|
76
69
|
raise "Cannot use t(#{key.inspect}) shortcut because path is not available"
|
77
70
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'action_view/helpers/javascript_helper'
|
2
2
|
require 'active_support/core_ext/array/access'
|
3
3
|
require 'active_support/core_ext/hash/keys'
|
4
|
+
require 'active_support/core_ext/string/output_safety'
|
4
5
|
require 'action_dispatch'
|
5
6
|
|
6
7
|
module ActionView
|
@@ -22,6 +23,10 @@ module ActionView
|
|
22
23
|
include ActionDispatch::Routing::UrlFor
|
23
24
|
include TagHelper
|
24
25
|
|
26
|
+
def _routes_context
|
27
|
+
controller
|
28
|
+
end
|
29
|
+
|
25
30
|
# Need to map default url options to controller one.
|
26
31
|
# def default_url_options(*args) #:nodoc:
|
27
32
|
# controller.send(:default_url_options, *args)
|
@@ -63,7 +68,7 @@ module ActionView
|
|
63
68
|
# # => /books/find
|
64
69
|
#
|
65
70
|
# <%= url_for(:action => 'login', :controller => 'members', :only_path => false, :protocol => 'https') %>
|
66
|
-
# # => https://www.
|
71
|
+
# # => https://www.example.com/members/login/
|
67
72
|
#
|
68
73
|
# <%= url_for(:action => 'play', :anchor => 'player') %>
|
69
74
|
# # => /messages/play/#player
|
@@ -76,9 +81,12 @@ module ActionView
|
|
76
81
|
# # => /workshops
|
77
82
|
#
|
78
83
|
# <%= url_for(@workshop) %>
|
79
|
-
# # calls @workshop.
|
84
|
+
# # calls @workshop.to_param which by default returns the id
|
80
85
|
# # => /workshops/5
|
81
86
|
#
|
87
|
+
# # to_param can be re-defined in a model to provide different URL names:
|
88
|
+
# # => /workshops/1-workshop-name
|
89
|
+
#
|
82
90
|
# <%= url_for("http://www.example.com") %>
|
83
91
|
# # => http://www.example.com
|
84
92
|
#
|
@@ -91,7 +99,7 @@ module ActionView
|
|
91
99
|
# # => javascript:history.back()
|
92
100
|
def url_for(options = {})
|
93
101
|
options ||= {}
|
94
|
-
|
102
|
+
case options
|
95
103
|
when String
|
96
104
|
options
|
97
105
|
when Hash
|
@@ -102,8 +110,6 @@ module ActionView
|
|
102
110
|
else
|
103
111
|
polymorphic_path(options)
|
104
112
|
end
|
105
|
-
|
106
|
-
url
|
107
113
|
end
|
108
114
|
|
109
115
|
# Creates a link tag of the given +name+ using a URL created by the set
|
@@ -180,7 +186,7 @@ module ActionView
|
|
180
186
|
# link_to "Profiles", :controller => "profiles"
|
181
187
|
# # => <a href="/profiles">Profiles</a>
|
182
188
|
#
|
183
|
-
# You can use a block as well if your link target is hard to fit into the name parameter.
|
189
|
+
# You can use a block as well if your link target is hard to fit into the name parameter. ERB example:
|
184
190
|
#
|
185
191
|
# <%= link_to(@profile) do %>
|
186
192
|
# <strong><%= @profile.name %></strong> -- <span>Check it out!</span>
|
@@ -238,8 +244,8 @@ module ActionView
|
|
238
244
|
href = html_options['href']
|
239
245
|
tag_options = tag_options(html_options)
|
240
246
|
|
241
|
-
href_attr = "href=\"#{html_escape(url)}\"" unless href
|
242
|
-
"<a #{href_attr}#{tag_options}>#{html_escape(name || url)}</a>".html_safe
|
247
|
+
href_attr = "href=\"#{ERB::Util.html_escape(url)}\"" unless href
|
248
|
+
"<a #{href_attr}#{tag_options}>#{ERB::Util.html_escape(name || url)}</a>".html_safe
|
243
249
|
end
|
244
250
|
end
|
245
251
|
|
@@ -250,8 +256,9 @@ module ActionView
|
|
250
256
|
# using the +link_to+ method with the <tt>:method</tt> modifier as described in
|
251
257
|
# the +link_to+ documentation.
|
252
258
|
#
|
253
|
-
#
|
254
|
-
# to allow styling of the form itself and its children.
|
259
|
+
# By default, the generated form element has a class name of <tt>button_to</tt>
|
260
|
+
# to allow styling of the form itself and its children. This can be changed
|
261
|
+
# using the <tt>:form_class</tt> modifier within +html_options+. You can control
|
255
262
|
# the form submission and input element behavior using +html_options+.
|
256
263
|
# This method accepts the <tt>:method</tt> and <tt>:confirm</tt> modifiers
|
257
264
|
# described in the +link_to+ documentation. If no <tt>:method</tt> modifier
|
@@ -264,7 +271,7 @@ module ActionView
|
|
264
271
|
# The +options+ hash accepts the same options as url_for.
|
265
272
|
#
|
266
273
|
# There are a few special +html_options+:
|
267
|
-
# * <tt>:method</tt> - Symbol of HTTP verb. Supported verbs are <tt>:post</tt>, <tt>:get</tt>,
|
274
|
+
# * <tt>:method</tt> - Symbol of HTTP verb. Supported verbs are <tt>:post</tt>, <tt>:get</tt>,
|
268
275
|
# <tt>:delete</tt> and <tt>:put</tt>. By default it will be <tt>:post</tt>.
|
269
276
|
# * <tt>:disabled</tt> - If set to true, it will generate a disabled button.
|
270
277
|
# * <tt>:confirm</tt> - This will use the unobtrusive JavaScript driver to
|
@@ -272,6 +279,8 @@ module ActionView
|
|
272
279
|
# processed normally, otherwise no action is taken.
|
273
280
|
# * <tt>:remote</tt> - If set to true, will allow the Unobtrusive JavaScript drivers to control the
|
274
281
|
# submit behaviour. By default this behaviour is an ajax submit.
|
282
|
+
# * <tt>:form_class</tt> - This controls the class of the form within which the submit button will
|
283
|
+
# be placed
|
275
284
|
#
|
276
285
|
# ==== Examples
|
277
286
|
# <%= button_to "New", :action => "new" %>
|
@@ -280,6 +289,12 @@ module ActionView
|
|
280
289
|
# # </form>"
|
281
290
|
#
|
282
291
|
#
|
292
|
+
# <%= button_to "New", :action => "new", :form_class => "new-thing" %>
|
293
|
+
# # => "<form method="post" action="/controller/new" class="new-thing">
|
294
|
+
# # <div><input value="New" type="submit" /></div>
|
295
|
+
# # </form>"
|
296
|
+
#
|
297
|
+
#
|
283
298
|
# <%= button_to "Delete Image", { :action => "delete", :id => @image.id },
|
284
299
|
# :confirm => "Are you sure?", :method => :delete %>
|
285
300
|
# # => "<form method="post" action="/images/delete/1" class="button_to">
|
@@ -309,6 +324,7 @@ module ActionView
|
|
309
324
|
end
|
310
325
|
|
311
326
|
form_method = method.to_s == 'get' ? 'get' : 'post'
|
327
|
+
form_class = html_options.delete('form_class') || 'button_to'
|
312
328
|
|
313
329
|
remote = html_options.delete('remote')
|
314
330
|
|
@@ -324,7 +340,7 @@ module ActionView
|
|
324
340
|
|
325
341
|
html_options.merge!("type" => "submit", "value" => name)
|
326
342
|
|
327
|
-
("<form method=\"#{form_method}\" action=\"#{html_escape(url)}\" #{"data-remote=\"true\"" if remote} class=\"
|
343
|
+
("<form method=\"#{form_method}\" action=\"#{ERB::Util.html_escape(url)}\" #{"data-remote=\"true\"" if remote} class=\"#{ERB::Util.html_escape(form_class)}\"><div>" +
|
328
344
|
method_tag + tag("input", html_options) + request_token_tag + "</div></form>").html_safe
|
329
345
|
end
|
330
346
|
|
@@ -470,45 +486,41 @@ module ActionView
|
|
470
486
|
# :subject => "This is an example email"
|
471
487
|
# # => <a href="mailto:me@domain.com?cc=ccaddress@domain.com&subject=This%20is%20an%20example%20email">My email</a>
|
472
488
|
def mail_to(email_address, name = nil, html_options = {})
|
473
|
-
email_address = html_escape(email_address)
|
489
|
+
email_address = ERB::Util.html_escape(email_address)
|
474
490
|
|
475
491
|
html_options = html_options.stringify_keys
|
476
492
|
encode = html_options.delete("encode").to_s
|
477
|
-
cc, bcc, subject, body = html_options.delete("cc"), html_options.delete("bcc"), html_options.delete("subject"), html_options.delete("body")
|
478
|
-
|
479
|
-
extras = []
|
480
|
-
extras << "cc=#{Rack::Utils.escape(cc).gsub("+", "%20")}" unless cc.nil?
|
481
|
-
extras << "bcc=#{Rack::Utils.escape(bcc).gsub("+", "%20")}" unless bcc.nil?
|
482
|
-
extras << "body=#{Rack::Utils.escape(body).gsub("+", "%20")}" unless body.nil?
|
483
|
-
extras << "subject=#{Rack::Utils.escape(subject).gsub("+", "%20")}" unless subject.nil?
|
484
|
-
extras = extras.empty? ? '' : '?' + html_escape(extras.join('&'))
|
485
493
|
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
494
|
+
extras = %w{ cc bcc body subject }.map { |item|
|
495
|
+
option = html_options.delete(item) || next
|
496
|
+
"#{item}=#{Rack::Utils.escape(option).gsub("+", "%20")}"
|
497
|
+
}.compact
|
498
|
+
extras = extras.empty? ? '' : '?' + ERB::Util.html_escape(extras.join('&'))
|
499
|
+
|
500
|
+
email_address_obfuscated = email_address.dup
|
501
|
+
email_address_obfuscated.gsub!(/@/, html_options.delete("replace_at")) if html_options.key?("replace_at")
|
502
|
+
email_address_obfuscated.gsub!(/\./, html_options.delete("replace_dot")) if html_options.key?("replace_dot")
|
503
|
+
case encode
|
504
|
+
when "javascript"
|
505
|
+
string = ''
|
493
506
|
html = content_tag("a", name || email_address_obfuscated.html_safe, html_options.merge("href" => "mailto:#{email_address}#{extras}".html_safe))
|
494
507
|
html = escape_javascript(html)
|
495
508
|
"document.write('#{html}');".each_byte do |c|
|
496
509
|
string << sprintf("%%%x", c)
|
497
510
|
end
|
498
511
|
"<script type=\"#{Mime::JS}\">eval(decodeURIComponent('#{string}'))</script>".html_safe
|
499
|
-
|
500
|
-
email_address_encoded = ''
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
email_address.each_byte do |c|
|
512
|
+
when "hex"
|
513
|
+
email_address_encoded = email_address_obfuscated.unpack('C*').map {|c|
|
514
|
+
sprintf("&#%d;", c)
|
515
|
+
}.join
|
516
|
+
|
517
|
+
string = 'mailto:'.unpack('C*').map { |c|
|
518
|
+
sprintf("&#%d;", c)
|
519
|
+
}.join + email_address.unpack('C*').map { |c|
|
509
520
|
char = c.chr
|
510
|
-
|
511
|
-
|
521
|
+
char =~ /\w/ ? sprintf("%%%x", c) : char
|
522
|
+
}.join
|
523
|
+
|
512
524
|
content_tag "a", name || email_address_encoded.html_safe, html_options.merge("href" => "#{string}#{extras}".html_safe)
|
513
525
|
else
|
514
526
|
content_tag "a", name || email_address_obfuscated.html_safe, html_options.merge("href" => "mailto:#{email_address}#{extras}".html_safe)
|
@@ -543,10 +555,10 @@ module ActionView
|
|
543
555
|
# current_page?(:controller => 'shop', :action => 'checkout')
|
544
556
|
# # => true
|
545
557
|
#
|
546
|
-
# current_page?(:controller => 'shop', :action => 'checkout', :order => 'desc', :page=>'1')
|
558
|
+
# current_page?(:controller => 'shop', :action => 'checkout', :order => 'desc', :page => '1')
|
547
559
|
# # => true
|
548
560
|
#
|
549
|
-
# current_page?(:controller => 'shop', :action => 'checkout', :order => 'desc', :page=>'2')
|
561
|
+
# current_page?(:controller => 'shop', :action => 'checkout', :order => 'desc', :page => '2')
|
550
562
|
# # => false
|
551
563
|
#
|
552
564
|
# current_page?(:controller => 'shop', :action => 'checkout', :order => 'desc')
|
@@ -584,40 +596,31 @@ module ActionView
|
|
584
596
|
|
585
597
|
private
|
586
598
|
def convert_options_to_data_attributes(options, html_options)
|
587
|
-
|
588
|
-
|
599
|
+
if html_options.nil?
|
600
|
+
link_to_remote_options?(options) ? {'data-remote' => 'true'} : {}
|
601
|
+
else
|
602
|
+
html_options = html_options.stringify_keys
|
603
|
+
html_options['data-remote'] = 'true' if link_to_remote_options?(options) || link_to_remote_options?(html_options)
|
589
604
|
|
590
|
-
|
591
|
-
|
592
|
-
|
605
|
+
disable_with = html_options.delete("disable_with")
|
606
|
+
confirm = html_options.delete('confirm')
|
607
|
+
method = html_options.delete('method')
|
593
608
|
|
594
|
-
|
595
|
-
|
609
|
+
html_options["data-disable-with"] = disable_with if disable_with
|
610
|
+
html_options["data-confirm"] = confirm if confirm
|
611
|
+
add_method_to_attributes!(html_options, method) if method
|
596
612
|
|
597
|
-
|
598
|
-
ActiveSupport::Deprecation.warn(":popup has been deprecated", caller)
|
613
|
+
html_options
|
599
614
|
end
|
600
|
-
|
601
|
-
method, href = html_options.delete("method"), html_options['href']
|
602
|
-
|
603
|
-
add_disable_with_to_attributes!(html_options, disable_with) if disable_with
|
604
|
-
add_confirm_to_attributes!(html_options, confirm) if confirm
|
605
|
-
add_method_to_attributes!(html_options, method) if method
|
606
|
-
|
607
|
-
html_options
|
608
|
-
end
|
609
|
-
|
610
|
-
def add_confirm_to_attributes!(html_options, confirm)
|
611
|
-
html_options["data-confirm"] = confirm if confirm
|
612
615
|
end
|
613
616
|
|
614
|
-
def
|
615
|
-
|
617
|
+
def link_to_remote_options?(options)
|
618
|
+
options.is_a?(Hash) && options.key?('remote') && options.delete('remote')
|
616
619
|
end
|
617
620
|
|
618
621
|
def add_method_to_attributes!(html_options, method)
|
619
|
-
html_options["rel"] = "nofollow" if method
|
620
|
-
html_options["data-method"] = method
|
622
|
+
html_options["rel"] = "nofollow" if method.to_s.downcase != "get"
|
623
|
+
html_options["data-method"] = method
|
621
624
|
end
|
622
625
|
|
623
626
|
def options_for_javascript(options)
|