Creating Simple Component Using HTML Templates

In my previous post Building a Simple H1 Component with Settings Panel you learned how to develop simple H1 Component for Oracle Sites Cloud Service (SCS). In this post I will show you how to create SCS Component that HTML and CS together with tempting language to render view. In this example I will use Mustache JS templates. The Component also provides a Settings panel to enable edit content in the HTML that you wish to make editable in the Site Builder by other users.

Step 1: Create the HTML Component

You will start by creating new Local Component in SCS Components catalog which is a starting point fro creating any new component. Repeat the steps described in my previous post, but this time call your new component “HTML Component”.

To build HTML Component:

1.   Add mustache.min.js file to the ‘assets‘ folder in the HTML Component. You can download this file from Mustache JS home page on GitHub.

2.   Create a new file in the ‘assets‘ folder called render.html that contains HTML for the body of your component. For this example, create render.html file with the following contents:

<ul class="wrapper">
	<li class="box">
<h1 class="title">One</h1>
<p class="text"> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</li>
	<li class="box">
<h1 class="title">Two</h1>
<p class="text"> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</li>
	<li class="box">
<h1 class="title">Three</h1>
<p class="text">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua./p></li>
	<li class="box">
<h1 class="title">Four</h1>
<p class="text">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</li>
</ul>

3.   Create a new file in the ‘assets‘ folder called design.css – this is CSS of your component.  For this example, add the following as the contents of design.css file:

.wrapper {
   text-align: center;
}
.box {
   display: inline-block;
   position: relative;
   width: 200px;
   height: 200px;
   padding:0px 10px 10px 10px;
   background: transparent;
   border-width:1px;
   border-style:solid;
   border-radius: 5px;
   border-color:#CCCCCC;
   z-index: 0;
   margin: 2px 2px 2px 2px;
   transition: all .15s ease-in-out;
}
.box:hover {
   background: #9CC;
   z-index: 100;
   transform: scale(1.2,1.2);
   box-shadow: 0 5px 10px 0 rgba(0,0,0,.2);
}
.title {
   color:red;
}
.text {
   color:#555555;
}

4.   Open up the render.js file under the “assets” directory and change the content to the following.  No matter what your HTML and CSS you used above, this render.js will render your HTML and CSS into the page for you:

/* globals define */
define(['jquery', './mustache.min', 'text!./render.html', 'css!./design.css'], function($, Mustache, template, css) {
'use strict';

// ----------------------------------------------
// Create a Mustache based component implemention
// ----------------------------------------------
var SampleComponentImpl = function(args) {
this.SitesSDK = args.SitesSDK;

// Initialze the custom component
this.createTemplate(args);
this.setupCallbacks();
};
// create the template based on the initial values
SampleComponentImpl.prototype.createTemplate = function(args) {
// create a unique ID for the div to add, this will be passed to the callback
this.contentId = args.id + '_content_' + args.viewMode;
// create a hidden custom component template that can be added to the DOM
this.template = '
<div id="' + this.contentId + '">' +
template +
'</div>
';
};
SampleComponentImpl.prototype.updateSettings = function(settings) {
if (settings.property === 'customSettingsData') {
this.update(settings.value);
}
};
SampleComponentImpl.prototype.update = function(data) {
this.data = data;
this.container.html(Mustache.to_html(this.template, this.data));
};
//
// SDK Callbacks
// setup the callbacks expected by the SDK API
//
SampleComponentImpl.prototype.setupCallbacks = function() {
//
// callback - render: add the component into the page
//
this.render = $.proxy(function(container) {
this.container = $(container);
this.SitesSDK.getProperty('customSettingsData', $.proxy(this.update, this));
}, this);
//
// callback - SETTINGS_UPDATED: retrive new custom data and re-render the component
//
this.SitesSDK.subscribe(this.SitesSDK.MESSAGE_TYPES.SETTINGS_UPDATED, $.proxy(this.updateSettings, this));
//
// callback - dispose: cleanup after component when it is removed from the page
//
this.dispose = $.proxy(function() {
// nothing required
}, this);
};
// ----------------------------------------------
// Create the factory object for your component
// ----------------------------------------------
var sampleComponentFactory = {
createComponent: function(args, callback) {
// return a new instance of the component
return callback(new SampleComponentImpl(args));
}
};
return sampleComponentFactory;
});

Checkpoint 1

1.   The ‘assets’ folder in your component will have 5 files

picture-1.jpg

2.   Add the new HTML Component to a page in your test site. In the Site Builder, you should see:

In Edit mode:

picture-2.jpg

     In Preview mode:

picture-3.jpg

Step 2: Adding User Supplied Data to the HTML

In this step you will add a Settings panel that provides fields for all data elements you define in your HTML.  An SCS user can then fill in the values for the component instance on the page in the Settings panel.

1.   Update HTML template in your render.html file to include any data elements you want.  In this example I am using Mustache JS tempting language, so they must be added using {{ and }} syntax, as follows:

<ul class="wrapper">
	<li class="box">
<h1 class="title">{{title1}}</h1>
<p class="text">{{text1}}</p>
</li>
	<li class="box">
<h1 class="title">{{title2}}</h1>
<p class="text">{{text2}}</p>
</li>
	<li class="box">
<h1 class="title">{{title3}}</h1>
<p class="text">{{text3}}</p>
</li>
	<li class="box">
<h1 class="title">{{title4}}</h1>
<p class="text">{{text4}}</p>
</li>
</ul>

2.   Provide default values for these data fields – change the content of the appinfo.json file in your HTML Component to the following:

{
"id": "html-component-id",

"settingsData": {
"settingsHeight":600,
"settingsWidth": 300,
"settingsRenderOption": "dialog",
"componentLayouts": [],
"triggers": [],
"actions": []
},
"initialData": {
"styleClassName": "html-component",
"customSettingsData": {
"title1":"One",
"title2":"Two",
"title3":"Three",
"title4":"Four",
"text1":"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
"text2":"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
"text3":"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
"text4":"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
},
"nestedComponents": []
}
}

3.   Add a Settings panel that will look for the data values as found in your HTML template render.html file to create the settings for an SCS user to change in the Site Builder. Change the contents of settings.html file to the following:

<!DOCTYPE html>
<html lang="en">

<head>
<!-- only allow embedding of this iFrame in SCS -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Hello There Settings</title>
	<link href="/_sitescloud/renderer/app/sdk/css/app-styles.css" rel="stylesheet">
<!--include knockout script-->
<script type="text/javascript" src="/_sitescloud/renderer/app/apps/js/knockout.min.js"></script>
 <!--include jquery script -->
 <script type="text/javascript" src="/_sitescloud/renderer/app/apps/js/jquery.min.js"></script>
<!-- include sdk -->
<script type="text/javascript" src="/_sitescloud/renderer/app/sdk/js/sites.min.js"></script>
 <!-- Mustache.js -->
 <script type="text/javascript" src="mustache.min.js"></script>
</head>

<body style="margin:0px; padding:0px;">
<div class="settings-box" tabindex="-1">
<div class="box-content">
<div class="form-group" data-bind="foreach: entriesArray">
<label for="message-text" class="settings-heading" data-bind="text: name"></label>
<input class="settings-text-box" id="namefield" data-bind="value: value" />
</div>
</div>
</div>
<script>

 // Load the HTML Template
 var $template = $('
<div>');
 $template.load('./render.html', $.proxy(function() {
 var templateEntries = [],
 parsedTemplate = Mustache.parse(this.text());

 for (var p = 0; p < parsedTemplate.length; p++) {
 var type = {},
 name = {};

 type = parsedTemplate[p][0];
 name = parsedTemplate[p][1];
 if (type === "&" || type == "name")
 {
 var entry = {};
 entry["name"] = name;
 entry["value"] = 'b';
 templateEntries.push(entry);
 }
 }

 // create the view model for the KO form
 viewModel = function() {
 var self = this;
 //self.entriesArray = ko.observableArray(templateEntries);
 self.entriesArray = ko.observableArray([]);
 self.templateEntries = templateEntries;

 self.updateEntries = function(updatedEntries) {
 var settingsDataToSend = {};

 for (var i = 0; i < updatedEntries.length; i++) {
 settingsDataToSend[updatedEntries[i].name] = updatedEntries[i].value();
 }
 SitesSDK.setProperty('customSettingsData', settingsDataToSend);
 }
 self.entriesArray.subscribe(self.updateEntries);
 self.forceUpdate = function(newValue) {
 self.entriesArray.valueHasMutated();
 };

 // fetch latest copy of custom settings data from host site
 self.loadSettingsData = function() {
 SitesSDK.getProperty('customSettingsData', function(data) {
 var existingEntries = self.entriesArray(),
 newEntries = [],
 value = undefined,
 valueObs,
 valueObj = {};

 // create entries for all template entries and add data entries if available
 for (var i = 0; i < templateEntries.length; i++) {
 value = templateEntries[i].value;

 // find any existing value from settings data
 for (var key in data) {
 if (data.hasOwnProperty(key)) {
 if (templateEntries[i].name == key) {
 value = data[key];
 }
 }
 }

 // create observable entry
 valueObs = ko.observable(value);
 valueObs.subscribe(self.forceUpdate);
 valueObj = {};
 valueObj["name"] = templateEntries[i].name;
 valueObj["value"] = valueObs;

 newEntries.push(valueObj);
 }

 self.entriesArray(newEntries);
 });

 };

 // execution block
 self.loadSettingsData();
 };

 // bind the view model
 ko.applyBindings(new viewModel());
 }, $template));
 </script>
</body>

</html>

NOTE: since you have changed the appinfo.json file, you must refresh the browser, add your component again to a page to pick up the changes.

Checkpoint 2

Your component will now pick up its default data from the appinfo.json file, you can then change the values in the Settings panel for the data that you chose.  Don’t forget you needed to refresh the browser and add your component again to the page since the appinfo.json file was changed.

picture-4.jpg

This is it! Now you have an SCS Component that uses HTML and CSS with Mustache JS templates to render its content based on the data that you enter on the Settings panel.

1 Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s