160 lines
4.8 KiB
JavaScript
160 lines
4.8 KiB
JavaScript
/// <reference types="ace" />
|
|
|
|
import { Debounce } from "./debounce.js";
|
|
import { PlaygroundConsole } from "./playground_console.js";
|
|
import { CodeRunner } from "./code_runner.js";
|
|
import { AssetEditor } from "./asset_editor.js";
|
|
import { AssetProvider } from "./asset_provider.js";
|
|
import { Gamelib } from "./gamelib.js";
|
|
import { CodeStopper } from "./code_stopper.js";
|
|
import { KarlkoderCodec } from "./karlkoder_codec.js";
|
|
import { promptUpload } from "./prompt_upload.js";
|
|
import { GamelibCompleter } from "./gamelib_completer.js";
|
|
import { TextCompleter } from "./text_completer.js";
|
|
import { ConsoleInput } from "./console_input.js";
|
|
import { downloadFile, slugify } from "./utils.js";
|
|
import { HtmlExporter } from "./html_exporter.js";
|
|
import { Gesundheit } from "./gesundheit.js";
|
|
|
|
const editor = ace.edit("editor");
|
|
editor.setTheme("ace/theme/gruvbox");
|
|
editor.session.setMode("ace/mode/javascript");
|
|
|
|
const langTools = ace.require("ace/ext/language_tools");
|
|
|
|
editor.setOptions({
|
|
enableBasicAutocompletion: true,
|
|
enableLiveAutocompletion: true,
|
|
copyWithEmptySelection: true,
|
|
});
|
|
|
|
langTools.setCompleters([new GamelibCompleter(), new TextCompleter()]);
|
|
|
|
editor.setValue(sessionStorage.getItem("code") ?? editor.getValue(), -1);
|
|
|
|
const playgroundConsole = new PlaygroundConsole(
|
|
document.querySelector("#console-code"),
|
|
editor,
|
|
);
|
|
|
|
addEventListener("DOMContentLoaded", () => {
|
|
playgroundConsole.getInterface().log("Karlkode 1.0");
|
|
});
|
|
|
|
const codeStopper = new CodeStopper();
|
|
|
|
const assetProvider = new AssetProvider();
|
|
|
|
const codeRunner = new CodeRunner(playgroundConsole.getInterface(), codeStopper);
|
|
const assetEditor = new AssetEditor(document.querySelector("#asset-editor-container"), []);
|
|
|
|
new ConsoleInput(document.querySelector("#console-input"), playgroundConsole, codeRunner);
|
|
|
|
const htmlExporter = new HtmlExporter(assetProvider);
|
|
|
|
const gamelib = new Gamelib(
|
|
playgroundConsole.getInterface(),
|
|
codeStopper,
|
|
assetProvider,
|
|
document.querySelector("canvas"),
|
|
);
|
|
|
|
globalThis.karlkoder = {
|
|
lib() {
|
|
return gamelib;
|
|
},
|
|
};
|
|
|
|
const runButton = document.querySelector("#run-button");
|
|
const toggleAssetEditorButton = document.querySelector("#toggle-asset-editor-button");
|
|
const projectName = document.querySelector("#project-name");
|
|
const saveButton = document.querySelector("#save-button");
|
|
const loadButton = document.querySelector("#load-button");
|
|
const exportButton = document.querySelector("#export-button");
|
|
|
|
const sessionSaveDebounce = new Debounce(1000);
|
|
editor.addEventListener("change", () => {
|
|
sessionSaveDebounce.run(() => {
|
|
sessionStorage.setItem("code", editor.getValue());
|
|
});
|
|
});
|
|
|
|
loadButton.onclick = async () => {
|
|
const files = await promptUpload(".karlkode", false);
|
|
if (files.length === 0) {
|
|
return;
|
|
}
|
|
if (files.length > 1) {
|
|
throw new Error(
|
|
`unreachable: something went wrong ! files.length > 1 : files.length = ${files.length}`,
|
|
);
|
|
}
|
|
const items = KarlkoderCodec.de(
|
|
await fetch(URL.createObjectURL(files[0])).then((x) => x.bytes()),
|
|
);
|
|
const assets = items
|
|
.filter((x) => x.tag === "asset")
|
|
.map((x) => {
|
|
delete x.tag;
|
|
return x;
|
|
});
|
|
const code = items.find((x) => x.tag === "code");
|
|
delete code.tag;
|
|
assetEditor.importAssets(
|
|
assets.map(({ name, mime, content }) => ({ name, mime, bytes: content })),
|
|
);
|
|
projectName.value = code.name;
|
|
const dec = new TextDecoder();
|
|
editor.setValue(dec.decode(code.content));
|
|
};
|
|
|
|
runButton.onclick = () => {
|
|
const code = editor.getValue();
|
|
|
|
karlkoder.lib().assetProvider.injectAssets(assetEditor.assets);
|
|
codeRunner.setCode(code);
|
|
codeRunner.toggle();
|
|
document.querySelector("canvas").focus();
|
|
|
|
if (codeRunner.isRunning) {
|
|
runButton.textContent = "✋ Stop";
|
|
runButton.classList.add("running");
|
|
} else {
|
|
runButton.textContent = "🏃 Run";
|
|
runButton.classList.remove("running");
|
|
}
|
|
};
|
|
|
|
exportButton.onclick = async () => {
|
|
const html = await htmlExporter.export(projectName.value, editor.getValue());
|
|
|
|
downloadFile(slugify(projectName.value) || "project", html, ".html", "text/html");
|
|
};
|
|
|
|
function saveKarlKoder() {
|
|
downloadFile(
|
|
slugify(projectName.value) || "project",
|
|
KarlkoderCodec.en(
|
|
projectName.value,
|
|
editor.getValue(),
|
|
assetEditor.assets,
|
|
),
|
|
".karlkode",
|
|
);
|
|
}
|
|
|
|
saveButton.onclick = () => saveKarlKoder();
|
|
|
|
addEventListener("keydown", (ev) => {
|
|
if (ev.ctrlKey && ev.key === "s") {
|
|
ev.preventDefault();
|
|
saveKarlKoder();
|
|
}
|
|
});
|
|
|
|
toggleAssetEditorButton.addEventListener("click", () => assetEditor.toggleEditor());
|
|
|
|
const gsh = await Gesundheit.load("assetdb");
|
|
|
|
await gsh.doSomethingOrOtter();
|