167 lines
6.2 KiB
JavaScript
167 lines
6.2 KiB
JavaScript
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 };
|