import { ProtoframePubsub } from 'protoframe'; import { iframeResizer } from 'iframe-resizer'; import { protocol, Protocol } from './protocol'; import { Deferred } from 'deferred'; export { protocol } from './protocol'; interface Filler { container: HTMLElement; iframe: HTMLIFrameElement; client: ProtoframePubsub; } type EventHandler = ( name: string, params: Array ) => void; type FillerHandle = string; // eslint-disable-next-line @typescript-eslint/no-unused-vars let fillerUrl: string; let fillers: Map; /** * Initializes the API. * * @param url Absolute url of the filler component */ export function init(url: string) { fillerUrl = url; fillers = new Map(); } /** * Creates filler component inside container HTML element. * Use options to specify additional parameters. * Filler will be fully initialized after this async call finished. * * Filler will take 100% width and 100% height of the container. * * @param container HTML container element * @param options Additional options * @returns Handle to the filler */ export async function createFiller( container: HTMLElement, options?: { hideMenu?: boolean; autoresize?: boolean; onEvent?: EventHandler; id?: string; templateId?: string; } ) { checkInitialized(); const url = new URL(fillerUrl); if (options?.hideMenu) { url.searchParams.append('hideMenu', '1'); url.searchParams.append('backgroundColor', 'transparent'); } if (options?.id !== undefined) { url.searchParams.append('id', options.id); } if (options?.templateId !== undefined) { url.searchParams.append('templateId', options.templateId); } const iframe = document.createElement('iframe'); iframe.src = url.toString(); iframe.width = '100%'; if (!options?.autoresize) { iframe.height = '100%'; } iframe.frameBorder = '0'; container.appendChild(iframe); const client = ProtoframePubsub.parent(protocol, iframe); // use onEvent handler if provided client.handleTell('signalAppEvent', ({ name, params }) => { options?.onEvent?.(name, params); }); const result = new Deferred(); client.handleTell('signalReady', async () => { console.log('signalReady received'); await ProtoframePubsub.connect(client); if (options?.autoresize) { iframeResizer({ log: false }, iframe); } const handle = String(fillers.size); const filler: Filler = { container, iframe, client }; fillers.set(handle, filler); result.resolve(handle); }); return result.promise; } /** * Destroys filler component. * Removes the component from the DOM and severe the connection to the filler. * * @param handle Handle to the filler */ export function destroyFiller(handle: FillerHandle) { checkInitialized(); const filler = getFiller(handle); filler.container.removeChild(filler.iframe); fillers.delete(handle); } /** * Opens a form provided as Buffer to the API. * * Name must end with *.fo or *.zfo extension. * * @param handle Handle to the filler * @param data Buffer with form data * @param name Name of the form. */ export async function openForm( handle: FillerHandle, data: Buffer, name: string ) { checkInitialized(); const filler = getFiller(handle); await filler.client.ask('openForm', { data, name }); } export function sendAppEvent( handle: FillerHandle, name: string, params: Array ) { checkInitialized(); const filler = getFiller(handle); filler.client.tell('sendAppEvent', { name, params }); } /** * Sets data to the filler. * * @param handle Handle to the filler * @param data Data to be set * @param path Path to the data */ export function setDataPart(handle: FillerHandle, path: string, data: string) { checkInitialized(); const filler = getFiller(handle); filler.client.tell('setData', { data, path }); } /** * Gets data from the filler. * * @param handle Handle to the filler * @param path Path to the data * @returns Data from the filler * @throws Error if filler is not initialized */ export async function getDataPart(handle: FillerHandle, path: string) { checkInitialized(); const filler = getFiller(handle); const { data } = await filler.client.ask('getDataPart', { path }); return data; } function checkInitialized() { if (fillerUrl === undefined) { throw new Error('Form filler api is not initialized.'); } } function getFiller(handle: FillerHandle) { const filler = fillers.get(handle); if (filler === undefined) { throw new Error(`Can not find form filler with handle ${handle}.`); } return filler; }