Skip to content

Commit c3c5e34

Browse files
committed
Publish reusable direct WebAssembly docs runner
1 parent 1520c20 commit c3c5e34

1 file changed

Lines changed: 89 additions & 0 deletions

File tree

assets/chrome/docs-runtime.js

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/** Reusable direct MicroPython runner for first-party Read the Docs embeds. */
2+
(function () {
3+
const RUNTIME_URL = "https://PyDevices.github.io/vendor/micropython/micropython.mjs";
4+
const state = { phase: "idle", errors: [], mp: null, activeOutput: null };
5+
window.__pydevicesDocsRuntime = state;
6+
7+
function setAll(demos, text) {
8+
demos.forEach((demo) => {
9+
const status = demo.querySelector(".demo-status");
10+
if (status) status.textContent = text;
11+
});
12+
}
13+
14+
async function runtime(demos) {
15+
if (state.mp) return state.mp;
16+
state.phase = "loading"; setAll(demos, "Downloading direct MicroPython…");
17+
const { loadMicroPython } = await import(RUNTIME_URL);
18+
state.mp = await loadMicroPython({
19+
stdout: (line) => { if (state.activeOutput) state.activeOutput.textContent += `${line}\n`; },
20+
stderr: (line) => { if (state.activeOutput) state.activeOutput.textContent += `${line}\n`; },
21+
heapsize: 16 * 1024 * 1024
22+
});
23+
state.phase = "ready"; setAll(demos, "Ready");
24+
window.dispatchEvent(new CustomEvent("pydevices-docs-ready"));
25+
return state.mp;
26+
}
27+
28+
async function execute(demo, demos) {
29+
const editor = demo.querySelector(".code-editor");
30+
const canvas = demo.querySelector("canvas");
31+
const output = demo.querySelector(".demo-output");
32+
const status = demo.querySelector(".demo-status");
33+
const button = demo.querySelector(".run-btn");
34+
if (!editor || !canvas) return;
35+
if (button) button.disabled = true;
36+
if (output) output.textContent = "";
37+
if (status) status.textContent = "Running…";
38+
try {
39+
const mp = await runtime(demos);
40+
state.activeOutput = output;
41+
const source = JSON.stringify(editor.value);
42+
const canvasId = JSON.stringify(canvas.id);
43+
await mp.runPythonAsync(`
44+
from displaydev import env_set
45+
env_set("PYDEVICES_CANVAS_ID", ${canvasId})
46+
CANVAS_ID = ${canvasId}
47+
_source = ${source}
48+
exec(compile(_source, "<docs-demo>", "exec"), {"__name__": "__main__", "CANVAS_ID": CANVAS_ID})
49+
`);
50+
if (status) status.textContent = "Active";
51+
} catch (error) {
52+
const detail = String(error && (error.stack || error));
53+
state.errors.push(detail); state.phase = "failed";
54+
if (output) output.textContent += `${detail}\n`;
55+
if (status) status.textContent = "Error";
56+
console.error("Direct documentation demo failed:", error);
57+
window.dispatchEvent(new CustomEvent("pydevices-docs-failed", { detail }));
58+
} finally {
59+
state.activeOutput = null;
60+
if (button) button.disabled = false;
61+
}
62+
}
63+
64+
function init() {
65+
const demos = [...document.querySelectorAll(".pydevices-live-demo")];
66+
demos.forEach((demo, index) => {
67+
const canvas = demo.querySelector("canvas");
68+
const editor = demo.querySelector(".code-editor");
69+
const run = demo.querySelector(".run-btn");
70+
const reset = demo.querySelector(".reset-btn");
71+
if (canvas && !canvas.id) canvas.id = `live_canvas_${index}`;
72+
if (editor) demo._initialCode = editor.value;
73+
run?.addEventListener("click", () => execute(demo, demos));
74+
reset?.addEventListener("click", () => {
75+
if (editor) editor.value = demo._initialCode || "";
76+
execute(demo, demos);
77+
});
78+
});
79+
if (!demos.length) return;
80+
runtime(demos).then(() => {
81+
demos.forEach((demo) => execute(demo, demos));
82+
}).catch((error) => {
83+
state.phase = "failed"; state.errors.push(String(error));
84+
setAll(demos, "Load Failed"); console.error(error);
85+
});
86+
}
87+
if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", init);
88+
else init();
89+
})();

0 commit comments

Comments
 (0)