/** * upload-progress.js * * Intercepts admin form submissions (add.php / edit.php) and submits via * XMLHttpRequest to display a progress bar for large file uploads. * Falls back to native form POST when JavaScript is unavailable. * * Requires an element with id="upload-progress-bar" inside the form. * The progress bar is normally hidden (display:none), shown only during upload. */ (() => { 'use strict'; const FORMS = document.querySelectorAll('form[data-upload-progress]'); if (!FORMS.length) return; for (const form of FORMS) { const progressWrap = form.querySelector('#upload-progress-wrap'); const progressBar = form.querySelector('#upload-progress-bar'); const progressText = form.querySelector('#upload-progress-text'); const submitBtn = form.querySelector('button[type="submit"]'); if (!progressBar || !progressWrap) continue; form.addEventListener('submit', function (e) { // Only intercept if files are actually attached (FilePond inputs have files) const fileInputs = form.querySelectorAll('input[type="file"]'); let hasFiles = false; for (const fi of fileInputs) { if (fi.files && fi.files.length > 0) { hasFiles = true; break; } } if (!hasFiles) return; // let native submit handle it e.preventDefault(); // Show progress bar progressWrap.style.display = 'block'; progressBar.value = 0; progressText.textContent = '0%'; if (submitBtn) submitBtn.disabled = true; // Build FormData const fd = new FormData(form); // Ensure any FilePond-managed files are included — FilePond with // storeAsFile:true copies files into the .files, so FormData // picks them up automatically from the DOM inputs. // But we must also respect queue_order hidden inputs. // FormData(form) already handles this since it reads all form fields. const xhr = new XMLHttpRequest(); xhr.upload.addEventListener('progress', function (evt) { if (evt.lengthComputable) { const pct = Math.round((evt.loaded / evt.total) * 100); progressBar.value = pct; progressText.textContent = pct + '%'; } }); xhr.addEventListener('load', function () { // Server returns a redirect (302) on success, or re-renders the form on error. // We can't follow 302 with XHR directly — the response body is the target page. // Check if we got a redirect by examining the response URL. const finalUrl = xhr.responseURL || ''; const isRedirect = xhr.status >= 200 && xhr.status < 300 && finalUrl !== '' && !finalUrl.endsWith(form.action); if (isRedirect) { // Success — navigate to the redirect target window.location.href = finalUrl; } else { // Error — the server returned the form HTML with flash messages. // Replace the current page content. document.open(); document.write(xhr.responseText); document.close(); } }); xhr.addEventListener('error', function () { progressText.textContent = 'Erreur réseau'; if (submitBtn) submitBtn.disabled = false; }); xhr.addEventListener('abort', function () { progressWrap.style.display = 'none'; if (submitBtn) submitBtn.disabled = false; }); xhr.open('POST', form.action, true); xhr.send(fd); }); } })();