mirror of
https://git.srhtnin.garden/sarah/srhtnin.github.io.git
synced 2026-10-13 18:38:11 +02:00
648 lines
13 KiB
JavaScript
648 lines
13 KiB
JavaScript
let AdminMassPlantCatalogue = {};
|
|
let AdminMassPlantSavePending = false;
|
|
|
|
|
|
async function AdminMassPlantRequest(
|
|
Action,
|
|
Data = {}
|
|
) {
|
|
const SaveKey =
|
|
localStorage.getItem(
|
|
SaveKeyName
|
|
);
|
|
|
|
if (
|
|
typeof SaveKey !== "string" ||
|
|
!/^[0-9A-Fa-f]{64}$/.test(
|
|
SaveKey
|
|
)
|
|
) {
|
|
throw new Error(
|
|
"A valid Account Key is required."
|
|
);
|
|
}
|
|
|
|
const Response = await fetch(
|
|
ApiUrl + "/AdminPlants.php",
|
|
{
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type":
|
|
"application/json"
|
|
},
|
|
body: JSON.stringify({
|
|
SaveKey: SaveKey,
|
|
Action: Action,
|
|
...Data
|
|
})
|
|
}
|
|
);
|
|
|
|
const Result =
|
|
await Response.json();
|
|
|
|
if (
|
|
!Response.ok ||
|
|
Result.Success !== true
|
|
) {
|
|
throw new Error(
|
|
Result.Error ??
|
|
"Plant admin request failed."
|
|
);
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
|
|
function GetSortedAdminMassPlantKeys() {
|
|
return Object.keys(
|
|
AdminMassPlantCatalogue
|
|
).sort(
|
|
(A, B) =>
|
|
Number(
|
|
AdminMassPlantCatalogue[A]
|
|
?.Id ?? 0
|
|
) -
|
|
Number(
|
|
AdminMassPlantCatalogue[B]
|
|
?.Id ?? 0
|
|
) ||
|
|
A.localeCompare(B)
|
|
);
|
|
}
|
|
|
|
|
|
function RenderAdminMassPlantSelection() {
|
|
const Container =
|
|
document.getElementById(
|
|
"AdminMassPlantSelection"
|
|
);
|
|
|
|
Container.replaceChildren();
|
|
|
|
for (
|
|
const PlantKey
|
|
of GetSortedAdminMassPlantKeys()
|
|
) {
|
|
const Plant =
|
|
AdminMassPlantCatalogue[
|
|
PlantKey
|
|
];
|
|
|
|
const Label =
|
|
document.createElement("label");
|
|
Label.className =
|
|
"AdminPlantChecklistItem";
|
|
|
|
const Input =
|
|
document.createElement("input");
|
|
Input.type = "checkbox";
|
|
Input.value = PlantKey;
|
|
Input.dataset.adminMassTarget =
|
|
"plant";
|
|
|
|
const Text =
|
|
document.createElement("span");
|
|
Text.textContent =
|
|
String(Plant.Id).padStart(
|
|
3,
|
|
"0"
|
|
) +
|
|
" — " +
|
|
(Plant.Name ?? PlantKey) +
|
|
(
|
|
Plant.Archived === true
|
|
? " (archived)"
|
|
: ""
|
|
);
|
|
|
|
Label.append(
|
|
Input,
|
|
Text
|
|
);
|
|
Container.appendChild(Label);
|
|
}
|
|
}
|
|
|
|
|
|
function SetAdminMassPlantSelection(
|
|
Checked
|
|
) {
|
|
for (
|
|
const Input
|
|
of document.querySelectorAll(
|
|
'[data-admin-mass-target="plant"]'
|
|
)
|
|
) {
|
|
Input.checked = Checked;
|
|
}
|
|
}
|
|
|
|
|
|
function UpdateAdminMassPlantFieldStates() {
|
|
const FieldMap = {
|
|
Name: [
|
|
"AdminMassPlantName"
|
|
],
|
|
Description: [
|
|
"AdminMassPlantDescription"
|
|
],
|
|
Tags: [
|
|
"AdminMassPlantTags"
|
|
],
|
|
GrowthTime: [
|
|
"AdminMassPlantGrowthHours",
|
|
"AdminMassPlantGrowthMinutes",
|
|
"AdminMassPlantGrowthSeconds"
|
|
],
|
|
HarvestMultiplier: [
|
|
"AdminMassPlantHarvestMultiplier"
|
|
],
|
|
ShopPlant: [
|
|
"AdminMassPlantShopPlant"
|
|
],
|
|
BaseCost: [
|
|
"AdminMassPlantBaseCost"
|
|
],
|
|
Effects: [
|
|
"AdminMassPlantEffects"
|
|
]
|
|
};
|
|
|
|
for (
|
|
const Apply
|
|
of document.querySelectorAll(
|
|
"[data-admin-mass-apply]"
|
|
)
|
|
) {
|
|
const FieldName =
|
|
Apply.dataset.adminMassApply;
|
|
|
|
for (
|
|
const ElementId
|
|
of FieldMap[FieldName] ?? []
|
|
) {
|
|
document.getElementById(
|
|
ElementId
|
|
).disabled = !Apply.checked;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
function GetAdminMassPlantSelectedKeys() {
|
|
return [
|
|
...document.querySelectorAll(
|
|
'[data-admin-mass-target="plant"]:checked'
|
|
)
|
|
].map(Input => Input.value);
|
|
}
|
|
|
|
|
|
function AdminMassPlantFieldEnabled(
|
|
FieldName
|
|
) {
|
|
return document.querySelector(
|
|
'[data-admin-mass-apply="' +
|
|
FieldName +
|
|
'"]'
|
|
)?.checked === true;
|
|
}
|
|
|
|
|
|
function ParseAdminMassPlantTags() {
|
|
return [
|
|
...new Set(
|
|
document.getElementById(
|
|
"AdminMassPlantTags"
|
|
).value
|
|
.split(",")
|
|
.map(Tag => Tag.trim())
|
|
.filter(Tag => Tag !== "")
|
|
)
|
|
];
|
|
}
|
|
|
|
|
|
function GetAdminMassPlantGrowthTime() {
|
|
const Hours = Number(
|
|
document.getElementById(
|
|
"AdminMassPlantGrowthHours"
|
|
).value
|
|
);
|
|
const Minutes = Number(
|
|
document.getElementById(
|
|
"AdminMassPlantGrowthMinutes"
|
|
).value
|
|
);
|
|
const Seconds = Number(
|
|
document.getElementById(
|
|
"AdminMassPlantGrowthSeconds"
|
|
).value
|
|
);
|
|
|
|
if (
|
|
!Number.isInteger(Hours) ||
|
|
!Number.isInteger(Minutes) ||
|
|
!Number.isInteger(Seconds) ||
|
|
Hours < 0 ||
|
|
Minutes < 0 ||
|
|
Minutes > 59 ||
|
|
Seconds < 0 ||
|
|
Seconds > 59
|
|
) {
|
|
throw new Error(
|
|
"Growth time is invalid."
|
|
);
|
|
}
|
|
|
|
return (
|
|
Hours * 3600000 +
|
|
Minutes * 60000 +
|
|
Seconds * 1000
|
|
);
|
|
}
|
|
|
|
|
|
function GetAdminMassPlantEffects() {
|
|
const Raw =
|
|
document.getElementById(
|
|
"AdminMassPlantEffects"
|
|
).value.trim();
|
|
|
|
const Effects = JSON.parse(
|
|
Raw === "" ? "{}" : Raw
|
|
);
|
|
|
|
if (!IsAdminPlainObject(Effects)) {
|
|
throw new Error(
|
|
"Effects JSON must be an object."
|
|
);
|
|
}
|
|
|
|
return Effects;
|
|
}
|
|
|
|
|
|
function GetAdminMassPlantPatch() {
|
|
const Patch = {};
|
|
|
|
if (AdminMassPlantFieldEnabled("Name")) {
|
|
Patch.Name =
|
|
document.getElementById(
|
|
"AdminMassPlantName"
|
|
).value.trim();
|
|
}
|
|
|
|
if (
|
|
AdminMassPlantFieldEnabled(
|
|
"Description"
|
|
)
|
|
) {
|
|
Patch.Description =
|
|
document.getElementById(
|
|
"AdminMassPlantDescription"
|
|
).value.trim();
|
|
}
|
|
|
|
if (AdminMassPlantFieldEnabled("Tags")) {
|
|
Patch.Tags =
|
|
ParseAdminMassPlantTags();
|
|
}
|
|
|
|
if (
|
|
AdminMassPlantFieldEnabled(
|
|
"GrowthTime"
|
|
)
|
|
) {
|
|
Patch.GrowthTime =
|
|
GetAdminMassPlantGrowthTime();
|
|
}
|
|
|
|
if (
|
|
AdminMassPlantFieldEnabled(
|
|
"HarvestMultiplier"
|
|
)
|
|
) {
|
|
Patch.HarvestMultiplier =
|
|
Number(
|
|
document.getElementById(
|
|
"AdminMassPlantHarvestMultiplier"
|
|
).value
|
|
);
|
|
}
|
|
|
|
if (
|
|
AdminMassPlantFieldEnabled(
|
|
"ShopPlant"
|
|
)
|
|
) {
|
|
Patch.ShopPlant =
|
|
document.getElementById(
|
|
"AdminMassPlantShopPlant"
|
|
).value === "true";
|
|
}
|
|
|
|
if (
|
|
AdminMassPlantFieldEnabled(
|
|
"BaseCost"
|
|
)
|
|
) {
|
|
Patch.BaseCost =
|
|
Number(
|
|
document.getElementById(
|
|
"AdminMassPlantBaseCost"
|
|
).value
|
|
);
|
|
}
|
|
|
|
if (
|
|
AdminMassPlantFieldEnabled(
|
|
"Effects"
|
|
)
|
|
) {
|
|
Patch.Effects =
|
|
GetAdminMassPlantEffects();
|
|
}
|
|
|
|
return Patch;
|
|
}
|
|
|
|
|
|
function BuildAdminMassPlantPayload(
|
|
PlantKey,
|
|
Patch
|
|
) {
|
|
const Source =
|
|
AdminMassPlantCatalogue[
|
|
PlantKey
|
|
];
|
|
|
|
const Plant = {
|
|
Id: Number(Source.Id),
|
|
PlantKey: PlantKey,
|
|
Name: Source.Name ?? "",
|
|
Description:
|
|
Source.Description ?? "",
|
|
Tags:
|
|
Array.isArray(Source.Tags)
|
|
? [...Source.Tags]
|
|
: [],
|
|
GrowthTime:
|
|
Number(Source.GrowthTime ?? 0),
|
|
HarvestMultiplier:
|
|
Number(
|
|
Source.HarvestMultiplier ??
|
|
1.5
|
|
),
|
|
Effects:
|
|
JSON.parse(
|
|
JSON.stringify(
|
|
Source.Effects ?? {}
|
|
)
|
|
),
|
|
DirectionalSprites:
|
|
Source.DirectionalSprites === true,
|
|
ShopPlant:
|
|
Source.Shop?.ShopPlant === true,
|
|
BaseCost:
|
|
Source.Shop?.BaseCost ?? null,
|
|
IsNew: false
|
|
};
|
|
|
|
Object.assign(
|
|
Plant,
|
|
JSON.parse(
|
|
JSON.stringify(Patch)
|
|
)
|
|
);
|
|
|
|
return Plant;
|
|
}
|
|
|
|
|
|
async function SaveAdminMassPlants(
|
|
Event
|
|
) {
|
|
Event.preventDefault();
|
|
|
|
if (AdminMassPlantSavePending) {
|
|
return;
|
|
}
|
|
|
|
const SelectedKeys =
|
|
GetAdminMassPlantSelectedKeys();
|
|
|
|
if (SelectedKeys.length === 0) {
|
|
SetAdminMassPlantMessage(
|
|
"Mark at least one plant first."
|
|
);
|
|
return;
|
|
}
|
|
|
|
let Patch;
|
|
|
|
try {
|
|
Patch = GetAdminMassPlantPatch();
|
|
} catch (Error) {
|
|
SetAdminMassPlantMessage(
|
|
Error.message
|
|
);
|
|
return;
|
|
}
|
|
|
|
if (Object.keys(Patch).length === 0) {
|
|
SetAdminMassPlantMessage(
|
|
"Enable at least one field to update."
|
|
);
|
|
return;
|
|
}
|
|
|
|
const Payloads = [];
|
|
|
|
try {
|
|
for (const PlantKey of SelectedKeys) {
|
|
const Plant =
|
|
BuildAdminMassPlantPayload(
|
|
PlantKey,
|
|
Patch
|
|
);
|
|
|
|
ValidateAdminPlant(
|
|
Plant,
|
|
AdminMassPlantCatalogue,
|
|
PlantKey
|
|
);
|
|
|
|
Payloads.push(Plant);
|
|
}
|
|
} catch (Error) {
|
|
SetAdminMassPlantMessage(
|
|
Error.message
|
|
);
|
|
return;
|
|
}
|
|
|
|
AdminMassPlantSavePending = true;
|
|
|
|
const SaveButton =
|
|
document.getElementById(
|
|
"AdminMassPlantSaveButton"
|
|
);
|
|
|
|
SaveButton.disabled = true;
|
|
|
|
let SavedCount = 0;
|
|
|
|
try {
|
|
for (const Plant of Payloads) {
|
|
SetAdminMassPlantMessage(
|
|
"Saving " +
|
|
(SavedCount + 1) +
|
|
" of " +
|
|
Payloads.length +
|
|
"..."
|
|
);
|
|
|
|
await AdminMassPlantRequest(
|
|
"Save",
|
|
{Plant: Plant}
|
|
);
|
|
|
|
SavedCount++;
|
|
}
|
|
|
|
localStorage.removeItem(
|
|
"SarahtoninGardenContent"
|
|
);
|
|
|
|
await LoadAdminMassPlants();
|
|
|
|
SetAdminMassPlantMessage(
|
|
SavedCount === 1
|
|
? "1 plant updated."
|
|
: SavedCount +
|
|
" plants updated."
|
|
);
|
|
} catch (Error) {
|
|
SetAdminMassPlantMessage(
|
|
"Saved " +
|
|
SavedCount +
|
|
" before stopping: " +
|
|
(Error.message ??
|
|
"Couldn't save plants.")
|
|
);
|
|
} finally {
|
|
AdminMassPlantSavePending = false;
|
|
SaveButton.disabled = false;
|
|
}
|
|
}
|
|
|
|
|
|
function BindAdminMassPlantEditor() {
|
|
document.getElementById(
|
|
"AdminMassPlantSelectAll"
|
|
).addEventListener(
|
|
"click",
|
|
() =>
|
|
SetAdminMassPlantSelection(
|
|
true
|
|
)
|
|
);
|
|
|
|
document.getElementById(
|
|
"AdminMassPlantClear"
|
|
).addEventListener(
|
|
"click",
|
|
() =>
|
|
SetAdminMassPlantSelection(
|
|
false
|
|
)
|
|
);
|
|
|
|
document.getElementById(
|
|
"AdminMassPlantForm"
|
|
).addEventListener(
|
|
"submit",
|
|
SaveAdminMassPlants
|
|
);
|
|
|
|
for (
|
|
const Apply
|
|
of document.querySelectorAll(
|
|
"[data-admin-mass-apply]"
|
|
)
|
|
) {
|
|
Apply.addEventListener(
|
|
"change",
|
|
UpdateAdminMassPlantFieldStates
|
|
);
|
|
}
|
|
|
|
UpdateAdminMassPlantFieldStates();
|
|
}
|
|
|
|
|
|
async function LoadAdminMassPlants() {
|
|
const Result =
|
|
await AdminMassPlantRequest(
|
|
"List"
|
|
);
|
|
|
|
AdminMassPlantCatalogue =
|
|
Result.Plants ?? {};
|
|
|
|
RenderAdminMassPlantSelection();
|
|
}
|
|
|
|
|
|
function SetAdminMassPlantMessage(
|
|
Message
|
|
) {
|
|
document.getElementById(
|
|
"AdminMassPlantMessage"
|
|
).textContent = Message;
|
|
}
|
|
|
|
|
|
async function StartAdminMassPlantEditor() {
|
|
try {
|
|
const Status =
|
|
await GetAdminStatus();
|
|
|
|
if (
|
|
Status.Success !== true ||
|
|
Status.IsAdmin !== true
|
|
) {
|
|
SetAdminMassPlantMessage(
|
|
"Admin access required."
|
|
);
|
|
return;
|
|
}
|
|
|
|
BindAdminMassPlantEditor();
|
|
await LoadAdminMassPlants();
|
|
|
|
SetAdminMassPlantMessage(
|
|
"Mark plants and enable the fields you want to change."
|
|
);
|
|
} catch (Error) {
|
|
console.error(
|
|
"Couldn't start Mass plant editor:",
|
|
Error
|
|
);
|
|
|
|
SetAdminMassPlantMessage(
|
|
Error.message ??
|
|
"Couldn't load the Mass plant editor."
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
document.addEventListener(
|
|
"DOMContentLoaded",
|
|
StartAdminMassPlantEditor
|
|
);
|