mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
Added new delete method dialog
This commit is contained in:
parent
d14741f3b1
commit
f954338c27
@ -140,6 +140,16 @@
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#slow-delete-popup {
|
||||
align-self: center;
|
||||
display:flex;
|
||||
justify-self: center;
|
||||
position: absolute;
|
||||
width: fit-content;
|
||||
height: fit-content;
|
||||
z-index: 9999999999;
|
||||
}
|
||||
|
||||
#log-panel {
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
|
||||
@ -699,7 +699,7 @@ nav.ol-panel> :last-child {
|
||||
overflow: hidden;
|
||||
width: 70%;
|
||||
max-width: 1200px;
|
||||
z-index: 99999;
|
||||
z-index: 999999;
|
||||
}
|
||||
|
||||
@media (min-width: 1700px) {
|
||||
@ -796,7 +796,7 @@ nav.ol-panel> :last-child {
|
||||
position: fixed;
|
||||
top: 0px;
|
||||
width: 100%;
|
||||
z-index: 9999;
|
||||
z-index: 99999;
|
||||
}
|
||||
|
||||
#authentication-form {
|
||||
@ -1148,7 +1148,7 @@ dl.ol-data-grid dd {
|
||||
background-color: var(--background-slate-blue);
|
||||
color: white;
|
||||
position: absolute;
|
||||
z-index: 9999;
|
||||
z-index: 999999;
|
||||
}
|
||||
|
||||
.ol-panel.ol-dialog {
|
||||
@ -1178,8 +1178,10 @@ dl.ol-data-grid dd {
|
||||
}
|
||||
|
||||
.ol-dialog-footer {
|
||||
align-content: center;
|
||||
border-top: 1px solid var(--background-grey);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding-top: 15px;
|
||||
row-gap: 10px;
|
||||
}
|
||||
|
||||
@ -209,4 +209,7 @@ export const MGRS_PRECISION_10KM = 2;
|
||||
export const MGRS_PRECISION_1KM = 3;
|
||||
export const MGRS_PRECISION_100M = 4;
|
||||
export const MGRS_PRECISION_10M = 5;
|
||||
export const MGRS_PRECISION_1M = 6;
|
||||
export const MGRS_PRECISION_1M = 6;
|
||||
|
||||
export const DELETE_CYCLE_TIME = 0.1;
|
||||
export const DELETE_SLOW_THRESHOLD = 50;
|
||||
19
client/src/dialog/dialog.ts
Normal file
19
client/src/dialog/dialog.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { Panel } from "../panels/panel";
|
||||
|
||||
export class Dialog extends Panel {
|
||||
|
||||
constructor( element:string ) {
|
||||
super( element );
|
||||
}
|
||||
|
||||
hide() {
|
||||
super.hide();
|
||||
document.getElementById( "gray-out" )?.classList.toggle("hide", true);
|
||||
}
|
||||
|
||||
show() {
|
||||
super.show();
|
||||
document.getElementById( "gray-out" )?.classList.toggle("hide", false);
|
||||
}
|
||||
|
||||
}
|
||||
@ -34,21 +34,26 @@ export class OlympusApp {
|
||||
#map: Map | null = null;
|
||||
|
||||
/* Managers */
|
||||
#dialogManager!: Manager;
|
||||
#missionManager: MissionManager | null = null;
|
||||
#panelsManager: Manager | null = null;
|
||||
#pluginsManager: PluginsManager | null = null;
|
||||
#popupsManager: Manager | null = null;
|
||||
#serverManager: ServerManager | null = null;
|
||||
#shortcutManager: ShortcutManager | null = null;
|
||||
#toolbarsManager: Manager | null = null;
|
||||
#unitsManager: UnitsManager | null = null;
|
||||
#weaponsManager: WeaponsManager | null = null;
|
||||
#missionManager: MissionManager | null = null;
|
||||
#pluginsManager: PluginsManager | null = null;
|
||||
#panelsManager: Manager | null = null;
|
||||
#popupsManager: Manager | null = null;
|
||||
#toolbarsManager: Manager | null = null;
|
||||
#shortcutManager: ShortcutManager | null = null;
|
||||
|
||||
constructor() {
|
||||
|
||||
}
|
||||
|
||||
// TODO add checks on null
|
||||
getDialogManager() {
|
||||
return this.#dialogManager as Manager;
|
||||
}
|
||||
|
||||
getMap() {
|
||||
return this.#map as Map;
|
||||
}
|
||||
@ -163,16 +168,14 @@ export class OlympusApp {
|
||||
/* Initialize base functionalitites */
|
||||
this.#map = new Map('map-container');
|
||||
|
||||
this.#serverManager = new ServerManager();
|
||||
this.#unitsManager = new UnitsManager();
|
||||
this.#weaponsManager = new WeaponsManager();
|
||||
this.#missionManager = new MissionManager();
|
||||
|
||||
this.#shortcutManager = new ShortcutManager();
|
||||
|
||||
this.#panelsManager = new Manager();
|
||||
this.#popupsManager = new Manager();
|
||||
this.#serverManager = new ServerManager();
|
||||
this.#shortcutManager = new ShortcutManager();
|
||||
this.#toolbarsManager = new Manager();
|
||||
this.#unitsManager = new UnitsManager();
|
||||
this.#weaponsManager = new WeaponsManager();
|
||||
|
||||
// Panels
|
||||
this.getPanelsManager()
|
||||
@ -186,7 +189,8 @@ export class OlympusApp {
|
||||
.add("unitList", new UnitListPanel("unit-list-panel", "unit-list-panel-content"))
|
||||
|
||||
// Popups
|
||||
this.getPopupsManager().add("infoPopup", new Popup("info-popup"));
|
||||
this.getPopupsManager()
|
||||
.add("infoPopup", new Popup("info-popup"));
|
||||
|
||||
// Toolbars
|
||||
this.getToolbarsManager().add("primaryToolbar", new PrimaryToolbar("primary-toolbar"))
|
||||
|
||||
@ -541,14 +541,15 @@ export class ServerManager {
|
||||
}
|
||||
|
||||
setConnected(newConnected: boolean) {
|
||||
if (this.#connected != newConnected)
|
||||
if (this.#connected != newConnected) {
|
||||
newConnected ? (getApp().getPopupsManager().get("infoPopup") as Popup).setText("Connected to DCS Olympus server") : (getApp().getPopupsManager().get("infoPopup") as Popup).setText("Disconnected from DCS Olympus server");
|
||||
this.#connected = newConnected;
|
||||
|
||||
if (this.#connected) {
|
||||
document.querySelector("#splash-screen")?.classList.add("hide");
|
||||
document.querySelector("#gray-out")?.classList.add("hide");
|
||||
if (newConnected) {
|
||||
document.getElementById("splash-screen")?.classList.add("hide");
|
||||
document.getElementById("gray-out")?.classList.add("hide");
|
||||
}
|
||||
}
|
||||
|
||||
this.#connected = newConnected;
|
||||
}
|
||||
|
||||
getConnected() {
|
||||
|
||||
@ -4,7 +4,7 @@ import { Unit } from "./unit";
|
||||
import { bearingAndDistanceToLatLng, deg2rad, getGroundElevation, getUnitDatabaseByCategory, keyEventWasInInput, latLngToMercator, mToFt, mercatorToLatLng, msToKnots, polyContains, polygonArea, randomPointInPoly, randomUnitBlueprint } from "../other/utils";
|
||||
import { CoalitionArea } from "../map/coalitionarea/coalitionarea";
|
||||
import { groundUnitDatabase } from "./databases/groundunitdatabase";
|
||||
import { DataIndexes, GAME_MASTER, IADSDensities, IDLE, MOVE_UNIT } from "../constants/constants";
|
||||
import { DELETE_CYCLE_TIME, DELETE_SLOW_THRESHOLD, DataIndexes, GAME_MASTER, IADSDensities, IDLE, MOVE_UNIT } from "../constants/constants";
|
||||
import { DataExtractor } from "../server/dataextractor";
|
||||
import { citiesDatabase } from "./citiesDatabase";
|
||||
import { aircraftDatabase } from "./databases/aircraftdatabase";
|
||||
@ -14,35 +14,40 @@ import { TemporaryUnitMarker } from "../map/markers/temporaryunitmarker";
|
||||
import { Popup } from "../popups/popup";
|
||||
import { HotgroupPanel } from "../panels/hotgrouppanel";
|
||||
import { Contact, UnitData, UnitSpawnTable } from "../interfaces";
|
||||
import { Dialog } from "../dialog/dialog";
|
||||
|
||||
/** The UnitsManager handles the creation, update, and control of units. Data is strictly updated by the server ONLY. This means that any interaction from the user will always and only
|
||||
* result in a command to the server, executed by means of a REST PUT request. Any subsequent change in data will be reflected only when the new data is sent back by the server. This strategy allows
|
||||
* to avoid client/server and client/client inconsistencies.
|
||||
*/
|
||||
export class UnitsManager {
|
||||
#units: { [ID: number]: Unit };
|
||||
#copiedUnits: UnitData[];
|
||||
#selectionEventDisabled: boolean = false;
|
||||
#deselectionEventDisabled: boolean = false;
|
||||
#requestDetectionUpdate: boolean = false;
|
||||
#selectionEventDisabled: boolean = false;
|
||||
#slowDeleteDialog!:Dialog;
|
||||
#units: { [ID: number]: Unit };
|
||||
|
||||
|
||||
constructor() {
|
||||
this.#units = {};
|
||||
this.#copiedUnits = [];
|
||||
this.#units = {};
|
||||
|
||||
document.addEventListener('commandModeOptionsChanged', () => { Object.values(this.#units).forEach((unit: Unit) => unit.updateVisibility()) });
|
||||
document.addEventListener('contactsUpdated', (e: CustomEvent) => { this.#requestDetectionUpdate = true });
|
||||
document.addEventListener('copy', () => this.selectedUnitsCopy());
|
||||
document.addEventListener('paste', () => this.pasteUnits());
|
||||
document.addEventListener('unitSelection', (e: CustomEvent) => this.#onUnitSelection(e.detail));
|
||||
document.addEventListener('unitDeselection', (e: CustomEvent) => this.#onUnitDeselection(e.detail));
|
||||
document.addEventListener('deleteSelectedUnits', () => this.selectedUnitsDelete());
|
||||
document.addEventListener('explodeSelectedUnits', () => this.selectedUnitsDelete(true));
|
||||
document.addEventListener('keyup', (event) => this.#onKeyUp(event));
|
||||
document.addEventListener('exportToFile', () => this.exportToFile());
|
||||
document.addEventListener('importFromFile', () => this.importFromFile());
|
||||
document.addEventListener('contactsUpdated', (e: CustomEvent) => { this.#requestDetectionUpdate = true });
|
||||
document.addEventListener('commandModeOptionsChanged', () => { Object.values(this.#units).forEach((unit: Unit) => unit.updateVisibility()) });
|
||||
document.addEventListener('selectedUnitsChangeSpeed', (e: any) => { this.selectedUnitsChangeSpeed(e.detail.type) });
|
||||
document.addEventListener('keyup', (event) => this.#onKeyUp(event));
|
||||
document.addEventListener('paste', () => this.pasteUnits());
|
||||
document.addEventListener('selectedUnitsChangeAltitude', (e: any) => { this.selectedUnitsChangeAltitude(e.detail.type) });
|
||||
document.addEventListener('selectedUnitsChangeSpeed', (e: any) => { this.selectedUnitsChangeSpeed(e.detail.type) });
|
||||
document.addEventListener('unitDeselection', (e: CustomEvent) => this.#onUnitDeselection(e.detail));
|
||||
document.addEventListener('unitSelection', (e: CustomEvent) => this.#onUnitSelection(e.detail));
|
||||
|
||||
this.#slowDeleteDialog = new Dialog( "slow-delete-dialog" );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -638,7 +643,7 @@ export class UnitsManager {
|
||||
try {
|
||||
groundElevation = parseFloat(response);
|
||||
} catch {
|
||||
console.log("Simulate fire fight: could not retrieve ground elevation")
|
||||
console.warn("Simulate fire fight: could not retrieve ground elevation")
|
||||
}
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].simulateFireFight(latlng, groundElevation);
|
||||
@ -754,14 +759,24 @@ export class UnitsManager {
|
||||
return;
|
||||
}
|
||||
|
||||
var immediate = false;
|
||||
if (selectedUnits.length > 20)
|
||||
immediate = confirm(`You are trying to delete ${selectedUnits.length} units, do you want to delete them immediately? This may cause lag for players.`)
|
||||
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].delete(explosion, immediate);
|
||||
const doDelete = (explosion = false, immediate = false) => {
|
||||
const selectedUnits = this.getSelectedUnits();
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].delete(explosion, immediate);
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `deleted`);
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `deleted`);
|
||||
|
||||
if (selectedUnits.length >= DELETE_SLOW_THRESHOLD)
|
||||
this.#showSlowDeleteDialog(selectedUnits).then((action:any) => {
|
||||
if (action === "delete-slow")
|
||||
doDelete(explosion, false);
|
||||
else if (action === "delete-immediate")
|
||||
doDelete(explosion, true);
|
||||
})
|
||||
else
|
||||
doDelete(explosion);
|
||||
|
||||
}
|
||||
|
||||
/** Compute the destinations of every unit in the selected units. This function preserves the relative positions of the units, and rotates the whole formation by rotation.
|
||||
@ -1083,4 +1098,32 @@ export class UnitsManager {
|
||||
else if (units.length > 1)
|
||||
(getApp().getPopupsManager().get("infoPopup") as Popup).setText(`${units[0].getUnitName()} and ${units.length - 1} other units ${message}`);
|
||||
}
|
||||
|
||||
#showSlowDeleteDialog(selectedUnits:Unit[]) {
|
||||
let button:HTMLButtonElement | null = null;
|
||||
const deletionTime = Math.round( selectedUnits.length * DELETE_CYCLE_TIME ).toString();
|
||||
const dialog = this.#slowDeleteDialog;
|
||||
const element = dialog.getElement();
|
||||
const listener = (ev:MouseEvent) => {
|
||||
if (ev.target instanceof HTMLButtonElement && ev.target.matches("[data-action]"))
|
||||
button = ev.target;
|
||||
}
|
||||
|
||||
element.querySelectorAll(".deletion-count").forEach( el => el.innerHTML = selectedUnits.length.toString() );
|
||||
element.querySelectorAll(".deletion-time").forEach( el => el.innerHTML = deletionTime );
|
||||
dialog.show();
|
||||
|
||||
return new Promise((resolve) => {
|
||||
element.addEventListener("click", listener);
|
||||
|
||||
const interval = setInterval(() => {
|
||||
if (button instanceof HTMLButtonElement ) {
|
||||
clearInterval(interval);
|
||||
dialog.hide();
|
||||
element.removeEventListener("click", listener);
|
||||
resolve( button.getAttribute("data-action") );
|
||||
}
|
||||
}, 250);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -304,4 +304,27 @@
|
||||
<button class="ol-button-apply" data-on-click="applycommandModeOptions">Apply</button>
|
||||
<button class="ol-button-close" data-on-click="closeDialog">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="slow-delete-dialog" class="ol-panel ol-dialog hide" oncontextmenu="return false;">
|
||||
<div class="ol-dialog-header">
|
||||
<h3 id="unit-name">Confirm deletion method</h3>
|
||||
</div>
|
||||
|
||||
<div class="ol-dialog-content">
|
||||
<p>You are trying to delete a large amount of units (<span class="deletion-count"></span>), which can cause the server to lag for players.</p>
|
||||
<p>You may:
|
||||
<ul>
|
||||
<li>delete in batches (less lag but Olympus cannot process any additional orders until<br /> all units have been deleted);</li>
|
||||
<li>delete immediately (you can continue to give Olympus orders but players may<br />experience lag while this happens);</li>
|
||||
<li>cancel this instruction.</li>
|
||||
</ul></p>
|
||||
</div>
|
||||
|
||||
<div class="ol-dialog-footer ol-group">
|
||||
<button data-action="delete-slow">Delete in batches (~<span class="deletion-time"></span>s)</button>
|
||||
<button data-action="delete-immediate">Delete immediately</button>
|
||||
<button data-action="delete-cancel">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user