diff --git a/front/src/Api/Events/MenuItemClickedEvent.ts b/front/src/Api/Events/MenuItemClickedEvent.ts new file mode 100644 index 00000000..dd80c0f2 --- /dev/null +++ b/front/src/Api/Events/MenuItemClickedEvent.ts @@ -0,0 +1,10 @@ +import * as tg from "generic-type-guard"; + +export const isMenuItemClickedEvent = + new tg.IsInterface().withProperties({ + menuItem: tg.isString + }).get(); +/** + * A message sent from the game to the iFrame when a user enters or leaves a zone marked with the "zone" property. + */ +export type MenuItemClickedEvent = tg.GuardedType; diff --git a/front/src/Api/Events/MenuItemRegisterEvent.ts b/front/src/Api/Events/MenuItemRegisterEvent.ts new file mode 100644 index 00000000..98d4c7d3 --- /dev/null +++ b/front/src/Api/Events/MenuItemRegisterEvent.ts @@ -0,0 +1,10 @@ +import * as tg from "generic-type-guard"; + +export const isMenuItemRegisterEvent = + new tg.IsInterface().withProperties({ + menutItem: tg.isString + }).get(); +/** + * A message sent from the game to the iFrame when a user enters or leaves a zone marked with the "zone" property. + */ +export type MenuItemRegisterEvent = tg.GuardedType; diff --git a/front/src/Api/IframeListener.ts b/front/src/Api/IframeListener.ts index c875ebbb..dbb45db3 100644 --- a/front/src/Api/IframeListener.ts +++ b/front/src/Api/IframeListener.ts @@ -12,6 +12,8 @@ import {ClosePopupEvent, isClosePopupEvent} from "./Events/ClosePopupEvent"; import {scriptUtils} from "./ScriptUtils"; import {GoToPageEvent, isGoToPageEvent} from "./Events/GoToPageEvent"; import {isOpenCoWebsite, OpenCoWebSiteEvent} from "./Events/OpenCoWebSiteEvent"; +import { isMenuItemRegisterEvent } from './Events/MenuItemRegisterEvent'; +import { MenuItemClickedEvent } from './Events/MenuItemClickedEvent'; /** @@ -52,6 +54,8 @@ class IframeListener { private readonly _removeBubbleStream: Subject = new Subject(); public readonly removeBubbleStream = this._removeBubbleStream.asObservable(); + private readonly _registerMenuCommandStream: Subject = new Subject(); + public readonly registerMenuCommandStream = this._registerMenuCommandStream.asObservable(); private readonly iframes = new Set(); private readonly scripts = new Map(); @@ -103,6 +107,8 @@ class IframeListener { } else if (payload.type === 'removeBubble'){ this._removeBubbleStream.next(); + } else if (payload.type == "registerMenuCommand" && isMenuItemRegisterEvent(payload.data)) { + this._registerMenuCommandStream.next(payload.data.menutItem) } } @@ -187,6 +193,15 @@ class IframeListener { this.scripts.delete(scriptUrl); } + sendMenuClickedEvent(menuItem: string) { + this.postMessage({ + 'type': 'menuItemClicked', + 'data': { + menuItem: menuItem, + } as MenuItemClickedEvent + }); + } + sendUserInputChat(message: string) { this.postMessage({ 'type': 'userInputChat', diff --git a/front/src/Phaser/Menu/MenuScene.ts b/front/src/Phaser/Menu/MenuScene.ts index 05cea305..9e11a873 100644 --- a/front/src/Phaser/Menu/MenuScene.ts +++ b/front/src/Phaser/Menu/MenuScene.ts @@ -9,6 +9,9 @@ import {connectionManager} from "../../Connexion/ConnectionManager"; import {GameConnexionTypes} from "../../Url/UrlManager"; import {WarningContainer, warningContainerHtml, warningContainerKey} from "../Components/WarningContainer"; import {worldFullWarningStream} from "../../Connexion/WorldFullWarningStream"; +import { HtmlUtils } from '../../WebRtc/HtmlUtils'; +import { iframeListener } from '../../Api/IframeListener'; +import { Subscription } from 'rxjs'; export const MenuSceneName = 'MenuScene'; const gameMenuKey = 'gameMenu'; @@ -36,11 +39,20 @@ export class MenuScene extends Phaser.Scene { private warningContainer: WarningContainer | null = null; private warningContainerTimeout: NodeJS.Timeout | null = null; + private apiMenus = [] + + + private subscriptions = new Subscription() constructor() { super({key: MenuSceneName}); this.gameQualityValue = localUserStore.getGameQualityValue(); this.videoQualityValue = localUserStore.getVideoQualityValue(); + + this.subscriptions.add(iframeListener.registerMenuCommandStream.subscribe(menuCommand => { + this.addMenuOption(menuCommand); + + })) } preload () { @@ -266,13 +278,28 @@ export class MenuScene extends Phaser.Scene { }); } - private onMenuClick(event:MouseEvent) { - if((event?.target as HTMLInputElement).classList.contains('not-button')){ + public addMenuOption(menuText: string) { + const wrappingSection = document.createElement("section") + wrappingSection.innerHTML = `` + const menuItemContainer = this.menuElement.node.querySelector("#gameMenu main"); + if (menuItemContainer) { + menuItemContainer.insertBefore(wrappingSection, menuItemContainer.querySelector("#socialLinks")) + } + } + + private onMenuClick(event: MouseEvent) { + const htmlMenuItem = (event?.target as HTMLInputElement); + if (htmlMenuItem.classList.contains('not-button')) { return; } event.preventDefault(); - switch ((event?.target as HTMLInputElement).id) { + if (htmlMenuItem.classList.contains("fromApi")) { + iframeListener.sendMenuClickedEvent(htmlMenuItem.id) + return + } + + switch (htmlMenuItem.id) { case 'changeNameButton': this.closeSideMenu(); gameManager.leaveGame(this, LoginSceneName, new LoginScene()); diff --git a/front/src/iframe_api.ts b/front/src/iframe_api.ts index 18d8d172..1b68b0c1 100644 --- a/front/src/iframe_api.ts +++ b/front/src/iframe_api.ts @@ -9,6 +9,8 @@ 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 { isMenuItemClickedEvent } from './Api/Events/MenuItemClickedEvent'; +import { MenuItemRegisterEvent } from './Api/Events/MenuItemRegisterEvent'; interface WorkAdventureApi { sendChatMessage(message: string, author: string): void; @@ -24,6 +26,7 @@ interface WorkAdventureApi { restorePlayerControl() : void; displayBubble() : void; removeBubble() : void; + registerMenuCommand(commandDescriptor: string, callback: (commandDescriptor: string) => void): void } declare global { @@ -40,7 +43,7 @@ const enterStreams: Map> = new Map> = new Map>(); const popups: Map = new Map(); const popupCallbacks: Map> = new Map>(); - +const menuCallbacks: Map void> = new Map() let popupId = 0; interface ButtonDescriptor { /** @@ -172,6 +175,16 @@ window.WA = { popups.set(popupId, popup) return popup; }, + + registerMenuCommand(commandDescriptor: string, callback: (commandDescriptor: string) => void) { + menuCallbacks.set(commandDescriptor, callback); + window.parent.postMessage({ + 'type': 'registerMenuCommand', + 'data': { + menutItem: commandDescriptor + } as MenuItemRegisterEvent + }, '*'); + }, /** * Listen to messages sent by the local user, in the chat. */ @@ -224,8 +237,12 @@ window.addEventListener('message', message => { if (callback) { callback(popup); } + } else if (payload.type == "menuItemClicked" && isMenuItemClickedEvent(payload.data)) { + const callback = menuCallbacks.get(payload.data.menuItem); + if (callback) { + callback(payload.data.menuItem) + } } - } // ...