From 8da5bf9f8ec37037e83945d47305df2efe27d767 Mon Sep 17 00:00:00 2001 From: jonny Date: Sun, 9 May 2021 21:30:29 +0200 Subject: [PATCH] typed iframe api events # Conflicts: # front/src/Api/IframeListener.ts # front/src/iframe_api.ts --- front/src/Api/Events/IframeEvent.ts | 60 ++++++++++++++++++++-- front/src/Api/IframeListener.ts | 13 ++++- front/src/iframe_api.ts | 78 ++++++++++++++--------------- 3 files changed, 106 insertions(+), 45 deletions(-) diff --git a/front/src/Api/Events/IframeEvent.ts b/front/src/Api/Events/IframeEvent.ts index 883f50fc..18d88ed7 100644 --- a/front/src/Api/Events/IframeEvent.ts +++ b/front/src/Api/Events/IframeEvent.ts @@ -1,7 +1,59 @@ -export interface IframeEvent { - type: string; - data: unknown; + + +//import { GameStateEvent } from './ApiGameStateEvent'; +//import { UpdateTileEvent } from './ApiUpdateTileEvent'; +import { ButtonClickedEvent } from './ButtonClickedEvent'; +import { ChatEvent } from './ChatEvent'; +import { ClosePopupEvent } from './ClosePopupEvent'; +import { EnterLeaveEvent } from './EnterLeaveEvent'; +import { GoToPageEvent } from './GoToPageEvent'; +import { LoadPageEvent } from './LoadPageEvent'; +import { MenuItemClickedEvent } from './MenuItemClickedEvent'; +import { MenuItemRegisterEvent } from './MenuItemRegisterEvent'; +import { OpenCoWebSiteEvent } from './OpenCoWebSiteEvent'; +import { OpenPopupEvent } from './OpenPopupEvent'; +import { OpenTabEvent } from './OpenTabEvent'; +import { UserInputChatEvent } from './UserInputChatEvent'; + + +export type IframeEventMap = { + //getState: GameStateEvent, + // updateTile: UpdateTileEvent + chat: ChatEvent, + openPopup: OpenPopupEvent + closePopup: ClosePopupEvent + openTab: OpenTabEvent + goToPage: GoToPageEvent + openCoWebSite: OpenCoWebSiteEvent + closeCoWebSite: null + disablePlayerControl: null + restorePlayerControl: null + displayBubble: null + removeBubble: null + registerMenuCommand: MenuItemRegisterEvent + loadPage: LoadPageEvent +} +export interface IframeEvent { + type: T; + data: IframeEventMap[T]; +} + + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export const isIframeEventWrapper = (event: any): event is IframeEvent => typeof event.type === 'string'; + +export interface IframeResponseEventMap { + menuItemClicked: MenuItemClickedEvent + userInputChat: UserInputChatEvent + enterEvent: EnterLeaveEvent + leaveEvent: EnterLeaveEvent + buttonClickedEvent: ButtonClickedEvent + // gameState: GameStateEvent +} +export interface IframeResponseEvent { + type: T; + data: IframeResponseEventMap[T]; } // eslint-disable-next-line @typescript-eslint/no-explicit-any -export const isIframeEventWrapper = (event: any): event is IframeEvent => typeof event.type === 'string'; +export const isIframeResponseEventWrapper = (event: { type?: string }): event is IframeResponseEvent => typeof event.type === 'string'; \ No newline at end of file diff --git a/front/src/Api/IframeListener.ts b/front/src/Api/IframeListener.ts index 7e51a281..651869d7 100644 --- a/front/src/Api/IframeListener.ts +++ b/front/src/Api/IframeListener.ts @@ -12,6 +12,15 @@ import {ClosePopupEvent, isClosePopupEvent} from "./Events/ClosePopupEvent"; import {scriptUtils} from "./ScriptUtils"; import {GoToPageEvent, isGoToPageEvent} from "./Events/GoToPageEvent"; import {isOpenCoWebsite, OpenCoWebSiteEvent} from "./Events/OpenCoWebSiteEvent"; +import { IframeEventMap, IframeEvent, IframeResponseEvent, IframeResponseEventMap, isIframeEventWrapper } from "./Events/IframeEvent"; +import { isLoadPageEvent } from './Events/LoadPageEvent'; +import { MenuItemClickedEvent } from './Events/MenuItemClickedEvent'; +import { isMenuItemRegisterEvent } from './Events/MenuItemRegisterEvent'; +import { isOpenCoWebsite, OpenCoWebSiteEvent } from "./Events/OpenCoWebSiteEvent"; +import { isOpenPopupEvent, OpenPopupEvent } from "./Events/OpenPopupEvent"; +import { isOpenTabEvent, OpenTabEvent } from "./Events/OpenTabEvent"; +import { UserInputChatEvent } from "./Events/UserInputChatEvent"; +import { scriptUtils } from "./ScriptUtils"; /** @@ -56,7 +65,7 @@ class IframeListener { private readonly scripts = new Map(); init() { - window.addEventListener("message", (message) => { + window.addEventListener("message", (message: MessageEvent>) => { // Do we trust the sender of this message? // Let's only accept messages from the iframe that are allowed. // Note: maybe we could restrict on the domain too for additional security (in case the iframe goes to another domain). @@ -231,7 +240,7 @@ class IframeListener { /** * Sends the message... to all allowed iframes. */ - private postMessage(message: IframeEvent) { + private postMessage(message: IframeResponseEvent) { for (const iframe of this.iframes) { iframe.contentWindow?.postMessage(message, '*'); } diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index 18d8d172..6d0ef354 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -1,14 +1,14 @@ -import {ChatEvent, isChatEvent} from "./Api/Events/ChatEvent"; -import {isIframeEventWrapper} from "./Api/Events/IframeEvent"; -import {isUserInputChatEvent, UserInputChatEvent} from "./Api/Events/UserInputChatEvent"; -import {Subject} from "rxjs"; -import {EnterLeaveEvent, isEnterLeaveEvent} from "./Api/Events/EnterLeaveEvent"; -import {OpenPopupEvent} from "./Api/Events/OpenPopupEvent"; -import {isButtonClickedEvent} from "./Api/Events/ButtonClickedEvent"; -import {ClosePopupEvent} from "./Api/Events/ClosePopupEvent"; -import {OpenTabEvent} from "./Api/Events/OpenTabEvent"; -import {GoToPageEvent} from "./Api/Events/GoToPageEvent"; -import {OpenCoWebSiteEvent} from "./Api/Events/OpenCoWebSiteEvent"; +import { ChatEvent } from "./Api/Events/ChatEvent"; +import { isIframeResponseEventWrapper } from "./Api/Events/IframeEvent"; +import { isUserInputChatEvent, UserInputChatEvent } from "./Api/Events/UserInputChatEvent"; +import { Subject } from "rxjs"; +import { EnterLeaveEvent, isEnterLeaveEvent } from "./Api/Events/EnterLeaveEvent"; +import { OpenPopupEvent } from "./Api/Events/OpenPopupEvent"; +import { isButtonClickedEvent } from "./Api/Events/ButtonClickedEvent"; +import { ClosePopupEvent } from "./Api/Events/ClosePopupEvent"; +import { OpenTabEvent } from "./Api/Events/OpenTabEvent"; +import { GoToPageEvent } from "./Api/Events/GoToPageEvent"; +import { OpenCoWebSiteEvent } from "./Api/Events/OpenCoWebSiteEvent"; interface WorkAdventureApi { sendChatMessage(message: string, author: string): void; @@ -20,10 +20,10 @@ interface WorkAdventureApi { goToPage(url : string): void; openCoWebSite(url : string): void; closeCoWebSite(): void; - disablePlayerControl() : void; - restorePlayerControl() : void; - displayBubble() : void; - removeBubble() : void; + disablePlayerControl(): void; + restorePlayerControl(): void; + displayBubble(): void; + removeBubble(): void; } declare global { @@ -50,7 +50,7 @@ interface ButtonDescriptor { /** * The type of the button. Can be one of "normal", "primary", "success", "warning", "error", "disabled" */ - className?: "normal"|"primary"|"success"|"warning"|"error"|"disabled", + className?: "normal" | "primary" | "success" | "warning" | "error" | "disabled", /** * Callback called if the button is pressed */ @@ -88,38 +88,38 @@ window.WA = { } as ChatEvent }, '*'); }, - disablePlayerControl() : void { - window.parent.postMessage({'type' : 'disablePlayerControl'},'*'); + disablePlayerControl(): void { + window.parent.postMessage({ 'type': 'disablePlayerControl' }, '*'); }, - restorePlayerControl() : void { - window.parent.postMessage({'type' : 'restorePlayerControl'},'*'); + restorePlayerControl(): void { + window.parent.postMessage({ 'type': 'restorePlayerControl' }, '*'); }, - displayBubble() : void { - window.parent.postMessage({'type' : 'displayBubble'},'*'); + displayBubble(): void { + window.parent.postMessage({ 'type': 'displayBubble' }, '*'); }, - removeBubble() : void { - window.parent.postMessage({'type' : 'removeBubble'},'*'); + removeBubble(): void { + window.parent.postMessage({ 'type': 'removeBubble' }, '*'); }, - openTab(url : string) : void{ + openTab(url: string): void { window.parent.postMessage({ - "type" : 'openTab', - "data" : { + "type": 'openTab', + "data": { url } as OpenTabEvent - },'*'); + }, '*'); }, - goToPage(url : string) : void{ + goToPage(url: string): void { window.parent.postMessage({ - "type" : 'goToPage', - "data" : { + "type": 'goToPage', + "data": { url } as GoToPageEvent - },'*'); + }, '*'); }, openCoWebSite(url : string) : void{ @@ -128,13 +128,13 @@ window.WA = { "data" : { url } as OpenCoWebSiteEvent - },'*'); + }, '*'); }, - closeCoWebSite() : void{ + closeCoWebSite(): void { window.parent.postMessage({ - "type" : 'closeCoWebSite' - },'*'); + "type": 'closeCoWebSite' + }, '*'); }, openPopup(targetObject: string, message: string, buttons: ButtonDescriptor[]): Popup { @@ -205,9 +205,9 @@ window.addEventListener('message', message => { const payload = message.data; - console.log(payload); + console.debug(payload); - if (isIframeEventWrapper(payload)) { + if (isIframeResponseEventWrapper(payload)) { const payloadData = payload.data; if (payload.type === 'userInputChat' && isUserInputChatEvent(payloadData)) { userInputChatStream.next(payloadData); @@ -219,7 +219,7 @@ window.addEventListener('message', message => { const callback = popupCallbacks.get(payloadData.popupId)?.get(payloadData.buttonId); const popup = popups.get(payloadData.popupId); if (popup === undefined) { - throw new Error('Could not find popup with ID "'+payloadData.popupId+'"'); + throw new Error('Could not find popup with ID "' + payloadData.popupId + '"'); } if (callback) { callback(popup);