Merge pull request #1832 from thecodingmachine/develop

Deploy 2022-02-07
This commit is contained in:
David Négrier 2022-02-07 18:52:14 +01:00 committed by GitHub
commit d72cc68c22
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 328 additions and 109 deletions

View file

@ -3,7 +3,7 @@
### Opening a web page in a new tab ### Opening a web page in a new tab
``` ```ts
WA.nav.openTab(url: string): void WA.nav.openTab(url: string): void
``` ```
@ -11,13 +11,13 @@ Opens the webpage at "url" in your browser, in a new tab.
Example: Example:
```javascript ```ts
WA.nav.openTab('https://www.wikipedia.org/'); WA.nav.openTab('https://www.wikipedia.org/');
``` ```
### Opening a web page in the current tab ### Opening a web page in the current tab
``` ```ts
WA.nav.goToPage(url: string): void WA.nav.goToPage(url: string): void
``` ```
@ -25,14 +25,13 @@ Opens the webpage at "url" in your browser in place of WorkAdventure. WorkAdvent
Example: Example:
```javascript ```ts
WA.nav.goToPage('https://www.wikipedia.org/'); WA.nav.goToPage('https://www.wikipedia.org/');
``` ```
### Going to a different map from the script ### Going to a different map from the script
``` ```ts
WA.nav.goToRoom(url: string): void WA.nav.goToRoom(url: string): void
``` ```
@ -43,7 +42,7 @@ global urls: "/_/global/domain/path/map.json[#start-layer-name]"
Example: Example:
```javascript ```ts
WA.nav.goToRoom("/@/tcm/workadventure/floor0") // workadventure urls WA.nav.goToRoom("/@/tcm/workadventure/floor0") // workadventure urls
WA.nav.goToRoom('../otherMap/map.json'); WA.nav.goToRoom('../otherMap/map.json');
WA.nav.goToRoom("/_/global/<path to global map>.json#start-layer-2") WA.nav.goToRoom("/_/global/<path to global map>.json#start-layer-2")
@ -51,25 +50,25 @@ WA.nav.goToRoom("/_/global/<path to global map>.json#start-layer-2")
### Opening/closing web page in Co-Websites ### Opening/closing web page in Co-Websites
``` ```ts
WA.nav.openCoWebSite(url: string, allowApi: boolean = false, allowPolicy: string = "", position: number, closable: boolean, lazy: boolean): Promise<CoWebsite> WA.nav.openCoWebSite(url: string, allowApi?: boolean = false, allowPolicy?: string = "", percentWidth?: number, position?: number, closable?: boolean, lazy?: boolean): Promise<CoWebsite>
``` ```
Opens the webpage at "url" in an iFrame (on the right side of the screen) or close that iFrame. `allowApi` allows the webpage to use the "IFrame API" and execute script (it is equivalent to putting the `openWebsiteAllowApi` property in the map). `allowPolicy` grants additional access rights to the iFrame. The `allowPolicy` parameter is turned into an [`allow` feature policy in the iFrame](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-allow), position in whitch slot the web page will be open, closable allow to close the webpage also you need to close it by the api and lazy Opens the webpage at "url" in an iFrame (on the right side of the screen) or close that iFrame. `allowApi` allows the webpage to use the "IFrame API" and execute script (it is equivalent to putting the `openWebsiteAllowApi` property in the map). `allowPolicy` grants additional access rights to the iFrame. The `allowPolicy` parameter is turned into an [`allow` feature policy in the iFrame](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-allow),widthPercent define the width of the main cowebsite beetween the min size and the max size (70% of the viewport), position in whitch slot the web page will be open, closable allow to close the webpage also you need to close it by the api and lazy
it's to add the cowebsite but don't load it. it's to add the cowebsite but don't load it.
Example: Example:
```javascript ```ts
const coWebsite = await WA.nav.openCoWebSite('https://www.wikipedia.org/'); const coWebsite = await WA.nav.openCoWebSite('https://www.wikipedia.org/');
const coWebsiteWorkAdventure = await WA.nav.openCoWebSite('https://workadventu.re/', true, "", 1, true, true); const coWebsiteWorkAdventure = await WA.nav.openCoWebSite('https://workadventu.re/', true, "", 70, 1, true, true);
// ... // ...
coWebsite.close(); coWebsite.close();
``` ```
### Get all Co-Websites ### Get all Co-Websites
``` ```ts
WA.nav.getCoWebSites(): Promise<CoWebsite[]> WA.nav.getCoWebSites(): Promise<CoWebsite[]>
``` ```
@ -77,6 +76,6 @@ Get all opened co-websites with their ids and positions.
Example: Example:
```javascript ```ts
const coWebsites = await WA.nav.getCowebSites(); const coWebsites = await WA.nav.getCowebSites();
``` ```

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

View file

@ -52,6 +52,13 @@ If you set `openWebsiteTrigger: onaction`, when the user walks on the layer, an
If you set `openWebsiteTriggerMessage: your message action` you can edit alert message displayed. If is not defined, the default message displayed is 'Press on SPACE to open the web site'. If you set `openWebsiteTriggerMessage: your message action` you can edit alert message displayed. If is not defined, the default message displayed is 'Press on SPACE to open the web site'.
If you set `openWebsiteTrigger: onicon`, when the user walks on the layer, an icon will be displayed at the bottom of the screen:
<figure class="figure">
<img src="images/icon_open_website.png" class="figure-img img-fluid rounded" alt="" />
<figcaption class="figure-caption">The iFrame will only open if the user clicks on icon</figcaption>
</figure>
### Setting the iFrame "allow" attribute ### Setting the iFrame "allow" attribute
By default, iFrames have limited rights in browsers. For instance, they cannot put their content in fullscreen, they cannot start your webcam, etc... By default, iFrames have limited rights in browsers. For instance, they cannot put their content in fullscreen, they cannot start your webcam, etc...

View file

@ -1,5 +1,4 @@
{ {
"printWidth": 120, "printWidth": 120,
"tabWidth": 4, "tabWidth": 4
"plugins": ["prettier-plugin-svelte"]
} }

View file

@ -5,6 +5,7 @@ export const isOpenCoWebsiteEvent = new tg.IsInterface()
url: tg.isString, url: tg.isString,
allowApi: tg.isOptional(tg.isBoolean), allowApi: tg.isOptional(tg.isBoolean),
allowPolicy: tg.isOptional(tg.isString), allowPolicy: tg.isOptional(tg.isString),
widthPercent: tg.isOptional(tg.isNumber),
position: tg.isOptional(tg.isNumber), position: tg.isOptional(tg.isNumber),
closable: tg.isOptional(tg.isBoolean), closable: tg.isOptional(tg.isBoolean),
lazy: tg.isOptional(tg.isBoolean), lazy: tg.isOptional(tg.isBoolean),

View file

@ -45,6 +45,7 @@ export class WorkadventureNavigationCommands extends IframeApiContribution<Worka
url: string, url: string,
allowApi?: boolean, allowApi?: boolean,
allowPolicy?: string, allowPolicy?: string,
widthPercent?: number,
position?: number, position?: number,
closable?: boolean, closable?: boolean,
lazy?: boolean lazy?: boolean
@ -55,6 +56,7 @@ export class WorkadventureNavigationCommands extends IframeApiContribution<Worka
url, url,
allowApi, allowApi,
allowPolicy, allowPolicy,
widthPercent,
position, position,
closable, closable,
lazy, lazy,

View file

@ -5,6 +5,7 @@
import { coWebsitesNotAsleep, mainCoWebsite } from "../../Stores/CoWebsiteStore"; import { coWebsitesNotAsleep, mainCoWebsite } from "../../Stores/CoWebsiteStore";
import { highlightedEmbedScreen } from "../../Stores/EmbedScreensStore"; import { highlightedEmbedScreen } from "../../Stores/EmbedScreensStore";
import type { CoWebsite } from "../../WebRtc/CoWebsiteManager"; import type { CoWebsite } from "../../WebRtc/CoWebsiteManager";
import { iframeStates } from "../../WebRtc/CoWebsiteManager";
import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager"; import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager";
export let index: number; export let index: number;
@ -35,8 +36,12 @@
if ($mainCoWebsite.iframe.id === coWebsite.iframe.id) { if ($mainCoWebsite.iframe.id === coWebsite.iframe.id) {
const coWebsites = $coWebsitesNotAsleep; const coWebsites = $coWebsitesNotAsleep;
const newMain = $highlightedEmbedScreen ?? coWebsites.length > 1 ? coWebsites[1] : undefined; const newMain = $highlightedEmbedScreen ?? coWebsites.length > 1 ? coWebsites[1] : undefined;
if (newMain) { if (newMain && newMain.iframe.id !== $mainCoWebsite.iframe.id) {
coWebsiteManager.goToMain(newMain); coWebsiteManager.goToMain(newMain);
} else if (coWebsiteManager.getMainState() === iframeStates.closed) {
coWebsiteManager.displayMain();
} else {
coWebsiteManager.hideMain();
} }
} else { } else {
highlightedEmbedScreen.toggleHighlight({ highlightedEmbedScreen.toggleHighlight({

View file

@ -53,7 +53,7 @@
<section class="terms-and-conditions"> <section class="terms-and-conditions">
<a style="display: none;" href="traduction">Need for traduction</a> <a style="display: none;" href="traduction">Need for traduction</a>
<p> <p>
{$LL.login.terms()} {@html $LL.login.terms()}
</p> </p>
</section> </section>
{/if} {/if}

View file

@ -69,6 +69,7 @@
} else { } else {
const customMenu = customMenuIframe.get(menu.label); const customMenu = customMenuIframe.get(menu.label);
if (customMenu !== undefined) { if (customMenu !== undefined) {
activeSubMenu = menu;
props = { url: customMenu.url, allowApi: customMenu.allowApi }; props = { url: customMenu.url, allowApi: customMenu.allowApi };
activeComponent = CustomSubMenu; activeComponent = CustomSubMenu;
} else { } else {

View file

@ -9,4 +9,7 @@ export interface UserInputHandlerInterface {
handlePointerUpEvent: (pointer: Phaser.Input.Pointer, gameObjects: Phaser.GameObjects.GameObject[]) => void; handlePointerUpEvent: (pointer: Phaser.Input.Pointer, gameObjects: Phaser.GameObjects.GameObject[]) => void;
handlePointerDownEvent: (pointer: Phaser.Input.Pointer, gameObjects: Phaser.GameObjects.GameObject[]) => void; handlePointerDownEvent: (pointer: Phaser.Input.Pointer, gameObjects: Phaser.GameObjects.GameObject[]) => void;
handleSpaceKeyUpEvent: (event: Event) => Event; handleSpaceKeyUpEvent: (event: Event) => Event;
addSpaceEventListener: (callback: Function) => void;
removeSpaceEventListner: (callback: Function) => void;
} }

View file

@ -159,6 +159,27 @@ export abstract class Character extends Container implements OutlineableInterfac
return { x: this.x, y: this.y }; return { x: this.x, y: this.y };
} }
/**
* Returns position based on where player is currently facing
* @param shift How far from player should the point of interest be.
*/
public getDirectionalActivationPosition(shift: number): { x: number; y: number } {
switch (this.lastDirection) {
case PlayerAnimationDirections.Down: {
return { x: this.x, y: this.y + shift };
}
case PlayerAnimationDirections.Left: {
return { x: this.x - shift, y: this.y };
}
case PlayerAnimationDirections.Right: {
return { x: this.x + shift, y: this.y };
}
case PlayerAnimationDirections.Up: {
return { x: this.x, y: this.y - shift };
}
}
}
public getObjectToOutline(): Phaser.GameObjects.GameObject { public getObjectToOutline(): Phaser.GameObjects.GameObject {
return this.playerNameText; return this.playerNameText;
} }
@ -455,16 +476,16 @@ export abstract class Character extends Container implements OutlineableInterfac
this.outlineColorStore.removeApiColor(); this.outlineColorStore.removeApiColor();
} }
public pointerOverOutline(): void { public pointerOverOutline(color: number): void {
this.outlineColorStore.pointerOver(); this.outlineColorStore.pointerOver(color);
} }
public pointerOutOutline(): void { public pointerOutOutline(): void {
this.outlineColorStore.pointerOut(); this.outlineColorStore.pointerOut();
} }
public characterCloseByOutline(): void { public characterCloseByOutline(color: number): void {
this.outlineColorStore.characterCloseBy(); this.outlineColorStore.characterCloseBy(color);
} }
public characterFarAwayOutline(): void { public characterFarAwayOutline(): void {

View file

@ -11,6 +11,11 @@ export class ActivatablesManager {
private currentPlayer: Player; private currentPlayer: Player;
private canSelectByDistance: boolean = true;
private readonly outlineColor = 0xffff00;
private readonly directionalActivationPositionShift = 50;
constructor(currentPlayer: Player) { constructor(currentPlayer: Player) {
this.currentPlayer = currentPlayer; this.currentPlayer = currentPlayer;
} }
@ -27,7 +32,7 @@ export class ActivatablesManager {
} }
this.selectedActivatableObjectByPointer = object; this.selectedActivatableObjectByPointer = object;
if (isOutlineable(this.selectedActivatableObjectByPointer)) { if (isOutlineable(this.selectedActivatableObjectByPointer)) {
this.selectedActivatableObjectByPointer?.pointerOverOutline(); this.selectedActivatableObjectByPointer?.pointerOverOutline(this.outlineColor);
} }
} }
@ -37,7 +42,7 @@ export class ActivatablesManager {
} }
this.selectedActivatableObjectByPointer = undefined; this.selectedActivatableObjectByPointer = undefined;
if (isOutlineable(this.selectedActivatableObjectByDistance)) { if (isOutlineable(this.selectedActivatableObjectByDistance)) {
this.selectedActivatableObjectByDistance?.characterCloseByOutline(); this.selectedActivatableObjectByDistance?.characterCloseByOutline(this.outlineColor);
} }
} }
@ -46,6 +51,9 @@ export class ActivatablesManager {
} }
public deduceSelectedActivatableObjectByDistance(): void { public deduceSelectedActivatableObjectByDistance(): void {
if (!this.canSelectByDistance) {
return;
}
const newNearestObject = this.findNearestActivatableObject(); const newNearestObject = this.findNearestActivatableObject();
if (this.selectedActivatableObjectByDistance === newNearestObject) { if (this.selectedActivatableObjectByDistance === newNearestObject) {
return; return;
@ -60,10 +68,42 @@ export class ActivatablesManager {
} }
this.selectedActivatableObjectByDistance = newNearestObject; this.selectedActivatableObjectByDistance = newNearestObject;
if (isOutlineable(this.selectedActivatableObjectByDistance)) { if (isOutlineable(this.selectedActivatableObjectByDistance)) {
this.selectedActivatableObjectByDistance?.characterCloseByOutline(); this.selectedActivatableObjectByDistance?.characterCloseByOutline(this.outlineColor);
} }
} }
public updateActivatableObjectsDistances(objects: ActivatableInterface[]): void {
const currentPlayerPos = this.currentPlayer.getDirectionalActivationPosition(
this.directionalActivationPositionShift
);
for (const object of objects) {
const distance = MathUtils.distanceBetween(currentPlayerPos, object.getPosition());
this.activatableObjectsDistances.set(object, distance);
}
}
public updateDistanceForSingleActivatableObject(object: ActivatableInterface): void {
this.activatableObjectsDistances.set(
object,
MathUtils.distanceBetween(
this.currentPlayer.getDirectionalActivationPosition(this.directionalActivationPositionShift),
object.getPosition()
)
);
}
public disableSelectingByDistance(): void {
this.canSelectByDistance = false;
if (isOutlineable(this.selectedActivatableObjectByDistance)) {
this.selectedActivatableObjectByDistance?.characterFarAwayOutline();
}
this.selectedActivatableObjectByDistance = undefined;
}
public enableSelectingByDistance(): void {
this.canSelectByDistance = true;
}
private findNearestActivatableObject(): ActivatableInterface | undefined { private findNearestActivatableObject(): ActivatableInterface | undefined {
let shortestDistance: number = Infinity; let shortestDistance: number = Infinity;
let closestObject: ActivatableInterface | undefined = undefined; let closestObject: ActivatableInterface | undefined = undefined;
@ -76,18 +116,8 @@ export class ActivatablesManager {
} }
return closestObject; return closestObject;
} }
public updateActivatableObjectsDistances(objects: ActivatableInterface[]): void {
const currentPlayerPos = this.currentPlayer.getPosition();
for (const object of objects) {
const distance = MathUtils.distanceBetween(currentPlayerPos, object.getPosition());
this.activatableObjectsDistances.set(object, distance);
}
}
public updateDistanceForSingleActivatableObject(object: ActivatableInterface): void { public isSelectingByDistanceEnabled(): boolean {
this.activatableObjectsDistances.set( return this.canSelectByDistance;
object,
MathUtils.distanceBetween(this.currentPlayer.getPosition(), object.getPosition())
);
} }
} }

View file

@ -26,15 +26,6 @@ export class Game extends Phaser.Game {
} }
} }
}); });
/*window.addEventListener('resize', (event) => {
// Let's trigger the onResize method of any active scene that is a ResizableScene
for (const scene of this.scene.getScenes(true)) {
if (scene instanceof ResizableScene) {
scene.onResize(event);
}
}
});*/
} }
public step(time: number, delta: number) { public step(time: number, delta: number) {

View file

@ -20,6 +20,7 @@ export enum GameMapProperties {
OPEN_WEBSITE = "openWebsite", OPEN_WEBSITE = "openWebsite",
OPEN_WEBSITE_ALLOW_API = "openWebsiteAllowApi", OPEN_WEBSITE_ALLOW_API = "openWebsiteAllowApi",
OPEN_WEBSITE_POLICY = "openWebsitePolicy", OPEN_WEBSITE_POLICY = "openWebsitePolicy",
OPEN_WEBSITE_WIDTH = "openWebsiteWidth",
OPEN_WEBSITE_POSITION = "openWebsitePosition", OPEN_WEBSITE_POSITION = "openWebsitePosition",
OPEN_WEBSITE_TRIGGER = "openWebsiteTrigger", OPEN_WEBSITE_TRIGGER = "openWebsiteTrigger",
OPEN_WEBSITE_TRIGGER_MESSAGE = "openWebsiteTriggerMessage", OPEN_WEBSITE_TRIGGER_MESSAGE = "openWebsiteTriggerMessage",

View file

@ -6,10 +6,9 @@ import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager";
import { layoutManagerActionStore } from "../../Stores/LayoutManagerStore"; import { layoutManagerActionStore } from "../../Stores/LayoutManagerStore";
import { localUserStore } from "../../Connexion/LocalUserStore"; import { localUserStore } from "../../Connexion/LocalUserStore";
import { get } from "svelte/store"; import { get } from "svelte/store";
import { ON_ACTION_TRIGGER_BUTTON } from "../../WebRtc/LayoutManager"; import { ON_ACTION_TRIGGER_BUTTON, ON_ICON_TRIGGER_BUTTON } from "../../WebRtc/LayoutManager";
import type { ITiledMapLayer } from "../Map/ITiledMap"; import type { ITiledMapLayer } from "../Map/ITiledMap";
import { GameMapProperties } from "./GameMapProperties"; import { GameMapProperties } from "./GameMapProperties";
import { highlightedEmbedScreen } from "../../Stores/EmbedScreensStore";
enum OpenCoWebsiteState { enum OpenCoWebsiteState {
ASLEEP, ASLEEP,
@ -18,12 +17,14 @@ enum OpenCoWebsiteState {
} }
interface OpenCoWebsite { interface OpenCoWebsite {
coWebsite: CoWebsite; actionId: string;
coWebsite?: CoWebsite;
state: OpenCoWebsiteState; state: OpenCoWebsiteState;
} }
export class GameMapPropertiesListener { export class GameMapPropertiesListener {
private coWebsitesOpenByLayer = new Map<ITiledMapLayer, OpenCoWebsite>(); private coWebsitesOpenByLayer = new Map<ITiledMapLayer, OpenCoWebsite>();
private coWebsitesActionTriggerByLayer = new Map<ITiledMapLayer, string>();
constructor(private scene: GameScene, private gameMap: GameMap) {} constructor(private scene: GameScene, private gameMap: GameMap) {}
@ -64,6 +65,7 @@ export class GameMapPropertiesListener {
let openWebsiteProperty: string | undefined; let openWebsiteProperty: string | undefined;
let allowApiProperty: boolean | undefined; let allowApiProperty: boolean | undefined;
let websitePolicyProperty: string | undefined; let websitePolicyProperty: string | undefined;
let websiteWidthProperty: number | undefined;
let websitePositionProperty: number | undefined; let websitePositionProperty: number | undefined;
let websiteTriggerProperty: string | undefined; let websiteTriggerProperty: string | undefined;
let websiteTriggerMessageProperty: string | undefined; let websiteTriggerMessageProperty: string | undefined;
@ -79,6 +81,9 @@ export class GameMapPropertiesListener {
case GameMapProperties.OPEN_WEBSITE_POLICY: case GameMapProperties.OPEN_WEBSITE_POLICY:
websitePolicyProperty = property.value as string | undefined; websitePolicyProperty = property.value as string | undefined;
break; break;
case GameMapProperties.OPEN_WEBSITE_WIDTH:
websiteWidthProperty = property.value as number | undefined;
break;
case GameMapProperties.OPEN_WEBSITE_POSITION: case GameMapProperties.OPEN_WEBSITE_POSITION:
websitePositionProperty = property.value as number | undefined; websitePositionProperty = property.value as number | undefined;
break; break;
@ -95,27 +100,19 @@ export class GameMapPropertiesListener {
return; return;
} }
const actionUuid = "openWebsite-" + (Math.random() + 1).toString(36).substring(7); const actionId = "openWebsite-" + (Math.random() + 1).toString(36).substring(7);
if (this.coWebsitesOpenByLayer.has(layer)) { if (this.coWebsitesOpenByLayer.has(layer)) {
return; return;
} }
const coWebsite = coWebsiteManager.addCoWebsite(
openWebsiteProperty,
this.scene.MapUrlFile,
allowApiProperty,
websitePolicyProperty,
websitePositionProperty,
false
);
this.coWebsitesOpenByLayer.set(layer, { this.coWebsitesOpenByLayer.set(layer, {
coWebsite: coWebsite, actionId: actionId,
coWebsite: undefined,
state: OpenCoWebsiteState.ASLEEP, state: OpenCoWebsiteState.ASLEEP,
}); });
const openWebsiteFunction = () => { const loadCoWebsiteFunction = (coWebsite: CoWebsite) => {
coWebsiteManager coWebsiteManager
.loadCoWebsite(coWebsite) .loadCoWebsite(coWebsite)
.then((coWebsite) => { .then((coWebsite) => {
@ -125,8 +122,10 @@ export class GameMapPropertiesListener {
console.error("Error during a co-website closing"); console.error("Error during a co-website closing");
}); });
this.coWebsitesOpenByLayer.delete(layer); this.coWebsitesOpenByLayer.delete(layer);
this.coWebsitesActionTriggerByLayer.delete(layer);
} else { } else {
this.coWebsitesOpenByLayer.set(layer, { this.coWebsitesOpenByLayer.set(layer, {
actionId,
coWebsite, coWebsite,
state: OpenCoWebsiteState.OPENED, state: OpenCoWebsiteState.OPENED,
}); });
@ -136,14 +135,60 @@ export class GameMapPropertiesListener {
console.error("Error during loading a co-website: " + coWebsite.url); console.error("Error during loading a co-website: " + coWebsite.url);
}); });
layoutManagerActionStore.removeAction(actionUuid); layoutManagerActionStore.removeAction(actionId);
};
const openCoWebsiteFunction = () => {
const coWebsite = coWebsiteManager.addCoWebsite(
openWebsiteProperty ?? "",
this.scene.MapUrlFile,
allowApiProperty,
websitePolicyProperty,
websiteWidthProperty,
websitePositionProperty,
false
);
loadCoWebsiteFunction(coWebsite);
}; };
if ( if (
!localUserStore.getForceCowebsiteTrigger() && localUserStore.getForceCowebsiteTrigger() ||
websiteTriggerProperty !== ON_ACTION_TRIGGER_BUTTON websiteTriggerProperty === ON_ACTION_TRIGGER_BUTTON
) { ) {
openWebsiteFunction(); if (!websiteTriggerMessageProperty) {
websiteTriggerMessageProperty = "Press SPACE or touch here to open web site";
}
this.coWebsitesActionTriggerByLayer.set(layer, actionId);
layoutManagerActionStore.addAction({
uuid: actionId,
type: "message",
message: websiteTriggerMessageProperty,
callback: () => openCoWebsiteFunction(),
userInputManager: this.scene.userInputManager,
});
} else if (websiteTriggerProperty === ON_ICON_TRIGGER_BUTTON) {
const coWebsite = coWebsiteManager.addCoWebsite(
openWebsiteProperty,
this.scene.MapUrlFile,
allowApiProperty,
websitePolicyProperty,
websiteWidthProperty,
websitePositionProperty,
false
);
const ObjectByLayer = this.coWebsitesOpenByLayer.get(layer);
if (ObjectByLayer) {
ObjectByLayer.coWebsite = coWebsite;
}
}
if (!websiteTriggerProperty) {
openCoWebsiteFunction();
} }
}); });
}; };
@ -192,6 +237,28 @@ export class GameMapPropertiesListener {
} }
this.coWebsitesOpenByLayer.delete(layer); this.coWebsitesOpenByLayer.delete(layer);
if (!websiteTriggerProperty) {
return;
}
const actionStore = get(layoutManagerActionStore);
const actionTriggerUuid = this.coWebsitesActionTriggerByLayer.get(layer);
if (!actionTriggerUuid) {
return;
}
const action =
actionStore && actionStore.length > 0
? actionStore.find((action) => action.uuid === actionTriggerUuid)
: undefined;
if (action) {
layoutManagerActionStore.removeAction(actionTriggerUuid);
}
this.coWebsitesActionTriggerByLayer.delete(layer);
}); });
}; };

View file

@ -1265,6 +1265,7 @@ ${escapedMessage}
iframeListener.getBaseUrlFromSource(source), iframeListener.getBaseUrlFromSource(source),
openCoWebsite.allowApi, openCoWebsite.allowApi,
openCoWebsite.allowPolicy, openCoWebsite.allowPolicy,
openCoWebsite.widthPercent,
openCoWebsite.position, openCoWebsite.position,
openCoWebsite.closable ?? true openCoWebsite.closable ?? true
); );
@ -1737,6 +1738,12 @@ ${escapedMessage}
emoteMenuStore.openEmoteMenu(); emoteMenuStore.openEmoteMenu();
} }
}); });
this.CurrentPlayer.on(Phaser.Input.Events.POINTER_OVER, (pointer: Phaser.Input.Pointer) => {
this.CurrentPlayer.pointerOverOutline(0x00ffff);
});
this.CurrentPlayer.on(Phaser.Input.Events.POINTER_OUT, (pointer: Phaser.Input.Pointer) => {
this.CurrentPlayer.pointerOutOutline();
});
this.CurrentPlayer.on(requestEmoteEventName, (emoteKey: string) => { this.CurrentPlayer.on(requestEmoteEventName, (emoteKey: string) => {
this.connection?.emitEmoteEvent(emoteKey); this.connection?.emitEmoteEvent(emoteKey);
analyticsClient.launchEmote(emoteKey); analyticsClient.launchEmote(emoteKey);

View file

@ -3,8 +3,8 @@ export interface OutlineableInterface {
removeFollowOutlineColor(): void; removeFollowOutlineColor(): void;
setApiOutlineColor(color: number): void; setApiOutlineColor(color: number): void;
removeApiOutlineColor(): void; removeApiOutlineColor(): void;
pointerOverOutline(): void; pointerOverOutline(color: number): void;
pointerOutOutline(): void; pointerOutOutline(): void;
characterCloseByOutline(): void; characterCloseByOutline(color: number): void;
characterFarAwayOutline(): void; characterFarAwayOutline(): void;
} }

View file

@ -53,10 +53,20 @@ export class GameSceneUserInputHandler implements UserInputHandlerInterface {
public handlePointerDownEvent(pointer: Phaser.Input.Pointer, gameObjects: Phaser.GameObjects.GameObject[]): void {} public handlePointerDownEvent(pointer: Phaser.Input.Pointer, gameObjects: Phaser.GameObjects.GameObject[]): void {}
public handleSpaceKeyUpEvent(event: Event): Event { public handleSpaceKeyUpEvent(event: Event): Event {
const activatable = this.gameScene.getActivatablesManager().getSelectedActivatableObject(); const activatableManager = this.gameScene.getActivatablesManager();
if (activatable && activatable.isActivatable()) { const activatable = activatableManager.getSelectedActivatableObject();
if (activatable && activatable.isActivatable() && activatableManager.isSelectingByDistanceEnabled()) {
activatable.activate(); activatable.activate();
} }
return event; return event;
} }
public addSpaceEventListener(callback: Function): void {
this.gameScene.input.keyboard.addListener("keyup-SPACE", callback);
this.gameScene.getActivatablesManager().disableSelectingByDistance();
}
public removeSpaceEventListner(callback: Function): void {
this.gameScene.input.keyboard.removeListener("keyup-SPACE", callback);
this.gameScene.getActivatablesManager().enableSelectingByDistance();
}
} }

View file

@ -223,10 +223,10 @@ export class UserInputManager {
} }
addSpaceEventListner(callback: Function) { addSpaceEventListner(callback: Function) {
this.scene.input.keyboard.addListener("keyup-SPACE", callback); this.userInputHandler.addSpaceEventListener(callback);
} }
removeSpaceEventListner(callback: Function) { removeSpaceEventListner(callback: Function) {
this.scene.input.keyboard.removeListener("keyup-SPACE", callback); this.userInputHandler.removeSpaceEventListner(callback);
} }
destroy(): void { destroy(): void {
@ -255,6 +255,11 @@ export class UserInputManager {
(pointer: Phaser.Input.Pointer, gameObjects: Phaser.GameObjects.GameObject[]) => { (pointer: Phaser.Input.Pointer, gameObjects: Phaser.GameObjects.GameObject[]) => {
this.joystick?.hide(); this.joystick?.hide();
this.userInputHandler.handlePointerUpEvent(pointer, gameObjects); this.userInputHandler.handlePointerUpEvent(pointer, gameObjects);
// Disable focus on iframe (need by Firefox)
if (pointer.downElement.nodeName === "CANVAS" && document.activeElement instanceof HTMLIFrameElement) {
document.activeElement.blur();
}
} }
); );

View file

@ -1,4 +1,5 @@
import { derived, writable } from "svelte/store"; import { derived, writable } from "svelte/store";
import type { ActivatablesManager } from "../Phaser/Game/ActivatablesManager";
import type { UserInputManager } from "../Phaser/UserInput/UserInputManager"; import type { UserInputManager } from "../Phaser/UserInput/UserInputManager";
export interface LayoutManagerAction { export interface LayoutManagerAction {

View file

@ -5,38 +5,33 @@ export function createColorStore() {
let followColor: number | undefined = undefined; let followColor: number | undefined = undefined;
let apiColor: number | undefined = undefined; let apiColor: number | undefined = undefined;
let pointedByPointer: number | undefined = undefined;
let pointedByPointer: boolean = false; let pointedByCharacter: number | undefined = undefined;
let pointedByCharacter: boolean = false;
const updateColor = () => { const updateColor = () => {
if (pointedByPointer || pointedByCharacter) { set(pointedByPointer ?? pointedByCharacter ?? followColor ?? apiColor);
set(0xffff00);
} else {
set(followColor ?? apiColor);
}
}; };
return { return {
subscribe, subscribe,
pointerOver() { pointerOver(color: number) {
pointedByPointer = true; pointedByPointer = color;
updateColor(); updateColor();
}, },
pointerOut() { pointerOut() {
pointedByPointer = false; pointedByPointer = undefined;
updateColor(); updateColor();
}, },
characterCloseBy() { characterCloseBy(color: number) {
pointedByCharacter = true; pointedByCharacter = color;
updateColor(); updateColor();
}, },
characterFarAway() { characterFarAway() {
pointedByCharacter = false; pointedByCharacter = undefined;
updateColor(); updateColor();
}, },

View file

@ -10,7 +10,7 @@ import { jitsiFactory } from "./JitsiFactory";
import { gameManager } from "../Phaser/Game/GameManager"; import { gameManager } from "../Phaser/Game/GameManager";
import { LayoutMode } from "./LayoutManager"; import { LayoutMode } from "./LayoutManager";
enum iframeStates { export enum iframeStates {
closed = 1, closed = 1,
loading, // loading an iframe can be slow, so we show some placeholder until it is ready loading, // loading an iframe can be slow, so we show some placeholder until it is ready
opened, opened,
@ -21,7 +21,7 @@ const gameOverlayDomId = "game-overlay";
const cowebsiteBufferDomId = "cowebsite-buffer"; // the id of the container who contains cowebsite iframes. const cowebsiteBufferDomId = "cowebsite-buffer"; // the id of the container who contains cowebsite iframes.
const cowebsiteAsideHolderDomId = "cowebsite-aside-holder"; const cowebsiteAsideHolderDomId = "cowebsite-aside-holder";
const cowebsiteLoaderDomId = "cowebsite-loader"; const cowebsiteLoaderDomId = "cowebsite-loader";
export const cowebsiteCloseButtonId = "cowebsite-close"; const cowebsiteCloseButtonId = "cowebsite-close";
const cowebsiteFullScreenButtonId = "cowebsite-fullscreen"; const cowebsiteFullScreenButtonId = "cowebsite-fullscreen";
const cowebsiteOpenFullScreenImageId = "cowebsite-fullscreen-open"; const cowebsiteOpenFullScreenImageId = "cowebsite-fullscreen-open";
const cowebsiteCloseFullScreenImageId = "cowebsite-fullscreen-close"; const cowebsiteCloseFullScreenImageId = "cowebsite-fullscreen-close";
@ -43,6 +43,7 @@ export type CoWebsite = {
closable: boolean; closable: boolean;
allowPolicy: string | undefined; allowPolicy: string | undefined;
allowApi: boolean | undefined; allowApi: boolean | undefined;
widthPercent?: number | undefined;
jitsi?: boolean; jitsi?: boolean;
altMessage?: string; altMessage?: string;
}; };
@ -74,6 +75,10 @@ class CoWebsiteManager {
this.resizeAllIframes(); this.resizeAllIframes();
}); });
public getMainState() {
return this.openedMain;
}
get width(): number { get width(): number {
return this.cowebsiteDom.clientWidth; return this.cowebsiteDom.clientWidth;
} }
@ -82,8 +87,13 @@ class CoWebsiteManager {
this.cowebsiteDom.style.width = width + "px"; this.cowebsiteDom.style.width = width + "px";
} }
set widthPercent(width: number) { get maxWidth(): number {
this.cowebsiteDom.style.width = width + "%"; let maxWidth = 75 * window.innerWidth;
if (maxWidth !== 0) {
maxWidth = Math.round(maxWidth / 100);
}
return maxWidth;
} }
get height(): number { get height(): number {
@ -94,6 +104,15 @@ class CoWebsiteManager {
this.cowebsiteDom.style.height = height + "px"; this.cowebsiteDom.style.height = height + "px";
} }
get maxHeight(): number {
let maxHeight = 60 * window.innerHeight;
if (maxHeight !== 0) {
maxHeight = Math.round(maxHeight / 100);
}
return maxHeight;
}
get verticalMode(): boolean { get verticalMode(): boolean {
return window.innerWidth < window.innerHeight; return window.innerWidth < window.innerHeight;
} }
@ -191,29 +210,21 @@ class CoWebsiteManager {
if (this.verticalMode) { if (this.verticalMode) {
const tempValue = this.height + y; const tempValue = this.height + y;
let maxHeight = 60 * window.innerHeight;
if (maxHeight !== 0) {
maxHeight = Math.round(maxHeight / 100);
}
if (tempValue < this.cowebsiteAsideHolderDom.offsetHeight) { if (tempValue < this.cowebsiteAsideHolderDom.offsetHeight) {
this.height = this.cowebsiteAsideHolderDom.offsetHeight; this.height = this.cowebsiteAsideHolderDom.offsetHeight;
} else if (tempValue > maxHeight) { } else if (tempValue > this.maxHeight) {
this.height = maxHeight; this.height = this.maxHeight;
} else { } else {
this.height = tempValue; this.height = tempValue;
} }
} else { } else {
const tempValue = this.width - x; const tempValue = this.width - x;
let maxWidth = 75 * window.innerWidth;
if (maxWidth !== 0) {
maxWidth = Math.round(maxWidth / 100);
}
if (tempValue < this.cowebsiteAsideHolderDom.offsetWidth) { if (tempValue < this.cowebsiteAsideHolderDom.offsetWidth) {
this.width = this.cowebsiteAsideHolderDom.offsetWidth; this.width = this.cowebsiteAsideHolderDom.offsetWidth;
} else if (tempValue > maxWidth) { } else if (tempValue > this.maxWidth) {
this.width = maxWidth; this.width = this.maxWidth;
} else { } else {
this.width = tempValue; this.width = tempValue;
} }
@ -299,6 +310,27 @@ class CoWebsiteManager {
}); });
} }
public displayMain() {
const coWebsite = this.getMainCoWebsite();
if (coWebsite) {
coWebsite.iframe.style.display = "block";
}
this.loadMain();
this.openMain();
this.fire();
}
public hideMain() {
const coWebsite = this.getMainCoWebsite();
if (coWebsite) {
coWebsite.iframe.style.display = "none";
}
this.cowebsiteDom.classList.add("closing");
this.cowebsiteDom.classList.remove("opened");
this.openedMain = iframeStates.closed;
this.fire();
}
private closeMain(): void { private closeMain(): void {
this.toggleFullScreenIcon(true); this.toggleFullScreenIcon(true);
this.cowebsiteDom.classList.add("closing"); this.cowebsiteDom.classList.add("closing");
@ -308,7 +340,7 @@ class CoWebsiteManager {
this.fire(); this.fire();
} }
private loadMain(): void { private loadMain(openingWidth?: number): void {
this.loaderAnimationInterval.interval = setInterval(() => { this.loaderAnimationInterval.interval = setInterval(() => {
if (!this.loaderAnimationInterval.trails) { if (!this.loaderAnimationInterval.trails) {
this.loaderAnimationInterval.trails = [0, 1, 2]; this.loaderAnimationInterval.trails = [0, 1, 2];
@ -337,6 +369,25 @@ class CoWebsiteManager {
trail === 3 ? 0 : trail + 1 trail === 3 ? 0 : trail + 1
); );
}, 200); }, 200);
if (!this.verticalMode && openingWidth) {
let newWidth = 50;
if (openingWidth > 100) {
newWidth = 100;
} else if (openingWidth > 1) {
newWidth = openingWidth;
}
newWidth = Math.round((newWidth * this.maxWidth) / 100);
if (newWidth < this.cowebsiteAsideHolderDom.offsetWidth) {
newWidth = this.cowebsiteAsideHolderDom.offsetWidth;
}
this.width = newWidth;
}
this.cowebsiteDom.classList.add("opened"); this.cowebsiteDom.classList.add("opened");
this.openedMain = iframeStates.loading; this.openedMain = iframeStates.loading;
} }
@ -346,7 +397,6 @@ class CoWebsiteManager {
this.resizeAllIframes(); this.resizeAllIframes();
}); });
this.openedMain = iframeStates.opened; this.openedMain = iframeStates.opened;
this.resetStyleMain();
} }
public resetStyleMain() { public resetStyleMain() {
@ -533,6 +583,7 @@ class CoWebsiteManager {
base: string, base: string,
allowApi?: boolean, allowApi?: boolean,
allowPolicy?: string, allowPolicy?: string,
widthPercent?: number,
position?: number, position?: number,
closable?: boolean, closable?: boolean,
altMessage?: string altMessage?: string
@ -549,6 +600,7 @@ class CoWebsiteManager {
closable: closable ?? false, closable: closable ?? false,
allowPolicy, allowPolicy,
allowApi, allowApi,
widthPercent,
altMessage, altMessage,
}; };
@ -561,12 +613,13 @@ class CoWebsiteManager {
iframe: HTMLIFrameElement, iframe: HTMLIFrameElement,
allowApi?: boolean, allowApi?: boolean,
allowPolicy?: string, allowPolicy?: string,
widthPercent?: number,
position?: number, position?: number,
closable?: boolean, closable?: boolean,
jitsi?: boolean jitsi?: boolean
): CoWebsite { ): CoWebsite {
if (get(coWebsitesNotAsleep).length < 1) { if (get(coWebsitesNotAsleep).length < 1) {
this.loadMain(); this.loadMain(widthPercent);
} }
iframe.id = this.generateUniqueId(); iframe.id = this.generateUniqueId();
@ -578,6 +631,7 @@ class CoWebsiteManager {
closable: closable ?? false, closable: closable ?? false,
allowPolicy, allowPolicy,
allowApi, allowApi,
widthPercent,
jitsi, jitsi,
}; };
@ -597,7 +651,12 @@ class CoWebsiteManager {
if (get(coWebsitesNotAsleep).length < 1) { if (get(coWebsitesNotAsleep).length < 1) {
coWebsites.remove(coWebsite); coWebsites.remove(coWebsite);
coWebsites.add(coWebsite, 0); coWebsites.add(coWebsite, 0);
this.loadMain(); this.loadMain(coWebsite.widthPercent);
}
// Check if the main is hide
if (this.getMainCoWebsite() && this.openedMain === iframeStates.closed) {
this.displayMain();
} }
coWebsite.state.set("loading"); coWebsite.state.set("loading");

View file

@ -179,7 +179,15 @@ class JitsiFactory {
const doResolve = (): void => { const doResolve = (): void => {
const iframe = coWebsiteManager.getCoWebsiteBuffer().querySelector<HTMLIFrameElement>('[id*="jitsi" i]'); const iframe = coWebsiteManager.getCoWebsiteBuffer().querySelector<HTMLIFrameElement>('[id*="jitsi" i]');
if (iframe && this.jitsiApi) { if (iframe && this.jitsiApi) {
const coWebsite = coWebsiteManager.addCoWebsiteFromIframe(iframe, false, undefined, 0, false, true); const coWebsite = coWebsiteManager.addCoWebsiteFromIframe(
iframe,
false,
undefined,
undefined,
0,
false,
true
);
this.jitsiApi.addListener("videoConferenceLeft", () => { this.jitsiApi.addListener("videoConferenceLeft", () => {
this.closeOrUnload(coWebsite); this.closeOrUnload(coWebsite);

View file

@ -13,5 +13,6 @@ export enum DivImportance {
} }
export const ON_ACTION_TRIGGER_BUTTON = "onaction"; export const ON_ACTION_TRIGGER_BUTTON = "onaction";
export const ON_ICON_TRIGGER_BUTTON = "onicon";
export type Box = { xStart: number; yStart: number; xEnd: number; yEnd: number }; export type Box = { xStart: number; yStart: number; xEnd: number; yEnd: number };

View file

@ -47,6 +47,11 @@
"name":"openWebsiteTrigger", "name":"openWebsiteTrigger",
"type":"string", "type":"string",
"value":"onaction" "value":"onaction"
},
{
"name":"openWebsiteWidth",
"type":"int",
"value":100
}], }],
"type":"tilelayer", "type":"tilelayer",
"visible":true, "visible":true,

View file

@ -2,6 +2,7 @@
# yarn lockfile v1 # yarn lockfile v1
"husky@^6.0.0": husky@^7.0.1:
"resolved" "https://registry.npmjs.org/husky/-/husky-6.0.0.tgz" version "7.0.4"
"version" "6.0.0" resolved "https://registry.yarnpkg.com/husky/-/husky-7.0.4.tgz#242048245dc49c8fb1bf0cc7cfb98dd722531535"
integrity sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==