Copy/Move functionality

This commit is contained in:
Ryan
2025-03-04 06:55:36 -05:00
committed by GitHub
parent 850e42af15
commit 8d05a36f04
7 changed files with 650 additions and 487 deletions

View File

@@ -1,8 +1,10 @@
// displayFileList.js
import { sendRequest, toggleVisibility } from './utils.js';
let fileData = [];
let sortOrder = { column: "uploaded", ascending: false };
export let currentFolder = "root"; // Global current folder
export function loadFileList() {
sendRequest("checkAuth.php")
@@ -13,7 +15,7 @@ export function loadFileList() {
return;
}
toggleVisibility("fileListContainer", true);
return sendRequest("getFileList.php");
return sendRequest("getFileList.php?folder=" + encodeURIComponent(currentFolder));
})
.then(data => {
if (!data) return;
@@ -26,111 +28,23 @@ export function loadFileList() {
return;
}
fileData = data.files;
sortFiles("uploaded", false);
//sortFiles("uploaded", false);
})
.catch(error => console.error("Error loading file list:", error));
}
export function sortFiles(column, forceAscending = null) {
if (sortOrder.column === column) {
sortOrder.ascending = forceAscending !== null ? forceAscending : !sortOrder.ascending;
} else {
sortOrder.column = column;
sortOrder.ascending = forceAscending !== null ? forceAscending : true;
}
fileData.sort((a, b) => {
let valA = a[column] || "";
let valB = b[column] || "";
if (column === "modified" || column === "uploaded") {
const dateA = new Date(valA);
const dateB = new Date(valB);
if (!isNaN(dateA.getTime()) && !isNaN(dateB.getTime())) {
valA = dateA.getTime();
valB = dateB.getTime();
} else {
valA = valA.toLowerCase();
valB = valB.toLowerCase();
}
} 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;
});
renderFileTable();
}
export function renderFileTable() {
const fileListContainer = document.getElementById("fileList");
let tableHTML = `<table class="table">
<thead>
<tr>
<th><input type="checkbox" id="selectAll" onclick="toggleAllCheckboxes(this)"></th>
<th onclick="sortFiles('name')" style="cursor:pointer; text-decoration: underline; white-space: nowrap;">
<span>File Name</span> <span>${sortOrder.column === "name" ? (sortOrder.ascending ? "▲" : "▼") : ""}</span>
</th>
<th onclick="sortFiles('modified')" style="cursor:pointer; text-decoration: underline; white-space: nowrap;">
<span>Date Modified</span> <span>${sortOrder.column === "modified" ? (sortOrder.ascending ? "▲" : "▼") : ""}</span>
</th>
<th onclick="sortFiles('uploaded')" style="cursor:pointer; text-decoration: underline; white-space: nowrap;">
<span>Upload Date</span> <span>${sortOrder.column === "uploaded" ? (sortOrder.ascending ? "▲" : "▼") : ""}</span>
</th>
<th onclick="sortFiles('size')" style="cursor:pointer; text-decoration: underline; white-space: nowrap;">
<span>File Size</span> <span>${sortOrder.column === "size" ? (sortOrder.ascending ? "▲" : "▼") : ""}</span>
</th>
<th onclick="sortFiles('uploader')" style="cursor:pointer; text-decoration: underline; white-space: nowrap;">
<span>Uploader</span> <span>${sortOrder.column === "uploader" ? (sortOrder.ascending ? "▲" : "▼") : ""}</span>
</th>
<th>Actions</th>
</tr>
</thead>
<tbody>`;
fileData.forEach(file => {
const isEditable = file.name.endsWith(".txt") || file.name.endsWith(".json") ||
file.name.endsWith(".ini") || file.name.endsWith(".css") ||
file.name.endsWith(".js") || file.name.endsWith(".csv") ||
file.name.endsWith(".md") || file.name.endsWith(".xml") ||
file.name.endsWith(".html") || file.name.endsWith(".py") ||
file.name.endsWith(".log") || file.name.endsWith(".conf") ||
file.name.endsWith(".config") || file.name.endsWith(".bat") ||
file.name.endsWith(".rtf") || file.name.endsWith(".doc") ||
file.name.endsWith(".docx");
tableHTML += `<tr>
<td><input type="checkbox" class="file-checkbox" value="${file.name}" onclick="toggleDeleteButton()"></td>
<td>${file.name}</td>
<td style="white-space: nowrap;">${file.modified}</td>
<td style="white-space: nowrap;">${file.uploaded}</td>
<td style="white-space: nowrap;">${file.size}</td>
<td style="white-space: nowrap;">${file.uploader || "Unknown"}</td>
<td>
<div style="display: inline-flex; align-items: center; gap: 5px; flex-wrap: nowrap;">
<a href="uploads/${file.name}" download>Download</a>
${isEditable ? `<button onclick="editFile('${file.name}')">Edit</button>` : ""}
</div>
</td>
</tr>`;
});
tableHTML += `</tbody></table>`;
fileListContainer.innerHTML = tableHTML;
const deleteBtn = document.getElementById("deleteSelectedBtn");
if (fileData.length > 0) {
deleteBtn.style.display = "block";
const selectedFiles = document.querySelectorAll(".file-checkbox:checked");
deleteBtn.disabled = selectedFiles.length === 0;
} else {
deleteBtn.style.display = "none";
}
}
export function toggleDeleteButton() {
const selectedFiles = document.querySelectorAll(".file-checkbox:checked");
const deleteBtn = document.getElementById("deleteSelectedBtn");
deleteBtn.disabled = selectedFiles.length === 0;
const copyBtn = document.getElementById("copySelectedBtn");
const moveBtn = document.getElementById("moveSelectedBtn");
const disabled = selectedFiles.length === 0;
deleteBtn.disabled = disabled;
if (copyBtn) copyBtn.disabled = disabled;
if (moveBtn) moveBtn.disabled = disabled;
}
export function toggleAllCheckboxes(source) {
@@ -141,7 +55,7 @@ export function toggleAllCheckboxes(source) {
export function deleteSelectedFiles() {
const selectedFiles = Array.from(document.querySelectorAll(".file-checkbox:checked"))
.map(checkbox => checkbox.value);
.map(checkbox => checkbox.value);
if (selectedFiles.length === 0) {
alert("No files selected for deletion.");
return;
@@ -158,10 +72,22 @@ export function deleteSelectedFiles() {
}
document.addEventListener("DOMContentLoaded", function () {
loadFileList();
loadCopyMoveFolderList();
const deleteBtn = document.getElementById("deleteSelectedBtn");
if (deleteBtn) {
deleteBtn.addEventListener("click", deleteSelectedFiles);
}
const copyBtn = document.getElementById("copySelectedBtn");
const moveBtn = document.getElementById("moveSelectedBtn");
if (copyBtn) {
copyBtn.addEventListener("click", copySelectedFiles);
}
if (moveBtn) {
moveBtn.addEventListener("click", moveSelectedFiles);
}
});
export function editFile(fileName) {
@@ -186,12 +112,12 @@ export function editFile(fileName) {
modal.id = "editorContainer";
modal.classList.add("modal", "editor-modal");
modal.innerHTML = `
<h3>Editing: ${fileName}</h3>
<textarea id="fileEditor" style="width:100%; height:60%; resize:none;">${content}</textarea>
<div style="margin-top:10px; text-align:right;">
<button onclick="saveFile('${fileName}')" class="btn btn-primary">Save</button>
<button onclick="document.getElementById('editorContainer').remove()" class="btn btn-secondary">Close</button>
</div>
<h3>Editing: ${fileName}</h3>
<textarea id="fileEditor" style="width:100%; height:60%; resize:none;">${content}</textarea>
<div style="margin-top:10px; text-align:right;">
<button onclick="saveFile('${fileName}')" class="btn btn-primary">Save</button>
<button onclick="document.getElementById('editorContainer').remove()" class="btn btn-secondary">Close</button>
</div>
`;
document.body.appendChild(modal);
modal.style.display = "block";
@@ -218,11 +144,91 @@ export function saveFile(fileName) {
.catch(error => console.error("Error saving file:", error));
}
// To support inline onclick attributes in the generated HTML, attach these functions to window.
window.sortFiles = sortFiles;
// ===== NEW CODE: Copy & Move Functions =====
// Copy selected files to a target folder
export function copySelectedFiles() {
const selectedFiles = Array.from(document.querySelectorAll(".file-checkbox:checked"))
.map(checkbox => checkbox.value);
const targetFolder = document.getElementById("copyMoveFolderSelect").value;
if (selectedFiles.length === 0) {
alert("Please select at least one file to copy.");
return;
}
if (!targetFolder) {
alert("Please select a target folder.");
return;
}
// Send the correct keys
sendRequest("copyFiles.php", "POST", {
source: currentFolder,
destination: targetFolder,
files: selectedFiles
})
.then(result => {
alert(result.success || result.error);
loadFileList();
})
.catch(error => console.error("Error copying files:", error));
}
export function moveSelectedFiles() {
const selectedFiles = Array.from(document.querySelectorAll(".file-checkbox:checked"))
.map(checkbox => checkbox.value);
const targetFolder = document.getElementById("copyMoveFolderSelect").value;
if (selectedFiles.length === 0) {
alert("Please select at least one file to move.");
return;
}
if (!targetFolder) {
alert("Please select a target folder.");
return;
}
console.log("Payload:", {
source: currentFolder,
destination: document.getElementById("copyMoveFolderSelect").value,
files: selectedFiles
});
sendRequest("moveFiles.php", "POST", {
source: currentFolder,
destination: targetFolder,
files: selectedFiles
})
.then(result => {
alert(result.success || result.error);
loadFileList();
})
.catch(error => console.error("Error moving files:", error));
}
// Populate the Copy/Move folder dropdown
export function loadCopyMoveFolderList() {
$.get('getFolderList.php', function (response) {
const folderSelect = $('#copyMoveFolderSelect');
folderSelect.empty();
// Always add a "Root" option as the default.
folderSelect.append($('<option>', { value: "root", text: "Root" }));
if (Array.isArray(response) && response.length > 0) {
response.forEach(function (folder) {
folderSelect.append($('<option>', {
value: folder,
text: folder
}));
});
}
}, 'json');
}
// Attach functions to window for inline onclick support
window.toggleDeleteButton = toggleDeleteButton;
window.toggleAllCheckboxes = toggleAllCheckboxes;
window.deleteSelectedFiles = deleteSelectedFiles;
window.editFile = editFile;
window.saveFile = saveFile;
window.loadFileList = loadFileList;
window.copySelectedFiles = copySelectedFiles;
window.moveSelectedFiles = moveSelectedFiles;