workadventure/front/src/WebRtc/DiscussionManager.ts

242 lines
8.8 KiB
TypeScript
Raw Normal View History

2020-10-25 21:59:14 +01:00
import {HtmlUtils} from "./HtmlUtils";
import {mediaManager, ReportCallback} from "./MediaManager";
2020-11-10 12:38:32 +01:00
import {UserInputManager} from "../Phaser/UserInput/UserInputManager";
import {connectionManager} from "../Connexion/ConnectionManager";
import {GameConnexionTypes} from "../Url/UrlManager";
2020-10-25 21:59:14 +01:00
export type SendMessageCallback = (message:string) => void;
export class DiscussionManager {
private mainContainer: HTMLDivElement;
private divDiscuss?: HTMLDivElement;
private divParticipants?: HTMLDivElement;
private nbpParticipants?: HTMLParagraphElement;
private divMessages?: HTMLParagraphElement;
private participants: Map<number|string, HTMLDivElement> = new Map<number|string, HTMLDivElement>();
private activeDiscussion: boolean = false;
2020-10-26 14:13:51 +01:00
private sendMessageCallBack : Map<number|string, SendMessageCallback> = new Map<number|string, SendMessageCallback>();
2020-10-25 21:59:14 +01:00
2020-11-10 12:38:32 +01:00
private userInputManager?: UserInputManager;
constructor() {
2020-10-25 21:59:14 +01:00
this.mainContainer = HtmlUtils.getElementByIdOrFail<HTMLDivElement>('main-container');
this.createDiscussPart(''); //todo: why do we always use empty string?
2020-10-25 21:59:14 +01:00
}
private createDiscussPart(name: string) {
this.divDiscuss = document.createElement('div');
this.divDiscuss.classList.add('discussion');
const buttonCloseDiscussion: HTMLButtonElement = document.createElement('button');
buttonCloseDiscussion.classList.add('close-btn');
buttonCloseDiscussion.innerHTML = `<img src="resources/logos/close.svg"/>`;
buttonCloseDiscussion.addEventListener('click', () => {
2020-11-10 12:38:32 +01:00
this.hideDiscussion();
2020-10-25 21:59:14 +01:00
});
this.divDiscuss.appendChild(buttonCloseDiscussion);
const myName: HTMLParagraphElement = document.createElement('p');
myName.innerText = name.toUpperCase();
this.nbpParticipants = document.createElement('p');
this.nbpParticipants.innerText = 'PARTICIPANTS (1)';
this.divParticipants = document.createElement('div');
this.divParticipants.classList.add('participants');
this.divMessages = document.createElement('div');
this.divMessages.classList.add('messages');
this.divMessages.innerHTML = "<h2>Local messages</h2>"
this.divDiscuss.appendChild(myName);
this.divDiscuss.appendChild(this.nbpParticipants);
this.divDiscuss.appendChild(this.divParticipants);
this.divDiscuss.appendChild(this.divMessages);
const sendDivMessage: HTMLDivElement = document.createElement('div');
sendDivMessage.classList.add('send-message');
const inputMessage: HTMLInputElement = document.createElement('input');
2021-01-06 13:36:18 +01:00
inputMessage.onfocus = () => {
if(this.userInputManager) {
this.userInputManager.clearAllInputKeyboard();
}
}
inputMessage.onblur = () => {
if(this.userInputManager) {
this.userInputManager.initKeyBoardEvent();
}
}
2020-10-25 21:59:14 +01:00
inputMessage.type = "text";
inputMessage.addEventListener('keyup', (event: KeyboardEvent) => {
if (event.key === 'Enter') {
event.preventDefault();
2020-11-10 12:38:32 +01:00
if(inputMessage.value === null
|| inputMessage.value === ''
|| inputMessage.value === undefined) {
return;
}
2020-10-25 21:59:14 +01:00
this.addMessage(name, inputMessage.value, true);
2020-10-26 14:13:51 +01:00
for(const callback of this.sendMessageCallBack.values()) {
2020-10-25 21:59:14 +01:00
callback(inputMessage.value);
}
inputMessage.value = "";
}
});
sendDivMessage.appendChild(inputMessage);
this.divDiscuss.appendChild(sendDivMessage);
//append in main container
this.mainContainer.appendChild(this.divDiscuss);
this.addParticipant('me', 'Moi', undefined, true);
}
2020-10-27 20:18:25 +01:00
public addParticipant(
userId: number|string,
name: string|undefined,
img?: string|undefined,
isMe: boolean = false,
reportCallback?: ReportCallback
) {
2020-10-25 21:59:14 +01:00
const divParticipant: HTMLDivElement = document.createElement('div');
divParticipant.classList.add('participant');
divParticipant.id = `participant-${userId}`;
const divImgParticipant: HTMLImageElement = document.createElement('img');
divImgParticipant.src = 'resources/logos/boy.svg';
if (img !== undefined) {
divImgParticipant.src = img;
}
const divPParticipant: HTMLParagraphElement = document.createElement('p');
if(!name){
name = 'Anonymous';
}
divPParticipant.innerText = name;
divParticipant.appendChild(divImgParticipant);
divParticipant.appendChild(divPParticipant);
if(
!isMe
&& connectionManager.getConnexionType
&& connectionManager.getConnexionType !== GameConnexionTypes.anonymous
) {
2020-10-25 21:59:14 +01:00
const reportBanUserAction: HTMLButtonElement = document.createElement('button');
reportBanUserAction.classList.add('report-btn')
reportBanUserAction.innerText = 'Report';
reportBanUserAction.addEventListener('click', () => {
2020-10-27 20:18:25 +01:00
if(reportCallback) {
mediaManager.showReportModal(`${userId}`, name ?? '', reportCallback);
2020-11-10 12:38:32 +01:00
}else{
console.info('report feature is not activated!');
2020-10-27 20:18:25 +01:00
}
2020-10-25 21:59:14 +01:00
});
divParticipant.appendChild(reportBanUserAction);
}
this.divParticipants?.appendChild(divParticipant);
2020-11-04 13:07:38 +01:00
2020-10-25 21:59:14 +01:00
this.participants.set(userId, divParticipant);
this.updateParticipant(this.participants.size);
}
public updateParticipant(nb: number) {
if (!this.nbpParticipants) {
return;
}
this.nbpParticipants.innerText = `PARTICIPANTS (${nb})`;
}
2021-03-16 20:27:06 +01:00
private escapeHtml(html: string): string {
const textReturn : HTMLSpanElement = document.createElement('span');
const text = document.createTextNode(html);
textReturn.innerText = text;
const p = document.createElement('p');
p.appendChild(text);
return p.innerHTML;
}
private urlify(text: string) : string {
const urlRegex = /(https?:\/\/[^\s]+)/g;
2021-03-16 20:27:06 +01:00
text = this.escapeHtml(text);
2021-01-06 12:20:02 +01:00
return text.replace(urlRegex, (url: string) => {
2021-03-16 20:27:06 +01:00
return '<a href="' + url + '" target="_blank" style=":visited {color: white}">' + url + '</a>';
});
2021-01-06 12:20:02 +01:00
}
2020-10-25 21:59:14 +01:00
public addMessage(name: string, message: string, isMe: boolean = false) {
const divMessage: HTMLDivElement = document.createElement('div');
divMessage.classList.add('message');
if(isMe){
divMessage.classList.add('me');
}
const pMessage: HTMLParagraphElement = document.createElement('p');
const date = new Date();
if(isMe){
name = 'Moi';
}
pMessage.innerHTML = `<span style="font-weight: bold">${name}</span>
<span style="color:#bac2cc;display:inline-block;font-size:12px;">
${date.getHours()}:${date.getMinutes()}
</span>`;
divMessage.appendChild(pMessage);
const userMessage: HTMLParagraphElement = document.createElement('p');
2021-01-06 13:36:18 +01:00
userMessage.innerHTML = this.urlify(message);
2020-10-25 21:59:14 +01:00
userMessage.classList.add('body');
divMessage.appendChild(userMessage);
this.divMessages?.appendChild(divMessage);
//automatic scroll when there are new message
setTimeout(() => {
this.divMessages?.scroll({
top: this.divMessages?.scrollTop + divMessage.getBoundingClientRect().y,
behavior: 'smooth'
});
}, 200);
2020-10-25 21:59:14 +01:00
}
public removeParticipant(userId: number|string){
const element = this.participants.get(userId);
if(element){
element.remove();
2020-11-04 13:07:38 +01:00
this.participants.delete(userId);
}
//if all participant leave, hide discussion button
2020-10-26 14:13:51 +01:00
this.sendMessageCallBack.delete(userId);
2020-10-25 21:59:14 +01:00
}
2020-10-26 14:13:51 +01:00
public onSendMessageCallback(userId: string|number, callback: SendMessageCallback): void {
this.sendMessageCallBack.set(userId, callback);
2020-10-25 21:59:14 +01:00
}
get activatedDiscussion(){
return this.activeDiscussion;
}
2020-11-04 13:07:38 +01:00
2020-11-10 12:38:32 +01:00
private showDiscussion(){
this.activeDiscussion = true;
this.divDiscuss?.classList.add('active');
}
private hideDiscussion(){
this.activeDiscussion = false;
this.divDiscuss?.classList.remove('active');
}
2020-11-10 12:38:32 +01:00
public setUserInputManager(userInputManager : UserInputManager){
this.userInputManager = userInputManager;
}
public showDiscussionPart(){
this.showDiscussion();
}
}
2021-03-16 20:27:06 +01:00
export const discussionManager = new DiscussionManager();