Every component can be rendered by using a view. A View is a script, usually a JSP file.
The module tag allows to render other components. The path or the node need to be passed.
A node needs to be associated to a template to be displayed in a full HTML page. A template will define which element to display and where to display them, gathering different component views in one single HTML page.
Templates are created with the Studio. Page templates are specially created for pages, and Content templates are created for all other type of content. The content templates are associated to a node type.
It's possible to limit templates to some users based on permissions. For example, templates showing some private areas or allowing to edit the content can be hidden for normal users.
A node can be associated to a template - this is the case for all page nodes. A template must be specified at creation time. The template is set in the property j:templateNode, defined by the mixin type jmix:hasTemplateNode
The user can also force the choice of a template by specifiying in the url the name of the template, before the .html extension. For example,
http://localhost:8080/cms/render/default/en/sites/ACME/home/news/maincontent/news_36.content-template.html
will use the template named content-template to display the node news_36.
Default templates are used automatically, if no specific template has been requested by the user, and if no template is associated to a node. As multiple templates can be used for one single node, and only one need to be selected, a priority can be defined. The template with the highest priority will be selected.
If no template is specified in the URL, no template associated to the node and no default template can be found, the node cannot be displayed and the system will throw a 404 error.
A template must either have an associated view, or must be contained inside another template. If a view is defined, it will be called to render the template. If not, the parent template will be called instead. This allows to cascade templates, from the most specific template to more global templates, defining standard headers and footers. The top-level template, defining all common areas, is usually called the base template.
The template sequencem that will be used for the rendering, is then defined as :
Building a page is a matter of aggregating the template and the requested node. This node is called the main resource, it's the one that we can find in the URL, and which contains the information to be displayed.
When a page need to be built, Jahia will look for the template node. The template node will defined the layout, and which information will be displayed from the main resource.
To use content from the main resource, some components are available in the studio.
Areas can be defined in the JSP views, with template:area tags, or in the templates, with the area component. The goal of an area is to display content coming from a node next in the templates sequence. An area is said to be enabled under one node if the list named like the area is present under that node. For example, an area maincontent defined in the template view is enabled in the main resource if the list maincontent is created under the main resource.
Area are represented as blue blocks in the studio.
For example, let's use the same the same templates sequence as before - template view, base template, home template and home page.
Absolute area are similar to area, but do not use the templates sequence to resolve the list to display - they use an ancestor of the main resource instead. A level of ancestor can be specified - 0 is for the home page level, 1 for the first sub pages level, etc.. If no level is specified, the content list will be taken from the home page of the site.
Absolute areas are represented as red blocks in the studio.
This component will call a specific view on the main resource node directly. It can be used in content templates only. It's represented in the studio as a grey area. It is used to gather in one complex templates different views of the same node - for example, in the wiki wiki-content template, we can find multiple main resource display components. Here in the history tab, the history and the compare views are displayed one on top of the other :
The view row.jsp is fully rendered. As home/pagecontent does not contain any other node, the home/pagecontent area rendering is finished. The view template.myset.jsp finishes its execution. The page is fully rendered.
An overview of all currently registered filters can be viewed in a Jahia Tools area JSP when the Jahia is running: http://localhost:8080/tools/renderFilters.jsp.
Jahia supports filter configuration using Spring bean definition files.
Default filter chain is defined in the applicationcontext-renderer.xml
Every filter needs to define a priority, which defines the order in which the filters will be executed.
<bean class="org.jahia.services.render.filter.portlet.PlutoProcessActionFilter">
<property name="priority" value="-3"/>
<property name="applyOnConfigurations" value="page"/>
</bean>
<bean class="org.jahia.services.render.filter.ExternalizeHtmlFilter">
<property name="priority" value="-1"/>
<property name="applyOnModes" value="live,preview"/>
<property name="applyOnConfigurations" value="page"/>
<property name="htmlExternalizationService" ref="HtmlExternalizationService"/>
</bean>
<bean class="org.jahia.services.render.filter.StaticAssetsFilter">
<property name="priority" value="0"/>
<property name="applyOnConfigurations" value="page"/>
<property name="applyOnTemplateTypes" value="html,edit,html-.*"/>
<property name="scriptEngineUtils" ref="scriptEngineUtils"/>
<property name="ajaxTemplate" value="/modules/assets/WEB-INF/scripts/ajaxResources.groovy"/>
<property name="template" value="/modules/assets/WEB-INF/scripts/resources.groovy"/>
</bean>
Any module can define its own filters to be executed. Filters are defined in a Spring bean definition file in an XML file (with any arbitrary name) in the templates/<module-name>/META-INF/spring/ folder. In order to define module filters, you simply need to provide a list of filter beans. The filters will be added to the render chain and executed for every request for all modules.
The priority defines where the filter will be inserted in the render chain. If the priority is > to 16, it will be executed the first time the resource is generated, and then the result will be cached. If the priority is < to 16, it will be reevaluated each time the resource is served. Be careful, this is very consuming in terms of performance.
An example of a filter definition for the Jahia Wiki module, located in the the templates/wiki/META-INF/spring/ folder, is:
<bean name="WikiFilter" class="org.jahia.modules.wiki.filter.WikiFilter">
<property name="priority" value="90"/>
<property name="syntaxFactory" ref="defaultSyntaxFactory"/>
<property name="inputSyntax" value="xwiki/2.0"/>
<property name="outputSyntax" value="xhtml/1.0"/>
<property name="applyOnNodeTypes" value="jnt:wikiPage"/>
<property name="applyOnTemplates" value="syntax"/>
</bean>
Any filter, extending org.jahia.services.render.filter.AbstractFilter
, can accept several types of conditions that control filter execution. If all conditions are matched, the filter is executed. Otherwise it is bypassed and the execution is continued with the next filter in the chain. An example of a filter, which is only executed for nodes of type jnt:wikiContent, was already given above. More conditions can be provided using:
More advanced configuration (using regular expressions for matching, NOT conditions or any arbitrary custom condition can be achieved by using filter's conditions property and providing a list of condition beans (instances of classes that implement org.jahia.services.render.filter.AbstractFilter.ExecutionCondition
). Please, consult the documentation of org.jahia.services.render.filter.AbstractFilter
for more details.
A filter is single class implementing the org.jahia.services.render.filter.RenderFilter
interface.
The interface defines mainly one method to implement:
public String doFilter(RenderContext renderContext, Resource resource, RenderChain chain) throws RenderFilterException;
This method returns the final output after filtering. The chain attribute gives the possibility to get the result generated by the remaining chain. This result can be used as an input for the filter.
If the filter needs to transform the output of the chain, it needs to call:
String out = chain.doFilter(renderContext, resource);
So, a basic filter, replacing all occurrences of letter a by letter b, would look like:
public String doFilter(RenderContext renderContext, Resource resource, RenderChain chain)
throws RenderFilterException {
String out = chain.doFilter(renderContext, resource);
return out.replace("a","b");
}
A filter can also break the chain, by returning its own content and not calling the rest of the chain. The following filter will just return some information on the node that was supposed to be displayed, but won't display the template itself :
public String doFilter(RenderContext renderContext, Resource resource, RenderChain chain)
throws RenderFilterException {
return resource.getNode().getPath() + " / " + resource.getResolvedTemplate();
}
An abstract class org.jahia.services.render.filter.AbstractFilter should be used as a base class for a new filter, which allows to specify execution conditions for a filter. In your filter extends the AbstractFilter, then your can implement the following methods:
String prepare(RenderContext renderContext, Resource resource, RenderChain chain) throws Exception;
When a resource is called by the end user, we enter in the prepare method. This method allows to put some information in the scope of the request before the generation of the HTML output.
String execute(String previousOut, RenderContext renderContext, Resource resource, RenderChain chain)
throws Exception;
After the resource rendering (HTML output generation), we enter in the execute method. It allows to modify the generated HTML fragment before to return it to the end user.
void finalize(RenderContext renderContext, Resource resource, RenderChain renderChain);
Finally, when the fragment is finalized, we enter in the finalize method. It allows to reset some things in the context or to reinitialize some variables. It is usually used by the system. At this step it is no more possible to interact with the generated HTML fragment.
See Conditional execution of filters in this document for more details on how to configure such filters.
Jahia provides some simple filters that can be added to the default configuration.
The filter org.jahia.services.render.filter.EmailObfuscatorFilter
replaces all mail addresses by entity-encoded values. This protects email addresses harvesting.
The filter org.jahia.services.render.filter.RegexpFilter
allows to make any replacement in the output, based on regular expressions. The list of replacements need to be defined in the regexp property. The following example replaces all text inside square brackets with <em> tag:
<bean class="org.jahia.services.render.filter.RegexpFilter" >
<property name="regexp">
<map>
<entry key="\[([a-zA-Z]*)\]">
<value><![CDATA[<em>$1</em>]]></value>
</entry>
</map>
</property>
</bean>
You can add a scriptinfo request parameter to obtain information about files used in modules to render the content
To activate, add moduleinfo=true in the url parameters
It will surround with a border all modules within a page, displaying an info bullet to get more information (like script used to be displayed, and time to render)
public int getPriority();
public Map<String,String> getChannelCapabilities(String identifier);
public String resolveChannel(HttpServletRequest request);
public List<String> getAllChannels();
To detect the channel, the resolveChannel() method will be called on each provider, in priority order, until one returns a valid channel.
The getAllChannels() method should return the list of channels that will be available in the studio and edit mode.
ChannelService will aggregate all capabilities from the different providers by calling the getChannelCapabilities() method.
This simple implementation use an XML spring configuration to list all the possible channels. For each channel, a regular expression on the user agent can be defined for channel detection. This provider is used in the channels module.
<bean class="org.jahia.services.channels.Channel">
<constructor-arg index="0" value="apple_iphone_ver1"/>
<property name="capabilities">
<map>
<entry key="display-name" value="iPhone"/>
<entry key="template-type-mapping" value="iphone"/>
<entry key="variants" value="portrait,landscape"/>
<entry key="variants-displayNames" value="Portrait,Landscape"/>
<entry key="usable-resolutions" value="320x356,480x208"/>
<entry key="device-image" value="/modules/channels/images/devices/iphone-small.png"/>
<entry key="decorator-images"
value="/modules/channels/images/devices/iphone-portrait.png,/modules/channels/images/devices/iphone-landscape.png"/>
<entry key="decorator-image-sizes" value="388x738,734x383"/>
<entry key="decorator-screen-positions" value="35x216,124x115"/>
<entry key="resolution_width" value="320"/>
<entry key="resolution_height" value="480"/>
<entry key="userAgentPattern" value=".*iPhone.*"/>
</map>
</property>
</bean>
This provider, available at https://github.com/Jahia/WURFLProvider , uses the WURFL database to detect devices and get the capabilities. The WURFL provider is able to detect more than 7000 devices, including phones, tablets, browsers, or webTV devices. Note that the devices are not automatically available in edit mode : they have to be declared in an other provider first.
When a channel is detected, the system can be used to use another view for a specific module. If a component need to be rendered differently when used on some device, it is possible to create a specific jsp that will be used only for that channel.
The property "template-type-mapping" that is returned in the device capabilities will be appended to the template type for resolving the view. If the view is not found with this specific mapping, it will fallback to the standard view.
On an iPhone device, where template-type-mapping is iphone, the system will try to resolve the view first in html-iphone folder, then in html.
It is possible to exclude some components for some devices, directly in the studio. In the layout tab, select "Exclude from channels" and select the channels in which the component should not appear.
The component jnt:toggleMobileDisplay can be used in a page to display a link to normal display. This will allows the user to switch from a device-specific view to the generic view.
Jahia provides a default condition that can define the visibility of a node based on the current date, hence doing time based publication. The node will be visible if the current date is after/between start date and after/(or before) end date. The conditions are checked every time we try to access the node, if a node is not visible nobody will see it in the live repository even in administration.
The conditions will not be checked against when in the cache, so you will need to flush the cache when reaching a change of condition that will make a node visible or not. This way the conditions will be reevaluated.
Conditions can be defined in any module, they are initialized through Spring framework. This way they have access to all services. To write your own condition simply implement the interface org.jahia.services.visiblity.VisibilityConditionRule.
/**
* Defines a visibility condition for a piece of content in Jahia.
*/
public interface VisibilityConditionRule {
/**
* Returns <code>true</code> if the condition is satisfied and content will be rendered.
*
* @param node
* the node to test visibility condition for
* @return <code>true</code> if the condition is satisfied and content will be rendered
*/
boolean matches(JCRNodeWrapper node);
/**
* Return the node type associated with this condition.
*
* @return Return the node type associated with this condition.
*/
String getAssociatedNodeType();
/**
* Return the associated display template that will be used by gwt.
*
* @return Return the associated display template that will be used by gwt.
*/
String getGWTDisplayTemplate(Locale locale);
/**
* Returns a list of field names, required to display the info.
*
* @return a list of field names, required to display the info
*/
List<String> getRequiredFieldNamesForTemplate();
}
Each condition should be associated with a node type that will provide a way for the end user to interact with it, by filling the associated auto generated form like we do for the workflow.
Example of a condition
Let us review the start/end date condition code.
/**
* This class handle the execution of a start/end date condition for checking a node visibility.
* If the current date is after the start date or if start date is not defined then the node is visible unless
* end date is defined and we are after end date.
*/
public class StartEndDateConditionRuleImpl extends BaseVisibilityConditionRule {
private transient static Logger logger = LoggerFactory.getLogger(StartEndDateConditionRuleImpl.class);
/**
* Return the associated display template that will be used by gwt.
*
* @return Return the associated display template that will be used by gwt.
*/
public String getGWTDisplayTemplate(Locale locale) {
return JahiaResourceBundle.getString("JahiaVisibility", "label.startEndDateCondition.xtemplate",locale, "Jahia Visibility");
}
public boolean matches(JCRNodeWrapper nodeWrapper) {
Calendar start = null;
Calendar end = null;
try {
start = nodeWrapper.getProperty("start").getValue().getDate();
} catch (PathNotFoundException e) {
logger.debug("start is not defined for this rule");
} catch (RepositoryException e) {
logger.error(e.getMessage(), e);
}
try {
end = nodeWrapper.getProperty("end").getValue().getDate();
} catch (PathNotFoundException e) {
logger.debug("end is not defined for this rule");
} catch (RepositoryException e) {
logger.error(e.getMessage(), e);
}
Calendar calendar = null;
try {
calendar = nodeWrapper.getSession().getPreviewDate();
} catch (RepositoryException e) {
}
if (calendar == null) {
calendar = Calendar.getInstance();
}
if (start != null) {
if (!calendar.after(start)) {
return false;
}
}
if (end != null) {
if (!calendar.before(end)) {
return false;
}
}
return true;
}
}
This condition is associated through Spring to this definition.
[jnt:startEndDateCondition] > jnt:condition
- start (date, datetimepicker)
- end (date, datetimepicker)
Association in the Spring file of the module.
<bean class="org.jahia.modules.visibility.conditions.StartEndDateConditionRuleImpl">
<property name="associatedNodeType" value="jnt:startEndDateCondition"/>
<property name="requiredFieldNamesForTemplate">
<list>
<value>start</value>
<value>end</value>
</list>
</property>
</bean>
Multiple conditions are handle in a very simple way either you have to only match one condition to be visible or you have to match them all. To change the rule simply check/uncheck the conditional visibility checkbox in the engine.
How to flush cache when conditions changed ?
In this example we will use rules to launch Quartz jobs at the specified date (start and/or end) to flush the cache of the node having the condition and its parent also. The jobs are implemented using org.jahia.services.content.rules.BackgroundAction.
rule "Flush caches for start date visibility condition"
salience 25
when
A property start has been set on a node
- the node has the type jnt:startEndDateCondition
then
Execute the action "startDateVisibilityAction" at start on the node
end
The code of the action itself
public class FlushCacheOnNodeBackgroundAction extends BaseBackgroundAction {
private static Logger logger = LoggerFactory.getLogger(FlushCacheOnNodeBackgroundAction.class);
private FileCacheManager fileCacheManager;
private ModuleCacheProvider cacheProvider;
private int startLevel;
private int levelsUp;
public FlushCacheOnNodeBackgroundAction() {
fileCacheManager = FileCacheManager.getInstance();
}
public void setCacheProvider(ModuleCacheProvider cacheProvider) {
this.cacheProvider = cacheProvider;
}
public void executeBackgroundAction(JCRNodeWrapper node) {
String workspace = Constants.LIVE_WORKSPACE;
try {
JCRNodeWrapper currentNode = node;
workspace = node.getSession().getWorkspace().getName();
for (int level = 0; level <= (startLevel + levelsUp); level++) {
if (level >= startLevel) {
cacheProvider.invalidate(currentNode.getPath());
if (currentNode.isFile()) {
fileCacheManager.invalidate(workspace, currentNode.getPath());
}
}
currentNode = currentNode.getParent();
}
} catch (RepositoryException e) {
//Flush by path directly as node might not be visible anymore
String currentNode = node.getPath();
for (int level = 0; level <= (startLevel + levelsUp); level++) {
if (level >= startLevel) {
cacheProvider.invalidate(currentNode);
fileCacheManager.invalidate(workspace, currentNode);
}
currentNode = StringUtils.substringBeforeLast(currentNode,"/");
}
}
}
public void setStartLevel(int startLevel) {
this.startLevel = startLevel;
}
public void setLevelsUp(int endLevel) {
this.levelsUp = endLevel;
}
}
Then the real actions are instantiated by Spring on module startup
<bean id="abstractFlushCacheOnVisibilityNodeBackgroundAction" parent="abstractFlushCacheOnNodeBackgroundAction" abstract="true">
<property name="startLevel" value="2"/>
<property name="levelsUp" value="1"/>
</bean>
<bean parent="abstractFlushCacheOnVisibilityNodeBackgroundAction">
<property name="name" value="startDateVisibilityAction"/>
</bean>
<bean parent="abstractFlushCacheOnVisibilityNodeBackgroundAction">
<property name="name" value="endDateVisibilityAction"/>
</bean>
A node can only have one job of the same name at he same time. The job name is determined by the action name, that is why we have one action for start and one for end to allow to have both jobs defined on the same condition.
Display a list in a generic way.
To identify lists, apply a mixin to the node
[jmix:list] mixin
Sample lists defined in Jahia :
jnt:contentList, jnt:query, jnt:folder
By default, the rendering of this mixin will be used to display the list. This rendering is structured like this:
<template:include view="hidden.header"/>
<c:forEach items="${moduleMap.currentList}" var="subchild" begin="${moduleMap.begin}" end="${moduleMap.end}">
<template:module node="${node}"/>
</c:forEach>
<template:include view="hidden.footer"/>
The hidden.header and hidden.footer views allow to define parameters for the list to be displayed. The hidden prefix allows to not display these views in the list of possible views offered in the edit interface. These parameters are stored in a map accessible by modules named moduleMap.
The default parameters are as follows:
We define a variable as follows:
<c:set target="${moduleMap}" property="subNodesView" value="${subNodesView}"/>
hidden.header
calls a "loader" whose role is to get all nodes to display and store them in ${moduleMap}
We store different types of content,
These requests or lists are evaluated in the hidden.header view.
The hidden.header view allows for managing list sorting and filters.
Summary - for a simple list:
list.jsp
<template:include view="hidden.header"/>
list.hidden.header.jsp
<template:include view="hidden.load"/>
list.hidden.load.jsp
<c:set target="${moduleMap}" property="currentList" value="${jcr:getChildrenOfType(currentNode, jcr:getConstraints(currentNode))}" />
<c:forEach items="${moduleMap.currentList}" var="subchild" begin="${moduleMap.begin}" end="${moduleMap.end}">
<template:module node="${node}"/>
</c:forEach>
Usage of these views:
Generally speaking, only "loader" is necessary to define a specific list type, it allows to define the elements to be displayed. If there is a request, we'll define listQuery or listQuerySql, if it is sub node, currentList should be used.
[jnt:latestComment] > jnt:content, jmix:queryContent, jmix:list, mix:title, jmix:renderableList, jmix:studioOnly, jmix:bindedComponent
- j:subNodesView (string, choicelist[templates=jnt:post,resourceBundle,image]) nofulltext itemtype = layout
Rendering will be performed using a file named jnt_latestComment/html/latestComment.hidden.load.jsp. It will setup the listQuery variable in the moduleMap as illustrated here:
<query:definition var="listQuery"
statement="select * from [jnt:post] as comments where isdescendantnode(comments, ['${renderContext.mainResource.node.path}']) order by comments.[jcr:lastModified] desc"
limit="20"/>
<c:set target="${moduleMap}" property="editable" value="false"/>
<c:set target="${moduleMap}" property="listQuery" value="${listQuery}"/>
Deploy and define a menu (Navigation menu) in your page.
Properties to set :
When you create one of these :
- Pages
- External link
- Internal links
- Menu labels
you automatically create a menu entry.
If you want that the item is only displayed in certain menus, you need to check the “Select this option if you want to specify the menu where this item should appear”, then select the menu you want.
The node type for menu is jnt:navMenu.
its definition (in modules/default/META-INF/definitions-nav-menu.cnd is :
[jnt:navMenu] > jnt:content, mix:title, jmix:siteComponent orderable - j:baselineNode (string,choicelist) < 'home', 'currentPage' - j:maxDepth (long) = 2 - j:startLevel (long) = 0 - j:menuItemView (string,choicelist[templates='jmix:navMenuItem,menuItem',resourceBundle,image]) = menuElement - j:styleName (string) nofulltext - j:layoutID (string) nofulltext
The default associated JSP file is : jnt_navMenu/html/navMenu.jsp in the default module.
An entry is a mixin (jmix:navMenuItem) set on any type.
[jmix:navMenuItem] mixin
The default associated JSP file is
jmix_navMenuItem/html/navMenuItem.menuElement.jsp in the default module.
We must specify a view (default is menuElement) as we want to display the mixin, not the default rendering of the node.
It will search for jmix:navMenuItem under the baseNode, and display items that match the set restrictions (like level or specified menu).
All these menus use the <ul><li> structure
We provide several examples of views for menus :
The view will be automatically available in the Layout tab’s view selector of the menu.
You just have to create a new file under the jnt_navMenu/html folder or create this folders tree in your module directory, named navMenu.<yourView>.jsp where <yourView> is your view name.
In a file named navMenu.<yourView>.properties you have to set two properties for this view, as they are needed to manage cache dependency:
cache.mainResource = true cache.mainResource.flushParent = true
The best practice is to copy one of the predefined menus, which is close to your needs and customize it.
The beginning of the file sets the properties to display the menus. The display part is between the <ul> tags.
The default view for items in a menu is defined in the menuElement view.
The rendering is applied on jmix:navMenuItem, it means the default JSP file used for rendering items will be :
jahia/modules/default/jmix_navMenuItem/html/navMenuItem.menuElement.jsp
You can define your own menu items by adding the jmix:navMenuItem to your type definition.
If you want a custom display, you have to create a new view menuElement for your type definition. For example Jahia uses a custom view for jnt:page items. This choice will let you add properties such as icon (reference to a file) or alternate text for a menu item.
ex :
[jnt:navMenuText] > jnt:content, mix:title, jmix:navMenuItem + * (jmix:navMenuItem)
or
[jnt:page] > nt:base, jmix:nodenameInfo, jmix:observable, jmix:basemetadata, mix:title, jmix:publication, jmix:tagged, jmix:navMenuItem, jmix:hasTemplateNode orderable - jcr:title (string) i18n mandatory - j:templateNode (weakreference,choicelist[templatesNode]) mandatory < jnt:template + * (nt:base) = nt:base version + * (jmix:navMenuItem) + * (jmix:navMenuItem) let you add sub menu items under your current menu.
You can also define your own view for items. You must define a default view for it. This view will be available to be set in the jnt:navMenu from the studio. All items in the menu will use the same view.
sites/ACME/home/page8.html?filter={name:"jcr:created",value:"2010-04-30",op:"eq",uuid:"226a954111-3279-475b-9129-e3110736a565",format:"yyyy-MM-dd",type:"Date"}
<c:url var="targetURL" value="${url.mainResource}" context="/">
<c:param name="filter" value='{name="j:tags",value:"${tag.uuid}",op:"!eq",uuid:"${boundComponent.UUID}",type:"${tag.type}"}'/>
</c:url>
All macros are found under the macros directory of your modules. They respect a simple rule: the filename of the macro defines its name.
<module>WEB-INF/macros/username.groovy
This define a macro name username.
It is as simple as putting in your text a call like this ##macro_name##.
Dear ##username##,
This will render something like, "Dear John Doe," based on the user rendering the page (you have to check the option perUser
for the cache in the options panel of your content to be sure that each user see his own name).
For the macro you can use any scripting language JSR-223 compliant deploy on your platform (by default Groovy, Velocity and Freemarker).
username.groovy if (currentUser.username.trim().equals("guest")) { print PrincipalViewHelper.getUserDisplayName(currentUser.username.trim()); } else { String property1 = currentUser.getProperty("j:firstName") if (property1 != null) print(property1.capitalize() + " "); String property2 = currentUser.getProperty("j:lastName") if (property2 != null) print(property2.capitalize()) if (property1 == null && property2 == null) print(currentUser.getUsername().capitalize()) }
Name | Class | Description |
---|---|---|
currentNode | org.jahia.services.content.JCRNodeWrapper | The node we are currently rendering |
currentUser | org.jahia.services.usermanager.JahiaUser | The user currently connected |
currentAliasUser | org.jahia.services.usermanager.JahiaUser | The user currently rendered if not the one connected |
renderContext | org.jahia.services.render.RenderContext | The current context for rendering |
currentResource | org.jahia.services.render.Resource | The resource associated with the current node |
url | org.jahia.services.render.URLGenerator | An URL generator allowing to create your own URL |
It is possible to define dedicated templates for specific user agents. If the system finds the request is coming from a configured user agent, it can append a specific classifier to the template type, and will then look the template in another folder.
The mapping between user agent and template types is done in the applicationContext-services.xml file, under the UserAgentFilter bean configuration :
<bean class="org.jahia.services.channels.filters.ChannelResolutionFilter" >
<property name="priority" value="4" />
<property name="applyOnModes" value="live,preview" />
<property name="userAgentMatchingRules">
<map>
<entry key=".*iPhone.*" value="iphone" />
<entry key=".*iPod.*" value="iphone" />
</map>
</property>
</bean>
The userAgentMatchingRules attribute defines a list of regular expression and the associated template type extension. Here, all user agents matching .*iPhone.* and .*iPod.* will have an iphone template type classifier.
When using the previous configuration, for any request coming from an iPhone, the system will try to find templates for iPhone. If a standard .html request was done, it will first lookup the template into the html-iphone folder, and will then fallback on the standard html folder if the template is not available. This is done for every node and wrapper included in the page: a page can mix user-agent specific and generic templates.