PageSourceSearch

https://www.jugendbudget.ch/wp-content/themes/jugendbudget/assets/js/guide-tracking.js?ver=1.01

js jugendbudget.ch collected 2026-10-05 09:54:37 UTC 4,793 bytes, 153 lines download raw bytes

1(function () {
2  'use strict';
3
4  var DEBUG = !!(window.guideTrackingConfig && window.guideTrackingConfig.debug);
5  var TAG = '[GuideTracking]';
6
7  function log() {
8    if (!DEBUG) return;
9    var args = Array.prototype.slice.call(arguments);
10    args.unshift(TAG);
11    console.log.apply(console, args);
12  }
13
14  function warn() {
15    if (!DEBUG) return;
16    var args = Array.prototype.slice.call(arguments);
17    args.unshift(TAG);
18    console.warn.apply(console, args);
19  }
20
21  // One entry per detected guide: { id, name, pdf, signupBlock, thanksBlock, signupFired }
22  var guides = [];
23
24  function slugify(str) {
25    return (str || '')
26      .toLowerCase()
27      .normalize('NFKD').replace(/[\u0300-\u036f]/g, '') // strip accents
28      .replace(/[^a-z0-9]+/g, '_')
29      .replace(/^_+|_+$/g, '');
30  }
31
32  function pdfFallbackId(href) {
33    var file = (href || '').split('/').pop() || '';
34    return slugify(file.replace(/\.[a-z0-9]+$/i, ''));
35  }
36
37  function isVisible(el) {
38    return !!(el && (el.offsetWidth || el.offsetHeight || el.getClientRects().length));
39  }
40
41  function push(eventName, guide) {
42    window.dataLayer = window.dataLayer || [];
43    window.dataLayer.push({ event: eventName, guide_id: guide.id, guide_name: guide.name });
44  }
45
46  // Build the guide registry from every signup block on the page.
47  function discoverGuides() {
48    guides = [];
49    var signupBlocks = document.querySelectorAll('.newsletter-form-holder');
50
51    var seenIds = {};
52
53    signupBlocks.forEach(function (signupBlock, index) {
54      // The thanks block normally lives inside the signup holder (next to
55      // .form-content); fall back to a following sibling for other layouts.
56      var thanksBlock = signupBlock.querySelector('.thanks');
57      if (!thanksBlock) {
58        thanksBlock = signupBlock.nextElementSibling;
59        while (thanksBlock && !thanksBlock.classList.contains('thanks')) {
60          thanksBlock = thanksBlock.nextElementSibling;
61        }
62      }
63      if (!thanksBlock) {
64        warn('signup block #' + index + ': no matching .thanks block found (inside or as sibling), skipping', signupBlock);
65        return;
66      }
67
68      var link = thanksBlock.querySelector('a.wp-block-button__link[href]');
69      if (!link) {
70        warn('signup block #' + index + ': .thanks block has no download link, skipping', thanksBlock);
71        return;
72      }
73
74      var pdf = link.getAttribute('href');
75      var heading = signupBlock.querySelector('h3');
76      var name = heading ? heading.textContent.trim() : pdf;
77      var id = heading ? slugify(name) : pdfFallbackId(pdf);
78      if (!id) id = pdfFallbackId(pdf);
79
80      if (seenIds[id]) {
81        warn('duplicate guide_id "' + id + '" detected (guide: "' + name + '") — events may merge with an earlier guide. Consider a more distinct heading.');
82      }
83      seenIds[id] = true;
84
85      guides.push({
86        id: id,
87        name: name,
88        pdf: pdf,
89        signupBlock: signupBlock,
90        thanksBlock: thanksBlock,
91        signupFired: false
92      });
93
94      log('form detected — guide_id:', id, '| guide_name:', name, '| guide_pdf:', pdf);
95    });
96  }
97
98  // Re-resolve each guide's thanks block by its stable PDF href, in case
99  // inline scripts / blocks get relocated at runtime by the site's JS
100  // optimization layer.
101  function findThanksBlockByPdf(pdf) {
102    var link = document.querySelector('.thanks a.wp-block-button__link[href="' + pdf + '"]');
103    return link ? link.closest('.thanks') : null;
104  }
105
106  function checkSignups() {
107    guides.forEach(function (guide) {
108      if (guide.signupFired) return;
109      var thanksBlock = findThanksBlockByPdf(guide.pdf) || guide.thanksBlock;
110      if (isVisible(thanksBlock)) {
111        guide.signupFired = true;
112        push('guide_signup', guide);
113      }
114    });
115  }
116
117  function init() {
118    discoverGuides();
119
120    if (!guides.length) {
121      warn('no guides detected on this page — tracking inactive');
122      return;
123    }
124
125    checkSignups();
126
127    new MutationObserver(checkSignups).observe(document.body, {
128      childList: true,
129      subtree: true,
130      attributes: true,
131      attributeFilter: ['style', 'class']
132    });
133
134    document.addEventListener('click', function (e) {
135      var link = e.target.closest('.thanks a.wp-block-button__link[href]');
136      if (!link) return;
137      var pdf = link.getAttribute('href');
138      var guide = guides.filter(function (g) { return g.pdf === pdf; })[0];
139      if (!guide) {
140        warn('download click on unrecognized link, no matching guide:', pdf);
141        return;
142      }
143      log('download click detected for guide:', guide.id);
144      push('guide_download', guide);
145    });
146  }
147
148  if (document.readyState === 'loading') {
149    document.addEventListener('DOMContentLoaded', init);
150  } else {
151    init();
152  }
153})();

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.