# Templates

RHCore includes a templating language that can be used in place of Content Server Weblingo or WebReports. It is motivated Django Templates, 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, 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 as img;
  • request - the current request record; and
  • now - the current date and time.

This can be used to create a link to the Enterprise Workspace:

<a href="{{ cgi }}?func=llworkspace">Enterprise Workspace</a>

# 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 RHObject subclasses such as RHNode, RHUser, RHWorkStatus, Iterator, etc. A few more examples:

// 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 RHNode representation of its input:

{{ "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:

<p>The contents of {{ node.name }} are:</p>

<ul>
	{% for child in node.children %}
		<li>{{ child.name }}</li>
	{% endfor %}
</ul>

We can sort the children using the sort filter:

<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:

Simple Template Rendering

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 importing rhcore/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 the load_base macro and passes in the parameter value of true (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 value 2000, converts it to an RHNode (using the |node filter), and sets the value to the context with a variable name of ews.
  • <table class="rhtable rhstriped"> - The rhtable and rhstriped classes are styled by a cascading style sheet that was imported with the load_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 to sort), but the actual sorting is done elsewhere.
  • {% for child in ews.children|sort:request.sort %} - Here we loop through the child elements of ews and sort by the sort parameter passed in by the request. Within the loop the child variable is in context.
  • {% usemacro gif child %} - The gif 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.

Last Updated: 5/20/2019, 11:42:35 AM