Developing Content Layouts for Content and Experience Cloud
By: Sivakumar Balagopalan
Tags: JavaScript

Prerequisite

Please refer to the previous post Developing for Content and Experience Cloud (CEC) using Sites Toolkit for an introduction to Sites Toolkit and installation. This post assumes that the Project Creation and Installation step is completed.

Content Layouts

Content layouts help users view the data in content items through content list or content placeholder components used in sites pages. You can create multiple content layouts for a content type to create different views or to represent different parts of a content item. In this post, we will explore how to use Sites Toolkit to develop content layouts.

Creating a content layout

To create a content layout, a content type is required. The template named BlogTemplate has the ‘Starter-Blog-Post’ content type. Let us create a template called ‘Starter-Blog-Template’ from the BlogTemplate.

cec create-template Starter-Blog-Template -f BlogTemplate

Now create a content layout for the ‘Starter-Blog-Post’ content type.

cec create-contentlayout My-Blog-Layout -c Starter-Blog-Post -t Starter-Blog-Template

Options:

— contenttype, -c <contenttype> Content layout is based on [required]

— template, -t <template> The mapping is for [required]

— layoutstyle, -s <style> Content layout style

My-Blog-Layout will be created under src/main/components/My-Blog-Layout. Also, add the content layout mapping to the Starter-Blog-Template.

cec add-contentlayout-mapping My-Blog-Layout -c Starter-Blog-Post -t Starter-Blog-Template -s Summary

Making simple changes to a content layout

You can edit the following files in the generated content layout to modify the content layout.

assets/layout.html

assets/design.css

assets/render.js

To make simple UI changes, you need to change only assets/layout.html and assets/design.css.

Making advanced changes to a content layout

To add more dynamic behavior to the content layout, you can edit assets/render.js. This section explores the code in src/main/components/My-Blog-Layout/assets/render.js.

RequireJS module definition

The RequireJS module is defined in the render.js file. Sites loads the dependencies, such as for JQuery, Mustache, the RequireJS Text Plugin, and the RequireJS CSS plugin. The mustache template system is used to render the layout. But you can use any library.

define([ 'jquery',

'mustache',

'text!./layout.html',

'css!./design.css'

], function ($, Mustache, templateHtml, css) {

// Content layout code goes here

}

The assets/render.js file for a content layout has the following properties:

It should be a RequireJS module

It should return a JavaScript Constructor function. Sites invokes the Constructor function by passing a parameter object. The parameter object has the content item data and the APIs required to render the layout.

This Constructor function should have a render(parentObj) method that handles rendering the content layout. This function should append the content layout DOM object to the parentObj object that is passed to the render()method.

The RequireJS module can use the dependencies, including JQuery, Mustache, the RequireJS Text Plugin, and the RequireJS CSS plugin. These dependencies will be loaded by Sites. You can use other libraries too.

Constructor function parameter

When Sites creates a new instance of the constructor function, it passes a parameter that contains contentItemData, scsData, and contentClient to help with Content Layout development.

Here is example code for the constructor function, render() method and returning:

// Constructor function function ContentLayout(params) {

this.contentItemData = params.contentItemData || {};

this.scsData = params.scsData;

this.contentClient = params.contentClient;

} // Prototype ContentLayout.prototype = { contentVersion: ">=1.0.0 <2.0.0", render: function (parentObj) {

var template,

content = $.extend({}, this.contentItemData),

scsData = this.scsData,

contentClient = this.contentClient,

contentType,

secureContent = false; // Merge the properties from params.scsData into

// content, so the template can make use of them too. if (this.scsData) {

content = $.extend(content, {

"scsData": this.scsData

});

//.... }

//....

} return ContentLayout;

The constructor function parameter includes the following objects:

params.contentItemData : Contains the content item, including its name, description, ID, and data. For example, the field blogpost_ title in the content item can be accessed using params.contentItemData.data[‘blogpost_ title’].

params.scsData : This object passes in information when the constructor is called from within sites. This object doesn’t exist for content layouts rendered in third-party applications. This object contains the SitesSDK, the method contentTriggerFunction to raise a trigger, and the Details page links.

params.contentClient : This is the contentClient object created from the Content Delivery SDK. It is therefore configured with the appropriate parameters for the content server. If you need to make additional calls to the content server, you can use this contentClient object rather than creating your own. This object contains client APIs for the content. APIs are available to query, search, and get content items and their content types. Other helper APIs are also available; for example, expandMacros() to expand the macros used in rich text.

Rendering a content layout

The render(params) method of ContentLayout renders a content layout from a template. The Mustache template is used by default for content layouts, but you can use any template technology you want.

The render(params) method of ContentLayout can use the following code to render the template with the data:

try {

// Mustache

template = Mustache.render(templateHtml, content);

if (template) {

$(parentObj).append(template);

} // Dynamic DOM Manipulation can be done here } catch (e) {

console.error(e.stack);

}

You can add the required data to the content object created from params.contentItemData .The rendered template should be appended to the parent object passed to the render() method.

Getting reference items

You can get a reference item for a content type with a reference data field that refers to another content type.

For example, the starter-blog-post_author field in the Blog-Post content type is a reference to the Author content type. The this.getRefItems() method can be used to query the referenced items.

if (data["starter-blog-post_author"]) { referedIds[referedIds.length] =

data["starter-blog-post_author"].id; } //..

this.getRefItems(referedIds).then(function (results) { var items = results && results.items || []; // use the reference items

Getting a media URL

You can use contentClient.getRenditionURL() to get the default rendition of a digital asset, such as an image.

blogImageRenditionURL: contentClient.getRenditionURL({ 'id': data['starter-blog-post_header_image'].id })

If you need other renditions, such as thumbnail , you can get the digital asset using contentClient.getItems() and refer to item.data.renditions.default and item.data.renditions.thumbnail .

Raising triggers

You can use scsData.contentTriggerFunction(payload) to raise a trigger from a content layout.

Getting rich text fields

If the content type has rich text fields and if the content layout will be used in a content list, query the item again to retrieve rich text fields. Additionally, if there are embedded images in rich text, use expandMacros().

// query the item again to get the rich text fields contentClient.getItem({ "id": content.id }).then(function (itemdata) { content = itemdata; //.. data["starter-blog-post_content"] =

contentClient.expandMacros(data["starter-blog-post_content"]);

Linking to the Details page

The Details page link of the current content item is available through scsData.detailPageLink .

Generating a URL for the other content items Details page

Some times current content item refers to other related content items and you want to get the Details page URL for those items. The following function can be used.

function getDetailsRelatedPageLink(scsData, reatedContentItemData) {

// Get the parts of the current detail link

var uriParts = scsData.detailPageLink.split('/');

var length = uriParts.length; // Fill the details of the related content item

uriParts[length - 1] = reatedContentItemData.name;

uriParts[length - 2] = reatedContentItemData.id;

uriParts[length - 3] = reatedContentItemData.type; // Got the url

return uriParts.join('/');

}

Generating URLs to local assets in a CEC content layout

Sometimes you may want to use a static asset that is locally available in the content layout itself such as a background image for styling purposes. For example, in the content layout that follows, the absolute URL to the images/background.jpg can be generated in render.js and used in layout.html.

The simplest way to generate an absolute URL is to use the built-in RequireJS module. Define ‘require’ as the dependency and use require.toURL() to generate the URL, as follows.

define([

'require',

'jquery',

'mustache',

'text!./layout.html',

'css!./design.css'

], function (require, $, Mustache, templateHtml, css) {

'use strict’; var imageURL = req.toUrl('./images/building.jpg');

Testing a content layout

As you modify the code in your editor, you can test the content layout in the local test harness. Since the content items are available locally in the Starter-Blog-Template, choose local and choose the Theme Design to preview. You could also test the content layout in the Starter-Blog-Template.

Testing a content layout in local test harness

Reviewers

Thanks to Bonnie Vaughan, Igor Polyakov, Kamal Kapoor, and Steve Burns for reviewing this article.

Reference:

Developing for Oracle Content and Experience Cloud