Nouvelle version table_editor (via Seb. L.)

This commit is contained in:
Emmanuel Viennet 2021-11-13 09:11:00 +01:00
parent c0dd83fadb
commit 477c2efac9
3 changed files with 161 additions and 111 deletions

View File

@ -10,84 +10,50 @@ body {
.tableau{ .tableau{
display: grid; display: grid;
grid-auto-rows: minmax(24px, auto); grid-auto-rows: minmax(24px, auto);
gap: 2px;
} }
.entete{ .entete{
background: #09c; background: #09c;
font-weight: bold; font-weight: bold;
} }
.tableau>div{ .tableau>div{
padding: 4px; padding: 4px 8px;
border-radius: 4px;
border: 1px solid #999; border: 1px solid #999;
grid-column: var(--x) / span var(--nbX); grid-column: var(--x) / span var(--nbX);
grid-row: var(--y) / span var(--nbY); grid-row: var(--y) / span var(--nbY);
} }
/***************************/ [data-editable="true"]{
/* Attente */
/***************************/
.wait {
position: fixed;
top: 32px;
left: 50%;
height: 4px;
width: 32px;
margin-left: -16px;
background: #424242;
animation: attente 0.4s infinite alternate;
display: none;
}
.go {
display: block;
}
@keyframes attente {
100% {
transform: translateY(-16px) rotate(360deg);
}
}
/***************************/
/* Système de modification */
/***************************/
.modifOnOff {
position: relative;
display: table;
margin: 16px;
padding-right: 8px;
cursor: pointer; cursor: pointer;
} }
.modifOnOff::before { /***************************/
content: ''; /* Statut des cellules */
width: 40px; /***************************/
height: 20px; .selected{ outline: 1px solid #c09; }
background: #c90; .modifying{ outline: 2px dashed #c09; }
position: absolute; .wait{ outline: 2px solid #c90; }
top: 0; .good{ outline: 2px solid #9c0; }
left: 100%;
border-radius: 20px;
transition: 0.2s;
}
.modifOnOff::after { /***************************/
content: ''; /* Message */
width: 16px; /***************************/
height: 16px; .message{
background: #FFF; position: fixed;
position: absolute; bottom: 100%;
top: 2px; left: 50%;
left: calc(100% + 2px); z-index: 10;
border-radius: 100%; padding: 20px;
transition: 0.2s; border-radius: 0 0 10px 10px;
background: #ec7068;
background: #90c;
color: #FFF;
font-size: 24px;
animation: message 3s;
transform: translate(-50%, 0);
} }
@keyframes message{
.modifOnOff.active::before { 20%{transform: translate(-50%, 100%)}
background: #9c0; 80%{transform: translate(-50%, 100%)}
}
.modifOnOff.active::after {
transform: translateX(20px);
} }

View File

@ -1,34 +1,6 @@
/* table_editor, par Sébastien L. /* table_editor, par Sébastien L. 2021-11-12
*/ */
/******************************/
/* Gestion de la modification */
/******************************/
function editableOnOff() {
if (this.classList.toggle("active")) {
document.querySelectorAll("[data-editable=true]").forEach(cellule => {
cellule.contentEditable = true;
cellule.addEventListener("input", delayBeforeSave);
cellule.addEventListener("blur", save);
})
} else {
document.querySelectorAll("[data-editable=true]").forEach(cellule => {
cellule.removeAttribute("contentEditable");
cellule.removeEventListener("input", delayBeforeSave);
cellule.removeEventListener("blur", save);
})
}
}
let timeout = 0;
function delayBeforeSave() {
clearTimeout(timeout);
document.querySelector(".wait").classList.add("go");
timeout = setTimeout(() => { save(this) }, 2000);
}
/*****************************/ /*****************************/
/* Mise en place des données */ /* Mise en place des données */
/*****************************/ /*****************************/
@ -38,19 +10,117 @@ function build_table(data) {
data.forEach((cellule) => { data.forEach((cellule) => {
output += ` output += `
<div <div
class="${cellule.style}" class="${cellule.style || ""}"
data-editable="${cellule.editable || "false"}" data-editable="${cellule.editable || "false"}"
data-module_id="${cellule.module_id}" data-module_id="${cellule.module_id}"
data-ue_id="${cellule.ue_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}"
style=" style="
--x:${cellule.x}; --x:${cellule.x};
--y:${cellule.y}; --y:${cellule.y};
--nbX:${cellule.nbX}; --nbX:${cellule.nbX || 1};
--nbY: ${cellule.nbY}; --nbY: ${cellule.nbY || 1};
"> ">
${cellule.data} ${cellule.data}
</div>`; </div>`;
}) })
document.querySelector(".tableau").innerHTML = output; document.querySelector(".tableau").innerHTML = output;
document.querySelector(".modifOnOff").addEventListener("click", editableOnOff); installListeners();
}
/*****************************/
/* Gestion des évènements */
/*****************************/
$(function () {
document.body.addEventListener("keydown", key);
});
function installListeners() {
document.querySelectorAll("[data-editable=true]").forEach(cellule => {
cellule.addEventListener("click", function () { selectCell(this) });
cellule.addEventListener("dblclick", function () { modifCell(this) });
});
}
/*********************************/
/* 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");
ArrowMove(0, 1);
}
}
/******************************/
/* 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);
} }

View File

@ -15,8 +15,6 @@
<h2>Formation {{formation.titre}} ({{formation.acronyme}}) <h2>Formation {{formation.titre}} ({{formation.acronyme}})
[version {{formation.version}}] code {{formation.code}}</h2> [version {{formation.version}}] code {{formation.code}}</h2>
<div class=wait></div>
<div class=modifOnOff>Modifier</div>
<div class="tableau"></div> <div class="tableau"></div>
<script> <script>
@ -26,15 +24,24 @@
}); });
}); });
function save(obj) { function save(obj) {
if (event?.currentTarget) { var value = obj.innerText.trim();
obj = event.currentTarget; if (value.length == 0) {
value = "0";
} }
document.querySelector(".wait").classList.remove("go"); if (!/^\d+$/.test(value)) {
message("Il est attendu un nombre");
return false;
}
if (value == obj.dataset.data) {
return true; // Aucune modification, pas d'enregistrement mais on continue normalement
}
obj.dataset.data = value;
obj.classList.add("wait");
// XXX DEBUG // XXX DEBUG
console.log(` console.log(`
x : ${getComputedStyle(obj).getPropertyValue("--x")} x : ${getComputedStyle(obj).getPropertyValue("--x")}
y : ${getComputedStyle(obj).getPropertyValue("--y")} y : ${getComputedStyle(obj).getPropertyValue("--y")}
data : ${obj.innerText} data : ${value}
ue_id: ${obj.dataset.ue_id} ue_id: ${obj.dataset.ue_id}
module_id : ${obj.dataset.module_id} module_id : ${obj.dataset.module_id}
`); `);
@ -42,10 +49,17 @@
{ {
module_id: `${obj.dataset.module_id}`, module_id: `${obj.dataset.module_id}`,
ue_id: `${obj.dataset.ue_id}`, ue_id: `${obj.dataset.ue_id}`,
coef: `${obj.innerText}` coef: `${value}`
}, },
function (result) { function (result) {
console.log("enregistré"); console.log("enregistré"); // XXX
obj.classList.remove("wait");
obj.classList.add("good");
// Lorsque les données sont bien enregistrés, on enlève
// l'indication que c'est bon au bout d'un temps
setTimeout(() => {
obj.classList.remove("good");
}, 1000);
} }
); );
} }