added typedef for subobject types
extracted popup functions # Conflicts: # front/package-lock.json # front/package.json # front/src/iframe_api.ts
This commit is contained in:
parent
1a1ab30574
commit
2de2d114a1
48
front/src/Api/iframe/IframeApiContribution.ts
Normal file
48
front/src/Api/iframe/IframeApiContribution.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import type { IframeEvent, IframeEventMap, IframeResponseEventMap } from '../Events/IframeEvent';
|
||||||
|
import type * as tg from "generic-type-guard";
|
||||||
|
|
||||||
|
|
||||||
|
export type PossibleSubobjects = "zone" | "chat" | "ui"
|
||||||
|
|
||||||
|
export function sendToWorkadventure(content: IframeEvent<keyof IframeEventMap>) {
|
||||||
|
window.parent.postMessage(content, "*")
|
||||||
|
}
|
||||||
|
type GuardedType<Guard extends tg.TypeGuard<unknown>> = Guard extends tg.TypeGuard<infer T> ? T : never
|
||||||
|
|
||||||
|
export function apiCallback<T extends tg.TypeGuard<unknown>>(callbackData: IframeCallbackContribution<T>) {
|
||||||
|
|
||||||
|
return callbackData
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IframeCallbackContribution<Guard extends tg.TypeGuard<unknown>, T = GuardedType<Guard>> {
|
||||||
|
|
||||||
|
type: keyof IframeResponseEventMap,
|
||||||
|
typeChecker: Guard,
|
||||||
|
callback: (payloadData: T) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* !! be aware that the implemented attributes (addMethodsAtRoot and subObjectIdentifier) must be readonly
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
export abstract class IframeApiContribution<T extends {
|
||||||
|
// i think this is specific enough
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
callbacks: Array<IframeCallbackContribution<tg.TypeGuard<any>>>,
|
||||||
|
readonly subObjectIdentifier: PossibleSubobjects,
|
||||||
|
readonly addMethodsAtRoot: boolean | undefined
|
||||||
|
}> {
|
||||||
|
|
||||||
|
abstract callbacks: T["callbacks"]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated this is only there for backwards compatibility on new apis this should be set to false or ignored
|
||||||
|
*/
|
||||||
|
addMethodsAtRoot = false
|
||||||
|
|
||||||
|
abstract readonly subObjectIdentifier: T["subObjectIdentifier"]
|
||||||
|
|
||||||
|
}
|
@ -1,10 +1,24 @@
|
|||||||
import { ChatEvent } from '../Events/ChatEvent'
|
import { ChatEvent } from '../Events/ChatEvent'
|
||||||
import { isUserInputChatEvent, UserInputChatEvent } from '../Events/UserInputChatEvent'
|
import { isUserInputChatEvent, UserInputChatEvent } from '../Events/UserInputChatEvent'
|
||||||
import { registerWorkadventureCommand, registerWorkadvntureCallback, sendToWorkadventure } from "./iframe-registration"
|
import { } from "./iframe-registration"
|
||||||
|
import { apiCallback, IframeApiContribution, sendToWorkadventure } from './IframeApiContribution'
|
||||||
|
|
||||||
let chatMessageCallback: (event: string) => void | undefined
|
|
||||||
|
|
||||||
class WorkadvntureChatCommands {
|
class WorkadvntureChatCommands extends IframeApiContribution<WorkadvntureChatCommands> {
|
||||||
|
readonly subObjectIdentifier = 'chat'
|
||||||
|
|
||||||
|
readonly addMethodsAtRoot = true
|
||||||
|
|
||||||
|
chatMessageCallback?: (event: string) => void
|
||||||
|
|
||||||
|
callbacks = [apiCallback({
|
||||||
|
callback: (event: UserInputChatEvent) => {
|
||||||
|
this.chatMessageCallback?.(event.message)
|
||||||
|
},
|
||||||
|
type: "userInputChat",
|
||||||
|
typeChecker: isUserInputChatEvent
|
||||||
|
})]
|
||||||
|
|
||||||
|
|
||||||
sendChatMessage(message: string, author: string) {
|
sendChatMessage(message: string, author: string) {
|
||||||
sendToWorkadventure({
|
sendToWorkadventure({
|
||||||
@ -20,16 +34,8 @@ class WorkadvntureChatCommands {
|
|||||||
* Listen to messages sent by the local user, in the chat.
|
* Listen to messages sent by the local user, in the chat.
|
||||||
*/
|
*/
|
||||||
onChatMessage(callback: (message: string) => void) {
|
onChatMessage(callback: (message: string) => void) {
|
||||||
chatMessageCallback = callback
|
this.chatMessageCallback = callback
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const commands = registerWorkadventureCommand(new WorkadvntureChatCommands())
|
export default new WorkadvntureChatCommands()
|
||||||
export const callbacks = registerWorkadvntureCallback([{
|
|
||||||
callback: (event: UserInputChatEvent) => {
|
|
||||||
chatMessageCallback?.(event.message)
|
|
||||||
},
|
|
||||||
type: "userInputChat",
|
|
||||||
typeChecker: isUserInputChatEvent
|
|
||||||
}])
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
import { IframeEvent, IframeEventMap, IframeResponseEventMap } from '../Events/IframeEvent';
|
import { IframeEvent, IframeEventMap, IframeResponseEventMap } from '../Events/IframeEvent';
|
||||||
import { registeredCallbacks, WorkAdventureApi } from "../../iframe_api"
|
import { registeredCallbacks, WorkAdventureApi } from "../../iframe_api"
|
||||||
export function registerWorkadventureCommand<T>(commnds: T): T {
|
/*export function registerWorkadventureCommand<T>(commnds: T): T {
|
||||||
const commandPrototype = Object.getPrototypeOf(commnds);
|
const commandPrototype = Object.getPrototypeOf(commnds);
|
||||||
const commandClassPropertyNames = Object.getOwnPropertyNames(commandPrototype).filter(name => name !== "constructor");
|
const commandClassPropertyNames = Object.getOwnPropertyNames(commandPrototype).filter(name => name !== "constructor");
|
||||||
for (const key of commandClassPropertyNames) {
|
for (const key of commandClassPropertyNames) {
|
||||||
@ -8,7 +8,7 @@ export function registerWorkadventureCommand<T>(commnds: T): T {
|
|||||||
}
|
}
|
||||||
return commnds
|
return commnds
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
export function registerWorkadvntureCallback<T extends Function>(callbacks: Array<{
|
export function registerWorkadvntureCallback<T extends Function>(callbacks: Array<{
|
||||||
type: keyof IframeResponseEventMap,
|
type: keyof IframeResponseEventMap,
|
||||||
@ -25,6 +25,3 @@ export function registerWorkadvntureCallback<T extends Function>(callbacks: Arra
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function sendToWorkadventure(content: IframeEvent<keyof IframeEventMap>) {
|
|
||||||
window.parent.postMessage(content, "*")
|
|
||||||
}
|
|
148
front/src/Api/iframe/popup.ts
Normal file
148
front/src/Api/iframe/popup.ts
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
import { isButtonClickedEvent } from '../Events/ButtonClickedEvent';
|
||||||
|
import { ClosePopupEvent } from '../Events/ClosePopupEvent';
|
||||||
|
import { apiCallback, IframeApiContribution, IframeCallbackContribution, sendToWorkadventure } from './IframeApiContribution';
|
||||||
|
import zoneCommands from "./zone-events"
|
||||||
|
class Popup {
|
||||||
|
constructor(private id: number) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the popup
|
||||||
|
*/
|
||||||
|
public close(): void {
|
||||||
|
window.parent.postMessage({
|
||||||
|
'type': 'closePopup',
|
||||||
|
'data': {
|
||||||
|
'popupId': this.id,
|
||||||
|
} as ClosePopupEvent
|
||||||
|
}, '*');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ButtonClickedCallback = (popup: Popup) => void;
|
||||||
|
interface ButtonDescriptor {
|
||||||
|
/**
|
||||||
|
* The label of the button
|
||||||
|
*/
|
||||||
|
label: string,
|
||||||
|
/**
|
||||||
|
* The type of the button. Can be one of "normal", "primary", "success", "warning", "error", "disabled"
|
||||||
|
*/
|
||||||
|
className?: "normal" | "primary" | "success" | "warning" | "error" | "disabled",
|
||||||
|
/**
|
||||||
|
* Callback called if the button is pressed
|
||||||
|
*/
|
||||||
|
callback: ButtonClickedCallback,
|
||||||
|
}
|
||||||
|
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>>();
|
||||||
|
|
||||||
|
interface ZonedPopupOptions {
|
||||||
|
zone: string
|
||||||
|
objectLayerName?: string,
|
||||||
|
popupText: string,
|
||||||
|
delay?: number
|
||||||
|
popupOptions: Array<ButtonDescriptor>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class PopupApiContribution extends IframeApiContribution<PopupApiContribution> {
|
||||||
|
|
||||||
|
readonly subObjectIdentifier = "ui"
|
||||||
|
|
||||||
|
readonly addMethodsAtRoot = true
|
||||||
|
callbacks = [apiCallback({
|
||||||
|
type: "buttonClickedEvent",
|
||||||
|
typeChecker: isButtonClickedEvent,
|
||||||
|
callback: (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(popup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})];
|
||||||
|
|
||||||
|
|
||||||
|
openPopup(targetObject: string, message: string, buttons: ButtonDescriptor[]): Popup {
|
||||||
|
popupId++;
|
||||||
|
const popup = new Popup(popupId);
|
||||||
|
const btnMap = new Map<number, () => 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++;
|
||||||
|
}
|
||||||
|
|
||||||
|
sendToWorkadventure({
|
||||||
|
'type': 'openPopup',
|
||||||
|
'data': {
|
||||||
|
popupId,
|
||||||
|
targetObject,
|
||||||
|
message,
|
||||||
|
buttons: buttons.map((button) => {
|
||||||
|
return {
|
||||||
|
label: button.label,
|
||||||
|
className: button.className
|
||||||
|
};
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
popups.set(popupId, popup)
|
||||||
|
return popup;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
popupInZone(options: ZonedPopupOptions) {
|
||||||
|
const objectLayerName = options.objectLayerName || options.zone
|
||||||
|
|
||||||
|
let lastOpened = 0;
|
||||||
|
|
||||||
|
let popup: Popup | undefined;
|
||||||
|
zoneCommands.onEnterZone(options.zone, () => {
|
||||||
|
if (options.delay) {
|
||||||
|
if (lastOpened + options.delay > Date.now()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastOpened = Date.now();
|
||||||
|
popup = this.openPopup(objectLayerName, options.popupText, options.popupOptions.map(option => {
|
||||||
|
const callback = option.callback;
|
||||||
|
const popupOptions = {
|
||||||
|
...option,
|
||||||
|
className: option.className || 'normal',
|
||||||
|
callback: () => {
|
||||||
|
if (callback && popup) {
|
||||||
|
callback(popup);
|
||||||
|
}
|
||||||
|
popup?.close();
|
||||||
|
popup = undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return popupOptions;
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
zoneCommands.onLeaveZone(options.zone, () => {
|
||||||
|
if (popup) {
|
||||||
|
popup.close();
|
||||||
|
popup = undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default new PopupApiContribution()
|
@ -1,27 +1,54 @@
|
|||||||
import { EnterLeaveEvent, isEnterLeaveEvent } from '../Events/EnterLeaveEvent'
|
import { EnterLeaveEvent, isEnterLeaveEvent } from '../Events/EnterLeaveEvent'
|
||||||
import { registerWorkadventureCommand, registerWorkadvntureCallback, sendToWorkadventure } from "./iframe-registration"
|
import { apiCallback as apiCallback, IframeApiContribution } from './IframeApiContribution'
|
||||||
|
import { Subject } from "rxjs";
|
||||||
|
|
||||||
|
|
||||||
|
const enterStreams: Map<string, Subject<EnterLeaveEvent>> = new Map<string, Subject<EnterLeaveEvent>>();
|
||||||
|
const leaveStreams: Map<string, Subject<EnterLeaveEvent>> = new Map<string, Subject<EnterLeaveEvent>>();
|
||||||
|
|
||||||
|
class WorkadventureZoneCommands extends IframeApiContribution<WorkadventureZoneCommands> {
|
||||||
|
|
||||||
|
readonly subObjectIdentifier = "zone"
|
||||||
|
|
||||||
|
readonly addMethodsAtRoot = true
|
||||||
|
callbacks = [
|
||||||
|
apiCallback({
|
||||||
|
callback: (payloadData: EnterLeaveEvent) => {
|
||||||
|
enterStreams.get(payloadData.name)?.next();
|
||||||
|
},
|
||||||
|
type: "enterEvent",
|
||||||
|
typeChecker: isEnterLeaveEvent
|
||||||
|
}),
|
||||||
|
apiCallback({
|
||||||
|
type: "leaveEvent",
|
||||||
|
typeChecker: isEnterLeaveEvent,
|
||||||
|
callback: (payloadData) => {
|
||||||
|
leaveStreams.get(payloadData.name)?.next();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
class WorkadventureZoneCommands {
|
|
||||||
|
|
||||||
onEnterZone(name: string, callback: () => void): void {
|
onEnterZone(name: string, callback: () => void): void {
|
||||||
|
let subject = enterStreams.get(name);
|
||||||
|
if (subject === undefined) {
|
||||||
|
subject = new Subject<EnterLeaveEvent>();
|
||||||
|
enterStreams.set(name, subject);
|
||||||
|
}
|
||||||
|
subject.subscribe(callback);
|
||||||
|
|
||||||
}
|
}
|
||||||
onLeaveZone(name: string, callback: () => void): void {
|
onLeaveZone(name: string, callback: () => void): void {
|
||||||
|
let subject = leaveStreams.get(name);
|
||||||
|
if (subject === undefined) {
|
||||||
|
subject = new Subject<EnterLeaveEvent>();
|
||||||
|
leaveStreams.set(name, subject);
|
||||||
|
}
|
||||||
|
subject.subscribe(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default new WorkadventureZoneCommands();
|
||||||
|
|
||||||
export const commands = registerWorkadventureCommand(new WorkadventureZoneCommands())
|
|
||||||
export const callbacks = registerWorkadvntureCallback([{
|
|
||||||
callback: (enterEvent: EnterLeaveEvent) => {
|
|
||||||
|
|
||||||
},
|
|
||||||
type: "enterEvent",
|
|
||||||
typeChecker: isEnterLeaveEvent
|
|
||||||
},])
|
|
||||||
|
|
@ -9,23 +9,54 @@ import type { ClosePopupEvent } from "./Api/Events/ClosePopupEvent";
|
|||||||
import type { OpenTabEvent } from "./Api/Events/OpenTabEvent";
|
import type { OpenTabEvent } from "./Api/Events/OpenTabEvent";
|
||||||
import type { GoToPageEvent } from "./Api/Events/GoToPageEvent";
|
import type { GoToPageEvent } from "./Api/Events/GoToPageEvent";
|
||||||
import type { OpenCoWebSiteEvent } from "./Api/Events/OpenCoWebSiteEvent";
|
import type { OpenCoWebSiteEvent } from "./Api/Events/OpenCoWebSiteEvent";
|
||||||
|
import { OpenTabEvent } from "./Api/Events/OpenTabEvent";
|
||||||
|
import { GoToPageEvent } from "./Api/Events/GoToPageEvent";
|
||||||
|
import { OpenCoWebSiteEvent, OpenCoWebSiteOptionsEvent } from "./Api/Events/OpenCoWebSiteEvent";
|
||||||
|
import { LoadPageEvent } from './Api/Events/LoadPageEvent';
|
||||||
|
import { isMenuItemClickedEvent } from './Api/Events/MenuItemClickedEvent';
|
||||||
|
import { MenuItemRegisterEvent } from './Api/Events/MenuItemRegisterEvent';
|
||||||
|
import { GameStateEvent, isGameStateEvent } from './Api/Events/ApiGameStateEvent';
|
||||||
|
import { updateTile, UpdateTileEvent } from './Api/Events/ApiUpdateTileEvent';
|
||||||
|
import { isMessageReferenceEvent, removeTriggerMessage, triggerMessage, TriggerMessageCallback, TriggerMessageEvent } from './Api/Events/TriggerMessageEvent';
|
||||||
|
import { HasMovedEvent, HasMovedEventCallback, isHasMovedEvent } from './Api/Events/HasMovedEvent';
|
||||||
|
|
||||||
const importType = Promise.all([
|
const importType = Promise.all([
|
||||||
|
import("./Api/iframe/popup"),
|
||||||
import("./Api/iframe/chatmessage"),
|
import("./Api/iframe/chatmessage"),
|
||||||
import("./Api/iframe/zone-events")
|
import("./Api/iframe/zone-events")
|
||||||
])
|
])
|
||||||
type UnPromise<P> = P extends Promise<infer T> ? T : P
|
|
||||||
|
|
||||||
type WorkadventureCommandClasses = UnPromise<typeof importType>[number]["commands"];
|
type PromiseReturnType<P> = P extends Promise<infer T> ? T : P
|
||||||
|
|
||||||
|
type WorkadventureCommandClasses = PromiseReturnType<typeof importType>[number]["default"];
|
||||||
|
|
||||||
type KeysOfUnion<T> = T extends T ? keyof T : never
|
type KeysOfUnion<T> = T extends T ? keyof T : never
|
||||||
type ObjectWithKeyOfUnion<O, Key> = O extends O ? (Key extends keyof O ? O[Key] : never) : never
|
|
||||||
|
|
||||||
type WorkAdventureApiFiles = { [Key in KeysOfUnion<WorkadventureCommandClasses>]: ObjectWithKeyOfUnion<WorkadventureCommandClasses, Key> };
|
type ObjectWithKeyOfUnion<Key, O = WorkadventureCommandClasses> = O extends O ? (Key extends keyof O ? O[Key] : never) : never
|
||||||
|
|
||||||
|
type ApiKeys = KeysOfUnion<WorkadventureCommandClasses>;
|
||||||
|
|
||||||
|
type ObjectOfKey<Key extends ApiKeys, O = WorkadventureCommandClasses> = O extends O ? (Key extends keyof O ? O : never) : never
|
||||||
|
|
||||||
|
type ShouldAddAttribute<Key extends ApiKeys> = ObjectWithKeyOfUnion<Key>;
|
||||||
|
|
||||||
|
type WorkadventureFunctions = { [K in ApiKeys]: ObjectWithKeyOfUnion<K> extends Function ? K : never }[ApiKeys]
|
||||||
|
|
||||||
|
type WorkadventureFunctionsFilteredByRoot = { [K in WorkadventureFunctions]: ObjectOfKey<K>["addMethodsAtRoot"] extends true ? K : never }[WorkadventureFunctions]
|
||||||
|
|
||||||
|
|
||||||
|
type JustMethodKeys<T> = ({ [P in keyof T]: T[P] extends Function ? P : never })[keyof T];
|
||||||
|
type JustMethods<T> = Pick<T, JustMethodKeys<T>>;
|
||||||
|
|
||||||
|
type SubObjectTypes = {
|
||||||
|
[importCl in WorkadventureCommandClasses as importCl["subObjectIdentifier"]]: JustMethods<importCl>;
|
||||||
|
};
|
||||||
|
|
||||||
|
type WorkAdventureApiFiles = {
|
||||||
|
[Key in WorkadventureFunctionsFilteredByRoot]: ShouldAddAttribute<Key>
|
||||||
|
} & SubObjectTypes
|
||||||
|
|
||||||
export interface WorkAdventureApi extends WorkAdventureApiFiles {
|
export interface WorkAdventureApi extends WorkAdventureApiFiles {
|
||||||
onEnterZone(name: string, callback: () => void): void;
|
|
||||||
onLeaveZone(name: string, callback: () => void): void;
|
|
||||||
openPopup(targetObject: string, message: string, buttons: ButtonDescriptor[]): Popup;
|
|
||||||
openTab(url : string): void;
|
openTab(url : string): void;
|
||||||
goToPage(url : string): void;
|
goToPage(url : string): void;
|
||||||
openCoWebSite(url : string): void;
|
openCoWebSite(url : string): void;
|
||||||
@ -47,47 +78,11 @@ declare global {
|
|||||||
let WA: WorkAdventureApi
|
let WA: WorkAdventureApi
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChatMessageCallback = (message: string) => void;
|
|
||||||
type ButtonClickedCallback = (popup: Popup) => void;
|
|
||||||
|
|
||||||
const userInputChatStream: Subject<UserInputChatEvent> = new Subject();
|
const userInputChatStream: Subject<UserInputChatEvent> = new Subject();
|
||||||
const enterStreams: Map<string, Subject<EnterLeaveEvent>> = new Map<string, Subject<EnterLeaveEvent>>();
|
|
||||||
const leaveStreams: Map<string, Subject<EnterLeaveEvent>> = new Map<string, Subject<EnterLeaveEvent>>();
|
|
||||||
const popups: Map<number, Popup> = new Map<number, Popup>();
|
|
||||||
const popupCallbacks: Map<number, Map<number, ButtonClickedCallback>> = new Map<number, Map<number, ButtonClickedCallback>>();
|
|
||||||
|
|
||||||
let popupId = 0;
|
|
||||||
interface ButtonDescriptor {
|
|
||||||
/**
|
|
||||||
* The label of the button
|
|
||||||
*/
|
|
||||||
label: string,
|
|
||||||
/**
|
|
||||||
* The type of the button. Can be one of "normal", "primary", "success", "warning", "error", "disabled"
|
|
||||||
*/
|
|
||||||
className?: "normal" | "primary" | "success" | "warning" | "error" | "disabled",
|
|
||||||
/**
|
|
||||||
* Callback called if the button is pressed
|
|
||||||
*/
|
|
||||||
callback: ButtonClickedCallback,
|
|
||||||
}
|
|
||||||
|
|
||||||
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 = {
|
window.WA = {
|
||||||
/**
|
/**
|
||||||
@ -152,59 +147,16 @@ window.WA = {
|
|||||||
}, '*');
|
}, '*');
|
||||||
},
|
},
|
||||||
|
|
||||||
openPopup(targetObject: string, message: string, buttons: ButtonDescriptor[]): Popup {
|
registerMenuCommand(commandDescriptor: string, callback: (commandDescriptor: string) => void) {
|
||||||
popupId++;
|
menuCallbacks.set(commandDescriptor, callback);
|
||||||
const popup = new Popup(popupId);
|
|
||||||
const btnMap = new Map<number, () => 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({
|
window.parent.postMessage({
|
||||||
'type': 'openPopup',
|
'type': 'registerMenuCommand',
|
||||||
'data': {
|
'data': {
|
||||||
popupId,
|
menutItem: commandDescriptor
|
||||||
targetObject,
|
} as MenuItemRegisterEvent
|
||||||
message,
|
|
||||||
buttons: buttons.map((button) => {
|
|
||||||
return {
|
|
||||||
label: button.label,
|
|
||||||
className: button.className
|
|
||||||
};
|
|
||||||
})
|
|
||||||
} as OpenPopupEvent
|
|
||||||
}, '*');
|
}, '*');
|
||||||
|
|
||||||
popups.set(popupId, popup)
|
|
||||||
return popup;
|
|
||||||
},
|
},
|
||||||
...({} as WorkAdventureApiFiles),
|
...({} as WorkAdventureApiFiles),
|
||||||
onEnterZone(name: string, callback: () => void): void {
|
|
||||||
let subject = enterStreams.get(name);
|
|
||||||
if (subject === undefined) {
|
|
||||||
subject = new Subject<EnterLeaveEvent>();
|
|
||||||
enterStreams.set(name, subject);
|
|
||||||
}
|
|
||||||
subject.subscribe(callback);
|
|
||||||
},
|
|
||||||
onLeaveZone(name: string, callback: () => void): void {
|
|
||||||
let subject = leaveStreams.get(name);
|
|
||||||
if (subject === undefined) {
|
|
||||||
subject = new Subject<EnterLeaveEvent>();
|
|
||||||
leaveStreams.set(name, subject);
|
|
||||||
}
|
|
||||||
subject.subscribe(callback);
|
|
||||||
},
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('message', message => {
|
window.addEventListener('message', message => {
|
||||||
@ -226,22 +178,9 @@ window.addEventListener('message', message => {
|
|||||||
|
|
||||||
if (payload.type === 'userInputChat' && isUserInputChatEvent(payloadData)) {
|
if (payload.type === 'userInputChat' && isUserInputChatEvent(payloadData)) {
|
||||||
userInputChatStream.next(payloadData);
|
userInputChatStream.next(payloadData);
|
||||||
} else if (payload.type === 'enterEvent' && isEnterLeaveEvent(payloadData)) {
|
|
||||||
enterStreams.get(payloadData.name)?.next();
|
|
||||||
} else if (payload.type === 'leaveEvent' && isEnterLeaveEvent(payloadData)) {
|
|
||||||
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(popup);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ...
|
// ...
|
||||||
});
|
});
|
Loading…
Reference in New Issue
Block a user