extraction idea

# Conflicts:
#	front/src/Api/ScriptUtils.ts
#	front/src/iframe_api.ts
This commit is contained in:
jonny 2021-05-25 13:47:41 +02:00
parent fe573893a1
commit 1a1ab30574
4 changed files with 122 additions and 15 deletions

View file

@ -0,0 +1,35 @@
import { ChatEvent } from '../Events/ChatEvent'
import { isUserInputChatEvent, UserInputChatEvent } from '../Events/UserInputChatEvent'
import { registerWorkadventureCommand, registerWorkadvntureCallback, sendToWorkadventure } from "./iframe-registration"
let chatMessageCallback: (event: string) => void | undefined
class WorkadvntureChatCommands {
sendChatMessage(message: string, author: string) {
sendToWorkadventure({
type: 'chat',
data: {
'message': message,
'author': author
} as ChatEvent
})
}
/**
* Listen to messages sent by the local user, in the chat.
*/
onChatMessage(callback: (message: string) => void) {
chatMessageCallback = callback
}
}
export const commands = registerWorkadventureCommand(new WorkadvntureChatCommands())
export const callbacks = registerWorkadvntureCallback([{
callback: (event: UserInputChatEvent) => {
chatMessageCallback?.(event.message)
},
type: "userInputChat",
typeChecker: isUserInputChatEvent
}])

View file

@ -0,0 +1,30 @@
import { IframeEvent, IframeEventMap, IframeResponseEventMap } from '../Events/IframeEvent';
import { registeredCallbacks, WorkAdventureApi } from "../../iframe_api"
export function registerWorkadventureCommand<T>(commnds: T): T {
const commandPrototype = Object.getPrototypeOf(commnds);
const commandClassPropertyNames = Object.getOwnPropertyNames(commandPrototype).filter(name => name !== "constructor");
for (const key of commandClassPropertyNames) {
window.WA[key as keyof WorkAdventureApi] = commandPrototype[key] as never
}
return commnds
}
export function registerWorkadvntureCallback<T extends Function>(callbacks: Array<{
type: keyof IframeResponseEventMap,
typeChecker: Function,
callback: T
}>) {
for (const callback of callbacks) {
registeredCallbacks[callback.type] = {
typeChecker: callback.typeChecker,
callback: callback.callback
}
}
return callbacks
}
export function sendToWorkadventure(content: IframeEvent<keyof IframeEventMap>) {
window.parent.postMessage(content, "*")
}

View file

@ -0,0 +1,27 @@
import { EnterLeaveEvent, isEnterLeaveEvent } from '../Events/EnterLeaveEvent'
import { registerWorkadventureCommand, registerWorkadvntureCallback, sendToWorkadventure } from "./iframe-registration"
class WorkadventureZoneCommands {
onEnterZone(name: string, callback: () => void): void {
}
onLeaveZone(name: string, callback: () => void): void {
}
}
export const commands = registerWorkadventureCommand(new WorkadventureZoneCommands())
export const callbacks = registerWorkadvntureCallback([{
callback: (enterEvent: EnterLeaveEvent) => {
},
type: "enterEvent",
typeChecker: isEnterLeaveEvent
},])

View file

@ -1,5 +1,5 @@
import type { ChatEvent } from "./Api/Events/ChatEvent";
import { isIframeResponseEventWrapper } from "./Api/Events/IframeEvent";
import { IframeEvent, IframeEventMap, IframeResponseEventMap, isIframeResponseEventWrapper } from "./Api/Events/IframeEvent";
import { isUserInputChatEvent, UserInputChatEvent } from "./Api/Events/UserInputChatEvent";
import { Subject } from "rxjs";
import { EnterLeaveEvent, isEnterLeaveEvent } from "./Api/Events/EnterLeaveEvent";
@ -10,9 +10,19 @@ import type { OpenTabEvent } from "./Api/Events/OpenTabEvent";
import type { GoToPageEvent } from "./Api/Events/GoToPageEvent";
import type { OpenCoWebSiteEvent } from "./Api/Events/OpenCoWebSiteEvent";
interface WorkAdventureApi {
sendChatMessage(message: string, author: string): void;
onChatMessage(callback: (message: string) => void): void;
const importType = Promise.all([
import("./Api/iframe/chatmessage"),
import("./Api/iframe/zone-events")
])
type UnPromise<P> = P extends Promise<infer T> ? T : P
type WorkadventureCommandClasses = UnPromise<typeof importType>[number]["commands"];
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> };
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;
@ -26,10 +36,15 @@ interface WorkAdventureApi {
removeBubble(): void;
}
declare global {
// eslint-disable-next-line no-var
var WA: WorkAdventureApi
declare global {
interface Window {
WA: WorkAdventureApi
}
let WA: WorkAdventureApi
}
type ChatMessageCallback = (message: string) => void;
@ -172,14 +187,7 @@ window.WA = {
popups.set(popupId, popup)
return popup;
},
/**
* Listen to messages sent by the local user, in the chat.
*/
onChatMessage(callback: ChatMessageCallback): void {
userInputChatStream.subscribe((userInputChatEvent) => {
callback(userInputChatEvent.message);
});
},
...({} as WorkAdventureApiFiles),
onEnterZone(name: string, callback: () => void): void {
let subject = enterStreams.get(name);
if (subject === undefined) {
@ -196,6 +204,7 @@ window.WA = {
}
subject.subscribe(callback);
},
}
window.addEventListener('message', message => {
@ -209,6 +218,12 @@ window.addEventListener('message', message => {
if (isIframeResponseEventWrapper(payload)) {
const payloadData = payload.data;
if (registeredCallbacks[payload.type] && registeredCallbacks[payload.type]?.typeChecker(payloadData)) {
registeredCallbacks[payload.type]?.callback(payloadData)
return
}
if (payload.type === 'userInputChat' && isUserInputChatEvent(payloadData)) {
userInputChatStream.next(payloadData);
} else if (payload.type === 'enterEvent' && isEnterLeaveEvent(payloadData)) {