diff --git a/front/src/Api/Events/ClosePopupEvent.ts b/front/src/Api/Events/ClosePopupEvent.ts new file mode 100644 index 00000000..83b09c96 --- /dev/null +++ b/front/src/Api/Events/ClosePopupEvent.ts @@ -0,0 +1,11 @@ +import * as tg from "generic-type-guard"; + +export const isClosePopupEvent = + new tg.IsInterface().withProperties({ + popupId: tg.isNumber, + }).get(); + +/** + * A message sent from the iFrame to the game to add a message in the chat. + */ +export type ClosePopupEvent = tg.GuardedType; diff --git a/front/src/Api/IframeListener.ts b/front/src/Api/IframeListener.ts index f55a70bd..41a1efc2 100644 --- a/front/src/Api/IframeListener.ts +++ b/front/src/Api/IframeListener.ts @@ -7,6 +7,7 @@ import {HtmlUtils} from "../WebRtc/HtmlUtils"; import {EnterLeaveEvent} from "./Events/EnterLeaveEvent"; import {isOpenPopupEvent, OpenPopupEvent} from "./Events/OpenPopupEvent"; import {ButtonClickedEvent} from "./Events/ButtonClickedEvent"; +import {ClosePopupEvent, isClosePopupEvent} from "./Events/ClosePopupEvent"; @@ -21,6 +22,9 @@ class IframeListener { private readonly _openPopupStream: Subject = new Subject(); public readonly openPopupStream = this._openPopupStream.asObservable(); + private readonly _closePopupStream: Subject = new Subject(); + public readonly closePopupStream = this._closePopupStream.asObservable(); + private readonly iframes = new Set(); private readonly scripts = new Map(); @@ -46,6 +50,8 @@ class IframeListener { this._chatStream.next(payload.data); } else if (payload.type === 'openPopup' && isOpenPopupEvent(payload.data)) { this._openPopupStream.next(payload.data); + } else if (payload.type === 'closePopup' && isClosePopupEvent(payload.data)) { + this._closePopupStream.next(payload.data); } } diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 0a422ff8..de7abd46 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -764,7 +764,6 @@ ${escapedMessage} const btnId = id; button.onclick = () => { iframeListener.sendButtonClickedEvent(openPopupEvent.popupId, btnId); - console.log('BUTTON CLICKED', btnId); } id++; } @@ -778,34 +777,24 @@ ${escapedMessage} this.popUpElements.set(openPopupEvent.popupId, domElement); }); - /*this.gameMap.onPropertyChange('inGameConsoleMessage', (newValue, oldValue, allProps) => { - if (newValue !== undefined) { - this.popUpElement?.destroy(); - this.popUpElement = this.add.dom(2100, 150).createFromHTML(newValue as string); - this.popUpElement.scale = 0; - this.tweens.add({ - targets : this.popUpElement , - scale : 1, - ease : "EaseOut", - duration : 400, - }); - this.popUpElement.setClassName("popUpElement"); - - } else { - this.tweens.add({ - targets : this.popUpElement , - scale : 0, - ease : "EaseOut", - duration : 400, - onComplete : () => { - this.popUpElement?.destroy(); - this.popUpElement = undefined; - }, - }); + iframeListener.closePopupStream.subscribe((closePopupEvent) => { + const popUpElement = this.popUpElements.get(closePopupEvent.popupId); + if (popUpElement === undefined) { + console.error('Could not close popup with ID ', closePopupEvent.popupId,'. Maybe it has already been closed?'); } - });*/ + this.tweens.add({ + targets : popUpElement , + scale : 0, + ease : "EaseOut", + duration : 400, + onComplete : () => { + popUpElement?.destroy(); + this.popUpElements.delete(closePopupEvent.popupId); + }, + }); + }); } private onMapExit(exitKey: string) { diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index e72093e6..44a7f0ea 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -5,13 +5,14 @@ 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"; interface WorkAdventureApi { sendChatMessage(message: string, author: string): void; onChatMessage(callback: (message: string) => void): void; onEnterZone(name: string, callback: () => void): void; onLeaveZone(name: string, callback: () => void): void; - openPopup(targetObject: string, message: string, buttons: ButtonDescriptor[]): number; + openPopup(targetObject: string, message: string, buttons: ButtonDescriptor[]): Popup; } declare global { @@ -20,11 +21,13 @@ declare global { } type ChatMessageCallback = (message: string) => void; +type ButtonClickedCallback = (popup: Popup) => void; const userInputChatStream: Subject = new Subject(); const enterStreams: Map> = new Map>(); const leaveStreams: Map> = new Map>(); -const popupCallbacks: Map void>> = new Map void>>(); +const popups: Map = new Map(); +const popupCallbacks: Map> = new Map>(); let popupId = 0; interface ButtonDescriptor { @@ -39,13 +42,30 @@ interface ButtonDescriptor { /** * Callback called if the button is pressed */ - callback?: () => void, + callback?: ButtonClickedCallback, /** * If set to true, the popup is closed when the button is clicked */ closeOnClick?: boolean } +class Popup { + constructor(private id: number) { + } + + /** + * Closes the popup + */ + public close(): void { + window.parent.postMessage({ + 'type': 'closePopup', + 'data': { + 'popupId': this.id, + } as ClosePopupEvent + }, '*'); + } +} + window.WA = { /** @@ -61,8 +81,25 @@ window.WA = { } as ChatEvent }, '*'); }, - openPopup(targetObject: string, message: string, buttons: ButtonDescriptor[]): number { + openPopup(targetObject: string, message: string, buttons: ButtonDescriptor[]): Popup { popupId++; + + const popup = new Popup(popupId); + + const btnMap = new Map void>(); + popupCallbacks.set(popupId, btnMap); + + let id = 0; + for (const button of buttons) { + const callback = button.callback; + if (callback) { + btnMap.set(id, () => { + callback(popup); + }); + } + id++; + } + window.parent.postMessage({ 'type': 'openPopup', 'data': { @@ -78,7 +115,9 @@ window.WA = { }) } as OpenPopupEvent }, '*'); - return popupId; + + popups.set(popupId, popup) + return popup; }, /** * Listen to messages sent by the local user, in the chat. @@ -125,8 +164,12 @@ window.addEventListener('message', message => { leaveStreams.get(payloadData.name)?.next(); } else if (payload.type === 'buttonClickedEvent' && isButtonClickedEvent(payloadData)) { 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+'"'); + } if (callback) { - callback(); + callback(popup); } } } diff --git a/maps/tests/script.js b/maps/tests/script.js index 5d5f3c62..072f3f63 100644 --- a/maps/tests/script.js +++ b/maps/tests/script.js @@ -19,10 +19,8 @@ WA.onEnterZone('notExist', () => { WA.sendChatMessage("YOU SHOULD NEVER SEE THIS", 'Poly Parrot'); }) -let popupId; - WA.onEnterZone('popupZone', () => { - popupId = WA.openPopup('foobar', 'This is a test message. Hi!', [ + WA.openPopup('foobar', 'This is a test message. Hi!', [ { label: "Close", className: "normal", @@ -31,8 +29,8 @@ WA.onEnterZone('popupZone', () => { { label: "Next", className: "success", - callback: () => { - console.log('BUTTON CLICKED') + callback: (popup) => { + popup.close(); } } ])