Rendering content
The rendering process is the chain of operations that Jahia executes to extract nodes from the repository and transform the content (usually an HTML page) before it is delivered to the user who requested it. The rendering process provides flexibility for developers who can add their own operations to the process.
Component rendering and views
Every component can be rendered by a view. A view is a script, usually stored as a JSP file.
Using the module tag
The module tag allows you to render other components. The path or node needs to be passed.
Templates
A node must be associated with a template to display in an HTML page. A template defines which elements to display, where to display them, and compiles different component views in a single HTML page.
You create templates in the Studio. You create page templates for pages and content templates for all other types of content. Content templates are associated with a node type. You can use permissions to limit templates to certain users. For example, you can hide templates from regular users that show private areas or that allow them to edit the content.
Selecting a template
A node can be associated with a template. This is the case for all page nodes. A template must be specified when a page is created. The template is set in the j:templateNode
property, defined by the jmix:hasTemplateNode
mixin type.
A user can also force the choice of a template by specifiying a template name in a URL before the .html extension. This example forces the use of the content-template
to display the news_36
node.
http://localhost:8080/cms/render/default/en/sites/ACME/home/news/maincontent/news_36.content-template.html
Default templates and priority
Default templates apply if no specific template is requested by a user and if no template is associated with a node. As multiple templates can be used for one single node and only one can be selected, you can define a template priority. The template with the highest priority will apply.
If no template is associated with a node or specified in the URL and no default template can be found, then the node cannot be displayed and the system will throw a 404 error.
Cascading templates
A template must either have an associated view or be contained inside another template. If a view is defined, the view is called to render the template. Otherwise, the parent template is called instead. This allows you to cascade templates, ranging from specific to general. The latter could, for example, contain standard headers and footers. The top-level template, that defines common areas, is usually called the base template.
The template sequence for rendering is then defined in this order:
- template view
- base template
- home template
- home page
Calling content from a template
Building a page is a matter of aggregating the template and the requested node. This node is called the main resource, which you can find in the URL and contains the information to display. Jahia looks for the template node when building a page. The template node defines the layout and the information to display from the main resource.
Other components are available in the Studio for you to use content from the main resource.
Areas
Areas are defined in JSP views with template:area
tags or in templates with the area component. An area displays content from the next node in the template sequence. An area is considered enabled under one node if a list with the same name as the area is present under that node. For example, a maincontent
area defined in the template view is enabled in the main resource if the maincontent
list is created under the main resource.
Areas are represented as blue blocks in the Studio. For example, let's use the same templates sequence as before: template view, base template, home template and home page. In the following diagram:
- The template view defines two area tags: header and pagecontent.
- Both are enabled in the base template as lists. The header list contains a head content content item and the pagecontent list contains two area nodes: areaA and pagecontent.
- The home template enables areaA containing one content1 content item.
- The home page enables the pagecontent area, containing the content2 content item.
Absolute areas
Absolute areas are similar to areas but do not use the templates sequence to resolve the list to display. Instead, they use an ancestor of the main resource. You can specify ancestor levels, 0
for the home page level, 1
for the first sub page level, etc. If no level is specified, the content list is taken from the home page of the site. Absolute areas are represented as red blocks in the Studio.
Main resource display
The main resource display component calls a specific view on the main resource node directly and is used in content templates only. The component is represented in the Studio as a grey area. Use the component to apply different views in one template. The following example shows multiple main resource display components. Here in the History tab, the history and the compare views display one on top of the other.
Example of rendering sequence
This section shows an example of a rendering sequence. In the example:
- The user requests a page.
- Jahia first tries to resolve the template and finds a home template associated with the page.
- The home template is contained inside the base template. Jahia first renders the base template.
- The base template is associated with a view, the template.myset.jsp file, and the JSP is called to start building the page.
- An area header is found. Jahia looks sequentially in base, home, and finally in the page to find a list named header. This list is found in the base template and contains a navigation menu. All nodes here are rendered using their own views.
- Another area pagecontent is found. This one does not exist in base, but is present in home. Jahia starts rendering the home/pagecontent.
- The first node found is a
jnt:row
node. The node is rendered using its own view, row.jsp. - The JSP contains a first area, row-col1. The system finds the area in home, which contains itself an area node named areaA.
- The areaA template is found in the page. The content of page/areaA renders.
- The rendering of row-col1 is over, another area is defined in the row.jsp file: row-col2. row-col2 is found in home, which contains an area
- Again, the areaB is found in the page. The content of page/areaB renders.
The view row.jsp is fully rendered. As home/pagecontent does not contain any other nodes, the home/pagecontent area rendering is finished. The view template.myset.jsp finishes its execution. The page is fully rendered.
Rendering filters
Rendering filters are classes that can transform the output of a module. They work like standard servlet filters, except that they are executed independently for every module inclusion. Filters can be executed on all modules or on specific module and nodes. Find an overview of all currently registered filters in the Jahia Tools area JSP when the Jahia is running: http://localhost:8080/tools/renderFilters.jsp.
Filter configuration
Jahia supports filter configuration using OSGi services in modules.
Module filters
A module can define its own filters to execute. To define module filters, you simply need to register OSGi services. The filters will be added to the render chain and executed for every request for all modules.
The priority defines where the filter is inserted in the render chain. If the priority is greater than 16, it executes the first time the resource is generated, and then the result is cached. If the priority is less than 16, it is evaluated each time the resource is served. Be careful, this is very consuming in terms of performance.
The following example is an extract of OSGi filter module sample.
@Component(service = RenderFilter.class)
public class SimpleFilter extends AbstractFilter {
private String headScript;
@Activate
public void activate() {
setPriority(3);
setApplyOnEditMode(true);
setSkipOnAjaxRequest(true);
setApplyOnConfigurations("page");
setApplyOnTemplateTypes("html,html-*");
}
@Override
public String prepare(RenderContext renderContext, Resource resource, RenderChain chain) throws Exception {
headScript = "\n<script>alert('Hello Jahia!')</script>\n<";
return super.prepare(renderContext, resource, chain);
}
@Override
public String execute(String previousOut, RenderContext renderContext, Resource resource, RenderChain chain) throws Exception {
String output = super.execute(previousOut, renderContext, resource, chain);
// add your custom process of the output here.
return output;
}
}
Conditional execution of filters
Any filter that extends 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 execution continues with the next filter in the chain. For example, you could have a filter that only executes for nodes of type jnt:wikiContent
. More conditions can be provided using:
- setApplyOnMainResource
the filter is applied only on the main resource - setApplyOnModules
comma-separated list of module names that the filter is executed for (all others are skipped) - setApplyOnNodeTypes
comma-separated list of node type names that the filter is executed for (all others are skipped) - setApplyOnTemplates
comma-separated list of template names that the filter is executed for (all others are skipped) - setApplyOnTemplateTypes
comma-separated list of template type names that the filter is executed for (all others are skipped) - setApplyOnConfigurations
comma-separated list of configurations that the filter is for (all others are skipped) - skipOnModules
comma-separated list of module names that the filter is not executed for - skipOnNodeTypes
comma-separated list of node type names that the filter is not executed for - skipOnTemplates
comma-separated list of template names that the filter is not executed for - skipOnTemplateTypes
comma-separated list of template type names that the filter is not executed for - skipOnConfigurations
comma-separated list of configurations that the filter is not executed for
For advanced filtering scenarios, such as regular expressions for matching and NOT conditions, use the filter's conditions property and provide a list of condition beans (instances of classes that implement org.jahia.services.render.filter.AbstractFilter.ExecutionCondition
). See the documentation on org.jahia.services.render.filter.AbstractFilter
for more details.
Implementing filters
A filter is single class that implements the org.jahia.services.render.filter.RenderFilter
interface. The interface primarily defines one method to implement:
String execute(String previousOut, RenderContext renderContext, Resource resource, RenderChain chain) throws Exception;
This method returns the final output after filtering. The chain attribute enables you to get the result generated by the remaining chain. This result can be used as an input for the filter. If you want your filter to transform the output of the chain, the filter must get the output from the previousOut
method argument.
A basic filter that replaces all occurrences of letter a with b would look like:
public String execute(RenderContext renderContext, Resource resource, RenderChain chain)
throws RenderFilterException {
return previousOut.replace("a","b");
}
An abstract org.jahia.services.render.filter.AbstractFilter
class should be used as the base class for a new filter, which allows you to specify execution conditions for a filter. If your filter extends the AbstractFilter
, then you can implement the following methods:
String prepare(RenderContext renderContext, Resource resource, RenderChain chain) throws Exception;
When a resource is called by the end user, you enter the prepare method. This method allows you to put information in the scope of the request before generating the HTML output.
String execute(String previousOut, RenderContext renderContext, Resource resource, RenderChain chain)
throws Exception;
After the resource rendering (HTML output generation), you enter in the execute method. It allows you to modify the generated HTML fragment before to returning it to the end user.
void finalize(RenderContext renderContext, Resource resource, RenderChain renderChain);
Finally, when the fragment is finalized, you enter in the finalize method, which allows you to reset specific context or reinitialize variables. It is usually used by the system. At this step, you can no longer interact with the generated HTML fragment.
Script execution info
You can add a scriptinfo request parameter to obtain information about files used in modules that render content. This will surround all modules within a page with a border and display an info bullet for more information (like script used to display and time to render).
To activate the script, add ?moduleinfo=true
in the url parameters in Preview mode.
Lists
The list component is composed of different elements that you can use to customize rendering while still retaining all the flexibility of the default component. The component covers many different uses cases for rendering lists.
To identify lists, apply a mixin to the node.
[jmix:list] mixin
Sample lists defined in Jahia include:
jnt:contentList, jnt:query, jnt:folder
By default, the rendering of this mixin displays 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 you to define parameters for the list to be displayed. The hidden prefix allows you to exclude these views from the list of possible views offered in the edit interface. These parameters are stored in a map accessible by the moduleMap
module.
The default parameters are:
- currentList
List of nodes to display - begin
Beginning of a list (integer) - end
End of a list (integer) - liveOnly
Makes an AJAX call of the list in live state and cannot be edited in default state - subNodesView
This view is used to display sub Nodes - editable
Allows editing of content (boolean, true by default) - emptyListMessage
Message to display if list is empty
You 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}
.
Jahia stores different types of content,
- Simple lists
currentList - SQL2 requests
listQuerySql - QOM requests
listQuery
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 you to define the elements to be displayed. If there is a request, you define listQuery
or listQuerySql
. If it is sub node, currentList should be used.
jmix:list
.
[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 is performed through the jnt_latestComment/html/latestComment.hidden.load.jsp
file. It will setup the listQuery
variable in the moduleMap
as shown 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}"/>
List filtering
filter
parameter to the URL of the page containing the list to filter. The actual value of the filter
parameter specifies how the list is filtered using a JSON format.- uuid
The Universally Unique IDentifier (UUID) identifying which list the filter should operate on. - op
A predicate that each element of the list with the name property must satisfy to be included in the filtered result. The only supported operation at this time is the equality, specified by theeq
value. You can also use the negation operator!
to only include elements not satisfying the predicate in the filtered result. To use the negation operator, simply preprend!
in front of the operation name. - value
The value of the property used to filter the list. - name
The name of the property present on the list elements and on which the filtering will occur. - type
The expected JCR type of the specified value. Possible values are defined by possible return values ofjavax.jcr.PropertyType.TYPENAME_*
constants. If omitted, the specified property value will be interpreted as a String (javax.jcr.PropertyType.TYPENAME_STRING
).
Date filtering
This example specifies that the list identified by the 226a954111-3279-475b-9129-e3110736a565
UUID on the sites/ACME/home/page8.html
page should be filtered to only keep elements where the jcr:created
property is equal to 2010-04-30
(op attribute is equals to "eq"). 2010-04-30
is of Date
type with the yyyy-MM-dd
format.
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"}
Creating a URL to filter a bound component in a JSP
This example creates a URL targeting the list associated with the component bound to the view associated with the JSP. The filter only displays elements that are not tagged and identified by the $tag.uuid
UUID. An element's tags are children nodes of the j:tags
property for this element and each is a WeakReference to the "real" tag node. Therefore, j:tags
is a list of UUIDs, each identifying a tag. Note that $tag.type
is WeakReference so that the filter knows to interpret the value attribute as a UUID pointing to a tag.
<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>
Macros
Macros allow you to add and process dynamic information in your text.
Defining a macro
All macros are found under the macros directory in your modules. They respect a simple rule: the filename of the macro defines its name. This example defines a macro name username.
<module>WEB-INF/macros/username.groovy
Using a macro
It is as simple as putting in your text a call like this ##macro_name##. This will render something like, "Dear John Doe," based on the user rendering the page. You have to check the perUser
option for the cache in the options panel of your content to ensure that each user see his own name.
Dear ##username##,
Writing a macro
To create a 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()) }
Default bindings available in your macros
Name | Class | Description |
---|---|---|
currentNode | org.jahia.services.content.JCRNodeWrapper | The node you 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 |
Default macros
- ##username##
Displays the current user name - ##authorname##
Displays the author name - ##creationdate##
Displays the content creation date - ##keywords##
Displays the keywords for the current node - ##devmode##
Displays information about the current content: the content id and the content path. For example, ##devmode(full)## renders something like, "Content path : /home/services Content id : services" - ##linktohomepage##
Displays a link to home page. For example, ##linktohomepage## renders something like "http://www.site.com/index.html". You can also make a link like this <a href="##linktohomepage##" title="Home Page">Home Page</a> to render a clean Home Page link . - ##userprofiledata##
Displays information about the current profile. The first parameter should be a node name like "contents". The second parameter should be a property name like "jcr:created". You can also use only one parameter in your text call like this ##userprofiledata(parameter)##. In this case, the parameter should be a property of the current user like "j:firstName". For example, ##userprofiledata(contents,jcd:created)## renders something like, "2013-11-05T18:26:10.357+01:00". ##userprofiledata(j:firstName)## renders something like, "Damien".