diff --git a/docs/maps/api-ui.md b/docs/maps/api-ui.md index 13610fed..89d46932 100644 --- a/docs/maps/api-ui.md +++ b/docs/maps/api-ui.md @@ -93,7 +93,11 @@ WA.ui.registerMenuCommand("test", () => { ### Awaiting User Confirmation (with space bar) ``` -WA.ui.displayActionMessage(message: string, callback: () => void): ActionMessage +WA.ui.displayActionMessage({ + message: string, + callback: () => void, + type?: "message"|"warning", +}): ActionMessage ``` Displays a message at the bottom of the screen (that will disappear when space bar is pressed). @@ -105,8 +109,11 @@ Displays a message at the bottom of the screen (that will disappear when space b Example: ```javascript -const triggerMessage = WA.ui.displayActionMessage("press 'space' to confirm", () => { - WA.chat.sendChatMessage("confirmed", "trigger message logic") +const triggerMessage = WA.ui.displayActionMessage({ + message: "press 'space' to confirm", + callback: () => { + WA.chat.sendChatMessage("confirmed", "trigger message logic") + } }); setTimeout(() => { diff --git a/front/src/Api/Events/ui/TriggerActionMessageEvent.ts b/front/src/Api/Events/ui/TriggerActionMessageEvent.ts index 009ae3c7..48f1cae6 100644 --- a/front/src/Api/Events/ui/TriggerActionMessageEvent.ts +++ b/front/src/Api/Events/ui/TriggerActionMessageEvent.ts @@ -1,12 +1,17 @@ -import * as tg from 'generic-type-guard'; +import * as tg from "generic-type-guard"; -export const triggerActionMessage = 'triggerActionMessage'; -export const removeActionMessage = 'removeActionMessage'; +export const triggerActionMessage = "triggerActionMessage"; +export const removeActionMessage = "removeActionMessage"; + +export const isActionMessageType = tg.isSingletonStringUnion("message", "warning"); + +export type ActionMessageType = tg.GuardedType; export const isTriggerActionMessageEvent = new tg.IsInterface() .withProperties({ message: tg.isString, uuid: tg.isString, + type: isActionMessageType, }) .get(); diff --git a/front/src/Api/IframeListener.ts b/front/src/Api/IframeListener.ts index 379927e4..2ed65f15 100644 --- a/front/src/Api/IframeListener.ts +++ b/front/src/Api/IframeListener.ts @@ -417,6 +417,15 @@ class IframeListener { }); } + sendActionMessageTriggered(uuid: string): void { + this.postMessage({ + type: "messageTriggered", + data: { + uuid, + }, + }); + } + /** * Sends the message... to all allowed iframes. */ diff --git a/front/src/Api/iframe/Ui/ActionMessage.ts b/front/src/Api/iframe/Ui/ActionMessage.ts index cdc8ab3b..912603b9 100644 --- a/front/src/Api/iframe/Ui/ActionMessage.ts +++ b/front/src/Api/iframe/Ui/ActionMessage.ts @@ -1,10 +1,12 @@ import { + ActionMessageType, MessageReferenceEvent, removeActionMessage, triggerActionMessage, TriggerActionMessageEvent, } from "../../Events/ui/TriggerActionMessageEvent"; import { queryWorkadventure } from "../IframeApiContribution"; +import type { ActionMessageOptions } from "../ui"; function uuidv4() { return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => { const r = (Math.random() * 16) | 0, @@ -13,29 +15,29 @@ function uuidv4() { }); } -export let triggerMessageInstance: ActionMessage | undefined = undefined; - export class ActionMessage { - uuid: string; + public readonly uuid: string; + private readonly type: ActionMessageType; + private readonly message: string; + private readonly callback: () => void; - constructor(private message: string, private callback: () => void) { + constructor(actionMessageOptions: ActionMessageOptions, private onRemove: () => void) { this.uuid = uuidv4(); - if (triggerMessageInstance) { - triggerMessageInstance.remove(); - } - triggerMessageInstance = this; + this.message = actionMessageOptions.message; + this.type = actionMessageOptions.type ?? "message"; + this.callback = actionMessageOptions.callback; this.create(); } - async create() { + private async create() { await queryWorkadventure({ type: triggerActionMessage, data: { message: this.message, + type: this.type, uuid: this.uuid, } as TriggerActionMessageEvent, }); - this.callback(); } async remove() { @@ -45,6 +47,10 @@ export class ActionMessage { uuid: this.uuid, } as MessageReferenceEvent, }); - triggerMessageInstance = undefined; + this.onRemove(); + } + + triggerCallback() { + this.callback(); } } diff --git a/front/src/Api/iframe/ui.ts b/front/src/Api/iframe/ui.ts index 91f61381..ab5b2007 100644 --- a/front/src/Api/iframe/ui.ts +++ b/front/src/Api/iframe/ui.ts @@ -5,6 +5,7 @@ import { apiCallback } from "./registeredCallbacks"; import type { ButtonClickedCallback, ButtonDescriptor } from "./Ui/ButtonDescriptor"; import { Popup } from "./Ui/Popup"; import { ActionMessage } from "./Ui/ActionMessage"; +import { isMessageReferenceEvent } from "../Events/ui/TriggerActionMessageEvent"; let popupId = 0; const popups: Map = new Map(); @@ -14,6 +15,7 @@ const popupCallbacks: Map> = new Map< >(); const menuCallbacks: Map void> = new Map(); +const actionMessages = new Map(); interface ZonedPopupOptions { zone: string; @@ -23,6 +25,12 @@ interface ZonedPopupOptions { popupOptions: Array; } +export interface ActionMessageOptions { + message: string; + type?: "message" | "warning"; + callback: () => void; +} + export class WorkAdventureUiCommands extends IframeApiContribution { callbacks = [ apiCallback({ @@ -49,6 +57,16 @@ export class WorkAdventureUiCommands extends IframeApiContribution { + const actionMessage = actionMessages.get(event.uuid); + if (actionMessage) { + actionMessage.triggerCallback(); + } + }, + }), ]; openPopup(targetObject: string, message: string, buttons: ButtonDescriptor[]): Popup { @@ -104,8 +122,12 @@ export class WorkAdventureUiCommands extends IframeApiContribution void): ActionMessage { - return new ActionMessage(message, callback); + displayActionMessage(actionMessageOptions: ActionMessageOptions): ActionMessage { + const actionMessage = new ActionMessage(actionMessageOptions, () => { + actionMessages.delete(actionMessage.uuid); + }); + actionMessages.set(actionMessage.uuid, actionMessage); + return actionMessage; } } diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index b47d1e48..73ff907d 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -1150,21 +1150,17 @@ ${escapedMessage} }); }); - iframeListener.registerAnswerer( - "triggerActionMessage", - (message) => - new Promise((resolver) => { - layoutManagerActionStore.addAction({ - uuid: message.uuid, - type: "message", - message: message.message, - callback: () => { - layoutManagerActionStore.removeAction(message.uuid); - resolver(); - }, - userInputManager: this.userInputManager, - }); - }) + iframeListener.registerAnswerer("triggerActionMessage", (message) => + layoutManagerActionStore.addAction({ + uuid: message.uuid, + type: "message", + message: message.message, + callback: () => { + layoutManagerActionStore.removeAction(message.uuid); + iframeListener.sendActionMessageTriggered(message.uuid); + }, + userInputManager: this.userInputManager, + }) ); iframeListener.registerAnswerer("removeActionMessage", (message) => { diff --git a/maps/tests/TriggerMessageApi/script.js b/maps/tests/TriggerMessageApi/script.js index b8d0885d..9ab02ec2 100644 --- a/maps/tests/TriggerMessageApi/script.js +++ b/maps/tests/TriggerMessageApi/script.js @@ -2,8 +2,11 @@ WA.onInit().then(() => { let message; WA.room.onEnterZone("carpet", () => { - message = WA.ui.displayActionMessage("This is a test message. Press space to display a chat message. Walk out to hide the message.", () => { - WA.chat.sendChatMessage("Hello world!", "The bot"); + message = WA.ui.displayActionMessage({ + message: "This is a test message. Press space to display a chat message. Walk out to hide the message.", + callback: () => { + WA.chat.sendChatMessage("Hello world!", "The bot"); + } }); });