149 lines
3.6 KiB
JavaScript
149 lines
3.6 KiB
JavaScript
/// <reference types="ace" />
|
|
|
|
async function runCode(code, consoleCode) {
|
|
consoleCode.textContent += `\nRunning code....\n`;
|
|
try {
|
|
const module = await import(
|
|
`data:text/javascript;charset=utf-8,${encodeURIComponent(code)}`
|
|
);
|
|
module.default?.();
|
|
} catch (error) {
|
|
consoleCode.textContent += `${error}\n`;
|
|
}
|
|
}
|
|
|
|
class Debounce {
|
|
timer = null;
|
|
lastCall = 0;
|
|
|
|
constructor(timeout) {
|
|
this.timeout = timeout;
|
|
}
|
|
|
|
run(fn) {
|
|
const now = Date.now();
|
|
if (this.timer === null && now - this.lastCall > this.timeout) {
|
|
fn();
|
|
this.lastCall = now;
|
|
return;
|
|
}
|
|
if (this.timer !== null) {
|
|
clearTimeout(this.timer);
|
|
this.timer = null;
|
|
}
|
|
this.timer = setTimeout(() => {
|
|
fn();
|
|
this.lastCall = Date.now();
|
|
this.timer = null;
|
|
}, this.timeout);
|
|
}
|
|
}
|
|
|
|
const editor = ace.edit("editor");
|
|
editor.setTheme("ace/theme/gruvbox");
|
|
editor.session.setMode("ace/mode/javascript");
|
|
|
|
editor.setValue(sessionStorage.getItem("code") ?? editor.getValue(), -1);
|
|
|
|
const runButton = document.querySelector("#run-button");
|
|
const saveButton = document.querySelector("#save-button");
|
|
const saveDropdown = document.querySelector("#save-dropdown");
|
|
const saveJsButton = document.querySelector("#save-js");
|
|
const saveHtmlButton = document.querySelector("#save-html");
|
|
const consoleCode = document.querySelector("#console-code");
|
|
|
|
const sessionSaveDebounce = new Debounce(1000);
|
|
editor.addEventListener("change", (ev) => {
|
|
sessionSaveDebounce.run(() => {
|
|
sessionStorage.setItem("code", editor.getValue());
|
|
});
|
|
});
|
|
|
|
runButton.onclick = (ev) => {
|
|
const code = editor.getValue();
|
|
runCode(code, consoleCode);
|
|
runButton.textContent = "⚙️ Running...";
|
|
};
|
|
|
|
function downloadFile(content, mime, extension) {
|
|
const filename = prompt("Filename?");
|
|
|
|
const element = document.createElement("a");
|
|
|
|
element.href = `data:${mime};charset=utf-8,${encodeURIComponent(content)}`;
|
|
element.download = filename.endsWith(extension)
|
|
? filename
|
|
: filename + extension;
|
|
element.style.display = "none";
|
|
|
|
document.body.appendChild(element);
|
|
|
|
element.click();
|
|
|
|
document.body.removeChild(element);
|
|
}
|
|
|
|
function minifyJs(code) {
|
|
return code
|
|
.replace(/[\s\n]+/g, " ")
|
|
.replace(/;\s+/g, ";");
|
|
}
|
|
|
|
saveButton.onclick = (ev) => {
|
|
if (saveButton.classList.contains("active")) {
|
|
saveButton.classList.remove("active");
|
|
|
|
saveDropdown.style.display = "none";
|
|
} else {
|
|
saveButton.classList.add("active");
|
|
|
|
saveDropdown.style.display = "block";
|
|
}
|
|
};
|
|
|
|
saveJsButton.onclick = (ev) => {
|
|
downloadFile(editor.getValue(), "text/javascript", ".js");
|
|
};
|
|
|
|
saveHtmlButton.onclick = async (ev) => {
|
|
const js = editor.getValue().split("\n").map((line) =>
|
|
" ".repeat(12) + line
|
|
).join("\n");
|
|
let lib = await (await fetch("./lib.js")).text();
|
|
lib = minifyJs(lib);
|
|
|
|
const html = `
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="generator" content="karlkoder playground">
|
|
<title>Game</title>
|
|
<style>
|
|
body {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
height: 100vh;
|
|
margin: 0;
|
|
}
|
|
</style>
|
|
<script type="importmap">
|
|
{
|
|
"imports": {
|
|
"lib": "data:text/javascript,${encodeURIComponent(lib)}"
|
|
}
|
|
}
|
|
</script>
|
|
<script type="module">
|
|
${js}
|
|
</script>
|
|
</head>
|
|
<body>
|
|
<canvas width="480" height="360"></canvas>
|
|
</body>
|
|
</html>`;
|
|
|
|
downloadFile(html, "text/html", ".html");
|
|
};
|