refactoring
This commit is contained in:
@@ -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 };
|
||||
Reference in New Issue
Block a user