import { escapeHTML, debounce, buildSearchAndPaginationControls, buildFileTableHeader, buildFileTableRow, buildBottomControls, updateFileActionButtons, showToast, updateRowHighlight, toggleRowSelection, previewFile as originalPreviewFile } from './domUtils.js'; export let fileData = []; export let sortOrder = { column: "uploaded", ascending: true }; window.itemsPerPage = window.itemsPerPage || 10; window.currentPage = window.currentPage || 1; window.viewMode = localStorage.getItem("viewMode") || "table"; // "table" or "gallery" // ============================== // VIEW MODE TOGGLE BUTTON // ============================== function createViewToggleButton() { let toggleBtn = document.getElementById("toggleViewBtn"); if (!toggleBtn) { toggleBtn = document.createElement("button"); toggleBtn.id = "toggleViewBtn"; toggleBtn.classList.add("btn", "btn-secondary"); const titleElem = document.getElementById("fileListTitle"); if (titleElem) { titleElem.parentNode.insertBefore(toggleBtn, titleElem.nextSibling); } } toggleBtn.textContent = window.viewMode === "gallery" ? "Switch to Table View" : "Switch to Gallery View"; toggleBtn.onclick = () => { window.viewMode = window.viewMode === "gallery" ? "table" : "gallery"; localStorage.setItem("viewMode", window.viewMode); loadFileList(window.currentFolder); toggleBtn.textContent = window.viewMode === "gallery" ? "Switch to Table View" : "Switch to Gallery View"; }; return toggleBtn; } window.createViewToggleButton = createViewToggleButton; // ----------------------------- // Helper: formatFolderName // ----------------------------- function formatFolderName(folder) { if (folder === "root") return "(Root)"; return folder .replace(/[_-]+/g, " ") .replace(/\b\w/g, char => char.toUpperCase()); } // Expose inline DOM helpers. window.toggleRowSelection = toggleRowSelection; window.updateRowHighlight = updateRowHighlight; // ============================================== // FEATURE: Public File Sharing Modal // ============================================== function openShareModal(file, folder) { const existing = document.getElementById("shareModal"); if (existing) existing.remove(); const modal = document.createElement("div"); modal.id = "shareModal"; modal.classList.add("modal"); modal.innerHTML = ` `; document.body.appendChild(modal); modal.style.display = "block"; document.getElementById("closeShareModal").addEventListener("click", () => { modal.remove(); }); document.getElementById("generateShareLinkBtn").addEventListener("click", () => { const expiration = document.getElementById("shareExpiration").value; const password = document.getElementById("sharePassword").value; fetch("createShareLink.php", { method: "POST", credentials: "include", headers: { "Content-Type": "application/json", "X-CSRF-Token": window.csrfToken }, body: JSON.stringify({ folder: folder, file: file.name, expirationMinutes: parseInt(expiration), password: password }) }) .then(response => response.json()) .then(data => { if (data.token) { // Get the share endpoint from the meta tag (or fallback to a global variable) let shareEndpoint = document.querySelector('meta[name="share-url"]') ? document.querySelector('meta[name="share-url"]').getAttribute('content') : (window.SHARE_URL || "share.php"); const shareUrl = `${shareEndpoint}?token=${encodeURIComponent(data.token)}`; const displayDiv = document.getElementById("shareLinkDisplay"); const inputField = document.getElementById("shareLinkInput"); inputField.value = shareUrl; displayDiv.style.display = "block"; } else { showToast("Error generating share link: " + (data.error || "Unknown error")); } }) .catch(err => { console.error("Error generating share link:", err); showToast("Error generating share link."); }); }); document.getElementById("copyShareLinkBtn").addEventListener("click", () => { const input = document.getElementById("shareLinkInput"); input.select(); document.execCommand("copy"); showToast("Link copied to clipboard!"); }); } // ============================================== // FEATURE: Enhanced Preview Modal with Navigation // ============================================= // This function replaces the previous preview behavior for images. // It uses your original modal layout and, if multiple images exist, // overlays transparent Prev/Next buttons over the image. function enhancedPreviewFile(fileUrl, fileName) { let modal = document.getElementById("filePreviewModal"); if (!modal) { modal = document.createElement("div"); modal.id = "filePreviewModal"; Object.assign(modal.style, { position: "fixed", top: "0", left: "0", width: "100vw", height: "100vh", backgroundColor: "rgba(0,0,0,0.7)", display: "flex", justifyContent: "center", alignItems: "center", zIndex: "1000" }); modal.innerHTML = ` `; document.body.appendChild(modal); document.getElementById("closeFileModal").addEventListener("click", function () { modal.style.display = "none"; }); modal.addEventListener("click", function (e) { if (e.target === modal) { modal.style.display = "none"; } }); } modal.querySelector("h4").textContent = fileName; const container = modal.querySelector(".file-preview-container"); container.innerHTML = ""; const extension = fileName.split('.').pop().toLowerCase(); const isImage = /\.(jpg|jpeg|png|gif|bmp|webp|svg|ico)$/i.test(fileName); if (isImage) { const img = document.createElement("img"); img.src = fileUrl; img.className = "image-modal-img"; img.style.maxWidth = "80vw"; img.style.maxHeight = "80vh"; container.appendChild(img); // If multiple images exist, add arrow navigation. const images = fileData.filter(file => /\.(jpg|jpeg|png|gif|bmp|webp|svg|ico)$/i.test(file.name)); if (images.length > 1) { modal.galleryImages = images; modal.galleryCurrentIndex = images.findIndex(f => f.name === fileName); const prevBtn = document.createElement("button"); prevBtn.textContent = "‹"; prevBtn.className = "gallery-nav-btn"; prevBtn.style.cssText = "position: absolute; top: 50%; left: 10px; transform: translateY(-50%); background: transparent; border: none; color: white; font-size: 48px; cursor: pointer;"; prevBtn.addEventListener("click", function (e) { e.stopPropagation(); modal.galleryCurrentIndex = (modal.galleryCurrentIndex - 1 + modal.galleryImages.length) % modal.galleryImages.length; let newFile = modal.galleryImages[modal.galleryCurrentIndex]; modal.querySelector("h4").textContent = newFile.name; img.src = ((window.currentFolder === "root") ? "uploads/" : "uploads/" + window.currentFolder.split("/").map(encodeURIComponent).join("/") + "/") + encodeURIComponent(newFile.name) + "?t=" + new Date().getTime(); }); const nextBtn = document.createElement("button"); nextBtn.textContent = "›"; nextBtn.className = "gallery-nav-btn"; nextBtn.style.cssText = "position: absolute; top: 50%; right: 10px; transform: translateY(-50%); background: transparent; border: none; color: white; font-size: 48px; cursor: pointer;"; nextBtn.addEventListener("click", function (e) { e.stopPropagation(); modal.galleryCurrentIndex = (modal.galleryCurrentIndex + 1) % modal.galleryImages.length; let newFile = modal.galleryImages[modal.galleryCurrentIndex]; modal.querySelector("h4").textContent = newFile.name; img.src = ((window.currentFolder === "root") ? "uploads/" : "uploads/" + window.currentFolder.split("/").map(encodeURIComponent).join("/") + "/") + encodeURIComponent(newFile.name) + "?t=" + new Date().getTime(); }); container.appendChild(prevBtn); container.appendChild(nextBtn); } } else { if (extension === "pdf") { const embed = document.createElement("embed"); const separator = fileUrl.indexOf('?') === -1 ? '?' : '&'; embed.src = fileUrl + separator + 't=' + new Date().getTime(); embed.type = "application/pdf"; embed.style.width = "80vw"; embed.style.height = "80vh"; embed.style.border = "none"; container.appendChild(embed); } else if (/\.(mp4|webm|mov|ogg)$/i.test(fileName)) { const video = document.createElement("video"); video.src = fileUrl; video.controls = true; video.className = "image-modal-img"; container.appendChild(video); } else { container.textContent = "Preview not available for this file type."; } } modal.style.display = "flex"; } export function previewFile(fileUrl, fileName) { enhancedPreviewFile(fileUrl, fileName); } // ============================================== // ORIGINAL FILE MANAGER FUNCTIONS // ============================================== export function loadFileList(folderParam) { const folder = folderParam || "root"; const fileListContainer = document.getElementById("fileList"); fileListContainer.style.visibility = "hidden"; fileListContainer.innerHTML = "
Loading files...
"; return fetch("getFileList.php?folder=" + encodeURIComponent(folder) + "&recursive=1&t=" + new Date().getTime()) .then(response => { // Check if the session has expired. if (response.status === 401) { showToast("Session expired. Please log in again."); // Redirect to logout.php to clear the session; this can trigger a login process. window.location.href = "logout.php"; // Throw error to stop further processing. throw new Error("Unauthorized"); } return response.json(); }) .then(data => { fileListContainer.innerHTML = ""; if (data.files && data.files.length > 0) { data.files = data.files.map(file => { file.fullName = (file.path || file.name).trim().toLowerCase(); file.editable = canEditFile(file.name); file.folder = folder; if (!file.type && /\.(jpg|jpeg|png|gif|bmp|webp|svg|ico)$/i.test(file.name)) { file.type = "image"; } return file; }); fileData = data.files; if (window.viewMode === "gallery") { renderGalleryView(folder); } else { renderFileTable(folder); } } else { fileListContainer.textContent = "No files found."; updateFileActionButtons(); } return data.files || []; }) .catch(error => { console.error("Error loading file list:", error); // Only update the container text if error is not due to an unauthorized response. if (error.message !== "Unauthorized") { fileListContainer.textContent = "Error loading files."; } return []; }) .finally(() => { fileListContainer.style.visibility = "visible"; }); } export function renderFileTable(folder) { const fileListContainer = document.getElementById("fileList"); const searchTerm = window.currentSearchTerm || ""; const itemsPerPageSetting = parseInt(localStorage.getItem('itemsPerPage') || '10', 10); let currentPage = window.currentPage || 1; const filteredFiles = fileData.filter(file => file.name.toLowerCase().includes(searchTerm.toLowerCase()) ); const totalFiles = filteredFiles.length; const totalPages = Math.ceil(totalFiles / itemsPerPageSetting); if (currentPage > totalPages) { currentPage = totalPages > 0 ? totalPages : 1; window.currentPage = currentPage; } const folderPath = (folder === "root") ? "uploads/" : "uploads/" + folder.split("/").map(encodeURIComponent).join("/") + "/"; const topControlsHTML = buildSearchAndPaginationControls({ currentPage, totalPages, searchTerm }); let headerHTML = buildFileTableHeader(sortOrder); // Do not add a separate share column; share button goes into the actions cell. const startIndex = (currentPage - 1) * itemsPerPageSetting; const endIndex = Math.min(startIndex + itemsPerPageSetting, totalFiles); let rowsHTML = ""; if (totalFiles > 0) { filteredFiles.slice(startIndex, endIndex).forEach(file => { let rowHTML = buildFileTableRow(file, folderPath); // Insert share button into the actions container. rowHTML = rowHTML.replace(/(<\/div>\s*<\/td>\s*<\/tr>)/, `$1`); rowsHTML += rowHTML; }); } else { rowsHTML += `No files found.`; } rowsHTML += ""; const bottomControlsHTML = buildBottomControls(itemsPerPageSetting); fileListContainer.innerHTML = topControlsHTML + headerHTML + rowsHTML + bottomControlsHTML; createViewToggleButton(); const newSearchInput = document.getElementById("searchInput"); if (newSearchInput) { newSearchInput.addEventListener("input", debounce(function () { window.currentSearchTerm = newSearchInput.value; window.currentPage = 1; renderFileTable(folder); setTimeout(() => { newSearchInput.focus(); newSearchInput.setSelectionRange(newSearchInput.value.length, newSearchInput.value.length); }, 0); }, 300)); } document.querySelectorAll("table.table thead th[data-column]").forEach(cell => { cell.addEventListener("click", function () { const column = this.getAttribute("data-column"); sortFiles(column, folder); }); }); document.querySelectorAll('#fileList .file-checkbox').forEach(checkbox => { checkbox.addEventListener('change', function (e) { updateRowHighlight(e.target); updateFileActionButtons(); }); }); // Bind share button events in table view. document.querySelectorAll(".share-btn").forEach(btn => { btn.addEventListener("click", function (e) { e.stopPropagation(); const fileName = this.getAttribute("data-file"); const file = fileData.find(f => f.name === fileName); if (file) { openShareModal(file, folder); } }); }); updateFileActionButtons(); } export function renderGalleryView(folder) { const fileListContainer = document.getElementById("fileList"); const folderPath = (folder === "root") ? "uploads/" : "uploads/" + folder.split("/").map(encodeURIComponent).join("/") + "/"; // Use CSS Grid for gallery layout. const gridStyle = "display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 10px; padding: 10px;"; let galleryHTML = `"; fileListContainer.innerHTML = galleryHTML; document.querySelectorAll(".gallery-share-btn").forEach(btn => { btn.addEventListener("click", function (e) { e.stopPropagation(); const fileName = this.getAttribute("data-file"); const folder = this.getAttribute("data-folder"); const file = fileData.find(f => f.name === fileName); if (file) { openShareModal(file, folder); } }); }); createViewToggleButton(); updateFileActionButtons(); } export function sortFiles(column, folder) { if (sortOrder.column === column) { sortOrder.ascending = !sortOrder.ascending; } else { sortOrder.column = column; sortOrder.ascending = true; } fileData.sort((a, b) => { let valA = a[column] || ""; let valB = b[column] || ""; if (column === "modified" || column === "uploaded") { const parsedA = parseCustomDate(valA); const parsedB = parseCustomDate(valB); valA = parsedA; valB = parsedB; } else if (typeof valA === "string") { valA = valA.toLowerCase(); valB = valB.toLowerCase(); } if (valA < valB) return sortOrder.ascending ? -1 : 1; if (valA > valB) return sortOrder.ascending ? 1 : -1; return 0; }); if (window.viewMode === "gallery") { renderGalleryView(folder); } else { renderFileTable(folder); } } function parseCustomDate(dateStr) { dateStr = dateStr.replace(/\s+/g, " ").trim(); const parts = dateStr.split(" "); if (parts.length !== 2) { return new Date(dateStr).getTime(); } const datePart = parts[0]; const timePart = parts[1]; const dateComponents = datePart.split("/"); if (dateComponents.length !== 3) { return new Date(dateStr).getTime(); } let month = parseInt(dateComponents[0], 10); let day = parseInt(dateComponents[1], 10); let year = parseInt(dateComponents[2], 10); if (year < 100) { year += 2000; } const timeRegex = /^(\d{1,2}):(\d{2})(AM|PM)$/i; const match = timePart.match(timeRegex); if (!match) { return new Date(dateStr).getTime(); } let hour = parseInt(match[1], 10); const minute = parseInt(match[2], 10); const period = match[3].toUpperCase(); if (period === "PM" && hour !== 12) { hour += 12; } if (period === "AM" && hour === 12) { hour = 0; } return new Date(year, month - 1, day, hour, minute).getTime(); } export function canEditFile(fileName) { const allowedExtensions = [ "txt", "html", "htm", "css", "js", "json", "xml", "md", "py", "ini", "csv", "log", "conf", "config", "bat", "rtf", "doc", "docx" ]; const ext = fileName.slice(fileName.lastIndexOf('.') + 1).toLowerCase(); return allowedExtensions.includes(ext); } export function handleDeleteSelected(e) { e.preventDefault(); e.stopImmediatePropagation(); const checkboxes = document.querySelectorAll(".file-checkbox:checked"); if (checkboxes.length === 0) { showToast("No files selected."); return; } window.filesToDelete = Array.from(checkboxes).map(chk => chk.value); document.getElementById("deleteFilesMessage").textContent = "Are you sure you want to delete " + window.filesToDelete.length + " selected file(s)?"; document.getElementById("deleteFilesModal").style.display = "block"; } document.addEventListener("DOMContentLoaded", function () { const cancelDelete = document.getElementById("cancelDeleteFiles"); if (cancelDelete) { cancelDelete.addEventListener("click", function () { document.getElementById("deleteFilesModal").style.display = "none"; window.filesToDelete = []; }); } const confirmDelete = document.getElementById("confirmDeleteFiles"); if (confirmDelete) { confirmDelete.addEventListener("click", function () { fetch("deleteFiles.php", { method: "POST", credentials: "include", headers: { "Content-Type": "application/json", "X-CSRF-Token": window.csrfToken }, body: JSON.stringify({ folder: window.currentFolder, files: window.filesToDelete }) }) .then(response => response.json()) .then(data => { if (data.success) { showToast("Selected files deleted successfully!"); loadFileList(window.currentFolder); } else { showToast("Error: " + (data.error || "Could not delete files")); } }) .catch(error => console.error("Error deleting files:", error)) .finally(() => { document.getElementById("deleteFilesModal").style.display = "none"; window.filesToDelete = []; }); }); } }); export function handleDownloadZipSelected(e) { e.preventDefault(); e.stopImmediatePropagation(); const checkboxes = document.querySelectorAll(".file-checkbox:checked"); if (checkboxes.length === 0) { showToast("No files selected for download."); return; } window.filesToDownload = Array.from(checkboxes).map(chk => chk.value); document.getElementById("downloadZipModal").style.display = "block"; } document.addEventListener("DOMContentLoaded", function () { const cancelDownloadZip = document.getElementById("cancelDownloadZip"); if (cancelDownloadZip) { cancelDownloadZip.addEventListener("click", function () { document.getElementById("downloadZipModal").style.display = "none"; }); } const confirmDownloadZip = document.getElementById("confirmDownloadZip"); if (confirmDownloadZip) { confirmDownloadZip.addEventListener("click", function () { let zipName = document.getElementById("zipFileNameInput").value.trim(); if (!zipName) { showToast("Please enter a name for the zip file."); return; } if (!zipName.toLowerCase().endsWith(".zip")) { zipName += ".zip"; } document.getElementById("downloadZipModal").style.display = "none"; const folder = window.currentFolder || "root"; fetch("downloadZip.php", { method: "POST", credentials: "include", headers: { "Content-Type": "application/json", "X-CSRF-Token": window.csrfToken }, body: JSON.stringify({ folder: folder, files: window.filesToDownload }) }) .then(response => { if (!response.ok) { return response.text().then(text => { throw new Error("Failed to create zip file: " + text); }); } return response.blob(); }) .then(blob => { if (!blob || blob.size === 0) { throw new Error("Received empty zip file."); } const url = window.URL.createObjectURL(blob); const a = document.createElement("a"); a.style.display = "none"; a.href = url; a.download = zipName; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); a.remove(); showToast("Download started."); }) .catch(error => { console.error("Error downloading zip:", error); showToast("Error downloading selected files as zip: " + error.message); }); }); } }); export function handleCopySelected(e) { e.preventDefault(); e.stopImmediatePropagation(); const checkboxes = document.querySelectorAll(".file-checkbox:checked"); if (checkboxes.length === 0) { showToast("No files selected for copying.", 5000); return; } window.filesToCopy = Array.from(checkboxes).map(chk => chk.value); document.getElementById("copyFilesModal").style.display = "block"; loadCopyMoveFolderListForModal("copyTargetFolder"); } export async function loadCopyMoveFolderListForModal(dropdownId) { try { const response = await fetch('getFolderList.php'); let folders = await response.json(); if (Array.isArray(folders) && folders.length && typeof folders[0] === "object" && folders[0].folder) { folders = folders.map(item => item.folder); } folders = folders.filter(folder => folder !== "root"); const folderSelect = document.getElementById(dropdownId); folderSelect.innerHTML = ''; const rootOption = document.createElement('option'); rootOption.value = 'root'; rootOption.textContent = '(Root)'; folderSelect.appendChild(rootOption); if (Array.isArray(folders) && folders.length > 0) { folders.forEach(folder => { const option = document.createElement('option'); option.value = folder; option.textContent = formatFolderName(folder); folderSelect.appendChild(option); }); } } catch (error) { console.error('Error loading folder list for modal:', error); } } document.addEventListener("DOMContentLoaded", function () { const cancelCopy = document.getElementById("cancelCopyFiles"); if (cancelCopy) { cancelCopy.addEventListener("click", function () { document.getElementById("copyFilesModal").style.display = "none"; window.filesToCopy = []; }); } const confirmCopy = document.getElementById("confirmCopyFiles"); if (confirmCopy) { confirmCopy.addEventListener("click", function () { const targetFolder = document.getElementById("copyTargetFolder").value; if (!targetFolder) { showToast("Please select a target folder for copying.", 5000); return; } if (targetFolder === window.currentFolder) { showToast("Error: Cannot copy files to the same folder."); return; } fetch("copyFiles.php", { method: "POST", credentials: "include", headers: { "Content-Type": "application/json", "X-CSRF-Token": window.csrfToken }, body: JSON.stringify({ source: window.currentFolder, files: window.filesToCopy, destination: targetFolder }) }) .then(response => response.json()) .then(data => { if (data.success) { showToast("Selected files copied successfully!", 5000); loadFileList(window.currentFolder); } else { showToast("Error: " + (data.error || "Could not copy files"), 5000); } }) .catch(error => console.error("Error copying files:", error)) .finally(() => { document.getElementById("copyFilesModal").style.display = "none"; window.filesToCopy = []; }); }); } }); export function handleMoveSelected(e) { e.preventDefault(); e.stopImmediatePropagation(); const checkboxes = document.querySelectorAll(".file-checkbox:checked"); if (checkboxes.length === 0) { showToast("No files selected for moving."); return; } window.filesToMove = Array.from(checkboxes).map(chk => chk.value); document.getElementById("moveFilesModal").style.display = "block"; loadCopyMoveFolderListForModal("moveTargetFolder"); } document.addEventListener("DOMContentLoaded", function () { const cancelMove = document.getElementById("cancelMoveFiles"); if (cancelMove) { cancelMove.addEventListener("click", function () { document.getElementById("moveFilesModal").style.display = "none"; window.filesToMove = []; }); } const confirmMove = document.getElementById("confirmMoveFiles"); if (confirmMove) { confirmMove.addEventListener("click", function () { const targetFolder = document.getElementById("moveTargetFolder").value; if (!targetFolder) { showToast("Please select a target folder for moving."); return; } if (targetFolder === window.currentFolder) { showToast("Error: Cannot move files to the same folder."); return; } fetch("moveFiles.php", { method: "POST", credentials: "include", headers: { "Content-Type": "application/json", "X-CSRF-Token": window.csrfToken }, body: JSON.stringify({ source: window.currentFolder, files: window.filesToMove, destination: targetFolder }) }) .then(response => response.json()) .then(data => { if (data.success) { showToast("Selected files moved successfully!"); loadFileList(window.currentFolder); } else { showToast("Error: " + (data.error || "Could not move files")); } }) .catch(error => console.error("Error moving files:", error)) .finally(() => { document.getElementById("moveFilesModal").style.display = "none"; window.filesToMove = []; }); }); } }); // Helper for CodeMirror editor mode based on file extension. function getModeForFile(fileName) { const ext = fileName.slice(fileName.lastIndexOf('.') + 1).toLowerCase(); switch (ext) { case 'css': return "css"; case 'json': return { name: "javascript", json: true }; case 'js': return "javascript"; case 'html': case 'htm': return "text/html"; case 'xml': return "xml"; default: return "text/plain"; } } function adjustEditorSize() { const modal = document.querySelector(".editor-modal"); if (modal && window.currentEditor) { const modalHeight = modal.getBoundingClientRect().height || 600; const newEditorHeight = Math.max(modalHeight * 0.80, 5) + "px"; window.currentEditor.setSize("100%", newEditorHeight); } } function observeModalResize(modal) { if (!modal) return; const resizeObserver = new ResizeObserver(() => { adjustEditorSize(); }); resizeObserver.observe(modal); } export function editFile(fileName, folder) { let existingEditor = document.getElementById("editorContainer"); if (existingEditor) { existingEditor.remove(); } const folderUsed = folder || window.currentFolder || "root"; const folderPath = (folderUsed === "root") ? "uploads/" : "uploads/" + folderUsed.split("/").map(encodeURIComponent).join("/") + "/"; const fileUrl = folderPath + encodeURIComponent(fileName) + "?t=" + new Date().getTime(); fetch(fileUrl, { method: "HEAD" }) .then(response => { const contentLength = response.headers.get("Content-Length"); if (!contentLength || parseInt(contentLength) > 10485760) { showToast("This file is larger than 10 MB and cannot be edited in the browser."); throw new Error("File too large."); } return fetch(fileUrl); }) .then(response => { if (!response.ok) { throw new Error("HTTP error! Status: " + response.status); } return response.text(); }) .then(content => { const modal = document.createElement("div"); modal.id = "editorContainer"; modal.classList.add("modal", "editor-modal"); modal.innerHTML = `

Editing: ${fileName}

`; document.body.appendChild(modal); modal.style.display = "block"; const mode = getModeForFile(fileName); const isDarkMode = document.body.classList.contains("dark-mode"); const theme = isDarkMode ? "material-darker" : "default"; const editor = CodeMirror.fromTextArea(document.getElementById("fileEditor"), { lineNumbers: true, mode: mode, theme: theme, viewportMargin: Infinity }); window.currentEditor = editor; setTimeout(() => { adjustEditorSize(); }, 50); observeModalResize(modal); let currentFontSize = 14; editor.getWrapperElement().style.fontSize = currentFontSize + "px"; editor.refresh(); document.getElementById("closeEditorX").addEventListener("click", function () { modal.remove(); }); document.getElementById("decreaseFont").addEventListener("click", function () { currentFontSize = Math.max(8, currentFontSize - 2); editor.getWrapperElement().style.fontSize = currentFontSize + "px"; editor.refresh(); }); document.getElementById("increaseFont").addEventListener("click", function () { currentFontSize = Math.min(32, currentFontSize + 2); editor.getWrapperElement().style.fontSize = currentFontSize + "px"; editor.refresh(); }); document.getElementById("saveBtn").addEventListener("click", function () { saveFile(fileName, folderUsed); }); document.getElementById("closeBtn").addEventListener("click", function () { modal.remove(); }); function updateEditorTheme() { const isDarkMode = document.body.classList.contains("dark-mode"); editor.setOption("theme", isDarkMode ? "material-darker" : "default"); } document.getElementById("darkModeToggle").addEventListener("click", updateEditorTheme); }) .catch(error => console.error("Error loading file:", error)); } export function saveFile(fileName, folder) { const editor = window.currentEditor; if (!editor) { console.error("Editor not found!"); return; } const folderUsed = folder || window.currentFolder || "root"; const fileDataObj = { fileName: fileName, content: editor.getValue(), folder: folderUsed }; fetch("saveFile.php", { method: "POST", credentials: "include", headers: { "Content-Type": "application/json", "X-CSRF-Token": window.csrfToken }, body: JSON.stringify(fileDataObj) }) .then(response => response.json()) .then(result => { showToast(result.success || result.error); document.getElementById("editorContainer")?.remove(); loadFileList(folderUsed); }) .catch(error => console.error("Error saving file:", error)); } export function displayFilePreview(file, container) { container.style.display = "inline-block"; if (/\.(jpg|jpeg|png|gif|bmp|webp|svg|ico)$/i.test(file.name)) { const img = document.createElement("img"); img.src = URL.createObjectURL(file); img.classList.add("file-preview-img"); container.appendChild(img); } else { const iconSpan = document.createElement("span"); iconSpan.classList.add("material-icons", "file-icon"); iconSpan.textContent = "insert_drive_file"; container.appendChild(iconSpan); } } export function initFileActions() { const deleteSelectedBtn = document.getElementById("deleteSelectedBtn"); if (deleteSelectedBtn) { deleteSelectedBtn.replaceWith(deleteSelectedBtn.cloneNode(true)); document.getElementById("deleteSelectedBtn").addEventListener("click", handleDeleteSelected); } const copySelectedBtn = document.getElementById("copySelectedBtn"); if (copySelectedBtn) { copySelectedBtn.replaceWith(copySelectedBtn.cloneNode(true)); document.getElementById("copySelectedBtn").addEventListener("click", handleCopySelected); } const moveSelectedBtn = document.getElementById("moveSelectedBtn"); if (moveSelectedBtn) { moveSelectedBtn.replaceWith(moveSelectedBtn.cloneNode(true)); document.getElementById("moveSelectedBtn").addEventListener("click", handleMoveSelected); } const downloadZipBtn = document.getElementById("downloadZipBtn"); if (downloadZipBtn) { downloadZipBtn.replaceWith(downloadZipBtn.cloneNode(true)); document.getElementById("downloadZipBtn").addEventListener("click", handleDownloadZipSelected); } } export function renameFile(oldName, folder) { window.fileToRename = oldName; window.fileFolder = folder || window.currentFolder || "root"; document.getElementById("newFileName").value = oldName; document.getElementById("renameFileModal").style.display = "block"; } document.addEventListener("DOMContentLoaded", () => { const cancelBtn = document.getElementById("cancelRenameFile"); if (cancelBtn) { cancelBtn.addEventListener("click", function () { document.getElementById("renameFileModal").style.display = "none"; document.getElementById("newFileName").value = ""; }); } const submitBtn = document.getElementById("submitRenameFile"); if (submitBtn) { submitBtn.addEventListener("click", function () { const newName = document.getElementById("newFileName").value.trim(); if (!newName || newName === window.fileToRename) { document.getElementById("renameFileModal").style.display = "none"; return; } const folderUsed = window.fileFolder; fetch("renameFile.php", { method: "POST", credentials: "include", headers: { "Content-Type": "application/json", "X-CSRF-Token": window.csrfToken }, body: JSON.stringify({ folder: folderUsed, oldName: window.fileToRename, newName: newName }) }) .then(response => response.json()) .then(data => { if (data.success) { showToast("File renamed successfully!"); loadFileList(folderUsed); } else { showToast("Error renaming file: " + (data.error || "Unknown error")); } }) .catch(error => { console.error("Error renaming file:", error); showToast("Error renaming file"); }) .finally(() => { document.getElementById("renameFileModal").style.display = "none"; document.getElementById("newFileName").value = ""; }); }); } }); window.renameFile = renameFile; window.changePage = function (newPage) { window.currentPage = newPage; renderFileTable(window.currentFolder); }; window.changeItemsPerPage = function (newCount) { window.itemsPerPage = parseInt(newCount); window.currentPage = 1; renderFileTable(window.currentFolder); }; window.previewFile = previewFile;