From f84c4b3276d79c55dd7f6cb33927e0b13864b4e7 Mon Sep 17 00:00:00 2001 From: Alexis Faizeau Date: Mon, 25 Oct 2021 18:42:51 +0200 Subject: [PATCH] Refacto insert cowebsite --- front/src/Api/Events/IframeEvent.ts | 6 +- front/src/Api/Events/OpenCoWebsiteEvent.ts | 2 +- front/src/Api/iframe/nav.ts | 21 ++- front/src/WebRtc/CoWebsiteManager.ts | 160 ++++++++------------- front/src/WebRtc/JitsiFactory.ts | 15 +- front/style/cowebsite.scss | 4 + 6 files changed, 98 insertions(+), 110 deletions(-) diff --git a/front/src/Api/Events/IframeEvent.ts b/front/src/Api/Events/IframeEvent.ts index 554e4545..9e31b46c 100644 --- a/front/src/Api/Events/IframeEvent.ts +++ b/front/src/Api/Events/IframeEvent.ts @@ -5,7 +5,7 @@ import type { ClosePopupEvent } from "./ClosePopupEvent"; import type { EnterLeaveEvent } from "./EnterLeaveEvent"; import type { GoToPageEvent } from "./GoToPageEvent"; import type { LoadPageEvent } from "./LoadPageEvent"; -import { coWebsite, isOpenCoWebsiteEvent } from "./OpenCoWebsiteEvent"; +import { isCoWebsite, isOpenCoWebsiteEvent } from "./OpenCoWebsiteEvent"; import type { OpenPopupEvent } from "./OpenPopupEvent"; import type { OpenTabEvent } from "./OpenTabEvent"; import type { UserInputChatEvent } from "./UserInputChatEvent"; @@ -114,11 +114,11 @@ export const iframeQueryMapTypeGuards = { }, openCoWebsite: { query: isOpenCoWebsiteEvent, - answer: coWebsite + answer: isCoWebsite }, getCoWebsites: { query: tg.isUndefined, - answer: tg.isArray(coWebsite) + answer: tg.isArray(isCoWebsite) }, closeCoWebsite: { query: tg.isString, diff --git a/front/src/Api/Events/OpenCoWebsiteEvent.ts b/front/src/Api/Events/OpenCoWebsiteEvent.ts index cc70b2e5..9c02b7a3 100644 --- a/front/src/Api/Events/OpenCoWebsiteEvent.ts +++ b/front/src/Api/Events/OpenCoWebsiteEvent.ts @@ -9,7 +9,7 @@ export const isOpenCoWebsiteEvent = new tg.IsInterface() }) .get(); -export const coWebsite = new tg.IsInterface() +export const isCoWebsite = new tg.IsInterface() .withProperties({ id: tg.isString, position: tg.isNumber, diff --git a/front/src/Api/iframe/nav.ts b/front/src/Api/iframe/nav.ts index 24b04e62..e91ded73 100644 --- a/front/src/Api/iframe/nav.ts +++ b/front/src/Api/iframe/nav.ts @@ -1,5 +1,16 @@ import { IframeApiContribution, sendToWorkadventure, queryWorkadventure } from "./IframeApiContribution"; +export class CoWebsite { + constructor(private readonly id: string, public readonly position: number) {} + + close() { + return queryWorkadventure({ + type: "closeCoWebsite", + data: this.id, + }); + } +} + export class WorkadventureNavigationCommands extends IframeApiContribution { callbacks = []; @@ -45,8 +56,8 @@ export class WorkadventureNavigationCommands extends IframeApiContribution { + const result = await queryWorkadventure({ type: "openCoWebsite", data: { url, @@ -55,13 +66,15 @@ export class WorkadventureNavigationCommands extends IframeApiContribution { + const result = await queryWorkadventure({ type: "getCoWebsites", data: undefined }); + return result.map((cowebsiteEvent) => new CoWebsite(cowebsiteEvent.id, cowebsiteEvent.position)); } /** diff --git a/front/src/WebRtc/CoWebsiteManager.ts b/front/src/WebRtc/CoWebsiteManager.ts index 06b29d18..0b2dc17d 100644 --- a/front/src/WebRtc/CoWebsiteManager.ts +++ b/front/src/WebRtc/CoWebsiteManager.ts @@ -442,138 +442,102 @@ class CoWebsiteManager { widthPercent?: number, position?: number ): Promise { - return new Promise((resolve, reject) => { - if (this.coWebsites.length < 1) { - this.loadMain(); - } else if (this.coWebsites.length === 5) { - return reject(); - } + return this.addCoWebsite((iframeBuffer) => { const iframe = document.createElement("iframe"); - - iframe?.classList.add("pixel"); - - do { - iframe.id = "cowebsite-iframe-" + (Math.random() + 1).toString(36).substring(7); - } while (iframe.id.toLowerCase().includes('jitsi') || this.getCoWebsiteById(iframe.id)); - iframe.src = new URL(url, base).toString() if (allowPolicy) { iframe.allow = allowPolicy; } - const onloadPromise = new Promise((resolve) => { - iframe.onload = () => resolve(); - }); - if (allowApi) { iframeListener.registerIframe(iframe); } - const icon = this.generateCoWebsiteIcon(iframe); + iframeBuffer.appendChild(iframe); - const coWebsite = { - iframe, - icon, - position: position ?? this.coWebsites.length, - }; - - // Iframe management on mobile - icon.addEventListener("click", () => { - if (this.isSmallScreen()) { - this.moveRightPreviousCoWebsite(coWebsite, 0); - } - }); - - this.coWebsites.push(coWebsite); - this.cowebsiteSubIconsDom.appendChild(icon); - this.cowebsiteBufferDom.appendChild(coWebsite.iframe); - - const onTimeoutPromise = new Promise((resolve) => { - setTimeout(() => resolve(), 2000); - }); - - this.currentOperationPromise = this.currentOperationPromise - .then(() => Promise.race([onloadPromise, onTimeoutPromise])) - .then(() => { - if (coWebsite.position === 0) { - this.openMain(); - if (widthPercent) { - this.widthPercent = widthPercent; - } - - setTimeout(() => { - this.fire(); - position ? - this.moveRightPreviousCoWebsite(coWebsite, coWebsite.position) : - this.moveCoWebsite(coWebsite, coWebsite.position); - }, animationTime); - } else { - position ? - this.moveRightPreviousCoWebsite(coWebsite, coWebsite.position) : - this.moveCoWebsite(coWebsite, coWebsite.position); - } - - return resolve(coWebsite); - }) - .catch((err) => { - console.error("Error loadCoWebsite => ", err); - this.removeCoWebsiteFromStack(coWebsite); - return reject(); - }); - }); + return iframe; + }, widthPercent, position); } - /** - * Just like loadCoWebsite but the div can be filled by the user. - */ - public insertCoWebsite(callback: (jitsiBuffer: HTMLDivElement) => Promise, widthPercent?: number): void { - if (this.coWebsites.length < 1) { - this.loadMain(); - } else if (this.coWebsites.length === 5) { - return; - } + public async addCoWebsite( + callback: (iframeBuffer: HTMLDivElement) => PromiseLike|HTMLIFrameElement, + widthPercent?: number, + position?: number + ): Promise { + return new Promise((resolve, reject) => { + if (this.coWebsites.length < 1) { + this.loadMain(); + } else if (this.coWebsites.length === 5) { + throw new Error('Too many we') + } - this.currentOperationPromise = this.currentOperationPromise - .then(() => callback(this.cowebsiteBufferDom)) - .then(() => { - const iframe = this.cowebsiteBufferDom.querySelector('[id*="jitsi" i]'); + Promise.resolve(callback(this.cowebsiteBufferDom)).then(iframe =>{ iframe?.classList.add("pixel"); - if (!iframe) { - console.error("Error insertCoWebsite => Cannot find Iframe Element on Jitsi DOM"); - return; + if (!iframe.id) { + do { + iframe.id = "cowebsite-iframe-" + (Math.random() + 1).toString(36).substring(7); + } while (this.getCoWebsiteById(iframe.id)); } + const onloadPromise = new Promise((resolve) => { + iframe.onload = () => resolve(); + }); + const icon = this.generateCoWebsiteIcon(iframe); const coWebsite = { iframe, icon, - position: 0, + position: position ?? this.coWebsites.length, }; + // Iframe management on mobile + icon.addEventListener("click", () => { + if (this.isSmallScreen()) { + this.moveRightPreviousCoWebsite(coWebsite, 0); + } + }); + this.coWebsites.push(coWebsite); this.cowebsiteSubIconsDom.appendChild(icon); - if (coWebsite.position === 0) { - this.openMain(); + const onTimeoutPromise = new Promise((resolve) => { + setTimeout(() => resolve(), 2000); + }); - if (widthPercent) { - this.widthPercent = widthPercent; - } + this.currentOperationPromise = this.currentOperationPromise + .then(() => Promise.race([onloadPromise, onTimeoutPromise])) + .then(() => { + if (coWebsite.position === 0) { + this.openMain(); + if (widthPercent) { + this.widthPercent = widthPercent; + } - setTimeout(() => { - this.fire(); - }, animationTime); - } + setTimeout(() => { + this.fire(); + position !== undefined ? + this.moveRightPreviousCoWebsite(coWebsite, coWebsite.position) : + this.moveCoWebsite(coWebsite, coWebsite.position); + }, animationTime); + } else { + position !== undefined ? + this.moveRightPreviousCoWebsite(coWebsite, coWebsite.position) : + this.moveCoWebsite(coWebsite, coWebsite.position); + } - this.moveRightPreviousCoWebsite(coWebsite, coWebsite.position); - }) - .catch((err) => { - console.error("Error insertCoWebsite => ", err); + return resolve(coWebsite); + }) + .catch((err) => { + console.error("Error loadCoWebsite => ", err); + this.removeCoWebsiteFromStack(coWebsite); + return reject(); + }); }); + }); } public closeCoWebsite(coWebsite: CoWebsite): Promise { diff --git a/front/src/WebRtc/JitsiFactory.ts b/front/src/WebRtc/JitsiFactory.ts index 5a1a4b91..df647f55 100644 --- a/front/src/WebRtc/JitsiFactory.ts +++ b/front/src/WebRtc/JitsiFactory.ts @@ -141,7 +141,7 @@ class JitsiFactory { jitsiUrl?: string, jitsiWidth?: number ): void { - coWebsiteManager.insertCoWebsite(async (cowebsiteDiv) => { + coWebsiteManager.addCoWebsite(async (cowebsiteDiv) => { // Jitsi meet external API maintains some data in local storage // which is sent via the appData URL parameter when joining a // conference. Problem is that this data grows indefinitely. Thus @@ -170,15 +170,22 @@ class JitsiFactory { } return new Promise((resolve, reject) => { - options.onload = () => resolve(); //we want for the iframe to be loaded before triggering animations. - setTimeout(() => resolve(), 2000); //failsafe in case the iframe is deleted before loading or too long to load + const doResolve = (): void => { + const iframe = cowebsiteDiv.querySelector('[id*="jitsi" i]'); + if (iframe === null) { + throw new Error("Could not find Jitsi Iframe"); + } + resolve(iframe); + } + options.onload = () => doResolve(); //we want for the iframe to be loaded before triggering animations. + setTimeout(() => doResolve(), 2000); //failsafe in case the iframe is deleted before loading or too long to load this.jitsiApi = new window.JitsiMeetExternalAPI(domain, options); this.jitsiApi.executeCommand("displayName", playerName); this.jitsiApi.addListener("audioMuteStatusChanged", this.audioCallback); this.jitsiApi.addListener("videoMuteStatusChanged", this.videoCallback); }); - }, jitsiWidth); + }, jitsiWidth, 0); } public stop() { diff --git a/front/style/cowebsite.scss b/front/style/cowebsite.scss index 223ed85a..8feb517d 100644 --- a/front/style/cowebsite.scss +++ b/front/style/cowebsite.scss @@ -170,6 +170,10 @@ .sub-main { pointer-events: all !important; } + + .thumbnail { + transform: scale(0.5, 0.5); + } } .pixel {