# Templates
RHCore includes a templating language that can be used in place of Content Server Weblingo or WebReports. It is motivated Django Templates (opens new window), shares many characteristics, but has some additions to play nice with Content Server.
Templates can be used to render text. Consider a few examples:
- rendering a static or interactive web page;
- rendering an e-mail;
- rendering a
RecArray
as HTML, CSV, XML, JSON, WordML, or ExcelML; - formatting the results of a LiveReport or search;
- etc.
Templates have a few key features:
- Widgets - Included is a widget library for rendering common UI components. See Widgets for more information.
- Compatibility - Templates are compatible with all data types commonly found in Content Server (e.g.,
Assoc
,RecArray
, etc.), but works particularily well with RHObject. - CSS - RHCore includes a CSS stylesheet for rendering tables and other elements in a style consistent with Content Server. See Page Styles for more information.
- Data Access - Templates can execute a LiveReport, fetch a user's assignments, traverse the
DTree
hierarchy, perform a simple search, execute OScript, etc. directly from within a template. - Readability - Templates are highly readable making it easier to debug and to see what's going on.
- Caching - RHCore does a lot of caching behind the scenes for optimal performance.
- Reusability - RHCore embraces the don't repeat yourself (DRY) principle (opens new window), which means common design patterns are abstracted away and made reusable to prevent having to write the same code over and over again. Tools are available to write your own reusable components whenever patterns are found in your own implementations.
- Table Views - RHCore makes it easy to apply the three most common operations to a table view: sorting, filtering, & pagination.
# Rendering
A template can be rendered from OScript by instantiating instances of RHTemplate
and RHContext
(each a subclass of RHObject
), setting values to the context, and calling the render()
function. For example:
Frame template = $RHTemplate.RHTemplate.New("Hello {{ name }}!") Frame context = $RHTemplate.RHContext.New()
context.setValueForKey('Kelly', 'name')
echo( template.render(context) )
> Hello Kelly!
Templates can also reside on the filesystem (in predefined locations) or as a Content Server node (any text-based node). These are constructed by passing two parameters to the constructor:
Frame template = $RHTemplate.RHTemplate.New(prgCtx, 'rhcore/my_template.html')
// or
Frame template = $RHTemplate.RHTemplate.New(prgCtx, 12345)
A context can also be constructed from a request, and will pre-populate the context with relevant variables. For example:
Frame context = $RHTemplate.RHContext.New(request)
This will add the following variables to the context:
cgi
- the path to the Content Server CGI (e.g.,/cs/cs.exe
);user
- an RHUser instance of the current user;node
- an RHNode instance of the current node, if applicable;img
- the relative path of the support directory (e.g.,/img/
);support
- the same asimg
;request
- the current request record; andnow
- the current date and time.
This can be used to create a link to the Enterprise Workspace:
# Variables
The {{ name }}
and {{ cgi }}
expressions in the previous section are examples of a variable evaluation, which is performed be surrounding a variable name with double braces (i.e., "{{" and "}}"). Variables can be of any data type in Content Server, including an Integer
, Date
, Assoc
, List
, Record
, RecArray
, Object
, or Frame
. It also supports all
// Create an RHUser instance and add it to the context
Frame user = $RHCore.RHUser.New(prgCtx, 'Admin')
context.setValueForKey(user, 'user')
Within a template we can access the user
variable with the double-brace notation:
Welcome {{ user }}!
>> Welcome << RHUser: Admin (1000) >>!
The << RHUser: Admin (1000) >>
text is a string representation of an RHUser object, and is output in place of an unhelpful memory address. Behind the scenes it calls the string()
method on the object, which is analogous to calling the toString()
method on a Java object. Templates support key paths, which allows easy traversal of data structures. For example:
Welcome {{ user.name.upper }}!
>> Welcome ADMIN!
{{ user.userid }}
>> 1000
{{ user.displayName }}
>> Christopher Meyer (Admin)
{{ user.firstname }} has a default group of {{ user.group.displayName }}.
>> Chris has a default group of DefaultGroup.
Consider another example with a Content Server node (represented by an RHNode), and we wish to access a category value on the parent:
{{ node.parent.categoryvalues.CategoryName.AttributeName }}
>> {'Attribute Value1','Attribute Value2', ... ,}
Key paths also work with the Assoc
, Record
, RecArray
, and List
datatypes. For example, the properties of a request
can be accessed with:
{{ request }}
>> R<'cookieData'=A<1,?,'BrowseSettings'='Rs+F2c ... ' >
{{ request.func }}
>> ll
{{ request.SCRIPT_NAME }}
>> /OTCS/cs.exe
{{ request.cookieData.LLCookie }}
>> w/usvsJZKQMifAeI7FxtHUfH ...
# Filters
Variables can be post processed with a filter. A filter is a function that operates on its input, may accept parameters, and returns a value. It is applied using the vertical bar character ("|") after the variable. For example, the upper
filter can be used to convert a string to uppercase:
My name is {{ user.displayName|upper }}.
>> My name is CHRISTOPHER MEYER (ADMIN).
Filters can also be chained and accept parameters. Parameters are added after the filter name and are separated by colons:
My name is {{ user.displayName|upper|replace:"HRI":"hri" }}.
>> My name is ChriSTOPHER MEYER (ADMIN).
Other filters exist for fetching related information. For example, the node
filter fetches the
{{ "2000"|node }}
>> << RHNode: Enterprise (2000) >>
See the Template Filter Guide for more information.
# Template Tags
Template tags have various purposes in a template. These include:
- flow control (for loops, if statements);
- setting values to the context;
- fragment caching;
- defining and calling macros;
- referencing other templates;
- etc.
Template tags are surrounded by "{%" and "%}" and have a variety of syntaxes. Depending on the syntax, an argument can be a variable (which will be resolved automatically), or a literal (wrapped in single or double quotes).
For example, say a folder is set to the context with the variable name node
. The contents of the folder can be itereated with the for
tag and children
property of the node:
The contents of {{ node.name }} are:
-
{% for child in node.children %}
- {{ child.name }} {% endfor %}
<ul>
{% for child in node.children|sort:"name" %}
<li>{{ child.name }}</li>
{% endfor %}
</ul>
Or, sort the results based on a URL parameter:
<ul>
{% for child in node.children|sort:request.sort %}
<li>{{ child.name }}</li>
{% endfor %}
</ul>
Or, only show items where the name begins with "Folder" using the filter
filter:
<ul>
{% for child in node.children|filter:"name":"startsWith":"Folder" %}
<li>{{ child.name }}</li>
{% endfor %}
</ul>
See the Template Tag Guide for more information.
# Example
Let's bring it all together with an example that everyone can relate to. Consider a standard browse page in Content Server, and how something similar might look rendered using a template:
{% include "rhcore/macros.html" %}
{% usemacro load_base true %}
{% set "2000"|node as ews %}
<table class="rhtable rhstriped">
<thead>
<tr>
<td class="minWidth">{% usemacro sortheader "subtype" "Type" %}</td>
<td class="width70">{% usemacro sortheader "name" "Name" %}</td>
<td class="alignRight">{% usemacro sortheader "size" "Size" %}</td>
<td class="alignCenter">{% usemacro sortheader "modifydate" "Modified" %}</td>
</tr>
</thead>
<tbody>
{% for child in ews.children|sort:request.sort %}
<tr>
<td>{% usemacro gif child %}</td>
<td>{% usemacro browselink child %}</td>
<td class="alignRight nowrap">{{ child.size }}</td>
<td class="alignCenter nowrap">
{{ child.modifydate|date }} ({{ child.modifydate|timesince }})
</td>
</tr>
{% endfor %}
</tbody>
</table>
Here is a screenshot:
Here's a line-by-line breakdown:
{% include "rhcore/macros.html" %}
- The{% include %}
tag is used to import an external template. In this example we are importingrhcore/macros.html
, which hosts a collections of reusable macros. Macros are like functions that be repeatedly called to render HTML fragments with different parameters. For example, to define a macro use the macro tag:
{% macro helloWorld parm1 %} Hello World! You passed in {{ parm1|quote }}. {% endmacro %}
This can be rendered with the usemacro tag:
{% usemacro helloWorld "car" %}
>> Hello World! You passed in "car".
{% usemacro helloWorld "boat" %}
>> Hello World! You passed in "boat".
The rhcore/macros.html
template has a number of predefined macros for function menu rendering, library importing, sort header rendering, and more. It is an extremely powerful feature of RHCore templates and should not be overlooked.
{% usemacro load_base true %}
- This renders theload_base
macro and passes in the parameter value oftrue
(the meaning of this parameter is not important now). This macro loads a number of CSS and JavaScript libraries into the page that are included with RHCore templates. These libraries are useful for rendering pages, forms, and widgets in the style of Content Server.{% set "2000"|node as ews %}
- The set tag is used to set a variable to the context. This line takes the value2000
, converts it to an RHNode (using the|node
filter), and sets the value to the context with a variable name ofews
.<table class="rhtable rhstriped">
- Therhtable
andrhstriped
classes are styled by a cascading style sheet that was imported with theload_base
macro call. These classes render the table in a style similar to that of Content Server (e.g., collapsed borders, grey title bar, striped rows, etc). See Page Styles for more information.{% usemacro sortheader %}
- This macro renders a sort header and handles all the nuances of creating the sort link with the appropriate up or down arrow. The first parameter is used in the URL generation (e.g.,&sort=-name
) and the second is for the label displayed in the page. An optional third parameter controls the URL parameter name (defaults tosort
), but the actual sorting is done elsewhere.{% for child in ews.children|sort:request.sort %}
- Here we loop through the child elements ofews
and sort by thesort
parameter passed in by the request. Within the loop thechild
variable is in context.{% usemacro gif child %}
- Thegif
macro is used to render a subtype icon (with the appropriate mouseovers).{% usemacro browselink child %}
- This macro renders a browse link for a node, but also includes the modified image callbacks (the little icons after the node) and the function menu. Of course, macros also exist to render the link, modified image callbacks, and function menus separately if required.
# Use in Request Handlers & WebNodeAction
Templates can also be used in request handlers and "WebNode Actions" in place of standard Content Server weblingo.
See the section on Request Handlers for more information.
# Simplates
There is an optional RHCore feature to allow templates (called "Simplates") to be added as nodes to Content Server (much like a WebReport). See ScriptNodes & Simplates for more information.
# Template Tag and Filter Guide
See the Template Tag Guide and Template Filter Guide for more information.