struts-issues mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Jasper Rosenberg (JIRA)" <j...@apache.org>
Subject [jira] [Commented] (WW-4145) file.ftl in xhtml theme directly references xhtml controlfooter.ftl
Date Wed, 31 Jul 2013 02:31:50 GMT

    [ https://issues.apache.org/jira/browse/WW-4145?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13724776#comment-13724776
] 

Jasper Rosenberg commented on WW-4145:
--------------------------------------

Okay, I think I actually have a working, non-invasive solution.  I will try to get a real
patch together tomorrow, but home right now, and not really set up well.  This code is tested
though and works.  The basic solution is to support special notation for theme hierarchy templates.
 Basically, if you see "**" (you can choose any token), it assumes that the following path
component is a theme that needs to be searched via the hierarchy.

Usage looks like for xhtml/form.ftl for example:
{code}
<#include "/${parameters.templateDir}/**${parameters.theme}/form-validate.ftl" />
<#include "/${parameters.templateDir}/**${parameters.theme}/form-common.ftl" />
<#if (parameters.validate?default(false))>
  onreset="${parameters.onreset?default('clearErrorMessages(this);clearErrorLabels(this);')}"
<#else>
  <#if parameters.onreset??>
  onreset="${parameters.onreset?html}"
  </#if>
</#if>
>
<#include "/${parameters.templateDir}/**${parameters.theme}/control.ftl" />
{code}

This has a lot of advantages because you can leave off the "**" if you don't want to allow
it to expand.

Once I took this approach, the code became much simpler and for the most part let me leverage
the existing hierarchy traversal methods already provided by the TemplateEngine.

Here is the new top level template loader:

{code:java}
import java.io.IOException;
import java.io.Reader;
import java.util.List;

import org.apache.struts2.components.template.Template;
import org.apache.struts2.components.template.TemplateEngine;

import freemarker.cache.TemplateLoader;

/**
 * When loading a template, if sees theme token in path, does a template search through
 * theme hierarchy for template, starting at the theme name after the token.
 */
public class ThemeTemplateLoader implements TemplateLoader {
    private final String themeExpansionToken;
    private final TemplateLoader parent;
    private final TemplateEngine templateEngine;
    
    public ThemeTemplateLoader(
        String themeExpansionToken, TemplateLoader parent, TemplateEngine templateEngine)
{
        this.themeExpansionToken = themeExpansionToken;
        this.parent = parent;
        this.templateEngine = templateEngine;
    }
    
    /** {@inheritDoc} */
    public Object findTemplateSource(String name) throws IOException {
        int tokenIndex = (name == null) ? -1 : name.indexOf(themeExpansionToken);
        if (tokenIndex < 0) {
            return parent.findTemplateSource(name);
        }

        int themeEndIndex = name.indexOf('/', tokenIndex);
        if (themeEndIndex < 0) {
            return parent.findTemplateSource(name);
        }

        Template template = new Template(
            name.substring(0, tokenIndex - 1), 
            name.substring(tokenIndex + 1, themeEndIndex), 
            name.substring(themeEndIndex + 1));
        
        List<Template> possibleTemplates = template.getPossibleTemplates(templateEngine);
        for (Template possibleTemplate : possibleTemplates) {
            Object templateSource = parent.findTemplateSource(possibleTemplate.toString());
            if (templateSource != null) {
                return templateSource;
            }
        }

        return null;
    }
    
    /** {@inheritDoc} */
    public long getLastModified(Object templateSource) {
        return parent.getLastModified(templateSource);
    }

    /** {@inheritDoc} */
    public Reader getReader(Object templateSource, String encoding) throws IOException {
        return parent.getReader(templateSource, encoding);
    }

    /** {@inheritDoc} */
    public void closeTemplateSource(Object templateSource) throws IOException {
        parent.closeTemplateSource(templateSource);
    }
}
{code}

The only necessary integration is in the FreemarkerManager.  Just inject the "ftl" Template
engine, and in init() change:
{code:java}
    config.setTemplateLoader(createTemplateLoader(servletContext, templatePath));
{code}

to 

{code:java}
        config.setTemplateLoader(new ThemeTemplateLoader(
            "**", 
            createTemplateLoader(servletContext, templatePath), 
            templateEngine));
{code}
                
> file.ftl in xhtml theme directly references xhtml controlfooter.ftl
> -------------------------------------------------------------------
>
>                 Key: WW-4145
>                 URL: https://issues.apache.org/jira/browse/WW-4145
>             Project: Struts 2
>          Issue Type: Bug
>          Components: Other
>    Affects Versions: 2.3.15.1
>            Reporter: Jasper Rosenberg
>            Assignee: Lukasz Lenart
>              Labels: freemarker, tags, xhtml
>             Fix For: 2.3.16
>
>
> Should use $\{parameters.theme} instead so can be used in theme extension.
> {code}
> <#include "/${parameters.templateDir}/${parameters.theme}/controlheader.ftl" />
> <#include "/${parameters.templateDir}/simple/file.ftl" />
> <#include "/${parameters.templateDir}/${parameters.theme}/controlfooter.ftl" />
> {code}

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira

Mime
View raw message