From 95ce125ec0ffa6b1a403b5b5f0e45794351a25de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juhani=20Krekel=C3=A4?= Date: Sun, 26 May 2024 16:17:50 +0300 Subject: [PATCH] =?UTF-8?q?MVP=20Raahaa=20&=20pudota=20lukuj=C3=A4rjestys?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 2 + käyttöliittymä.js | 124 ++++++++++++++++++++++++++++++++++++++++++++-- tietokanta.js | 13 +++++ tyyli.css | 12 +++++ 4 files changed, 148 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index 82d4a13..0f1aad3 100644 --- a/index.html +++ b/index.html @@ -69,6 +69,8 @@ +
+ diff --git a/käyttöliittymä.js b/käyttöliittymä.js index 67eecfb..ef2dc86 100644 --- a/käyttöliittymä.js +++ b/käyttöliittymä.js @@ -53,7 +53,7 @@ document.getElementById('tunnit-uusi').addEventListener('submit', (e) => { const tilat = valitutHTMLLuokalla('tunnit-uusi-tila'); t.lisää(taulut.tunnit, { nimi, luokat, opettajat, tilat, - milloin: new Array(kertaa), + milloin: new Array(kertaa).fill(null), }); document.getElementById('tunnit-uusi-nimi').value = ''; document.getElementById('tunnit-uusi-kertaa').value = 1; @@ -63,6 +63,43 @@ document.getElementById('tunnit-uusi').addEventListener('submit', (e) => { })); }); +document.getElementById('lukkari-valinta').addEventListener('input', () => { + päivitäLukkari(); +}); + +let raahattava; +document.addEventListener('dragstart', (e) => { + raahattava = e.target; +}); + +function teePudotuskohteeksi(elementti) { + elementti.addEventListener('dragover', (e) => { + e.preventDefault(); + }); + + elementti.addEventListener('drop', (e) => { + e.preventDefault(); + const raahattavaId = ilmanPrefiksiä('lukkari-tunti-', raahattava.id); + const [tunti, toteutus] = raahattavaId.split('-').map((x) => Number.parseInt(x)); + // XXX: Transaktio ja suoritus + if (elementti.id !== 'sijoittamattomat') { + const kohdeId = ilmanPrefiksiä('lukkari-solu-', elementti.id); + const ajoitus = kohdeId.split('-').map((x) => Number.parseInt(x)); + _tietokanta.hae(taulut.tunnit, tunti).milloin[toteutus] = ajoitus; + } else { + _tietokanta.hae(taulut.tunnit, tunti).milloin[toteutus] = null; + } + päivitäLukkari(); + }); +} + +function ilmanPrefiksiä(prefiksi, teksti) { + if (!teksti.startsWith(prefiksi)) { + throw new Error(`"${teksti}" ei ala prefiksillä "${prefiksi}"`); + } + return teksti.slice(prefiksi.length); +} + function valitutHTMLLuokalla(htmlLuokka) { const valitut = []; for (const valinta of document.getElementsByClassName(htmlLuokka)) { @@ -78,6 +115,7 @@ function suorita([tietokanta, muutokset]) { suoritaMuutos(tietokanta, muutos); } tallennaTietokanta(tietokanta); + päivitäLukkari(); } function suoritaMuutos(tietokanta, muutos) { @@ -147,11 +185,11 @@ function suoritaMuutos(tietokanta, muutos) { } else if (taulu === taulut.tunnit && vanha === undefined) { // Uusi tunti const seuraavaId = idJälkeen(tietokanta, taulu, id, - (a, b) => vertaa(a.nimi, b.nimi) + (a, b) => vertaa(tuntiTeksti(tietokanta, a), tuntiTeksti(tietokanta, b)) ); const tunnitLista = document.getElementById('tunnit-lista'); // ks. kommentti uuden luokan tapauksessa - const seuraava = document.getElementById(`tunti-${id}`); + const seuraava = document.getElementById(`tunti-${seuraavaId}`); tunnitLista.insertBefore(luoTunti(tietokanta, id, uusi), seuraava); } else if (taulu === taulut.tunnit && uusi === undefined) { poistaElementti(document.getElementById(`tunti-${id}`)); @@ -335,3 +373,83 @@ function luoTilaVaihtoehto(id, nimi) { option.appendChild(document.createTextNode(nimi)); return option; } + +let päivät = ['ma', 'ti', 'ke', 'to', 'pe']; +let ajat = ['8', '9', '10', '11', '12', '13', '14', '15']; + +function päivitäLukkari() { + const taulukko = document.createElement('table'); + taulukko.id = 'lukkari'; + const taulukonOtsikko = document.createElement('caption'); + taulukko.appendChild(taulukonOtsikko); + const rivit = document.createElement('tbody'); + const otsikkoRivi = document.createElement('tr'); + otsikkoRivi.appendChild(document.createElement('td')); + for (const päivä of päivät) { + const otsikko = document.createElement('th'); + otsikko.appendChild(document.createTextNode(päivä)); + otsikkoRivi.appendChild(otsikko); + } + rivit.appendChild(otsikkoRivi); + for (const [aikaId, aika] of numeroi(ajat)) { + const rivi = document.createElement('tr'); + const otsikko = document.createElement('th'); + otsikko.appendChild(document.createTextNode(aika)); + rivi.appendChild(otsikko); + for (const [päiväId, päivä] of numeroi(päivät)) { + const solu = document.createElement('td'); + solu.id = `lukkari-solu-${päiväId}-${aikaId}`; + teePudotuskohteeksi(solu); + const lista = document.createElement('ul'); + solu.appendChild(lista); + rivi.appendChild(solu) + } + rivit.appendChild(rivi); + } + taulukko.appendChild(rivit); + + const lista = document.createElement('ul'); + lista.id = 'sijoittamattomat'; + teePudotuskohteeksi(lista); + + const valinta = document.getElementById('lukkari-valinta').value; + if (valinta !== '') { + let [tyyppi, valintaId] = valinta.split('-'); + valintaId = Number.parseInt(valintaId); + const tunnit = _tietokanta.järjestyksessä(taulut.tunnit, + (a, b) => vertaa(tuntiTeksti(_tietokanta, a), tuntiTeksti(_tietokanta, b)) + ); + for (const id of tunnit) { + const tunti = _tietokanta.hae(taulut.tunnit, id); + if ( + (tyyppi === 'luokka' && !tunti.luokat.includes(valintaId)) || + (tyyppi === 'opettaja' && !tunti.opettajat.includes(valintaId)) || + (tyyppi === 'tila' && !tunti.tilat.includes(valintaId)) + ) { + continue; + } + for (const [numero, toteutus] of numeroi(tunti.milloin)) { + const laatta = document.createElement('li'); + laatta.id = `lukkari-tunti-${id}-${numero}`; + laatta.draggable = true; + laatta.appendChild(document.createTextNode(tuntiTeksti(_tietokanta, tunti))); + if (toteutus === null) { + lista.appendChild(laatta); + } else { + const [päiväId, aikaId] = toteutus; + const solu = rivit.children[aikaId + 1].children[päiväId + 1]; + solu.firstChild.appendChild(laatta); + } + } + } + } + + const vanhaTaulukko = document.getElementById('lukkari'); + vanhaTaulukko.parentElement.replaceChild(taulukko, vanhaTaulukko); + const vanhaLista = document.getElementById('sijoittamattomat'); + vanhaLista.parentElement.replaceChild(lista, vanhaLista); +} + +function numeroi(iteroitava) { + return iteroitava.map((elementti, numero) => [numero, elementti]); +} diff --git a/tietokanta.js b/tietokanta.js index 8e9096f..318925a 100644 --- a/tietokanta.js +++ b/tietokanta.js @@ -234,6 +234,19 @@ class Tietokanta { return taulukko.map(([id, _]) => id); } + 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)) { + if (suodatin(sisältö)) { + suodatetut.push(id); + } + } + return suodatetut; + } + serialisoi() { return JSON.stringify(this, (avain, arvo) => { if (avain === 'historia') { diff --git a/tyyli.css b/tyyli.css index 46fcac9..41741bd 100644 --- a/tyyli.css +++ b/tyyli.css @@ -8,3 +8,15 @@ .valintalista > li { flex: 1 fit-content; } + +#lukkari { + border-collapse: collapse; +} + +#lukkari td { + border: 1px solid black; +} + +#lukkari th { + border: 1px solid black; +}