Adding ability to listen to user types chat messages using WA.onChatMessage

This commit is contained in:
David Négrier 2021-03-06 15:26:07 +01:00
parent 5178dff108
commit e927e0fa16
7 changed files with 82 additions and 10 deletions

View File

@ -5,4 +5,7 @@ export const isChatEvent =
message: tg.isString, message: tg.isString,
author: tg.isString, author: tg.isString,
}).get(); }).get();
/**
* A message sent from the iFrame to the game to add a message in the chat.
*/
export type ChatEvent = tg.GuardedType<typeof isChatEvent>; export type ChatEvent = tg.GuardedType<typeof isChatEvent>;

View File

@ -1,4 +1,4 @@
interface IframeEvent { export interface IframeEvent {
type: string; type: string;
data: unknown; data: unknown;
} }

View File

@ -0,0 +1,10 @@
import * as tg from "generic-type-guard";
export const isUserInputChatEvent =
new tg.IsInterface().withProperties({
message: tg.isString,
}).get();
/**
* A message sent from the game to the iFrame when a user types a message in the chat.
*/
export type UserInputChatEvent = tg.GuardedType<typeof isUserInputChatEvent>;

View File

@ -1,6 +1,7 @@
import {Subject} from "rxjs"; import {Subject} from "rxjs";
import {ChatEvent, isChatEvent} from "./Events/ChatEvent"; import {ChatEvent, isChatEvent} from "./Events/ChatEvent";
import {isIframeEventWrapper} from "./Events/IframeEvent"; import {IframeEvent, isIframeEventWrapper} from "./Events/IframeEvent";
import {UserInputChatEvent} from "./Events/UserInputChatEvent";
@ -12,15 +13,15 @@ class IframeListener {
public readonly chatStream = this._chatStream.asObservable(); public readonly chatStream = this._chatStream.asObservable();
init() { init() {
window.addEventListener("message", (event) => { window.addEventListener("message", (message) => {
// Do we trust the sender of this message? // Do we trust the sender of this message?
//if (event.origin !== "http://example.com:8080") //if (message.origin !== "http://example.com:8080")
// return; // return;
// event.source is window.opener // message.source is window.opener
// event.data is the data sent by the iframe // message.data is the data sent by the iframe
const payload = event.data; const payload = message.data;
if (isIframeEventWrapper(payload)) { if (isIframeEventWrapper(payload)) {
if (payload.type === 'chat' && isChatEvent(payload.data)) { if (payload.type === 'chat' && isChatEvent(payload.data)) {
this._chatStream.next(payload.data); this._chatStream.next(payload.data);
@ -29,6 +30,27 @@ class IframeListener {
}, false); }, false);
}
sendUserInputChat(message: string) {
this.postMessage({
'type': 'userInputChat',
'data': {
'message': message,
} as UserInputChatEvent
});
}
/**
* Sends the message... to absolutely all the iFrames that can be found in the current document.
*/
private postMessage(message: IframeEvent) {
// TODO: not the most effecient implementation if there are many events sent!
for (const iframe of document.querySelectorAll<HTMLIFrameElement>('iframe')) {
iframe.contentWindow?.postMessage(message, '*');
}
} }
} }

View File

@ -31,6 +31,9 @@ export class DiscussionManager {
this.addMessage(chatEvent.author, chatEvent.message, false); this.addMessage(chatEvent.author, chatEvent.message, false);
this.showDiscussion(); this.showDiscussion();
}); });
this.onSendMessageCallback('iframe_listener', (message) => {
iframeListener.sendUserInputChat(message);
})
} }
private createDiscussPart(name: string) { private createDiscussPart(name: string) {

View File

@ -1,4 +1,7 @@
import {ChatEvent} from "./Api/Events/ChatEvent"; import {ChatEvent, isChatEvent} from "./Api/Events/ChatEvent";
import {isIframeEventWrapper} from "./Api/Events/IframeEvent";
import {isUserInputChatEvent, UserInputChatEvent} from "./Api/Events/UserInputChatEvent";
import {Subject} from "rxjs";
interface WorkAdventureApi { interface WorkAdventureApi {
sendChatMessage(message: string, author: string): void; sendChatMessage(message: string, author: string): void;
@ -10,6 +13,11 @@ declare global {
var WA: WorkAdventureApi var WA: WorkAdventureApi
} }
type ChatMessageCallback = (message: string) => void;
const userInputChatStream: Subject<UserInputChatEvent> = new Subject();
window.WA = { window.WA = {
/** /**
* Send a message in the chat. * Send a message in the chat.
@ -27,7 +35,25 @@ window.WA = {
/** /**
* 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): void { onChatMessage(callback: ChatMessageCallback): void {
userInputChatStream.subscribe((userInputChatEvent) => {
callback(userInputChatEvent.message);
});
} }
} }
window.addEventListener('message', message => {
if (message.source !== window.parent) {
console.log('MESSAGE SKIPPED!!!')
return; // Skip message in this event listener
}
const payload = message.data;
if (isIframeEventWrapper(payload)) {
if (payload.type === 'userInputChat' && isUserInputChatEvent(payload.data)) {
userInputChatStream.next(payload.data);
}
}
// ...
});

View File

@ -13,5 +13,13 @@
WA.sendChatMessage('Hello world!', 'Mr Robot'); WA.sendChatMessage('Hello world!', 'Mr Robot');
} }
</script> </script>
<div id="chatSent"></div>
<script>
WA.onChatMessage((message => {
const chatDiv = document.createElement('p');
chatDiv.innerText = message;
document.getElementById('chatSent').append(chatDiv);
}));
</script>
</body> </body>
</html> </html>