mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-06-25 16:19:19 +02:00
170 lines
6.4 KiB
JavaScript
170 lines
6.4 KiB
JavaScript
/**
|
||
* upload-progress.js
|
||
*
|
||
* Intercepts admin form submissions with files and submits via XMLHttpRequest.
|
||
* Polls GET /admin/actions/upload-progress.php?token=xxx for server-side
|
||
* processing progress (PeerTube uploads, file moves).
|
||
*
|
||
* Progress display:
|
||
* 0%–25% : browser → server upload (XHR upload.progress)
|
||
* 25%–99% : server processing (polled from progress endpoint)
|
||
* 100% : response received — "Téléversé avec succès", then redirect
|
||
*/
|
||
(() => {
|
||
'use strict';
|
||
|
||
const FORMS = document.querySelectorAll('form[data-upload-progress]');
|
||
if (!FORMS.length) return;
|
||
|
||
const POLL_INTERVAL = 400;
|
||
const UPLOAD_CAP = 25;
|
||
const PROCESSING_MAX = 99;
|
||
const SUCCESS_DELAY = 800;
|
||
|
||
for (const form of FORMS) {
|
||
const progressWrap = form.querySelector('#upload-progress-wrap');
|
||
const progressBar = form.querySelector('#upload-progress-bar');
|
||
const progressLabel = form.querySelector('#upload-progress-label');
|
||
const progressFile = form.querySelector('#upload-progress-file');
|
||
const submitBtn = form.querySelector('button[type="submit"]');
|
||
const tokenInput = form.querySelector('input[name="progress_token"]');
|
||
|
||
if (!progressBar || !progressWrap) continue;
|
||
|
||
function collectFileNames() {
|
||
const names = [];
|
||
const inputs = form.querySelectorAll('input[type="file"]');
|
||
for (const fi of inputs) {
|
||
if (fi.files) {
|
||
for (const f of fi.files) {
|
||
if (f.name) names.push(f.name);
|
||
}
|
||
}
|
||
}
|
||
return names;
|
||
}
|
||
|
||
form.addEventListener('submit', function (e) {
|
||
const fileNames = collectFileNames();
|
||
if (!fileNames.length) return;
|
||
|
||
e.preventDefault();
|
||
|
||
const token = tokenInput ? tokenInput.value : '';
|
||
|
||
progressWrap.style.display = '';
|
||
progressBar.value = 0;
|
||
progressBar.removeAttribute('data-complete');
|
||
progressLabel.textContent = 'Téléversement en cours…';
|
||
progressFile.textContent = fileNames.length === 1
|
||
? fileNames[0]
|
||
: fileNames.length + ' fichiers';
|
||
if (submitBtn) submitBtn.disabled = true;
|
||
|
||
const fd = new FormData(form);
|
||
const xhr = new XMLHttpRequest();
|
||
|
||
let uploadDone = false;
|
||
let lastUploadPct = 0;
|
||
let pollingTimer = null;
|
||
|
||
/** Poll server-side progress */
|
||
function startPolling() {
|
||
if (pollingTimer || !token) return;
|
||
progressLabel.textContent = 'Traitement en cours…';
|
||
pollingTimer = setInterval(function () {
|
||
fetch('/admin/actions/upload-progress.php?token=' + encodeURIComponent(token))
|
||
.then(function (r) { return r.json(); })
|
||
.then(function (data) {
|
||
if (data && data.stage && data.stage !== 'upload') {
|
||
const pct = Math.min(PROCESSING_MAX, Math.max(UPLOAD_CAP, data.pct || UPLOAD_CAP));
|
||
progressBar.value = pct;
|
||
if (data.file) {
|
||
progressFile.textContent = data.file;
|
||
}
|
||
}
|
||
})
|
||
.catch(function () { /* ignore poll errors */ });
|
||
}, POLL_INTERVAL);
|
||
}
|
||
|
||
function stopPolling() {
|
||
if (pollingTimer) {
|
||
clearInterval(pollingTimer);
|
||
pollingTimer = null;
|
||
}
|
||
}
|
||
|
||
function finishSuccess() {
|
||
stopPolling();
|
||
progressBar.value = 100;
|
||
progressBar.setAttribute('data-complete', '');
|
||
progressLabel.textContent = 'Téléversé avec succès';
|
||
progressFile.textContent = '';
|
||
}
|
||
|
||
// ── Upload phase (0% → UPLOAD_CAP) ──
|
||
xhr.upload.addEventListener('progress', function (evt) {
|
||
if (evt.lengthComputable) {
|
||
const rawPct = Math.round((evt.loaded / evt.total) * 100);
|
||
const scaled = Math.round((rawPct / 100) * UPLOAD_CAP);
|
||
if (scaled > lastUploadPct) {
|
||
lastUploadPct = scaled;
|
||
progressBar.value = scaled;
|
||
}
|
||
}
|
||
});
|
||
|
||
xhr.upload.addEventListener('loadend', function () {
|
||
uploadDone = true;
|
||
progressBar.value = UPLOAD_CAP;
|
||
startPolling();
|
||
});
|
||
|
||
// ── Response handling ──
|
||
xhr.addEventListener('readystatechange', function () {
|
||
if (xhr.readyState !== XMLHttpRequest.DONE) return;
|
||
|
||
stopPolling();
|
||
|
||
if (xhr.status >= 200 && xhr.status < 300) {
|
||
finishSuccess();
|
||
|
||
setTimeout(function () {
|
||
const finalUrl = xhr.responseURL || '';
|
||
if (finalUrl && finalUrl !== form.action) {
|
||
window.location.href = finalUrl;
|
||
} else {
|
||
document.open();
|
||
document.write(xhr.responseText);
|
||
document.close();
|
||
}
|
||
}, SUCCESS_DELAY);
|
||
} else {
|
||
progressLabel.textContent = 'Erreur';
|
||
progressFile.textContent = 'Échec du téléversement';
|
||
document.open();
|
||
document.write(xhr.responseText);
|
||
document.close();
|
||
}
|
||
});
|
||
|
||
xhr.addEventListener('error', function () {
|
||
stopPolling();
|
||
progressLabel.textContent = 'Erreur réseau';
|
||
progressFile.textContent = '';
|
||
if (submitBtn) submitBtn.disabled = false;
|
||
});
|
||
|
||
xhr.addEventListener('abort', function () {
|
||
stopPolling();
|
||
progressWrap.style.display = 'none';
|
||
if (submitBtn) submitBtn.disabled = false;
|
||
});
|
||
|
||
xhr.open('POST', form.action, true);
|
||
xhr.send(fd);
|
||
});
|
||
}
|
||
})();
|