2010-03-28 08:15:02 -04:00
|
|
|
require 'active_support/core_ext/object/blank'
|
2010-10-11 14:39:12 -04:00
|
|
|
require 'active_support/core_ext/string/output_safety'
|
2010-03-28 08:15:02 -04:00
|
|
|
|
2005-03-14 18:37:38 -05:00
|
|
|
module ActionView
|
2010-06-16 14:17:49 -04:00
|
|
|
# = Action View Capture Helper
|
2005-03-14 18:37:38 -05:00
|
|
|
module Helpers
|
2007-06-23 13:49:18 -04:00
|
|
|
# CaptureHelper exposes methods to let you extract generated markup which
|
|
|
|
# can be used in other parts of a template or layout file.
|
2010-06-16 14:17:49 -04:00
|
|
|
#
|
Add deprecation notices for <% %>.
* The approach is to compile <% %> into a method call that checks whether
the value returned from a block is a String. If it is, it concats to the buffer and
prints a deprecation warning.
* <%= %> uses exactly the same logic to compile the template, which first checks
to see whether it's compiling a block.
* This should have no impact on other uses of block in templates. For instance, in
<% [1,2,3].each do |i| %><%= i %><% end %>, the call to each returns an Array,
not a String, so the result is not concatenated
* In two cases (#capture and #cache), a String can be returned that should *never*
be concatenated. We have temporarily created a String subclass called NonConcattingString
which behaves (and is serialized) identically to String, but is not concatenated
by the code that handles deprecated <% %> block helpers. Once we remove support
for <% %> block helpers, we can remove NonConcattingString.
2010-03-15 14:58:05 -04:00
|
|
|
# It provides a method to capture blocks into variables through capture and
|
2007-06-28 14:32:34 -04:00
|
|
|
# a way to capture a block of markup for use in a layout through content_for.
|
2005-03-14 18:37:38 -05:00
|
|
|
module CaptureHelper
|
Add deprecation notices for <% %>.
* The approach is to compile <% %> into a method call that checks whether
the value returned from a block is a String. If it is, it concats to the buffer and
prints a deprecation warning.
* <%= %> uses exactly the same logic to compile the template, which first checks
to see whether it's compiling a block.
* This should have no impact on other uses of block in templates. For instance, in
<% [1,2,3].each do |i| %><%= i %><% end %>, the call to each returns an Array,
not a String, so the result is not concatenated
* In two cases (#capture and #cache), a String can be returned that should *never*
be concatenated. We have temporarily created a String subclass called NonConcattingString
which behaves (and is serialized) identically to String, but is not concatenated
by the code that handles deprecated <% %> block helpers. Once we remove support
for <% %> block helpers, we can remove NonConcattingString.
2010-03-15 14:58:05 -04:00
|
|
|
# The capture method allows you to extract part of a template into a
|
|
|
|
# variable. You can then use this variable anywhere in your templates or layout.
|
|
|
|
#
|
2007-06-23 13:49:18 -04:00
|
|
|
# ==== Examples
|
2011-04-02 23:47:51 -04:00
|
|
|
# The capture method can be used in ERB templates...
|
Add deprecation notices for <% %>.
* The approach is to compile <% %> into a method call that checks whether
the value returned from a block is a String. If it is, it concats to the buffer and
prints a deprecation warning.
* <%= %> uses exactly the same logic to compile the template, which first checks
to see whether it's compiling a block.
* This should have no impact on other uses of block in templates. For instance, in
<% [1,2,3].each do |i| %><%= i %><% end %>, the call to each returns an Array,
not a String, so the result is not concatenated
* In two cases (#capture and #cache), a String can be returned that should *never*
be concatenated. We have temporarily created a String subclass called NonConcattingString
which behaves (and is serialized) identically to String, but is not concatenated
by the code that handles deprecated <% %> block helpers. Once we remove support
for <% %> block helpers, we can remove NonConcattingString.
2010-03-15 14:58:05 -04:00
|
|
|
#
|
2005-03-14 18:37:38 -05:00
|
|
|
# <% @greeting = capture do %>
|
2007-06-23 13:49:18 -04:00
|
|
|
# Welcome to my shiny new web page! The date and time is
|
|
|
|
# <%= Time.now %>
|
2006-02-26 14:47:50 -05:00
|
|
|
# <% end %>
|
|
|
|
#
|
2007-06-23 13:49:18 -04:00
|
|
|
# ...and Builder (RXML) templates.
|
Add deprecation notices for <% %>.
* The approach is to compile <% %> into a method call that checks whether
the value returned from a block is a String. If it is, it concats to the buffer and
prints a deprecation warning.
* <%= %> uses exactly the same logic to compile the template, which first checks
to see whether it's compiling a block.
* This should have no impact on other uses of block in templates. For instance, in
<% [1,2,3].each do |i| %><%= i %><% end %>, the call to each returns an Array,
not a String, so the result is not concatenated
* In two cases (#capture and #cache), a String can be returned that should *never*
be concatenated. We have temporarily created a String subclass called NonConcattingString
which behaves (and is serialized) identically to String, but is not concatenated
by the code that handles deprecated <% %> block helpers. Once we remove support
for <% %> block helpers, we can remove NonConcattingString.
2010-03-15 14:58:05 -04:00
|
|
|
#
|
2007-06-23 13:49:18 -04:00
|
|
|
# @timestamp = capture do
|
|
|
|
# "The current timestamp is #{Time.now}."
|
2006-02-26 14:47:50 -05:00
|
|
|
# end
|
2007-06-23 13:49:18 -04:00
|
|
|
#
|
2007-06-28 14:32:34 -04:00
|
|
|
# You can then use that variable anywhere else. For example:
|
2007-06-23 13:49:18 -04:00
|
|
|
#
|
|
|
|
# <html>
|
|
|
|
# <head><title><%= @greeting %></title></head>
|
|
|
|
# <body>
|
|
|
|
# <b><%= @greeting %></b>
|
|
|
|
# </body></html>
|
|
|
|
#
|
2010-03-09 21:00:28 -05:00
|
|
|
def capture(*args)
|
|
|
|
value = nil
|
2010-03-17 02:24:00 -04:00
|
|
|
buffer = with_output_buffer { value = yield(*args) }
|
Add deprecation notices for <% %>.
* The approach is to compile <% %> into a method call that checks whether
the value returned from a block is a String. If it is, it concats to the buffer and
prints a deprecation warning.
* <%= %> uses exactly the same logic to compile the template, which first checks
to see whether it's compiling a block.
* This should have no impact on other uses of block in templates. For instance, in
<% [1,2,3].each do |i| %><%= i %><% end %>, the call to each returns an Array,
not a String, so the result is not concatenated
* In two cases (#capture and #cache), a String can be returned that should *never*
be concatenated. We have temporarily created a String subclass called NonConcattingString
which behaves (and is serialized) identically to String, but is not concatenated
by the code that handles deprecated <% %> block helpers. Once we remove support
for <% %> block helpers, we can remove NonConcattingString.
2010-03-15 14:58:05 -04:00
|
|
|
if string = buffer.presence || value and string.is_a?(String)
|
2010-11-02 18:02:13 -04:00
|
|
|
ERB::Util.html_escape string
|
Add deprecation notices for <% %>.
* The approach is to compile <% %> into a method call that checks whether
the value returned from a block is a String. If it is, it concats to the buffer and
prints a deprecation warning.
* <%= %> uses exactly the same logic to compile the template, which first checks
to see whether it's compiling a block.
* This should have no impact on other uses of block in templates. For instance, in
<% [1,2,3].each do |i| %><%= i %><% end %>, the call to each returns an Array,
not a String, so the result is not concatenated
* In two cases (#capture and #cache), a String can be returned that should *never*
be concatenated. We have temporarily created a String subclass called NonConcattingString
which behaves (and is serialized) identically to String, but is not concatenated
by the code that handles deprecated <% %> block helpers. Once we remove support
for <% %> block helpers, we can remove NonConcattingString.
2010-03-15 14:58:05 -04:00
|
|
|
end
|
2005-03-14 18:37:38 -05:00
|
|
|
end
|
2008-06-02 12:12:00 -04:00
|
|
|
|
2007-06-28 14:32:34 -04:00
|
|
|
# Calling content_for stores a block of markup in an identifier for later use.
|
2010-05-15 09:33:30 -04:00
|
|
|
# You can make subsequent calls to the stored content in other templates, helper modules
|
|
|
|
# or the layout by passing the identifier as an argument to <tt>content_for</tt>.
|
|
|
|
#
|
|
|
|
# Note: <tt>yield</tt> can still be used to retrieve the stored content, but calling
|
|
|
|
# <tt>yield</tt> doesn't work in helper modules, while <tt>content_for</tt> does.
|
Add deprecation notices for <% %>.
* The approach is to compile <% %> into a method call that checks whether
the value returned from a block is a String. If it is, it concats to the buffer and
prints a deprecation warning.
* <%= %> uses exactly the same logic to compile the template, which first checks
to see whether it's compiling a block.
* This should have no impact on other uses of block in templates. For instance, in
<% [1,2,3].each do |i| %><%= i %><% end %>, the call to each returns an Array,
not a String, so the result is not concatenated
* In two cases (#capture and #cache), a String can be returned that should *never*
be concatenated. We have temporarily created a String subclass called NonConcattingString
which behaves (and is serialized) identically to String, but is not concatenated
by the code that handles deprecated <% %> block helpers. Once we remove support
for <% %> block helpers, we can remove NonConcattingString.
2010-03-15 14:58:05 -04:00
|
|
|
#
|
2007-06-23 13:49:18 -04:00
|
|
|
# ==== Examples
|
Add deprecation notices for <% %>.
* The approach is to compile <% %> into a method call that checks whether
the value returned from a block is a String. If it is, it concats to the buffer and
prints a deprecation warning.
* <%= %> uses exactly the same logic to compile the template, which first checks
to see whether it's compiling a block.
* This should have no impact on other uses of block in templates. For instance, in
<% [1,2,3].each do |i| %><%= i %><% end %>, the call to each returns an Array,
not a String, so the result is not concatenated
* In two cases (#capture and #cache), a String can be returned that should *never*
be concatenated. We have temporarily created a String subclass called NonConcattingString
which behaves (and is serialized) identically to String, but is not concatenated
by the code that handles deprecated <% %> block helpers. Once we remove support
for <% %> block helpers, we can remove NonConcattingString.
2010-03-15 14:58:05 -04:00
|
|
|
#
|
2007-06-28 14:32:34 -04:00
|
|
|
# <% content_for :not_authorized do %>
|
|
|
|
# alert('You are not authorized to do that!')
|
2007-06-23 13:49:18 -04:00
|
|
|
# <% end %>
|
|
|
|
#
|
2010-05-15 09:33:30 -04:00
|
|
|
# You can then use <tt>content_for :not_authorized</tt> anywhere in your templates.
|
|
|
|
#
|
|
|
|
# <%= content_for :not_authorized if current_user.nil? %>
|
|
|
|
#
|
|
|
|
# This is equivalent to:
|
2007-06-23 13:49:18 -04:00
|
|
|
#
|
2007-06-28 14:32:34 -04:00
|
|
|
# <%= yield :not_authorized if current_user.nil? %>
|
2007-06-23 13:49:18 -04:00
|
|
|
#
|
2010-05-15 09:33:30 -04:00
|
|
|
# <tt>content_for</tt>, however, can also be used in helper modules.
|
|
|
|
#
|
|
|
|
# module StorageHelper
|
|
|
|
# def stored_content
|
|
|
|
# content_for(:storage) || "Your storage is empty"
|
|
|
|
# end
|
|
|
|
# end
|
|
|
|
#
|
|
|
|
# This helper works just like normal helpers.
|
|
|
|
#
|
|
|
|
# <%= stored_content %>
|
|
|
|
#
|
|
|
|
# You can use the <tt>yield</tt> syntax alongside an existing call to <tt>yield</tt> in a layout. For example:
|
2007-06-23 13:49:18 -04:00
|
|
|
#
|
2007-09-24 19:01:50 -04:00
|
|
|
# <%# This is the layout %>
|
2007-06-23 13:49:18 -04:00
|
|
|
# <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
|
|
|
# <head>
|
|
|
|
# <title>My Website</title>
|
|
|
|
# <%= yield :script %>
|
|
|
|
# </head>
|
|
|
|
# <body>
|
|
|
|
# <%= yield %>
|
|
|
|
# </body>
|
|
|
|
# </html>
|
|
|
|
#
|
2010-05-15 09:33:30 -04:00
|
|
|
# And now, we'll create a view that has a <tt>content_for</tt> call that
|
2007-06-23 13:49:18 -04:00
|
|
|
# creates the <tt>script</tt> identifier.
|
|
|
|
#
|
2007-09-24 19:01:50 -04:00
|
|
|
# <%# This is our view %>
|
2007-06-23 13:49:18 -04:00
|
|
|
# Please login!
|
|
|
|
#
|
2007-06-28 14:32:34 -04:00
|
|
|
# <% content_for :script do %>
|
|
|
|
# <script type="text/javascript">alert('You are not authorized to view this page!')</script>
|
2005-03-14 18:37:38 -05:00
|
|
|
# <% end %>
|
|
|
|
#
|
2007-06-28 14:32:34 -04:00
|
|
|
# Then, in another view, you could to do something like this:
|
2007-06-23 13:49:18 -04:00
|
|
|
#
|
2010-03-16 02:05:12 -04:00
|
|
|
# <%= link_to 'Logout', :action => 'logout', :remote => true %>
|
2007-06-23 13:49:18 -04:00
|
|
|
#
|
2007-06-28 14:32:34 -04:00
|
|
|
# <% content_for :script do %>
|
2007-06-23 13:49:18 -04:00
|
|
|
# <%= javascript_include_tag :defaults %>
|
|
|
|
# <% end %>
|
2006-04-25 00:03:51 -04:00
|
|
|
#
|
2011-03-26 17:19:18 -04:00
|
|
|
# That will place +script+ tags for your default set of JavaScript files on the page;
|
|
|
|
# this technique is useful if you'll only be using these scripts in a few views.
|
2005-06-21 02:43:14 -04:00
|
|
|
#
|
2007-09-20 23:40:25 -04:00
|
|
|
# Note that content_for concatenates the blocks it is given for a particular
|
2007-06-28 14:32:34 -04:00
|
|
|
# identifier in order. For example:
|
2006-04-25 00:03:51 -04:00
|
|
|
#
|
2007-06-28 14:32:34 -04:00
|
|
|
# <% content_for :navigation do %>
|
|
|
|
# <li><%= link_to 'Home', :action => 'index' %></li>
|
|
|
|
# <% end %>
|
|
|
|
#
|
2007-09-24 19:01:50 -04:00
|
|
|
# <%# Add some other content, or use a different template: %>
|
Add deprecation notices for <% %>.
* The approach is to compile <% %> into a method call that checks whether
the value returned from a block is a String. If it is, it concats to the buffer and
prints a deprecation warning.
* <%= %> uses exactly the same logic to compile the template, which first checks
to see whether it's compiling a block.
* This should have no impact on other uses of block in templates. For instance, in
<% [1,2,3].each do |i| %><%= i %><% end %>, the call to each returns an Array,
not a String, so the result is not concatenated
* In two cases (#capture and #cache), a String can be returned that should *never*
be concatenated. We have temporarily created a String subclass called NonConcattingString
which behaves (and is serialized) identically to String, but is not concatenated
by the code that handles deprecated <% %> block helpers. Once we remove support
for <% %> block helpers, we can remove NonConcattingString.
2010-03-15 14:58:05 -04:00
|
|
|
#
|
2007-06-28 14:32:34 -04:00
|
|
|
# <% content_for :navigation do %>
|
|
|
|
# <li><%= link_to 'Login', :action => 'login' %></li>
|
|
|
|
# <% end %>
|
|
|
|
#
|
|
|
|
# Then, in another template or layout, this code would render both links in order:
|
|
|
|
#
|
2010-05-15 09:33:30 -04:00
|
|
|
# <ul><%= content_for :navigation %></ul>
|
2007-09-20 23:40:25 -04:00
|
|
|
#
|
|
|
|
# Lastly, simple content can be passed as a parameter:
|
|
|
|
#
|
|
|
|
# <% content_for :script, javascript_include_tag(:defaults) %>
|
|
|
|
#
|
2007-06-28 14:32:34 -04:00
|
|
|
# WARNING: content_for is ignored in caches. So you shouldn't use it
|
|
|
|
# for elements that will be fragment cached.
|
2006-10-22 19:41:11 -04:00
|
|
|
def content_for(name, content = nil, &block)
|
2008-06-06 21:01:14 -04:00
|
|
|
content = capture(&block) if block_given?
|
2011-05-01 06:16:31 -04:00
|
|
|
result = @view_flow.append(name, content) if content
|
2011-04-15 19:09:05 -04:00
|
|
|
result unless content
|
2005-03-14 18:37:38 -05:00
|
|
|
end
|
2006-02-26 14:47:50 -05:00
|
|
|
|
2011-04-16 04:28:47 -04:00
|
|
|
# The same as +content_for+ but when used with streaming flushes
|
|
|
|
# straight back to the layout. In other words, if you want to
|
|
|
|
# concatenate several times to the same buffer when rendering a given
|
2011-04-16 05:34:07 -04:00
|
|
|
# template, you should use +content_for+, if not, use +provide+ to tell
|
|
|
|
# the layout to stop looking for more contents.
|
2011-04-16 04:28:47 -04:00
|
|
|
def provide(name, content = nil, &block)
|
|
|
|
content = capture(&block) if block_given?
|
2011-05-01 06:16:31 -04:00
|
|
|
result = @view_flow.append!(name, content) if content
|
2011-04-16 05:34:07 -04:00
|
|
|
result unless content
|
2011-04-16 04:28:47 -04:00
|
|
|
end
|
|
|
|
|
2009-06-21 12:05:43 -04:00
|
|
|
# content_for? simply checks whether any content has been captured yet using content_for
|
|
|
|
# Useful to render parts of your layout differently based on what is in your views.
|
Add deprecation notices for <% %>.
* The approach is to compile <% %> into a method call that checks whether
the value returned from a block is a String. If it is, it concats to the buffer and
prints a deprecation warning.
* <%= %> uses exactly the same logic to compile the template, which first checks
to see whether it's compiling a block.
* This should have no impact on other uses of block in templates. For instance, in
<% [1,2,3].each do |i| %><%= i %><% end %>, the call to each returns an Array,
not a String, so the result is not concatenated
* In two cases (#capture and #cache), a String can be returned that should *never*
be concatenated. We have temporarily created a String subclass called NonConcattingString
which behaves (and is serialized) identically to String, but is not concatenated
by the code that handles deprecated <% %> block helpers. Once we remove support
for <% %> block helpers, we can remove NonConcattingString.
2010-03-15 14:58:05 -04:00
|
|
|
#
|
2009-06-21 12:05:43 -04:00
|
|
|
# ==== Examples
|
|
|
|
#
|
|
|
|
# Perhaps you will use different css in you layout if no content_for :right_column
|
|
|
|
#
|
|
|
|
# <%# This is the layout %>
|
|
|
|
# <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
|
|
|
# <head>
|
|
|
|
# <title>My Website</title>
|
|
|
|
# <%= yield :script %>
|
|
|
|
# </head>
|
|
|
|
# <body class="<%= content_for?(:right_col) ? 'one-column' : 'two-column' %>">
|
|
|
|
# <%= yield %>
|
|
|
|
# <%= yield :right_col %>
|
|
|
|
# </body>
|
|
|
|
# </html>
|
|
|
|
def content_for?(name)
|
2011-05-01 06:16:31 -04:00
|
|
|
@view_flow.get(name).present?
|
2009-06-21 12:05:43 -04:00
|
|
|
end
|
|
|
|
|
2008-07-15 21:42:22 -04:00
|
|
|
# Use an alternate output buffer for the duration of the block.
|
|
|
|
# Defaults to a new empty string.
|
2009-05-28 17:56:09 -04:00
|
|
|
def with_output_buffer(buf = nil) #:nodoc:
|
|
|
|
unless buf
|
2010-03-09 21:00:28 -05:00
|
|
|
buf = ActionView::OutputBuffer.new
|
2010-07-25 02:37:36 -04:00
|
|
|
buf.force_encoding(output_buffer.encoding) if output_buffer.respond_to?(:encoding) && buf.respond_to?(:force_encoding)
|
2009-05-28 17:56:09 -04:00
|
|
|
end
|
2008-07-15 21:42:22 -04:00
|
|
|
self.output_buffer, old_buffer = buf, output_buffer
|
|
|
|
yield
|
|
|
|
output_buffer
|
|
|
|
ensure
|
|
|
|
self.output_buffer = old_buffer
|
|
|
|
end
|
2009-03-13 03:25:05 -04:00
|
|
|
|
|
|
|
# Add the output buffer to the response body and start a new one.
|
|
|
|
def flush_output_buffer #:nodoc:
|
2009-05-28 17:56:09 -04:00
|
|
|
if output_buffer && !output_buffer.empty?
|
2009-03-13 03:25:05 -04:00
|
|
|
response.body_parts << output_buffer
|
2010-06-28 05:06:03 -04:00
|
|
|
self.output_buffer = output_buffer[0,0]
|
2009-05-28 17:56:09 -04:00
|
|
|
nil
|
2009-03-13 03:25:05 -04:00
|
|
|
end
|
|
|
|
end
|
2005-03-14 18:37:38 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|