192 lines
5.7 KiB
JavaScript
192 lines
5.7 KiB
JavaScript
|
|
(function () {
|
||
|
|
const fileBrowser = document.querySelector("[data-file-browser]");
|
||
|
|
const viewButtons = document.querySelectorAll("[data-view-button]");
|
||
|
|
const previewImages = document.querySelector("[data-preview-images]");
|
||
|
|
const previewActions = document.querySelectorAll("[data-preview-action]");
|
||
|
|
const fileContextMenu = document.querySelector("[data-file-context-menu]");
|
||
|
|
|
||
|
|
let ctrlCopyMode = false;
|
||
|
|
let contextFile = null;
|
||
|
|
const contextMenuCloseDistance = 80;
|
||
|
|
|
||
|
|
if (fileBrowser) {
|
||
|
|
viewButtons.forEach((button) => {
|
||
|
|
button.addEventListener("click", () => {
|
||
|
|
const view = button.getAttribute("data-view-button");
|
||
|
|
fileBrowser.classList.toggle("is-list", view === "list");
|
||
|
|
fileBrowser.classList.toggle("is-thumbs", view === "thumbs");
|
||
|
|
viewButtons.forEach((item) => item.classList.toggle("is-active", item === button));
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
if (previewImages) {
|
||
|
|
previewImages.addEventListener("click", () => {
|
||
|
|
fileBrowser.classList.toggle("images-only");
|
||
|
|
previewImages.classList.toggle("is-active");
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (fileBrowser && fileContextMenu) {
|
||
|
|
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(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(file.previewURL);
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
if (action === "copy-download") {
|
||
|
|
await window.Warpbox.writeClipboard(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;
|
||
|
|
}
|
||
|
|
})();
|