ScoDoc/app/static/js/table_editor.js

268 lines
7.0 KiB
JavaScript

/* table_editor, par Sébastien L. 2021-11-12
*/
/*****************************/
/* Mise en place des données */
/*****************************/
let lastX;
let lastY;
function build_table(data) {
let output = "";
let sumsUE = {};
let sumsRessources = {};
let value;
data.forEach((cellule) => {
output += `
<div
class="${cellule.style || ""}"
data-editable="${cellule.editable || "false"}"
data-module_id="${cellule.module_id}"
data-ue_id="${cellule.ue_id}"
data-x="${cellule.x}"
data-y="${cellule.y}"
data-nbX="${cellule.nbX || 1}"
data-nbY="${cellule.nbY || 1}"
data-data="${cellule.data}"
data-orig="${cellule.data}"
title="${cellule.title || ""}"
style="
--x:${cellule.x};
--y:${cellule.y};
--nbX:${cellule.nbX || 1};
--nbY: ${cellule.nbY || 1};
">${cellule.data}</div>`; // ne pas mettre d'espace car c'est utilisé par :not(:empty) après
if (cellule.style.includes("champs")) {
if (cellule.editable == true && cellule.data) {
value = parseFloat(cellule.data) * 100;
} else {
value = 0;
}
sumsRessources[cellule.y] = (sumsRessources[cellule.y] ?? 0) + value;
sumsUE[cellule.x] = (sumsUE[cellule.x] ?? 0) + value;
}
});
output += showSums(sumsRessources, sumsUE);
document.querySelector(".tableau").innerHTML = output;
installListeners();
}
function showSums(sumsRessources, sumsUE) {
lastX = Object.keys(sumsUE).length + 2;
lastY = Object.keys(sumsRessources).length + 2;
let output = "";
Object.entries(sumsUE).forEach(([num, value]) => {
output += `
<div
class="sums"
data-editable="false"
data-x="${num}"
data-y="${lastY}"
style="
--x:${num};
--y:${lastY};
--nbX:1;
--nbY:1;
">
${(value / 100).toLocaleString(undefined, {
minimumFractionDigits: 0,
maximumFractionDigits: 2,
})}
</div>`;
});
Object.entries(sumsRessources).forEach(([num, value]) => {
output += `
<div
class="sums"
data-editable="false"
data-x="${lastX}"
data-y="${num}"
style="
--x:${lastX};
--y:${num};
--nbX:1;
--nbY:1;
">
${(value / 100).toLocaleString(undefined, {
minimumFractionDigits: 0,
maximumFractionDigits: 2,
})}
</div>`;
});
return output;
}
/*****************************/
/* Gestion des évènements */
/*****************************/
function installListeners() {
if (read_only) {
return;
}
document.body.addEventListener("keydown", key);
document.querySelectorAll("[data-editable=true]").forEach((cellule) => {
cellule.addEventListener("click", function () {
selectCell(this);
});
cellule.addEventListener("dblclick", function () {
modifCell(this);
});
cellule.addEventListener("blur", function () {
let currentModif = document.querySelector(".modifying");
if (currentModif) {
if (!save(currentModif)) {
return;
}
}
});
cellule.addEventListener("input", processSums);
});
}
/*********************************/
/* Interaction avec les cellules */
/*********************************/
function selectCell(obj) {
if (obj.classList.contains("modifying")) {
return; // Cellule en cours de modification, ne pas sélectionner.
}
let currentModif = document.querySelector(".modifying");
if (currentModif) {
if (!save(currentModif)) {
return;
}
}
document.querySelectorAll(".selected, .modifying").forEach((cellule) => {
cellule.classList.remove("selected", "modifying");
cellule.removeAttribute("contentEditable");
cellule.removeEventListener("keydown", keyCell);
});
obj.classList.add("selected");
}
function modifCell(obj) {
if (obj) {
obj.classList.add("modifying");
obj.contentEditable = true;
obj.addEventListener("keydown", keyCell);
obj.focus();
}
}
function key(event) {
switch (event.key) {
case "Enter":
modifCell(document.querySelector(".selected"));
event.preventDefault();
break;
case "ArrowRight":
ArrowMove(1, 0);
break;
case "ArrowLeft":
ArrowMove(-1, 0);
break;
case "ArrowUp":
ArrowMove(0, -1);
break;
case "ArrowDown":
ArrowMove(0, 1);
break;
}
}
function ArrowMove(x, y) {
if (
document.querySelector(".modifying") ||
!document.querySelector(".selected")
) {
return; // S'il n'y a aucune cellule selectionnée ou si une cellule est encours de modification, on ne change pas
}
let selected = document.querySelector(".selected");
let next = document.querySelector(
`[data-x="${parseInt(selected.dataset.x) + x}"][data-y="${
parseInt(selected.dataset.y) + y
}"][data-editable="true"]`
);
if (next) {
selectCell(next);
}
}
function keyCell(event) {
if (event.key == "Enter") {
event.preventDefault();
event.stopPropagation();
if (!save(this)) {
return;
}
this.classList.remove("modifying");
let selected = document.querySelector(".selected");
ArrowMove(0, 1);
if (selected != document.querySelector(".selected")) {
modifCell(document.querySelector(".selected"));
}
}
}
function processSums() {
let sum = 0;
document
.querySelectorAll(
`[data-editable="true"][data-x="${this.dataset.x}"]:not(:empty)`
)
.forEach((e) => {
let val = parseFloat(e.innerText);
if (!isNaN(val)) {
sum += val * 100;
}
});
document.querySelector(
`.sums[data-x="${this.dataset.x}"][data-y="${lastY}"]`
).innerText = (sum / 100).toLocaleString(undefined, {
minimumFractionDigits: 0,
maximumFractionDigits: 2,
});
sum = 0;
document
.querySelectorAll(
`[data-editable="true"][data-y="${this.dataset.y}"]:not(:empty)`
)
.forEach((e) => {
let val = parseFloat(e.innerText);
if (!isNaN(val)) {
sum += val * 100;
}
});
document.querySelector(
`.sums[data-x="${lastX}"][data-y="${this.dataset.y}"]`
).innerText = (sum / 100).toLocaleString(undefined, {
minimumFractionDigits: 0,
maximumFractionDigits: 2,
});
}
/******************************/
/* Affichage d'un message */
/******************************/
function message(msg) {
var div = document.createElement("div");
div.className = "message";
div.innerHTML = msg;
document.querySelector("body").appendChild(div);
setTimeout(() => {
div.remove();
}, 3000);
}