Spaces:
Running
Running
File size: 2,641 Bytes
7547388 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | (() => {
let frame = null;
let ready = false;
let bootPromise = null;
let resolveBoot = null;
let rejectBoot = null;
let timeout = null;
let runId = 0;
let activeRunId = 0;
let onMessage = () => {};
function receive(event) {
if (!frame || event.source !== frame.contentWindow) return;
const message = event.data || {};
if (message.type === "ready") {
ready = true;
clearTimeout(timeout);
timeout = null;
resolveBoot?.();
resolveBoot = null;
rejectBoot = null;
bootPromise = null;
return;
}
if (message.type === "load_error") {
const error = new Error(message.text || "無法載入瀏覽器版 Pygame");
clearTimeout(timeout);
timeout = null;
rejectBoot?.(error);
resolveBoot = null;
rejectBoot = null;
bootPromise = null;
onMessage({ ...message, runId: activeRunId });
return;
}
if (message.runId && message.runId !== activeRunId) return;
onMessage(message);
}
window.addEventListener("message", receive);
window.ClassroomPygame = {
attach(target, handler) {
frame = target;
onMessage = handler;
},
isPygame(files) {
return Object.entries(files || {}).some(([path, code]) =>
path.toLowerCase().endsWith(".py") &&
/^\s*(?:import\s+pygame(?:\s|,|$)|from\s+pygame(?:\.|\s+import\s))/m.test(code)
);
},
async run(files) {
const thisRun = ++runId;
activeRunId = thisRun;
frame.hidden = false;
if (!ready) {
if (!bootPromise) {
bootPromise = new Promise((resolve, reject) => {
resolveBoot = resolve;
rejectBoot = reject;
timeout = setTimeout(() => {
const error = new Error("Pygame 載入逾時,請確認網路連線後重試。");
bootPromise = null;
resolveBoot = null;
rejectBoot = null;
reject(error);
}, 60000);
frame.src = "/classroom-assets/pygame-runner.html?v=2026fall-1";
});
}
await bootPromise;
}
if (thisRun !== runId) return;
frame.contentWindow.postMessage({ type: "run", runId: thisRun, files }, "*");
},
stop() {
++runId;
activeRunId = runId;
ready = false;
clearTimeout(timeout);
timeout = null;
if (rejectBoot) rejectBoot(new Error("Pygame 已停止"));
resolveBoot = null;
rejectBoot = null;
bootPromise = null;
if (frame) {
frame.hidden = true;
frame.src = "about:blank";
}
},
};
})();
|