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/schovani_korektur.html" %} | ||||||
| 
 | 
 | ||||||
| {% include "korektury/korekturovatko/moduly/edit_komentar.html" %} | {% include "korektury/korekturovatko/moduly/edit_komentar.html" %} | ||||||
|  | @ -12,10 +13,11 @@ | ||||||
| 
 | 
 | ||||||
| <script> | <script> | ||||||
|   /** |   /** | ||||||
|    * |    * Fetchne korektury a komentáře a na základě toho aktualizuje všechno | ||||||
|    * @param {RequestInit} data |    * (korektury, komentáře, zásluhy, počty korektur v daných stavech, umístění korektur) | ||||||
|    * @param {Boolean} catchError |    * @param {RequestInit} data FormData a jiné náležitosti (method: POST) posílané při přidání/úpravě korektury/komentáře | ||||||
|    * @param pri_uspechu Akce, která se má provést při úspěchu (speciálně zavřít formulář) |    * @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. |   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) |     fetch('{% url "korektury_api_opravy_a_komentare" korekturovanepdf.id %}', data) | ||||||
|  | @ -39,7 +41,7 @@ | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   window.addEventListener("load", _ => { |   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 |       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 |   setInterval(() => aktualizuj_vse({}, false), 120000); // Každý dvě minuty fetchni korektury | ||||||
| </script> | </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> | <form id='CSRF_form' style='display: none'>{% csrf_token %}</form> | ||||||
| 
 | 
 | ||||||
| <script> | <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'); |   const CSRF_FORM = document.getElementById('CSRF_form'); | ||||||
| </script> | </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 %} | {% load static %} | ||||||
| 
 | 
 | ||||||
| <html lang='cs'> | <html lang='cs'> | ||||||
|  | @ -36,8 +37,13 @@ | ||||||
|   <hr> |   <hr> | ||||||
| 
 | 
 | ||||||
|   <script> |   <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") |     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() { |     function aktualizuj_pocty_zasluh() { | ||||||
|       const pocty_autoru = {}; |       const pocty_autoru = {}; | ||||||
|       for (let komentar of Object.values(komentare)) { |       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 %} | {% load static %} | ||||||
| 
 | 
 | ||||||
| <div id="korektury-sipky"> | <div id="korektury-sipky"> | ||||||
|  | @ -29,7 +30,6 @@ Nemusíš mačkat, pokud ti stačí, že se korektury aktualizují samy každé | ||||||
| </div> | </div> | ||||||
| 
 | 
 | ||||||
| <script> | <script> | ||||||
|   // Přidání event listenerů |  | ||||||
|   document.getElementById('predchozi-korektura').addEventListener('click', _ => { dalsi_nebo_predchozi_korektura(false) }); |   document.getElementById('predchozi-korektura').addEventListener('click', _ => { dalsi_nebo_predchozi_korektura(false) }); | ||||||
|   document.getElementById('dalsi-korektura').addEventListener('click', _ => { dalsi_nebo_predchozi_korektura(true) }); |   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") }); |   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. |   // 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)); |   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) { |   function dalsi_nebo_predchozi_korektura(dalsi=true, stav=null) { | ||||||
|     let predchozi = null; |     let predchozi = null; | ||||||
|     for (const strana of setrizene_strany) { |     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"> | <div id="korekturovaci-formular-div" style="display: none"> | ||||||
|   <input size="24" name="au" value="{{user.first_name}} {{user.last_name}}" readonly/> |   <input size="24" name="au" value="{{user.first_name}} {{user.last_name}}" readonly/> | ||||||
|   <button type="button" id="korekturovaci-formular-odesli">Oprav!</button> |   <button type="button" id="korekturovaci-formular-odesli">Oprav!</button> | ||||||
|  | @ -14,7 +15,39 @@ | ||||||
| </div> | </div> | ||||||
| 
 | 
 | ||||||
| <script> | <script> | ||||||
|  |   /** V podstatě singleton (viz korekturovaci_formular) starající se o editační/přidávací formulář. */ | ||||||
|   class _KorekturovaciFormular { |   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() { |     constructor() { | ||||||
|       this.div = document.getElementById('korekturovaci-formular-div'); |       this.div = document.getElementById('korekturovaci-formular-div'); | ||||||
|       this.text = document.getElementById('korekturovaci-formular-text'); |       this.text = document.getElementById('korekturovaci-formular-text'); | ||||||
|  | @ -36,18 +69,28 @@ | ||||||
|       this.pri_otevreni_odvyber_tagy = true; |       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) { |     vyber_nebo_odvyber_tag(event) { | ||||||
|       const button = event.target; |       const button = event.target; | ||||||
|       button.dataset.vybran = String(button.dataset.vybran === "false"); |       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"; } |     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'; } |     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) { |     _zobraz(strana, x, y) { | ||||||
|       this.odesilaci_button.disabled = false; |       this.odesilaci_button.disabled = false; | ||||||
|       this.div.style.display = 'block'; |       this.div.style.display = 'block'; | ||||||
|  | @ -59,7 +102,15 @@ | ||||||
|       this.text.focus(); |       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) { |     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; |       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); |       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() { |     odesli_formular() { | ||||||
|       this.odesilaci_button.disabled = true; |       this.odesilaci_button.disabled = true; | ||||||
|       const data = new FormData(CSRF_FORM); |       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(); |   const korekturovaci_formular = new _KorekturovaciFormular(); | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
|  | @ -1,3 +1,4 @@ | ||||||
|  | {# Template starající se o jeden každý komentář u korektury. #} | ||||||
| {% load static %} | {% load static %} | ||||||
| 
 | 
 | ||||||
| <div class='comment' id='prekomentar' {# id='k{{k.id}}' #}> | <div class='comment' id='prekomentar' {# id='k{{k.id}}' #}> | ||||||
|  | @ -24,25 +25,57 @@ | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| <script> | <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'); |   const prekomentar = document.getElementById('prekomentar'); | ||||||
|  |   /** | ||||||
|  |    * Mapování ID |-> komentář | ||||||
|  |    * @type {Object.<Number, Komentar>} | ||||||
|  |    */ | ||||||
|   const komentare = {}; |   const komentare = {}; | ||||||
| 
 | 
 | ||||||
|  |   /** Třída reprezentující jeden komentář (a starající se o vytvoření a updatování jeho HTML reprezentace) */ | ||||||
|   class Komentar { |   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) { |     static aktualizuj_nebo_vytvor(komentar_data, korektura) { | ||||||
|       const id = komentar_data['id']; |       const id = komentar_data['id']; | ||||||
|       if (id in komentare) komentare[id].aktualizuj(komentar_data); |       if (id in komentare) komentare[id].aktualizuj(komentar_data); | ||||||
|       else new Komentar(komentar_data, korektura); |       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; |     htmlElement; | ||||||
|     id; korektura; {# komentar_data; #} | 
 | ||||||
|  |     /** @type {Number} */ | ||||||
|  |     id; | ||||||
|  |     /** @type{Korektura} */ | ||||||
|  |     korektura; | ||||||
|  |     /** @type{string} */ | ||||||
|     autor; |     autor; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * |      * Vytvoří HTML reprezentaci, připojí komentář pod korekturu, nastaví event-listenery, uloží si data | ||||||
|      * @param komentar_data |      * @param {Object.<string, ?>} komentar_data „Slovník“ obsahující data daného komentáře | ||||||
|      * @param {Korektura} korektura |      * @param {Korektura} korektura korektura ke které se komentář má připojit | ||||||
|      */ |      */ | ||||||
|     constructor(komentar_data, korektura) { |     constructor(komentar_data, korektura) { | ||||||
|       this.htmlElement = prekomentar.cloneNode(true); |       this.htmlElement = prekomentar.cloneNode(true); | ||||||
|  | @ -63,28 +96,38 @@ | ||||||
|       komentare[this.id] = this; |       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) { |     aktualizuj(komentar_data) { | ||||||
|       {# this.komentar_data = komentar_data; #} |  | ||||||
|       this.set_autor(komentar_data['autor']); |       this.set_autor(komentar_data['autor']); | ||||||
|       this.set_text(komentar_data['text']); |       this.set_text(komentar_data['text']); | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * Aktualizuje/nastaví JS data i HTML reprezentaci autora komentáře | ||||||
|  |      * @param {String} autor | ||||||
|  |      */ | ||||||
|     set_autor(autor) { |     set_autor(autor) { | ||||||
|       this.#autor.textContent=autor; |       this.#autor.textContent=autor; | ||||||
|       this.autor = autor; |       this.autor = autor; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * @param {String} text | ||||||
|  |      */ | ||||||
|     set_text(text) { |     set_text(text) { | ||||||
|       this.#text.innerHTML=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() { |     #uprav_komentar() { | ||||||
|       return korekturovaci_formular.zobraz(this.korektura.strana, this.korektura.x, this.korektura.y, this.#text.textContent, this.korektura.id, this.id); |       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() { |     #smaz_komentar() { | ||||||
|       if (confirm('Opravdu smazat komentář?')) { |       if (confirm('Opravdu smazat komentář?')) { | ||||||
|         const data = new FormData(CSRF_FORM); |         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() { |     smaz_pouze_na_strance() { | ||||||
|       delete komentare[this.id]; |       delete komentare[this.id]; | ||||||
|       this.htmlElement.remove(); |       this.htmlElement.remove(); | ||||||
|  |  | ||||||
|  | @ -58,22 +58,75 @@ | ||||||
| </div> | </div> | ||||||
| 
 | 
 | ||||||
| <script> | <script> | ||||||
|  |   /** | ||||||
|  |    * Prototyp korektury, ze kterého se vygeneruje každý komentář (resp. jeho HTML reprezentace) v dokumentu | ||||||
|  |    * @type {HTMLElement} | ||||||
|  |    */ | ||||||
|   const prekorektura = document.getElementById('prekorektura'); |   const prekorektura = document.getElementById('prekorektura'); | ||||||
|  |   /** | ||||||
|  |    * Prototyp pointeru (té lomené čáry od korektury) | ||||||
|  |    * @type {HTMLElement} | ||||||
|  |    */ | ||||||
|   const prepointer = document.getElementById('prepointer'); |   const prepointer = document.getElementById('prepointer'); | ||||||
|  |   /** | ||||||
|  |    * Mapování ID |-> korektura | ||||||
|  |    * @type {Object.<Number, Korektura>} | ||||||
|  |    */ | ||||||
|   const korektury = {}; |   const korektury = {}; | ||||||
| 
 | 
 | ||||||
|  |   /** Třída reprezentující jednu korekturu (a starající se o vytvoření a updatování její HTML reprezentace) */ | ||||||
|   class Korektura { |   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) { |     static aktualizuj_nebo_vytvor(korektura_data) { | ||||||
|       const id = korektura_data['id']; |       const id = korektura_data['id']; | ||||||
|       if (id in korektury) return korektury[id].aktualizuj(korektura_data); |       if (id in korektury) return korektury[id].aktualizuj(korektura_data); | ||||||
|       else return new Korektura(korektura_data); |       else return new Korektura(korektura_data); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     #komentare; #tagy; |     /** | ||||||
|     htmlElement; pointer; |      * <div> obsahující <div>y komentářů | ||||||
|     id; x; y; strana; stav; sbalena = false; {# korektura_data; #} |      * @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; |     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) { |     constructor(korektura_data) { | ||||||
|       this.htmlElement = prekorektura.cloneNode(true); |       this.htmlElement = prekorektura.cloneNode(true); | ||||||
|       this.pointer = prepointer.cloneNode(true); |       this.pointer = prepointer.cloneNode(true); | ||||||
|  | @ -109,12 +162,25 @@ | ||||||
|       korektury[this.id] = this; |       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) { |     aktualizuj(korektura_data) { | ||||||
|       {# this.korektura_data = korektura_data; #} |  | ||||||
|       this.set_stav(korektura_data['status']); |       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.innerHTML = ""; | ||||||
|       this.tagy = new Set(); |       this.tagy = new Set(); | ||||||
|       for (const tag of korektura_data["tagy"]) { |       for (const tag of tagy) { | ||||||
|         this.tagy.add(tag["id"]); |         this.tagy.add(tag["id"]); | ||||||
|         const span = document.createElement("span"); |         const span = document.createElement("span"); | ||||||
|         span.innerHTML = tag["nazev"]; |         span.innerHTML = tag["nazev"]; | ||||||
|  | @ -122,32 +188,44 @@ | ||||||
|         span.style.backgroundColor = tag["barva"]; |         span.style.backgroundColor = tag["barva"]; | ||||||
|         this.#tagy.appendChild(span); |         this.#tagy.appendChild(span); | ||||||
|       } |       } | ||||||
|       return this; |     } | ||||||
|     }; |  | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * Aktualizuje/nastaví JS data i HTML reprezentaci stavu korektury | ||||||
|  |      * @param {String} stav | ||||||
|  |      */ | ||||||
|     set_stav(stav) { |     set_stav(stav) { | ||||||
|       this.stav = stav; |       this.stav = stav; | ||||||
|       this.htmlElement.dataset.stav_korektury=stav; |       this.htmlElement.dataset.stav_korektury=stav; | ||||||
|       this.pointer.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); } |     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() { |     sbal_nebo_rozbal() { | ||||||
|       this.sbalena = !this.sbalena; |       this.sbalena = !this.sbalena; | ||||||
|       this.htmlElement.dataset.korektura_sbalena = String(this.sbalena); |       this.htmlElement.dataset.korektura_sbalena = String(this.sbalena); | ||||||
|     } |     } | ||||||
|  |     /** Doplněk sbal_nebo_rozbal, který i přeskládá korektury. */ | ||||||
|     #sbal_nebo_rozbal(){ |     #sbal_nebo_rozbal(){ | ||||||
|       this.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); } |     #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) { |     #zmen_stav_korektury(event) { | ||||||
|       const data = new FormData(CSRF_FORM); |       const data = new FormData(CSRF_FORM); | ||||||
|       data.append('id', this.id); |       data.append('id', this.id); | ||||||
|  | @ -164,6 +242,7 @@ | ||||||
|         .catch(error => {alert('Něco se nepovedlo:' + error);}); |         .catch(error => {alert('Něco se nepovedlo:' + error);}); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** Smaže korekturu (když je zmáčknuto „smaz-korekturu“) */ | ||||||
|     #smaz_korekturu() { |     #smaz_korekturu() { | ||||||
|       if (confirm('Opravdu smazat korekturu?')) { |       if (confirm('Opravdu smazat korekturu?')) { | ||||||
|         const data = new FormData(CSRF_FORM); |         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() { |     #smaz_pouze_na_strance() { | ||||||
|       this.strana.korektury.splice(this.strana.korektury.indexOf(this), 1); |       this.strana.korektury.splice(this.strana.korektury.indexOf(this), 1); | ||||||
|       delete korektury[this.id]; |       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: | Zobrazit: | ||||||
| <input type="checkbox" id="k_oprave_checkbox" checked> | <input type="checkbox" id="k_oprave_checkbox" checked> | ||||||
| <label for="k_oprave_checkbox">K opravě (<span id="k_oprave_pocet">↺</span>)</label> | <label for="k_oprave_checkbox">K opravě (<span id="k_oprave_pocet">↺</span>)</label> | ||||||
|  | @ -30,6 +31,10 @@ Zobrazit: | ||||||
|     umisti_korektury(); |     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) |   function skryj_nebo_zobraz_korektury(aclass) | ||||||
|   { |   { | ||||||
|     const stylesheets = document.styleSheets; |     const stylesheets = document.styleSheets; | ||||||
|  | @ -56,6 +61,11 @@ Zobrazit: | ||||||
|     umisti_korektury(); |     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 = { |   const spany_s_pocty_stavu_korektur = { | ||||||
|     'k_oprave': document.getElementById('k_oprave_pocet'), |     'k_oprave': document.getElementById('k_oprave_pocet'), | ||||||
|     'opraveno': document.getElementById('opraveno_pocet'), |     'opraveno': document.getElementById('opraveno_pocet'), | ||||||
|  | @ -63,6 +73,7 @@ Zobrazit: | ||||||
|     'k_zaneseni': document.getElementById('k_zaneseni_pocet'), |     'k_zaneseni': document.getElementById('k_zaneseni_pocet'), | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   /** Aktualizuje počty korektur jednotlivých stavů */ | ||||||
|   function aktualizuj_pocty_stavu() { |   function aktualizuj_pocty_stavu() { | ||||||
|     const pocty_stavu_korektur = {}; |     const pocty_stavu_korektur = {}; | ||||||
|     for (const stav_korektury of Object.keys(spany_s_pocty_stavu_korektur)) pocty_stavu_korektur[stav_korektury] = 0; |     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 %} | {% for i in indexy_stran %} | ||||||
|   <div class='imgdiv'> |   <div class='imgdiv'> | ||||||
|     <img |     <img | ||||||
|  | @ -19,14 +20,40 @@ | ||||||
|   const MINIMALNI_VYSKA_POINTERU = 30; |   const MINIMALNI_VYSKA_POINTERU = 30; | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|  |    * Mapování index_strany |-> strana | ||||||
|    * @type {Object.<int, Strana>} |    * @type {Object.<int, Strana>} | ||||||
|    */ |    */ | ||||||
|   const strany = {}; |   const strany = {}; | ||||||
| 
 | 
 | ||||||
|  |   /** Třída spravující jednu stranu PDF a umisťující na ni příslušné korektury. */ | ||||||
|   class Strana { |   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) { |     constructor(htmlElement_img) { | ||||||
|       this.htmlElement_img = htmlElement_img; |       this.htmlElement_img = htmlElement_img; | ||||||
|       this.htmlElement_div = this.htmlElement_img.parentNode; |       this.htmlElement_div = this.htmlElement_img.parentNode; | ||||||
|  | @ -39,6 +66,10 @@ | ||||||
|       strany[this.id] = this; |       strany[this.id] = this; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * Otevře korekturovací formulář pro přidání korektury v daném místě | ||||||
|  |      * @param {MouseEvent} event | ||||||
|  |      */ | ||||||
|     #korekturuj(event) { |     #korekturuj(event) { | ||||||
|       switch (document.body.dataset.stav_pdf) { |       switch (document.body.dataset.stav_pdf) { | ||||||
|         case 'zanaseni': |         case 'zanaseni': | ||||||
|  | @ -61,8 +92,10 @@ | ||||||
|       console.log("Pro přesun korektur: strana = " + this.id + ", x = " + dx + ", y = " + dy); |       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); } |     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() { |     umisti_korektury() { | ||||||
|       this.setrid_korektury() |       this.setrid_korektury() | ||||||
| 
 | 
 | ||||||
|  | @ -98,11 +131,17 @@ | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   // Vytvoření objektu Strana pro každou stranu | ||||||
|   for (const strana_img of document.getElementsByClassName('strana')) |   for (const strana_img of document.getElementsByClassName('strana')) | ||||||
|     new Strana(strana_img); |     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); |   const setrizene_strany = Object.values(strany); | ||||||
|   setrizene_strany.sort((a, b) => a.htmlElement_img.offsetTop - b.htmlElement_img.offsetTop); |   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(); } |   function umisti_korektury() { for (const strana of Object.values(strany)) strana.umisti_korektury(); } | ||||||
| </script> | </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> | <b>Změnit stav PDF:</b> | ||||||
| <br> | <br> | ||||||
| <form method="post" id="PDFSTAV_FORM"> | <form method="post" id="PDFSTAV_FORM"> | ||||||
|  | @ -12,12 +13,17 @@ | ||||||
| </form> | </form> | ||||||
| 
 | 
 | ||||||
| <script> | <script> | ||||||
|  |   /** | ||||||
|  |    * Formulář měnící stav korekturovaného PDF | ||||||
|  |    * @type {HTMLFormElement} | ||||||
|  |    */ | ||||||
|   const pdfstav_form = document.getElementById('PDFSTAV_FORM'); |   const pdfstav_form = document.getElementById('PDFSTAV_FORM'); | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * |    * Fetchne stav korekturovaného PDF a změní ho na dané stránce. | ||||||
|    * @param {RequestInit} data |    * FIXME: nemění, který radio-button je vybrán. | ||||||
|    * @param {Boolean} catchError |    * @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) { |   function fetchStav(data, catchError=true) { | ||||||
|     fetch("{% url 'korektury_api_pdf_stav' korekturovanepdf.id %}", data |     fetch("{% url 'korektury_api_pdf_stav' korekturovanepdf.id %}", data | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue