function createPageLoader(options = {}) {
const title = String(options.title || 'Chargement…');
const subtitle = String(options.subtitle || 'Préparation de la page…');
let progress = 0;
let removed = false;
const overlay = document.createElement('div');
overlay.className = 'page-loader-overlay';
overlay.setAttribute('role', 'status');
overlay.setAttribute('aria-live', 'polite');
overlay.setAttribute('aria-busy', 'true');
overlay.innerHTML = `
${title}
${subtitle}
`;
const barEl = () => overlay.querySelector('#page-loader-bar');
const subtitleEl = () => overlay.querySelector('#page-loader-subtitle');
const actionsEl = () => overlay.querySelector('#page-loader-actions');
const retryBtnEl = () => overlay.querySelector('#page-loader-retry');
function clampPct(p) {
const n = Number(p);
if (!Number.isFinite(n)) return 0;
return Math.max(0, Math.min(100, n));
}
function setProgress(p) {
progress = clampPct(p);
const bar = barEl();
if (bar) bar.style.width = `${progress}%`;
}
function setSubtitle(text) {
const el = subtitleEl();
if (el) el.textContent = String(text || '');
}
function ensureMounted() {
if (removed) return;
if (!overlay.isConnected) {
document.body.classList.add('page-loading');
document.body.appendChild(overlay);
}
}
function hideAndRemoveSoon() {
if (removed) return;
overlay.classList.add('page-loader-hide');
overlay.setAttribute('aria-busy', 'false');
document.body.classList.remove('page-loading');
window.setTimeout(() => {
removed = true;
try { overlay.remove(); } catch (_) {}
}, 220);
}
function done() {
setProgress(100);
hideAndRemoveSoon();
}
function fail(message) {
setSubtitle(message || 'Erreur lors du chargement.');
setProgress(Math.max(progress, 90));
const actions = actionsEl();
if (actions) actions.classList.remove('d-none');
const btn = retryBtnEl();
if (btn) btn.onclick = () => window.location.reload();
}
ensureMounted();
setProgress(8);
return { setProgress, setSubtitle, done, fail };
}
window.onload = async function () {
const pageLoader = createPageLoader({
title: 'Chargement de la checklist',
subtitle: 'Récupération des données…'
});
const token = localStorage.getItem('auth_token');
const movieTableBody = document.getElementById('movie-table-body');
const watchedRatioEl = document.getElementById('watched-ratio');
function showTableError(message) {
if (!movieTableBody) return;
movieTableBody.innerHTML = `
|
${message || 'Erreur lors du chargement.'}
|
`;
}
const DEFAULT_COMPLETION_MODAL = Object.freeze({
title: 'Félicitations! very nice 🎉🎉🎉',
bodyText: '',
videoSrc: 'video/reward.mp4',
bodyHtml: ''
});
function sanitizeHtml(raw) {
const html = String(raw || '');
const withoutScripts = html.replace(/