diff --git a/front/.eslintrc.json b/front/.eslintrc.json index 037fddae..944e3893 100644 --- a/front/.eslintrc.json +++ b/front/.eslintrc.json @@ -25,8 +25,11 @@ ], "rules": { "no-unused-vars": "off", + "quotes": [ + "warn", + "single" + ], "@typescript-eslint/no-explicit-any": "error", - // TODO: remove those ignored rules and write a stronger code! "@typescript-eslint/no-floating-promises": "off", "@typescript-eslint/no-unsafe-call": "off", @@ -36,4 +39,4 @@ "@typescript-eslint/no-unsafe-member-access": "off", "@typescript-eslint/restrict-template-expressions": "off" } -} +} \ No newline at end of file diff --git a/front/.prettierrc.json b/front/.prettierrc.json index e8980d15..b4f04948 100644 --- a/front/.prettierrc.json +++ b/front/.prettierrc.json @@ -1,4 +1,5 @@ { "printWidth": 120, - "tabWidth": 4 + "tabWidth": 4, + "singleQuote": true } diff --git a/front/src/Api/Events/IframeEvent.ts b/front/src/Api/Events/IframeEvent.ts index ed2db1db..1cf67891 100644 --- a/front/src/Api/Events/IframeEvent.ts +++ b/front/src/Api/Events/IframeEvent.ts @@ -1,29 +1,29 @@ -import type { GameStateEvent } from "./GameStateEvent"; -import type { ButtonClickedEvent } from "./ButtonClickedEvent"; -import type { ChatEvent } from "./ChatEvent"; -import type { ClosePopupEvent } from "./ClosePopupEvent"; -import type { EnterLeaveEvent } from "./EnterLeaveEvent"; -import type { GoToPageEvent } from "./GoToPageEvent"; -import type { LoadPageEvent } from "./LoadPageEvent"; -import type { OpenCoWebSiteEvent } from "./OpenCoWebSiteEvent"; -import type { OpenPopupEvent } from "./OpenPopupEvent"; -import type { OpenTabEvent } from "./OpenTabEvent"; -import type { UserInputChatEvent } from "./UserInputChatEvent"; -import type { DataLayerEvent } from "./DataLayerEvent"; -import type { LayerEvent } from "./LayerEvent"; -import type { SetPropertyEvent } from "./setPropertyEvent"; -import type { LoadSoundEvent } from "./LoadSoundEvent"; -import type { PlaySoundEvent } from "./PlaySoundEvent"; -import type { MenuItemClickedEvent } from "./ui/MenuItemClickedEvent"; -import type { MenuItemRegisterEvent } from "./ui/MenuItemRegisterEvent"; -import type { HasPlayerMovedEvent } from "./HasPlayerMovedEvent"; -import type { SetTilesEvent } from "./SetTilesEvent"; +import type { GameStateEvent } from './GameStateEvent'; +import type { ButtonClickedEvent } from './ButtonClickedEvent'; +import type { ChatEvent } from './ChatEvent'; +import type { ClosePopupEvent } from './ClosePopupEvent'; +import type { EnterLeaveEvent } from './EnterLeaveEvent'; +import type { GoToPageEvent } from './GoToPageEvent'; +import type { LoadPageEvent } from './LoadPageEvent'; +import type { OpenCoWebSiteEvent } from './OpenCoWebSiteEvent'; +import type { OpenPopupEvent } from './OpenPopupEvent'; +import type { OpenTabEvent } from './OpenTabEvent'; +import type { UserInputChatEvent } from './UserInputChatEvent'; +import type { DataLayerEvent } from './DataLayerEvent'; +import type { LayerEvent } from './LayerEvent'; +import type { SetPropertyEvent } from './setPropertyEvent'; +import type { LoadSoundEvent } from './LoadSoundEvent'; +import type { PlaySoundEvent } from './PlaySoundEvent'; +import type { MenuItemClickedEvent } from './ui/MenuItemClickedEvent'; +import type { MenuItemRegisterEvent } from './ui/MenuItemRegisterEvent'; +import type { HasPlayerMovedEvent } from './HasPlayerMovedEvent'; +import type { SetTilesEvent } from './SetTilesEvent'; import type { MessageReferenceEvent, removeTriggerMessage, triggerMessage, TriggerMessageEvent, -} from "./ui/TriggerMessageEvent"; +} from './ui/TriggerMessageEvent'; export interface TypedMessageEvent extends MessageEvent { data: T; @@ -67,7 +67,7 @@ export interface IframeEvent { // eslint-disable-next-line @typescript-eslint/no-explicit-any export const isIframeEventWrapper = (event: any): event is IframeEvent => - typeof event.type === "string"; + typeof event.type === 'string'; export interface IframeResponseEventMap { userInputChat: UserInputChatEvent; @@ -87,7 +87,7 @@ export interface IframeResponseEvent { // eslint-disable-next-line @typescript-eslint/no-explicit-any export const isIframeResponseEventWrapper = (event: { type?: string; -}): event is IframeResponseEvent => typeof event.type === "string"; +}): event is IframeResponseEvent => typeof event.type === 'string'; /** * List event types sent from an iFrame to WorkAdventure that expect a unique answer from WorkAdventure along the type for the answer from WorkAdventure to the iFrame @@ -111,7 +111,7 @@ export type IframeQueryMap = { export interface IframeQuery { type: T; - data: IframeQueryMap[T]["query"]; + data: IframeQueryMap[T]['query']; } export interface IframeQueryWrapper { @@ -120,22 +120,22 @@ export interface IframeQueryWrapper { } // eslint-disable-next-line @typescript-eslint/no-explicit-any -export const isIframeQuery = (event: any): event is IframeQuery => typeof event.type === "string"; +export const isIframeQuery = (event: any): event is IframeQuery => typeof event.type === 'string'; // eslint-disable-next-line @typescript-eslint/no-explicit-any export const isIframeQueryWrapper = (event: any): event is IframeQueryWrapper => - typeof event.id === "number" && isIframeQuery(event.query); + typeof event.id === 'number' && isIframeQuery(event.query); export interface IframeAnswerEvent { id: number; type: T; - data: IframeQueryMap[T]["answer"]; + data: IframeQueryMap[T]['answer']; } export const isIframeAnswerEvent = (event: { type?: string; id?: number; -}): event is IframeAnswerEvent => typeof event.type === "string" && typeof event.id === "number"; +}): event is IframeAnswerEvent => typeof event.type === 'string' && typeof event.id === 'number'; export interface IframeErrorAnswerEvent { id: number; @@ -148,4 +148,4 @@ export const isIframeErrorAnswerEvent = (event: { id?: number; error?: string; }): event is IframeErrorAnswerEvent => - typeof event.type === "string" && typeof event.id === "number" && typeof event.error === "string"; + typeof event.type === 'string' && typeof event.id === 'number' && typeof event.error === 'string'; diff --git a/front/src/Api/Events/ui/TriggerMessageEvent.ts b/front/src/Api/Events/ui/TriggerMessageEvent.ts index 5b42b02e..6698104c 100644 --- a/front/src/Api/Events/ui/TriggerMessageEvent.ts +++ b/front/src/Api/Events/ui/TriggerMessageEvent.ts @@ -1,21 +1,21 @@ -import * as tg from "generic-type-guard"; +import * as tg from 'generic-type-guard'; -export const triggerMessage = "triggerMessage" -export const removeTriggerMessage = "removeTriggerMessage" - -export const isTriggerMessageEvent = new tg.IsInterface().withProperties({ - message: tg.isString, - uuid: tg.isString -}).get() +export const triggerMessage = 'triggerMessage'; +export const removeTriggerMessage = 'removeTriggerMessage'; +export const isTriggerMessageEvent = new tg.IsInterface() + .withProperties({ + message: tg.isString, + uuid: tg.isString, + }) + .get(); export type TriggerMessageEvent = tg.GuardedType; - -export const isMessageReferenceEvent = - new tg.IsInterface().withProperties({ - uuid: tg.isString - }).get(); - +export const isMessageReferenceEvent = new tg.IsInterface() + .withProperties({ + uuid: tg.isString, + }) + .get(); export type MessageReferenceEvent = tg.GuardedType; diff --git a/front/src/Api/Events/ui/TriggerMessageEventHandler.ts b/front/src/Api/Events/ui/TriggerMessageEventHandler.ts index d7326e00..06cc0917 100644 --- a/front/src/Api/Events/ui/TriggerMessageEventHandler.ts +++ b/front/src/Api/Events/ui/TriggerMessageEventHandler.ts @@ -1,22 +1,11 @@ -import { Subject } from "rxjs"; -import { iframeListener } from "../../IframeListener"; import { isMessageReferenceEvent, isTriggerMessageEvent, - MessageReferenceEvent, removeTriggerMessage, triggerMessage, - TriggerMessageEvent, -} from "./TriggerMessageEvent"; -import * as tg from "generic-type-guard"; -export function sendMessageTriggeredEvent(uuid: string) { - iframeListener.postMessage({ - type: "messageTriggered", - data: { - uuid, - } as MessageReferenceEvent, - }); -} +} from './TriggerMessageEvent'; + +import * as tg from 'generic-type-guard'; const isTriggerMessageEventObject = new tg.IsInterface() .withProperties({ diff --git a/front/src/Api/IframeListener.ts b/front/src/Api/IframeListener.ts index 224f86db..df9596c1 100644 --- a/front/src/Api/IframeListener.ts +++ b/front/src/Api/IframeListener.ts @@ -1,15 +1,15 @@ -import { Subject } from "rxjs"; -import type * as tg from "generic-type-guard"; -import { ChatEvent, isChatEvent } from "./Events/ChatEvent"; -import { HtmlUtils } from "../WebRtc/HtmlUtils"; -import type { EnterLeaveEvent } from "./Events/EnterLeaveEvent"; -import { isOpenPopupEvent, OpenPopupEvent } from "./Events/OpenPopupEvent"; -import { isOpenTabEvent, OpenTabEvent } from "./Events/OpenTabEvent"; -import type { ButtonClickedEvent } from "./Events/ButtonClickedEvent"; -import { ClosePopupEvent, isClosePopupEvent } from "./Events/ClosePopupEvent"; -import { scriptUtils } from "./ScriptUtils"; -import { GoToPageEvent, isGoToPageEvent } from "./Events/GoToPageEvent"; -import { isOpenCoWebsite, OpenCoWebSiteEvent } from "./Events/OpenCoWebSiteEvent"; +import { Subject } from 'rxjs'; +import type * as tg from 'generic-type-guard'; +import { ChatEvent, isChatEvent } from './Events/ChatEvent'; +import { HtmlUtils } from '../WebRtc/HtmlUtils'; +import type { EnterLeaveEvent } from './Events/EnterLeaveEvent'; +import { isOpenPopupEvent, OpenPopupEvent } from './Events/OpenPopupEvent'; +import { isOpenTabEvent, OpenTabEvent } from './Events/OpenTabEvent'; +import type { ButtonClickedEvent } from './Events/ButtonClickedEvent'; +import { ClosePopupEvent, isClosePopupEvent } from './Events/ClosePopupEvent'; +import { scriptUtils } from './ScriptUtils'; +import { GoToPageEvent, isGoToPageEvent } from './Events/GoToPageEvent'; +import { isOpenCoWebsite, OpenCoWebSiteEvent } from './Events/OpenCoWebSiteEvent'; import { IframeErrorAnswerEvent, IframeEvent, @@ -21,24 +21,24 @@ import { isIframeEventWrapper, isIframeQueryWrapper, TypedMessageEvent, -} from "./Events/IframeEvent"; -import type { UserInputChatEvent } from "./Events/UserInputChatEvent"; -import { isPlaySoundEvent, PlaySoundEvent } from "./Events/PlaySoundEvent"; -import { isStopSoundEvent, StopSoundEvent } from "./Events/StopSoundEvent"; -import { isLoadSoundEvent, LoadSoundEvent } from "./Events/LoadSoundEvent"; -import { isSetPropertyEvent, SetPropertyEvent } from "./Events/setPropertyEvent"; -import { isLayerEvent, LayerEvent } from "./Events/LayerEvent"; -import { isMenuItemRegisterEvent } from "./Events/ui/MenuItemRegisterEvent"; -import type { DataLayerEvent } from "./Events/DataLayerEvent"; -import type { GameStateEvent } from "./Events/GameStateEvent"; -import type { HasPlayerMovedEvent } from "./Events/HasPlayerMovedEvent"; -import { isLoadPageEvent } from "./Events/LoadPageEvent"; -import { handleMenuItemRegistrationEvent, isMenuItemRegisterIframeEvent } from "./Events/ui/MenuItemRegisterEvent"; -import { SetTilesEvent, isSetTilesEvent } from "./Events/SetTilesEvent"; +} from './Events/IframeEvent'; +import type { UserInputChatEvent } from './Events/UserInputChatEvent'; +import { isPlaySoundEvent, PlaySoundEvent } from './Events/PlaySoundEvent'; +import { isStopSoundEvent, StopSoundEvent } from './Events/StopSoundEvent'; +import { isLoadSoundEvent, LoadSoundEvent } from './Events/LoadSoundEvent'; +import { isSetPropertyEvent, SetPropertyEvent } from './Events/setPropertyEvent'; +import { isLayerEvent, LayerEvent } from './Events/LayerEvent'; +import { isMenuItemRegisterEvent } from './Events/ui/MenuItemRegisterEvent'; +import type { DataLayerEvent } from './Events/DataLayerEvent'; +import type { GameStateEvent } from './Events/GameStateEvent'; +import type { HasPlayerMovedEvent } from './Events/HasPlayerMovedEvent'; +import { isLoadPageEvent } from './Events/LoadPageEvent'; +import { handleMenuItemRegistrationEvent, isMenuItemRegisterIframeEvent } from './Events/ui/MenuItemRegisterEvent'; +import { SetTilesEvent, isSetTilesEvent } from './Events/SetTilesEvent'; type AnswererCallback = ( - query: IframeQueryMap[T]["query"] -) => IframeQueryMap[T]["answer"] | Promise; + query: IframeQueryMap[T]['query'] +) => IframeQueryMap[T]['answer'] | Promise; /** * Listens to messages from iframes and turn those messages into easy to use observables. @@ -122,7 +122,7 @@ class IframeListener { init() { window.addEventListener( - "message", + 'message', ( message: TypedMessageEvent> ) => { @@ -144,10 +144,10 @@ class IframeListener { if (foundSrc === undefined || iframe === undefined) { if (isIframeEventWrapper(payload)) { console.warn( - "It seems an iFrame is trying to communicate with WorkAdventure but was not explicitly granted the permission to do so. " + - "If you are looking to use the WorkAdventure Scripting API inside an iFrame, you should allow the " + + 'It seems an iFrame is trying to communicate with WorkAdventure but was not explicitly granted the permission to do so. ' + + 'If you are looking to use the WorkAdventure Scripting API inside an iFrame, you should allow the ' + 'iFrame to communicate with WorkAdventure by using the "openWebsiteAllowApi" property in your map (or passing "true" as a second' + - "parameter to WA.nav.openCoWebSite())" + 'parameter to WA.nav.openCoWebSite())' ); } return; @@ -172,7 +172,7 @@ class IframeListener { type: query.type, error: errorMsg, } as IframeErrorAnswerEvent, - "*" + '*' ); return; } @@ -185,11 +185,11 @@ class IframeListener { type: query.type, data: value, }, - "*" + '*' ); }) .catch((reason) => { - console.error("An error occurred while responding to an iFrame query.", reason); + console.error('An error occurred while responding to an iFrame query.', reason); let reasonMsg: string; if (reason instanceof Error) { reasonMsg = reason.message; @@ -203,54 +203,54 @@ class IframeListener { type: query.type, error: reasonMsg, } as IframeErrorAnswerEvent, - "*" + '*' ); }); } else if (isIframeEventWrapper(payload)) { - if (payload.type === "showLayer" && isLayerEvent(payload.data)) { + if (payload.type === 'showLayer' && isLayerEvent(payload.data)) { this._showLayerStream.next(payload.data); - } else if (payload.type === "hideLayer" && isLayerEvent(payload.data)) { + } else if (payload.type === 'hideLayer' && isLayerEvent(payload.data)) { this._hideLayerStream.next(payload.data); - } else if (payload.type === "setProperty" && isSetPropertyEvent(payload.data)) { + } else if (payload.type === 'setProperty' && isSetPropertyEvent(payload.data)) { this._setPropertyStream.next(payload.data); - } else if (payload.type === "chat" && isChatEvent(payload.data)) { + } else if (payload.type === 'chat' && isChatEvent(payload.data)) { this._chatStream.next(payload.data); - } else if (payload.type === "openPopup" && isOpenPopupEvent(payload.data)) { + } else if (payload.type === 'openPopup' && isOpenPopupEvent(payload.data)) { this._openPopupStream.next(payload.data); - } else if (payload.type === "closePopup" && isClosePopupEvent(payload.data)) { + } else if (payload.type === 'closePopup' && isClosePopupEvent(payload.data)) { this._closePopupStream.next(payload.data); - } else if (payload.type === "openTab" && isOpenTabEvent(payload.data)) { + } else if (payload.type === 'openTab' && isOpenTabEvent(payload.data)) { scriptUtils.openTab(payload.data.url); - } else if (payload.type === "goToPage" && isGoToPageEvent(payload.data)) { + } else if (payload.type === 'goToPage' && isGoToPageEvent(payload.data)) { scriptUtils.goToPage(payload.data.url); - } else if (payload.type === "loadPage" && isLoadPageEvent(payload.data)) { + } else if (payload.type === 'loadPage' && isLoadPageEvent(payload.data)) { this._loadPageStream.next(payload.data.url); - } else if (payload.type === "playSound" && isPlaySoundEvent(payload.data)) { + } else if (payload.type === 'playSound' && isPlaySoundEvent(payload.data)) { this._playSoundStream.next(payload.data); - } else if (payload.type === "stopSound" && isStopSoundEvent(payload.data)) { + } else if (payload.type === 'stopSound' && isStopSoundEvent(payload.data)) { this._stopSoundStream.next(payload.data); - } else if (payload.type === "loadSound" && isLoadSoundEvent(payload.data)) { + } else if (payload.type === 'loadSound' && isLoadSoundEvent(payload.data)) { this._loadSoundStream.next(payload.data); - } else if (payload.type === "openCoWebSite" && isOpenCoWebsite(payload.data)) { + } else if (payload.type === 'openCoWebSite' && isOpenCoWebsite(payload.data)) { scriptUtils.openCoWebsite( payload.data.url, foundSrc, payload.data.allowApi, payload.data.allowPolicy ); - } else if (payload.type === "closeCoWebSite") { + } else if (payload.type === 'closeCoWebSite') { scriptUtils.closeCoWebSite(); - } else if (payload.type === "disablePlayerControls") { + } else if (payload.type === 'disablePlayerControls') { this._disablePlayerControlStream.next(); - } else if (payload.type === "restorePlayerControls") { + } else if (payload.type === 'restorePlayerControls') { this._enablePlayerControlStream.next(); - } else if (payload.type === "displayBubble") { + } else if (payload.type === 'displayBubble') { this._displayBubbleStream.next(); - } else if (payload.type === "removeBubble") { + } else if (payload.type === 'removeBubble') { this._removeBubbleStream.next(); - } else if (payload.type == "onPlayerMove") { + } else if (payload.type == 'onPlayerMove') { this.sendPlayerMove = true; - } else if (payload.type == "getDataLayer") { + } else if (payload.type == 'getDataLayer') { this._dataLayerChangeStream.next(); } else if (isMenuItemRegisterIframeEvent(payload)) { const data = payload.data.menutItem; @@ -259,7 +259,7 @@ class IframeListener { this._unregisterMenuCommandStream.next(data); }); handleMenuItemRegistrationEvent(payload.data); - } else if (payload.type == "setTiles" && isSetTilesEvent(payload.data)) { + } else if (payload.type == 'setTiles' && isSetTilesEvent(payload.data)) { this._setTilesStream.next(payload.data); } } @@ -270,7 +270,7 @@ class IframeListener { sendDataLayerEvent(dataLayerEvent: DataLayerEvent) { this.postMessage({ - type: "dataLayer", + type: 'dataLayer', data: dataLayerEvent, }); } @@ -291,18 +291,18 @@ class IframeListener { } registerScript(scriptUrl: string): void { - console.log("Loading map related script at ", scriptUrl); + console.log('Loading map related script at ', scriptUrl); - if (!process.env.NODE_ENV || process.env.NODE_ENV === "development") { + if (!process.env.NODE_ENV || process.env.NODE_ENV === 'development') { // Using external iframe mode ( - const iframe = document.createElement("iframe"); + const iframe = document.createElement('iframe'); iframe.id = IframeListener.getIFrameId(scriptUrl); - iframe.style.display = "none"; - iframe.src = "/iframe.html?script=" + encodeURIComponent(scriptUrl); + iframe.style.display = 'none'; + iframe.src = '/iframe.html?script=' + encodeURIComponent(scriptUrl); // We are putting a sandbox on this script because it will run in the same domain as the main website. - iframe.sandbox.add("allow-scripts"); - iframe.sandbox.add("allow-top-navigation-by-user-activation"); + iframe.sandbox.add('allow-scripts'); + iframe.sandbox.add('allow-top-navigation-by-user-activation'); document.body.prepend(iframe); @@ -310,31 +310,31 @@ class IframeListener { this.registerIframe(iframe); } else { // production code - const iframe = document.createElement("iframe"); + const iframe = document.createElement('iframe'); iframe.id = IframeListener.getIFrameId(scriptUrl); - iframe.style.display = "none"; + iframe.style.display = 'none'; // We are putting a sandbox on this script because it will run in the same domain as the main website. - iframe.sandbox.add("allow-scripts"); - iframe.sandbox.add("allow-top-navigation-by-user-activation"); + iframe.sandbox.add('allow-scripts'); + iframe.sandbox.add('allow-top-navigation-by-user-activation'); //iframe.src = "data:text/html;charset=utf-8," + escape(html); iframe.srcdoc = - "\n" + - "\n" + + '\n' + + '\n' + '\n' + - "\n" + + '\n' + '\n' + '\n' + - "\n" + - "\n" + - "\n"; + '\n' + + '\n' + + '\n'; document.body.prepend(iframe); @@ -353,7 +353,7 @@ class IframeListener { } private static getIFrameId(scriptUrl: string): string { - return "script" + btoa(scriptUrl); + return 'script' + btoa(scriptUrl); } unregisterScript(scriptUrl: string): void { @@ -370,7 +370,7 @@ class IframeListener { sendUserInputChat(message: string) { this.postMessage({ - type: "userInputChat", + type: 'userInputChat', data: { message: message, } as UserInputChatEvent, @@ -379,7 +379,7 @@ class IframeListener { sendEnterEvent(name: string) { this.postMessage({ - type: "enterEvent", + type: 'enterEvent', data: { name: name, } as EnterLeaveEvent, @@ -388,7 +388,7 @@ class IframeListener { sendLeaveEvent(name: string) { this.postMessage({ - type: "leaveEvent", + type: 'leaveEvent', data: { name: name, } as EnterLeaveEvent, @@ -398,7 +398,7 @@ class IframeListener { hasPlayerMoved(event: HasPlayerMovedEvent) { if (this.sendPlayerMove) { this.postMessage({ - type: "hasPlayerMoved", + type: 'hasPlayerMoved', data: event, }); } @@ -406,7 +406,7 @@ class IframeListener { sendButtonClickedEvent(popupId: number, buttonId: number): void { this.postMessage({ - type: "buttonClickedEvent", + type: 'buttonClickedEvent', data: { popupId, buttonId, @@ -419,7 +419,7 @@ class IframeListener { */ public postMessage(message: IframeResponseEvent) { for (const iframe of this.iframes) { - iframe.contentWindow?.postMessage(message, "*"); + iframe.contentWindow?.postMessage(message, '*'); } } @@ -431,7 +431,7 @@ class IframeListener { * @param key The "type" of the query we are answering * @param callback */ - public registerAnswerer>( + public registerAnswerer>( key: T, callback: AnswererCallback, typeChecker?: Guard diff --git a/front/src/Api/iframe/Ui/TriggerMessage.ts b/front/src/Api/iframe/Ui/TriggerMessage.ts index 333e6992..3afc0064 100644 --- a/front/src/Api/iframe/Ui/TriggerMessage.ts +++ b/front/src/Api/iframe/Ui/TriggerMessage.ts @@ -3,12 +3,12 @@ import { removeTriggerMessage, triggerMessage, TriggerMessageEvent, -} from "../../Events/ui/TriggerMessageEvent"; -import { queryWorkadventure } from "../IframeApiContribution"; +} from '../../Events/ui/TriggerMessageEvent'; +import { queryWorkadventure } from '../IframeApiContribution'; function uuidv4() { - return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { const r = (Math.random() * 16) | 0, - v = c === "x" ? r : (r & 0x3) | 0x8; + v = c === 'x' ? r : (r & 0x3) | 0x8; return v.toString(16); }); } diff --git a/front/src/Api/iframe/ui.ts b/front/src/Api/iframe/ui.ts index c1fa85b5..302a9eff 100644 --- a/front/src/Api/iframe/ui.ts +++ b/front/src/Api/iframe/ui.ts @@ -1,10 +1,10 @@ -import { isButtonClickedEvent } from "../Events/ButtonClickedEvent"; -import { isMenuItemClickedEvent } from "../Events/ui/MenuItemClickedEvent"; -import { IframeApiContribution, sendToWorkadventure } from "./IframeApiContribution"; -import { apiCallback } from "./registeredCallbacks"; -import type { ButtonClickedCallback, ButtonDescriptor } from "./Ui/ButtonDescriptor"; -import { Popup } from "./Ui/Popup"; -import { TriggerMessage } from "./Ui/TriggerMessage"; +import { isButtonClickedEvent } from '../Events/ButtonClickedEvent'; +import { isMenuItemClickedEvent } from '../Events/ui/MenuItemClickedEvent'; +import { IframeApiContribution, sendToWorkadventure } from './IframeApiContribution'; +import { apiCallback } from './registeredCallbacks'; +import type { ButtonClickedCallback, ButtonDescriptor } from './Ui/ButtonDescriptor'; +import { Popup } from './Ui/Popup'; +import { TriggerMessage } from './Ui/TriggerMessage'; let popupId = 0; const popups: Map = new Map(); @@ -26,7 +26,7 @@ interface ZonedPopupOptions { export class WorkAdventureUiCommands extends IframeApiContribution { callbacks = [ apiCallback({ - type: "buttonClickedEvent", + type: 'buttonClickedEvent', typeChecker: isButtonClickedEvent, callback: (payloadData) => { const callback = popupCallbacks.get(payloadData.popupId)?.get(payloadData.buttonId); @@ -40,7 +40,7 @@ export class WorkAdventureUiCommands extends IframeApiContribution { const callback = menuCallbacks.get(event.menuItem); @@ -68,7 +68,7 @@ export class WorkAdventureUiCommands extends IframeApiContribution void) { menuCallbacks.set(commandDescriptor, callback); sendToWorkadventure({ - type: "registerMenuCommand", + type: 'registerMenuCommand', data: { menutItem: commandDescriptor, }, @@ -97,11 +97,11 @@ export class WorkAdventureUiCommands extends IframeApiContribution void): TriggerMessage { diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 530a31e2..17f0594f 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -1,8 +1,8 @@ -import type { Subscription } from "rxjs"; -import { GlobalMessageManager } from "../../Administration/GlobalMessageManager"; -import { userMessageManager } from "../../Administration/UserMessageManager"; -import { iframeListener } from "../../Api/IframeListener"; -import { connectionManager } from "../../Connexion/ConnectionManager"; +import type { Subscription } from 'rxjs'; +import { GlobalMessageManager } from '../../Administration/GlobalMessageManager'; +import { userMessageManager } from '../../Administration/UserMessageManager'; +import { iframeListener } from '../../Api/IframeListener'; +import { connectionManager } from '../../Connexion/ConnectionManager'; import type { GroupCreatedUpdatedMessageInterface, MessageUserJoined, @@ -12,10 +12,10 @@ import type { PointInterface, PositionInterface, RoomJoinedMessageInterface, -} from "../../Connexion/ConnexionModels"; -import { DEBUG_MODE, JITSI_PRIVATE_MODE, MAX_PER_GROUP, POSITION_DELAY } from "../../Enum/EnvironmentVariable"; +} from '../../Connexion/ConnexionModels'; +import { DEBUG_MODE, JITSI_PRIVATE_MODE, MAX_PER_GROUP, POSITION_DELAY } from '../../Enum/EnvironmentVariable'; -import { Queue } from "queue-typescript"; +import { Queue } from 'queue-typescript'; import { AUDIO_LOOP_PROPERTY, AUDIO_VOLUME_PROPERTY, @@ -26,72 +26,72 @@ import { TRIGGER_JITSI_PROPERTIES, TRIGGER_WEBSITE_PROPERTIES, WEBSITE_MESSAGE_PROPERTIES, -} from "../../WebRtc/LayoutManager"; -import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager"; -import type { UserMovedMessage } from "../../Messages/generated/messages_pb"; -import { ProtobufClientUtils } from "../../Network/ProtobufClientUtils"; -import type { RoomConnection } from "../../Connexion/RoomConnection"; -import { Room } from "../../Connexion/Room"; -import { jitsiFactory } from "../../WebRtc/JitsiFactory"; -import { urlManager } from "../../Url/UrlManager"; -import { audioManager } from "../../WebRtc/AudioManager"; -import { TextureError } from "../../Exception/TextureError"; -import { localUserStore } from "../../Connexion/LocalUserStore"; -import { HtmlUtils } from "../../WebRtc/HtmlUtils"; -import { mediaManager } from "../../WebRtc/MediaManager"; -import { SimplePeer } from "../../WebRtc/SimplePeer"; -import { addLoader } from "../Components/Loader"; -import { OpenChatIcon, openChatIconName } from "../Components/OpenChatIcon"; -import { lazyLoadPlayerCharacterTextures, loadCustomTexture } from "../Entity/PlayerTexturesLoadingManager"; -import { RemotePlayer } from "../Entity/RemotePlayer"; -import type { ActionableItem } from "../Items/ActionableItem"; -import type { ItemFactoryInterface } from "../Items/ItemFactoryInterface"; -import { SelectCharacterScene, SelectCharacterSceneName } from "../Login/SelectCharacterScene"; +} from '../../WebRtc/LayoutManager'; +import { coWebsiteManager } from '../../WebRtc/CoWebsiteManager'; +import type { UserMovedMessage } from '../../Messages/generated/messages_pb'; +import { ProtobufClientUtils } from '../../Network/ProtobufClientUtils'; +import type { RoomConnection } from '../../Connexion/RoomConnection'; +import { Room } from '../../Connexion/Room'; +import { jitsiFactory } from '../../WebRtc/JitsiFactory'; +import { urlManager } from '../../Url/UrlManager'; +import { audioManager } from '../../WebRtc/AudioManager'; +import { TextureError } from '../../Exception/TextureError'; +import { localUserStore } from '../../Connexion/LocalUserStore'; +import { HtmlUtils } from '../../WebRtc/HtmlUtils'; +import { mediaManager } from '../../WebRtc/MediaManager'; +import { SimplePeer } from '../../WebRtc/SimplePeer'; +import { addLoader } from '../Components/Loader'; +import { OpenChatIcon, openChatIconName } from '../Components/OpenChatIcon'; +import { lazyLoadPlayerCharacterTextures, loadCustomTexture } from '../Entity/PlayerTexturesLoadingManager'; +import { RemotePlayer } from '../Entity/RemotePlayer'; +import type { ActionableItem } from '../Items/ActionableItem'; +import type { ItemFactoryInterface } from '../Items/ItemFactoryInterface'; +import { SelectCharacterScene, SelectCharacterSceneName } from '../Login/SelectCharacterScene'; import type { ITiledMap, ITiledMapLayer, ITiledMapLayerProperty, ITiledMapObject, ITiledTileSet, -} from "../Map/ITiledMap"; -import { MenuScene, MenuSceneName } from "../Menu/MenuScene"; -import { PlayerAnimationDirections } from "../Player/Animation"; -import { hasMovedEventName, Player, requestEmoteEventName } from "../Player/Player"; -import { ErrorSceneName } from "../Reconnecting/ErrorScene"; -import { ReconnectingSceneName } from "../Reconnecting/ReconnectingScene"; -import { UserInputManager } from "../UserInput/UserInputManager"; -import type { AddPlayerInterface } from "./AddPlayerInterface"; -import { gameManager } from "./GameManager"; -import { GameMap } from "./GameMap"; -import { PlayerMovement } from "./PlayerMovement"; -import { PlayersPositionInterpolator } from "./PlayersPositionInterpolator"; +} from '../Map/ITiledMap'; +import { MenuScene, MenuSceneName } from '../Menu/MenuScene'; +import { PlayerAnimationDirections } from '../Player/Animation'; +import { hasMovedEventName, Player, requestEmoteEventName } from '../Player/Player'; +import { ErrorSceneName } from '../Reconnecting/ErrorScene'; +import { ReconnectingSceneName } from '../Reconnecting/ReconnectingScene'; +import { UserInputManager } from '../UserInput/UserInputManager'; +import type { AddPlayerInterface } from './AddPlayerInterface'; +import { gameManager } from './GameManager'; +import { GameMap } from './GameMap'; +import { PlayerMovement } from './PlayerMovement'; +import { PlayersPositionInterpolator } from './PlayersPositionInterpolator'; import Texture = Phaser.Textures.Texture; import Sprite = Phaser.GameObjects.Sprite; import CanvasTexture = Phaser.Textures.CanvasTexture; import GameObject = Phaser.GameObjects.GameObject; import FILE_LOAD_ERROR = Phaser.Loader.Events.FILE_LOAD_ERROR; import DOMElement = Phaser.GameObjects.DOMElement; -import { worldFullMessageStream } from "../../Connexion/WorldFullMessageStream"; -import { lazyLoadCompanionResource } from "../Companion/CompanionTexturesLoadingManager"; -import { DirtyScene } from "./DirtyScene"; -import { TextUtils } from "../Components/TextUtils"; -import { touchScreenManager } from "../../Touch/TouchScreenManager"; -import { PinchManager } from "../UserInput/PinchManager"; -import { joystickBaseImg, joystickBaseKey, joystickThumbImg, joystickThumbKey } from "../Components/MobileJoystick"; -import { waScaleManager } from "../Services/WaScaleManager"; -import { EmoteManager } from "./EmoteManager"; +import { worldFullMessageStream } from '../../Connexion/WorldFullMessageStream'; +import { lazyLoadCompanionResource } from '../Companion/CompanionTexturesLoadingManager'; +import { DirtyScene } from './DirtyScene'; +import { TextUtils } from '../Components/TextUtils'; +import { touchScreenManager } from '../../Touch/TouchScreenManager'; +import { PinchManager } from '../UserInput/PinchManager'; +import { joystickBaseImg, joystickBaseKey, joystickThumbImg, joystickThumbKey } from '../Components/MobileJoystick'; +import { waScaleManager } from '../Services/WaScaleManager'; +import { EmoteManager } from './EmoteManager'; import EVENT_TYPE = Phaser.Scenes.Events; import RenderTexture = Phaser.GameObjects.RenderTexture; import Tilemap = Phaser.Tilemaps.Tilemap; -import type { HasPlayerMovedEvent } from "../../Api/Events/HasPlayerMovedEvent"; +import type { HasPlayerMovedEvent } from '../../Api/Events/HasPlayerMovedEvent'; -import AnimatedTiles from "phaser-animated-tiles"; -import { StartPositionCalculator } from "./StartPositionCalculator"; -import { soundManager } from "./SoundManager"; -import { peerStore, screenSharingPeerStore } from "../../Stores/PeerStore"; -import { videoFocusStore } from "../../Stores/VideoFocusStore"; -import { biggestAvailableAreaStore } from "../../Stores/BiggestAvailableAreaStore"; -import { isMessageReferenceEvent, isTriggerMessageEvent } from "../../Api/Events/ui/TriggerMessageEvent"; +import AnimatedTiles from 'phaser-animated-tiles'; +import { StartPositionCalculator } from './StartPositionCalculator'; +import { soundManager } from './SoundManager'; +import { peerStore, screenSharingPeerStore } from '../../Stores/PeerStore'; +import { videoFocusStore } from '../../Stores/VideoFocusStore'; +import { biggestAvailableAreaStore } from '../../Stores/BiggestAvailableAreaStore'; +import { isMessageReferenceEvent, isTriggerMessageEvent } from '../../Api/Events/ui/TriggerMessageEvent'; export interface GameSceneInitInterface { initPosition: PointInterface | null; @@ -99,32 +99,32 @@ export interface GameSceneInitInterface { } interface InitUserPositionEventInterface { - type: "InitUserPositionEvent"; + type: 'InitUserPositionEvent'; event: MessageUserPositionInterface[]; } interface AddPlayerEventInterface { - type: "AddPlayerEvent"; + type: 'AddPlayerEvent'; event: AddPlayerInterface; } interface RemovePlayerEventInterface { - type: "RemovePlayerEvent"; + type: 'RemovePlayerEvent'; userId: number; } interface UserMovedEventInterface { - type: "UserMovedEvent"; + type: 'UserMovedEvent'; event: MessageUserMovedInterface; } interface GroupCreatedUpdatedEventInterface { - type: "GroupCreatedUpdatedEvent"; + type: 'GroupCreatedUpdatedEvent'; event: GroupCreatedUpdatedMessageInterface; } interface DeleteGroupEventInterface { - type: "DeleteGroupEvent"; + type: 'DeleteGroupEvent'; groupId: number; } @@ -177,7 +177,7 @@ export class GameScene extends DirtyScene { currentTick!: number; lastSentTick!: number; // The last tick at which a position was sent. lastMoveEventSent: HasPlayerMovedEvent = { - direction: "", + direction: '', moving: false, x: -1000, y: -1000, @@ -231,29 +231,29 @@ export class GameScene extends DirtyScene { } } - this.load.image(openChatIconName, "resources/objects/talk.png"); + this.load.image(openChatIconName, 'resources/objects/talk.png'); if (touchScreenManager.supportTouchScreen) { this.load.image(joystickBaseKey, joystickBaseImg); this.load.image(joystickThumbKey, joystickThumbImg); } - this.load.audio("audio-webrtc-in", "/resources/objects/webrtc-in.mp3"); - this.load.audio("audio-webrtc-out", "/resources/objects/webrtc-out.mp3"); + this.load.audio('audio-webrtc-in', '/resources/objects/webrtc-in.mp3'); + this.load.audio('audio-webrtc-out', '/resources/objects/webrtc-out.mp3'); //this.load.audio('audio-report-message', '/resources/objects/report-message.mp3'); this.sound.pauseOnBlur = false; this.load.on(FILE_LOAD_ERROR, (file: { src: string }) => { // If we happen to be in HTTP and we are trying to load a URL in HTTPS only... (this happens only in dev environments) if ( - window.location.protocol === "http:" && + window.location.protocol === 'http:' && file.src === this.MapUrlFile && - file.src.startsWith("http:") && + file.src.startsWith('http:') && this.originalMapUrl === undefined ) { this.originalMapUrl = this.MapUrlFile; - this.MapUrlFile = this.MapUrlFile.replace("http://", "https://"); + this.MapUrlFile = this.MapUrlFile.replace('http://', 'https://'); this.load.tilemapTiledJSON(this.MapUrlFile, this.MapUrlFile); this.load.on( - "filecomplete-tilemapJSON-" + this.MapUrlFile, + 'filecomplete-tilemapJSON-' + this.MapUrlFile, (key: string, type: string, data: unknown) => { this.onMapLoad(data); } @@ -264,18 +264,18 @@ export class GameScene extends DirtyScene { // So if we are in https, we can still try to load a HTTP local resource (can be useful for testing purposes) // See https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts#when_is_a_context_considered_secure const url = new URL(file.src); - const host = url.host.split(":")[0]; + const host = url.host.split(':')[0]; if ( - window.location.protocol === "https:" && + window.location.protocol === 'https:' && file.src === this.MapUrlFile && - (host === "127.0.0.1" || host === "localhost" || host.endsWith(".localhost")) && + (host === '127.0.0.1' || host === 'localhost' || host.endsWith('.localhost')) && this.originalMapUrl === undefined ) { this.originalMapUrl = this.MapUrlFile; - this.MapUrlFile = this.MapUrlFile.replace("https://", "http://"); + this.MapUrlFile = this.MapUrlFile.replace('https://', 'http://'); this.load.tilemapTiledJSON(this.MapUrlFile, this.MapUrlFile); this.load.on( - "filecomplete-tilemapJSON-" + this.MapUrlFile, + 'filecomplete-tilemapJSON-' + this.MapUrlFile, (key: string, type: string, data: unknown) => { this.onMapLoad(data); } @@ -284,17 +284,17 @@ export class GameScene extends DirtyScene { } //once preloading is over, we don't want loading errors to crash the game, so we need to disable this behavior after preloading. - console.error("Error when loading: ", file); + console.error('Error when loading: ', file); if (this.preloading) { this.scene.start(ErrorSceneName, { - title: "Network error", - subTitle: "An error occurred while loading resource:", + title: 'Network error', + subTitle: 'An error occurred while loading resource:', message: this.originalMapUrl ?? file.src, }); } }); - this.load.scenePlugin("AnimatedTiles", AnimatedTiles, "animatedTiles", "animatedTiles"); - this.load.on("filecomplete-tilemapJSON-" + this.MapUrlFile, (key: string, type: string, data: unknown) => { + this.load.scenePlugin('AnimatedTiles', AnimatedTiles, 'animatedTiles', 'animatedTiles'); + this.load.on('filecomplete-tilemapJSON-' + this.MapUrlFile, (key: string, type: string, data: unknown) => { this.onMapLoad(data); }); //TODO strategy to add access token @@ -306,13 +306,13 @@ export class GameScene extends DirtyScene { this.onMapLoad(data); } - this.load.bitmapFont("main_font", "resources/fonts/arcade.png", "resources/fonts/arcade.xml"); + this.load.bitmapFont('main_font', 'resources/fonts/arcade.png', 'resources/fonts/arcade.xml'); //eslint-disable-next-line @typescript-eslint/no-explicit-any (this.load as any).rexWebFont({ custom: { - families: ["Press Start 2P"], - urls: ["/resources/fonts/fonts.css"], - testString: "abcdefg", + families: ['Press Start 2P'], + urls: ['/resources/fonts/fonts.css'], + testString: 'abcdefg', }, }); @@ -326,9 +326,9 @@ export class GameScene extends DirtyScene { // Triggered when the map is loaded // Load tiles attached to the map recursively this.mapFile = data.data; - const url = this.MapUrlFile.substr(0, this.MapUrlFile.lastIndexOf("/")); + const url = this.MapUrlFile.substr(0, this.MapUrlFile.lastIndexOf('/')); this.mapFile.tilesets.forEach((tileset) => { - if (typeof tileset.name === "undefined" || typeof tileset.image === "undefined") { + if (typeof tileset.name === 'undefined' || typeof tileset.image === 'undefined') { console.warn("Don't know how to handle tileset ", tileset); return; } @@ -340,7 +340,7 @@ export class GameScene extends DirtyScene { const objects = new Map(); for (const layer of this.mapFile.layers) { - if (layer.type === "objectgroup") { + if (layer.type === 'objectgroup') { for (const object of layer.objects) { let objectsOfType: ITiledMapObject[] | undefined; if (!objects.has(object.type)) { @@ -348,7 +348,7 @@ export class GameScene extends DirtyScene { } else { objectsOfType = objects.get(object.type); if (objectsOfType === undefined) { - throw new Error("Unexpected object type not found"); + throw new Error('Unexpected object type not found'); } } objectsOfType.push(object); @@ -363,8 +363,8 @@ export class GameScene extends DirtyScene { let itemFactory: ItemFactoryInterface; switch (itemType) { - case "computer": { - const module = await import("../Items/Computer/computer"); + case 'computer': { + const module = await import('../Items/Computer/computer'); itemFactory = module.default; break; } @@ -376,7 +376,7 @@ export class GameScene extends DirtyScene { itemFactory.preload(this.load); this.load.start(); // Let's manually start the loader because the import might be over AFTER the loading ends. - this.load.on("complete", () => { + this.load.on('complete', () => { // FIXME: the factory might fail because the resources might not be loaded yet... // We would need to add a loader ended event in addition to the createPromise this.createPromise.then(async () => { @@ -432,7 +432,7 @@ export class GameScene extends DirtyScene { const playerName = gameManager.getPlayerName(); if (!playerName) { - throw "playerName is not set"; + throw 'playerName is not set'; } this.playerName = playerName; this.characterLayers = gameManager.getCharacterLayers(); @@ -440,7 +440,7 @@ export class GameScene extends DirtyScene { //initalise map this.Map = this.add.tilemap(this.MapUrlFile); - const mapDirUrl = this.MapUrlFile.substr(0, this.MapUrlFile.lastIndexOf("/")); + const mapDirUrl = this.MapUrlFile.substr(0, this.MapUrlFile.lastIndexOf('/')); this.mapFile.tilesets.forEach((tileset: ITiledTileSet) => { this.Terrains.push( this.Map.addTilesetImage( @@ -460,7 +460,7 @@ export class GameScene extends DirtyScene { //add layer on map this.gameMap = new GameMap(this.mapFile, this.Map, this.Terrains); for (const layer of this.gameMap.flatLayers) { - if (layer.type === "tilelayer") { + if (layer.type === 'tilelayer') { const exitSceneUrl = this.getExitSceneUrl(layer); if (exitSceneUrl !== undefined) { this.loadNextGame(exitSceneUrl); @@ -470,7 +470,7 @@ export class GameScene extends DirtyScene { this.loadNextGame(exitUrl); } } - if (layer.type === "objectgroup") { + if (layer.type === 'objectgroup') { for (const object of layer.objects) { if (object.text) { TextUtils.createTextFromITiledMapObject(this, object); @@ -501,7 +501,7 @@ export class GameScene extends DirtyScene { mediaManager.setUserInputManager(this.userInputManager); if (localUserStore.getFullscreen()) { - document.querySelector("body")?.requestFullscreen(); + document.querySelector('body')?.requestFullscreen(); } //notify game manager can to create currentUser in map @@ -511,7 +511,7 @@ export class GameScene extends DirtyScene { this.initCamera(); this.animatedTiles.init(this.Map); - this.events.on("tileanimationupdate", () => (this.dirty = true)); + this.events.on('tileanimationupdate', () => (this.dirty = true)); this.initCirclesCanvas(); @@ -561,11 +561,11 @@ export class GameScene extends DirtyScene { this.peerStoreUnsubscribe = peerStore.subscribe((peers) => { const newPeerNumber = peers.size; if (newPeerNumber > oldPeerNumber) { - this.sound.play("audio-webrtc-in", { + this.sound.play('audio-webrtc-in', { volume: 0.2, }); } else if (newPeerNumber < oldPeerNumber) { - this.sound.play("audio-webrtc-out", { + this.sound.play('audio-webrtc-out', { volume: 0.2, }); } @@ -613,7 +613,7 @@ export class GameScene extends DirtyScene { this.connection.onUserMoved((message: UserMovedMessage) => { const position = message.getPosition(); if (position === undefined) { - throw new Error("Position missing from UserMovedMessage"); + throw new Error('Position missing from UserMovedMessage'); } const messageUserMoved: MessageUserMovedInterface = { @@ -641,10 +641,10 @@ export class GameScene extends DirtyScene { }); this.connection.onServerDisconnected(() => { - console.log("Player disconnected from server. Reloading scene."); + console.log('Player disconnected from server. Reloading scene.'); this.cleanupClosingScene(); - const gameSceneKey = "somekey" + Math.round(Math.random() * 10000); + const gameSceneKey = 'somekey' + Math.round(Math.random() * 10000); const game: Phaser.Scene = new GameScene(this.room, this.MapUrlFile, gameSceneKey); this.scene.add(gameSceneKey, game, true, { initPosition: { @@ -723,34 +723,34 @@ export class GameScene extends DirtyScene { private initCirclesCanvas(): void { // Let's generate the circle for the group delimiter let circleElement = Object.values(this.textures.list).find( - (object: Texture) => object.key === "circleSprite-white" + (object: Texture) => object.key === 'circleSprite-white' ); if (circleElement) { - this.textures.remove("circleSprite-white"); + this.textures.remove('circleSprite-white'); } - circleElement = Object.values(this.textures.list).find((object: Texture) => object.key === "circleSprite-red"); + circleElement = Object.values(this.textures.list).find((object: Texture) => object.key === 'circleSprite-red'); if (circleElement) { - this.textures.remove("circleSprite-red"); + this.textures.remove('circleSprite-red'); } //create white circle canvas use to create sprite - this.circleTexture = this.textures.createCanvas("circleSprite-white", 96, 96); + this.circleTexture = this.textures.createCanvas('circleSprite-white', 96, 96); const context = this.circleTexture.context; context.beginPath(); context.arc(48, 48, 48, 0, 2 * Math.PI, false); // context.lineWidth = 5; - context.strokeStyle = "#ffffff"; + context.strokeStyle = '#ffffff'; context.stroke(); this.circleTexture.refresh(); //create red circle canvas use to create sprite - this.circleRedTexture = this.textures.createCanvas("circleSprite-red", 96, 96); + this.circleRedTexture = this.textures.createCanvas('circleSprite-red', 96, 96); const contextRed = this.circleRedTexture.context; contextRed.beginPath(); contextRed.arc(48, 48, 48, 0, 2 * Math.PI, false); //context.lineWidth = 5; - contextRed.strokeStyle = "#ff0000"; + contextRed.strokeStyle = '#ff0000'; contextRed.stroke(); this.circleRedTexture.refresh(); } @@ -765,35 +765,35 @@ export class GameScene extends DirtyScene { } private triggerOnMapLayerPropertyChange() { - this.gameMap.onPropertyChange("exitSceneUrl", (newValue, oldValue) => { + this.gameMap.onPropertyChange('exitSceneUrl', (newValue, oldValue) => { if (newValue) this.onMapExit(newValue as string); }); - this.gameMap.onPropertyChange("exitUrl", (newValue, oldValue) => { + this.gameMap.onPropertyChange('exitUrl', (newValue, oldValue) => { if (newValue) this.onMapExit(newValue as string); }); - this.gameMap.onPropertyChange("openWebsite", (newValue, oldValue, allProps) => { + this.gameMap.onPropertyChange('openWebsite', (newValue, oldValue, allProps) => { if (newValue === undefined) { - layoutManager.removeActionButton("openWebsite", this.userInputManager); + layoutManager.removeActionButton('openWebsite', this.userInputManager); coWebsiteManager.closeCoWebsite(); } else { const openWebsiteFunction = () => { coWebsiteManager.loadCoWebsite( newValue as string, this.MapUrlFile, - allProps.get("openWebsiteAllowApi") as boolean | undefined, - allProps.get("openWebsitePolicy") as string | undefined + allProps.get('openWebsiteAllowApi') as boolean | undefined, + allProps.get('openWebsitePolicy') as string | undefined ); - layoutManager.removeActionButton("openWebsite", this.userInputManager); + layoutManager.removeActionButton('openWebsite', this.userInputManager); }; const openWebsiteTriggerValue = allProps.get(TRIGGER_WEBSITE_PROPERTIES); if (openWebsiteTriggerValue && openWebsiteTriggerValue === ON_ACTION_TRIGGER_BUTTON) { let message = allProps.get(WEBSITE_MESSAGE_PROPERTIES); if (message === undefined) { - message = "Press SPACE or touch here to open web site"; + message = 'Press SPACE or touch here to open web site'; } layoutManager.addActionButton( - "openWebsite", + 'openWebsite', message.toString(), () => { openWebsiteFunction(); @@ -805,32 +805,32 @@ export class GameScene extends DirtyScene { } } }); - this.gameMap.onPropertyChange("jitsiRoom", (newValue, oldValue, allProps) => { + this.gameMap.onPropertyChange('jitsiRoom', (newValue, oldValue, allProps) => { if (newValue === undefined) { - layoutManager.removeActionButton("jitsiRoom", this.userInputManager); + layoutManager.removeActionButton('jitsiRoom', this.userInputManager); this.stopJitsi(); } else { const openJitsiRoomFunction = () => { const roomName = jitsiFactory.getRoomName(newValue.toString(), this.instance); - const jitsiUrl = allProps.get("jitsiUrl") as string | undefined; + const jitsiUrl = allProps.get('jitsiUrl') as string | undefined; if (JITSI_PRIVATE_MODE && !jitsiUrl) { - const adminTag = allProps.get("jitsiRoomAdminTag") as string | undefined; + const adminTag = allProps.get('jitsiRoomAdminTag') as string | undefined; this.connection?.emitQueryJitsiJwtMessage(roomName, adminTag); } else { this.startJitsi(roomName, undefined); } - layoutManager.removeActionButton("jitsiRoom", this.userInputManager); + layoutManager.removeActionButton('jitsiRoom', this.userInputManager); }; const jitsiTriggerValue = allProps.get(TRIGGER_JITSI_PROPERTIES); if (jitsiTriggerValue && jitsiTriggerValue === ON_ACTION_TRIGGER_BUTTON) { let message = allProps.get(JITSI_MESSAGE_PROPERTIES); if (message === undefined) { - message = "Press SPACE or touch here to enter Jitsi Meet room"; + message = 'Press SPACE or touch here to enter Jitsi Meet room'; } layoutManager.addActionButton( - "jitsiRoom", + 'jitsiRoom', message.toString(), () => { openJitsiRoomFunction(); @@ -842,14 +842,14 @@ export class GameScene extends DirtyScene { } } }); - this.gameMap.onPropertyChange("silent", (newValue, oldValue) => { - if (newValue === undefined || newValue === false || newValue === "") { + this.gameMap.onPropertyChange('silent', (newValue, oldValue) => { + if (newValue === undefined || newValue === false || newValue === '') { this.connection?.setSilent(false); } else { this.connection?.setSilent(true); } }); - this.gameMap.onPropertyChange("playAudio", (newValue, oldValue, allProps) => { + this.gameMap.onPropertyChange('playAudio', (newValue, oldValue, allProps) => { const volume = allProps.get(AUDIO_VOLUME_PROPERTY) as number | undefined; const loop = allProps.get(AUDIO_LOOP_PROPERTY) as boolean | undefined; newValue === undefined @@ -857,14 +857,14 @@ export class GameScene extends DirtyScene { : audioManager.playAudio(newValue, this.getMapDirUrl(), volume, loop); }); // TODO: This legacy property should be removed at some point - this.gameMap.onPropertyChange("playAudioLoop", (newValue, oldValue) => { + this.gameMap.onPropertyChange('playAudioLoop', (newValue, oldValue) => { newValue === undefined ? audioManager.unloadAudio() : audioManager.playAudio(newValue, this.getMapDirUrl(), undefined, true); }); - this.gameMap.onPropertyChange("zone", (newValue, oldValue) => { - if (newValue === undefined || newValue === false || newValue === "") { + this.gameMap.onPropertyChange('zone', (newValue, oldValue) => { + if (newValue === undefined || newValue === false || newValue === '') { iframeListener.sendLeaveEvent(oldValue as string); } else { iframeListener.sendEnterEvent(newValue as string); @@ -892,22 +892,22 @@ export class GameScene extends DirtyScene { let html = `