module ActionView module Helpers # Capture lets you extract parts of code which # can be used in other points of the template or even layout file. # # == Capturing a block into an instance variable # # <% @script = capture do %> # [some html...] # <% end %> # # == Add javascript to header using content_for # # content_for("name") is a wrapper for capture which will # make the fragment available by name to a yielding layout or template. # # layout.rhtml: # # # # layout with js # # # # <%= yield %> # # # # view.rhtml # # This page shows an alert box! # # <% content_for("script") do %> # alert('hello world') # <% end %> # # Normal view text module CaptureHelper # Capture allows you to extract a part of the template into an # instance variable. You can use this instance variable anywhere # in your templates and even in your layout. # # Example of capture being used in a .rhtml page: # # <% @greeting = capture do %> # Welcome To my shiny new web page! # <% end %> # # Example of capture being used in a .rxml page: # # @greeting = capture do # 'Welcome To my shiny new web page!' # end def capture(*args, &block) # execute the block begin buffer = eval("_erbout", block.binding) rescue buffer = nil end if buffer.nil? capture_block(*args, &block) else capture_erb_with_buffer(buffer, *args, &block) end end # Calling content_for stores the block of markup for later use. # Subsequently, you can make calls to it by name with yield # in another template or in the layout. # # Example: # # <% content_for("header") do %> # alert('hello world') # <% end %> # # You can use yield :header anywhere in your templates. # # <%= yield :header %> # # NOTE: Beware that content_for is ignored in caches. So you shouldn't use it # for elements that are going to be fragment cached. # # The deprecated way of accessing a content_for block was to use a instance variable # named @@content_for_#{name_of_the_content_block}@. So <%= content_for('footer') %> # would be avaiable as <%= @content_for_footer %>. The preferred notation now is # <%= yield :footer %>. def content_for(name, &block) eval "@content_for_#{name} = (@content_for_#{name} || '') + capture(&block)" end private def capture_block(*args, &block) block.call(*args) end def capture_erb(*args, &block) buffer = eval("_erbout", block.binding) capture_erb_with_buffer(buffer, *args, &block) end def capture_erb_with_buffer(buffer, *args, &block) pos = buffer.length block.call(*args) # extract the block data = buffer[pos..-1] # replace it in the original with empty string buffer[pos..-1] = '' data end def erb_content_for(name, &block) eval "@content_for_#{name} = (@content_for_#{name} || '') + capture_erb(&block)" end def block_content_for(name, &block) eval "@content_for_#{name} = (@content_for_#{name} || '') + capture_block(&block)" end end end end