From 0722729bcd8a032e22ccae33a58b14fcef720292 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jon=C3=A1=C5=A1=20Havelka?= <jonas.havelka@volny.cz>
Date: Thu, 6 Mar 2025 11:41:45 +0100
Subject: [PATCH] =?UTF-8?q?Okomentov=C3=A1n=C3=AD=20m=C3=A9ho=20zb=C4=9Bsi?=
 =?UTF-8?q?l=C3=A9ho=20frontendu=20ke=20korekturov=C3=A1tku?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../hlavni_cast_korekturovatka.html           |  17 ++-
 .../korektury/korekturovatko/html_obal.html   |   6 ++
 .../moduly/dalsi_korektura.html               |   8 +-
 .../korekturovatko/moduly/edit_komentar.html  |  62 ++++++++++-
 .../korekturovatko/moduly/komentar.html       |  61 +++++++++--
 .../korekturovatko/moduly/korektura.html      | 100 ++++++++++++++++--
 .../moduly/schovani_korektur.html             |  11 ++
 .../korekturovatko/moduly/stranky_pdfka.html  |  43 +++++++-
 .../korekturovatko/zmena_stavu_pdf.html       |  12 ++-
 9 files changed, 287 insertions(+), 33 deletions(-)

diff --git a/korektury/templates/korektury/korekturovatko/hlavni_cast_korekturovatka.html b/korektury/templates/korektury/korekturovatko/hlavni_cast_korekturovatka.html
index c467e350..be5f816a 100644
--- a/korektury/templates/korektury/korekturovatko/hlavni_cast_korekturovatka.html
+++ b/korektury/templates/korektury/korekturovatko/hlavni_cast_korekturovatka.html
@@ -1,3 +1,4 @@
+{# Část korekturovátka, která obsahuje všechno okolo korektur #}
 {% include "korektury/korekturovatko/moduly/schovani_korektur.html" %}
 
 {% include "korektury/korekturovatko/moduly/edit_komentar.html" %}
@@ -12,10 +13,11 @@
 
 <script>
   /**
-   *
-   * @param {RequestInit} data
-   * @param {Boolean} catchError
-   * @param pri_uspechu Akce, která se má provést při úspěchu (speciálně zavřít formulář)
+   * Fetchne korektury a komentáře a na základě toho aktualizuje všechno
+   * (korektury, komentáře, zásluhy, počty korektur v daných stavech, umístění korektur)
+   * @param {RequestInit} data FormData a jiné náležitosti (method: POST) posílané při přidání/úpravě korektury/komentáře
+   * @param {Boolean} catchError jestli padat hlasitě (pokud se aktualizuje automaticky a spadne to např. na nepřítomnost sítě, pak není třeba informovat uživatele)
+   * @param {(() => *)?} pri_uspechu akce, která se má provést při úspěchu (speciálně zavřít formulář)
    */
   function aktualizuj_vse(data={}, catchError=true, pri_uspechu=null) { // FIXME není mi jasné, zda v {} nemá být `cache: "no-store"`, aby prohlížeč necachoval GET.
     fetch('{% url "korektury_api_opravy_a_komentare" korekturovanepdf.id %}', data)
@@ -39,7 +41,7 @@
   }
 
   window.addEventListener("load", _ => {
-    aktualizuj_vse({}, true, _ => {
+    aktualizuj_vse({}, true, () => {
       if (location.hash !== "") location.hash = location.hash; // Po rozházení korektur sescrollujeme na kotvu v URL
     });
   });
@@ -48,8 +50,13 @@
   setInterval(() => aktualizuj_vse({}, false), 120000); // Každý dvě minuty fetchni korektury
 </script>
 
+{# Formulář, který mouhou použít tlačítka bez svého formuláře k vytvoření POST requestu, viz CSRF_FORM níže #}
 <form id='CSRF_form' style='display: none'>{% csrf_token %}</form>
 
 <script>
+  /**
+   * Formulář, který mouhou použít tlačítka bez svého formuláře k vytvoření POST requestu
+   * @type {HTMLFormElement}
+   */
   const CSRF_FORM = document.getElementById('CSRF_form');
 </script>
diff --git a/korektury/templates/korektury/korekturovatko/html_obal.html b/korektury/templates/korektury/korekturovatko/html_obal.html
index bba431d1..daf1f535 100644
--- a/korektury/templates/korektury/korekturovatko/html_obal.html
+++ b/korektury/templates/korektury/korekturovatko/html_obal.html
@@ -1,3 +1,4 @@
+{# Okolí samotného hlavni_cast_korekturovatka.html, tedy „povinné HTML věci“, informace o korekturovaném PDF a starání se o stav PDF #}
 {% load static %}
 
 <html lang='cs'>
@@ -36,8 +37,13 @@
   <hr>
 
   <script>
+    /**
+     * HTML prvek, kam se zapíší (pomocí .innerHTML) počty korektur jednotlivých autorů
+     * @type {HTMLElement}
+     */
     const span_s_pocty_autoru = document.getElementById("pocty_autoru")
 
+    /** Aktualizuje, kolik který autor má komentářů u daného korekturovaného PDF. */
     function aktualizuj_pocty_zasluh() {
       const pocty_autoru = {};
       for (let komentar of Object.values(komentare)) {
diff --git a/korektury/templates/korektury/korekturovatko/moduly/dalsi_korektura.html b/korektury/templates/korektury/korekturovatko/moduly/dalsi_korektura.html
index c3b06098..69969f43 100644
--- a/korektury/templates/korektury/korekturovatko/moduly/dalsi_korektura.html
+++ b/korektury/templates/korektury/korekturovatko/moduly/dalsi_korektura.html
@@ -1,3 +1,4 @@
+{# Template starající se o tlačítka v levém dolním rohu, především skákající na další/předchozí korekturu. #}
 {% load static %}
 
 <div id="korektury-sipky">
@@ -29,7 +30,6 @@ Nemusíš mačkat, pokud ti stačí, že se korektury aktualizují samy každé
 </div>
 
 <script>
-  // Přidání event listenerů
   document.getElementById('predchozi-korektura').addEventListener('click', _ => { dalsi_nebo_predchozi_korektura(false) });
   document.getElementById('dalsi-korektura').addEventListener('click', _ => { dalsi_nebo_predchozi_korektura(true) });
   document.getElementById('predchozi-korektura-k-oprave').addEventListener('click', _ => { dalsi_nebo_predchozi_korektura(false, "k_oprave") });
@@ -40,6 +40,12 @@ Nemusíš mačkat, pokud ti stačí, že se korektury aktualizují samy každé
   // FIXME není mi jasné, zda v {} nemá být `cache: "no-store"`, aby prohlížeč necachoval GET.
   document.getElementById("korektury-aktualizace").addEventListener("click", _ => aktualizuj_vse({}, false));
 
+  /**
+   * Sescrolluje na další nebo předchozí (vůči hornímu okraji okna) korekturu (v daném stavu).
+   * V případě neexistence takové korektury vyhodí alert.
+   * @param {boolean} dalsi reprezentuje, zda chceme další nebo předchozí korekturu
+   * @param {?string} stav pokud je nenullový, tak ignoruje korektury v jiném stavu
+   */
   function dalsi_nebo_predchozi_korektura(dalsi=true, stav=null) {
     let predchozi = null;
     for (const strana of setrizene_strany) {
diff --git a/korektury/templates/korektury/korekturovatko/moduly/edit_komentar.html b/korektury/templates/korektury/korekturovatko/moduly/edit_komentar.html
index 02e0e055..23eead69 100644
--- a/korektury/templates/korektury/korekturovatko/moduly/edit_komentar.html
+++ b/korektury/templates/korektury/korekturovatko/moduly/edit_komentar.html
@@ -1,3 +1,4 @@
+{# Template starající se o editační/přidávací formulář. #}
 <div id="korekturovaci-formular-div" style="display: none">
   <input size="24" name="au" value="{{user.first_name}} {{user.last_name}}" readonly/>
   <button type="button" id="korekturovaci-formular-odesli">Oprav!</button>
@@ -14,7 +15,39 @@
 </div>
 
 <script>
+  /** V podstatě singleton (viz korekturovaci_formular) starající se o editační/přidávací formulář. */
   class _KorekturovaciFormular {
+    /**
+     * <div> obsahující celý formulář.
+     * @type {HTMLElement}
+     */
+    div;
+    /**
+     * Políčko, kam uživatel vyplňuje text.
+     * @type {HTMLElement}
+     */
+    text;
+    /**
+     * Tlačítko odeslat. Často ho chceme disablenout.
+     * @type {HTMLElement}
+     */
+    odesilaci_button;
+    /**
+     * <div> obsahující všechny tagy, pomocí tagy.getElementsByTagName("button") umíme dělat operace nad všemi tagy.
+     * @type {HTMLElement}
+     */
+    tagy;
+    /**
+     * Text upozorňující na to, že tagy nepřidáváme, ale editujeme. (Tj. chceme ho schovat, když vytváříme novou korekturu.)
+     * @type {HTMLElement}
+     */
+    tagy_info;
+    /**
+     * zda při přidávání nové korektury mají být všechny tagy odvybrané, nebo mají kopírovat předchozí nastavení
+     * @type {boolean}
+     */
+    pri_otevreni_odvyber_tagy;
+
     constructor() {
       this.div = document.getElementById('korekturovaci-formular-div');
       this.text = document.getElementById('korekturovaci-formular-text');
@@ -36,18 +69,28 @@
       this.pri_otevreni_odvyber_tagy = true;
     }
 
+    /**
+     * Přepne tag na vybraný/nevybraný (v závislosti na tom, zda byl nevybrán/vybrán)
+     * @param {MouseEvent} event vyvolaný kliknutím na daný tag (musí mít za event.target daný tag)
+     */
     vyber_nebo_odvyber_tag(event) {
       const button = event.target;
       button.dataset.vybran = String(button.dataset.vybran === "false");
     }
 
+    /** Nastaví všechny tagy na nevybrané. */
     odvyber_tagy() { for (const tag of this.tagy.getElementsByTagName("button")) tag.dataset.vybran = "false"; }
 
 
-    // schová korekturovací formulář
+    /** Schová (zavře) korekturovací formulář */
     schovej() { this.div.style.display = 'none'; }
 
-    // zobrazí korekturovací formulář
+    /**
+     * Zobrazí/otevře korekturovací formulář (bez toho, aby v něm cokoliv měnil).
+     * @param {Strana} strana (na které straně se má zobrazit)
+     * @param {number} x
+     * @param {number} y
+     */
     _zobraz(strana, x, y) {
       this.odesilaci_button.disabled = false;
       this.div.style.display = 'block';
@@ -59,7 +102,15 @@
       this.text.focus();
     }
 
-    // fill up comment form and show him
+    /**
+     * Předvyplní správně korekturovací formulář a zobrazí/otevře ho
+     * @param {Strana} strana (na které straně se má zobrazit)
+     * @param {Number} x
+     * @param {Number} y
+     * @param {string} text (text k předvyplněný, místo null chceš psáť "")
+     * @param {Number} komentar_id (!= -1 znamená úprava komentáře, -1 znamená přidávání korektury/komentáře)
+     * @param {Number} korektura_id (v případě komentar_id != -1 znamená: -1 je nová korektura, ne-1 je nový komentář)
+     */
     zobraz(strana, x, y, text, korektura_id=-1, komentar_id=-1) {
       if (this.div.style.display !== 'none' && this.text.value !== "" && !confirm("Zavřít předchozí okénko přidávání korektury / editace komentáře?")) return;
 
@@ -85,6 +136,7 @@
       this._zobraz(strana, x, y);
     }
 
+    /** Shrábne data a pošle daný požadavek, čímž kromě vyřízení dané věci aktualizuje korektury+komentáře. */
     odesli_formular() {
       this.odesilaci_button.disabled = true;
       const data = new FormData(CSRF_FORM);
@@ -106,5 +158,9 @@
     }
   }
 
+  /**
+   * Objekt starající se o editační/přidávací formulář (jeho předvyplňování, zobrazování a posílání).
+   * @type {_KorekturovaciFormular}
+   */
   const korekturovaci_formular = new _KorekturovaciFormular();
 </script>
diff --git a/korektury/templates/korektury/korekturovatko/moduly/komentar.html b/korektury/templates/korektury/korekturovatko/moduly/komentar.html
index 748a9d48..5e51b2db 100644
--- a/korektury/templates/korektury/korekturovatko/moduly/komentar.html
+++ b/korektury/templates/korektury/korekturovatko/moduly/komentar.html
@@ -1,3 +1,4 @@
+{# Template starající se o jeden každý komentář u korektury. #}
 {% load static %}
 
 <div class='comment' id='prekomentar' {# id='k{{k.id}}' #}>
@@ -24,25 +25,57 @@
 
 
 <script>
+  /**
+   * Prototyp komentáře, ze kterého se vygeneruje každý komentář (resp. jeho HTML reprezentace) v dokumentu
+   * @type {HTMLElement}
+   */
   const prekomentar = document.getElementById('prekomentar');
+  /**
+   * Mapování ID |-> komentář
+   * @type {Object.<Number, Komentar>}
+   */
   const komentare = {};
 
+  /** Třída reprezentující jeden komentář (a starající se o vytvoření a updatování jeho HTML reprezentace) */
   class Komentar {
+    /**
+     * Z dat aktualizuje (v případě, že korektura s daným ID existuje) nebo vytvoří Komentar
+     * @param {Object.<string, ?>} komentar_data „Slovník“ obsahující data daného komentáře
+     * @param {Korektura} korektura ke které se komentář má připojit
+     */
     static aktualizuj_nebo_vytvor(komentar_data, korektura) {
       const id = komentar_data['id'];
       if (id in komentare) komentare[id].aktualizuj(komentar_data);
       else new Komentar(komentar_data, korektura);
     }
 
-    #autor; #text;
+    /**
+     * <div> se jménem autora komentáře
+     * @type {HTMLElement}
+     */
+    #autor;
+    /**
+     * <div> obsahující text komentáře
+     * @type {HTMLElement}
+     */
+    #text;
+    /**
+     * <div> reprezentující celý komentář
+     * @type {HTMLElement}
+     */
     htmlElement;
-    id; korektura; {# komentar_data; #}
+
+    /** @type {Number} */
+    id;
+    /** @type{Korektura} */
+    korektura;
+    /** @type{string} */
     autor;
 
     /**
-     *
-     * @param komentar_data
-     * @param {Korektura} korektura
+     * Vytvoří HTML reprezentaci, připojí komentář pod korekturu, nastaví event-listenery, uloží si data
+     * @param {Object.<string, ?>} komentar_data „Slovník“ obsahující data daného komentáře
+     * @param {Korektura} korektura korektura ke které se komentář má připojit
      */
     constructor(komentar_data, korektura) {
       this.htmlElement = prekomentar.cloneNode(true);
@@ -63,28 +96,38 @@
       komentare[this.id] = this;
     }
 
+    /**
+     * Aktualizuje/nastaví JS data i HTML reprezentaci komentáře
+     * @param {Object.<string, ?>} komentar_data „Slovník“ obsahující data daného komentáře
+     */
     aktualizuj(komentar_data) {
-      {# this.komentar_data = komentar_data; #}
       this.set_autor(komentar_data['autor']);
       this.set_text(komentar_data['text']);
     };
 
+    /**
+     * Aktualizuje/nastaví JS data i HTML reprezentaci autora komentáře
+     * @param {String} autor
+     */
     set_autor(autor) {
       this.#autor.textContent=autor;
       this.autor = autor;
     };
 
+    /**
+     * @param {String} text
+     */
     set_text(text) {
       this.#text.innerHTML=text;
     };
 
 
-    // Ukaž formulář na editaci komentáře (když je zmáčknuto „uprav-komentar“)
+    /** Ukáže formulář na editaci komentáře (když je zmáčknuto „uprav-komentar“) */
     #uprav_komentar() {
       return korekturovaci_formular.zobraz(this.korektura.strana, this.korektura.x, this.korektura.y, this.#text.textContent, this.korektura.id, this.id);
     }
 
-    // Smaž komentář (když je zmáčknuto „smaz-komentar“)
+    /** Smaže komentář (když je zmáčknuto „smaz-komentar“) */
     #smaz_komentar() {
       if (confirm('Opravdu smazat komentář?')) {
         const data = new FormData(CSRF_FORM);
@@ -99,7 +142,7 @@
       }
     }
 
-    // Smaž div komentáře, když je smazán komentář nebo jeho nadřazená korektura
+    /** Smaže div komentáře (ne databázový záznam!), používá se, když je smazán komentář nebo jeho nadřazená korektura */
     smaz_pouze_na_strance() {
       delete komentare[this.id];
       this.htmlElement.remove();
diff --git a/korektury/templates/korektury/korekturovatko/moduly/korektura.html b/korektury/templates/korektury/korekturovatko/moduly/korektura.html
index 1f90e104..4b23b247 100644
--- a/korektury/templates/korektury/korekturovatko/moduly/korektura.html
+++ b/korektury/templates/korektury/korekturovatko/moduly/korektura.html
@@ -58,22 +58,75 @@
 </div>
 
 <script>
+  /**
+   * Prototyp korektury, ze kterého se vygeneruje každý komentář (resp. jeho HTML reprezentace) v dokumentu
+   * @type {HTMLElement}
+   */
   const prekorektura = document.getElementById('prekorektura');
+  /**
+   * Prototyp pointeru (té lomené čáry od korektury)
+   * @type {HTMLElement}
+   */
   const prepointer = document.getElementById('prepointer');
+  /**
+   * Mapování ID |-> korektura
+   * @type {Object.<Number, Korektura>}
+   */
   const korektury = {};
 
+  /** Třída reprezentující jednu korekturu (a starající se o vytvoření a updatování její HTML reprezentace) */
   class Korektura {
+    /**
+     * Z dat aktualizuje (v případě, že korektura s daným ID existuje) nebo vytvoří Korekturu
+     * @param {Object.<string, ?>} korektura_data „Slovník“ obsahující data dané korektury
+     * @returns {Korektura} vytvořená/aktualizovaná Korektura (pro použití při vytváření/aktualizaci komentářů)
+     */
     static aktualizuj_nebo_vytvor(korektura_data) {
       const id = korektura_data['id'];
       if (id in korektury) return korektury[id].aktualizuj(korektura_data);
       else return new Korektura(korektura_data);
     }
 
-    #komentare; #tagy;
-    htmlElement; pointer;
-    id; x; y; strana; stav; sbalena = false; {# korektura_data; #}
+    /**
+     * <div> obsahující <div>y komentářů
+     * @type {HTMLElement}
+     */
+    #komentare;
+    /**
+     * <div> obsahující tagy
+     * @type {HTMLElement}
+     */
+    #tagy;
+    /**
+     * <div> reprezentující celý korekturu
+     * @type {HTMLElement}
+     */
+    htmlElement;
+    /**
+     * <div> reprezentující pointer (tu lomenou čáru od korektury)
+     * @type {HTMLElement}
+     */
+    pointer;
+
+    /** @type {Number} */
+    id;
+    /** @type {Number} */
+    x;
+    /** @type {Number} */
+    y;
+    /** @type {Strana} */
+    strana;
+    /** @type {string} */
+    stav;
+    /** @type {boolean} */
+    sbalena = false;
+    /** @type Set<Number> */
     tagy;
 
+    /**
+     * Vytvoří HTML reprezentaci, připojí korekturu pod stranu (ale neumístí ji), nastaví event-listenery, uloží si data
+     * @param {Object.<string, ?>} korektura_data „Slovník“ obsahující data dané korektury
+     */
     constructor(korektura_data) {
       this.htmlElement = prekorektura.cloneNode(true);
       this.pointer = prepointer.cloneNode(true);
@@ -109,12 +162,25 @@
       korektury[this.id] = this;
     }
 
+    /**
+     * Aktualizuje/nastaví JS data i HTML reprezentaci korektury
+     * @param {Object.<string, ?>} korektura_data „Slovník“ obsahující data dané korektury
+     * @returns {Korektura} pro jednodušší implementaci aktualizuj_nebo_vytvor vracíme this
+     */
     aktualizuj(korektura_data) {
-      {# this.korektura_data = korektura_data; #}
       this.set_stav(korektura_data['status']);
+      this.set_tagy(korektura_data["tagy"]);
+      return this;
+    };
+
+    /**
+     * Aktualizuje/nastaví JS data i HTML reprezentaci tagů korektury
+     * @param {Object.<string, ?>[]} tagy
+     */
+    set_tagy(tagy) {
       this.#tagy.innerHTML = "";
       this.tagy = new Set();
-      for (const tag of korektura_data["tagy"]) {
+      for (const tag of tagy) {
         this.tagy.add(tag["id"]);
         const span = document.createElement("span");
         span.innerHTML = tag["nazev"];
@@ -122,32 +188,44 @@
         span.style.backgroundColor = tag["barva"];
         this.#tagy.appendChild(span);
       }
-      return this;
-    };
+    }
 
+    /**
+     * Aktualizuje/nastaví JS data i HTML reprezentaci stavu korektury
+     * @param {String} stav
+     */
     set_stav(stav) {
       this.stav = stav;
       this.htmlElement.dataset.stav_korektury=stav;
       this.pointer.dataset.stav_korektury=stav;
     };
 
+    /**
+     * Přidá HTML reprezentaci komentáře pod tuto korekturu
+     * @param {HTMLElement} htmlElement přidávaný komentář (jako HTML prvek)
+     */
     pridej_htmlElement_komentare(htmlElement) { this.#komentare.appendChild(htmlElement); }
 
 
 
-
+    /** Sbalí/rozbalí (podle toho, zda byla rozbalená/sbalená) korekturu, ale nezmění pozice korektur (je třeba později zavolat umisti_korektury()) */
     sbal_nebo_rozbal() {
       this.sbalena = !this.sbalena;
       this.htmlElement.dataset.korektura_sbalena = String(this.sbalena);
     }
+    /** Doplněk sbal_nebo_rozbal, který i přeskládá korektury. */
     #sbal_nebo_rozbal(){
       this.sbal_nebo_rozbal();
-      umisti_korektury()
+      umisti_korektury();
     }
 
-    // Ukaž komentovací formulář (když je zmáčknuto komentovat)
+    /** Ukaž komentovací formulář (když je zmáčknuto komentovat) */
     #komentuj() { korekturovaci_formular.zobraz(this.strana, this.x, this.y, "", this.id); }
 
+    /**
+     * Změní stav (když je zmáčknuto tlačítko daného stavu)
+     * @param {MouseEvent} event který vyvolal danou změnu (event.target.value musí být chtěný stav)
+     */
     #zmen_stav_korektury(event) {
       const data = new FormData(CSRF_FORM);
       data.append('id', this.id);
@@ -164,6 +242,7 @@
         .catch(error => {alert('Něco se nepovedlo:' + error);});
     }
 
+    /** Smaže korekturu (když je zmáčknuto „smaz-korekturu“) */
     #smaz_korekturu() {
       if (confirm('Opravdu smazat korekturu?')) {
         const data = new FormData(CSRF_FORM);
@@ -180,6 +259,7 @@
       }
     }
 
+    /** Smaže div korektury (včetně všech komentářů; ne databázový záznam!) */
     #smaz_pouze_na_strance() {
       this.strana.korektury.splice(this.strana.korektury.indexOf(this), 1);
       delete korektury[this.id];
diff --git a/korektury/templates/korektury/korekturovatko/moduly/schovani_korektur.html b/korektury/templates/korektury/korekturovatko/moduly/schovani_korektur.html
index 4f34f3e2..87061b5a 100644
--- a/korektury/templates/korektury/korekturovatko/moduly/schovani_korektur.html
+++ b/korektury/templates/korektury/korekturovatko/moduly/schovani_korektur.html
@@ -1,3 +1,4 @@
+{# Template starající se o tlačítkovou lištu nahoře, tj. hlavně o hromadné schovávání korektur. #}
 Zobrazit:
 <input type="checkbox" id="k_oprave_checkbox" checked>
 <label for="k_oprave_checkbox">K opravě (<span id="k_oprave_pocet">↺</span>)</label>
@@ -30,6 +31,10 @@ Zobrazit:
     umisti_korektury();
   })
 
+  /**
+   * Změní CSS tak, aby se korektury příslušného stavu nezobrazovali/zobrazovali (v závislosti na tom, jestli byly zobrazené/nezobrazené)
+   * @param {string} aclass stav korektur, které mají být skryty/zobrazeny
+   */
   function skryj_nebo_zobraz_korektury(aclass)
   {
     const stylesheets = document.styleSheets;
@@ -56,6 +61,11 @@ Zobrazit:
     umisti_korektury();
   }
 
+  /**
+   * Mapování stav korektur |-> span, kde se píše, kolik je korektur toho stavu.
+   * Používané v následující funcki
+   * @type {Object.<string, HTMLElement>}
+   */
   const spany_s_pocty_stavu_korektur = {
     'k_oprave': document.getElementById('k_oprave_pocet'),
     'opraveno': document.getElementById('opraveno_pocet'),
@@ -63,6 +73,7 @@ Zobrazit:
     'k_zaneseni': document.getElementById('k_zaneseni_pocet'),
   }
 
+  /** Aktualizuje počty korektur jednotlivých stavů */
   function aktualizuj_pocty_stavu() {
     const pocty_stavu_korektur = {};
     for (const stav_korektury of Object.keys(spany_s_pocty_stavu_korektur)) pocty_stavu_korektur[stav_korektury] = 0;
diff --git a/korektury/templates/korektury/korekturovatko/moduly/stranky_pdfka.html b/korektury/templates/korektury/korekturovatko/moduly/stranky_pdfka.html
index 6f09ed2e..c96cf544 100644
--- a/korektury/templates/korektury/korekturovatko/moduly/stranky_pdfka.html
+++ b/korektury/templates/korektury/korekturovatko/moduly/stranky_pdfka.html
@@ -1,3 +1,4 @@
+{# Template starající se o zobrazení PDF stran a o umístění korektur na ně. (O samotné korektury se stará `./korektura.html`.) #}
 {% for i in indexy_stran %}
   <div class='imgdiv'>
     <img
@@ -19,14 +20,40 @@
   const MINIMALNI_VYSKA_POINTERU = 30;
 
   /**
+   * Mapování index_strany |-> strana
    * @type {Object.<int, Strana>}
    */
   const strany = {};
 
+  /** Třída spravující jednu stranu PDF a umisťující na ni příslušné korektury. */
   class Strana {
-    htmlElement_img; htmlElement_div;
-    id; korektury;
+    /**
+     * <img> příslušící straně
+     * @type {HTMLElement}
+     */
+    htmlElement_img;
+    /**
+     * <div> obalující stranu, do něj se umisťují korektury
+     * @type {HTMLElement}
+     */
+    htmlElement_div;
 
+    /**
+     * Index strany (používá se při ukládání korektury (a načítání <img>))
+     * @type {Number}
+     */
+    id;
+    /**
+     * Korektury na příslušné straně (BÚNO setříděné podle vertikálního umístění)
+     * @type {Korektura[]}
+     */
+    korektury;
+
+
+    /**
+     * Uloží si data (včetně pointrů na správné části HTML DOMu) a nastaví event-listener
+     * @param {HTMLElement} htmlElement_img
+     */
     constructor(htmlElement_img) {
       this.htmlElement_img = htmlElement_img;
       this.htmlElement_div = this.htmlElement_img.parentNode;
@@ -39,6 +66,10 @@
       strany[this.id] = this;
     }
 
+    /**
+     * Otevře korekturovací formulář pro přidání korektury v daném místě
+     * @param {MouseEvent} event
+     */
     #korekturuj(event) {
       switch (document.body.dataset.stav_pdf) {
         case 'zanaseni':
@@ -61,8 +92,10 @@
       console.log("Pro přesun korektur: strana = " + this.id + ", x = " + dx + ", y = " + dy);
     }
 
+    /** Setřídí seznam korektur příslušný dané straně */
     setrid_korektury() { this.korektury.sort((a, b) => a.y - b.y); }
 
+    /** Zobrazí korektury a jejich pointry (a umístí je správně pod sebe) na dané straně */
     umisti_korektury() {
       this.setrid_korektury()
 
@@ -98,11 +131,17 @@
     }
   }
 
+  // Vytvoření objektu Strana pro každou stranu
   for (const strana_img of document.getElementsByClassName('strana'))
     new Strana(strana_img);
 
+  /**
+   * Seznam stran setřízený podle toho, jak jdou po sobě (aby se dali korektury prohledávat od první na HTML stránce po poslední)
+   * @type {Strana[]}
+   */
   const setrizene_strany = Object.values(strany);
   setrizene_strany.sort((a, b) => a.htmlElement_img.offsetTop - b.htmlElement_img.offsetTop);
 
+  /** Zobrazí korektury a jejich pointry (a umístí je správně pod sebe) na všech stranách */
   function umisti_korektury() { for (const strana of Object.values(strany)) strana.umisti_korektury(); }
 </script>
diff --git a/korektury/templates/korektury/korekturovatko/zmena_stavu_pdf.html b/korektury/templates/korektury/korekturovatko/zmena_stavu_pdf.html
index 94e0be6e..61c7db25 100644
--- a/korektury/templates/korektury/korekturovatko/zmena_stavu_pdf.html
+++ b/korektury/templates/korektury/korekturovatko/zmena_stavu_pdf.html
@@ -1,3 +1,4 @@
+{# Template starající se o formulář na změnu stavu PDF (včetně jeho odeslání) #}
 <b>Změnit stav PDF:</b>
 <br>
 <form method="post" id="PDFSTAV_FORM">
@@ -12,12 +13,17 @@
 </form>
 
 <script>
+  /**
+   * Formulář měnící stav korekturovaného PDF
+   * @type {HTMLFormElement}
+   */
   const pdfstav_form = document.getElementById('PDFSTAV_FORM');
 
   /**
-   *
-   * @param {RequestInit} data
-   * @param {Boolean} catchError
+   * Fetchne stav korekturovaného PDF a změní ho na dané stránce.
+   * FIXME: nemění, který radio-button je vybrán.
+   * @param {RequestInit} data FormData a jiné náležitosti (method: POST) posílané při změně stavu korekturovaného PDF
+   * @param {Boolean} catchError jestli padat hlasitě (pokud se aktualizuje automaticky a spadne to např. na nepřítomnost sítě, pak není třeba informovat uživatele)
    */
   function fetchStav(data, catchError=true) {
     fetch("{% url 'korektury_api_pdf_stav' korekturovanepdf.id %}", data