/* ===================================================================== DIE ANRUF-PROBE (19.09.2026) Filipe, nach einem langen Abend: „funktioniert nichts davon was machst du?" Zu Recht. Ich habe an diesem Abend fünf Dinge repariert, jedes einzeln nachgewiesen -- und trotzdem klingelte bei ihm nichts. Der Grund ist immer derselbe: Ich kann von hier aus messen, was der SERVER tut, aber nicht, was in seinem Browser ankommt. Und genau dort lag es jedes Mal. Diese Seite dreht das um. Sie läuft in SEINEM Browser und beantwortet der Reihe nach die Fragen, die ich ihm sonst stellen müsste: 1. Ist die neue Fassung überhaupt geladen? (Der häufigste Fall: eine alte Seite aus dem Zwischenspeicher, die alte Dateien nachlädt. Dann ist jede Reparatur unsichtbar.) 2. Darf der Browser überhaupt Ton abspielen? 3. Sind Benachrichtigungen erlaubt -- und ist ein Gerät angemeldet? 4. Steht die Verbindung zum Server, über die das Klingeln kommt? Sie ruft niemanden an. Man kann sie so oft aufmachen, wie man will. ===================================================================== */ (() => { const $ = (id) => document.getElementById(id); const ziel = $('ergebnis'); if (!ziel) return; const punkte = []; function punkt(stand, titel, satz) { punkte.push({ stand, titel, satz }); const k = document.createElement('div'); k.className = 'punkt'; k.dataset.stand = stand; const z = document.createElement('span'); z.className = 'punkt__zeichen'; z.textContent = stand === 'gut' ? '✓' : stand === 'warn' ? '!' : '✗'; const t = document.createElement('div'); t.className = 'punkt__text'; const h = document.createElement('p'); h.className = 'punkt__titel'; h.textContent = titel; const s = document.createElement('p'); s.className = 'punkt__satz'; s.textContent = satz; t.append(h, s); k.append(z, t); ziel.append(k); } /* ---- 1. WELCHE FASSUNG IST GELADEN? ----------------------------- Der wichtigste Punkt, und der am häufigsten übersehene. Die Anruf-Datei trägt einen Stempel im Namen (anruf.js?v=…). Steht in der geladenen Seite ein alter Stempel, kommt aus dem Zwischenspeicher eine alte Datei -- und jede Reparatur am Server ist unsichtbar, egal wie oft man neu lädt. */ async function fassungPruefen() { const skript = [...document.querySelectorAll('script[src]')] .map((s) => s.getAttribute('src')) .find((s) => /anruf-probe\.js/.test(s || '')); const stempel = (skript || '').split('v=')[1] || '(keiner)'; try { const a = await fetch(`assets/js/anruf.js?v=${stempel}`, { cache: 'no-store' }); const text = await a.text(); const hatTon = text.includes('klingelTon'); const hatOffen = text.includes('anruf/offen'); if (hatTon && hatOffen) { punkt('gut', 'Die neue Fassung ist geladen', `Klingelton und Nachklingeln sind da (Stand ${stempel}).`); } else { punkt('schlecht', 'Es läuft eine ALTE Fassung', `Der Klingelton fehlt${hatOffen ? '' : ', das Nachklingeln auch'}. ` + 'Die Seite kommt aus dem Zwischenspeicher. ' + 'Hilft: die Seite ganz schließen (in der App aus dem Wechsler wischen) und neu öffnen.'); } } catch { punkt('warn', 'Fassung nicht prüfbar', 'Die Datei ließ sich nicht laden – bist du gerade offline?'); } } /* ---- 2. DARF DER BROWSER TON ABSPIELEN? ------------------------- Browser erlauben Ton erst, wenn jemand auf der Seite etwas angeklickt hat. Wer über eine Benachrichtigung hereinkommt und nichts berührt, hört deshalb unter Umständen nichts -- und hält das Telefon für kaputt. */ function tonPruefen() { const K = window.AudioContext || window.webkitAudioContext; if (!K) { punkt('schlecht', 'Dieser Browser kann keinen Ton erzeugen', 'Sehr selten. Ein anderer Browser hilft.'); return null; } const raum = new K(); if (raum.state === 'running') { punkt('gut', 'Ton ist erlaubt', 'Der Klingelton kann abgespielt werden.'); } else { punkt('warn', 'Ton ist noch gesperrt', 'Der Browser lässt Ton erst zu, nachdem man einmal etwas angetippt hat. ' + 'Drück unten auf „Klingelton anhören“ – danach ist er frei, ' + 'solange die Seite offen bleibt.'); } return raum; } /* ---- 3. BENACHRICHTIGUNGEN ---------------------------------------- */ async function meldungPruefen() { if (!('Notification' in window)) { punkt('warn', 'Benachrichtigungen kennt dieser Browser nicht', 'Anrufe klingeln dann nur, wenn die Seite offen ist.'); return; } const erlaubt = Notification.permission; if (erlaubt === 'granted') punkt('gut', 'Benachrichtigungen sind erlaubt', 'Gut.'); else if (erlaubt === 'denied') { punkt('schlecht', 'Benachrichtigungen sind blockiert', 'Dann kommt kein Anruf an, solange die Seite zu ist. ' + 'In den Browsereinstellungen für diese Seite wieder erlauben.'); } else { punkt('warn', 'Benachrichtigungen sind noch nicht erlaubt', 'Im Chat oben auf die Glocke tippen und zustimmen.'); } /* Ist auch wirklich ein Gerät beim Server angemeldet? Erlaubnis im Browser und Anmeldung beim Server sind zwei verschiedene Dinge -- genau diese Lücke sieht man sonst nirgends. */ try { const a = await fetch('/workspace/api/push/stand', { credentials: 'same-origin' }); if (a.ok) { const d = await a.json(); /* `geraete` ist eine LISTE, keine Zahl -- nachgesehen in workspace-push.js statt geraten. */ const n = Array.isArray(d.geraete) ? d.geraete.length : 0; if (n > 0) punkt('gut', 'Dieses Konto hat ein Gerät angemeldet', `${n} Gerät(e).`); else { punkt('schlecht', 'Kein Gerät beim Server angemeldet', 'Der Browser darf zwar, aber es ist nichts hinterlegt. ' + 'Im Chat auf die Glocke tippen und neu zustimmen.'); } /* UND DIE RUHEZEIT. Sie hat gestern Abend den ganzen Anruf verschluckt; seit heute sind Anrufe ausgenommen. Wer das hier liest, soll es sehen, statt es zu vermuten. */ if (d.ruhe) { const anrufArt = (d.arten || []).find((x) => x.schluessel === 'anruf'); if (anrufArt && anrufArt.an === false) { punkt('schlecht', 'Anrufe sind bei dir abgeschaltet', 'In den Benachrichtigungen die Art „Jemand ruft an“ wieder einschalten.'); } else if (d.ruhe.jetzt) { punkt('gut', `Es ist Ruhezeit (${d.ruhe.ab}–${d.ruhe.bis} Uhr)`, 'Erinnerungen bleiben jetzt liegen – Anrufe kommen trotzdem durch.'); } } } } catch { /* die Route gibt es vielleicht nicht -- kein Grund zur Panik */ } } /* ---- 4. KOMMT ETWAS VOM SERVER AN? ------------------------------- */ async function serverPruefen() { try { const a = await fetch('/workspace/api/anruf/offen', { credentials: 'same-origin' }); if (a.status === 401) { punkt('schlecht', 'Du bist nicht angemeldet', 'Dann kann auch nichts klingeln. Melde dich neu an.'); return; } if (!a.ok) { /* NICHT NUR DIE ZAHL (19.09.2026). Alle zwoelf anderen Punkte sagen, was zu tun ist -- dieser sagte "Antwort 503.". Und er kann als Erster im Schlussrat landen, also ganz unten als das, was offen bleibt. Diese Seite ist ausdruecklich fuer jemanden gebaut, der nicht technisch ist; eine dreistellige Zahl ist fuer ihn keine Auskunft, sondern die Bestaetigung, dass er hier nichts ausrichten kann. */ punkt('warn', 'Der Server antwortet gerade ungewöhnlich', 'Wahrscheinlich wird er gerade neu gestartet oder ist kurz ' + 'überlastet. Warte eine Minute und öffne diese Seite noch ' + `einmal. Bleibt es dabei, sag DogFather Bescheid – Kennzahl ${a.status}.`); return; } const d = await a.json(); punkt('gut', 'Die Verbindung zum Server steht', (d.anrufe?.length ? `Gerade klingelt sogar etwas (${d.anrufe.length}).` : 'Gerade klingelt nichts – das ist normal.')); } catch { punkt('schlecht', 'Keine Verbindung zum Server', 'Kein Netz? Ohne sie kommt kein Anruf an.'); } } /* ---- Der Rat am Ende --------------------------------------------- */ function ratGeben() { const schlecht = punkte.filter((p) => p.stand === 'schlecht'); const warn = punkte.filter((p) => p.stand === 'warn'); const r = $('rat'); if (!r) return; if (schlecht.length) { r.textContent = 'Das Wichtigste zuerst: ' + schlecht[0].titel + '. ' + schlecht[0].satz; } else if (warn.length) { r.textContent = 'Fast alles steht. Offen ist: ' + warn[0].titel + '. ' + warn[0].satz; } else { r.textContent = 'Alles, was von hier aus prüfbar ist, steht. ' + 'Wenn es jetzt noch klemmt, liegt es an der Verbindung zwischen ' + 'den beiden Geräten – dann hilft nur ein echter Anruf zu zweit.'; } } /* ---- Der Knopf: Ton wirklich hören -------------------------------- */ let tonRaum = null; $('ton-probe')?.addEventListener('click', () => { try { const K = window.AudioContext || window.webkitAudioContext; tonRaum = tonRaum || new K(); if (tonRaum.state === 'suspended') tonRaum.resume(); const spiel = (hz, ab, lang) => { const o = tonRaum.createOscillator(); const v = tonRaum.createGain(); o.type = 'sine'; o.frequency.value = hz; const t = tonRaum.currentTime + ab; v.gain.setValueAtTime(0, t); v.gain.linearRampToValueAtTime(0.16, t + 0.03); v.gain.linearRampToValueAtTime(0, t + lang); o.connect(v).connect(tonRaum.destination); o.start(t); o.stop(t + lang + 0.05); }; /* Genau der Klingelton aus dem Anruf -- damit man hört, was man hören würde. */ spiel(880, 0, 0.22); spiel(660, 0.3, 0.26); try { navigator.vibrate?.([250, 200, 250]); } catch { /* egal */ } $('ton-probe').textContent = 'Nochmal anhören'; } catch { $('ton-probe').textContent = 'Ton ging nicht – siehe oben'; } }); (async () => { await fassungPruefen(); tonPruefen(); await meldungPruefen(); await serverPruefen(); ratGeben(); })(); })(); /* --------------------------------------------------------------------- DER RÜCKWEG FÜHRT DORTHIN, WO MAN HERKAM (19.09.2026) Hier stand fest „‹ Zum Chat". Erreicht wird diese Seite aber auch von der STARTSEITE aus -- über den Hinweis „Bei dir klingelt nichts". Wer von dort kam, landete im Chat statt zurück, und das ist auf einer Hilfeseite die falscheste Richtung überhaupt. Jede andere Unterseite bekommt über kopf.js einen Zurück-Knopf, der wirklich zurückführt. Diese Seite lädt kopf.js bewusst nicht (sie soll auch dann noch stehen, wenn anderes klemmt) -- also hier dieselbe Rechnung in vier Zeilen: Gibt es einen Verlauf, geh zurück; sonst bleibt der Link auf die Startseite, wie er im HTML steht. ------------------------------------------------------------------- */ (function () { var weg = document.getElementById('zurueck-weg'); if (!weg || history.length <= 1) return; weg.addEventListener('click', function (e) { e.preventDefault(); history.back(); }); })();