diff --git a/app/static/css/partition_editor.css b/app/static/css/partition_editor.css index e1bd992d..4f9915dc 100644 --- a/app/static/css/partition_editor.css +++ b/app/static/css/partition_editor.css @@ -31,6 +31,126 @@ main h3 { font-weight: 400; } +body:not(.editionActivated) .editing { + display: none !important; +} + +.editionActivated #zoneChoix .etudiants>div { + pointer-events: none; + opacity: 0.5; +} + +/****************/ +.ajoutPartition, +.ajoutGroupe { + background: #0c9 !important; + padding: 8px 16px !important; + cursor: pointer; +} + +.move, +.modif, +.suppr { + color: #000; + padding: 4px; + cursor: pointer; +} + +.move { + cursor: grab; +} + +.move:active { + cursor: grabbing; +} + +body.editionActivated .filtres>div>div>div>div { + padding: 8px 16px; + position: relative; +} + +.editingText { + background: #FFF; + color: #000; + border-radius: 4px; + outline: 4px solid #FFF; +} + +/* Suppression */ +.confirm { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 100; + background: rgba(0, 0, 0, 0.8); + display: flex; + justify-content: center; + align-items: center; +} + +.confirm span { + color: #09c; +} + +.confirm>div { + background: #FFF; + margin: 32px; + padding: 32px 64px; + border-radius: 8px; + text-align: center; +} + +.confirm>div>div { + display: flex; + gap: 32px; + justify-content: center; +} + +.confirm>div>div>div { + padding: 16px 32px; + border-radius: 8px; + color: #FFF; + cursor: pointer; +} + +.confirm .ok { + background: #0c9; +} + +.confirm .nok { + background: #c44; +} + +/* Déplacements */ +.moving { + opacity: 0.8; + pointer-events: none; + ; +} + +.grabbing>div:not([data-idgroupe="aucun"]):hover:before { + content: ""; + position: absolute; + bottom: -4px; + top: -4px; + right: calc(100% + 1px); + width: 2px; + background: #c44; + animation: insert 0.2s infinite alternate ease-in-out; +} + +@keyframes insert { + 0% { + transform: translateY(-4px) + } + + 100% { + transform: translateY(4px) + } +} + /*****************************/ /* Zone Choix */ /*****************************/ @@ -46,7 +166,7 @@ main h3 { flex-wrap: wrap; gap: 4px; row-gap: 2px; - margin: 4px 0; + margin: 8px 0; } .filtres>div>div>div>div { @@ -55,14 +175,17 @@ main h3 { border-radius: 4px; padding: 8px 32px; box-shadow: 0 2px 2px rgba(0, 0, 0, 0.25); +} + +body:not(.editionActivated) .filtres>div>div>div>div { cursor: pointer; } -.filtres>div>div>div>div:hover { +body:not(.editionActivated) .filtres>div>div>div>div:hover { box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6); } -.filtres>div>div>div>div:active { +body:not(.editionActivated) .filtres>div>div>div>div:active { box-shadow: 0 0 0 #000; transform: translateY(2px); } diff --git a/app/templates/scolar/partition_editor.html b/app/templates/scolar/partition_editor.html index 43465e36..7b6d8a9e 100644 --- a/app/templates/scolar/partition_editor.html +++ b/app/templates/scolar/partition_editor.html @@ -1,8 +1,16 @@ {# -*- mode: jinja-html -*- #}

{% if not read_only %}Édition des p{% else %}P{%endif%}artitions

+
+ +
+
+

Choix

@@ -30,6 +38,7 @@ go(); async function go() { + document.querySelector('.wait').style.display = ""; let params = (new URL(document.location)).searchParams; let formsemestre_id = params.get('formsemestre_id'); @@ -65,7 +74,7 @@ let outputGroupes = ""; Object.entries(partitions).forEach(([idPartition, partition]) => { // Filtres - outputPartitions += `
${partition.partition_name}
`; + outputPartitions += `
||${partition.partition_name}✏️
`; outputMasques += `
Non affectés - ${partition.partition_name}
`; // Groupes @@ -80,7 +89,7 @@ let output = ""; Object.entries(partition.groups).forEach(([idGroupe, titreGroupe]) => { /***************/ - outputMasques += `
${titreGroupe.name}
`; + outputMasques += `
||${titreGroupe.name}✏️
`; /***************/ output += `
@@ -91,9 +100,13 @@ return output; })()}
`; - outputMasques += "
" + outputMasques += ` +
+
+
`; }) - document.querySelector(".filtres>.partitions>div").innerHTML = outputPartitions + ""; + document.querySelector(".filtres>.partitions>div").innerHTML = outputPartitions + ` +
+
+ `; document.querySelector(".filtres>.masques>div").innerHTML = outputMasques; document.querySelector("#zoneGroupes>.groupes").innerHTML = outputGroupes; @@ -141,19 +154,38 @@ return `
${etudiant.nom_disp} ${etudiant.prenom}
` } + /******************************/ + /* Gestionnaire d'événements */ + /******************************/ function processEvents() { - document.querySelectorAll(".filtres>div>div>div>div").forEach(btn => { - btn.addEventListener("click", filtre); - btn.addEventListener("mousedown", (event) => { event.preventDefault() }) // Eviter de sélectionner le texte si on clique plusieurs fois frénétiquement - }); - document.querySelectorAll("#zoneChoix label").forEach(btn => { btn.addEventListener("mousedown", (event) => { event.preventDefault() }) }); + /*--------------------*/ + /* Edition partitions */ + /*--------------------*/ + document.querySelector(".edition>input").addEventListener("input", () => { document.querySelector("body").classList.toggle("editionActivated") }); + document.querySelectorAll(".ajoutPartition, .ajoutGroupe").forEach(btnPlus => { btnPlus.addEventListener("click", addPartition) }) + document.querySelectorAll(".modif").forEach(btn => { btn.addEventListener("click", editText) }) + document.querySelectorAll(".suppr").forEach(btn => { btn.addEventListener("click", suppr) }) + document.querySelectorAll(".move").forEach(btn => { btn.addEventListener("mousedown", moveStart) }) - document.querySelectorAll(".etudiants input").forEach(input => { - input.addEventListener("input", assignment); - }) + /*---------*/ + /* Filtres */ + /*---------*/ + document.querySelectorAll(".filtres>div>div>div>div:not(.editing)").forEach(btn => { btn.addEventListener("click", filtre) }) + + /*--------------------*/ + /* Changement groupe */ + /*--------------------*/ + document.querySelectorAll("#zoneChoix label").forEach(btn => { btn.addEventListener("mousedown", (event) => { event.preventDefault() }) }); + document.querySelectorAll(".etudiants input").forEach(input => { input.addEventListener("input", assignment) }) } + /**********************/ + /* Filtrage */ + /**********************/ function filtre() { + if (document.querySelector("body").classList.contains("editionActivated")) { + return; + } let nbUnselected = this.parentElement.querySelectorAll(".unselect").length; let nbBtn = this.parentElement.children.length; @@ -192,20 +224,20 @@ this.parentElement.parentElement.querySelectorAll("[data-idgroupe]:not(.unselect)").forEach(e => { let idpartition = e.parentElement.dataset.idpartition; - if(!groupesSelected[idpartition]){ + if (!groupesSelected[idpartition]) { groupesSelected[idpartition] = []; } groupesSelected[idpartition].push(e.dataset.idgroupe) }) document.querySelectorAll("#zoneChoix .etudiants>div").forEach(e => { let found = true; - Object.entries(groupesSelected).forEach(([idpartition, tabGroupes])=>{ - if( !tabGroupes.includes( - e.querySelector(`[data-idpartition="${idpartition}"] input:checked`).value - ) - ){ + Object.entries(groupesSelected).forEach(([idpartition, tabGroupes]) => { + if (!tabGroupes.includes( + e.querySelector(`[data-idpartition="${idpartition}"] input:checked`).value + ) + ) { found = false - } + } }) if (found) { @@ -216,7 +248,9 @@ }) } } - + /****************************/ + /* Affectation à un groupe */ + /****************************/ function assignment() { let groupe = this.parentElement.parentElement.parentElement.parentElement; let nom = groupe.children[0].dataset.nom; @@ -267,4 +301,155 @@ }) } + + /*******************/ + /* Ajout partition */ + /*******************/ + function addPartition() { + let div = document.createElement("div"); + div.innerHTML = ` + || + Nouveau + ✏️ + `; + + div.querySelector(".modif").addEventListener("click", editText); + div.querySelector(".suppr").addEventListener("click", suppr); + div.querySelector(".move").addEventListener("mousedown", moveStart); + this.parentElement.insertBefore(div, this); + + // Save + } + + /********************/ + /* Edition du texte */ + /********************/ + function editText() { + //this.addEventListener("click", saveEditing, { once: true }) + this.previousElementSibling.classList.add("editingText"); + this.previousElementSibling.setAttribute("contenteditable", "true"); + this.previousElementSibling.focus(); + + this.previousElementSibling.addEventListener("keydown", writing); + } + + function writing(event) { + switch (event.key) { + case 'Enter': + saveEditing(this); + event.preventDefault(); + break; + case 'Escape': + saveEditing(this); + event.preventDefault(); + break; + } + } + + function saveEditing(obj) { + obj.classList.remove("editingText"); + obj.setAttribute("contenteditable", "false"); + obj.removeEventListener("keydown", writing); + // Save + console.log( + obj.parentElement.dataset.idpartition || obj.parentElement.dataset.idgroupe, + obj.innerText); + } + + /*********************************/ + /* Suppression parcours / groupe */ + /*********************************/ + function suppr() { + if (this.parentElement.dataset.idpartition) { + var data = `data-idpartition="${this.parentElement.dataset.idpartition}"`; + } else { + var data = `data-idgroupe="${this.parentElement.dataset.idgroupe}"`; + } + let div = document.createElement("div"); + div.className = "confirm"; + div.innerHTML = ` +
+

Vous être sur le point de supprimer ${this.previousElementSibling.previousElementSibling.innerText}, cette opération est irréversible

+
+
Supprimer
+
Annuler
+
+
+ `; + document.body.append(div); + document.querySelector(".ok").addEventListener("click", supprConfirmed); + document.querySelector(".nok").addEventListener("click", closeConfirm); + } + + function supprConfirmed() { + closeConfirm(); + /* Suppression des éléments dans la page */ + if (this.dataset.idpartition) { + document.querySelectorAll(`[data-idpartition="${this.dataset.idpartition}"]`).forEach(e => { e.remove() }) + } else { + document.querySelectorAll(`[value="${this.dataset.idgroupe}"]`).forEach(e => { + if (e.checked == true) { + e.parentElement.parentElement.querySelector("label").click() + } + e.parentElement.remove() + }) + document.querySelectorAll(`[data-idgroupe="${this.dataset.idgroupe}"]`).forEach(e => { e.remove() }) + } + //Save + console.log(this.dataset.idpartition || this.dataset.idgroupe); + + } + + function closeConfirm() { + document.querySelector(".confirm").remove(); + } + + /*************************/ + /* Changement de l'ordre */ + /*************************/ + let moveData = {}; + function moveStart(event) { + moveData.x = event.pageX; + moveData.y = event.pageY; + moveData.element = this.parentElement; + moveData.element.classList.add("moving"); + moveData.element.parentElement.classList.add('grabbing'); + document.body.addEventListener("mousemove", move); + moveData.element.parentElement.querySelectorAll("div:not([data-idgroupe=aucun])").forEach(e => { + e.addEventListener("mouseup", newPosition) + }) + document.body.addEventListener("mouseup", moveEnd); + } + + function move(event) { + event.preventDefault(); + moveData.element.style.transform = `translate(${event.pageX - moveData.x}px, ${event.pageY - moveData.y}px)` + } + + function moveEnd() { + document.body.removeEventListener("mousemove", move); + document.body.removeEventListener("mouseup", moveEnd); + moveData.element.parentElement.classList.remove('grabbing'); + moveData.element.style.transform = ""; + moveData.element.classList.remove("moving"); + moveData.element.parentElement.querySelectorAll("div:not([data-idgroupe=aucun])").forEach(e => { + e.removeEventListener("mouseup", newPosition) + }) + moveData = {}; + } + + function newPosition() { + moveData.element.parentElement.insertBefore(moveData.element, this); + + let positions = []; + Array.from(moveData.element.parentElement.children).forEach(e => { + if (e.dataset.idpartition || (e.dataset.idgroupe && e.dataset.idgroupe != "aucun")) { + positions.push(e.dataset.idpartition || e.dataset.idgroupe) + } + }) + + // Save positions + console.log(positions) + } + \ No newline at end of file