Implementation of openPopup script method (WIP)
This commit is contained in:
parent
ed2ce68f37
commit
1e002f93ed
22
front/src/Api/Events/OpenPopupEvent.ts
Normal file
22
front/src/Api/Events/OpenPopupEvent.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import * as tg from "generic-type-guard";
|
||||
|
||||
const isButtonDescriptor =
|
||||
new tg.IsInterface().withProperties({
|
||||
label: tg.isString,
|
||||
className: tg.isOptional(tg.isString),
|
||||
closeOnClick: tg.isOptional(tg.isBoolean)
|
||||
}).get();
|
||||
type ButtonDescriptor = tg.GuardedType<typeof isButtonDescriptor>;
|
||||
|
||||
export const isOpenPopupEvent =
|
||||
new tg.IsInterface().withProperties({
|
||||
popupId: tg.isNumber,
|
||||
targetObject: tg.isString,
|
||||
message: tg.isString,
|
||||
buttons: tg.isAny //tg.isArray<ButtonDescriptor>,
|
||||
}).get();
|
||||
|
||||
/**
|
||||
* A message sent from the iFrame to the game to add a message in the chat.
|
||||
*/
|
||||
export type OpenPopupEvent = tg.GuardedType<typeof isOpenPopupEvent>;
|
@ -5,6 +5,7 @@ import {UserInputChatEvent} from "./Events/UserInputChatEvent";
|
||||
import * as crypto from "crypto";
|
||||
import {HtmlUtils} from "../WebRtc/HtmlUtils";
|
||||
import {EnterLeaveEvent} from "./Events/EnterLeaveEvent";
|
||||
import {isOpenPopupEvent, OpenPopupEvent} from "./Events/OpenPopupEvent";
|
||||
|
||||
|
||||
|
||||
@ -16,6 +17,9 @@ class IframeListener {
|
||||
private readonly _chatStream: Subject<ChatEvent> = new Subject();
|
||||
public readonly chatStream = this._chatStream.asObservable();
|
||||
|
||||
private readonly _openPopupStream: Subject<OpenPopupEvent> = new Subject();
|
||||
public readonly openPopupStream = this._openPopupStream.asObservable();
|
||||
|
||||
private readonly iframes = new Set<HTMLIFrameElement>();
|
||||
private readonly scripts = new Map<string, HTMLIFrameElement>();
|
||||
|
||||
@ -36,9 +40,14 @@ class IframeListener {
|
||||
}
|
||||
|
||||
const payload = message.data;
|
||||
console.log('FOO');
|
||||
if (isIframeEventWrapper(payload)) {
|
||||
console.log('FOOBAR', payload);
|
||||
if (payload.type === 'chat' && isChatEvent(payload.data)) {
|
||||
this._chatStream.next(payload.data);
|
||||
} else if (payload.type === 'openPopup' && isOpenPopupEvent(payload.data)) {
|
||||
console.log('OPENPOPUP called');
|
||||
this._openPopupStream.next(payload.data);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,6 +75,7 @@ import {localUserStore} from "../../Connexion/LocalUserStore";
|
||||
import {iframeListener} from "../../Api/IframeListener";
|
||||
import DOMElement = Phaser.GameObjects.DOMElement;
|
||||
import Tween = Phaser.Tweens.Tween;
|
||||
import {HtmlUtils} from "../../WebRtc/HtmlUtils";
|
||||
|
||||
export interface GameSceneInitInterface {
|
||||
initPosition: PointInterface|null,
|
||||
@ -165,8 +166,8 @@ export class GameScene extends ResizableScene implements CenterListener {
|
||||
private openChatIcon!: OpenChatIcon;
|
||||
private playerName!: string;
|
||||
private characterLayers!: string[];
|
||||
private popUpElements : Map<number, DOMElement> = new Map<number, Phaser.GameObjects.DOMElement>();
|
||||
|
||||
private popUpElement : DOMElement| undefined;
|
||||
constructor(private room: Room, MapUrlFile: string, customKey?: string|undefined) {
|
||||
super({
|
||||
key: customKey ?? room.id
|
||||
@ -442,6 +443,7 @@ export class GameScene extends ResizableScene implements CenterListener {
|
||||
// From now, this game scene will be notified of reposition events
|
||||
layoutManager.setListener(this);
|
||||
this.triggerOnMapLayerPropertyChange();
|
||||
this.listenToIframeEvents();
|
||||
|
||||
const camera = this.cameras.main;
|
||||
|
||||
@ -655,33 +657,6 @@ export class GameScene extends ResizableScene implements CenterListener {
|
||||
this.gameMap.onPropertyChange('exitSceneUrl', (newValue, oldValue) => {
|
||||
if (newValue) this.onMapExit(newValue as string);
|
||||
});
|
||||
this.gameMap.onPropertyChange('inGameConsoleMessage', (newValue, oldValue, allProps) => {
|
||||
if (newValue !== undefined) {
|
||||
this.popUpElement?.destroy();
|
||||
this.popUpElement = this.add.dom(2100, 150).createFromHTML(newValue as string);
|
||||
this.popUpElement.scale = 0;
|
||||
this.tweens.add({
|
||||
targets : this.popUpElement ,
|
||||
scale : 1,
|
||||
ease : "EaseOut",
|
||||
duration : 400,
|
||||
});
|
||||
|
||||
this.popUpElement.setClassName("popUpElement");
|
||||
|
||||
} else {
|
||||
this.tweens.add({
|
||||
targets : this.popUpElement ,
|
||||
scale : 0,
|
||||
ease : "EaseOut",
|
||||
duration : 400,
|
||||
onComplete : () => {
|
||||
this.popUpElement?.destroy();
|
||||
this.popUpElement = undefined;
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
this.gameMap.onPropertyChange('exitUrl', (newValue, oldValue) => {
|
||||
if (newValue) this.onMapExit(newValue as string);
|
||||
});
|
||||
@ -765,6 +740,56 @@ export class GameScene extends ResizableScene implements CenterListener {
|
||||
|
||||
}
|
||||
|
||||
private listenToIframeEvents(): void {
|
||||
iframeListener.openPopupStream.subscribe((openPopupEvent) => {
|
||||
const escapedMessage = HtmlUtils.escapeHtml(openPopupEvent.message);
|
||||
|
||||
let html = `<div class="nes-container with-title is-centered">
|
||||
${escapedMessage}
|
||||
</div>`;
|
||||
|
||||
const domElement = this.add.dom(150, 150).createFromHTML(html);
|
||||
domElement.scale = 0;
|
||||
domElement.setClassName('popUpElement');
|
||||
this.tweens.add({
|
||||
targets : domElement ,
|
||||
scale : 1,
|
||||
ease : "EaseOut",
|
||||
duration : 400,
|
||||
});
|
||||
|
||||
this.popUpElements.set(openPopupEvent.popupId, domElement);
|
||||
});
|
||||
/*this.gameMap.onPropertyChange('inGameConsoleMessage', (newValue, oldValue, allProps) => {
|
||||
if (newValue !== undefined) {
|
||||
this.popUpElement?.destroy();
|
||||
this.popUpElement = this.add.dom(2100, 150).createFromHTML(newValue as string);
|
||||
this.popUpElement.scale = 0;
|
||||
this.tweens.add({
|
||||
targets : this.popUpElement ,
|
||||
scale : 1,
|
||||
ease : "EaseOut",
|
||||
duration : 400,
|
||||
});
|
||||
|
||||
this.popUpElement.setClassName("popUpElement");
|
||||
|
||||
} else {
|
||||
this.tweens.add({
|
||||
targets : this.popUpElement ,
|
||||
scale : 0,
|
||||
ease : "EaseOut",
|
||||
duration : 400,
|
||||
onComplete : () => {
|
||||
this.popUpElement?.destroy();
|
||||
this.popUpElement = undefined;
|
||||
},
|
||||
});
|
||||
}
|
||||
});*/
|
||||
|
||||
}
|
||||
|
||||
private onMapExit(exitKey: string) {
|
||||
const {roomId, hash} = Room.getIdFromIdentifier(exitKey, this.MapUrlFile, this.instance);
|
||||
if (!roomId) throw new Error('Could not find the room from its exit key: '+exitKey);
|
||||
|
@ -24,7 +24,7 @@ export class HtmlUtils {
|
||||
throw new Error("Cannot find HTML element with id '"+id+"'");
|
||||
}
|
||||
|
||||
private static escapeHtml(html: string): string {
|
||||
public static escapeHtml(html: string): string {
|
||||
const text = document.createTextNode(html);
|
||||
const p = document.createElement('p');
|
||||
p.appendChild(text);
|
||||
|
@ -3,12 +3,14 @@ import {isIframeEventWrapper} from "./Api/Events/IframeEvent";
|
||||
import {isUserInputChatEvent, UserInputChatEvent} from "./Api/Events/UserInputChatEvent";
|
||||
import {Subject} from "rxjs";
|
||||
import {EnterLeaveEvent, isEnterLeaveEvent} from "./Api/Events/EnterLeaveEvent";
|
||||
import {OpenPopupEvent} from "./Api/Events/OpenPopupEvent";
|
||||
|
||||
interface WorkAdventureApi {
|
||||
sendChatMessage(message: string, author: string): void;
|
||||
onChatMessage(callback: (message: string) => void): void;
|
||||
onEnterZone(name: string, callback: () => void): void;
|
||||
onLeaveZone(name: string, callback: () => void): void;
|
||||
openPopup(targetObject: string, message: string, buttons: ButtonDescriptor[]): number;
|
||||
}
|
||||
|
||||
declare global {
|
||||
@ -21,6 +23,25 @@ type ChatMessageCallback = (message: string) => void;
|
||||
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>>();
|
||||
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?: () => void,
|
||||
/**
|
||||
* If set to true, the popup is closed when the button is clicked
|
||||
*/
|
||||
closeOnClick?: boolean
|
||||
}
|
||||
|
||||
|
||||
window.WA = {
|
||||
@ -37,6 +58,25 @@ window.WA = {
|
||||
} as ChatEvent
|
||||
}, '*');
|
||||
},
|
||||
openPopup(targetObject: string, message: string, buttons: ButtonDescriptor[]): number {
|
||||
popupId++;
|
||||
window.parent.postMessage({
|
||||
'type': 'openPopup',
|
||||
'data': {
|
||||
popupId,
|
||||
targetObject,
|
||||
message,
|
||||
buttons: buttons.map((button) => {
|
||||
return {
|
||||
label: button.label,
|
||||
className: button.className,
|
||||
closeOnClick: button.closeOnClick
|
||||
};
|
||||
})
|
||||
} as OpenPopupEvent
|
||||
}, '*');
|
||||
return popupId;
|
||||
},
|
||||
/**
|
||||
* Listen to messages sent by the local user, in the chat.
|
||||
*/
|
||||
|
@ -18,3 +18,26 @@ WA.onLeaveZone('myTrigger', () => {
|
||||
WA.onEnterZone('notExist', () => {
|
||||
WA.sendChatMessage("YOU SHOULD NEVER SEE THIS", 'Poly Parrot');
|
||||
})
|
||||
|
||||
let popupId;
|
||||
|
||||
WA.onEnterZone('popupZone', () => {
|
||||
popupId = WA.openPopup('foobar', 'This is a test message. Hi!', [
|
||||
{
|
||||
label: "Close",
|
||||
className: "normal",
|
||||
closeOnClick: true
|
||||
},
|
||||
{
|
||||
label: "Next",
|
||||
className: "success",
|
||||
callback: () => {
|
||||
console.log('BUTTON CLICKED')
|
||||
}
|
||||
}
|
||||
])
|
||||
})
|
||||
|
||||
/*WA.onLeaveZone('popupZone', () => {
|
||||
WA.sendChatMessage("Thanks!", 'Poly Parrot');
|
||||
})*/
|
||||
|
@ -39,6 +39,24 @@
|
||||
"x":0,
|
||||
"y":0
|
||||
},
|
||||
{
|
||||
"data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 23, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
"height":10,
|
||||
"id":7,
|
||||
"name":"popupZone",
|
||||
"opacity":1,
|
||||
"properties":[
|
||||
{
|
||||
"name":"zone",
|
||||
"type":"string",
|
||||
"value":"popupZone"
|
||||
}],
|
||||
"type":"tilelayer",
|
||||
"visible":true,
|
||||
"width":10,
|
||||
"x":0,
|
||||
"y":0
|
||||
},
|
||||
{
|
||||
"data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
"height":10,
|
||||
@ -55,15 +73,26 @@
|
||||
"draworder":"topdown",
|
||||
"id":3,
|
||||
"name":"floorLayer",
|
||||
"objects":[],
|
||||
"objects":[
|
||||
{
|
||||
"height":120.377012261239,
|
||||
"id":1,
|
||||
"name":"myPopup",
|
||||
"rotation":0,
|
||||
"type":"",
|
||||
"visible":true,
|
||||
"width":162.815914588373,
|
||||
"x":77.4042872633247,
|
||||
"y":61.1226958044874
|
||||
}],
|
||||
"opacity":1,
|
||||
"type":"objectgroup",
|
||||
"visible":true,
|
||||
"x":0,
|
||||
"y":0
|
||||
}],
|
||||
"nextlayerid":7,
|
||||
"nextobjectid":1,
|
||||
"nextlayerid":8,
|
||||
"nextobjectid":2,
|
||||
"orientation":"orthogonal",
|
||||
"properties":[
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user