Process freemarker snippets

Hi all! I’ve been looking for this but couldn’t find anything. Our customer wants to setup a new component where they can insert freemarker snippets. Something similar to rich text snippets, but adding the possibility to use resource bundles inside and some additional logic.

We saw it’s possible with the freemarker template library for java, but this will only work for native freemarker tags, it’s not possible to, for example, make use of the JspTagLib, so the <@fmt.message> it’s not allowed (only for Freemarker Servlets according to the logs).

We can bypass this by analyzing the snippet for resource bundles, but it’s a bit of a dirty solution and it would be nice to know if there could be a nice to actually make use of @fmt or other tag libraries.

Thanks!

Hi Pablo,

If the authors want to enter variables to be expanded by resource bundles, then you don’t need FreeMarker, but you can let them do it and replace those variables in your template.
See this page:

Regards,

Woonsan

Hi Woonsan,

Probably I wasn’t very explanatory, but I don’t think that’s what we want. The thing is that we want, from within a component, evaluate and process a piece of freemarker. This is working fine with the Template java class from freemarker.template (https://freemarker.apache.org/docs/api/index.html). The problem is that this APIs will only evaluate core native freemarker tags, and import other libraries is not allowed, so the author can’t add @fmt or also @hst functionalities.

We can manually find a solution for the resource bundles, but scanning the code looking for keys and then querying the repo and replacing all these values is not the cleanest solution, that’s what I was asking.

Thanks!

I don’t have a solution for your problem, but is this really a robust design? Giving editors that much control can make it quite difficult to maintain a proper site. Can’t you use a variety of catalog components with template variants to give them the flexibility they need?

Hi Jasper,

Yes that’s another discussion, we already mentioned them that this is not the way to go, but this is supposed to be only for specific embedded html that will come from third-parties that are providing special content. I also thought that there’s no solution rather than manually handle the messages, but it was worth the shot. Thanks!

I suppose you could submit the template to a servlet for processing. You can do this in your component and then add the response to the reponse.

There’s a solution, which I would avoid if possible. But it’s technically possible. Judgment based on requirements is yours. :wink:

All right, here we go:

Suppose you have a document with a simple string field where your power user wants to type HTML + FreeMarker template. e.g, /content/documents/myhippoproject/specialone/specialone/@myhippoproject:fmcontent.ftl (string) = “blah blah…”.
(The path must end with “.ftl”.)

And, suppose you have an HstComponent at configuration, “body”, having a child configuration, “fmcontentcomp” associated with another HstComponent. Both components can access the document.

Now, as an example, the “body” component simply “hst:include” the child component, “fmcontentcomp”, which sets the renderPath dynamically through HstResponse.setRenderPath(String) in its #doBeforeRender() like the following:

response.setRenderPath("jcr:" + document.getPath() + "/myhippoproject:fmcontent.ftl");

Regards,

Woonsan

1 Like

Hi Woonsan! Thanks for your response, it does a seem a bit of a tricky solution :grin: but it could work indeed. Before I try this, the first that comes to my mind is: how is the user going to manage this? Because two different components need to be nested for this to work, is this doable from the components catalog?

Hi Pablo,

I found an easier and cleaner solution.
You don’t need to have a nested child component. Instead, in your FreeMarker template of the component (e.g, “body” component mentioned earlier), use “?interprete” built-in [1].
For example, if you put the following in the template, it will work:

<#-- Note: That r was needed so that the ${var} is not interpreted below. -->
<#assign templateSource = r"Site Content Base Path: ${hstRequestContext.siteContentBasePath}">
<#assign inlineTemplate = templateSource?interpret>
<@inlineTemplate />

Now, you can replace the first line with this (from document property):

<#assign templateSource = document.powerUserTemplate>

This approach is better than my previous solution because:

  • no need to have a nested component. So, no complexity in catalog component configuration.
  • no need to suffix the property with ‘.ftl’ any more.
  • no worry about cache invalidation. The previous solution has a problem of cache invalidation from the default cache setting of HST.

Regards,

Woonsan

[1] https://freemarker.apache.org/docs/ref_builtins_expert.html#ref_builtin_interpret

1 Like

Hi Woonsan,

The intepret built-in is great! Didn’t know about it, this makes it very easy! Thanks a lot!