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;