Files
racket-wiki/static/js/widgets/description-preview.js
T

66 lines
2.0 KiB
JavaScript

import { Tooltip } from "./tooltip.js";
/**
* Load and display rendered wiki-page content as a concept description.
*
* DescriptionPreview caches rendered pages for the lifetime of the workspace.
* A sequence token prevents a slow request from replacing a newer preview.
*/
export class DescriptionPreview {
constructor(loadPage, renderMarkdown) {
const element = document.createElement("div");
element.id = "cmap-description-tooltip";
element.className = "cmap-description-tooltip hidden";
element.setAttribute("role", "tooltip");
document.body.append(element);
this.tooltip = new Tooltip(element);
this.loadPage = loadPage;
this.renderMarkdown = renderMarkdown;
this.cache = new Map();
this.sequence = 0;
}
hide() {
this.sequence += 1;
this.tooltip.hide();
}
clear() {
this.cache.clear();
this.hide();
}
/** Load a referenced wiki page and show it beside the supplied anchor. */
async show(anchor, reference, loadingText = "Loading…") {
if (!anchor.classList.contains("is-filled") || !reference) return;
const sequence = ++this.sequence;
this.tooltip.show(anchor);
this.tooltip.setText(loadingText);
try {
let preview = this.cache.get(reference);
if (preview === undefined) {
const page = await this.loadPage(reference);
preview = String(page.markdown || "").trim() ?
this.renderMarkdown(page.markdown, page.slug) : null;
this.cache.set(reference, preview);
}
if (sequence !== this.sequence) return;
if (!preview) {
anchor.classList.remove("is-filled");
anchor.classList.add("is-empty");
this.tooltip.hide();
return;
}
this.tooltip.setHtml(`<article class="markdown-body">${preview}</article>`);
} catch (error) {
if (sequence !== this.sequence) return;
anchor.classList.remove("is-filled");
anchor.classList.add("is-empty");
this.tooltip.hide();
if (error.status !== 404) console.error(error);
}
}
}