Nouvelle version editeur partitions

This commit is contained in:
Sébastien Lehmann 2023-01-08 17:31:15 +01:00 committed by iziram
parent 47b3eec14b
commit b7983a8d59
2 changed files with 448 additions and 221 deletions

View File

@ -1,3 +1,7 @@
html {
overflow-x: hidden;
}
.wait { .wait {
position: fixed; position: fixed;
width: 50px; width: 50px;
@ -44,19 +48,43 @@
margin-bottom: 16px; margin-bottom: 16px;
display: inline-block; display: inline-block;
cursor: pointer; cursor: pointer;
pointer-events: none;
}
.loaded .edition {
pointer-events: initial;
}
.filtres>label {
display: none;
}
.editionActivated .valider {
display: block;
width: fit-content;
margin-left: auto;
padding: 8px 32px;
background: #90c;
color: #fff;
box-shadow: 0 2px 2px rgb(0, 0, 0, 0.25);
border-radius: 4px;
cursor: pointer;
} }
main { main {
font-family: Verdana, Geneva, Tahoma, sans-serif; font-family: Verdana, Geneva, Tahoma, sans-serif;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 32px; gap: 8px;
row-gap: 4px;
margin-right: 16px; margin-right: 16px;
padding: 8px;
border-radius: 12px;
background: #424242;
} }
main h2 { main h2 {
border-bottom: 4px solid #09c; border-bottom: 4px solid #09c;
font-size: 150% !important;
} }
main h2, main h2,
@ -64,11 +92,22 @@ main h3 {
font-weight: 400; font-weight: 400;
} }
body:not(.editionActivated) .editing { section {
display: none !important; background: #fff;
padding: 8px;
border-radius: 8px;
} }
.editionActivated #zoneChoix .etudiants>div { body:not(.editionActivated) .editing {
display: none;
}
.nonEditable .editing {
display: none;
}
.editionActivated #zoneChoix,
.editionActivated #zoneGroupes {
pointer-events: none; pointer-events: none;
opacity: 0.2; opacity: 0.2;
} }
@ -80,7 +119,9 @@ body:not(.editionActivated) .editing {
} }
@keyframes boing { @keyframes boing {
100% {transform: translateY(-20px)} 100% {
transform: translateY(-20px)
}
} }
/****************/ /****************/
@ -89,13 +130,19 @@ body:not(.editionActivated) .editing {
background: #0c9 !important; background: #0c9 !important;
padding: 8px 16px !important; padding: 8px 16px !important;
cursor: pointer; cursor: pointer;
color: #fff;
box-shadow: 0 2px 2px rgb(0, 0, 0, 0.25);
border-radius: 4px;
text-align: center;
margin-bottom: 4px;
width: fit-content;
} }
.move, .move,
.modif, .modif,
.suppr { .suppr {
color: #000; color: #000;
padding: 4px; padding: 0 4px;
cursor: pointer; cursor: pointer;
} }
@ -172,10 +219,31 @@ body.editionActivated .filtres>div>div>div>div {
.moving { .moving {
opacity: 0.8; opacity: 0.8;
pointer-events: none; pointer-events: none;
;
} }
.grabbing>div:not([data-idgroupe="aucun"]):hover:before { .grabbing>div[data-idpartition]:not([data-idgroupe]):hover:before {
content: "";
position: absolute;
left: -4px;
right: -4px;
bottom: calc(100% + 1px);
height: 2px;
width: auto;
background: #c44;
animation: insertPartion 0.2s infinite alternate ease-in-out;
}
@keyframes insertPartion {
0% {
transform: translateX(-4px)
}
100% {
transform: translateX(4px)
}
}
.grabbing>*:not([data-idgroupe="aucun"]):hover:before {
content: ""; content: "";
position: absolute; position: absolute;
bottom: -4px; bottom: -4px;
@ -183,10 +251,10 @@ body.editionActivated .filtres>div>div>div>div {
right: calc(100% + 1px); right: calc(100% + 1px);
width: 2px; width: 2px;
background: #c44; background: #c44;
animation: insert 0.2s infinite alternate ease-in-out; animation: insertGroupe 0.2s infinite alternate ease-in-out;
} }
@keyframes insert { @keyframes insertGroupe {
0% { 0% {
transform: translateY(-4px) transform: translateY(-4px)
} }
@ -197,51 +265,77 @@ body.editionActivated .filtres>div>div>div>div {
} }
/*****************************/ /*****************************/
/* Zone Partitions */ /* Zone Filtres */
/*****************************/ /*****************************/
#zonePartitions { #zonePartitions {
width: 100%; width: 100%;
} }
.filtres { #zonePartitions>div {
display: table; width: fit-content;
} }
.filtres>div { #zonePartitions h3{
background: #ddd; display: flex;
}
#zonePartitions h3 .onoff{
margin-left: auto;
cursor: pointer;
display: flex;
align-items: center;
gap: 4px;
font-size: 16px;
}
#zonePartitions .filtres {
width: fit-content;
}
#zonePartitions .filtres>div {
background: #eee;
padding: 8px; padding: 8px;
border-radius: 8px; border-radius: 8px;
margin-bottom: 8px; margin-bottom: 8px;
position: relative;
} }
.filtres>div>div>div { #zonePartitions .filtres .groupes {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 4px; gap: 4px;
row-gap: 2px; row-gap: 2px;
margin: 8px 0; margin: 4px 0 0 0;
} }
.filtres>div>div>div>div { #zonePartitions .filtres .groupes>div {
position: relative;
background: #09c; background: #09c;
color: #FFF; color: #FFF;
border-radius: 4px; border-radius: 4px;
padding: 8px 32px; padding: 8px 32px;
margin: 0;
box-shadow: 0 2px 2px rgba(0, 0, 0, 0.25); box-shadow: 0 2px 2px rgba(0, 0, 0, 0.25);
} }
body:not(.editionActivated) .filtres>div>div>div>div { body:not(.editionActivated) .filtres .groupes>div {
cursor: pointer; cursor: pointer;
} }
body:not(.editionActivated) .filtres>div>div>div>div:hover { body:not(.editionActivated) .filtres .groupes>div:hover {
box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6); box-shadow: 0 2px 2px rgba(0, 0, 0, 0.6) !important;
} }
body:not(.editionActivated) .filtres>div>div>div>div:active { body:not(.editionActivated) .filtres .groupes>div:active {
box-shadow: 0 0 0 #000; box-shadow: 0 0 0 #000 !important;
transform: translateY(2px); transform: translateY(2px);
} }
body.editionActivated .filtres [data-idgroupe=aucun]{
display: none;
}
body.editionActivated .filtres .nonEditable .move{
display: initial;
}
.filtres .unselect { .filtres .unselect {
background: rgba(0, 153, 204, 0.5); background: rgba(0, 153, 204, 0.5);
@ -250,12 +344,37 @@ body:not(.editionActivated) .filtres>div>div>div>div:active {
/*****************************/ /*****************************/
/* Zone Etudiants */ /* Zone Etudiants */
/*****************************/ /*****************************/
#zoneChoix>.autoAffectation{
background: #3c3c3c;
color: #fff;
padding: 4px 8px;
margin-bottom: 16px;
border-radius: 4px;
}
#zoneChoix>.autoAffectation>select{
border: none;
padding: 4px 16px;
border-radius: 4px;
}
#zoneChoix>.autoAffectation>.affectationGo{
display: inline-block;
background: #0c9;
padding: 8px 16px;
cursor: pointer;
color: #fff;
box-shadow: 0 2px 2px rgb(0 0 0 / 25%);
border-radius: 4px;
text-align: center;
margin-top: 4px;
margin-bottom: 4px;
width: fit-content;
}
#zoneChoix .etudiants>div { #zoneChoix .etudiants>div {
background: #FFF; background: #FFF;
border: 1px solid #aaa; border: 1px solid #aaa;
border-radius: 4px; border-radius: 4px;
padding: 4px 8px; padding: 4px 8px;
margin: 4px 0; margin: -1px 0;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: space-between; justify-content: space-between;
@ -266,16 +385,22 @@ body:not(.editionActivated) .filtres>div>div>div>div:active {
flex: 1; flex: 1;
} }
#zoneChoix small { #zoneChoix .small {
color: #444; color: #444;
font-size: 8px;
font-style: italic; font-style: italic;
} }
#zoneChoix .etudiants .grpPartitions {
display: flex;
flex-direction: column;
gap: 2px;
}
#zoneChoix .etudiants .partition { #zoneChoix .etudiants .partition {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 4px; gap: 4px;
margin-bottom: 4px;
} }
#zoneChoix label { #zoneChoix label {
@ -313,9 +438,12 @@ body:not(.editionActivated) .filtres>div>div>div>div:active {
color: #fff; color: #fff;
} }
.hide { section:not(#zonePartitions) .hide {
display: none !important; display: none !important;
} }
#zonePartitions .hide{
opacity: 0.4;
}
.saved+span { .saved+span {
position: relative; position: relative;
@ -346,11 +474,8 @@ body:not(.editionActivated) .filtres>div>div>div>div:active {
flex: 1; flex: 1;
} }
#zoneGroupes .groupes { #zoneGroupes h3 {
display: flex; width: 100%;
flex-wrap: wrap;
align-items: flex-start;
gap: 16px;
} }
#zoneGroupes .partition { #zoneGroupes .partition {
@ -358,8 +483,9 @@ body:not(.editionActivated) .filtres>div>div>div>div:active {
padding: 8px; padding: 8px;
border-radius: 8px; border-radius: 8px;
display: flex; display: flex;
flex-direction: column; flex-wrap: wrap;
gap: 8px; gap: 8px;
margin-bottom: 8px;
} }
h3 { h3 {
@ -390,5 +516,6 @@ h3 {
} }
#zoneGroupes [data-idgroupe=aucun] { #zoneGroupes [data-idgroupe=aucun] {
background: #b5c2c3 !important; background: #3c3c3c !important;
color: #fff;
} }

View File

@ -5,30 +5,30 @@
<div class="wait"></div> <div class="wait"></div>
<section id="zonePartitions"> <section id="zonePartitions">
<h2>Partitions et groupes</h2> <h2>Filtres</h2>
<div> <div>
<label class="edition"> <label class="edition">
<input type="checkbox" autocomplete="off"> <input type="checkbox" autocomplete="off" id="inputModif">
Modifier les partitions et groupes - tout s'enregistre automatiquement dès qu'il y a modification Modifier les partitions et groupes
</label> </label>
<div class="filtres"> <div class="filtres"></div>
<div class="partitions"> <div style="display: flex; justify-content: space-between;">
<h3>Afficher les partitions</h3> <div class="editing ajoutPartition">Ajouter une partition</div>
<div></div> <label class="editing valider" for="inputModif">Fini</label>
</div>
<div class="masques">
<h3>
Afficher les étudiants affectés aux groupes<br>
<small>Ne s'actualise pas automatiquement lors d'une modification</small>
</h3>
<div></div>
</div>
</div> </div>
</div> </div>
</section> </section>
<section id="zoneChoix"> <section id="zoneChoix">
<h2>Etudiants</h2> <h2>Etudiants</h2>
<div class="autoAffectation">
Affecter automatiquement les étudiants du groupe<br>
<select name="affectationFrom" id="affectationFrom"></select>
vers le groupe
<select name="affectationTo" id="affectationTo"></select>
<div class="affectationGo">Valider</div>
</div>
<div class="etudiants"></div> <div class="etudiants"></div>
</section> </section>
@ -55,7 +55,9 @@
processDatas(partitions, etudiants); processDatas(partitions, etudiants);
processEvents(); processEvents();
listeGroupesAutoaffectation();
document.querySelector("body").classList.add("loaded");
document.querySelector('.wait').style.display = "none"; document.querySelector('.wait').style.display = "none";
} }
@ -73,22 +75,25 @@
function processDatas(partitions, etudiants) { function processDatas(partitions, etudiants) {
/* Filtres et groupes */ /* Filtres et groupes */
let outputPartitions = "<div>"; let divFiltres = document.querySelector(".filtres");
let outputMasques = "";
let outputGroupes = ""; let outputGroupes = "";
let arrayPartitions = Object.values(partitions).sort((a, b) => { let arrayPartitions = Object.values(partitions).sort((a, b) => {
return a.numero - b.numero; return a.numero - b.numero;
}) })
arrayPartitions.forEach((partition) => { arrayPartitions.forEach((partition) => {
// Filtres
if (partition.groups_editable) {
outputPartitions += `<div data-idpartition="${partition.id}"><span class="editing move">||</span><span>${partition.partition_name}</span><span class="editing modif">✏️</span><span class="editing suppr"></span></div>`;
} else {
outputPartitions += `<div data-idpartition="${partition.id}"><span>${partition.partition_name}</span></div>`;
}
outputMasques += `<div data-idpartition="${partition.id}"><div data-idpartition="${partition.id}" data-idgroupe=aucun>Non affectés - ${partition.partition_name}</div>`; let divPartition = templateFiltres_partition(partition);
divFiltres.appendChild(divPartition);
let arrayGroups = Object.values(partition.groups).sort((a, b) => {
return a.numero - b.numero;
})
arrayGroups.forEach((groupe) => {
let divPlus = divPartition.querySelector(".ajoutGroupe");
divPlus.parentElement.insertBefore(templateFiltres_groupe(groupe), divPlus);
})
// Groupes // Groupes
outputGroupes += ` outputGroupes += `
@ -104,35 +109,21 @@
}) })
let output = ""; let output = "";
arrayGroups.forEach((groupe) => { arrayGroups.forEach((groupe) => {
/***************/
if (partition.groups_editable) {
outputMasques += `<div data-idgroupe="${groupe.id}"><span class="editing move">||</span><span>${groupe.group_name}</span><span class="editing modif">✏️</span><span class="editing suppr"></span></div>`;
} else {
outputMasques += `<div data-idgroupe="${groupe.id}"><span>${groupe.group_name}</span></div>`;
}
/***************/
output += templateGroupe_zoneGroupes(groupe.id, groupe.group_name); output += templateGroupe_zoneGroupes(groupe.id, groupe.group_name);
}) })
return output; return output;
})()} })()}
</div>`; </div>`;
outputMasques += `
<div class="editing ajoutGroupe">+</div>
</div>`;
}) })
document.querySelector(".filtres>.partitions>div").innerHTML = outputPartitions + `
<div class="editing ajoutPartition">+</div>
</div>`;
document.querySelector(".filtres>.masques>div").innerHTML = outputMasques;
document.querySelector("#zoneGroupes>.groupes").innerHTML = outputGroupes;
document.querySelector("#zoneGroupes>.groupes").innerHTML = outputGroupes;
/* Etudiants */ /* Etudiants */
output = ""; output = "";
etudiants.forEach(etudiant => { etudiants.forEach(etudiant => {
output += ` output += `
<div> <div>
<div class=nom data-etudid="${etudiant.etudid}" data-nom="${etudiant.nom_disp}" data-prenom="${etudiant.prenom}">${etudiant.nom_disp} ${etudiant.prenom}<br><small>${etudiant.bac}</small></div> <div class=nom data-etudid="${etudiant.etudid}" data-nom="${etudiant.nom_disp}" data-prenom="${etudiant.prenom}">${etudiant.nom_disp} ${etudiant.prenom}<div class=small>${etudiant.bac}</div></div>
${(() => { ${(() => {
let output = "<div class=grpPartitions>"; let output = "<div class=grpPartitions>";
arrayPartitions.forEach((partition) => { arrayPartitions.forEach((partition) => {
@ -168,6 +159,58 @@
document.querySelector("#zoneChoix>.etudiants").innerHTML = output; document.querySelector("#zoneChoix>.etudiants").innerHTML = output;
} }
function templateFiltres_partition(partition) {
let div = document.createElement("div");
div.dataset.idpartition = partition.id;
if (partition.groups_editable == false) {
div.classList.add("nonEditable");
}
div.innerHTML = `
<!-- Partition -->
<h3 data-idpartition="${partition.id}">
<span class="editing move">||</span>
<span>${partition.partition_name}</span>
<span class="editing modif">✏️</span>
<span class="editing suppr"></span>
<div class=onoff>Masquer<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#0b0b0b" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path><circle cx="12" cy="12" r="3"></circle></svg></div>
</h3>
<!-- Groupes -->
<div class=groupes>
<div data-idgroupe=aucun>
Non affectés
</div>
<div class="editing ajoutGroupe">+</div>
</div>`;
div.querySelector(".move").addEventListener("mousedown", moveStart);
div.querySelector(".modif").addEventListener("click", editText);
div.querySelector(".suppr").addEventListener("click", suppr);
div.querySelector(".onoff").addEventListener("click", masquerPartitions);
div.querySelector("[data-idgroupe]").addEventListener("click", filtre);
div.querySelector(".ajoutGroupe").addEventListener("click", addGroupe);
return div;
}
function templateFiltres_groupe(groupe) {
let div = document.createElement("div");
div.dataset.idgroupe = groupe.id;
div.innerHTML = `
<span class="editing move">||</span>
<span>${groupe.group_name}</span>
<span class="editing modif">✏️</span>
<span class="editing suppr"></span>`;
div.addEventListener("click", filtre);
div.querySelector(".move").addEventListener("mousedown", moveStart);
div.querySelector(".modif").addEventListener("click", editText);
div.querySelector(".suppr").addEventListener("click", suppr);
return div;
}
function templateGroupe_zoneGroupes(idGroupe, name) { function templateGroupe_zoneGroupes(idGroupe, name) {
return `<div class=groupe data-idgroupe="${idGroupe}"> return `<div class=groupe data-idgroupe="${idGroupe}">
<div>${name}</div> <div>${name}</div>
@ -179,6 +222,24 @@
return `<div data-etudid="${etudiant.etudid}" data-nom="${etudiant.nom_disp}" data-prenom="${etudiant.prenom}">${etudiant.nom_disp} ${etudiant.prenom}</div>` return `<div data-etudid="${etudiant.etudid}" data-nom="${etudiant.nom_disp}" data-prenom="${etudiant.prenom}">${etudiant.nom_disp} ${etudiant.prenom}</div>`
} }
function listeGroupesAutoaffectation() {
let output = '<option value disabled selected hidden>Choisir</option>';
document.querySelectorAll('#zonePartitions .filtres>div').forEach(partition => {
output += `<optgroup label="${partition.children[0].children[1].innerText}">`;
partition.querySelectorAll('[data-idgroupe]:not([data-idgroupe="aucun"])').forEach(groupe => {
output += `<option value=${groupe.dataset.idgroupe}>${groupe.innerText}</option>`;
})
output += "</optgroup>";
})
document.querySelector("#affectationFrom").innerHTML = output;
document.querySelector("#affectationTo").innerHTML = output;
}
/******************************/ /******************************/
/* Gestionnaire d'événements */ /* Gestionnaire d'événements */
/******************************/ /******************************/
@ -187,11 +248,11 @@
if (!editing) { if (!editing) {
document.querySelector("body").classList.toggle("editionActivated"); document.querySelector("body").classList.toggle("editionActivated");
return; return;
} }
this.checked = true; this.checked = true;
if(!editing.classList.contains("highlight")) { if (!editing.classList.contains("highlight")) {
editing.classList.add("highlight"); editing.classList.add("highlight");
setTimeout(()=>{editing.classList.remove("highlight")}, 1000); setTimeout(() => { editing.classList.remove("highlight") }, 1000);
} }
} }
function processEvents() { function processEvents() {
@ -199,26 +260,25 @@
/* Edition partitions */ /* Edition partitions */
/*--------------------*/ /*--------------------*/
document.querySelector(".edition>input").addEventListener("input", setEditMode); document.querySelector(".edition>input").addEventListener("input", setEditMode);
document.querySelectorAll(".ajoutPartition, .ajoutGroupe").forEach(btnPlus => { btnPlus.addEventListener("click", addPartition) }) document.querySelectorAll(".ajoutPartition").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) })
/*---------*/
/* Filtres */
/*---------*/
document.querySelectorAll(".filtres>div>div>div>div:not(.editing)").forEach(btn => { btn.addEventListener("click", filtre) })
/*--------------------*/ /*--------------------*/
/* Changement groupe */ /* Changement groupe */
/*--------------------*/ /*--------------------*/
document.querySelectorAll("label").forEach(btn => { btn.addEventListener("mousedown", (event) => { event.preventDefault() }) }); document.querySelectorAll("label").forEach(btn => { btn.addEventListener("mousedown", (event) => { event.preventDefault() }) });
document.querySelectorAll(".etudiants input").forEach(input => { input.addEventListener("input", assignment) }) document.querySelectorAll(".etudiants input").forEach(input => { input.addEventListener("input", assignment) })
document.querySelector(".affectationGo").addEventListener("click", affectationGo);
} }
/**********************/ /**********************/
/* Filtrage */ /* Filtrage */
/**********************/ /**********************/
function masquerPartitions() {
let idPartition = this.closest("[data-idpartition]").dataset.idpartition;
document.querySelectorAll(`[data-idpartition="${idPartition}"]`).forEach(e => {
e.classList.toggle("hide");
})
}
function filtre() { function filtre() {
if (document.querySelector("body").classList.contains("editionActivated")) { if (document.querySelector("body").classList.contains("editionActivated")) {
return; return;
@ -241,7 +301,7 @@
}) })
} }
if (!this.dataset.idgroupe) { /*if (!this.dataset.idgroupe) {
// Partitions // Partitions
let groupesSelected = []; let groupesSelected = [];
this.parentElement.querySelectorAll(":not(.unselect)").forEach(e => { this.parentElement.querySelectorAll(":not(.unselect)").forEach(e => {
@ -257,39 +317,51 @@
e.classList.add("hide") e.classList.add("hide")
} }
}) })
} else { } else {*/
// Groupes // Groupes
let groupesSelected = {}; let groupesSelected = {};
this.parentElement.parentElement.querySelectorAll("[data-idgroupe]:not(.unselect)").forEach(e => { this.parentElement.parentElement.querySelectorAll("[data-idgroupe]:not(.unselect)").forEach(e => {
let idpartition = e.parentElement.dataset.idpartition; let idpartition = e.parentElement.dataset.idpartition;
if (!groupesSelected[idpartition]) { if (!groupesSelected[idpartition]) {
groupesSelected[idpartition] = []; groupesSelected[idpartition] = [];
} }
groupesSelected[idpartition].push(e.dataset.idgroupe) groupesSelected[idpartition].push(e.dataset.idgroupe)
}) })
document.querySelectorAll("#zoneChoix .etudiants>div").forEach(e => { document.querySelectorAll("#zoneChoix .etudiants>div").forEach(e => {
let found = true; let found = true;
Object.entries(groupesSelected).forEach(([idpartition, tabGroupes]) => { Object.entries(groupesSelected).forEach(([idpartition, tabGroupes]) => {
if (!tabGroupes.includes( if (!tabGroupes.includes(
e.querySelector(`[data-idpartition="${idpartition}"] input:checked`).value e.querySelector(`[data-idpartition="${idpartition}"] input:checked`).value
) )
) { ) {
found = false found = false
}
})
if (found) {
e.classList.remove("hide")
} else {
e.classList.add("hide")
} }
}) })
}
if (found) {
e.classList.remove("hide")
} else {
e.classList.add("hide")
}
})
//}
} }
/****************************/ /****************************/
/* Affectation à un groupe */ /* Affectation à un groupe */
/****************************/ /****************************/
function affectationGo(){
let from = document.querySelector("#affectationFrom").value;
let to = document.querySelector("#affectationTo").value;
if(!from || !to){
return;
}
document.querySelectorAll(`#zoneChoix .etudiants [value="${from}"]:checked`).forEach(groupeSelected=>{
groupeSelected.closest(".grpPartitions").querySelector(`[value="${to}"]`).click();
})
}
function assignment() { function assignment() {
let groupe = this.parentElement.parentElement.parentElement.parentElement; let groupe = this.parentElement.parentElement.parentElement.parentElement;
let nom = groupe.children[0].dataset.nom; let nom = groupe.children[0].dataset.nom;
@ -346,32 +418,12 @@
/****************************/ /****************************/
function addPartition() { function addPartition() {
let date = new Date; let date = new Date;
if (this.classList.contains("ajoutPartition")) {
// Partition
var name = "Nouvelle " + date.getSeconds();
let params = (new URL(document.location)).searchParams;
let formsemestre_id = params.get('formsemestre_id');
var url = "/ScoDoc/{{formsemestre.departement.acronym}}/api/formsemestre/" + formsemestre_id + "/partition/create";
var payload = { partition_name: name };
} else {
// Groupe
var name = "Nouveau " + date.getSeconds();
var url = `/ScoDoc/{{formsemestre.departement.acronym}}/api/partition/${this.parentElement.dataset.idpartition}/group/create`;
var payload = { group_name: name };
}
var div = document.createElement("div");
div.innerHTML = `
<span class="editing move">||</span>
<span>${name}</span>
<span class="editing modif">✏️</span>
<span class="editing suppr"></span>`;
div.querySelector(".modif").addEventListener("click", editText); var name = "Nouvelle " + date.getSeconds();
div.querySelector(".suppr").addEventListener("click", suppr); let params = (new URL(document.location)).searchParams;
div.querySelector(".move").addEventListener("mousedown", moveStart); let formsemestre_id = params.get('formsemestre_id');
this.parentElement.insertBefore(div, this); var url = "/ScoDoc/{{formsemestre.departement.acronym}}/api/formsemestre/" + formsemestre_id + "/partition/create";
var payload = { partition_name: name };
div.querySelector(".modif").click();
// Save // Save
fetch(url, fetch(url,
@ -390,76 +442,110 @@
div.remove(); div.remove();
return; return;
} }
if (this.classList.contains("ajoutPartition")) {
div.dataset.idpartition = r.id;
// Ajout dans la zone masques // Ajout dans la zone filtres
div = document.createElement("div"); let partition = {
div.dataset.idpartition = r.id; id: r.id,
div.innerHTML = ` partition_name: name
<div data-idpartition="${r.id}" data-idgroupe=aucun>Non affectés - ${name}</div>
<div class="editing ajoutGroupe">+</div>`;
div.querySelector("div").addEventListener("click", filtre);
div.querySelector(".ajoutGroupe").addEventListener("click", addPartition);
document.querySelector("#zonePartitions .masques>div").appendChild(div);
// Ajout de la zone pour chaque étudiant
let outputGroupes = "";
document.querySelectorAll("#zoneChoix .grpPartitions").forEach(e => {
let etudid = e.previousElementSibling.dataset.etudid;
// Préparation pour la section suivante
let etudiant = {
etudid: etudid,
nom_disp: e.previousElementSibling.dataset.nom,
prenom: e.previousElementSibling.dataset.prenom
}
outputGroupes += templateEtudiant_zoneGroupes(etudiant);
////////////////////////
let div = document.createElement("div");
div.className = "partition";
div.dataset.idpartition = r.id;
div.innerHTML = `
<div>${name}</div>
<label title="Aucun groupe">
<input type="radio" name="${r.id}-${etudid}" value="aucun" checked>
<span class="aucun"></span>
</label>
`;
div.querySelector("input").addEventListener("input", assignment);
e.appendChild(div);
});
// Ajout de la zone groupes
document.querySelector("#zoneGroupes>.groupes").innerHTML += `
<div class=partition data-idpartition="${r.id}">
<h3>${name}</h3>
<div class=groupe data-idgroupe=aucun>
<div>Non affecté(s)</div>
<div class=etudiants>${outputGroupes}</div>
</div>
</div>`;
} else {
div.dataset.idgroupe = r.id;
// Ajout du bouton pour chaque étudiant
let idpartition = this.parentElement.dataset.idpartition;
document.querySelectorAll(`#zoneChoix .etudiants [data-idpartition="${idpartition}"]`).forEach(e => {
let etudid = e.parentElement.parentElement.dataset.etudid;
let label = document.createElement("label");
label.innerHTML = `<input type=radio name="${idpartition}-${etudid}" value="${r.id}"><span>${name}</span>`;
label.querySelector("input").addEventListener("input", assignment);
e.appendChild(label);
})
// Ajout du groupe dans la zone Groupes
document.querySelector(`#zoneGroupes .partition[data-idpartition="${idpartition}"]`).innerHTML += templateGroupe_zoneGroupes(r.id, name);
} }
let divPartition = templateFiltres_partition(partition);
document.querySelector("#zonePartitions .filtres").appendChild(divPartition);
divPartition.querySelector(".modif").click();
// Ajout de la zone pour chaque étudiant
let outputGroupes = "";
document.querySelectorAll("#zoneChoix .grpPartitions").forEach(e => {
let etudid = e.previousElementSibling.dataset.etudid;
// Préparation pour la section suivante
let etudiant = {
etudid: etudid,
nom_disp: e.previousElementSibling.dataset.nom,
prenom: e.previousElementSibling.dataset.prenom
}
outputGroupes += templateEtudiant_zoneGroupes(etudiant);
////////////////////////
let div = document.createElement("div");
div.className = "partition";
div.dataset.idpartition = r.id;
div.innerHTML = `
<div>${name}</div>
<label title="Aucun groupe">
<input type="radio" name="${r.id}-${etudid}" value="aucun" checked>
<span class="aucun"></span>
</label>
`;
div.querySelector("input").addEventListener("input", assignment);
e.appendChild(div);
});
// Ajout de la zone groupes
document.querySelector("#zoneGroupes>.groupes").innerHTML += `
<div class=partition data-idpartition="${r.id}">
<h3>${name}</h3>
<div class=groupe data-idgroupe=aucun>
<div>Non affecté(s)</div>
<div class=etudiants>${outputGroupes}</div>
</div>
</div>`;
listeGroupesAutoaffectation();
})
.catch(error => {
document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données.</h2>";
})
}
function addGroupe() {
let date = new Date;
// Groupe
var name = "Nouveau " + date.getSeconds();
let idPartition = this.parentElement.previousElementSibling.dataset.idpartition;
var url = `/ScoDoc/{{formsemestre.departement.acronym}}/api/partition/${idPartition}/group/create`;
var payload = { group_name: name };
fetch(url,
{
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
})
.then(r => { return r.json() })
.then(r => {
if (r.message == "invalid partition_name" || r.message == "invalid group_name") {
message("Le nom " + name + " existe déjà");
return;
}
let groupe = {
id: r.id,
group_name: name
}
let divGroupe = templateFiltres_groupe(groupe);
this.parentElement.insertBefore(divGroupe, this);
// Ajout du bouton pour chaque étudiant
document.querySelectorAll(`#zoneChoix .etudiants [data-idpartition="${idPartition}"]`).forEach(e => {
let etudid = e.parentElement.previousElementSibling.dataset.etudid;
let label = document.createElement("label");
label.innerHTML = `<input type=radio name="${idPartition}-${etudid}" value="${r.id}"><span>${name}</span>`;
label.querySelector("input").addEventListener("input", assignment);
e.appendChild(label);
})
// Ajout du groupe dans la zone Groupes
document.querySelector(`#zoneGroupes .partition[data-idpartition="${idPartition}"]`).innerHTML += templateGroupe_zoneGroupes(r.id, name);
// Lancement de l'édition du nom
divGroupe.querySelector(".modif").click();
listeGroupesAutoaffectation();
}) })
.catch(error => { .catch(error => {
document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données.</h2>"; document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données.</h2>";
@ -474,6 +560,7 @@
e.classList.add("editingText"); e.classList.add("editingText");
e.setAttribute("contenteditable", "true"); e.setAttribute("contenteditable", "true");
e.addEventListener("keydown", writing); e.addEventListener("keydown", writing);
e.addEventListener("focusout", () => { saveEditing(this.previousElementSibling) });
// On sélectionne la zone // On sélectionne la zone
const range = document.createRange(); const range = document.createRange();
@ -506,7 +593,6 @@
var url = `/ScoDoc/{{formsemestre.departement.acronym}}/api/partition/${obj.parentElement.dataset.idpartition}/edit`; var url = `/ScoDoc/{{formsemestre.departement.acronym}}/api/partition/${obj.parentElement.dataset.idpartition}/edit`;
var payload = { partition_name: obj.innerText } var payload = { partition_name: obj.innerText }
document.querySelector(`.masques [data-idpartition="${obj.parentElement.dataset.idpartition}"][data-idgroupe="aucun"]`).innerText = "Non affectés - " + obj.innerText;
document.querySelectorAll(`#zoneChoix .etudiants [data-idpartition="${obj.parentElement.dataset.idpartition}"]>div`).forEach(e => { e.innerText = obj.innerText }); document.querySelectorAll(`#zoneChoix .etudiants [data-idpartition="${obj.parentElement.dataset.idpartition}"]>div`).forEach(e => { e.innerText = obj.innerText });
document.querySelector(`#zoneGroupes [data-idpartition="${obj.parentElement.dataset.idpartition}"]>h3`).innerText = obj.innerText; document.querySelector(`#zoneGroupes [data-idpartition="${obj.parentElement.dataset.idpartition}"]>h3`).innerText = obj.innerText;
} else { } else {
@ -531,6 +617,7 @@
if (!r) { if (!r) {
document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données.</h2>"; document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données.</h2>";
} }
listeGroupesAutoaffectation();
}) })
.catch(error => { .catch(error => {
document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données.</h2>"; document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données.</h2>";
@ -586,6 +673,7 @@
if (r.OK != true) { if (r.OK != true) {
document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données.</h2>"; document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données.</h2>";
} }
listeGroupesAutoaffectation();
}) })
} }
@ -600,14 +688,21 @@
function moveStart(event) { function moveStart(event) {
moveData.x = event.pageX; moveData.x = event.pageX;
moveData.y = event.pageY; moveData.y = event.pageY;
moveData.element = this.parentElement; if (this.parentElement.dataset.idpartition) {
moveData.element = this.parentElement.parentElement;
} else {
moveData.element = this.parentElement;
}
moveData.element.classList.add("moving"); moveData.element.classList.add("moving");
moveData.element.parentElement.classList.add('grabbing'); moveData.element.parentElement.classList.add('grabbing');
document.body.addEventListener("mousemove", move); 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); document.body.addEventListener("mouseup", moveEnd);
Array.from(moveData.element.parentElement.children).forEach(e => {
if ((e.dataset.idpartition && e.classname != "nonEditable") ||
(e.dataset.idgroupe != "aucun")) {
e.addEventListener("mouseup", newPosition)
}
})
} }
function move(event) { function move(event) {
@ -621,24 +716,28 @@
moveData.element.parentElement.classList.remove('grabbing'); moveData.element.parentElement.classList.remove('grabbing');
moveData.element.style.transform = ""; moveData.element.style.transform = "";
moveData.element.classList.remove("moving"); moveData.element.classList.remove("moving");
moveData.element.parentElement.querySelectorAll("div:not([data-idgroupe=aucun])").forEach(e => { Array.from(moveData.element.parentElement.children).forEach(e => {
e.removeEventListener("mouseup", newPosition) if ((e.dataset.idpartition && e.classname != "nonEditable") ||
(e.dataset.idgroupe && e.dataset.idgroupe != "aucun")) {
e.removeEventListener("mouseup", newPosition)
}
}) })
moveData = {}; moveData = {};
} }
function newPosition() { function newPosition(event) {
moveData.element.parentElement.insertBefore(moveData.element, this); moveData.element.parentElement.insertBefore(moveData.element, this);
let positions = []; let positions = [];
Array.from(moveData.element.parentElement.children).forEach(e => { Array.from(moveData.element.parentElement.children).forEach(e => {
if ((e.dataset.idpartition && e.dataset.idgroupe != "aucun") || (e.dataset.idgroupe && e.dataset.idgroupe != "aucun")) { if ((e.dataset.idpartition && e.classname != "nonEditable") ||
positions.push(parseInt(e.dataset.idgroupe || e.dataset.idpartition)) (e.dataset.idgroupe && e.dataset.idgroupe != "aucun")) {
positions.push(parseInt(e.dataset.idpartition || e.dataset.idgroupe))
} }
}) })
// Save positions // Save positions
if (this.parentElement.parentElement.parentElement.className == "partitions") { if (this.dataset.idpartition) {
let params = (new URL(document.location)).searchParams; let params = (new URL(document.location)).searchParams;
let formsemestre_id = params.get('formsemestre_id'); let formsemestre_id = params.get('formsemestre_id');
var url = `/ScoDoc/{{formsemestre.departement.acronym}}/api/formsemestre/${formsemestre_id}/partitions/order`; var url = `/ScoDoc/{{formsemestre.departement.acronym}}/api/formsemestre/${formsemestre_id}/partitions/order`;
@ -659,14 +758,15 @@
}) })
}) })
} else { } else {
var url = `/ScoDoc/{{formsemestre.departement.acronym}}/api/partition/${this.parentElement.dataset.idpartition}/groups/order`; let idPartition = this.closest("[data-idpartition]").dataset.idpartition;
var url = `/ScoDoc/{{formsemestre.departement.acronym}}/api/partition/${idPartition}/groups/order`;
document.querySelectorAll(`#zoneChoix .etudiants .partition[data-idpartition="${this.parentElement.dataset.idpartition}"]`).forEach(partition => { document.querySelectorAll(`#zoneChoix .etudiants .partition[data-idpartition="${idPartition}"]`).forEach(partition => {
positions.forEach(position => { positions.forEach(position => {
partition.append(partition.querySelector(`[value="${position}"]`).parentElement) partition.append(partition.querySelector(`[value="${position}"]`).parentElement)
}) })
}) })
document.querySelectorAll(`#zoneGroupes .partition[data-idpartition="${this.parentElement.dataset.idpartition}"]`).forEach(partition => { document.querySelectorAll(`#zoneGroupes .partition[data-idpartition="${idPartition}"]`).forEach(partition => {
positions.forEach(position => { positions.forEach(position => {
partition.append(partition.querySelector(`[data-idgroupe="${position}"]`)) partition.append(partition.querySelector(`[data-idgroupe="${position}"]`))
}) })
@ -687,11 +787,11 @@
if (!r) { if (!r) {
document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données.</h2>"; document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données.</h2>";
} }
listeGroupesAutoaffectation();
}) })
.catch(error => { .catch(error => {
document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données.</h2>"; document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données.</h2>";
}) })
} }
/*************************/ /*************************/