refactoring

This commit is contained in:
2026-09-02 08:38:03 +02:00
parent 649ff0d7c5
commit 38f255c1a4
48 changed files with 6998 additions and 5577 deletions
+166
View File
@@ -0,0 +1,166 @@
import { pageRoute } from "../routes.js";
/* Page-alias administration view. */
class AliasAdmin {
/**
* goal : Create a controller for retained page aliases.
* pre : api and translate are application services; reloadPages refreshes
* the public page and alias catalogue after an administrative edit.
* post : The controller is ready to load and mutate aliases.
* result : A directly usable alias administration controller.
*/
constructor(api, translate, reloadPages) {
this.api = api;
this.translate = translate;
this.reloadPages = reloadPages;
this.list = document.getElementById("alias-list");
this.status = document.getElementById("alias-admin-status");
}
/**
* goal : Load retained aliases and render their references and actions.
* pre : The current session has administrator permission.
* post : The alias list represents the current server state.
* result : A promise that resolves when all alias rows have been rendered.
*/
async load() {
this.status.textContent = "";
const result = await this.api("/api/admin/aliases");
const aliases = result.aliases || [];
this.list.replaceChildren();
if (aliases.length === 0) {
const empty = document.createElement("p");
empty.className = "muted";
empty.textContent = this.translate("no-page-aliases", "No page aliases.");
this.list.append(empty);
return;
}
for (const alias of aliases) this.list.append(this.#renderAlias(alias));
}
/** Build one alias row, including cleanup and deletion actions. */
#renderAlias(alias) {
const row = document.createElement("article");
row.className = "alias-row";
const address = document.createElement("div");
address.className = "alias-address";
const target = document.createElement("a");
target.href = pageRoute(alias.targetSlug);
target.textContent = alias.targetSlug;
address.append(
document.createTextNode(
`${this.translate("old-address", "Old address")}: ${alias.slug} · ` +
`${this.translate("current-address", "Current address")}: `),
target
);
row.append(address);
const references = alias.references || [];
const currentSummary = document.createElement("div");
currentSummary.className = "alias-summary";
currentSummary.textContent =
`${this.translate("current-references", "Current references")}: ${references.length}`;
row.append(currentSummary);
if (references.length > 0) {
const referenceList = document.createElement("ul");
referenceList.className = "alias-references";
for (const reference of references) {
const item = document.createElement("li");
const link = document.createElement("a");
link.href = pageRoute(reference.slug);
link.textContent = reference.title;
item.append(link);
referenceList.append(item);
}
row.append(referenceList);
}
const historicalCount = Number(alias.historicalReferenceCount || 0);
const historicalSummary = document.createElement("div");
historicalSummary.className = "alias-summary muted";
historicalSummary.textContent =
`${this.translate("historical-references", "Historical references")}: ${historicalCount}`;
row.append(historicalSummary);
const historicalReferences = alias.historicalReferences || [];
if (historicalReferences.length > 0) {
const historyList = document.createElement("ul");
historyList.className = "alias-references alias-history";
for (const reference of historicalReferences) {
const item = document.createElement("li");
item.textContent = `${reference.title} · ` +
`${this.translate("version", "Version")} ${reference.version}`;
historyList.append(item);
}
row.append(historyList);
}
const actions = document.createElement("div");
actions.className = "alias-actions";
actions.append(
this.#cleanupButton(alias, references),
this.#deleteButton(alias, references, historicalCount)
);
row.append(actions);
return row;
}
/** Build the action that replaces current references to an old address. */
#cleanupButton(alias, references) {
const button = document.createElement("button");
button.type = "button";
button.textContent = this.translate("cleanup-alias", "Clean up references");
button.disabled = references.length === 0;
button.addEventListener("click", () => {
this.#cleanup(alias).catch((error) => console.error(error));
});
return button;
}
/** Build the action that removes an unused alias. */
#deleteButton(alias, references, historicalCount) {
const button = document.createElement("button");
button.type = "button";
button.textContent = this.translate("delete-alias", "Delete alias");
button.disabled = references.length > 0;
button.addEventListener("click", () => {
this.#delete(alias, historicalCount).catch((error) => console.error(error));
});
return button;
}
/** Confirm, perform and report reference cleanup for one alias. */
async #cleanup(alias) {
const question = this.translate(
"cleanup-alias-confirm",
"Replace all current references to this old address with the current address? Historical versions will not be changed.");
if (!window.confirm(question)) return;
const result = await this.api(`/api/admin/aliases/${alias.id}/cleanup`, {
method: "POST"
});
await this.reloadPages();
await this.load();
this.status.textContent =
`${this.translate("cleanup-complete", "Cleanup complete")}: ${result.changedPages || 0}`;
}
/** Confirm and remove one alias that has no current references. */
async #delete(alias, historicalCount) {
const warning = historicalCount > 0
? this.translate(
"delete-alias-history-confirm",
"Delete this alias? Historical page versions still contain this old address and those links may stop resolving.")
: this.translate("delete-alias-confirm", "Delete this alias?");
if (!window.confirm(warning)) return;
await this.api(`/api/admin/aliases/${alias.id}`, { method: "DELETE" });
await this.reloadPages();
await this.load();
}
}
export { AliasAdmin };