namespace SmartBusiness.Web.Components { /** * Types macros */ type IHistoryState = SVGLD.IHistoryState; type IEditorState = SVGLD.IEditorState; export class SVGLayoutDesigner extends Components.ComponentBase { public constructor(componentInfo: KnockoutComponentTypes.ComponentInfo, params: any) { super(componentInfo, params); } /** * Return the HTML component handling the editor */ public GetEditorComponent() { const component = this.$component[0] .querySelector('iframe') .contentDocument .querySelector('.Editor'); if (component === undefined) { throw new Error('[SVGLD] Cannot hook the event because the editor is not yet open') } return component; } /** * Return the root HTML component of the SmartComponent * In the iframe, it would be the document. */ public GetRootComponent() { return this.$component[0] .querySelector('iframe') .contentDocument; } /// Custom Events /// /** * Return in a callback the current state in the history of the editor * @param callback */ public GetCurrentHistoryState(callback: (state: IHistoryState) => void) { const eventType = 'getCurrentHistoryState'; this.AddEventListener(callback, eventType); const component = this.GetEditorComponent(); component.dispatchEvent(new CustomEvent(eventType)); } /** * Return in a callback the current state of the editor * @param callback */ public GetEditorState(callback: (state: IEditorState) => void) { const eventType = 'getEditorState'; this.AddEventListener(callback, eventType); const component = this.GetEditorComponent(); component.dispatchEvent(new CustomEvent(eventType)); } /** * Set the current history of the editor * @param history Whole history of the editor * @param callback (optional) */ public SetEditorState(history: .IHistoryState[], callback?: (state: IEditorState) => void) { const eventType = 'setEditorState'; this.AddEventListener(callback, eventType); const component = this.GetEditorComponent(); component.dispatchEvent(new CustomEvent(eventType, { detail: history })); } /** * Revive the references in the editor state by mutation * Useful after using JSON.stringify with a replacer * @param editorState Editor state to revive * @param callback Callback with the revived state */ public ReviveEditorState(editorState: .IEditorState, callback: (state: IEditorState) => void) { const eventType = 'reviveEditorState'; this.AddEventListener(callback, eventType); const component = this.GetEditorComponent(); component.dispatchEvent(new CustomEvent(eventType, { detail: editorState })); } /** * Revive the references in the history by mutation * Useful after using JSON.stringify with a replacer * @param history History to revive * @param callback Callback with the revived state */ public ReviveHistory(history: .IHistoryState[], callback: (state: IHistoryState[]) => void) { const eventType = 'reviveHistory'; this.AddEventListener(callback, eventType); const component = this.GetEditorComponent(); component.dispatchEvent(new CustomEvent(eventType, { detail: history })); } /** * Add a new state to the editor * @param historyState New history state to append * @param callback */ public AppendNewHistoryState(historyState: .IHistoryState, callback?: (state: IEditorState) => void) { const eventType = 'appendNewState'; this.AddEventListener(callback, eventType); this.GetEditorComponent().dispatchEvent(new CustomEvent(eventType, { detail: historyState })); } /** * Create a new container at the given index position in a given parent container * @param index Position to insert the container * @param type Container type to create * @param parentId Parent container of the new container * @param callback */ public AddContainer(index: number, type: string, parentId: string, callback?: (state: IEditorState) => void) { const eventType = 'addContainer'; this.AddEventListener(callback, eventType); const detail = { index, type, parentId } this.GetEditorComponent().dispatchEvent(new CustomEvent(eventType, { detail })); } /** * Create a new container at the given index position in the current selected container * @param index Position to insert the container * @param type Container type to create * @param callback */ public AddContainerToSelectedContainer(index: number, type: string, callback?: (state: IEditorState) => void) { const eventType = 'addContainerToSelectedContainer'; this.AddEventListener(callback, eventType); const detail = { index, type } this.GetEditorComponent().dispatchEvent(new CustomEvent(eventType, { detail })); } /** * Append a new container in a given parent container * @param type Container type to create * @param parentId Parent container of the new container * @param callback */ public AppendContainer(type: string, parentId: string, callback?: (state: IEditorState) => void) { const eventType = 'appendContainer'; this.AddEventListener(callback, eventType); const detail = { type, parentId } this.GetEditorComponent().dispatchEvent(new CustomEvent(eventType, { detail })); } /** * Append a new container in the current selected container * @param type Container type to create * @param callback */ public AppendContainerToSelectedContainer(type: string, callback?: (state: IEditorState) => void) { const eventType = 'appendContainerToSelectedContainer'; this.AddEventListener(callback, eventType); const detail = { type } this.GetEditorComponent().dispatchEvent(new CustomEvent(eventType, { detail })); } /** * Select a container by id * @param containerId Container's id to select * @param callback */ public SelectContainer(containerId: string, callback?: (state: IEditorState) => void) { const eventType = 'selectContainer'; this.AddEventListener(callback, eventType); const detail = { containerId } this.GetEditorComponent().dispatchEvent(new CustomEvent(eventType, { detail })); } /** * Delete a container by id * @param containerId Container's id to delete * @param callback */ public DeleteContainer(containerId: string, callback?: (state: IEditorState) => void) { const eventType = 'deleteContainer'; this.AddEventListener(callback, eventType); const detail = { containerId } this.GetEditorComponent().dispatchEvent(new CustomEvent(eventType, { detail })); } /** * Create a new symbol * @param name Name of the symbol present in the config * @param callback */ public AddSymbol(name: string, callback?: (state: IEditorState) => void) { const eventType = 'addSymbol'; this.AddEventListener(callback, eventType); const detail = { name } this.GetEditorComponent().dispatchEvent(new CustomEvent(eventType, { detail })); } /** * Select a symbol by id * @param symbolId Symbol's id to select * @param callback */ public SelectSymbol(symbolId: string, callback?: (state: IEditorState) => void) { const eventType = 'selectSymbol'; this.AddEventListener(callback, eventType); const detail = { symbolId } this.GetEditorComponent().dispatchEvent(new CustomEvent(eventType, { detail })); } /** * Delete a symbol by id * @param symbolId Symbol's id to delete * @param callback */ public DeleteSymbol(symbolId: string, callback?: (state: IEditorState) => void) { const eventType = 'deleteSymbol'; this.AddEventListener(callback, eventType); const detail = { symbolId } this.GetEditorComponent().dispatchEvent(new CustomEvent(eventType, { detail })); } /** * Add the a new event listener that will be delete on call, * optionnally call a callback * @param callback Callback function to call in the event listener * @param eventType Event type for the listener to listen to */ private AddEventListener(callback: ((...args: any[]) => void) | undefined, eventType: string) { const root = this.GetRootComponent(); const listener = (e: CustomEvent) => { e.target.removeEventListener(e.type, listener); callback && callback(e.detail); }; root.addEventListener(eventType, listener); } } ko.components.register('svg-layout-designer', { viewModel: { createViewModel: function (params, componentInfo) { return new SmartBusiness.Web.Components.SVGLayoutDesigner(componentInfo, params); } }, template: { element: 'svg-layout-designer' } }); }