PageSourceSearch

https://www.schwedentor.de/templates/yoo_sun/js/stt-consent-gating.js?v=20260806

js schwedentor.de collected 2026-10-02 12:51:42 UTC 8,871 bytes, 248 lines download raw bytes

1/**
2 * stt-consent-gating.js — Consent-Gating für schwedentor.de
3 * Lädt GA4, Facebook-Plugin und Embeds erst nach Einwilligung:
4 * CMP (TCF, Purpose 1) ODER 2-Klick-Platzhalter je Inhalt.
5 * Seit 2026-08-06 zusaetzlich: Google Consent Mode v2. Die Signale
6 * ad_storage / ad_user_data / ad_personalization / analytics_storage
7 * starten auf 'denied' und werden aus den TCF-Zwecken abgeleitet.
8 * Ohne diese Kommandos hat gtag ad_personalization als nicht erteilt
9 * behandelt und npa=1 gesendet (Befund 2026-08-06).
10 * Doku: WORK_Schwedentor\consent-gating\README_Consent-Gating.md
11 * Stand: 2026-08-06 (Sven)
12 */
13(function () {
14  'use strict';
15
16  var CFG = window.sttConsentConfig || {};
17  var GA4_IDS = CFG.ga4 || [];
18  var LS_PREFIX = 'sttConsent_';
19  var tcfUnlocked = false;
20
21  function onReady(fn) {
22    if (document.readyState !== 'loading') { fn(); }
23    else { document.addEventListener('DOMContentLoaded', fn); }
24  }
25  function remember(service) {
26    try { localStorage.setItem(LS_PREFIX + service, '1'); } catch (e) {}
27  }
28  function remembered(service) {
29    try { return localStorage.getItem(LS_PREFIX + service) === '1'; } catch (e) { return false; }
30  }
31
32  function injectStyles() {
33    var css =
34      '.stt-embed-ph{border:1px solid #d5e2ee;border-radius:8px;background:#f4f7fa;' +
35      'padding:18px 16px;text-align:center;font-family:inherit;color:#33404a}' +
36      '.stt-embed-ph p{margin:0 0 10px;font-size:.9em;line-height:1.45}' +
37      '.stt-embed-ph button{background:#005293;color:#fff;border:0;border-radius:5px;' +
38      'padding:8px 18px;font-size:.95em;cursor:pointer}' +
39      '.stt-embed-ph button:hover{background:#003e70}' +
40      '.stt-embed-ph label{display:block;margin-top:8px;font-size:.8em;color:#667}' +
41      '.stt-embed-16x9{position:relative;width:100%;padding-top:56.25%}' +
42      '.stt-embed-16x9 iframe{position:absolute;top:0;left:0;width:100%;height:100%;border:0}';
43    var s = document.createElement('style');
44    s.textContent = css;
45    document.head.appendChild(s);
46  }
47
48  /* ---------- Google Consent Mode v2 ---------- */
49
50  function ensureGtag() {
51    window.dataLayer = window.dataLayer || [];
52    window.gtag = window.gtag || function () { window.dataLayer.push(arguments); };
53  }
54
55  var defaultsSet = false;
56  function setConsentDefaults() {
57    if (defaultsSet) { return; }
58    defaultsSet = true;
59    ensureGtag();
60    window.gtag('consent', 'default', {
61      ad_storage: 'denied',
62      ad_user_data: 'denied',
63      ad_personalization: 'denied',
64      analytics_storage: 'denied',
65      wait_for_update: 500
66    });
67  }
68
69  /* TCF-Zwecke -> Consent-Mode-Signale.
70     GVL-Vendor 755 = Google Advertising Products.
71     Zweck 1 = Speichern/Zugriff Endgeraet, 3 = personalisiertes Anzeigenprofil,
72     4 = personalisierte Anzeigen auswaehlen, 7 = Anzeigenleistung messen. */
73  function deriveConsent(tcData) {
74    if (tcData.gdprApplies === false) {
75      return { ad_storage: 'granted', ad_user_data: 'granted',
76               ad_personalization: 'granted', analytics_storage: 'granted' };
77    }
78    var p = (tcData.purpose && tcData.purpose.consents) || {};
79    var v = (tcData.vendor && tcData.vendor.consents) || {};
80    var google = v[755] === true;
81    var store = p[1] === true;
82    function g(ok) { return ok ? 'granted' : 'denied'; }
83    return {
84      ad_storage: g(store && google),
85      ad_user_data: g(store && p[7] === true && google),
86      ad_personalization: g(p[3] === true && p[4] === true && google),
87      analytics_storage: g(store)
88    };
89  }
90
91  var lastConsent = '';
92  function applyConsent(tcData) {
93    var state = deriveConsent(tcData);
94    var sig = state.ad_storage + state.ad_user_data +
95              state.ad_personalization + state.analytics_storage;
96    if (sig === lastConsent) { return; }
97    lastConsent = sig;
98    ensureGtag();
99    window.gtag('consent', 'update', state);
100  }
101
102  var gaLoaded = false;
103  function loadGA4() {
104    if (gaLoaded || !GA4_IDS.length) { return; }
105    gaLoaded = true;
106    ensureGtag();
107    window.gtag('js', new Date());
108    for (var i = 0; i < GA4_IDS.length; i++) {
109      window.gtag('config', GA4_IDS[i], { anonymize_ip: true });
110    }
111    var s = document.createElement('script');
112    s.async = true;
113    s.src = 'https://www.googletagmanager.com/gtag/js?id=' + encodeURIComponent(GA4_IDS[0]);
114    document.head.appendChild(s);
115  }
116
117  var fbLoaded = false;
118  function loadFbSdk(cb) {
119    if (fbLoaded) { cb(); return; }
120    fbLoaded = true;
121    if (!document.getElementById('fb-root')) {
122      var r = document.createElement('div');
123      r.id = 'fb-root';
124      document.body.appendChild(r);
125    }
126    var s = document.createElement('script');
127    s.async = true; s.defer = true; s.crossOrigin = 'anonymous';
128    s.src = 'https://connect.facebook.net/de_DE/sdk.js#xfbml=1&version=v19.0';
129    s.onload = cb;
130    document.head.appendChild(s);
131  }
132
133  function renderEmbed(el) {
134    var type = el.getAttribute('data-stt-type') || 'iframe';
135    var src = el.getAttribute('data-stt-src') || '';
136    el.innerHTML = '';
137
138    if (type === 'iframe') {
139      var ratio = el.getAttribute('data-stt-ratio');
140      var ifr = document.createElement('iframe');
141      ifr.src = src;
142      ifr.setAttribute('allowfullscreen', '');
143      ifr.setAttribute('loading', 'lazy');
144      ifr.setAttribute('referrerpolicy', 'no-referrer-when-downgrade');
145      if (ratio === '16x9') {
146        var wrap = document.createElement('div');
147        wrap.className = 'stt-embed-16x9';
148        wrap.appendChild(ifr);
149        el.appendChild(wrap);
150      } else {
151        ifr.width = el.getAttribute('data-stt-width') || '100%';
152        ifr.height = el.getAttribute('data-stt-height') || '300';
153        ifr.style.border = '0';
154        el.appendChild(ifr);
155      }
156    } else if (type === 'script') {
157      var sc = document.createElement('script');
158      sc.src = src;
159      sc.async = true;
160      el.appendChild(sc);
161    } else if (type === 'fbpage') {
162      var href = el.getAttribute('data-stt-href') || '';
163      var fb = document.createElement('div');
164      fb.className = 'fb-page';
165      fb.setAttribute('data-href', href);
166      fb.setAttribute('data-width', el.getAttribute('data-stt-width') || '340');
167      fb.setAttribute('data-small-header', 'true');
168      fb.setAttribute('data-hide-cover', 'true');
169      el.appendChild(fb);
170      loadFbSdk(function () {
171        if (window.FB && window.FB.XFBML) { window.FB.XFBML.parse(el); }
172      });
173    }
174    el.setAttribute('data-stt-loaded', '1');
175  }
176
177  function renderPlaceholder(el) {
178    if (el.getAttribute('data-stt-ph')) { return; }
179    el.setAttribute('data-stt-ph', '1');
180    var service = el.getAttribute('data-stt-service') || 'einem externen Anbieter';
181    var ph = document.createElement('div');
182    ph.className = 'stt-embed-ph';
183    var p = document.createElement('p');
184    p.textContent = 'Externer Inhalt von ' + service + '. Beim Laden werden Daten ' +
185      '(u. a. Ihre IP-Adresse) an den Anbieter übertragen. Details: Datenschutzerklärung.';
186    var btn = document.createElement('button');
187    btn.type = 'button';
188    btn.textContent = 'Inhalt laden';
189    var lbl = document.createElement('label');
190    var chk = document.createElement('input');
191    chk.type = 'checkbox';
192    lbl.appendChild(chk);
193    lbl.appendChild(document.createTextNode(' Inhalte von ' + service + ' immer laden'));
194    btn.addEventListener('click', function () {
195      if (chk.checked) { remember(service); }
196      renderEmbed(el);
197    });
198    ph.appendChild(p);
199    ph.appendChild(btn);
200    ph.appendChild(lbl);
201    el.innerHTML = '';
202    el.appendChild(ph);
203  }
204
205  function processEmbeds() {
206    var list = document.querySelectorAll('.stt-embed:not([data-stt-loaded])');
207    for (var i = 0; i < list.length; i++) {
208      var el = list[i];
209      var service = el.getAttribute('data-stt-service') || '';
210      if (tcfUnlocked || remembered(service)) { renderEmbed(el); }
211      else { renderPlaceholder(el); }
212    }
213  }
214
215  function unlockAll() {
216    tcfUnlocked = true;
217    loadGA4();
218    processEmbeds();
219  }
220
221  function bindTcf() {
222    if (typeof window.__tcfapi !== 'function') { return false; }
223    window.__tcfapi('addEventListener', 2, function (tcData, ok) {
224      if (!ok || !tcData) { return; }
225      if (tcData.eventStatus === 'tcloaded' || tcData.eventStatus === 'useractioncomplete') {
226        applyConsent(tcData);
227        if (tcData.gdprApplies === false) { unlockAll(); return; }
228        var p = tcData.purpose && tcData.purpose.consents;
229        if (p && p[1]) { unlockAll(); }
230      }
231    });
232    return true;
233  }
234
235  setConsentDefaults();
236
237  onReady(function () {
238    injectStyles();
239    processEmbeds();
240    if (!bindTcf()) {
241      var tries = 0;
242      var t = setInterval(function () {
243        tries++;
244        if (bindTcf() || tries >= 20) { clearInterval(t); }
245      }, 500);
246    }
247  });
248})();

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.