Files
FileRise/public/js/fileActions.js

576 lines
20 KiB
JavaScript

// fileActions.js
import { showToast, attachEnterKeyListener } from './domUtils.js';
import { loadFileList } from './fileListView.js';
import { formatFolderName } from './fileListView.js';
import { t } from './i18n.js';
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);
const count = window.filesToDelete.length;
document.getElementById("deleteFilesMessage").textContent = t("confirm_delete_files", { count: count });
document.getElementById("deleteFilesModal").style.display = "block";
attachEnterKeyListener("deleteFilesModal", "confirmDeleteFiles");
}
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("/api/file/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 = [];
});
});
}
});
attachEnterKeyListener("downloadZipModal", "confirmDownloadZip");
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";
setTimeout(() => {
const input = document.getElementById("zipFileNameInput");
input.focus();
}, 100);
};
export function openDownloadModal(fileName, folder) {
// Store file details globally for the download confirmation function.
window.singleFileToDownload = fileName;
window.currentFolder = folder || "root";
// Optionally pre-fill the file name input in the modal.
const input = document.getElementById("downloadFileNameInput");
if (input) {
input.value = fileName; // Use file name as-is (or modify if desired)
}
// Show the single file download modal (a new modal element).
document.getElementById("downloadFileModal").style.display = "block";
// Optionally focus the input after a short delay.
setTimeout(() => {
if (input) input.focus();
}, 100);
}
export function confirmSingleDownload() {
// Get the file name from the modal. Users can change it if desired.
let fileName = document.getElementById("downloadFileNameInput").value.trim();
if (!fileName) {
showToast("Please enter a name for the file.");
return;
}
// Hide the download modal.
document.getElementById("downloadFileModal").style.display = "none";
// Show the progress modal (same as in your ZIP download flow).
document.getElementById("downloadProgressModal").style.display = "block";
// Build the URL for download.php using GET parameters.
const folder = window.currentFolder || "root";
const downloadURL = "/api/file/download.php?folder=" + encodeURIComponent(folder) +
"&file=" + encodeURIComponent(window.singleFileToDownload);
fetch(downloadURL, {
method: "GET",
credentials: "include"
})
.then(response => {
if (!response.ok) {
return response.text().then(text => {
throw new Error("Failed to download file: " + text);
});
}
return response.blob();
})
.then(blob => {
if (!blob || blob.size === 0) {
throw new Error("Received empty file.");
}
const url = window.URL.createObjectURL(blob);
const a = document.createElement("a");
a.style.display = "none";
a.href = url;
a.download = fileName;
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
a.remove();
// Hide the progress modal.
document.getElementById("downloadProgressModal").style.display = "none";
showToast("Download started.");
})
.catch(error => {
// Hide progress modal and show error.
document.getElementById("downloadProgressModal").style.display = "none";
console.error("Error downloading file:", error);
showToast("Error downloading file: " + error.message);
});
}
export function handleExtractZipSelected(e) {
if (e) {
e.preventDefault();
e.stopImmediatePropagation();
}
const checkboxes = document.querySelectorAll(".file-checkbox:checked");
if (!checkboxes.length) {
showToast("No files selected.");
return;
}
const zipFiles = Array.from(checkboxes)
.map(chk => chk.value)
.filter(name => name.toLowerCase().endsWith(".zip"));
if (!zipFiles.length) {
showToast("No zip files selected.");
return;
}
// Change progress modal text to "Extracting files..."
const progressText = document.querySelector("#downloadProgressModal p");
if (progressText) {
progressText.textContent = "Extracting files...";
}
// Show the progress modal.
document.getElementById("downloadProgressModal").style.display = "block";
fetch("/api/file/extractZip.php", {
method: "POST",
credentials: "include",
headers: {
"Content-Type": "application/json",
"X-CSRF-Token": window.csrfToken
},
body: JSON.stringify({
folder: window.currentFolder || "root",
files: zipFiles
})
})
.then(response => response.json())
.then(data => {
// Hide the progress modal once the request has completed.
document.getElementById("downloadProgressModal").style.display = "none";
if (data.success) {
let toastMessage = "Zip file(s) extracted successfully!";
if (data.extractedFiles && Array.isArray(data.extractedFiles) && data.extractedFiles.length) {
toastMessage = "Extracted: " + data.extractedFiles.join(", ");
}
showToast(toastMessage);
loadFileList(window.currentFolder);
} else {
showToast("Error extracting zip: " + (data.error || "Unknown error"));
}
})
.catch(error => {
// Hide the progress modal on error.
document.getElementById("downloadProgressModal").style.display = "none";
console.error("Error extracting zip files:", error);
showToast("Error extracting zip files.");
});
}
const extractZipBtn = document.getElementById("extractZipBtn");
if (extractZipBtn) {
extractZipBtn.replaceWith(extractZipBtn.cloneNode(true));
document.getElementById("extractZipBtn").addEventListener("click", handleExtractZipSelected);
}
document.addEventListener("DOMContentLoaded", function () {
const cancelDownloadZip = document.getElementById("cancelDownloadZip");
if (cancelDownloadZip) {
cancelDownloadZip.addEventListener("click", function () {
document.getElementById("downloadZipModal").style.display = "none";
});
}
// This part remains in your confirmDownloadZip event handler:
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";
}
// Hide the ZIP name input modal
document.getElementById("downloadZipModal").style.display = "none";
// Show the progress modal here only on confirm
console.log("Download confirmed. Showing progress modal.");
document.getElementById("downloadProgressModal").style.display = "block";
const folder = window.currentFolder || "root";
fetch("/api/file/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();
// Hide the progress modal after download starts
document.getElementById("downloadProgressModal").style.display = "none";
showToast("Download started.");
})
.catch(error => {
// Hide the progress modal on error
document.getElementById("downloadProgressModal").style.display = "none";
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) {
const folderSelect = document.getElementById(dropdownId);
folderSelect.innerHTML = "";
if (window.userFolderOnly) {
const username = localStorage.getItem("username") || "root";
try {
const response = await fetch("/api/folder/getFolderList.php?restricted=1");
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.toLowerCase() !== "trash" &&
(folder === username || folder.indexOf(username + "/") === 0)
);
const rootOption = document.createElement("option");
rootOption.value = username;
rootOption.textContent = formatFolderName(username);
folderSelect.appendChild(rootOption);
folders.forEach(folder => {
if (folder !== username) {
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);
}
return;
}
try {
const response = await fetch("/api/folder/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" && folder.toLowerCase() !== "trash");
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 = folder;
folderSelect.appendChild(option);
});
}
} catch (error) {
console.error("Error loading folder list for modal:", error);
}
}
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 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("/api/file/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 = [];
});
});
}
});
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("/api/file/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 = [];
});
});
}
});
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";
setTimeout(() => {
const input = document.getElementById("newFileName");
input.focus();
const lastDot = oldName.lastIndexOf('.');
if (lastDot > 0) {
input.setSelectionRange(0, lastDot);
} else {
input.select();
}
}, 100);
}
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("/api/file/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 = "";
});
});
}
});
// Expose initFileActions so it can be called from fileManager.js
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);
}
const extractZipBtn = document.getElementById("extractZipBtn");
if (extractZipBtn) {
extractZipBtn.replaceWith(extractZipBtn.cloneNode(true));
document.getElementById("extractZipBtn").addEventListener("click", handleExtractZipSelected);
}
}
window.renameFile = renameFile;