diff --git a/VERSION b/VERSION index 76482c7..176746d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1112 \ No newline at end of file +1113 \ No newline at end of file diff --git a/backend/static/index.html b/backend/static/index.html index 02a2004..d2b53fe 100644 --- a/backend/static/index.html +++ b/backend/static/index.html @@ -86,14 +86,14 @@ Ban Yaro - + - - - - - + + + + + @@ -617,11 +617,11 @@ - - - - - + + + + + @@ -631,7 +631,7 @@ - + diff --git a/backend/static/js/app.js b/backend/static/js/app.js index 84f25ec..f9e13fb 100644 --- a/backend/static/js/app.js +++ b/backend/static/js/app.js @@ -3,7 +3,7 @@ Router, State-Management, Navigation, Initialisierung. ============================================================ */ -const APP_VER = '1112'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen +const APP_VER = '1113'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen const APP_VERSION = '1.6.0'; // ← semantische Version, wird bei make release gesetzt window.APP_VER = APP_VER; // global verfügbar für andere Module (z.B. offline-indicator) window.APP_VERSION = APP_VERSION; diff --git a/backend/static/js/pages/admin.js b/backend/static/js/pages/admin.js index 13e56af..5002350 100644 --- a/backend/static/js/pages/admin.js +++ b/backend/static/js/pages/admin.js @@ -202,7 +202,7 @@ window.Page_admin = (() => { // Manager-Tabelle const managerRows = d.managers.map(m => ` - ${_esc(m.name)} + ${UI.escape(m.name)} ${m.published} ${m.with_link} ${m.published > 0 ? ` @@ -241,13 +241,13 @@ window.Page_admin = (() => { ${_fmt(p.published_at)} ${_esc(p.topic)} + white-space:nowrap">${UI.escape(p.topic)} ${_PL[p.platform]||p.platform||'–'} - ${_esc(p.category||'–')} + ${UI.escape(p.category||'–')} ${p.ai_score ? '⭐'.repeat(p.ai_score) : '–'} - ${_esc(p.manager||'–')} + ${UI.escape(p.manager||'–')} ${p.post_url - ? `🔗 Link` : ``} `).join(''); @@ -319,7 +319,7 @@ window.Page_admin = (() => { try { d = await API.get('/admin/analytics'); } catch (err) { el.innerHTML = `
- ${UI.icon('warning')} Fehler: ${_esc(err.message || String(err))}
`; + ${UI.icon('warning')} Fehler: ${UI.escape(err.message || String(err))}`; return; } @@ -396,7 +396,7 @@ window.Page_admin = (() => { const pct = ((p[valKey] ?? 0) / maxV * 100).toFixed(0); return `
- ${_esc(p[labelKey] || '—')} + ${UI.escape(p[labelKey] || '—')} ${fmt(p[valKey] ?? 0)}
@@ -549,7 +549,7 @@ window.Page_admin = (() => { box-shadow:0 0 4px ${dot}"> ${label} · - ${_esc(model)} + ${UI.escape(model)} Modus: ${ki.local_reachable ? 'local' : 'cloud'} @@ -641,8 +641,8 @@ window.Page_admin = (() => { ${(kiH.top_users).map(u => ` - ${_esc(u.name)} - ${_esc(u.email.length > 22 ? u.email.split('@')[1] : u.email)} + ${UI.escape(u.name)} + ${UI.escape(u.email.length > 22 ? u.email.split('@')[1] : u.email)} ${u.cloud} ${u.total} ${u.last_date?.slice(5) || '—'} @@ -837,24 +837,24 @@ window.Page_admin = (() => { background:var(--c-surface-2); display:flex;align-items:center;justify-content:center; font-weight:var(--weight-bold);color:var(--c-text-secondary)"> - ${_esc(u.name[0].toUpperCase())} + ${UI.escape(u.name[0].toUpperCase())}
- ${_esc(u.name)} + ${UI.escape(u.name)} ${u.is_banned ? ` GESPERRT` : ''}
- ${_esc(u.email)} · + ${UI.escape(u.email)} · - ${_esc(u.rolle)} + ${UI.escape(u.rolle)} · - ${_esc(u.subscription_tier || 'standard')} + ${UI.escape(u.subscription_tier || 'standard')} · ${u.dog_count} Hund${u.dog_count !== 1 ? 'e' : ''} · ${u.thread_count} Threads @@ -875,28 +875,28 @@ window.Page_admin = (() => {
${u.is_banned - ? `` - : `` } ${isAdmin ? ` @@ -1087,18 +1087,18 @@ window.Page_admin = (() => {
${r.resolved ? '✓ Erledigt · ' : ''} - ${_esc(r.target_type)} #${r.target_id} · - Gemeldet von ${_esc(r.melder_name)} + ${UI.escape(r.target_type)} #${r.target_id} · + Gemeldet von ${UI.escape(r.melder_name)}
- Grund: ${_esc(r.grund)} + Grund: ${UI.escape(r.grund)}
${r.content_preview ? `
- ${_esc(r.content_preview)} + ${UI.escape(r.content_preview)}
` : ''}
@@ -1175,10 +1175,10 @@ window.Page_admin = (() => {
- ${t.is_deleted ? '' : ''}${_esc(t.titel)}${t.is_deleted ? '' : ''} + ${t.is_deleted ? '' : ''}${UI.escape(t.titel)}${t.is_deleted ? '' : ''}
- von ${_esc(t.autor_name)} · + von ${UI.escape(t.autor_name)} · ${t.antworten} Antworten · ${t.is_pinned ? '📌 ' : ''}${t.is_locked ? '🔒 ' : ''}${t.is_deleted ? '🗑 gelöscht' : ''}
@@ -1313,8 +1313,8 @@ window.Page_admin = (() => { return `
` + `${r.t} ` + `${r.l} ` + - `${_esc(r.n)} ` + - `${_esc(r.m)}
`; + `${UI.escape(r.n)} ` + + `${UI.escape(r.m)}
`; }).join('') || 'Keine Einträge'; }; el.querySelector('#adm-sys-refresh').addEventListener('click', () => { @@ -1385,13 +1385,13 @@ window.Page_admin = (() => { const scoreBar = v => `${v.toFixed(1)}`; const rows = d.results.filter(r => !r.error).map(r => ` - ${_esc(r.name)} + ${UI.escape(r.name)} ${scoreBar(r.vollstaendigkeit)} ${scoreBar(r.korrektheit)} ${scoreBar(r.sprachqualitaet)} ${scoreBar(r.konsistenz)} ${scoreBar(r.gesamt)} - ${_esc(r.hinweis || '')} + ${UI.escape(r.hinweis || '')} ` ).join(''); box.style.display = 'block'; @@ -1459,9 +1459,9 @@ window.Page_admin = (() => {
- Python ${_esc(s.python_version)} + Python ${UI.escape(s.python_version)} - APP v${typeof APP_VER !== 'undefined' ? APP_VER : '—'} · ${_esc(s.sw_version || '?')} + APP v${typeof APP_VER !== 'undefined' ? APP_VER : '—'} · ${UI.escape(s.sw_version || '?')}
@@ -1504,9 +1504,9 @@ window.Page_admin = (() => { const userRows = topUsers.map(u => { const emailDisplay = (u.email || '').length > 20 ? '@' + (u.email || '').split('@')[1] - : _esc(u.email || ''); + : UI.escape(u.email || ''); return ` - ${_esc(u.name || '–')} + ${UI.escape(u.name || '–')} ${emailDisplay} ${u.total ?? 0} ${u.last_week || '–'} @@ -1549,7 +1549,7 @@ window.Page_admin = (() => {
30 Tage - ${_esc(lastDate)} + ${UI.escape(lastDate)}
${topUsers.length ? ` @@ -1704,12 +1704,12 @@ window.Page_admin = (() => { ${zuchterPending.map((z, i) => ` - ${_esc(z.rasse_slug)} - ${_esc(z.name)}${z.zwingername ? `
${_esc(z.zwingername)}` : ''} - ${_esc([z.plz, z.ort, z.bundesland].filter(Boolean).join(' '))} + ${UI.escape(z.rasse_slug)} + ${UI.escape(z.name)}${z.zwingername ? `
${UI.escape(z.zwingername)}` : ''} + ${UI.escape([z.plz, z.ort, z.bundesland].filter(Boolean).join(' '))} ${z.vdh_mitglied ? ` VDH` : '—'} ${_ageLabel(z.created_at)} - ${z.website ? `Link` : '—'} + ${z.website ? `Link` : '—'} @@ -1719,8 +1719,8 @@ window.Page_admin = (() => { } // Züchter-History if (zuchterDone.length) html += _historySection('Züchter-Einreichungen', zuchterDone, - z => `${_esc(z.name)} · ${_esc(z.rasse_slug)} · - ${UI.icon('check-circle')} ${_esc(z.verified_by_name||'?')} · ${(z.verified_at||'').slice(0,10)}`); + z => `${UI.escape(z.name)} · ${UI.escape(z.rasse_slug)} · + ${UI.icon('check-circle')} ${UI.escape(z.verified_by_name||'?')} · ${(z.verified_at||'').slice(0,10)}`); // --- Wiki-Foto-Einreichungen --- html += `

${fotosPending.map(f => `
- -
${_esc(f.rasse_name)}
-
von ${_esc(f.user_name)}
+
${UI.escape(f.rasse_name)}
+
von ${UI.escape(f.user_name)}
${_ageLabel(f.created_at)}
- ${f.aktuell_foto ? `Aktuell
↑ aktuelles Foto
` : ''} @@ -1756,10 +1756,10 @@ window.Page_admin = (() => { // Fotos-History if (fotosDone.length) html += _historySection('Foto-Einreichungen', fotosDone, - f => ` - ${_esc(f.rasse_name||'?')} · von ${_esc(f.user_name||'?')} · + f => ` + ${UI.escape(f.rasse_name||'?')} · von ${UI.escape(f.user_name||'?')} · ${f.status==='approved' ? `${UI.icon('check-circle')} genehmigt` : `${UI.icon('x-circle')} abgelehnt`} - ${f.reviewed_by_name ? ` von ${_esc(f.reviewed_by_name)}` : ''} · ${(f.reviewed_at||'').slice(0,10)}`); + ${f.reviewed_by_name ? ` von ${UI.escape(f.reviewed_by_name)}` : ''} · ${(f.reviewed_at||'').slice(0,10)}`); // --- Forum-Meldungen --- html += `

- ${_esc(r.target_type)} #${r.target_id} · Gemeldet von ${_esc(r.melder_name || '?')} + ${UI.escape(r.target_type)} #${r.target_id} · Gemeldet von ${UI.escape(r.melder_name || '?')} ${_ageLabel(r.created_at)}
- Grund: ${_esc(r.grund)} + Grund: ${UI.escape(r.grund)}
${r.content_preview ? `
${_esc(r.content_preview)}
` : ''} + border-radius:var(--radius-sm)">${UI.escape(r.content_preview)}
` : ''}

@@ -2053,11 +2053,11 @@ window.Page_admin = (() => { body: docs.length ? `` : `

Keine Dokumente hochgeladen.

`, @@ -2155,12 +2155,12 @@ window.Page_admin = (() => { const rows = breeders.map(b => ` -
${_esc(b.name)}
-
${_esc(b.email)}
+
${UI.escape(b.name)}
+
${UI.escape(b.email)}
- ${_esc(b.zwingername || '—')} - ${_esc(b.rasse_text || '—')} - ${_esc(b.stadt || '—')} + ${UI.escape(b.zwingername || '—')} + ${UI.escape(b.rasse_text || '—')} + ${UI.escape(b.stadt || '—')} ${b.wuerfe_count || 0} Würfe
${b.hunde_count || 0} Hunde @@ -2171,7 +2171,7 @@ window.Page_admin = (() => { @@ -2241,17 +2241,17 @@ window.Page_admin = (() => { ${jobs.map((j, i) => ` - ${_esc(j.name)} -
${_esc(j.id)}
+ ${UI.escape(j.name)} +
${UI.escape(j.id)}
${j.next_run_time ? _formatDateTime(j.next_run_time) : ''} - ${_esc(j.trigger)} + ${UI.escape(j.trigger)} - @@ -2542,11 +2542,11 @@ window.Page_admin = (() => { background:var(--c-bg-elevated);border-radius:var(--radius-md);border:1px solid var(--c-border)">
- ${_esc(t.label)} + ${UI.escape(t.label)} ${accountBadge(t.from_account)}
- ${_esc(t.subject)} + ${UI.escape(t.subject)}
@@ -2632,9 +2632,9 @@ window.Page_admin = (() => { onmouseover="this.style.background='var(--c-surface-2)'" onmouseout="this.style.background=''"> ${accountBadge(l.from_account)} - ${_esc(l.recipient)} - ${_esc(l.subject)} - ${_esc(l.sent_by_name || '')} + ${UI.escape(l.recipient)} + ${UI.escape(l.subject)} + ${UI.escape(l.sent_by_name || '')} ${(l.sent_at||'').slice(0,16).replace('T',' ')} `).join('')} @@ -2650,17 +2650,17 @@ window.Page_admin = (() => { const l = log[Number(row.dataset.logIdx)]; if (!l) return; UI.modal.open({ - title: _esc(l.subject), + title: UI.escape(l.subject), body: `
- An: ${_esc(l.recipient)}  ·  - Von: ${_esc(l.from_account)}@banyaro.app  ·  + An: ${UI.escape(l.recipient)}  ·  + Von: ${UI.escape(l.from_account)}@banyaro.app  ·  ${(l.sent_at||'').slice(0,16).replace('T',' ')}
${_esc(l.body || '(kein Text gespeichert)')}
`, + color:var(--c-text)">${UI.escape(l.body || '(kein Text gespeichert)')}`, footer: ``, }); }); @@ -2733,7 +2733,7 @@ window.Page_admin = (() => {
+ value="${UI.escape(tpl?.key || '')}" ${isNew ? '' : 'readonly'}>
@@ -2746,17 +2746,17 @@ window.Page_admin = (() => {
+ value="${UI.escape(tpl?.label || '')}">
+ value="${UI.escape(tpl?.subject || '')}">
+ style="font-family:monospace;font-size:var(--text-sm);resize:vertical">${UI.escape(tpl?.body || '')}
`, footer: ` @@ -2826,14 +2826,14 @@ window.Page_admin = (() => { ${_formatDateTime(r.created_at)} - ${_esc(r.admin_name || '—')} + ${UI.escape(r.admin_name || '—')} - ${_esc(r.action)} - ${r.detail ? `
${_esc(r.detail)}
` : ''} + ${UI.escape(r.action)} + ${r.detail ? `
${UI.escape(r.detail)}
` : ''} - ${_esc(r.target || '—')} + ${UI.escape(r.target || '—')} `).join('')} @@ -2889,11 +2889,6 @@ window.Page_admin = (() => { `; } - function _esc(s) { - if (!s) return ''; - return String(s).replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"'); - } - // ------------------------------------------------------------------ // BEWERBUNGEN — Social-Media-Job // ------------------------------------------------------------------ @@ -2932,19 +2927,19 @@ window.Page_admin = (() => {
-
${_esc(r.name)} - ${r.username ? `(@${_esc(r.username)})` : ''} +
${UI.escape(r.name)} + ${r.username ? `(@${UI.escape(r.username)})` : ''}
- ${_esc(r.email)} · @${_esc(r.social_handle||'—')} - ${r.dog_name ? ` · 🐕 ${_esc(r.dog_name)} (${_esc(r.dog_rasse||'')})` : ''} + ${UI.escape(r.email)} · @${UI.escape(r.social_handle||'—')} + ${r.dog_name ? ` · 🐕 ${UI.escape(r.dog_name)} (${UI.escape(r.dog_rasse||'')})` : ''}
${r.created_at?.slice(0,16).replace('T',' ')} · ${r.doc_count} Anhang/Anhänge
- ${_esc((r.motivation||'').slice(0,200))}${(r.motivation||'').length>200?'…':''} + ${UI.escape((r.motivation||'').slice(0,200))}${(r.motivation||'').length>200?'…':''}
@@ -2976,25 +2971,25 @@ window.Page_admin = (() => { const docsHtml = app.docs?.length ? app.docs.map(d => ` - 📎 ${_esc(d.filename)}`).join('') + 📎 ${UI.escape(d.filename)}`).join('') : 'Keine Anhänge'; UI.modal.open({ - title: `Bewerbung — ${_esc(app.name)}`, + title: `Bewerbung — ${UI.escape(app.name)}`, body: `
-
E-Mail: ${_esc(app.email)}
-
Social: @${_esc(app.social_handle||'—')}
- ${app.dog_name ? `
Hund: ${_esc(app.dog_name)} (${_esc(app.dog_rasse||'')})
` : ''} +
E-Mail: ${UI.escape(app.email)}
+
Social: @${UI.escape(app.social_handle||'—')}
+ ${app.dog_name ? `
Hund: ${UI.escape(app.dog_name)} (${UI.escape(app.dog_rasse||'')})
` : ''}
Motivation:
${_esc(app.motivation)}
+ margin-top:var(--space-1);font-size:var(--text-sm);white-space:pre-wrap">${UI.escape(app.motivation)}
Anhänge:
${docsHtml}
Admin-Notiz: + placeholder="Interne Notiz / Nachricht an Bewerber">${UI.escape(app.admin_note||'')}
`, footer: ` @@ -3052,7 +3047,7 @@ window.Page_admin = (() => { border:1.5px solid var(--c-border);border-radius:var(--radius-md); background:var(--c-surface);color:var(--c-text);font-size:var(--text-sm)"> ${Object.entries(KAT_LABEL).map(([k,v]) => - `` + `` ).join('')}
@@ -3125,7 +3120,7 @@ window.Page_admin = (() => { text-transform:uppercase;letter-spacing:0.05em; padding:var(--space-2) 0;margin-bottom:var(--space-2); border-bottom:1px solid var(--c-border)"> - ${_esc(label)} + ${UI.escape(label)}
`; for (const a of items) { @@ -3138,7 +3133,7 @@ window.Page_admin = (() => { padding:var(--space-3) var(--space-4)"> - ${_esc(a.frage)} + ${UI.escape(a.frage)} @@ -3159,7 +3154,7 @@ window.Page_admin = (() => {
@@ -3177,7 +3172,7 @@ window.Page_admin = (() => { border:1.5px solid var(--c-border);border-radius:var(--radius-md); background:var(--c-surface);color:var(--c-text);font-size:var(--text-sm)"> ${Object.entries(KAT_LABEL).map(([k,v]) => - `` + `` ).join('')}
@@ -3185,7 +3180,7 @@ window.Page_admin = (() => { ${_esc(a.antwort)} + resize:vertical;font-family:inherit">${UI.escape(a.antwort)}
+ style="resize:vertical;font-family:inherit">${UI.escape(p.recipient_address || '')}
+ value="${UI.escape(p.service_period || '')}">
@@ -4066,7 +4061,7 @@ window.Page_admin = (() => { + placeholder="Interne Notiz / Zahlungshinweis">${UI.escape(p.notes || (!isEdit && !p.recipient_name ? 'Zahlbar innerhalb von 14 Tagen ab Rechnungsdatum.' : ''))}

@@ -4120,7 +4115,7 @@ window.Page_admin = (() => { itemEl.style.cssText = 'display:grid;grid-template-columns:1fr 60px 100px auto;gap:var(--space-2);align-items:center'; itemEl.innerHTML = ` + value="${UI.escape(desc)}" class="text-sm"> { body: `

- Rechnung ${_esc(invoiceNum)} stornieren. + Rechnung ${UI.escape(invoiceNum)} stornieren.

@@ -4360,7 +4355,7 @@ window.Page_admin = (() => { const itemsHtml = (inv.items || []).map(item => ` - ${_esc(item.description)} + ${UI.escape(item.description)} ${item.quantity} ${_fmtEur(item.unit_price)} ${_fmtEur(item.total)} @@ -4368,15 +4363,15 @@ window.Page_admin = (() => { `).join(''); UI.modal.open({ - title: `${UI.icon('receipt')} ${_esc(inv.invoice_number)}`, + title: `${UI.icon('receipt')} ${UI.escape(inv.invoice_number)}`, body: `
Empfänger
-
${_esc(inv.recipient_name)}
- ${inv.recipient_email ? `
${_esc(inv.recipient_email)}
` : ''} - ${inv.recipient_address ? `
${_esc(inv.recipient_address)}
` : ''} +
${UI.escape(inv.recipient_name)}
+ ${inv.recipient_email ? `
${UI.escape(inv.recipient_email)}
` : ''} + ${inv.recipient_address ? `
${UI.escape(inv.recipient_address)}
` : ''}
Status
@@ -4392,7 +4387,7 @@ window.Page_admin = (() => { ${inv.service_period ? `
Leistungszeitraum
-
${_esc(inv.service_period)}
+
${UI.escape(inv.service_period)}
` : ''} @@ -4421,7 +4416,7 @@ window.Page_admin = (() => {
Notizen
${_esc(inv.notes)}
+ font-size:var(--text-xs);white-space:pre-wrap">${UI.escape(inv.notes)}
` : ''}
`, @@ -4451,7 +4446,7 @@ window.Page_admin = (() => { const monthRows = (cf.monthly || []).map((m, i) => ` - ${_esc(m.month)} + ${UI.escape(m.month)} ${m.count} ${_fmtEur(m.revenue)} `).join(''); @@ -4593,8 +4588,8 @@ window.Page_admin = (() => { ? ` (RG: ${_fmtE(inv.amount_gross)})` : ''; return ` - ${_esc(inv.invoice_number)} - ${_esc(inv.recipient_name)} + ${UI.escape(inv.invoice_number)} + ${UI.escape(inv.recipient_name)} ${_fmtE(effectiveAmt)}${amtNote} ${sL[inv.status]||inv.status} ${_fmtD(inv.created_at)} @@ -4602,7 +4597,7 @@ window.Page_admin = (() => { }).join(''); resultEl.innerHTML = `
- ${_esc(data.period || `Q${q} ${year}`)} — ${data.count} Buchung(en) · Summe: ${_fmtE(data.total_gross)} + ${UI.escape(data.period || `Q${q} ${year}`)} — ${data.count} Buchung(en) · Summe: ${_fmtE(data.total_gross)}
@@ -4622,7 +4617,7 @@ window.Page_admin = (() => {
`; } catch (e) { - resultEl.innerHTML = `
Fehler: ${_esc(e.message)}
`; + resultEl.innerHTML = `
Fehler: ${UI.escape(e.message)}
`; } }); } diff --git a/backend/static/js/pages/adoption.js b/backend/static/js/pages/adoption.js index 4dfad9b..b2c6410 100644 --- a/backend/static/js/pages/adoption.js +++ b/backend/static/js/pages/adoption.js @@ -56,7 +56,7 @@ window.Page_adoption = (() => { + value="${UI.escape(_rasseFilter)}">
@@ -610,7 +610,7 @@ window.Page_adoption = (() => { function _communityCard(l) { const foto = l.foto_url - ? `${_esc(l.name)}` : '
🐾
'; @@ -635,11 +635,11 @@ window.Page_adoption = (() => { const interestBtn = l.user_interested ? `` : ``; @@ -657,7 +657,7 @@ window.Page_adoption = (() => { display:flex;align-items:center;justify-content:center"> - ${_esc(statusLabel)} + ${UI.escape(statusLabel)}
` : ''} @@ -666,17 +666,17 @@ window.Page_adoption = (() => {
- ${_esc(l.name)} + ${UI.escape(l.name)}
${l.rasse ? `
- ${_esc(l.rasse)} + ${UI.escape(l.rasse)}
` : ''}
${alterLabel ? ` - ${_esc(alterLabel)} + ${UI.escape(alterLabel)} ` : ''} ${genderIcon ? ` @@ -684,14 +684,14 @@ window.Page_adoption = (() => { ` : ''} ${distTxt ? ` - ${_esc(distTxt)} + ${UI.escape(distTxt)} ` : ''}
- ${ort ? `
${_esc(ort)}
` : ''} + ${ort ? `
${UI.escape(ort)}
` : ''} ${l.beschreibung ? `
- ${_esc(l.beschreibung)} + ${UI.escape(l.beschreibung)}
` : ''} ${l.interesse_count ? `
❤️ ${l.interesse_count} Interessent${l.interesse_count !== 1 ? 'en' : ''} @@ -717,20 +717,20 @@ window.Page_adoption = (() => {
- ${_esc(l.name)} + ${UI.escape(l.name)}
${l.interesse_count || 0} Interessent${(l.interesse_count || 0) !== 1 ? 'en' : ''}
@@ -849,7 +849,7 @@ window.Page_adoption = (() => {
+ placeholder="z.B. 80331" value="${UI.escape(_lat ? '' : '')}">
@@ -941,15 +941,6 @@ window.Page_adoption = (() => { return 'Senior'; } - function _esc(s) { - if (s == null) return ''; - return String(s) - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"'); - } - // ---------------------------------------------------------- // PUBLIC API // ---------------------------------------------------------- diff --git a/backend/static/js/pages/breeder-editor.js b/backend/static/js/pages/breeder-editor.js index e8ccf0b..959bfd2 100644 --- a/backend/static/js/pages/breeder-editor.js +++ b/backend/static/js/pages/breeder-editor.js @@ -46,7 +46,7 @@ window.Page_breeder_editor = (() => { background:var(--c-surface-2);overflow:hidden;flex-shrink:0; display:flex;align-items:center;justify-content:center"> ${p.logo_url - ? `` + ? `` : ``}
@@ -70,45 +70,45 @@ window.Page_breeder_editor = (() => {
+ value="${UI.escape(p.zwingername || '')}">
+ value="${UI.escape(p.rasse_text || '')}">
+ value="${UI.escape(p.tagline || '')}">
+ placeholder="Wer seid ihr, was ist euch bei der Zucht wichtig?">${UI.escape(p.beschreibung || '')}
- +
- +
+ placeholder="https://" value="${UI.escape(p.website || '')}">
+ placeholder="@zwingername" value="${UI.escape(p.instagram || '')}">
`; @@ -312,10 +312,6 @@ window.Page_breeder_editor = (() => { }); } - function _esc(s) { - return String(s ?? '').replace(/[&<>"']/g, c => - ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])); - } return { init, refresh, onDogChange }; diff --git a/backend/static/js/pages/breeder.js b/backend/static/js/pages/breeder.js index 2770ce8..7ac2104 100644 --- a/backend/static/js/pages/breeder.js +++ b/backend/static/js/pages/breeder.js @@ -7,8 +7,6 @@ window.Page_breeder = (() => { let _container = null; let _appState = null; - const _esc = s => UI.esc ? UI.esc(s) : String(s ?? '').replace(/[&<>"']/g, - c => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])); // ---------------------------------------------------------- // INIT @@ -51,7 +49,7 @@ window.Page_breeder = (() => { } catch (e) { document.getElementById('breeder-profile-body').innerHTML = `
- ${UI.icon('magnifying-glass')} ${_esc(e.message || 'Züchter nicht gefunden.')} + ${UI.icon('magnifying-glass')} ${UI.escape(e.message || 'Züchter nicht gefunden.')}
`; } } @@ -80,17 +78,17 @@ window.Page_breeder = (() => { ${UI.icon('seal-check')} Verifizierter Züchter

- ${_esc(p.zwingername)} + ${UI.escape(p.zwingername)}

- ${p.rasse_text ? `${_esc(p.rasse_text)}` : ''} + ${p.rasse_text ? `${UI.escape(p.rasse_text)}` : ''} ${p.vdh_mitglied ? `${UI.icon('certificate')} VDH` : ''} - ${p.stadt ? `${UI.icon('map-pin')} ${_esc(p.stadt)}` : ''} - ${seit ? `Züchter seit ${_esc(seit)}` : ''} + ${p.stadt ? `${UI.icon('map-pin')} ${UI.escape(p.stadt)}` : ''} + ${seit ? `Züchter seit ${UI.escape(seit)}` : ''}
${p.logo_url - ? `Zwinger-Logo` @@ -117,7 +115,7 @@ window.Page_breeder = (() => { Anmelden um zu schreiben ` } - ${p.website ? ` -

${_esc(p.beschreibung)}

+

${UI.escape(p.beschreibung)}

` : ''} @@ -192,8 +190,8 @@ window.Page_breeder = (() => { ${p.website ? `
Website
-
${_esc(p.website)}
+
${UI.escape(p.website)}
` : ''} ${seit ? _dl('Züchter seit', seit) : ''} @@ -209,11 +207,11 @@ window.Page_breeder = (() => {
${p.fotos.map((ph, i) => ` - - ${_esc(ph.caption)} @@ -221,7 +219,7 @@ window.Page_breeder = (() => { color:white;font-size:9px;font-weight:700;border-radius:999px;padding:1px 6px">Logo` : ''} ${ph.caption ? `
${_esc(ph.caption)}
` : ''} + color:white;font-size:10px;padding:12px 6px 4px;line-height:1.3">${UI.escape(ph.caption)}
` : ''} `).join('')} ` : ''} @@ -251,14 +249,14 @@ window.Page_breeder = (() => { const augeTest = h.health_tests?.find(t => t.test_typ === 'augen'); const testPills = [ - hdTest ? `HD ${_esc(hdTest.ergebnis)}` : '', - edTest ? `ED ${_esc(edTest.ergebnis)}` : '', + hdTest ? `HD ${UI.escape(hdTest.ergebnis)}` : '', + edTest ? `ED ${UI.escape(edTest.ergebnis)}` : '', augeTest ? `Augen ✓` : '', ].filter(Boolean).join(''); const titlePills = (h.titel || []).map(t => `${_esc(t)}` + border-radius:999px;padding:1px 8px;font-size:10px;font-weight:700">${UI.escape(t)}
` ).join(''); const genBadge = h.gentests_total > 0 @@ -272,11 +270,11 @@ window.Page_breeder = (() => { padding:var(--space-3);display:flex;flex-direction:column;gap:var(--space-2)">
${gIcon} - ${_esc(h.name)} - ${h.rufname ? `"${_esc(h.rufname)}"` : ''} + ${UI.escape(h.name)} + ${h.rufname ? `"${UI.escape(h.rufname)}"` : ''} ${alter !== null ? `${alter} J.` : ''}
- ${h.farbe ? `

${_esc(h.farbe)}

` : ''} + ${h.farbe ? `

${UI.escape(h.farbe)}

` : ''} ${testPills ? `
${testPills}
` : ''} ${titlePills ? `
${titlePills}
` : ''} ${genBadge} @@ -318,16 +316,16 @@ window.Page_breeder = (() => {
- ${_esc(eltern)} + ${UI.escape(eltern)} ${sl}
- ${datum ? `${UI.icon('calendar-dots')} ${_esc(datum)}` : ''} + ${datum ? `${UI.icon('calendar-dots')} ${UI.escape(datum)}` : ''} ${w.welpen_gesamt ? `${UI.icon('dog')} ${w.welpen_verfuegbar ?? '?'}/${w.welpen_gesamt} verfügbar` : ''} - ${w.preis_spanne ? `${UI.icon('currency-eur')} ${_esc(w.preis_spanne)}` : ''} + ${w.preis_spanne ? `${UI.icon('currency-eur')} ${UI.escape(w.preis_spanne)}` : ''}
- ${w.beschreibung ? `

${_esc(w.beschreibung)}

` : ''} + ${w.beschreibung ? `

${UI.escape(w.beschreibung)}

` : ''}
`; } @@ -340,11 +338,11 @@ window.Page_breeder = (() => { return `

${_esc(label)}

+ color:var(--c-text-muted);text-transform:uppercase;letter-spacing:.06em">${UI.escape(label)}

${stats.map(r => `
- ${_esc(r.ergebnis || '—')} + ${UI.escape(r.ergebnis || '—')} ${r.cnt}× @@ -359,8 +357,8 @@ window.Page_breeder = (() => { function _dl(label, value) { if (!value) return ''; return `
-
${_esc(label)}
-
${_esc(String(value))}
+
${UI.escape(label)}
+
${UI.escape(String(value))}
`; } @@ -383,10 +381,10 @@ window.Page_breeder = (() => {
${photos.map(ph => ` - - ${_esc(ph.caption||'')} `).join('')} diff --git a/backend/static/js/pages/chat.js b/backend/static/js/pages/chat.js index 8a29659..3d7d877 100644 --- a/backend/static/js/pages/chat.js +++ b/backend/static/js/pages/chat.js @@ -122,7 +122,7 @@ window.Page_chat = (() => { el.innerHTML = convs.map(c => { const initials = (c.partner_name || '?')[0].toUpperCase(); const preview = c.last_text - ? _esc(c.last_text.substring(0, 60)) + (c.last_text.length > 60 ? '…' : '') + ? UI.escape(c.last_text.substring(0, 60)) + (c.last_text.length > 60 ? '…' : '') : 'Noch keine Nachrichten'; const timeStr = c.last_msg_at ? _fmtTime(c.last_msg_at) : ''; const badge = c.unread_count > 0 @@ -138,7 +138,7 @@ window.Page_chat = (() => { ${onlineDot ? `` : ''}
-
${_esc(c.partner_name)}
+
${UI.escape(c.partner_name)}
${preview}
@@ -332,10 +332,10 @@ window.Page_chat = (() => { } if (m.text) { bubbleContent += (m.media_url ? `
` : '') + - _esc(m.text) + + UI.escape(m.text) + (m.media_url ? `
` : ''); } - if (!bubbleContent) bubbleContent = _esc(m.text); + if (!bubbleContent) bubbleContent = UI.escape(m.text); html += `
@@ -450,13 +450,6 @@ window.Page_chat = (() => { return d.toLocaleDateString('de-DE', { day: '2-digit', month: 'long', year: 'numeric' }); } - function _esc(s) { - if (!s) return ''; - return String(s) - .replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"') - .replace(/\n/g, '
'); - } - // ---------------------------------------------------------- // Neue Nachricht — Freundesliste als Picker // ---------------------------------------------------------- diff --git a/backend/static/js/pages/dog-profile.js b/backend/static/js/pages/dog-profile.js index e38c765..1195e18 100644 --- a/backend/static/js/pages/dog-profile.js +++ b/backend/static/js/pages/dog-profile.js @@ -84,7 +84,7 @@ window.Page_dog_profile = (() => {
${dog.foto_url ? `
- ${_esc(dog.name)}
` : `
${UI.icon('dog')}
`} @@ -95,9 +95,9 @@ window.Page_dog_profile = (() => {

${_esc(dog.name)}

+ color:var(--c-text);margin:0 0 var(--space-1)">${UI.escape(dog.name)} ${dog.rasse - ? `

${_esc(dog.rasse)}

` + ? `

${UI.escape(dog.rasse)}

` : `

`} @@ -141,7 +141,7 @@ window.Page_dog_profile = (() => { Transponder
${dog.chip_nr - ? `
${_esc(dog.chip_nr)}
` + ? `
${UI.escape(dog.chip_nr)}
` : `
nicht eingetragen @@ -153,7 +153,7 @@ window.Page_dog_profile = (() => { ${dog.bio ? `

- "${_esc(dog.bio)}" + "${UI.escape(dog.bio)}"

` : ''} @@ -335,7 +335,7 @@ window.Page_dog_profile = (() => { - ${_esc(skill.exercise_name)} + ${UI.escape(skill.exercise_name)} `; }; @@ -413,7 +413,7 @@ window.Page_dog_profile = (() => {
🛁 - Pflegetipps${data.rasse_name ? ` für ${_esc(data.rasse_name)}` : ''} + Pflegetipps${data.rasse_name ? ` für ${UI.escape(data.rasse_name)}` : ''}
@@ -426,24 +426,24 @@ window.Page_dog_profile = (() => { ${t.saisonal_aktuell ? '🌸 Aktuell & Saisonal' : '💡 Tipp des Tages'}
- ${kat_icons[t.kategorie]||_ph('paw-print')} ${_esc(t.titel)} + ${kat_icons[t.kategorie]||_ph('paw-print')} ${UI.escape(t.titel)}
${_esc(t.beschreibung||'')}
+ line-height:1.5">${UI.escape(t.beschreibung||'')}
${t.haeufigkeit ? `
- 🔄 ${_esc(t.haeufigkeit)}
` : ''} + 🔄 ${UI.escape(t.haeufigkeit)}
` : ''} ${t.materialien ? `
- 🛒 ${_esc(t.materialien)}
` : ''} + 🛒 ${UI.escape(t.materialien)}
` : ''} ${t.schritte?.length ? `
Anleitung anzeigen
    - ${t.schritte.map(s=>`
  1. ${_esc(s)}
  2. `).join('')} + ${t.schritte.map(s=>`
  3. ${UI.escape(s)}
  4. `).join('')}
${t.tipp ? `
💜 ${_esc(t.tipp)}
` : ''} + font-style:italic">💜 ${UI.escape(t.tipp)}
` : ''} ` : ''}
` : ''} @@ -460,26 +460,26 @@ window.Page_dog_profile = (() => {
- ${kat_icons[kat]||_ph('paw-print')} ${_esc(kat)}${katBadge}
+ ${kat_icons[kat]||_ph('paw-print')} ${UI.escape(kat)}${katBadge}
${katTipps.map(tip => `
- ${_esc(tip.titel)} + ${UI.escape(tip.titel)} ${tip.saisonal_aktuell ? '● Aktuell' : ''}
${_esc(tip.beschreibung||'')}
+ line-height:1.5">${UI.escape(tip.beschreibung||'')} ${tip.haeufigkeit ? `
🔄 ${_esc(tip.haeufigkeit)}
` : ''} + margin-top:4px">🔄 ${UI.escape(tip.haeufigkeit)}` : ''} ${tip.schritte?.length ? `
    - ${tip.schritte.map(s=>`
  1. ${_esc(s)}
  2. `).join('')} + ${tip.schritte.map(s=>`
  3. ${UI.escape(s)}
  4. `).join('')}
` : ''} ${tip.tipp ? `
💜 ${_esc(tip.tipp)}
` : ''} + font-style:italic">💜 ${UI.escape(tip.tipp)}` : ''}
`).join('')} `; }).join('')} @@ -499,12 +499,6 @@ window.Page_dog_profile = (() => { }); } - function _esc(s) { - if (!s) return ''; - return String(s).replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"'); - } - // ---------------------------------------------------------- // SITTER-ZUGANG // ---------------------------------------------------------- @@ -527,8 +521,8 @@ window.Page_dog_profile = (() => {
- ${_esc(s.sitter_name)} - · bis ${_esc(s.valid_until)} + ${UI.escape(s.sitter_name)} + · bis ${UI.escape(s.valid_until)}
@@ -1195,7 +1189,7 @@ window.Page_dog_profile = (() => { (optional) + placeholder="Kurze Beschreibung…">${UI.escape(dog?.bio || '')}
@@ -1477,7 +1471,7 @@ window.Page_dog_profile = (() => { Auf diesem Foto konnte kein Hund erkannt werden.
Bitte lade ein deutlicheres Foto hoch.

- ${data.hinweis ? `

${_esc(data.hinweis)}

` : ''} + ${data.hinweis ? `

${UI.escape(data.hinweis)}

` : ''}
`, footer: ``, }); @@ -1490,24 +1484,24 @@ window.Page_dog_profile = (() => { return `
-
${isTop ? '🐕 ' : ''}${_esc(r.name)}
+
${isTop ? '🐕 ' : ''}${UI.escape(r.name)}
${r.sicherheit}%
- ${r.beschreibung ? `
${_esc(r.beschreibung)}
` : ''} + ${r.beschreibung ? `
${UI.escape(r.beschreibung)}
` : ''}
${isTop ? `` : ``} ${r.wiki_slug ? `` : ''}
@@ -1521,7 +1515,7 @@ window.Page_dog_profile = (() => {
${data.hinweis ? `
ℹ️ ${_esc(data.hinweis)}
` : ''} + color:var(--c-text-secondary)">ℹ️ ${UI.escape(data.hinweis)}
` : ''} ${cardsHtml}

@@ -1582,18 +1576,13 @@ window.Page_dog_profile = (() => { : `${j} Jahr${j !== 1 ? 'e' : ''} alt`; } - function _esc(str) { - if (!str) return ''; - return str.replace(/&/g, '&').replace(//g, '>') - .replace(/"/g, '"'); - } // ---------------------------------------------------------- // HUNDEPASS // ---------------------------------------------------------- async function _showPassportModal(dog) { UI.modal.open({ - title: `Hundepass — ${_esc(dog.name)}`, + title: `Hundepass — ${UI.escape(dog.name)}`, body: `

Fehler beim Laden: ${_esc(e.message)}

`; + wrap.innerHTML = `

Fehler beim Laden: ${UI.escape(e.message)}

`; return; } @@ -1670,13 +1659,13 @@ window.Page_dog_profile = (() => {
Blutgruppe
- ${_esc(meta.blutgruppe) || 'nicht eingetragen'} + ${UI.escape(meta.blutgruppe) || 'nicht eingetragen'}
Allergien
- ${_esc(meta.allergien) || 'keine'} + ${UI.escape(meta.allergien) || 'keine'}
@@ -1684,7 +1673,7 @@ window.Page_dog_profile = (() => {
Besonderheiten
- ${_esc(meta.besonderheiten)} + ${UI.escape(meta.besonderheiten)}
` : ''}
@@ -1709,12 +1698,12 @@ window.Page_dog_profile = (() => {
-
${_esc(v.krankheit)}
+
${UI.escape(v.krankheit)}
Gegeben: ${_fmt(v.datum)} ${v.naechste ? ` · Nächste: ${_fmt(v.naechste)}` : ''} - ${v.tierarzt ? ` · ${_esc(v.tierarzt)}` : ''} - ${v.charge_nr ? ` · Charge: ${_esc(v.charge_nr)}` : ''} + ${v.tierarzt ? ` · ${UI.escape(v.tierarzt)}` : ''} + ${v.charge_nr ? ` · Charge: ${UI.escape(v.charge_nr)}` : ''}
@@ -2037,7 +2026,7 @@ window.Page_dog_profile = (() => { return; } - const name = _esc(data.dog_name); + const name = UI.escape(data.dog_name); const km = data.gesamt_km || 0; const konfetti = km > 100; @@ -2079,8 +2068,8 @@ window.Page_dog_profile = (() => {
Tagebucheinträge
${data.fotos_gesamt > 0 ? `
📷 ${data.fotos_gesamt} Fotos
` : ''} ${data.gassi_tage > 0 ? `
🐾 ${data.gassi_tage} aktive Tage
` : ''} - ${data.lieblings_monat ? `
Meiste Einträge: ${_esc(data.lieblings_monat)}
` : ''} - ${aktivitaet ? `
Lieblingsaktivität: ${_esc(aktivitaet)}
` : ''} + ${data.lieblings_monat ? `
Meiste Einträge: ${UI.escape(data.lieblings_monat)}
` : ''} + ${aktivitaet ? `
Lieblingsaktivität: ${UI.escape(aktivitaet)}
` : ''} `), _card(`
🌡️
@@ -2299,7 +2288,7 @@ window.Page_dog_profile = (() => { // ---------------------------------------------------------- async function _showTimelineModal(dog) { UI.modal.open({ - title: `Lebens-Timeline — ${_esc(dog.name)}`, + title: `Lebens-Timeline — ${UI.escape(dog.name)}`, body: `

Fehler: ${_esc(e.message)}

`; + if (b) b.innerHTML = `

Fehler: ${UI.escape(e.message)}

`; return; } @@ -2351,14 +2340,14 @@ window.Page_dog_profile = (() => { for (const ev of events) { const year = ev.datum ? ev.datum.substring(0, 4) : null; if (year && year !== lastYear) { - html += `
${_esc(year)}
`; + html += `
${UI.escape(year)}
`; lastYear = year; } const kat = _KAT[ev.kategorie] || _KAT.tagebuch; const big = ev.is_milestone; - let label = _esc(ev.titel); + let label = UI.escape(ev.titel); if (ev.is_first && ev.kategorie === 'tagebuch') label = `🎉 Erster Tagebucheintrag — ${label}`; if (ev.is_first && ev.kategorie === 'route') label = `🎉 Erste Route — ${label}`; if (ev.is_first && ev.kategorie === 'training') label = `🎉 Erstes Training — ${label}`; @@ -2376,13 +2365,13 @@ window.Page_dog_profile = (() => { box-shadow:${big ? `0 0 0 4px ${kat.color}22` : 'none'}">
${big && ev.foto_url ? ` -
` : ''} +
` : ''}
- ${_esc(kat.label)} + ${UI.escape(kat.label)} ${_fmtDate(ev.datum)}
@@ -2451,8 +2440,8 @@ window.Page_dog_profile = (() => { if (!data || data.count === 0) return; const hauptRasse = data.rassen[0]?.rasse || ''; const label = data.count === 1 - ? `1 anderer ${_esc(hauptRasse)}-Halter in der App` - : `${data.count} andere ${_esc(hauptRasse)}-Halter in der App`; + ? `1 anderer ${UI.escape(hauptRasse)}-Halter in der App` + : `${data.count} andere ${UI.escape(hauptRasse)}-Halter in der App`; el.innerHTML = `
@@ -209,7 +201,7 @@ window.Page_ernaehrung = (() => {
+ value="${UI.escape(_profil.marke)}" placeholder="z. B. Royal Canin">
@@ -219,7 +211,7 @@ window.Page_ernaehrung = (() => {
+ placeholder="Besonderheiten, Allergien...">${UI.escape(_profil.notizen)}
@@ -511,7 +503,7 @@ window.Page_ernaehrung = (() => { border:1px solid var(--c-border)"> Der KI-Futterberater beantwortet Ernährungsfragen für - ${_esc(dog?.name || 'deinen Hund')}. + ${UI.escape(dog?.name || 'deinen Hund')}. Bei Gesundheitsfragen immer den Tierarzt zurate ziehen.
@@ -524,8 +516,8 @@ window.Page_ernaehrung = (() => { 'Welche Leckerlis sind gesund?', ].map(q => ` + data-q="${UI.escape(q)}" + class="text-xs">${UI.escape(q)} `).join('')}
@@ -577,7 +569,7 @@ window.Page_ernaehrung = (() => {
- ${_esc(frage)} + ${UI.escape(frage)}
`); @@ -617,7 +609,7 @@ window.Page_ernaehrung = (() => { } } - const antwortHtml = _esc(antwort) + const antwortHtml = UI.escape(antwort) .replace(/\n\n/g, '

') .replace(/\n/g, '
'); @@ -746,7 +738,7 @@ window.Page_ernaehrung = (() => { const dl = document.getElementById('vert-futter-datalist'); if (!dl) return; const names = [...new Set((list || []).map(e => e.futter_name))]; - dl.innerHTML = names.map(n => `

- ${_esc(f.name)} + ${UI.escape(f.name)}
- ${_esc(TYP_LABELS[f.typ] || f.typ)} · ${f.mahlzeiten} Mahlzeit${f.mahlzeiten !== 1 ? 'en' : ''} + ${UI.escape(TYP_LABELS[f.typ] || f.typ)} · ${f.mahlzeiten} Mahlzeit${f.mahlzeiten !== 1 ? 'en' : ''} ${f.status !== 'neu' ? `· +${f.positiv} / -${f.negativ}` : ''}
${katChips ? `
${katChips}
` : ''}
- ${_esc(cfg.label)} + ${UI.escape(cfg.label)} `; @@ -1085,9 +1077,9 @@ window.Page_ernaehrung = (() => {
-
${_esc(item.futter_name)}
+
${UI.escape(item.futter_name)}
- ${_esc(item.datum)} ${_esc(item.uhrzeit)} + ${UI.escape(item.datum)} ${UI.escape(item.uhrzeit)} ${item.menge_g ? ` · ${item.menge_g} g` : ''}
@@ -1112,11 +1104,11 @@ window.Page_ernaehrung = (() => {
- ${_esc(REAK_LABELS[item.reaktion_typ] || item.reaktion_typ)} + ${UI.escape(REAK_LABELS[item.reaktion_typ] || item.reaktion_typ)} (${item.intensitaet}/5)
- ${_esc(item.datum)} ${_esc(item.uhrzeit)} + ${UI.escape(item.datum)} ${UI.escape(item.uhrzeit)}
diff --git a/backend/static/js/pages/expenses.js b/backend/static/js/pages/expenses.js index ec9d07d..0a69315 100644 --- a/backend/static/js/pages/expenses.js +++ b/backend/static/js/pages/expenses.js @@ -71,7 +71,7 @@ window.Page_expenses = (() => { if (dogs.length < 2) return ''; const pills = [{ id: null, name: 'Alle' }, ...dogs].map(d => ` `).join(''); return `
${pills}
`; } @@ -283,10 +283,10 @@ window.Page_expenses = (() => { const datum = new Date(e.datum + 'T00:00:00') .toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit' }); const dogBadge = e.dog_name - ? `${UI.icon('paw-print')} ${_esc(e.dog_name)}` + ? `${UI.icon('paw-print')} ${UI.escape(e.dog_name)}` : ''; const notiz = e.notiz - ? `
${_esc(e.notiz)}
` + ? `
${UI.escape(e.notiz)}
` : ''; return `
@@ -376,11 +376,11 @@ window.Page_expenses = (() => {
${UI.icon(k.icon)}
${k.label}
- ${r.notiz ? `
${_esc(r.notiz)}
` : ''} + ${r.notiz ? `
${UI.escape(r.notiz)}
` : ''}
${HAEUFIGKEIT_LABEL[r.haeufigkeit] || r.haeufigkeit} · ${UI.icon('calendar')} ${naechste} - ${r.dog_name ? `· ${UI.icon('paw-print')} ${_esc(r.dog_name)}` : ''} + ${r.dog_name ? `· ${UI.icon('paw-print')} ${UI.escape(r.dog_name)}` : ''} ${!r.aktiv ? '· Pausiert' : ''}
@@ -444,7 +444,7 @@ window.Page_expenses = (() => { ].map(k => ``).join(''); const dogOptions = (_appState.dogs || []).map(d => - `` + `` ).join(''); const body = ` @@ -480,7 +480,7 @@ window.Page_expenses = (() => {
+ value="${UI.escape(r?.notiz || '')}" placeholder="z.B. Haftpflicht Allianz">
`; @@ -683,7 +683,7 @@ window.Page_expenses = (() => { const defaultDogId = entry?.dog_id ?? _selectedDogId; const dogOptions = (_appState.dogs || []).map(d => - `` + `` ).join(''); // Kategorie-Kacheln statt Dropdown @@ -725,7 +725,7 @@ window.Page_expenses = (() => {
@@ -852,14 +852,5 @@ window.Page_expenses = (() => { return Math.round(val) + ' €'; } - function _esc(s) { - if (!s) return ''; - return String(s) - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"'); - } - return { init, refresh }; })(); diff --git a/backend/static/js/pages/forum.js b/backend/static/js/pages/forum.js index f831b87..a6fe6d8 100644 --- a/backend/static/js/pages/forum.js +++ b/backend/static/js/pages/forum.js @@ -39,12 +39,7 @@ window.Page_forum = (() => { // ---------------------------------------------------------- // Helpers // ---------------------------------------------------------- - function _esc(s) { - return String(s || '').replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"'); - } - - function _fmtDate(iso) { +function _fmtDate(iso) { if (!iso) return '—'; const d = new Date(iso); const now = new Date(); @@ -108,7 +103,7 @@ window.Page_forum = (() => {
${KATEGORIEN.map(k => ` + data-kat="${k.key}">${UI.escape(k.label)} `).join('')} @@ -217,7 +212,7 @@ window.Page_forum = (() => { .format(new Date(+year, +month - 1, 1)); const top = data.top?.[0]; const winnerLine = top - ? `🥇 ${_esc(top.name)}${top.rasse ? ` · ${_esc(top.rasse)}` : ''}` + ? `🥇 ${UI.escape(top.name)}${top.rasse ? ` · ${UI.escape(top.rasse)}` : ''}` : 'Noch keine Stimmen'; const metaLine = top ? `${top.stimmen} Stimme${top.stimmen !== 1 ? 'n' : ''}` @@ -227,7 +222,7 @@ window.Page_forum = (() => {
🏆
-
Hund des Monats · ${_esc(monthName)}
+
Hund des Monats · ${UI.escape(monthName)}
${winnerLine}
${metaLine}
@@ -251,16 +246,16 @@ window.Page_forum = (() => { ? data.top.slice(0, 5).map((dog, i) => { const medal = ['🥇','🥈','🥉','4️⃣','5️⃣'][i]; const av = dog.foto_url - ? `${_esc(dog.name)}` - : `${_esc(dog.name.charAt(0).toUpperCase())}`; - const vorname = dog.besitzer_name ? _esc(dog.besitzer_name.split(' ')[0]) : ''; + ? `${UI.escape(dog.name)}` + : `${UI.escape(dog.name.charAt(0).toUpperCase())}`; + const vorname = dog.besitzer_name ? UI.escape(dog.besitzer_name.split(' ')[0]) : ''; return `
${medal}
${av}
-
${_esc(dog.name)}
- ${dog.rasse ? `
${_esc(dog.rasse)}
` : ''} +
${UI.escape(dog.name)}
+ ${dog.rasse ? `
${UI.escape(dog.rasse)}
` : ''} ${vorname ? `
von ${vorname}
` : ''}
${dog.stimmen} ${UI.icon('star')}
@@ -291,7 +286,7 @@ window.Page_forum = (() => {
🏆

Hund des Monats

-
${_esc(monthName)}
+
${UI.escape(monthName)}
${voteHint}
@@ -320,14 +315,14 @@ window.Page_forum = (() => { grid.innerHTML = list.map(dog => { const isVoted = data.user_vote === dog.id; const av = dog.foto_url - ? `${_esc(dog.name)}` - : `${_esc(dog.name.charAt(0).toUpperCase())}`; - const vorname = dog.besitzer_name ? _esc(dog.besitzer_name.split(' ')[0]) : ''; + ? `${UI.escape(dog.name)}` + : `${UI.escape(dog.name.charAt(0).toUpperCase())}`; + const vorname = dog.besitzer_name ? UI.escape(dog.besitzer_name.split(' ')[0]) : ''; return `
${av}
-
${_esc(dog.name)}
- ${dog.rasse ? `
${_esc(dog.rasse)}
` : ''} +
${UI.escape(dog.name)}
+ ${dog.rasse ? `
${UI.escape(dog.rasse)}
` : ''} ${vorname ? `
von ${vorname}
` : ''} ${dog.stimmen > 0 ? `
${dog.stimmen} ${UI.icon('star')}
` : ''}
` : ``; - UI.modal.open({ title: `${UI.icon('chat-circle-dots')} ${_esc(thread.titel)}`, body, footer }); + UI.modal.open({ title: `${UI.icon('chat-circle-dots')} ${UI.escape(thread.titel)}`, body, footer }); // Close document.getElementById('ft-close')?.addEventListener('click', UI.modal.close); @@ -778,7 +773,7 @@ window.Page_forum = (() => { const isOwn = uid && uid === p.user_id; const fotoHtml = (p.foto_urls?.length) ? `
${p.foto_urls.map(u => - `` + `` ).join('')}
` : ''; @@ -788,13 +783,13 @@ window.Page_forum = (() => { return `
-
${_esc(_initial(p.autor_name))}
- +
${UI.escape(_initial(p.autor_name))}
+ ${p.autor_founder_number ? `Gründer #${p.autor_founder_number}` : ''}
-
${_esc(p.text)}
+
${UI.escape(p.text)}
${fotoHtml}
@@ -803,7 +798,7 @@ window.Page_forum = (() => { ${(!isOwn && uid) ? `` : ''}
- ${isOwn ? `` : ''} + ${isOwn ? `` : ''} ${canDelete ? `` : ''}
@@ -991,7 +986,7 @@ window.Page_forum = (() => { // ---------------------------------------------------------- function _showCreateForm() { const katOptions = KATEGORIEN.filter(k => k.key !== 'alle').map(k => - `` + `` ).join(''); const body = ` @@ -1241,12 +1236,12 @@ window.Page_forum = (() => { background:var(--c-primary);color:#fff;font-size:13px;font-weight:700; display:flex;align-items:center;justify-content:center; box-shadow:0 2px 5px rgba(0,0,0,0.35); - border:2px solid rgba(255,255,255,0.8)">${_esc((m.vorname||'?')[0].toUpperCase())}
`, + border:2px solid rgba(255,255,255,0.8)">${UI.escape((m.vorname||'?')[0].toUpperCase())}
`, iconSize: [32, 32], iconAnchor: [16, 16], }); _clusterGroup.addLayer( L.marker([m.lat, m.lon], { icon }) - .bindPopup(`${_esc(m.vorname || '?')}`) + .bindPopup(`${UI.escape(m.vorname || '?')}`) ); }); _map.addLayer(_clusterGroup); @@ -1296,11 +1291,11 @@ window.Page_forum = (() => { ${reports.map(r => `
- ${_esc(r.target_type)} #${r.target_id} - — ${_esc(r.grund)} + ${UI.escape(r.target_type)} #${r.target_id} + — ${UI.escape(r.grund)}
- von ${_esc(r.melder_name || '?')} · ${_fmtDate(r.created_at)} + von ${UI.escape(r.melder_name || '?')} · ${_fmtDate(r.created_at)}
- ${_esc(item.user_name)} + ${UI.escape(item.user_name)} ${dogLabel}
- ${text ? `
${_esc(text)}
` : ''} -
${_esc(ago)}
+ ${text ? `
${UI.escape(text)}
` : ''} +
${UI.escape(ago)}
`; @@ -353,7 +353,7 @@ window.Page_friends = (() => {
- ${_esc(r.requester_name)} + ${UI.escape(r.requester_name)}
${_dogPills(r.dogs, 2)}
@@ -392,11 +392,11 @@ window.Page_friends = (() => { display:flex;align-items:center;justify-content:center; font-weight:var(--weight-bold);color:var(--c-text-secondary); font-size:var(--text-sm);flex-shrink:0"> - ${_esc((r.addressee_name || '?')[0].toUpperCase())} + ${UI.escape((r.addressee_name || '?')[0].toUpperCase())}
${_esc(r.addressee_name)}
+ color:var(--c-text)">${UI.escape(r.addressee_name)}
Anfrage ausstehend
${d.rasse - ? `
${_esc(d.rasse)}
` + ? `
${UI.escape(d.rasse)}
` : ''}
`).join('')} @@ -589,7 +589,7 @@ window.Page_friends = (() => { if (profile.wohnort) { parts.push(`
- 📍 ${_esc(profile.wohnort)} + 📍 ${UI.escape(profile.wohnort)}
`); } if (profile.erfahrung && _erfahrungBadge[profile.erfahrung]) { @@ -600,13 +600,13 @@ window.Page_friends = (() => { if (profile.bio && profile.profil_sichtbarkeit !== 'private') { parts.push(`
- ${_esc(profile.bio)} + ${UI.escape(profile.bio)}
`); } if (profile.social_link) { parts.push(`
- ${_esc(profile.social_link)} + ${UI.escape(profile.social_link)}
`); } if (!parts.length) return ''; @@ -627,7 +627,7 @@ window.Page_friends = (() => { ` : ''; UI.modal.open({ - title: _esc(friendName), + title: UI.escape(friendName), body: `
${badgesHTML} @@ -687,7 +687,7 @@ window.Page_friends = (() => {
${_esc(u.name)} + color:var(--c-text)">${UI.escape(u.name)} ${u.is_founder ? `${u.founder_number ? `Gründer #${u.founder_number}` : 'Gründer'}` : ''} ${u.is_partner ? `Partner` : ''} ${_erfahrungSpan(u.erfahrung)} @@ -697,12 +697,12 @@ window.Page_friends = (() => { ${u.dogs?.length ? `
- ${u.dogs.map(d => _esc(d.name) + (d.rasse ? ` · ${_esc(d.rasse)}` : '')).join('  |  ')} + ${u.dogs.map(d => UI.escape(d.name) + (d.rasse ? ` · ${UI.escape(d.rasse)}` : '')).join('  |  ')}
` : ''}
@@ -786,13 +786,13 @@ window.Page_friends = (() => { // ---------------------------------------------------------- function _userAvatar(name, firstDog, avatarUrl) { if (avatarUrl) { - return `${_esc(name)}`; } if (firstDog?.foto_url) { - return `${_esc(firstDog.name)}`; @@ -803,7 +803,7 @@ window.Page_friends = (() => { border:2px solid var(--c-primary); display:flex;align-items:center;justify-content:center; font-weight:var(--weight-bold);color:var(--c-primary)"> - ${_esc((name || '?')[0].toUpperCase())} + ${UI.escape((name || '?')[0].toUpperCase())} `; } @@ -823,7 +823,7 @@ window.Page_friends = (() => { function _wohnortLine(wohnort) { if (!wohnort) return ''; - return `📍 ${_esc(wohnort)}`; + return `📍 ${UI.escape(wohnort)}`; } function _bioLine(bio, sichtbarkeit) { @@ -832,7 +832,7 @@ window.Page_friends = (() => { return `
${_esc(text)}
`; + -webkit-box-orient:vertical">${UI.escape(text)}`; } function _dogPills(dogs, max) { @@ -844,7 +844,7 @@ window.Page_friends = (() => { ${visible.map(d => ` - 🐕 ${_esc(d.name)}${d.rasse ? ` · ${_esc(d.rasse)}` : ''} + 🐕 ${UI.escape(d.name)}${d.rasse ? ` · ${UI.escape(d.rasse)}` : ''} `).join('')} ${rest > 0 ? `+${rest}` : ''} @@ -852,11 +852,6 @@ window.Page_friends = (() => { `; } - function _esc(s) { - if (!s) return ''; - return String(s).replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"'); - } - function _emptyState(icon, title, text, cta = '') { return `
Notiz
-
${_esc(parentLabel)}
+
${UI.escape(parentLabel)}
diff --git a/backend/static/js/pages/gruender.js b/backend/static/js/pages/gruender.js index ba62b49..b528c59 100644 --- a/backend/static/js/pages/gruender.js +++ b/backend/static/js/pages/gruender.js @@ -92,7 +92,7 @@ window.Page_gruender = (() => { background:${i === 0 ? 'linear-gradient(135deg,#fef9c3,#fef3c7)' : 'var(--c-surface-2)'}">
${medal}
-
${_esc(p.label)}
+
${UI.escape(p.label)}
#${f.founder_number} - ${_esc(f.name)} + ${UI.escape(f.name)}
`).join('')} @@ -144,10 +144,6 @@ window.Page_gruender = (() => { `; } - function _esc(s) { - return String(s || '').replace(/[&<>"']/g, c => - ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])); - } return { init, refresh, onDogChange }; diff --git a/backend/static/js/pages/health.js b/backend/static/js/pages/health.js index f0f5d7d..78f2430 100644 --- a/backend/static/js/pages/health.js +++ b/backend/static/js/pages/health.js @@ -92,7 +92,7 @@ window.Page_health = (() => { Transponder: - ${dog?.chip_nr ? `${_esc(dog.chip_nr)}` : 'nicht eingetragen'} + ${dog?.chip_nr ? `${UI.escape(dog.chip_nr)}` : 'nicht eingetragen'}
@@ -426,7 +426,7 @@ window.Page_health = (() => { return `
-
${_esc(e.bezeichnung)}
+
${UI.escape(e.bezeichnung)}
${UI.time.format(e.datum + 'T00:00:00')} ${e.kosten != null ? ` · ${Number(e.kosten).toFixed(2)} €` : ''} @@ -434,13 +434,13 @@ window.Page_health = (() => { ${praxisName ? `
- ${_esc(praxisName)}${praxisOrt ? ` · ${_esc(praxisOrt)}` : ''} + ${UI.escape(praxisName)}${praxisOrt ? ` · ${UI.escape(praxisOrt)}` : ''}
` : ''} - ${e.diagnose ? `
Diagnose: ${_esc(e.diagnose)}
` : ''} - ${e.notiz ? `
${_esc(e.notiz)}
` : ''} + ${e.diagnose ? `
Diagnose: ${UI.escape(e.diagnose)}
` : ''} + ${e.notiz ? `
${UI.escape(e.notiz)}
` : ''}
@@ -489,10 +489,10 @@ window.Page_health = (() => { ${e.wert} ${e.einheit || 'kg'}
- ${e.notiz ? `
${_esc(e.notiz)}
` : ''} + ${e.notiz ? `
${UI.escape(e.notiz)}
` : ''} @@ -727,10 +727,10 @@ window.Page_health = (() => { ${e.wert ? `Dauer: ${e.wert} Tage` : 'Dauer nicht angegeben'} ${interval ? ` · Abstand zur Vorherigen: ${interval} Tage` : ''} - ${e.notiz ? `
${_esc(e.notiz)}
` : ''} + ${e.notiz ? `
${UI.escape(e.notiz)}
` : ''} `; @@ -759,16 +759,16 @@ window.Page_health = (() => { ${items.map(e => `
-
${_esc(e.bezeichnung)}
+
${UI.escape(e.bezeichnung)}
- ${e.dosierung ? _esc(e.dosierung) : ''} - ${e.haeufigkeit ? ` · ${_esc(e.haeufigkeit)}` : ''} + ${e.dosierung ? UI.escape(e.dosierung) : ''} + ${e.haeufigkeit ? ` · ${UI.escape(e.haeufigkeit)}` : ''} ${e.bis_datum ? ` · bis ${UI.time.format(e.bis_datum + 'T00:00:00')}` : ''}
- ${e.notiz ? `
${_esc(e.notiz)}
` : ''} + ${e.notiz ? `
${UI.escape(e.notiz)}
` : ''}
@@ -799,17 +799,17 @@ window.Page_health = (() => {
- ${e.schweregrad ? SCHWEREGRAD[e.schweregrad] || '' : ''} ${_esc(e.bezeichnung)} + ${e.schweregrad ? SCHWEREGRAD[e.schweregrad] || '' : ''} ${UI.escape(e.bezeichnung)}
Erstmals: ${UI.time.format(e.datum + 'T00:00:00')} - ${e.schweregrad ? ` · Schweregrad: ${_esc(e.schweregrad)}` : ''} + ${e.schweregrad ? ` · Schweregrad: ${UI.escape(e.schweregrad)}` : ''}
- ${e.reaktion ? `
Reaktion: ${_esc(e.reaktion)}
` : ''} - ${e.notiz ? `
${_esc(e.notiz)}
` : ''} + ${e.reaktion ? `
Reaktion: ${UI.escape(e.reaktion)}
` : ''} + ${e.notiz ? `
${UI.escape(e.notiz)}
` : ''}
@@ -840,29 +840,29 @@ window.Page_health = (() => { return `
${firstImg - ? `Vorschau` + ? `Vorschau` : `
`}
-
${_esc(e.bezeichnung)}
+
${UI.escape(e.bezeichnung)}
${UI.time.format(e.datum + 'T00:00:00')} ${count > 1 ? ` · ${count} Dateien` : ''}
- ${e.notiz ? `
${_esc(e.notiz)}
` : ''} + ${e.notiz ? `
${UI.escape(e.notiz)}
` : ''} ${count ? `
${mediaList.slice(0, 3).map(m => m.media_type === 'pdf' - ? ` PDF ` - : ` Bild @@ -992,12 +992,12 @@ window.Page_health = (() => { const mediaHtml = mediaItems.length ? `` @@ -1015,7 +1015,7 @@ window.Page_health = (() => { ? `${tabInfo.icon} ${entry.wert} ${entry.einheit || 'kg'}` : entry.typ === 'laeufigkeit' ? `${tabInfo.icon} Läufigkeit ${UI.time.format(entry.datum + 'T00:00:00')}` - : `${tabInfo.icon} ${_esc(entry.bezeichnung)}`; + : `${tabInfo.icon} ${UI.escape(entry.bezeichnung)}`; UI.modal.open({ title: modalTitle, body }); document.getElementById('health-detail-edit')?.addEventListener('click', () => { @@ -1041,23 +1041,23 @@ window.Page_health = (() => { const praxis = _praxen.find(p => p.id === e.tierarzt_id); if (praxis) { const adresse = [praxis.strasse, [praxis.plz, praxis.ort].filter(Boolean).join(' ')].filter(Boolean).join(', '); - const tel = praxis.telefon ? ` · ${_esc(praxis.telefon)}` : ''; - const oh = praxis.opening_hours ? `
🕐 ${_esc(_fmtOeffnungszeiten(praxis.opening_hours))}` : ''; - rows.push(['Praxis', ` ${_esc(praxis.name)}${adresse ? `
${_esc(adresse)}${tel}` : tel}${oh}`]); + const tel = praxis.telefon ? ` · ${UI.escape(praxis.telefon)}` : ''; + const oh = praxis.opening_hours ? `
🕐 ${UI.escape(_fmtOeffnungszeiten(praxis.opening_hours))}` : ''; + rows.push(['Praxis', ` ${UI.escape(praxis.name)}${adresse ? `
${UI.escape(adresse)}${tel}` : tel}${oh}`]); } } else if (e.tierarzt_name) { - rows.push(['Tierarzt', _esc(e.tierarzt_name)]); + rows.push(['Tierarzt', UI.escape(e.tierarzt_name)]); } - if (e.charge_nr) rows.push(['Charge-Nr.', _esc(e.charge_nr)]); + if (e.charge_nr) rows.push(['Charge-Nr.', UI.escape(e.charge_nr)]); if (e.kosten != null) rows.push(['Kosten', `${Number(e.kosten).toFixed(2)} €`]); - if (e.diagnose) rows.push(['Diagnose', _esc(e.diagnose)]); + if (e.diagnose) rows.push(['Diagnose', UI.escape(e.diagnose)]); if (e.wert) rows.push(['Gewicht', `${e.wert} ${e.einheit || 'kg'}`]); - if (e.dosierung) rows.push(['Dosierung', _esc(e.dosierung)]); - if (e.haeufigkeit) rows.push(['Häufigkeit', _esc(e.haeufigkeit)]); + if (e.dosierung) rows.push(['Dosierung', UI.escape(e.dosierung)]); + if (e.haeufigkeit) rows.push(['Häufigkeit', UI.escape(e.haeufigkeit)]); if (e.bis_datum) rows.push(['Bis', UI.time.format(e.bis_datum + 'T00:00:00')]); - if (e.schweregrad) rows.push(['Schweregrad',_esc(e.schweregrad)]); - if (e.reaktion) rows.push(['Reaktion', _esc(e.reaktion)]); - if (e.notiz) rows.push(['Notiz', _esc(e.notiz)]); + if (e.schweregrad) rows.push(['Schweregrad',UI.escape(e.schweregrad)]); + if (e.reaktion) rows.push(['Reaktion', UI.escape(e.reaktion)]); + if (e.notiz) rows.push(['Notiz', UI.escape(e.notiz)]); return `
${ rows.map(([k, v]) => `
${k}
${v}
`).join('') @@ -1077,7 +1077,7 @@ window.Page_health = (() => {
` : ''}
@@ -1091,7 +1091,7 @@ window.Page_health = (() => { const notizField = `
- +
`; @@ -1110,7 +1110,7 @@ window.Page_health = (() => { : ''; return `
${isImg - ? `Vorschau` + ? `Vorschau` : `
PDF
`} ${removeBtn}
`; @@ -1174,7 +1174,7 @@ window.Page_health = (() => { const thumb = document.createElement('div'); thumb.className = 'health-media-thumb health-media-thumb--pending'; if (isPdf) { - thumb.innerHTML = `
PDF
${_esc(f.name.slice(0, 18))}`; + thumb.innerHTML = `
PDF
${UI.escape(f.name.slice(0, 18))}`; } else { const img = document.createElement('img'); img.src = URL.createObjectURL(f); @@ -1331,7 +1331,7 @@ window.Page_health = (() => { ${aktivePraxen.map(p => ` `).join('')}
`; @@ -1350,7 +1350,7 @@ window.Page_health = (() => { ${_praxisSelectField(entry)}
- +
`; case 'entwurmung': return ` @@ -1373,7 +1373,7 @@ window.Page_health = (() => { ${aktivePraxen.map(p => ` `).join('')}
` @@ -1386,13 +1386,13 @@ window.Page_health = (() => {
+ value="${UI.escape(entry?.tierarzt_name || '')}" placeholder="Dr. Muster">
`; return ` ${praxisField}
- +
@@ -1416,12 +1416,12 @@ window.Page_health = (() => {
+ value="${UI.escape(entry?.dosierung || '')}" placeholder="z.B. 1 Tablette">
+ value="${UI.escape(entry?.haeufigkeit || '')}" placeholder="z.B. täglich, 2x wöchentlich">
@@ -1450,7 +1450,7 @@ window.Page_health = (() => {
- +
`; case 'laeufigkeit': { @@ -1632,7 +1632,7 @@ window.Page_health = (() => {
- ${_esc(p.name)} + ${UI.escape(p.name)} ${!p.aktiv ? ' · Ehemalig' : ''}
${(p.strasse || p.plz || p.ort) ? ` @@ -1642,17 +1642,17 @@ window.Page_health = (() => { ${p.opening_hours ? `
- ${_esc(_fmtOeffnungszeiten(p.opening_hours))} + ${UI.escape(_fmtOeffnungszeiten(p.opening_hours))}
` : ''} ${ratingHtml}
${p.telefon ? ` - Anrufen ` : ''} ${p.notfall_telefon ? ` - Notfall ` : ''} @@ -1749,7 +1749,7 @@ window.Page_health = (() => { async function _showPraxisDetail(praxis) { // Erst mit Lade-Spinner öffnen, dann Daten laden UI.modal.open({ - title: _esc(praxis.name), + title: UI.escape(praxis.name), body: `
Freundlichkeit: ${_renderStarsReadonly(k.freundlichkeit)}` : ''} ${k.kompetenz ? `Kompetenz: ${_renderStarsReadonly(k.kompetenz)}` : ''}
` : ''} -

${_esc(k.text || '')}

+

${UI.escape(k.text || '')}

`).join('') : `

Noch keine Kommentare.

`; @@ -1863,13 +1863,13 @@ window.Page_health = (() => {
+ placeholder="Deine Erfahrungen mit dieser Praxis…">${UI.escape(cur.text || '')}
max. 500 Zeichen
`; UI.modal.open({ - title: `${_esc(praxis.name)} bewerten`, + title: `${UI.escape(praxis.name)} bewerten`, body, footer: ` @@ -1948,41 +1948,41 @@ window.Page_health = (() => {
+ value="${UI.escape(praxis?.name || '')}" placeholder="Dr. Muster Tierarztpraxis" required>
+ value="${UI.escape(praxis?.strasse || '')}" placeholder="Musterstraße 1">
+ value="${UI.escape(praxis?.plz || '')}" placeholder="12345">
+ value="${UI.escape(praxis?.ort || '')}" placeholder="Musterstadt">
+ value="${UI.escape(praxis?.telefon || '')}" placeholder="089 123456">
+ value="${UI.escape(praxis?.notfall_telefon || '')}" placeholder="089 999999">
+ value="${UI.escape(praxis?.email || '')}" placeholder="praxis@beispiel.de">
+ placeholder="Besonderheiten, interne Hinweise…">${UI.escape(praxis?.notizen || '')}
${result.einschaetzung - ? `

${_esc(result.einschaetzung)}

` + ? `

${UI.escape(result.einschaetzung)}

` : ''} ${hinweiseHtml} ${zumTierarztHtml} @@ -2244,7 +2244,7 @@ window.Page_health = (() => {
+ value="${UI.escape(currentNr)}" placeholder="z.B. 276009200123456" maxlength="20">
`, footer: ` @@ -2260,7 +2260,7 @@ window.Page_health = (() => { UI.modal.close(); const nrEl = _container.querySelector('#health-transponder-nr'); if (nrEl) nrEl.innerHTML = nr - ? `${_esc(nr)}` + ? `${UI.escape(nr)}` : 'nicht eingetragen'; } catch (e) { UI.setLoading(btn, false); @@ -2286,8 +2286,8 @@ window.Page_health = (() => { ? new Date(neuester.erstellt_at).toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric' }) : ''; const preview = neuester.bericht.length > 180 - ? _esc(neuester.bericht.slice(0, 180)) + '…' - : _esc(neuester.bericht); + ? UI.escape(neuester.bericht.slice(0, 180)) + '…' + : UI.escape(neuester.bericht); el.innerHTML = `
${fmtDate(b)}
-
${_esc(b.bericht)}
`, +
${UI.escape(b.bericht)}
`, }); } @@ -2370,8 +2370,8 @@ window.Page_health = (() => { return `
-
${_esc(v.bezeichnung)}
-
${_esc(v.label)}${v.praxis_name ? ' · ' + _esc(v.praxis_name) : ''}
+
${UI.escape(v.bezeichnung)}
+
${UI.escape(v.label)}${v.praxis_name ? ' · ' + UI.escape(v.praxis_name) : ''}
${badge}
@@ -2380,7 +2380,7 @@ window.Page_health = (() => {
${v.uhrzeit_vorschlag} Uhr
@@ -2417,21 +2417,21 @@ window.Page_health = (() => {
- +
- +
- +
- +
`, @@ -2490,20 +2490,20 @@ window.Page_health = (() => {
${vet ? ` -
${_esc(vet.name)}
- ${adresse ? `
${_esc(adresse)}
` : ''} +
${UI.escape(vet.name)}
+ ${adresse ? `
${UI.escape(adresse)}
` : ''} ${vet.telefon ? ` ` : ''} ${vet.notfall_telefon ? `
- - Notfall: ${_esc(vet.notfall_telefon)} + Notfall: ${UI.escape(vet.notfall_telefon)}
` : ''} ` : ` @@ -2581,17 +2581,17 @@ window.Page_health = (() => { return `
- +
-
${_esc(doc.titel)}
+
${UI.escape(doc.titel)}
- ${_esc(label)}${datum ? ' · ' + datum : ''} - ${doc.vet_name ? ' · ' + _esc(doc.vet_name) : ''} + ${UI.escape(label)}${datum ? ' · ' + datum : ''} + ${doc.vet_name ? ' · ' + UI.escape(doc.vet_name) : ''}
- ${doc.beschreibung ? `
${_esc(doc.beschreibung)}
` : ''} + ${doc.beschreibung ? `
${UI.escape(doc.beschreibung)}
` : ''} ` : ''} @@ -2776,7 +2776,7 @@ window.Page_health = (() => { else if (res.saved_count !== undefined) UI.toast.info(`${res.saved_count} Bericht(e) in DB`, { duration: 8000 }); UI.modal.open({ title: `${UI.icon('star')} KI-Gesundheitsbericht`, - body: `
${_esc(zusammenfassung)}
`, + body: `
${UI.escape(zusammenfassung)}
`, }); // Berichte-Liste nach Generierung frisch laden (Cache-Buster) _loadKiBerichte(_appState.activeDog.id, true); @@ -2796,32 +2796,25 @@ window.Page_health = (() => { // ---------------------------------------------------------- // HELPER // ---------------------------------------------------------- - function _esc(str) { - if (!str) return ''; - return String(str) - .replace(/&/g, '&').replace(//g, '>') - .replace(/"/g, '"'); - } - - function _showPoiKorrekturModal(osmId, poiName, currentOh) { +function _showPoiKorrekturModal(osmId, poiName, currentOh) { UI.modal.open({ title: 'Öffnungszeiten korrigieren', body: `

- Korrektur für ${_esc(poiName)}.
+ Korrektur für ${UI.escape(poiName)}.
Dein Vorschlag wird von einem Moderator geprüft und dann für alle übernommen.

-
+ value="${UI.escape(currentOh)}">
`, @@ -2872,7 +2865,7 @@ window.Page_health = (() => { display:flex;align-items:center;justify-content:space-between;flex-shrink:0">
Notiz
-
${_esc(parentLabel)}
+
${UI.escape(parentLabel)}
@@ -2956,7 +2949,7 @@ window.Page_health = (() => {

+ placeholder="${UI.escape(placeholder)}">
') .replace(/\n/g, '
'); const restHtml = result.limit - result.anfragen_heute > 0 @@ -3092,7 +3085,7 @@ window.Page_health = (() => {
- ${_esc(r.bezeichnung)} + ${UI.escape(r.bezeichnung)} ${TYPE_LABEL[r.typ] || r.typ}
${label} @@ -3122,8 +3115,8 @@ window.Page_health = (() => {
-
${_esc(p.anbieter)}
- ${p.police_nr ? `
Police: ${_esc(p.police_nr)}
` : ''} +
${UI.escape(p.anbieter)}
+ ${p.police_nr ? `
Police: ${UI.escape(p.police_nr)}
` : ''}
`).join('') : `
@@ -3172,10 +3165,10 @@ window.Page_health = (() => { const id = `ins-form-${Date.now()}`; const body = `
- +
- +
@@ -3186,10 +3179,10 @@ window.Page_health = (() => {
- +
- +
`; const footer = ` @@ -3271,12 +3264,12 @@ window.Page_health = (() => {
- ${_esc(katLabel)} - ${trigLabel ? `${_esc(trigLabel)}` : ''} + ${UI.escape(katLabel)} + ${trigLabel ? `${UI.escape(trigLabel)}` : ''} ${fmtDate(e.datum)}${e.uhrzeit ? ' ' + e.uhrzeit : ''}
${dots}
- ${e.notiz ? `
${_esc(e.notiz)}
` : ''} + ${e.notiz ? `
${UI.escape(e.notiz)}
` : ''}
@@ -136,7 +136,7 @@ window.Page_hilfe = (() => { color:var(--c-text-secondary);text-transform:uppercase; letter-spacing:0.08em;padding:var(--space-1) 0 var(--space-2); margin-bottom:var(--space-1)"> - ${_esc(label)} + ${UI.escape(label)}
`; @@ -148,12 +148,12 @@ window.Page_hilfe = (() => { // Highlight Suchtreffer in der Frage const frageHtml = _search ? _highlight(a.frage, _search) - : _esc(a.frage); + : UI.escape(a.frage); // Antwort: Zeilenumbrüche in
wandeln const antwortHtml = _search ? _highlight(a.antwort, _search).replace(/\n/g, '
') - : _esc(a.antwort).replace(/\n/g, '
'); + : UI.escape(a.antwort).replace(/\n/g, '
'); // Bei aktiver Suche: Antwort gleich aufgeklappt const openByDefault = !!_search; @@ -222,20 +222,12 @@ window.Page_hilfe = (() => { } // ---------------------------------------------------------- - function _esc(s) { - if (s == null) return ''; - return String(s) - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"'); - } function _highlight(text, term) { if (!term) return text; const safe = term.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); const re = new RegExp(`(${safe})`, 'gi'); - return _esc(text).replace(re, + return UI.escape(text).replace(re, '$1' ); } diff --git a/backend/static/js/pages/jobs.js b/backend/static/js/pages/jobs.js index 4f2b7d3..7a07034 100644 --- a/backend/static/js/pages/jobs.js +++ b/backend/static/js/pages/jobs.js @@ -7,7 +7,6 @@ window.Page_jobs = (() => { let _container = null; let _appState = null; - const _esc = s => UI.escape(s ?? ''); const _ph = (name, size = 22) => ``; @@ -130,7 +129,7 @@ window.Page_jobs = (() => {
${app.admin_note ? `
${_esc(app.admin_note)}
` : ''} + color:var(--c-text-secondary);text-align:left">${UI.escape(app.admin_note)}
` : ''}
`; } @@ -147,13 +146,13 @@ window.Page_jobs = (() => {
+ value="${u ? UI.escape(u.name) : ''}" placeholder="Vorname oder Nickname" required>
+ value="${u ? UI.escape(u.email || '') : ''}" placeholder="deine@email.de" required>
diff --git a/backend/static/js/pages/knigge.js b/backend/static/js/pages/knigge.js index e0694e4..0d1f3ce 100644 --- a/backend/static/js/pages/knigge.js +++ b/backend/static/js/pages/knigge.js @@ -135,11 +135,11 @@ window.Page_knigge = (() => { const cards = BEGEGNUNGEN.map((b, i) => `
`).join(''); @@ -175,14 +175,14 @@ window.Page_knigge = (() => { const cards = SZENARIEN.map(s => `

- ${_esc(s.frage)} + ${UI.escape(s.frage)}

${s.antworten.map(a => ` `).join('')}
@@ -263,7 +263,7 @@ window.Page_knigge = (() => {
- ${isU ? UI.icon('arrow-right') + ' ' : ''}${_esc(a.text)}${isR ? ' ' + UI.icon('check') : ''} + ${isU ? UI.icon('arrow-right') + ' ' : ''}${UI.escape(a.text)}${isR ? ' ' + UI.icon('check') : ''} ${pct}% (${cnt})
@@ -282,7 +282,7 @@ window.Page_knigge = (() => {
${bars}
${badge} - ${_esc(szenario.erklaerung)} + ${UI.escape(szenario.erklaerung)}
`; } @@ -336,7 +336,7 @@ window.Page_knigge = (() => { padding:var(--space-4);line-height:1.6;color:var(--c-text)">
${UI.icon('robot')} KI-Rat
- ${_esc(data.rat)} + ${UI.escape(data.rat)}
`; result.style.display = 'block'; @@ -347,7 +347,7 @@ window.Page_knigge = (() => { padding:var(--space-4);color:var(--c-text-secondary);font-size:var(--text-sm)"> ${is402 ? 'Für KI-Rat wird Ban Yaro Plus oder ein laufender KI-Server benötigt.' - : _esc(err.message || 'Fehler beim KI-Abruf.')} + : UI.escape(err.message || 'Fehler beim KI-Abruf.')}
`; result.style.display = 'block'; @@ -400,16 +400,7 @@ window.Page_knigge = (() => { // ---------------------------------------------------------- // HELPER // ---------------------------------------------------------- - function _esc(str) { - if (!str) return ''; - return String(str) - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"'); - } - - // ---------------------------------------------------------- +// ---------------------------------------------------------- // PUBLIC // ---------------------------------------------------------- return { init, refresh }; diff --git a/backend/static/js/pages/litters.js b/backend/static/js/pages/litters.js index fd56fcf..6ef1748 100644 --- a/backend/static/js/pages/litters.js +++ b/backend/static/js/pages/litters.js @@ -19,15 +19,11 @@ window.Page_litters = (() => { return `
${UI.icon(icon)}
-

${_esc(title)}

-

${_esc(text)}

+

${UI.escape(title)}

+

${UI.escape(text)}

`; } - function _esc(s) { - return UI.escape ? UI.escape(s || '') : (s || '').replace(/[&<>"']/g, c => - ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])); - } function _statusBadge(status) { const map = { @@ -37,7 +33,7 @@ window.Page_litters = (() => { abgeschlossen: { label: 'Abgeschlossen', cls: 'badge-muted' }, }; const s = map[status] || { label: status, cls: 'badge-muted' }; - return `${_esc(s.label)}`; + return `${UI.escape(s.label)}`; } function _fmtDate(iso) { @@ -59,7 +55,7 @@ window.Page_litters = (() => { abgegeben: { label: 'Abgegeben', cls: 'badge-muted' }, }; const s = map[status] || { label: status, cls: 'badge-muted' }; - return `${_esc(s.label)}`; + return `${UI.escape(s.label)}`; } // ---------------------------------------------------------- @@ -101,7 +97,7 @@ window.Page_litters = (() => { const zwinger = _breederInfo?.zwingername || 'Mein Zwinger'; const logoUrl = _breederInfo?.logo_url || null; const logoHtml = logoUrl - ? `Logo` @@ -121,7 +117,7 @@ window.Page_litters = (() => {

${_esc(zwinger)}

+ text-overflow:ellipsis;line-height:1.2">${UI.escape(zwinger)}
@@ -315,7 +311,7 @@ window.Page_litters = (() => { function _litterCardHTML(l) { const verfuegbar = l.welpen_verfuegbar != null ? l.welpen_verfuegbar : '?'; const gesamt = l.welpen_gesamt != null ? l.welpen_gesamt : '?'; - const elternLabel = [l.vater_name, l.mutter_name].filter(Boolean).map(n => _esc(n)).join(' × ') || '—'; + const elternLabel = [l.vater_name, l.mutter_name].filter(Boolean).map(n => UI.escape(n)).join(' × ') || '—'; // Datum + Countdown let datumChip = ''; @@ -341,7 +337,7 @@ window.Page_litters = (() => { const welpenChip = `${UI.icon('dog')} ${verfuegbar}/${gesamt} verfügbar`; const preisChip = l.preis_spanne - ? `${UI.icon('currency-eur')} ${_esc(l.preis_spanne)}` + ? `${UI.icon('currency-eur')} ${UI.escape(l.preis_spanne)}` : ''; return ` @@ -355,8 +351,8 @@ window.Page_litters = (() => {
${(l.wurf_rang || l.wurf_name) ? `
- ${l.wurf_rang ? `${_esc(l.wurf_rang)}-Wurf` : ''} - ${l.wurf_name ? `${_esc(l.wurf_name)}` : ''} + ${l.wurf_rang ? `${UI.escape(l.wurf_rang)}-Wurf` : ''} + ${l.wurf_name ? `${UI.escape(l.wurf_name)}` : ''}
` : ''}
${elternLabel} @@ -395,7 +391,7 @@ window.Page_litters = (() => {
- ${l.beschreibung ? `

${_esc(l.beschreibung)}

` : ''} + ${l.beschreibung ? `

${UI.escape(l.beschreibung)}

` : ''}
@@ -455,7 +451,7 @@ window.Page_litters = (() => { const puppies = await API.litters.puppies(litterId); _renderPuppies(inner, litterId, puppies); } catch (err) { - inner.innerHTML = `

${_esc(err.message || 'Fehler beim Laden.')}

`; + inner.innerHTML = `

${UI.escape(err.message || 'Fehler beim Laden.')}

`; } } @@ -469,8 +465,8 @@ window.Page_litters = (() => {
${_genderIcon(p.geschlecht)} - ${p.name ? _esc(p.name) : 'Unbenannt'} - ${p.farbe ? `${_esc(p.farbe)}` : ''} + ${p.name ? UI.escape(p.name) : 'Unbenannt'} + ${p.farbe ? `${UI.escape(p.farbe)}` : ''} ${_puppyStatusBadge(p.status)}
@@ -565,7 +561,7 @@ window.Page_litters = (() => { `; UI.modal.open({ - title: `${UI.icon('scales')} Gewichtsverlauf — ${_esc(puppyLabel)}`, + title: `${UI.icon('scales')} Gewichtsverlauf — ${UI.escape(puppyLabel)}`, body, footer, }); @@ -695,7 +691,7 @@ window.Page_litters = (() => { `; } catch (err) { - el.innerHTML = `

${_esc(err.message || 'Fehler beim Laden.')}

`; + el.innerHTML = `

${UI.escape(err.message || 'Fehler beim Laden.')}

`; } } @@ -737,7 +733,7 @@ window.Page_litters = (() => { btn.innerHTML = `${UI.icon('list-bullets')} Warteliste${active ? ` ${active}` : ''}`; } } catch (err) { - inner.innerHTML = `

${_esc(err.message || 'Fehler.')}

`; + inner.innerHTML = `

${UI.escape(err.message || 'Fehler.')}

`; } } @@ -776,18 +772,18 @@ window.Page_litters = (() => {
${i + 1}
- ${_esc(e.name)} + ${UI.escape(e.name)} ${_wlStatusBadge(e.status)} ${e.wunsch_geschlecht && e.wunsch_geschlecht !== 'egal' ? `${e.wunsch_geschlecht === 'maennlich' ? '♂ Rüde' : '♀ Hündin'}` : ''} - ${e.wunsch_farbe ? `${_esc(e.wunsch_farbe)}` : ''} + ${e.wunsch_farbe ? `${UI.escape(e.wunsch_farbe)}` : ''}
- ${e.email ? `${UI.icon('envelope')} ${_esc(e.email)}` : ''} - ${e.telefon ? `${UI.icon('phone')} ${_esc(e.telefon)}` : ''} + ${e.email ? `${UI.icon('envelope')} ${UI.escape(e.email)}` : ''} + ${e.telefon ? `${UI.icon('phone')} ${UI.escape(e.telefon)}` : ''} ${UI.icon('calendar-dots')} ${e.created_at ? e.created_at.slice(0, 10) : '—'}
- ${e.nachricht ? `
"${_esc(e.nachricht)}"
` : ''} - ${e.notiz ? `
${UI.icon('note-pencil')} ${_esc(e.notiz)}
` : ''} + ${e.nachricht ? `
"${UI.escape(e.nachricht)}"
` : ''} + ${e.notiz ? `
${UI.icon('note-pencil')} ${UI.escape(e.notiz)}
` : ''}
@@ -823,16 +819,16 @@ window.Page_litters = (() => {
- +
- +
- +
@@ -846,12 +842,12 @@ window.Page_litters = (() => {
- +
- +
@@ -867,7 +863,7 @@ window.Page_litters = (() => {
- +
`, footer: ` @@ -919,7 +915,7 @@ window.Page_litters = (() => { const buildSelect = (name, idName, list, currentId, currentName, placeholder) => { const opts = list.map(h => { const label = h.name + (h.rufname ? ` (${h.rufname})` : '') + (h.zuchtbuchnummer ? ` · ${h.zuchtbuchnummer}` : ''); - return ``; + return ``; }).join(''); return ` `; + value="${UI.escape(currentName || '')}" placeholder="oder Namen frei eingeben">`; }; const rangOpts = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('').map(l => @@ -949,7 +945,7 @@ window.Page_litters = (() => { + value="${UI.escape(v.wurf_name || '')}">
@@ -968,13 +964,13 @@ window.Page_litters = (() => {
+ value="${UI.escape(v.erwartetes_datum || '')}">

Für geplante Würfe / laufende Trächtigkeit

+ value="${UI.escape(v.geburt_datum || '')}">

Wenn die Welpen bereits geboren sind

@@ -1005,19 +1001,19 @@ window.Page_litters = (() => {
+ value="${UI.escape(v.preis_spanne || '')}" placeholder="z. B. 1.500 – 2.000 €">
+ placeholder="Elternlinie, Besonderheiten, Charakter…">${UI.escape(v.beschreibung || '')}
+ placeholder="HD, ED, Gentest, Augenkontrolle…">${UI.escape(v.gesundheitstests || '')}
@@ -1030,7 +1026,7 @@ window.Page_litters = (() => {
+ value="${UI.escape(v.sichtbar_bis || '')}">
@@ -1138,7 +1134,7 @@ window.Page_litters = (() => {
+ value="${UI.escape(v.name || '')}" placeholder="z. B. Max">
@@ -1153,7 +1149,7 @@ window.Page_litters = (() => {
+ value="${UI.escape(v.farbe || '')}" placeholder="z. B. schwarz-braun">
@@ -1169,7 +1165,7 @@ window.Page_litters = (() => {
+ value="${UI.escape(v.chip_nr || '')}" placeholder="15-stellig">
@@ -1188,7 +1184,7 @@ window.Page_litters = (() => {
+ placeholder="Interne Notizen…">${UI.escape(v.notiz || '')}
@@ -1279,7 +1275,7 @@ window.Page_litters = (() => { `; UI.modal.open({ - title: `${UI.icon('file-text')} Kaufvertrag — ${_esc(puppyLabel)}`, + title: `${UI.icon('file-text')} Kaufvertrag — ${UI.escape(puppyLabel)}`, body, footer, }); @@ -1336,7 +1332,7 @@ window.Page_litters = (() => { `; UI.modal.open({ - title: `${UI.icon('images')} Fotos — ${_esc(label)}`, + title: `${UI.icon('images')} Fotos — ${UI.escape(label)}`, body, footer, }); @@ -1358,21 +1354,21 @@ window.Page_litters = (() => { const vis = visLabels[ph.visibility] || visLabels.private; return `
- - ${_esc(ph.caption || '')} + ${UI.escape(ph.caption || '')} `, }); return; @@ -1548,7 +1544,7 @@ window.Page_litters = (() => { UI.modal.open({ title: `${UI.icon('sparkle')} KI-Wurfankündigung`, - body: `
${_esc(text)}
`, + body: `
${UI.escape(text)}
`, footer: ` @@ -447,19 +447,19 @@ window.Page_lost = (() => { : ''}
- 🐕 ${_escape(r.name)} - ${r.rasse ? `${_escape(r.rasse)}` : ''} + 🐕 ${UI.escape(r.name)} + ${r.rasse ? `${UI.escape(r.rasse)}` : ''}

- ${_escape(r.beschreibung)} + ${UI.escape(r.beschreibung)}

📍 ${r.lat.toFixed(5)}, ${r.lon.toFixed(5)}${distStr ? ' (' + distStr + ' entfernt)' : ''}
📅 Gemeldet: ${_fmtDate(r.created_at)}
- ${r.melder_name ? `
👤 Gemeldet von: ${_escape(r.melder_name.split(' ')[0])}
` : ''} + ${r.melder_name ? `
👤 Gemeldet von: ${UI.escape(r.melder_name.split(' ')[0])}
` : ''}
@@ -473,7 +473,7 @@ window.Page_lost = (() => {
`; - UI.modal.open({ title: `🔍 ${_escape(r.name)} wird vermisst`, body }); + UI.modal.open({ title: `🔍 ${UI.escape(r.name)} wird vermisst`, body }); document.getElementById('detail-lost-map')?.addEventListener('click', () => { UI.modal.close(); @@ -511,10 +511,10 @@ window.Page_lost = (() => { // ---------------------------------------------------------- function _showFoundDialog(r) { UI.modal.open({ - title: `🎉 ${_escape(r.name)} gefunden?`, + title: `🎉 ${UI.escape(r.name)} gefunden?`, body: `

- Wurde ${_escape(r.name)} wiedergefunden? Die Meldung wird als + Wurde ${UI.escape(r.name)} wiedergefunden? Die Meldung wird als abgeschlossen markiert und aus der Liste entfernt.

`, @@ -555,7 +555,7 @@ window.Page_lost = (() => { const dogs = _appState.dogs || []; const dogOpts = dogs.length > 0 ? `` + - dogs.map(d => ``).join('') + dogs.map(d => ``).join('') : ''; const body = ` @@ -790,17 +790,7 @@ window.Page_lost = (() => { day: '2-digit', month: '2-digit', year: 'numeric' }); } - - function _escape(str) { - if (!str) return ''; - return String(str) - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"'); - } - - function _emptyState(icon, title, text, cta = '') { +function _emptyState(icon, title, text, cta = '') { return `
Notiz
-
${_escape(parentLabel)}
+
${UI.escape(parentLabel)}
diff --git a/backend/static/js/pages/map.js b/backend/static/js/pages/map.js index b51ce30..7b70409 100644 --- a/backend/static/js/pages/map.js +++ b/backend/static/js/pages/map.js @@ -1344,15 +1344,15 @@ window.Page_map = (() => { }); const marker = L.marker([b.location_lat, b.location_lng], { icon, zIndexOffset: t.z ?? 0 }) - .bindTooltip(_esc(b.zwingername), { direction: 'top', offset: [0, -16] }); + .bindTooltip(UI.escape(b.zwingername), { direction: 'top', offset: [0, -16] }); marker.on('click', () => { - const rasseText = b.rasse_text ? `
${_esc(b.rasse_text)}
` : ''; - const stadtText = b.stadt ? `
${_esc(b.stadt)}
` : ''; + const rasseText = b.rasse_text ? `
${UI.escape(b.rasse_text)}
` : ''; + const stadtText = b.stadt ? `
${UI.escape(b.stadt)}
` : ''; marker.bindPopup(`
-
${t.icon} ${_esc(b.zwingername)}
+
${t.icon} ${UI.escape(b.zwingername)}
${rasseText}${stadtText}
diff --git a/backend/static/js/pages/moderation.js b/backend/static/js/pages/moderation.js index d1dfd7f..048fef5 100644 --- a/backend/static/js/pages/moderation.js +++ b/backend/static/js/pages/moderation.js @@ -162,17 +162,17 @@ window.Page_moderation = (() => { gap:var(--space-4)"> ${fotos.map(f => `
- - +
- ${_esc(f.rasse_name || f.rasse_slug)} + ${UI.escape(f.rasse_name || f.rasse_slug)}
- von ${_esc(f.user_name)} + von ${UI.escape(f.user_name)}
${f.rights_confirmed @@ -183,7 +183,7 @@ window.Page_moderation = (() => {
${f.aktuell_foto ? `
Aktuell:
- Aktuell @@ -299,23 +299,23 @@ window.Page_moderation = (() => { background:var(--c-surface-2); display:flex;align-items:center;justify-content:center; font-weight:var(--weight-bold);color:var(--c-text-secondary)"> - ${_esc(u.name[0].toUpperCase())} + ${UI.escape(u.name[0].toUpperCase())}
- ${_esc(u.name)} + ${UI.escape(u.name)} ${u.is_banned ? `GESPERRT` : ''}
- ${_esc(u.email)} · + ${UI.escape(u.email)} · - ${_esc(u.rolle)} + ${UI.escape(u.rolle)}
@@ -323,12 +323,12 @@ window.Page_moderation = (() => { ${canAction ? (u.is_banned ? `` : ``) @@ -408,19 +408,19 @@ window.Page_moderation = (() => {
- ${_esc(r.target_type)} #${r.target_id} · - Gemeldet von ${_esc(r.melder_name)} + ${UI.escape(r.target_type)} #${r.target_id} · + Gemeldet von ${UI.escape(r.melder_name)}
- Grund: ${_esc(r.grund)} + Grund: ${UI.escape(r.grund)}
${r.content_preview ? `
- ${_esc(r.content_preview)} + ${UI.escape(r.content_preview)}
` : ''}
@@ -202,17 +202,17 @@ window.Page_movies = (() => { const _ico = name => ``; const typLabel = film.typ === 'serie' ? `${_ico('list')} Serie` : film.typ === 'doku' ? `${_ico('camera')} Doku` : ''; const imdb = film.imdb_rating ? `IMDb ${film.imdb_rating}` : ''; - const streaming = film.streaming ? `${_esc(film.streaming)}` : ''; + const streaming = film.streaming ? `${UI.escape(film.streaming)}` : ''; return ` -
+
${film.bild_emoji}
-
${_esc(film.titel)} (${film.jahr})
+
${UI.escape(film.titel)} (${film.jahr})
- ${_esc(film.genre)}${typLabel ? `${typLabel}` : ''} + ${UI.escape(film.genre)}${typLabel ? `${typLabel}` : ''}
-
${_esc(film.hund_rasse)}
+
${UI.escape(film.hund_rasse)}
${tag}
${imdb}${streaming}
${stars}
@@ -234,17 +234,17 @@ window.Page_movies = (() => { const body = `
${film.bild_emoji}
- ${_esc(film.genre)} - ${_esc(film.hund_rasse)} + ${UI.escape(film.genre)} + ${UI.escape(film.hund_rasse)} ${film.jahr}
${bannerText}
-

${_esc(film.beschreibung)}

+

${UI.escape(film.beschreibung)}

Community-Bewertung:
- -
@@ -102,30 +102,30 @@ window.Page_partner_profil = (() => { + value="${UI.escape(p.display_name || '')}">
+ value="${UI.escape(p.tagline || '')}">
+ placeholder="Wer bist du, was machst du, was verbindet dich mit Hunden?">${UI.escape(p.bio || p.pp_bio || '')}
+ value="${UI.escape(p.website || '')}">
+ value="${UI.escape(p.instagram || '')}">
`; } - function _esc(s) { - return String(s || '').replace(/[&<>"']/g, c => - ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])); - } return { init, refresh, onDogChange }; diff --git a/backend/static/js/pages/partner.js b/backend/static/js/pages/partner.js index 884d4b2..a59b2b2 100644 --- a/backend/static/js/pages/partner.js +++ b/backend/static/js/pages/partner.js @@ -77,10 +77,10 @@ window.Page_partner = (() => {
${p.logo_url - ? `` : p.avatar_url - ? `` : `
-
${_esc(p.display_name || p.name)}
- ${p.tagline ? `
${_esc(p.tagline)}
` : ''} +
${UI.escape(p.display_name || p.name)}
+ ${p.tagline ? `
${UI.escape(p.tagline)}
` : ''}
- ${p.website ? ` - 🌐 ${_esc(p.website.replace(/^https?:\/\//, ''))}` : ''} - ${p.instagram ? `📸 ${_esc(p.instagram)}` : ''} + 🌐 ${UI.escape(p.website.replace(/^https?:\/\//, ''))}` : ''} + ${p.instagram ? `📸 ${UI.escape(p.instagram)}` : ''}
${p.pp_bio || p.bio ? `

- ${_esc(p.pp_bio || p.bio)} + ${UI.escape(p.pp_bio || p.bio)}

` : ''} ${p.photos?.length ? `
` - : ``; + : ``; }).join('')}
` : ''}
@@ -143,10 +143,6 @@ window.Page_partner = (() => { `; } - function _esc(s) { - return String(s || '').replace(/[&<>"']/g, c => - ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])); - } return { init, refresh, onDogChange }; diff --git a/backend/static/js/pages/playdate.js b/backend/static/js/pages/playdate.js index 1527c97..618a9fb 100644 --- a/backend/static/js/pages/playdate.js +++ b/backend/static/js/pages/playdate.js @@ -15,21 +15,16 @@ window.Page_playdate = (() => { // ------------------------------------------------------------------ // Helpers // ------------------------------------------------------------------ - function _esc(s) { - return String(s || '').replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); - } - - function _fmtDate(iso) { +function _fmtDate(iso) { if (!iso) return ''; const d = new Date(iso.replace(' ', 'T')); return d.toLocaleDateString('de-DE'); } function _dogAvatar(foto_url, name, size = 48) { - const initials = _esc((name || '?').charAt(0).toUpperCase()); + const initials = UI.escape((name || '?').charAt(0).toUpperCase()); if (foto_url) { - return `${initials}`; } @@ -250,29 +245,29 @@ window.Page_playdate = (() => { ${_dogAvatar(d.foto_url, d.dog_name, 56)}
${_esc(d.dog_name)}
- ${d.rasse ? `
${_esc(d.rasse)}
` : ''} - ${d.alter ? `
${_esc(d.alter)}
` : ''} + color:var(--c-text)">${UI.escape(d.dog_name)}
+ ${d.rasse ? `
${UI.escape(d.rasse)}
` : ''} + ${d.alter ? `
${UI.escape(d.alter)}
` : ''}
${UI.icon('map-pin')} - ${d.ort_name ? _esc(d.ort_name) + ' · ' : ''}${d.entfernung_km} km entfernt + ${d.ort_name ? UI.escape(d.ort_name) + ' · ' : ''}${d.entfernung_km} km entfernt - ${d.geschlecht ? `${_esc(d.geschlecht)}` : ''} + ${d.geschlecht ? `${UI.escape(d.geschlecht)}` : ''}
${d.beschreibung ? `

- ${_esc(d.beschreibung)} + ${UI.escape(d.beschreibung)}

` : ''}
@@ -393,8 +388,8 @@ window.Page_playdate = (() => {
${_dogAvatar(dog.foto_url, dog.name, 44)}
-
${_esc(dog.name)}
- ${dog.rasse ? `
${_esc(dog.rasse)}
` : ''} +
${UI.escape(dog.name)}
+ ${dog.rasse ? `
${UI.escape(dog.rasse)}
` : ''}
${UI.icon('map-pin')} - ${listing.ort_name ? _esc(listing.ort_name) + ' · ' : ''} + ${listing.ort_name ? UI.escape(listing.ort_name) + ' · ' : ''} Radius: ${listing.radius_km} km
${listing.beschreibung ? `

${_esc(listing.beschreibung)}

` : ''} + margin:0 0 var(--space-3);line-height:1.5">${UI.escape(listing.beschreibung)}

` : ''} ` : `

Noch kein Inserat — trage dich ein, damit andere dich finden können. @@ -445,7 +440,7 @@ window.Page_playdate = (() => {

+ value="${UI.escape(existing?.ort_name || '')}">
`; } return ``; }).join(''); @@ -230,27 +222,27 @@ window.Page_reise = (() => { const done = !!checked[key]; if (_editMode) { return `
- ${_esc(item)} -
`; } return ``; }).join(''); const addRow = _editMode ? `
- - @@ -261,9 +253,9 @@ window.Page_reise = (() => {
- ${_esc(cat.label)} + ${UI.escape(cat.label)}
${stdRows}${customRows}${addRow} @@ -389,10 +381,10 @@ window.Page_reise = (() => { ${l.flag}
- ${_esc(l.name)} + ${UI.escape(l.name)}
- ${_esc(l.regel)} + ${UI.escape(l.regel)}
${l.warn ? `
- ${_esc(m.text)} + ${UI.escape(m.text)}
`).join(''); el.innerHTML = ` diff --git a/backend/static/js/pages/settings.js b/backend/static/js/pages/settings.js index 0244b5f..ced3e39 100644 --- a/backend/static/js/pages/settings.js +++ b/backend/static/js/pages/settings.js @@ -509,9 +509,9 @@ window.Page_settings = (() => { // Avatar: Bild oder Buchstabe const avatarInner = u.avatar_url - ? `Avatar` - : _esc(u.name.charAt(0).toUpperCase()); + : UI.escape(u.name.charAt(0).toUpperCase()); // Mitglied seit const memberSince = (() => { @@ -547,9 +547,9 @@ window.Page_settings = (() => {
-
${_esc(u.name)}
+
${UI.escape(u.name)}
- ${_esc(u.email)} + ${UI.escape(u.email)} ${u.email_verified ? `` : ` {
${memberSince ? `
- Mitglied seit ${_esc(memberSince)} + Mitglied seit ${UI.escape(memberSince)}
` : ''} ${u.bio - ? `
${_esc(u.bio)}
` + ? `
${UI.escape(u.bio)}
` : ''} ${u.wohnort ? `
- 📍 ${_esc(u.wohnort)} + 📍 ${UI.escape(u.wohnort)}
` : ''} ${u.erfahrung && erfahrungLabel[u.erfahrung] ? `
- ${_esc(erfahrungLabel[u.erfahrung])} + ${UI.escape(erfahrungLabel[u.erfahrung])}
` : ''} ${u.social_link ? `` : ''} ${!u.bio && !u.wohnort && !u.erfahrung && !u.social_link @@ -877,17 +877,17 @@ window.Page_settings = (() => { if (!el || !dogs.length) return; el.innerHTML = dogs.map(d => { const av = d.foto_url - ? `` + ? `` : `
`; const jahr = d.verstorben_am ? d.verstorben_am.slice(0, 4) : ''; return ` -
${_FL[idea.format]||idea.format} @@ -427,16 +427,16 @@ window.Page_social = (() => {
@@ -522,15 +522,15 @@ window.Page_social = (() => { margin-bottom:6px;display:flex;align-items:center;gap:10px">
- ${_esc(e.name)}
+ ${UI.escape(e.name)}
- ${_esc(e.schwierigkeit||'')} · ${_esc(e.alter_ab||'')} · ${_esc(e.dauer||'')}
+ ${UI.escape(e.schwierigkeit||'')} · ${UI.escape(e.alter_ab||'')} · ${UI.escape(e.dauer||'')}
${e.posts_count > 0 ? ` ${e.posts_count}x` : ''}
@@ -580,9 +580,9 @@ window.Page_social = (() => { 🎾
- Trainingstipp · ${_esc(data.exercise_kat||'')} · ${stilLabel}
+ Trainingstipp · ${UI.escape(data.exercise_kat||'')} · ${stilLabel}
- ${_esc(data.exercise_name||'')}
+ ${UI.escape(data.exercise_name||'')}
${_renderResult(data, null)}`; @@ -592,7 +592,7 @@ window.Page_social = (() => { } catch(e) { clearInterval(interval.bar); clearInterval(interval.msg); res.innerHTML = `
- 😬 ${_esc(e.message||String(e))}
`; + 😬 ${UI.escape(e.message||String(e))}
`; } finally { btn.disabled = false; } @@ -620,10 +620,10 @@ window.Page_social = (() => { 🛁
- Pflegetipp · ${_esc(data.pflege_kat||'')} - ${data.rasse_name ? ` · speziell für ${_esc(data.rasse_name)}` : ''}
+ Pflegetipp · ${UI.escape(data.pflege_kat||'')} + ${data.rasse_name ? ` · speziell für ${UI.escape(data.rasse_name)}` : ''}
- ${_esc(data.pflege_titel||'')}
+ ${UI.escape(data.pflege_titel||'')}
${_renderResult(data, null)}`; @@ -633,7 +633,7 @@ window.Page_social = (() => { } catch(e) { clearInterval(interval.bar); clearInterval(interval.msg); res.innerHTML = `
- 😬 ${_esc(e.message||String(e))}
`; + 😬 ${UI.escape(e.message||String(e))}
`; } finally { btn.disabled = false; } }); @@ -663,7 +663,7 @@ window.Page_social = (() => {
Rasse des Tages
- ${_esc(data.topic?.replace('Rasse des Tages: ',''))}
+ ${UI.escape(data.topic?.replace('Rasse des Tages: ',''))}
${_renderResult(data, mediaUrl)}`; @@ -675,7 +675,7 @@ window.Page_social = (() => { } catch(e) { clearInterval(interval.bar); clearInterval(interval.msg); res.innerHTML = `
- 😬 ${_esc(e.message||String(e))}
`; + 😬 ${UI.escape(e.message||String(e))}
`; } finally { btn.disabled = false; } @@ -719,7 +719,7 @@ window.Page_social = (() => { clearInterval(interval); res.innerHTML = `
- 😬 Ups: ${_esc(e.message||String(e))}
`; + 😬 Ups: ${UI.escape(e.message||String(e))}
`; } finally { btn.disabled = false; btn.innerHTML = ' Los geht\'s!'; @@ -816,7 +816,7 @@ window.Page_social = (() => {
Luna sagt:
-
${_esc(data.coaching)}
+
${UI.escape(data.coaching)}
` : ''} @@ -903,9 +903,9 @@ window.Page_social = (() => { ${data.hook ? `
🎣 Hook
- "${_esc(data.hook)}"
` : ''} + "${UI.escape(data.hook)}"` : ''} ${data.cta ? `
📣 Call-to-Action
-
${_esc(data.cta)}
` : ''} +
${UI.escape(data.cta)}
` : ''} ` : ''} ${_resultBlock('📸 Was du filmen/fotografieren solltest', data.visual_brief, false)} ${data.script ? ` @@ -914,7 +914,7 @@ window.Page_social = (() => { margin-bottom:var(--space-3);box-shadow:var(--shadow-xs)">
🎬 Video-Aufbau
${_esc(data.script)}
+ line-height:1.7">${UI.escape(data.script)} ` : ''} ${(data.image_prompt||data.canva_notes||unsplash) ? `
${_esc(data.image_prompt)}
+ margin-bottom:var(--space-3);line-height:1.5">${UI.escape(data.image_prompt)} ${_copyBtn(data.image_prompt)}` : ''} ${data.canva_notes ? `
Canva:
${_esc(data.canva_notes)}
` : ''} + line-height:1.6">${UI.escape(data.canva_notes)}` : ''} ${unsplash ? ` 🔍 Kostenlose Fotos auf Unsplash →` : ''} @@ -945,14 +945,14 @@ window.Page_social = (() => { margin-bottom:var(--space-3);box-shadow:var(--shadow-xs)">
${label}
${_esc(text)}
+ margin-bottom:${copyable?'var(--space-3)':'0'}">${UI.escape(text)} ${copyable ? _copyBtn(text) : ''} `; } function _copyBtn(text) { return ``; @@ -1012,7 +1012,7 @@ window.Page_social = (() => {
🎉 Super! Post als veröffentlicht markiert. - ${url ? `
Post ansehen →` : ''}
`; // Stats aktualisieren @@ -1073,7 +1073,7 @@ window.Page_social = (() => {
- ${_esc((item.caption||'').substring(0,150))}${(item.caption||'').length>150?'…':''}
+ ${UI.escape((item.caption||'').substring(0,150))}${(item.caption||'').length>150?'…':''} ${item.hashtags ? `
@@ -1156,11 +1156,11 @@ window.Page_social = (() => { ${c.ai_score ? `${'⭐'.repeat(c.ai_score)}` : ''}
${_esc(c.topic)}
+ line-height:1.3">${UI.escape(c.topic)} ${c.hook ? `
🎣 ${_esc(c.hook)}
` : ''} + font-style:italic;margin-bottom:2px">🎣 ${UI.escape(c.hook)}` : ''} ${c.post_url - ? ` Post ansehen` @@ -1195,10 +1195,10 @@ window.Page_social = (() => { border-top:1px solid var(--c-border);padding-top:10px"> ${c.coaching ? `
- 🌙 ${_esc(c.coaching)}
` : ''} + 🌙 ${UI.escape(c.coaching)}` : ''} ${c.caption ? `
Caption:
${_esc(c.caption)}
+ margin-bottom:8px">${UI.escape(c.caption)} ${_copyBtn(c.caption)}` : ''} ${c.hashtags ? `
@@ -1375,7 +1375,7 @@ window.Page_social = (() => {
Lunas Feedback:
-
${_esc(data.notes)}
+
${UI.escape(data.notes)}
` : ''} @@ -1384,7 +1384,7 @@ window.Page_social = (() => { API.get('/social/stats').then(s => { _stats = s; }); } catch(e) { clearInterval(interval); - res.innerHTML = `
😬 Fehler: ${_esc(e.message||String(e))}
`; + res.innerHTML = `
😬 Fehler: ${UI.escape(e.message||String(e))}
`; } finally { btn.disabled = false; btn.innerHTML = '🔍 Luna, schau mal drüber!'; @@ -1404,12 +1404,6 @@ window.Page_social = (() => { return picked; } - function _esc(s) { - if (!s) return ''; - return String(s).replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"'); - } - // CSS const style = document.createElement('style'); style.textContent = ` diff --git a/backend/static/js/pages/trainingsplaene.js b/backend/static/js/pages/trainingsplaene.js index faa3bbe..7752ea7 100644 --- a/backend/static/js/pages/trainingsplaene.js +++ b/backend/static/js/pages/trainingsplaene.js @@ -26,16 +26,7 @@ window.Page_trainingsplaene = (() => { // ---------------------------------------------------------- // HELPER // ---------------------------------------------------------- - function _esc(str) { - if (!str) return ''; - return String(str) - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"'); - } - - function _icon(name) { +function _icon(name) { return ``; } @@ -57,9 +48,9 @@ window.Page_trainingsplaene = (() => { // ---------------------------------------------------------- function _renderTable(headers, rows) { - const ths = headers.map(h => `${_esc(h)}`).join(''); + const ths = headers.map(h => `${UI.escape(h)}`).join(''); const trs = rows.map(row => { - const tds = row.map((cell, i) => `${_esc(cell)}`).join(''); + const tds = row.map((cell, i) => `${UI.escape(cell)}`).join(''); return `${tds}`; }).join(''); return ` @@ -80,15 +71,15 @@ window.Page_trainingsplaene = (() => { if (checked) doneCount++; return ` `; }).join(''); const progress = total > 0 ? Math.round((doneCount / total) * 100) : 0; return ` -
+
${_icon('check-circle')} Lernziele @@ -106,13 +97,13 @@ window.Page_trainingsplaene = (() => { function _renderAccordionPhase(id, title, content) { return ` -
- - @@ -122,7 +113,7 @@ window.Page_trainingsplaene = (() => { function _renderHintBox(text) { return `
- ${_icon('info')} ${_esc(text)} + ${_icon('info')} ${UI.escape(text)}
`; } @@ -141,7 +132,7 @@ window.Page_trainingsplaene = (() => { justify-content:center;gap:2px;white-space:normal;text-align:center;line-height:1.2"> ${p.label} - ${_esc(p.sub)} + ${UI.escape(p.sub)} `).join(''); return `
${btns}
`; } @@ -764,7 +755,7 @@ window.Page_trainingsplaene = (() => {
- ${_esc(MONTHS[month - 1])} ${year} + ${UI.escape(MONTHS[month - 1])} ${year}
${wdayHeader} @@ -793,7 +784,7 @@ window.Page_trainingsplaene = (() => { display:flex;align-items:center;justify-content:space-between;flex-shrink:0">
Notiz
-
${_esc(parentLabel)}
+
${UI.escape(parentLabel)}
diff --git a/backend/static/js/pages/uebungen.js b/backend/static/js/pages/uebungen.js index 578d687..56dcd02 100644 --- a/backend/static/js/pages/uebungen.js +++ b/backend/static/js/pages/uebungen.js @@ -633,7 +633,7 @@ window.Page_uebungen = (() => { border-radius:var(--radius-full,999px); background:var(--c-primary-subtle);color:var(--c-primary); font-size:var(--text-xs);font-weight:var(--weight-semibold)"> - ${b.icon || '🏅'} ${_esc(b.name || b.badge_id)} + ${b.icon || '🏅'} ${UI.escape(b.name || b.badge_id)} `).join(''); const more = rest > 0 @@ -715,8 +715,8 @@ window.Page_uebungen = (() => { text-transform:uppercase;letter-spacing:.04em">${cfg.label}
${_esc(r.exercise_name)}
-
${_esc(r.reason)}
+ color:var(--c-text);line-height:1.3">${UI.escape(r.exercise_name)}
+
${UI.escape(r.reason)}
${r.suggested_reps}× empfohlen @@ -724,7 +724,7 @@ window.Page_uebungen = (() => { ${prognose}
@@ -817,25 +817,25 @@ window.Page_uebungen = (() => { ${ALL.map(g => `
- ${_esc(g.group)} + ${UI.escape(g.group)}
${g.items.map(u => { const key = _progressKey(g.tab, u.name); const cur = _getStatus(g.tab, u.name); return `
+ padding:var(--space-2) 0;border-bottom:1px solid var(--c-border)" data-key="${UI.escape(key)}"> ${_esc(u.name)} + overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${UI.escape(u.name)}
${STATUS_QUICK.map(s => ` - `).join('')}
`; @@ -899,7 +899,7 @@ window.Page_uebungen = (() => { ${TABS.map(t => ` `).join('')}
@@ -922,18 +922,18 @@ window.Page_uebungen = (() => { return `
- ${_esc(s.title)} + ${UI.escape(s.title)}
- ${_esc(s.text)} + ${UI.escape(s.text)}
@@ -1074,7 +1074,7 @@ window.Page_uebungen = (() => { ); if (!allExercises.length) { return `
- ${UI.icon('magnifying-glass')} Keine Übungen gefunden für „${_esc(q)}" + ${UI.icon('magnifying-glass')} Keine Übungen gefunden für „${UI.escape(q)}"
`; } return `
@@ -1082,7 +1082,7 @@ window.Page_uebungen = (() => {
${_esc(u.kategorie)}
+ margin-bottom:var(--space-1);padding:0 var(--space-2)">${UI.escape(u.kategorie)}
${_renderCard(u, i)}
`).join('')}
`; @@ -1114,25 +1114,25 @@ window.Page_uebungen = (() => { const hasBody = (u.schritte?.length > 0) || (u.fehler?.length > 0) || !!u.steigerung || !!u.tipp; return ` -
+
- ${_esc(u.name)} + ${UI.escape(u.name)} - ${_esc(diff.label)} + ${UI.escape(diff.label)}
@@ -1178,20 +1178,20 @@ window.Page_uebungen = (() => {
- ${_esc(u.dauer)} + ${UI.escape(u.dauer)} - ${_esc(u.alter)} + ${UI.escape(u.alter)} - ${_esc(u.material)} + ${UI.escape(u.material)}
${u.beschreibung ? `

- ${_esc(u.beschreibung)} + ${UI.escape(u.beschreibung)}

` : ''} ${u.hinweis ? ` @@ -1200,7 +1200,7 @@ window.Page_uebungen = (() => { font-size:var(--text-xs);color:var(--c-text);line-height:1.4; display:flex;align-items:flex-start;gap:var(--space-2)"> - ${_esc(u.hinweis)} + ${UI.escape(u.hinweis)}
` : ''}
@@ -1225,7 +1225,7 @@ window.Page_uebungen = (() => {

    ${u.schritte.map(s => ` -
  1. ${_esc(s)}
  2. +
  3. ${UI.escape(s)}
  4. `).join('')}
` : ''} @@ -1237,7 +1237,7 @@ window.Page_uebungen = (() => {

    ${u.fehler.map(f => ` -
  • ${_esc(f)}
  • +
  • ${UI.escape(f)}
  • `).join('')}
` : ''} @@ -1247,14 +1247,14 @@ window.Page_uebungen = (() => { - Steigerung: ${_esc(u.steigerung)} + Steigerung: ${UI.escape(u.steigerung)}
` : ''} ${u.tipp ? `
- 💡 ${_esc(u.tipp)} + 💡 ${UI.escape(u.tipp)}
` : ''}
` : ''} @@ -1281,7 +1281,7 @@ window.Page_uebungen = (() => { - ${next ? `${_esc(sm.label)}` : ''} + ${next ? `${UI.escape(sm.label)}` : ''} `; }); }); @@ -1344,7 +1344,7 @@ window.Page_uebungen = (() => {

- Notiz: ${_esc(exerciseName)} + Notiz: ${UI.escape(exerciseName)}

@@ -1359,7 +1359,7 @@ window.Page_uebungen = (() => { border-radius:var(--radius-md);font-size:var(--text-sm); font-family:var(--font-sans);background:var(--c-surface); color:var(--c-text);resize:vertical;outline:none; - line-height:1.5">${_esc(noteText)} + line-height:1.5">${UI.escape(noteText)}
@@ -1569,7 +1569,7 @@ window.Page_uebungen = (() => {

- Einheit loggen: ${_esc(exerciseName)} + Einheit loggen: ${UI.escape(exerciseName)}

@@ -1620,7 +1620,7 @@ window.Page_uebungen = (() => { border-radius:var(--radius-md);border:1.5px solid var(--c-border); background:var(--c-surface-2);cursor:pointer;transition:all 0.15s"> ${emoji} - ${_esc(val)} + ${UI.escape(val)} `).join('')}
@@ -2103,7 +2103,7 @@ window.Page_uebungen = (() => { : ''; const noteHtml = s.notiz ? `
${_esc(s.notiz)}
` + line-height:1.4;font-style:italic">${UI.escape(s.notiz)}` : ''; return `
${_esc(s.exercise_name)} + color:var(--c-text)">${UI.escape(s.exercise_name)} ${topBadge}
@@ -2146,7 +2146,7 @@ window.Page_uebungen = (() => {
- ${_esc(label)} + ${UI.escape(label)}
${sessions.map(_sessionRow).join('')} @@ -2216,7 +2216,7 @@ window.Page_uebungen = (() => {
- ${_esc(dateLabel)} + ${UI.escape(dateLabel)} ${erfolg} ${s.erfolgsquote}%${top} ${s.wiederholungen}× Wdh.${stimmung ? ' ' + stimmung : ''} @@ -2244,12 +2244,12 @@ window.Page_uebungen = (() => {
- ${_esc(ex.name)} + ${UI.escape(ex.name)}
${ex.sessions.length} Einheit${ex.sessions.length !== 1 ? 'en' : ''} ${ex.topCount ? ' · ' + ex.topCount + '× TOP' : ''} - · ${_esc(lastLabel)} + · ${UI.escape(lastLabel)}
@@ -2350,8 +2350,8 @@ window.Page_uebungen = (() => { ['Ablenkungstraining', 'Wieder häufiger (höhere Anforderung)'], ].map(([p, b], i) => ` - ${_esc(p)} - ${_esc(b)} + ${UI.escape(p)} + ${UI.escape(b)} `).join('')} @@ -2391,9 +2391,9 @@ window.Page_uebungen = (() => { ].map(([s, b, c], i) => ` - ${_esc(s)} + ${UI.escape(s)} - ${_esc(b)} + ${UI.escape(b)} `).join('')} @@ -2425,7 +2425,7 @@ window.Page_uebungen = (() => { color:${ok ? 'var(--c-success)' : 'var(--c-danger)'}" aria-hidden="true"> - ${_esc(text)} + ${UI.escape(text)} `).join('')} @@ -2438,16 +2438,7 @@ window.Page_uebungen = (() => { // ---------------------------------------------------------- // HELPER // ---------------------------------------------------------- - function _esc(str) { - if (!str) return ''; - return String(str) - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"'); - } - - // ---------------------------------------------------------- +// ---------------------------------------------------------- // PUBLIC // ---------------------------------------------------------- return { init, refresh, onDogChange }; diff --git a/backend/static/js/pages/wetter.js b/backend/static/js/pages/wetter.js index 225a8c4..e3803fe 100644 --- a/backend/static/js/pages/wetter.js +++ b/backend/static/js/pages/wetter.js @@ -368,7 +368,7 @@ window.Page_wetter = (() => { box-shadow:${shadow};transform:${transform}; transition:all .15s;user-select:none"> ${_esc(dayName)} + margin-bottom:var(--space-1)">${UI.escape(dayName)}
${_wmoIcon(d.weathercode, '1.5rem', active ? 'filter:brightness(0) invert(1)' : '')}
@@ -414,13 +414,13 @@ window.Page_wetter = (() => { : 0; } - const locName = _data.location_name ? `
${_esc(_data.location_name)}
` : ''; + const locName = _data.location_name ? `
${UI.escape(_data.location_name)}
` : ''; el.innerHTML = ` ${locName}
${_wmoIcon(d.weathercode, '3.5rem')}
-
${_esc(desc)}
+
${UI.escape(desc)}
${Math.round(d.temp_max)}° @@ -445,10 +445,10 @@ window.Page_wetter = (() => { margin-bottom:var(--space-1)"> - ${_esc(sunriseStr)} + ${UI.escape(sunriseStr)} - ${_esc(sunsetStr)} + ${UI.escape(sunsetStr)}
@@ -469,9 +469,9 @@ window.Page_wetter = (() => {
- ${_esc(compass)} · ${Math.round(d.wind_kmh ?? 0)} km/h + ${UI.escape(compass)} · ${Math.round(d.wind_kmh ?? 0)} km/h
-
${_esc(bft)}
+
${UI.escape(bft)}
${d.precip_sum != null ? `
@@ -488,7 +488,7 @@ window.Page_wetter = (() => { font-size:var(--text-xs);margin-bottom:4px"> UV-Index - ${d.uv_index ?? 0} — ${_esc(uvLabel)} + ${d.uv_index ?? 0} — ${UI.escape(uvLabel)}
@@ -596,7 +596,7 @@ window.Page_wetter = (() => { Niederschlagswahrscheinlichkeit - ${_selDay === 0 ? 'heute' : _esc(d.date ? new Date(d.date + 'T12:00').toLocaleDateString('de', {weekday:'short', day:'numeric', month:'short'}) : '')} + ${_selDay === 0 ? 'heute' : UI.escape(d.date ? new Date(d.date + 'T12:00').toLocaleDateString('de', {weekday:'short', day:'numeric', month:'short'}) : '')}
@@ -648,10 +648,10 @@ window.Page_wetter = (() => { margin-bottom:var(--space-4);text-align:center">
${_wl.emoji}
- ${_esc(_wl.label)} + ${UI.escape(_wl.label)}
- ${_esc(_wl.sub)} + ${UI.escape(_wl.sub)}

@@ -670,10 +670,10 @@ window.Page_wetter = (() => {
- Asphalt ~${Math.round(d.asphalt_temp)}°C — ${_esc(aspText)} + Asphalt ~${Math.round(d.asphalt_temp)}°C — ${UI.escape(aspText)}
${aspAdvice ? `
- ${_esc(aspAdvice)} + ${UI.escape(aspAdvice)}
` : ''}

@@ -735,7 +735,7 @@ window.Page_wetter = (() => { padding:3px 10px;background:${col}22; border:1px solid ${col}55;color:${col};font-weight:600"> - ${_esc(name)}: ${_esc(lbl)} + ${UI.escape(name)}: ${UI.escape(lbl)}
`; }).join('')}
@@ -756,7 +756,7 @@ window.Page_wetter = (() => {
Zecken-Risiko: - ${_esc(tickLabel)} + ${UI.escape(tickLabel)}
@@ -786,7 +786,7 @@ window.Page_wetter = (() => { -
${_esc(fellHint.text)}
+
${UI.escape(fellHint.text)}
`; } @@ -876,7 +876,7 @@ window.Page_wetter = (() => { / 10 — ${_esc(text)} + white-space:nowrap">— ${UI.escape(text)} `; } @@ -912,7 +912,7 @@ window.Page_wetter = (() => { padding:3px 10px;background:${s.color}22; border:1px solid ${s.color}55;color:${s.color};font-weight:600"> - Schnüffel: ${_esc(s.label)} + Schnüffel: ${UI.escape(s.label)} `; } @@ -1072,15 +1072,6 @@ window.Page_wetter = (() => { return ['hoch', '#F44336']; } - function _esc(s) { - if (s == null) return ''; - return String(s) - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"'); - } - // ---------------------------------------------------------- // MEINE WETTERREKORDE // ---------------------------------------------------------- @@ -1116,15 +1107,15 @@ window.Page_wetter = (() => { display:flex;align-items:center;gap:3px;font-weight:700; text-transform:uppercase;letter-spacing:.04em"> ${emoji} - ${_esc(title)} + ${UI.escape(title)}
- ${_esc(value)} + ${UI.escape(value)}
- ${_esc(subtitle)} + ${UI.escape(subtitle)}
`; diff --git a/backend/static/js/pages/widget.js b/backend/static/js/pages/widget.js index 0415c9b..51a5579 100644 --- a/backend/static/js/pages/widget.js +++ b/backend/static/js/pages/widget.js @@ -49,9 +49,9 @@ window.Page_widget = (() => { const photoHtml = photo ? `
- ${_esc(photo.titel || '')} + ${UI.escape(photo.titel || '')}
- ${_esc(photo.titel || '')} + ${UI.escape(photo.titel || '')} ${_fmtDate(photo.datum)}
` @@ -64,7 +64,7 @@ window.Page_widget = (() => { ? `
-
${_esc(rem.bezeichnung)}
+
${UI.escape(rem.bezeichnung)}
${_fmtDate(rem.naechstes)}
` @@ -79,7 +79,7 @@ window.Page_widget = (() => { `; const dogAvatar = dog.foto_url - ? `${_esc(dog.name)}` + ? `${UI.escape(dog.name)}` : `
🐕
`; _container.innerHTML = ` @@ -89,8 +89,8 @@ window.Page_widget = (() => {
${dogAvatar}
-
${_esc(dog.name)}
- ${dog.rasse ? `
${_esc(dog.rasse)}
` : ''} +
${UI.escape(dog.name)}
+ ${dog.rasse ? `
${UI.escape(dog.rasse)}
` : ''}
@@ -593,13 +593,13 @@ window.Page_wiki = (() => { ? `

Noch keine Züchter eingetragen.

` : zuchter.map(z => `
-
${_esc(z.name)} - ${z.zwingername ? ` „${_esc(z.zwingername)}“` : ''} +
${UI.escape(z.name)} + ${z.zwingername ? ` „${UI.escape(z.zwingername)}“` : ''} ${z.vdh_mitglied ? `VDH` : ''}
${(z.ort || z.bundesland) ? `
${[z.ort, z.bundesland].filter(Boolean).map(_esc).join(', ')}
` : ''} - ${z.beschreibung ? `

${_esc(z.beschreibung)}

` : ''} - ${z.website ? `${_esc(z.website)}` : ''} + ${z.beschreibung ? `

${UI.escape(z.beschreibung)}

` : ''} + ${z.website ? `${UI.escape(z.website)}` : ''}
`).join(''); @@ -627,7 +627,7 @@ window.Page_wiki = (() => {
@@ -731,7 +731,7 @@ window.Page_wiki = (() => { // Temperament chips const chips = rasse.temperament - ? rasse.temperament.split(',').map(t => `${_esc(t.trim())}`).join('') + ? rasse.temperament.split(',').map(t => `${UI.escape(t.trim())}`).join('') : ''; const _dogSvgLg = _DOG_SILHOUETTE.replace('width="48" height="48"', 'width="56" height="56"'); @@ -743,7 +743,7 @@ window.Page_wiki = (() => { const photoHtml = allFotos.length ? `` : ''}
` : ''}`} `; - UI.modal.open({ title: _esc(rasse.name), body }); + UI.modal.open({ title: UI.escape(rasse.name), body }); // Async: load stats + züchter in parallel Promise.all([_fetchStats(slug), _fetchZuchter(slug)]).then(([stats, zuchter]) => { @@ -936,7 +936,7 @@ window.Page_wiki = (() => {

- +
@@ -1030,14 +1030,14 @@ window.Page_wiki = (() => { return berichte.map(b => `
- ${_esc(b.autor)} + ${UI.escape(b.autor)} ${_formatDate(b.created_at)} ${_appState.user && _appState.user.name === b.autor - ? `` + ? `` : ''}
-
${_esc(b.titel)}
-

${_esc(b.text)}

+
${UI.escape(b.titel)}
+

${UI.escape(b.text)}

`).join(''); } @@ -1047,7 +1047,7 @@ window.Page_wiki = (() => {
- +
@@ -1095,11 +1095,11 @@ window.Page_wiki = (() => {
${UI.icon(s.icon)} - ${_esc(s.titel)} + ${UI.escape(s.titel)} ${UI.icon('caret-down')}
`).join(''); @@ -1126,13 +1126,13 @@ window.Page_wiki = (() => {
${UI.icon('map-pin')} - ${_esc(r.land)} + ${UI.escape(r.land)} ${UI.icon('caret-down')}
`).join(''); @@ -1174,8 +1174,8 @@ window.Page_wiki = (() => { const optionsHtml = frage.optionen.map(o => ` `).join(''); @@ -1185,7 +1185,7 @@ window.Page_wiki = (() => {

Frage ${_quizStep + 1} von ${QUIZ_FRAGEN.length}

-

${_esc(frage.frage)}

+

${UI.escape(frage.frage)}

${optionsHtml}
${_quizStep > 0 @@ -1225,24 +1225,24 @@ window.Page_wiki = (() => { const cardsHtml = data.results.map(r => { const photoHtml = r.foto_url - ? `${_esc(r.name)}` + ? `${UI.escape(r.name)}` : `
${UI.icon('dog')}
`; return `
${photoHtml}
-
${_esc(r.name)}
-
${_esc(r.gruppe || '')}
+
${UI.escape(r.name)}
+
${UI.escape(r.gruppe || '')}
- ${_groesseLabel(r.groesse)} - ${_aktivLabel(r.aktivitaet)} + ${_groesseLabel(r.groesse)} + ${_aktivLabel(r.aktivitaet)}
- ${r.temperament ? `

${_esc(r.temperament.split(',').slice(0,4).join(', '))}

` : ''} + ${r.temperament ? `

${UI.escape(r.temperament.split(',').slice(0,4).join(', '))}

` : ''}
${UI.icon('house-line')} ${r.wohnung_geeignet ? 'Wohnung' : 'Haus'} ${UI.icon('users')} ${r.kinder_geeignet ? 'Kinderfreundlich' : 'Erfahrung nötig'}
- +
`; @@ -1334,14 +1334,7 @@ window.Page_wiki = (() => { return new Date(iso).toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric' }); } catch { return iso; } } - - function _esc(str) { - if (!str) return ''; - return String(str).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); - } - - // ---------------------------------------------------------- +// ---------------------------------------------------------- // RASSEN-ERKENNUNG PER KI (Wiki-Tab) // ---------------------------------------------------------- function _bindWikiRasseErkennung(el) { @@ -1405,7 +1398,7 @@ window.Page_wiki = (() => { Auf diesem Foto konnte kein Hund erkannt werden.
Bitte lade ein deutlicheres Foto hoch.

- ${data.hinweis ? `

${_esc(data.hinweis)}

` : ''} + ${data.hinweis ? `

${UI.escape(data.hinweis)}

` : ''}
`, footer: ``, }); @@ -1418,18 +1411,18 @@ window.Page_wiki = (() => { return `
-
${isTop ? '🐕 ' : ''}${_esc(r.name)}
+
${isTop ? '🐕 ' : ''}${UI.escape(r.name)}
${r.sicherheit}%
- ${r.beschreibung ? `
${_esc(r.beschreibung)}
` : ''} + ${r.beschreibung ? `
${UI.escape(r.beschreibung)}
` : ''} ${r.wiki_slug ? `
` : ''} @@ -1443,7 +1436,7 @@ window.Page_wiki = (() => {
${data.hinweis ? `
ℹ️ ${_esc(data.hinweis)}
` : ''} + color:var(--c-text-secondary)">ℹ️ ${UI.escape(data.hinweis)}
` : ''} ${cardsHtml}

diff --git a/backend/static/js/pages/wurfboerse.js b/backend/static/js/pages/wurfboerse.js index c84995f..501632c 100644 --- a/backend/static/js/pages/wurfboerse.js +++ b/backend/static/js/pages/wurfboerse.js @@ -12,10 +12,6 @@ window.Page_wurfboerse = (() => { // ---------------------------------------------------------- // Hilfsfunktionen // ---------------------------------------------------------- - function _esc(s) { - return UI.escape ? UI.escape(s || '') : (s || '').replace(/[&<>"']/g, c => - ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])); - } function _fmtDate(iso) { if (!iso) return '—'; @@ -157,8 +153,8 @@ window.Page_wurfboerse = (() => { el.innerHTML = `

${UI.icon('dog')}
-

${_esc(title)}

-

${_esc(text)}

+

${UI.escape(title)}

+

${UI.escape(text)}

`; } @@ -168,13 +164,13 @@ window.Page_wurfboerse = (() => { function _cardHTML(b) { // Züchter-Kopfzeile const zuechterName = b.zuechter_name || b.zwingername || '—'; - const zwingername = b.zwingername ? ` (${_esc(b.zwingername)})` : ''; - const stadtLine = b.stadt ? ` · ${_esc(b.stadt)}` : ''; + const zwingername = b.zwingername ? ` (${UI.escape(b.zwingername)})` : ''; + const stadtLine = b.stadt ? ` · ${UI.escape(b.stadt)}` : ''; // Elterntiere const elternParts = []; - if (b.vater_name) elternParts.push(_esc(b.vater_name)); - if (b.mutter_name) elternParts.push(_esc(b.mutter_name)); + if (b.vater_name) elternParts.push(UI.escape(b.vater_name)); + if (b.mutter_name) elternParts.push(UI.escape(b.mutter_name)); const elternLine = elternParts.length === 2 ? `
${UI.icon('gender-male')} ${elternParts[0]} × ${UI.icon('gender-female')} ${elternParts[1]}
` : elternParts.length === 1 @@ -194,34 +190,34 @@ window.Page_wurfboerse = (() => { if (b.welpen_gesamt != null || b.welpen_verfuegbar != null) { const gesamt = b.welpen_gesamt != null ? b.welpen_gesamt : '?'; const verfuegb = b.welpen_verfuegbar != null ? b.welpen_verfuegbar : '?'; - welpenLine = `
${UI.icon('paw-print')} Welpen verfügbar: ${_esc(String(verfuegb))} von ${_esc(String(gesamt))}
`; + welpenLine = `
${UI.icon('paw-print')} Welpen verfügbar: ${UI.escape(String(verfuegb))} von ${UI.escape(String(gesamt))}
`; } // Preis const preisLine = b.preis_spanne - ? `
${UI.icon('currency-eur')} Preis: ${_esc(b.preis_spanne)} €
` + ? `
${UI.icon('currency-eur')} Preis: ${UI.escape(b.preis_spanne)} €
` : ''; // Gesundheitstests const gesundheitLine = b.gesundheitstests - ? `
${UI.icon('heart')} ${_esc(b.gesundheitstests)}
` + ? `
${UI.icon('heart')} ${UI.escape(b.gesundheitstests)}
` : ''; // Beschreibung (max. 150 Zeichen) const beschreibungLine = b.beschreibung - ? `
${_esc(_truncate(b.beschreibung, 150))}
` + ? `
${UI.escape(_truncate(b.beschreibung, 150))}
` : ''; return `
- ${_esc(zuechterName)}${zwingername}${stadtLine} + ${UI.escape(zuechterName)}${zwingername}${stadtLine}
${_statusBadge(b.status)}
- ${b.rasse_text ? `
${UI.icon('dog')} ${_esc(b.rasse_text)}
` : ''} + ${b.rasse_text ? `
${UI.icon('dog')} ${UI.escape(b.rasse_text)}
` : ''}
${elternLine} @@ -235,7 +231,7 @@ window.Page_wurfboerse = (() => { ` : ''} ${dob ? `
${dob}
` : ''} ${node.zuchtbuchnummer ? `
${_esc(node.zuchtbuchnummer)}
` + overflow:hidden;text-overflow:ellipsis;">${UI.escape(node.zuchtbuchnummer)}
` : ''}
`; } @@ -377,12 +368,12 @@ window.Page_zucht_profil = (() => { const rows = tests.map(t => ` - ${_esc(t.test_typ || 'Sonstiges')} - ${t.test_name ? `
${_esc(t.test_name)}` : ''} + ${UI.escape(t.test_typ || 'Sonstiges')} + ${t.test_name ? `
${UI.escape(t.test_name)}` : ''} ${_healthBadge(t.test_typ || '', t.ergebnis)} ${t.untersuch_am ? _fmtDate(t.untersuch_am) : '—'} - ${t.labor ? _esc(t.labor) : '—'} + ${t.labor ? UI.escape(t.labor) : '—'} `).join(''); return ` @@ -412,11 +403,11 @@ window.Page_zucht_profil = (() => { const rows = tests.map(t => ` - ${_esc(t.marker_name || '—')} + ${UI.escape(t.marker_name || '—')} ${_geneticBadge(t.ergebnis_klasse)} ${t.getestet_am ? _fmtDate(t.getestet_am) : '—'} - ${t.labor ? _esc(t.labor) : '—'} + ${t.labor ? UI.escape(t.labor) : '—'} `).join(''); return ` @@ -455,15 +446,15 @@ window.Page_zucht_profil = (() => {
${_titleTypBadge(t.titel_typ)} ${t.formwert - ? `${_esc(t.formwert)}` + ? `${UI.escape(t.formwert)}` : ''}
-
${_esc(t.titel_name || '—')}
+
${UI.escape(t.titel_name || '—')}
${t.verliehen_am ? `${UI.icon('calendar-dots')} ${_fmtDate(t.verliehen_am)}` : ''} - ${t.ort ? ` ·  ${UI.icon('map-pin')} ${_esc(t.ort)}` : ''} - ${t.richter ? ` ·  ${UI.icon('user')} ${_esc(t.richter)}` : ''} - ${t.ausstellung ? `
${UI.icon('ticket')} ${_esc(t.ausstellung)}` : ''} + ${t.ort ? ` ·  ${UI.icon('map-pin')} ${UI.escape(t.ort)}` : ''} + ${t.richter ? ` ·  ${UI.icon('user')} ${UI.escape(t.richter)}` : ''} + ${t.ausstellung ? `
${UI.icon('ticket')} ${UI.escape(t.ausstellung)}` : ''}
`).join(''); diff --git a/backend/static/js/pages/zuchthunde.js b/backend/static/js/pages/zuchthunde.js index cb7bbb8..384d2ba 100644 --- a/backend/static/js/pages/zuchthunde.js +++ b/backend/static/js/pages/zuchthunde.js @@ -17,10 +17,6 @@ window.Page_zuchthunde = (() => { // ---------------------------------------------------------- // Hilfsfunktionen // ---------------------------------------------------------- - function _esc(s) { - return UI.escape ? UI.escape(s || '') : (s || '').replace(/[&<>"']/g, c => - ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])); - } function _fmtDate(iso) { if (!iso) return '—'; @@ -54,7 +50,7 @@ window.Page_zuchthunde = (() => { else if (e === '3' || e === 'ED 3') color = '#EF4444'; } - return `${_esc(ergebnis || '—')}`; + return `${UI.escape(ergebnis || '—')}`; } function _geneticBadge(ergebnis) { @@ -63,7 +59,7 @@ window.Page_zuchthunde = (() => { if (e === 'clear') color = '#22C55E'; if (e === 'carrier') color = '#EAB308'; if (e === 'affected') color = '#EF4444'; - return `${_esc(ergebnis || '—')}`; + return `${UI.escape(ergebnis || '—')}`; } // ---------------------------------------------------------- @@ -103,7 +99,7 @@ window.Page_zuchthunde = (() => { const zwinger = _breederInfo?.zwingername || 'Mein Zwinger'; const logoUrl = _breederInfo?.logo_url || null; const logoHtml = logoUrl - ? `Logo` @@ -123,7 +119,7 @@ window.Page_zuchthunde = (() => {

${_esc(zwinger)}

+ text-overflow:ellipsis;line-height:1.2">${UI.escape(zwinger)}
@@ -208,7 +204,7 @@ window.Page_zuchthunde = (() => { const el = document.getElementById('zh-list'); if (el) el.innerHTML = `

- ${_esc(err.message || 'Fehler beim Laden.')} + ${UI.escape(err.message || 'Fehler beim Laden.')}

`; } } @@ -228,7 +224,7 @@ window.Page_zuchthunde = (() => { if (!filtered.length) { el.innerHTML = _query - ? `

Keine Treffer für „${_esc(_query)}".

` + ? `

Keine Treffer für „${UI.escape(_query)}".

` : `
${UI.icon('dog')}
@@ -299,12 +295,12 @@ window.Page_zuchthunde = (() => { // Hund-Card HTML // ---------------------------------------------------------- function _hundCardHTML(h) { - const nameLabel = h.name ? _esc(h.name) : 'Unbenannt'; - const rufname = h.rufname ? ` (${_esc(h.rufname)})` : ''; + const nameLabel = h.name ? UI.escape(h.name) : 'Unbenannt'; + const rufname = h.rufname ? ` (${UI.escape(h.rufname)})` : ''; const geburtstag = h.geburtsdatum ? _fmtDate(h.geburtsdatum) : null; - const vaterLabel = h.vater_name ? `Vater: ${_esc(h.vater_name)}` : null; - const mutterLabel = h.mutter_name ? `Mutter: ${_esc(h.mutter_name)}` : null; + const vaterLabel = h.vater_name ? `Vater: ${UI.escape(h.vater_name)}` : null; + const mutterLabel = h.mutter_name ? `Mutter: ${UI.escape(h.mutter_name)}` : null; const eltern = [vaterLabel, mutterLabel].filter(Boolean).join('  ·  '); const pubLabel = h.is_public @@ -317,14 +313,14 @@ window.Page_zuchthunde = (() => {
${_genderIcon(h.geschlecht)} - ${nameLabel}${_esc(rufname)} + ${nameLabel}${UI.escape(rufname)} ${pubLabel}
- ${h.rasse ? `${UI.icon('paw-print')} ${_esc(h.rasse)}  ` : ''} + ${h.rasse ? `${UI.icon('paw-print')} ${UI.escape(h.rasse)}  ` : ''} ${geburtstag ? `${UI.icon('calendar-dots')} ${geburtstag}  ` : ''} - ${h.chip_nr ? `${UI.icon('barcode')} ${_esc(h.chip_nr)}  ` : ''} - ${h.zuchtbuchnummer ? `${UI.icon('book-open')} ${_esc(h.zuchtbuchnummer)}  ` : ''} + ${h.chip_nr ? `${UI.icon('barcode')} ${UI.escape(h.chip_nr)}  ` : ''} + ${h.zuchtbuchnummer ? `${UI.icon('book-open')} ${UI.escape(h.zuchtbuchnummer)}  ` : ''}
${eltern ? `
${eltern}
` : ''}
@@ -416,7 +412,7 @@ window.Page_zuchthunde = (() => { const tests = await API.zuchthunde.healthTests(hundId); _renderHealthSection(hundId, wrap, tests); } catch (err) { - wrap.innerHTML = `

${_esc(err.message || 'Fehler.')}

`; + wrap.innerHTML = `

${UI.escape(err.message || 'Fehler.')}

`; } } @@ -425,11 +421,11 @@ window.Page_zuchthunde = (() => { ? tests.map(t => `
- ${_esc(t.test_typ || 'Sonstiges')} - ${t.test_name ? `${_esc(t.test_name)}` : ''} + ${UI.escape(t.test_typ || 'Sonstiges')} + ${t.test_name ? `${UI.escape(t.test_name)}` : ''} ${_healthBadge(t.test_typ || '', t.ergebnis)} ${t.untersuch_am ? `${_fmtDate(t.untersuch_am)}` : ''} - ${t.labor ? `${_esc(t.labor)}` : ''} + ${t.labor ? `${UI.escape(t.labor)}` : ''}
@@ -480,7 +476,7 @@ window.Page_zuchthunde = (() => { const tests = await API.zuchthunde.geneticTests(hundId); _renderGeneticSection(hundId, wrap, tests); } catch (err) { - wrap.innerHTML = `

${_esc(err.message || 'Fehler.')}

`; + wrap.innerHTML = `

${UI.escape(err.message || 'Fehler.')}

`; } } @@ -489,10 +485,10 @@ window.Page_zuchthunde = (() => { ? tests.map(t => `
- ${_esc(t.marker_name || '—')} + ${UI.escape(t.marker_name || '—')} ${_geneticBadge(t.ergebnis_klasse)} ${t.getestet_am ? `${_fmtDate(t.getestet_am)}` : ''} - ${t.labor ? `${_esc(t.labor)}` : ''} + ${t.labor ? `${UI.escape(t.labor)}` : ''}
@@ -543,7 +539,7 @@ window.Page_zuchthunde = (() => { const titles = await API.zuchthunde.titles(hundId); _renderTitlesSection(hundId, wrap, titles); } catch (err) { - wrap.innerHTML = `

${_esc(err.message || 'Fehler.')}

`; + wrap.innerHTML = `

${UI.escape(err.message || 'Fehler.')}

`; } } @@ -552,12 +548,12 @@ window.Page_zuchthunde = (() => { ? titles.map(t => `
- ${_esc(t.titel_name || '—')} - ${t.titel_typ ? `${_esc(t.titel_typ)}` : ''} + ${UI.escape(t.titel_name || '—')} + ${t.titel_typ ? `${UI.escape(t.titel_typ)}` : ''} ${t.verliehen_am ? `${_fmtDate(t.verliehen_am)}` : ''} - ${t.ort ? `${_esc(t.ort)}` : ''} - ${t.richter ? `${_esc(t.richter)}` : ''} - ${t.formwert ? `${_esc(t.formwert)}` : ''} + ${t.ort ? `${UI.escape(t.ort)}` : ''} + ${t.richter ? `${UI.escape(t.richter)}` : ''} + ${t.formwert ? `${UI.escape(t.formwert)}` : ''}
@@ -614,13 +610,13 @@ window.Page_zuchthunde = (() => { const vaterOptions = [ ``, ...maennliche.map(h => - ``), + ``), ].join(''); const mutterOptions = [ ``, ...weibliche.map(h => - ``), + ``), ].join(''); const body = ` @@ -630,12 +626,12 @@ window.Page_zuchthunde = (() => {
+ value="${UI.escape(v.name || '')}" placeholder="z. B. Banyaro's Black Diamond">
+ value="${UI.escape(v.rufname || '')}" placeholder="z. B. Diamond">
@@ -651,7 +647,7 @@ window.Page_zuchthunde = (() => {
+ value="${UI.escape(v.geburtsdatum || '')}">
@@ -659,12 +655,12 @@ window.Page_zuchthunde = (() => {
+ value="${UI.escape(v.sterbedatum || '')}">
+ value="${UI.escape(v.farbe || '')}" placeholder="z. B. schwarz-braun">
@@ -672,19 +668,19 @@ window.Page_zuchthunde = (() => {
+ value="${UI.escape(v.chip_nr || '')}" placeholder="15-stellig">
+ value="${UI.escape(v.taetowier_nr || '')}">
+ value="${UI.escape(v.zuchtbuchnummer || '')}" placeholder="z. B. SZ 123456">
@@ -702,19 +698,19 @@ window.Page_zuchthunde = (() => {
+ value="${UI.escape(v.zuechter_name || '')}" placeholder="Bei Fremdzüchter">
+ value="${UI.escape(v.eigentuemer_name || '')}">
+ placeholder="Interne Anmerkungen…">${UI.escape(v.notiz || '')}
@@ -1121,14 +1117,14 @@ window.Page_zuchthunde = (() => { ``, ..._hunde .filter(h => h.geschlecht !== 'weiblich') - .map(h => ``), + .map(h => ``), ].join(''); const muetterOptions = [ ``, ..._hunde .filter(h => h.geschlecht !== 'maennlich') - .map(h => ``), + .map(h => ``), ].join(''); const body = ` @@ -1206,7 +1202,7 @@ window.Page_zuchthunde = (() => { if (v.gen_vater != null) genInfo.push(`Gen. ${v.gen_vater} Vater`); if (v.gen_mutter != null) genInfo.push(`Gen. ${v.gen_mutter} Mutter`); const genStr = genInfo.length ? ` (${genInfo.join(' / ')})` : ''; - return `
  • ${_esc(v.name || '—')}${genStr}
  • `; + return `
  • ${UI.escape(v.name || '—')}${genStr}
  • `; }).join('') : `
  • Keine gemeinsamen Vorfahren gefunden.
  • `; @@ -1220,13 +1216,13 @@ window.Page_zuchthunde = (() => { const wIssueHTML = (welfare.issues || []).map(i => `
    ${UI.icon('warning')} - ${_esc(i.text)} + ${UI.escape(i.text)}
    `).join(''); const wOkHTML = (welfare.ok_points || []).map(p => `
    ${UI.icon('check')} - ${_esc(p)} + ${UI.escape(p)}
    `).join(''); welfareHTML = ` @@ -1254,7 +1250,7 @@ window.Page_zuchthunde = (() => { ${ik.toFixed(2)} %
    - ${_esc(result.ik_rating || ampelLabel)} + ${UI.escape(result.ik_rating || ampelLabel)}
    @@ -1314,7 +1310,7 @@ window.Page_zuchthunde = (() => { } catch (err) { UI.modal.open({ title: `${UI.icon('sparkle')} KI-Hunde-Beschreibung`, - body: `

    ${_esc(err.message || 'Fehler beim Generieren.')}

    `, + body: `

    ${UI.escape(err.message || 'Fehler beim Generieren.')}

    `, footer: ``, }); return; @@ -1322,7 +1318,7 @@ window.Page_zuchthunde = (() => { UI.modal.open({ title: `${UI.icon('sparkle')} KI-Hunde-Beschreibung`, - body: `
    ${_esc(text)}
    `, + body: `
    ${UI.escape(text)}
    `, footer: ` `, }); return; @@ -1429,7 +1425,7 @@ window.Page_zuchthunde = (() => { body: ` ${savedId ? `

    ${UI.icon('check-circle')} Automatisch gespeichert

    ` : ''} -
    ${_esc(text)}
    `, +
    ${UI.escape(text)}
    `, footer: ` `, }); return; @@ -1561,9 +1557,9 @@ window.Page_zuchthunde = (() => {
    - ${UI.icon('check-circle')} ${_esc(empfehlungLabel)} + ${UI.icon('check-circle')} ${UI.escape(empfehlungLabel)}
    ` : ''} -
    ${_esc(text)}
    +
    ${UI.escape(text)}
    `, footer: `