Information Classification: External Restricted.
See https://www.chili-publish.com/security

Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 7 Next »

Concept

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

There are many reasons a team would want to do this. Some examples are:

  • Updating variables on document load

  • Connecting to a custom widget

  • Building a partial or complete custom interface

  • Creating a “Save” button or an auto-save feature

Connection To CHILI publisher

You cannot communicate with the CHILI publisher directly due to the editor running in an iframe and browser security blocking JavaScript communication across iframes.

Therefore, if you want to utilize our JavaScript API across iframes you need to utilize our plugin: publisher-connector

You can install PublisherConnector via npm

npm i @chili-publish/publisher-connector

or through yarn

yarn add @chili-publish/publisher-connector


Or you can use the version from unpkg.com in your <script/> tags:

https://unpkg.com/@chili-publish/publisher-connector@latest/dist/PublisherConnector.min.js

Which one should I use?

If you utilize the NPM package, you will get all the benefits of TypeScript declaration files. However, you will need to use a module bundler like Webpack, Parcel, Rollup, etc. to package your JavaScript files for the web.

If you want to use this library in your integration without requiring a build phase, or you just want something simple, you can utilize the unpkg.com URL

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

  • Create an instance of the PublishConnector

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

Create an instance of the PublishConnector

To create an instance of the PublisherConnector, you will need to use the .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.

<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.

<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>

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.

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

The full JavaScript example would look like:

<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);
            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

<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:

<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(e);
            }
           
        })();
    </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

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:

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

You would do:

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

or use await, in a function marked async:

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.

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

Removing an event is pretty much the same.

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

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

editorObject Object

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

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

editorObject Object

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

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

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

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.

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

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

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

editorObject Object

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

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

editorObject Object

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:

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

 Click to see on-prem instructions


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):

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

The GetEditor function will request the actual editor instance:

var editor;
var frameWindow;

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

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


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

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"):

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

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:

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:

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");
}





  • No labels