In this blog post you will learn how to create a simple Oracle Sites Cloud Service component that uses a DIV tag with the “contenteditable” attribute enabled to allow end users to enter their own text in the page that will be saved with the component. I will explain how to convert the pre-defined files you get when you create new component in SCS into your own implementation. The intent is to describe what is required and what is optional within those seeded files. When you create a component you get a set of seeded files that will work out of the box. The seed code covers most of the functionality of a component within the product and the “Tutorial: Developing Components with Knockout JS” section in the SCS documentation explains how all the pieces of the components fit together.
In this tutorial, we cover how to change the seeded code to create your own component. It also covers other aspects not covered in the standard tutorial such as:
- How to provide different templating based on the viewMode of the component
- Saving data from the component instead of from the settings panel
- Integration with the page’s undo/redo events
Note: This sample is simply aimed at explaining the various pieces that make up a generic SCS Custom Component. It should not be used “as is” as a production component.
Step 1: Create New Component
After this step you will have created your component with the Sites Cloud Service that you can immediately drop onto the page. This is the starting point for creating any new component.
To create a local component:
- Navigate to Sites -> Components
- Select option Create -> Create Local Component
- Enter a name, for example “BasicTextEditor” and optionally, description
- Click “Create” to create new component
Checkpoint 1
Now that you have successfully created a component, you should see this component in the Component catalog as well as in the Add > Custom component palette for any site you create. Use the following steps to validate your component creation:
- Create a new site using any seeded Template, for example create a site called “ComponentTest” using the “StarterTemplate” template.
- Select Edit option and create an update for the site to open it in the Site Builder.
- Edit a page within the site that you created.
- Click on the Add (“+”) button on the left bar and select “Custom” for the list of custom components.
- Select the “BasicTextEditor” from the custom component Palette and drop it onto the page. You should now see a default rendering for the local component you created
- Select the context menu in the banner for the component you dropped
- Select “Settings” from the drop-down menu. You can change setting to see how seeded component rendering will change.
The following steps cover how you can modify seeded files to create a new custom component and how to modify it for your own purposes.
Step2: Create the Basic Text Component
In this step you will remove most of the content in seeded files to create a simple text component. It will simply display the text that you seed when you create the viewModel. In subsequent steps you will learn how to make that text editable by the end users.
To review the structure of your local component:
- Using the Document Cloud Service Desktop Sync Client, locate your component and sync it with the file system (select the Start Sync option)
- If you don’t have the Desktop Sync Client, you can also select the component in the Components tab of the Sites Cloud Service and drill down to see the files
- If you list the files under the component, you will see:
- “assets” folder with the component files:
- render.js
- settings.html
- appinfo.json – JSON file with component description , and
- _folder_icon.jpg – icon that is displayed in the Components catalog
- “assets” folder with the component files:
For details about appinfo.json file content see “About Developing Component” section in SCS documentation.
To cerate a simple text component:
1. Open up the render.js file under “assets” directory in you favorite text editor
2. Change the sampleComponentTemplate object to:
// ---------------------------------------------- // Define a Knockout Template for your component // ---------------------------------------------- var sampleComponentTemplate = '<!-- ko if: initialized -->' + ' <div class="my-custom-component"> ' + ' <div data-bind="html: text"></div> ' + '</div> ' + '<!-- /ko -->';
3. Change the SampleComponentViewModel object to:
// ---------------------------------------------- // Define a Knockout ViewModel for your template // ---------------------------------------------- var SampleComponentViewModel = function (args) { var self = this, SitesSDK = args.SitesSDK; // store standard args self.mode = args.viewMode; self.id = args.id; // create observables to persiste the data self.text = ko.observable('Welcome to Components World!'); // handle initialization self.customDataInitialized = ko.observable(false); self.initialized = ko.computed(function () { var initialized = self.customDataInitialized(); return initialized; }, self); // handle property changes self.updateCustomSettingsData = function(customSettingsData) { if (customSettingsData && customSettingsData.text) { self.text(customSettingsData.text); } self.customDataInitialized(true); }; // initialize the viewModel // // get the Custom Settings Data, we need both before first render SitesSDK.getProperty('customSettingsData', self.updateCustomSettingsData); };
This update changes the component to the core necessary pieces:
- ViewModel:
- Storage of the passed in Sites SDK & instance values for the component: SitesSDK, id and self.mode
- A single knockout observable to display the text: text
- Generic code to retrieve the customSettingsData via the SDK and note component has been initialized once that has happened
- Template:
- A minimal template displaying the text once the component initialization has completed
Checkpoint 2
- Sync your changes
- In the Site Builder refresh the page, for example by switching between Preview and Edit modes. At this point you should see “Welcome to Components World!” text displayed in the component:
Step 3: Separate Knockout Template to HTML File
So far your component was using Knockout template that is defined inline in the render.js file. In this step you will learn how to use Knockout template that is defined in a separate HTML file which makes it easier for you to change component view.
1. In the “assets” directory, create new HTML file template.html file
2. Move HTML defined in the sampleComponentTemlate object to this file:
<!-- ko if: initialized --> <div class="my-custom-component"> <div data-bind="html: text"></div> </div> <!-- /ko -->
3. Delete explicit definition of the sampleComponentTemlate object and change RequireJS module definition in the render.js to:
/* globals define */ define(['knockout', 'jquery', 'text!./template.html'], function (ko, $, sampleComponentTemplate) { 'use strict';
The above define(…) call initializes sampleComponentTemplate object with the content of the template.html file.
Checkpoint 3
- Sync your changes
- In the Site Builder refresh the page, for example by switching between Preview and Edit modes. At this point you should see the same “Welcome to Components World!” text displayed in the component.
Step 4: Enable in-place Text Edit
The purpose of this component is to allow the end user to edit the text directly in the page. To do this we will leverage the “contenteditable” attribute against a DIV tag. After this step, the user will be able to click on the text and modify it
To make the component editable, make the following changes:
1. In template.html, change DIV element as follows:
<!-- ko if: initialized --> <div class="my-custom-component"> <div contenteditable="true" data-bind="html: editText" style="-webkit-user-select: text; user-select: text;"></div> </div> <!-- /ko -->
The “user-select” property in CSS controls how the text in an element is allowed to be selected. For cross-browser compatibility you may need to use (for details see):
-webkit-user-select: text; -khtml-user-select: text; -moz-user-select: text; -o-user-select: text; user-select: text;
2. Then in render.js, change the SampleComponentViewModel object:
Replace:
// create observables to persiste the data self.text = ko.observable('Welcome to Components World!');
With:
// create observables to persiste the data self.text = ko.observable('Welcome to Components World!'); // set the default value for text self.editText = ko.observable('Edit me');
The reason we want to have an “editText” observable as well is that we want to have some indication to the end user that they can edit the value of the text but we don’t want to store that value. We’ll look at storage in a later step and how to pass the values between these observables.
Checkpoint 4
- Sync your changes.
- Take your page into Edit mode
- Click on the “Edit me” text
- Make Changes yo the text and click out
After this, you should see the text updated while you are in Edit mode. Also note the following:
- If you switch to Preview mode, your changes are lost and text reverts to “Edit me”
- While in Preview mode, you can again click on the “Edit me” text and change it.
In Part 2 of this blog post you will learn how to handle the Site Builder Edit / Preview modes and persists changes to the text.
2 Comments