108 lines
3.4 KiB
JavaScript
108 lines
3.4 KiB
JavaScript
import { StatusField } from "../../../widgets/status-field.js";
|
|
|
|
/**
|
|
* Run the user-facing Markdown and JSON export actions for one CMap.
|
|
*
|
|
* Export generation is supplied by the workspace. This controller owns export
|
|
* options, progress messages, clipboard handling and browser downloads.
|
|
*/
|
|
export class CmapExportDialog {
|
|
constructor(dialog, tr, buildMarkdown, buildJson) {
|
|
this.dialog = dialog;
|
|
this.tr = tr;
|
|
this.buildMarkdown = buildMarkdown;
|
|
this.buildJson = buildJson;
|
|
this.form = dialog.querySelector("form");
|
|
this.depth = dialog.querySelector("#cmap-export-depth");
|
|
this.pages = dialog.querySelector("#cmap-export-pages");
|
|
this.status = new StatusField(dialog.querySelector("#cmap-export-status"));
|
|
this.conceptMapSlug = "concept-map";
|
|
|
|
dialog.querySelector("#cmap-export-cancel").addEventListener("click", () => dialog.close());
|
|
dialog.querySelector("#cmap-export-copy").addEventListener("click", () => {
|
|
this.exportMarkdown(false);
|
|
});
|
|
dialog.querySelector("#cmap-export-json").addEventListener("click", () => {
|
|
this.exportJson();
|
|
});
|
|
this.form.addEventListener("submit", (event) => {
|
|
event.preventDefault();
|
|
this.exportMarkdown(true);
|
|
});
|
|
}
|
|
|
|
open(conceptMapSlug) {
|
|
this.conceptMapSlug = conceptMapSlug;
|
|
this.status.clear();
|
|
this.dialog.showModal();
|
|
this.depth.focus();
|
|
}
|
|
|
|
options() {
|
|
return {
|
|
depth: Math.max(0, Math.min(10, Number(this.depth.value) || 0)),
|
|
includeWikiPages: this.pages.checked
|
|
};
|
|
}
|
|
|
|
async exportJson() {
|
|
this.status.set(this.tr("preparing-cmap-json", "Preparing complete CMap JSON…"));
|
|
try {
|
|
const bundle = await this.buildJson(this.options().depth);
|
|
this.download(`${JSON.stringify(bundle, null, 2)}\n`,
|
|
`${bundle.rootCmapSlug}-cmap.json`, "application/json;charset=utf-8");
|
|
this.status.set(this.tr("cmap-json-downloaded", "CMap JSON downloaded."));
|
|
return true;
|
|
} catch (error) {
|
|
this.status.set(error.message);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
async exportMarkdown(download) {
|
|
this.status.set(this.tr("preparing-markdown-export", "Preparing Markdown export…"));
|
|
try {
|
|
const markdown = await this.buildMarkdown(this.options());
|
|
if (download) {
|
|
this.download(markdown, `${this.conceptMapSlug}-report.md`,
|
|
"text/markdown;charset=utf-8");
|
|
this.status.set(this.tr("markdown-export-downloaded", "Markdown export downloaded."));
|
|
} else {
|
|
await this.copy(markdown);
|
|
this.status.set(this.tr("markdown-export-copied", "Markdown export copied."));
|
|
}
|
|
return true;
|
|
} catch (error) {
|
|
this.status.set(error.message);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
download(text, filename, contentType) {
|
|
const blob = new Blob([text], { type: contentType });
|
|
const url = URL.createObjectURL(blob);
|
|
const link = document.createElement("a");
|
|
link.href = url;
|
|
link.download = filename;
|
|
document.body.append(link);
|
|
link.click();
|
|
link.remove();
|
|
window.setTimeout(() => URL.revokeObjectURL(url), 0);
|
|
}
|
|
|
|
async copy(text) {
|
|
try {
|
|
await navigator.clipboard.writeText(text);
|
|
} catch (_error) {
|
|
const input = document.createElement("textarea");
|
|
input.value = text;
|
|
input.style.position = "fixed";
|
|
input.style.left = "-10000px";
|
|
document.body.append(input);
|
|
input.select();
|
|
document.execCommand("copy");
|
|
input.remove();
|
|
}
|
|
}
|
|
}
|