Making embedded iframes scriptable using the WA.room.website namespace.
This commit is contained in:
parent
5bb29e99ba
commit
6b9b999996
14 changed files with 737 additions and 28 deletions
48
front/src/Api/Events/EmbeddedWebsiteEvent.ts
Normal file
48
front/src/Api/Events/EmbeddedWebsiteEvent.ts
Normal file
|
@ -0,0 +1,48 @@
|
|||
import * as tg from "generic-type-guard";
|
||||
|
||||
export const isRectangle = new tg.IsInterface()
|
||||
.withProperties({
|
||||
x: tg.isNumber,
|
||||
y: tg.isNumber,
|
||||
width: tg.isNumber,
|
||||
height: tg.isNumber,
|
||||
})
|
||||
.get();
|
||||
|
||||
export const isEmbeddedWebsiteEvent = new tg.IsInterface()
|
||||
.withProperties({
|
||||
name: tg.isString,
|
||||
})
|
||||
.withOptionalProperties({
|
||||
url: tg.isString,
|
||||
visible: tg.isBoolean,
|
||||
allowApi: tg.isBoolean,
|
||||
allow: tg.isString,
|
||||
x: tg.isNumber,
|
||||
y: tg.isNumber,
|
||||
width: tg.isNumber,
|
||||
height: tg.isNumber,
|
||||
})
|
||||
.get();
|
||||
|
||||
export const isCreateEmbeddedWebsiteEvent = new tg.IsInterface()
|
||||
.withProperties({
|
||||
name: tg.isString,
|
||||
url: tg.isString,
|
||||
position: isRectangle,
|
||||
})
|
||||
.withOptionalProperties({
|
||||
visible: tg.isBoolean,
|
||||
allowApi: tg.isBoolean,
|
||||
allow: tg.isString,
|
||||
})
|
||||
.get();
|
||||
|
||||
/**
|
||||
* A message sent from the iFrame to the game to modify an embedded website
|
||||
*/
|
||||
export type ModifyEmbeddedWebsiteEvent = tg.GuardedType<typeof isEmbeddedWebsiteEvent>;
|
||||
|
||||
export type CreateEmbeddedWebsiteEvent = tg.GuardedType<typeof isCreateEmbeddedWebsiteEvent>;
|
||||
// TODO: make a variation that is all optional (except for the name)
|
||||
export type Rectangle = tg.GuardedType<typeof isRectangle>;
|
|
@ -22,6 +22,8 @@ import type { SetVariableEvent } from "./SetVariableEvent";
|
|||
import { isGameStateEvent } from "./GameStateEvent";
|
||||
import { isMapDataEvent } from "./MapDataEvent";
|
||||
import { isSetVariableEvent } from "./SetVariableEvent";
|
||||
import type { EmbeddedWebsite } from "../iframe/Room/EmbeddedWebsite";
|
||||
import { isCreateEmbeddedWebsiteEvent } from "./EmbeddedWebsiteEvent";
|
||||
import type { LoadTilesetEvent } from "./LoadTilesetEvent";
|
||||
import { isLoadTilesetEvent } from "./LoadTilesetEvent";
|
||||
import type {
|
||||
|
@ -63,6 +65,7 @@ export type IframeEventMap = {
|
|||
loadTileset: LoadTilesetEvent;
|
||||
registerMenuCommand: MenuItemRegisterEvent;
|
||||
setTiles: SetTilesEvent;
|
||||
modifyEmbeddedWebsite: Partial<EmbeddedWebsite>; // Note: name should be compulsory in fact
|
||||
};
|
||||
export interface IframeEvent<T extends keyof IframeEventMap> {
|
||||
type: T;
|
||||
|
@ -122,6 +125,18 @@ export const iframeQueryMapTypeGuards = {
|
|||
query: isMessageReferenceEvent,
|
||||
answer: tg.isUndefined,
|
||||
},
|
||||
getEmbeddedWebsite: {
|
||||
query: tg.isString,
|
||||
answer: isCreateEmbeddedWebsiteEvent,
|
||||
},
|
||||
deleteEmbeddedWebsite: {
|
||||
query: tg.isString,
|
||||
answer: tg.isUndefined,
|
||||
},
|
||||
createEmbeddedWebsite: {
|
||||
query: isCreateEmbeddedWebsiteEvent,
|
||||
answer: tg.isUndefined,
|
||||
},
|
||||
};
|
||||
|
||||
type GuardedType<T> = T extends (x: unknown) => x is infer T ? T : never;
|
||||
|
@ -158,7 +173,12 @@ export const isIframeQuery = (event: any): event is IframeQuery<keyof IframeQuer
|
|||
if (!isIframeQueryKey(type)) {
|
||||
return false;
|
||||
}
|
||||
return iframeQueryMapTypeGuards[type].query(event.data);
|
||||
|
||||
const result = iframeQueryMapTypeGuards[type].query(event.data);
|
||||
if (!result) {
|
||||
console.warn('Received a query with type "' + type + '" but the payload is invalid.');
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
|
|
@ -32,6 +32,8 @@ import { isLoadPageEvent } from "./Events/LoadPageEvent";
|
|||
import { handleMenuItemRegistrationEvent, isMenuItemRegisterIframeEvent } from "./Events/ui/MenuItemRegisterEvent";
|
||||
import { SetTilesEvent, isSetTilesEvent } from "./Events/SetTilesEvent";
|
||||
import type { SetVariableEvent } from "./Events/SetVariableEvent";
|
||||
import { ModifyEmbeddedWebsiteEvent, isEmbeddedWebsiteEvent } from "./Events/EmbeddedWebsiteEvent";
|
||||
import { EmbeddedWebsite } from "./iframe/Room/EmbeddedWebsite";
|
||||
|
||||
type AnswererCallback<T extends keyof IframeQueryMap> = (
|
||||
query: IframeQueryMap[T]["query"],
|
||||
|
@ -109,6 +111,9 @@ class IframeListener {
|
|||
private readonly _setTilesStream: Subject<SetTilesEvent> = new Subject();
|
||||
public readonly setTilesStream = this._setTilesStream.asObservable();
|
||||
|
||||
private readonly _modifyEmbeddedWebsiteStream: Subject<ModifyEmbeddedWebsiteEvent> = new Subject();
|
||||
public readonly modifyEmbeddedWebsiteStream = this._modifyEmbeddedWebsiteStream.asObservable();
|
||||
|
||||
private readonly iframes = new Set<HTMLIFrameElement>();
|
||||
private readonly iframeCloseCallbacks = new Map<HTMLIFrameElement, (() => void)[]>();
|
||||
private readonly scripts = new Map<string, HTMLIFrameElement>();
|
||||
|
@ -264,6 +269,8 @@ class IframeListener {
|
|||
handleMenuItemRegistrationEvent(payload.data);
|
||||
} else if (payload.type == "setTiles" && isSetTilesEvent(payload.data)) {
|
||||
this._setTilesStream.next(payload.data);
|
||||
} else if (payload.type == "modifyEmbeddedWebsite" && isEmbeddedWebsiteEvent(payload.data)) {
|
||||
this._modifyEmbeddedWebsiteStream.next(payload.data);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
90
front/src/Api/iframe/Room/EmbeddedWebsite.ts
Normal file
90
front/src/Api/iframe/Room/EmbeddedWebsite.ts
Normal file
|
@ -0,0 +1,90 @@
|
|||
import { sendToWorkadventure } from "../IframeApiContribution";
|
||||
import type {
|
||||
CreateEmbeddedWebsiteEvent,
|
||||
ModifyEmbeddedWebsiteEvent,
|
||||
Rectangle,
|
||||
} from "../../Events/EmbeddedWebsiteEvent";
|
||||
|
||||
export class EmbeddedWebsite {
|
||||
public readonly name: string;
|
||||
private _url: string;
|
||||
private _visible: boolean;
|
||||
private _allow: string;
|
||||
private _allowApi: boolean;
|
||||
private _position: Rectangle;
|
||||
|
||||
constructor(private config: CreateEmbeddedWebsiteEvent) {
|
||||
this.name = config.name;
|
||||
this._url = config.url;
|
||||
this._visible = config.visible ?? true;
|
||||
this._allow = config.allow ?? "";
|
||||
this._allowApi = config.allowApi ?? false;
|
||||
this._position = config.position;
|
||||
}
|
||||
|
||||
public set url(url: string) {
|
||||
this._url = url;
|
||||
sendToWorkadventure({
|
||||
type: "modifyEmbeddedWebsite",
|
||||
data: {
|
||||
name: this.name,
|
||||
url: this._url,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public set visible(visible: boolean) {
|
||||
this._visible = visible;
|
||||
sendToWorkadventure({
|
||||
type: "modifyEmbeddedWebsite",
|
||||
data: {
|
||||
name: this.name,
|
||||
visible: this._visible,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public set x(x: number) {
|
||||
this._position.x = x;
|
||||
sendToWorkadventure({
|
||||
type: "modifyEmbeddedWebsite",
|
||||
data: {
|
||||
name: this.name,
|
||||
x: this._position.x,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public set y(y: number) {
|
||||
this._position.y = y;
|
||||
sendToWorkadventure({
|
||||
type: "modifyEmbeddedWebsite",
|
||||
data: {
|
||||
name: this.name,
|
||||
y: this._position.y,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public set width(width: number) {
|
||||
this._position.width = width;
|
||||
sendToWorkadventure({
|
||||
type: "modifyEmbeddedWebsite",
|
||||
data: {
|
||||
name: this.name,
|
||||
width: this._position.width,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public set height(height: number) {
|
||||
this._position.height = height;
|
||||
sendToWorkadventure({
|
||||
type: "modifyEmbeddedWebsite",
|
||||
data: {
|
||||
name: this.name,
|
||||
height: this._position.height,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
|
@ -6,6 +6,8 @@ import { IframeApiContribution, queryWorkadventure, sendToWorkadventure } from "
|
|||
import { apiCallback } from "./registeredCallbacks";
|
||||
|
||||
import type { ITiledMap } from "../../Phaser/Map/ITiledMap";
|
||||
import type { WorkadventureRoomWebsiteCommands } from "./website";
|
||||
import website from "./website";
|
||||
|
||||
const enterStreams: Map<string, Subject<EnterLeaveEvent>> = new Map<string, Subject<EnterLeaveEvent>>();
|
||||
const leaveStreams: Map<string, Subject<EnterLeaveEvent>> = new Map<string, Subject<EnterLeaveEvent>>();
|
||||
|
@ -105,6 +107,7 @@ export class WorkadventureRoomCommands extends IframeApiContribution<Workadventu
|
|||
}
|
||||
return mapURL;
|
||||
}
|
||||
|
||||
async loadTileset(url: string): Promise<number> {
|
||||
return await queryWorkadventure({
|
||||
type: "loadTileset",
|
||||
|
@ -113,6 +116,10 @@ export class WorkadventureRoomCommands extends IframeApiContribution<Workadventu
|
|||
},
|
||||
});
|
||||
}
|
||||
|
||||
get website(): WorkadventureRoomWebsiteCommands {
|
||||
return website;
|
||||
}
|
||||
}
|
||||
|
||||
export default new WorkadventureRoomCommands();
|
||||
|
|
38
front/src/Api/iframe/website.ts
Normal file
38
front/src/Api/iframe/website.ts
Normal file
|
@ -0,0 +1,38 @@
|
|||
import type { LoadSoundEvent } from "../Events/LoadSoundEvent";
|
||||
import type { PlaySoundEvent } from "../Events/PlaySoundEvent";
|
||||
import type { StopSoundEvent } from "../Events/StopSoundEvent";
|
||||
import { IframeApiContribution, queryWorkadventure, sendToWorkadventure } from "./IframeApiContribution";
|
||||
import { Sound } from "./Sound/Sound";
|
||||
import { EmbeddedWebsite } from "./Room/EmbeddedWebsite";
|
||||
import type { CreateEmbeddedWebsiteEvent } from "../Events/EmbeddedWebsiteEvent";
|
||||
|
||||
export class WorkadventureRoomWebsiteCommands extends IframeApiContribution<WorkadventureRoomWebsiteCommands> {
|
||||
callbacks = [];
|
||||
|
||||
async get(objectName: string): Promise<EmbeddedWebsite> {
|
||||
const websiteEvent = await queryWorkadventure({
|
||||
type: "getEmbeddedWebsite",
|
||||
data: objectName,
|
||||
});
|
||||
return new EmbeddedWebsite(websiteEvent);
|
||||
}
|
||||
|
||||
create(createEmbeddedWebsiteEvent: CreateEmbeddedWebsiteEvent): EmbeddedWebsite {
|
||||
queryWorkadventure({
|
||||
type: "createEmbeddedWebsite",
|
||||
data: createEmbeddedWebsiteEvent,
|
||||
}).catch((e) => {
|
||||
console.error(e);
|
||||
});
|
||||
return new EmbeddedWebsite(createEmbeddedWebsiteEvent);
|
||||
}
|
||||
|
||||
async delete(objectName: string): Promise<void> {
|
||||
return await queryWorkadventure({
|
||||
type: "deleteEmbeddedWebsite",
|
||||
data: objectName,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default new WorkadventureRoomWebsiteCommands();
|
198
front/src/Phaser/Game/EmbeddedWebsiteManager.ts
Normal file
198
front/src/Phaser/Game/EmbeddedWebsiteManager.ts
Normal file
|
@ -0,0 +1,198 @@
|
|||
import type { GameScene } from "./GameScene";
|
||||
import { iframeListener } from "../../Api/IframeListener";
|
||||
import type { Subscription } from "rxjs";
|
||||
import type { CreateEmbeddedWebsiteEvent, ModifyEmbeddedWebsiteEvent } from "../../Api/Events/EmbeddedWebsiteEvent";
|
||||
import DOMElement = Phaser.GameObjects.DOMElement;
|
||||
|
||||
type EmbeddedWebsite = CreateEmbeddedWebsiteEvent & { iframe: HTMLIFrameElement; phaserObject: DOMElement };
|
||||
|
||||
export class EmbeddedWebsiteManager {
|
||||
private readonly embeddedWebsites = new Map<string, EmbeddedWebsite>();
|
||||
private readonly subscription: Subscription;
|
||||
|
||||
constructor(private gameScene: GameScene) {
|
||||
iframeListener.registerAnswerer("getEmbeddedWebsite", (name: string) => {
|
||||
const website = this.embeddedWebsites.get(name);
|
||||
if (website === undefined) {
|
||||
throw new Error('Cannot find embedded website with name "' + name + '"');
|
||||
}
|
||||
const rect = website.iframe.getBoundingClientRect();
|
||||
return {
|
||||
url: website.url,
|
||||
name: website.name,
|
||||
visible: website.visible,
|
||||
allowApi: website.allowApi,
|
||||
allow: website.allow,
|
||||
position: {
|
||||
x: website.phaserObject.x,
|
||||
y: website.phaserObject.y,
|
||||
width: rect["width"],
|
||||
height: rect["height"],
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
iframeListener.registerAnswerer("deleteEmbeddedWebsite", (name: string) => {
|
||||
const website = this.embeddedWebsites.get(name);
|
||||
if (!website) {
|
||||
throw new Error('Could not find website to delete with the name "' + name + '" in your map');
|
||||
}
|
||||
|
||||
website.iframe.remove();
|
||||
website.phaserObject.destroy();
|
||||
this.embeddedWebsites.delete(name);
|
||||
});
|
||||
|
||||
iframeListener.registerAnswerer(
|
||||
"createEmbeddedWebsite",
|
||||
(createEmbeddedWebsiteEvent: CreateEmbeddedWebsiteEvent) => {
|
||||
if (this.embeddedWebsites.has(createEmbeddedWebsiteEvent.name)) {
|
||||
throw new Error('An embedded website with the name "' + name + '" already exists in your map');
|
||||
}
|
||||
|
||||
this.createEmbeddedWebsite(
|
||||
createEmbeddedWebsiteEvent.name,
|
||||
createEmbeddedWebsiteEvent.url,
|
||||
createEmbeddedWebsiteEvent.position.x,
|
||||
createEmbeddedWebsiteEvent.position.y,
|
||||
createEmbeddedWebsiteEvent.position.width,
|
||||
createEmbeddedWebsiteEvent.position.height,
|
||||
createEmbeddedWebsiteEvent.visible ?? true,
|
||||
createEmbeddedWebsiteEvent.allowApi ?? false,
|
||||
createEmbeddedWebsiteEvent.allow ?? ""
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
this.subscription = iframeListener.modifyEmbeddedWebsiteStream.subscribe(
|
||||
(embeddedWebsiteEvent: ModifyEmbeddedWebsiteEvent) => {
|
||||
const website = this.embeddedWebsites.get(embeddedWebsiteEvent.name);
|
||||
if (!website) {
|
||||
throw new Error(
|
||||
'Could not find website with the name "' + embeddedWebsiteEvent.name + '" in your map'
|
||||
);
|
||||
}
|
||||
|
||||
gameScene.markDirty();
|
||||
|
||||
if (embeddedWebsiteEvent.url !== undefined) {
|
||||
website.url = embeddedWebsiteEvent.url;
|
||||
const absoluteUrl = new URL(embeddedWebsiteEvent.url, this.gameScene.MapUrlFile).toString();
|
||||
website.iframe.src = absoluteUrl;
|
||||
}
|
||||
|
||||
if (embeddedWebsiteEvent.visible !== undefined) {
|
||||
website.visible = embeddedWebsiteEvent.visible;
|
||||
website.phaserObject.visible = embeddedWebsiteEvent.visible;
|
||||
}
|
||||
|
||||
if (embeddedWebsiteEvent.allowApi !== undefined) {
|
||||
website.allowApi = embeddedWebsiteEvent.allowApi;
|
||||
if (embeddedWebsiteEvent.allowApi) {
|
||||
iframeListener.registerIframe(website.iframe);
|
||||
} else {
|
||||
iframeListener.unregisterIframe(website.iframe);
|
||||
}
|
||||
}
|
||||
|
||||
if (embeddedWebsiteEvent.allow !== undefined) {
|
||||
website.allow = embeddedWebsiteEvent.allow;
|
||||
website.iframe.allow = embeddedWebsiteEvent.allow;
|
||||
}
|
||||
|
||||
if (embeddedWebsiteEvent?.x !== undefined) {
|
||||
website.phaserObject.x = embeddedWebsiteEvent.x;
|
||||
}
|
||||
if (embeddedWebsiteEvent?.y !== undefined) {
|
||||
website.phaserObject.y = embeddedWebsiteEvent.y;
|
||||
}
|
||||
if (embeddedWebsiteEvent?.width !== undefined) {
|
||||
website.iframe.style.width = embeddedWebsiteEvent.width + "px";
|
||||
}
|
||||
if (embeddedWebsiteEvent?.height !== undefined) {
|
||||
website.iframe.style.height = embeddedWebsiteEvent.height + "px";
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public createEmbeddedWebsite(
|
||||
name: string,
|
||||
url: string,
|
||||
x: number,
|
||||
y: number,
|
||||
width: number,
|
||||
height: number,
|
||||
visible: boolean,
|
||||
allowApi: boolean,
|
||||
allow: string
|
||||
): void {
|
||||
if (this.embeddedWebsites.has(name)) {
|
||||
throw new Error('An embedded website with the name "' + name + '" already exists in your map');
|
||||
}
|
||||
|
||||
const embeddedWebsiteEvent: CreateEmbeddedWebsiteEvent = {
|
||||
name,
|
||||
url,
|
||||
/*x,
|
||||
y,
|
||||
width,
|
||||
height,*/
|
||||
allow,
|
||||
allowApi,
|
||||
visible,
|
||||
position: {
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
},
|
||||
};
|
||||
|
||||
const embeddedWebsite = this.doCreateEmbeddedWebsite(embeddedWebsiteEvent, visible);
|
||||
|
||||
this.embeddedWebsites.set(name, embeddedWebsite);
|
||||
}
|
||||
|
||||
private doCreateEmbeddedWebsite(
|
||||
embeddedWebsiteEvent: CreateEmbeddedWebsiteEvent,
|
||||
visible: boolean
|
||||
): EmbeddedWebsite {
|
||||
const absoluteUrl = new URL(embeddedWebsiteEvent.url, this.gameScene.MapUrlFile).toString();
|
||||
|
||||
const iframe = document.createElement("iframe");
|
||||
iframe.src = absoluteUrl;
|
||||
iframe.style.width = embeddedWebsiteEvent.position.width + "px";
|
||||
iframe.style.height = embeddedWebsiteEvent.position.height + "px";
|
||||
iframe.style.margin = "0";
|
||||
iframe.style.padding = "0";
|
||||
iframe.style.border = "none";
|
||||
|
||||
const embeddedWebsite = {
|
||||
...embeddedWebsiteEvent,
|
||||
phaserObject: this.gameScene.add
|
||||
.dom(embeddedWebsiteEvent.position.x, embeddedWebsiteEvent.position.y, iframe)
|
||||
.setVisible(visible)
|
||||
.setOrigin(0, 0),
|
||||
iframe: iframe,
|
||||
};
|
||||
if (embeddedWebsiteEvent.allowApi) {
|
||||
iframeListener.registerIframe(iframe);
|
||||
}
|
||||
|
||||
return embeddedWebsite;
|
||||
}
|
||||
|
||||
close(): void {
|
||||
for (const [key, website] of this.embeddedWebsites) {
|
||||
if (website.allowApi) {
|
||||
iframeListener.unregisterIframe(website.iframe);
|
||||
}
|
||||
}
|
||||
|
||||
this.subscription.unsubscribe();
|
||||
iframeListener.unregisterAnswerer("getEmbeddedWebsite");
|
||||
iframeListener.unregisterAnswerer("deleteEmbeddedWebsite");
|
||||
iframeListener.unregisterAnswerer("createEmbeddedWebsite");
|
||||
}
|
||||
}
|
|
@ -89,6 +89,7 @@ import Tileset = Phaser.Tilemaps.Tileset;
|
|||
import { userIsAdminStore } from "../../Stores/GameStore";
|
||||
import { layoutManagerActionStore } from "../../Stores/LayoutManagerStore";
|
||||
import { get } from "svelte/store";
|
||||
import { EmbeddedWebsiteManager } from "./EmbeddedWebsiteManager";
|
||||
|
||||
export interface GameSceneInitInterface {
|
||||
initPosition: PointInterface | null;
|
||||
|
@ -200,7 +201,7 @@ export class GameScene extends DirtyScene {
|
|||
private startPositionCalculator!: StartPositionCalculator;
|
||||
private sharedVariablesManager!: SharedVariablesManager;
|
||||
private objectsByType = new Map<string, ITiledMapObject[]>();
|
||||
private inMapIframes = new Array<HTMLIFrameElement>();
|
||||
private embeddedWebsiteManager!: EmbeddedWebsiteManager;
|
||||
|
||||
constructor(private room: Room, MapUrlFile: string, customKey?: string | undefined) {
|
||||
super({
|
||||
|
@ -419,6 +420,7 @@ export class GameScene extends DirtyScene {
|
|||
|
||||
//hook create scene
|
||||
create(): void {
|
||||
console.log("GAAAAAAAGAGAGAGAGA");
|
||||
this.preloading = false;
|
||||
this.trackDirtyAnims();
|
||||
|
||||
|
@ -460,6 +462,8 @@ export class GameScene extends DirtyScene {
|
|||
//permit to set bound collision
|
||||
this.physics.world.setBounds(0, 0, this.Map.widthInPixels, this.Map.heightInPixels);
|
||||
|
||||
this.embeddedWebsiteManager = new EmbeddedWebsiteManager(this);
|
||||
|
||||
//add layer on map
|
||||
this.gameMap = new GameMap(this.mapFile, this.Map, this.Terrains);
|
||||
for (const layer of this.gameMap.flatLayers) {
|
||||
|
@ -487,26 +491,20 @@ export class GameScene extends DirtyScene {
|
|||
object.properties,
|
||||
'in the "' + object.name + '" object of type "website"'
|
||||
);
|
||||
const absoluteUrl = new URL(url, this.MapUrlFile).toString();
|
||||
const allowApi = PropertyUtils.findBooleanProperty("allowApi", object.properties);
|
||||
|
||||
const iframe = document.createElement("iframe");
|
||||
iframe.src = absoluteUrl;
|
||||
iframe.style.width = object.width + "px";
|
||||
iframe.style.height = object.height + "px";
|
||||
iframe.style.margin = "0";
|
||||
iframe.style.padding = "0";
|
||||
iframe.style.border = "none";
|
||||
|
||||
this.add.dom(object.x, object.y).setElement(iframe).setOrigin(0, 0);
|
||||
|
||||
const allowApi = PropertyUtils.findBooleanProperty(
|
||||
"allowApi",
|
||||
object.properties,
|
||||
// TODO: add a "allow" property to iframe
|
||||
this.embeddedWebsiteManager.createEmbeddedWebsite(
|
||||
object.name,
|
||||
url,
|
||||
object.x,
|
||||
object.y,
|
||||
object.width,
|
||||
object.height,
|
||||
object.visible,
|
||||
allowApi ?? false,
|
||||
""
|
||||
);
|
||||
if (allowApi) {
|
||||
iframeListener.registerIframe(iframe);
|
||||
this.inMapIframes.push(iframe);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1197,6 +1195,27 @@ ${escapedMessage}
|
|||
iframeListener.registerAnswerer("removeActionMessage", (message) => {
|
||||
layoutManagerActionStore.removeAction(message.uuid);
|
||||
});
|
||||
|
||||
this.iframeSubscriptionList.push(
|
||||
iframeListener.modifyEmbeddedWebsiteStream.subscribe((embeddedWebsite) => {
|
||||
// TODO
|
||||
// TODO
|
||||
// TODO
|
||||
// TODO
|
||||
// TODO
|
||||
// TODO
|
||||
// TODO
|
||||
// TODO
|
||||
// TODO
|
||||
// TODO
|
||||
// TODO
|
||||
// TODO
|
||||
// TODO
|
||||
// TODO
|
||||
// TODO
|
||||
// TODO
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private setPropertyLayer(
|
||||
|
@ -1264,7 +1283,7 @@ ${escapedMessage}
|
|||
let targetRoom: Room;
|
||||
try {
|
||||
targetRoom = await Room.createRoom(roomUrl);
|
||||
} catch (e) {
|
||||
} catch (e /*: unknown*/) {
|
||||
console.error('Error while fetching new room "' + roomUrl.toString() + '"', e);
|
||||
this.mapTransitioning = false;
|
||||
return;
|
||||
|
@ -1303,9 +1322,6 @@ ${escapedMessage}
|
|||
for (const script of scripts) {
|
||||
iframeListener.unregisterScript(script);
|
||||
}
|
||||
for (const iframe of this.inMapIframes) {
|
||||
iframeListener.unregisterIframe(iframe);
|
||||
}
|
||||
|
||||
this.stopJitsi();
|
||||
audioManager.unloadAudio();
|
||||
|
@ -1327,6 +1343,7 @@ ${escapedMessage}
|
|||
iframeListener.unregisterAnswerer("triggerActionMessage");
|
||||
iframeListener.unregisterAnswerer("removeActionMessage");
|
||||
this.sharedVariablesManager?.close();
|
||||
this.embeddedWebsiteManager?.close();
|
||||
|
||||
mediaManager.hideGameOverlay();
|
||||
|
||||
|
@ -1398,7 +1415,7 @@ ${escapedMessage}
|
|||
try {
|
||||
const room = await Room.createRoom(exitRoomPath);
|
||||
return gameManager.loadMap(room, this.scene);
|
||||
} catch (e) {
|
||||
} catch (e /*: unknown*/) {
|
||||
console.warn('Error while pre-loading exit room "' + exitRoomPath.toString() + '"', e);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue