๐Ÿ“œ
menu.js
โ† Back
๐Ÿ“ Javascript โšก Executable Ctrl+S: Save โ€ข Ctrl+R: Run โ€ข Ctrl+F: Find
(function () { window.AppMenu = window.AppMenu || []; // Add InstaFile menu item window.AppMenu.push({ label: '๐Ÿ“‹ InstaFile (Paste to File)', action: () => { if (window.AppOverlay) { const instaFileSection = { title: 'InstaFile - Paste to File', html: ` <div style="padding: 1rem;"> <h3 style="margin-top: 0;">๐Ÿ“‹ Paste Content to Create File</h3> <p style="color: #94a3b8; margin-bottom: 1rem;"> Paste text from clipboard and save it as a file on your SFTP server. </p> <div style="margin-bottom: 1rem;"> <label style="display: block; font-weight: 600; margin-bottom: 0.5rem;"> File Name: </label> <input type="text" id="instaFileName" placeholder="example.txt" style="width: 100%; padding: 0.6rem; background: #0f1725; border: 1px solid #2a3648; border-radius: 8px; color: #e6edf3;" /> </div> <div style="margin-bottom: 1rem;"> <label style="display: block; font-weight: 600; margin-bottom: 0.5rem;"> Content (tap to paste): </label> <textarea id="instaFileContent" placeholder="Tap here and paste your content..." style="width: 100%; min-height: 300px; padding: 0.75rem; background: #0f1725; border: 1px solid #2a3648; border-radius: 8px; color: #e6edf3; font-family: monospace; font-size: 14px; resize: vertical;" ></textarea> </div> <div style="display: flex; gap: 0.5rem;"> <button id="instaFileSave" style="flex: 1; padding: 0.75rem; background: linear-gradient(135deg, #3b82f6, #9333ea); border: none; border-radius: 8px; color: white; font-weight: 600; cursor: pointer;"> ๐Ÿ’พ Save to SFTP </button> <button id="instaFileCancel" style="padding: 0.75rem 1.5rem; background: #2a3648; border: none; border-radius: 8px; color: #e6edf3; font-weight: 600; cursor: pointer;"> Cancel </button> </div> <div id="instaFileMessage" style="margin-top: 1rem; padding: 0.75rem; border-radius: 8px; display: none;"></div> </div> ` }; AppOverlay.open([instaFileSection], 0); // Wait for overlay to render setTimeout(() => { const saveBtn = document.getElementById('instaFileSave'); const cancelBtn = document.getElementById('instaFileCancel'); const fileNameInput = document.getElementById('instaFileName'); const contentArea = document.getElementById('instaFileContent'); const messageDiv = document.getElementById('instaFileMessage'); // Focus textarea for easy pasting contentArea.focus(); // Cancel button if (cancelBtn) { cancelBtn.onclick = () => { if (AppOverlay && AppOverlay.close) AppOverlay.close(); }; } // Save button if (saveBtn) { saveBtn.onclick = async () => { const fileName = fileNameInput.value.trim(); const content = contentArea.value; if (!fileName) { messageDiv.style.display = 'block'; messageDiv.style.background = 'rgba(239, 68, 68, 0.2)'; messageDiv.style.color = '#ef4444'; messageDiv.style.border = '1px solid rgba(239, 68, 68, 0.3)'; messageDiv.textContent = 'โŒ Please enter a file name'; return; } if (!content) { messageDiv.style.display = 'block'; messageDiv.style.background = 'rgba(239, 68, 68, 0.2)'; messageDiv.style.color = '#ef4444'; messageDiv.style.border = '1px solid rgba(239, 68, 68, 0.3)'; messageDiv.textContent = 'โŒ Please paste some content'; return; } try { saveBtn.disabled = true; saveBtn.textContent = 'โณ Saving...'; // Use instafile.php to save content const res = await fetch('instafile.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ path: '/' + fileName, // Save to root directory content: content }) }); const data = await res.json(); if (data.success) { messageDiv.style.display = 'block'; messageDiv.style.background = 'rgba(16, 185, 129, 0.2)'; messageDiv.style.color = '#10b981'; messageDiv.style.border = '1px solid rgba(16, 185, 129, 0.3)'; messageDiv.textContent = 'โœ… File saved successfully!'; // Clear form setTimeout(() => { fileNameInput.value = ''; contentArea.value = ''; if (AppOverlay && AppOverlay.close) { AppOverlay.close(); } }, 1500); } else { throw new Error(data.message || 'Upload failed'); } } catch (err) { messageDiv.style.display = 'block'; messageDiv.style.background = 'rgba(239, 68, 68, 0.2)'; messageDiv.style.color = '#ef4444'; messageDiv.style.border = '1px solid rgba(239, 68, 68, 0.3)'; messageDiv.textContent = 'โŒ Error: ' + err.message; } finally { saveBtn.disabled = false; saveBtn.textContent = '๐Ÿ’พ Save to SFTP'; } }; } }, 100); } } }); // Add Copy File to Clipboard menu item window.AppMenu.push({ label: '๐Ÿ“„ Copy File to Clipboard', action: () => { if (window.AppOverlay) { const copyFileSection = { title: 'Copy File to Clipboard', html: ` <div style="padding: 1rem;"> <h3 style="margin-top: 0;">๐Ÿ“„ Copy File Content</h3> <p style="color: #94a3b8; margin-bottom: 1rem;"> Enter the file path to copy its entire content to your clipboard. </p> <div style="margin-bottom: 1rem;"> <label style="display: block; font-weight: 600; margin-bottom: 0.5rem;"> File Path: </label> <input type="text" id="copyFilePath" placeholder="/path/to/file.txt" style="width: 100%; padding: 0.6rem; background: #0f1725; border: 1px solid #2a3648; border-radius: 8px; color: #e6edf3;" /> </div> <div style="display: flex; gap: 0.5rem;"> <button id="copyFileBtn" style="flex: 1; padding: 0.75rem; background: linear-gradient(135deg, #3b82f6, #9333ea); border: none; border-radius: 8px; color: white; font-weight: 600; cursor: pointer;"> ๐Ÿ“‹ Copy to Clipboard </button> <button id="copyFileCancel" style="padding: 0.75rem 1.5rem; background: #2a3648; border: none; border-radius: 8px; color: #e6edf3; font-weight: 600; cursor: pointer;"> Cancel </button> </div> <div id="copyFilePreview" style="margin-top: 1rem; padding: 0.75rem; background: #0f1725; border: 1px solid #2a3648; border-radius: 8px; max-height: 300px; overflow-y: auto; font-family: monospace; font-size: 13px; white-space: pre-wrap; display: none; color: #94a3b8;"></div> <div id="copyFileMessage" style="margin-top: 1rem; padding: 0.75rem; border-radius: 8px; display: none;"></div> </div> ` }; AppOverlay.open([copyFileSection], 0); // Wait for overlay to render setTimeout(() => { const copyBtn = document.getElementById('copyFileBtn'); const cancelBtn = document.getElementById('copyFileCancel'); const filePathInput = document.getElementById('copyFilePath'); const previewDiv = document.getElementById('copyFilePreview'); const messageDiv = document.getElementById('copyFileMessage'); // Cancel button if (cancelBtn) { cancelBtn.onclick = () => { if (AppOverlay && AppOverlay.close) AppOverlay.close(); }; } // Copy button if (copyBtn) { copyBtn.onclick = async () => { const filePath = filePathInput.value.trim(); if (!filePath) { messageDiv.style.display = 'block'; messageDiv.style.background = 'rgba(239, 68, 68, 0.2)'; messageDiv.style.color = '#ef4444'; messageDiv.style.border = '1px solid rgba(239, 68, 68, 0.3)'; messageDiv.textContent = 'โŒ Please enter a file path'; return; } try { copyBtn.disabled = true; copyBtn.textContent = 'โณ Reading file...'; // Download file content using SFTPdownload.php const res = await fetch('SFTPdownload.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ path: filePath }) }); if (!res.ok) { const errorText = await res.text(); throw new Error(errorText || 'File not found or cannot be read'); } const content = await res.text(); // Show preview previewDiv.style.display = 'block'; previewDiv.textContent = content.substring(0, 500) + (content.length > 500 ? '...\n\n(Preview truncated)' : ''); // Copy to clipboard await navigator.clipboard.writeText(content); messageDiv.style.display = 'block'; messageDiv.style.background = 'rgba(16, 185, 129, 0.2)'; messageDiv.style.color = '#10b981'; messageDiv.style.border = '1px solid rgba(16, 185, 129, 0.3)'; messageDiv.textContent = `โœ… Copied ${content.length} characters to clipboard!`; } catch (err) { messageDiv.style.display = 'block'; messageDiv.style.background = 'rgba(239, 68, 68, 0.2)'; messageDiv.style.color = '#ef4444'; messageDiv.style.border = '1px solid rgba(239, 68, 68, 0.3)'; messageDiv.textContent = 'โŒ Error: ' + err.message; } finally { copyBtn.disabled = false; copyBtn.textContent = '๐Ÿ“‹ Copy to Clipboard'; } }; } }, 100); } } }); // Add menu items here window.AppMenu.push({ label: '๐Ÿ”„ Refresh Connection', action: async () => { try { const res = await fetch('SFTPconnector.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'status' }) }); const data = await res.json(); if (data.success && data.data?.connected) { alert('โœ… Connection is active\n\n' + `Host: ${data.data.config.host}\n` + `User: ${data.data.config.username}\n` + `Port: ${data.data.config.port}`); } else { alert('โŒ No active connection'); } } catch (err) { alert('Error checking connection: ' + err.message); } } }); window.AppMenu.push({ label: '๐Ÿ”Œ Disconnect All', action: async () => { if (!confirm('Disconnect from SFTP server?')) return; try { const res = await fetch('SFTPconnector.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'disconnect' }) }); const data = await res.json(); if (data.success) { // Update localStorage const STORAGE_KEY = 'sftp_connections'; const connections = JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]'); connections.forEach(c => c.active = false); localStorage.setItem(STORAGE_KEY, JSON.stringify(connections)); alert('โœ… Disconnected successfully'); // Trigger re-render if on Connections tab const event = new CustomEvent('sftp-disconnected'); document.dispatchEvent(event); } else { alert('โŒ ' + (data.message || 'Disconnect failed')); } } catch (err) { alert('Error: ' + err.message); } } }); window.AppMenu.push({ label: '๐Ÿงช Test SFTP', action: async () => { try { const res = await fetch('SFTPconnector.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'test' }) }); const data = await res.json(); if (data.success) { const info = data.data; alert('๐Ÿงช SFTP Test Results\n\n' + `SSH2 Extension: ${info.ssh2_loaded ? 'โœ…' : 'โŒ'}\n` + `Exec Available: ${info.exec_available ? 'โœ…' : 'โŒ'}\n` + `Session Active: ${info.session_active ? 'โœ…' : 'โŒ'}\n` + `PHP Version: ${info.php_version}\n` + `Preferred Method: ${info.preferred_method}\n` + `Server Time: ${info.time}`); } else { alert('โŒ Test failed: ' + (data.message || 'Unknown error')); } } catch (err) { alert('Error: ' + err.message); } } }); window.AppMenu.push({ label: '๐Ÿ—‘๏ธ Clear Saved Connections', action: () => { if (!confirm('Delete all saved connections? This cannot be undone.')) return; localStorage.removeItem('sftp_connections'); alert('โœ… All saved connections deleted'); // Trigger re-render if on Connections tab const event = new CustomEvent('connections-cleared'); document.dispatchEvent(event); } }); window.AppMenu.push({ label: 'โ„น๏ธ About', action: () => { alert('SFTP Manager v1.0\n\n' + 'Secure file transfer manager\n' + 'Built with PHP SSH2 Extension\n\n' + 'ยฉ 2025 DevBrewing'); } }); // Listen for custom events to re-render connections document.addEventListener('sftp-disconnected', () => { const grid = document.getElementById('connectionsGrid'); if (grid && typeof renderConnections === 'function') { renderConnections(); } }); document.addEventListener('connections-cleared', () => { const grid = document.getElementById('connectionsGrid'); if (grid && typeof renderConnections === 'function') { renderConnections(); } }); console.log('[menu.js] Loaded - 3-dot menu with', window.AppMenu.length, 'items'); })();