FeDirect/static/config.mts

151 lines
5.8 KiB
TypeScript
Raw Normal View History

2025-01-28 23:26:21 +01:00
import { parseHost } from "./add_an_instance.mjs";
import { AddInstanceFlow } from "./add_instance_flow.mjs";
2025-02-03 19:00:15 +01:00
import { dialogDetailsFromInstance, dialogDetailsToInstance, InstanceDetailsDialog, InstanceDetailsDialogData } from "./confirm_instance_details.mjs";
2025-01-28 23:26:21 +01:00
import { findButtonOrFail, findDialogOrFail, findOlOrFail } from "./dom.mjs";
2025-02-03 19:00:15 +01:00
import storageManager, { Instance } from "./storage_manager.mjs";
2025-01-28 23:26:21 +01:00
let reordering = false;
2025-02-03 19:00:15 +01:00
let unsaved = false;
2025-01-28 23:26:21 +01:00
// Dragging code is a heavily modified version of https://stackoverflow.com/a/28962290
let elementBeingDragged: HTMLLIElement | undefined;
2025-02-03 01:11:29 +01:00
const mainDialog = findDialogOrFail(document.body, "#mainDialog");
const startAddInstanceFlowButton = findButtonOrFail(document.body, "#startAddInstanceFlow");
2025-01-28 23:26:21 +01:00
const addDialog = findDialogOrFail(document.body, "#addInstance");
const spinnerDialog = findDialogOrFail(document.body, "#spinner");
const detailsDialog = findDialogOrFail(document.body, "#instanceDetails");
2025-01-28 23:26:21 +01:00
const instanceList = findOlOrFail(document.body, "#instanceList");
const saveButton = findButtonOrFail(document.body, "#save");
const reorderButton = findButtonOrFail(document.body, "#reorder");
let instanceDetailsDialog = new InstanceDetailsDialog(detailsDialog, true);
let addInstanceFlow = new AddInstanceFlow(addDialog, spinnerDialog, instanceDetailsDialog);
2025-02-03 19:00:15 +01:00
startAddInstanceFlowButton.addEventListener("click", e => {
2025-02-03 19:03:18 +01:00
addInstanceFlow.start(false).then(_ => {
updateInstanceList();
unsavedChanges();
});
2025-01-28 23:26:21 +01:00
});
2025-02-03 19:00:15 +01:00
saveButton.addEventListener("click", e => saveChanges());
2025-01-28 23:26:21 +01:00
reorderButton.addEventListener("click", () => {
reordering = !reordering;
if (!reordering) applyReordering();
updateInstanceList();
reorderButton.innerText = reordering ? "Finish reordering" : "Reorder";
});
updateInstanceList();
storageManager.addSaveCallback(updateInstanceList);
2025-02-03 01:11:29 +01:00
mainDialog.show();
2025-02-03 19:00:15 +01:00
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);
2025-02-03 19:37:15 +01:00
updateInstanceList();
2025-02-03 19:00:15 +01:00
unsavedChanges();
}
2025-02-03 19:03:18 +01:00
function deleteInstance(instance: Instance) {
storageManager.storage.instances.splice(
2025-02-03 19:24:34 +01:00
storageManager.storage.instances.indexOf(instance),
1
2025-02-03 19:03:18 +01:00
);
updateInstanceList();
unsavedChanges();
}
2025-01-28 23:26:21 +01:00
function updateInstanceList() {
instanceList.replaceChildren(); // Erase all child nodes
instanceList.style.listStyleType = reordering ? "\"≡ \"" : "disc";
for (let n = 0; n < storageManager.storage.instances.length; n++) {
const instance = storageManager.storage.instances[n];
const li = document.createElement("li");
li.setAttribute("x-option", n.toString());
const label = document.createElement("label");
label.htmlFor = instance.origin;
label.innerText = instance.name + " ";
label.style.cursor = "inherit";
if (instance.iconURL) {
const img = new Image();
img.src = instance.iconURL;
img.alt = `${instance.name} icon`;
img.className = "inlineIcon medium-height";
label.append(img, " ");
}
if (reordering) {
li.draggable = true;
li.addEventListener("dragstart", e => {
if (e.dataTransfer === null) return;
if (!(e.target instanceof HTMLLIElement)) return;
e.dataTransfer.effectAllowed = "move";
e.dataTransfer.setData("text/plain", "");
elementBeingDragged = e.target;
});
li.addEventListener("dragover", e => {
if (elementBeingDragged === undefined) return;
if (!(e.target instanceof HTMLElement)) return;
const listElement = e.target.closest("li");
if (listElement === null) return;
if (listElement.parentNode === null) return;
if (isBefore(elementBeingDragged, listElement))
listElement.parentNode.insertBefore(elementBeingDragged, listElement);
else
listElement.parentNode.insertBefore(elementBeingDragged, listElement.nextSibling);
e.preventDefault();
});
li.addEventListener("dragenter", e => e.preventDefault());
li.style.cursor = "grab";
} else {
const editLink = document.createElement("a");
editLink.innerText = `Edit`;
editLink.href = "#";
2025-02-03 19:00:15 +01:00
editLink.addEventListener("click", e => editInstance(instance));
2025-01-28 23:26:21 +01:00
const deleteLink = document.createElement("a");
deleteLink.innerText = `Delete`;
deleteLink.href = "#";
2025-02-03 19:03:18 +01:00
deleteLink.addEventListener("click", e => deleteInstance(instance));
2025-01-28 23:26:21 +01:00
label.append(editLink, " ", deleteLink);
}
li.appendChild(label);
instanceList.appendChild(li);
}
}
function isBefore(el1: HTMLLIElement, el2: HTMLLIElement) {
if (el2.parentNode === el1.parentNode)
for (let cur = el1.previousSibling; cur && cur.nodeType !== 9; cur = cur.previousSibling)
if (cur === el2)
return true;
return false;
}
function applyReordering() {
const indices: number[] = [];
for (const el of instanceList.children) {
if (!(el instanceof HTMLLIElement)) continue;
const option = el.getAttribute("x-option");
if (option === null) continue;
indices.push(parseInt(option));
}
storageManager.storage.instances = indices.map(i => storageManager.storage.instances[i]);
2025-02-03 19:00:15 +01:00
unsavedChanges();
2025-01-28 23:26:21 +01:00
}