note fallback
<script>
(function () {
var content = document.getElementById("content");
if (!content) return;
var m = document.body.className.match(/type-([\w-]+)/);
var type = m ? m[1] : "";
var widgetTypes = ["mermaid", "canvas", "mindMap", "webView", "relationMap", "spreadsheet", "search", "geo"];
if (widgetTypes.indexOf(type) === -1) return;
if (content.querySelector("svg, iframe, canvas, .excalidraw, .mindmap, .mermaid")) return;
var clone = content.cloneNode(true);
clone.querySelectorAll("script, style, nav, a, .blog-prevnext, .reading-time").forEach(function (el) { el.remove(); });
var raw = (clone.textContent || "").trim();
if (!raw) return;
function makePre(text) {
var pre = document.createElement("pre");
pre.className = "note-fallback";
var code = document.createElement("code");
code.className = "language-json";
code.textContent = text;
pre.appendChild(code);
applyHighlight(code);
return pre;
}
var hljsLoading = false;
function applyHighlight(codeEl) {
if (window.hljs) {
codeEl.classList.add("hljs");
try { hljs.highlightElement(codeEl); } catch (e) {}
if (window.hljs.lineNumbersBlock) {
try { hljs.lineNumbersBlock(codeEl); } catch (e) {}
}
return;
}
if (hljsLoading) {
setTimeout(function () { applyHighlight(codeEl); }, 200);
return;
}
hljsLoading = true;
var s = document.createElement("script");
s.src = "api/notes/vuVkfngB4d0j/download";
s.onload = function () {
if (window.hljs && window.hljs.lineNumbersBlock) { applyHighlight(codeEl); return; }
var p = document.createElement("script");
p.src = "api/notes/eHpLkUWWMEaM/download";
p.onload = function () { applyHighlight(codeEl); };
document.head.appendChild(p);
};
document.head.appendChild(s);
}
if (type === "mermaid") {
content.querySelectorAll("img, hr").forEach(function (el) { el.remove(); });
var nativePre = content.querySelector("pre");
if (!nativePre) return;
var src = nativePre.textContent;
if (!src.trim()) return;
var nativeDetails = nativePre.closest("details");
var wrapper = document.createElement("div");
wrapper.className = "mermaid-render";
var diagram = document.createElement("div");
diagram.className = "mermaid-diagram";
var details = document.createElement("details");
details.className = "mermaid-source";
var summary = document.createElement("summary");
summary.textContent = "Source";
var pre = document.createElement("pre");
var code = document.createElement("code");
code.textContent = src;
pre.appendChild(code);
addCopyButton(pre, src);
details.appendChild(summary);
details.appendChild(pre);
wrapper.appendChild(diagram);
wrapper.appendChild(details);
(nativeDetails || nativePre).replaceWith(wrapper);
applyHighlight(code);
var MMD_DARK = {
background: "transparent",
textColor: "#ebdbb2",
titleColor: "#fbf1c7",
lineColor: "#a89984",
edgeLabelBackground: "#3c3836",
nodeTextColor: "#fbf1c7",
primaryColor: "#458588", primaryTextColor: "#fbf1c7", primaryBorderColor: "#458588",
secondaryColor: "#b8bb26", secondaryTextColor: "#1d2021", secondaryBorderColor: "#b8bb26",
tertiaryColor: "#d3869b", tertiaryTextColor: "#1d2021", tertiaryBorderColor: "#d3869b"
};
var MMD_LIGHT = {
background: "transparent",
textColor: "#3c3836",
titleColor: "#282828",
lineColor: "#928374",
edgeLabelBackground: "#ebdbb2",
nodeTextColor: "#1d2021",
primaryColor: "#83a598", primaryTextColor: "#1d2021", primaryBorderColor: "#076678",
secondaryColor: "#98971a", secondaryTextColor: "#fbf1c7", secondaryBorderColor: "#79740e",
tertiaryColor: "#b16286", tertiaryTextColor: "#fbf1c7", tertiaryBorderColor: "#8f3f71"
};
function mermaidConfig() {
var light = document.documentElement.classList.contains("theme-light");
return { startOnLoad: false, theme: "base", themeVariables: light ? MMD_LIGHT : MMD_DARK };
}
function renderMermaid() {
import("/assets/mermaid.core-BUJU3YJZ.js").then(function (mod) {
var mermaid = mod.default;
mermaid.initialize(mermaidConfig());
return mermaid.render("mm-" + Date.now(), src);
}).then(function (res) {
diagram.innerHTML = res.svg;
diagram.querySelectorAll(".node rect, .cluster rect").forEach(function (r) {
var rad = Math.min(8, Math.min(parseFloat(r.getAttribute("width") || 50), parseFloat(r.getAttribute("height") || 50)) * 0.15);
r.setAttribute("rx", rad);
r.setAttribute("ry", rad);
});
}).catch(function () {
diagram.textContent = src;
});
}
renderMermaid();
var themeInput = document.querySelector(".theme-selection input");
if (themeInput) {
themeInput.addEventListener("change", renderMermaid);
}
return;
}
if (type === "webView") {
var p = document.createElement("p");
p.className = "note-fallback note-fallback-link";
p.innerHTML = "Embedded page: <a href=\"" + raw + "\" target=\"_blank\" rel=\"noopener noreferrer\">" + raw + "</a>";
content.appendChild(p);
return;
}
var NS = "http://www.w3.org/2000/svg";
function svgEl(name, attrs) {
var n = document.createElementNS(NS, name);
for (var k in attrs) n.setAttribute(k, attrs[k]);
return n;
}
function fallbackCopy(text, done) {
var ta = document.createElement("textarea");
ta.value = text;
ta.style.position = "fixed";
ta.style.opacity = "0";
document.body.appendChild(ta);
ta.select();
try { document.execCommand("copy"); } catch (e) {}
document.body.removeChild(ta);
done();
}
function addCopyButton(pre, text) {
var btn = document.createElement("button");
btn.className = "code-copy-btn";
btn.type = "button";
btn.textContent = "Copy";
btn.addEventListener("click", function () {
var done = function () {
btn.textContent = "Copied";
setTimeout(function () { btn.textContent = "Copy"; }, 1500);
};
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).then(done, function () { fallbackCopy(text, done); });
} else {
fallbackCopy(text, done);
}
});
pre.appendChild(btn);
}
function makeSourceDetails(text) {
var details = document.createElement("details");
details.className = "mermaid-source";
var summary = document.createElement("summary");
summary.textContent = "Source";
var pre = document.createElement("pre");
var code = document.createElement("code");
code.className = "language-json";
code.textContent = text;
pre.appendChild(code);
addCopyButton(pre, text);
details.appendChild(summary);
details.appendChild(pre);
applyHighlight(code);
return details;
}
/* ---------- MindMap (MindElixir data) ---------- */
var MIND_DARK = [
{ bg: "#458588", bd: "#3a6b70", text: "#fbf1c7" },
{ bg: "#b8bb26", bd: "#98971a", text: "#1d2021" },
{ bg: "#d3869b", bd: "#b16286", text: "#1d2021" },
{ bg: "#8ec07c", bd: "#689d6a", text: "#1d2021" },
{ bg: "#fe8019", bd: "#d65d0e", text: "#1d2021" }
];
var MIND_LIGHT = [
{ bg: "#83a598", bd: "#458588", text: "#1d2021" },
{ bg: "#98971a", bd: "#79740e", text: "#fbf1c7" },
{ bg: "#b16286", bd: "#8f3f71", text: "#fbf1c7" },
{ bg: "#427b58", bd: "#3a6350", text: "#fbf1c7" },
{ bg: "#af3a03", bd: "#8f3003", text: "#fbf1c7" }
];
function mindPalette() {
return document.documentElement.classList.contains("theme-light") ? MIND_LIGHT : MIND_DARK;
}
function mindEdgeColor() {
return document.documentElement.classList.contains("theme-light") ? "#928374" : "#a89984";
}
function mindSize(topic, fontSize) {
var lines = String(topic || "").split("\n");
var w = 0;
for (var i = 0; i < lines.length; i++) w = Math.max(w, lines[i].length * fontSize * 0.62);
return { w: Math.max(w + 24, 56), h: Math.max(lines.length * (fontSize + 6) + 10, 32) };
}
function mindSubHeight(n, depth) {
n.depth = depth;
var fs = depth === 0 ? 16 : 14;
n.box = mindSize(n.topic, fs);
if (n.children && n.children.length) {
var sum = 0;
for (var i = 0; i < n.children.length; i++) sum += mindSubHeight(n.children[i], depth + 1);
n.childSpan = sum + (n.children.length - 1) * 18;
n.total = Math.max(n.box.h, n.childSpan);
} else {
n.total = n.box.h;
}
return n.total;
}
function mindPlace(n, x, side, yTop) {
n.x = x - n.box.w / 2;
n.y = yTop + (n.total - n.box.h) / 2;
if (!n.children || !n.children.length) return;
var cursor = yTop;
for (var i = 0; i < n.children.length; i++) {
var c = n.children[i];
var childSide = side === 0 ? (i % 2 === 0 ? -1 : 1) : side;
var childX = x + childSide * (n.box.w / 2 + 46 + c.box.w / 2);
mindPlace(c, childX, childSide, cursor);
cursor += c.total + 18;
}
}
function renderMindMap(nodeData) {
var wrap = document.createElement("div");
wrap.className = "mindmap-render";
var root = nodeData;
mindSubHeight(root, 0);
mindPlace(root, 0, 0, -root.total / 2);
var minX = 1e9, minY = 1e9, maxX = -1e9, maxY = -1e9;
(function walk(n) {
minX = Math.min(minX, n.x); maxX = Math.max(maxX, n.x + n.box.w);
minY = Math.min(minY, n.y); maxY = Math.max(maxY, n.y + n.box.h);
if (n.children) n.children.forEach(walk);
})(root);
var pad = 34;
var MIND = mindPalette();
var EDGE = mindEdgeColor();
var W = maxX - minX + pad * 2, H = maxY - minY + pad * 2;
var svg = svgEl("svg", { class: "mindmap-svg", viewBox: (minX - pad) + " " + (minY - pad) + " " + W + " " + H, width: W, height: H });
function draw(n) {
var col = MIND[Math.min(n.depth, MIND.length - 1)];
var g = svgEl("g");
g.appendChild(svgEl("rect", { x: n.x, y: n.y, width: n.box.w, height: n.box.h, rx: 8, fill: col.bg, stroke: col.bd, "stroke-width": 1.5 }));
var lines = String(n.topic || "").split("\n");
var fs = n.depth === 0 ? 16 : 14;
var lh = fs + 5;
for (var i = 0; i < lines.length; i++) {
var t = svgEl("text", { x: n.x + n.box.w / 2, y: n.y + n.box.h / 2 - ((lines.length - 1) * lh) / 2 + i * lh, "text-anchor": "middle", "dominant-baseline": "central", "font-size": fs, fill: col.text, "font-family": "sans-serif" });
t.textContent = lines[i];
g.appendChild(t);
}
svg.appendChild(g);
if (n.children) n.children.forEach(function (c) {
var sy = n.y + n.box.h / 2, ey = c.y + c.box.h / 2;
var sx = c.x > n.x ? n.x + n.box.w : n.x;
var ex = c.x > n.x ? c.x : c.x + c.box.w;
var dir = ex >= sx ? 1 : -1;
var dx = Math.max(26, Math.min(56, Math.abs(ex - sx) * 0.4));
var lead = dx * 0.5;
svg.appendChild(svgEl("path", {
d: "M " + sx + " " + sy +
" L " + (sx + dir * lead) + " " + sy +
" C " + (sx + dir * dx) + " " + sy + " " + (ex - dir * dx) + " " + ey + " " + (ex - dir * lead) + " " + ey +
" L " + ex + " " + ey,
fill: "none", stroke: EDGE, "stroke-width": 2.5,
"stroke-linecap": "round", "stroke-linejoin": "round"
}));
draw(c);
});
}
draw(root);
wrap.appendChild(svg);
return wrap;
}
/* ---------- Canvas (Excalidraw) ---------- */
function renderExcalidraw(elements) {
var wrap = document.createElement("div");
wrap.className = "excalidraw-render";
var els = elements.filter(function (e) { return e && !e.isDeleted; });
if (!els.length) { wrap.textContent = "Empty canvas"; return wrap; }
var pad = 40;
var minX = 1e9, minY = 1e9, maxX = -1e9, maxY = -1e9;
els.forEach(function (e) {
minX = Math.min(minX, e.x); minY = Math.min(minY, e.y);
maxX = Math.max(maxX, e.x + e.width); maxY = Math.max(maxY, e.y + e.height);
});
var W = maxX - minX + pad * 2, H = maxY - minY + pad * 2;
var svg = svgEl("svg", { class: "excalidraw-svg", viewBox: (minX - pad) + " " + (minY - pad) + " " + W + " " + H, width: W, height: H });
els.forEach(function (e) {
var g = svgEl("g");
if (e.angle) g.setAttribute("transform", "rotate(" + (e.angle * 180 / Math.PI) + " " + (e.x + e.width / 2) + " " + (e.y + e.height / 2) + ")");
if (typeof e.opacity === "number" && e.opacity < 100) g.setAttribute("opacity", e.opacity / 100);
var sc = e.strokeColor || "#282828", bg = e.backgroundColor || "transparent", sw = Math.max(1, e.strokeWidth || 2);
var filled = bg && bg !== "transparent";
var fillOp = e.fillStyle === "solid" ? 1 : 0.35;
function strokeShape(shape) {
if (filled) { shape.setAttribute("fill", bg); shape.setAttribute("fill-opacity", fillOp); }
else shape.setAttribute("fill", "none");
shape.setAttribute("stroke", sc); shape.setAttribute("stroke-width", sw);
g.appendChild(shape);
}
if (e.type === "rectangle") {
strokeShape(svgEl("rect", { x: e.x, y: e.y, width: e.width, height: e.height, rx: Math.min(8, Math.min(e.width, e.height) * 0.08) }));
} else if (e.type === "ellipse") {
strokeShape(svgEl("ellipse", { cx: e.x + e.width / 2, cy: e.y + e.height / 2, rx: e.width / 2, ry: e.height / 2 }));
} else if (e.type === "diamond") {
var cx = e.x + e.width / 2, cy = e.y + e.height / 2;
strokeShape(svgEl("polygon", { points: cx + "," + e.y + " " + (e.x + e.width) + "," + cy + " " + cx + "," + (e.y + e.height) + " " + e.x + "," + cy }));
} else if (e.type === "line" || e.type === "arrow") {
var pts = e.points || [];
if (!pts.length) return;
var coords = pts.map(function (pt) { return (e.x + pt[0]) + "," + (e.y + pt[1]); }).join(" ");
strokeShape(svgEl("polyline", { points: coords }));
if (e.type === "arrow" && pts.length > 1) {
var last = pts[pts.length - 1], prev = pts[pts.length - 2];
var ang = Math.atan2(last[1] - prev[1], last[0] - prev[0]);
var ax = e.x + last[0], ay = e.y + last[1], al = 9 + sw;
g.appendChild(svgEl("polygon", { points: (ax + Math.cos(ang) * al) + "," + (ay + Math.sin(ang) * al) + " " + (ax + Math.cos(ang + 2.6) * al * 0.6) + "," + (ay + Math.sin(ang + 2.6) * al * 0.6) + " " + (ax + Math.cos(ang - 2.6) * al * 0.6) + "," + (ay + Math.sin(ang - 2.6) * al * 0.6), fill: sc, stroke: sc }));
}
} else if (e.type === "freedraw") {
var fpts = e.points || [];
if (!fpts.length) return;
strokeShape(svgEl("path", { d: "M " + fpts.map(function (pt) { return (e.x + pt[0]) + "," + (e.y + pt[1]); }).join(" L "), "stroke-linecap": "round", "stroke-linejoin": "round" }));
} else if (e.type === "text") {
var fs = e.fontSize || 20;
var ff = e.fontFamily === 2 ? "sans-serif" : (e.fontFamily === 3 ? "monospace" : "'Comic Sans MS','Comic Sans',cursive");
var ta = e.textAlign === "left" ? "start" : (e.textAlign === "right" ? "end" : "middle");
var x = ta === "middle" ? e.x + e.width / 2 : e.x;
var y = e.verticalAlign === "top" ? e.y + fs * 0.8 : e.y + e.height / 2 + fs * 0.35;
var lines = String(e.text || "").split("\n");
var t = svgEl("text", { x: x, y: y, "font-size": fs, fill: sc, "font-family": ff, "text-anchor": ta });
for (var li = 0; li < lines.length; li++) {
var ts = document.createElementNS(NS, "tspan");
ts.setAttribute("x", x);
ts.setAttribute("dy", li === 0 ? 0 : fs * 1.2);
ts.textContent = lines[li];
t.appendChild(ts);
}
g.appendChild(t);
}
svg.appendChild(g);
});
wrap.appendChild(svg);
return wrap;
}
/* content per Download-Endpoint holen */
var noteId = document.body.getAttribute("data-note-id");
var box = document.createElement("div");
var prevnext = content.querySelector(".blog-prevnext");
if (prevnext) { content.insertBefore(box, prevnext); }
else { content.appendChild(box); }
function renderWidget() {
fetch("api/notes/" + noteId + "/download")
.then(function (r) { return r.text(); })
.then(function (text) {
var pretty = text, data = null;
try { data = JSON.parse(text); pretty = JSON.stringify(data, null, 2); } catch (e) {}
box.innerHTML = "";
var rendered = null;
if (data && type === "mindMap" && data.nodeData) rendered = renderMindMap(data.nodeData);
else if (data && type === "canvas" && Array.isArray(data.elements)) rendered = renderExcalidraw(data.elements);
if (rendered) {
rendered.appendChild(makeSourceDetails(pretty));
box.appendChild(rendered);
} else {
box.appendChild(makePre(pretty));
box.appendChild(makeSourceDetails(pretty));
}
})
.catch(function () {
box.textContent = "Content not available.";
});
}
renderWidget();
var widgetThemeInput = document.querySelector(".theme-selection input");
if (widgetThemeInput) {
widgetThemeInput.addEventListener("change", renderWidget);
}
})();
</script>