Overview
Handlebars allows you to create Content Layouts and Page Layouts with placeholders and simple logic that will be filled in with data at Publish time, making it easier to manage and manipulate content in ways that are not possible using standard T4 Tags without needing extensive coding expertise or familiarity with the complexities of Programmable Layouts.
One of the key features of Handlebars is its simplicity. With a syntax that closely resembles regular HTML, users can quickly grasp the basics and start building more "dynamic" Content types and Page layouts.
Handlebars uses double curly braces {{}}
to denote placeholders, which are then replaced with actual data when the layout is Published – much like the t4 tags you may be familiar with today.
The Terminalfour implementation of Handlebars comes with an extensive toolkit of "Helpers" to allow you to add logic to your layouts in a way that just isn't possible with t4 tags.
From Terminalfour 8.3.19 you can make use of Handlebars by selecting it as a processor type on your Page Layouts and Content Layouts:
Before we dive in...
8.3.19 is our initial release of Handlebars and we'll be extending the functionality and improving the experience over the next several releases of the platform.
Before we explore how Handlebars works it's important to mention a few items up front to help you make the best use of the feature.
Mixing t4 tags and Handlebars expressions
When setting the Content layout processor to Handlebars Content you can no longer use "T4 tags" in the layout. Instead you must use the Handlebars Helpers outlined in the rest of this guide.
Types of Expressions
There are three main types of expressions you will be working with in your Handlebars code:
//Standard Expression:
{{exampleHelper "foo" example="bar"}}
//Block Expression:
{{#exampleHelper}}
<p>Some stuff</p>
{{/exampleHelper}}
//Subexpression:
{{exampleHelper (otherHelper)}}
Subexpressions
A subexpression is an expression inside another expression. It’s used when you want to call a helper or a calculation inside another expression. Subexpressions are wrapped in parentheses.
For example, if you wanted to use the publish Helper to output the Title element of a Content item it might look like this:
{{publish element="Title"}}
But if you wanted to make use of the built in upper Helper to output that value in uppercase you'd need to pass in the publish Helper into the upper Helper as a subexpression like this:
{{upper (publish element="Title")}}Notice that by using subexpressions you can combine different Helpers, thereby creating more powerful Handlebars expressions. You will look at several examples of doing this throughout this training, remember that when using subexpressions you will need to use parentheses in your syntax.
Types of Parameters
//Unnamed Parameter:
{{exampleHelper "foo"}}
//Named Parameter:
{{exampleHelper example="bar"}}
"Double stashing" and "Triple stashing"
With some limited exceptions, Handlebars HTML-escapes values returned by an expression using two curly-braces (e.g. {{expression}}
).
This means certain special characters will be converted to their HTML equivalents. For example, if a user entered a value of <
then a "double-stashed" handlebars expression would convert that to <
.
If you don't want Handlebars to escape a value, use the "triple-stash", {{{
.
Double-stash example
{{publish element="Title"}}If a user enters the value <h2>Test</h2>
into a Title element then this expression would output <h2>Test</h2>
(the value is HTML-escaped)
Triple-stash example
{{{publish element="Title"}}}If a user enters the value <h2>Test</h2>
into a Title element then this expression would output <h2>Test</h2>
(the value is not HTML-escaped)
Error handling
Like with standard T4 tag based layouts and programmable layouts it's possible to configure things incorrectly and get undesired or unexpected results.
Preview & Direct Edit
When an error is encountered with a Handlebars layout during Preview or Direct Edit we output an inline error message on the page to users.
This error is in the form of a table and displays the following info:
- The Section ID where the error is occurring
- The asset language
- The Content ID (if applicable)
- The error message
- The content layout name (if applicable)
- The layout code (if applicable)
This should give you enough information to find out where the problem exists so you can debug.
Example:
Publish
When a Publish happens and an error is encountered we could have done one of two things:
- We could ignore the error, and continue the Publish
- We could stop the publish to prevent breaking the live site
Both have their pros and cons and ultimately we'll need to hear from you, our users, about how you're using Handlebars to determine the best long term solution.
For now, we've taken the safest and least destructive option which is to fail the publish. This means if you accidentally introduce a breaking error in your most commonly used Content Type or Page Layout we'll prevent that error from getting pushed to your live site and ultimately breaking a significant portion of your web pages.
When the publish fails it does so with very clear messaging in the logs explaining the reason for the failure.
Example
Adding Comments in Handlebars Layouts
Handlebars allows you to add comments in your layouts that will be ignored when a page is being Previewed or Published.
This might be useful if you want to add some comments about how a layout works but don't want those comments to end up on the published site.
Handlebars comments begin with a {{!--
and end with --}}
For example:
{{!-- This is a comment and won't appear on the published page --}}Comments can span multiple lines:
{{!-- This is a
multi-line comment.
--}}
Overview of JavaScript ES6 Syntax
String Literals
Prior to ES6 concatenation using the + operator was used.
var foo = "bar";
var oldWay = "The value of foo is: " + foo;
ES6 introduced Template literals which use backticks and allow interpolation with ${expression}.
var foo = "bar";
var newWay = `The value of foo is ${foo}`;
Spread Syntax
Spread syntax lets you break up elements of arrays or properties of an object. The code below shows using spread syntax to copy an object.
var obj = {
foo: "bar"
}
var newObj = {
...obj,
baz: "quz"
}
console.log (newObj);
output:
{
foo: "bar",
baz: "quz"
}
let and const
let and const both introduced in ES6 are two block-scoped ways of declaring variables.
let foo = "bar";
foo = "baz"; //This will work
const quz = "bar";
quz = "baz"; //This will error
Some Other Concepts
Type Coercion
The !! operator is a quick way to coerce any value into a Boolean (true or false).
let isValid = '';
typeOf isValid; // 'string'
typeOf !! isValid; // 'boolean'
Ternary Operator
The ternary operator ? is a shorthand for an if else statement.
let isValid = true;
let foo = isValid ? 'true' : 'false'
Before You Start
Be sure you have the following added to your training site:
1. Duplicate the "T206: Training Site Example (Duplicate Me)" into your Site Structure
2. Duplicate the "T206 Training Site Example (Duplicate Me)" Page Layout
3. Create a "T206 Training Site Example" Channel
4. Duplicate the "T206 Training Site Example: General (Duplicate Me)" Content Type
5. Enable your "T206 Training Site Example: General" Content Type into your Home branch section.
Where to Create Custom Helpers
There is no dedicated UI to manage Custom Helpers. Custom Helpers are added by adding an instance of a new System Content Type to a hidden section.
You will need to find the ID of the section you need to edit, to do so run the following SQL command:
select * from config_option where config_key = 'handlebars.helpersSectionId'In the training instance you will be using throughout this course, the Section Id needed to access the Custom Helpers hidden Section is: 8303. You may want to crate a bookmark to this section to access easily as you are completing the exercises in the course.
1. Hello, World!
- Let's start with a Hello World example to learn how to create Custom Helpers in Terminalfour. In this example, you will learn where and how Custom Helpers are created and how to use context and options to output named and unnamed parameters.
Exercise 1.1: Creating the "helloWorld" Custom Helper
- Click on any section within your site structure.
- Modify the URL for your section by changing the section Id in the URL to '8303' and hitting enter. This will take you to the Custom Helpers hidden section in the training instance.
- Click on the Add Content button to create a new Custom Helper.
- Name: Give your Custom Helper a name, "helloWorld". (There should be no spaces in the name field, use camel case as a convention for your Custom Helpers names).
- Function Code: Enter your Custom Helper code into this field as specified below.
All Handlebars Custom Helpers start out as a function that has two arguments: context and options.
function (context, options) {
return `Hello, World!`;
}
- Click Save changes to save the changes to your Custom Helper.
Exercise 1.2: Updating the "text/html" content layout
- Go to Assets > Content Types.
- Click your Content Type name to edit it. (Use the Filter tool to search). Open the Content layouts tab.
- The Content Layout tab is an area to add Content Layout(s) for your Content Type. Click into the "text/html" content layout to edit it.
- Add a Handlebars expression that uses the "helloWorld" Custom Helper that you created in the previous exercise. To do this use the name of the newly created Custom Helper ("helloWorld") inside the curly braces as below:
<p>{{helloWorld}}</p>
- Click Save changes to save your Content Type.
- Update your preview to check the result.
Exercise 1.3: Adding an unnamed parameter
- Go to Assets > Content Types.
- Click your Content Type name to edit it. (Use the Filter tool to search). Open the Content layouts tab.
- The Content layouts tab is an area to add Content Layout(s) for your Content Type. Click into the "text/html" default content layout to edit it.
- Update the existing code by adding an unnamed parameter like so (Replace the [Your Name] placeholder with your actual name):
<p>{{helloWorld [Your Name]}}</p>
You can also pass an unnamed parameter using the publish Helper rather than hard coding in a value like so:
<p>{{helloWorld (publish element="Name")}}</p>
Here a subexpression is created that passes the "Name" element of the Content Type as an unnamed parameter.
<p>{{helloWorld (publish element="Name")}}</p>
- Click Save changes to save the changes to your Content Type.
- Go to your "helloWorld" Custom Helper.
The context parameter will contain the first unnamed parameter passed to a Custom Helper.You will now make use of the context parameter to access the unnamed parameter inside of your Custom Helper code.
- Update your Custom Helper code as per below:
function helloWorld(context, options) {
return `Hello ${context}!`;
}
- Click Save changes to save the changes to your Custom Helper.
- Update your preview to check the result.
Exercise 1.4: Adding a named parameter
- Go to Assets > Content Types.
- Click your Content Type name to edit it. (Use the Filter tool to search). Open the Content layouts tab.
- The Content layouts tab is an area to add Content Layout(s) for your Content Type. Click into the "text/html" default content layout to edit it.
- Update the existing code by adding a Handlebars expression that uses the "greetings" Custom Helper that you will create in the next exercise with a named parameter. To do this use the name of the Custom Helper ("greetings") inside the curly braces and add the name parameter like so (Replace the [Your Name] and [Last Name] placeholders with your name and last name respectively):
<p>{{greetings firstName="[First Name]" lastName="[Last Name]"}}</p>
- Click Save changes to save the changes to your Content Type.
Exercise 1.5: Creating the "greetings" Custom Helper
- Let's create a new Custom Helper to use named parameters.
- Click on any section within your site structure.
- Modify the URL for your section by changing the section Id in the URL to '8303' and hitting enter. This will take you to the Custom Helpers hidden section in the training instance.
- Click on the Add Content button to create a new Custom Helper.
- Name: Give your Custom Helper a name, "greetings". (There should be no spaces in the name field, use camel case as a convention for your Custom Helpers names).
- Function Code: Enter your Custom Helper code into this field as specified below.
To access named parameters you will use the options parameter and call the the hash method. You will then pass the name of your parameter to the hash method.
function (context, options) {
return `Greetings, ${options.hash('firstName')} ${options.hash('lastName')}!`;
}
- Click Save changes to save the changes to your Custom Helper.
- Update your preview to check the result.
Exercise 1.6: Adding exception handling
- You should always consider adding exception handling to your code, let's look at a couple of methods you can use to better capture potential errors in your code when using context and options.
- Let's revisit the "helloWorld" Custom Helper and add code to check whether the context parameter is set. Currently, if we use the "helloWorld" Custom Helper and forget to pass an unnamed parameter we might get an unexpected result.
- Go to your "helloWorld" Custom Helper and update the code as per below:
function (context, options) {
//create a variable called type to store whether context is referring to the global object
const type = Object.prototype.toString.call(context);
//return the String only if the global object is not being returned by context
if (type !== '[object global]' && type !== '[object Window]') {
return `Hello ${context}!`;
}
}
- Click Save changes to save the changes to your Custom Helper.
- Update your preview to check the result.
Now, let's also add exception handling to the "greetings" Custom Helper. In this instance you are using the options parameter instead.
The hash method of the options parameter has a second parameter that is the default output so if the first parameter is null for some reason, the second parameter will be output instead.
- Go to your "greetings" Custom Helper and update the code as per below:
function (context, options) {
return `Greetings, ${options.hash('firstName', 'First Name')} ${options.hash('lastName', 'Last Name')}!`;
}
- Click Save changes to save the changes to your Custom Helper.
- Update your preview to check the result.
2. Escape JSON
- In this exercise, you will create a Custom Helper, "escapeJson" that will allow you to escape text to ensure it's safe to use as JSON output.
Exercise 2.1: Updating the "text/html" content layout
- Go to Assets > Content Types.
- Click your Content Type name to edit it. (Use the Filter tool to search). Open the Content layouts tab.
- The Content Layout tab is an area to add Content Layout(s) for your Content Type. Click into the "text/html" content layout to edit it.
- Add a Handlebars expression that uses the "escapeJson" Custom Helper that you will create in the next exercise. Make sure you pass the "Description" element as an unnamed parameter using the publish Helper.
<p>{{escapeJson (publish element="Description")}}</p>
- Click Save changes to save the changes to your content layout.
Exercise 2.2: Creating the "escapeJson" Custom Helper
- Click on any section within your site structure.
- Modify the URL for your section by changing the section Id in the URL to '8303' and hitting enter. This will take you to the Custom Helpers hidden section in the training instance.
- Click on the Add Content button to create a new Custom Helper.
- Name: Give your Custom Helper a name, "escapeJson". (There should be no spaces in the name field, use camel case as a convention for your Custom Helpers names).
- Function Code: Complete the TODO below to create your Custom Helper.
TODO:
1. Return the JSON escaped string by using the JavaScript stringify method.
function (context, options) {
//1. TODO: return the JSON escaped string
return JSON.stringify();
}
- Click Save changes to save the changes to your Custom Helper.
- Update your preview to check the result.
3. Trim
- In this exercise, you will create a Custom Helper, "trim". The "trim" Custom Helper can be used to remove whitespace before and after text.
Exercise 3.1: Updating the "text/html" content layout
- Go to Assets > Content Types.
- Click your Content Type name to edit it. (Use the Filter tool to search). Open the Content layouts tab.
- The Content Layout tab is an area to add Content Layout(s) for your Content Type. Click into the "text/html" content layout to edit it.
- Add Handlebars expressions that uses the "trim" Custom Helper that you will create in the next exercise:
<p>{{trim " string to trim "}}</p>
<p>{{trim (publish element="Name")}}</p>
- Click Save changes to save your Content Type.
Exercise 3.2: Creating the "trim" Custom Helper
- Click on any section within your site structure.
- Modify the URL for your section by changing the section Id in the URL to '8303' and hitting enter. This will take you to the Custom Helpers hidden section in the training instance.
- Click on the Add Content button to create a new Custom Helper.
- Name: Give your Custom Helper a name, "trim". (There should be no spaces in the name field, use camel case as a convention for your Custom Helpers names).
- Function Code: Complete the TODO below to create your Custom Helper.
TODO:
1. Use the JavaScript trim function to trim and return the string.
function (context, options) {
//1. TODO: Use the JavaScript trim function and return the string
return
}
- Click Save changes to save the changes to your Custom Helper.
- Update your preview to check the result.
4. Extract Href
- The "extractHref" Custom Helper can be used to return the href value of a link.
-
This is used mainly to get the URL out from a fulltext link. A native Helper will be created in a future release that will just return the fulltext URL directly (e.g. {{fulltextURL}}).
- Let's learn how to create the "extractHref" Custom Helper and use it to apply customization to a fulltext link.
Exercise 4.1: Updating the "text/html" content layout
- Go to Assets > Content Types.
- Click your Content Type name to edit it. (Use the Filter tool to search). Open the Content layouts tab.
- The Content Layout tab is an area to add Content Layout(s) for your Content Type. Click into the "text/html" content layout to edit it.
- Click into the </> Content layout code tab and add the code below which uses the "extractHref" Custom Helper that you will create in the next exercise.
- Create an additional fulltext link and customize it by adding some additional attributes:
- Add a target="_blank" attribute.
- Add a title element.
- Add a class of "button".
<h3>{{extractHref (fulltext linkText=(publish element="Headline"))}}</h3>
<h3><a href="{{extractHref (fulltext linkText=(publish element="Headline"))}}" target="_blank" title="My fulltext link" class="button">{{publish element="Headline"}}</a></h3>
- Click Save changes to save your Content Type.
Exercise 4.2: Creating the "extractHref" Custom Helper
- Click on any section within your site structure.
- Modify the URL for your section by changing the section Id in the URL to '8303' and hitting enter. This will take you to the Custom Helpers hidden section in the training instance.
- Click on the Add Content button to create a new Custom Helper.
- Name: Give your Custom Helper a name, "extractHref". (There should be no spaces in the name field, use camel case as a convention for your Custom Helpers names).
- Function Code: Copy/paste the following code to create your Custom Helper.
function (context, options) {
const re = /.*href="(.*?)".*/;
const found = context.match(re);
if (found)
return found[1];
return '';
}
- Click Save changes to save the changes to your Custom Helper.
- Update your preview to check the result.
5. String Contains
- In this exercise, you will create your first block level expression Custom Helper.
- Let's explore what is available within options and build a Custom Helper that uses some of its available methods.
- The "stringContains" Custom Helper you will build next checks whether a String is contained within a second String.
Method | What it does |
---|---|
options.params | Returns a List <Object> of all positional parameters |
options.param(int) | Gets a specific positional parameter by index |
options.hash(String) | Gets a named (hash-style) param |
options.fn() | Gets the template block (for block content) |
options.inverse() | Gets the {{else}} block |
options.data() | Another way to pass data back about your Helper (Not recommended) |
Exercise 5.1: Updating the "text/html" content layout
- Go to Assets > Content Types.
- Click your Content Type name to edit it. (Use the Filter tool to search). Open the Content layouts tab.
- The Content Layout tab is an area to add Content Layout(s) for your Content Type. Click into the "text/html" content layout to edit it.
- Add a Handlebars block expression that uses the "stringContains" Custom Helper that you will create in the next exercise:
{{#stringContains "string-to-check" "value"}}
<p>Yes the first string contains the second string!</p>
{{else}}
<p>No. The first string does not contain the second string!</p>
{{/stringContains}}
- Click Save changes to save your Content Type.
Exercise 5.2: Creating the "stringContains" Custom Helper
- Click on any section within your site structure.
- Modify the URL for your section by changing the section Id in the URL to '8303' and hitting enter. This will take you to the Custom Helpers hidden section in the training instance.
- Click on the Add Content button to create a new Custom Helper.
- Name: Give your Custom Helper a name, "stringContains". (There should be no spaces in the name field, use camel case as a convention for your Custom Helpers names).
- Function Code: Complete the TODOs below to create your Custom Helper.
TODOs:
1. Get the string passed in from context and store it into the "mainString" variable.
2. Get the string to check by using the params method.
3. Return "this" using the fn method.
4. Return "this" using the inverse method.
function (context, options) {
//1. TODO: Get the string from context
const mainString
//2. TODO: Get the string to check (use the params method)
const stringToCheck
const result = mainString.indexOf(stringToCheck);
if (result != -1) {
//3. TODO: return "this" using the fn method
return
}
//4. TODO: return "this" using the inverse method
return
}
- Click Save changes to save the changes to your Custom Helper.
- Update your preview to check the result.
Adding different behaviors to the "stringContains" Custom Helper
The fulltext Helper for example takes on completely different behavior if it is used as a block expression vs a standard expression.
As a standard expression, the fulltext Helper will output a link to a fulltext page. In the code below, the fulltext Helper would generate a link to a fulltext page using the "Headline" element of a Content Type.
{{{fulltext linkText=(publish element="Headline")}}}In contrast, as a block level expression, the fulltext Helper will let you know if the current page is a fulltext page or not.
{{#fulltext}}
<p>This is a fulltext page.</p>
{{else}}
<p>This is not a fulltext page.</p>
{{/fulltext}}Let's learn how we can add different behaviors to our Custom Helpers. The key is to use the "options.tagType" variable which will return a string letting you know the type of expression:
function (context, options) {
return options.tagType;
}The returned value in the above code example will be one of the following:
Value (options.tagType) | Expression |
---|---|
VAR | Standard expression |
TRIPLE_VAR | Standard expression that is "triple stashed" |
SUB_EXPRESSION | Subexpression |
SECTION | Block expression |
You can use these values to provide different behaviors depending on the type of expression being used for your Custom Helpers.
Let's build an example where we are adding an additional behavior to your "stringContains" Custom Helper if it is used as a standard expression. When used as a standard expression, "stringContains" should return the length of the String passed in.
Exercise 5.3: Updating the "text/html" content layout
- Go to Assets > Content Types.
- Click your Content Type name to edit it. (Use the Filter tool to search). Open the Content layouts tab.
- The Content Layout tab is an area to add Content Layout(s) for your Content Type. Click into the "text/html" content layout to edit it.
- Add a Handlebars expression that uses the "stringContains" Custom Helper as a standard level expression. To do this use the Custom Helper ("stringContains") inside the curly braces as below:
<p>{{stringContains "count how many characters in this string"}}</p>
- Click Save changes to save your Content Type.
Exercise 5.4: Updating the "stringContains" Custom Helper
- Click on any section within your site structure.
- Modify the URL for your section by changing the section Id in the URL to '8303' and hitting enter. This will take you to the Custom Helpers hidden section in the training instance.
- Click on the "stringContains" Custom Helper button to update it.
- Function Code: Complete the TODOs below to update your Custom Helper.
TODOs:
1. Wrap the previous code in an if statement so it only executes when the Custom Helper is used as a block level expression.
2. Add an else condition for when the code should execute as a standard level expression.
3. Return the length of the passed in string if it's a standard level expression.
function (context, options) {
//1. TODO: add an if statement for block level expressions
const mainString = context;
const stringToCheck = options.param(0);
const result = mainString.indexOf(stringToCheck);
if (result != -1) {
return options.fn(this);
}
return options.inverse(this);
//2. TODO: add an else condition for standard level expressions
//3. TODO: return the length of the passed in string if it's a standard level expression
}
- Click Save changes to save the changes to your Custom Helper.
- Update your preview to check the result.
6. Epoch
- In this exercise, you will get to create the "epoch" Custom Helper. It will be used to return the number of seconds since January 1, 1970, given a specific date. In essence, it will take in a date and then perform calculations to return back the number of seconds since January 1, 1970 to that date.
Exercise 6.1: Updating the "text/html" content layout
- Go to Assets > Content Types.
- Click your Content Type name to edit it. (Use the Filter tool to search). Open the Content layouts tab.
- The Content Layout tab is an area to add Content Layout(s) for your Content Type. Click into the "text/html" content layout to edit it.
- Add a Handlebars expression that uses the "epoch" Custom Helper that you will create in the next exercise. Make sure to pass the "date" element as an unnamed parameter using the publish Helper.
<p>{{epoch (dateFormat (dateElement element="Date") "YYYY/MM/dd hh:mma")}}</p>
- Click Save changes to save your Content Type.
Exercise 6.2: Creating the "epoch" Custom Helper
- Click on any section within your site structure.
- Modify the URL for your section by changing the section Id in the URL to '8303' and hitting enter. This will take you to the Custom Helpers hidden section in the training instance.
- Click on the Add Content button to create a new Custom Helper.
- Name: Give your Custom Helper a name, "epoch". (There should be no spaces in the name field, use camel case as a convention for your Custom Helpers names).
- Function Code: Complete the TODOs below to create your Custom Helper.
TODOs:
1. Get the date passed via context and store it into the "dateString" variable.
2. Pass the date into the floor method to convert it to seconds. (HINT: Use the getTime() method).
function (context, options) {
//1. TODO: store the date from context
const dateString =
const date = new Date(dateString);
//2. TODO: pass the date to the floor method and convert it to seconds
const epochTime = Math.floor( /1000);
return epochTime.toString();
}
- Click Save changes to save the changes to your Custom Helper.
- Update your preview to check the result.
7. Date Range
- The "dateRange" Custom Helper can be used to check whether a date is between a range of dates and then output a corresponding message.
- Let's use the "dateRange" Custom Helper to check whether the current date falls between a holiday start date and a holiday end date and then output a corresponding message to the page.
Exercise 7.1: Updating the "text/html" content layout
- Go to Assets > Content Types.
- Click your Content Type name to edit it. (Use the Filter tool to search). Open the Content layouts tab.
- The Content Layout tab is an area to add Content Layout(s) for your Content Type. Click into the "text/html" content layout to edit it.
- Click into the </> Content layout code tab and add a Handlebars expression that uses the "dateRange" Custom Helper that you will create in the next exercise.
<p>{{dateRange (publish element="Start Date") (publish element="End Date")}}</p>
- Click Save changes to save your Content Type.
Exercise 7.2: Creating the "dateRange" Custom Helper
- Click on any section within your site structure.
- Modify the URL for your section by changing the section Id in the URL to '8303' and hitting enter. This will take you to the Custom Helpers hidden section in the training instance.
- Click on the Add Content button to create a new Custom Helper.
- Name: Give your Custom Helper a name, "dateRange". (There should be no spaces in the name field, use camel case as a convention for your Custom Helpers names).
- Function Code: Complete the TODOs below to create your Custom Helper.
TODOs:
1. Get the holiday start date from context.
2. Get the holiday end date using the options param method.
3. Return the holiday opening hours message.
4. Return the regular opening hours message.
function (context, options) {
//1. TODO: get the holiday start date using context
const holidayStart =
//2. TODO: get the holiday end date using the options param method
const holidayEnd =
let todaysDate = new Date();
// Remove "IST" or any extra time zone abbreviation
const cleanedHolidayStart = holidayStart.replace(/ [A-Z]{3,4}$/, '');
const cleanedHolidayEnd = holidayEnd.replace(/ [A-Z]{3,4}$/, '');
const d1 = new Date(cleanedHolidayStart);
const day1 = String(d1.getDate());
const month1 = String(d1.getMonth() + 1);
const year1 = d1.getFullYear();
const d2 = new Date(cleanedHolidayEnd);
const day2 = String(d2.getDate());
const month2 = String(d2.getMonth() + 1);
const year2 = d2.getFullYear();
let from = new Date(year1, month1-1, day1);
let to = new Date(year2, month2-1, day2);
let isBetweenDates = (todaysDate > from && todaysDate < to);
if (isBetweenDates) {
//3. TODO: return a String: "Holiday opening hours"
return
} else {
//4. TODO: return a String: "Regular opening hours"
return
}
}
- Click Save changes to save the changes to your Custom Helper.
- Update your preview to check the result.
8. Selected Contains
- The "selectedContains" Custom Helper that you will create next can be used to evaluate if a user has selected a given string from a list in a Content Type.
- In this exercise, you will get additional practice using the fn and inverse methods, as well as, using the hash method to retrieve a named parameter passed to the custom Helper.
Exercise 8.1: Updating the "text/html" content layout
- Go to Assets > Content Types.
- Click your Content Type name to edit it. (Use the Filter tool to search). Open the Content layouts tab.
- The Content Layout tab is an area to add Content Layout(s) for your Content Type. Click into the "text/html" content layout to edit it.
- Add a Handlebars block expression that uses the "selectedContains" Custom Helper that you will create in the next exercise:
{{#selectedContains (selected element="Academic Program") string_to_check="Education" }}
<p>You must consult with an advisor first to select this academic program.</p>
{{else}}
<p>Your selection is now complete and has been forwarded to the registration office!</p>
{{/selectedContains}}
- Click Save changes to save your Content Type.
Exercise 8.2: Creating the "selectedContains" Custom Helper
- Click on any section within your site structure.
- Modify the URL for your section by changing the section Id in the URL to '8303' and hitting enter. This will take you to the Custom Helpers hidden section in the training instance.
- Click on the Add Content button to create a new Custom Helper.
- Name: Give your Custom Helper a name, "selectedContains". (There should be no spaces in the name field, use camel case as a convention for your Custom Helpers names).
- Function Code: Complete the TODOs below to create your Custom Helper.
TODOs:
1. Get the ''string_to_check' using the hash method.
2. Return "this" using the fn method.
3. Return "this" using the inverse method.
function (context, options) {
if(!options.hash('string_to_check')) {
return `<div style="border: 1px solid #300;background-color:#fdd;color:#300;padding:1rem;font-size:1rem;border-radius:10px">No string passed to compare</div>`;
}
//1. TODO: get the 'string_to_check' using the hash method
const testString =
let id = 'name';
if (options.hash('field_to_check') === 'name' || options.hash('field_to_check') === 'value') {
id = options.hash('field_to_check');
}
let result = false;
for (let i = 0; i < context.length; i++) {
if(context[i].get(id) === testString) {
result = true;
break;
}
}
if(result) {
//2. TODO: return "this" using the fn method
return
}
//3. TODO: return "this" using the inverse method
return
}
- Click Save changes to save the changes to your Custom Helper.
- Update your preview to check the result.
9. Math
- The "math" Custom Helper can be used to perform some simple mathematical operations on some inputs.
-
It can be used to perform any of the following operations:
- Addition - using
+
- Subtraction - using
-
- Multiplication - using
*
- Division - using
/
- Modulus - using
%
- Addition - using
Exercise 9.1: Updating the "text/html" content layout
- Go to Assets > Content Types.
- Click your Content Type name to edit it. (Use the Filter tool to search). Open the Content layouts tab.
- The Content Layout tab is an area to add Content Layout(s) for your Content Type. Click into the "text/html" content layout to edit it.
- Add Handlebars expressions that use the "math" Custom Helper that you will create in the next exercise. Feel free to test additional operators like (-, /, %).
<p>{{math 1 '+' 2}}</p>
<p>{{math 5 '*' 2}}</p>
- Click Save changes to save your Content Type.
Exercise 9.2: Creating the "math" Custom Helper
- Click on any section within your site structure.
- Modify the URL for your section by changing the section Id in the URL to '8303' and hitting enter. This will take you to the Custom Helpers hidden section in the training instance.
- Click on the Add Content button to create a new Custom Helper.
- Name: Give your Custom Helper a name, "math". (There should be no spaces in the name field, use camel case as a convention for your Custom Helpers names).
- Function Code: Complete the TODOs below to create your Custom Helper.
TODOs:
1. Extract the operator by using the options param method.
2. Extract the right hand value by using the options param method. (HINT: Check how "lvalue" is retrieved from context)
function (context, options) {
//Convert context to a number
const lvalue = context % 1 === 0 ? parseInt(context): parseFloat(context);
//1. TODO: Extract the operator: use the options param method
const operator =
//2. TODO: Extract the right hand value: use the options param method
const rvalue =
}
- Click Save changes to save the changes to your Custom Helper.
Exercise 9.3: Completing the "math" Custom Helper
- Update your code by adding a result variable that implements the different math operators, then return the result at the end of your function. Complete the TODO below.
TODO:
1. Complete the code by adding the missing operators to your function. You should add: "-", "*", "/", and "%".
function (context, options) {
// Perform the appropriate operation based on the provided operator
const result = {
"+": lvalue + rvalue,
//1. TODO: Add the missing operators
}[operator]
return result;
}
- Click Save changes to save the changes to your Custom Helper.
- Update your preview to check the result.
10. Video Embed
- In this exercise, you will create a Custom Helper, "videoEmbed" that will allow you to output video.
- The "videoEmbed" Helper can be used to convert a youtube or vimeo into an iframe effectively. This allows users to paste YouTube or Vimeo links into a plain text field in various formats and have them be converted effectively into an iframe to be output on the page.
Exercise 10.1: Updating the "text/html" content layout
- Go to Assets > Content Types.
- Click your Content Type name to edit it. (Use the Filter tool to search). Open the Content layouts tab.
- The Content Layout tab is an area to add Content Layout(s) for your Content Type. Click into the "text/html" content layout to edit it.
- Add a Handlebars expression that uses the "videoEmbed" Custom Helper that you will create in the next exercise. Make sure you pass the "Video Link" element as an unnamed parameter.
The videoEmbed Custom Helper will generate an iframe <iframe> tag, notice that you will need to triple-stash your expression so the html being generated gets parsed correctly and the video displays within an embedded iframe to your page.
{{{videoEmbed (publish element="Video URL")}}}
- Click Save changes to save the changes to your content layout.
Exercise 10.2: Creating the "videoEmbed" Custom Helper
- Click on any section within your site structure.
- Modify the URL for your section by changing the section Id in the URL to '8303' and hitting enter. This will take you to the Custom Helpers hidden section in the training instance.
- Click on the Add Content button to create a new Custom Helper.
- Name: Give your Custom Helper a name, "videoEmbed". (There should be no spaces in the name field, use camel case as a convention for your Custom Helpers names).
- Function Code: Copy/Paste the code below to create your Custom Helper.
function (context, options) {
const media = {};
if(context.match('https?://(www.)?youtube|youtu.be')) {
const ytrx = `^.*(?:(?:youtu\.?be\/|v\/|vi\/|u\/\w\/|embed\/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?"']*).*`;
const ytr = context.match(ytrx);
media.type = 'youtube';
media.id = ytr[1];
}
else if (context.match('https?://(player.)?(www.)?vimeo.com')) {
const vrx = `^.*(?:(?:vimeo\.?com\/|v\/|vi\/|v\/u\/\w\/|video\/)|(?:(?:video)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?"'\/]*).*`;
const vr = context.match(vrx);
let vimeo_id = vr ? vr[2] || vr[1] : null;
media.type = 'vimeo';
media.id = vimeo_id;
}
if (media.type === 'youtube') {
return `<iframe class="embed-responsive-item" width="560" height="315" src="https://www.youtube.com/embed/${media.id}" frameborder="0" allowfullscreen></iframe>`;
}
if (media.type === 'vimeo') {
return `<iframe class="embed-responsive-item" src="https://player.vimeo.com/video/${media.id}?color=f36788" width="560" height="315" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>`;
}
// error handling
if (publishConfig.isPreview ()) {
return `<div style="background: #fdd; color: #411; padding: 1rem; font-size: 1rem; border: 1px solid #411;border-radius: .25rem;margin-bottom: 1rem"><strong>Preview error:</strong> Invalid video link added</div>`;
}
else {
return `<script>console.warn('Video embed cannot be created because an invalid video URL was supplied')</script>`;
}
}
- Click Save changes to save the changes to your Custom Helper.
- Update your preview to check the result.
11. Responsive Text
- In this exercise, you will create the "responsiveText" Custom Helper which can be used to return responsive markup for a text element. It requires two parameters, the text and the length of the string at which point the element should be hidden on small screens.
Exercise 11.1: Updating the "text/html" content layout
- Go to Assets > Content Types.
- Click your Content Type name to edit it. (Use the Filter tool to search). Open the Content layouts tab.
- The Content Layout tab is an area to add Content Layout(s) for your Content Type. Click into the "text/html" content layout to edit it.
- Click into the </> Content layout code tab and add a Handlebars expression that uses the "responsiveText" Custom Helper that you will create in the next exercise.
<h2>{{{responsiveText (publish element="Heading") "50"}}}</h2>
- Click Save changes to save your Content Type.
Exercise 11.2: Creating the "responsiveText" Custom Helper
- Click on any section within your site structure.
- Modify the URL for your section by changing the section Id in the URL to '8303' and hitting enter. This will take you to the Custom Helpers hidden section in the training instance.
- Click on the Add Content button to create a new Custom Helper.
- Name: Give your Custom Helper a name, "responsiveText". (There should be no spaces in the name field, use camel case as a convention for your Custom Helpers names).
- Function Code: Complete the TODOs below to create your Custom Helper.
TODOs:
1. Get the element using the context parameter and store it in the "elementStr" variable.
2. Get the length of the string passed in by using the options param method.
3. Return the string as is by storing it in the "responsiveString" variable.
function (context, options) {
//1. TODO: get the element from context
const elementStr =
//2. TODO: get the length of the string using the options param method
const lengthOfString =
//Some hard coded default values which could be overwritten using elements in your content type)
let defaults = {
breaker: '...',
smallClass: 'show-for-small-only',
largeClass: 'show-for-large-only'
};
let separator,
shortenedString,
remainingCharacters,
responsiveString;
// if the string is shorter that the specified length, just return the element as is.
if (elementStr.length < lengthOfString) {
//3. TODO: return the string as is by storing it in responsiveString
} else {
shortenedString = elementStr.substr(0,lengthOfString);
remainingCharacters = elementStr.substr(lengthOfString);
separator = (defaults.breaker === undefined) ? '' : '<span class="'+ defaults.smallClass +'">' + defaults.breaker + '</span>';
responsiveString = shortenedString + separator + '<span class="'+ defaults.largeClass +'">' + remainingCharacters + '</span>';
}
return responsiveString;
};
- Click Save changes to save the changes to your Custom Helper.
- Update your preview to check the result.
12. The IPublish API
The IPublishAPI allows you to interact with the Terminalfour platform from within Custom Helpers. It is a public facing, customer centric, read only API.
All core built-in Helpers provided by Terminalfour are implemented using the IPublishAPI. Any new Helpers that are created going forward will also be backed up by the IPublishAPI.
How to use the IPublish API
IPublishAPI Documentation:
https://docs.terminalfour.com/publishapi/8.4.0/com/terminalfour/publish/api/IPublishAPI.html
To access the IPublish API, you can make use of the apis variable. See examples below:
apis
//Examples:
apis.getPage(); //gets the current Page
apis.getSection(); //gets the current section
apis.getPage().getPageURL(); //gets the current page URL
apis.getSection().getId(); //gets the current section Id
Let's create some Handlebars expressions to practice using the IPublish API:
Exercise 12.1: Get the current channel name
Write a Handlebars expression to retrieve the current channel's name.
Exercise 12.2: Find if an element is set
Write a Handlebars expression that returns whether an element is set.
Exercise 12.3: Get the content from a specific section by using the section Id
Write a Handlebars expression that returns all the content from a specific section.
Exercise 12.4: Find if the current page is a fulltext page
Write a Handlebars expression that returns whether the current page is a fulltext page.
13. Get Section Name By Id
-
The "getSectionNameById" Custom Helper can be used to retrieve a specific section from the site structure based on a provided Id.
- In the following exercise, you will create the "getSectionNameById" Custom Helper to output the section name to the page.
Exercise 13.1: Updating the "text/html" content layout
- Go to Assets > Content Types.
- Click your Content Type name to edit it. (Use the Filter tool to search). Open the Content layouts tab.
- The Content Layout tab is an area to add Content Layout(s) for your Content Type. Click into the "text/html" content layout to edit it.
- Click into the </> Content layout code tab and add the code below which uses the "getSectionNameById" Custom Helper that you will create in the next exercise. Pass a correct Id from your site structure as an unnamed parameter.
<p>{{getSectionNameById id}}</p>
- Click Save changes to save your Content Type.
Exercise 13.2: Creating the "getSectionNameById" Custom Helper
- Click on any section within your site structure.
- Modify the URL for your section by changing the section Id in the URL to '8303' and hitting enter. This will take you to the Custom Helpers hidden section in the training instance.
- Click on the Add Content button to create a new Custom Helper.
- Name: Give your Custom Helper a name, "getSectionNameById". (There should be no spaces in the name field, use camel case as a convention for your Custom Helpers names).
- Function Code: Complete the TODOs below to create your Custom Helper.
TODOs:
1. Get the section Id from context.
2. Get the section name using the section Id.
3. Return the section name.
function(context, options) {
//1. TODO: use context to get the section Id
let sectionId =
//2. TODO: retrieve the section name
let section =
//3. TODO: return the section name
return
}
- Click Save changes to save the changes to your Custom Helper.
- Update your preview to check the result.
14. Tabs
- In the following exercise, you will create a tabs container. You will create a Custom Helper called "loopContentInSequence" and use it to return an array of items containing details about other Content Items using the Same Content Type in sequence.
- This Custom Helper is designed to be used alongside the each Helper so you can loop over the array and output the data you need.
- It makes most sense when used inside the firstInSequence or lastInSequence Helpers.
- The purpose of this Helper is to support the output of Markup for components like "Tabs" or some "Carousels".
first and last Helpers
The first Helper will be true when the content item is the first piece of content in a section.
{{#first}}
<h1>First content item in the section</h1>
{{/first}}The last Helper will be true when the content item is the last piece of content in a section.
{{#last}}
<footer>Last content item in the section</footer>
{{/last}}
firstOfType and lastOfType Helpers
These Helpers let you know if an item of content is the first and last of its type in a section:
{{#firstOfType}}
Only output if first of this content type in section
{{/firstOfType}}{{#lastOfType}}
Only output if last of this content type in section}}
{{/lastOfType}}
firstInSequence and lastInSequence Helpers
Perhaps more flexible though, are these Helpers which allow you to determine if an item of content is the first and last of its type in an uninterrupted sequence of content in a section.
The firstInSequence Helper will be true when the content item is the first piece of content using this Content Type in an uninterrupted sequence of content in a section.
{{#firstInSequence}}
Only output if first of this content type in an uninterrupted sequence in this section
{{/firstInSequence}}
The lastInSequence Helper will be true when the content item is the last piece of content using this Content Type in an uninterrupted sequence of content in a section.
{{#lastInSequence}}
Only output if last of this content type in an uninterrupted sequence in this section
{{/lastInSequence}}
Exercise 14.1: Setting up the jQuery UI Library
The Tabs container is generated using the jQuery UI Library. In order to use this library, you will need to upload three files into your media library and then target them using Handlebars in your page layout. These files have been previously uploaded to the media library, let's learn how to reference them using Handlebars in the page layout.
- Go to Content > Media Library.
- Click into "T206 Training Site Example" and then into Developer Assets.
- Click into the CSS and JavaScript folders to retrieve the corresponding ids of the required libraries.
- Go to Assets > Page Layouts.
- Click your page layout name to edit it. (Use the Filter tool to search). Open the </> Header code tab.
- Use the media Helper to create the link to the jQuery UI CSS file.
{{{media id="10925" layout="css/*"}}} <!-- jQuery UI CSS-->
- Open the </> Footer code tab.
- Use the media Helper to create the link to the jQuery UI file.
{{{media id="10926" layout="text/javascript"}}} <!-- jQuery UI JS -->
- Use the media Helper to insert the jQuery tabs script that generates the tab container.
{{{media id="12261" layout="text/javascript"}}} <!-- jQuery UI Tabs Script -->
- Click Save changes to save the changes to your page layout.
Exercise 14.2: Creating the Tabs Content Type
- Go to Assets > Content Types > Create content type.
- Fill in the General content type information:
- Name: enter a name here. This should suggest what type of content it is used for.
- Description: describe in more detail when to use this Content Type.
- Minimum user level: if you wish to restrict who can use this content type, you can set a level here. If content types are created in groups, a user must be a member of the group as well as meet the minimum user level criteria to use the Content Type.
- Enable direct edit: decide if direct edit can be used for this content type.
- Mark as eForm: If checked, this allows your Content Type to collect eForm data.
- Workflow: if relevant, enable a workflow for content created using this content type.
- Primary group: Select your group. This allows you to select the group which is permitted to use this content type. Click Toggle shared groups to share the content type with more than one group.
- Select the Elements Tab.
- Each content type has a Name element by default. This is used to name the content and is typically not displayed on the published site.
- Add the other elements you need by filling in the information as outlined in the table below. Click add element to begin filling in the details for each element.
Name | Description | Type | Max Size | Required | Show |
---|---|---|---|---|---|
Tab Title | Tab Title | Plain Text | 50 | Yes | Yes |
Tab Content | Tab Content | HTML | 100000 | Yes | Yes |
- Once you have added all your elements, click Save changes. The Content Layout tab opens.
Exercise 14.3: Creating the "text/html" content layout
- Go to Assets > Content Types.
- Click on + Add content layout
- Fill in the General information tab:
- Name: "text/html".
- File extension: Default - unless this is used with a different File Extension. This requires other extensions being permitted in the Channel.
- Syntax type: HTML/XML - this determines which syntax is highlighted.
- Content layout processor: Handlebars Content
- Click into the </> Content layout code tab and add Handlebars expressions that use the "loopContentInSequence" Custom Helper that you will create in the next exercise.
- Let's start by creating the HTML structure for the Tabs container and wrapping it inside a firstInSequence block expression. Complete the TODOs below.
TODOs:
1. Open a firstInSequence block expression.
2. Close a firstInSequence block expression.
[1. TODO: Open firstInSequence]
<div id="tabs">
<ul>
<li></li>
</ul>
<div>
</div>
[2. TODO: Close firstInSequence]
- Click Save changes to save your Content Type.
Exercise 14.4: Adding the "loopContentInSequence" to output the tab title
- Add an each Helper expression combined with the "loopContentInSequence" Helper. The each Helper expression should wrap the output of the individual list items that contain the tab title.
When using the "loopContentInSequence" Helper inside an each block there are two variables available to output:
{{id}} - Outputs the Content Id of the returned Content Item (always returned)
{{value}} - Outputs the value contained within the passed element (returned if the element attribute was provided)
Use the {{value}} variable in your code below to output the Tab Title.
Complete the TODOs below.
TODOs:
1. Use the each Helper to iterate through the tabs, pass the sequence to the each Helper using the loopContentInSequence Custom Helper.
2. Output the tab title.
3. Close the each Helper block expression.
{{#firstInSequence}}
<div id="tabs">
<ul>
[1. TODO: Use the each Helper and pass the sequence to iterate using the loopContentInSequence Custom Helper]
<li>[2. TODO: Output the tab title]</li>
[3. TODO: Close the each block]
</ul>
<div>
</div>
{{/firstInSequence}}
- Click Save changes to save your Content Type.
Exercise 14.5: Adding the "loopContentInSequence" to output the tab content
- Use the each and "loopContentInSequence" Helpers to output the Tab Content element. Complete the TODOs below.
TODOs:
1. Use the each Helper to iterate through the tabs, pass the sequence to the each Helper using the loopContentInSequence Custom Helper.
2. Output the tab content.
3. Close the each Helper block expression.
{{#firstInSequence}}
<div id="tabs">
<ul>
{{#each (loopContentInSequence element="Tab Title")}}
<li>{{value}}</li>
{{/each}}
</ul>
[1. TODO: Use the each Helper and pass the sequence to iterate using the loopContentInSequence Custom Helper]
<div>
[2. TODO: Output the tab content]
</div>
[3. TODO: Close the each block]
{{/firstInSequence}}
- Click Save changes to save your Content Type.
Exercise 14.6: Creating the links for the tab titles
- The individual tab titles should be clickable links that open to the corresponding content for each tab title. Let's add links (<a>) for each tab title. To do this add an <a> tag within each list item<li>. Complete the TODO below.
The href attribute of the link should have a value of "tabs-sequence", where sequence is the value returned from the "loopContentInSequence" Custom Helper. Use the {{id}} variable of the Custom Helper to achieve this.
TODO:
1. Create links (<a>) inside the list items. Provide the appropriate href attribute as specified above.
{{#firstInSequence}}
<div id="tabs">
<ul>
{{#each (loopContentInSequence element="Tab Title")}}
[1. TODO: Create links (<a>) inside the list items. Provide the appropriate href attribute as specified above.]
<li>{{value}}</li>
{{/each}}
</ul>
{{#each (loopContentInSequence element="Tab Content")}}
<div>
{{{value}}}
</div>
{{/each}}
{{/firstInSequence}}
- Click Save changes to save your Content Type.
Exercise 14.7: Adding the id to the tab content divs
In order for the tabs to open correctly, each individual div should reference the same id as in the href attribute of each link.
- Add an id of "tabs-id" to each div where id is given by the {{id}} variable. Complete the TODO below.
TODO:
1. Add the id to the div of the tab content. The id should follow the format: "tabs-id".
{{#firstInSequence}}
<div id="tabs">
<ul>
{{#each (loopContentInSequence element="Tab Title")}}
<li><a href="#tabs-{{id}}">{{value}}</a></li>
{{/each}}
</ul>
[1. TODO: ADD the id to the div of the tab content.]
{{#each (loopContentInSequence element="Tab Content")}}
<div>
{{{value}}}
</div>
{{/each}}
{{/firstInSequence}}
- Click Save changes to save your Content Type.
Exercise 14.8: Adding the closing div to the wrapper
Finally, let's add the closing div for your tabs container. To do this you need to make use of the lastInSequence Helper.
- Write a block expression using the lastInSequence Helper. Complete the TODOs below.
TODOs:
1. Open a lastInSequence block expression.
2. Close a lastInSequence block expression.
{{#firstInSequence}}
<div id="tabs">
<ul>
{{#each (loopContentInSequence element="Tab Title")}}
<li><a href="#tabs-{{id}}">{{value}}</a></li>
{{/each}}
</ul>
{{#each (loopContentInSequence element="Tab Content")}}
<div id="tabs-{{id}}">
{{{value}}}
</div>
{{/each}}
{{/firstInSequence}}
[1. TODO: Open a lastInSequence block]
</div>
[2. TODO: Close the lastInSequence block]
- Click Save changes to save your Content Type.
- Update your preview to check the result.
Exercise 14.9: Creating the "loopContentInSequence" Custom Helper
- Click on any section within your site structure.
- Modify the URL for your section by changing the section Id in the URL to '8303' and hitting enter. This will take you to the Custom Helpers hidden section in the training instance.
- Click on the Add Content button to create a new Custom Helper.
- Name: Give your Custom Helper a name, "loopContentInSequence". (There should be no spaces in the name field, use camel case as a convention for your Custom Helpers names).
- Function Code: Complete the TODOs below to create your Custom Helper.
TODOs:
1. Get the content (HINT: Use pageContext).
2. Get the Id (HINT: Use the getId method).
3. Get the content in a list format. (HINT: Get the section first)
4. Get the content index (HINT: Use the getIndex method and pass the contentList and the contentId)
function(context, options) {
let providedElement = null;
if(options.hash ('element')) {
providedElement = options.hash ('element');
}
const sequence = [];
const getIndex = (list, id) => {
for (let idx = 0; idx < list.size (); idx++) {
if (list.get (idx).getId () == id)
return idx;
}
return -1;
}
//1. TODO: get the content (HINT: use pageContext)
const content =
//2. TODO: get the id (HINT: use the getId method)
const contentId =
//3. TODO: get the content in a list format (HINT: get the section first)
const contentList =
//4. TODO: get the content index (HINT: use the getIndex method and pass the contentList and the contentId)
const contentIndex =
const selfContentObj = {"id": contentId};
if (providedElement) {
selfContentObj["value"] = content.getElement(providedElement).process()
}
sequence.push(selfContentObj);
for (let nextIndex = contentIndex + 1; nextIndex < contentList.size (); nextIndex++) {
let next = contentList.get (nextIndex);
if (next.getContentTypeId () != content.getContentTypeId ())
break;
const nextContentObj = {"id": next.getId()};
if (providedElement) {
nextContentObj["value"] = apis.getContent().get(next.getId()).getElement(providedElement).process();
}
sequence.push(nextContentObj);
}
return sequence;
};
- Click Save changes to save the changes to your Custom Helper.
Let's add some sample content using the "Tabs" Content Type.
1. On the Site Structure screen, click on the name of your "Tabs" section.
2. The General information about this section screen appears, select the Content types tab.
3. Using the Filter feature, locate your Content Type.
4. Select the radio button to enable your content type for either the branch or section:
a. Enabled (branch): the Content Type can be used in this section as well as all its sub-sections.
b. Enabled (section): the Content Type can be used in this section only.
5. Click Save changes to confirm your selection. You can now use the "Tabs" Content Type to add content to your section.
6. Add at least two "Tab Items" to your "Tabs" section of your website. Feel free to use this Lorem Ipsum generator.
- Update your preview to check the result.
15. Value from First in Sequence
- The "valueFromFirstInSequence" Helper is used to return a provided list element's value for the first Content Item in the sequence.
- This is used for some more advanced "wrapping" scenarios where you need to know some information about the first content item in a sequence from all subsequent content items. (e.g. the 2nd, 3rd, 4th, and 5th, content item in a sequence all need to output a value from the first content item in the sequence)
- In the following example, you will update the tabs container. You will create a Custom Helper called "valueFromFirstInSequence" and use it to return a value in the first content item in the sequence that you will need in the subsequent tabs of your tabs container.
Exercise 15.1: Adding a List element to the Tabs Content Type
- Go to Assets > Content Types.
- Click your Content Type name to edit it. (Use the Filter tool to search).
- Open the Elements tab.
- Add a new list element by filling in the information as outlined in the table below. Click add element to begin filling in the details for the element.
Name | Description | Type | Max Size | Required | Show |
---|---|---|---|---|---|
Academic Program | Choose an academic program from the list. | Select Box (T206 Academic Programs) | 80 | No | Yes |
- Once you have added all your elements, click Save changes.
Exercise 15.2: Updating the "text/html" content layout
- Go to Assets > Content Types.
- Click your Content Type name to edit it. (Use the Filter tool to search). Open the Content layouts tab.
- The Content Layout tab is an area to add Content Layout(s) for your Content Type. Click into the "text/html" content layout to edit it.
- Click into the </> Content layout code tab and add a Handlebars expression that uses the "valueFromFirstInSequence" Custom Helper that you will create in the next exercise.
{{#firstInSequence}}
<div id="tabs">
<ul>
{{#each (loopContentInSequence element="Tab Title")}}
<li><a href="#tabs-{{id}}">{{value}}</a></li>
{{/each}}
</ul>
{{#each (loopContentInSequence element="Tab Content")}}
<div id="tabs-{{id}}">
<p>Academic Program: {{valueFromFirstInSequence element="Academic Program"}}</p>
{{{value}}}
</div>
{{/each}}
{{/firstInSequence}}
{{#lastInSequence}}
</div>
{{/lastInSequence}}
- Click Save changes to save your Content Type.
Exercise 15.3: Creating the "valueFromFirstInSequence" Custom Helper
- Click on any section within your site structure.
- Modify the URL for your section by changing the section Id in the URL to '8303' and hitting enter. This will take you to the Custom Helpers hidden section in the training instance.
- Click on the Add Content button to create a new Custom Helper.
- Name: Give your Custom Helper a name, "valueFromFirstInSequence". (There should be no spaces in the name field, use camel case as a convention for your Custom Helpers names).
- Function Code: Complete the TODOs below to create your Custom Helper.
TODOs:
1. Get the content id of the current item.
2. Get a listing of the entries (HINT: start with apis.getContent().get(contentId)).
3. Get the list of content items in the current section.
4. Get the index of the current content item.
function (context, options) {
const providedElement = options.hash ('element'); // Expects a list element to be passed in
//1. TODO: get the content id of the current item
const contentId = // Gets the content id of the current item
// Assume the current content item is the first in the sequence
// Capture the value of the list item selected (assumes single selection)
//2. TODO: get the entries (Hint: start with apis.getContent().get(contentId))
let entries =
let result;
for (let i = 0; i < entries.length; i++) {
if(entries[i].isSelected()) {
result = entries[i].getValue();
}
};
// A function to get the index of a given item in a list
const getIndex = (list, id) => {
for (let idx = 0; idx < list.size(); idx++) {
if (list.get (idx).getId() == id)
return idx;
}
return -1;
}
//3. TODO: get the list of content items in the current section
const contentList = apis.getSection().listContent();
//4. TODO: get the index of the current content item
const contentIndex = getIndex(contentList, contentId);
// Loop backwards through the content in the section
for (let prevIndex = contentIndex - 1; prevIndex >= 0; prevIndex--) {
// Get the previous content item
let prev = contentList.get (prevIndex);
// If the content type changes, break out of the loop
if (prev.getContentTypeId() != pageContext.getContent().getContentTypeId ()) {
break;
}
// We haven't broken out of the loop which means the previous content item is of the same type
// Capture the value from the list item selected (assumes one selection)
let entries = apis.getContent().get(prev.getId()).getElement(providedElement).toListElement().getValue().getEntries();
for (let i = 0; i < entries.length; i++) {
if(entries[i].isSelected()) {
result = entries[i].getValue();
break;
}
};
}
// Return true if the first element in the sequence has the list item selected
return result;
};
- Click Save changes to save the changes to your Custom Helper.
- Update your preview to check the result.
16. Content Report
- In the following exercise, you will create a report for the content of a specified section. You will create a Custom Helper called "ContentReportById" and use it to return an array of items containing details about the Content Item.
- This Custom Helper makes use of the "DataTables" JavaScript table library which will have to be available within your page layout.
Exercise 16.1: Setting up the DataTables Library
The Content Report is generated using the "DataTables" Library. In order to use this library, you will need to insert the below code into the header of your page layout.
- Go to Assets > Page Layouts.
- Click your page layout name to edit it. (Use the Filter tool to search). Open the </> Header code tab.
- Copy/paste the code below into the header of your page layout:
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
<script type="text/javascript" src="https://cdn.datatables.net/1.10.12/js/jquery.dataTables.min.js"></script>
<link rel="stylesheet" type="text/css" media="all" href="https://cdn.datatables.net/1.10.12/css/jquery.dataTables.min.css" />
<script type="text/javascript">
$(document).ready(function(){
$('table').DataTable();
});
</script>
- Click Save changes to save the changes to your page layout.
Exercise 16.2: Updating the "text/html" content layout
- Go to Assets > Content Types.
- Click your Content Type name to edit it. (Use the Filter tool to search). Open the Content layouts tab.
- The Content Layout tab is an area to add Content Layout(s) for your Content Type. Click into the "text/html" content layout to edit it.
- Add a Handlebars expression that uses the "contentReportById" Custom Helper that you will create in the next exercise. Make sure you pass a valid Content Id from your site structure.
TODOs:
1. Write a Handlebars expression that uses the contentReportById Custom Helper and passes in a Content Id from your site structure. Replace [####] with a valid Id from your site structure.
{{{contenReportById [####]}}}
- Click Save changes to save your Content Type.
Exercise 16.3: Creating the "contentReportById" Custom Helper
- Click on any section within your site structure.
- Modify the URL for your section by changing the section Id in the URL to '8303' and hitting enter. This will take you to the Custom Helpers hidden section in the training instance.
- Click on the Add Content button to create a new Custom Helper.
- Name: Give your Custom Helper a name, "contentReportById". (There should be no spaces in the name field, use camel case as a convention for your Custom Helpers names).
- Function Code: Complete the TODOs below to create your Custom Helper.
TODOs:
1. Get the expiry date.
2. Get the last modified date.
3. Get the publish date.
4. Get the version.
5. Get the elements.
6. Complete the template literal by inserting the variables needed to generate the content of the data table.
7. Return the contentReport string
function(context, options) {
//1. TODO: get the expiry date
let expiryDate =
//2. TODO: get the last modified date
let lastModified =
//3. TODO: get the publish date
let publishDate =
//4. TODO: get the version
let version =
//5. TODO: get the elements
let elements =
//6. TODO: complete the template literal by inserting the variables needed to generate the content of the data table
let contentReport += `<table class="table-striped"><thead><tr><th>Content</th><th>Value</th></tr></thead><tr><td>Expiry Date</td><td></td></tr><tr><td>Last Modified Date</td><td></td></tr><tr><td>Publish Date</td><td></td></tr><tr><td>Version</td><td></td></tr><tr><td>Elements</td><td></td></tr></table>`;
//7. TODO: return the contentReport string
return
};
- Click Save changes to save the changes to your Custom Helper.
- Update your preview to check the result.
17. Sequence
-
The "sequence" Custom Helper can be used to output the index (starting from 0) of all the content items in a given sequence of content items.
-
In the following example, you will use the "sequence" Custom Helper to add a carousel slider of all the news items. You will create a Custom Helper called "sequence" and use it to iterate through the items.
Exercise 17.1: Updating the "text/html" content layout
- Go to Assets > Content Types.
- Click your Content Type name to edit it. (Use the Filter tool to search). Open the Content layouts tab.
- The Content Layout tab is an area to add Content Layout(s) for your Content Type. Click into the "text/html" content layout to edit it.
- Click into the </> Content layout code tab and add the code below which uses the "sequence" Custom Helper that you will create in the next exercise.
{{#firstInSequence}}
<ol class="carousel-indicators">
{{#each (sequence)}}
<li data-target="#heroBannerCarousel" data-slide-to="{{@index}}"></li>
{{/each}}
</ol>
{{/firstInSequence}}
- Click Save changes to save your Content Type.
Exercise 17.2: Creating the "sequence" Custom Helper
- Click on any section within your site structure.
- Modify the URL for your section by changing the section Id in the URL to '8303' and hitting enter. This will take you to the Custom Helpers hidden section in the training instance.
- Click on the Add Content button to create a new Custom Helper.
- Name: Give your Custom Helper a name, "sequence". (There should be no spaces in the name field, use camel case as a convention for your Custom Helpers names).
- Function Code: Complete the TODOs below to create your Custom Helper.
TODOs:
1. Get the content (HINT: use pageContext).
2. Get the content Id.
3. Get a listing of the content.
4. Get the contentIndex (HINT: Use the getIndex function at the top of the code listing).
function(context, options) {
let getIndex = function (list, id) {
for (let idx = 0; idx < list.size (); idx++) {
if (list.get (idx).getId () == id)
return idx;
}
return -1;
}
//1. TODO: get the content
let content =
//2. TODO: get the contentId
let contentId =
//3. TODO: get a listing of the content
let contentList =
//4. TODO: get the contentIndex
let contentIndex =
let endIndex = contentIndex + 1;
for (; endIndex < contentList.size (); endIndex++) {
let next = contentList.get (endIndex);
if (next.getContentTypeId () != content.getContentTypeId ())
break;
}
return contentList.subList(contentIndex, endIndex);
};
- Click Save changes to save the changes to your Custom Helper.
- Update your preview to check the result.