LivePersonInc/chronosjs

View on GitHub
README/Courier.md

Summary

Maintainability
Test Coverage
#Overview

Courier is a cross iFrame implementation of an event bus using [postMessage](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage) and [MessagChannel](https://developer.mozilla.org/en-US/docs/Web/API/MessageChannel) APIs.

It contains all three Event types we support in this Chronos: [Events](Events.md), [Commands](Commands.md) and [ReqRes](ReqRes.md).

Courier exists in the <b>/dist/</b> folder and the <b>/dist/min/</b> folder in two version:

1. <b>PostMessageCourierNoDep.js</b> - without it's dependencies included (Channels, Events, Commands, ReqRes)

2. <b>PostMessageCourier.js</b> - as a complete package with all dependencies

####Courier functions in two main ways:

1. Spawning it's own private events engine

2. Receiving an event engine ([Channels](Channels.md) externally) it can share across iFrames / same Page Apps (*see [Channels](Channels.md) for <b>externalProxy</b> flag)

It is important to note the use case you want when creating a Courier instance.

Example (Private events channel):
```javascript
    var courier = new new Chronos.PostMessageCourier({ target :  targetConfiguration });
```

Example shared Events channel:
```javascript
    var channel = new Chronos.Channels(); //Shared instance you can pass around to other couriers and share Events triggers
    var courier = new new Chronos.PostMessageCourier({
        eventChannel: channel,
        target :  targetConfiguration
    });
```

##How to set up iFrames with Courier
Both parent page and child iFrame need to include the <b>PostMessageCourier.js</b> from the dist directory (there is a minified, compressed version in the <b>min</b> directory).

In order to set up iFrames you have two options:

1. Create your own iFrame and pass it in to Courier
2. Pass in a URL and let Courier create it for you


##Creating your own iFrame
```javascript
    function createIFrame(options) {
        var src ,
        frame = document.createElement("IFRAME");

        for(var key in options.attributes){
            frame.setAttribute(key, options[key]);
        }
        for(var attr in options.styles){
            frame.style[attr] = options.styles[attr];
        }

        frame.addEventListener("load", function() {
            if (typeof options.callback === "function") {
                options.callback(options.context);
            }
        }.bind(this), true);

        document.body.appendChild(frame);

        if (options && options.target && options.target.url) {
            src = options.url + (0 < options.url.indexOf("?") ? "&bust=" : "?bust=");
            src += (new Date()).getTime();
            src += ("&host=" + document.location.protocol + "//" + document.location.host);
            frame.setAttribute("src", src);
        }
        return frame;
    }
```
After you have created your own iFrame you need to create a courier instance and pass it to the Courier.

```javascript
    var frame = createIFrame({
        url: "https://mysite.com/integration/index.html",
        attrs: {
            id: "MyId",
            title: "MyTitle",
            name: "MyName",
            tabindex : 0
        },
        styles : {
            position: "fixed",
            top: "5px",
            left: "5px",
            width: "50%",
            height: "300px"
        }
    });

    var courier = new Chronos.PostMessageCourier({
        target: frame,
        targetOrigin: protocol + hostname + port
    });
```

The other option is to let Courier create the iFrame and pass it back to you.
###Please note if you dont set any attributes the iFrame will be hidden from view.

```javascript
     var courier = new Chronos.PostMessageCourier({
        target: {
            url: protocol + hostname + port + "/MYPATH/index.html",
            style: {
                width: "100px",
                height: "100px"
            },
            attributes :{
                name : "name"
            }
        }
     });
```

##Configuration for Courier

The configuration supports the following properties in the target attribute:

| Parameter | Type | Description |  Defaults |
| ---       | ---  | ---         | ---       |
| url | String | The URL of your iFrame | None |
| bust | Boolean | If to use a cache bust parameter when adding the iFrame | true |
| container | DOM Element | The element you want the iFrame in | document.body |
| style | Object | The style attributes you'd like to set on the iFrame | ```{ width :"0px", height : "0px", position :"absolute", top : "-1000px",  left : "-1000px" }``` |
| attributes | Object | The attributes you'd like to set on the iFrame | ```{"id": name, "name" :name, "tabindex": "-1", "aria-hidden": "true", "title":  "","role": "presentation","allowTransparency":"true"}```|
| callback | Function | A function to be called after the iFrame has loaded | None|
| context | Object | The execution context for the callback | None |

Example:
```
{ target :{
    url: ...,
    style: { ... },
    attributes :{ ... }
    container: ...,
    callback: function() { ... },
    context : ...
  }
}
```

Other configuration options:

| Parameter | Type | Description |  Defaults |
| ---       | ---  | ---         | ---       |
| onready | Object with callback and context | A function to be called when the handshake with the iFrame has been completed | None |
| serialize | Function | Function for serializing data into the iFrame | JSON.stringify |
| deserialize | deserialize | Function for deserializing data from the iFrame | JSON.parse |
| targetOrigin | String | the domain of the iFrame being added <b>*must be supplied in case of external iFrame</b> | None |
| handshakeInterval | milliseconds | Number of milliseconds before handshake retry | 5000 |
| handshakeAttempts | int | Maximum attempts at handshake | 3 |

Example:
```
{
    target :{ ... }
    onready : {
      callback: function(){},
      context : ...
    },
    serialize : function() { ... },
    deserialize : function() { ... },
    targetOrigin: ...,
    handshakeInterval : ...,
    handshakeAttempts : ...
}
```

##How to use Courier
Once you have a courier instance you can use all the methods supported just like events:

 ```javascript
 // Initialize a new Courier
 var courier = Chronos.PostMessageCourier({
     target: {
         url: "http://www.crossdomain.com/"
     }
 });

 ///// ---- BINDINGS ------ ////
 courier.bind({
     appName: "host",
     eventName: "multiply",
     func: multiply
 });
 courier.comply({
     appName: "host",
     cmdName: "square",
     func: square
 });
 courier.reply({
     appName: "host",
     reqName: "divide",
     func: divide
 });

 ///// ---- INVOCATION ------ ////
 courier.trigger({
     appName: "frame",
     eventName: "got_it",
     data: data * 2
 });
 courier.command({
     appName: "frame",
     cmdName: "expect",
     data: data
 }, function(err) {
     if (err) {
         console.log("Problem invoking command");
     }
 });
 courier.request({
     appName: "frame",
     reqName: "askBack",
     data: data
 }, function(err, data) {
     if (err) {
         console.log("Problem invoking request");
         return;
     }
     // Do Something with the data
     console.log(data);
 });
 ```