import { parse } from "wmap-parser"; import { renderToCanvas } from "wmap-renderer-canvas"; import DOMPurify from "isomorphic-dompurify"; const internals = { kStyleSheet: "/plugins/wmap/wmap.css", kCanvasWidth: 1384, kCanvasHeight: 1884, // Returns HTML that shows a message in the wiki. message(text) { return `
${text}
`; }, // Creates a wmap PNG from text. async renderImage(source) { const parsedText = parse(source); const canvas = document.createElement("canvas"); canvas.width = internals.kCanvasWidth; canvas.height = internals.kCanvasHeight; await renderToCanvas(parsedText, canvas); return canvas.toDataURL(); }, // Starts a download of the image. download(filename, text) { var element = document.createElement("a"); element.setAttribute("href", text); element.setAttribute("download", filename); element.style.display = "none"; document.body.appendChild(element); element.click(); document.body.removeChild(element); }, // Replaces the image in a window. Intended for use in a dialog. replaceImage(window, imageData) { const $container = window.document.querySelector("main"); $container.querySelectorAll("img").forEach((img) => img.remove()); const image = document.createElement("img"); image.src = imageData; image.alt = "Wardley map rendered from source."; $container.appendChild(image); }, }; /** * Runs once for each block. Do setup for the block before rendering. */ const emit = function emit($item) { const hasStyleSheet = [...document.styleSheets].some((styleSheet) => styleSheet.href.endsWith(internals.kStyleSheet), ); if (!hasStyleSheet) { console.log("Adding wmap stylesheet."); const link = document.createElement("link"); link.rel = "stylesheet"; link.href = internals.kStyleSheet; link.type = "text/css"; document.getElementsByTagName("head")[0].appendChild(link); } return $item.append(internals.message("Loading Wardley Map")); }; /** * Bind to events on the rendered block. Called once per block. * Convention is that double click opens the editor. * * @param {JQuery} $item the HTML element representing hte block. * @param {Object} item the configuration for that particular object. */ const bind = async function bind($item, item) { $item.on("dblclick", () => { return wiki.textEditor($item, item); }); $item.on("click", "a", (event) => { const { currentTarget } = event; const action = currentTarget.dataset?.action; if (!action) { return; } event.stopPropagation(); event.preventDefault(); switch (action) { case "download": { const slug = $item.parents(".page").attr("id"); internals.download(`${slug}.png`, item.png); } break; case "zoom": { const shouldOpenStandalone = !!event.shiftKey; const target = shouldOpenStandalone ? "_blank" : "wmap"; const dialog = window.open( "/plugins/wmap/dialog/#", target, "popup,height=600,width=800", ); if (dialog.location.pathname !== "/plugins/wmap/dialog/") { dialog.addEventListener("load", () => { internals.replaceImage(dialog, item.png); }); } else { internals.replaceImage(dialog, item.png); } } break; } }); try { let imageData = await internals.renderImage(item.text); item.png = imageData; $item.find(".viewer").html(`
`); } catch (err) { console.log("Failed to parse wardley map: ", err); $item.html(internals.message(err.message)); } }; /** * On load, attempt to add the emit and bind functions to window, as these * are called by the wiki plugin manager. */ if (typeof window !== "undefined" && window !== null) { if (!window.plugins.wmap) { window.plugins.wmap = { emit, bind }; } } const expand = function (text) { return DOMPurify.sanitize(text); }; export const wmap = typeof window === "undefined" ? { expand } : undefined;