From 09d60b29b3d9b2e4454cf5360038fe11a9fb7db9 Mon Sep 17 00:00:00 2001 From: Hugo H Date: Fri, 26 Dec 2025 18:08:52 +0000 Subject: [PATCH] Added code storage api for storing code in the future --- .gitea/workflows/deploy.yaml | 2 +- codestorage/default.php | 93 ++++++++++++++++++++++++++++ index.html | 114 +++++++++++++++++++++++++++++++++++ 3 files changed, 208 insertions(+), 1 deletion(-) create mode 100644 codestorage/default.php diff --git a/.gitea/workflows/deploy.yaml b/.gitea/workflows/deploy.yaml index e2b0e41..fcfb44a 100644 --- a/.gitea/workflows/deploy.yaml +++ b/.gitea/workflows/deploy.yaml @@ -15,7 +15,7 @@ jobs: - name: Upload specific files via FTP shell: bash run: | - FILES=("index.html" "screen.js") + FILES=("index.html" "screen.js" "codestorage/default.php") for FILE in "${FILES[@]}"; do echo "Uploading $FILE..." diff --git a/codestorage/default.php b/codestorage/default.php new file mode 100644 index 0000000..69eb1e1 --- /dev/null +++ b/codestorage/default.php @@ -0,0 +1,93 @@ + PDO::ERRMODE_EXCEPTION, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + PDO::ATTR_EMULATE_PREPARES => false, + ]); + + $createTableSql = " + CREATE TABLE IF NOT EXISTS codeData ( + id BIGINT PRIMARY KEY, + data LONGTEXT NOT NULL + ) ENGINE=InnoDB; + "; + $pdo->exec($createTableSql); + + // 3. Handle Request Methods + $method = $_SERVER['REQUEST_METHOD']; + + if ($method === 'GET') { + // --- READ LOGIC --- + if (isset($_GET['id'])) { + $id = (int) $_GET['id']; + + $stmt = $pdo->prepare("SELECT data FROM codeData WHERE id = ?"); + $stmt->execute([$id]); + $row = $stmt->fetch(); + + if ($row) { + header('Content-Type: text/plain'); + echo $row['data']; + } else { + http_response_code(404); + echo "Error: Record with ID $id not found."; + } + } else { + http_response_code(400); + echo "Error: Missing 'id' parameter in query string."; + } + + } elseif ($method === 'POST') { + // --- WRITE LOGIC --- + // Get raw POST body + $inputData = file_get_contents('php://input'); + + if (!empty($inputData)) { + $idGenerated = false; + $newId = 0; + + // Generate a unique random ID and ensure it doesn't collide + while (!$idGenerated) { + $newId = mt_rand(100000, 999999999); // Range for the random ID + + // Check if ID exists + $checkStmt = $pdo->prepare("SELECT id FROM codeData WHERE id = ?"); + $checkStmt->execute([$newId]); + if (!$checkStmt->fetch()) { + $idGenerated = true; + } + } + + // Insert the new row + $insertStmt = $pdo->prepare("INSERT INTO codeData (id, data) VALUES (?, ?)"); + $insertStmt->execute([$newId, $inputData]); + + header('Content-Type: application/json'); + echo json_encode(['id' => $newId, 'status' => 'success']); + } else { + http_response_code(400); + echo "Error: POST body is empty."; + } + + } else { + // Unsupported Method + http_response_code(405); + echo "Error: Method $method not allowed."; + } + +} catch (PDOException $e) { + // Handle connection or query errors + http_response_code(500); + echo "Database Error: " . $e->getMessage(); + exit; +} +?> \ No newline at end of file diff --git a/index.html b/index.html index 42ab3c3..18f054d 100644 --- a/index.html +++ b/index.html @@ -183,6 +183,19 @@ +
+ + +
@@ -331,11 +344,112 @@ } } + // File System Access API support detection + let currentFileHandle = null; + + async function saveFile() { + try { + // Check if File System Access API is supported + if ('showSaveFilePicker' in window) { + // Use existing file handle if available, otherwise prompt for new file + if (!currentFileHandle) { + const options = { + types: [{ + description: 'Python Files', + accept: { 'text/x-python': ['.py'] }, + }], + suggestedName: 'sketch.py' + }; + currentFileHandle = await window.showSaveFilePicker(options); + } + + const writable = await currentFileHandle.createWritable(); + await writable.write(codeEditor.getValue()); + await writable.close(); + + term.write('\r\n✓ File saved successfully\r\n'); + } else { + // Fallback to download for browsers that don't support File System Access API + downloadCode(); + } + } catch (err) { + if (err.name !== 'AbortError') { + console.error('Save failed:', err); + term.write('\r\n✗ Save failed: ' + err.message + '\r\n'); + } + } + } + + async function openFile() { + try { + if ('showOpenFilePicker' in window) { + const [fileHandle] = await window.showOpenFilePicker({ + types: [{ + description: 'Python Files', + accept: { 'text/x-python': ['.py'] }, + }], + multiple: false + }); + + currentFileHandle = fileHandle; + const file = await fileHandle.getFile(); + const contents = await file.text(); + codeEditor.setValue(contents, -1); + + term.write('\r\n✓ File opened: ' + file.name + '\r\n'); + } else { + // Fallback to file input for browsers that don't support File System Access API + const input = document.createElement('input'); + input.type = 'file'; + input.accept = '.py'; + input.onchange = async (e) => { + const file = e.target.files[0]; + if (file) { + const contents = await file.text(); + codeEditor.setValue(contents, -1); + term.write('\r\n✓ File opened: ' + file.name + '\r\n'); + } + }; + input.click(); + } + } catch (err) { + if (err.name !== 'AbortError') { + console.error('Open failed:', err); + term.write('\r\n✗ Open failed: ' + err.message + '\r\n'); + } + } + } + + function downloadCode() { + const code = codeEditor.getValue(); + const blob = new Blob([code], { type: 'text/x-python' }); + const url = URL.createObjectURL(blob); + const link = document.createElement('a'); + link.href = url; + link.download = 'sketch.py'; + link.click(); + URL.revokeObjectURL(url); + term.write('\r\n✓ File downloaded\r\n'); + } + document.addEventListener('keydown', function (e) { + // Ctrl+Enter or Cmd+Enter to run code if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') { e.preventDefault(); runCurrentCode(); } + + // Ctrl+S or Cmd+S to save file + if ((e.ctrlKey || e.metaKey) && e.key === 's') { + e.preventDefault(); + saveFile(); + } + + // Ctrl+O or Cmd+O to open file + if ((e.ctrlKey || e.metaKey) && e.key === 'o') { + e.preventDefault(); + openFile(); + } }); window.addEventListener('load', () => {