app/helpers/nestive/layout_helper.rb in nestive-0.1.0 vs app/helpers/nestive/layout_helper.rb in nestive-0.2.0

- old
+ new

@@ -1,11 +1,11 @@ module Nestive - + # The Nestive LayoutHelper provides a handful of helper methods for use in your layouts and views. # - # See the documentation for each individual method for detailed information, but at a high level, - # your parent layouts define `area`s of content. You can define an area and optionally add content + # See the documentation for each individual method for detailed information, but at a high level, + # your parent layouts define `area`s of content. You can define an area and optionally add content # to it at the same time using either a String, or a block: # # # app/views/layouts/global.html.erb # <html> # <head> @@ -22,15 +22,15 @@ # <% end %> # </div> # </body> # </html> # - # Your child layouts (or views) inherit and modify the parent by wrapping in an `extend` block - # helper. You can then either `append`, `prepend` or `replace` the content that has previously + # Your child layouts (or views) inherit and modify the parent by wrapping in an `extends` block + # helper. You can then either `append`, `prepend` or `replace` the content that has previously # been assigned to each area by parent layouts. # - # The `append`, `prepend` or `replace` helpers are *similar* to Rails' own `content_for`, which + # The `append`, `prepend` or `replace` helpers are *similar* to Rails' own `content_for`, which # accepts content for the named area with either a String or with a block). They're different to # `content_for` because they're only used modify the content assigned to the area, not retrieve it: # # # app/views/layouts/admin.html.erb # <%= extends :global do %> @@ -49,11 +49,11 @@ # <% replace :content do %> # Normal view stuff goes here. # <% end %> # <% end %> module LayoutHelper - + # Declares that the current layour (or view) is inheriting from and extending another layout. # # @param [Symbol] name # The base name of the file in `layouts/` that you wish to extend (eg `:application` for `layouts/application.html.erb`) # @@ -68,27 +68,35 @@ # # # app/controllers/admin/posts_controller.rb # class Admin::PostsController < ApplicationController # # You can disable Rails' layout rendering for all actions # layout nil - # + # # # Or disable Rails' layout rendering per-controller # def index - # render :layout => nil + # render :layout => nil # end # end # # # app/views/admin/posts/index.html.erb # <%= extends :admin do %> # ... # <% end %> - def extends(name, &block) - capture(&block) - render(:file => "layouts/#{name}") + def extends(layout, &block) + # Make sure it's a string + layout = layout.to_s + + # If there's no directory component, presume a plain layout name + layout = layout.include?('/') ? layout : "layouts/#{layout}" + + # Capture the content to be placed inside the extended layout + content_for(:layout).replace capture(&block) + + render :file => layout end - - # Defines an area of content in your layout that can be modified or replaced by child layouts + + # Defines an area of content in your layout that can be modified or replaced by child layouts # that extend it. You can optionally add content to an area using either a String, or a block. # # Areas are declared in a parent layout and modified by a child layout, but since Nestive # allows for multiple levels of inheritance, a child layout can also declare an area for it's # children to modify. @@ -119,17 +127,17 @@ def area(name, content=nil, &block) content = capture(&block) if block_given? append(name, content) render_area(name) end - + def block(name, content=nil, &block) ActiveSupport::Deprecation.warn("block() is deprecated and will be removed very soon, please use area() instead") area(name, content, &block) end - - # Appends content to an area previously defined or modified in parent layout(s). You can provide + + # Appends content to an area previously defined or modified in parent layout(s). You can provide # the content using either a String, or a block. # # @example Appending content with a String # <% append :sidebar, "Some content." %> # @@ -144,13 +152,14 @@ # @param [String] content # Optionally provide a String of content, instead of a block. A block will take precedence. def append(name, content=nil, &block) content = capture(&block) if block_given? add_instruction_to_area(name, :push, content) + nil end - # Prepends content to an area previously declared or modified in parent layout(s). You can + # Prepends content to an area previously declared or modified in parent layout(s). You can # provide the content using either a String, or a block. # # @example Prepending content with a String # <% prepend :sidebar, "Some content." %> # @@ -165,13 +174,14 @@ # @param [String] content # Optionally provide a String of content, instead of a block. A block will take precedence. def prepend(name, content=nil, &block) content = capture(&block) if block_given? add_instruction_to_area(name, :unshift, content) + nil end - - # Replaces the content of an area previously declared or modified in parent layout(s). You can + + # Replaces the content of an area previously declared or modified in parent layout(s). You can # provide the content using either a String, or a block. # # @example Prepending content with a String # <% replace :sidebar, "New content." %> # @@ -186,39 +196,40 @@ # @param [String] content # Optionally provide a String of content, instead of a block. A block will take precedence. def replace(name, content=nil, &block) content = capture(&block) if block_given? add_instruction_to_area(name, :replace, [content]) + nil end - + private - + # We record the instructions (declaring, appending, prepending and replacing) for an area of # content into an array that we can later retrieve and replay. Instructions are stored in an - # instance variable Hash `@_area_for`, with each key representing an area name, and each value - # an Array of instructions. Each instruction is a two element array containing a instruction + # instance variable Hash `@_area_for`, with each key representing an area name, and each value + # an Array of instructions. Each instruction is a two element array containing a instruction # method (eg `:push`, `:unshift`, `:replace`) and a value (content String). # # @_area_for[:sidebar] # => [ [:push,"World"], [:unshift,"Hello"] ] # # Due to the way we extend layouts (render the parent layout after the child), the instructions - # are captured in reverse order. `render_area` reversed them and plays them back at rendering + # are captured in reverse order. `render_area` reversed them and plays them back at rendering # time. # # @example # add_instruction_to_area(:sidebar, :push, "More content.") def add_instruction_to_area(name, instruction, value) @_area_for ||= {} @_area_for[name] ||= [] @_area_for[name] << [instruction, value] end - + # Take the instructions we've gathered for the area and replay them one after the other on # an empty array. These instructions will push, unshift or replace items into our output array, # which we then join and mark as html_safe. # - # These instructions are reversed and replayed when we render the block (rather than as they + # These instructions are reversed and replayed when we render the block (rather than as they # happen) due to the way they are gathered by the layout extension process (in reverse). # # @todo is `html_safe` "safe" here? def render_area(name) output = [] @@ -227,6 +238,6 @@ end output.join.html_safe end end -end \ No newline at end of file +end