even better sandbox

This commit is contained in:
りき萌 2024-02-18 12:10:02 +01:00
parent 0580db6c68
commit 668e9a050e
10 changed files with 169 additions and 19 deletions

View file

@ -200,12 +200,25 @@ class OutputMode {
clearResults() {
this.frame.replaceChildren();
}
static messageOutputArrayToString(output) {
return output
.map(x => {
if (typeof x === "object") return JSON.stringify(x);
else return x + "";
})
.join(" ");
}
}
class GraphicsMode {
constructor(frame) {
this.frame = frame;
this.error = document.createElement("pre");
this.error.classList.add("error");
this.frame.appendChild(this.error);
this.iframe = document.createElement("iframe");
this.iframe.classList.add("hidden");
this.iframe.src = import.meta.resolve("../../html/sandbox.html");
@ -213,15 +226,20 @@ class GraphicsMode {
this.iframe.contentWindow.addEventListener("message", event => {
let message = event.data;
if (message.kind == "resize") {
if (message.kind == "ready") {
this.evaluate();
}
else if (message.kind == "resize") {
this.resize(message);
} else if (message.kind == "output" && message.output.kind == "error") {
this.error.textContent = OutputMode.messageOutputArrayToString(message.output.message);
this.iframe.classList.add("hidden");
} else if (message.kind == "evalComplete") {
this.error.textContent = "";
}
});
this.iframe.contentWindow.addEventListener("DOMContentLoaded", () => this.evaluate());
this.frame.program.onChanged.push(_ => this.evaluate());
this.evaluate();
}
evaluate() {

View file

@ -18,7 +18,22 @@ async function withTemporaryGlobalScope(callback) {
}
}
export async function evaluate(commands) {
let evaluationComplete = null;
export async function evaluate(commands, { start, success, error }) {
if (evaluationComplete != null) {
await evaluationComplete;
}
if (start != null) {
start();
}
let signalEvaluationComplete;
evaluationComplete = new Promise((resolve, _reject) => {
signalEvaluationComplete = resolve;
})
outputIndex = 0;
try {
await withTemporaryGlobalScope(async scope => {
@ -34,15 +49,25 @@ export async function evaluate(commands) {
}
}
});
} catch (error) {
if (success != null) {
success();
}
postMessage({
kind: "evalComplete",
});
} catch (err) {
postMessage({
kind: "output",
output: {
kind: "error",
message: [error.toString()],
message: [err.toString()],
},
outputIndex,
});
if (error != null) {
error();
}
}
signalEvaluationComplete();
}

View file

@ -18,6 +18,6 @@ globalThis.console = {
addEventListener("message", async event => {
let message = event.data;
if (message.action == "eval") {
evaluate(message.input);
evaluate(message.input, {});
}
});

View file

@ -1,3 +1,15 @@
export const internals = {
body: document.createElement("body"),
};
export function body() {
return internals.body;
}
export function addElement(element) {
body().appendChild(element);
}
export class Sketch {
constructor(width, height) {
this.canvas = document.createElement("canvas");
@ -5,6 +17,6 @@ export class Sketch {
this.canvas.height = height;
this.ctx = this.canvas.getContext("2d");
document.body.appendChild(this.canvas);
addElement(this.canvas);
}
}

View file

@ -306,8 +306,8 @@ export function CodeJar(editor, highlight, opt = {}) {
}
}
function handleSelfClosingCharacters(event) {
const open = `([{'"`;
const close = `)]}'"`;
const open = `([{'"\``;
const close = `)]}'"\``;
if (open.includes(event.key)) {
preventDefault(event);
const pos = save();