ScoDoc/app/templates/scolar/partition_editor.j2
2023-08-09 08:19:06 +02:00

945 lines
32 KiB
Django/Jinja

{# -*- mode: jinja-html -*- #}
<h1>{% if not read_only %}Édition des p{% else %}P{%endif%}artitions</h1>
<main>
<div class="wait"></div>
<section id="zonePartitions">
<h2>Filtres</h2>
<div>
<label class="edition">
<input type="checkbox" autocomplete="off" id="inputModif">
Modifier les partitions et groupes
</label>
<div class="filtres"></div>
<div style="display: flex; justify-content: space-between;">
<div class="editing ajoutPartition">Ajouter une partition</div>
<label class="editing valider" for="inputModif">Fini</label>
</div>
</div>
</section>
<section id="zoneChoix">
<h2>Étudiants</h2>
<details>
<summary>Outils d'affectation</summary>
<div class="autoAffectation">
<a href="students_groups_auto_assignment?formsemestre_id={{formsemestre.id}}"><svg
xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none"
stroke="#0b0b0b" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
<path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4M10 17l5-5-5-5M13.8 12H3" />
</svg> Aide à l'affectation dans les parcours</a>
<div>Importer les résultats :
<form class=dropZone>
<div>
Déposez le fichier .xlsx ou <br>
<label>
<input type=file accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet">
</label>
</div>
</form>
</div>
</div>
<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 class="progress">
<div></div>
</div>
</div>
</details>
<div class="etudiants"></div>
</section>
<section id="zoneGroupes">
<h2>Groupes</h2>
<div class="groupes"></div>
</section>
</main>
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx-populate/1.21.0/xlsx-populate.min.js"></script>
<script>
go();
async function go() {
document.querySelector('.wait').style.display = "";
let params = (new URL(document.location)).searchParams;
let formsemestre_id = params.get('formsemestre_id');
let partitions = await fetchData("/ScoDoc/{{formsemestre.departement.acronym}}/api/formsemestre/" + formsemestre_id + "/partitions");
let etudiants = await fetchData("/ScoDoc/{{formsemestre.departement.acronym}}/api/formsemestre/" + formsemestre_id + "/resultats");
etudiants.sort((a, b) => {
return a.nom_short.localeCompare(b.nom_short)
})
processDatas(partitions, etudiants);
processEvents();
listeGroupesAutoaffectation();
document.querySelector("body").classList.add("loaded");
document.querySelector('.wait').style.display = "none";
{% if edit_partition %}
setEditMode();
{% endif %}
}
function fetchData(request) {
return fetch(request)
.then(r => { return r.json() })
.then(data => {
return data;
}).catch(error => {
document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors du transfert des données.</h2>";
throw 'Fin du script - données invalides';
})
}
function processDatas(partitions, etudiants) {
/* Filtres et groupes */
let divFiltres = document.querySelector(".filtres");
let outputGroupes = "";
let arrayPartitions = Object.values(partitions).sort((a, b) => {
return a.numero - b.numero;
})
arrayPartitions.forEach((partition) => {
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
outputGroupes += `
<div class=partition data-idpartition="${partition.id}">
<h3>${partition.partition_name}</h3>
<div class=groupe data-idgroupe=aucun>
<div>Non affecté(s)</div>
<div class=etudiants></div>
</div>
${(() => {
let arrayGroups = Object.values(partition.groups).sort((a, b) => {
return a.numero - b.numero;
})
let output = "";
arrayGroups.forEach((groupe) => {
output += templateGroupe_zoneGroupes(groupe.id, groupe.group_name);
})
return output;
})()}
</div>`;
})
document.querySelector("#zoneGroupes>.groupes").innerHTML = outputGroupes;
/* Etudiants */
output = "";
etudiants.forEach(etudiant => {
output += `
<div data-etudid="${etudiant.etudid}" >
<div class=nom data-etudid="${etudiant.etudid}" data-nom="${etudiant.nom_disp}" data-prenom="${etudiant.prenom}"><a href="ficheEtud?etudid=${etudiant.etudid}">${etudiant.nom_disp} ${etudiant.prenom}</a><div class=small>${etudiant.bac}</div></div>
${(() => {
let output = "<div class=grpPartitions>";
arrayPartitions.forEach((partition) => {
output += `
<div class=partition data-idpartition="${partition.id}">
<div>${partition.partition_name}</div>
${(() => {
let output = "";
let affected = false;
let arrayGroups = Object.values(partition.groups).sort((a, b) => {
return a.numero - b.numero;
})
arrayGroups.forEach((groupe) => {
output += `
<label><input type=radio name="${partition.id}-${etudiant.etudid}" value="${groupe.id}" ${(etudiant.partitions[partition.id] == groupe.id) ? "checked" : ""}><span data-grpname="${groupe.group_name}">${groupe.group_name}</span></label>`;
if (etudiant.partitions[partition.id] == groupe.id) {
affected = true;
document.querySelector(`#zoneGroupes [data-idgroupe="${groupe.id}"]>.etudiants`).innerHTML += templateEtudiant_zoneGroupes(etudiant);
}
})
if (!affected) {
document.querySelector(`#zoneGroupes [data-idpartition="${partition.id}"]>[data-idgroupe="aucun"]>.etudiants`).innerHTML += templateEtudiant_zoneGroupes(etudiant);
}
return `<label title="Aucun groupe"><input type=radio name="${partition.id}-${etudiant.etudid}" value="aucun" ${(!affected) ? "checked" : ""}><span class=aucun> - </span></label>` + output;
})()}
</div>`;
})
return output + "</div>";
})()}
</div>`;
})
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>
<button class="dt-button" data-idgroupe=aucun>
Non affectés
</button>
<div class="editing ajoutGroupe">+</div>
</div>
<!-- Config -->
<div class=config>
Configuration
<hr>
<label title="Calculer et afficher les rangs dans les groupes de cette partition ?">
<input class=rang type=checkbox ${partition.bul_show_rank ? "checked" : ""} data-attr=bul_show_rank> Rang bulletins
</label>
<label title="Doit-on afficher les groupes de cette partition dans les listes ?">
<input class=groupe type=checkbox ${partition.show_in_lists ? "checked" : ""} data-attr=show_in_lists> Afficher sur bulletins et tableaux
</label>
<label>
<a class="stdlink" href="/ScoDoc/{{formsemestre.departement.acronym}}/Scolarite/groups_auto_repartition?partition_id=${partition.id}">Répartir les étudiants</a>
</label>
</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);
div.querySelector(".rang").addEventListener("input", setAttribute);
div.querySelector(".groupe").addEventListener("input", setAttribute);
return div;
}
function templateFiltres_groupe(groupe) {
let div = document.createElement("button");
div.classList.add("dt-button");
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) {
return `<div class=groupe data-idgroupe="${idGroupe}">
<div>${name}</div>
<div class=etudiants></div>
</div>`;
}
function templateEtudiant_zoneGroupes(etudiant) {
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}">
<option value="non-${partition.dataset.idpartition}">Non affectés ${partition.children[0].children[1].innerText}</option>`;
partition.querySelectorAll('[data-idgroupe]:not([data-idgroupe="aucun"])').forEach(groupe => {
output += `<option value=${groupe.dataset.idgroupe}>${groupe.children[1].innerText}</option>`;
})
output += "</optgroup>";
})
document.querySelector("#affectationFrom").innerHTML = output;
document.querySelector("#affectationTo").innerHTML = output;
}
/******************************/
/* Gestionnaire d'événements */
/******************************/
function setEditMode() {
let editing = document.querySelector("[contentEditable=true]");
if (!editing) {
document.querySelector("body").classList.toggle("editionActivated");
return;
}
this.checked = true;
if (!editing.classList.contains("highlight")) {
editing.classList.add("highlight");
setTimeout(() => { editing.classList.remove("highlight") }, 1000);
}
}
function processEvents() {
/*--------------------*/
/* Edition partitions */
/*--------------------*/
document.querySelector(".edition>input").addEventListener("input", setEditMode);
document.querySelectorAll(".ajoutPartition").forEach(btnPlus => { btnPlus.addEventListener("click", addPartition) })
/*--------------------*/
/* Changement groupe */
/*--------------------*/
document.querySelectorAll("label").forEach(btn => { btn.addEventListener("mousedown", (event) => { event.preventDefault() }) });
document.querySelectorAll(".etudiants input").forEach(input => { input.addEventListener("input", assignment) })
document.querySelector(".affectationGo").addEventListener("click", affectationGo);
}
/**********************/
/* Filtrage */
/**********************/
function masquerPartitions() {
let idPartition = this.closest("[data-idpartition]").dataset.idpartition;
document.querySelectorAll(`[data-idpartition="${idPartition}"]`).forEach(e => {
e.classList.toggle("hide");
})
}
function filtre() {
if (document.querySelector("body").classList.contains("editionActivated")) {
return;
}
let nbUnselected = this.parentElement.querySelectorAll(".unselect").length;
let nbBtn = this.parentElement.children.length;
if (nbUnselected == 0) {
Array.from(this.parentElement.children).forEach(e => {
e.classList.toggle("unselect");
})
}
this.classList.toggle("unselect");
nbUnselected = this.parentElement.querySelectorAll(".unselect").length;
if (nbUnselected == nbBtn) {
Array.from(this.parentElement.children).forEach(e => {
e.classList.toggle("unselect");
})
}
// Groupes
let groupesSelected = {};
document.querySelectorAll(".filtres [data-idgroupe]:not(.unselect)").forEach(e => {
let idpartition = e.closest("[data-idpartition]").dataset.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
)
) {
found = false
}
})
if (found) {
e.classList.remove("hide")
} else {
e.classList.add("hide")
}
})
}
/*****************************************/
/* Import des résultats auto affectation */
/*****************************************/
document.querySelector(".dropZone").addEventListener("drop", dropFile);
document.querySelector(".dropZone input").addEventListener("change", dropFile);
document.querySelector(".dropZone").addEventListener("dragover", dragOver);
document.querySelector(".dropZone").addEventListener("dragleave", dragLeave);
function dropFile(event) {
event.preventDefault();
this.classList.remove("fileOver");
if (event.target.files?.[0] || event.dataTransfer.items[0].type.match('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')) {
let file = event.target.files?.[0] || event.dataTransfer.items[0].getAsFile();
let reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onloadend = () => {
manageFile(reader.result)
}
}
}
function manageFile(file) {
XlsxPopulate.fromDataAsync(file)
.then(function (workbook) {
const sheet = workbook.sheet(0);
let ligne = 1;
let colonne = 1;
let parcours;
let etudid;
while (parcours = sheet.row(ligne).cell(colonne).value()) {
ligne += 2;
while (etudid = sheet.row(ligne).cell(colonne).value()) {
console.log(parcours, etudid);
document.querySelector(`#zoneChoix .etudiants [data-etudid="${etudid}"] [data-grpname="${parcours}"]`)?.click();
ligne++;
}
ligne = 1;
colonne += 3;
}
})
}
function dragOver(event) {
event.preventDefault();
this.classList.add("fileOver")
}
function dragLeave() {
this.classList.remove("fileOver")
}
/****************************/
/* Affectation à un groupe */
/****************************/
var progressNb = 0;
var progressRef = 0;
function affectationGo() {
let from = document.querySelector("#affectationFrom").value;
let to = document.querySelector("#affectationTo").value;
if (!from || !to) {
return;
}
let elements = [];
if (from[0] != "n") {
elements = document.querySelectorAll(`#zoneChoix .etudiants [value="${from}"]:checked`)
} else {
document.querySelectorAll(`#zoneChoix .etudiants [data-idpartition="${from.split("-")[1]}"]`).forEach(element => {
if (!element.querySelector('input:not([value="aucun"]):checked')) {
elements.push(element);
}
})
}
let progress = document.querySelector("#zoneChoix .autoAffectation .progress");
if (elements.length > 1) {
progress.style.setProperty('--reference', elements.length);
progress.style.setProperty('--nombre', 0);
progressRef = elements.length;
progressNb = 0;
}
elements.forEach(groupeSelected => {
if (to[0] != "n") {
groupeSelected.closest(".grpPartitions").querySelector(`[value="${to}"]`).click();
} else {
groupeSelected.closest(".grpPartitions").querySelector(`[value="aucun"]`).click();
}
})
}
function assignment() {
let groupe = this.parentElement.parentElement.parentElement.parentElement;
let nom = groupe.children[0].dataset.nom;
let prenom = groupe.children[0].dataset.prenom;
let etudid = groupe.children[0].dataset.etudid;
let idPartition = this.parentElement.parentElement.dataset.idpartition;
let idGroupe = this.value;
document.querySelector(`#zoneGroupes [data-idPartition="${idPartition}"] [data-etudid="${etudid}"]`).remove();
let etudiant = {
etudid: etudid,
nom_disp: nom,
prenom: prenom
}
let results = document.querySelector(`#zoneGroupes [data-idPartition="${idPartition}"] [data-idgroupe="${idGroupe}"]>.etudiants`);
results.innerHTML += templateEtudiant_zoneGroupes(etudiant);
/* Tri */
let results2 = [...results.children];
results2.sort((a, b) => {
return (a.dataset.nom + a.dataset.prenom).localeCompare(b.dataset.nom + b.dataset.prenom)
})
results.innerHTML = "";
results.append(...results2);
/* Save */
this.classList.add("saving");
if (idGroupe == "aucun") {
var url = `/ScoDoc/{{formsemestre.departement.acronym}}/api/partition/${idPartition}/remove_etudiant/${etudid}`;
} else {
var url = `/ScoDoc/{{formsemestre.departement.acronym}}/api/group/${idGroupe}/set_etudiant/${etudid}`
}
fetch(url, { method: "POST" })
.then(r => { return r.json() })
.then(r => {
if (r.etudid == etudid) {
this.classList.remove("saving");
this.classList.add("saved");
setTimeout(() => { this.classList.remove("saved") }, 800);
let progress = document.querySelector("#zoneChoix .autoAffectation .progress");
progress.style.setProperty('--nombre', ++progressNb);
if (progressNb == progressRef) {
sco_message("Tous les étudiants sont affectés");
}
return;
}
throw 'Les données retournées ne sont pas valides';
})
.catch(error => {
document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données.</h2>";
})
}
/****************************/
/* Ajout partition / groupe */
/****************************/
function addPartition() {
let date = new Date;
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 };
// Save
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") {
sco_message("Le nom " + name + " existe déjà");
div.remove();
return;
}
// Ajout dans la zone filtres
let partition = {
id: r.id,
partition_name: 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") {
sco_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 => {
document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données.</h2>";
})
}
/********************/
/* Edition du texte */
/********************/
function editText() {
let e = this.previousElementSibling;
e.classList.add("editingText");
e.setAttribute("contenteditable", "true");
e.addEventListener("keydown", writing);
e.addEventListener("focusout", () => { saveEditing(this.previousElementSibling) });
// On sélectionne la zone
const range = document.createRange();
const selection = window.getSelection();
selection.removeAllRanges();
range.selectNodeContents(e);
selection.addRange(range);
}
function writing(event) {
switch (event.key) {
case 'Enter':
saveEditing(this);
event.preventDefault();
break;
case 'Escape':
saveEditing(this);
event.preventDefault();
break;
}
}
function saveEditing(obj) {
// Vérification que le champ est non vide
if (obj.innerText == "") {
event.preventDefault();
sco_message("Ce champ ne peut rester vide.");
obj.focus();
return;
}
// Fin de l'édition
obj.classList.remove("editingText");
obj.setAttribute("contenteditable", "false");
obj.removeEventListener("keydown", writing);
// Save
if (obj.parentElement.dataset.idpartition) {
var url = `/ScoDoc/{{formsemestre.departement.acronym}}/api/partition/${obj.parentElement.dataset.idpartition}/edit`;
var payload = { partition_name: 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;
} else {
var url = `/ScoDoc/{{formsemestre.departement.acronym}}/api/group/${obj.parentElement.dataset.idgroupe}/edit`;
var payload = { group_name: obj.innerText }
document.querySelectorAll(`#zoneChoix .etudiants [value="${obj.parentElement.dataset.idgroupe}"]+span`).forEach(e => { e.innerText = obj.innerText });
document.querySelector(`#zoneGroupes [data-idgroupe="${obj.parentElement.dataset.idgroupe}"]>div`).innerText = obj.innerText;
}
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) {
document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données.</h2>";
}
listeGroupesAutoaffectation();
})
.catch(error => {
document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données.</h2>";
})
}
/*********************************/
/* 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 = `
<div>
<h1>Vous être sur le point de supprimer <span>${this.previousElementSibling.previousElementSibling.innerText}</span>,<br>cette opération est irréversible</h1>
<div>
<div class="ok" ${data}>Supprimer</div>
<div class="nok">Annuler</div>
</div>
</div>
`;
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() })
var url = "/ScoDoc/{{formsemestre.departement.acronym}}/api/partition/" + this.dataset.idpartition + "/delete";
} 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() })
var url = "/ScoDoc/{{formsemestre.departement.acronym}}/api/group/" + this.dataset.idgroupe + "/delete";
}
//Save
fetch(url, { method: "POST" })
.then(r => { return r.json() })
.then(r => {
if (r.OK != true) {
document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données.</h2>";
}
listeGroupesAutoaffectation();
})
}
function closeConfirm() {
document.querySelector(".confirm").remove();
}
/*************************/
/* Changement de l'ordre */
/*************************/
let moveData = {};
function moveStart(event) {
moveData.x = event.pageX;
moveData.y = event.pageY;
if (this.parentElement.dataset.idpartition) {
moveData.element = this.parentElement.parentElement;
} else {
moveData.element = this.parentElement;
}
moveData.element.classList.add("moving");
moveData.element.parentElement.classList.add('grabbing');
document.body.addEventListener("mousemove", move);
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) {
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");
Array.from(moveData.element.parentElement.children).forEach(e => {
if ((e.dataset.idpartition && e.classname != "nonEditable") ||
(e.dataset.idgroupe && e.dataset.idgroupe != "aucun")) {
e.removeEventListener("mouseup", newPosition)
}
})
moveData = {};
}
function newPosition(event) {
moveData.element.parentElement.insertBefore(moveData.element, this);
let positions = [];
Array.from(moveData.element.parentElement.children).forEach(e => {
if ((e.dataset.idpartition && e.classname != "nonEditable") ||
(e.dataset.idgroupe && e.dataset.idgroupe != "aucun")) {
positions.push(parseInt(e.dataset.idpartition || e.dataset.idgroupe))
}
})
// Save positions
if (this.dataset.idpartition) {
let params = (new URL(document.location)).searchParams;
let formsemestre_id = params.get('formsemestre_id');
var url = `/ScoDoc/{{formsemestre.departement.acronym}}/api/formsemestre/${formsemestre_id}/partitions/order`;
document.querySelectorAll(`#zonePartitions .masques>div`).forEach(parent => {
positions.forEach(position => {
parent.append(parent.querySelector(`[data-idpartition="${position}"]`))
})
})
document.querySelectorAll(`#zoneChoix .grpPartitions`).forEach(parent => {
positions.forEach(position => {
parent.append(parent.querySelector(`[data-idpartition="${position}"]`))
})
})
document.querySelectorAll(`#zoneGroupes>.groupes`).forEach(parent => {
positions.forEach(position => {
parent.append(parent.querySelector(`[data-idpartition="${position}"]`))
})
})
} else {
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="${idPartition}"]`).forEach(partition => {
positions.forEach(position => {
partition.append(partition.querySelector(`[value="${position}"]`).parentElement)
})
})
document.querySelectorAll(`#zoneGroupes .partition[data-idpartition="${idPartition}"]`).forEach(partition => {
positions.forEach(position => {
partition.append(partition.querySelector(`[data-idgroupe="${position}"]`))
})
})
}
fetch(url,
{
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(positions)
})
.then(r => { return r.json() })
.then(r => {
if (!r) {
document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données.</h2>";
}
listeGroupesAutoaffectation();
})
.catch(error => {
document.querySelector("main").innerHTML = "<h2>Une erreur s'est produite lors de la sauvegarde des données.</h2>";
})
}
/*****************/
/* Config */
/*****************/
function setAttribute() {
fetch("partition_set_attr",
{
method: "post",
headers: {
"Content-type": "application/x-www-form-urlencoded; charset=UTF-8"
},
body: `partition_id=${this.closest("[data-idpartition]").dataset.idpartition}&attr=${this.dataset.attr}&value=${this.checked ? 1 : 0}`
}
).then(function (response) {
return response.text();
})
.then(function (txt) {
sco_message(txt);
});
}
</script>