Files
warpbox-dev/backend/static/js/10-file-browser.js

245 lines
7.4 KiB
JavaScript
Raw Normal View History

(function () {
const fileBrowser = document.querySelector("[data-file-browser]");
const viewButtons = document.querySelectorAll("[data-view-button]");
const previewActions = document.querySelectorAll("[data-preview-action]");
const fileContextMenu = document.querySelector("[data-file-context-menu]");
const fileBrowserWindow = document.querySelector("[data-file-browser-window]");
let ctrlCopyMode = false;
let contextFile = null;
const contextMenuCloseDistance = 80;
const viewStorageKey = "warpbox.fileBrowser.view";
if (fileBrowser) {
applySavedFileBrowserPreferences();
viewButtons.forEach((button) => {
button.addEventListener("click", () => {
const view = button.getAttribute("data-view-button");
setFileBrowserView(view);
savePreference(viewStorageKey, view);
});
});
}
if (fileBrowser && fileContextMenu) {
document.body.appendChild(fileContextMenu);
fileBrowser.addEventListener("click", (event) => {
if (!fileBrowser.classList.contains("is-list")) {
return;
}
if (event.target.closest("a, button, input, select, textarea")) {
return;
}
const card = event.target.closest("[data-file-context]");
const link = card ? card.querySelector(".file-open") : null;
if (!link) {
return;
}
event.preventDefault();
if (link.target === "_blank") {
window.Warpbox.openInNewTab(link.href);
return;
}
window.location.href = link.href;
});
fileBrowser.addEventListener("contextmenu", (event) => {
const card = event.target.closest("[data-file-context]");
if (!card) {
return;
}
event.preventDefault();
contextFile = {
previewURL: card.dataset.previewUrl,
viewURL: card.dataset.viewUrl,
downloadURL: card.dataset.downloadUrl,
fileName: card.dataset.fileName,
};
showContextMenu(event.clientX, event.clientY);
});
fileContextMenu.addEventListener("click", async (event) => {
const button = event.target.closest("[data-context-action]");
if (!button || !contextFile) {
return;
}
const shouldHide = await runContextAction(button.dataset.contextAction, contextFile);
if (shouldHide !== false) {
hideContextMenu();
}
});
document.addEventListener("click", (event) => {
if (!fileContextMenu.contains(event.target)) {
hideContextMenu();
}
});
document.addEventListener("keydown", (event) => {
if (event.key === "Escape") {
hideContextMenu();
}
});
document.addEventListener("mousemove", (event) => {
if (fileContextMenu.hidden || isPointerNearContextMenu(event.clientX, event.clientY)) {
return;
}
hideContextMenu();
});
window.addEventListener("resize", hideContextMenu);
window.addEventListener("scroll", hideContextMenu, true);
}
if (previewActions.length > 0) {
previewActions.forEach((button) => {
button.addEventListener("click", async (event) => {
if (!event.ctrlKey && !ctrlCopyMode) {
return;
}
event.preventDefault();
await copyPreviewLink(button);
});
});
window.addEventListener("keydown", (event) => {
if (event.key === "Control") {
setPreviewCopyMode(true);
}
});
window.addEventListener("keyup", (event) => {
if (event.key === "Control") {
setPreviewCopyMode(false);
}
});
window.addEventListener("blur", () => setPreviewCopyMode(false));
}
async function copyPreviewLink(button) {
await window.Warpbox.writeClipboard(window.Warpbox.absoluteURL(button.href));
const label = button.querySelector("[data-preview-label]");
if (!label) {
return;
}
label.textContent = "Copied";
setTimeout(() => {
label.textContent = ctrlCopyMode ? button.dataset.copyLabel || "Copy link" : button.dataset.viewLabel || "View";
}, 1200);
}
function setPreviewCopyMode(enabled) {
ctrlCopyMode = enabled;
previewActions.forEach((button) => {
const label = button.querySelector("[data-preview-label]");
const viewIcon = button.querySelector("[data-preview-view-icon]");
const copyIcon = button.querySelector("[data-preview-copy-icon]");
if (label) {
label.textContent = enabled ? button.dataset.copyLabel || "Copy link" : button.dataset.viewLabel || "View";
}
if (viewIcon) {
viewIcon.hidden = enabled;
}
if (copyIcon) {
copyIcon.hidden = !enabled;
}
});
}
async function runContextAction(action, file) {
if (action === "preview") {
window.Warpbox.openInNewTab(file.previewURL);
return true;
}
if (action === "view") {
window.Warpbox.openInNewTab(file.viewURL);
return true;
}
if (action === "copy-preview") {
await window.Warpbox.writeClipboard(window.Warpbox.absoluteURL(file.previewURL));
return true;
}
if (action === "copy-download") {
await window.Warpbox.writeClipboard(window.Warpbox.absoluteURL(file.downloadURL));
return true;
}
if (action === "download") {
window.Warpbox.openInNewTab(file.downloadURL);
}
return true;
}
function showContextMenu(x, y) {
fileContextMenu.hidden = false;
fileContextMenu.style.left = "0px";
fileContextMenu.style.top = "0px";
const rect = fileContextMenu.getBoundingClientRect();
const margin = 8;
const left = Math.min(x, window.innerWidth - rect.width - margin);
const top = Math.min(y, window.innerHeight - rect.height - margin);
fileContextMenu.style.left = `${Math.max(margin, left)}px`;
fileContextMenu.style.top = `${Math.max(margin, top)}px`;
}
function hideContextMenu() {
if (!fileContextMenu || fileContextMenu.hidden) {
return;
}
fileContextMenu.hidden = true;
contextFile = null;
}
function isPointerNearContextMenu(x, y) {
const rect = fileContextMenu.getBoundingClientRect();
return x >= rect.left - contextMenuCloseDistance &&
x <= rect.right + contextMenuCloseDistance &&
y >= rect.top - contextMenuCloseDistance &&
y <= rect.bottom + contextMenuCloseDistance;
}
function applySavedFileBrowserPreferences() {
const savedView = readPreference(viewStorageKey);
setFileBrowserView(savedView === "list" ? "list" : "thumbs");
}
function setFileBrowserView(view) {
const normalized = view === "thumbs" ? "thumbs" : "list";
fileBrowser.classList.toggle("is-list", normalized === "list");
fileBrowser.classList.toggle("is-thumbs", normalized === "thumbs");
if (fileBrowserWindow) {
fileBrowserWindow.classList.toggle("is-list-view", normalized === "list");
fileBrowserWindow.classList.toggle("is-icon-view", normalized === "thumbs");
}
viewButtons.forEach((item) => {
const active = item.getAttribute("data-view-button") === normalized;
item.classList.toggle("is-active", active);
item.setAttribute("aria-pressed", active ? "true" : "false");
});
}
function readPreference(key) {
try {
return window.localStorage.getItem(key);
} catch (_) {
return "";
}
}
function savePreference(key, value) {
try {
window.localStorage.setItem(key, value);
} catch (_) {
// LocalStorage can be unavailable in private or locked-down browsers.
}
}
})();