<ul id="contextMenu" class="context-menu"> <li id="detailOption">Détails</li> <li id="editOption">Éditer</li> <li id="deleteOption">Supprimer</li> </ul> {% include "assiduites/widgets/alert.j2" %} {% include "assiduites/widgets/prompt.j2" %} <script> const itemsPerPage = 10; const contextMenu = document.getElementById("contextMenu"); const editOption = document.getElementById("editOption"); const detailOption = document.getElementById("detailOption"); const deleteOption = document.getElementById("deleteOption"); let selectedRow; document.addEventListener("click", () => { contextMenu.style.display = "none"; if (contextMenu.childElementCount > 3) { contextMenu.removeChild(contextMenu.lastElementChild) } }); editOption.addEventListener("click", () => { if (selectedRow) { const type = selectedRow.getAttribute('type'); const obj_id = selectedRow.getAttribute('obj_id'); if (type == "assiduite") { editionAssiduites(obj_id); } else { editionJustificatifs(obj_id); } } }); detailOption.addEventListener("click", () => { if (selectedRow) { const type = selectedRow.getAttribute('type'); const obj_id = selectedRow.getAttribute('obj_id'); if (type == "assiduite") { detailAssiduites(obj_id); } else { detailJustificatifs(obj_id); } } }); deleteOption.addEventListener("click", () => { if (selectedRow) { const type = selectedRow.getAttribute('type'); const obj_id = selectedRow.getAttribute('obj_id'); if (type == "assiduite") { deleteAssiduite(obj_id); } else { deleteJustificatif(obj_id); } loadAll(); } }); function filterArray(array, f) { return array.filter((el) => { let t = Object.keys(f).every((k) => { if (k == "etat") { return f.etat.includes(el.etat.toLowerCase()) }; if (k == "est_just") { if (f.est_just != "") { return `${el.est_just}` == f.est_just; } } if (k.indexOf('date') != -1) { const assi_time = new Date(el[k]); const filter_time = f[k].time; switch (f[k].pref) { case "0": return assi_time.isSame(filter_time, 'minute'); case "-1": return assi_time.isBefore(filter_time, 'minutes'); case "1": return assi_time.isAfter(filter_time, 'minutes'); } } if (k == "moduleimpl_id") { const m = el[k] == undefined || el[k] == null ? "null" : el[k]; if (f.moduleimpl_id != '') { return m == f.moduleimpl_id; } } if (k == "obj_id") { const obj_id = el.assiduite_id || el.justif_id; return f.obj_id.includes(obj_id) } if (k == "formsemestre") { return f.formsemestre === "" || (el.hasOwnProperty("formsemestre") && el.formsemestre.title.replaceAll('-', ' ').indexOf(f.formsemestre) != -1); } if (k == "etud") { const e = getEtudiant(el.etudid); const str = `${e.prenom.capitalize()} ${e.nom.toUpperCase()}` return f.etud === "" || str.indexOf(f.etud) != -1; } return true; }) return t; }) } function generateTableHead(columns, assi = true) { const table = assi ? "#assiduiteTable" : "#justificatifTable" const call = assi ? [assiduiteCallBack, true] : [justificatifCallBack, false] const tr = document.querySelector(`${table} thead tr`); tr.innerHTML = "" columns.forEach((c) => { const th = document.createElement('th'); const div = document.createElement('div'); const span = document.createElement('span'); span.textContent = columnTranslator(c); const a = document.createElement('a'); a.classList.add('icon', "order"); a.onclick = () => { order(c, call[0], a, call[1]) } div.appendChild(span) div.appendChild(a) th.appendChild(div); tr.appendChild(th); }) } function renderPaginationButtons(array, assi = true) { const totalPages = Math.ceil(array.length / itemsPerPage); if (totalPages <= 1) { if (assi) { paginationContainerAssiduites.innerHTML = "" } else { paginationContainerJustificatifs.innerHTML = "" } return; } if (assi) { paginationContainerAssiduites.innerHTML = "<span class='liste_pagination'><button class='pagination_moins'><</button><select id='paginationAssi'></select><button class='pagination_plus'>></button></span>" paginationContainerAssiduites.querySelector('#paginationAssi')?.addEventListener('change', (e) => { currentPageAssiduites = e.target.value; assiduiteCallBack(array); }) paginationContainerAssiduites.querySelector('.pagination_moins').addEventListener('click', () => { if (currentPageAssiduites > 1) { currentPageAssiduites--; paginationContainerAssiduites.querySelector('#paginationAssi').value = currentPageAssiduites + "" assiduiteCallBack(array); } }) paginationContainerAssiduites.querySelector('.pagination_plus').addEventListener('click', () => { if (currentPageAssiduites < totalPages) { currentPageAssiduites++; paginationContainerAssiduites.querySelector('#paginationAssi').value = currentPageAssiduites + "" assiduiteCallBack(array); } }) } else { paginationContainerJustificatifs.innerHTML = "<span class='liste_pagination'><button class='pagination_moins'><</button><select id='paginationJusti'></select><button class='pagination_plus'>></button></span>" paginationContainerJustificatifs.querySelector('#paginationJusti')?.addEventListener('change', (e) => { currentPageJustificatifs = e.target.value; justificatifCallBack(array); }) paginationContainerJustificatifs.querySelector('.pagination_moins').addEventListener('click', () => { if (currentPageJustificatifs > 1) { currentPageJustificatifs--; paginationContainerJustificatifs.querySelector('#paginationJusti').value = currentPageJustificatifs justificatifCallBack(array); } }) paginationContainerJustificatifs.querySelector('.pagination_plus').addEventListener('click', () => { if (currentPageJustificatifs < totalPages) { currentPageJustificatifs++; paginationContainerJustificatifs.querySelector('#paginationJusti').value = currentPageJustificatifs justificatifCallBack(array); } }) } for (let i = 1; i <= totalPages; i++) { const paginationButton = document.createElement("option"); paginationButton.textContent = i; paginationButton.value = i; if (assi) { paginationContainerAssiduites.querySelector('#paginationAssi').appendChild(paginationButton) if (i == currentPageAssiduites) paginationContainerAssiduites.querySelector('#paginationAssi').value = i + ""; } else { paginationContainerJustificatifs.querySelector('#paginationJusti').appendChild(paginationButton) if (i == currentPageJustificatifs) paginationContainerJustificatifs.querySelector('#paginationJusti').value = i + ""; } } updateActivePaginationButton(assi); } function updateActivePaginationButton(assi = true) { if (assi) { const paginationButtons = paginationContainerAssiduites.querySelectorAll("#paginationContainerAssiduites .pagination-button"); paginationButtons.forEach((button) => { if (parseInt(button.textContent) === currentPageAssiduites) { button.classList.add("active"); } else { button.classList.remove("active"); } }); } else { const paginationButtons = paginationContainerJustificatifs.querySelectorAll("#paginationContainerJustificatifs .pagination-button"); paginationButtons.forEach((button) => { if (parseInt(button.textContent) === currentPageJustificatifs) { button.classList.add("active"); } else { button.classList.remove("active"); } }); } } function loadAll() { try { getAssi(assiduiteCallBack) } catch { } try { getJusti(justificatifCallBack) } catch { } } function order(keyword, callback = () => { }, el, assi = true) { const call = (array, ordered) => { const sorted = array.sort((a, b) => { let keyValueA = a[keyword]; let keyValueB = b[keyword]; if (keyword.indexOf("date") != -1) { keyValueA = new Date(keyValueA) keyValueB = new Date(keyValueB) } if (keyword.indexOf("module") != -1) { keyValueA = getModuleImpl(a); keyValueB = getModuleImpl(b); } if (keyword.indexOf("etudid") != -1) { keyValueA = getEtudiant(a.etudid); keyValueB = getEtudiant(b.etudid); keyValueA = `${keyValueA.prenom.capitalize()} ${keyValueA.nom.toUpperCase()}` keyValueB = `${keyValueB.prenom.capitalize()} ${keyValueB.nom.toUpperCase()}` } let orderDertermined = keyValueA > keyValueB; if (!ordered) { orderDertermined = keyValueA < keyValueB; } return orderDertermined }); callback(sorted); }; if (assi) { orderAssiduites = !orderAssiduites; getAssi((a) => { call(a, orderAssiduites) }); } else { orderJustificatifs = !orderJustificatifs; getJusti((a) => { call(a, orderJustificatifs) }); } } function columnTranslator(colName) { switch (colName) { case "date_debut": return "Début"; case "entry_date": return "Saisie le"; case "date_fin": return "Fin"; case "etat": return "État"; case "moduleimpl_id": return "Module"; case "est_just": return "Justifiée"; case "raison": return "Raison"; case "fichier": return "Fichier"; case "etudid": return "Etudiant"; case "formsemestre": return "Semestre"; } } function openContext(e) { e.preventDefault(); selectedRow = e.target.parentElement; contextMenu.style.top = `${e.clientY - contextMenu.offsetHeight}px`; contextMenu.style.left = `${e.clientX}px`; contextMenu.style.display = "block"; if (contextMenu.childElementCount > 3) { contextMenu.removeChild(contextMenu.lastElementChild) } if (selectedRow.getAttribute('type') == "assiduite") { const li = document.createElement('li') li.textContent = "Justifier" let obj_id = selectedRow.getAttribute('obj_id'); let assi = Object.values(assiduites).flat().filter((a) => { return a.assiduite_id == obj_id })[0] li.addEventListener('click', () => { if (assi && !assi.est_just && assi.etat != "PRESENT") { fastJustify(assi) } else { openAlertModal("Erreur", document.createTextNode("L'assiduité est déjà justifiée.")) } }) if (assi && assi.etat != "PRESENT") { contextMenu.appendChild(li); } } } function downloadStr(data, name) { const blob = new Blob([data], { type: 'text/csv' }); const url = window.URL.createObjectURL(blob) const a = document.createElement('a') a.setAttribute('href', url) a.setAttribute('download', name); a.click() a.remove() } function askDownload(data) { const div = document.createElement('div'); const head = document.createElement('h3'); const input = document.createElement('input'); head.textContent = "Veuillez nommer le fichier qui sera téléchargé (sera au format CSV)" input.type = "text"; input.placeholder = "liste.csv" div.appendChild(head) div.appendChild(input) openPromptModal("Préparation du téléchargement", div, () => { downloadStr(data, input.value ? input.value : "download.csv") }, () => { }, "green"); } function toCSV(array, filters) { array = filterArray(array, filters.filters) let csv = filters.columns.map((c) => columnTranslator(c)).join(',') + "\n"; array.forEach((a) => { let line = "" filters.columns.forEach((c) => { switch (c) { case "fichier": line += a[c] ? "Oui," : "Non," break; case "etudid": const e = getEtudiant(a.etudid); line += `${e.nom.toUpperCase()} ${e.prenom.capitalize()},` break; case "formsemestre": line += a.hasOwnProperty("formsemestre") ? a.formsemestre.title : "" line += "," break; case "est_just": line += a[c] ? "Oui," : "Non," break; case "moduleimpl_id": line += `${getModuleImpl(a)},` break; default: line += `${a[c]},`; break; } }) line = line.substring(0, line.lastIndexOf(',')) + "\n" csv += line; }) askDownload(csv); } function getEtudiant(id) { if (id in etuds) { return etuds[id]; } getSingleEtud(id); return etuds[id]; } </script> <style> .pageContent { width: 100%; max-width: var(--sco-content-max-width); display: flex; flex-direction: column; flex-wrap: wrap; } table { border-collapse: collapse; text-align: left; margin: 20px 0; } th, td { border: 1px solid #dddddd; padding: 8px; } th { background-color: #f2f2f2; } tr:hover { filter: brightness(1.2) } .context-menu { display: none; position: fixed; list-style-type: none; padding: 10px 0; background-color: #f9f9f9; border: 1px solid #ccc; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2); cursor: pointer; z-index: 45; } .context-menu li { padding: 8px 16px; background-color: #f9f9f9; } .context-menu li:hover { filter: brightness(0.7); } #deleteOption { background-color: #F1A69C; } .l-present { background-color: #9CF1AF; } .l-absent, .l-invalid { background-color: #F1A69C; } .l-valid { background-color: #8f7eff; } .l-retard { background-color: #F1D99C; } /* Ajoutez des styles pour le conteneur de pagination et les boutons */ .pagination-container { display: flex; justify-content: center; margin: 20px 0; } .pagination-button { padding: 10px; border: 1px solid #ccc; cursor: pointer; background-color: #f9f9f9; margin: 0 5px; text-decoration: none; color: #000; } .pagination-button:hover { background-color: #ddd; } .pagination-button.active { background-color: #007bff; color: #fff; border-color: #007bff; } th>div { display: flex; justify-content: space-between; align-items: center; } .filter-head { display: flex; flex-wrap: wrap; gap: 5px; } .filter-line { display: flex; justify-content: start; align-items: center; margin: 15px; } .filter-line>* { margin-right: 5px; } .rbtn { width: 35px; height: 35px; margin: 0 5px !important; } .f-label { margin: 0 5px; } .chk { margin-left: 2px !important; } .filter-body label { display: flex; justify-content: center; align-items: center; padding: 0; margin: 0; } .obj-title { text-decoration: underline #bbb; font-weight: bold; } .obj-part { display: flex; flex-direction: column; justify-content: center; align-items: center; width: 33%; padding: 5px; border: 1px solid #bbb; } .obj-dates, .obj-mod, .obj-rest { display: flex; justify-content: space-evenly; margin: 2px; } .liste_pagination { display: flex; justify-content: space-evenly; align-items: center; gap: 5px; } </style>