Tuntien lisääminen

This commit is contained in:
Juhani Krekelä 2024-05-22 14:17:26 +03:00
parent dd41081202
commit 8c00c82258
3 changed files with 196 additions and 3 deletions

View File

@ -3,6 +3,7 @@
<head>
<meta charset="utf-8">
<title>Lukujärjestäjä 0.1</title>
<link href="tyyli.css" rel="stylesheet">
</head>
<body>
<input id="kumoa" type="button" value="Kumoa">
@ -37,6 +38,25 @@
<details class="ruutu" open>
<summary>Tunnit</summary>
<ul id="tunnit-lista"></ul>
<form id="tunnit-uusi">
<input id="tunnit-uusi-nimi" type="text" placeholder="tunti" required>
<input id="tunnit-uusi-kertaa" type="number" min="1" value="1" required>
<label for="tunnit-uusi-kertaa">kertaa viikossa</label>
<fieldset>
<legend>Luokat</legend>
<ul id="tunnit-uusi-luokat" class="valintalista"></ul>
</fieldset>
<fieldset>
<legend>Opettajat</legend>
<ul id="tunnit-uusi-opettajat" class="valintalista"></ul>
</fieldset>
<fieldset>
<legend>Tilat</legend>
<ul id="tunnit-uusi-tilat" class="valintalista"></ul>
</fieldset>
<input type="submit" value="+">
</form>
</details>
<script src="tietokanta.js"></script>

View File

@ -42,6 +42,37 @@ document.getElementById('tilat-uusi').addEventListener('submit', (e) => {
}));
});
document.getElementById('tunnit-uusi').addEventListener('submit', (e) => {
e.preventDefault();
suorita(_tietokanta.transaktio((t) => {
const nimi = document.getElementById('tunnit-uusi-nimi').value;
const kertaa =
Number.parseInt(document.getElementById('tunnit-uusi-kertaa').value);
const luokat = valitutHTMLLuokalla('tunnit-uusi-luokka');
const opettajat = valitutHTMLLuokalla('tunnit-uusi-opettaja');
const tilat = valitutHTMLLuokalla('tunnit-uusi-tila');
t.lisää(taulut.tunnit, {
nimi, luokat, opettajat, tilat,
milloin: new Array(kertaa),
});
document.getElementById('tunnit-uusi-nimi').value = '';
document.getElementById('tunnit-uusi-kertaa').value = 1;
for (const valinta of document.getElementsByClassName('tunnit-uusi-valinta')) {
valinta.checked = false;
}
}));
});
function valitutHTMLLuokalla(htmlLuokka) {
const valitut = [];
for (const valinta of document.getElementsByClassName(htmlLuokka)) {
if (valinta.checked) {
valitut.push(Number.parseInt(valinta.value));
}
}
return valitut;
}
function suorita([tietokanta, muutokset]) {
for (const muutos of muutokset) {
suoritaMuutos(tietokanta, muutos);
@ -59,11 +90,15 @@ function suoritaMuutos(tietokanta, muutos) {
// on viimeinen, seuraavaId on undefined, eikä DOM:ssa ole luokkaa
// "luokka-undefined". seuraava on siis null silloin kuin tämä luokka
// tulee lisätä listan loppuun, joka vastaa insertBefore:n toimintaa
const seuraava = document.getElementById(`luokka-${seuraavaId}`);
let seuraava = document.getElementById(`luokka-${seuraavaId}`);
luokatLista.insertBefore(luoLuokka(id, uusi), seuraava);
const tunnitUusiLuokat = document.getElementById('tunnit-uusi-luokat');
seuraava = document.getElementById(`tunnit-uusi-luokka-${seuraavaId}`);
tunnitUusiLuokat.insertBefore(luoLuokkaValinta(id, uusi), seuraava);
} else if (taulu === taulut.luokat && uusi === undefined) {
// Luokka poistettu
poistaElementti(document.getElementById(`luokka-${id}`));
poistaElementti(document.getElementById(`tunnit-uusi-luokka-${id}`));
// TODO: luokka muutos
} else if (taulu === taulut.opettajat && vanha === undefined) {
// Uusi opettaja
@ -72,22 +107,36 @@ function suoritaMuutos(tietokanta, muutos) {
);
const opettajatLista = document.getElementById('opettajat-lista');
// ks. kommentti uuden luokan tapauksessa
const seuraava = document.getElementById(`opettaja-${seuraavaId}`);
let seuraava = document.getElementById(`opettaja-${seuraavaId}`);
opettajatLista.insertBefore(luoOpettaja(id, uusi), seuraava);
const tunnitUusiOpettajat = document.getElementById('tunnit-uusi-opettajat');
seuraava = document.getElementById(`tunnit-uusi-opettaja-${seuraavaId}`);
tunnitUusiOpettajat.insertBefore(luoOpettajaValinta(id, uusi), seuraava);
} else if (taulu === taulut.opettajat && uusi === undefined) {
// Opettaja poistettu
poistaElementti(document.getElementById(`opettaja-${id}`));
poistaElementti(document.getElementById(`tunnit-uusi-opettaja-${id}`));
// TODO: opettaja muutos
} else if (taulu === taulut.tilat && vanha === undefined) {
// Uusi tila
const seuraavaId = idJälkeen(tietokanta, taulu, id, vertaa);
const tilatLista = document.getElementById('tilat-lista');
const seuraava = document.getElementById(`tila-${seuraavaId}`);
let seuraava = document.getElementById(`tila-${seuraavaId}`);
tilatLista.insertBefore(luoTila(id, uusi), seuraava);
const tunnitUusiTilat = document.getElementById(`tunnit-uusi-tilat`);
seuraava = document.getElementById(`tunnit-uusi-tila-${seuraavaId}`);
tunnitUusiTilat.insertBefore(luoTilaValinta(id, uusi), seuraava);
} else if (taulu === taulut.tilat && uusi === undefined) {
// Tila poistettu
poistaElementti(document.getElementById(`tila-${id}`));
poistaElementti(document.getElementById(`tunnit-uusi-tila-${id}`));
// TODO: tila muutos
} else if (taulu === taulut.tunnit && vanha === undefined) {
// Uusi tunti
// TODO: Järjestys
const tunnitLista = document.getElementById('tunnit-lista');
tunnitLista.appendChild(luoTunti(tietokanta, id, uusi));
// TODO: tunti poistettu, muutos
} else {
throw new Error(`Ei toteutettu ${taulu} ${id} ${vanha} ${uusi}`);
}
@ -154,3 +203,68 @@ function luoTila(id, nimi) {
li.appendChild(document.createTextNode(nimi));
return li;
}
function luoTunti(tietokanta, id, tunti) {
const li = document.createElement('li');
li.id = `tunti-${id}`;
const poistoPainike = document.createElement('input');
poistoPainike.type = 'button';
poistoPainike.value = '-';
poistoPainike.addEventListener('click', () => {
suorita(_tietokanta.transaktio((t) => {
t.poista(taulut.tunnit, id);
}));
});
li.appendChild(poistoPainike);
li.appendChild(document.createTextNode(tuntiTeksti(tietokanta, tunti)));
return li;
}
function tuntiTeksti(tietokanta, tunti) {
const kertaa = tunti.milloin.length;
const nimi = tunti.nimi;
const luokat = tunti.luokat.map((x) => tietokanta.hae(taulut.luokat, x));
const opettajat = tunti.opettajat
.map((x) => tietokanta.hae(taulut.opettajat, x).lyhenne);
const tilat = tunti.tilat.map((x) => tietokanta.hae(taulut.tilat, x));
return `${kertaa}× ${nimi} ${luokat} ${opettajat} ${tilat}`;
}
function luoLuokkaValinta(id, nimi) {
const li = document.createElement('li');
li.id = `tunnit-uusi-luokka-${id}`;
const valinta = document.createElement('input');
valinta.type = 'checkbox';
valinta.classList.add('tunnit-uusi-valinta');
valinta.classList.add('tunnit-uusi-luokka');
valinta.value = id;
li.appendChild(valinta);
li.appendChild(document.createTextNode(nimi));
return li;
}
function luoOpettajaValinta(id, {nimi, lyhenne}) {
const li = document.createElement('li');
li.id = `tunnit-uusi-opettaja-${id}`;
const valinta = document.createElement('input');
valinta.type = 'checkbox';
valinta.classList.add('tunnit-uusi-valinta');
valinta.classList.add('tunnit-uusi-opettaja');
valinta.value = id;
li.appendChild(valinta);
li.appendChild(document.createTextNode(`${nimi} (${lyhenne})`));
return li;
}
function luoTilaValinta(id, nimi) {
const li = document.createElement('li');
li.id = `tunnit-uusi-tila-${id}`;
const valinta = document.createElement('input');
valinta.type = 'checkbox';
valinta.classList.add('tunnit-uusi-valinta');
valinta.classList.add('tunnit-uusi-tila');
valinta.value = id;
li.appendChild(valinta);
li.appendChild(document.createTextNode(nimi));
return li;
}

View File

@ -4,6 +4,7 @@ const taulut = {
luokat: 'luokat',
opettajat: 'opettajat',
tilat: 'tilat',
tunnit: 'tunnit',
};
class Transaktio {
@ -67,6 +68,29 @@ class Transaktio {
});
this.taulut.get(taulu).set(id, undefined);
}
suodata(taulu, suodatin) {
if (!this.taulut.has(taulu)) {
throw new Error(`ei taulua ${taulu}`);
}
const suodatetut = [];
for (const [id, sisältö] of this.taulut.get(taulu)) {
// Jos sisältö on undefined, rivi on poistettu, eikä sitä tule ottaa
// huomioon suodatettaessa
if (sisältö !== undefined && suodatin(sisältö)) {
suodatetut.push(id);
}
}
for (const [id, sisältö] of this.tietokanta.taulut.get(taulu)) {
// Älä huomio rivejä, jotka löytyvät transaktion tauluista. Ne on
// joko käsitelty jo edellisessä silmukassa (jos ne on päivitetty)
// tai niitä ei tulisi käsitellä ollenkaan (jos ne on poistettu).
if (!this.taulut.get(taulu).has(id) && suodatin(sisältö)) {
suodatetut.push(id);
}
}
return suodatetut;
}
}
class Tietokanta {
@ -110,6 +134,41 @@ class Tietokanta {
// Varmista, että invariantit ovat yhä totta
for (const {taulu, id, vanha, uusi} of transaktio.muutokset) {
if (uusi === undefined && taulu !== taulut.tunnit) {
// Poistettu luokka, opettaja tai tila ei ole tunnin käytössä
const roikkuvat = transaktio.suodata(taulut.tunnit, (tunti) => {
if (taulu === taulut.luokat) {
return tunti.luokat.includes(id);
} else if (taulu === taulut.opettajat) {
return tunti.opettajat.includes(id);
} else if (taulu === taulut.tilat) {
return tunti.tilat.includes(id);
} else {
throw new Error(`Ei-tunnettu taulu ${taulu}`);
}
});
if (roikkuvat.length !== 0) {
throw new Error(`Yritetty poistaa ${taulu}:${id}, joka on ${roikkuvat} käytössä`);
}
} else if (taulu === taulut.tunnit) {
// Uusi tunti käyttää vain olemassaolevia luokkia, opettajia ja
// tiloja
for (const luokka of uusi.luokat) {
if (transaktio.hae(taulut.luokat, luokka) === undefined) {
throw new Error(`Yritetty luoda tunti ${id} olemattomalla luokalla ${luokka}`);
}
}
for (const opettaja of uusi.opettajat) {
if (transaktio.hae(taulut.opettajat, opettaja) === undefined) {
throw new Error(`Yritetty luoda tunti ${id} olemattomalla opettajalla ${opettaja}`);
}
}
for (const tila of uusi.tilat) {
if (transaktio.hae(taulut.tilat, tila) === undefined) {
throw new Error(`Yritetty luoda tunti ${id} olemattomalla tilalla ${tila}`);
}
}
}
}
// Suorita muutokset