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 */
|
/* Le tableau */
|
||||||
/***************************/
|
/***************************/
|
||||||
.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 8px;
|
||||||
padding: 4px;
|
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);
|
|
||||||
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
@ -13,10 +13,8 @@
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
<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);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user