/** * file-upload-queue.js * * Provides single-file previews for file inputs with the data-preview attribute * (couverture, note_intention, annexes, etc.). * * The multi-file TFE queue is rendered server-side via HTMX fragments * (upload-tfe-file.php / remove-tfe-file.php). * * Exposes window.XamxamInitFileUploads() so HTMX fragments can re-bind * after swap without a global event listener. */ window.XamxamInitFileUploads = function () { console.log("[file-upload-queue] XamxamInitFileUploads called"); var ICON = { pdf: "\uD83D\uDCC4", video: "\uD83C\uDFAC", audio: "\uD83D\uDD0A", zip: "\uD83D\uDDDC\uFE0F", vtt: "\uD83D\uDCAC", image: "\uD83D\uDDBC\uFE0F", other: "\uD83D\uDCCE", }; function iconFor(file) { var t = file.type || "", n = file.name.toLowerCase(); if (/^image\//.test(t)) return ICON.image; if (t === "application/pdf" || /\.pdf$/.test(n)) return ICON.pdf; if (/^video\//.test(t) || /\.(mp4|webm|mov|ogv)$/.test(n)) return ICON.video; if (/^audio\//.test(t) || /\.(mp3|ogg|oga|wav|flac|aac|m4a)$/.test(n)) return ICON.audio; if (/\.(zip|tar|gz|tgz)$/.test(n)) return ICON.zip; if (/\.vtt$/.test(n)) return ICON.vtt; return ICON.other; } function humanSize(b) { return b >= 1073741824 ? (b / 1073741824).toFixed(2) + " GB" : b >= 1048576 ? (b / 1048576).toFixed(2) + " MB" : b >= 1024 ? (b / 1024).toFixed(1) + " KB" : b + " B"; } function esc(s) { return s.replace(/[&<>"]/g, function (c) { return { "&": "&", "<": "<", ">": ">", '"': """ }[c]; }); } // ── Single-file previews (data-preview attribute) ──────────────────── document .querySelectorAll('input[type="file"][data-preview]') .forEach(function (input) { if (input.id === "tfe-files-input") return; console.log( "[file-upload-queue] binding preview for", input.id, "multiple=", input.multiple, ); var container = document.getElementById( input.getAttribute("data-preview"), ); if (!container) return; input.onchange = function () { container.innerHTML = ""; Array.from(input.files).forEach(function (file) { var item = document.createElement("div"); item.className = "fp-item"; if (/^image\//.test(file.type)) { var img = document.createElement("img"); img.className = "fp-thumb"; img.alt = file.name; var reader = new FileReader(); reader.onload = function (e) { img.src = e.target.result; }; reader.readAsDataURL(file); item.appendChild(img); } else { var ic = document.createElement("span"); ic.className = "fp-icon"; ic.textContent = iconFor(file); item.appendChild(ic); } var meta = document.createElement("span"); meta.className = "fp-meta"; meta.innerHTML = '' + esc(file.name) + '' + humanSize(file.size) + ""; item.appendChild(meta); container.appendChild(item); }); }; }); }; // Bootstrap on page load if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", window.XamxamInitFileUploads); else window.XamxamInitFileUploads();