-
+
+
-
+
diff --git a/front/dist/resources/style/style.css b/front/dist/resources/style/style.css
index 5f5d37f2..edd3ddf0 100644
--- a/front/dist/resources/style/style.css
+++ b/front/dist/resources/style/style.css
@@ -242,15 +242,10 @@ body {
.main-container {
height: 100vh;
width: 100vw;
- display: flex;
- align-items: stretch;
+ position: absolute;
}
@media (min-aspect-ratio: 1/1) {
- .main-container {
- flex-direction: row;
- }
-
.game-overlay {
flex-direction: row;
}
@@ -266,12 +261,21 @@ body {
.sidebar > div:hover {
max-height: 25%;
}
+
+ #cowebsite {
+ right: 0;
+ top: 0;
+ width: 50%;
+ height: 100vh;
+ }
+ #cowebsite.loading {
+ transform: translateX(90%);
+ }
+ #cowebsite.hidden {
+ transform: translateX(100%);
+ }
}
@media (max-aspect-ratio: 1/1) {
- .main-container {
- flex-direction: column;
- }
-
.game-overlay {
flex-direction: column;
}
@@ -288,24 +292,36 @@ body {
.sidebar > div:hover {
max-width: 25%;
}
+
+ #cowebsite {
+ left: 0;
+ bottom: 0;
+ width: 100%;
+ height: 50%;
+ }
+ #cowebsite.loading {
+ transform: translateY(90%);
+ }
+ #cowebsite.hidden {
+ transform: translateY(100%);
+ }
}
-.game {
- flex-basis: 100%;
+#game {
+ width: 100%;
position: relative; /* Position relative is needed for the game-overlay. */
}
/* A potentially shared website could appear in an iframe in the cowebsite space. */
-.cowebsite {
- flex-basis: 100%;
- transition: flex-basis 0.5s;
+#cowebsite {
+ position: fixed;
+ transition: transform 0.5s;
+}
+#cowebsite.loading {
+ background-color: gray;
}
-/*.cowebsite:hover {
- flex-basis: 100%;
-}*/
-
-.cowebsite > iframe {
+#cowebsite > iframe {
width: 100%;
height: 100%;
}
diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts
index bfc6402e..96648255 100644
--- a/front/src/Phaser/Game/GameScene.ts
+++ b/front/src/Phaser/Game/GameScene.ts
@@ -38,7 +38,7 @@ import CanvasTexture = Phaser.Textures.CanvasTexture;
import GameObject = Phaser.GameObjects.GameObject;
import FILE_LOAD_ERROR = Phaser.Loader.Events.FILE_LOAD_ERROR;
import {GameMap} from "./GameMap";
-import {CoWebsiteManager} from "../../WebRtc/CoWebsiteManager";
+import {coWebsiteManager} from "../../WebRtc/CoWebsiteManager";
import {mediaManager} from "../../WebRtc/MediaManager";
import {FourOFourSceneName} from "../Reconnecting/FourOFourScene";
import {ItemFactoryInterface} from "../Items/ItemFactoryInterface";
@@ -292,13 +292,6 @@ export class GameScene extends ResizableScene implements CenterListener {
// });
// });
}
-
- // TEST: let's load a module dynamically!
- /*let foo = "http://maps.workadventure.localhost/computer.js";
- import(/* webpackIgnore: true * / foo).then(result => {
- console.log(result);
-
- });*/
}
//hook initialisation
@@ -476,9 +469,9 @@ export class GameScene extends ResizableScene implements CenterListener {
this.gameMap.onPropertyChange('openWebsite', (newValue, oldValue) => {
if (newValue === undefined) {
- CoWebsiteManager.closeCoWebsite();
+ coWebsiteManager.closeCoWebsite();
} else {
- CoWebsiteManager.loadCoWebsite(newValue as string);
+ coWebsiteManager.loadCoWebsite(newValue as string);
}
});
this.gameMap.onPropertyChange('jitsiRoom', (newValue, oldValue, allProps) => {
diff --git a/front/src/WebRtc/CoWebsiteManager.ts b/front/src/WebRtc/CoWebsiteManager.ts
index 1793335b..ab63e60a 100644
--- a/front/src/WebRtc/CoWebsiteManager.ts
+++ b/front/src/WebRtc/CoWebsiteManager.ts
@@ -2,47 +2,90 @@ import {HtmlUtils} from "./HtmlUtils";
export type CoWebsiteStateChangedCallback = () => void;
-export class CoWebsiteManager {
+enum iframeStates {
+ closed = 1,
+ loading, // loading an iframe can be slow, so we show some placeholder until it is ready
+ opened,
+}
- private static observers = new Array();
+const cowebsiteDivId = "cowebsite"; // the id of the parent div of the iframe.
+const animationTime = 500; //time used by the css transitions, in ms.
- public static loadCoWebsite(url: string): void {
- const cowebsiteDiv = HtmlUtils.getElementByIdOrFail("cowebsite");
+class CoWebsiteManager {
+
+ private opened: iframeStates = iframeStates.closed;
+
+ private observers = new Array();
+
+ private close(): HTMLDivElement {
+ const cowebsiteDiv = HtmlUtils.getElementByIdOrFail(cowebsiteDivId);
+ cowebsiteDiv.classList.remove('loaded'); //edit the css class to trigger the transition
+ cowebsiteDiv.classList.add('hidden');
+ this.opened = iframeStates.closed;
+ return cowebsiteDiv;
+ }
+ private load(): HTMLDivElement {
+ const cowebsiteDiv = HtmlUtils.getElementByIdOrFail(cowebsiteDivId);
+ cowebsiteDiv.classList.remove('hidden'); //edit the css class to trigger the transition
+ cowebsiteDiv.classList.add('loading');
+ this.opened = iframeStates.loading;
+ return cowebsiteDiv;
+ }
+ private open(): HTMLDivElement {
+ const cowebsiteDiv = HtmlUtils.getElementByIdOrFail(cowebsiteDivId);
+ cowebsiteDiv.classList.remove('loading', 'hidden'); //edit the css class to trigger the transition
+ this.opened = iframeStates.opened;
+ return cowebsiteDiv;
+ }
+
+ public loadCoWebsite(url: string): void {
+ const cowebsiteDiv = this.load();
cowebsiteDiv.innerHTML = '';
const iframe = document.createElement('iframe');
iframe.id = 'cowebsite-iframe';
iframe.src = url;
+ const onloadPromise = new Promise((resolve) => {
+ iframe.onload = () => resolve();
+ });
cowebsiteDiv.appendChild(iframe);
- //iframe.onload = () => {
- // onload can be long to trigger. Maybe we should display the website, whatever happens, after 1 second?
- CoWebsiteManager.fire();
- //}
+ const onTimeoutPromise = new Promise((resolve) => {
+ setTimeout(() => resolve(), 2000);
+ });
+ Promise.race([onloadPromise, onTimeoutPromise]).then(() => {
+ this.open();
+ setTimeout(() => {
+ this.fire();
+ }, animationTime)
+ });
}
/**
* Just like loadCoWebsite but the div can be filled by the user.
*/
- public static insertCoWebsite(callback: (cowebsite: HTMLDivElement) => void): void {
- const cowebsiteDiv = HtmlUtils.getElementByIdOrFail("cowebsite");
- cowebsiteDiv.innerHTML = '';
-
- callback(cowebsiteDiv);
- //iframe.onload = () => {
- // onload can be long to trigger. Maybe we should display the website, whatever happens, after 1 second?
- CoWebsiteManager.fire();
- //}
+ public insertCoWebsite(callback: (cowebsite: HTMLDivElement) => Promise): void {
+ const cowebsiteDiv = this.load();
+ callback(cowebsiteDiv).then(() => {
+ this.open();
+ setTimeout(() => {
+ this.fire();
+ }, animationTime)
+ });
}
- public static closeCoWebsite(): void {
- const cowebsiteDiv = HtmlUtils.getElementByIdOrFail("cowebsite");
- cowebsiteDiv.innerHTML = '';
- CoWebsiteManager.fire();
+ public closeCoWebsite(): Promise {
+ return new Promise((resolve, reject) => {
+ const cowebsiteDiv = this.close();
+ this.fire();
+ setTimeout(() => {
+ resolve();
+ setTimeout(() => cowebsiteDiv.innerHTML = '', 500)
+ }, animationTime)
+ });
}
- public static getGameSize(): {width: number, height: number} {
- const hasChildren = HtmlUtils.getElementByIdOrFail("cowebsite").children.length > 0;
- if (hasChildren === false) {
+ public getGameSize(): {width: number, height: number} {
+ if (this.opened !== iframeStates.opened) {
return {
width: window.innerWidth,
height: window.innerHeight
@@ -61,13 +104,15 @@ export class CoWebsiteManager {
}
}
- public static onStateChange(observer: CoWebsiteStateChangedCallback) {
- CoWebsiteManager.observers.push(observer);
+ public onStateChange(observer: CoWebsiteStateChangedCallback) {
+ this.observers.push(observer);
}
- private static fire(): void {
- for (const callback of CoWebsiteManager.observers) {
+ private fire(): void {
+ for (const callback of this.observers) {
callback();
}
}
}
+
+export const coWebsiteManager = new CoWebsiteManager();
\ No newline at end of file
diff --git a/front/src/WebRtc/JitsiFactory.ts b/front/src/WebRtc/JitsiFactory.ts
index 191642fb..45b9b3cf 100644
--- a/front/src/WebRtc/JitsiFactory.ts
+++ b/front/src/WebRtc/JitsiFactory.ts
@@ -1,6 +1,6 @@
-import {CoWebsiteManager} from "./CoWebsiteManager";
import {JITSI_URL} from "../Enum/EnvironmentVariable";
import {mediaManager} from "./MediaManager";
+import {coWebsiteManager} from "./CoWebsiteManager";
declare const window:any; // eslint-disable-line @typescript-eslint/no-explicit-any
const interfaceConfig = {
@@ -31,9 +31,9 @@ class JitsiFactory {
private videoCallback = this.onVideoChange.bind(this);
public start(roomName: string, playerName:string, jwt?: string): void {
- CoWebsiteManager.insertCoWebsite((cowebsiteDiv => {
+ coWebsiteManager.insertCoWebsite((cowebsiteDiv => {
const domain = JITSI_URL;
- const options = {
+ const options: any = { // eslint-disable-line @typescript-eslint/no-explicit-any
roomName: roomName,
jwt: jwt,
width: "100%",
@@ -49,19 +49,23 @@ class JitsiFactory {
if (!options.jwt) {
delete options.jwt;
}
- this.jitsiApi = new window.JitsiMeetExternalAPI(domain, options);
- this.jitsiApi.executeCommand('displayName', playerName);
+
+ return new Promise((resolve) => {
+ options.onload = () => resolve(); //we want for the iframe to be loaded before triggering animations.
+ this.jitsiApi = new window.JitsiMeetExternalAPI(domain, options);
+ this.jitsiApi.executeCommand('displayName', playerName);
- this.jitsiApi.addListener('audioMuteStatusChanged', this.audioCallback);
- this.jitsiApi.addListener('videoMuteStatusChanged', this.videoCallback);
+ this.jitsiApi.addListener('audioMuteStatusChanged', this.audioCallback);
+ this.jitsiApi.addListener('videoMuteStatusChanged', this.videoCallback);
+ });
}));
}
- public stop(): void {
+ public async stop(): Promise {
+ await coWebsiteManager.closeCoWebsite();
this.jitsiApi.removeListener('audioMuteStatusChanged', this.audioCallback);
this.jitsiApi.removeListener('videoMuteStatusChanged', this.videoCallback);
this.jitsiApi?.dispose();
- CoWebsiteManager.closeCoWebsite();
}
private onAudioChange({muted}: {muted: boolean}): void {
diff --git a/front/src/index.ts b/front/src/index.ts
index e12d8707..fe7ceb34 100644
--- a/front/src/index.ts
+++ b/front/src/index.ts
@@ -10,12 +10,9 @@ import {FourOFourScene} from "./Phaser/Reconnecting/FourOFourScene";
import WebGLRenderer = Phaser.Renderer.WebGL.WebGLRenderer;
import {OutlinePipeline} from "./Phaser/Shaders/OutlinePipeline";
import {CustomizeScene} from "./Phaser/Login/CustomizeScene";
-import {CoWebsiteManager} from "./WebRtc/CoWebsiteManager";
-import {gameManager} from "./Phaser/Game/GameManager";
import {ResizableScene} from "./Phaser/Login/ResizableScene";
import {EntryScene} from "./Phaser/Login/EntryScene";
-
-//CoWebsiteManager.loadCoWebsite('https://thecodingmachine.com');
+import {coWebsiteManager} from "./WebRtc/CoWebsiteManager";
// Load Jitsi if the environment variable is set.
if (JITSI_URL) {
@@ -24,7 +21,7 @@ if (JITSI_URL) {
document.head.appendChild(jitsiScript);
}
-const {width, height} = CoWebsiteManager.getGameSize();
+const {width, height} = coWebsiteManager.getGameSize();
const config: GameConfig = {
title: "WorkAdventure",
@@ -53,8 +50,7 @@ cypressAsserter.gameStarted();
const game = new Phaser.Game(config);
window.addEventListener('resize', function (event) {
- const {width, height} = CoWebsiteManager.getGameSize();
-
+ const {width, height} = coWebsiteManager.getGameSize();
game.scale.resize(width / RESOLUTION, height / RESOLUTION);
// Let's trigger the onResize method of any active scene that is a ResizableScene
@@ -64,8 +60,7 @@ window.addEventListener('resize', function (event) {
}
}
});
-CoWebsiteManager.onStateChange(() => {
- const {width, height} = CoWebsiteManager.getGameSize();
-
+coWebsiteManager.onStateChange(() => {
+ const {width, height} = coWebsiteManager.getGameSize();
game.scale.resize(width / RESOLUTION, height / RESOLUTION);
});
-
-
-
-
@@ -88,7 +72,7 @@