Fix: restliche CSP-blockierte Inline-Handler — Bild-Fallbacks (globaler data-fb Error-Handler) + Hover-Effekte (CSS-Utilities + data-hover-play)
App ist jetzt vollständig frei von Inline-Event-Handlern (onerror/onmouseenter/etc.). data-fb Modi: hide/hide-parent/dim-grandparent/sibling/show-el/emoji/initials + data-fb-src. Hover: .by-hover-lift/-surface2/-surface3 in utilities.css. SW v1165
This commit is contained in:
parent
2ddd8ac350
commit
c07b1cc01b
23 changed files with 125 additions and 68 deletions
|
|
@ -3,7 +3,7 @@
|
|||
Router, State-Management, Navigation, Initialisierung.
|
||||
============================================================ */
|
||||
|
||||
const APP_VER = '1164'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
|
||||
const APP_VER = '1165'; // ← 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;
|
||||
|
|
@ -434,6 +434,62 @@ const App = (() => {
|
|||
// NAVIGATION EVENTS
|
||||
// ----------------------------------------------------------
|
||||
function _bindNavigation() {
|
||||
// Globaler Bild-Fallback — ersetzt CSP-blockierte onerror-Attribute.
|
||||
// 'error' bubbelt nicht → Capture-Phase. Greift nur bei [data-fb]/[data-fb-src].
|
||||
document.addEventListener('error', e => {
|
||||
const el = e.target;
|
||||
if (!el || el.tagName !== 'IMG') return;
|
||||
const fb = el.dataset.fb, altSrc = el.dataset.fbSrc;
|
||||
if (fb === undefined && altSrc === undefined) return;
|
||||
// Schritt 1: Alternative Quelle versuchen (z.B. _preview → Original / Platzhalter)
|
||||
if (altSrc && !el.dataset.fbTried) {
|
||||
el.dataset.fbTried = '1';
|
||||
el.src = altSrc;
|
||||
return;
|
||||
}
|
||||
// Schritt 2: terminaler Fallback
|
||||
switch (fb) {
|
||||
case 'hide-parent':
|
||||
if (el.parentElement) el.parentElement.style.display = 'none';
|
||||
break;
|
||||
case 'dim-grandparent':
|
||||
if (el.parentElement?.parentElement) el.parentElement.parentElement.style.opacity = '.4';
|
||||
break;
|
||||
case 'sibling':
|
||||
el.style.display = 'none';
|
||||
if (el.nextElementSibling) el.nextElementSibling.style.display = 'flex';
|
||||
break;
|
||||
case 'show-el': {
|
||||
el.style.display = 'none';
|
||||
const t = el.dataset.fbEl && document.getElementById(el.dataset.fbEl);
|
||||
if (t) t.style.display = 'flex';
|
||||
break;
|
||||
}
|
||||
case 'emoji':
|
||||
if (el.parentElement) el.parentElement.innerHTML =
|
||||
`<div style="display:flex;align-items:center;justify-content:center;height:100%;font-size:${el.dataset.fbSize || '2rem'}">${el.dataset.fbEmoji || '🐾'}</div>`;
|
||||
break;
|
||||
case 'initials': {
|
||||
const sz = parseInt(el.dataset.fbSize, 10) || 40;
|
||||
el.outerHTML =
|
||||
`<div style="width:${sz}px;height:${sz}px;border-radius:50%;background:var(--c-primary-subtle);display:flex;align-items:center;justify-content:center;font-size:${Math.round(sz * 0.45)}px;font-weight:700;color:var(--c-primary)">${el.dataset.fbInitials || ''}</div>`;
|
||||
break;
|
||||
}
|
||||
default: // 'hide'
|
||||
el.style.display = 'none';
|
||||
el.classList.add('img-broken');
|
||||
}
|
||||
}, true);
|
||||
|
||||
// Video-Vorschau bei Hover (ersetzt CSP-blockierte onmouseenter/leave).
|
||||
// <video> hat keine Kinder → e.target ist das Video selbst (matches() O(1)).
|
||||
document.addEventListener('mouseover', e => {
|
||||
if (e.target.matches?.('[data-hover-play]')) e.target.play?.().catch(() => {});
|
||||
});
|
||||
document.addEventListener('mouseout', e => {
|
||||
if (e.target.matches?.('[data-hover-play]')) e.target.pause?.();
|
||||
});
|
||||
|
||||
// Bottom Nav + Sidebar Klicks
|
||||
document.addEventListener('click', e => {
|
||||
const item = e.target.closest('[data-page]');
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue