/* 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); }