From e3326f00765e95af93347f05e2c0a47a7a1cbb58 Mon Sep 17 00:00:00 2001 From: Reimar Date: Wed, 15 Oct 2025 09:08:35 +0200 Subject: [PATCH] add project save handler for reals --- src/project_save_handler.js | 113 ++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 src/project_save_handler.js diff --git a/src/project_save_handler.js b/src/project_save_handler.js new file mode 100644 index 0000000..812ff07 --- /dev/null +++ b/src/project_save_handler.js @@ -0,0 +1,113 @@ +import { promptUpload } from "./prompt_upload.js"; +import { downloadFile, slugify } from "./utils.js"; +import { HtmlExporter } from "./html_exporter.js"; + +export class ProjectSaveHandler { + constructor(editor, assetEditor, assetProvider, projectName) { + this.editor = editor; + this.assetEditor = assetEditor; + this.projectName = projectName; + + this.htmlExporter = new HtmlExporter(assetProvider); + + this.saveName = null; + this.isSaved = true; + + editor.addEventListener("change", () => { + this.isSaved = false; + }); + + assetEditor.addChangeListener(() => { + this.isSaved = false; + }); + } + + async loadFromFile() { + if ( + !this.isSaved && + !confirm( + "Your project has not been saved. Loading a new project will override your current one. Continue?", + ) + ) { + return; + } + + 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 }) => { + const file = new File([content], name, { type: mime }); + + return { name, file }; + }), + ); + + this.projectName.value = code.name; + const dec = new TextDecoder(); + this.editor.setValue(dec.decode(code.content)); + } + + async saveFile() { + const filename = prompt("Filename?", this.getSaveFileName()); + if (!filename) { + return; + } + + this.saveName = filename; + this.isSaved = true; + + downloadFile( + filename, + await KarlkoderCodec.en( + this.projectName.value, + this.editor.getValue(), + await assetEditor.getAssets(), + ), + ".karlkode", + ); + } + + async exportProject() { + const filename = prompt("Filename?", this.getSaveFileName()); + if (!filename) { + return; + } + + this.saveName = filename; + + const html = await this.htmlExporter.export(this.projectName.value, this.editor.getValue()); + + downloadFile(filename, html, ".html", "text/html"); + } + + getSaveFileName() { + if (this.saveName) { + return this.saveName; + } + + return slugify(this.projectName.value) || "project"; + } +}