Scripting

Cloud CMS provides a server-side Scripting API that allows you to write custom actions, rules and behaviors that execute on the server. These scripts can be introduced at any time and do not require any server downtime. Developers can write scripts and hook them into Cloud CMS at any time to adjust how the product behaves and operates.

The Scripting API consists of a set of server-side Scripting Objects that wrap your content and expose a select set of API service methods for your use. These Scripting Objects are accessible from a few different code formats, including:

  • Server-side JavaScript
  • Handlebars Templates
  • FreeMarker Templates

Using Server-side JavaScript, you can write scripts (method implementations) that hook into the following points:

  • Custom Actions
  • Rule-triggered Script Actions
  • Workflow-triggered Script Actions
  • Node Policy / Behavior Implementations

Using Content Templates, you can write template files that reference scriptable objects from a pre-provided model. The templates execute within a few different places in Cloud CMS, including:

  • Custom Email Templates
  • Custom PDF-generation Templates
  • Custom Report-generation Templates
  • Workflow Email Templates
  • Preview URL Templates

Scripting API

Fundamentally, the Scripting API exposes a set of objects that provide properties and methods that let you access your content information as well as execute services against it. Properties are typically reserve for retrieving scalar or known values where as methods are used to execute functions that do some quanitity of work.

The Scripting API is available here:

Engines

As noted, the Scripting API is available from within a few different engines. These are:

  • JavaScript
  • Handlebars
  • FreeMarker

Server-Side JavaScript Engine

Given a script, the JS engine will quickly compile and execute your script within a safe and monitored sandbox. Your script will be provided data according to how it is intended to be invoked. In general, you will implement a function and your function will have the responsibility of receiving method arguments and producing a return or result.

Here is an example of a custom script that implements the "before update node" Node Policy (p:beforeUpdateNode). As you might suspect, this policy triggers right before a node is updated by anyone. By registering the script shown here as a handler for that policy, it will execute right before anyone updates a piece of content.

function beforeUpdateNode(node, original) {

    // walk over each link in the node's "links" array
    for (var i = 0; i < node.properties.links.length; i++)
    {
        var link = node.properties.links[i];
        
        logger.info("Updating link: " + link.url + " with altText: " + link.altText);
    }    
}

With this script, we implement the beforeUpdateNode method with the correct method signature. There are two expected arguments - the node argument containing the updated values to be written and the original argument containing the value of the node prior to modification.

For more information on the p:beforeUpdateNode policy, see p:beforeUpdateNode Policy.

Server-Side Template Engines

Server-side templates are executed at various points within the product. In every case, the idea is that a model is constructed ahead of time which consists of a set of key/value pairs. This model may contain interesting information such as the current node (node), the current user (user) and the current project (project). Each of these variables is a Scripting API object that you can work with from within the template.

The precise key/value pair combination available to you will vary depending on what you're using the template for. But the idea is essentially the same. You can work with whatever you are given to produce a textual output that is used to populate emails, generate PDFs, render reports and more.

Handlebars Engine

Cloud CMS packages up an implementation of Handlebars along with a fairly vast set of helpers that you can use to build interesting templates. These templates work with the Scripting API objects to produce meaningful and interesting content.

Here is an example of an Email Template that is used to generate the body of an email.

<p>
    {{node.properties.body}}
</p>
<ul>
    {{#each node.properties.links}}
    <li>
        <a title="{{altText}}" href="{{url}}">
            {{title}}
        </a>
    </li>
    {{/each}}
</ul>

In this case, the Email Template has access to a root-scoped Scripting variable named node. This node variable is in fact a Script Node. As such, you can use the .properties accessor to reach into that associate map of node properties, just like you would from JavaScript itself.

FreeMarker Engine

Cloud CMS also supports FreeMarker. If you were using the FreeMarker engine, you could write the same template like this:

<p>
    ${node.properties.body}
</p>
<ul>
    <#list node.properties.links as link>
    <li>
        <a title="${link.altText}" href="${link.url}">
            ${link.title}
        </a>
    </li>
</#list>
</ul>

Script and Template Execution

Any server-side scripts or templates that you code will execute synchronously. That is to say, the function signatures take in arguments and the result of that execution is returned from the function. Script functions do not support Promises or asynchronous callbacks.

The server-side scripting execution occurs within a sandbox that prevents cross-tenant and cross-thread inspection of any runtime context. Functions are given their arguments and a minimal set of global root-scope variables. There are no additional third-party libraries included and developers will, by and large, need to stick to core ECMAScript.

Root Scoped Variables

The following root-scoped variables are automatically provided:

  • logger - a Logger instance that can be used to send log messages.
  • actions - an Actions instance that can be used to fire off Actions.

Debugging Scripts

To debug scripts, we recommend the following:

  1. Build your scripts in a test project with test data.
  2. Trigger your scripts and then monitor your project logs.
  3. When scripts fail due to compilation issues or runtime problems, those errors will be logged. The log entries will include the problematic JavaScript source as well as the line number and column of any offending statements.
  4. Modify your scripts to account for any issues and then try again.

We further recommend using the logger root-scoped variable to log out messages to your tenant as needed. You can then watch the tenant logs to get a sense of how your scripts are executing.

It is not possible to attach a debugger to server-side scripting at this time.