From 72c6e4e94eb02f3e45751ab93aa6653874acff18 Mon Sep 17 00:00:00 2001 From: PeekabooSteam Date: Sat, 30 Sep 2023 22:33:47 +0100 Subject: [PATCH] Using proper add and not being lazy --- client/public/stylesheets/panels/unitlist.css | 55 ++++++ client/src/panels/unitlistpanel.ts | 182 ++++++++++++++++++ client/views/panels/unitlist.ejs | 10 + 3 files changed, 247 insertions(+) create mode 100644 client/public/stylesheets/panels/unitlist.css create mode 100644 client/src/panels/unitlistpanel.ts create mode 100644 client/views/panels/unitlist.ejs diff --git a/client/public/stylesheets/panels/unitlist.css b/client/public/stylesheets/panels/unitlist.css new file mode 100644 index 00000000..c87f0ef6 --- /dev/null +++ b/client/public/stylesheets/panels/unitlist.css @@ -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; +} \ No newline at end of file diff --git a/client/src/panels/unitlistpanel.ts b/client/src/panels/unitlistpanel.ts new file mode 100644 index 00000000..6132cf9d --- /dev/null +++ b/client/src/panels/unitlistpanel.ts @@ -0,0 +1,182 @@ +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; + + 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": "Quote" + }); + + this.startUpdates(); + + } + + doUpdate() { + + if ( !this.getVisible() ) { + return; + } + + this.#contentElement.innerHTML = ""; + + this.#units = Object.values( this.#olympusApp.getUnitsManager().getUnits() ); + + + if ( this.#currentSortAlgorithm === "unitName" ) { + this.#sortUnitsByUnitName(); + } + + if ( this.#currentSortAlgorithm === "name" ) { + this.#sortUnitsByName(); + } + + + Object.values( this.#units ).forEach( ( unit:Unit ) => { + + // Exclude dead units + if ( !unit.getAlive() ) { + return; + } + + this.#contentElement.innerHTML += ` +
+
${unit.getUnitName()}
+
${unit.getName()}
+
${unit.getCoalition()}
+
${unit.getHuman() ? "Human" : "AI"}
+
`; + + }); + + } + + 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 ); + }); + + } + + #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(); + + } +} diff --git a/client/views/panels/unitlist.ejs b/client/views/panels/unitlist.ejs new file mode 100644 index 00000000..0c0085e3 --- /dev/null +++ b/client/views/panels/unitlist.ejs @@ -0,0 +1,10 @@ +
+

Unit List

+
+
Name
+
Vehicle
+
Coalition
+
Human/AI
+
+
+
\ No newline at end of file