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; }
|
#historiqueParcours tr.shown > td { background: #fffdf5; }
|
||||||
.parcours-details { font-size: 0.95rem; }
|
.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)
|
// Initialiser DataTables en mode server-side (obligé pour pagination)
|
||||||
const table = initServerSideDataTable();
|
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
|
// Exports CSV/XLSX
|
||||||
$("#exportCSV").on("click", function () {
|
$("#exportCSV").on("click", function () {
|
||||||
|
if (isExporting) return;
|
||||||
|
|
||||||
const dt = $("#historiqueParcours").DataTable();
|
const dt = $("#historiqueParcours").DataTable();
|
||||||
if (!dt) {
|
if (!dt) {
|
||||||
displayError("Impossible d'accéder à la table de données.");
|
displayError("Impossible d'accéder à la table de données.");
|
||||||
|
|
@ -32,6 +54,8 @@ document.addEventListener("DOMContentLoaded", async function () {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setExportButtonsState(true);
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
mode: "full", // export total
|
mode: "full", // export total
|
||||||
search: { value: "" },
|
search: { value: "" },
|
||||||
|
|
@ -62,12 +86,18 @@ document.addEventListener("DOMContentLoaded", async function () {
|
||||||
a.click();
|
a.click();
|
||||||
URL.revokeObjectURL(url);
|
URL.revokeObjectURL(url);
|
||||||
a.remove();
|
a.remove();
|
||||||
|
setExportButtonsState(false);
|
||||||
})
|
})
|
||||||
.catch(() => displayError("Export CSV (complet) impossible"));
|
.catch((err) => {
|
||||||
|
displayError("Export CSV (complet) impossible");
|
||||||
|
setExportButtonsState(false);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
$("#exportCSVFilter").on("click", function () {
|
$("#exportCSVFilter").on("click", function () {
|
||||||
|
if (isExporting) return;
|
||||||
|
|
||||||
const dt = $("#historiqueParcours").DataTable();
|
const dt = $("#historiqueParcours").DataTable();
|
||||||
if (!dt) {
|
if (!dt) {
|
||||||
displayError("Impossible d'accéder à la table de données.");
|
displayError("Impossible d'accéder à la table de données.");
|
||||||
|
|
@ -80,6 +110,8 @@ document.addEventListener("DOMContentLoaded", async function () {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setExportButtonsState(true);
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
mode: "filtered", // export avec les filtres/colonnes/tri actuels
|
mode: "filtered", // export avec les filtres/colonnes/tri actuels
|
||||||
search: { value: dt.search() || "" }, // recherche globale
|
search: { value: dt.search() || "" }, // recherche globale
|
||||||
|
|
@ -108,12 +140,18 @@ document.addEventListener("DOMContentLoaded", async function () {
|
||||||
a.click();
|
a.click();
|
||||||
URL.revokeObjectURL(url);
|
URL.revokeObjectURL(url);
|
||||||
a.remove();
|
a.remove();
|
||||||
|
setExportButtonsState(false);
|
||||||
})
|
})
|
||||||
.catch(() => displayError("Export CSV (filtré) impossible"));
|
.catch((err) => {
|
||||||
|
displayError("Export CSV (filtré) impossible");
|
||||||
|
setExportButtonsState(false);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
$("#exportXlxs").on("click", function () {
|
$("#exportXlxs").on("click", function () {
|
||||||
|
if (isExporting) return;
|
||||||
|
|
||||||
const dt = $("#historiqueParcours").DataTable();
|
const dt = $("#historiqueParcours").DataTable();
|
||||||
if (!dt) {
|
if (!dt) {
|
||||||
displayError("Impossible d'accéder à la table de données.");
|
displayError("Impossible d'accéder à la table de données.");
|
||||||
|
|
@ -126,6 +164,8 @@ document.addEventListener("DOMContentLoaded", async function () {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setExportButtonsState(true);
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
mode: "full",
|
mode: "full",
|
||||||
search: { value: "" },
|
search: { value: "" },
|
||||||
|
|
@ -145,12 +185,18 @@ document.addEventListener("DOMContentLoaded", async function () {
|
||||||
a.href = url; a.download = "historique_parcours_complet.xls";
|
a.href = url; a.download = "historique_parcours_complet.xls";
|
||||||
document.body.appendChild(a); a.click();
|
document.body.appendChild(a); a.click();
|
||||||
URL.revokeObjectURL(url); a.remove();
|
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 () {
|
$("#exportXlxsFilter").on("click", function () {
|
||||||
|
if (isExporting) return;
|
||||||
|
|
||||||
const dt = $("#historiqueParcours").DataTable();
|
const dt = $("#historiqueParcours").DataTable();
|
||||||
if (!dt) {
|
if (!dt) {
|
||||||
displayError("Impossible d'accéder à la table de données.");
|
displayError("Impossible d'accéder à la table de données.");
|
||||||
|
|
@ -163,6 +209,8 @@ document.addEventListener("DOMContentLoaded", async function () {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setExportButtonsState(true);
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
mode: "filtered", // export avec les filtres/colonnes/tri actuels
|
mode: "filtered", // export avec les filtres/colonnes/tri actuels
|
||||||
search: { value: dt.search() || "" }, // recherche globale
|
search: { value: dt.search() || "" }, // recherche globale
|
||||||
|
|
@ -191,8 +239,12 @@ document.addEventListener("DOMContentLoaded", async function () {
|
||||||
a.click();
|
a.click();
|
||||||
URL.revokeObjectURL(url);
|
URL.revokeObjectURL(url);
|
||||||
a.remove();
|
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: "" },
|
search: data.search || { value: "" },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
if (inflightController) inflightController.abort(); // action en cours
|
if (inflightController) inflightController.abort(); // action en cours
|
||||||
inflightController = new AbortController();
|
inflightController = new AbortController();
|
||||||
|
const currentController = inflightController;
|
||||||
|
|
||||||
fetch("/historiqueParcours/datatable", {
|
fetch("/historiqueParcours/datatable", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify(body),
|
body: JSON.stringify(body),
|
||||||
signal: inflightController.signal,
|
signal: currentController.signal,
|
||||||
})
|
})
|
||||||
.then(res => {
|
.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}`);
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.then(payload => {
|
.then(payload => {
|
||||||
|
// Vérifier si la requête a été annulée
|
||||||
|
if (currentController.signal.aborted || inflightController !== currentController) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!payload || typeof payload !== 'object') {
|
if (!payload || typeof payload !== 'object') {
|
||||||
throw new Error("Réponse invalide du serveur");
|
throw new Error("Réponse invalide du serveur");
|
||||||
}
|
}
|
||||||
|
|
@ -269,7 +329,15 @@ function initServerSideDataTable() {
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.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.");
|
displayError("Failed to fetch data. Please try again later.");
|
||||||
callback({ draw: 0, recordsTotal: 0, recordsFiltered: 0, data: [] });
|
callback({ draw: 0, recordsTotal: 0, recordsFiltered: 0, data: [] });
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue