PageSourceSearch

https://www.934tel.de/js/doc-frame.js

js 934tel.de collected 2026-10-06 13:40:29 UTC 4,458 bytes, 91 lines download raw bytes

1'use strict';
2/**
3 * 934tel – DocFrame: eingefrorene Dokumente (PDF) SICHER in ein <iframe> laden.
4 *
5 * Warum es diesen Helfer gibt (Vorfall 2026-09-29, Rechnung F-000418 zeigte das PDF einer
6 * anderen Rechnung): Wird die `src` eines BESTEHENDEN iframes per Skript geändert, legt der
7 * Browser dafür einen eigenen Eintrag im Seitenverlauf an. „Zurück“ navigiert dann NUR das
8 * iframe auf das vorherige Dokument, während die Seite selbst beim aktuellen Beleg bleibt –
9 * Kopf, Positionen und Vorschau laufen auseinander. Auf Seiten ohne Hash-Routing
10 * (rechnungen.html) sind die iframe-Navigationen sogar die EINZIGEN Verlaufseinträge.
11 *
12 * Regeln, die dieser Helfer durchsetzt:
13 *  1. NIE `.src` auf einem vorhandenen iframe setzen. Je Dokument ein FRISCHES Element,
14 *     `src` VOR dem Einfügen → die Erst-Navigation ersetzt about:blank und erzeugt keinen
15 *     Verlaufseintrag (Chromium + Firefox verifiziert).
16 *  2. Jede Navigation des Rahmens, die nicht von uns stammt (Zurück/Vorwärts, Reload durch
17 *     den Browser), wird am `load`-Ereignis erkannt (URL des Rahmens ≠ erwartete URL oder
18 *     zweiter load ohne Auftrag) → Rahmen sofort neu aufbauen. Nach 3 Versuchen leer lassen
19 *     statt Falsches zu zeigen.
20 *  3. Kommt die Seite aus dem Back-Forward-Cache zurück (`pageshow`, persisted), werden alle
21 *     Rahmen neu aufgebaut.
22 *  4. `data-doc` am Rahmen trägt den Beleg-Schlüssel – Prüfbarkeit im DOM.
23 *
24 * API:  DocFrame.set(frameId, url, docKey)  → neues iframe-Element (oder null)
25 *       DocFrame.clear(frameId)             → leerer Rahmen (beim Verlassen der Detailansicht)
26 *       DocFrame.current(frameId)           → docKey des aktuell geladenen Dokuments
27 */
28(function () {
29  var STATE = {}; // frameId -> { url, key, loads, rebuilds }
30  var MAX_REBUILDS = 3;
31
32  function pathOf(href) {
33    try { var u = new URL(href, location.href); return u.pathname + u.search; } catch (e) { return null; }
34  }
35
36  function cloneShell(old, key) {
37    var f = document.createElement('iframe');
38    for (var i = 0; i < old.attributes.length; i++) {
39      var a = old.attributes[i];
40      if (a.name === 'src' || a.name === 'srcdoc' || a.name === 'data-doc') continue;
41      f.setAttribute(a.name, a.value);
42    }
43    if (key) f.setAttribute('data-doc', key); else f.removeAttribute('data-doc');
44    return f;
45  }
46
47  function onLoad(frameId, f, st) {
48    if (STATE[frameId] !== st || f !== document.getElementById(frameId)) return; // veraltet
49    st.loads++;
50    var actual = null;
51    try { actual = f.contentWindow.location.href; } catch (e) { actual = null; }
52    if (actual === 'about:blank') return; // Leer-Dokument, kein Inhalt
53    var ok = actual == null ? (st.loads === 1) : (pathOf(actual) === pathOf(st.url));
54    if (ok && st.loads === 1) return; // der eine erwartete load
55    // Fremdnavigation (Zurück/Vorwärts im Rahmen) oder unerwarteter Reload → neu aufbauen.
56    if (st.rebuilds >= MAX_REBUILDS) { blank(frameId, 'Dokument konnte nicht sicher angezeigt werden. Bitte Seite neu laden.'); return; }
57    var rebuilds = st.rebuilds + 1;
58    set(frameId, st.url, st.key, rebuilds);
59  }
60
61  function set(frameId, url, key, rebuilds) {
62    var old = document.getElementById(frameId); if (!old) return null;
63    key = key || url;
64    var st = { url: url, key: key, loads: 0, rebuilds: rebuilds || 0 };
65    STATE[frameId] = st;
66    var f = cloneShell(old, key);
67    f.addEventListener('load', function () { onLoad(frameId, f, st); });
68    f.src = url; // VOR dem Einfügen: Erst-Navigation = Ersetzen, kein Verlaufseintrag
69    old.parentNode.replaceChild(f, old);
70    return f;
71  }
72
73  function blank(frameId, message) {
74    var old = document.getElementById(frameId); if (!old) return null;
75    delete STATE[frameId];
76    var f = cloneShell(old, '');
77    if (message) f.setAttribute('srcdoc', '<!doctype html><p style="font-family:sans-serif;color:#b00020;padding:1rem;">' + String(message).replace(/[<>&]/g, '') + '</p>');
78    old.parentNode.replaceChild(f, old);
79    return f;
80  }
81
82  function clear(frameId) { return blank(frameId, ''); }
83  function current(frameId) { return STATE[frameId] ? STATE[frameId].key : null; }
84
85  window.addEventListener('pageshow', function (ev) {
86    if (!ev.persisted) return;
87    Object.keys(STATE).forEach(function (id) { var st = STATE[id]; set(id, st.url, st.key, 0); });
88  });
89
90  window.DocFrame = { set: set, clear: clear, current: current };
91})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.