That's an interesting solution, in principle similar to the solution I
had for the same problem. However, there are some very un-Rails-ish
statements in your tag implementation that make your intentions
unclear. For example, you find PageParts by their page_id, when really
you should use the existing association:
ancestor_part_names = ancestor.parts.map(&:name)
Next, you use Array.detect where include? will suffice:
if ancestor_part_names.include?(layout_name)
Radiant's page model offers a shortcut method to getting a part by name,
so your next detect call is also unneeded. In fact this whole block of
statements can be replaced by one line:
tag.locals.page = ancestor if ancestor.part(layout_name)
Page#part will return nil if no matching part is found. Better yet, use
find/detect instead of each:
tag.locals.page = page.ancestors.find {|p| p.part(layout_name) }
There are several other things in your tag definitions that could use
attention, I'll probably make a pass at them later.
Sean
Witter Cheng wrote:
> I have revived this post in order to get comments on my implementation
> of nested layouts. I created custom tags to allow for this. Here is my
> solution to the scenario given above.
>
> First, in "/", create a page part called "layout" to be used as the
> nested layout. It will look like this:
>
> <r:layout_part name="left">
> <div class="left">
> <r:content part="left" />
> </div>
> </r:layout_part>
>
> <r:layout_part name="main">
> <div class="main">
> <r:content part="main" />
> </div>
> </r:layout_part>
>
> Then edit the "body" page part of "page1" and "page2" to look like this:
>
> <r:layout />
>
> The code behind r:layout and r:layout_part follows:
>
> ---------------------
>
> # the layout is actually a page part
> # if the named page part is not a part of the current page
> # ancestors are searched until the named page part is found
> tag 'layout' do |tag|
> ret_val = ""
> layout_name = tag.attr['layout_name'] || "layout"
> page = tag.locals.page
> page_part_names =
> page.instance_variable_get(:@parts).collect(&:name)
> parts_for_layout = tag.attr['parts'] ||
> page_part_names.delete_if{|part| part == "body" || part == layout_name }
> found = nil
> og_page_id = page.id
> if !page_part_names.include? layout_name
> page.ancestors.each do |ancestor|
> pp =
> PagePart.find_all_by_page_id(ancestor.instance_variable_get(:@attributes)["id"],
>
> :include => [:page])
> ancestor_part_names = pp.collect(&:name)
> if ancestor_part_names.detect{|part| part == layout_name
> } && !found
> tag.locals.page = pp.detect{|p| p.name ==
> layout_name}.page
> found = 1
> end
> end
> tag.render('content', {"part" => layout_name,
> "parts_page_id" => og_page_id})
> else
> tag.render('content', {"part" => layout_name})
> end
> end
>
> tag 'layout_part' do |tag|
> part_to_render = tag.attr['name']
>
> # this mess is necessary; trying to get tag_binding_stack
> directly from the context returns a different array
> page = tag.locals.page
> response = page.instance_variable_get(:@response)
> template = response.instance_variable_get(:@template)
> controller = template.instance_variable_get(:@controller)
> pagee = controller.instance_variable_get(:@page)
> context = pagee.instance_variable_get(:@context)
> tbs = context.instance_variable_get(:@tag_binding_stack)
>
> parts_page_id = tbs.last.attributes["parts_page_id"]
>
> # if the layout is in the same page as the parts being laid out
> # the parts_page_id will not have been specified, so do not
> reset the tag page
> unless parts_page_id.blank?
> parts_page = Page.find(parts_page_id)
> tag.locals.page = parts_page
> end
>
> # e.g. name of part is specified in the tag as 'blah'
> # but the page calling the layout tag which wraps this tag does
> not have a 'blah' part
> # in such a case don't display this tag
> # NOTE: there is likely a more efficient way to do this check
> than a db query
> pp = PagePart.find_by_name_and_page_id(part_to_render,
> parts_page_id || tag.locals.page.id)
> tag.expand unless pp.blank?
> end
>
>
> ---------------------
>
> Thank you in advance for any criticism/comments.
>
_______________________________________________
Radiant mailing list
Post: [email protected]
Search: http://radiantcms.org/mailing-list/search/
Site: http://lists.radiantcms.org/mailman/listinfo/radiant