How to use custom panels in SDL LiveContent Create
An introduction to the possibilities when using custom panels in your implementation.
Introduction
SDL LiveContent Create has three panels to the right, the property panel, the find and replace panel and the change tracking panel. It is possible to put a custom panel on top of the other panels. The API has a way of showing it:
Editor.getScope().set("showCustomPanel", true);
You can pass false to hide the panel again. This panel is an empty <div>:
<div id="customPanel"></div>
This <div> only exists when the scope property has been set to true. Because of this, it isn't always very easy to use. Below is an explanation of how to use it in a safe way.
SDL LiveContent Create exists as a Javascript object called Editor in the API. When you load a document, SDL LiveContent Create creates an iframe to load this document in. So essentially you have this:
- window (index.html) (Editor)
- iframe (about:blank/html5.html) (the document rendering)
Each page has its own document object which is a reference to the HTML DOM of the page. Each page also has its own Javascript scope and can contain other JavaScript code. API script is always added in the document iframe.
The UI exists in the top window, and therefore exists in the DOM of the document of window:
window.document.getElementById("customPanel")
But this is not always going to work. What if SDL LiveContent Create is itself in an iframe, as it is for example when used in SDL LiveContent Reach?
- window (something.html)
- iframe (index.html) (Editor)
- iframe (about:blank/html5.html) (the document rendering)
- iframe (index.html) (Editor)
Then window.document will not give us the correct DOM to go look for the custom panel. So first we need something like this:
function findWindowAndEditor(fr)
{
if(fr.Editor)
return {win:fr, editor:fr.Editor};
else if(fr.frameElement && fr.frameElement.contentWindow.Editor)
return {win:fr, editor:fr.frameElement.contentWindow.Editor};
else
{
for(var i = 0;i < fr.frames.length; i++)
var obj = findWindowAndEditor(fr.frames[i]) // dig deeper
return obj;
}
return false;
}
Which we can call like this:
var obj = findWindowAndEditor(top);This returns an obj which contains a win property, and the Editor (SDL LiveContent Create itself). From obj.win.document we can find the customPanel now. However the UI framework might be taking a moment to actually create that <div>, and the browser might need a moment to lay it out, when you do the following:
Editor.getScope().set("showCustomPanel", true); This code waits until everything exists before continuing:
var doc, editor, to;
function init(obj)
{
if(obj && obj.editor)
{
doc = obj.win.document;
editor = obj.editor;
//wait until the panel is ready
if(editor.getScope().get("showCustomPanel"))
window.setTimeout(function(){render();},100);
}
else //editor may need some time to start
to = window.setTimeout(function(){ init(obj);}, 50);
}
var rootEl;
function render()
{
rootEl = doc.getElementById("customPanel");
if(rootEl)
{
// go put something in the panel
}
else //custom panel sometimes needs time to be rendered by Xopus
{
if(editor.getScope().get("showCustomPanel"))
window.setTimeout(function(){render();},50);
}
}
Filling the panel with content
In order to put contents in an HTML element, which is what rootEl is, you can do this:
rootEl.innerHTML = "<div>Hello World</div>";
This means you would have to create a string of all the contents that you want to put in whenever you want to render the custom panel.
A more useful way would be to write functions that build HTML elements in the panel, and to re-use these functions to re-render the parts of the panel that need updating.
function writeText(rootEl, text)
{
var div = doc.getElementById("text");
if(!div)
{
div = doc.createElement("div");
rootEl.appendChild(div);
}
div.setAttribute("id", "text");
var textNode = doc.createTextNode(text);
div.appendChild(textNode);
}
writeText(rootEl, "Hello World");
This is just a simple example of course, but this make for a very clean way of rendering a custom panel.