Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Concept

An editor which that is embedded in your HTML pages can be interacted with using our JavaScript API. See Embedding an Editor in your own portals

...

Once you have decided, it is time to begin your integration. There are three two steps:

  • Create an instance of the PublishConnector

  • Listen to the event for the CHILI document to be fully renderedStart making modifications

Create an instance of the PublishConnector

To create an instance of the PublisherConnector, you will need to use the “build” .build() method and pass in the iframe element.

Below is the code of a quite simple website where the iframe URL for CHILI publisher is already set.

Code Block
languagejsxjs
<body>
    <iframe id="editor-iframe" style="width:1200px; height:800px"
        src="https://example.chili-publish.online/example/editor_html.aspx?doc=3d178228-a9b9-49d0-90d9-c1c8f8b67f05&apiKey=Sczs1ruhiZcaFiqg0G07gMFMq07X+SG2o8KlW8oAeZGvqoB1a0YvkbeZU1wJK15aIhANgZmhg+13NQlxpBEq7Q=="></iframe>
    <script type="module">
        import {PublisherConnector} from 'https://unpkg.com/@chili-publish/publisher-connector@latest/dist/PublisherConnector.min.js';
    
        const iframe = document.getElementById("editor-iframe");
    
        (async () => {
            const publisherConnector = await PublisherConnector.build(iframe);
           
        })();
    </script>
</body>

Notice that the .build() method returns a Promise. In the code above we utilize the async/await syntax, but we could also use the alternative then syntax.

Code Block
<body>
    <iframe id="editor-iframe" style="width:1200px; height:800px"
        src="https://example.chili-publish.online/example/editor_html.aspx?doc=3d178228-a9b9-49d0-90d9-c1c8f8b67f05&apiKey=Sczs1ruhiZcaFiqg0G07gMFMq07X+SG2o8KlW8oAeZGvqoB1a0YvkbeZU1wJK15aIhANgZmhg+13NQlxpBEq7Q=="></iframe>
    <script type="module">
        import {PublisherConnector} from 'https://unpkg.com/@chili-publish/publisher-connector@latest/dist/PublisherConnector.min.js';
    
        const iframe = document.getElementById("editor-iframe");
    
        PublisherConnector.build(iframe).then((connector)=>
          const publisherConnector = connector
        );
    </script>
</body>

Note

Warning

It is important that the “build” method is called before the iframe is fully loaded. The is due to how our library relies on another library called Penpal. Failure to do this will lead to the library not being able to communicate with the iframe.

If you set the src attribute of the iframe in your HTML and have a script tag that runs the build method all in the same (or almost) event loop, then everything will be fine. A good example of doing this wrong would be to call the “build” method after the onload event is fired off.

Listen to the event for the CHILI document to be fully rendered

As soon as the Promise from the .build() method is resolved, you are good to begin interacting with the CHILI publisher editor. However, due to the loading of the document it may be wise to wait until the document has fully rendered before you start your interaction.

To do this, we need to add an event listener for the event DocumentFullyRendered. The event DocumentFullyRendered is fired off only when the CHILI document and workspace are completely drawn to the screen.

Now, this is not a web event, we must use a special method called .addListener(). This method takes an event name (string) and a callback function to be called when the event is fired off.

Code Block
languagejs
await publisherConnector.addListener(
  "DocumentFullyRendered", 
  target => console.log("document is rendered")
);

The full JavaScript example would look like:

Code Block
languagejs
<body>
    <iframe id="editor-iframe" style="width:1200px; height:800px"
        src="https://example.chili-publish.online/example/editor_html.aspx?doc=3d178228-a9b9-49d0-90d9-c1c8f8b67f05&apiKey=Sczs1ruhiZcaFiqg0G07gMFMq07X+SG2o8KlW8oAeZGvqoB1a0YvkbeZU1wJK15aIhANgZmhg+13NQlxpBEq7Q=="></iframe>
    <script type="module">
        import {PublisherConnector} from 'https://unpkg.com/@chili-publish/publisher-connector@latest/dist/PublisherConnector.min.js';
    
        const iframe = document.getElementById("editor-iframe");
    
        (async () => {
            const documentName = await publisherConnector.getObject("document.name"); publisherConnector = await PublisherConnector.build(iframe);
            await publisherConnector.addListener(
              "DocumentFullyRendered", 
              target => { // Do stuff }
            );
           
        })();
    </script>
</body>

These method calls we are making will return an Exception if something goes wrong. Therefore, it is important to wrap your calls with a try/catch

Code Block
<body>
    <iframe id="editor-iframe" style="width:1200px; height:800px"
        src="https://example.chili-publish.online/example/editor_html.aspx?doc=3d178228-a9b9-49d0-90d9-c1c8f8b67f05&apiKey=Sczs1ruhiZcaFiqg0G07gMFMq07X+SG2o8KlW8oAeZGvqoB1a0YvkbeZU1wJK15aIhANgZmhg+13NQlxpBEq7Q=="></iframe>
    <script type="module">
        import {PublisherConnector} from 'https://unpkg.com/@chili-publish/publisher-connector@latest/dist/PublisherConnector.min.js';
    
        const iframe = document.getElementById("editor-iframe");
    
        (async () => {
            try {
              const publisherConnector = await PublisherConnector.build(iframe);
              await publisherConnector.addListener(
                "DocumentFullyRendered", 
                target => { // Do stuff }
              );
            }
            catch(e) {
              console.log(e);
            }
           
        })();
    </script>
</body>

There is an earlier event called DocumentFullyLoaded, this event is called when the CHILI document has been fully deserialized from the XML format into an in-memory JavaScript object. If you would like to listen for that, the method is similar:

Code Block
<body>
    <iframe id="editor-iframe" style="width:1200px; height:800px"
        src="https://example.chili-publish.online/example/editor_html.aspx?doc=3d178228-a9b9-49d0-90d9-c1c8f8b67f05&apiKey=Sczs1ruhiZcaFiqg0G07gMFMq07X+SG2o8KlW8oAeZGvqoB1a0YvkbeZU1wJK15aIhANgZmhg+13NQlxpBEq7Q=="></iframe>
    <script type="module">
        import {PublisherConnector} from 'https://unpkg.com/@chili-publish/publisher-connector@latest/dist/PublisherConnector.min.js';
    
        const iframe = document.getElementById("editor-iframe");
    
        (async () => {
            try {
              const publisherConnector = await PublisherConnector.build(iframe);
              await publisherConnector.addListener(
                "DocumentFullyLoaded", 
                target => { // Do stuff - but be warned things can still change as they are being loaded }
              );
              await publisherConnector.addListener(
                "DocumentFullyRendered", 
                target => { // Do stuff }
              );
            }
            catch(e) {
              console.log(documentNamee);
            }
           
        })();
    </script>
</body>

Working With CHILI publisher JavaScript API

If you have followed along, you should have a working example as an HTML file, and you can begin playing around with our JavaScript API.

You can check out pages like: Common JavaScript integration tasks, but you will notice they are using editor or editorObject and there is no Promise to be found in any of the examples. The reason it looks different is because all examples outside this one page communicate with CHILI publisher directly, meaning no iframe and no PublisherConnector. The PublisherConnector is just an interface that uses the postMessage() method, but under the hood it utilizes the direct editorObject.

You can find the source code that is running on the Online server here: https://github.com/chili-publish/publisher-connector/blob/main/onServer/chiliInternalWrapper.ts

Info

Confused?

When CHILI publisher loads it adds an object to the window called editorObject, or its alias editor. This object provides a series of methods that allow you to interact with the editor. So, you can access it via window.editorObject. However, this object is unreachable if CHILI publisher is running in an iframe. Therefore, we built a postMessage() interface called PublisherConnector which allows you to easily interact with the PublisherConnector object as though it was the editorObject.

However, because postMessage() works through events, there is a time delay, and therefore PublisherConnector object will return a Promise whereas the editorObject returns the response immediately.

There are a few differences between the PublisherConnector interface and the direct editorObject:

  • Naming Convention

  • Promise Return

  • Events

Naming Convention

A small, but important difference is that the methods from the PublisherConnector uses common JavaScript naming - camel case. This differs from the Pascal case used by the editorObject.

So editorObject.GetObject() becomes publisherConnector.getObject().

So editorObject.SetProperty() becomes publisherConnector.setProperty().

Promise Return

While the editorObject methods return without delay, the PublisherConnector uses postMessage(). This means that the message must be serialized, sent, deserialized across from one window to another.

To make this easy, the PublisherConnector methods return a Promise.

So instead of:

Code Block
const documentId = editorObject.GetObject("document.id");
console.log(documentId);

You would do:

Code Block
publisherConnector.getObject("document.id").then(
    documentId => console.log(documentId)
);

or use await, in a function marked async:

Code Block
const documentId = await publisherConnector.getObject("document.id");
console.log(documentId);

Just like editorObject methods, if something goes wrong, an Exception will be thrown.

Events

The PublisherConnector does events completely different from what is documented for the editorObject.

To use events with the editorObject, it involved calling the editorObject.AddListener() method and then defining a function on window.OnEditorEvent() method that took a string for events. The OnEditorEvent() function would typically have a switch case or a series of if/else to determine which event was called.

PublisherConnector makes things much simpler. If you want to listen to an event and then do something, then name it and add a callback function.

Code Block
await publisherConnector.addListener(
  "FrameMoveFinished", 
  target => console.log("Frame moved with id " + target)
);

Removing an event is pretty much the same.

Code Block
await publisherConnector.removeListener("FrameMoveFinished");

Four Main Methods

Okay now that you understand the difference between the PublishConnector object and the editorObject, let us look at the four main methods on both objects:

  • Listening to Events

  • Reading Properties

  • Setting Properties

  • Executing Functions

Listening to Events

You can listen to events using this method .addListener(). The first parameter takes an event name (string) and a callback function to be called when the event is fired off.

PublisherConnector Object

Code Block
await publisherConnector.addListener(
  "FrameMoveFinished", 
  target => console.log("Frame moved with id " + target)
);

editorObject Object

Code Block
window.OnEventListener = (event, target) => {
  if (event == "FrameMovedFinished") {
    console.log("Frame moved with id " + target)
  }
}

editorObject.AddListener("FrameMoveFinished");

Reading Properties

To read properties of the document, you use the method .getObject() which will return to you either a copy of the JavaScript object or a primitive. CHILI publisher converts the XML into a big JavaScript object starting at the document element with a all the child elements becoming properties.

So, if you wanted to get the full document object you could do this:

PublisherConnector Object

Code Block
const chiliDoc = await publisherConnector.getObject("document");

editorObject Object

Code Block
const chiliDoc = editorObject.GetObject("document");

The above calls will give you a shallow snapshot of the document. By shallow, we mean that it only goes one level deep down the key/value object tree. By snapshot, we mean that the object returned has no reference to the in-memory CHILI document object.

If you wanted to get the name, you could just then do .name

Code Block
console.log("Document name is: " + chiliDoc.name)

You can also get the property directly by passing the string document.name in the getObject() method.

Code Block
console.log("Document name is:" + await publisherConnector.getObject("document"));

The string document.name is commonly referred to as CHILI path. It is the key/value path of the object.

For example, if you wanted to get the id of the first frame on page two.

Code Block
console.log("First frame on page 2 id is:" + await publisherConnector.getObject("document.pages[1].frames[0]"));

Note

Warning

The behavior and response of the .GetObject() with a CHILI path is not always euqal as accessing it via the return object. For example, the below two examples do not return the same value

editorObject.GetObject("document.pages") != editorObject.GetObject("document").pages

However, these two are the same

editorObject.GetObject("document.zoom") == editorObject.GetObject("document").zoom

Reading Properties

Okay we know how to read properties, but how do we set properties? We utilize the setProperty() method. This method takes a CHILI path string, the property to set, and the value to set it to.

PublisherConnector Object

Code Block
await publisherConnector.setProperty("document", "zoom", 100);

editorObject Object

Code Block
editorObject.SetProperty("document", "zoom", 100);

Executing Functions

Remember that CHILI publisher serializes the XML to a JavaScript object. Well that object has methods/functions, which we can interact with via CHILI path.

We can do this utilizing the .executeFunction() method. This method’s signature takes the CHILI path, the function name, and then a variable number of parameters based on the function you wish to call. The response will vary based on the function you wish to call.

So, for example, creating a new frame:

PublisherConnector Object

Code Block
const newFrame = await publisherConnector.executeFunction("document.pages[1].frames","Add","rectangle","10mm","50mm","100mm","70mm");

editorObject Object

Code Block
const newFrame = editorObject.ExecuteFunction("document.pages[1].frames","Add","rectangle","10mm","50mm","100mm","70mm");

While getting the XML of the document, it has no extra parameters:

Code Block
const xml = await publisherConnector.executeFunction("document", "GetTempXML");

Unfortunately, unlike properties, functions on CHILI objects are not shown in the .getObject() method. The most common function names can be found in this documentation, or contact support to see if there exist a function for what you are trying to achieve.


Working With Older CHILI publish On-prem

Expand
titleClick to see on-prem instructions


Info

Do not follow these instructions if you are using CHILI publish Online


The iframe should contain an "onload" javascript, calling one of your own functions.
In this function, an editor instance can be requested (using a callback which receives the instance once the swf has actually finished loading):

Code Block
<iframe id="chili-iframe" onload="iFrameLoaded()" src="EDITOR_URL" />

The GetEditor function will request the actual editor instance:

Code Block
var editor;
var frameWindow;

function iFrameLoaded()
{
    frameWindow = document.getElementById("chili-iframe").contentWindow;
    frameWindow.GetEditor(EditorLoaded);
}

function EditorLoaded(jsInterface)
{
     editor = frameWindow.editorObject;
}


Warning

Please consult the JavaScript Security Considerations if this code is not working for you. 

Registering To Events

Events can be handled by inserting an "OnEditorEvent" function in your HTML page.
The following events are always registered:

  • DocumentFullyLoaded

  • SelectedPageChanged

  • DocumentSaved

Code Block
function OnEditorEvent(type,targetID)
{
    switch (type){
        case "DocumentFullyLoaded":
            //DO MAGIC
            break;
        case "SelectedPageChanged":
            ShowSelectedPage();
            break;
    }
}

To register additional events, you can call the "AddListener" function (and remove them using "RemoveListener"):

Code Block
function EditorLoaded(jsInterface)
{
    editor = frameWindow.editorObject;
    editor.AddListener("CursorChanged");
}

Getting Object Instances

To provide immediate access to the entire document object model, CHILI Editor contains a number of functions which allow you to get information/set values/... based on a descriptor of the object.

Objects are "translated" to a JavaScript representation, which contains the various property values of the object as strings (or simple datatypes, where applicable).
If a simple datatype (e.g. string or boolean) is requested directly, it will be preserved in that type.

Object descriptors consist of a string pointing the functions to the appropriate object.
Point annotation can be used to get to properties.

For lists, you can use a "[]" annotation to provide one of the following descriptors to get an item (which will be evaluated in this order):

  • ID

  • Index

  • Name

  • Tag

Code Block
function GetInfo()
{
   obj = editor.GetObject("document.pages[0].frames[0]");

   //LIST ALL PROPERTIES OF THE REQUESTED OBJECT:
   txt = "<table>";
   for (var i in obj)
   {
        txt += "<tr><td width=120>" + i + ":</td><td>" + obj[i] + "</td></tr>";
   }
   txt \+= "</table>"
   document.getElementById("objectInfo").innerHTML = txt;

   //GET ID ON FRAME OBJECT:
   var id1 = obj.id;
   //GET ID DIRECTLY, as a string:
   var id2 = editor.GetObject("document.pages[0].frames[0].id");
}

Setting Property Values

Using the object descriptor, you can also set property values:

Code Block
function SetProperty()
{
   objDescriptor = "document.selectedFrame";
   propName = "borderWidth";
   propValue = "3";

   editor.SetProperty(objDescriptor,propName,propValue);
}

Calling Functions

For any of the found objects, you can also call any of the public functions:

Code Block
function CreateFrame()
{
   frame = editor.ExecuteFunction("document.pages[1].frames","Add","rectangle","10mm","50mm","100mm","70mm");
   editor.SetProperty("document.pages[1].frames[" + frame.id + "]","borderWidth","5");
}


...