Re: Multiple layout section override ?
Daniel Dekany <[email protected]> Sun, 10 Mar 2013 12:42:55 +0100
| Newsgroups | gmane.comp.web.freemarker.user |
|---|---|
| Message-ID | <[email protected]> |
Saturday, March 9, 2013, 2:00:38 PM, Albert Kam wrote:
> Thanks for the ideas.
>
> I have tried the macro solution from your reply, seems great !
>
> the layout file :
> <#macro defaultHeader>
> defaultHeader here
> </#macro>
>
> <#macro defaultFooter>
> defaultFooter here
> </#macro>
>
> <#macro layout header=defaultHeader footer=defaultFooter>
> <@header />
> <#nested>
> <@footer />
> </#macro>
>
> the 'page' file that overrides a header n provide a body as usual:
> <#macro overrideHeader>
> header overriden
> </#macro>
>
> <@layout header=overrideHeader>
> body overriden
> </@layout>
>
> The output is :
> header overriden
> body overriden
> defaultFooter here
>
> ------------------
>
> I have not tried the java directive yet. I would like to clarify
> some points before trying it out :
>
>> The layout macro need to push a TemplateHashModel into a stack that's stored in a custom Environment attribute,
> How to do this inside the macro, is it by using #assign directive
> to store to the global variable so it can be fetched later from the
> TemplateDirectiveModel's Environment via the getGlobalVariable() ?
> If yes, how do i assign a 'hash' to a global variable ? And i dont
> see any stack in the Environment api doc.
You can't, or at least, shouldn't implement the more technical parts
of this in FTL. FTL, being an MVC View language, really just meant to
get everything ready from the data-model or from a directive/method
that was implemented in Java. So certainly you need to write a few
directives like:
- <@my.setBlock name="whatever">output will be captured here</@my.push>
which stores the captured output into the top hash of said stack.
- my.blocks.whatever: get an earlier set block from the top hash of
the stack.
- For convenience, maybe: <@my.printBlock name="whatever" />
which is basically <#noesacpe>${my.blocks.whatever}</#noescape>.
- <@my.collectBlocks>...</@>
which pushes a new empty hash into said stack, then pops it at the
end
Then can use these when writing macros and just forgat about the
technical parts.
As of the technical parts... freemarker.core.Environment has a
set/getCustomAttribute method. There's no restriction regarding the
type of the attribute value, so there *you* can implement that stacks.
As of the hash thing... My quick idea was that the stack items are
themselves TemplateHashModelEx instances, so that you can easily
access them from the templates, but this really and unimportant
detail, and above I haven't even used it in that form. Because above
my.blocks is a TemplateHashModelEx that shows the topmost stack item.
Anyway, this should really be a core feature of FreeMarker, but I
don't think I will have time to implement this in the near future,
so...
>> then call #nested.
> This is as simple as providing <#nested> in the macro, correct ?
Yes.
>> Then, @block should capture the content generated inside its body, get the topmost TemplateHashModel from said
> stack, and put the captured content into with block name (like"heading") as the key.
> So, this means that the <#nested> in the layout doesnt produce any output at all.
Yes.
> And to produce the header, body, footer, i have to loop all the
> captured contents stored in the global variable, correct ?
Well, I would put them into that stack that's stored in an Envionment
attribute, but that's similar to a global variable in its scope and
life-cycle.
> And if this is so, what is the convenient way to provide a default
> content for a section that might not be overriden ?
For example, <@my.printBlock name="whatever" /> could have optionally
nested content that provides the default value.
> Thank you so much !
>
>
> On Sat, Mar 9, 2013 at 7:53 AM, Daniel Dekany <[email protected]> wrote:
> Wednesday, March 6, 2013, 2:46:26 PM, Albert Kam wrote:
>
>> I am aware that i can use macros for layouting, for example, a main
>> layout that contains header, left body section, center body section, footer.
>>
>> Based on the examples i have googled, like this one here
>> http://wendefer.blogspot.com/2007/09/handy-tip-for-layouts-in-freemarker.html,
>> i can use <#nested> in the main layout for dynamic values for other
>> templates that use this main layout macro.
>>
>> But in my case, i would like the other templates to be able to
>> 'override' more than 1 <#nested>, for example, providing the content
>> of left body section -and- center body section (like apache tiles).
>>
>> Is this supported, or maybe is there any other approaches to do this ?
>
> Sadly, there's still no built-in solution for this. I have seen two
> approaches to work this around. First is passing macros to the layout
> macro:
>
> <#macro myHeading>
> ...
> </#macro>
>
> <#macro myFooter>
> ...
> </#macro>
>
> <@myApp.page heading=myHeading body=myFooter>
> ... this is the body ...
> </@myApp.page>
>
> It's kind of noisy though. So I would rather implement this (some
> deeper FreeMarker knowledge is needed):
>
> <@myApp.page>
> <@block name="heading">
> ...
> </@block>
> <@block name="body">
> ...
> </@block>
> <@block name="footer">
> ...
> </@block>
> </@myApp.page>
>
> Here @block has to be implemented by you, in Java
> (TemplateDirectiveModel). The layout macro need to push a
> TemplateHashModel into a stack that's stored in a custom Environment
> attribute, then call #nested. Then, @block should capture the content
> generated inside its body, get the topmost TemplateHashModel from said
> stack, and put the captured content into with block name (like
> "heading") as the key.
>
> --
> Best regards,
> Daniel Dekany
>
>
> ------------------------------------------------------------------------------
> Symantec Endpoint Protection 12 positioned as A LEADER in The Forrester
> Wave(TM): Endpoint Security, Q1 2013 and "remains a good choice" in the
> endpoint security space. For insight on selecting the right partner to
> tackle endpoint security challenges, access the full report.
> http://p.sf.net/sfu/symantec-dev2dev
> _______________________________________________
> FreeMarker-user mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/freemarker-user
>
>
>
--
Best regards,
Daniel Dekany
------------------------------------------------------------------------------
Symantec Endpoint Protection 12 positioned as A LEADER in The Forrester
Wave(TM): Endpoint Security, Q1 2013 and "remains a good choice" in the
endpoint security space. For insight on selecting the right partner to
tackle endpoint security challenges, access the full report.
http://p.sf.net/sfu/symantec-dev2dev