Fix: alle funktionalen Inline-Event-Handler → addEventListener/Delegation (von CSP-Härtung 65cfa25 app-weit blockiert)

Chat (senden/öffnen/löschen/Foto), Tagebuch-Buch, KI-Berichte, Wiki-Moderation,
Events-Detail, Walks-Lightbox, Routen-Foto, Navigations-CTAs (data-page),
Presse-Copy + Züchter-Landing (externes JS). 35x UI.modal.close → data-modal-close,
28x totes event.stopPropagation entfernt. Verbleibend: kosmetische onerror/Hover. SW v1164
This commit is contained in:
rene 2026-06-04 13:59:27 +02:00
parent 152fde716c
commit 2ddd8ac350
34 changed files with 228 additions and 173 deletions

View file

@ -83,7 +83,7 @@ window.Page_health = (() => {
icon: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#syringe"></use></svg>',
title: 'Noch kein Hund angelegt',
text: 'Erstelle zuerst ein Hundeprofil.',
action: `<button class="btn btn-primary" onclick="App.navigate('dog-profile')">Profil erstellen</button>`,
action: `<button class="btn btn-primary" data-page="dog-profile">Profil erstellen</button>`,
});
return;
}
@ -403,8 +403,7 @@ window.Page_health = (() => {
${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="${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>
data-label="${UI.escape(e.bezeichnung)}"><svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#note-pencil"></use></svg> Notiz</button>
</div>
</div>
`;
@ -511,8 +510,7 @@ window.Page_health = (() => {
${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="${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>
data-label="${UI.escape(e.bezeichnung)}"><svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#note-pencil"></use></svg> Notiz</button>
</div>
</div>
`;
@ -563,8 +561,7 @@ window.Page_health = (() => {
${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 ${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>
data-label="Gewicht ${UI.escape(e.datum)}"><svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#note-pencil"></use></svg> Notiz</button>
</div>
</div>
`).join('');
@ -801,8 +798,7 @@ window.Page_health = (() => {
${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 ${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>
data-label="Läufigkeit ${UI.escape(e.datum)}"><svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#note-pencil"></use></svg> Notiz</button>
</div>
</div>`;
}).join('');
@ -839,8 +835,7 @@ window.Page_health = (() => {
${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="${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>
data-label="${UI.escape(e.bezeichnung)}"><svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#note-pencil"></use></svg> Notiz</button>
</div>
</div>
`).join('')}
@ -880,8 +875,7 @@ window.Page_health = (() => {
${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="${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>
data-label="${UI.escape(e.bezeichnung)}"><svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#note-pencil"></use></svg> Notiz</button>
</div>
</div>
`).join('');
@ -923,19 +917,16 @@ window.Page_health = (() => {
${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="${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>
data-label="${UI.escape(e.bezeichnung)}"><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="${UI.escape(m.url)}" target="_blank" rel="noopener"
class="btn btn-secondary btn-sm" style="display:inline-flex"
onclick="event.stopPropagation()">
class="btn btn-secondary btn-sm" style="display:inline-flex">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#file-text"></use></svg> PDF
</a>`
: `<a href="${UI.escape(m.url)}" target="_blank" rel="noopener"
class="btn btn-secondary btn-sm" style="display:inline-flex"
onclick="event.stopPropagation()">
class="btn btn-secondary btn-sm" style="display:inline-flex">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#image"></use></svg> Bild
</a>`
).join('')}
@ -1773,28 +1764,24 @@ window.Page_health = (() => {
${ratingHtml}
<div style="display:flex;gap:var(--space-2);margin-top:var(--space-2);flex-wrap:wrap">
${p.telefon ? `
<a href="tel:${UI.escape(p.telefon)}" class="btn btn-secondary btn-sm"
onclick="event.stopPropagation()">
<a href="tel:${UI.escape(p.telefon)}" class="btn btn-secondary btn-sm">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#phone"></use></svg> Anrufen
</a>` : ''}
${p.notfall_telefon ? `
<a href="tel:${UI.escape(p.notfall_telefon)}" class="btn btn-danger btn-sm"
onclick="event.stopPropagation()">
<a href="tel:${UI.escape(p.notfall_telefon)}" class="btn btn-danger btn-sm">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#warning"></use></svg> Notfall
</a>` : ''}
<button class="btn btn-sm btn-secondary"
data-action="bewerten" data-praxis-id="${p.id}"
title="Bewertung abgeben"
style="flex-shrink:0"
onclick="event.stopPropagation()">
style="flex-shrink:0">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#star"></use></svg>
Bewerten
</button>
<button class="btn btn-sm ${isFav ? 'btn-primary' : 'btn-secondary'}"
data-action="toggle-fav" data-praxis-id="${p.id}"
title="${isFav ? 'Favorit entfernen' : 'Als mein Tierarzt merken'}"
style="flex-shrink:0"
onclick="event.stopPropagation()">
style="flex-shrink:0">
<svg class="ph-icon" aria-hidden="true">
<use href="/icons/phosphor.svg#${isFav ? 'heart-fill' : 'heart'}"></use>
</svg>
@ -1803,8 +1790,7 @@ window.Page_health = (() => {
<button class="btn btn-sm btn-secondary"
data-action="edit-praxis" data-praxis-id="${p.id}"
title="Praxis bearbeiten"
style="flex-shrink:0"
onclick="event.stopPropagation()">
style="flex-shrink:0">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#pencil-simple"></use></svg>
</button>
</div>
@ -1881,7 +1867,7 @@ window.Page_health = (() => {
<use href="/icons/phosphor.svg#spinner-gap"></use>
</svg>
</div>`,
footer: `<button class="btn btn-secondary" onclick="UI.modal.close()">Schließen</button>
footer: `<button class="btn btn-secondary" data-modal-close>Schließen</button>
<button class="btn btn-primary" id="detail-bewerten-btn">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#star"></use></svg>
Jetzt bewerten
@ -1998,7 +1984,7 @@ window.Page_health = (() => {
title: `${UI.escape(praxis.name)} bewerten`,
body,
footer: `
<button class="btn btn-secondary" onclick="UI.modal.close()">Abbrechen</button>
<button class="btn btn-secondary" data-modal-close>Abbrechen</button>
<button class="btn btn-primary" id="bew-submit-btn" form="bew-form">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#star"></use></svg>
${existing ? 'Bewertung aktualisieren' : 'Bewertung abgeben'}
@ -2373,7 +2359,7 @@ window.Page_health = (() => {
value="${UI.escape(currentNr)}" placeholder="z.B. 276009200123456" maxlength="20">
</div>`,
footer: `
<button class="btn btn-secondary" onclick="UI.modal.close()">Abbrechen</button>
<button class="btn btn-secondary" data-modal-close>Abbrechen</button>
<button class="btn btn-primary" id="transponder-save-btn">Speichern</button>`,
});
document.getElementById('transponder-save-btn').addEventListener('click', async () => {
@ -2441,11 +2427,11 @@ window.Page_health = (() => {
const b = berichte[idx];
const nav = berichte.length > 1 ? `
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:12px">
<button onclick="window._kiPrev()" style="padding:6px 16px;border-radius:999px;
<button data-ki-nav="prev" style="padding:6px 16px;border-radius:999px;
border:1.5px solid var(--c-border);background:var(--c-surface);cursor:pointer;
font-size:var(--text-sm);${idx >= berichte.length-1 ? 'opacity:.3;pointer-events:none' : ''}"> Älter</button>
<span class="text-xs-muted">${idx+1} / ${berichte.length}</span>
<button onclick="window._kiNext()" style="padding:6px 16px;border-radius:999px;
<button data-ki-nav="next" style="padding:6px 16px;border-radius:999px;
border:1.5px solid var(--c-border);background:var(--c-surface);cursor:pointer;
font-size:var(--text-sm);${idx <= 0 ? 'opacity:.3;pointer-events:none' : ''}">Neuer </button>
</div>` : '';
@ -2455,10 +2441,13 @@ window.Page_health = (() => {
<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)">${UI.escape(b.bericht)}</div>`,
});
// Inline-onclick wird von der CSP blockiert → per addEventListener verdrahten.
document.querySelector('[data-ki-nav="prev"]')
?.addEventListener('click', () => { if (idx < berichte.length - 1) { idx++; showBericht(); } });
document.querySelector('[data-ki-nav="next"]')
?.addEventListener('click', () => { if (idx > 0) { idx--; showBericht(); } });
}
window._kiPrev = () => { if (idx < berichte.length - 1) { idx++; showBericht(); } };
window._kiNext = () => { if (idx > 0) { idx--; showBericht(); } };
showBericht();
});
} catch (_) {
@ -2620,15 +2609,13 @@ window.Page_health = (() => {
${adresse ? `<div class="list-item-meta-row">${UI.escape(adresse)}</div>` : ''}
${vet.telefon ? `
<div class="mt-2">
<a href="tel:${UI.escape(vet.telefon)}" class="btn btn-secondary btn-sm"
onclick="event.stopPropagation()">
<a href="tel:${UI.escape(vet.telefon)}" class="btn btn-secondary btn-sm">
<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:${UI.escape(vet.notfall_telefon)}" class="btn btn-danger btn-sm"
onclick="event.stopPropagation()">
<a href="tel:${UI.escape(vet.notfall_telefon)}" class="btn btn-danger btn-sm">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#warning"></use></svg> Notfall: ${UI.escape(vet.notfall_telefon)}
</a>
</div>` : ''}
@ -2718,14 +2705,13 @@ window.Page_health = (() => {
${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="${UI.escape(doc.file_path)}" target="_blank" rel="noopener"
class="btn btn-secondary btn-sm" onclick="event.stopPropagation()">
class="btn btn-secondary btn-sm">
${isImg
? '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#image"></use></svg> Bild öffnen'
: '<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#file-text"></use></svg> PDF öffnen'}
</a>
<button class="btn btn-ghost btn-xs text-danger"
data-action="delete-hdoc" data-doc-id="${doc.id}"
onclick="event.stopPropagation()">
data-action="delete-hdoc" data-doc-id="${doc.id}">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#trash"></use></svg>
</button>
</div>
@ -3007,7 +2993,7 @@ function _showPoiKorrekturModal(osmId, poiName, currentOh) {
Bei ernsthaften oder sich verschlechternden Symptomen sofort zum Tierarzt.
</div>`,
footer: `
<button class="btn btn-secondary" onclick="UI.modal.close()">Schließen</button>
<button class="btn btn-secondary" data-modal-close>Schließen</button>
<button class="btn btn-primary" id="ki-tierarzt-submit-btn">Frage stellen</button>`,
});
@ -3233,7 +3219,7 @@ function _showPoiKorrekturModal(osmId, poiName, currentOh) {
</div>
</form>`;
const footer = `
<button class="btn btn-secondary" onclick="UI.modal.close()">Abbrechen</button>
<button class="btn btn-secondary" data-modal-close>Abbrechen</button>
<button class="btn btn-primary" id="ins-save-btn" form="${id}">Speichern</button>`;
UI.modal.open({ title: existing ? 'Versicherung bearbeiten' : 'Versicherung eintragen', body, footer });
setTimeout(() => {
@ -3385,7 +3371,7 @@ function _showPoiKorrekturModal(osmId, poiName, currentOh) {
</div>
</form>`;
const footer = `
<button class="btn btn-secondary" onclick="UI.modal.close()">Abbrechen</button>
<button class="btn btn-secondary" data-modal-close>Abbrechen</button>
<button class="btn btn-primary" id="beh-save-btn" form="${id}">Speichern</button>`;
UI.modal.open({ title: 'Verhalten erfassen', body, footer });
setTimeout(() => {