menu command api

This commit is contained in:
jonny 2021-06-21 18:22:31 +02:00
parent 979ae73d8d
commit ba1bcf226a
9 changed files with 381 additions and 252 deletions

View file

@ -6,12 +6,14 @@ import type { ClosePopupEvent } from './ClosePopupEvent';
import type { EnterLeaveEvent } from './EnterLeaveEvent';
import type { GoToPageEvent } from './GoToPageEvent';
import type { LoadPageEvent } from './LoadPageEvent';
import type { LoadSoundEvent } from "./LoadSoundEvent";
import type { OpenCoWebSiteEvent } from './OpenCoWebSiteEvent';
import type { OpenPopupEvent } from './OpenPopupEvent';
import type { OpenTabEvent } from './OpenTabEvent';
import type { PlaySoundEvent } from "./PlaySoundEvent";
import type { MenuItemClickedEvent } from './ui/MenuItemClickedEvent';
import type { MenuItemRegisterEvent } from './ui/MenuItemRegisterEvent';
import type { UserInputChatEvent } from './UserInputChatEvent';
import type { LoadSoundEvent} from "./LoadSoundEvent";
import type {PlaySoundEvent} from "./PlaySoundEvent";
export interface TypedMessageEvent<T> extends MessageEvent {
@ -36,6 +38,7 @@ export type IframeEventMap = {
loadSound: LoadSoundEvent
playSound: PlaySoundEvent
stopSound: null,
registerMenuCommand: MenuItemRegisterEvent
}
export interface IframeEvent<T extends keyof IframeEventMap> {
type: T;
@ -52,6 +55,7 @@ export interface IframeResponseEventMap {
leaveEvent: EnterLeaveEvent
buttonClickedEvent: ButtonClickedEvent
// gameState: GameStateEvent
menuItemClicked: MenuItemClickedEvent
}
export interface IframeResponseEvent<T extends keyof IframeResponseEventMap> {
type: T;

View file

@ -0,0 +1,21 @@
import * as tg from "generic-type-guard";
import { iframeListener } from '../../IframeListener';
export const isMenuItemClickedEvent =
new tg.IsInterface().withProperties({
menuItem: tg.isString
}).get();
/**
* A message sent from the game to the iFrame when a menu item is clicked.
*/
export type MenuItemClickedEvent = tg.GuardedType<typeof isMenuItemClickedEvent>;
export function sendMenuClickedEvent(menuItem: string) {
iframeListener.postMessage({
'type': 'menuItemClicked',
'data': {
menuItem: menuItem,
} as MenuItemClickedEvent
});
}

View file

@ -0,0 +1,25 @@
import * as tg from "generic-type-guard";
import { Subject } from 'rxjs';
export const isMenuItemRegisterEvent =
new tg.IsInterface().withProperties({
menutItem: tg.isString
}).get();
/**
* A message sent from the iFrame to the game to add a new menu item.
*/
export type MenuItemRegisterEvent = tg.GuardedType<typeof isMenuItemRegisterEvent>;
export const isMenuItemRegisterIframeEvent =
new tg.IsInterface().withProperties({
type: tg.isSingletonString("registerMenuCommand"),
data: isMenuItemRegisterEvent
}).get();
const _registerMenuCommandStream: Subject<string> = new Subject();
export const registerMenuCommandStream = _registerMenuCommandStream.asObservable();
export function handleMenuItemRegistrationEvent(event: MenuItemRegisterEvent) {
_registerMenuCommandStream.next(event.menutItem)
}

View file

@ -1,21 +1,22 @@
import { Subject } from "rxjs";
import { ChatEvent, isChatEvent } from "./Events/ChatEvent";
import { HtmlUtils } from "../WebRtc/HtmlUtils";
import type { ButtonClickedEvent } from "./Events/ButtonClickedEvent";
import { ChatEvent, isChatEvent } from "./Events/ChatEvent";
import { ClosePopupEvent, isClosePopupEvent } from "./Events/ClosePopupEvent";
import type { EnterLeaveEvent } from "./Events/EnterLeaveEvent";
import { GoToPageEvent, isGoToPageEvent } from "./Events/GoToPageEvent";
import { IframeEvent, IframeEventMap, IframeResponseEvent, IframeResponseEventMap, isIframeEventWrapper, TypedMessageEvent } from "./Events/IframeEvent";
import { isLoadPageEvent } from './Events/LoadPageEvent';
import { isLoadSoundEvent, LoadSoundEvent } from "./Events/LoadSoundEvent";
import { isOpenCoWebsite, OpenCoWebSiteEvent } from "./Events/OpenCoWebSiteEvent";
import { isOpenPopupEvent, OpenPopupEvent } from "./Events/OpenPopupEvent";
import { isOpenTabEvent, OpenTabEvent } from "./Events/OpenTabEvent";
import type { ButtonClickedEvent } from "./Events/ButtonClickedEvent";
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, TypedMessageEvent } from "./Events/IframeEvent";
import { isPlaySoundEvent, PlaySoundEvent } from "./Events/PlaySoundEvent";
import { isStopSoundEvent, StopSoundEvent } from "./Events/StopSoundEvent";
import { handleMenuItemRegistrationEvent, isMenuItemRegisterIframeEvent } from './Events/ui/MenuItemRegisterEvent';
import type { UserInputChatEvent } from "./Events/UserInputChatEvent";
import { isLoadPageEvent } from './Events/LoadPageEvent';
import {isPlaySoundEvent, PlaySoundEvent} from "./Events/PlaySoundEvent";
import {isStopSoundEvent, StopSoundEvent} from "./Events/StopSoundEvent";
import {isLoadSoundEvent, LoadSoundEvent} from "./Events/LoadSoundEvent";
import { scriptUtils } from "./ScriptUtils";
/**
* Listens to messages from iframes and turn those messages into easy to use observables.
* Also allows to send messages to those iframes.
@ -33,7 +34,7 @@ class IframeListener {
private readonly _goToPageStream: Subject<GoToPageEvent> = new Subject();
public readonly goToPageStream = this._goToPageStream.asObservable();
private readonly _loadPageStream: Subject<string> = new Subject();
public readonly loadPageStream = this._loadPageStream.asObservable();
@ -137,9 +138,11 @@ class IframeListener {
}
else if (payload.type === 'removeBubble') {
this._removeBubbleStream.next();
}else if (payload.type === 'loadPage' && isLoadPageEvent(payload.data)){
} else if (payload.type === 'loadPage' && isLoadPageEvent(payload.data)) {
this._loadPageStream.next(payload.data.url);
}
} else if (isMenuItemRegisterIframeEvent(payload)) [
handleMenuItemRegistrationEvent(payload.data)
]
}
@ -263,7 +266,7 @@ class IframeListener {
/**
* Sends the message... to all allowed iframes.
*/
private postMessage(message: IframeResponseEvent<keyof IframeResponseEventMap>) {
public postMessage(message: IframeResponseEvent<keyof IframeResponseEventMap>) {
for (const iframe of this.iframes) {
iframe.contentWindow?.postMessage(message, '*');
}

View file

@ -1,14 +1,17 @@
import { isButtonClickedEvent } from '../Events/ButtonClickedEvent';
import type { ClosePopupEvent } from '../Events/ClosePopupEvent';
import { isMenuItemClickedEvent } from '../Events/ui/MenuItemClickedEvent';
import type { MenuItemRegisterEvent } from '../Events/ui/MenuItemRegisterEvent';
import { IframeApiContribution, sendToWorkadventure } from './IframeApiContribution';
import { apiCallback } from "./registeredCallbacks";
import {Popup} from "./Ui/Popup";
import type {ButtonClickedCallback, ButtonDescriptor} from "./Ui/ButtonDescriptor";
import type { ButtonClickedCallback, ButtonDescriptor } from "./Ui/ButtonDescriptor";
import { Popup } from "./Ui/Popup";
let popupId = 0;
const popups: Map<number, Popup> = new Map<number, Popup>();
const popupCallbacks: Map<number, Map<number, ButtonClickedCallback>> = new Map<number, Map<number, ButtonClickedCallback>>();
const menuCallbacks: Map<string, (command: string) => void> = new Map()
interface ZonedPopupOptions {
zone: string
objectLayerName?: string,
@ -33,6 +36,16 @@ class WorkAdventureUiCommands extends IframeApiContribution<WorkAdventureUiComma
callback(popup);
}
}
}),
apiCallback({
type: "menuItemClicked",
typeChecker: isMenuItemClickedEvent,
callback: event => {
const callback = menuCallbacks.get(event.menuItem);
if (callback) {
callback(event.menuItem)
}
}
})];
@ -71,6 +84,16 @@ class WorkAdventureUiCommands extends IframeApiContribution<WorkAdventureUiComma
return popup;
}
registerMenuCommand(commandDescriptor: string, callback: (commandDescriptor: string) => void) {
menuCallbacks.set(commandDescriptor, callback);
sendToWorkadventure({
'type': 'registerMenuCommand',
'data': {
menutItem: commandDescriptor
} as MenuItemRegisterEvent
});
}
displayBubble(): void {
sendToWorkadventure({ 'type': 'displayBubble', data: null });
}