"use strict"; // DAO_master — Folder File Pro UI (v4.0) // - Folder icon from web/ico_dossier.png (non déformée) // - Grid/List, scroll fiable, double-clic, type-to-select, Explorer import { app } from "/scripts/app.js"; import { api } from "/scripts/api.js"; /* ---------- Lightbox (image/vidéo/audio) ---------- */ function ensureLightbox() { let el = document.getElementById("ffp-lightbox"); if (el) return; el = document.createElement("div"); el.id = "ffp-lightbox"; el.style.cssText = "position:fixed;inset:0;background:rgba(0,0,0,.85);display:none;align-items:center;justify-content:center;z-index:10000;"; el.innerHTML = '' + '' + '' + ''; document.body.appendChild(el); const close = () => { const i = el.querySelector("img"), v = el.querySelector("video"), a = el.querySelector("audio"); if (i) i.src = ""; if (v) { v.pause(); v.src = ""; } if (a) { a.pause(); a.src = ""; } el.style.display = "none"; }; el.querySelector(".ffp-close").onclick = close; el.addEventListener("click", (e) => { if (e.target === el) close(); }); } /* ---------- Icône dossier PNG depuis /web ---------- */ const FFP_FOLDER_URL = new URL("./ico_dossier.png", import.meta.url).href; /* ---------- Badge d'extension pour non-images ---------- */ function extBadge(ext) { if (!ext) ext = ".file"; if (ext[0] !== ".") ext = "." + ext; return '
Saisir un dossier puis Refresh.
' + (e.message || String(e)) + "
"; lastDir = String(wDir ? wDir.value : ""); lastView = viewSel.value; forceResetScroll = false; } finally { isLoading = false; grid.style.opacity = "1"; } } /* --------- Résolution index pour sortie --------- */ async function resolveAndSelect(targetPath) { if (!targetPath) return; try { const params = new URLSearchParams({ directory: String(wDir ? wDir.value : ""), exts: String(wExt ? wExt.value : ""), sort_by: String(wSort ? wSort.value : "name"), descending: String(!!(wDesc && wDesc.value)), regex: String(wRe ? wRe.value : ""), regex_mode: String(wReM ? wReM.value : "include"), regex_ic: String(!!(wReIC && wReIC.value)), path: String(targetPath), }).toString(); const res = await api.fetchApi( "/folder_file_pro/resolve_index?" + params ); const data = await res.json(); const idxW = this.widgets.find((w) => w.name === "index"); if (idxW && data.index >= 0) { idxW.value = data.index; this.setDirtyCanvas(true, true); } } catch (e) { console.warn("[FolderFilePro] resolve_index error", e); } } /* --------- Interactions --------- */ grid.addEventListener("click", (e) => { const card = e.target.closest(".ffp-card"); if (!card) return; selectCard.call(this, card, { scroll: false }); grid.focus(); }); grid.addEventListener("dblclick", (e) => { const card = e.target.closest(".ffp-card"); if (!card) return; const p = card.dataset.path; if (card.dataset.type === "dir") { if (wDir) { wDir.value = p; forceResetScroll = true; fetchList(); } return; } const isImg = /\.(png|jpg|jpeg|bmp|gif|webp|svg)$/i.test(p); const lb = document.getElementById("ffp-lightbox"); const i = lb.querySelector("img"), v = lb.querySelector("video"), a = lb.querySelector("audio"); i.style.display = v.style.display = a.style.display = "none"; v.pause(); a.pause(); if (isImg) { i.src = "/folder_file_pro/view?filepath=" + encodeURIComponent(p); i.style.display = "block"; lb.style.display = "flex"; } else { window.open( "/folder_file_pro/view?filepath=" + encodeURIComponent(p), "_blank" ); } }); // tape-pour-sélectionner function handleType(char) { if (!char) return; typeBuffer += char.toLowerCase(); if (typeTimer) clearTimeout(typeTimer); typeTimer = setTimeout(() => (typeBuffer = ""), TYPE_TIMEOUT); const list = cardsArray(); if (!list.length) return; let start = currentIndex.call(this) + 1; const N = list.length; for (let k = 0; k < N; k++) { const idx = (start + k) % N; const nm = getNameFromCard(list[idx]).toLowerCase(); if (nm.startsWith(typeBuffer)) { selectByIndex.call(this, idx); return; } } } grid.addEventListener("keydown", (e) => { const tag = (document.activeElement && document.activeElement.tagName) || ""; if (tag === "INPUT" || tag === "SELECT" || tag === "TEXTAREA") return; if (e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) { handleType.call(this, e.key); e.preventDefault(); return; } if (e.key === "Backspace") { typeBuffer = typeBuffer.slice(0, -1); e.preventDefault(); return; } if (e.key === "Escape") { typeBuffer = ""; return; } }); // relier widgets aux refresh function rewire(w) { if (!w) return; const prev = w.callback; w.callback = function () { if (prev) prev.apply(w, arguments); fetchList(); }; } [wDir, wExt, wRe, wReM, wReIC, wSort, wDesc].forEach(rewire); // barre d’actions upBtn.onclick = () => { if (parentDir && wDir) { wDir.value = parentDir; forceResetScroll = true; fetchList(); } }; goBtn.onclick = () => { if (wDir) { wDir.value = pathInput.value; forceResetScroll = true; fetchList(); } }; viewSel.onchange = () => { forceResetScroll = true; fetchList(); }; exploreBtn.onclick = async () => { const toOpen = (selectedPath || (wDir ? wDir.value : "") || "").toString(); if (!toOpen) return; try { await api.fetchApi("/folder_file_pro/open_explorer", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ path: toOpen }), }); } catch (e) { console.warn("open_explorer failed", e); } }; // init (async () => { try { const r = await api.fetchApi("/folder_file_pro/get_last_path"); const d = await r.json(); const last = d.last_path || (wDir ? wDir.value : ""); if (last) { if (wDir) wDir.value = last; pathInput.value = last; } lastDir = last || ""; lastView = viewSel.value; } catch (e) { /* ignore */ } forceResetScroll = true; fetchList(); })(); }; }, }); console.log("[DAO_master] Folder File Pro UI v4.0 loaded");