PageSourceSearch

https://www.juwelierswebshop.nl/wp-content/plugins/jw-statistieken/assets/t.js?ver=1.1.3

js juwelierswebshop.nl collected 2026-10-09 00:29:02 UTC 17,256 bytes, 316 lines download raw bytes

1/* JW Statistieken: meting in de browser (cache-veilig). */
2(function () {
3    'use strict';
4    var C = window.jwstatCtx;
5    if (!C || !C.u || !window.FormData) { return; }
6
7    /* Consent: is er een consent-cookie ingesteld en is die er (nog) niet, dan NIET stoppen maar wachten.
8       Zodra de bezoeker accepteert (zonder herladen) meten we alsnog deze pagina, met de oorspronkelijke
9       verwijzer (Google e.d.). Voorheen stopte het script hier, waardoor de binnenkomstpagina ontbrak en
10       de sessie op pagina 2 begon als 'Direct'. */
11    function heeftConsent() { return !C.k || document.cookie.indexOf(C.k) !== -1; }
12    if (!heeftConsent()) {
13        var klaar = false, t0 = Date.now();
14        var probeer = function () {
15            if (klaar) { return; }
16            if (heeftConsent()) { klaar = true; clearInterval(iv); start(); }
17            else if (Date.now() - t0 > 30 * 60 * 1000) { klaar = true; clearInterval(iv); }
18        };
19        var iv = setInterval(probeer, 500);
20        ['click', 'keydown', 'touchend', 'visibilitychange'].forEach(function (ev) { document.addEventListener(ev, function () { setTimeout(probeer, 50); }, true); });
21        // Bekende CMP-events (Complianz, Cookiebot, CookieYes, Borlabs, Usercentrics) versnellen de start.
22        ['cmplz_status_change', 'cmplz_fire_categories', 'CookiebotOnAccept', 'cookieyes_consent_update', 'borlabs-cookie-consent-saved', 'ucEvent'].forEach(function (ev) {
23            window.addEventListener(ev, function () { setTimeout(probeer, 50); });
24            document.addEventListener(ev, function () { setTimeout(probeer, 50); });
25        });
26        return;
27    }
28    start();
29
30    function start() {
31    var NAAM = 'jwstat_vid';
32
33    // Cookie op het hoofddomein (ook geldig op www.), zie jwstat_cookie_domein().
34    var CD = C.cd && (location.hostname === C.cd || location.hostname.slice(-C.cd.length - 1) === '.' + C.cd) ? '; domain=' + C.cd : '';
35    function leesCookie(n) {
36        var re = new RegExp('(?:^|; )' + n + '=([a-f0-9]{32})', 'g'), m, alle = [];
37        while ((m = re.exec(document.cookie))) { alle.push(m[1]); }
38        return alle.length ? alle[alle.length - 1] : '';
39    }
40    function nieuwId() {
41        var a = new Uint8Array(16), s = '', i;
42        (window.crypto || window.msCrypto).getRandomValues(a);
43        for (i = 0; i < a.length; i++) { s += ('0' + a[i].toString(16)).slice(-2); }
44        return s;
45    }
46    /* Bezoeker-ID: cookie, met localStorage en sessionStorage als reserve. Sommige cookiemeldingen wissen
47       cookies die vóór of tijdens het accepteren zijn gezet; dan werd de volgende pagina een 'nieuwe bezoeker'. */
48    function opslag(soort) { try { var s = window[soort]; s.setItem('jwstat_t', '1'); s.removeItem('jwstat_t'); return s; } catch (e) { return null; } }
49    var LS = opslag('localStorage'), SS = opslag('sessionStorage');
50    function leesOpslag(s) { try { var v = s ? s.getItem(NAAM) : ''; return /^[a-f0-9]{32}$/.test(v || '') ? v : ''; } catch (e) { return ''; } }
51    var DEBUG = /[?&]jwstat_debug=1/.test(location.search) || (LS && LS.getItem('jwstat_debug') === '1');
52    if (DEBUG && LS) { LS.setItem('jwstat_debug', '1'); }
53    function log() { if (DEBUG && window.console) { console.info.apply(console, ['[jw-statistieken]'].concat([].slice.call(arguments))); } }
54
55    var vidBron = 'c';
56    var vid = leesCookie(NAAM);
57    if (!vid) { vid = leesOpslag(LS); vidBron = 'l'; }
58    if (!vid) { vid = leesOpslag(SS); vidBron = 's'; }
59    if (!vid) { vid = nieuwId(); vidBron = 'n'; }
60    function bewaarVid(v) {
61        vid = v;
62        // Elke paginaweergave de looptijd verlengen (= bewaartermijn). Oude cookie van alleen dit (sub)domein opruimen.
63        if (CD) { document.cookie = NAAM + '=; path=/; max-age=0'; }
64        document.cookie = NAAM + '=' + v + '; path=/; max-age=' + (C.d * 86400) + '; samesite=lax' + CD + (location.protocol === 'https:' ? '; secure' : '');
65        try { if (LS) { LS.setItem(NAAM, v); } if (SS) { SS.setItem(NAAM, v); } } catch (e) {}
66    }
67    bewaarVid(vid);
68    log('bezoeker', vid, { bron: { c: 'cookie', l: 'localStorage (cookie was weg)', s: 'sessionStorage (cookie was weg)', n: 'nieuw' }[vidBron], cookieNaGezet: !!leesCookie(NAAM), consent: C.k || '(geen)' });
69
70    /* Vorige pagina in dit tabblad: eigen 'verwijzer', want de browser stuurt soms alleen het domein mee. */
71    var VORIGE = 'jwstat_prev';
72    // Met categorie en groep: dan hoeft de server de vorige pagina niet zelf uit de URL te herleiden.
73    function leesVorige() { try { var x = JSON.parse((SS && SS.getItem(VORIGE)) || 'null'); return x && x.p && Date.now() - x.t < 1800000 ? x : null; } catch (e) { return null; } }
74    function zetVorige() { try { if (SS) { SS.setItem(VORIGE, JSON.stringify({ p: location.pathname, t: Date.now(), c: C.c || '', g: C.g || '' })); } } catch (e) {} }
75
76    var pv = 0, cid = '', zichtbaarSinds = document.visibilityState === 'visible' ? Date.now() : 0, actief = 0, maxScroll = 0;
77
78    function fd(data) {
79        var f = new FormData();
80        f.append('action', 'jwstat_h');
81        f.append('v', vid);
82        for (var k in data) { if (Object.prototype.hasOwnProperty.call(data, k)) { f.append(k, data[k]); } }
83        return f;
84    }
85    function beacon(data) {
86        var f = fd(data);
87        if (navigator.sendBeacon && navigator.sendBeacon(C.u, f)) { return; }
88        try { fetch(C.u, { method: 'POST', body: f, keepalive: true, credentials: 'same-origin' }); } catch (e) {}
89    }
90    // Kliks en tijd gaan direct mee met de code van deze weergave (cid); de server koppelt ze ook als
91    // het antwoord met het pageview-nummer nog niet binnen is (bv. klik vlak na binnenkomst).
92    function stuur(data) {
93        data.pv = pv || 0;
94        data.cid = cid;
95        beacon(data);
96    }
97
98    /* Weergave die nog niet bevestigd is, bewaren in sessionStorage. Lukt het versturen niet (bv. direct
99       doorgeklikt terwijl het verzoek nog liep), dan stuurt de volgende pagina hem alsnog, met de echte tijd. */
100    var OPEN = 'jwstat_open';
101    function leesOpen() { try { return JSON.parse(sessionStorage.getItem(OPEN) || 'null'); } catch (e) { return null; } }
102    function zetOpen(v) { try { if (v) { sessionStorage.setItem(OPEN, JSON.stringify(v)); } else { sessionStorage.removeItem(OPEN); } } catch (e) {} }
103
104    function verstuurPv(data, ago) {
105        var d = {}; for (var k in data) { d[k] = data[k]; }
106        d.t = 'pv'; d.ago = ago || 0;
107        // keepalive: het verzoek loopt door, ook als de bezoeker meteen doorklikt.
108        return fetch(C.u, { method: 'POST', credentials: 'same-origin', keepalive: true, body: fd(d) })
109            .then(function (r) { return r.json(); });
110    }
111
112    function nieuwCid() { return nieuwId().slice(0, 16); }
113
114    function paginaweergave() {
115        pv = 0;
116        cid = nieuwCid();
117        startHartslag(false);
118        var vorige = leesVorige();
119        var nu = {
120            cid: cid,
121            p: location.pathname, q: location.search, r: document.referrer || '',
122            ti: (document.title || '').slice(0, 250), c: C.c || '', g: C.g || '', id: C.p || 0, l: C.l || '',
123            w: (window.screen && screen.width) || 0, wd: navigator.webdriver ? 1 : 0,
124            pp: vorige ? vorige.p : '', pc: vorige ? (vorige.c || '') : '', pg: vorige ? (vorige.g || '') : '',
125            vb: vidBron, jv: C.v || '?'
126        };
127        zetVorige();
128        vidBron = 'c';
129        var oud = leesOpen();
130        zetOpen({ d: nu, ts: Date.now() });
131        var eerst = Promise.resolve();
132        if (oud && oud.d && oud.ts && Date.now() - oud.ts < 1800000) {
133            eerst = verstuurPv(oud.d, Date.now() - oud.ts).catch(function () {});
134        }
135        eerst.then(function () { return verstuurPv(nu, 0); }).then(function (d) {
136            if (d && d.pv) {
137                zetOpen(null);
138                pv = d.pv;
139                // De server herkende deze bezoeker aan zijn vorige pagina: oude ID terugzetten.
140                if (d.v && /^[a-f0-9]{32}$/.test(d.v) && d.v !== vid) { log('gekoppeld aan bestaande bezoeker', d.v); bewaarVid(d.v); }
141                log('paginaweergave', pv, d.s ? 'sessie ' + d.s : '');
142            }
143        }).catch(function () {});
144    }
145
146    /* Actieve tijd (tabblad zichtbaar) en scrolldiepte. */
147    function actieveTijd() {
148        return actief + (zichtbaarSinds ? Date.now() - zichtbaarSinds : 0);
149    }
150    function meetScroll() {
151        var h = Math.max(document.documentElement.scrollHeight, document.body ? document.body.scrollHeight : 0);
152        var p = h > 0 ? Math.round(Math.min(1, (window.scrollY + window.innerHeight) / h) * 100) : 0;
153        if (p > maxScroll) { maxScroll = p; }
154    }
155    var sT = false;
156    window.addEventListener('scroll', function () {
157        if (sT) { return; }
158        sT = true;
159        requestAnimationFrame(function () { sT = false; meetScroll(); });
160    }, { passive: true });
161    window.addEventListener('load', meetScroll);
162
163    /* lv = live-status: 1 tabblad zichtbaar, 2 op de achtergrond, 0 pagina verlaten. */
164    function engagement(lv) {
165        if (!cid) { return; }
166        meetScroll();
167        stuur({ t: 'pe', e: actieveTijd(), s: maxScroll, lv: lv });
168    }
169
170    /* Hartslag voor de Live-pagina: elke 30 s zolang het tabblad zichtbaar is. Na 15 min zonder
171       scrollen/klikken/typen stopt hij (tabblad laten openstaan is geen bezoek); bij de volgende actie
172       gaat hij direct weer door. Werkt tegelijk de actieve tijd bij. */
173    var HB = 30000, STIL = 15 * 60 * 1000, laatsteActie = Date.now(), hbT = null;
174    function hartslag() {
175        hbT = null;
176        if (document.visibilityState !== 'visible' || !cid) { return; }
177        if (Date.now() - laatsteActie > STIL) { return; }
178        engagement(1);
179        hbT = setTimeout(hartslag, HB);
180    }
181    function startHartslag(direct) {
182        if (hbT) { clearTimeout(hbT); hbT = null; }
183        if (direct) { hartslag(); } else { hbT = setTimeout(hartslag, HB); }
184    }
185    function stopHartslag() { if (hbT) { clearTimeout(hbT); hbT = null; } }
186    ['click', 'keydown', 'scroll', 'touchstart', 'mousemove'].forEach(function (ev) {
187        window.addEventListener(ev, function () {
188            laatsteActie = Date.now();
189            if (!hbT && cid && document.visibilityState === 'visible') { startHartslag(true); }
190        }, { passive: true, capture: true });
191    });
192
193    document.addEventListener('visibilitychange', function () {
194        if (document.visibilityState === 'hidden') {
195            if (zichtbaarSinds) { actief += Date.now() - zichtbaarSinds; zichtbaarSinds = 0; }
196            stopHartslag();
197            engagement(2);
198        } else {
199            if (!zichtbaarSinds) { zichtbaarSinds = Date.now(); }
200            laatsteActie = Date.now();
201            startHartslag(true);
202        }
203    });
204    window.addEventListener('pagehide', function () { stopHartslag(); engagement(0); });
205    // Terug via de knop van de browser (bfcache): telt als nieuwe weergave.
206    window.addEventListener('pageshow', function (e) {
207        if (e.persisted) { actief = 0; maxScroll = 0; zichtbaarSinds = Date.now(); laatsteActie = Date.now(); paginaweergave(); }
208    });
209
210    /* Klikgedrag. */
211    function blokVan(el) {
212        for (var n = el; n && n !== document.body; n = n.parentElement) {
213            if (!n.classList) { continue; }
214            for (var i = 0; i < n.classList.length; i++) {
215                var c = n.classList[i];
216                if (c.indexOf('dc-') === 0 && c.indexOf('__') === -1 && c !== 'dc-container' && c !== 'dc-small-container' && c !== 'dc-sec') { return c; }
217            }
218            if (n.tagName === 'SECTION' && n.id) { return '#' + n.id; }
219        }
220        return '';
221    }
222    function zoneVan(el) {
223        if (el.closest('[role=dialog], .dc-revmodal, .dc-mwmodal, .dc-vk-modal')) { return 'popup'; }
224        if (el.closest('header, #masthead, .site-header')) { return 'header'; }
225        if (el.closest('footer, #colophon, .site-footer')) { return 'footer'; }
226        if (el.closest('nav')) { return 'menu'; }
227        if (el.closest('aside')) { return 'zijbalk'; }
228        return 'inhoud';
229    }
230    document.addEventListener('click', function (e) {
231        var el = e.target && e.target.closest ? e.target.closest('a, button, [role=button], input[type=submit], summary, .swiper-button-next, .swiper-button-prev') : null;
232        if (!el) { return; }
233        var href = el.getAttribute('href') || '';
234        var k = 'knop';
235        // Interactie op de pagina zelf: uitklappen (accordeon/FAQ), tabs, sliderpijlen.
236        if (el.matches('.dc-faq__q, summary, [aria-expanded], [data-bs-toggle=collapse], .dc-toggle')) { k = 'uitklap'; }
237        else if (el.matches('.dc-dtabs__tab, [role=tab]')) { k = 'tab'; }
238        else if (el.matches('.swiper-button-next, .swiper-button-prev, [class*="-prev"], [class*="-next"]') && el.tagName !== 'A') { k = 'slider'; }
239        if (el.tagName === 'A') {
240            if (/^tel:/i.test(href)) { k = 'telefoon'; }
241            else if (/^mailto:/i.test(href)) { k = 'email'; }
242            else if (/wa\.me|whatsapp\.com|whatsapp:/i.test(href)) { k = 'whatsapp'; }
243            else if (/\.(pdf|docx?|xlsx?|zip)(\?|$)/i.test(href)) { k = 'download'; }
244            else if (el.host && el.host !== location.host) { k = 'extern'; }
245            else { k = 'link'; }
246        }
247        var label = (el.getAttribute('aria-label') || el.innerText || el.value || el.getAttribute('title') || '').replace(/\s+/g, ' ').trim().slice(0, 120);
248        if (k === 'link' && el.host === location.host) { href = el.pathname || href; }
249        stuur({ t: 'ev', k: k, lb: label, h: href.slice(0, 250), z: zoneVan(el), b: blokVan(el) });
250    }, true);
251
252    /* JavaScript-fouten van de eigen site (max. 5 per pagina, geen fouten van extensies of externe scripts). */
253    var fouten = 0, gezien = {};
254    function jsFout(msg, bron, regel, kol) {
255        if (fouten >= 5 || !msg) { return; }
256        if (bron && bron.indexOf(location.host) === -1 && !/^\//.test(bron)) { return; }
257        var f = (bron ? bron.replace(location.origin, '') : 'inline') + (regel ? ':' + regel + (kol ? ':' + kol : '') : '');
258        var k = msg + '|' + f;
259        if (gezien[k]) { return; }
260        gezien[k] = true; fouten++;
261        stuur({ t: 'er', m: String(msg).slice(0, 250), f: f.slice(0, 250) });
262    }
263    window.addEventListener('error', function (e) {
264        if (!e || !e.message || e.message === 'Script error.') { return; }
265        jsFout(e.message, e.filename || '', e.lineno, e.colno);
266    });
267    window.addEventListener('unhandledrejection', function (e) {
268        var r = e && e.reason;
269        jsFout('Promise: ' + (r && r.message ? r.message : String(r)), (r && r.stack && (r.stack.match(/https?:\/\/[^\s)]+/) || [''])[0]) || '', 0, 0);
270    });
271
272    /* CF7 houdt een formulier met fouten soms al in de browser tegen (veldcontrole), dan ziet de server niets.
273       Na een verstuurpoging: staat het formulier nog op 'init' met foutmeldingen, dan die velden + meldingen
274       doorgeven (nooit de ingevulde waarden). Keurt de server het af, dan registreert de server het zelf. */
275    var cfLaatst = {};
276    function cf7Poging(form) {
277        if (!form || !form.classList || !form.classList.contains('wpcf7-form')) { return; }
278        var idEl = form.querySelector('input[name="_wpcf7"]');
279        var fid = idEl ? idEl.value : '';
280        if (cfLaatst[fid] && Date.now() - cfLaatst[fid] < 1500) { return; }
281        cfLaatst[fid] = Date.now();
282        setTimeout(function () {
283            var status = form.getAttribute('data-status') || '';
284            if (status !== 'init') { return; }
285            var velden = [];
286            form.querySelectorAll('.wpcf7-not-valid-tip').forEach(function (tip) {
287                var w = tip.closest('[data-name]');
288                velden.push({ veld: w ? w.getAttribute('data-name') : '', melding: (tip.textContent || '').trim().slice(0, 190) });
289            });
290            if (!velden.length) { return; }
291            stuur({ t: 'cf', fid: fid, vf: JSON.stringify(velden.slice(0, 20)) });
292        }, 1200);
293    }
294    // Ook bij indrukken (mousedown/touchstart): als CF7 bij het verlaten van een veld een foutmelding toont,
295    // schuift de knop weg en valt de klik ernaast. De poging telt dan wel.
296    ['mousedown', 'touchstart', 'click'].forEach(function (ev) {
297        document.addEventListener(ev, function (e) {
298            var btn = e.target && e.target.closest ? e.target.closest('input[type=submit], button[type=submit]') : null;
299            if (btn && btn.form) { cf7Poging(btn.form); }
300        }, true);
301    });
302    document.addEventListener('submit', function (e) { cf7Poging(e.target); }, true);
303
304    /* Voorgeladen pagina (prerender door Chrome of speculation rules): pas meten als de bezoeker hem echt
305       opent. Anders telt een pagina mee die nooit bekeken is (Direct, 0 s actief). */
306    if (document.prerendering) {
307        document.addEventListener('prerenderingchange', function () {
308            zichtbaarSinds = document.visibilityState === 'visible' ? Date.now() : 0;
309            laatsteActie = Date.now();
310            paginaweergave();
311        }, { once: true });
312    } else {
313        paginaweergave();
314    }
315    }
316})();

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.