Framebus allows you to easily send messages across frames (and iframes) with a simple bus.
npm install framebusFramebus allows you to easily send messages across frames (and iframes)
with a simple bus.
In one frame:
``js
var Framebus = require("framebus");
var bus = new Framebus();
bus.emit("message", {
from: "Ron",
contents: "they named it...San Diago",
});
`
In another frame:
`js
var Framebus = require("framebus");
var bus = new Framebus();
bus.on("message", function (data) {
console.log(data.from + " said: " + data.contents);
});
`
The Framebus class takes a configuration object, where all the params
are optional.
`js`
type FramebusOptions = {
origin?: string, // default: "*"
channel?: string, // no default
verifyDomain?: (url: string) => boolean, // no default
targetFrames?:
};
The origin sets the framebus instance to only operate on the chosen
origin.
The channel namespaces the events called with on and emit so you
can have multiple bus instances on the page and have them only
communicate with buses with the same channel value.
If a verifyDomain function is passed, then the on listener will onlylocation.href
fire if the domain of the origin of the post message matches the value of page or the function passed for verifyDomaintrue
returns .
`js`
var bus = new Framebus({
verifyDomain: function (url) {
// only return true if the domain of the url matches exactly
url.indexOf("https://my-domain") === 0;
},
});
If a targetFrames array is passed, then framebus will only sendWindow
messages to those frames and listen for messages from those frames. You
can pass a reference to a (the return value of window.open)HTMLFrameElement
or an (a DOM node representing an iframe).
`js
var myIframe = document.getElementById("my-iframe");
var bus = new Framebus({
targetFrames: [myIframe],
});
`
To add additional frames to the targetFrames array in the future, useaddTargetFrame
the method. targetFrames must be set, even if it's an
empty array, for this method to work.
`js
var myIframe = document.getElementById("my-iframe");
var bus = new Framebus({
targetFrames: [],
});
bus.addTargetFrame(myIframe);
`
#### target(options: FramebusOptions): framebus
returns: a chainable instance of framebus that operates on the
chosen origin.
This method is used in conjunction with emit, on, and off to'*'
restrict their results to the given origin. By default, an origin of is used.
`javascript`
framebus
.target({
origin: "https://example.com",
})
.on("my cool event", function () {});
// will ignore all incoming 'my cool event' NOT from 'https://example.com'
| Argument | Type | Description |
| --------- | --------------- | ---------------------------------- |
| options | FramebusOptions | See above section for more details |
#### emit('event', data?, callback?): boolean
returns: true if the event was successfully published, false
otherwise
| Argument | Type | Description |
| ---------------- | -------- | ---------------------------------------------------- |
| event | String | The name of the event |data
| | Object | The data to give to subscribers |callback(data)
| | Function | Give subscribers a function for easy, direct replies |
#### emitAsPromise('event', data?): Promise
returns: A promise that resolves when the emitted event is responded
to the first time. It will reject if the event could not be successfully
published.
| Argument | Type | Description |
| -------- | ------ | ------------------------------- |
| event | String | The name of the event |data
| | Object | The data to give to subscribers |
Using this method assumes the browser context you are using supports
Promises. If it does not, set a polyfill for the Framebus class with
setPromise
`js
// or however you want to polyfill the promise
const PolyfilledPromise = require("promise-polyfill");
Framebus.setPromise(PolyfilledPromise);
`
#### on('event', fn): boolean
returns: true if the subscriber was successfully added, false
otherwise
Unless already bound to a scope, the listener will be executed with
this set to the MessageEvent received over
postMessage.
| Argument | Type | Description |
| ---------------------- | -------- | ----------------------------------------------------------- |
| event | String | The name of the event |fn(data?, callback?)
| | Function | Event handler. Arguments are from the emit invocation |this
| ↳ | scope | The MessageEvent object from the underlying postMessage |
#### off('event', fn): boolean
returns: true if the subscriber was successfully removed, false
otherwise
| Argument | Type | Description |
| -------- | -------- | -------------------------------- |
| event | String | The name of the event |fn
| | Function | The function that was subscribed |
#### include(popup): boolean
returns: true if the popup was successfully included, false
otherwise
`javascript
var popup = window.open("https://example.com");
framebus.include(popup);
framebus.emit("hello popup and friends!");
`
| Argument | Type | Description |
| -------- | ------ | --------------------------------------------- |
| popup | Window | The popup reference returned by window.open |
#### addTargetFrame(frame): boolean
Used in conjunction with targetFrames configuration. If atargetFrames array is not passed on instantiation, this method will
noop.
`javascript
var frame = document.getElementById("my-iframe");
framebus.addTargetFrame(frame);
framebus.emit("hello targeted iframe!");
`
| Argument | Type | Description |
| -------- | --------------------------- | -------------------------------------------- |
| frame | Window or HTMLIFrameElement | The iframe or popup to add to targetFrames |
#### teardown(): void
Calls off on all listeners used for this bus instance and makesnoop
subsequent calls to all methods .
`javascript
bus.on("event-name", handler);
// event-name listener is torn down
bus.teardown();
// these now do nothing
bus.on("event-name", handler);
bus.emit("event-name", data);
bus.off("event-name", handler);
`
These are some things to keep in mind while using framebus to handle
your event delegation
framebus allows convenient event delegation across iframe borders.
By default it will broadcast events to all iframes on the page,
regardless of origin. Use the optional target() method when you know
the exact domain of the iframes you are communicating with. This will
protect your event data from malicious domains.
framebus operates over postMessage using JSON.parse andJSON.stringify to facilitate message data passing. Keep in mind thatundefined
not all JavaScript objects serialize cleanly into and out of JSON, such
as .
Even when the subscriber and publisher are within the same frame, events
go through postMessage. Keep in mind that postMessage is an
asynchronous protocol and that publication and subscription handling
occur on separate iterations of the event loop
(MDN).
When you specify a callback while using emit, the function is not
actually given to the subscriber. The subscriber receives a one-time-use
function that is generated locally by the subscriber's framebus.
This one-time-use callback function is pre-configured to publish an
event back to the event origin's domain using a
UUID as the event name. The events
occur as follows:
1. http://emitter.example.com publishes an event with a function as
the event data
`javascript
var callback = function (data) {
console.log("Got back %s as a reply!", data);
};
framebus.emit("Marco!", callback, "http://listener.example.com");
`
2. The framebus on http://emitter.example.com generates a UUID ascallback
an event name and adds the as a subscriber to this event.
3. The framebus on http://listener.example.com sees that a'Marco!'
special callback event is in the event payload. A one-time-use
function is created locally and given to subscribers of
as the event data.
4. The subscriber on http://listener.example.com uses the local
one-time-use callback function to send data back to the emitter's
origin
`javascript`
framebus
.target("http://emitter.example.com")
.on("Marco!", function (callback) {
callback("Polo!");
});
5. The one-time-use function on http://listener.example.com publishes
an event as the UUID generated in step 2 to the origin that
emitted the event.
6. Back on http://emitter.example.com, the callback is called and
unsubscribed from the special UUID event afterward.
If you are importing framebus via import { Framebus } from 'framebus/dist/framebus', your functions may error out due to missing the attach() call done in index.ts. You may need to add an additional line, import 'framebus/dist/index'` to ensure this call completes.
See here for more details.
See CONTRIBUTING.md