cloud-compiler

A real-time, low-latency code ...
Log | Files | Refs | README | LICENSE

commit 8d3e3d8e24fa6d52ce1716d7173e523c16bf77cd
parent ff2036a74fa37a5ac41dad18c6cf14163065229b
Author: Amit Dutta <amitdutta4255@gmail.com>
Date:   Mon, 12 Jan 2026 19:27:55 +0530

new sharing logic (firebase) added

Diffstat:
Mpublic/c.html | 206++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
Mpublic/cpp.html | 201++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
Mpublic/docs.html | 61++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Mpublic/index.html | 3++-
Mpublic/python.html | 200++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
5 files changed, 549 insertions(+), 122 deletions(-)

diff --git a/public/c.html b/public/c.html @@ -243,7 +243,42 @@ int main() { </div> </div> - <script> + <script type="module"> + import { initializeApp } from "https://www.gstatic.com/firebasejs/10.7.1/firebase-app.js"; + import { getFirestore, doc, getDoc, setDoc } from "https://www.gstatic.com/firebasejs/10.7.1/firebase-firestore.js"; + import { getAuth, signInAnonymously } from "https://www.gstatic.com/firebasejs/10.7.1/firebase-auth.js"; + + // --- Firebase Config --- + const firebaseConfig = { + apiKey: "AIzaSyC8U49NgW7EtYBeKL0Sw08-QvM_Bl59zDw", + authDomain: "compiler-aranag-site.firebaseapp.com", + projectId: "compiler-aranag-site", + storageBucket: "compiler-aranag-site.firebasestorage.app", + messagingSenderId: "558890639400", + appId: "1:558890639400:web:125525d10ab51696a5951d", + measurementId: "G-KH9BGSRRGY" + }; + + // Initialize Firebase + const app = initializeApp(firebaseConfig); + const db = getFirestore(app); + const auth = getAuth(app); + + // Attempt initial sign-in, but don't crash if it fails (restricted op) + signInAnonymously(auth).catch((error) => { + console.warn("Auto-Auth failed (likely disabled in console). App will try unauthenticated access.", error.code); + }); + + // --- Helper: Generate ID --- + function generateId(length = 7) { + const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + let result = ''; + for (let i = 0; i < length; i++) { + result += chars.charAt(Math.floor(Math.random() * chars.length)); + } + return result; + } + // --- DOM Elements --- const runBtn = document.getElementById('run-btn'); const resetBtn = document.getElementById('reset-btn'); @@ -293,13 +328,52 @@ int main() { } }); - window.addEventListener('load', () => { + window.addEventListener('load', async () => { const params = new URLSearchParams(window.location.search); - const sharedCode = params.get('code'); - if (sharedCode) { - try { codeInput.value = atob(sharedCode); } + const shareId = params.get('share'); + const sharedCodeOld = params.get('code'); + + if (shareId) { + // Fetch from Firebase + try { + toast.textContent = "Loading shared code..."; + toast.classList.add('show'); + + const docRef = doc(db, "shares", shareId); + const docSnap = await getDoc(docRef); + + if (docSnap.exists()) { + const data = docSnap.data(); + codeInput.value = data.code; + + // Restore Output if it exists + if (data.output && term) { + term.write('\r\n\x1b[38;2;115;115;115m> PREVIOUS OUTPUT:\x1b[0m\r\n'); + term.write(data.output.replace(/\n/g, '\r\n')); + term.write('\r\n\x1b[38;2;115;115;115m> ----------------\x1b[0m\r\n'); + } + + toast.textContent = "Code loaded successfully"; + } else { + toast.textContent = "Shared code not found"; + } + setTimeout(() => toast.classList.remove('show'), 3000); + } catch (e) { + console.error("Fetch error:", e); + // More descriptive error for user + if (e.code === 'permission-denied') { + toast.textContent = "Error: Database Access Denied"; + } else { + toast.textContent = "Error loading code"; + } + setTimeout(() => toast.classList.remove('show'), 3000); + } + } else if (sharedCodeOld) { + // Fallback for Base64 + try { codeInput.value = atob(sharedCodeOld); } catch(e) {} } + setTimeout(connect, 500); }); @@ -326,6 +400,32 @@ int main() { fitAddon.fit(); window.addEventListener('resize', () => fitAddon.fit()); + // Helper: Get Clean Terminal Output + function getTerminalContent() { + if (!term) return ""; + const buffer = term.buffer.active; + let text = ""; + for (let i = 0; i < buffer.length; i++) { + const line = buffer.getLine(i); + if (line) { + let lineText = line.translateToString(true); + // Filter system messages + if(lineText.trim().startsWith("> [") || + lineText.trim().startsWith("> ./a.out") || + lineText.includes("SYSTEM READY") || + lineText.includes("ATTEMPTING") || + lineText.includes("CONNECTION") || + lineText.includes("PREVIOUS OUTPUT") || + lineText.includes("> ----------------") + ) { + continue; + } + text += lineText + "\n"; + } + } + return text.trim(); + } + // Custom Key Handler for Ctrl+C Copy term.attachCustomKeyEventHandler((arg) => { if (arg.ctrlKey && arg.code === "KeyC" && arg.type === "keydown") { @@ -433,28 +533,70 @@ int main() { term.write(`\x1b[38;2;190;242;100m> CONNECTION ESTABLISHED.\x1b[0m\r\n> ./a.out\r\n`); }); - // --- Share Functionality with Native Share API --- + // --- Share Functionality (Firebase) --- shareBtn.addEventListener('click', async () => { - const code = codeInput.value; - const encoded = btoa(code); - const url = new URL(window.location.href); - url.searchParams.set('code', encoded); - const shareUrl = url.toString(); - - // Try native sharing first (Mobile/Supported Browsers) - if (navigator.share) { - try { - await navigator.share({ - title: document.title, - text: 'Check out my C code!', - url: shareUrl - }); - } catch (err) { - // Ignore cancellation or errors, no fallback needed if cancelled + // Original Share icon animation + const originalIcon = shareBtn.innerHTML; + shareBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i>'; + shareBtn.disabled = true; + + try { + // Robust Auth Check: + // 1. If not logged in, try to log in. + // 2. If login fails (restricted), proceed anyway (swallow error). + // 3. This allows "Test Mode" (open DB) to work even if Auth is disabled. + if (!auth.currentUser) { + try { + await signInAnonymously(auth); + } catch (authError) { + console.warn("Anonymous auth failed (proceeding to unauthenticated write attempt):", authError.code); + } + } + + const code = codeInput.value; + const output = getTerminalContent(); // Capture output + const shareId = generateId(); + + // Save to Firestore + await setDoc(doc(db, "shares", shareId), { + code: code, + language: 'c', + output: output, // Store output + createdAt: new Date().toISOString() + }); + + // Generate URL + const url = new URL(window.location.href); + url.searchParams.delete('code'); // Remove legacy param + url.searchParams.set('share', shareId); + const shareUrl = url.toString(); + + // Share or Copy + if (navigator.share) { + try { + await navigator.share({ + title: document.title, + text: 'Check out my C code!', + url: shareUrl + }); + } catch (err) { + // If canceled, still copy to clipboard as fallback + fallbackCopyTextToClipboard(shareUrl); + } + } else { + fallbackCopyTextToClipboard(shareUrl); + } + } catch (error) { + console.error("Share failed:", error); + if (error.code === 'permission-denied') { + showToast("Share Failed: Access Denied"); + console.log("Tip: Enable Anonymous Auth in Firebase Console OR set Firestore rules to public."); + } else { + showToast("Share Failed: " + error.message); } - } else { - // Fallback to clipboard copy - fallbackCopyTextToClipboard(shareUrl); + } finally { + shareBtn.innerHTML = originalIcon; + shareBtn.disabled = false; } }); @@ -466,19 +608,7 @@ int main() { // --- Smart Copy Function --- copyBtn.addEventListener('click', () => { - const buffer = term.buffer.active; - let text = ""; - for (let i = 0; i < buffer.length; i++) { - const line = buffer.getLine(i); - if (line) { - let lineText = line.translateToString(true); - if(lineText.trim().startsWith("> [") || lineText.trim().startsWith("> ./a.out") || lineText.includes("SYSTEM READY") || lineText.includes("ATTEMPTING") || lineText.includes("CONNECTION")) { - continue; - } - text += lineText + "\n"; - } - } - text = text.trim(); + const text = getTerminalContent(); fallbackCopyTextToClipboard(text); }); diff --git a/public/cpp.html b/public/cpp.html @@ -241,7 +241,42 @@ int main() { </div> </div> - <script> + <script type="module"> + import { initializeApp } from "https://www.gstatic.com/firebasejs/10.7.1/firebase-app.js"; + import { getFirestore, doc, getDoc, setDoc } from "https://www.gstatic.com/firebasejs/10.7.1/firebase-firestore.js"; + import { getAuth, signInAnonymously } from "https://www.gstatic.com/firebasejs/10.7.1/firebase-auth.js"; + + // --- Firebase Config --- + const firebaseConfig = { + apiKey: "AIzaSyC8U49NgW7EtYBeKL0Sw08-QvM_Bl59zDw", + authDomain: "compiler-aranag-site.firebaseapp.com", + projectId: "compiler-aranag-site", + storageBucket: "compiler-aranag-site.firebasestorage.app", + messagingSenderId: "558890639400", + appId: "1:558890639400:web:125525d10ab51696a5951d", + measurementId: "G-KH9BGSRRGY" + }; + + // Initialize Firebase + const app = initializeApp(firebaseConfig); + const db = getFirestore(app); + const auth = getAuth(app); + + // Attempt initial sign-in, but don't crash if it fails (restricted op) + signInAnonymously(auth).catch((error) => { + console.warn("Auto-Auth failed (likely disabled in console). App will try unauthenticated access.", error.code); + }); + + // --- Helper: Generate ID --- + function generateId(length = 7) { + const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + let result = ''; + for (let i = 0; i < length; i++) { + result += chars.charAt(Math.floor(Math.random() * chars.length)); + } + return result; + } + // --- DOM Elements --- const runBtn = document.getElementById('run-btn'); const resetBtn = document.getElementById('reset-btn'); @@ -291,13 +326,52 @@ int main() { } }); - window.addEventListener('load', () => { + window.addEventListener('load', async () => { const params = new URLSearchParams(window.location.search); - const sharedCode = params.get('code'); - if (sharedCode) { - try { codeInput.value = atob(sharedCode); } + const shareId = params.get('share'); + const sharedCodeOld = params.get('code'); + + if (shareId) { + // Fetch from Firebase + try { + toast.textContent = "Loading shared code..."; + toast.classList.add('show'); + + const docRef = doc(db, "shares", shareId); + const docSnap = await getDoc(docRef); + + if (docSnap.exists()) { + const data = docSnap.data(); + codeInput.value = data.code; + + // Restore Output if it exists + if (data.output && term) { + term.write('\r\n\x1b[38;2;115;115;115m> PREVIOUS OUTPUT:\x1b[0m\r\n'); + term.write(data.output.replace(/\n/g, '\r\n')); + term.write('\r\n\x1b[38;2;115;115;115m> ----------------\x1b[0m\r\n'); + } + + toast.textContent = "Code loaded successfully"; + } else { + toast.textContent = "Shared code not found"; + } + setTimeout(() => toast.classList.remove('show'), 3000); + } catch (e) { + console.error("Fetch error:", e); + // More descriptive error for user + if (e.code === 'permission-denied') { + toast.textContent = "Error: Database Access Denied"; + } else { + toast.textContent = "Error loading code"; + } + setTimeout(() => toast.classList.remove('show'), 3000); + } + } else if (sharedCodeOld) { + // Fallback for Base64 + try { codeInput.value = atob(sharedCodeOld); } catch(e) {} } + setTimeout(connect, 500); }); @@ -324,6 +398,32 @@ int main() { fitAddon.fit(); window.addEventListener('resize', () => fitAddon.fit()); + // Helper: Get Clean Terminal Output + function getTerminalContent() { + if (!term) return ""; + const buffer = term.buffer.active; + let text = ""; + for (let i = 0; i < buffer.length; i++) { + const line = buffer.getLine(i); + if (line) { + let lineText = line.translateToString(true); + // Filter system messages + if(lineText.trim().startsWith("> [") || + lineText.trim().startsWith("> ./a.out") || + lineText.includes("SYSTEM READY") || + lineText.includes("ATTEMPTING") || + lineText.includes("CONNECTION") || + lineText.includes("PREVIOUS OUTPUT") || + lineText.includes("> ----------------") + ) { + continue; + } + text += lineText + "\n"; + } + } + return text.trim(); + } + // Custom Key Handler for Ctrl+C Copy term.attachCustomKeyEventHandler((arg) => { if (arg.ctrlKey && arg.code === "KeyC" && arg.type === "keydown") { @@ -431,28 +531,65 @@ int main() { term.write(`\x1b[38;2;190;242;100m> CONNECTION ESTABLISHED.\x1b[0m\r\n> ./a.out\r\n`); }); - // --- Share Functionality with Native Share API --- + // --- Share Functionality with Firebase --- shareBtn.addEventListener('click', async () => { - const code = codeInput.value; - const encoded = btoa(code); - const url = new URL(window.location.href); - url.searchParams.set('code', encoded); - const shareUrl = url.toString(); - - // Try native sharing first (Mobile/Supported Browsers) - if (navigator.share) { - try { - await navigator.share({ - title: document.title, - text: 'Check out my C++ code!', - url: shareUrl - }); - } catch (err) { - // Ignore cancellation or errors + // Original Share icon animation + const originalIcon = shareBtn.innerHTML; + shareBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i>'; + shareBtn.disabled = true; + + try { + // Robust Auth Check + if (!auth.currentUser) { + try { + await signInAnonymously(auth); + } catch (authError) { + console.warn("Anonymous auth failed (proceeding to unauthenticated write attempt):", authError.code); + } + } + + const code = codeInput.value; + const output = getTerminalContent(); + const shareId = generateId(); + + // Save to Firestore + await setDoc(doc(db, "shares", shareId), { + code: code, + language: 'cpp', + output: output, + createdAt: new Date().toISOString() + }); + + // Generate URL + const url = new URL(window.location.href); + url.searchParams.delete('code'); + url.searchParams.set('share', shareId); + const shareUrl = url.toString(); + + // Share or Copy + if (navigator.share) { + try { + await navigator.share({ + title: document.title, + text: 'Check out my C++ code!', + url: shareUrl + }); + } catch (err) { + fallbackCopyTextToClipboard(shareUrl); + } + } else { + fallbackCopyTextToClipboard(shareUrl); + } + } catch (error) { + console.error("Share failed:", error); + if (error.code === 'permission-denied') { + showToast("Share Failed: Access Denied"); + } else { + showToast("Share Failed: " + error.message); } - } else { - // Fallback to clipboard copy - fallbackCopyTextToClipboard(shareUrl); + } finally { + shareBtn.innerHTML = originalIcon; + shareBtn.disabled = false; } }); @@ -464,19 +601,7 @@ int main() { // --- Smart Copy Function --- copyBtn.addEventListener('click', () => { - const buffer = term.buffer.active; - let text = ""; - for (let i = 0; i < buffer.length; i++) { - const line = buffer.getLine(i); - if (line) { - let lineText = line.translateToString(true); - if(lineText.trim().startsWith("> [") || lineText.trim().startsWith("> ./a.out") || lineText.includes("SYSTEM READY") || lineText.includes("ATTEMPTING") || lineText.includes("CONNECTION")) { - continue; - } - text += lineText + "\n"; - } - } - text = text.trim(); + const text = getTerminalContent(); fallbackCopyTextToClipboard(text); }); diff --git a/public/docs.html b/public/docs.html @@ -99,6 +99,7 @@ <a href="#communication" class="nav-link font-mono text-sm">WebSocket Protocol</a> <a href="#python-engine" class="nav-link font-mono text-sm">Python Engine</a> <a href="#cpp-engine" class="nav-link font-mono text-sm">C / C++ Engine</a> + <a href="#sharing" class="nav-link font-mono text-sm">Sharing & Persistence</a> <a href="#security" class="nav-link font-mono text-sm">Security & Sandbox</a> <a href="#privacy" class="nav-link font-mono text-sm">Privacy & Data</a> <a href="#disclaimer" class="nav-link font-mono text-sm">Legal & Disclaimer</a> @@ -108,7 +109,7 @@ <p class="text-xs text-neutral-400 mb-2">Powered by</p> <div class="flex flex-wrap gap-2"> <span class="text-xs px-2 py-1 rounded bg-black border border-white/10 text-lime-300 font-mono">aiohttp</span> - <span class="text-xs px-2 py-1 rounded bg-black border border-white/10 text-lime-300 font-mono">Python 3.10</span> + <span class="text-xs px-2 py-1 rounded bg-black border border-white/10 text-lime-300 font-mono">Firebase</span> <span class="text-xs px-2 py-1 rounded bg-black border border-white/10 text-lime-300 font-mono">GCC 11</span> </div> </div> @@ -236,11 +237,57 @@ def check_and_install_packages(code): Standard Input buffer flushing is handled automatically to ensure prompts (like <code>cin >> var</code>) appear immediately in the terminal before blocking for input. </p> </section> + + <!-- Sharing & Persistence --> + <section id="sharing" class="doc-section"> + <h2 class="text-2xl font-heading font-bold text-lime-300 mb-6 flex items-center"> + <span class="mr-3">05.</span> Sharing & Persistence + </h2> + <p class="text-neutral-300 mb-4"> + The sharing functionality leverages <strong>Firebase Firestore</strong> to provide persistent access to code and execution results. This ensures that sharing a link not only loads the correct source code but also restores the exact terminal state seen at the moment of sharing. + </p> + + <h3 class="text-lg font-bold text-white mt-6 mb-2">How Sharing Works</h3> + <div class="grid grid-cols-1 md:grid-cols-2 gap-6 my-4"> + <div class="p-6 rounded-xl bg-white/5 border border-white/10"> + <h4 class="text-white font-bold mb-2">1. Snapshot Creation</h4> + <p class="text-sm text-neutral-400 mb-2"> + When the "Share" button is clicked, the system captures: + </p> + <ul class="list-disc list-inside text-xs text-neutral-500 space-y-1"> + <li>The complete source code from the editor.</li> + <li>The current terminal output (stripped of system messages).</li> + <li>Metadata (language, timestamp).</li> + </ul> + </div> + <div class="p-6 rounded-xl bg-white/5 border border-white/10"> + <h4 class="text-white font-bold mb-2">2. Storage & Retrieval</h4> + <p class="text-sm text-neutral-400 mb-2"> + This data is stored in a Firestore document under a unique 7-character ID. + </p> + <ul class="list-disc list-inside text-xs text-neutral-500 space-y-1"> + <li><strong>Write:</strong> Uses Anonymous Auth to securely write to the DB.</li> + <li><strong>Read:</strong> The URL `?share=ID` fetches this document.</li> + <li><strong>Restore:</strong> The editor fills with code, and the terminal replays the saved output.</li> + </ul> + </div> + </div> + + <div class="code-block"> + <pre><code class="language-javascript">// Data Structure in Firestore +{ + "code": "#include <stdio.h>\n...", + "language": "c", + "output": "Enter count: 5\nCounting to 5:\n1 2 3 4 5 \nDone.", + "createdAt": "2023-10-27T10:00:00.000Z" +}</code></pre> + </div> + </section> <!-- Security --> <section id="security" class="doc-section"> <h2 class="text-2xl font-heading font-bold text-lime-300 mb-6 flex items-center"> - <span class="mr-3">05.</span> Security & Limitations + <span class="mr-3">06.</span> Security & Limitations </h2> <p class="text-neutral-300 mb-4"> The current implementation runs code directly on the host instance. While effective for a portfolio demonstration or trusted environment, this setup is <strong>not sandboxed</strong>. @@ -268,16 +315,16 @@ def check_and_install_packages(code): <!-- Privacy & Data Handling --> <section id="privacy" class="doc-section"> <h2 class="text-2xl font-heading font-bold text-lime-300 mb-6 flex items-center"> - <span class="mr-3">06.</span> Privacy & Data Handling + <span class="mr-3">07.</span> Privacy & Data Handling </h2> <p class="text-neutral-300 mb-4"> We believe in complete transparency regarding how your data is handled. As a demonstration platform, we prioritize privacy and ephemeral execution. </p> <div class="grid grid-cols-1 md:grid-cols-3 gap-6 my-8"> <div class="p-6 rounded-xl bg-white/5 border border-white/10"> - <h3 class="text-white font-bold mb-2"><i class="fas fa-trash-alt text-lime-300 mr-2"></i> No Storage</h3> + <h3 class="text-white font-bold mb-2"><i class="fas fa-trash-alt text-lime-300 mr-2"></i> Ephemeral Execution</h3> <p class="text-sm text-neutral-400"> - Your code is processed in volatile memory or temporary files that are <strong>immediately deleted</strong> after execution. We do not maintain a database of user code. + By default, your code is processed in volatile memory and <strong>immediately deleted</strong> after execution. Code is stored in our database <strong>only</strong> when you explicitly click "Share". </p> </div> <div class="p-6 rounded-xl bg-white/5 border border-white/10"> @@ -289,7 +336,7 @@ def check_and_install_packages(code): <div class="p-6 rounded-xl bg-white/5 border border-white/10"> <h3 class="text-white font-bold mb-2"><i class="fab fa-github text-lime-300 mr-2"></i> Open Source</h3> <p class="text-sm text-neutral-400"> - The entire backend infrastructure is open source. You can audit the code yourself on <a href="https://github.com/notamitgamer" target="_blank" class="text-lime-300 hover:underline">GitHub</a>. + The entire backend infrastructure is open source. You can audit the code yourself on <a href="https://github.com/notamitgamer/cloud-compiler" target="_blank" class="text-lime-300 hover:underline">GitHub</a>. </p> </div> </div> @@ -298,7 +345,7 @@ def check_and_install_packages(code): <!-- Legal & Disclaimer --> <section id="disclaimer" class="doc-section"> <h2 class="text-2xl font-heading font-bold text-lime-300 mb-6 flex items-center"> - <span class="mr-3">07.</span> Legal & Disclaimer + <span class="mr-3">08.</span> Legal & Disclaimer </h2> <div class="p-6 rounded-xl border border-red-500/20 bg-red-500/5"> <p class="text-neutral-300 mb-4"> diff --git a/public/index.html b/public/index.html @@ -355,4 +355,4 @@ }); </script> </body> -</html> +</html>+ \ No newline at end of file diff --git a/public/python.html b/public/python.html @@ -232,7 +232,42 @@ print("Done.")</textarea> </div> </div> - <script> + <script type="module"> + import { initializeApp } from "https://www.gstatic.com/firebasejs/10.7.1/firebase-app.js"; + import { getFirestore, doc, getDoc, setDoc } from "https://www.gstatic.com/firebasejs/10.7.1/firebase-firestore.js"; + import { getAuth, signInAnonymously } from "https://www.gstatic.com/firebasejs/10.7.1/firebase-auth.js"; + + // --- Firebase Config --- + const firebaseConfig = { + apiKey: "AIzaSyC8U49NgW7EtYBeKL0Sw08-QvM_Bl59zDw", + authDomain: "compiler-aranag-site.firebaseapp.com", + projectId: "compiler-aranag-site", + storageBucket: "compiler-aranag-site.firebasestorage.app", + messagingSenderId: "558890639400", + appId: "1:558890639400:web:125525d10ab51696a5951d", + measurementId: "G-KH9BGSRRGY" + }; + + // Initialize Firebase + const app = initializeApp(firebaseConfig); + const db = getFirestore(app); + const auth = getAuth(app); + + // Attempt initial sign-in + signInAnonymously(auth).catch((error) => { + console.warn("Auto-Auth failed. App will try unauthenticated access.", error.code); + }); + + // --- Helper: Generate ID --- + function generateId(length = 7) { + const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + let result = ''; + for (let i = 0; i < length; i++) { + result += chars.charAt(Math.floor(Math.random() * chars.length)); + } + return result; + } + // --- DOM Elements --- const runBtn = document.getElementById('run-btn'); const resetBtn = document.getElementById('reset-btn'); @@ -274,11 +309,49 @@ print("Done.")</textarea> } }); - window.addEventListener('load', () => { + window.addEventListener('load', async () => { const params = new URLSearchParams(window.location.search); - const sharedCode = params.get('code'); - if (sharedCode) { - try { codeInput.value = atob(sharedCode); } + const shareId = params.get('share'); + const sharedCodeOld = params.get('code'); + + if (shareId) { + // Fetch from Firebase + try { + toast.textContent = "Loading shared code..."; + toast.classList.add('show'); + + const docRef = doc(db, "shares", shareId); + const docSnap = await getDoc(docRef); + + if (docSnap.exists()) { + const data = docSnap.data(); + codeInput.value = data.code; + + // Restore Output if it exists + if (data.output && term) { + term.write('\r\n\x1b[38;2;115;115;115m> PREVIOUS OUTPUT:\x1b[0m\r\n'); + term.write(data.output.replace(/\n/g, '\r\n')); + term.write('\r\n\x1b[38;2;115;115;115m> ----------------\x1b[0m\r\n'); + } + + toast.textContent = "Code loaded successfully"; + } else { + toast.textContent = "Shared code not found"; + } + setTimeout(() => toast.classList.remove('show'), 3000); + } catch (e) { + console.error("Fetch error:", e); + // More descriptive error for user + if (e.code === 'permission-denied') { + toast.textContent = "Error: Database Access Denied"; + } else { + toast.textContent = "Error loading code"; + } + setTimeout(() => toast.classList.remove('show'), 3000); + } + } else if (sharedCodeOld) { + // Fallback for Base64 + try { codeInput.value = atob(sharedCodeOld); } catch(e) {} } setTimeout(connect, 500); @@ -307,6 +380,32 @@ print("Done.")</textarea> fitAddon.fit(); window.addEventListener('resize', () => fitAddon.fit()); + // Helper: Get Clean Terminal Output + function getTerminalContent() { + if (!term) return ""; + const buffer = term.buffer.active; + let text = ""; + for (let i = 0; i < buffer.length; i++) { + const line = buffer.getLine(i); + if (line) { + let lineText = line.translateToString(true); + // Filter system messages + if(lineText.trim().startsWith("> [") || + lineText.trim().startsWith("> python") || + lineText.includes("SYSTEM READY") || + lineText.includes("ATTEMPTING") || + lineText.includes("CONNECTION") || + lineText.includes("PREVIOUS OUTPUT") || + lineText.includes("> ----------------") + ) { + continue; + } + text += lineText + "\n"; + } + } + return text.trim(); + } + // Custom Key Handler for Ctrl+C Copy term.attachCustomKeyEventHandler((arg) => { if (arg.ctrlKey && arg.code === "KeyC" && arg.type === "keydown") { @@ -403,28 +502,65 @@ print("Done.")</textarea> term.write(`\x1b[38;2;190;242;100m> CONNECTION ESTABLISHED.\x1b[0m\r\n> python3 main.py\r\n`); }); - // --- Share Functionality with Native Share API --- + // --- Share Functionality with Firebase --- shareBtn.addEventListener('click', async () => { - const code = codeInput.value; - const encoded = btoa(code); - const url = new URL(window.location.href); - url.searchParams.set('code', encoded); - const shareUrl = url.toString(); - - // Try native sharing first (Mobile/Supported Browsers) - if (navigator.share) { - try { - await navigator.share({ - title: document.title, - text: 'Check out my Python code!', - url: shareUrl - }); - } catch (err) { - // Ignore cancellation or errors + // Original Share icon animation + const originalIcon = shareBtn.innerHTML; + shareBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i>'; + shareBtn.disabled = true; + + try { + // Robust Auth Check + if (!auth.currentUser) { + try { + await signInAnonymously(auth); + } catch (authError) { + console.warn("Anonymous auth failed (proceeding to unauthenticated write attempt):", authError.code); + } + } + + const code = codeInput.value; + const output = getTerminalContent(); + const shareId = generateId(); + + // Save to Firestore + await setDoc(doc(db, "shares", shareId), { + code: code, + language: 'python', + output: output, + createdAt: new Date().toISOString() + }); + + // Generate URL + const url = new URL(window.location.href); + url.searchParams.delete('code'); // Remove legacy param + url.searchParams.set('share', shareId); + const shareUrl = url.toString(); + + // Share or Copy + if (navigator.share) { + try { + await navigator.share({ + title: document.title, + text: 'Check out my Python code!', + url: shareUrl + }); + } catch (err) { + fallbackCopyTextToClipboard(shareUrl); + } + } else { + fallbackCopyTextToClipboard(shareUrl); + } + } catch (error) { + console.error("Share failed:", error); + if (error.code === 'permission-denied') { + showToast("Share Failed: Access Denied"); + } else { + showToast("Share Failed: " + error.message); } - } else { - // Fallback to clipboard copy - fallbackCopyTextToClipboard(shareUrl); + } finally { + shareBtn.innerHTML = originalIcon; + shareBtn.disabled = false; } }); @@ -436,19 +572,7 @@ print("Done.")</textarea> // --- Smart Copy Function --- copyBtn.addEventListener('click', () => { - const buffer = term.buffer.active; - let text = ""; - for (let i = 0; i < buffer.length; i++) { - const line = buffer.getLine(i); - if (line) { - let lineText = line.translateToString(true); - if(lineText.trim().startsWith("> [") || lineText.trim().startsWith("> python") || lineText.includes("SYSTEM READY") || lineText.includes("ATTEMPTING") || lineText.includes("CONNECTION")) { - continue; - } - text += lineText + "\n"; - } - } - text = text.trim(); + const text = getTerminalContent(); fallbackCopyTextToClipboard(text); });
© notamitgamer • Site Built: 2026-07-21 13:58:23 UTC • git-mirror commit: 1037f62 [view raw info]
Originally created with stagit • modified by notamitgamer
Forked from github.com/notamitgamer/git-mirror