refactoring van de cmap structuren bijna compleet

This commit is contained in:
2026-09-03 16:21:21 +02:00
parent 1abc84489f
commit bd1ef6bed0
75 changed files with 2547 additions and 1967 deletions
@@ -0,0 +1,66 @@
"use strict";
import { escapeHtml } from "../../cmap/cmap-utils.js";
/** Render wiki-specific HTML content for CMap editor items. */
export class CmapEditorPresentation {
constructor({ state, translate, canonicalPageReference, referenceIndex }) {
this.state = state;
this.translate = translate;
this.canonicalPageReference = canonicalPageReference;
this.referenceIndex = referenceIndex;
}
renderItem(record) {
const safeLabel = escapeHtml(record.label || "");
const safeSynopsis = escapeHtml(record.synopsis || "");
const safeKind = escapeHtml(record.kind || "concept");
const safeImageSource = escapeHtml(record.imageSource || "");
const image = safeImageSource ? `<img class="cmap-card-image" src="${safeImageSource}" alt="">` : "";
const aspects = (Array.isArray(record.aspects) ? record.aspects : [])
.map((aspect) => `<span class="cmap-card-aspect">${escapeHtml(aspect)}</span>`)
.join("");
const aspectList = aspects ? `<div class="cmap-card-aspects">${aspects}</div>` : "";
const personNames = (Array.isArray(record.tags) ? record.tags : [])
.filter((tag) => tag && typeof tag === "object" && tag.type === "person" && tag.value)
.map((tag) => String(tag.value));
const peopleLabel = personNames.length ?
this.translate("person-tags-title", "Responsibility/action: {people}").replace("{people}", personNames.join(", ")) : "";
const personTags = personNames.length ?
`<div class="cmap-card-people" title="${escapeHtml(peopleLabel)}"><span aria-hidden="true">&#128100;</span> ${personNames.map(escapeHtml).join(" · ")}</div>` : "";
const usageCount = record.conceptId && record.kind !== "phrase" ?
this.conceptUsage(record) : null;
const usageLabel = usageCount === null ? "" :
this.translate("concept-usage-count", "{count} placements across all concept maps")
.replace("{count}", String(usageCount));
const usage = usageCount === null ? "" :
`<span class="cmap-card-usage" title="${escapeHtml(usageLabel)}">(${usageCount})</span>`;
const descriptionReference = this.canonicalPageReference(record.descriptionPageSlug || "");
const descriptionExists = Boolean(descriptionReference &&
this.state.pages.some((page) => page.slug === descriptionReference));
const descriptionButton = record.descriptionPageSlug ?
`<button type="button" class="rw-cmap-view-description ${descriptionExists ? "is-filled" : "is-empty"}" aria-label="${escapeHtml(this.translate("view-concept-description", "View concept description"))}">I</button>` : "";
const linkedTarget = record.pageSlug || record.cmapSlug || record.parentCmapLink;
const linkedButton = linkedTarget && record.kind !== "submap" ?
`<button type="button" class="rw-cmap-open-linked" title="${escapeHtml(this.translate("open-linked-item", "Open linked page or CMap"))}" aria-label="${escapeHtml(this.translate("open-linked-item", "Open linked page or CMap"))}">↗</button>` : "";
const externalButton = record.externalUrl ?
`<button type="button" class="rw-cmap-open-external" aria-label="${escapeHtml(this.translate("open-external-web-page", "Open external web page"))}">↗</button>` : "";
const linkedCmapClass = record.cmapSlug || record.parentCmapLink ? " cmap-card-linked-cmap" : "";
return `<div class="cmap-card cmap-card-${safeKind}${linkedCmapClass}">${descriptionButton}${linkedButton}${externalButton}${image}<div class="cmap-card-title">${safeLabel} ${usage}</div>${aspectList}${personTags}${safeSynopsis ? `<div class="cmap-card-synopsis">${safeSynopsis}</div>` : ""}</div>`;
}
conceptUsage(record) {
const maps = this.referenceIndex.byConceptId.get(record.conceptId);
const storedTotal = maps ? Array.from(maps.values()).reduce((sum, entry) =>
sum + (typeof entry === "number" ? entry : Number(entry.count) || 0), 0) : 0;
const editor = this.state.cmapPrototype?.editor;
if (!editor || !editor.containsItemRecord(record)) {
return Math.max(1, storedTotal || Number(record.usageCount) || 1);
}
const currentSlug = this.state.currentConceptMapSource?.slug ||
this.state.currentConceptMap?.slug || null;
const entry = currentSlug && maps ? maps.get(currentSlug) : null;
const current = typeof entry === "number" ? entry : Number(entry?.count) || 0;
return Math.max(1, storedTotal - current + (Number(record.usageCount) || 1));
}
}