# Window Management

Source: https://docs.interop.io/browser/capabilities/windows/window-management/index.html

## Overview

Using the [Window Management API](https://docs.interop.io/browser/reference/javascript/windows/api/index.md), your app can easily open and manipulate browser windows. This allows you to transform your traditional single-window web app into a multi-window native-like web app. The Window Management API enables apps to:

- open multiple windows;
- manipulate the position and size of opened windows;
- pass context data upon opening new windows;
- listen for and handle events related to opening and closing windows;

The Window Management API is accessible via the [`io.windows`](https://docs.interop.io/browser/reference/javascript/windows/api/index.md) object.

The [Live Examples](#live_examples) section demonstrates using the Window Management API.

## Configuration

Use the `windows` property of the configuration object for initializing the [`@interopio/browser-platform`](https://www.npmjs.com/package/@interopio/browser-platform) library in the [Main app](https://docs.interop.io/browser/developers/browser-platform/overview/index.md) to specify custom settings for the Window Management library:

```javascript
import IOBrowserPlatform from "@interopio/browser-platform";

const config = {
    licenseKey: "my-license-key",
    windows: {
        windowResponseTimeoutMs: 10000,
        defaultWindowOpenBounds: {
            top: 0,
            left: 0,
            width: 600,
            height: 600
        }
    }
};

const { io } = await IOBrowserPlatform(config);
```

Configuring the Window Management library is optional. The configuration object for the `windows` property has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `defaultWindowOpenBounds` | `object` | [`Bounds`](https://docs.interop.io/browser/reference/javascript/windows/bounds/index.md) object specifying default bounds for opening a new window or an app instance. |
| `windowResponseTimeout` | `number` | Sets the timeout in milliseconds that the io.Connect library will wait for a valid success response from the target window after the io.Connect library has been initialized and a window operation is being executed on the window object (e.g., `myWindow.moveTo(200, 200)`). If no response has been received within this period, the io.Connect library will assume that either the window isn't interop-enabled, or io.Connect hasn't been initialized yet. > ⚠️ *Note that this timeout is valid only for operations on the window object - it doesn't affect an `io.windows.open()` call, for example.*  |

## Opening Windows

To open a new io.Connect Window, use the [`open()`](https://docs.interop.io/browser/reference/javascript/windows/api/index.md#API-open) method:

```javascript
const name = "io-connect-docs";
const url = "https://docs.interop.io";
// Specify location for the new window.
const options = {
    top: 200,
    left: 200
};

const ioWindow = await io.windows.open(name, url, options);
```

The `name` and `url` parameters are required. The window `name` must be unique. The third parameter is an optional [`Settings`](https://docs.interop.io/browser/reference/javascript/windows/settings/index.md) object which specifies various settings for the new io.Connect Window - bounds, relative position and context.

> ℹ️ *For more details on all available settings when opening a new io.Connect Window, see the [Window Settings](#window_settings) section.*

### Opening PDF Files

To open a PDF file in an io.Connect Window, use the [`open()`](https://docs.interop.io/browser/reference/javascript/windows/api/index.md#API-open) method. Pass the URL to the PDF file and optionally specify parameters in the URL for opening the PDF file:

```javascript
// This will open the PDF file with the PDF toolbar turned off.
const PDF_URL = "https://url-to-pdf.com/file-name.pdf#toolbar=0";

await io.windows.open("PDF File", PDF_URL);
```

To specify parameters in the URL, use the following template:

```cmd
<URL to PDF file>#<parameter>=<value>
```

To specify multiple parameters in the URL, use `&` to separate them:

```cmd
<URL to PDF file>#<parameter>=<value>&<parameter>=<value>&<parameter>=<value>
```

> ⚠️ *Note that `#`, `&` and `=` are special characters which you must not use in parameter values because they can't be escaped.*

The following example will display page 3 of the PDF file, hide the PDF toolbar, set the zoom factor to 150% and scroll the page vertically and horizontally by 100px (pixels are relative to the zoom factor):

```javascript
const PDF_URL = "https://url-to-pdf.com/file-name.pdf#page=3&toolbar=0&zoom=150,100,100";

await io.windows.open("PDF File", PDF_URL);
```

The following table lists all supported URL parameters for opening PDF files:

| Parameter | Description | Examples |
|-----------|-------------|----------|
| `page` | Specifies which page to display. Accepts an integer as a value. The first page of the document has a value of 1. | To open the PDF file to page 3, use `page=3`. |
| `toolbar` | Whether to enable or disable the PDF toolbar. Accepts 0 or 1 as values. | To hide the PDF toolbar, use `toolbar=0`. |
| `view` | Specifies the view mode of the page using values defined in the PDF language specification. See the possible values in the next table. Use the `page` parameter before `view`. | To fit the page in the window, use `view=Fit`. To fit the page vertically, use `view=FitV`. To fit the page horizontally and scroll it 200px vertically, use `view=FitH,200`. |
| `zoom` | Specifies the zoom factor and also the vertical and horizontal scroll position of the page in regard to the top left corner of the window. Accepts integer or floating point values. | To set the zoom factor to 150.5%, use `zoom=150.5`. To set the zoom factor to 120% and scroll the page 200px vertically and 100px horizontally, use `zoom=120,200,100`.

The following table lists the possible values for the `view` parameter:

| Value | Description | Example |
|-------|-------------|---------|
| `Fit` | Fits the entire page horizontally and vertically in the window. If the vertical and horizontal magnification factors are different, the smaller one will be used for fitting the page. In the other dimension the page will be centered. | `view=Fit` |
| `FitH` | Fits the page horizontally in the window. | `view=FitH` |
| `FitH,<top>` | Fits the page horizontally and scrolls it vertically from the top edge of the window with the specified integer or floating point value. | `view=FitH,200` |
| `FitV` | Fits the page vertically in the window. | `view=FitV` |
| `FitV,<left>` | Fits the page vertically and scrolls it horizontally from the left edge of the window with the specified integer or floating point value. | `view=FitV,200` |

## Finding Windows

All functions for finding io.Connect Windows return a [`WebWindow`](https://docs.interop.io/browser/reference/javascript/windows/webwindow/index.md) object (or a collection of such objects).

### Listing

To obtain a collection of all io.Connect Windows, use the [`list()`](https://docs.interop.io/browser/reference/javascript/windows/api/index.md#API-list) method:

```javascript
const allWindows = io.windows.list();
```

### Current Window

To get a reference to the current window, use the [`my()`](https://docs.interop.io/browser/reference/javascript/windows/api/index.md#API-my) method:

```javascript
const currentWindow = io.windows.my();
```

### By ID

To find a window by ID, use the [`findById()`](https://docs.interop.io/browser/reference/javascript/windows/api/index.md#API-findById) method:

```javascript
const ID = "2506_04";
const ioWindow = io.windows.findById(ID);
```

## Window Settings

Provide window settings per window by passing a [`Settings`](https://docs.interop.io/browser/reference/javascript/windows/settings/index.md) object to the [`open()`](https://docs.interop.io/browser/reference/javascript/windows/api/index.md#API-open) method:

```javascript
const name = "io-connect-docs";
const url = "https://docs.interop.io";
// Specify location for the new window.
const options = {
    height: 640,
    width: 560,
    left: 100,
    top: 100,
    context: { io: 42 }
};

const ioWindow = await io.windows.open(name, url, options);
```

The [`Settings`](https://docs.interop.io/browser/reference/javascript/windows/settings/index.md) object has the following properties:

| Property | Type | Description |
|----------|------|-------------|
| `context` | `object` | Context data for the new window. |
| `height` | `number` | Window height in pixels. |
| `left` | `number` | Distance of the top left window corner from the left edge of the screen in pixels. |
| `relativeDirection` | `"bottom"` \| `"top"` \| `"left"` \| `"right"` | Direction for positioning the window relatively to the `relativeTo` window. Considered only if `relativeTo` is supplied. |
| `relativeTo` | `string` | The ID of the window that will be used to relatively position the new window. Can be combined with `relativeDirection`. |
| `top` | `number` | Distance of the top left window corner from the top edge of the screen in pixels. |
| `width` | `number` | Window width in pixels. |

### Relative Position

Position a new io.Connect Window relatively to an already existing io.Connect Window by providing the ID of the existing window and the relative direction:

```javascript
const clientsWindow = io.windows.findById("3HI0hHjdSq");

const name = "clientportfolio";
const url = "http://localhost:22080/clientportfolio/index.html";
// Provide the existing window ID and the relative direction.
const options = {
    relativeTo: clientsWindow.id,
    relativeDirection: "right"
};

await io.windows.open(name, url, options);
```

## Window Operations

The Window Management API enables you to control a [`WebWindow`](https://docs.interop.io/browser/reference/javascript/windows/webwindow/index.md) instance programmatically. Access or change various window settings using the provided properties and methods.

### Title

To get the title of an io.Connect Window, use the [`getTitle()`](https://docs.interop.io/browser/reference/javascript/windows/webwindow/index.md#WebWindow-getTitle) method of a [`WebWindow`](https://docs.interop.io/browser/reference/javascript/windows/webwindow/index.md) instance:

```javascript
const winTitle = await myWindow.getTitle();
```

To set the title of a window, use the [`setTitle()`](https://docs.interop.io/browser/reference/javascript/windows/webwindow/index.md#WebWindow-setTitle) method:

```javascript
await myWindow.setTitle("New Title");
```

### URL

To get the URL of an io.Connect Window, use the [`getURL()`](https://docs.interop.io/browser/reference/javascript/windows/webwindow/index.md#WebWindow-getURL) method of a [`WebWindow`](https://docs.interop.io/browser/reference/javascript/windows/webwindow/index.md) instance:

```javascript
const winURL = await myWindow.getURL();
```

### Bounds

The bounds of a window describe its position (top and left coordinates) and size (width and height) on the screen.

To get the bounds of an io.Connect Window, use the [`getBounds()`](https://docs.interop.io/browser/reference/javascript/windows/webwindow/index.md#WebWindow-getBounds) method of a [`WebWindow`](https://docs.interop.io/browser/reference/javascript/windows/webwindow/index.md) instance:

```javascript
const winBounds = await myWindow.getBounds();
```

To move or resize an io.Connect Window, use the [`moveTo()`](https://docs.interop.io/browser/reference/javascript/windows/webwindow/index.md#WebWindow-moveTo), [`resizeTo()`](https://docs.interop.io/browser/reference/javascript/windows/webwindow/index.md#WebWindow-resizeTo) or [`moveResize()`](https://docs.interop.io/browser/reference/javascript/windows/webwindow/index.md#WebWindow-moveResize) methods.

To move a window:

```javascript
// Top and left coordinates (in pixels) for the top-left window corner.
await myWindow.moveTo(200, 300);
```

To resize a window:

```javascript
// Width and height (in pixels) for the window.
await myWindow.resizeTo(300, 400);
```

To move and/or resize a window:

```javascript
// New bounds for the window. All properties are optional.
const bounds = {
    top: 200,
    left: 300,
    width: 300,
    height: 400
};

await myWindow.moveResize(bounds);
```

> ⚠️ *Note that programmatically moving and resizing the window of the [Main app](https://docs.interop.io/browser/developers/browser-platform/overview/index.md) isn't possible.*

### Focus

To bring a window on focus, use the  [`focus()`](https://docs.interop.io/browser/reference/javascript/windows/webwindow/index.md#WebWindow-focus) method:

```javascript
await myWindow.focus();
```

> ⚠️ *Note that programmatically focusing the window of the [Main app](https://docs.interop.io/browser/developers/browser-platform/overview/index.md) isn't possible.*

### Close

To close an io.Connect Window, use the [`close()`](https://docs.interop.io/browser/reference/javascript/windows/webwindow/index.md#WebWindow-close) method of a [`WebWindow`](https://docs.interop.io/browser/reference/javascript/windows/webwindow/index.md) instance:

```javascript
await myWindow.close();
```

> ⚠️ *Note that programmatically closing the window of the [Main app](https://docs.interop.io/browser/developers/browser-platform/overview/index.md) isn't possible.*

### Zoom

Available since io.Connect Browser 4.1

To retrieve the zoom factor of an io.Connect Window, use the `zoomFactor` property of a [`WebWindow`](https://docs.interop.io/browser/reference/javascript/windows/webwindow/index.md) instance:

```javascript
const zoomFactor = myWindow.zoomFactor;
```

Use the [`zoomIn()`](https://docs.interop.io/browser/reference/javascript/windows/webwindow/index.md#WebWindow-zoomIn), [`zoomOut()`](https://docs.interop.io/browser/reference/javascript/windows/webwindow/index.md#WebWindow-zoomOut) and [`setZoomFactor()`](https://docs.interop.io/browser/reference/javascript/windows/webwindow/index.md#WebWindow-zoomOut) methods to change the window zoom factor.

To increment or decrement the zoom factor by one step:

```javascript
// Zoom in by one step.
await myWindow.zoomIn();

// Zoom out by one step.
await myWindow.zoomOut();
```

To set the zoom factor:

```javascript
await myWindow.setZoomFactor(125);
```

> ⚠️ *Note that if your app logic includes both zooming a window and retrieving its size with the `window.innerHeight` or `window.innerWidth` DOM properties, you have to consider the fact that the browser will report adjusted size values based on the zoom factor. In such cases, it's recommended to use `window.outerHeight` and `window.outerWidth`, or the [`getBounds()`](https://docs.interop.io/browser/reference/javascript/windows/webwindow/index.md#WebWindow-getBounds) method of a [`WebWindow`](https://docs.interop.io/browser/reference/javascript/windows/webwindow/index.md) instance.*

## Context

Each io.Connect Window has a dedicated [context](https://docs.interop.io/browser/capabilities/data-sharing/shared-contexts/index.md). The window context is a JavaScript object which may contain any information regarding the window instance in the form of key/value pairs.

Contexts can be set initially on window creation and updated dynamically. Context changes can be tracked by subscribing to an event which fires when the window context has been updated (see [Window Events](#window_events)).

> ⚠️ *Note that saving large volumes of custom data as window context (e.g., thousands of lines of table data) can lead to significant delays. A user usually has several (in some cases - many) running apps and/or Workspaces (which can also contain many apps) and if one or more of the apps saves large amounts of context data, this will significantly slow down the saving process (e.g., on shutdown or when saving a layout). Saving custom context works best with smaller amounts of data. If your app needs to save large amounts of data, you have to think about how to design this process better - for instance, you may store IDs, indices, etc., as context data, save the actual data to a database and when you restore the app, fetch the data using the data IDs saved as window context.*

### Get

To get the context of an io.Connect Window, use the [`getContext()`](https://docs.interop.io/browser/reference/javascript/windows/webwindow/index.md#WebWindow-getContext) method of a [`WebWindow`](https://docs.interop.io/browser/reference/javascript/windows/webwindow/index.md) instance:

```javascript
const winContext = await myWindow.getContext();
```

### Update

To update the context of an io.Connect Window, use the [`updateContext()`](https://docs.interop.io/browser/reference/javascript/windows/webwindow/index.md#WebWindow-updateContext) method of a [`WebWindow`](https://docs.interop.io/browser/reference/javascript/windows/webwindow/index.md) instance:

```javascript
const newContext = { io: 42 };

await myWindow.udpateContext(newContext);
```

This method will update the current context object with the provided properties and values, adding any new properties and updating the values of existing ones.

### Set

To open an io.Connect Window with initially set context, use the `context` property of the [`Settings`](https://docs.interop.io/browser/reference/javascript/windows/settings/index.md) object:

```javascript
const name = "io-connect-docs";
const url = "https://docs.interop.io";
// Specify window context.
const options = {
    context: { io: 42 }
};

const ioWindow = await io.windows.open(name, url, options);
```

To replace the current window context, use the [`setContext()`](https://docs.interop.io/browser/reference/javascript/windows/webwindow/index.md#WebWindow-setContext) method of a [`WebWindow`](https://docs.interop.io/browser/reference/javascript/windows/webwindow/index.md) instance:

```javascript
const newContext = { io: 42 };
const winContext = await myWindow.setContext(newContext);
```

This method will completely overwrite the existing context object, replacing its current value with the specified one.

## Window Events

Methods for tracking io.Connect Window events are available at top-level of the Window Management API and on the [`WebWindow`](https://docs.interop.io/browser/reference/javascript/windows/webwindow/index.md) instance. The following sections describe the available window events with examples of how to handle them.

> ℹ️ *The window event methods return an unsubscribe function which you can use to stop tracking the respective event.*

### Window Added or Removed

To track the opening and closing of io.Connect Windows, use the [`onWindowAdded()`](https://docs.interop.io/browser/reference/javascript/windows/api/index.md#API-onWindowAdded) and [`onWindowRemoved()`](https://docs.interop.io/browser/reference/javascript/windows/api/index.md#API-onWindowRemoved) methods of the Window Management API and pass handlers for the respective events:

```javascript
const handlers = {
    onAdded: (ioWindow) => {
        console.log(`Window added: ${ioWindow.name}`);
    },

    onRemoved: (ioWindow) => {
        console.log(`Window removed: ${ioWindow.name}`);
    }
};

io.windows.onWindowAdded(handlers.onAdded);
io.windows.onWindowRemoved(handlers.onRemoved);
```

### Context Update

To track updates of the context of an io.Connect Window, use the [`onContextUpdated()`](https://docs.interop.io/browser/reference/javascript/windows/webwindow/index.md#WebWindow-onContextUpdated) method of a [`WebWindow`](https://docs.interop.io/browser/reference/javascript/windows/webwindow/index.md) instance and pass an event handler:

```javascript
const contextUpdatedHandler = (context, ioWindow) => {
    console.log(`The context of "${ioWindow.name}" has been updated: ${JSON.stringify(context)}`);
};

myWindow.onContextUpdated(contextUpdatedHandler);
```

## Live Examples

### Opening Windows

The following app demonstrates opening a new window with basic configuration (context and size) by using the [`open()`](https://docs.interop.io/browser/reference/javascript/windows/api/index.md#API-open) method of the Window Management API.

Use the input fields in App A to assign a name (required) to the new window and set the window context and size. Click the "Open Window" button to open a new window.

<div class="d-flex">
    <iframe src="https://jp8hk.csb.app" style="border: none;"></iframe>
</div>

### Window Events

The following apps demonstrate handling window events - opening and closing windows.

On load, App A and App B subscribe for the [`onWindowAdded()`](https://docs.interop.io/browser/reference/javascript/windows/api/index.md#API-onWindowAdded) and the [`onWindowRemoved()`](https://docs.interop.io/browser/reference/javascript/windows/api/index.md#API-onWindowRemoved) events of the Window Management API and will print to the page every time a new window is opened or an existing window is closed.

Open several new windows by using the input fields in App A to assign a name (required) to the new window and set the window context and size. Click the "Open Window" button to open a new window.

<div class="d-flex mb-3">
    <iframe src="https://6wgpf.csb.app" style="border: none;"></iframe>
</div>

## API Reference

For a complete list of the available Window Management API methods and properties, see the [Window Management API Reference Documentation](https://docs.interop.io/browser/reference/javascript/windows/api/index.md).
