OpenFin windows

Windows created using the OpenFin Platform API act as a host (or container) for OpenFin Views. If your content is rendered in Views, your window can be used to display UI controllers, and acts as a "frame" within which views are drawn.

OpenFin standard window customization

The OpenFin Platform API includes OpenFin’s standard window, which has typical window controls (close, minimize, maximize) and some style customization.

As the name suggests, the standard window is used as the default window you get if you don’t specify the window’s URL upon creation.

Example of OpenFin's standard window including buttons for minimize, maximize, and close

You can easily apply your own stylesheet to the standard window by specifying the stylesheetUrl property within defaultWindowOptions in your manifest. The path or URL must be absolute, not relative.

Example of setting stylesheetUrl:

{
  "platform": {
    "uuid": "example_platform",
    "defaultWindowOptions": {
      "stylesheetUrl": "full-url-to-css-stylesheet"
    }
  },
  "snapshot": {
    ...
  }
}

📘

Overriding standard frame CSS selectors

To get an idea of the selectors that are available for you to override, take a look at the Platform style examples or inspect the window using Chrome Developer Tools.

Modal windows

You can create windows that are modal relative to a parent window. This enables you to create the same effect as modal dialog boxes in native applications. To create a modal window, add modalParentIdentity to the window options when you create it. It's also important, for usability, to set autoShow to true; otherwise, it could be hidden but still blocking interaction with its parent window.

Example in JavaScript of creating a modal window:

let winOption = {
    name:'child',
    defaultWidth: 300,
    defaultHeight: 300,
    url: 'https://cdn.openfin.co/docs/javascript/stable/tutorial-Window.create.html',
    frame: true,
    autoShow: true,
    modalParentIdentity: {uuid: "OpenfinPOC", name: "OpenfinPOC"}
  };
fin.Window.create(winOption);

Complete window customization

You can also overwrite OpenFin's standard window and "bring your own window." To do so, specify the url property as a window option in your manifest. This HTML file must contain a div component where you want the layout to be rendered. Use this div as the containerId property when you call Layout.init to initialize the Layout in the window and load the views. A url can also be specified in windowOptions in a snapshot, or when launching a snapshot via other methods. The URL must be absolute, not relative.

Example of overriding the window with url:

{
  "platform": {
    "uuid": "example_platform",
    "defaultWindowOptions": {
      "url": "full-url-to-html-file"
    }
  },
  "snapshot": {
    ...
  }
}

The Layout.init() method must be called in the custom window to initialize the layout and load the views. Call init() on the DOMContentLoaded event or after the window is set up and the target <div> element has been created.

window.addEventListener('DOMContentLoaded', () => {
  fin.Platform.Layout.init({containerId: 'id-of-div'});
});

📘

Note

The defaultWindowOptions.stylesheetUrl property is supported only for overriding standard window styles. If you are providing a custom window, include your stylesheets in your custom HTML document.

Popup windows

OpenFin V26 introduces a new API to make creating and managing Popup windows easier for developers. Popup windows are independent windows which are not restricted to the bounds of the DOM of the calling window. This allows content to be displayed on top of views. Some use cases for popup windows are dialog boxes, floating help windows, and tooltips.

Popup windows also close when the launching view or window closes.

Example in JavaScript of a simple popup window:

const result = await fin.me.showPopupWindow({
  url: 'https://app_popup_url_here',  // The URL of your app's popup window.
  x: 150,                             // The x location for the upper left corner of your popup window.
  y: 100,                             // The y location for the upper left corner of your popup window.
  height: 150,                        // The popup window height.
  width: 300                          // The popup window width.
});

Popup windows can be placed programmatically so that you can place the window in a logical location, such as near the button the user clicked to launch the popup window.

Example in JavaScript of programmatic placement of the popup window:

const parentWindow = await (fin.me as OpenFin.View).getCurrentWindow();
const { identity: modalParentIdentity } = parentWindow;
const parentBounds = await parentWindow.getBounds();
const result = await fin.me.showPopupWindow({
  url: location.href.replace('app', 'popup'),
  x: Math.floor(parentBounds.width / 8),  // Location and size of popup window derived from parent window bounds.
  y: Math.floor(parentBounds.height / 8) - PARENT_FRAME_OFFSET,
  height: Math.floor(parentBounds.height - parentBounds.height / 4),
  width: Math.floor(parentBounds.width - parentBounds.width / 4),
});

Popup windows can return one or many results. By default when showPopupWindow is called it will wait for the popup to be dismissed or call dispatchPopupResult. If an onPopupResult callback is passed to showPopupWindow, the popup can dispatch many results to the caller and showPopupWindow will wait for the popup window to be dismissed.

Example in JavaScript of creating a popup window that sends multiple results:

const { right, height } = event.target.getBoundingClientRect();
const result = await fin.me.showPopupWindow({
  initialOptions: {
    customData: await fin.me.interop.getContextGroups()
  },
  url: location.href.replace('app', 'popup'),
  x: right + 5,
  y: Math.round((height / 2) + 15),
  height: 30,
  width: 250,
  resultDispatchBehavior: 'none',
  onPopupResult: (result) => {
    renderPopupResult(result);
  }
});
renderPopupResult(result);

Just as normal windows can be modal, popup windows can be modal windows as well. Just add modalParentIdentity in the initialOptions of the popup window.

Example in JavaScript of another way to add modalParentIdentity to the initial window options:

const result = await fin.me.showPopupWindow({
  initialOptions: {
    modalParentIdentity
  },
  url: 'https://app_popup_url_here',  // The URL of your app's popup window.
  x: 150,                             // The x location for the upper left corner of your popup window.
  y: 100,                             // The y location for the upper left corner of your popup window.
  height: 150,                        // The popup window height.
  width: 300                          // The popup window width.
  blurBehavior: 'modal'
});

Context menus

From OpenFin v12, context menus have been configured with the contextMenuSettings property of the Window and View options. Beginning in v27, OpenFin context menus can instead be configured with the contextMenuOptions property, which provides an easier to use and more versatile method of creating context menus via an API that closely matches the shape of both the Electron Menu API, and the OpenFin PopupMenu API. Additionally, three new context menu features are available via the new API: navigateForward, navigateBack, and reload. For backward compatibility, contextMenuSettings remains the default method to create context menus, but will likely be deprecated in a future release.

The spellCheck item is the only item that requires a bit of extra work to make it work in a context menu. To make the spell check option appear, a "spellCheck": true must be added to the defaultViewOptions or defaultWindowOptions property, and "spellcheck" must be included in the contextMenuOptions.template array. Both steps are required for proper functionality.

To leverage the new context menu features, add a contextMenuOptions property to your window or view options. The optional enabled property toggles the visibility of the entire context menu (defaults to true), while the optional template property is an array of one or more items from the list of available context menu items (defaults to a close approximation of v26 behavior, minus support for emoji, Copy link to highlight, and Print as plaintext). These options can be placed in any order, and can be repeated more than once in the list (a feature which is particularly useful for the separator item).

"defaultViewOptions": {
  "spellCheck": true,
  "contextMenuOptions": {
    "template": ["spellCheck", "separator", "cut", "copy", "paste", "separator", "reload", "navigateForward", "navigateBack", "separator", "inspect", "print"]
  }
}

Using the above defaultViewOptions, a right-click would show a context menu that looks like this:

Right-click context menu showing spellcheck, cut, copy, paste, reload, forward, back, inspect, and print

The template has a fixed list of options that can be added to a context menu:

Context menu itemDescription
navigateForwardNavigate forward to the next page of content.
navigateBackNavigate back to the previous page of content.
printPrint the selected view or window.
separatorA separator between menu items.
cutCut the selected content and place it on the clipboard.
copyCopy the selected content and place it on the clipboard.
pastePaste the content on the clipboard to the selected view or window.
undoUndo the last action.
redoRedo the last undone action.
selectAllSelect all in the right-clicked control.
spellCheckInvokes a spell check on the text of the selected view or window.
inspectLoads the Entity Viewer to view the entity that was right-clicked.
reloadReloads the view or window.

Print views and windows

Starting in version 31, OpenFin Runtime expanded printing functionality to allow you to print all views in a window, with or without the window content, and to print screenshots.

Changes to printing options

A new printing options object has been added, WindowPrintOptions. WindowPrintOptions is a TypeScript discriminated union which means WindowPrintOptions can resolve to a PrintOptions object, a ScreenshotPrintOptions object, or a WindowViewsPrintOptions object depending on the value of the content element.

This is true in both JavaScript and TypeScript.

Here is how the value of content resolves the WindowPrintOptions object:

The value of contentWindowPrintOptions resolves to
'screenshot'ScreenshotPrintOptions
'views'WindowViewsPrintOptions
undefined or 'self'PrintOptions

Additionally, when content is set to 'views', a new element, includeSelf, becomes available. The includeSelf boolean declares whether window content will or will not be printed when printing views.

Print a screenshot

// Print a screenshot of the current window.
win.print({ content: 'screenshot' });

When content is set to 'screenshot', a screenshot will be captured and sent to the printer.

The settings in the PrintOptions object will not be used for this print.

Print all views including window content

// Print all views of a window including all window content.
win.print({ content: 'views', includeSelf: true });

When content is set to 'views' and includeSelf is true, all views in the current window, and the window contents, will be sent to the printer.

The settings in the PrintOptions object will not be used for this print.

Print all views excluding window content

// Print all views of a window without printing the window content.
win.print({ content: 'views', includeSelf: false });

When content is set to 'views' and includeSelf is false, all views in the current window, without the window contents, will be sent to the printer.

The settings in the PrintOptions object will not be used for this print.

Legacy behavior

// Print using V30 functionality.
win.print({content: 'self'});

When content is undefined or set to 'self', the win.print function will work as it did in version 30 and earlier.

The settings in the PrintOptions object will be used for this print.

Window-closing behavior

When the user tries to close an app with unsaved changes, or navigate away from a form that hasn't been submitted, you can launch a warn-before-close dialog window. A warn-before-close dialog window is completely controlled by you as the platform provider and is exposed as an override that can be customized.

To intercept the close of a window or view:

  • Set "enableBeforeUnload": true under the Platform options in the app manifest.
  • Override the getUserDecisionForBeforeUnload function as in the example below.

Example in JavaScript of how to use a warn-before-close dialog:

const overrideCallback = async (PlatformProvider) => {
  class MyOverride extends PlatformProvider {
 
    // By overriding this function we can intercept the close action
    // of any Window or View and show our own custom dialog.
    async getUserDecisionForBeforeUnload(payload) {
 
      // We gather all relevant information from the payload:
      // Which views are preventing the unload and which aren't.
      // Also, if this a Window or View close.
      const { windowClose, 
              viewsPreventingUnload, 
              viewsNotPreventingUnload, 
              windowId, 
              closeType } = payload;
 
      // Launch a dialog that displays the relevant information to the user.
      const continueWithClose = await launchDialog(viewsPreventingUnload, windowId, closeType);
 
      if (continueWithClose) {
 
        // If the user decides to close the view, we send back an array of Views to close,
        // and whether the Window should close or not close.
        return { windowShouldClose: windowClose,
                 viewsToClose: [...viewsNotPreventingUnload, ...viewsPreventingUnload] };
      } else {
 
        // If the user cancels the close, we send an empty array of Views to close,
        // and indicate that the Window should not close.
        return { windowShouldClose: false, viewsToClose: [] };
      }
    }
  }
  return new MyOverride();
};

// Include the overrideCallback in the platform initialization call
fin.Platform.init({ overrideCallback });

See also