File size: 2,137 Bytes
9b983fb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/* Usage-Analytics (anonym, non-blocking).
 * window.smTrack('cat:name') sammelt Events und schickt sie GEBUENDELT per
 * navigator.sendBeacon('/track', ...) -> feuern-und-vergessen, blockiert NIE den
 * Render-/Interaktionspfad. Es wird NICHTS Personenbezogenes gesendet (kein Name,
 * keine ID, keine IP). Server haelt nur anonyme Event->Count je UTC-Tag.
 * Erlaubte Kategorien (muessen zum Server passen):
 *   tab action stat lookup opt lb view sort filter gear info
 */
(function () {
  "use strict";
  var QUEUE = [];
  var timer = null;
  var FLUSH_MS = 4000;     // kurze Sammelphase, damit mehrere Klicks in EINEM Beacon landen
  var MAX_QUEUE = 40;      // bei Flut sofort flushen (deckt sich mit dem Server-Batch-Deckel)

  function send(list) {
    if (!list || !list.length) return;
    var body = JSON.stringify({ e: list });
    try {
      if (navigator.sendBeacon) {
        var blob = new Blob([body], { type: "application/json" });
        if (navigator.sendBeacon("/track", blob)) return;
      }
    } catch (e) {}
    // Fallback: keepalive-fetch (stoert den Hauptpfad nicht, ueberlebt unload)
    try {
      fetch("/track", {
        method: "POST", body: body, keepalive: true,
        headers: { "Content-Type": "application/json" }
      }).catch(function () {});
    } catch (e) {}
  }

  function flush() {
    if (timer) { clearTimeout(timer); timer = null; }
    if (!QUEUE.length) return;
    send(QUEUE.splice(0, QUEUE.length));
  }

  window.smTrack = function (ev) {
    try {
      if (typeof ev !== "string" || !ev) return;
      if (ev.length > 60) ev = ev.slice(0, 60);
      QUEUE.push(ev);
      if (QUEUE.length >= MAX_QUEUE) { flush(); return; }
      if (!timer) timer = setTimeout(flush, FLUSH_MS);
    } catch (e) {}
  };

  // Beim Verlassen/Verstecken alles rausschicken (sendBeacon ueberlebt unload)
  try {
    document.addEventListener("visibilitychange", function () {
      if (document.visibilityState === "hidden") flush();
    });
    window.addEventListener("pagehide", flush);
  } catch (e) {}

  // Erster Seitenaufruf
  try { window.smTrack("view:load"); } catch (e) {}
})();