Crvi/assets/js/extra/agenda-loading-feedback.js
2026-01-20 07:54:37 +01:00

231 lines
7.1 KiB
JavaScript

/* Feedback de chargement pour FullCalendar et spinner sur le bouton Enregistrer du modal */
(function () {
function setDisabled(containerSelector, disabled) {
try {
var container = document.querySelector(containerSelector);
if (!container) return;
var els = container.querySelectorAll('button, input, select, textarea');
els.forEach(function (el) {
el.disabled = !!disabled;
});
} catch (e) {}
}
function showIndicator(id, show) {
try {
var el = document.getElementById(id);
if (el) {
el.style.display = show ? 'block' : 'none';
}
} catch (e) {}
}
function attachLoading(calendar, indicatorId, filtersSelector) {
try {
if (!calendar || typeof calendar.setOption !== 'function') return;
calendar.setOption('loading', function (isLoading) {
showIndicator(indicatorId, isLoading);
// Ne pas désactiver les filtres pendant le chargement, uniquement overlay sur le calendrier
try {
var calEl = document.getElementById('agenda-calendar') || (calendar.el || null);
if (calEl && window.CRVI_OVERLAY) {
if (isLoading) {
window.CRVI_OVERLAY.show(calEl);
} else {
window.CRVI_OVERLAY.hide(calEl);
}
}
} catch (e) {}
});
} catch (e) {}
}
// Gestionnaire de chargement global, pour couvrir les appels AJAX génériques (création, update, delete, etc.)
// Usage: window.CRVI_LOADING.start(); ... finally window.CRVI_LOADING.end();
(function initGlobalLoading() {
var counter = 0;
var defaultIndicatorId = 'loading-indicator';
// Ne pas désactiver automatiquement les zones de filtres
var defaultDisableSelectors = [];
function updateUi() {
var isLoading = counter > 0;
try {
showIndicator(defaultIndicatorId, isLoading);
// Désactiver quelques containers communs si présents
defaultDisableSelectors.forEach(function (sel) {
setDisabled(sel, isLoading);
});
} catch (e) {}
}
if (!window.CRVI_LOADING) {
window.CRVI_LOADING = {
start: function () {
counter++;
updateUi();
},
end: function () {
if (counter > 0) counter--;
updateUi();
},
// Permet d'ajuster la cible si besoin ailleurs
configure: function (opts) {
if (opts && typeof opts.indicatorId === 'string') {
defaultIndicatorId = opts.indicatorId;
}
if (opts && Array.isArray(opts.disableSelectors)) {
defaultDisableSelectors = opts.disableSelectors.slice();
}
updateUi();
},
// Pour diagnostics
_getCount: function () {
return counter;
}
};
}
})();
// Overlay ciblé par élément: window.CRVI_OVERLAY.show(elementOrSelector), .hide(...)
(function initElementOverlay() {
function getTarget(elOrSelector) {
if (!elOrSelector) return null;
if (typeof elOrSelector === 'string') return document.querySelector(elOrSelector);
return elOrSelector.nodeType === 1 ? elOrSelector : null;
}
function ensurePositioned(target) {
var style = window.getComputedStyle(target);
if (style.position === 'static' || !style.position) {
target.style.position = 'relative';
}
}
function createOverlay(target) {
var overlay = document.createElement('div');
overlay.className = 'crvi-overlay';
overlay.style.position = 'absolute';
overlay.style.top = '0';
overlay.style.left = '0';
overlay.style.right = '0';
overlay.style.bottom = '0';
overlay.style.background = 'rgba(255,255,255,0.6)';
overlay.style.display = 'flex';
overlay.style.alignItems = 'center';
overlay.style.justifyContent = 'center';
overlay.style.zIndex = '20';
var spinner = document.createElement('div');
spinner.className = 'spinner-border text-primary';
spinner.setAttribute('role', 'status');
spinner.setAttribute('aria-hidden', 'true');
overlay.appendChild(spinner);
return overlay;
}
function getCount(target) {
var c = parseInt(target.getAttribute('data-overlay-count') || '0', 10);
return isNaN(c) ? 0 : c;
}
function setCount(target, c) {
target.setAttribute('data-overlay-count', String(c));
}
function show(elOrSelector) {
var target = getTarget(elOrSelector);
if (!target) return;
ensurePositioned(target);
var count = getCount(target);
setCount(target, count + 1);
if (count > 0 && target.querySelector(':scope > .crvi-overlay')) {
return;
}
var overlay = createOverlay(target);
target.appendChild(overlay);
}
function hide(elOrSelector) {
var target = getTarget(elOrSelector);
if (!target) return;
var count = getCount(target);
count = Math.max(0, count - 1);
setCount(target, count);
if (count === 0) {
var overlay = target.querySelector(':scope > .crvi-overlay');
if (overlay) {
overlay.remove();
}
}
}
if (!window.CRVI_OVERLAY) {
window.CRVI_OVERLAY = { show: show, hide: hide };
}
})();
function tryAttach() {
if (window.currentCalendar) {
attachLoading(window.currentCalendar, 'loading-indicator', '.filters');
}
if (window.currentColleaguesCalendar) {
attachLoading(
window.currentColleaguesCalendar,
'loading-indicator-colleagues',
'.filters-colleagues'
);
}
}
document.addEventListener('DOMContentLoaded', function () {
// Essayer d'attacher au démarrage puis quelques tentatives (calendriers init asynchrones)
tryAttach();
var iv = setInterval(tryAttach, 500);
setTimeout(function () {
clearInterval(iv);
}, 10000);
// Spinner + désactivation sur le bouton Enregistrer du modal
document.addEventListener(
'click',
function (e) {
var btn = e.target && (e.target.closest ? e.target.closest('#saveEvent') : null);
if (!btn) return;
if (btn.dataset.loading === '1') return;
btn.dataset.loading = '1';
btn.disabled = true;
if (!btn.dataset.originalHtml) {
btn.dataset.originalHtml = btn.innerHTML;
}
btn.innerHTML =
'<span class="spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span>Enregistrer';
var onDone = function () {
btn.disabled = false;
btn.dataset.loading = '0';
if (btn.dataset.originalHtml) {
btn.innerHTML = btn.dataset.originalHtml;
}
};
// Réactiver à la fermeture du modal ou après un timeout de secours
var modal = document.getElementById('eventModal');
if (modal) {
var handler = function () {
modal.removeEventListener('hidden.bs.modal', handler);
onDone();
};
modal.addEventListener('hidden.bs.modal', handler);
}
setTimeout(onDone, 8000);
},
true
);
});
})();