Editing & saving changes & fixes

This commit is contained in:
CenTdemeern1 2025-02-03 19:00:15 +01:00
parent f451b1fbc3
commit 7e1416a721
5 changed files with 75 additions and 30 deletions

View file

@ -1,5 +1,5 @@
import { AddInstanceDialog } from "./add_an_instance.mjs";
import { InstanceDetailsDialog, InstanceDetailsDialogData } from "./confirm_instance_details.mjs";
import { dialogDetailsToInstance, InstanceDetailsDialog, InstanceDetailsDialogData } from "./confirm_instance_details.mjs";
import { Dialog } from "./dialog.mjs";
import storageManager, { Instance } from "./storage_manager.mjs";
@ -26,14 +26,14 @@ export class AddInstanceFlow {
this.detailsDialog = new InstanceDetailsDialog(detailsDialog, true);
}
async start() {
async start(autoSave: boolean) {
const {
autoQueryMetadata,
host,
secure,
} = await this.addDialog.present();
let detailsDialogData: InstanceDetailsDialogData = {
const detailsDialogData: InstanceDetailsDialogData = {
name: host,
host,
hostSecure: secure,
@ -62,17 +62,11 @@ export class AddInstanceFlow {
} catch { }
this.spinnerDialog.close();
detailsDialogData = await this.detailsDialog.present(detailsDialogData);
const instance: Instance = {
name: detailsDialogData.name,
origin: `http${detailsDialogData.hostSecure ? "s" : ""}://${detailsDialogData.host}`,
software: detailsDialogData.software,
iconURL: detailsDialogData.iconURL ?? undefined
};
const finalData = await this.detailsDialog.present(detailsDialogData);
const instance = dialogDetailsToInstance(finalData, {});
storageManager.storage.instances.push(instance);
storageManager.save();
if (autoSave) storageManager.save();
console.log("Successfully added new instance:", instance);
}
}

View file

@ -1,10 +1,11 @@
import { parseHost } from "./add_an_instance.mjs";
import { AddInstanceFlow } from "./add_instance_flow.mjs";
import { InstanceDetailsDialog } from "./confirm_instance_details.mjs";
import { dialogDetailsFromInstance, dialogDetailsToInstance, InstanceDetailsDialog, InstanceDetailsDialogData } from "./confirm_instance_details.mjs";
import { findButtonOrFail, findDialogOrFail, findOlOrFail } from "./dom.mjs";
import storageManager from "./storage_manager.mjs";
import storageManager, { Instance } from "./storage_manager.mjs";
let reordering = false;
let unsaved = false;
// Dragging code is a heavily modified version of https://stackoverflow.com/a/28962290
let elementBeingDragged: HTMLLIElement | undefined;
@ -20,12 +21,12 @@ const reorderButton = findButtonOrFail(document.body, "#reorder");
let instanceDetailsDialog = new InstanceDetailsDialog(detailsDialog, true);
let addInstanceFlow = new AddInstanceFlow(addDialog, spinnerDialog, instanceDetailsDialog);
startAddInstanceFlowButton.addEventListener("click", e => addInstanceFlow.start());
saveButton.addEventListener("click", e => {
storageManager.save();
startAddInstanceFlowButton.addEventListener("click", e => {
addInstanceFlow.start(false).then(_ => unsavedChanges());
});
saveButton.addEventListener("click", e => saveChanges());
reorderButton.addEventListener("click", () => {
reordering = !reordering;
if (!reordering) applyReordering();
@ -38,6 +39,26 @@ storageManager.addSaveCallback(updateInstanceList);
mainDialog.show();
function saveChanges() {
storageManager.save();
unsaved = false;
saveButton.classList.remove("pulse-red");
}
function unsavedChanges() {
if (!unsaved) {
unsaved = true;
saveButton.classList.add("pulse-red");
}
}
async function editInstance(instance: Instance) {
const data = dialogDetailsFromInstance(instance);
const newData = await instanceDetailsDialog.present(data);
dialogDetailsToInstance(newData, instance);
unsavedChanges();
}
function updateInstanceList() {
instanceList.replaceChildren(); // Erase all child nodes
instanceList.style.listStyleType = reordering ? "\"≡ \"" : "disc";
@ -83,17 +104,7 @@ function updateInstanceList() {
const editLink = document.createElement("a");
editLink.innerText = `Edit`;
editLink.href = "#";
editLink.addEventListener("click", e => {
const host = parseHost(instance.origin)!;
populateInstanceDetailsDialog(
instance.name,
host.host,
host.secure,
instance.software,
instance.iconURL ?? null
);
showInstanceDetailsDialog();
});
editLink.addEventListener("click", e => editInstance(instance));
const deleteLink = document.createElement("a");
deleteLink.innerText = `Delete`;
deleteLink.href = "#";
@ -127,4 +138,5 @@ function applyReordering() {
indices.push(parseInt(option));
}
storageManager.storage.instances = indices.map(i => storageManager.storage.instances[i]);
unsavedChanges();
}

View file

@ -1,11 +1,17 @@
// This file handles the "Confirm instance details" dialog
import { parseHost } from "./add_an_instance.mjs";
import { FormDialog, ONCE } from "./dialog.mjs";
import { findButtonOrFail, findFormOrFail, findImageOrFail, findInputOrFail, findSelectOrFail } from "./dom.mjs";
import knownSoftware from "./known_software.mjs";
import { Instance } from "./storage_manager.mjs";
const blankImage = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
export function mergeHost(host: string, secure: boolean): string {
return `http${secure ? "s" : ""}://${host}`;
}
export type InstanceDetailsDialogData = {
name: string,
host: string,
@ -14,6 +20,25 @@ export type InstanceDetailsDialogData = {
iconURL: string | null
};
export function dialogDetailsFromInstance(instance: Instance): InstanceDetailsDialogData {
const host = parseHost(instance.origin)!;
return {
name: instance.name,
host: host.host,
hostSecure: host.secure,
software: instance.software,
iconURL: instance.iconURL ?? null
};
}
export function dialogDetailsToInstance(data: InstanceDetailsDialogData, instance: Partial<Instance>): Instance {
instance.name = data.name;
instance.origin = mergeHost(data.host, data.hostSecure);
instance.software = data.software;
instance.iconURL = data.iconURL ?? undefined;
return instance as Instance;
}
export class InstanceDetailsDialog extends FormDialog {
protected instanceName: HTMLInputElement;
protected instanceHost: HTMLInputElement;

View file

@ -31,7 +31,7 @@ if (!autoRedirect()) {
mainDialog.show();
};
startAddInstanceFlowButton.addEventListener("click", e => addInstanceFlow?.start());
startAddInstanceFlowButton.addEventListener("click", e => addInstanceFlow?.start(true));
redirectButton.addEventListener("click", e => {
// Can be assumed to not fail because the button is disabled if there are no options and the first one is selected by default

View file

@ -185,3 +185,17 @@ abbr[title] {
.buttonPanel>* {
margin-top: min(var(--xl), 6vh);
}
.pulse-red {
animation: 1s ease-in-out 0s infinite alternate both running pulse-red-anim;
}
@keyframes pulse-red-anim {
0% {
box-shadow: 0px 0px 0px var(--red);
}
100% {
box-shadow: 0px 0px 20px var(--red);
}
}