Okomentování mého zběsilého frontendu ke korekturovátku
This commit is contained in:
		
							parent
							
								
									82dc7e1a83
								
							
						
					
					
						commit
						0722729bcd
					
				
					 9 changed files with 287 additions and 33 deletions
				
			
		|  | @ -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> | ||||
|  |  | |||
|  | @ -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)) { | ||||
|  |  | |||
|  | @ -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) { | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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(); | ||||
|  |  | |||
|  | @ -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]; | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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> | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue