fix : bouton desactivé pendant le téléchargement + plus de abort
This commit is contained in:
parent
5de492b308
commit
0a536140ab
|
|
@ -230,3 +230,11 @@ td.nc-value {
|
|||
|
||||
#historiqueParcours tr.shown > td { background: #fffdf5; }
|
||||
.parcours-details { font-size: 0.95rem; }
|
||||
|
||||
|
||||
/* Style pour les boutons d'export désactivés */
|
||||
#divBtnFilter button:disabled {
|
||||
opacity: 0.5 !important;
|
||||
cursor: not-allowed !important;
|
||||
pointer-events: none !important;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,30 @@ document.addEventListener("DOMContentLoaded", async function () {
|
|||
// Initialiser DataTables en mode server-side (obligé pour pagination)
|
||||
const table = initServerSideDataTable();
|
||||
|
||||
// Variable pour suivre l'état des exports
|
||||
let isExporting = false;
|
||||
|
||||
// Fonction pour désactiver/activer les boutons d'export
|
||||
function setExportButtonsState(disabled) {
|
||||
isExporting = disabled;
|
||||
const buttons = ["#exportCSV", "#exportCSVFilter", "#exportXlxs", "#exportXlxsFilter"];
|
||||
buttons.forEach(selector => {
|
||||
const $btn = $(selector);
|
||||
$btn.prop("disabled", disabled);
|
||||
if (disabled) {
|
||||
$btn.css("opacity", "0.5");
|
||||
$btn.css("cursor", "not-allowed");
|
||||
} else {
|
||||
$btn.css("opacity", "1");
|
||||
$btn.css("cursor", "pointer");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Exports CSV/XLSX
|
||||
$("#exportCSV").on("click", function () {
|
||||
if (isExporting) return;
|
||||
|
||||
const dt = $("#historiqueParcours").DataTable();
|
||||
if (!dt) {
|
||||
displayError("Impossible d'accéder à la table de données.");
|
||||
|
|
@ -32,6 +54,8 @@ document.addEventListener("DOMContentLoaded", async function () {
|
|||
return;
|
||||
}
|
||||
|
||||
setExportButtonsState(true);
|
||||
|
||||
const payload = {
|
||||
mode: "full", // export total
|
||||
search: { value: "" },
|
||||
|
|
@ -62,12 +86,18 @@ document.addEventListener("DOMContentLoaded", async function () {
|
|||
a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
a.remove();
|
||||
setExportButtonsState(false);
|
||||
})
|
||||
.catch(() => displayError("Export CSV (complet) impossible"));
|
||||
.catch((err) => {
|
||||
displayError("Export CSV (complet) impossible");
|
||||
setExportButtonsState(false);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$("#exportCSVFilter").on("click", function () {
|
||||
if (isExporting) return;
|
||||
|
||||
const dt = $("#historiqueParcours").DataTable();
|
||||
if (!dt) {
|
||||
displayError("Impossible d'accéder à la table de données.");
|
||||
|
|
@ -80,6 +110,8 @@ document.addEventListener("DOMContentLoaded", async function () {
|
|||
return;
|
||||
}
|
||||
|
||||
setExportButtonsState(true);
|
||||
|
||||
const payload = {
|
||||
mode: "filtered", // export avec les filtres/colonnes/tri actuels
|
||||
search: { value: dt.search() || "" }, // recherche globale
|
||||
|
|
@ -108,12 +140,18 @@ document.addEventListener("DOMContentLoaded", async function () {
|
|||
a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
a.remove();
|
||||
setExportButtonsState(false);
|
||||
})
|
||||
.catch(() => displayError("Export CSV (filtré) impossible"));
|
||||
.catch((err) => {
|
||||
displayError("Export CSV (filtré) impossible");
|
||||
setExportButtonsState(false);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$("#exportXlxs").on("click", function () {
|
||||
if (isExporting) return;
|
||||
|
||||
const dt = $("#historiqueParcours").DataTable();
|
||||
if (!dt) {
|
||||
displayError("Impossible d'accéder à la table de données.");
|
||||
|
|
@ -126,6 +164,8 @@ document.addEventListener("DOMContentLoaded", async function () {
|
|||
return;
|
||||
}
|
||||
|
||||
setExportButtonsState(true);
|
||||
|
||||
const payload = {
|
||||
mode: "full",
|
||||
search: { value: "" },
|
||||
|
|
@ -145,12 +185,18 @@ document.addEventListener("DOMContentLoaded", async function () {
|
|||
a.href = url; a.download = "historique_parcours_complet.xls";
|
||||
document.body.appendChild(a); a.click();
|
||||
URL.revokeObjectURL(url); a.remove();
|
||||
setExportButtonsState(false);
|
||||
})
|
||||
.catch(() => displayError("Export XLS (complet) impossible"));
|
||||
.catch((err) => {
|
||||
displayError("Export XLS (complet) impossible");
|
||||
setExportButtonsState(false);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$("#exportXlxsFilter").on("click", function () {
|
||||
if (isExporting) return;
|
||||
|
||||
const dt = $("#historiqueParcours").DataTable();
|
||||
if (!dt) {
|
||||
displayError("Impossible d'accéder à la table de données.");
|
||||
|
|
@ -163,6 +209,8 @@ document.addEventListener("DOMContentLoaded", async function () {
|
|||
return;
|
||||
}
|
||||
|
||||
setExportButtonsState(true);
|
||||
|
||||
const payload = {
|
||||
mode: "filtered", // export avec les filtres/colonnes/tri actuels
|
||||
search: { value: dt.search() || "" }, // recherche globale
|
||||
|
|
@ -191,8 +239,12 @@ document.addEventListener("DOMContentLoaded", async function () {
|
|||
a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
a.remove();
|
||||
setExportButtonsState(false);
|
||||
})
|
||||
.catch(() => displayError("Export XLS (filtré) impossible"));
|
||||
.catch((err) => {
|
||||
displayError("Export XLS (filtré) impossible");
|
||||
setExportButtonsState(false);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
|
@ -243,21 +295,29 @@ function initServerSideDataTable() {
|
|||
search: data.search || { value: "" },
|
||||
};
|
||||
|
||||
|
||||
if (inflightController) inflightController.abort(); // action en cours
|
||||
inflightController = new AbortController();
|
||||
const currentController = inflightController;
|
||||
|
||||
fetch("/historiqueParcours/datatable", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(body),
|
||||
signal: inflightController.signal,
|
||||
signal: currentController.signal,
|
||||
})
|
||||
.then(res => {
|
||||
// Vérifier si la requête a été annulée
|
||||
if (currentController.signal.aborted || inflightController !== currentController) {
|
||||
return null;
|
||||
}
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||
return res.json();
|
||||
})
|
||||
.then(payload => {
|
||||
// Vérifier si la requête a été annulée
|
||||
if (currentController.signal.aborted || inflightController !== currentController) {
|
||||
return;
|
||||
}
|
||||
if (!payload || typeof payload !== 'object') {
|
||||
throw new Error("Réponse invalide du serveur");
|
||||
}
|
||||
|
|
@ -269,7 +329,15 @@ function initServerSideDataTable() {
|
|||
});
|
||||
})
|
||||
.catch(err => {
|
||||
if (err && err.name === "AbortError") return;
|
||||
// Ignorer silencieusement toutes les erreurs d'abort
|
||||
if (err && (err.name === "AbortError" || err.name === "DOMException")) {
|
||||
return;
|
||||
}
|
||||
// Vérifier aussi si le signal a été aborted
|
||||
if (currentController.signal.aborted || inflightController !== currentController) {
|
||||
return;
|
||||
}
|
||||
// Seulement afficher une erreur si ce n'est PAS un abort
|
||||
displayError("Failed to fetch data. Please try again later.");
|
||||
callback({ draw: 0, recordsTotal: 0, recordsFiltered: 0, data: [] });
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue