Folder sharing added

This commit is contained in:
Ryan
2025-04-09 01:46:07 -04:00
committed by GitHub
parent b9ce3f92a4
commit b2ff3efb3b
13 changed files with 993 additions and 91 deletions

View File

@@ -2,7 +2,7 @@ import { showToast, toggleVisibility, attachEnterKeyListener } from './domUtils.
import { sendRequest } from './networkUtils.js';
import { t, applyTranslations, setLocale } from './i18n.js';
const version = "v1.0.9";
const version = "v1.1.0";
const adminTitle = `Admin Panel <small style="font-size: 12px; color: gray;">${version}</small>`;
let lastLoginData = null;

View File

@@ -3,6 +3,7 @@
import { loadFileList } from './fileListView.js';
import { showToast, escapeHTML, attachEnterKeyListener } from './domUtils.js';
import { t } from './i18n.js';
import { openFolderShareModal } from './folderShareModal.js';
/* ----------------------
Helper Functions (Data/State)
@@ -418,7 +419,7 @@ export async function loadFolderTree(selectedFolder) {
localStorage.setItem("lastOpenedFolder", window.currentFolder);
const titleEl = document.getElementById("fileListTitle");
titleEl.innerHTML = "Files in (" + renderBreadcrumb(window.currentFolder) + ")";
titleEl.innerHTML = t("files_in") + " (" + renderBreadcrumb(window.currentFolder) + ")";
setupBreadcrumbDelegation();
loadFileList(window.currentFolder);
@@ -442,7 +443,7 @@ export async function loadFolderTree(selectedFolder) {
window.currentFolder = selected;
localStorage.setItem("lastOpenedFolder", selected);
const titleEl = document.getElementById("fileListTitle");
titleEl.innerHTML = "Files in (" + renderBreadcrumb(selected) + ")";
titleEl.innerHTML = t("files_in") + " (" + renderBreadcrumb(selected) + ")";
setupBreadcrumbDelegation();
loadFileList(selected);
});
@@ -735,18 +736,22 @@ function folderManagerContextMenuHandler(e) {
target.classList.add("selected");
const menuItems = [
{
label: "Create Folder",
label: t("create_folder"),
action: () => {
document.getElementById("createFolderModal").style.display = "block";
document.getElementById("newFolderName").focus();
}
},
{
label: "Rename Folder",
label: t("rename_folder"),
action: () => { openRenameFolderModal(); }
},
{
label: "Delete Folder",
label: t("folder_share"),
action: () => { openFolderShareModal(); }
},
{
label: t("delete_folder"),
action: () => { openDeleteFolderModal(); }
}
];
@@ -785,4 +790,21 @@ document.addEventListener("DOMContentLoaded", function () {
});
});
document.addEventListener("DOMContentLoaded", function () {
const shareFolderBtn = document.getElementById("shareFolderBtn");
if (shareFolderBtn) {
shareFolderBtn.addEventListener("click", () => {
const selectedFolder = window.currentFolder || "root";
if (!selectedFolder || selectedFolder === "root") {
showToast("Please select a valid folder to share.");
return;
}
// Call the folder share modal from the module.
openFolderShareModal(selectedFolder);
});
} else {
console.warn("shareFolderBtn element not found in the DOM.");
}
});
bindFolderManagerContextMenu();

107
js/folderShareModal.js Normal file
View File

@@ -0,0 +1,107 @@
// folderShareModal.js
import { escapeHTML, showToast } from './domUtils.js';
import { t } from './i18n.js';
export function openFolderShareModal(folder) {
// Remove any existing folder share modal
const existing = document.getElementById("folderShareModal");
if (existing) existing.remove();
// Create the modal container
const modal = document.createElement("div");
modal.id = "folderShareModal";
modal.classList.add("modal");
modal.innerHTML = `
<div class="modal-content share-modal-content" style="width: 600px; max-width: 90vw;">
<div class="modal-header">
<h3>${t("share_folder")}: ${escapeHTML(folder)}</h3>
<span class="close-image-modal" id="closeFolderShareModal" title="Close">&times;</span>
</div>
<div class="modal-body">
<p>${t("set_expiration")}</p>
<select id="folderShareExpiration">
<option value="30">30 ${t("minutes")}</option>
<option value="60" selected>60 ${t("minutes")}</option>
<option value="120">120 ${t("minutes")}</option>
<option value="180">180 ${t("minutes")}</option>
<option value="240">240 ${t("minutes")}</option>
<option value="1440">1 ${t("day")}</option>
</select>
<p>${t("password_optional")}</p>
<input type="text" id="folderSharePassword" placeholder="${t("password")}" style="width: 100%;"/>
<br>
<label>
<input type="checkbox" id="folderShareAllowUpload"> ${t("allow_uploads")}
</label>
<br><br>
<button id="generateFolderShareLinkBtn" class="btn btn-primary" style="margin-top: 10px;">${t("generate_share_link")}</button>
<div id="folderShareLinkDisplay" style="margin-top: 10px; display: none;">
<p>${t("shareable_link")}</p>
<input type="text" id="folderShareLinkInput" readonly style="width: 100%;"/>
<button id="copyFolderShareLinkBtn" class="btn btn-primary" style="margin-top: 5px;">${t("copy_link")}</button>
</div>
</div>
</div>
`;
document.body.appendChild(modal);
modal.style.display = "block";
// Close button handler
document.getElementById("closeFolderShareModal").addEventListener("click", () => {
modal.remove();
});
// Handler for generating the share link
document.getElementById("generateFolderShareLinkBtn").addEventListener("click", () => {
const expiration = document.getElementById("folderShareExpiration").value;
const password = document.getElementById("folderSharePassword").value;
const allowUpload = document.getElementById("folderShareAllowUpload").checked ? 1 : 0;
// Retrieve the CSRF token from the meta tag.
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute("content");
if (!csrfToken) {
showToast(t("csrf_error"));
return;
}
// Post to the createFolderShareLink endpoint.
fetch("/createFolderShareLink.php", {
method: "POST",
credentials: "include",
headers: {
"Content-Type": "application/json",
"X-CSRF-Token": csrfToken
},
body: JSON.stringify({
folder: folder,
expirationMinutes: parseInt(expiration, 10),
password: password,
allowUpload: allowUpload
})
})
.then(response => response.json())
.then(data => {
if (data.token && data.link) {
const shareUrl = data.link;
const displayDiv = document.getElementById("folderShareLinkDisplay");
const inputField = document.getElementById("folderShareLinkInput");
inputField.value = shareUrl;
displayDiv.style.display = "block";
showToast(t("share_link_generated"));
} else {
showToast(t("error_generating_share_link") + ": " + (data.error || t("unknown_error")));
}
})
.catch(err => {
console.error("Error generating folder share link:", err);
showToast(t("error_generating_share_link") + ": " + (err.error || t("unknown_error")));
});
});
// Copy share link button handler
document.getElementById("copyFolderShareLinkBtn").addEventListener("click", () => {
const input = document.getElementById("folderShareLinkInput");
input.select();
document.execCommand("copy");
showToast(t("link_copied"));
});
}

View File

@@ -84,6 +84,7 @@ const translations = {
// File List keys:
"file_list_title": "Files in (Root)",
"files_in": "Files in",
"delete_files": "Delete Files",
"delete_selected_files_title": "Delete Selected Files",
"delete_files_message": "Are you sure you want to delete the selected files?",
@@ -126,6 +127,18 @@ const translations = {
// Rename File keys:
"rename_file_title": "Rename File",
"rename_file_placeholder": "Enter new file name",
// Folder Share
"share_folder": "Share Folder",
"allow_uploads": "Allow Uploads",
"share_link_generated": "Share Link Generated",
"error_generating_share_link": "Error Generating Share Link",
// Folder
"create_folder": "Create Folder",
"rename_folder": "Rename Folder",
"folder_share": "Share Folder",
"delete_folder": "Delete Folder",
// Custom Confirm Modal keys:
"yes": "Yes",
@@ -136,7 +149,14 @@ const translations = {
"copy": "Copy",
"extract": "Extract",
"user": "User:",
"password": "Password:",
"unknown_error": "Unknown Error",
"link_copied": "Link Copied to Clipboard",
"minutes": "minutes",
"hours": "hours",
"days": "days",
"weeks": "weeks",
"months": "months",
"seconds": "seconds",
// Dark Mode Toggle
"dark_mode_toggle": "Dark Mode",

View File

@@ -48,9 +48,6 @@ function getFilesFromDataTransferItems(items) {
return Promise.all(promises).then(results => results.flat());
}
/* -----------------------------------------------------
UI Helpers (Mostly unchanged from your original code)
----------------------------------------------------- */
function setDropAreaDefault() {
const dropArea = document.getElementById("uploadDropArea");
if (dropArea) {