mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
15
client/@types/olympus/index.d.ts
vendored
15
client/@types/olympus/index.d.ts
vendored
@@ -1085,7 +1085,7 @@ declare module "unit/unit" {
|
||||
carpetBomb(latlng: LatLng): void;
|
||||
bombBuilding(latlng: LatLng): void;
|
||||
fireAtArea(latlng: LatLng): void;
|
||||
simulateFireFight(latlng: LatLng, groundElevation: number | null): void;
|
||||
simulateFireFight(latlng: LatLng, targetGroundElevation: number | null): void;
|
||||
/***********************************************/
|
||||
onAdd(map: Map): this;
|
||||
}
|
||||
@@ -1967,6 +1967,19 @@ declare module "server/servermanager" {
|
||||
getPaused(): boolean;
|
||||
}
|
||||
}
|
||||
declare module "panels/unitlistpanel" {
|
||||
import { OlympusApp } from "olympusapp";
|
||||
import { Panel } from "panels/panel";
|
||||
export class UnitListPanel extends Panel {
|
||||
#private;
|
||||
constructor(olympusApp: OlympusApp, panelElement: string, contentElement: string);
|
||||
doUpdate(): void;
|
||||
getContentElement(): HTMLElement;
|
||||
startUpdates(): void;
|
||||
stopUpdates(): void;
|
||||
toggle(): void;
|
||||
}
|
||||
}
|
||||
declare module "olympusapp" {
|
||||
import { Map } from "map/map";
|
||||
import { MissionManager } from "mission/missionmanager";
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
@import url("panels/unitcontrol.css");
|
||||
@import url("panels/unitinfo.css");
|
||||
@import url("panels/logpanel.css");
|
||||
@import url("panels/unitlist.css");
|
||||
|
||||
@import url("other/contextmenus.css");
|
||||
@import url("other/popup.css");
|
||||
|
||||
55
client/public/stylesheets/panels/unitlist.css
Normal file
55
client/public/stylesheets/panels/unitlist.css
Normal file
@@ -0,0 +1,55 @@
|
||||
#unit-list-panel {
|
||||
bottom:20px;
|
||||
display:flex;
|
||||
flex-direction: column;
|
||||
justify-self:center;
|
||||
position: absolute;
|
||||
z-index:999;
|
||||
}
|
||||
|
||||
#unit-list-panel h3 {
|
||||
margin-bottom:4px;
|
||||
}
|
||||
|
||||
#unit-list-panel-content {
|
||||
display:flex;
|
||||
flex-flow: column nowrap;
|
||||
max-height: 200px;
|
||||
row-gap: 4px;
|
||||
}
|
||||
|
||||
#unit-list-panel .unit-list-unit {
|
||||
column-gap: 4px;
|
||||
display:flex;
|
||||
flex-flow: row nowrap;
|
||||
padding:2px 0;
|
||||
}
|
||||
|
||||
#unit-list-panel .unit-list-unit.headers {
|
||||
column-gap: 2px;
|
||||
display:flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
#unit-list-panel .unit-list-unit.headers [data-sort-field] {
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
#unit-list-panel .unit-list-unit.headers > * {
|
||||
background-color: var( --background-grey );
|
||||
margin-bottom: 2px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#unit-list-panel .unit-list-unit > * {
|
||||
overflow: hidden;
|
||||
width:100px;
|
||||
}
|
||||
|
||||
#unit-list-panel .unit-list-unit > [data-unit-id] {
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
#unit-list-panel .unit-list-unit > [data-unit-id]:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import { helicopterDatabase } from "./unit/databases/helicopterdatabase";
|
||||
import { groundUnitDatabase } from "./unit/databases/groundunitdatabase";
|
||||
import { navyUnitDatabase } from "./unit/databases/navyunitdatabase";
|
||||
import { ConfigurationOptions } from "./interfaces";
|
||||
import { UnitListPanel } from "./panels/unitlistpanel";
|
||||
|
||||
export class OlympusApp {
|
||||
/* Global data */
|
||||
@@ -181,6 +182,7 @@ export class OlympusApp {
|
||||
.add("serverStatus", new ServerStatusPanel("server-status-panel"))
|
||||
.add("unitControl", new UnitControlPanel("unit-control-panel"))
|
||||
.add("unitInfo", new UnitInfoPanel("unit-info-panel"))
|
||||
.add("unitList", new UnitListPanel( this, "unit-list-panel", "unit-list-panel-content" ) )
|
||||
|
||||
// Popups
|
||||
this.getPopupsManager().add("infoPopup", new Popup("info-popup"));
|
||||
|
||||
208
client/src/panels/unitlistpanel.ts
Normal file
208
client/src/panels/unitlistpanel.ts
Normal file
@@ -0,0 +1,208 @@
|
||||
import { OlympusApp } from "../olympusapp";
|
||||
import { ShortcutKeyboard } from "../shortcut/shortcut";
|
||||
import { Unit } from "../unit/unit";
|
||||
import { Panel } from "./panel";
|
||||
|
||||
export class UnitListPanel extends Panel {
|
||||
|
||||
#contentElement: HTMLElement;
|
||||
#currentSortAlgorithm: string = "unitName";
|
||||
#currentSortDirection: string = "ASC";
|
||||
#olympusApp: OlympusApp;
|
||||
#units: Unit[] = [];
|
||||
#updatesInterval!: ReturnType<typeof setInterval>;
|
||||
|
||||
constructor( olympusApp:OlympusApp, panelElement:string, contentElement:string ) {
|
||||
|
||||
super( panelElement );
|
||||
|
||||
this.#olympusApp = olympusApp;
|
||||
|
||||
const getElement = document.getElementById( contentElement );
|
||||
|
||||
if ( getElement instanceof HTMLElement ) {
|
||||
this.#contentElement = getElement;
|
||||
} else {
|
||||
throw new Error( `UnitList: unable to find element "${contentElement}".` );
|
||||
}
|
||||
|
||||
// Add the header click listener and sorting
|
||||
[].slice.call( this.getElement().querySelectorAll( ".headers > *" ) ).forEach( ( header:HTMLElement ) => {
|
||||
header.addEventListener( "click", ( ev:MouseEvent ) => {
|
||||
const el = ev.target;
|
||||
|
||||
if ( el instanceof HTMLElement ) {
|
||||
const newSort = el.getAttribute( "data-sort-field" ) || "unitName";
|
||||
|
||||
if ( this.#currentSortAlgorithm === newSort ) {
|
||||
this.#currentSortDirection = ( this.#currentSortDirection === "ASC" ) ? "DESC" : "ASC";
|
||||
} else {
|
||||
this.#currentSortDirection = "ASC";
|
||||
}
|
||||
|
||||
this.#currentSortAlgorithm = newSort;
|
||||
|
||||
this.doUpdate();
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Dynamically listen for clicks in order to do stuff with units
|
||||
this.getElement().addEventListener( "click", ( ev:MouseEvent ) => {
|
||||
|
||||
const t = ev.target;
|
||||
|
||||
if ( t instanceof HTMLElement ) {
|
||||
|
||||
let id:number = Number( t.getAttribute( "data-unit-id" ) || 0 );
|
||||
|
||||
this.#olympusApp.getUnitsManager().selectUnit( id );
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
new ShortcutKeyboard({
|
||||
"callback": () => {
|
||||
this.toggle()
|
||||
},
|
||||
"code": "KeyU"
|
||||
});
|
||||
|
||||
this.startUpdates();
|
||||
|
||||
}
|
||||
|
||||
doUpdate() {
|
||||
|
||||
if ( !this.getVisible() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.#contentElement.innerHTML = "";
|
||||
|
||||
this.#units = Object.values( this.#olympusApp.getUnitsManager().getUnits() );
|
||||
|
||||
|
||||
if ( this.#currentSortAlgorithm === "coalition" ) {
|
||||
this.#sortUnitsByCoalition();
|
||||
}
|
||||
|
||||
if ( this.#currentSortAlgorithm === "name" ) {
|
||||
this.#sortUnitsByName();
|
||||
}
|
||||
|
||||
if ( this.#currentSortAlgorithm === "unitName" ) {
|
||||
this.#sortUnitsByUnitName();
|
||||
}
|
||||
|
||||
|
||||
Object.values( this.#units ).forEach( ( unit:Unit ) => {
|
||||
|
||||
// Exclude dead units
|
||||
if ( !unit.getAlive() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.#contentElement.innerHTML += `
|
||||
<div class="unit-list-unit" data-value-unitName="${unit.getUnitName()}" data-value-name="${unit.getName()}" data-value-coalition="${unit.getCoalition()}" data-value-human="${unit.getHuman() ? "Human" : "AI"}">
|
||||
<div data-unit-id="${unit.ID}">${unit.getUnitName()}</div>
|
||||
<div>${unit.getName()}</div>
|
||||
<div>${unit.getCoalition()}</div>
|
||||
<div>${unit.getHuman() ? "Human" : "AI"}</div>
|
||||
</div>`;
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
getContentElement() {
|
||||
return this.#contentElement;
|
||||
}
|
||||
|
||||
#sortStringsCompare( str1:string, str2:string ) {
|
||||
|
||||
if ( str1 > str2 ) {
|
||||
return ( this.#currentSortDirection === "ASC" ) ? 1 : -1;
|
||||
} else if ( str1 < str2 ) {
|
||||
return ( this.#currentSortDirection === "ASC" ) ? -1 : 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
#sortUnitsByUnitName() {
|
||||
|
||||
this.#units.sort( ( unit1:Unit, unit2:Unit ) => {
|
||||
|
||||
const str1 = unit1.getUnitName().toLowerCase();
|
||||
const str2 = unit2.getUnitName().toLowerCase();
|
||||
|
||||
return this.#sortStringsCompare( str1, str2 );
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
#sortUnitsByCoalition() {
|
||||
|
||||
this.#units.sort( ( unit1:Unit, unit2:Unit ) => {
|
||||
|
||||
let str1 = unit1.getCoalition();
|
||||
let str2 = unit2.getCoalition();
|
||||
|
||||
let cmp = this.#sortStringsCompare( str1, str2 );
|
||||
|
||||
if ( cmp !== 0 ) {
|
||||
return cmp;
|
||||
}
|
||||
|
||||
str1 = unit1.getUnitName().toLowerCase();
|
||||
str2 = unit2.getUnitName().toLowerCase();
|
||||
|
||||
return this.#sortStringsCompare( str1, str2 );
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
#sortUnitsByName() {
|
||||
|
||||
this.#units.sort( ( unit1:Unit, unit2:Unit ) => {
|
||||
|
||||
const str1 = unit1.getName().toLowerCase();
|
||||
const str2 = unit2.getName().toLowerCase();
|
||||
|
||||
return this.#sortStringsCompare( str1, str2 );
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
startUpdates() {
|
||||
|
||||
this.doUpdate();
|
||||
|
||||
this.#updatesInterval = setInterval(() => {
|
||||
this.doUpdate();
|
||||
}, 2000 );
|
||||
|
||||
}
|
||||
|
||||
stopUpdates() {
|
||||
clearInterval( this.#updatesInterval );
|
||||
}
|
||||
|
||||
toggle() {
|
||||
if ( this.getVisible() ) {
|
||||
this.stopUpdates();
|
||||
} else {
|
||||
this.startUpdates();
|
||||
}
|
||||
|
||||
super.toggle();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@
|
||||
<%- include('panels/serverstatus.ejs') %>
|
||||
<%- include('panels/hotgroup.ejs') %>
|
||||
<%- include('panels/logpanel.ejs') %>
|
||||
<%- include('panels/unitlist.ejs') %>
|
||||
|
||||
<!-- Context menus -->
|
||||
<%- include('contextmenus/airbase.ejs') %>
|
||||
|
||||
10
client/views/panels/unitlist.ejs
Normal file
10
client/views/panels/unitlist.ejs
Normal file
@@ -0,0 +1,10 @@
|
||||
<div id="unit-list-panel" class="ol-panel hide">
|
||||
<h3>Unit List</h3>
|
||||
<div class="unit-list-unit headers">
|
||||
<div data-sort-field="unitName">Name</div>
|
||||
<div data-sort-field="name">Vehicle</div>
|
||||
<div data-sort-field="coalition">Coalition</div>
|
||||
<div>Human/AI</div>
|
||||
</div>
|
||||
<div id="unit-list-panel-content" class="ol-scrollable"></div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user