diff --git a/client/@types/olympus/index.d.ts b/client/@types/olympus/index.d.ts index faa3f853..0b4d41c3 100644 --- a/client/@types/olympus/index.d.ts +++ b/client/@types/olympus/index.d.ts @@ -253,6 +253,8 @@ declare module "constants/constants" { export const MGRS_PRECISION_100M = 4; export const MGRS_PRECISION_10M = 5; export const MGRS_PRECISION_1M = 6; + export const DELETE_CYCLE_TIME = 0.05; + export const DELETE_SLOW_THRESHOLD = 50; } declare module "map/markers/custommarker" { import { Map, Marker } from "leaflet"; @@ -303,7 +305,7 @@ declare module "controls/dropdown" { #private; constructor(ID: string | null, callback: CallableFunction, options?: string[] | null, defaultText?: string); getContainer(): HTMLElement; - setOptions(optionsList: string[], sortAlphabetically?: boolean): void; + setOptions(optionsList: string[], sort?: "" | "string" | "number"): void; setOptionsElements(optionsElements: HTMLElement[]): void; getOptionElements(): HTMLCollection; addOptionElement(optionElement: HTMLElement): void; @@ -604,6 +606,7 @@ declare module "interfaces" { export interface ShortcutOptions { altKey?: boolean; callback: CallableFunction; + context?: string; ctrlKey?: boolean; name?: string; shiftKey?: boolean; @@ -786,9 +789,11 @@ declare module "controls/unitspawnmenu" { import { UnitSpawnOptions } from "interfaces"; export class UnitSpawnMenu { #private; - spawnOptions: UnitSpawnOptions; + protected showRangeCircles: boolean; + protected spawnOptions: UnitSpawnOptions; constructor(ID: string, unitDatabase: UnitDatabase, orderByRole: boolean); getContainer(): HTMLElement; + getVisible(): boolean; reset(): void; setCountries(): void; refreshOptions(): void; @@ -824,6 +829,7 @@ declare module "controls/unitspawnmenu" { deployUnits(spawnOptions: UnitSpawnOptions, unitsCount: number): void; } export class GroundUnitSpawnMenu extends UnitSpawnMenu { + protected showRangeCircles: boolean; /** * * @param ID - the ID of the HTML element which will contain the context menu @@ -1331,6 +1337,20 @@ declare module "contextmenus/airbasespawnmenu" { setAirbase(airbase: Airbase): void; } } +declare module "context/context" { + export interface ContextInterface { + useSpawnMenu?: boolean; + useUnitControlPanel?: boolean; + useUnitInfoPanel?: boolean; + } + export class Context { + #private; + constructor(config: ContextInterface); + getUseSpawnMenu(): boolean; + getUseUnitControlPanel(): boolean; + getUseUnitInfoPanel(): boolean; + } +} declare module "other/manager" { export class Manager { #private; @@ -1569,6 +1589,7 @@ declare module "panels/unitinfopanel" { export class UnitInfoPanel extends Panel { #private; constructor(ID: string); + show(): void; } } declare module "plugin/pluginmanager" { @@ -1647,6 +1668,14 @@ declare module "unit/citiesDatabase" { pop: number; }[]; } +declare module "dialog/dialog" { + import { Panel } from "panels/panel"; + export class Dialog extends Panel { + constructor(element: string); + hide(): void; + show(): void; + } +} declare module "unit/unitsmanager" { import { LatLng, LatLngBounds } from "leaflet"; import { Unit } from "unit/unit"; @@ -2094,6 +2123,18 @@ declare module "panels/unitlistpanel" { toggle(): void; } } +declare module "context/contextmanager" { + import { Manager } from "other/manager"; + import { ContextInterface } from "context/context"; + export class ContextManager extends Manager { + #private; + constructor(); + add(name: string, contextConfig: ContextInterface): this; + currentContextIs(contextName: string): boolean; + getCurrentContext(): any; + setContext(contextName: string): false | undefined; + } +} declare module "olympusapp" { import { Map } from "map/map"; import { MissionManager } from "mission/missionmanager"; @@ -2103,10 +2144,15 @@ declare module "olympusapp" { import { WeaponsManager } from "weapon/weaponsmanager"; import { Manager } from "other/manager"; import { ServerManager } from "server/servermanager"; + import { ContextManager } from "context/contextmanager"; + import { Context } from "context/context"; export class OlympusApp { #private; constructor(); + getDialogManager(): Manager; getMap(): Map; + getCurrentContext(): Context; + getContextManager(): ContextManager; getServerManager(): ServerManager; getPanelsManager(): Manager; getPopupsManager(): Manager; @@ -2158,3 +2204,11 @@ declare module "index" { import { OlympusApp } from "olympusapp"; export function getApp(): OlympusApp; } +declare module "context/contextmenumanager" { + import { ContextMenu } from "contextmenus/contextmenu"; + import { Manager } from "other/manager"; + export class ContextMenuManager extends Manager { + constructor(); + add(name: string, contextMenu: ContextMenu): this; + } +} diff --git a/client/public/stylesheets/style/style.css b/client/public/stylesheets/style/style.css index dd5c7381..94b98cee 100644 --- a/client/public/stylesheets/style/style.css +++ b/client/public/stylesheets/style/style.css @@ -72,10 +72,6 @@ form { padding: 0; } -form>div { - margin: 20px 0; -} - .pill { background-color: var(--background-steel); border-radius: 999px; @@ -669,8 +665,8 @@ nav.ol-panel> :last-child { width:10px; } -.ol-navbar-buttons-group > .protectable > button.lock svg.locked { - filter:invert(100); +.ol-navbar-buttons-group > .protectable > button.lock svg.locked * { + fill:white !important; } .ol-navbar-buttons-group > .protectable > button:not([data-protected]).lock svg.unlocked, @@ -850,7 +846,7 @@ nav.ol-panel> :last-child { column-gap: 10px; display: flex; flex-direction: row; - margin: 10px 0px; + margin: 20px 0px; flex-wrap: wrap; width: 100%; row-gap: 10px; diff --git a/client/src/context/context.ts b/client/src/context/context.ts index f92f5168..4fe02f5f 100644 --- a/client/src/context/context.ts +++ b/client/src/context/context.ts @@ -1,11 +1,31 @@ export interface ContextInterface { - + useSpawnMenu?: boolean; + useUnitControlPanel?: boolean; + useUnitInfoPanel?: boolean; } export class Context { - constructor( config:ContextInterface ) { + #useSpawnMenu:boolean; + #useUnitControlPanel:boolean; + #useUnitInfoPanel:boolean; + constructor( config:ContextInterface ) { + this.#useSpawnMenu = ( config.useSpawnMenu !== false ); + this.#useUnitControlPanel = ( config.useUnitControlPanel !== false ); + this.#useUnitInfoPanel = ( config.useUnitInfoPanel !== false ); + } + + getUseSpawnMenu() { + return this.#useSpawnMenu; + } + + getUseUnitControlPanel() { + return this.#useUnitControlPanel; + } + + getUseUnitInfoPanel() { + return this.#useUnitInfoPanel; } } \ No newline at end of file diff --git a/client/src/contextmenus/mapcontextmenu.ts b/client/src/contextmenus/mapcontextmenu.ts index f7924fcd..0f75a596 100644 --- a/client/src/contextmenus/mapcontextmenu.ts +++ b/client/src/contextmenus/mapcontextmenu.ts @@ -99,6 +99,9 @@ export class MapContextMenu extends ContextMenu { * @param latlng Leaflet latlng object of the mouse click */ show(x: number, y: number, latlng: LatLng) { + if (!getApp().getCurrentContext().getUseSpawnMenu()) + return false; + super.show(x, y, latlng); this.#aircraftSpawnMenu.setLatLng(latlng); diff --git a/client/src/map/map.ts b/client/src/map/map.ts index 06a95d15..b82feb05 100644 --- a/client/src/map/map.ts +++ b/client/src/map/map.ts @@ -734,7 +734,7 @@ export class Map extends L.Map { const makeTitle = (isProtected:boolean) => { return ( isProtected ) ? "Unit type is protected and will ignore orders" : "Unit is NOT protected and will respond to orders"; } - this.#mapMarkerControls.forEach( (control:MapMarkerControl) => { + this.getMapMarkerControls().forEach( (control:MapMarkerControl) => { const toggles = `["${control.toggles.join('","')}"]`; const div = document.createElement("div"); div.className = control.protectable === true ? "protectable" : ""; @@ -901,5 +901,9 @@ export class Map extends L.Map { this.#visibilityOptions[option] = ev.currentTarget.checked; document.dispatchEvent(new CustomEvent("mapVisibilityOptionsChanged")); } + + getMapMarkerControls() { + return this.#mapMarkerControls; + } } diff --git a/client/src/olympusapp.ts b/client/src/olympusapp.ts index ac2bc16e..22f2ebf8 100644 --- a/client/src/olympusapp.ts +++ b/client/src/olympusapp.ts @@ -403,19 +403,26 @@ export class OlympusApp { }); /* Try and connect with the Olympus REST server */ - document.addEventListener("tryConnection", () => { - const form = document.querySelector("#splash-content")?.querySelector("#authentication-form"); - const username = (form?.querySelector("#username") as HTMLInputElement).value; - const password = (form?.querySelector("#password") as HTMLInputElement).value; + const loginForm = document.getElementById("authentication-form"); + if (loginForm instanceof HTMLFormElement) { + loginForm.addEventListener("submit", (ev:SubmitEvent) => { + ev.preventDefault(); + ev.stopPropagation(); + const username = (loginForm.querySelector("#username") as HTMLInputElement).value; + const password = (loginForm.querySelector("#password") as HTMLInputElement).value; - /* Update the user credentials */ - this.getServerManager().setCredentials(username, password); + // Update the user credentials + this.getServerManager().setCredentials(username, password); - /* Start periodically requesting updates */ - this.getServerManager().startUpdate(); + // Start periodically requesting updates + this.getServerManager().startUpdate(); + + this.setLoginStatus("connecting"); + }); + } else { + console.error("Unable to find login form."); + } - this.setLoginStatus("connecting"); - }) /* Reload the page, used to mimic a restart of the app */ document.addEventListener("reloadPage", () => { diff --git a/client/src/panels/unitcontrolpanel.ts b/client/src/panels/unitcontrolpanel.ts index c590c652..07ef385e 100644 --- a/client/src/panels/unitcontrolpanel.ts +++ b/client/src/panels/unitcontrolpanel.ts @@ -131,6 +131,10 @@ export class UnitControlPanel extends Panel { } show() { + const context = getApp().getCurrentContext(); + if ( !context.getUseUnitControlPanel() ) + return; + super.show(); this.#speedTypeSwitch.resetExpectedValue(); this.#altitudeTypeSwitch.resetExpectedValue(); diff --git a/client/src/panels/unitinfopanel.ts b/client/src/panels/unitinfopanel.ts index 1595e946..1193ca85 100644 --- a/client/src/panels/unitinfopanel.ts +++ b/client/src/panels/unitinfopanel.ts @@ -1,3 +1,4 @@ +import { getApp } from ".."; import { Ammo } from "../interfaces"; import { aircraftDatabase } from "../unit/databases/aircraftdatabase"; import { Unit } from "../unit/unit"; @@ -92,4 +93,12 @@ export class UnitInfoPanel extends Panel { else this.hide(); } + + show() { + const context = getApp().getCurrentContext(); + if ( !context.getUseUnitInfoPanel() ) + return; + + super.show(); + } } \ No newline at end of file diff --git a/client/views/other/dialogs.ejs b/client/views/other/dialogs.ejs index 14296f1c..738bc97d 100644 --- a/client/views/other/dialogs.ejs +++ b/client/views/other/dialogs.ejs @@ -6,11 +6,11 @@