FreeMarker is the template framework used for user interface.
To tell FreeMarker to log error messages instead of rendering them to HTML, you set a Jive system property: jive.freemarker.logError to true.
You won't always get nice feedback pointing to the line number of the FreeMarker error. On occasion if the syntax is mangled enough you will get a FileNotFoundException from FreeMarker, and the application will give you a SystemError. In that case you need to back your changes out to the point where you're getting clear feedback.
If you're overriding a template from a plugin, on occasion when there is a failure it will default back to the original FreeMarker template.
You can give the template authors complete freedom over which classes' static methods they use by placing the static models hash into your template root model with
root.put("statics", BeansWrapper.getDefaultInstance().getStaticModels());
This object exposes just about any class' static methods if it's used as a hash with class name as the key. You can then use expression like
${statics["java.lang.System"].currentTimeMillis()}
in your template. You can give the template authors complete freedom over which enum classes they use by placing the enum models hash into your template root model with
root.put("enums", BeansWrapper.getDefaultInstance().getEnumModels());
This object exposes any enum class if it's used as a hash with class name as the key. You can then use an expression like this in your template:
${enums["java.math.RoundingMode"].UP}
We
override the standard FreeMarker manager with our custom manager
to provide access to application resources from the UI templates.
Some example resources are: JiveGlobals, JiveConstants, LocaleUtils and StringUtils.
There's an update delay in FreeMarker manager set to cache each FreeMarker file in memory forever. However, you can change the delay by setting the system property to a number, the value is in seconds that must elapse before checking if there's a newer version of the template file.
jive.freemarker.templateUpdateDelay = 123
On JiveFreemarkerManager there's a method to flush the cache:
JiveFreemarkerManager.flushTemplateCache()
As part of the performance tuning done for CS 2.0, we increased the template caching behaviors to allow for caching all FTLs in the application (previously only about 3/4 of the templates could be cached in a stressed system). Additionally, the interval at which CS would check for new template files was quite low -- 5 seconds. This meant that the FTL engine would hit the file system for each accessed FTL every five seconds. This number has been set to an indefinite value to improve production performance for 2.0.
As a consequence of these changes, developers may not see changes to FTLs when running in a standard CS configuration. To restore this desired behavior, we've added checks to the FTL manager that, if jive.devMode is enabled, FTL caching and change checks will be entirely turned off. To enable this behavior:
Set a java system property "-Djive.devMode=true"
or
Set a jive property (jive_startup.xml or in jiveProperty) with the same name and value true
Additionally, these values can be individually tuned when not in devMode with the following Jive Properties:
jive.freemarker.templateUpdateDelay | The interval after which FreeMarker will check for changes to an FTL file |
jive.freemarker.strongTemplateCacheSize | The number of hard references FTL will keep in the cache |
jive.freemarker.weakTemplateCacheSize | The number of weak references FTL will keep in the cache when hard references are exhausted |
The conditions when the Jive properties would need to be changed are few and far between, change with caution.
Here's how to handle missing values: http://freemarker.sourceforge.net/docs/dgui_template_exp.html#dgui_template_exp_missing
Some explanation: http://freemarker.sourceforge.net/docs/app_faq.html#faq_picky_about_missing_vars
You need to "sanitize" your output to prevent various XSS security hacks and exploits, involving hijacking HTML. This prevents people working in array blocks, end of string declarations, etc., creating new HTML tags like script tags, closing tags to deface the page, etc.
Sanitize your output using the ?html and ?javascript FreeMarker directives; for example, ${community.name?html}
communityName = "${community.name?javascript}";
Under almost every circumstance, user input which is rendered should be either:
' + https://yourcommunity.com/ ;
foo?url
or if the character encoding is not specified by you application
foo?url('ISO-8859-1')
or whatever your encoding is.
foo?html
when using a FreeMarker variable inside of a JavaScript statement
foo?js_string
Prototype syntax and FreeMarker syntax are very similar and easy to mix up; for example, Prototype is like this:
$('somediv').close();
${user.name}
Avoid using method calls through the statics mechanism. All data should be passed in to you through an Action method. If you need something from some other manager class or object in the system, proxy the call through the action method. This better insulates you from changes in the API during upgrades, because the call will be caught at compile time, not at run time.
When you create a variable assignment use a variable unlikely to collide with other variables, because FreeMarker doesn't complain when you reassign a variable. For example if you
<#assign user = 'Nate'>
you may be reassigning the variable user that was assigned in a superclass of your action, for example in JiveActionSupport.
For example:
<@jive.userAvatar>
These are specific Jive macros added via the JiveFreemarkerManager.
Here are some examples of Jive macros:
<#macro displayUserDisplayName user=''>
<#macro userDisplayNameLink user='' rel=''>
<#macro userAvatar user='' size=16 class='' useLinks=true>
<#macro userStatusLevel user='' container='' showPoints=false>
<#macro jiveContentList content=content showContainer=false limit=-1>
<#macro importJavascript scripts>
The only way to do that right now is to overlay template/global/include/jive-macros.ftl. We recommend avoiding this if possible.
JiveFreemarkerManager is specified as a spring bean --> freemarkerManager. You could simply modify the bean to point to your custom FreeMarker manager, which extends the method:
public static void populateStatics(Map<String, Object> model) {
and adds in any classes you want to the static model.
Generally you should follow the model-view-controller (MVC) pattern, making the FTL only responsible for display. Examples of FTL logic would be looping over a collection to generate items in a list or rows in a table.
If you have to manipulate data in any way for display you should put that logic in an action.
OGNL is the way FreeMarker resolves object and method references. Struts depends on OGNL. Struts OGNL Documentation: http://struts.apache.org/2.0.11.2/docs/ognl.html
When mixing HTML and FreeMarker markup where the FreeMarker notation is nested inside an HTML attribute or other value that is in quotes, please toggle the use of double or single quotes. To clarify:
<a href="></a>">bad</a>
<a href='></a>'>bad</a>
<a href='></a>'>good</a>
<a href="></a>">most preferred</a>
Here are the benefits of doing so: