Web Components Dock Manager Desktop Integration
El componente Infragistics Web Components Dock Manager se puede utilizar en una aplicación de escritorio Electron de múltiples ventanas para administrar el diseño de cada ventana, arrastrar paneles fuera de una ventana para crear una nueva ventana y arrastrar/soltar paneles de una ventana a otra. Puede encontrar un ejemplo de implementación de dicha aplicación en el siguiente repositorio https://github.com/IgniteUI/dock-manager-electron-app.
Implementación
Repasemos las partes más importantes de la implementación de esta aplicación.
Estructura del proyecto
Hemos utilizado la herramienta CLI de Electron Forge y su plantilla Typecript + Webpack para crear una aplicación de Electron. Electron tiene dos tipos de procesos: principal y renderizador.
- El proceso principal crea páginas web mediante la creación de instancias de BrowserWindow. Cada instancia de BrowserWindow ejecuta la página web en su proceso de renderizado.
- El proceso Renderer gestiona solo la página web correspondiente.
El script index.ts especifica el punto de entrada de la aplicación Electron que ejecutará el proceso principal. La mayor parte del código de nuestra aplicación está dentro del archivo renderer.ts que se ejecuta en el proceso de Renderer. El index.html representa el contenido de la página web. Los estilos de la página web están alojados en el archivo index.css.
Configuración del administrador de muelle
Después de instalar el paquete Dock Manager, hemos registrado el componente Dock Manager usando defineCustomElements() en el archivo renderer.ts. Esto permite agregar el
Para el contenido del panel del Dock Manager, hemos utilizado elementos iframe que alojan diferentes URL. En nuestro caso, estas urls apuntan a muestras Ignite UI for Angular. Dado que los elementos iframe son autónomos, es fácil moverlos de una ventana a otra.
Arrastrar y soltar
Para admitir el arrastre de paneles fuera de la ventana de la aplicación, hemos reemplazado la función de arrastrar y soltar incorporada que crea paneles flotantes en la aplicación con una implementación personalizada basada en la API HTML de arrastrar y soltar. Nos hemos suscrito a los eventos PaneHeaderConnected
y TabHeaderConnected
que se activan cuando un elemento de encabezado se conecta al DOM. Cuando se conecta un elemento de encabezado, restablecemos el dragService
incorporado y adjuntamos los detectores de eventos DragStart
y DragEnd
.
const paneHeaderConnected = (event: CustomEvent<IgcPaneHeaderConnectionEventArgs>) => {
const element = event.detail.element;
element.dragService.destroy();
element.dragService = null;
element.draggable = true;
element.ondragstart = ev => {
paneHeaderDragStart(event.detail.pane, ev);
};
element.ondragend = ev => {
paneHeaderDragEnd(ev);
};
}
dockManager.addEventListener('paneHeaderConnected', paneHeaderConnected);
ts
En la función PaneHeaderDragStart
configuramos la propiedad draggedPane
del componente Dock Manager que le notificará que se ha iniciado una operación de arrastre.
const paneHeaderDragStart = async (pane: IgcContentPane, event: DragEvent) => {
event.dataTransfer.dropEffect = 'move';
dockManager.draggedPane = pane;
// ...
}
ts
Nos hemos suscrito a los eventos DragOver
y drop
del elemento del document
. En el oyente DragOver
notificamos al Dock Manager que el mouse se arrastra sobre él configurando su propiedad dropPosition
). Esto obliga al Dock Manager a mostrar sus indicadores de atraque.
const handleDocumentDragOver = (event: DragEvent) => {
event.preventDefault();
event.dataTransfer.dropEffect = 'move';
dockManager.dropPosition = {
x: event.clientX,
y: event.clientY
};
}
document.addEventListener('dragover', handleDocumentDragOver);
document.addEventListener('drop', handleDocumentDrop);
ts
En la función paneHeaderDragEnd
detectamos si el panel se soltó fuera de la ventana de la aplicación y llamamos a la función droppedOutOfWindow
.
const paneHeaderDragEnd = async (event: DragEvent) => {
event.preventDefault();
// ...
// dropped outside of the application
if (event.dataTransfer.dropEffect === 'none') {
await droppedOutOfWindow(event);
}
// ...
}
ts
Cuando el encabezado del panel se coloca dentro de un documento, llamamos al método DropPane
, que notifica al Dock Manager que el panel arrastrado se soltó. Si el panel se colocó en un indicador de acoplamiento, el método devuelve verdadero. Si el panel se soltó en la misma ventana desde la que se arrastró, el panel se acoplará a su nueva posición automáticamente. Sin embargo, si se colocó en otra ventana, llamamos a la función droppedInAnotherWindow
que primero elimina el panel del Dock Manager de origen y luego lo agrega al nuevo.
const handleDocumentDrop = async (event: DragEvent) => {
const contentId = (dockManager.draggedPane as IgcContentPane).contentId;
const docked = await dockManager.dropPane();
if (docked) {
const contentElement = dockManager.querySelector('[slot=' + contentId + ']');
// if the content element is missing from the current dock manager it means it comes from another window
if (!contentElement) {
await droppedInAnotherWindow();
}
}
}
ts
Cuando un panel se elimina de su ventana actual, debemos eliminar el draggedPane
de su componente Dock Manager y actualizar el diseño.
const draggedPane = dockManager.draggedPane as IgcContentPane;
await dockManager.removePane(draggedPane);
dockManager.layout = { ...dockManager.layout };
ts
A continuación, debemos mover el elemento de contenido del panel a su nueva ventana. Para este propósito, utilizamos el método document.adoptNode(), que nos permite transferir el nodo del elemento de contenido al nuevo documento y, finalmente, agregarlo como hijo del nuevo componente Dock Manager.
const contentElement = dockManager.querySelector('[slot=' + draggedPane.contentId + ']');
const newDocument = childWindow.document;
const newDockManager = newDocument.getElementById('dockManager') as IgcDockManagerComponent;
const adoptedNode = newDocument.adoptNode(contentElement);
newDockManager.appendChild(adoptedNode);
ts
Gestión de ventanas
Estamos utilizando el método nativo window.open() para abrir una nueva ventana en el proceso del Renderizador. Configuramos la opción nativeWindowOpen
en verdadero al crear BrowserWindow
en index.ts. Esto nos da acceso directo al objeto Window
hijo y su document
. Puede leer más sobre cómo abrir ventanas desde el proceso del Renderizador en este tema de Electron. Tenga en cuenta que la opción nativeWindowOpen
aún es experimental.
mainWindow = new BrowserWindow({
height: 800,
width: 1000,
webPreferences: {
nativeWindowOpen: true
}
});
ts
En esta aplicación hemos implementado un tipo IDockManagerWindow
que podría ser una ventana principal (IMainDockManagerWindow
) o una ventana secundaria (IChildDockManagerWindow
). La ventana principal es la que se crea cuando se inicia la aplicación. Contiene referencias a todas sus ventanas secundarias. Una ventana secundaria se crea cuando un panel se elimina de una ventana y tiene una referencia a la ventana principal de la aplicación.
Para obtener el código fuente completo, clone el repositorio.