Skip Headers
Oracle® Universal Content Management
10g Release 4 (10.1.4)
Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
 
Next
Next

Implementing a Custom Element

In order for a custom element to function properly in a Contributor form, a custom element must use an API and implement a hand-full of callbacks. The following notes highlight the ElementAPI and its methods regarding creating custom elements.


Note:

The path (URL) to a custom element must be in the same domain as the Contributor form. This is so that the Contributor form and the custom element can communicate without violating cross-domain scripting rules.

ElementAPI

The ElementAPI object is a JavaScript object explicitly loaded into the custom element page that facilitates communication between the Contributor form and the custom element. The ElementAPI provides methods for custom elements to communicate to the Contributor from, and a callback mechanism for the Contributor form to pass notifications to the custom element.

Loading the ElementAPI JavaScript Object

Before the ElementAPI and its supporting libraries can be used, the ElementAPI must first be loaded into the custom element page. After the ElementAPI is loaded, the custom element should continue with page initialization and notify the Contributor form that the custom element is loaded and ready to go.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"         "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml">  <head>  <title>Simple Custom Element</title>  <style type="text/css">  * { padding: 0; margin: 0; }  body { font-size: 10pt; font-family: Tahoma; }  #container { height: 150px; overflow: auto; width: 100%; text-align: center; align: center;}  #content { width: 99%; }  </style>  <script type="text/javascript">  var Custom = {};  Custom.originalData = null;  Custom.Initialize = function()  {    // Set callback methods for the Contributor Form to send notifications to this Element.    ElementAPI.SetCallback('GetElementContent', function(callback)    {      callback(Custom.GetData());    });    ElementAPI.SetCallback('ActivateElement', function(callback){ $ID('content').focus(); callback(); });    ElementAPI.SetCallback('CanCloseElement', function(callback){ callback({canClose: true}); });    ElementAPI.SetCallback('Show', function(callback){ callback(); });    ElementAPI.SetCallback('Hide', function(callback){ callback(); });    ElementAPI.SetCallback('IsDirty', function()   {      return { isDirty: (Custom.originalData !== Custom.GetData()) };    });    // Set the height of the Custom Element form's host.    var height = ( ElementAPI.GetElementCount() == 1 ) ? '100%' : '150px';    var flags = ElementAPI.GetElementConfigProperty('flags') || {};    var config = ElementAPI.GetElementConfiguration() || {};    if( flags.canSetHeight && config.height && ( config.height.length > 0 ) )    {      height = config.height;    }     height = ElementAPI.SetHostHeight(height);  // Get the default content stored within the data file.    $ID('content').value = Custom.GetDefaultData();    // Add base styles    WCM.DHTML.AddStyleSheet({path: WCM.path + './base/wcm.base.css', context: window});    // Add a resize handler for when the window is resized.    var ResizeHandler = function()    {    WCM.DHTML.SetStyle('container', 'height', WCM.DHTML.GetViewportHeight() + 'px');    WCM.DHTML.SetStyle('container', 'width', WCM.DHTML.GetViewportWidth() + 'px');   };    ResizeHandler();    WCM.DHTML.AddWindowResizeEvent(window, ResizeHandler);   // Immediately store the original data as a baseline for the IsDirty comparison.   Custom.originalData = Custom.GetData();    // Let the Contributor Form know this Custom Element is ready. (required)    ElementAPI.Ready();  };  Custom.GetDefaultData = function()  {    return ElementAPI.GetDefaultData()                .replace(/<pre>/g, '')                .replace(/<\/pre>/g, '')                .replace(/&lt;/g, "<")                .replace(/&gt;/g, ">") || 'Some default content.';   };  Custom.GetData = function()  {    return '<pre>' + $ID('content').value.replace(/</g, "&lt;").replace(/>/g, "&gt;") + '</pre>';  };  try {    // Tell the Contributor Form to load the Custom Element dependent JavaScript libraries. (required)    // PARAMETERS    // 1st parameter: The context (window) in which the form loads the Custom Element dependent JavaScript libraries into.    // 2nd parameter: A user defined function pointer for the Contributor Form to call when initialization is complete.    window.top.WCM.InitializeCustomElement(window, Custom.Initialize);    catch(e) { }  </script>  </head><body>  <div id="container">  <div id="title">Simple Custom Element</div>  <div><textarea id="content" rows="5"></textarea></div>  </div></body></html>

Note:

The code example loads the ElementAPI and notifies the Contributor form that it is loaded and ready. It does not, however, collect or save data.

Communication From Contributor Form to Custom Element

The Contributor form communicates with a custom element by executing functions implemented by the custom element. As part of the initialization process, a custom element must register these functions by passing their function pointers to the Contributor form.

The table below lists the functions that can be registered with the Contributor form. None of these functions must be implemented by the custom element; however, a few of them are required if the intention is to collect and save data from a Contributor user. Furthermore, all of these functions (except the IsDirty() function), when executed, pass a callback function pointer to execute when the task is complete. This enables asynchronous communication if a custom element must perform an asynchronous task during execution.

Function Signature Description
CanCloseElement(callback); The Contributor form executes this method when the Contributor user performs an update. The implementation of the function should calculate whether the custom element can be safely closed. For instance, if the data does not pass validation, then the custom element should indicate that it cannot be closed.
GetElementContent(callback); The Contributor form executes this method when the Contributor user performs an update. The implementation of the function should pass back string content to be saved.
Hide(callback); The Contributor form executes this method whenever the form performs a DHTML task that overlays an HTML element over the custom element. For instance, this method is executed when the Metadata tab is activated and the Contributor elements are obscured.

This method was introduced specifically for the Ephox-based elements, because Java applets always have top z-index. All other elements (HTML-based elements) can ignore this method.

Show(callback); The Contributor form executes this method whenever the form performs a DHTML task that removes an overlay that makes custom element reappear.

This method was introduced specifically for the Ephox-based elements because Java applets always have top z-index. All other elements (HTML-based elements) can ignore this method.

IsDirty(); The Contributor form executes this method whenever the form popup is being closed without updating. The custom element should calculate whether unsaved changes exist so that the Contributor user can be notified if there are unsaved changes.

The following is a JavaScript code snippet of how a custom element can register functions with the Contributor form:

function CanCloseElement(callback){    // No data validation in this sample - just pass back a true value.    callback({canClose: true});    // Here is an example of passing a false value    // callback({canClose: false, reason: 'Failed validation. Use only lowercase
    // letters.'};}function GetElementContent(callback){    // Pass back some sample content for demo purposes.    callback('This is my Custom Element Content.');}function Show(callback){    // Just handle this notification by executing the callback.    callback(); }function Hide(callback){    // Just handle this notification by executing the callback.    callback(); }function IsDirty(){    // This Custom Element is never dirty - so pass a false value.    return {isDirty: false}; }// Set callback methods for the Contributor Form to send notifications to this
// Element.ElementAPI.SetCallback('CanCloseElement', CanCloseElement);ElementAPI.SetCallback('GetElementContent', GetElementContent);ElementAPI.SetCallback('Show', Show);ElementAPI.SetCallback('Hide', Hide);ElementAPI.SetCallback('IsDirty', IsDirty);

Communication From Custom Element to Contributor Form

A custom element initiates communication with the Contributor form by using the ElementAPI JavaScript object. The following is a list of available ElementAPI methods.

Function Signature Description
ElementAPI.GetDefaultData(); Retrieves the default content stored in the data file.
ElementAPI.GetSearchResults(options); Displays the Content Server's Get Search Results page.
ElementAPI.GetQueryText(options); Displays the Get Query Text UI.
ElementAPI.CaptureQuery(options); Displays the Content Server's Capture Query page.
ElementAPI.GetHyperlink(options); Displays the Hyperlink Wizard UI.
ElementAPI.FocusForm(options); Focuses the parent window thereby blurring the Element window.
ElementAPI.SetHostHeight(height); Sets the height of the Element's containing IFRAME.
ElementAPI.SetRequiredIndicator(isRequired); Toggles the Required graphic indicator in the Contributor Form UI.
ElementAPI.GetSite(options); Displays the Choose Website picker UI.
ElementAPI.GetSection(options); Displays the Choose Website Section picker UI.
ElementAPI.GetColor(options); Displays the Color picker UI.
ElementAPI.GetFont(options); Displays the Get Font picker UI.

ElementAPI Dependent Scripts

When the ElementAPI is loaded into the custom element page, so are the ElementAPI dependent scripts. These scripts contain most of the JavaScript WCM library and is also available for custom element authors to use. The following script files are loaded into a custom element:

Example of a Source-Mode Type of Custom Element

The following simple custom element example saves content entered into a TEXTAREA by Contributor users, and displays it directly in the layout.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"         "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml">  <head>  <title>Simple Custom Element</title>  <style type="text/css">  * { padding: 0; margin: 0; }  body { font-size: 10pt; font-family: Tahoma; }  #container  {    height: 150px;    overflow: auto;    width: 100%;    text-align: left;    align: left;    padding: 7px;   } .controls {   border: 1px solid #B9B9B4;   border-top-color: #DDDDD8;   border-bottom-color: #797975;   vertical-align: middle;   font-family: tahoma,verdana,arial,helvetica,sans-serif;   font-size: 100%; /* 11px @ Normal */   font-color: #000;  }  </style>  <script type="text/javascript">  var Custom = {};  Custom.originalData = null;  Custom.Initialize = function()  {    ElementAPI.SetCallback('GetElementContent', function(callback)    {      callback(Custom.GetData());    });    ElementAPI.SetCallback('ActivateElement', function(callback){ $ID('content').focus(); callback(); });    ElementAPI.SetCallback('CanCloseElement', function(callback){ callback({canClose: true}); });    ElementAPI.SetCallback('Show', function(callback){ callback(); });    ElementAPI.SetCallback('Hide', function(callback){ callback(); });    ElementAPI.SetCallback('IsDirty', function()    {      return { isDirty: (Custom.originalData !== Custom.GetData()) };    });    var height = ( ElementAPI.GetElementCount() == 1 ) ? '100%' : '150px';    var flags = ElementAPI.GetElementConfigProperty('flags') || {};    var config = ElementAPI.GetElementConfiguration() || {};    if( flags.canSetHeight && config.height && ( config.height.length > 0 ) )    {      height = config.height;    }    height = ElementAPI.SetHostHeight(height);    $ID('input-value').value = ElementAPI.GetDefaultData();    WCM.DHTML.AddStyleSheet({path: WCM.path + './base/wcm.base.css', context: window});    var ResizeHandler = function()    {      var viewPortWidth = WCM.DHTML.GetViewportWidth();      var viewPortHeight = WCM.DHTML.GetViewportHeight();      WCM.DHTML.SetStyle('container', 'height', viewPortHeight + 'px');      WCM.DHTML.SetStyle('container', 'width', viewPortWidth + 'px');      WCM.DHTML.SetStyle('input-value', 'height', (viewPortHeight - 15) + 'px');      WCM.DHTML.SetStyle('input-value', 'width', (viewPortWidth - (WCM.IS_IE ? 15 : 15)) + 'px');    };    ResizeHandler();    WCM.DHTML.AddWindowResizeEvent(window, ResizeHandler);    Custom.originalData = Custom.GetData();    ElementAPI.Ready();   };  Custom.GetData = function()  {    return $ID('input-value').value;  };  try {    window.top.WCM.InitializeCustomElement(window, Custom.Initialize);  } catch(e) { }  </script>  </head><body>  <div id="container" nowrap>  <textarea id="input-value" class="controls" type="text" title="URL"></textarea>  </div></body></html>