merged develop
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
import type CancelablePromise from "cancelable-promise";
|
||||
import type { Readable, Writable } from "svelte/store";
|
||||
|
||||
export type CoWebsiteState = "asleep" | "loading" | "ready";
|
||||
|
||||
export interface CoWebsite {
|
||||
getId(): string;
|
||||
getUrl(): URL;
|
||||
getState(): CoWebsiteState;
|
||||
getStateSubscriber(): Readable<CoWebsiteState>;
|
||||
getIframe(): HTMLIFrameElement | undefined;
|
||||
getLoadIframe(): CancelablePromise<HTMLIFrameElement> | undefined;
|
||||
getWidthPercent(): number | undefined;
|
||||
isClosable(): boolean;
|
||||
load(): CancelablePromise<HTMLIFrameElement>;
|
||||
unload(): Promise<void>;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
import CancelablePromise from "cancelable-promise";
|
||||
import { gameManager } from "../../Phaser/Game/GameManager";
|
||||
import { coWebsiteManager } from "../CoWebsiteManager";
|
||||
import { jitsiFactory } from "../JitsiFactory";
|
||||
import { SimpleCoWebsite } from "./SimpleCoWebsite";
|
||||
|
||||
export class JitsiCoWebsite extends SimpleCoWebsite {
|
||||
private jitsiLoadPromise?: () => CancelablePromise<HTMLIFrameElement>;
|
||||
|
||||
constructor(url: URL, allowApi?: boolean, allowPolicy?: string, widthPercent?: number, closable?: boolean) {
|
||||
const coWebsite = coWebsiteManager.searchJitsi();
|
||||
|
||||
if (coWebsite) {
|
||||
coWebsiteManager.closeCoWebsite(coWebsite);
|
||||
}
|
||||
|
||||
super(url, allowApi, allowPolicy, widthPercent, closable);
|
||||
}
|
||||
|
||||
setJitsiLoadPromise(promise: () => CancelablePromise<HTMLIFrameElement>): void {
|
||||
this.jitsiLoadPromise = promise;
|
||||
}
|
||||
|
||||
load(): CancelablePromise<HTMLIFrameElement> {
|
||||
return new CancelablePromise((resolve, reject, cancel) => {
|
||||
this.state.set("loading");
|
||||
|
||||
gameManager.getCurrentGameScene().disableMediaBehaviors();
|
||||
jitsiFactory.restart();
|
||||
|
||||
if (!this.jitsiLoadPromise) {
|
||||
return reject("Undefined Jitsi start callback");
|
||||
}
|
||||
|
||||
const jitsiLoading = this.jitsiLoadPromise()
|
||||
.then((iframe) => {
|
||||
this.iframe = iframe;
|
||||
this.iframe.classList.add("pixel");
|
||||
this.state.set("ready");
|
||||
return resolve(iframe);
|
||||
})
|
||||
.catch((err) => {
|
||||
return reject(err);
|
||||
});
|
||||
|
||||
cancel(() => {
|
||||
jitsiLoading.cancel();
|
||||
this.unload().catch((err) => {
|
||||
console.error("Cannot unload Jitsi co-website while cancel loading", err);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
unload(): Promise<void> {
|
||||
jitsiFactory.destroy();
|
||||
gameManager.getCurrentGameScene().enableMediaBehaviors();
|
||||
|
||||
return super.unload();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
import CancelablePromise from "cancelable-promise";
|
||||
import { get, Readable, writable, Writable } from "svelte/store";
|
||||
import { iframeListener } from "../../Api/IframeListener";
|
||||
import { coWebsiteManager } from "../CoWebsiteManager";
|
||||
import type { CoWebsite, CoWebsiteState } from "./CoWesbite";
|
||||
|
||||
export class SimpleCoWebsite implements CoWebsite {
|
||||
protected id: string;
|
||||
protected url: URL;
|
||||
protected state: Writable<CoWebsiteState>;
|
||||
protected iframe?: HTMLIFrameElement;
|
||||
protected loadIframe?: CancelablePromise<HTMLIFrameElement>;
|
||||
protected allowApi?: boolean;
|
||||
protected allowPolicy?: string;
|
||||
protected widthPercent?: number;
|
||||
protected closable: boolean;
|
||||
|
||||
constructor(url: URL, allowApi?: boolean, allowPolicy?: string, widthPercent?: number, closable?: boolean) {
|
||||
this.id = coWebsiteManager.generateUniqueId();
|
||||
this.url = url;
|
||||
this.state = writable("asleep" as CoWebsiteState);
|
||||
this.allowApi = allowApi;
|
||||
this.allowPolicy = allowPolicy;
|
||||
this.widthPercent = widthPercent;
|
||||
this.closable = closable ?? false;
|
||||
}
|
||||
|
||||
getId(): string {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
getUrl(): URL {
|
||||
return this.url;
|
||||
}
|
||||
|
||||
getState(): CoWebsiteState {
|
||||
return get(this.state);
|
||||
}
|
||||
|
||||
getStateSubscriber(): Readable<CoWebsiteState> {
|
||||
return this.state;
|
||||
}
|
||||
|
||||
getIframe(): HTMLIFrameElement | undefined {
|
||||
return this.iframe;
|
||||
}
|
||||
|
||||
getLoadIframe(): CancelablePromise<HTMLIFrameElement> | undefined {
|
||||
return this.loadIframe;
|
||||
}
|
||||
|
||||
getWidthPercent(): number | undefined {
|
||||
return this.widthPercent;
|
||||
}
|
||||
|
||||
isClosable(): boolean {
|
||||
return this.closable;
|
||||
}
|
||||
|
||||
load(): CancelablePromise<HTMLIFrameElement> {
|
||||
this.loadIframe = new CancelablePromise((resolve, reject, cancel) => {
|
||||
this.state.set("loading");
|
||||
|
||||
const iframe = document.createElement("iframe");
|
||||
this.iframe = iframe;
|
||||
this.iframe.src = this.url.toString();
|
||||
this.iframe.id = this.id;
|
||||
|
||||
if (this.allowPolicy) {
|
||||
this.iframe.allow = this.allowPolicy;
|
||||
}
|
||||
|
||||
if (this.allowApi) {
|
||||
iframeListener.registerIframe(this.iframe);
|
||||
}
|
||||
|
||||
this.iframe.classList.add("pixel");
|
||||
|
||||
const onloadPromise = new Promise<void>((resolve) => {
|
||||
if (this.iframe) {
|
||||
this.iframe.onload = () => {
|
||||
this.state.set("ready");
|
||||
resolve();
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
const onTimeoutPromise = new Promise<void>((resolve) => {
|
||||
setTimeout(() => resolve(), 2000);
|
||||
});
|
||||
|
||||
coWebsiteManager.getCoWebsiteBuffer().appendChild(this.iframe);
|
||||
|
||||
const race = CancelablePromise.race([onloadPromise, onTimeoutPromise])
|
||||
.then(() => {
|
||||
return resolve(iframe);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("Error on co-website loading => ", err);
|
||||
return reject();
|
||||
});
|
||||
|
||||
cancel(() => {
|
||||
race.cancel();
|
||||
this.unload().catch((err) => {
|
||||
console.error("Cannot unload co-website while cancel loading", err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return this.loadIframe;
|
||||
}
|
||||
|
||||
unload(): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
if (this.iframe) {
|
||||
if (this.allowApi) {
|
||||
iframeListener.unregisterIframe(this.iframe);
|
||||
}
|
||||
this.iframe.parentNode?.removeChild(this.iframe);
|
||||
}
|
||||
|
||||
if (this.loadIframe) {
|
||||
this.loadIframe.cancel();
|
||||
this.loadIframe = undefined;
|
||||
}
|
||||
|
||||
this.state.set("asleep");
|
||||
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,13 @@
|
||||
import { HtmlUtils } from "./HtmlUtils";
|
||||
import { Subject } from "rxjs";
|
||||
import { iframeListener } from "../Api/IframeListener";
|
||||
import { waScaleManager } from "../Phaser/Services/WaScaleManager";
|
||||
import { coWebsites, coWebsitesNotAsleep, mainCoWebsite } from "../Stores/CoWebsiteStore";
|
||||
import { get, Writable, writable } from "svelte/store";
|
||||
import { coWebsites, coWebsitesNotAsleep, jitsiCoWebsite, mainCoWebsite } from "../Stores/CoWebsiteStore";
|
||||
import { get } from "svelte/store";
|
||||
import { embedScreenLayout, highlightedEmbedScreen } from "../Stores/EmbedScreensStore";
|
||||
import { isMediaBreakpointDown } from "../Utils/BreakpointsUtils";
|
||||
import { jitsiFactory } from "./JitsiFactory";
|
||||
import { gameManager } from "../Phaser/Game/GameManager";
|
||||
import { LayoutMode } from "./LayoutManager";
|
||||
import type { CoWebsite } from "./CoWebsite/CoWesbite";
|
||||
import type CancelablePromise from "cancelable-promise";
|
||||
|
||||
export enum iframeStates {
|
||||
closed = 1,
|
||||
@@ -34,30 +33,12 @@ interface TouchMoveCoordinates {
|
||||
y: number;
|
||||
}
|
||||
|
||||
export type CoWebsiteState = "asleep" | "loading" | "ready";
|
||||
|
||||
export type CoWebsite = {
|
||||
iframe: HTMLIFrameElement;
|
||||
url: URL;
|
||||
state: Writable<CoWebsiteState>;
|
||||
closable: boolean;
|
||||
allowPolicy: string | undefined;
|
||||
allowApi: boolean | undefined;
|
||||
widthPercent?: number | undefined;
|
||||
jitsi?: boolean;
|
||||
altMessage?: string;
|
||||
};
|
||||
|
||||
class CoWebsiteManager {
|
||||
private openedMain: iframeStates = iframeStates.closed;
|
||||
|
||||
private _onResize: Subject<void> = new Subject();
|
||||
public onResize = this._onResize.asObservable();
|
||||
/**
|
||||
* Quickly going in and out of an iframe trigger can create conflicts between the iframe states.
|
||||
* So we use this promise to queue up every cowebsite state transition
|
||||
*/
|
||||
private currentOperationPromise: Promise<void> = Promise.resolve();
|
||||
|
||||
private cowebsiteDom: HTMLDivElement;
|
||||
private resizing: boolean = false;
|
||||
private gameOverlayDom: HTMLDivElement;
|
||||
@@ -147,13 +128,11 @@ class CoWebsiteManager {
|
||||
throw new Error("Undefined main co-website on closing");
|
||||
}
|
||||
|
||||
if (coWebsite.closable) {
|
||||
this.closeCoWebsite(coWebsite).catch(() => {
|
||||
console.error("Error during closing a co-website by a button");
|
||||
});
|
||||
if (coWebsite.isClosable()) {
|
||||
this.closeCoWebsite(coWebsite);
|
||||
} else {
|
||||
this.unloadCoWebsite(coWebsite).catch(() => {
|
||||
console.error("Error during unloading a co-website by a button");
|
||||
this.unloadCoWebsite(coWebsite).catch((err) => {
|
||||
console.error("Cannot unload co-website on click on close button", err);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -241,7 +220,10 @@ class CoWebsiteManager {
|
||||
return;
|
||||
}
|
||||
|
||||
coWebsite.iframe.style.display = "none";
|
||||
const iframe = coWebsite.getIframe();
|
||||
if (iframe) {
|
||||
iframe.style.display = "none";
|
||||
}
|
||||
this.resizing = true;
|
||||
document.addEventListener("mousemove", movecallback);
|
||||
});
|
||||
@@ -257,7 +239,10 @@ class CoWebsiteManager {
|
||||
return;
|
||||
}
|
||||
|
||||
coWebsite.iframe.style.display = "flex";
|
||||
const iframe = coWebsite.getIframe();
|
||||
if (iframe) {
|
||||
iframe.style.display = "flex";
|
||||
}
|
||||
this.resizing = false;
|
||||
});
|
||||
|
||||
@@ -270,7 +255,10 @@ class CoWebsiteManager {
|
||||
return;
|
||||
}
|
||||
|
||||
coWebsite.iframe.style.display = "none";
|
||||
const iframe = coWebsite.getIframe();
|
||||
if (iframe) {
|
||||
iframe.style.display = "none";
|
||||
}
|
||||
this.resizing = true;
|
||||
const touchEvent = event.touches[0];
|
||||
this.previousTouchMoveCoordinates = { x: touchEvent.pageX, y: touchEvent.pageY };
|
||||
@@ -289,7 +277,10 @@ class CoWebsiteManager {
|
||||
return;
|
||||
}
|
||||
|
||||
coWebsite.iframe.style.display = "flex";
|
||||
const iframe = coWebsite.getIframe();
|
||||
if (iframe) {
|
||||
iframe.style.display = "flex";
|
||||
}
|
||||
this.resizing = false;
|
||||
});
|
||||
}
|
||||
@@ -313,9 +304,12 @@ class CoWebsiteManager {
|
||||
public displayMain() {
|
||||
const coWebsite = this.getMainCoWebsite();
|
||||
if (coWebsite) {
|
||||
coWebsite.iframe.style.display = "block";
|
||||
const iframe = coWebsite.getIframe();
|
||||
if (iframe) {
|
||||
iframe.style.display = "block";
|
||||
}
|
||||
}
|
||||
this.loadMain();
|
||||
this.loadMain(coWebsite?.getWidthPercent());
|
||||
this.openMain();
|
||||
this.fire();
|
||||
}
|
||||
@@ -323,7 +317,10 @@ class CoWebsiteManager {
|
||||
public hideMain() {
|
||||
const coWebsite = this.getMainCoWebsite();
|
||||
if (coWebsite) {
|
||||
coWebsite.iframe.style.display = "none";
|
||||
const iframe = coWebsite.getIframe();
|
||||
if (iframe) {
|
||||
iframe.style.display = "none";
|
||||
}
|
||||
}
|
||||
this.cowebsiteDom.classList.add("closing");
|
||||
this.cowebsiteDom.classList.remove("opened");
|
||||
@@ -409,7 +406,9 @@ class CoWebsiteManager {
|
||||
}
|
||||
|
||||
public getCoWebsiteById(coWebsiteId: string): CoWebsite | undefined {
|
||||
return get(coWebsites).find((coWebsite: CoWebsite) => coWebsite.iframe.id === coWebsiteId);
|
||||
return get(coWebsites).find((coWebsite: CoWebsite) => {
|
||||
return coWebsite.getId() === coWebsiteId;
|
||||
});
|
||||
}
|
||||
|
||||
private getCoWebsiteByPosition(position: number): CoWebsite | undefined {
|
||||
@@ -429,7 +428,9 @@ class CoWebsiteManager {
|
||||
}
|
||||
|
||||
private getPositionByCoWebsite(coWebsite: CoWebsite): number {
|
||||
return get(coWebsites).findIndex((currentCoWebsite) => currentCoWebsite.iframe.id === coWebsite.iframe.id);
|
||||
return get(coWebsites).findIndex((currentCoWebsite) => {
|
||||
return currentCoWebsite.getId() === coWebsite.getId();
|
||||
});
|
||||
}
|
||||
|
||||
private getSlotByCowebsite(coWebsite: CoWebsite): HTMLDivElement | undefined {
|
||||
@@ -443,7 +444,7 @@ class CoWebsiteManager {
|
||||
if (index === 0) {
|
||||
id += "main";
|
||||
} else {
|
||||
id += coWebsite.iframe.id;
|
||||
id += coWebsite.getId();
|
||||
}
|
||||
|
||||
const slot = HtmlUtils.getElementById<HTMLDivElement>(id);
|
||||
@@ -460,60 +461,72 @@ class CoWebsiteManager {
|
||||
|
||||
const bounding = coWebsiteSlot.getBoundingClientRect();
|
||||
|
||||
coWebsite.iframe.style.top = bounding.top + "px";
|
||||
coWebsite.iframe.style.left = bounding.left + "px";
|
||||
coWebsite.iframe.style.width = bounding.right - bounding.left + "px";
|
||||
coWebsite.iframe.style.height = bounding.bottom - bounding.top + "px";
|
||||
const iframe = coWebsite.getIframe();
|
||||
|
||||
if (iframe) {
|
||||
iframe.style.top = bounding.top + "px";
|
||||
iframe.style.left = bounding.left + "px";
|
||||
iframe.style.width = bounding.right - bounding.left + "px";
|
||||
iframe.style.height = bounding.bottom - bounding.top + "px";
|
||||
}
|
||||
}
|
||||
|
||||
public resizeAllIframes() {
|
||||
const mainCoWebsite = this.getCoWebsiteByPosition(0);
|
||||
const mainIframe = mainCoWebsite?.getIframe();
|
||||
const highlightEmbed = get(highlightedEmbedScreen);
|
||||
|
||||
get(coWebsites).forEach((coWebsite) => {
|
||||
const notMain = !mainCoWebsite || (mainCoWebsite && mainCoWebsite.iframe.id !== coWebsite.iframe.id);
|
||||
get(coWebsites).forEach((coWebsite: CoWebsite) => {
|
||||
const iframe = coWebsite.getIframe();
|
||||
if (!iframe) {
|
||||
return;
|
||||
}
|
||||
|
||||
const notMain = !mainCoWebsite || (mainCoWebsite && mainIframe && mainIframe.id !== iframe.id);
|
||||
const notHighlighEmbed =
|
||||
!highlightEmbed ||
|
||||
(highlightEmbed &&
|
||||
(highlightEmbed.type !== "cowebsite" ||
|
||||
(highlightEmbed.type === "cowebsite" &&
|
||||
highlightEmbed.embed.iframe.id !== coWebsite.iframe.id)));
|
||||
(highlightEmbed.type === "cowebsite" && highlightEmbed.embed.getId() !== coWebsite.getId())));
|
||||
|
||||
if (coWebsite.iframe.classList.contains("main") && notMain) {
|
||||
coWebsite.iframe.classList.remove("main");
|
||||
if (iframe.classList.contains("main") && notMain) {
|
||||
iframe.classList.remove("main");
|
||||
}
|
||||
|
||||
if (coWebsite.iframe.classList.contains("highlighted") && notHighlighEmbed) {
|
||||
coWebsite.iframe.classList.remove("highlighted");
|
||||
coWebsite.iframe.classList.add("pixel");
|
||||
coWebsite.iframe.style.top = "-1px";
|
||||
coWebsite.iframe.style.left = "-1px";
|
||||
if (iframe.classList.contains("highlighted") && notHighlighEmbed) {
|
||||
iframe.classList.remove("highlighted");
|
||||
iframe.classList.add("pixel");
|
||||
iframe.style.top = "-1px";
|
||||
iframe.style.left = "-1px";
|
||||
}
|
||||
|
||||
if (notMain && notHighlighEmbed) {
|
||||
coWebsite.iframe.classList.add("pixel");
|
||||
coWebsite.iframe.style.top = "-1px";
|
||||
coWebsite.iframe.style.left = "-1px";
|
||||
iframe.classList.add("pixel");
|
||||
iframe.style.top = "-1px";
|
||||
iframe.style.left = "-1px";
|
||||
}
|
||||
|
||||
this.setIframeOffset(coWebsite);
|
||||
});
|
||||
|
||||
if (mainCoWebsite) {
|
||||
mainCoWebsite.iframe.classList.add("main");
|
||||
mainCoWebsite.iframe.classList.remove("pixel");
|
||||
if (mainIframe) {
|
||||
mainIframe.classList.add("main");
|
||||
mainIframe.classList.remove("pixel");
|
||||
}
|
||||
|
||||
if (highlightEmbed && highlightEmbed.type === "cowebsite") {
|
||||
highlightEmbed.embed.iframe.classList.add("highlighted");
|
||||
highlightEmbed.embed.iframe.classList.remove("pixel");
|
||||
const highlightEmbedIframe = highlightEmbed.embed.getIframe();
|
||||
if (highlightEmbedIframe) {
|
||||
highlightEmbedIframe.classList.add("highlighted");
|
||||
highlightEmbedIframe.classList.remove("pixel");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private removeHighlightCoWebsite(coWebsite: CoWebsite) {
|
||||
const highlighted = get(highlightedEmbedScreen);
|
||||
|
||||
if (highlighted && highlighted.type === "cowebsite" && highlighted.embed.iframe.id === coWebsite.iframe.id) {
|
||||
if (highlighted && highlighted.type === "cowebsite" && highlighted.embed.getId() === coWebsite.getId()) {
|
||||
highlightedEmbedScreen.removeHighlight();
|
||||
}
|
||||
}
|
||||
@@ -526,7 +539,9 @@ class CoWebsiteManager {
|
||||
this.closeMain();
|
||||
}
|
||||
|
||||
coWebsite.iframe.remove();
|
||||
coWebsite.unload().catch((err) => {
|
||||
console.error("Cannot unload cowebsite on remove from stack");
|
||||
});
|
||||
}
|
||||
|
||||
public goToMain(coWebsite: CoWebsite) {
|
||||
@@ -538,8 +553,8 @@ class CoWebsiteManager {
|
||||
isMediaBreakpointDown("lg") &&
|
||||
get(embedScreenLayout) === LayoutMode.Presentation &&
|
||||
mainCoWebsite &&
|
||||
mainCoWebsite.iframe.id !== coWebsite.iframe.id &&
|
||||
get(mainCoWebsite.state) !== "asleep"
|
||||
mainCoWebsite.getId() !== coWebsite.getId() &&
|
||||
mainCoWebsite.getState() !== "asleep"
|
||||
) {
|
||||
highlightedEmbedScreen.toggleHighlight({
|
||||
type: "cowebsite",
|
||||
@@ -551,25 +566,15 @@ class CoWebsiteManager {
|
||||
}
|
||||
|
||||
public searchJitsi(): CoWebsite | undefined {
|
||||
return get(coWebsites).find((coWebsite: CoWebsite) => coWebsite.jitsi);
|
||||
return get(jitsiCoWebsite);
|
||||
}
|
||||
|
||||
private initialiseCowebsite(coWebsite: CoWebsite, position: number | undefined) {
|
||||
if (coWebsite.allowPolicy) {
|
||||
coWebsite.iframe.allow = coWebsite.allowPolicy;
|
||||
}
|
||||
|
||||
if (coWebsite.allowApi) {
|
||||
iframeListener.registerIframe(coWebsite.iframe);
|
||||
}
|
||||
|
||||
coWebsite.iframe.classList.add("pixel");
|
||||
|
||||
public addCoWebsiteToStore(coWebsite: CoWebsite, position: number | undefined) {
|
||||
const coWebsitePosition = position === undefined ? get(coWebsites).length : position;
|
||||
coWebsites.add(coWebsite, coWebsitePosition);
|
||||
}
|
||||
|
||||
private generateUniqueId() {
|
||||
public generateUniqueId() {
|
||||
let id = undefined;
|
||||
do {
|
||||
id = "cowebsite-iframe-" + (Math.random() + 1).toString(36).substring(7);
|
||||
@@ -578,80 +583,11 @@ class CoWebsiteManager {
|
||||
return id;
|
||||
}
|
||||
|
||||
public addCoWebsite(
|
||||
url: string,
|
||||
base: string,
|
||||
allowApi?: boolean,
|
||||
allowPolicy?: string,
|
||||
widthPercent?: number,
|
||||
position?: number,
|
||||
closable?: boolean,
|
||||
altMessage?: string
|
||||
): CoWebsite {
|
||||
const iframe = document.createElement("iframe");
|
||||
const fullUrl = new URL(url, base);
|
||||
iframe.src = fullUrl.toString();
|
||||
iframe.id = this.generateUniqueId();
|
||||
|
||||
const newCoWebsite: CoWebsite = {
|
||||
iframe,
|
||||
url: fullUrl,
|
||||
state: writable("asleep" as CoWebsiteState),
|
||||
closable: closable ?? false,
|
||||
allowPolicy,
|
||||
allowApi,
|
||||
widthPercent,
|
||||
altMessage,
|
||||
};
|
||||
|
||||
this.initialiseCowebsite(newCoWebsite, position);
|
||||
|
||||
return newCoWebsite;
|
||||
}
|
||||
|
||||
public addCoWebsiteFromIframe(
|
||||
iframe: HTMLIFrameElement,
|
||||
allowApi?: boolean,
|
||||
allowPolicy?: string,
|
||||
widthPercent?: number,
|
||||
position?: number,
|
||||
closable?: boolean,
|
||||
jitsi?: boolean
|
||||
): CoWebsite {
|
||||
if (get(coWebsitesNotAsleep).length < 1) {
|
||||
this.loadMain(widthPercent);
|
||||
}
|
||||
|
||||
iframe.id = this.generateUniqueId();
|
||||
|
||||
const newCoWebsite: CoWebsite = {
|
||||
iframe,
|
||||
url: new URL(iframe.src),
|
||||
state: writable("ready" as CoWebsiteState),
|
||||
closable: closable ?? false,
|
||||
allowPolicy,
|
||||
allowApi,
|
||||
widthPercent,
|
||||
jitsi,
|
||||
};
|
||||
|
||||
if (position === 0) {
|
||||
this.openMain();
|
||||
setTimeout(() => {
|
||||
this.fire();
|
||||
}, animationTime);
|
||||
}
|
||||
|
||||
this.initialiseCowebsite(newCoWebsite, position);
|
||||
|
||||
return newCoWebsite;
|
||||
}
|
||||
|
||||
public loadCoWebsite(coWebsite: CoWebsite): Promise<CoWebsite> {
|
||||
public loadCoWebsite(coWebsite: CoWebsite): CancelablePromise<void> {
|
||||
if (get(coWebsitesNotAsleep).length < 1) {
|
||||
coWebsites.remove(coWebsite);
|
||||
coWebsites.add(coWebsite, 0);
|
||||
this.loadMain(coWebsite.widthPercent);
|
||||
this.loadMain(coWebsite.getWidthPercent());
|
||||
}
|
||||
|
||||
// Check if the main is hide
|
||||
@@ -659,125 +595,73 @@ class CoWebsiteManager {
|
||||
this.displayMain();
|
||||
}
|
||||
|
||||
coWebsite.state.set("loading");
|
||||
const coWebsiteLloading = coWebsite
|
||||
.load()
|
||||
.then(() => {
|
||||
const mainCoWebsite = this.getMainCoWebsite();
|
||||
if (mainCoWebsite && mainCoWebsite.getId() === coWebsite.getId()) {
|
||||
this.openMain();
|
||||
|
||||
const mainCoWebsite = this.getMainCoWebsite();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const onloadPromise = new Promise<void>((resolve) => {
|
||||
coWebsite.iframe.onload = () => {
|
||||
coWebsite.state.set("ready");
|
||||
resolve();
|
||||
};
|
||||
setTimeout(() => {
|
||||
this.fire();
|
||||
}, animationTime);
|
||||
}
|
||||
this.resizeAllIframes();
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("Error on co-website loading => ", err);
|
||||
this.removeCoWebsiteFromStack(coWebsite);
|
||||
});
|
||||
|
||||
const onTimeoutPromise = new Promise<void>((resolve) => {
|
||||
setTimeout(() => resolve(), 2000);
|
||||
});
|
||||
|
||||
this.cowebsiteBufferDom.appendChild(coWebsite.iframe);
|
||||
|
||||
if (coWebsite.jitsi) {
|
||||
const gameScene = gameManager.getCurrentGameScene();
|
||||
gameScene.disableMediaBehaviors();
|
||||
jitsiFactory.restart();
|
||||
}
|
||||
|
||||
this.currentOperationPromise = this.currentOperationPromise
|
||||
.then(() => Promise.race([onloadPromise, onTimeoutPromise]))
|
||||
.then(() => {
|
||||
if (mainCoWebsite && mainCoWebsite.iframe.id === coWebsite.iframe.id) {
|
||||
this.openMain();
|
||||
|
||||
setTimeout(() => {
|
||||
this.fire();
|
||||
}, animationTime);
|
||||
}
|
||||
|
||||
return resolve(coWebsite);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("Error on co-website loading => ", err);
|
||||
this.removeCoWebsiteFromStack(coWebsite);
|
||||
return reject();
|
||||
});
|
||||
});
|
||||
return coWebsiteLloading;
|
||||
}
|
||||
|
||||
public unloadCoWebsite(coWebsite: CoWebsite): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.removeHighlightCoWebsite(coWebsite);
|
||||
this.removeHighlightCoWebsite(coWebsite);
|
||||
|
||||
coWebsite.iframe.parentNode?.removeChild(coWebsite.iframe);
|
||||
coWebsite.state.set("asleep");
|
||||
coWebsites.remove(coWebsite);
|
||||
return coWebsite
|
||||
.unload()
|
||||
.then(() => {
|
||||
coWebsites.remove(coWebsite);
|
||||
const mainCoWebsite = this.getMainCoWebsite();
|
||||
|
||||
if (coWebsite.jitsi) {
|
||||
jitsiFactory.stop();
|
||||
const gameScene = gameManager.getCurrentGameScene();
|
||||
gameScene.enableMediaBehaviors();
|
||||
}
|
||||
if (mainCoWebsite) {
|
||||
this.removeHighlightCoWebsite(mainCoWebsite);
|
||||
this.goToMain(mainCoWebsite);
|
||||
this.resizeAllIframes();
|
||||
} else {
|
||||
this.closeMain();
|
||||
}
|
||||
|
||||
const mainCoWebsite = this.getMainCoWebsite();
|
||||
|
||||
if (mainCoWebsite) {
|
||||
this.removeHighlightCoWebsite(mainCoWebsite);
|
||||
this.goToMain(mainCoWebsite);
|
||||
this.resizeAllIframes();
|
||||
} else {
|
||||
this.closeMain();
|
||||
}
|
||||
|
||||
coWebsites.add(coWebsite, get(coWebsites).length);
|
||||
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
public closeCoWebsite(coWebsite: CoWebsite): Promise<void> {
|
||||
this.currentOperationPromise = this.currentOperationPromise.then(
|
||||
() =>
|
||||
new Promise((resolve) => {
|
||||
if (coWebsite.jitsi) {
|
||||
jitsiFactory.destroy();
|
||||
const gameScene = gameManager.getCurrentGameScene();
|
||||
gameScene.enableMediaBehaviors();
|
||||
}
|
||||
|
||||
if (get(coWebsites).length === 1) {
|
||||
this.fire();
|
||||
}
|
||||
|
||||
if (coWebsite.allowApi) {
|
||||
iframeListener.unregisterIframe(coWebsite.iframe);
|
||||
}
|
||||
|
||||
this.removeCoWebsiteFromStack(coWebsite);
|
||||
|
||||
const mainCoWebsite = this.getMainCoWebsite();
|
||||
|
||||
if (mainCoWebsite) {
|
||||
this.removeHighlightCoWebsite(mainCoWebsite);
|
||||
this.goToMain(mainCoWebsite);
|
||||
this.resizeAllIframes();
|
||||
} else {
|
||||
this.closeMain();
|
||||
}
|
||||
resolve();
|
||||
})
|
||||
);
|
||||
return this.currentOperationPromise;
|
||||
}
|
||||
|
||||
public closeCoWebsites(): Promise<void> {
|
||||
return (this.currentOperationPromise = this.currentOperationPromise.then(() => {
|
||||
get(coWebsites).forEach((coWebsite: CoWebsite) => {
|
||||
this.closeCoWebsite(coWebsite).catch(() => {
|
||||
console.error("Error during closing a co-website");
|
||||
});
|
||||
coWebsites.add(coWebsite, get(coWebsites).length);
|
||||
})
|
||||
.catch(() => {
|
||||
console.error();
|
||||
});
|
||||
}));
|
||||
return this.currentOperationPromise;
|
||||
}
|
||||
|
||||
public closeCoWebsite(coWebsite: CoWebsite): void {
|
||||
if (get(coWebsites).length === 1) {
|
||||
this.fire();
|
||||
}
|
||||
|
||||
this.removeCoWebsiteFromStack(coWebsite);
|
||||
|
||||
const mainCoWebsite = this.getMainCoWebsite();
|
||||
|
||||
if (mainCoWebsite) {
|
||||
this.removeHighlightCoWebsite(mainCoWebsite);
|
||||
this.goToMain(mainCoWebsite);
|
||||
this.resizeAllIframes();
|
||||
} else {
|
||||
this.closeMain();
|
||||
}
|
||||
}
|
||||
|
||||
public closeCoWebsites(): void {
|
||||
get(coWebsites).forEach((coWebsite: CoWebsite) => {
|
||||
this.closeCoWebsite(coWebsite);
|
||||
});
|
||||
}
|
||||
|
||||
public getGameSize(): { width: number; height: number } {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { JITSI_URL } from "../Enum/EnvironmentVariable";
|
||||
import { CoWebsite, coWebsiteManager } from "./CoWebsiteManager";
|
||||
import { coWebsiteManager } from "./CoWebsiteManager";
|
||||
import { requestedCameraState, requestedMicrophoneState } from "../Stores/MediaStore";
|
||||
import { get } from "svelte/store";
|
||||
import type { CoWebsite } from "./CoWebsite/CoWesbite";
|
||||
import CancelablePromise from "cancelable-promise";
|
||||
|
||||
interface jitsiConfigInterface {
|
||||
startWithAudioMuted: boolean;
|
||||
@@ -134,92 +136,90 @@ class JitsiFactory {
|
||||
return slugify(instance.replace("/", "-") + "-" + roomName);
|
||||
}
|
||||
|
||||
public async start(
|
||||
public start(
|
||||
roomName: string,
|
||||
playerName: string,
|
||||
jwt?: string,
|
||||
config?: object,
|
||||
interfaceConfig?: object,
|
||||
jitsiUrl?: string
|
||||
) {
|
||||
const coWebsite = coWebsiteManager.searchJitsi();
|
||||
): CancelablePromise<HTMLIFrameElement> {
|
||||
return new CancelablePromise((resolve, reject, cancel) => {
|
||||
// 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
|
||||
// after some time the URLs get so huge that loading the iframe
|
||||
// becomes slow and eventually breaks completely. Thus lets just
|
||||
// clear jitsi local storage before starting a new conference.
|
||||
window.localStorage.removeItem("jitsiLocalStorage");
|
||||
|
||||
if (coWebsite) {
|
||||
await coWebsiteManager.closeCoWebsite(coWebsite);
|
||||
}
|
||||
|
||||
// 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
|
||||
// after some time the URLs get so huge that loading the iframe
|
||||
// becomes slow and eventually breaks completely. Thus lets just
|
||||
// clear jitsi local storage before starting a new conference.
|
||||
window.localStorage.removeItem("jitsiLocalStorage");
|
||||
|
||||
const domain = jitsiUrl || JITSI_URL;
|
||||
if (domain === undefined) {
|
||||
throw new Error("Missing JITSI_URL environment variable or jitsiUrl parameter in the map.");
|
||||
}
|
||||
await this.loadJitsiScript(domain);
|
||||
|
||||
const options: JitsiOptions = {
|
||||
roomName: roomName,
|
||||
jwt: jwt,
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
parentNode: coWebsiteManager.getCoWebsiteBuffer(),
|
||||
configOverwrite: mergeConfig(config),
|
||||
interfaceConfigOverwrite: { ...defaultInterfaceConfig, ...interfaceConfig },
|
||||
};
|
||||
|
||||
if (!options.jwt) {
|
||||
delete options.jwt;
|
||||
}
|
||||
|
||||
const doResolve = (): void => {
|
||||
const iframe = coWebsiteManager.getCoWebsiteBuffer().querySelector<HTMLIFrameElement>('[id*="jitsi" i]');
|
||||
if (iframe && this.jitsiApi) {
|
||||
const coWebsite = coWebsiteManager.addCoWebsiteFromIframe(
|
||||
iframe,
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
0,
|
||||
false,
|
||||
true
|
||||
);
|
||||
|
||||
this.jitsiApi.addListener("videoConferenceLeft", () => {
|
||||
this.closeOrUnload(coWebsite);
|
||||
});
|
||||
|
||||
this.jitsiApi.addListener("readyToClose", () => {
|
||||
this.closeOrUnload(coWebsite);
|
||||
});
|
||||
const domain = jitsiUrl || JITSI_URL;
|
||||
if (domain === undefined) {
|
||||
throw new Error("Missing JITSI_URL environment variable or jitsiUrl parameter in the map.");
|
||||
}
|
||||
|
||||
coWebsiteManager.resizeAllIframes();
|
||||
};
|
||||
const loadScript = this.loadJitsiScript(domain).then(() => {
|
||||
const options: JitsiOptions = {
|
||||
roomName: roomName,
|
||||
jwt: jwt,
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
parentNode: coWebsiteManager.getCoWebsiteBuffer(),
|
||||
configOverwrite: mergeConfig(config),
|
||||
interfaceConfigOverwrite: { ...defaultInterfaceConfig, ...interfaceConfig },
|
||||
};
|
||||
|
||||
this.jitsiApi = undefined;
|
||||
if (!options.jwt) {
|
||||
delete options.jwt;
|
||||
}
|
||||
|
||||
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);
|
||||
const timemout = setTimeout(() => doResolve(), 2000); //failsafe in case the iframe is deleted before loading or too long to load
|
||||
|
||||
this.jitsiApi.addListener("audioMuteStatusChanged", this.audioCallback);
|
||||
this.jitsiApi.addListener("videoMuteStatusChanged", this.videoCallback);
|
||||
const doResolve = (): void => {
|
||||
clearTimeout(timemout);
|
||||
const iframe = coWebsiteManager
|
||||
.getCoWebsiteBuffer()
|
||||
.querySelector<HTMLIFrameElement>('[id*="jitsi" i]');
|
||||
if (iframe && this.jitsiApi) {
|
||||
this.jitsiApi.addListener("videoConferenceLeft", () => {
|
||||
this.closeOrUnload();
|
||||
});
|
||||
|
||||
this.jitsiApi.addListener("readyToClose", () => {
|
||||
this.closeOrUnload();
|
||||
});
|
||||
|
||||
return resolve(iframe);
|
||||
}
|
||||
};
|
||||
|
||||
this.jitsiApi = undefined;
|
||||
|
||||
options.onload = () => doResolve(); //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);
|
||||
});
|
||||
|
||||
cancel(() => {
|
||||
loadScript.cancel();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private closeOrUnload = function (coWebsite: CoWebsite) {
|
||||
if (coWebsite.closable) {
|
||||
coWebsiteManager.closeCoWebsite(coWebsite).catch(() => {
|
||||
console.error("Error during closing a Jitsi Meet");
|
||||
});
|
||||
private closeOrUnload = function () {
|
||||
const coWebsite = coWebsiteManager.searchJitsi();
|
||||
if (!coWebsite) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (coWebsite.isClosable()) {
|
||||
coWebsiteManager.closeCoWebsite(coWebsite);
|
||||
} else {
|
||||
coWebsiteManager.unloadCoWebsite(coWebsite).catch(() => {
|
||||
console.error("Error during unloading a Jitsi Meet");
|
||||
coWebsiteManager.unloadCoWebsite(coWebsite).catch((err) => {
|
||||
console.error("Cannot unload co-website from the Jitsi factory", err);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -233,8 +233,6 @@ class JitsiFactory {
|
||||
this.jitsiApi.addListener("videoMuteStatusChanged", this.videoCallback);
|
||||
|
||||
const coWebsite = coWebsiteManager.searchJitsi();
|
||||
console.log("jitsi api ", this.jitsiApi);
|
||||
console.log("iframe cowebsite", coWebsite?.iframe);
|
||||
|
||||
if (!coWebsite) {
|
||||
this.destroy();
|
||||
@@ -242,11 +240,11 @@ class JitsiFactory {
|
||||
}
|
||||
|
||||
this.jitsiApi.addListener("videoConferenceLeft", () => {
|
||||
this.closeOrUnload(coWebsite);
|
||||
this.closeOrUnload();
|
||||
});
|
||||
|
||||
this.jitsiApi.addListener("readyToClose", () => {
|
||||
this.closeOrUnload(coWebsite);
|
||||
this.closeOrUnload();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -284,8 +282,8 @@ class JitsiFactory {
|
||||
}
|
||||
}
|
||||
|
||||
private async loadJitsiScript(domain: string): Promise<void> {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
private loadJitsiScript(domain: string): CancelablePromise<void> {
|
||||
return new CancelablePromise<void>((resolve, reject, cancel) => {
|
||||
if (this.jitsiScriptLoaded) {
|
||||
resolve();
|
||||
return;
|
||||
@@ -304,6 +302,10 @@ class JitsiFactory {
|
||||
};
|
||||
|
||||
document.head.appendChild(jitsiScript);
|
||||
|
||||
cancel(() => {
|
||||
jitsiScript.remove();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user