Lesson Templates

Fathom uses the Liquid template language for theming and templating in the system. Templating is done at the Lesson level, while theming is done at the Zone level.

Required reading: You should understand the Zone Theme first.

  1. Configuration
  2. Importing a Template
  3. Versioning
  4. The Template
  5. Example
  6. Attributes Available to my Template

Importing a Template

In Fathom, Templates belong to their own collection and are usable between all Zones belonging to a Company. A Template is imported similarly to a Theme in that an admin will import a zip archive through the LMS interface. Only the Admin role has this ability.

Global template files live at /:company_id/templates/ with a directory for each Template type. Zone templates live at /:company_id/zones/:zone/templates/. Imagine a folder looking similar to this:

// path - /:company_id/templates
...and on

You must define at least a template.html file. Creating a template.js and template.css file with populate the corresponding has_javascript_file and has_css_file properties on the template object. This is useful for theme includes so they can load these files only if they exist. Consider this example in a theme include:

  {% if template.has_javascript_file %}
    <script type="text/javascript" src="{{ templatePath }}/template.js" />
  {% endif %}


Template files are versioned on each publish, so if you update a template, it will not impact courses until you republish those courses.

The Template

Now that you understand the difference between a Template and a Theme, let’s get into what the Templates look like, and how they are used.

First, what is a Template?

A Template is directly tied to a Lesson within the LMS. A Lesson can be thought of as a single page (whether it is a boring page, or a single page web-app or game is of your concern, not ours). Each Lesson has an attribute named template_id that references a template in the Template collection. When a Zone is published, each Lesson is looked at, compiled via its template_id and content, and renderd into a static HTML file on the server using Liquid.

What’s the Template Look Like?

Here is an example of a very simple template.

<% include 'head.html' %>
  <div class="someClassName">
    <h1 data-name="Title" data-type="string">{{ lesson.title }}</h1>
    <p data-name="Body" data-type="text">{{ lesson.body }}</p>
  <img src="{{ themePath }}/img/path/to/a/static/asset.png" width="400" height="200">
<% include 'foot.html' %>

You can see that it first includes the theme’s head. Which theme? The Zone’s theme. This means this Template is completely unaware of the Zone it’s in. This makes it reusable. Next, it provides some markup and tokens to display the Lesson content. And lastly, it includes the theme’s foot.

If the Template does not include the head and foot, it is going to look pretty terrible and not work. Don’t do this.

But what is that data-name thing? That’s how you, as a developer tell the LMS what is and isn’t editible for an Author. WHOOOOAAAAAA, you say. Yeah. This is what gives you control of your markup, and the author the control and comfort of how their content looks within the template! No more separation of content and design. The Author is literally editing this HTML, and how it is styled how you want it to be within the browser.

Behind the scenes, the LMS is scanning your template for the data-editable attribute and tokenizing those fields based on the data-name attribute.

Template CSS

You can put anything you want in your template.css file, or you can add other css files to the template directory. If you want to reference a template image in the css, use relative paths. Here’s an example template zip:


Now the template.css file can reference picture.png with a relative path:

.picture-box {
  background: url('img/picture.png') no-repeat 50% 50%;

What Can I Use in My Templates?

You will have access to any tokens you have supplied with the data-name attribute, as well as these lesson object attributes:

  • title
  • lesson_id
  • zone
    • id
    • title
  • module
    • id
    • title
    • required
  • name
  • estimated_time
  • language (the language currently being published, useful for css classes or other localization customizations)

You will also have access to the following properties:

  • themePath (a url to the root of your theme)
  • templatePath (a url to the root of your template directory)
  • template
    • has_css_file
    • has_javascript_file
    • title
    • is_game
    • template_name (machine name)

The data attributes you can use for the editable fields are:

  • string
  • text
  • number
  • image
  • video
  • file
  • boolean

Editing Templates

Once you have created a template through the LMS administration interface, you will be able to see those template files on Amazon S3. We have supplied your company specific S3 tokens in the Access Information view under the Administration section. We want to make it as easy as possible for front-end developers to edit templates on the fly.

Template Customization

There are two ways to handle defining fields that are not WYSIWYG-compatible:

  1. Create a custom form definition
  2. Create a form settings definition

Creating a custom form means you lose all WYSIWYG capabilities with the template, but for javascript heavy templates this is probably the solution you want.

Adding a form_settings definition allows you to specify any number of fields that are edited through form generation, while the rest of the template is still editable through WYSIWYG.

Custom Form

If you are looking to create an advanced, editable template, you can supply a settings.json file in the template directory you upload. The settings allow you to override the automatic data-name parsing in favor of letting you define your own form. This works well for cases where you want to nest objects and arrays, as is frequently the case in a game.

You have access to the same form elements provided through the data-type attribute described above. In addition, nested fields are supported, as well as arrays. Here’s an example form in a settings.json file:

  "form": {
    "name": "string", // This can be any data type
    // Nested fields
    "content": {
      "title": "string", // Accessible in the template as lesson.content.title
      "body": "text"
    // Arrays
    "items": {
      "_type": "array",
      "_object": {
        "name": "string",
        "image": "image"
      "_length" // Optional property, sets required length
    // Custom labels
    "image": {
      _label: "Image (800x600)",
      _type: "image"

When accessing different form elements via JavaScript in your template, it is important to be cognizant of the type of content that is being input. For example, if text with quotes is being input into an HTML element, it is important that those characters be escaped in order for the JavaScript to execute properly. There are many filters available for dealing with these kinds of content output issues and you can read about some of those here. An example of using an escape filter in a template is shown below.

    window.CONTENT = {
      gameMode: '{{ lesson.gameMode | escape }}',
      steps: [
        {% for step in lesson.steps %}
          className: '{{step.className | escape }}',
          order: '{{step.order | escape }}',
          text: '{{step.text | escape }}'
        }{% if forloop.index < forloop.length %},{% endif %}
        {% endfor %}


When a _type: "array" is specified, you must also supply an _object property that defines the objects in the array. The form generator will supply an “Add Item” button which will populate a new, blank object in the array. The _length property is optional and will show the given number of blank items in the form. The property defines both the minimum and maximum length (you cannot have any more or any fewer items).

Form Settings

In the settings.json file described above, you can specify a form_settings property to render a few fields in the form, while the rest of the template fields use WYSIWYG.

  "form_settings": {
    "background-image": "image"

Translation Support

Translation support is available via a custom filter with Liquid Templating. Some additional setup is required to ensure that translations work as expected in your templates. There are two requirements for implementing translation of static strings in your templates. First, a list of translatable strings must be specified in your settings.json file and second, an additional script tag in which you declare a variable referencing the appropriate strings is required. The following sample code shows how to setup template to translate the static text “Loading Video….”

As discussed above, we first need to have a reference to the text being translated in the settings.json file. This is accomplished by adding a translate property to the settings.json. The translate property is an array of strings to be translated. For this particular example the array only has one string.

  "translate": [
    "Loading Video...."

Next step is to define a variable in our template that contains a reference to the strings of interest. This is done by adding a script tag at the top of the template.html file.

  var translatableStrings = {
    loading: 'Loading Video...'

the ‘t’ in the sample code above is the translation filter used in the Liquid Engine.

With these two additions in place, the appropriately translated string can now be accessed anywhere in the template by referencing the translatableStrings.loading value.