/** * Edit CMap metadata without knowing how the active CMap is persisted. * * The controller owns field population and validation. Its save handler * receives normalized metadata and reports success with a boolean result. */ export class CmapMetadataDialog { constructor(dialog, tr, normalizePageReference) { this.dialog = dialog; this.tr = tr; this.normalizePageReference = normalizePageReference; this.form = dialog.querySelector("form"); this.summary = dialog.querySelector("#cmap-metadata-summary"); this.namespace = dialog.querySelector("#cmap-metadata-namespace"); this.tags = dialog.querySelector("#cmap-metadata-tags"); this.explanationPage = dialog.querySelector("#cmap-metadata-explanation-page"); this.saveHandler = null; dialog.querySelector("#cmap-metadata-cancel") .addEventListener("click", () => dialog.close()); this.explanationPage.addEventListener("input", () => this.explanationPage.setCustomValidity("")); this.form.addEventListener("submit", (event) => { event.preventDefault(); this.save().catch((error) => window.alert(error.message)); }); } onSave(handler) { this.saveHandler = handler; return this; } open(metadata) { this.namespace.value = metadata.namespace || ""; this.summary.value = metadata.summary || ""; this.tags.value = (metadata.tags || []).join(", "); this.explanationPage.value = metadata.explanationPageSlug || ""; this.explanationPage.setCustomValidity(""); this.dialog.showModal(); this.summary.focus(); } metadata() { const namespace = this.namespace.value.trim().toLocaleLowerCase(); if (namespace && !/^[\p{L}\p{N}][\p{L}\p{N}-]*$/u.test(namespace)) { this.namespace.setCustomValidity( this.tr("invalid-concept-map-namespace", "Use letters, numbers and hyphens for the namespace.")); this.namespace.reportValidity(); return null; } this.namespace.setCustomValidity(""); const explanationInput = this.explanationPage.value.trim(); const explanationPageSlug = explanationInput ? this.normalizePageReference(explanationInput) : ""; if (explanationInput && !explanationPageSlug) { this.explanationPage.setCustomValidity( this.tr("invalid-description-page", "Enter a valid description page address.")); this.explanationPage.reportValidity(); return null; } return { namespace, tags: this.tags.value.split(",").map((tag) => tag.trim()).filter(Boolean), summary: this.summary.value.trim(), explanationPageSlug }; } async save() { const metadata = this.metadata(); if (!metadata || !this.saveHandler) return false; const saved = await this.saveHandler(metadata); if (saved) this.dialog.close(); return saved; } }