mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
Added a selective interface for import and export
This commit is contained in:
parent
b89c5142b6
commit
210c1fbecf
@ -759,20 +759,6 @@ nav.ol-panel> :last-child {
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
#unit-import-export-dialog th {
|
||||
padding:4px 8px;
|
||||
}
|
||||
|
||||
#unit-import-export-dialog tr :first-child {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#unit-import-export-dialog td {
|
||||
color:white;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
#splash-screen {
|
||||
border-radius: var(--border-radius-md);
|
||||
overflow: hidden;
|
||||
@ -1306,6 +1292,10 @@ dl.ol-data-grid dd {
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.ol-checkbox input[type="checkbox"]:disabled:before {
|
||||
opacity: 10%;
|
||||
}
|
||||
|
||||
.ol-checkbox input[type="checkbox"]:checked::before {
|
||||
background-image: url("/resources/theme/images/icons/square-check-solid.svg");
|
||||
}
|
||||
@ -1516,3 +1506,50 @@ input[type=number]::-webkit-outer-spin-button {
|
||||
.ol-log-entry {
|
||||
border-bottom: 1px solid #FFFFFF44;
|
||||
}
|
||||
|
||||
.file-import-export {
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
.file-import-export .ol-dialog-content {
|
||||
display:flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.file-import-export p {
|
||||
background-color: var(--background-grey);
|
||||
border-left:6px solid var(--secondary-blue-text);
|
||||
padding:12px;
|
||||
}
|
||||
|
||||
.file-import-export th {
|
||||
padding:4px 6px;
|
||||
}
|
||||
|
||||
.file-import-export tr td:first-child {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.file-import-export td {
|
||||
color:white;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.file-import-export .ol-checkbox {
|
||||
display:flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.file-import-export .ol-checkbox input::before {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.file-import-export .ol-checkbox span {
|
||||
display:none;
|
||||
}
|
||||
|
||||
.file-import-export button.start-transfer {
|
||||
background-color: var(--secondary-blue-text);
|
||||
border-color: var(--secondary-blue-text);
|
||||
}
|
||||
@ -434,14 +434,24 @@ export function convertDateAndTimeToDate(dateAndTime: DateAndTime) {
|
||||
return new Date(year, month, date.Day, time.h, time.m, time.s);
|
||||
}
|
||||
|
||||
export function createCheckboxOption(value: string, text: string, checked: boolean = true, callback: CallableFunction = (ev: any) => {}) {
|
||||
export function createCheckboxOption(value: string, text: string, checked: boolean = true, callback: CallableFunction = (ev: any) => {}, options?:any) {
|
||||
options = {
|
||||
"disabled": false,
|
||||
"name": "",
|
||||
"readOnly": false,
|
||||
...options
|
||||
};
|
||||
var div = document.createElement("div");
|
||||
div.classList.add("ol-checkbox");
|
||||
var label = document.createElement("label");
|
||||
label.title = text;
|
||||
var input = document.createElement("input");
|
||||
input.type = "checkbox";
|
||||
input.checked = checked;
|
||||
input.checked = checked;
|
||||
input.name = options.name;
|
||||
input.disabled = options.disabled;
|
||||
input.readOnly = options.readOnly;
|
||||
input.value = value;
|
||||
var span = document.createElement("span");
|
||||
span.innerText = value;
|
||||
label.appendChild(input);
|
||||
|
||||
@ -1,3 +1,58 @@
|
||||
import { Dialog } from "../dialog/dialog";
|
||||
import { createCheckboxOption } from "../other/utils";
|
||||
|
||||
export abstract class UnitDataFile {
|
||||
|
||||
protected data:any;
|
||||
protected dialog!:Dialog;
|
||||
|
||||
constructor() {}
|
||||
|
||||
buildCategoryCoalitionTable() {
|
||||
|
||||
const categories = this.#getCategoriesFromData();
|
||||
const coalitions = ["blue", "neutral", "red"];
|
||||
|
||||
let headersHTML:string = ``;
|
||||
let matrixHTML:string = ``;
|
||||
|
||||
categories.forEach((category:string, index) => {
|
||||
matrixHTML += `<tr><td>${category}</td>`;
|
||||
|
||||
coalitions.forEach((coalition:string) => {
|
||||
if (index === 0)
|
||||
headersHTML += `<th data-coalition="${coalition}">${coalition[0].toUpperCase()+coalition.substring(1)}</th>`;
|
||||
|
||||
const optionIsValid = this.data[category].hasOwnProperty(coalition);
|
||||
let checkboxHTML = createCheckboxOption(`${category}:${coalition}`, category, optionIsValid, () => {}, {
|
||||
"disabled": !optionIsValid,
|
||||
"name": "category-coalition-selection",
|
||||
"readOnly": !optionIsValid
|
||||
}).outerHTML;
|
||||
|
||||
if (optionIsValid)
|
||||
checkboxHTML = checkboxHTML.replace( `"checkbox"`, `"checkbox" checked`); // inner and outerHTML screw default checked up
|
||||
|
||||
matrixHTML += `<td data-coalition="${coalition}">${checkboxHTML}</td>`;
|
||||
|
||||
});
|
||||
matrixHTML += "</tr>";
|
||||
});
|
||||
|
||||
const table = <HTMLTableElement>this.dialog.getElement().querySelector("table.categories-coalitions");
|
||||
|
||||
(<HTMLElement>table.tHead).innerHTML = `<tr><td> </td>${headersHTML}</tr>`;
|
||||
(<HTMLElement>table.querySelector(`tbody`)).innerHTML = matrixHTML;
|
||||
|
||||
}
|
||||
|
||||
#getCategoriesFromData() {
|
||||
const categories = Object.keys(this.data);
|
||||
categories.sort();
|
||||
return categories;
|
||||
}
|
||||
|
||||
getData() {
|
||||
return this.data;
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,4 @@
|
||||
import { getApp } from "..";
|
||||
import { GROUND_UNIT_AIR_DEFENCE_REGEX } from "../constants/constants";
|
||||
import { Dialog } from "../dialog/dialog";
|
||||
import { zeroAppend } from "../other/utils";
|
||||
import { Unit } from "./unit";
|
||||
@ -7,20 +6,16 @@ import { UnitDataFile } from "./unitdatafile";
|
||||
|
||||
export class UnitDataFileExport extends UnitDataFile {
|
||||
|
||||
#data!:any;
|
||||
#dialog:Dialog;
|
||||
protected data!:any;
|
||||
protected dialog:Dialog;
|
||||
#element!:HTMLElement;
|
||||
#categoryCoalitionHeaders!: HTMLElement;
|
||||
#categoryCoalitionMatrix!: HTMLElement;
|
||||
|
||||
constructor( elementId:string ) {
|
||||
super();
|
||||
this.#dialog = new Dialog(elementId);
|
||||
this.#element = this.#dialog.getElement();
|
||||
this.#categoryCoalitionMatrix = <HTMLElement>this.#element.querySelector("tbody");
|
||||
this.#categoryCoalitionHeaders = <HTMLElement>this.#element.querySelector("thead");
|
||||
this.dialog = new Dialog(elementId);
|
||||
this.#element = this.dialog.getElement();
|
||||
|
||||
this.#element.querySelector(".start-transfer.export")?.addEventListener("click", (ev:MouseEventInit) => {
|
||||
this.#element.querySelector(".start-transfer")?.addEventListener("click", (ev:MouseEventInit) => {
|
||||
this.#doExport();
|
||||
});
|
||||
}
|
||||
@ -28,56 +23,27 @@ export class UnitDataFileExport extends UnitDataFile {
|
||||
/**
|
||||
* Show the form to start the export journey
|
||||
*/
|
||||
showForm(units:Unit[]) {
|
||||
this.#element.setAttribute( "data-mode", "export" );
|
||||
|
||||
showForm(units:Unit[]) {
|
||||
const data:any = {};
|
||||
const categories:string[] = [];
|
||||
const coalitions:string[] = [];
|
||||
const unitCanBeExported = (unit:Unit) => !["Aircraft", "Helicopter"].includes(unit.getCategory());
|
||||
|
||||
units.filter((unit:Unit) => unit.getAlive() && unitCanBeExported(unit)).forEach((unit:Unit) => {
|
||||
const category = unit.getCategoryLabel();
|
||||
const category = unit.getCategory();
|
||||
const coalition = unit.getCoalition();
|
||||
|
||||
if (!coalitions.includes(coalition))
|
||||
coalitions.push(coalition);
|
||||
|
||||
if (!data.hasOwnProperty(category)) {
|
||||
data[category] = {};
|
||||
categories.push(category);
|
||||
}
|
||||
|
||||
// Cache unit data
|
||||
if (!data[category].hasOwnProperty(coalition))
|
||||
data[category][coalition] = [];
|
||||
|
||||
data[category][coalition].push(unit);
|
||||
});
|
||||
|
||||
this.#data = data;
|
||||
|
||||
categories.sort();
|
||||
coalitions.sort();
|
||||
|
||||
let headersHTML:string = ``;
|
||||
let matrixHTML:string = ``;
|
||||
|
||||
categories.forEach((category:string, index) => {
|
||||
matrixHTML += `<tr><td>${category}</td>`;
|
||||
|
||||
coalitions.forEach((coalition:string) => {
|
||||
if (index === 0)
|
||||
headersHTML += `<th data-coalition="${coalition}">${coalition}</th>`;
|
||||
matrixHTML += `<td data-coalition="${coalition}"><input type="checkbox" name="category-coalition-selection" value="${category}:${coalition}" ${(data[category].hasOwnProperty(coalition)) ? "checked": "disabled readonly"} /></td>`;
|
||||
});
|
||||
|
||||
matrixHTML += "</tr>";
|
||||
});
|
||||
|
||||
this.#categoryCoalitionHeaders.innerHTML = `<tr><td> </td>${headersHTML}</tr>`;
|
||||
this.#categoryCoalitionMatrix.innerHTML = matrixHTML;
|
||||
this.#dialog.show();
|
||||
this.data = data;
|
||||
this.buildCategoryCoalitionTable();
|
||||
this.dialog.show();
|
||||
}
|
||||
|
||||
#doExport() {
|
||||
@ -87,7 +53,7 @@ export class UnitDataFileExport extends UnitDataFile {
|
||||
this.#element.querySelectorAll(`input[type="checkbox"][name="category-coalition-selection"]:checked`).forEach(<HTMLInputElement>(checkbox:HTMLInputElement) => {
|
||||
if (checkbox instanceof HTMLInputElement) {
|
||||
const [category, coalition] = checkbox.value.split(":"); // e.g. "category:coalition"
|
||||
selectedUnits = selectedUnits.concat(this.#data[category][coalition]);
|
||||
selectedUnits = selectedUnits.concat(this.data[category][coalition]);
|
||||
}
|
||||
});
|
||||
|
||||
@ -111,7 +77,7 @@ export class UnitDataFileExport extends UnitDataFile {
|
||||
a.href = URL.createObjectURL(file);
|
||||
a.download = `olympus_${getApp().getMissionManager().getTheatre().replace( /[^\w]/gi, "" ).toLowerCase()}_${date.getFullYear()}${zeroAppend(date.getMonth()+1, 2)}${zeroAppend(date.getDate(), 2)}_${zeroAppend(date.getHours(), 2)}${zeroAppend(date.getMinutes(), 2)}${zeroAppend(date.getSeconds(), 2)}.json`;
|
||||
a.click();
|
||||
this.#dialog.hide();
|
||||
this.dialog.hide();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,43 +1,110 @@
|
||||
import { getApp } from "..";
|
||||
import { GROUND_UNIT_AIR_DEFENCE_REGEX } from "../constants/constants";
|
||||
import { Dialog } from "../dialog/dialog";
|
||||
import { zeroAppend } from "../other/utils";
|
||||
import { Unit } from "./unit";
|
||||
import { UnitData } from "../interfaces";
|
||||
import { UnitDataFile } from "./unitdatafile";
|
||||
|
||||
export class UnitDataFileImport extends UnitDataFile {
|
||||
|
||||
#data!:any;
|
||||
#dialog:Dialog;
|
||||
#element!:HTMLElement;
|
||||
#categoryCoalitionHeaders!: HTMLElement;
|
||||
#categoryCoalitionMatrix!: HTMLElement;
|
||||
protected data!:any;
|
||||
protected dialog:Dialog;
|
||||
#fileData!:{[key:string]: UnitData[]};
|
||||
|
||||
constructor( elementId:string ) {
|
||||
super();
|
||||
this.#dialog = new Dialog(elementId);
|
||||
this.#element = this.#dialog.getElement();
|
||||
this.#categoryCoalitionMatrix = <HTMLElement>this.#element.querySelector("tbody");
|
||||
this.#categoryCoalitionHeaders = <HTMLElement>this.#element.querySelector("thead");
|
||||
|
||||
// this.#element.querySelector(".start-transfer.import")?.addEventListener("click", (ev:MouseEventInit) => {
|
||||
// this.#doImport();
|
||||
// });
|
||||
this.dialog = new Dialog(elementId);
|
||||
this.dialog.getElement().querySelector(".start-transfer")?.addEventListener("click", (ev:MouseEventInit) => {
|
||||
this.#doImport();
|
||||
this.dialog.hide();
|
||||
});
|
||||
}
|
||||
|
||||
#doImport() {
|
||||
|
||||
/*
|
||||
for (let groupName in groups) {
|
||||
if (groupName !== "" && groups[groupName].length > 0 && (groups[groupName].every((unit: UnitData) => { return unit.category == "GroundUnit"; }) || groups[groupName].every((unit: any) => { return unit.category == "NavyUnit"; }))) {
|
||||
var aliveUnits = groups[groupName].filter((unit: UnitData) => { return unit.alive });
|
||||
var units = aliveUnits.map((unit: UnitData) => {
|
||||
return { unitType: unit.name, location: unit.position, liveryID: "" }
|
||||
});
|
||||
getApp().getUnitsManager().spawnUnits(groups[groupName][0].category, units, groups[groupName][0].coalition, true);
|
||||
}
|
||||
}
|
||||
//*/
|
||||
|
||||
let selectedCategories:any = {};
|
||||
const unitsManager = getApp().getUnitsManager();
|
||||
|
||||
this.dialog.getElement().querySelectorAll(`input[type="checkbox"][name="category-coalition-selection"]:checked`).forEach(<HTMLInputElement>(checkbox:HTMLInputElement) => {
|
||||
if (checkbox instanceof HTMLInputElement) {
|
||||
const [category, coalition] = checkbox.value.split(":"); // e.g. "category:coalition"
|
||||
selectedCategories[category] = selectedCategories[category] || {};
|
||||
selectedCategories[category][coalition] = true;
|
||||
}
|
||||
});
|
||||
|
||||
for (const[groupName, groupData] of Object.entries(this.#fileData)) {
|
||||
if (groupName === "" || groupData.length === 0 || !this.#unitGroupDataCanBeImported(groupData))
|
||||
continue;
|
||||
|
||||
let { category, coalition } = groupData[0];
|
||||
|
||||
if (!selectedCategories.hasOwnProperty(category)
|
||||
|| !selectedCategories[category].hasOwnProperty(coalition)
|
||||
|| selectedCategories[category][coalition] !== true )
|
||||
continue;
|
||||
|
||||
let unitsToSpawn = groupData.filter((unitData:UnitData) => this.#unitDataCanBeImported(unitData)).map((unitData:UnitData) => {
|
||||
return { unitType: unitData.name, location: unitData.position, liveryID: "" }
|
||||
});
|
||||
|
||||
unitsManager.spawnUnits(category, unitsToSpawn, coalition, true);
|
||||
}
|
||||
|
||||
/*
|
||||
for (let groupName in groups) {
|
||||
if (groupName !== "" && groups[groupName].length > 0 && (groups[groupName].every((unit: UnitData) => { return unit.category == "GroundUnit"; }) || groups[groupName].every((unit: any) => { return unit.category == "NavyUnit"; }))) {
|
||||
var aliveUnits = groups[groupName].filter((unit: UnitData) => { return unit.alive });
|
||||
var units = aliveUnits.map((unit: UnitData) => {
|
||||
return { unitType: unit.name, location: unit.position, liveryID: "" }
|
||||
});
|
||||
getApp().getUnitsManager().spawnUnits(groups[groupName][0].category, units, groups[groupName][0].coalition, true);
|
||||
}
|
||||
}
|
||||
//*/
|
||||
}
|
||||
|
||||
#showForm() {
|
||||
const data:any = {};
|
||||
|
||||
for (const [ group, units ] of Object.entries(this.#fileData) ) {
|
||||
if (group === "" || units.length === 0)
|
||||
continue;
|
||||
|
||||
if (units.some((unit:UnitData) => !this.#unitDataCanBeImported(unit)))
|
||||
continue;
|
||||
|
||||
const category = units[0].category;
|
||||
|
||||
if (!data.hasOwnProperty(category)) {
|
||||
data[category] = {};
|
||||
}
|
||||
|
||||
units.forEach((unit:UnitData) => {
|
||||
if (!data[category].hasOwnProperty(unit.coalition))
|
||||
data[category][unit.coalition] = [];
|
||||
|
||||
data[category][unit.coalition].push(unit);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
groups.filter((unit:Unit) => unitCanBeImported(unit)).forEach((unit:Unit) => {
|
||||
const category = unit.getCategoryLabel();
|
||||
const coalition = unit.getCoalition();
|
||||
|
||||
if (!data.hasOwnProperty(category)) {
|
||||
data[category] = {};
|
||||
}
|
||||
|
||||
if (!data[category].hasOwnProperty(coalition))
|
||||
data[category][coalition] = [];
|
||||
|
||||
data[category][coalition].push(unit);
|
||||
});
|
||||
//*/
|
||||
this.data = data;
|
||||
this.buildCategoryCoalitionTable();
|
||||
this.dialog.show();
|
||||
}
|
||||
|
||||
selectFile() {
|
||||
@ -49,14 +116,23 @@ export class UnitDataFileImport extends UnitDataFile {
|
||||
return;
|
||||
}
|
||||
var reader = new FileReader();
|
||||
reader.onload = function (e: any) {
|
||||
var contents = e.target.result;
|
||||
var groups = JSON.parse(contents);
|
||||
console.log(groups);
|
||||
reader.onload = (e: any) => {
|
||||
this.#fileData = JSON.parse(e.target.result);
|
||||
this.#showForm();
|
||||
};
|
||||
reader.readAsText(file);
|
||||
})
|
||||
input.click();
|
||||
}
|
||||
|
||||
#unitDataCanBeImported(unitData:UnitData) {
|
||||
return unitData.alive && this.#unitGroupDataCanBeImported([unitData]);
|
||||
}
|
||||
|
||||
#unitGroupDataCanBeImported(unitGroupData:UnitData[]) {
|
||||
return unitGroupData.every((unitData:UnitData) => {
|
||||
return !["Aircraft", "Helicopter"].includes(unitData.category);
|
||||
}) && unitGroupData.some((unitData:UnitData) => unitData.alive);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1006,7 +1006,7 @@ export class UnitsManager {
|
||||
*/
|
||||
exportToFile() {
|
||||
if (!this.#unitDataExport)
|
||||
this.#unitDataExport = new UnitDataFileExport("unit-import-export-dialog");
|
||||
this.#unitDataExport = new UnitDataFileExport("unit-export-dialog");
|
||||
this.#unitDataExport.showForm(Object.values(this.#units));
|
||||
}
|
||||
|
||||
@ -1015,7 +1015,7 @@ export class UnitsManager {
|
||||
*/
|
||||
importFromFile() {
|
||||
if (!this.#unitDataImport)
|
||||
this.#unitDataImport = new UnitDataFileImport("unit-import-export-dialog");
|
||||
this.#unitDataImport = new UnitDataFileImport("unit-import-dialog");
|
||||
this.#unitDataImport.selectFile();
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,17 @@
|
||||
<%- include('dialogs/advancedsettings.ejs') %>
|
||||
<%- include('dialogs/commandmodesettings.ejs') %>
|
||||
<%- include('dialogs/customformation.ejs') %>
|
||||
<%- include('dialogs/importexport.ejs') %>
|
||||
<%- include('dialogs/importexport.ejs', {
|
||||
"dialogId": "unit-export-dialog",
|
||||
"submitButtonText": "Export units to file",
|
||||
"textContent": "Select the unit categories you would like to export. Note: only ground and naval units can be exported at this time.",
|
||||
"title": "Export"
|
||||
}) %>
|
||||
<%- include('dialogs/importexport.ejs', {
|
||||
"dialogId": "unit-import-dialog",
|
||||
"submitButtonText": "Import units into mission",
|
||||
"textContent": "Select the unit categories you would like to import.",
|
||||
"title": "Import"
|
||||
}) %>
|
||||
<%- include('dialogs/slowdelete.ejs') %>
|
||||
<%- include('dialogs/splash.ejs') %>
|
||||
@ -1,11 +1,11 @@
|
||||
<div id="unit-import-export-dialog" class="ol-panel ol-dialog hide" oncontextmenu="return false;">
|
||||
<div id="<%= dialogId %>" class="ol-panel ol-dialog file-import-export hide" oncontextmenu="return false;">
|
||||
<div class="ol-dialog-header">
|
||||
<h3 class="export">Export unit data to file</h3>
|
||||
<h3><%= title %></h3>
|
||||
</div>
|
||||
|
||||
<div class="ol-dialog-content">
|
||||
<p>Note: only ground and naval units can be exported at this time. (Air units will be possible <em>soon</em>.)</p>
|
||||
<table>
|
||||
<p><%= textContent %></p>
|
||||
<table class="categories-coalitions">
|
||||
<thead>
|
||||
</thead>
|
||||
<tbody>
|
||||
@ -14,8 +14,7 @@
|
||||
</div>
|
||||
|
||||
<div class="ol-dialog-footer ol-group">
|
||||
<button class="start-transfer import">Import units into mission</button>
|
||||
<button class="start-transfer export">Export units to file</button>
|
||||
<button data-on-click="closeDialog">Cancel</button>
|
||||
<button class="start-transfer"><%= submitButtonText %></button>
|
||||
<button data-on-click="closeDialog">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
Loading…
x
Reference in New Issue
Block a user