More work on database manager

This commit is contained in:
Pax1601 2023-09-25 17:35:17 +02:00
parent 099cbfdf75
commit e9100504a0
6 changed files with 421 additions and 112 deletions

View File

@ -1,41 +1,75 @@
import { LoadoutBlueprint, UnitBlueprint } from "interfaces";
import { UnitEditor } from "./uniteditor";
import { LoadoutEditor } from "./loadouteditor";
import { addDropdownInput, addLoadoutsScroll, addNewElementInput, addStringInput } from "./utils";
export class AirUnitEditor extends UnitEditor {
#blueprint: UnitBlueprint | null = null;
#loadoutEditor: LoadoutEditor | null = null;
constructor(scrollDiv: HTMLElement, contentDiv1: HTMLElement, contentDiv2: HTMLElement) {
super(scrollDiv, contentDiv1, contentDiv2);
this.#loadoutEditor = new LoadoutEditor(this.contentDiv2);
}
setContent(blueprint: UnitBlueprint) {
this.contentDiv1.replaceChildren();
constructor(contentDiv1: HTMLElement, contentDiv2: HTMLElement, contentDiv3: HTMLElement) {
super(contentDiv1, contentDiv2, contentDiv3);
this.#loadoutEditor = new LoadoutEditor(this.contentDiv3);
this.contentDiv2.addEventListener("refresh", () => {
if (this.#blueprint !== null)
this.setBlueprint(this.#blueprint);
});
this.addStringInput("Name", blueprint.name);
this.addStringInput("Label", blueprint.label);
this.addStringInput("Short label", blueprint.shortLabel);
this.addDropdownInput("Coalition", blueprint.coalition, ["", "blue", "red"]);
this.addDropdownInput("Era", blueprint.era, ["WW2", "Early Cold War", "Mid Cold War", "Late Cold War", "Modern"]);
this.addStringInput("Filename", blueprint.filename?? "");
this.addStringInput("Cost", String(blueprint.cost)?? "", "number");
this.addLoadoutList(blueprint.loadouts?? []);
this.contentDiv3.addEventListener("refresh", () => {
if (this.#blueprint !== null)
this.setBlueprint(this.#blueprint);
this.#loadoutEditor?.show();
});
}
addLoadoutList(loadouts: LoadoutBlueprint[]) {
var loadoutsEl = document.createElement("div");
loadoutsEl.classList.add("dc-scroll-container", "dc-loadout-container")
loadouts.forEach((loadout: LoadoutBlueprint) => {
var div = document.createElement("div");
loadoutsEl.appendChild(div);
div.textContent = loadout.name;
div.onclick = () => {
setBlueprint(blueprint: UnitBlueprint) {
this.#blueprint = blueprint;
if (this.#blueprint !== null) {
this.contentDiv2.replaceChildren();
addStringInput(this.contentDiv2, "Name", blueprint.name, "text", (value: string) => {blueprint.name = value; }, true);
addStringInput(this.contentDiv2, "Label", blueprint.label, "text", (value: string) => {blueprint.label = value; });
addStringInput(this.contentDiv2, "Short label", blueprint.shortLabel, "text", (value: string) => {blueprint.shortLabel = value; });
addDropdownInput(this.contentDiv2, "Coalition", blueprint.coalition, ["", "blue", "red"],);
addDropdownInput(this.contentDiv2, "Era", blueprint.era, ["WW2", "Early Cold War", "Mid Cold War", "Late Cold War", "Modern"]);
addStringInput(this.contentDiv2, "Filename", blueprint.filename?? "", "text", (value: string) => {blueprint.filename = value; });
addStringInput(this.contentDiv2, "Cost", String(blueprint.cost)?? "", "number", (value: string) => {blueprint.cost = parseFloat(value); });
addLoadoutsScroll(this.contentDiv2, blueprint.loadouts?? [], (loadout: LoadoutBlueprint) => {
this.#loadoutEditor?.setLoadout(loadout);
this.#loadoutEditor?.show();
};
});
this.contentDiv1.appendChild(loadoutsEl);
});
addNewElementInput(this.contentDiv2, (ev: MouseEvent, input: HTMLInputElement) => { this.addLoadout(input.value); });
this.#loadoutEditor?.hide();
}
}
addBlueprint(key: string) {
if (this.database != null) {
this.database.blueprints[key] = {
name: key,
coalition: "",
label: "",
shortLabel: "",
era: "",
loadouts: []
}
this.show();
this.setBlueprint(this.database.blueprints[key]);
}
}
addLoadout(loadoutName: string) {
if (loadoutName && this.#blueprint !== null) {
this.#blueprint.loadouts?.push({
name: loadoutName,
code: "",
fuel: 1,
items: [],
roles: []
})
this.setBlueprint(this.#blueprint);
}
}
}

View File

@ -6,11 +6,13 @@ export class DatabaseManagerPlugin implements OlympusPlugin {
#app: OlympusApp | null = null;
#element: HTMLElement;
#scrollDiv: HTMLElement;
#container: HTMLElement;
#contentDiv1: HTMLElement;
#contentDiv2: HTMLElement;
#contentDiv3: HTMLElement;
#aircraftEditor: AirUnitEditor;
#helicopterEditor: AirUnitEditor;
constructor() {
this.#element = document.createElement("div");
@ -19,19 +21,46 @@ export class DatabaseManagerPlugin implements OlympusPlugin {
this.#element.classList.add("ol-dialog");
document.body.appendChild(this.#element);
this.#scrollDiv = document.createElement("div");
this.#scrollDiv.classList.add("dc-scroll-container");
this.#element.appendChild(this.#scrollDiv);
let buttonContainer = document.createElement("div");
let button1 = document.createElement("button");
button1.textContent = "Aircraft";
button1.onclick = () => this.#aircraftEditor.show();
buttonContainer.appendChild(button1);
let button2 = document.createElement("button");
button2.textContent = "Helicopter";
button2.onclick = () => this.#helicopterEditor.show();
buttonContainer.appendChild(button2);
let button3 = document.createElement("button");
button3.textContent = "Ground Unit";
buttonContainer.appendChild(button3);
let button4 = document.createElement("button");
button4.textContent = "Navy Unit";
buttonContainer.appendChild(button4);
this.#element.appendChild(buttonContainer);
this.#container = document.createElement("div");
this.#container.classList.add("dc-container");
this.#element.appendChild(this.#container)
this.#contentDiv1 = document.createElement("div");
this.#contentDiv1.classList.add("dc-content-container");
this.#element.appendChild(this.#contentDiv1);
this.#container.appendChild(this.#contentDiv1);
this.#contentDiv2 = document.createElement("div");
this.#contentDiv2.classList.add("dc-content-container");
this.#element.appendChild(this.#contentDiv2);
this.#container.appendChild(this.#contentDiv2);
this.#aircraftEditor = new AirUnitEditor(this.#scrollDiv, this.#contentDiv1, this.#contentDiv2);
this.#contentDiv3 = document.createElement("div");
this.#contentDiv3.classList.add("dc-content-container");
this.#container.appendChild(this.#contentDiv3);
this.#aircraftEditor = new AirUnitEditor(this.#contentDiv1, this.#contentDiv2, this.#contentDiv3);
this.#helicopterEditor = new AirUnitEditor(this.#contentDiv1, this.#contentDiv2, this.#contentDiv3);
}
getName() {
@ -44,7 +73,11 @@ export class DatabaseManagerPlugin implements OlympusPlugin {
var aircraftDatabase = this.#app?.getAircraftDatabase();
if (aircraftDatabase != null) {
this.#aircraftEditor.setDatabase(aircraftDatabase);
this.#aircraftEditor.show();
}
var helicopterDatabase = this.#app?.getHelicopterDatabase();
if (helicopterDatabase != null) {
this.#helicopterEditor.setDatabase(helicopterDatabase);
}
return true;

View File

@ -1,4 +1,5 @@
import { LoadoutBlueprint, LoadoutItemBlueprint } from "interfaces";
import { addLoadoutItemsEditor, addStringInput } from "./utils";
export class LoadoutEditor {
#contentDiv: HTMLElement;
@ -6,6 +7,7 @@ export class LoadoutEditor {
constructor(contentDiv: HTMLElement) {
this.#contentDiv = contentDiv;
this.#contentDiv.addEventListener("refresh", () => { this.show(); })
}
setLoadout(loadout: LoadoutBlueprint) {
@ -16,30 +18,14 @@ export class LoadoutEditor {
this.#contentDiv.replaceChildren();
if (this.#loadout) {
this.addStringInput("Name", this.#loadout.name);
this.addStringInput("Code", this.#loadout.code);
var itemsEl = document.createElement("div");
itemsEl.classList.add("dc-scroll-container", "dc-items-container");
this.#loadout.items.forEach((item: LoadoutItemBlueprint) => {
var div = document.createElement("div");
itemsEl.appendChild(div);
div.textContent = item.name;
})
this.#contentDiv.appendChild(itemsEl);
var laodout = this.#loadout;
addStringInput(this.#contentDiv, "Name", laodout.name, "text", (value: string) => {laodout.name = value; this.#contentDiv.dispatchEvent(new Event("refresh"));});
addStringInput(this.#contentDiv, "Code", laodout.code, "text", (value: string) => {laodout.code = value; });
addLoadoutItemsEditor(this.#contentDiv, this.#loadout);
}
}
addStringInput(key: string, value: string, type?: string) {
var dt = document.createElement("dt");
var dd = document.createElement("dd");
dt.innerText = key;
var input = document.createElement("input");
input.value = value;
input.textContent = value;
input.type = type?? "text";
dd.appendChild(input);
this.#contentDiv.appendChild(dt);
this.#contentDiv.appendChild(dd);
hide() {
this.#contentDiv.replaceChildren();
}
}

View File

@ -1,65 +1,47 @@
import { LoadoutBlueprint, UnitBlueprint } from "interfaces";
import { UnitDatabase } from "unit/databases/unitdatabase";
import { addBlueprintsScroll, addNewElementInput } from "./utils";
export abstract class UnitEditor {
database: UnitDatabase | null = null;
scrollDiv: HTMLElement;
database: {blueprints: {[key: string]: UnitBlueprint}} | null = null;
contentDiv1: HTMLElement;
contentDiv2: HTMLElement;
contentDiv3: HTMLElement;
constructor(scrollDiv: HTMLElement, contentDiv1: HTMLElement, contentDiv2: HTMLElement) {
this.scrollDiv = scrollDiv;
constructor(contentDiv1: HTMLElement, contentDiv2: HTMLElement, contentDiv3: HTMLElement) {
this.contentDiv1 = contentDiv1;
this.contentDiv2 = contentDiv2;
this.contentDiv3 = contentDiv3;
this.contentDiv1.addEventListener("refresh", () => { this.show(); })
}
setDatabase(database: any) {
this.database = database;
setDatabase(database: UnitDatabase) {
this.database = JSON.parse(JSON.stringify(database));
}
show() {
if (this.database !== null) {
var blueprints: {[key: string]: UnitBlueprint} = this.database.getBlueprints();
this.contentDiv1.replaceChildren();
this.contentDiv2.replaceChildren();
this.contentDiv3.replaceChildren();
for (let key in blueprints) {
var div = document.createElement("div");
this.scrollDiv.appendChild(div);
div.textContent = key;
div.onclick = () => this.setContent(blueprints[key]);
}
if (this.database != null) {
addBlueprintsScroll(this.contentDiv1, this.database, (key: string) => {
if (this.database != null)
this.setBlueprint(this.database.blueprints[key])
})
addNewElementInput(this.contentDiv1, (ev: MouseEvent, input: HTMLInputElement) => {
if (input.value != "")
this.addBlueprint((input).value);
});
}
}
addStringInput(key: string, value: string, type?: string) {
var dt = document.createElement("dt");
var dd = document.createElement("dd");
dt.innerText = key;
var input = document.createElement("input");
input.value = value;
input.textContent = value;
input.type = type?? "text";
dd.appendChild(input);
this.contentDiv1.appendChild(dt);
this.contentDiv1.appendChild(dd);
hide() {
this.contentDiv1.replaceChildren();
this.contentDiv2.replaceChildren();
this.contentDiv3.replaceChildren();
}
addDropdownInput(key: string, value: string, options: string[]) {
var dt = document.createElement("dt");
var dd = document.createElement("dd");
dt.innerText = key;
var select = document.createElement("select");
options.forEach((option: string) => {
var el = document.createElement("option");
el.value = option;
el.innerText = option;
select.appendChild(el);
});
select.value = value;
dd.appendChild(select);
this.contentDiv1.appendChild(dt);
this.contentDiv1.appendChild(dd);
}
abstract setContent(blueprint: UnitBlueprint): void;
abstract setBlueprint(blueprint: UnitBlueprint): void;
abstract addBlueprint(key: string): void;
}

View File

@ -0,0 +1,161 @@
import { LoadoutBlueprint, LoadoutItemBlueprint, UnitBlueprint } from "interfaces";
export function addStringInput(div: HTMLElement, key: string, value: string, type: string, callback: CallableFunction, disabled?: boolean) {
var row = document.createElement("div");
var dt = document.createElement("dt");
var dd = document.createElement("dd");
dt.innerText = key;
var input = document.createElement("input");
input.value = value;
input.textContent = value;
input.type = type?? "text";
input.disabled = disabled?? false;
input.onchange = () => callback(input.value);
dd.appendChild(input);
row.appendChild(dt);
row.appendChild(dd);
row.classList.add("input-row");
div.appendChild(row);
}
export function addDropdownInput(div: HTMLElement, key: string, value: string, options: string[]) {
var row = document.createElement("div");
var dt = document.createElement("dt");
var dd = document.createElement("dd");
dt.innerText = key;
var select = document.createElement("select");
options.forEach((option: string) => {
var el = document.createElement("option");
el.value = option;
el.innerText = option;
select.appendChild(el);
});
select.value = value;
dd.appendChild(select);
row.appendChild(dt);
row.appendChild(dd);
row.classList.add("input-row");
div.appendChild(row);
}
export function addLoadoutItemsEditor(div: HTMLElement, loadout: LoadoutBlueprint) {
var itemsEl = document.createElement("div");
itemsEl.classList.add("dc-scroll-container", "dc-items-container");
loadout.items.forEach((item: LoadoutItemBlueprint, index: number) => {
var rowDiv = document.createElement("div");
var nameLabel = document.createElement("label");
nameLabel.innerText = "Name"
rowDiv.appendChild(nameLabel);
var nameInput = document.createElement("input");
rowDiv.appendChild(nameInput);
nameInput.textContent = item.name;
nameInput.value = item.name
nameInput.onchange = () => { loadout.items[index].name = nameInput.value; }
var quantityLabel = document.createElement("label");
quantityLabel.innerText = "Quantity"
rowDiv.appendChild(quantityLabel);
var quantityInput = document.createElement("input");
rowDiv.appendChild(quantityInput);
quantityInput.textContent = String(item.quantity);
quantityInput.value = String(item.quantity);
quantityInput.type = "number";
quantityInput.step = "1";
quantityInput.onchange = () => { loadout.items[index].quantity = parseInt(quantityInput.value); }
var button = document.createElement("button");
button.innerText = "X";
button.onclick = () => {
loadout.items.splice(index, 1);
div.dispatchEvent(new Event("refresh"));
}
rowDiv.appendChild(button);
itemsEl.appendChild(rowDiv);
})
div.appendChild(itemsEl);
var inputDiv = document.createElement("div");
inputDiv.classList.add("dc-new-item-input");
var button = document.createElement("button");
button.innerText = "Add";
inputDiv.appendChild(button);
div.appendChild(inputDiv);
button.addEventListener("click", (ev: MouseEvent) => {
loadout?.items.push({
name: "",
quantity: 1
})
div.dispatchEvent(new Event("refresh"));
});
}
export function addNewElementInput(div: HTMLElement, callback: CallableFunction) {
var inputDiv = document.createElement("div");
inputDiv.classList.add("dc-new-element-input");
var input = document.createElement("input");
inputDiv.appendChild(input);
var button = document.createElement("button");
button.innerText = "Add";
button.addEventListener("click", (ev: MouseEvent) => callback(ev, input));
inputDiv.appendChild(button);
div.appendChild(inputDiv);
}
export function addBlueprintsScroll(div: HTMLElement, database: {blueprints: {[key: string]: UnitBlueprint}}, callback: CallableFunction) {
var scrollDiv = document.createElement("div");
scrollDiv.classList.add("dc-scroll-container");
if (database !== null) {
var blueprints: {[key: string]: UnitBlueprint} = database.blueprints;
for (let key in blueprints) {
var rowDiv = document.createElement("div");
scrollDiv.appendChild(rowDiv);
var text = document.createElement("label");
text.textContent = key;
text.onclick = () => callback(key);
rowDiv.appendChild(text);
var button = document.createElement("button");
button.innerText = "X";
button.onclick = () => {
delete blueprints[key];
div.dispatchEvent(new Event("refresh"));
}
rowDiv.appendChild(button);
}
}
div.appendChild(scrollDiv);
}
export function addLoadoutsScroll(div: HTMLElement, loadouts: LoadoutBlueprint[], callback: CallableFunction) {
var loadoutsEl = document.createElement("div");
loadoutsEl.classList.add("dc-scroll-container", "dc-loadout-container")
loadouts.forEach((loadout: LoadoutBlueprint, index: number) => {
var rowDiv = document.createElement("div");
loadoutsEl.appendChild(rowDiv);
var text = document.createElement("label");
text.textContent = loadout.name;
text.onclick = () => { callback(loadout) };
rowDiv.appendChild(text);
if (loadout.name !== "Empty loadout") {
var button = document.createElement("button");
button.innerText = "X";
button.onclick = () => {
loadouts.splice(index, 1);
div.dispatchEvent(new Event("refresh"));
}
rowDiv.appendChild(button);
}
});
div.appendChild(loadoutsEl);
}

View File

@ -1,17 +1,53 @@
#database-control-panel {
display: flex;
flex-direction: row;
flex-direction: column;
width: 80%;
height: 80%;
padding: 10px;
}
#database-control-panel * {
font-size: 13;
font-weight: bold;
}
#database-control-panel>div:first-child {
display: flex;
column-gap: 2px;
align-items: center;
}
.dc-container {
display: flex;
flex-direction: row;
width: 100%;
height: 100%;
padding: 10px;
}
.dc-container>div {
min-width: 200px;
width: fit-content;
margin: 10px;
}
.dc-container>div:nth-child(3) {
flex: 1;
}
.dc-scroll-container {
overflow-y: scroll;
display: flex;
flex-direction: column;
overflow-y: auto;
max-height: 600px;
margin: 10px;
color: black;
font-weight: bold;
}
.dc-scroll-container>* {
padding: 2px;
}
.dc-scroll-container>div:nth-child(even) {
background-color: gainsboro;
}
@ -20,26 +56,103 @@
background-color: white;
}
.dc-scroll-container>div:hover{
.dc-scroll-container>div *:nth-child(1) {
height: 100%;
width: 100%;
}
.dc-scroll-container>div *:nth-child(1):hover{
background-color: var(--secondary-blue-text);
color: white;
cursor: pointer;
}
.dc-content-container {
margin: 10px;
.dc-scroll-container>div {
display: flex;
align-items: center;
justify-content: space-between;
}
.dc-content-container>dd>input {
.dc-scroll-container>div>button {
height: 20px;
width: 20px;
padding: 0px;
}
.dc-content-container {
margin: 10px;
display: flex;
flex-direction: column;
row-gap: 5px;
}
.input-row {
width: 100%;
display: flex;
flex-direction: row;
}
.input-row>dt {
width: 150px;
}
.input-row>dd {
width: 100%;
}
.input-row>dd>* {
width: 100%;
font-weight: bold;
}
.dc-loadout-container {
max-height: 200px;
width: 300px;
max-height: 100%;
width: 400px;
}
.dc-items-container {
max-height: 200px;
max-height: 100%;
height: fit-content;
}
.dc-items-container>div {
display: flex;
align-items: center;
column-gap: 2px;
}
.dc-items-container>div>label {
width: 80px !important;
}
.dc-items-container div>input:nth-of-type(1) {
width: 100%;
}
.dc-items-container div>input:nth-of-type(2) {
width: 40px;
}
.dc-new-element-input {
display: flex;
flex-direction: row;
column-gap: 2px;
width: 100%;
align-items: center;
}
.dc-new-element-input>input {
width: 100%;
}
.dc-new-element-input>button {
width: 60px;
}
.dc-new-item-input {
display: flex;
justify-content: end;
}
.dc-new-item-input>button {
width: 60px;
}