"use strict"; var section, listMain, listLists, listCats, indexCats, listorder = 0, LIST_CELLS = 5, showcat = undefined, curList = -1, curSide = 0, curHigh = -1, curHighId, editing = false; function $(id){ return document.getElementById(id); } function http(method, url, callback, body){ var r = new XMLHttpRequest(); r.onreadystatechange = function() { if (r.readyState == 4) callback(r.responseText); }; r.open(method, url, true); r.send(body); } function today(){ var o = new Date(), d = [o.getDate(), o.getMonth()+1, o.getFullYear()]; for(var i = 0; i < d.length; ++i) d[i] = (d[i] < 10 ? "0" : "")+d[i]; return d.join("."); } function stav(msg){ $("stav").innerHTML = msg; } function encode(t){ return encodeURIComponent(t); } function encodeObject(o){ return encode(JSON.stringify(o)); } function log(text){ http("post", "/log:"+encode(text), noop); } function posunSeznam(){ var e = $("list"), top = $("header").clientHeight; e.style.marginTop = top+"px"; e.getElementsByTagName("thead")[0].style.top = (top-1)+"px"; } function exit(){ document.getElementsByTagName("body")[0].innerHTML = '
'; http("post", "/exit", stav); } function noop(){} function highlight(ev){ var e = ev.target; if(e.localName == "td") e = e.parentElement; if(e.localName != "tr") return; if(curHigh != -1){ if(editing){ curHigh = +e.getAttribute("data-i"); newRecordCb({target: editing.getElementsByTagName("button")[0]}); return; } else unhighlight(); } if(e.children.length == LIST_CELLS){ var ne = document.createElement("td"); ne.innerHTML = '' +'' +' ' +' ' +' '; e.appendChild(ne); if(curList == -1) ne.children[0].children[0].style.display = "none"; } e.className = "highlight"; curHigh = +e.getAttribute("data-i"); } function edit(ev){ var td = ev.target.parentElement.parentElement, tr = td.parentElement, c = tr.children, data = listMain[curHigh]; editing = tr; c[0].innerHTML = ''; c[1].innerHTML = ''; c[2].innerHTML = ''; var chunks = ['') c[3].innerHTML = chunks.join(""); c[4].innerHTML = ''; for(var i = 0; i < LIST_CELLS; ++i) c[i].children[0].value = data[i+1]; c[0].children[0].focus(); td.innerHTML = '' +' '; } function editCancel(ev){ var tr = ev.target.parentElement.parentElement, c = tr.children, id = tr.getAttribute("data-i"), data = listMain[id]; editing = false; for(var i = 0; i < 3; ++i) c[i].innerHTML = data[i+1]; c[3].innerHTML = (data[4] != undefined && indexCats[data[4]] || ""); c[4].innerHTML = data[4+1]; tr.removeChild(c[LIST_CELLS]); if(curHigh == id) highlight({target: tr}); } function remove(){ if(!confirm('Opravdu smazat "'+listMain[curHigh][2]+'"?')) return; editing = false; stav("Odstraňování..."); http("post", "/list:-1:"+curHigh, updateListMainCb); } function unhighlight(){ if(curHigh == -1) return; var e = document.getElementsByClassName("highlight")[0]; if(!e) return; e.className = ""; curHigh = -1; var c = e.children[LIST_CELLS]; if(c && c.children[0].className == "admin") e.removeChild(c); } function getList(id, callback){ http("get", "/list:"+id, callback); } function updateListMainCb(res){ curHighId = curHigh == -1 ? undefined : listMain[curHigh][1]; try{ listMain = JSON.parse(res); }catch(e){ stav(res); return; } curHigh = -1; for(var i = 0; i < listMain.length; ++i) if(listMain[i][1] === curHighId){ curHigh = i; break; } renderListMain(); stav(""); } function setsort(col){ listorder = col + 1; renderListMain(); } function numericCompare(a,b){ a = a[1][listorder]; b = b[1][listorder]; var enda = 0, endb = 0; if(typeof a == "number"){ if(typeof b == "number"){ return a - b; } a = a.toString(); enda = a.indexOf("."); if(enda == -1) enda = a.length; ++enda; } else if(typeof b == "number"){ b = b.toString(); endb = b.indexOf("."); if(endb == -1) endb = b.length; ++endb; } if(!enda) while(enda <= a.length && !isNaN(a.substring(0,enda))) ++enda; if(!endb) while(endb <= b.length && !isNaN(b.substring(0,endb))) ++endb; if(enda != endb) return enda - endb; return a.localeCompare(b); } function filterListMain(){ var list = []; for(var i = 0; i < listMain.length; ++i){ var li = listMain[i]; if(li[0] == section && (showcat === undefined || li[4] === showcat)){ list.push([i,li]); } } if(listorder>0) list.sort(numericCompare); return list; } function renderListMain(){ var chunks = [], high = -1, list = filterListMain(); if(!list.length) chunks.push('Žádná položka k zobrazení'); else for(var j = 0; j < list.length; ++j){ var i = list[j][0], li = list[j][1]; for(var k = li.length; k < 6; ++k) li[k] = ""; if(i == curHigh) high = j; chunks.push( '', li[1], '', li[2], '', li[3], '', (li[4] != undefined && indexCats[li[4]] || ""), '', li[5], '' ); } $("listbody").innerHTML = chunks.join(""); if(high != -1) highlight({target: $("listbody").children[high]}); } function newRecord(){ if($("newid")) { $("newid").focus(); return; } var e = document.createElement("tr"); e.setAttribute("data-i","-1"); var chunks = ['', '', ' ', '') e.innerHTML = chunks.join(""); $("listbody").appendChild(e); e.children[0].children[0].focus(); } function newRecordCb(ev){ var tr = ev.target.parentElement.parentElement, idx = tr.getAttribute("data-i"), e = tr.children[0].children[0], ne = tr.children[1].children[0], id = e.value, name = ne.value, date = tr.children[2].children[0].value, cat = tr.children[3].children[0].value, note = tr.children[4].children[0].value; if(!id.length){ stav("Chybí číslo"); e.focus(); return; } for(var i = 0; i < listMain.length; ++i) if(section == listMain[i][0] && id == listMain[i][1] && i != idx){ stav("Číslo je již obsazené"); e.focus(); return; } if(!name.length){ stav("Chybí název"); ne.focus(); return; } if(id.length && !isNaN(id)) id = +id; var arr = [section, id, name, date]; if(cat.length || note.length){ if(cat.length && !isNaN(cat)) cat = +cat; arr.push(cat); if(note.length) arr.push(note); } else if(!date.length){ arr.pop(); } stav("Ukládání..."); editing = false; http("post", "/list:-1:"+idx+":"+encodeObject(arr), updateListMainCb); } function newRecordCancel(){ var e = $("newid").parentElement.parentElement; e.parentElement.removeChild(e); } function exportList(){ var table = [["Číslo","Název","Kategorie","Poznámka"]]; // idx 1, 2, *4, 5 var list = filterListMain(); if(!list.length) table.push(["","Žádná položka k zobrazení"]); else for(var i = 0; i < list.length; ++i){ var li = list[i][1]; var row = [li[1], li[2]]; if(li.length > 4 && (typeof li[4] == "number" || (li.length > 5 && li[5].length) )) { // cat or note present if(typeof li[4] == "number") row.push(indexCats[li[4]]); else if(li.length > 5 && li[5].length) row.push(""); if(li.length > 5 && li[5].length) row.push(li[5]); } table.push(row); } exportTable( $("sectionswitch").children[section].innerHTML + (showcat === undefined ? "" : (" - " + indexCats[li[4]])) + " - " + new Date().toLocaleDateString(), table ); } function exportSubList(){ getList(listID(curList), exportSubListCb); } function exportSubListCb(items){ items = JSON.parse(items); var table = [["","Číslo","Název","Poznámka"]]; // idx #, *1, *2, *5 if(!items.length) table.push(["","","Seznam je prázdný"]) else for(var i = 0; i < items.length; ++i){ var name = '(odstraněná)', note, id = items[i]; for(var j = 0; j < listMain.length; ++j){ if(listMain[j][0] == section && listMain[j][1] == id){ name = listMain[j][2]; note = listMain[j][5]; break; } } var row = [i+1+".", id, name]; if(typeof note != "undefined") row.push(note); table.push(row); } exportTable(listName(curList), table); } function exportTable(title, table){ var colWidth = []; for(var i = 0; i < table[0].length; ++i) colWidth[i] = 0; for(var i = 0; i < table.length; ++i) for(var j = 0; j < table[i].length; ++j) { switch(typeof table[i][j]) { case "undefined": table[i][j] = ""; break; case "string": break; case "number": table[i][j] = table[i][j].toString(); break; } if(colWidth[j] < table[i][j].length) colWidth[j] = table[i][j].length; } var rows = [title,"=================================================="]; for(var i = 0; i < table.length; ++i) { for(var j = 0; j < table[i].length; ++j) { if(j+1 < table[i].length) { while(table[i][j].length < colWidth[j]) table[i][j] += " "; } } rows.push(table[i].join(" ")); } exportFile(title + ".txt", rows.join("\n")); } function exportFile(name, content){ let a = document.createElement('a'); a.href = URL.createObjectURL(new Blob([content], {type: 'text/plain'})); a.download = name; document.body.appendChild(a); a.click(); document.body.removeChild(a); } function listID(i){ return listLists[i][1]; } function listName(i){ return listLists[i][2]; } function newSide(){ if($("newname")) return; var e = document.createElement("div"); e.innerHTML = ''; $("sidebar").appendChild(e); $("newname").focus(); posunSeznam(); } function newSideCb(){ var name = $("newname").value; if(!name.length) return; stav("Vytváření..."); var newid = 0; var list = curSide == 1 ? listCats : listLists; for(var i = 0; i < list.length; ++i) if(list[i][1] > newid) newid = list[i][1]; // last used cats/lists list entry id if(curSide == 1) for(var i = 0; i < listMain.length; ++i) if(listMain[i][4] > newid) newid = listMain[i][4]; // last used cat id ++newid; http("post", "/list:"+(curSide-4)+":-1:"+encodeObject([section, newid, name]), function(res){ var list; try{ list = JSON.parse(res); }catch(e){ stav(res); return; } if(curSide == 1){ updateListCats(list); showCats(); var e = document.getElementsByClassName("newcat"); for(var i = 0; i < e.length; ++i){ var ne = document.createElement("option"); ne.value = newid ne.innerHTML = name e[i].appendChild(ne); } } else{ listLists = list; showLists(); } stav(""); }); } function showList(i){ $("sublistname").innerHTML = listName(i); $("sublistbody").innerHTML = 'Načítání seznamu...' $("sublist").style.display = ""; curList = i; posunSeznam(); getList(listID(i), showListCb); } function showListCb(items){ items = JSON.parse(items); var chunks = []; if(!items.length) chunks.push('Seznam je prázdný') else for(var i = 0; i < items.length; ++i){ var name = '(odstraněná)', note, id = items[i]; for(var j = 0; j < listMain.length; ++j){ if(listMain[j][0] == section && listMain[j][1] == id){ name = listMain[j][2]; note = listMain[j][5]; break; } } chunks.push( '', (i+1), '', id, '', name, '', note, '' ); if(i > 0) chunks.push(''); chunks.push(''); if(i < items.length - 1) chunks.push(''); chunks.push( '' ); } $("sublistbody").innerHTML = chunks.join(""); var la = document.getElementsByClassName("listAdd"); for(var i = 0; i < la.length; ++i) la[i].style.display = ""; closeSidebar(); //posunSeznam(); } function listUpdateFn(str){ http("post", "/list:"+listID(curList)+str, function(res){ try{ JSON.parse(res); showListCb(res); stav(""); }catch(e){ stav(res); } }); } function listAdd(){ if(curList == -1 || curHigh == -1) return; var id = listMain[curHigh][1]; stav("Přidávání do seznamu..."); listUpdateFn(":-1:"+encodeObject(id)); } function listSwap(i){ stav("Změna pořadí v seznamu..."); listUpdateFn(":"+i+":s"); } function listRemove(i){ if(!confirm('Opravdu odstranit položku ze seznamu?')) return; stav("Odstraňování ze seznamu..."); listUpdateFn(":"+i) } function renameList(){ var e = $("sublistname"); if(e.children.length) return; e.innerHTML = '' +'>'; e = $("newname"); e.value = listName(curList); e.focus(); } function renameListCb(){ var i = curList; var n = $("newname").value; stav("Přejmenování seznamu..."); http("post", "/list:-2:"+curList+":"+encodeObject([section, listID(curList), n]), function(res){ try{ listLists = JSON.parse(res); }catch(e){ stav(res); return; } if(curSide == 2) showLists(); if(curList == i) $("sublistname").innerHTML = n; stav(""); } ); } function deleteList(){ if(!confirm('Opravdu odstranit seznam "'+listName(curList)+'"?')) return; stav("Odstraňování seznamu..."); http("post", "/list:-2:"+curList, function(res){ closeList(); try{ listLists = JSON.parse(res); }catch(e){ stav(res); return; } if(curSide == 2) showLists(); stav(""); }); } function closeList(){ var la = document.getElementsByClassName("listAdd"); for(var i = 0; i < la.length; ++i) la[i].style.display = "none"; curList = -1; $("sublist").style.display = "none"; posunSeznam(); } function showSide(){ var chunks = [ '

', curSide == 1 ? "Kategorie" : "Seznamy", '', '

', ], list, show; if(curSide == 1){ list = listCats; show = 'Cat'; } else { list = listLists; show = 'List' } var olen = chunks.length; for(var i = list.length - 1; i >= 0; --i) if(list[i][0] == section) chunks.push('
', list[i][2], '
'); if(olen == chunks.length) chunks.push('
Žádná položka k zobrazení
'); $("sidebar").innerHTML = chunks.join(""); posunSeznam(); } function showLists(){ curSide = 2; closeList(); showSide(); } function showCats(){ curSide = 1; showSide(); } function showCat(i){ $("resetcat").style.display = ""; showcat = listCats[i][1]; renderListMain(); } function resetCat(){ $("resetcat").style.display = "none"; showcat = undefined; renderListMain(); } function closeSidebar(){ curSide = 0; $("sidebar").innerHTML = ""; posunSeznam(); } function renderLists(){ renderListMain(); if(curSide == 1) showCats(); else if(curSide == 2) showLists(); if(curList != -1) showList(curList); } function updateListCats(data){ listCats = data; indexCats = []; for(var i = 0; i < listCats.length; ++i) indexCats[listCats[i][1]] = listCats[i][2]; } function initLists(data){ data = JSON.parse(data); listMain = data[0];// [ [section, cislo, nazev, datum_zarazeni, kategorie, poznamka] ] listLists = data[1];// [ [section, serial, popis="Aktuální seznam"] ] initSectionSwitch(); updateListCats(data[2]); renderLists(); stav(""); } function updatePerms(perms){ switch(+perms){ case 0: document.body.className = "nolocal noadmin"; break; case 1: document.body.className = "nolocal"; break; case 2: document.body.className = ""; break; } $("login").style.display = perms == 0 ? "" : "none"; $("logout").style.display = perms == 1 ? "" : "none"; posunSeznam(); } function loginForm(){ $("loginform").style.display = ""; $("login").style.display = "none"; $("loginpw").focus(); posunSeznam(); } function login(){ http("post", "/login", updatePerms, $("loginpw").value); loginClose(); } function loginClose(){ $("loginform").style.display = "none"; $("login").style.display = ""; $("loginpw").value = ""; posunSeznam(); } function logout(){ http("post", "/login", function(){updatePerms(0);}); } function initSectionArg(){ var l = document.location.href; l = +l.substring(l.lastIndexOf("/")+2); section = isNaN(l) ? 0 : l; } function initSectionSwitch(){ var e = $("sectionswitch"); var l = []; for(var i = 0; i < listMain.length; ++i) if(listMain[i][0] == -1) l[listMain[i][1]] = ""; e.innerHTML = l.join(" "); e = e.children[section]; e.innerHTML = e.children[0/* button, the only child */].innerHTML; } function newSection(){ $("newsection").style.display = "none"; $("newsectionform").style.display = ""; $("newsectionname").focus(); } function newSectionCb(){ var name = $("newsectionname").value; if(!name.length) return; stav("Vytváření sekce..."); newSectionClose(); var e = $("sectionswitch"); http("post", "/list:-1:-1:"+encodeObject([-1, e.children.length, name]), loadLists); } function newSectionClose(){ $("newsectionform").style.display = "none"; $("newsectionname").value = ""; $("newsection").style.display = ""; } function switchSection(ev){ if(ev.target.localName != 'button') return; var p = ev.target.parentElement, // span sections = p.parentElement.children; // #sectionswitch var id = -1; for(var i = 0; i < sections.length; ++i) if(sections[i] == p){ id = i; break; } if(id < 0) return; var prev = sections[section]; prev.innerHTML = ''; section = id; if(typeof history.pushState == 'function'){ history.pushState(undefined, "", ":"+id); } p.innerHTML = ev.target.innerHTML; if(curList != -1) closeList(); renderLists(); } function loadLists(){ stav("Načítání..."); getList(-4, initLists); } function loadPerms(){ http("get", "/perms", updatePerms); } window.onkeyup = function(ev){ if(ev.target == document.body && (ev.keyCode == 49 /*+*/ || ev.keyCode == 107 /*Num+*/)) newRecord(); else if(ev.keyCode == 13 && ev.target.tagName == "INPUT"){ switch(ev.target.parentElement.tagName){ case "DIV": case "SPAN": ev.target.nextElementSibling.focus(); break; case "TD": ev.target.parentElement.nextElementSibling.children[0].focus(); break; } } }; log(navigator.userAgent); initSectionArg(); loadLists(); loadPerms();