Web Components Dock Manager Desktop Integration

    O componente Infragistics Web Components Dock Manager pode ser usado em um aplicativo de desktop Electron de várias janelas para gerenciar o layout de cada janela, arrastar painéis para fora de uma janela para criar uma nova janela e arrastar/soltar painéis de uma janela para outra. Você pode encontrar um exemplo de implementação desse aplicativo no repositório a seguir https://github.com/IgniteUI/dock-manager-electron-app.

    Web Components Dock Manager desktop integration

    Implementation

    Vamos passar pelas partes mais importantes da implementação deste aplicativo.

    Project Structure

    Usamos a ferramenta Electron Forge CLI e seu modelo Typescript + Webpack para criar um aplicativo Electron. O Electron tem dois tipos de processos: Main e Renderer.

    • O processo Main cria páginas da Web criando instâncias de BrowserWindow. Cada instância de BrowserWindow executa a página da Web em seu processo de renderização.
    • O processo do Renderizador gerencia apenas a página da Web correspondente.

    O script index.ts especifica o ponto de entrada do aplicativo Electron que executará o processo Main. A maior parte do código do nosso aplicativo está dentro do arquivo renderer.ts que é executado no processo Renderer. O index.html representa o conteúdo da página da web. Os estilos da página da Web são hospedados no arquivo index.css.

    Dock Manager Setup

    Depois de instalar o pacote do Dock Manager, registramos o componente do Dock Manager usando o defineCustomElements() no arquivo renderer.ts. Isso permite adicionar ono arquivo index.html.

    Para o conteúdo do painel do Dock Manager, usamos elementos iframe que hospedam URLs diferentes. No nosso caso, esses urls apontam para Ignite UI for Angular exemplos. Como os elementos iframe são independentes, movê-los de uma janela para outra é facilmente realizado.

    Drag and drop

    Para oferecer suporte ao arrastar painéis para fora da janela do aplicativo, substituímos o arrastar / soltar interno que cria painéis flutuantes no aplicativo por uma implementação personalizada com base na API HTML Drag and Drop. Assinamos os PaneHeaderConnected eventos and TabHeaderConnected que são disparados quando um elemento de cabeçalho é conectado ao DOM. Quando um elemento de cabeçalho é conectado, redefinimos os ouvintes internos dragService e de anexação DragStart e DragEnd eventos.

    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);
    

    PaneHeaderDragStart Na função, definimos a draggedPane propriedade do componente Dock Manager, que o notificará de que uma operação de arrastar foi iniciada.

    const paneHeaderDragStart = async (pane: IgcContentPane, event: DragEvent) => {
        event.dataTransfer.dropEffect = 'move';
        dockManager.draggedPane = pane;
        // ...
    }
    

    Nós nos inscrevemos nos DragOver eventos and drop do document elemento. DragOver No ouvinte, notificamos o Dock Manager de que o mouse é arrastado sobre ele definindo sua dropPosition propriedade). Isso força o Dock Manager a exibir seus indicadores de encaixe.

    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);
    

    paneHeaderDragEnd Na função, detectamos se o painel foi descartado fora da janela do aplicativo e chamamos a droppedOutOfWindow função.

    const paneHeaderDragEnd = async (event: DragEvent) => {
        event.preventDefault();
        // ...
    
        // dropped outside of the application
        if (event.dataTransfer.dropEffect === 'none') {
            await droppedOutOfWindow(event);
        }
        // ...
    }
    

    Quando o cabeçalho do painel é solto dentro de um documento, chamamos o DropPane método que notifica o Dock Manager de que o painel arrastado foi descartado. Se o painel foi descartado em um indicador de encaixe, o método retornará true. Se o painel foi solto na mesma janela da qual foi arrastado, o painel será encaixado em sua nova posição automaticamente. No entanto, se ele foi descartado em outra janela, chamamos a droppedInAnotherWindow função que primeiro remove o painel do Dock Manager de origem e, em seguida, o adiciona ao novo.

    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();
            }
        }
    }
    

    Quando um painel é removido de sua janela atual, precisamos removê-lo draggedPane de seu componente Dock Manager e atualizar o layout.

    const draggedPane = dockManager.draggedPane as IgcContentPane;
    await dockManager.removePane(draggedPane);
    dockManager.layout = { ...dockManager.layout };
    

    Em seguida, precisamos mover o elemento de conteúdo do painel para sua nova janela. Para isso, usamos o método document.adoptNode(), que nos permite transferir o nó do elemento de conteúdo para o novo documento e, finalmente, anexá-lo como filho do novo componente do 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);
    

    Window Management

    Estamos usando o método nativo window.open() para abrir uma nova janela no processo do Renderizador. Definimos a nativeWindowOpen opção como true ao criar o BrowserWindow no index.ts. Isso nos dá acesso direto ao objeto filho Window e seu. document Você pode ler mais sobre como abrir janelas do processo Renderer neste tópico do Electron. Observe que a nativeWindowOpen opção ainda é experimental.

    mainWindow = new BrowserWindow({
        height: 800,
        width: 1000,
        webPreferences: {
            nativeWindowOpen: true
        }
    });
    

    Nesta aplicação, implementamos um IDockManagerWindow tipo que pode ser uma janela principal (IMainDockManagerWindow) ou uma janela filha (IChildDockManagerWindow). A janela principal é aquela criada quando o aplicativo é iniciado. Ele contém referências a todas as suas janelas filho. Uma janela filho é criada quando um painel é solto de uma janela e tem uma referência à janela principal do aplicativo.

    Para obter o código-fonte completo, clone o repositório.

    API References