Skip to content

Commit

Permalink
Added app channel documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
johnman committed Jul 10, 2024
1 parent 7ab56ed commit 2012140
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 28 deletions.
1 change: 1 addition & 0 deletions how-to/hints-and-tips/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ This section is where we will add small hints and tips that isn't specific to an
| Topic | Description |
| --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| [Channel API](./docs/channel-api.md) | This section covers things related to the Channel API and it's use. |
| [FDC3 App Channel API](./docs/window-level-app-channel.md) | This document covers an example of how you can use OpenFin and FDC3 APIs to have a window level app channel that updates as your views are moved from one window to another. |
| [User Engagement - Idleness and Visibility](./docs/visible-idle-detection.md) | This document covers how you can detect if the user is currently active and when they show or hide your content. |
| [User Engagement - Responding to the resize of a view](./docs/resize-detection.md) | This document covers how you can detect if the user has resized the view in some way. |
| [Version Info](./docs/version-info.md) | This document covers how you can look up information related to your application, the rvm, the runtime or the workspace components. |
Expand Down
139 changes: 111 additions & 28 deletions how-to/hints-and-tips/docs/window-level-app-channel.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,121 @@

# Window Level App Channel

If you want to share information across all views in a window then you can use an FDC3 app channel or an Interop Session Context Group to share that information.
If you want to share information in a custom way e.g. across all views in a window then you can use an FDC3 app channel or an Interop Session Context Group to share that information. Alternatively you can look at creating a custom implementation using a custom interop broker to create user groups per window and ensuring the views are assigned and removed from those groups as they get added and removed from a window.

The important piece is to have a common key shared across all views (and panels if you are using the Browser Fixed panel support). Views are created and initially assigned to your provider window until the target window is created and the view is moved.
This example uses app channels and the window name as the key. This logic could be packaged as reusable packages for your views. The important piece is to have a common key shared across all views (and panels if you are using the Browser Fixed panel support). Views are created and initially assigned to your provider window until the target window is created and the view is moved.

If you request the parent window early from a view (e.g. inside of a preload script or early on in the process) then you may initially see the provider id as the window identity which is not what you want.
## Listening for window level messages

```js
/**
* Get the identity of the window containing a view.
* @param view The view to get the containing window identity.
* @returns The identity of the containing window.
*/
private async getViewWindowIdentity(view: OpenFin.View): Promise<OpenFin.Identity> {
const currentWindow = await view.getCurrentWindow();

// If the view is not yet attached to a window, wait for the
// target-changed event which means it has been attached
if (currentWindow.identity.name === undefined || currentWindow.identity.name === currentWindow.identity.uuid) {
return new Promise<OpenFin.Identity>((resolve, reject) => {
// eslint-disable-next-line jsdoc/require-jsdoc
async function hostWindowChanged(): Promise<void> {
const hostWindow = await view.getCurrentWindow();
if (hostWindow.identity.name !== hostWindow.identity.uuid) {
await view.removeListener("target-changed", hostWindowChanged);
resolve(hostWindow.identity);
}
let windowLevelChannelListener;

async function listenToWindowLevelChannel(contextType, callbackToReceiveContext) {
if(window.fdc3 !== undefined && window.fin !== undefined) {
if(windowLevelChannelListener !== undefined) {
// We are currently listening to something. Lets dispose of this as we ay be setting up
// a new listener.
console.log("Unsubscribing from previous channel.");
windowLevelChannelListener.unsubscribe();
}
try {
const currentWindow = await fin.me.getCurrentWindow();
const windowIdentity = currentWindow.identity;
if(windowIdentity.name !== undefined && windowIdentity.name !== windowIdentity.uuid) {
// the view has been assigned to a window, start listening.
console.log("Creating or fetching app channel with name:", windowIdentity.name);
const appChannel = await window.fdc3.getOrCreateChannel(windowIdentity.name);
// start listening
windowLevelChannelListener = appChannel.addContextListener(contextType, callbackToReceiveContext);
}
} catch (err){
//app could not register the channel
console.error("Error registering the window channel", err);
windowLevelChannelListener = undefined;
}
view
.on("target-changed", hostWindowChanged)
.catch(() => {});
});
} else {
console.warn("Unable to listen to window level context as the fdc3 and/or fin api is not available.");
}
return currentWindow.identity;
}
}

async function contextHandler(ctx) {
console.log("This is the function that would be passed the window level context", ctx);
}

async function init() {
// listen for messages sent to the window.
// this is using fdc3.contact as an example. You can pass null if you want to listen for all messages
await listenToWindowLevelChannel("fdc3.contact", contextHandler);

// listen for times that the view is moved from one window to another and update
// your listener.
fin.me.on("target-changed", async ()=> {
// this is using fdc3.contact as an example. You can pass null if you want to listen for all messages
await listenToWindowLevelChannel("fdc3.contact", contextHandler);
});
}

// trigger the init call e.g. when the document is loaded.
await init();
```

## Publishing window level messages

```js
let windowChannel;

async function assignWindowLevelChannel() {
if(window.fdc3 !== undefined && window.fin !== undefined) {
try {
const currentWindow = await fin.me.getCurrentWindow();
const windowIdentity = currentWindow.identity;
if(windowIdentity.name !== undefined && windowIdentity.name !== windowIdentity.uuid) {
// the view has been assigned to a window, get a channel to use for broadcasting.
console.log("Creating or fetching app channel with name:", windowIdentity.name);
windowChannel = await window.fdc3.getOrCreateChannel(windowIdentity.name);
}
} catch (err){
//app could not register the channel
console.error("Error getting or retrieving the channel", err);
windowChannel = undefined;
}
} else {
console.warn("Unable to create a window level channel as fdc3 is not available.");
}
}

async function init() {
// create the window level channel
await assignWindowLevelChannel();

// listen for times that the view is moved from one window to another and update
// the window level channel.
fin.me.on("target-changed", async ()=> {
await assignWindowLevelChannel();
});
}

async function broadcastContext(contact){
// this is using fdc3.contact as an example but you could be sending any context type.
if(windowChannel !== undefined) {
console.log("Broadcasting context:", contact);
windowChannel.broadcast(contact);
} else {
console.warn("Window level channel is not available yet. Ensure you have called the init function before trying to broadcast.");
}
}

// initialize your code e.g. on document load
await init();
// in your code you might have something that is listening for a contact selection from a
// grid and then triggers the broadcast like the following:

const selectedContact = {
type: "fdc3.contact",
name: "Joe Smith",
id: {
email: "[email protected]"
}
};
broadcastContext(selectedContact);
```

0 comments on commit 2012140

Please sign in to comment.