# Nadpis
## Sekce
### Pod
**tučně**
*kurzíva*
[[Název]]
[text](url)
- položka
1. první
> citace
`kód`
---
Zadej slug výstřižku — AI vygeneruje zárodek hesla v Markdownu.
${c.trimEnd()}
$1
/g,'\n'); s = s.replace(/\[\[([^\]]+)\]\]/g,(_,t)=>`${t}`); s = s.replace(/\[([^\]]+)\]\(([^)]+)\)/g,'$1'); s = s.replace(/!\[([^\]]*)\]\(([^)]+)\)/g,''); s = parseTable(s); s = s.replace(/((?:^[ \t]*[-*+]\s.+\n?)+)/gm, b=>`${b.trim().split('\n').map(l=>`${l.replace(/^[ \t]*[-*+]\s/,'').trim()}`).join('')}`); s = s.replace(/((?:^\d+\.\s.+\n?)+)/gm, b=>`${b.trim().split('\n').map(l=>`${l.replace(/^\d+\.\s/,'').trim()}`).join('')}`); s = s.split(/\n{2,}/).map(p=>{p=p.trim();if(!p)return '';if(/^<(h[1-6]|ul|ol|blockquote|pre|hr|table)/.test(p))return p;return `${p.replace(/\n/g,' ')}`;}).join('\n'); return s; } function hid(t){return t.toLowerCase().replace(/[^a-z0-9]+/gi,'-').replace(/^-|-$/g,'');} function parseTable(s){return s.replace(/(\|.+\|\n\|[-| :]+\|\n(?:\|.+\|\n?)+)/g,b=>{const rows=b.trim().split('\n');const hd=rows[0].split('|').filter(c=>c.trim()).map(c=>`${c.trim()}`).join('');const bd=rows.slice(2).map(r=>''+r.split('|').filter(c=>c.trim()).map(c=>`${c.trim()}`).join('')+'').join('');return `${hd}${bd}`;});} // ── MD Toolbar ──────────────────────────────────────────────────────────────── function insertAtCursor(ta, before, after='', defaultText='') { const s = ta.selectionStart, e = ta.selectionEnd; const sel = ta.value.slice(s,e) || defaultText; const newVal = ta.value.slice(0,s) + before + sel + after + ta.value.slice(e); ta.value = newVal; ta.selectionStart = s + before.length; ta.selectionEnd = s + before.length + sel.length; ta.focus(); updateStats(); updatePreview(); } function insertLine(ta, prefix, defaultText='text') { const s = ta.selectionStart; const lineStart = ta.value.lastIndexOf('\n', s-1) + 1; const before = ta.value.slice(0, lineStart); const after = ta.value.slice(lineStart); const sel = ta.value.slice(ta.selectionStart, ta.selectionEnd) || defaultText; ta.value = before + prefix + sel + '\n' + after; ta.selectionStart = ta.selectionEnd = lineStart + prefix.length + sel.length; ta.focus(); updateStats(); updatePreview(); } document.querySelector('.md-toolbar').addEventListener('click', e => { const btn = e.target.closest('.md-btn[data-action]'); if (!btn) return; const ta = document.getElementById('mdInput'); switch(btn.dataset.action) { case 'h2': insertLine(ta, '## ', 'Název sekce'); break; case 'h3': insertLine(ta, '### ', 'Podnadpis'); break; case 'bold': insertAtCursor(ta, '**', '**', 'tučný text'); break; case 'italic':insertAtCursor(ta, '*', '*', 'kurzíva'); break; case 'ul': insertLine(ta, '- ', 'položka'); break; case 'ol': insertLine(ta, '1. ', 'první položka'); break; case 'bq': insertLine(ta, '> ', 'citace'); break; case 'hr': insertLine(ta, '---', ''); break; case 'link': const url = prompt('URL:', 'https://'); if (url) insertAtCursor(ta, '[', `](${url})`, 'text odkazu'); break; case 'wikilink': const art = prompt('Název wiki článku:', ''); if (art) insertAtCursor(ta, `[[${art}]]`, '', ''); break; case 'table': const tbl = '\n| Sloupec 1 | Sloupec 2 | Sloupec 3 |\n|-----------|-----------|----------|\n| hodnota | hodnota | hodnota |\n'; const pos = ta.selectionEnd; ta.value = ta.value.slice(0,pos) + tbl + ta.value.slice(pos); ta.selectionStart = ta.selectionEnd = pos + tbl.length; ta.focus(); updateStats(); updatePreview(); break; } }); document.getElementById('csToggle').addEventListener('click', () => { document.getElementById('cheatsheet').classList.toggle('open'); }); // ── Preview toggle ──────────────────────────────────────────────────────────── document.getElementById('previewToggle').addEventListener('click', () => { previewOn = !previewOn; document.getElementById('previewPane').style.display = previewOn ? '' : 'none'; document.getElementById('previewToggle').classList.toggle('on', previewOn); if (previewOn) updatePreview(); }); // ── Input events ────────────────────────────────────────────────────────────── document.getElementById('mdInput').addEventListener('input', () => { updateStats(); clearTimeout(saveTimer); saveTimer = setTimeout(updatePreview, 400); }); // Tab → 2 mezery document.getElementById('mdInput').addEventListener('keydown', e => { if (e.key === 'Tab') { e.preventDefault(); insertAtCursor(document.getElementById('mdInput'), ' ', '', ''); } if (e.key === 's' && (e.ctrlKey||e.metaKey)) { e.preventDefault(); save(); } }); // ── Uložit ──────────────────────────────────────────────────────────────────── async function save() { const title = document.getElementById('fTitle').value.trim(); const kategorie= document.getElementById('fKat').value.trim(); const tagy = document.getElementById('fTagy').value.trim(); let slug = document.getElementById('fSlug').value.trim() || slugify(title); const obsah = document.getElementById('mdInput').value; if (!title) { showToast('Zadejte název článku'); document.getElementById('fTitle').focus(); return; } if (!slug) { slug = slugify(title); document.getElementById('fSlug').value = slug; } const btn = document.getElementById('saveBtn'); btn.disabled = true; btn.textContent = 'Ukládám…'; const r = await fetch(API, { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({ action:'save', title, kategorie, tagy, slug, obsah }) }); btn.disabled = false; btn.textContent = 'Uložit'; if (r.ok) { const d = await r.json(); isNew = false; document.getElementById('fSlug').value = d.slug; updateSlugHint(); document.getElementById('stSaved').innerHTML = `Uloženo ${new Date().toLocaleTimeString('cs-CZ',{hour:'2-digit',minute:'2-digit'})}`; showToast('Uloženo ✓'); // Aktualizovat URL bez přesměrování history.replaceState({}, '', `editor.html?slug=${encodeURIComponent(d.slug)}`); } else { const err = await r.json().catch(()=>({})); if (r.status === 403) { showToast('Nejste přihlášen'); location.reload(); } else showToast('Chyba: ' + (err.error||r.status)); } } document.getElementById('saveBtn').addEventListener('click', save); // ── Toast ───────────────────────────────────────────────────────────────────── function showToast(msg, dur=2800) { const t = document.getElementById('toast'); t.textContent = msg; t.classList.add('show'); setTimeout(()=>t.classList.remove('show'), dur); } // ── Start ───────────────────────────────────────────────────────────────────── checkAuth();
${p.replace(/\n/g,' ')}