diff --git a/main/files.js b/main/files.js index 7b502f91..07db82b7 100644 --- a/main/files.js +++ b/main/files.js @@ -448,6 +448,14 @@ export function stripFilename(inputString) { return removeEnd.substring(lastIndex + 1).trim(); } +// Holds the FileSystemFileHandle from the last explicit save (File System Access API) +let currentFileHandle = null; + +// Clears the stored file handle (call whenever a new project is loaded) +export function clearFileHandle() { + currentFileHandle = null; +} + // Function to export project code export async function exportCode(workspace) { try { @@ -497,6 +505,7 @@ export async function exportCode(workspace) { const writable = await fileHandle.createWritable(); await writable.write(jsonString); await writable.close(); + currentFileHandle = fileHandle; } else { const blob = new Blob([jsonString], { type: FLOCK_MIME }); const link = document.createElement("a"); @@ -511,6 +520,26 @@ export async function exportCode(workspace) { } } +// Autosave to the last explicitly-saved file handle (no picker shown) +export async function autoSaveToFile(workspace) { + if (!currentFileHandle) return; + try { + const ws = + workspace && workspace.getAllBlocks + ? workspace + : Blockly.getMainWorkspace(); + if (!ws || !ws.getAllBlocks) return; + + const json = Blockly.serialization.workspaces.save(ws); + const jsonString = JSON.stringify(json, null, 2); + const writable = await currentFileHandle.createWritable(); + await writable.write(jsonString); + await writable.close(); + } catch (e) { + console.error("Error during file autosave:", e); + } +} + // Function to import snippet from file export function importSnippet() { const fileInput = document.getElementById("importFile"); @@ -679,6 +708,7 @@ function processProjectFileDrop(file, workspace, executeCallback) { const baseName = sanitizedName.replace(/\.(json|flock)$/i, ""); document.getElementById("projectName").value = stripFilename(baseName); + clearFileHandle(); loadWorkspaceAndExecute(json, workspace, executeCallback); } catch (e) { console.error("Error loading Blockly project:", e); @@ -833,6 +863,7 @@ export function setupFileInput(workspace, executeCallback) { document.getElementById("projectName").value = stripFilename(baseName); + clearFileHandle(); loadWorkspaceAndExecute(json, workspace, executeCallback); } catch (e) { console.error("Error loading Blockly project:", e); @@ -869,6 +900,7 @@ export function loadExample(workspace, executeCallback) { .then((response) => response.json()) .then((json) => { console.log("Loading:", selectedOption); + clearFileHandle(); loadWorkspaceAndExecute(json, workspace, executeCallback); }) .catch((error) => { @@ -895,6 +927,7 @@ export function newProject() { fetch("examples/new.flock") .then((response) => response.json()) .then((json) => { + clearFileHandle(); loadWorkspaceAndExecute(json, workspace, executeCode); }) .catch((error) => { diff --git a/main/main.js b/main/main.js index 14658a42..035943d5 100644 --- a/main/main.js +++ b/main/main.js @@ -23,6 +23,7 @@ import { saveWorkspace, loadWorkspace, exportCode, + autoSaveToFile, setupFileInput, setupDragAndDrop, loadExampleWrapper, @@ -414,8 +415,11 @@ window.onload = async function () { console.log("Welcome to Flock 🐑🐑🐑"); - // Call this function to autosave periodically - setInterval(() => saveWorkspace(workspace), 30000); // Autosave every 30 seconds + // Autosave every 30 seconds: to localStorage and (if a file was saved) to that file + setInterval(() => { + saveWorkspace(workspace); + autoSaveToFile(workspace); + }, 30000); (async () => { await flock.initialize();