Refactor: 1167 _esc() → UI.escape() in 36 Dateien, SW by-v1113

Bündel 1 aus dem Duplikat-Audit: existierende zentrale Helper nutzen
statt lokale Duplikate.

Pure Migration ohne neuen Code:
- 1167 _esc()-Aufrufe in 36 Page-Modulen migriert auf UI.escape()
- 24 lokale _esc/_escape-Definitionen entfernt
- lost.js hatte _escape() (Variante) — 17 Aufrufe ebenfalls migriert
- jobs.js + breeder.js: tote Alias-Wrapper entfernt

UI.escape() existierte schon — wurde nur überall lokal nochmal
implementiert. Funktional identisch (gleiche 4-replace-chain für
& < > ").

Tests 19/19 grün. Frontend-LOC um ~120 Zeilen reduziert.

Hinweis: _emptyState (7 Stellen) und _icon (8 Stellen) wurden NICHT
migriert — sie haben abweichende Signaturen von UI.emptyState({...})
bzw. UI.icon(name). Eigener Sprint nötig.
This commit is contained in:
rene 2026-05-27 10:15:33 +02:00
parent e7939ce98e
commit c517c9281d
42 changed files with 1115 additions and 1341 deletions

View file

@ -92,7 +92,7 @@ window.Page_health = (() => {
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#wave-sine"></use></svg>
<span class="health-transponder-label">Transponder:</span>
<span class="health-transponder-nr" id="health-transponder-nr">
${dog?.chip_nr ? `<strong>${_esc(dog.chip_nr)}</strong>` : '<em class="text-muted">nicht eingetragen</em>'}
${dog?.chip_nr ? `<strong>${UI.escape(dog.chip_nr)}</strong>` : '<em class="text-muted">nicht eingetragen</em>'}
</span>
<button class="btn btn-link btn-sm health-transponder-edit" id="health-transponder-edit"
style="padding:0;font-size:var(--text-xs);color:var(--c-text-muted)">
@ -197,7 +197,7 @@ window.Page_health = (() => {
<div class="flex-1-min">
<div style="font-size:var(--text-sm);font-weight:var(--weight-medium);
white-space:nowrap;overflow:hidden;text-overflow:ellipsis">
${_esc(e.bezeichnung)}
${UI.escape(e.bezeichnung)}
</div>
<div class="text-xs-muted">
${ageLabel} · ${dateStr}
@ -379,19 +379,19 @@ window.Page_health = (() => {
<div class="list-item-card list-item-card--clickable health-card" data-id="${e.id}" data-action="open-entry">
<div class="health-card-ampel ampel-${ampel.color}" title="${ampel.label}"></div>
<div class="list-item-body">
<div class="list-item-title">${_esc(e.bezeichnung)}</div>
<div class="list-item-title">${UI.escape(e.bezeichnung)}</div>
<div class="list-item-meta-row">
${UI.time.format(e.datum + 'T00:00:00')}
${e.charge_nr ? ` · Ch.-Nr: ${_esc(e.charge_nr)}` : ''}
${e.charge_nr ? ` · Ch.-Nr: ${UI.escape(e.charge_nr)}` : ''}
</div>
${vetName ? `<div style="font-size:var(--text-sm);color:var(--c-text-secondary);margin-top:var(--space-1)"><svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#first-aid"></use></svg> ${_esc(vetName)}</div>` : ''}
${vetName ? `<div style="font-size:var(--text-sm);color:var(--c-text-secondary);margin-top:var(--space-1)"><svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#first-aid"></use></svg> ${UI.escape(vetName)}</div>` : ''}
${e.naechstes ? `<div class="health-card-next ampel-text-${ampel.color}">
Nächste Impfung: ${UI.time.format(e.naechstes + 'T00:00:00')} ${ampel.icon}
</div>` : ''}
${e.notiz ? `<div class="list-item-text">${_esc(e.notiz)}</div>` : ''}
${e.notiz ? `<div class="list-item-text">${UI.escape(e.notiz)}</div>` : ''}
<button class="btn btn-ghost btn-xs" style="margin-top:var(--space-2);font-size:var(--text-xs);color:var(--c-text-muted);padding:2px 6px"
data-action="open-note" data-entry-id="${e.id}"
data-label="${_esc(e.bezeichnung)}"
data-label="${UI.escape(e.bezeichnung)}"
onclick="event.stopPropagation()"><svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#note-pencil"></use></svg> Notiz</button>
</div>
</div>
@ -426,7 +426,7 @@ window.Page_health = (() => {
return `
<div class="list-item-card list-item-card--clickable health-card" data-id="${e.id}" data-action="open-entry">
<div class="list-item-body">
<div class="list-item-title">${_esc(e.bezeichnung)}</div>
<div class="list-item-title">${UI.escape(e.bezeichnung)}</div>
<div class="list-item-meta-row">
${UI.time.format(e.datum + 'T00:00:00')}
${e.kosten != null ? ` · ${Number(e.kosten).toFixed(2)}` : ''}
@ -434,13 +434,13 @@ window.Page_health = (() => {
${praxisName ? `
<div style="display:flex;align-items:center;gap:var(--space-1);
margin-top:var(--space-1);font-size:var(--text-sm);color:var(--c-text-secondary)">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#first-aid"></use></svg> ${_esc(praxisName)}${praxisOrt ? ` · ${_esc(praxisOrt)}` : ''}
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#first-aid"></use></svg> ${UI.escape(praxisName)}${praxisOrt ? ` · ${UI.escape(praxisOrt)}` : ''}
</div>` : ''}
${e.diagnose ? `<div class="list-item-text"><b>Diagnose:</b> ${_esc(e.diagnose)}</div>` : ''}
${e.notiz ? `<div class="list-item-text">${_esc(e.notiz)}</div>` : ''}
${e.diagnose ? `<div class="list-item-text"><b>Diagnose:</b> ${UI.escape(e.diagnose)}</div>` : ''}
${e.notiz ? `<div class="list-item-text">${UI.escape(e.notiz)}</div>` : ''}
<button class="btn btn-ghost btn-xs" style="margin-top:var(--space-2);font-size:var(--text-xs);color:var(--c-text-muted);padding:2px 6px"
data-action="open-note" data-entry-id="${e.id}"
data-label="${_esc(e.bezeichnung)}"
data-label="${UI.escape(e.bezeichnung)}"
onclick="event.stopPropagation()"><svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#note-pencil"></use></svg> Notiz</button>
</div>
</div>
@ -489,10 +489,10 @@ window.Page_health = (() => {
${e.wert} <span class="text-sm-secondary">${e.einheit || 'kg'}</span>
</span>
</div>
${e.notiz ? `<div class="list-item-text" style="padding-top:var(--space-1)">${_esc(e.notiz)}</div>` : ''}
${e.notiz ? `<div class="list-item-text" style="padding-top:var(--space-1)">${UI.escape(e.notiz)}</div>` : ''}
<button class="btn btn-ghost btn-xs" style="margin-top:var(--space-1);font-size:var(--text-xs);color:var(--c-text-muted);padding:2px 6px"
data-action="open-note" data-entry-id="${e.id}"
data-label="Gewicht ${_esc(e.datum)}"
data-label="Gewicht ${UI.escape(e.datum)}"
onclick="event.stopPropagation()"><svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#note-pencil"></use></svg> Notiz</button>
</div>
</div>
@ -727,10 +727,10 @@ window.Page_health = (() => {
${e.wert ? `Dauer: ${e.wert} Tage` : 'Dauer nicht angegeben'}
${interval ? ` · Abstand zur Vorherigen: ${interval} Tage` : ''}
</div>
${e.notiz ? `<div class="list-item-text">${_esc(e.notiz)}</div>` : ''}
${e.notiz ? `<div class="list-item-text">${UI.escape(e.notiz)}</div>` : ''}
<button class="btn btn-ghost btn-xs" style="margin-top:var(--space-2);font-size:var(--text-xs);color:var(--c-text-muted);padding:2px 6px"
data-action="open-note" data-entry-id="${e.id}"
data-label="Läufigkeit ${_esc(e.datum)}"
data-label="Läufigkeit ${UI.escape(e.datum)}"
onclick="event.stopPropagation()"><svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#note-pencil"></use></svg> Notiz</button>
</div>
</div>`;
@ -759,16 +759,16 @@ window.Page_health = (() => {
${items.map(e => `
<div class="list-item-card list-item-card--clickable health-card${e.aktiv ? '' : ' list-item-card--inactive health-card--inactive'}" data-id="${e.id}" data-action="open-entry">
<div class="list-item-body">
<div class="list-item-title">${_esc(e.bezeichnung)}</div>
<div class="list-item-title">${UI.escape(e.bezeichnung)}</div>
<div class="list-item-meta-row">
${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')}` : ''}
</div>
${e.notiz ? `<div class="list-item-text">${_esc(e.notiz)}</div>` : ''}
${e.notiz ? `<div class="list-item-text">${UI.escape(e.notiz)}</div>` : ''}
<button class="btn btn-ghost btn-xs" style="margin-top:var(--space-2);font-size:var(--text-xs);color:var(--c-text-muted);padding:2px 6px"
data-action="open-note" data-entry-id="${e.id}"
data-label="${_esc(e.bezeichnung)}"
data-label="${UI.escape(e.bezeichnung)}"
onclick="event.stopPropagation()"><svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#note-pencil"></use></svg> Notiz</button>
</div>
</div>
@ -799,17 +799,17 @@ window.Page_health = (() => {
<div class="list-item-card list-item-card--clickable health-card" data-id="${e.id}" data-action="open-entry">
<div class="list-item-body">
<div class="list-item-title">
${e.schweregrad ? SCHWEREGRAD[e.schweregrad] || '' : ''} ${_esc(e.bezeichnung)}
${e.schweregrad ? SCHWEREGRAD[e.schweregrad] || '' : ''} ${UI.escape(e.bezeichnung)}
</div>
<div class="list-item-meta-row">
Erstmals: ${UI.time.format(e.datum + 'T00:00:00')}
${e.schweregrad ? ` · Schweregrad: ${_esc(e.schweregrad)}` : ''}
${e.schweregrad ? ` · Schweregrad: ${UI.escape(e.schweregrad)}` : ''}
</div>
${e.reaktion ? `<div class="list-item-text"><b>Reaktion:</b> ${_esc(e.reaktion)}</div>` : ''}
${e.notiz ? `<div class="list-item-text">${_esc(e.notiz)}</div>` : ''}
${e.reaktion ? `<div class="list-item-text"><b>Reaktion:</b> ${UI.escape(e.reaktion)}</div>` : ''}
${e.notiz ? `<div class="list-item-text">${UI.escape(e.notiz)}</div>` : ''}
<button class="btn btn-ghost btn-xs" style="margin-top:var(--space-2);font-size:var(--text-xs);color:var(--c-text-muted);padding:2px 6px"
data-action="open-note" data-entry-id="${e.id}"
data-label="${_esc(e.bezeichnung)}"
data-label="${UI.escape(e.bezeichnung)}"
onclick="event.stopPropagation()"><svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#note-pencil"></use></svg> Notiz</button>
</div>
</div>
@ -840,29 +840,29 @@ window.Page_health = (() => {
return `
<div class="list-item-card list-item-card--clickable health-card" data-id="${e.id}" data-action="open-entry">
${firstImg
? `<img src="${_esc(firstImg.url)}" class="list-item-thumb health-doc-thumb" alt="Vorschau">`
? `<img src="${UI.escape(firstImg.url)}" class="list-item-thumb health-doc-thumb" alt="Vorschau">`
: `<div style="width:48px;height:48px;display:flex;align-items:center;justify-content:center;
font-size:2rem;flex-shrink:0"><svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#file-text"></use></svg></div>`}
<div class="list-item-body">
<div class="list-item-title">${_esc(e.bezeichnung)}</div>
<div class="list-item-title">${UI.escape(e.bezeichnung)}</div>
<div class="list-item-meta-row">
${UI.time.format(e.datum + 'T00:00:00')}
${count > 1 ? ` · ${count} Dateien` : ''}
</div>
${e.notiz ? `<div class="list-item-text">${_esc(e.notiz)}</div>` : ''}
${e.notiz ? `<div class="list-item-text">${UI.escape(e.notiz)}</div>` : ''}
<button class="btn btn-ghost btn-xs" style="margin-top:var(--space-2);font-size:var(--text-xs);color:var(--c-text-muted);padding:2px 6px"
data-action="open-note" data-entry-id="${e.id}"
data-label="${_esc(e.bezeichnung)}"
data-label="${UI.escape(e.bezeichnung)}"
onclick="event.stopPropagation()"><svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#note-pencil"></use></svg> Notiz</button>
${count
? `<div style="display:flex;gap:var(--space-2);margin-top:var(--space-2);align-items:center;flex-wrap:wrap">
${mediaList.slice(0, 3).map(m => m.media_type === 'pdf'
? `<a href="${_esc(m.url)}" target="_blank" rel="noopener"
? `<a href="${UI.escape(m.url)}" target="_blank" rel="noopener"
class="btn btn-secondary btn-sm" style="display:inline-flex"
onclick="event.stopPropagation()">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#file-text"></use></svg> PDF
</a>`
: `<a href="${_esc(m.url)}" target="_blank" rel="noopener"
: `<a href="${UI.escape(m.url)}" target="_blank" rel="noopener"
class="btn btn-secondary btn-sm" style="display:inline-flex"
onclick="event.stopPropagation()">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#image"></use></svg> Bild
@ -992,12 +992,12 @@ window.Page_health = (() => {
const mediaHtml = mediaItems.length
? `<div class="health-media-gallery mt-4">
${mediaItems.map(m => m.media_type === 'pdf'
? `<a href="${_esc(m.url)}" target="_blank" rel="noopener"
? `<a href="${UI.escape(m.url)}" target="_blank" rel="noopener"
class="btn btn-secondary btn-sm health-media-gallery-pdf">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#file-text"></use></svg> PDF öffnen
</a>`
: `<a href="${_esc(m.url)}" target="_blank" rel="noopener" class="health-media-gallery-img">
<img src="${_esc(m.url)}" alt="Bild" loading="lazy">
: `<a href="${UI.escape(m.url)}" target="_blank" rel="noopener" class="health-media-gallery-img">
<img src="${UI.escape(m.url)}" alt="Bild" loading="lazy">
</a>`
).join('')}
</div>`
@ -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 ? ` · <a href="tel:${_esc(praxis.telefon)}">${_esc(praxis.telefon)}</a>` : '';
const oh = praxis.opening_hours ? `<br><small class="text-secondary">🕐 ${_esc(_fmtOeffnungszeiten(praxis.opening_hours))}</small>` : '';
rows.push(['Praxis', `<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#first-aid"></use></svg> ${_esc(praxis.name)}${adresse ? `<br><small class="text-secondary">${_esc(adresse)}${tel}</small>` : tel}${oh}`]);
const tel = praxis.telefon ? ` · <a href="tel:${UI.escape(praxis.telefon)}">${UI.escape(praxis.telefon)}</a>` : '';
const oh = praxis.opening_hours ? `<br><small class="text-secondary">🕐 ${UI.escape(_fmtOeffnungszeiten(praxis.opening_hours))}</small>` : '';
rows.push(['Praxis', `<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#first-aid"></use></svg> ${UI.escape(praxis.name)}${adresse ? `<br><small class="text-secondary">${UI.escape(adresse)}${tel}</small>` : 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 `<dl class="health-detail-dl">${
rows.map(([k, v]) => `<dt>${k}</dt><dd>${v}</dd>`).join('')
@ -1077,7 +1077,7 @@ window.Page_health = (() => {
<div class="form-group">
<label class="form-label">Bezeichnung *</label>
<input class="form-control" type="text" name="bezeichnung"
value="${_esc(entry?.bezeichnung || '')}" required
value="${UI.escape(entry?.bezeichnung || '')}" required
placeholder="${_formPlaceholder(t)}">
</div>` : ''}
<div class="form-group">
@ -1091,7 +1091,7 @@ window.Page_health = (() => {
const notizField = `
<div class="form-group">
<label class="form-label">Notiz</label>
<textarea class="form-control" name="notiz" rows="3">${_esc(entry?.notiz || '')}</textarea>
<textarea class="form-control" name="notiz" rows="3">${UI.escape(entry?.notiz || '')}</textarea>
</div>
`;
@ -1110,7 +1110,7 @@ window.Page_health = (() => {
: '';
return `<div class="health-media-thumb" data-media-id="${m.id || ''}">
${isImg
? `<img src="${_esc(m.url)}" alt="Vorschau">`
? `<img src="${UI.escape(m.url)}" alt="Vorschau">`
: `<div class="health-media-thumb-pdf"><svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#file-text"></use></svg><span>PDF</span></div>`}
${removeBtn}
</div>`;
@ -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 = `<div class="health-media-thumb-pdf"><svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#file-text"></use></svg><span>PDF</span></div><small>${_esc(f.name.slice(0, 18))}</small>`;
thumb.innerHTML = `<div class="health-media-thumb-pdf"><svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#file-text"></use></svg><span>PDF</span></div><small>${UI.escape(f.name.slice(0, 18))}</small>`;
} else {
const img = document.createElement('img');
img.src = URL.createObjectURL(f);
@ -1331,7 +1331,7 @@ window.Page_health = (() => {
<option value=""> optional </option>
${aktivePraxen.map(p => `
<option value="${p.id}" ${entry?.tierarzt_id === p.id ? 'selected' : ''}>
${_esc(p.name)}${p.ort ? ` · ${_esc(p.ort)}` : ''}
${UI.escape(p.name)}${p.ort ? ` · ${UI.escape(p.ort)}` : ''}
</option>`).join('')}
</select>
</div>`;
@ -1350,7 +1350,7 @@ window.Page_health = (() => {
${_praxisSelectField(entry)}
<div class="form-group">
<label class="form-label">Chargen-Nr.</label>
<input class="form-control" type="text" name="charge_nr" value="${_esc(entry?.charge_nr || '')}">
<input class="form-control" type="text" name="charge_nr" value="${UI.escape(entry?.charge_nr || '')}">
</div>
`;
case 'entwurmung': return `
@ -1373,7 +1373,7 @@ window.Page_health = (() => {
${aktivePraxen.map(p => `
<option value="${p.id}"
${entry?.tierarzt_id === p.id ? 'selected' : ''}>
${_esc(p.name)}${p.ort ? ` · ${_esc(p.ort)}` : ''}
${UI.escape(p.name)}${p.ort ? ` · ${UI.escape(p.ort)}` : ''}
</option>`).join('')}
</select>
</div>`
@ -1386,13 +1386,13 @@ window.Page_health = (() => {
</div>
<label class="form-label mt-2">Tierarzt / Praxis (Freitext)</label>
<input class="form-control" name="tierarzt_name"
value="${_esc(entry?.tierarzt_name || '')}" placeholder="Dr. Muster">
value="${UI.escape(entry?.tierarzt_name || '')}" placeholder="Dr. Muster">
</div>`;
return `
${praxisField}
<div class="form-group">
<label class="form-label">Diagnose</label>
<textarea class="form-control" name="diagnose" rows="2">${_esc(entry?.diagnose || '')}</textarea>
<textarea class="form-control" name="diagnose" rows="2">${UI.escape(entry?.diagnose || '')}</textarea>
</div>
<div class="form-group">
<label class="form-label">Kosten ()</label>
@ -1416,12 +1416,12 @@ window.Page_health = (() => {
<div class="form-group">
<label class="form-label">Dosierung</label>
<input class="form-control" type="text" name="dosierung"
value="${_esc(entry?.dosierung || '')}" placeholder="z.B. 1 Tablette">
value="${UI.escape(entry?.dosierung || '')}" placeholder="z.B. 1 Tablette">
</div>
<div class="form-group">
<label class="form-label">Häufigkeit</label>
<input class="form-control" type="text" name="haeufigkeit"
value="${_esc(entry?.haeufigkeit || '')}" placeholder="z.B. täglich, 2x wöchentlich">
value="${UI.escape(entry?.haeufigkeit || '')}" placeholder="z.B. täglich, 2x wöchentlich">
</div>
<div class="grid-2">
<div class="form-group">
@ -1450,7 +1450,7 @@ window.Page_health = (() => {
</div>
<div class="form-group">
<label class="form-label">Reaktion / Symptome</label>
<textarea class="form-control" name="reaktion" rows="2">${_esc(entry?.reaktion || '')}</textarea>
<textarea class="form-control" name="reaktion" rows="2">${UI.escape(entry?.reaktion || '')}</textarea>
</div>
`;
case 'laeufigkeit': {
@ -1632,7 +1632,7 @@ window.Page_health = (() => {
<div style="font-size:1.5rem"><svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#${p.ist_notfallpraxis ? 'warning' : 'first-aid'}"></use></svg></div>
<div class="list-item-body">
<div class="list-item-title">
${_esc(p.name)}
${UI.escape(p.name)}
${!p.aktiv ? '<span style="font-size:var(--text-xs);color:var(--c-text-secondary);font-weight:400"> · Ehemalig</span>' : ''}
</div>
${(p.strasse || p.plz || p.ort) ? `
@ -1642,17 +1642,17 @@ window.Page_health = (() => {
${p.opening_hours ? `
<div class="list-item-meta-row" style="margin-top:var(--space-1)">
<svg class="ph-icon" aria-hidden="true" style="font-size:0.9em"><use href="/icons/phosphor.svg#clock"></use></svg>
${_esc(_fmtOeffnungszeiten(p.opening_hours))}
${UI.escape(_fmtOeffnungszeiten(p.opening_hours))}
</div>` : ''}
${ratingHtml}
<div style="display:flex;gap:var(--space-2);margin-top:var(--space-2);flex-wrap:wrap">
${p.telefon ? `
<a href="tel:${_esc(p.telefon)}" class="btn btn-secondary btn-sm"
<a href="tel:${UI.escape(p.telefon)}" class="btn btn-secondary btn-sm"
onclick="event.stopPropagation()">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#phone"></use></svg> Anrufen
</a>` : ''}
${p.notfall_telefon ? `
<a href="tel:${_esc(p.notfall_telefon)}" class="btn btn-danger btn-sm"
<a href="tel:${UI.escape(p.notfall_telefon)}" class="btn btn-danger btn-sm"
onclick="event.stopPropagation()">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#warning"></use></svg> Notfall
</a>` : ''}
@ -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: `<div style="text-align:center;padding:var(--space-6)">
<svg class="ph-icon spin" aria-hidden="true" style="font-size:2rem">
<use href="/icons/phosphor.svg#spinner-gap"></use>
@ -1804,7 +1804,7 @@ window.Page_health = (() => {
${k.freundlichkeit ? `<span>Freundlichkeit: ${_renderStarsReadonly(k.freundlichkeit)}</span>` : ''}
${k.kompetenz ? `<span>Kompetenz: ${_renderStarsReadonly(k.kompetenz)}</span>` : ''}
</div>` : ''}
<p style="margin:0;font-size:var(--text-sm)">${_esc(k.text || '')}</p>
<p style="margin:0;font-size:var(--text-sm)">${UI.escape(k.text || '')}</p>
</div>`).join('')
: `<p class="text-sm-muted">Noch keine Kommentare.</p>`;
@ -1863,13 +1863,13 @@ window.Page_health = (() => {
<div class="form-group mt-3">
<label class="form-label">Kommentar <span style="font-weight:400;color:var(--c-text-muted)">(optional, anonym)</span></label>
<textarea class="form-control" name="text" maxlength="500" rows="3"
placeholder="Deine Erfahrungen mit dieser Praxis…">${_esc(cur.text || '')}</textarea>
placeholder="Deine Erfahrungen mit dieser Praxis…">${UI.escape(cur.text || '')}</textarea>
<div style="font-size:var(--text-xs);color:var(--c-text-muted);text-align:right">max. 500 Zeichen</div>
</div>
</form>`;
UI.modal.open({
title: `${_esc(praxis.name)} bewerten`,
title: `${UI.escape(praxis.name)} bewerten`,
body,
footer: `
<button class="btn btn-secondary" onclick="UI.modal.close()">Abbrechen</button>
@ -1948,41 +1948,41 @@ window.Page_health = (() => {
<div class="form-group">
<label class="form-label">Name der Praxis *</label>
<input class="form-control" type="text" name="name"
value="${_esc(praxis?.name || '')}" placeholder="Dr. Muster Tierarztpraxis" required>
value="${UI.escape(praxis?.name || '')}" placeholder="Dr. Muster Tierarztpraxis" required>
</div>
<div class="form-group">
<label class="form-label">Straße &amp; Hausnummer</label>
<input class="form-control" type="text" name="strasse"
value="${_esc(praxis?.strasse || '')}" placeholder="Musterstraße 1">
value="${UI.escape(praxis?.strasse || '')}" placeholder="Musterstraße 1">
</div>
<div style="display:grid;grid-template-columns:120px 1fr;gap:var(--space-3)">
<div class="form-group">
<label class="form-label">PLZ</label>
<input class="form-control" type="text" name="plz" inputmode="numeric"
value="${_esc(praxis?.plz || '')}" placeholder="12345">
value="${UI.escape(praxis?.plz || '')}" placeholder="12345">
</div>
<div class="form-group">
<label class="form-label">Ort</label>
<input class="form-control" type="text" name="ort"
value="${_esc(praxis?.ort || '')}" placeholder="Musterstadt">
value="${UI.escape(praxis?.ort || '')}" placeholder="Musterstadt">
</div>
</div>
<div class="grid-2">
<div class="form-group">
<label class="form-label">Telefon</label>
<input class="form-control" type="tel" name="telefon"
value="${_esc(praxis?.telefon || '')}" placeholder="089 123456">
value="${UI.escape(praxis?.telefon || '')}" placeholder="089 123456">
</div>
<div class="form-group">
<label class="form-label">Notfall-Telefon</label>
<input class="form-control" type="tel" name="notfall_telefon"
value="${_esc(praxis?.notfall_telefon || '')}" placeholder="089 999999">
value="${UI.escape(praxis?.notfall_telefon || '')}" placeholder="089 999999">
</div>
</div>
<div class="form-group">
<label class="form-label">E-Mail</label>
<input class="form-control" type="email" name="email"
value="${_esc(praxis?.email || '')}" placeholder="praxis@beispiel.de">
value="${UI.escape(praxis?.email || '')}" placeholder="praxis@beispiel.de">
</div>
<div class="form-group">
<label class="form-label">
@ -1994,14 +1994,14 @@ window.Page_health = (() => {
</label>
<input class="form-control" type="text" name="opening_hours"
id="praxis-opening-hours"
value="${_esc(praxis?.opening_hours || '')}"
value="${UI.escape(praxis?.opening_hours || '')}"
placeholder="z.B. MoFr 08:0018:00 · Sa 09:0013:00">
<div id="praxis-osm-results" style="display:none;margin-top:var(--space-2)"></div>
</div>
<div class="form-group">
<label class="form-label">Notizen</label>
<textarea class="form-control" name="notizen" rows="2"
placeholder="Besonderheiten, interne Hinweise…">${_esc(praxis?.notizen || '')}</textarea>
placeholder="Besonderheiten, interne Hinweise…">${UI.escape(praxis?.notizen || '')}</textarea>
</div>
<div class="form-group">
<label class="form-label" style="display:flex;align-items:center;gap:var(--space-2);cursor:pointer">
@ -2043,20 +2043,20 @@ window.Page_health = (() => {
resultsEl.innerHTML = hits.map(h => `
<div class="health-card mb-2">
<div style="cursor:pointer;flex:1"
data-osm-id="${_esc(h.osm_id)}"
data-name="${_esc(h.name)}"
data-oh="${_esc(h.opening_hours || '')}"
data-phone="${_esc(h.phone || '')}"
data-osm-id="${UI.escape(h.osm_id)}"
data-name="${UI.escape(h.name)}"
data-oh="${UI.escape(h.opening_hours || '')}"
data-phone="${UI.escape(h.phone || '')}"
data-action="pick-osm">
<div style="font-weight:600">${_esc(h.name)}</div>
${h.opening_hours_fmt ? `<div class="text-sm-secondary">${_esc(h.opening_hours_fmt)}</div>` : '<div class="text-sm-muted">Öffnungszeiten unbekannt</div>'}
<div style="font-weight:600">${UI.escape(h.name)}</div>
${h.opening_hours_fmt ? `<div class="text-sm-secondary">${UI.escape(h.opening_hours_fmt)}</div>` : '<div class="text-sm-muted">Öffnungszeiten unbekannt</div>'}
<div class="text-xs-secondary">${h.distanz_km} km entfernt</div>
</div>
<button class="btn btn-secondary btn-sm" style="flex-shrink:0;align-self:flex-start"
data-action="korrigieren"
data-osm-id="${_esc(h.osm_id)}"
data-poi-name="${_esc(h.name)}"
data-current-oh="${_esc(h.opening_hours || '')}">
data-osm-id="${UI.escape(h.osm_id)}"
data-poi-name="${UI.escape(h.name)}"
data-current-oh="${UI.escape(h.opening_hours || '')}">
</button>
</div>
@ -2199,11 +2199,11 @@ window.Page_health = (() => {
tierarzt_sofort:{ badgeClass: 'badge-danger', icon: 'first-aid-kit', label: 'Sofort zum Tierarzt!' },
notfall: { badgeClass: 'badge-danger', icon: 'first-aid-kit', label: 'Notfall — sofort zum Tierarzt!' },
};
const d = DRINGLICHKEIT[result.dringlichkeit] || { badgeClass: 'badge-primary', icon: 'info', label: _esc(result.dringlichkeit) };
const d = DRINGLICHKEIT[result.dringlichkeit] || { badgeClass: 'badge-primary', icon: 'info', label: UI.escape(result.dringlichkeit) };
const hinweiseHtml = (result.hinweise || []).length
? `<ul style="margin:var(--space-2) 0 0;padding-left:var(--space-5);font-size:var(--text-sm)">
${result.hinweise.map(h => `<li style="margin-bottom:var(--space-1)">${_esc(h)}</li>`).join('')}
${result.hinweise.map(h => `<li style="margin-bottom:var(--space-1)">${UI.escape(h)}</li>`).join('')}
</ul>`
: '';
@ -2211,7 +2211,7 @@ window.Page_health = (() => {
? `<div style="margin-top:var(--space-3);padding:var(--space-3);
background:var(--c-surface-alt,var(--c-surface));
border-radius:var(--radius-md);font-size:var(--text-sm)">
<strong>Zum Tierarzt wenn:</strong> ${_esc(result.zum_tierarzt_wenn)}
<strong>Zum Tierarzt wenn:</strong> ${UI.escape(result.zum_tierarzt_wenn)}
</div>`
: '';
@ -2223,7 +2223,7 @@ window.Page_health = (() => {
</span>
</div>
${result.einschaetzung
? `<p style="font-size:var(--text-sm);line-height:1.6;margin:0">${_esc(result.einschaetzung)}</p>`
? `<p style="font-size:var(--text-sm);line-height:1.6;margin:0">${UI.escape(result.einschaetzung)}</p>`
: ''}
${hinweiseHtml}
${zumTierarztHtml}
@ -2244,7 +2244,7 @@ window.Page_health = (() => {
<div class="mb-3">
<label class="form-label">Chip-Nummer (15-stellig)</label>
<input id="transponder-input" class="form-control" type="text"
value="${_esc(currentNr)}" placeholder="z.B. 276009200123456" maxlength="20">
value="${UI.escape(currentNr)}" placeholder="z.B. 276009200123456" maxlength="20">
</div>`,
footer: `
<button class="btn btn-secondary" onclick="UI.modal.close()">Abbrechen</button>
@ -2260,7 +2260,7 @@ window.Page_health = (() => {
UI.modal.close();
const nrEl = _container.querySelector('#health-transponder-nr');
if (nrEl) nrEl.innerHTML = nr
? `<strong>${_esc(nr)}</strong>`
? `<strong>${UI.escape(nr)}</strong>`
: '<em class="text-muted">nicht eingetragen</em>';
} 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)) + '&hellip;'
: _esc(neuester.bericht);
? UI.escape(neuester.bericht.slice(0, 180)) + '&hellip;'
: UI.escape(neuester.bericht);
el.innerHTML = `
<div class="health-ki-bericht-banner" style="
background:var(--c-surface-2,#f7f2eb);
@ -2327,7 +2327,7 @@ window.Page_health = (() => {
title: `${UI.icon('star')} KI-Gesundheitsberichte`,
body: `${nav}
<div style="font-size:var(--text-xs);color:var(--c-text-muted);text-align:center;margin-bottom:8px">${fmtDate(b)}</div>
<div style="white-space:pre-wrap;line-height:1.7;font-size:var(--text-sm)">${_esc(b.bericht)}</div>`,
<div style="white-space:pre-wrap;line-height:1.7;font-size:var(--text-sm)">${UI.escape(b.bericht)}</div>`,
});
}
@ -2370,8 +2370,8 @@ window.Page_health = (() => {
return `
<div class="health-card" style="flex-direction:row;align-items:center;gap:var(--space-3)">
<div class="flex-1-min">
<div style="font-weight:600;font-size:var(--text-sm)">${_esc(v.bezeichnung)}</div>
<div class="text-xs-secondary">${_esc(v.label)}${v.praxis_name ? ' · ' + _esc(v.praxis_name) : ''}</div>
<div style="font-weight:600;font-size:var(--text-sm)">${UI.escape(v.bezeichnung)}</div>
<div class="text-xs-secondary">${UI.escape(v.label)}${v.praxis_name ? ' · ' + UI.escape(v.praxis_name) : ''}</div>
${badge}
</div>
<div style="text-align:right;flex-shrink:0">
@ -2380,7 +2380,7 @@ window.Page_health = (() => {
<div class="text-xs-secondary">${v.uhrzeit_vorschlag} Uhr</div>
<button class="btn btn-primary btn-sm" style="margin-top:var(--space-1)"
data-action="termin-anlegen"
data-v='${_esc(JSON.stringify(v))}'>
data-v='${UI.escape(JSON.stringify(v))}'>
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#calendar-plus"></use></svg> In Kalender
</button>
</div>
@ -2417,21 +2417,21 @@ window.Page_health = (() => {
<form id="termin-form">
<div class="form-group">
<label class="form-label">Bezeichnung</label>
<input class="form-control" type="text" name="titel" value="${_esc(titel)}" required>
<input class="form-control" type="text" name="titel" value="${UI.escape(titel)}" required>
</div>
<div class="grid-2">
<div class="form-group">
<label class="form-label">Datum</label>
<input class="form-control" type="date" name="datum" value="${_esc(v.datum_vorschlag)}" required>
<input class="form-control" type="date" name="datum" value="${UI.escape(v.datum_vorschlag)}" required>
</div>
<div class="form-group">
<label class="form-label">Uhrzeit</label>
<input class="form-control" type="time" name="uhrzeit" value="${_esc(v.uhrzeit_vorschlag)}">
<input class="form-control" type="time" name="uhrzeit" value="${UI.escape(v.uhrzeit_vorschlag)}">
</div>
</div>
<div class="form-group">
<label class="form-label">Notiz</label>
<input class="form-control" type="text" name="beschreibung" value="${_esc(beschreibung)}">
<input class="form-control" type="text" name="beschreibung" value="${UI.escape(beschreibung)}">
</div>
</form>
`,
@ -2490,20 +2490,20 @@ window.Page_health = (() => {
</div>
<div class="list-item-body flex-1-min">
${vet ? `
<div class="list-item-title">${_esc(vet.name)}</div>
${adresse ? `<div class="list-item-meta-row">${_esc(adresse)}</div>` : ''}
<div class="list-item-title">${UI.escape(vet.name)}</div>
${adresse ? `<div class="list-item-meta-row">${UI.escape(adresse)}</div>` : ''}
${vet.telefon ? `
<div class="mt-2">
<a href="tel:${_esc(vet.telefon)}" class="btn btn-secondary btn-sm"
<a href="tel:${UI.escape(vet.telefon)}" class="btn btn-secondary btn-sm"
onclick="event.stopPropagation()">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#phone"></use></svg> ${_esc(vet.telefon)}
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#phone"></use></svg> ${UI.escape(vet.telefon)}
</a>
</div>` : ''}
${vet.notfall_telefon ? `
<div style="margin-top:var(--space-1)">
<a href="tel:${_esc(vet.notfall_telefon)}" class="btn btn-danger btn-sm"
<a href="tel:${UI.escape(vet.notfall_telefon)}" class="btn btn-danger btn-sm"
onclick="event.stopPropagation()">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#warning"></use></svg> Notfall: ${_esc(vet.notfall_telefon)}
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#warning"></use></svg> Notfall: ${UI.escape(vet.notfall_telefon)}
</a>
</div>` : ''}
` : `
@ -2581,17 +2581,17 @@ window.Page_health = (() => {
return `
<div class="list-item-card health-card" style="align-items:flex-start">
<div style="font-size:1.4rem;flex-shrink:0;color:var(--c-primary)">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#${_esc(icon)}"></use></svg>
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#${UI.escape(icon)}"></use></svg>
</div>
<div class="list-item-body flex-1-min">
<div class="list-item-title">${_esc(doc.titel)}</div>
<div class="list-item-title">${UI.escape(doc.titel)}</div>
<div class="list-item-meta-row">
${_esc(label)}${datum ? ' · ' + datum : ''}
${doc.vet_name ? ' · <svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#first-aid"></use></svg> ' + _esc(doc.vet_name) : ''}
${UI.escape(label)}${datum ? ' · ' + datum : ''}
${doc.vet_name ? ' · <svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#first-aid"></use></svg> ' + UI.escape(doc.vet_name) : ''}
</div>
${doc.beschreibung ? `<div class="list-item-text">${_esc(doc.beschreibung)}</div>` : ''}
${doc.beschreibung ? `<div class="list-item-text">${UI.escape(doc.beschreibung)}</div>` : ''}
<div style="display:flex;gap:var(--space-2);margin-top:var(--space-2);flex-wrap:wrap">
<a href="${_esc(doc.file_path)}" target="_blank" rel="noopener"
<a href="${UI.escape(doc.file_path)}" target="_blank" rel="noopener"
class="btn btn-secondary btn-sm" onclick="event.stopPropagation()">
${isImg
? '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#image"></use></svg> Bild öffnen'
@ -2680,7 +2680,7 @@ window.Page_health = (() => {
<select class="form-control" name="vet_id">
<option value=""> optional </option>
${aktivePraxen.map(p =>
`<option value="${p.id}">${_esc(p.name)}${p.ort ? ' · ' + _esc(p.ort) : ''}</option>`
`<option value="${p.id}">${UI.escape(p.name)}${p.ort ? ' · ' + UI.escape(p.ort) : ''}</option>`
).join('')}
</select>
</div>` : ''}
@ -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: `<div style="white-space:pre-wrap;line-height:1.7;font-size:var(--text-sm)">${_esc(zusammenfassung)}</div>`,
body: `<div style="white-space:pre-wrap;line-height:1.7;font-size:var(--text-sm)">${UI.escape(zusammenfassung)}</div>`,
});
// 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, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
.replace(/"/g, '&quot;');
}
function _showPoiKorrekturModal(osmId, poiName, currentOh) {
function _showPoiKorrekturModal(osmId, poiName, currentOh) {
UI.modal.open({
title: 'Öffnungszeiten korrigieren',
body: `
<p style="font-size:var(--text-sm);color:var(--c-text-secondary);margin-bottom:var(--space-3)">
Korrektur für <strong>${_esc(poiName)}</strong>.<br>
Korrektur für <strong>${UI.escape(poiName)}</strong>.<br>
Dein Vorschlag wird von einem Moderator geprüft und dann für alle übernommen.
</p>
<form id="poi-korrektur-form">
<div class="form-group">
<label class="form-label">Aktuelle Angabe</label>
<input class="form-control" type="text" value="${_esc(currentOh)}" disabled
<input class="form-control" type="text" value="${UI.escape(currentOh)}" disabled
class="text-muted">
</div>
<div class="form-group">
<label class="form-label">Korrekte Öffnungszeiten *</label>
<input class="form-control" type="text" name="new_value" required
placeholder="z.B. MoFr 08:0018:00 · Sa 09:0013:00"
value="${_esc(currentOh)}">
value="${UI.escape(currentOh)}">
</div>
</form>
`,
@ -2872,7 +2865,7 @@ window.Page_health = (() => {
display:flex;align-items:center;justify-content:space-between;flex-shrink:0">
<div>
<div style="font-weight:var(--weight-semibold);font-size:var(--text-base)"><svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#note-pencil"></use></svg> Notiz</div>
<div style="font-size:var(--text-xs);color:var(--c-text-muted);margin-top:2px">${_esc(parentLabel)}</div>
<div style="font-size:var(--text-xs);color:var(--c-text-muted);margin-top:2px">${UI.escape(parentLabel)}</div>
</div>
<button id="by-note-close" style="background:none;border:none;cursor:pointer;font-size:1.4rem;color:var(--c-text-muted);padding:4px 8px" aria-label="Schließen">×</button>
</div>
@ -2956,7 +2949,7 @@ window.Page_health = (() => {
</p>
<div class="form-group">
<textarea id="ki-tierarzt-symptom" class="form-control" rows="4"
placeholder="${_esc(placeholder)}"></textarea>
placeholder="${UI.escape(placeholder)}"></textarea>
</div>
<div id="ki-tierarzt-result" class="hidden"></div>
<div style="margin-top:var(--space-3);padding:var(--space-3);
@ -3018,7 +3011,7 @@ window.Page_health = (() => {
return;
}
const antwortHtml = _esc(result.antwort)
const antwortHtml = UI.escape(result.antwort)
.replace(/\n\n/g, '</p><p style="margin:var(--space-2) 0">')
.replace(/\n/g, '<br>');
const restHtml = result.limit - result.anfragen_heute > 0
@ -3092,7 +3085,7 @@ window.Page_health = (() => {
<use href="/icons/phosphor.svg#bell-ringing"></use>
</svg>
<div class="flex-1-min">
<span style="font-weight:600;font-size:var(--text-sm);color:var(--c-text)">${_esc(r.bezeichnung)}</span>
<span style="font-weight:600;font-size:var(--text-sm);color:var(--c-text)">${UI.escape(r.bezeichnung)}</span>
<span style="font-size:var(--text-xs);color:var(--c-text-secondary);margin-left:var(--space-1)">${TYPE_LABEL[r.typ] || r.typ}</span>
</div>
<span style="font-size:var(--text-xs);font-weight:600;color:${color};white-space:nowrap">${label}</span>
@ -3122,8 +3115,8 @@ window.Page_health = (() => {
<div class="card" style="padding:var(--space-4);margin-bottom:var(--space-3)" data-ins-id="${p.id}">
<div style="display:flex;align-items:flex-start;justify-content:space-between;gap:var(--space-2)">
<div>
<div style="font-weight:700;font-size:var(--text-base)">${_esc(p.anbieter)}</div>
${p.police_nr ? `<div style="font-size:var(--text-xs);color:var(--c-text-muted);margin-top:2px">Police: ${_esc(p.police_nr)}</div>` : ''}
<div style="font-weight:700;font-size:var(--text-base)">${UI.escape(p.anbieter)}</div>
${p.police_nr ? `<div style="font-size:var(--text-xs);color:var(--c-text-muted);margin-top:2px">Police: ${UI.escape(p.police_nr)}</div>` : ''}
</div>
<div style="display:flex;gap:var(--space-1)">
<button class="btn btn-ghost btn-sm ins-edit-btn" data-id="${p.id}" style="padding:4px 8px">
@ -3137,8 +3130,8 @@ window.Page_health = (() => {
<div style="display:grid;grid-template-columns:1fr 1fr;gap:var(--space-2);margin-top:var(--space-3);font-size:var(--text-sm)">
<div><span class="text-secondary">Jahresbeitrag</span><br><strong>${_fmtEur(p.jahresbeitrag)}</strong></div>
<div><span class="text-secondary">Läuft ab</span><br><strong>${_fmtDate(p.ablaufdatum)}</strong></div>
${p.kontakt ? `<div style="grid-column:1/-1"><span class="text-secondary">Kontakt</span><br>${_esc(p.kontakt)}</div>` : ''}
${p.notizen ? `<div style="grid-column:1/-1"><span class="text-secondary">Notizen</span><br>${_esc(p.notizen)}</div>` : ''}
${p.kontakt ? `<div style="grid-column:1/-1"><span class="text-secondary">Kontakt</span><br>${UI.escape(p.kontakt)}</div>` : ''}
${p.notizen ? `<div style="grid-column:1/-1"><span class="text-secondary">Notizen</span><br>${UI.escape(p.notizen)}</div>` : ''}
</div>
</div>`).join('') : `
<div style="text-align:center;padding:var(--space-6);color:var(--c-text-muted)">
@ -3172,10 +3165,10 @@ window.Page_health = (() => {
const id = `ins-form-${Date.now()}`;
const body = `<form id="${id}">
<div class="by-form-group"><label class="by-label">Anbieter *</label>
<input type="text" name="anbieter" class="form-control by-input" value="${_esc(existing?.anbieter||'')}" required placeholder="z. B. HUK-Coburg">
<input type="text" name="anbieter" class="form-control by-input" value="${UI.escape(existing?.anbieter||'')}" required placeholder="z. B. HUK-Coburg">
</div>
<div class="by-form-group"><label class="by-label">Police-Nr.</label>
<input type="text" name="police_nr" class="form-control by-input" value="${_esc(existing?.police_nr||'')}" placeholder="optional">
<input type="text" name="police_nr" class="form-control by-input" value="${UI.escape(existing?.police_nr||'')}" placeholder="optional">
</div>
<div class="grid-2">
<div class="by-form-group"><label class="by-label">Jahresbeitrag ()</label>
@ -3186,10 +3179,10 @@ window.Page_health = (() => {
</div>
</div>
<div class="by-form-group"><label class="by-label">Kontakt / Telefon</label>
<input type="text" name="kontakt" class="form-control by-input" value="${_esc(existing?.kontakt||'')}" placeholder="optional">
<input type="text" name="kontakt" class="form-control by-input" value="${UI.escape(existing?.kontakt||'')}" placeholder="optional">
</div>
<div class="by-form-group"><label class="by-label">Notizen</label>
<textarea name="notizen" class="form-control by-input" rows="2">${_esc(existing?.notizen||'')}</textarea>
<textarea name="notizen" class="form-control by-input" rows="2">${UI.escape(existing?.notizen||'')}</textarea>
</div>
</form>`;
const footer = `
@ -3271,12 +3264,12 @@ window.Page_health = (() => {
<div style="width:3px;border-radius:2px;background:${color};align-self:stretch;flex-shrink:0"></div>
<div class="flex-1-min">
<div style="display:flex;align-items:center;gap:var(--space-2);flex-wrap:wrap">
<span style="font-weight:700;font-size:var(--text-sm);color:${color}">${_esc(katLabel)}</span>
${trigLabel ? `<span style="font-size:var(--text-xs);background:var(--c-surface-2);padding:1px 6px;border-radius:100px;color:var(--c-text-secondary)">${_esc(trigLabel)}</span>` : ''}
<span style="font-weight:700;font-size:var(--text-sm);color:${color}">${UI.escape(katLabel)}</span>
${trigLabel ? `<span style="font-size:var(--text-xs);background:var(--c-surface-2);padding:1px 6px;border-radius:100px;color:var(--c-text-secondary)">${UI.escape(trigLabel)}</span>` : ''}
<span style="font-size:var(--text-xs);color:var(--c-text-muted);margin-left:auto">${fmtDate(e.datum)}${e.uhrzeit ? ' ' + e.uhrzeit : ''}</span>
</div>
<div style="display:flex;gap:3px;margin-top:4px">${dots}</div>
${e.notiz ? `<div style="font-size:var(--text-xs);color:var(--c-text-secondary);margin-top:4px">${_esc(e.notiz)}</div>` : ''}
${e.notiz ? `<div style="font-size:var(--text-xs);color:var(--c-text-secondary);margin-top:4px">${UI.escape(e.notiz)}</div>` : ''}
</div>
<button class="btn btn-ghost btn-sm beh-del-btn" data-id="${e.id}" style="padding:4px 6px;color:var(--c-danger);flex-shrink:0">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#trash"></use></svg>