forked from ScoDoc/ScoDoc
Nouvelle version table_editor (via Seb. L.)
This commit is contained in:
parent
c0dd83fadb
commit
477c2efac9
@ -7,87 +7,53 @@ body {
|
||||
/***************************/
|
||||
/* Le tableau */
|
||||
/***************************/
|
||||
.tableau {
|
||||
.tableau{
|
||||
display: grid;
|
||||
grid-auto-rows: minmax(24px, auto);
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.entete {
|
||||
.entete{
|
||||
background: #09c;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.tableau>div {
|
||||
padding: 4px;
|
||||
.tableau>div{
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #999;
|
||||
grid-column: var(--x) / span var(--nbX);
|
||||
grid-row: var(--y) / span var(--nbY);
|
||||
}
|
||||
|
||||
/***************************/
|
||||
/* 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;
|
||||
[data-editable="true"]{
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.modifOnOff::before {
|
||||
content: '';
|
||||
width: 40px;
|
||||
height: 20px;
|
||||
background: #c90;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 100%;
|
||||
border-radius: 20px;
|
||||
transition: 0.2s;
|
||||
}
|
||||
/***************************/
|
||||
/* Statut des cellules */
|
||||
/***************************/
|
||||
.selected{ outline: 1px solid #c09; }
|
||||
.modifying{ outline: 2px dashed #c09; }
|
||||
.wait{ outline: 2px solid #c90; }
|
||||
.good{ outline: 2px solid #9c0; }
|
||||
|
||||
.modifOnOff::after {
|
||||
content: '';
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background: #FFF;
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: calc(100% + 2px);
|
||||
border-radius: 100%;
|
||||
transition: 0.2s;
|
||||
/***************************/
|
||||
/* Message */
|
||||
/***************************/
|
||||
.message{
|
||||
position: fixed;
|
||||
bottom: 100%;
|
||||
left: 50%;
|
||||
z-index: 10;
|
||||
padding: 20px;
|
||||
border-radius: 0 0 10px 10px;
|
||||
background: #ec7068;
|
||||
background: #90c;
|
||||
color: #FFF;
|
||||
font-size: 24px;
|
||||
animation: message 3s;
|
||||
transform: translate(-50%, 0);
|
||||
}
|
||||
|
||||
.modifOnOff.active::before {
|
||||
background: #9c0;
|
||||
}
|
||||
|
||||
.modifOnOff.active::after {
|
||||
transform: translateX(20px);
|
||||
@keyframes message{
|
||||
20%{transform: translate(-50%, 100%)}
|
||||
80%{transform: translate(-50%, 100%)}
|
||||
}
|
@ -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 */
|
||||
/*****************************/
|
||||
@ -38,19 +10,117 @@ function build_table(data) {
|
||||
data.forEach((cellule) => {
|
||||
output += `
|
||||
<div
|
||||
class="${cellule.style}"
|
||||
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}"
|
||||
style="
|
||||
--x:${cellule.x};
|
||||
--y:${cellule.y};
|
||||
--nbX:${cellule.nbX};
|
||||
--nbY: ${cellule.nbY};
|
||||
--nbX:${cellule.nbX || 1};
|
||||
--nbY: ${cellule.nbY || 1};
|
||||
">
|
||||
${cellule.data}
|
||||
</div>`;
|
||||
})
|
||||
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);
|
||||
}
|
@ -15,8 +15,6 @@
|
||||
<h2>Formation {{formation.titre}} ({{formation.acronyme}})
|
||||
[version {{formation.version}}] code {{formation.code}}</h2>
|
||||
|
||||
<div class=wait></div>
|
||||
<div class=modifOnOff>Modifier</div>
|
||||
<div class="tableau"></div>
|
||||
|
||||
<script>
|
||||
@ -26,15 +24,24 @@
|
||||
});
|
||||
});
|
||||
function save(obj) {
|
||||
if (event?.currentTarget) {
|
||||
obj = event.currentTarget;
|
||||
var value = obj.innerText.trim();
|
||||
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
|
||||
console.log(`
|
||||
x : ${getComputedStyle(obj).getPropertyValue("--x")}
|
||||
y : ${getComputedStyle(obj).getPropertyValue("--y")}
|
||||
data : ${obj.innerText}
|
||||
data : ${value}
|
||||
ue_id: ${obj.dataset.ue_id}
|
||||
module_id : ${obj.dataset.module_id}
|
||||
`);
|
||||
@ -42,10 +49,17 @@
|
||||
{
|
||||
module_id: `${obj.dataset.module_id}`,
|
||||
ue_id: `${obj.dataset.ue_id}`,
|
||||
coef: `${obj.innerText}`
|
||||
coef: `${value}`
|
||||
},
|
||||
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);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user