PageSourceSearch

https://kentuckylake.com/wp-content/plugins/klo-network-tracking/assets/js/klo-network-tracking.js?ver=1.1.0

js kentuckylake.com collected 2026-10-02 13:34:26 UTC 8,908 bytes, 228 lines download raw bytes

1(function () {
2    'use strict';
3
4    var config = window.KLOTrackingConfig || {};
5    if (!config.relayUrl) return;
6
7    var observed = new WeakSet();
8    var pageSeen = new Set();
9    var impressionTimers = new WeakMap();
10    var storageKey = 'klo_tracking_visitor_v1';
11    var detailKey = 'klo_tracking_detail_source_v1';
12
13    function visitorToken() {
14        try {
15            var existing = window.localStorage.getItem(storageKey);
16            if (existing) return existing;
17            var token = '';
18            if (window.crypto && typeof window.crypto.randomUUID === 'function') {
19                token = window.crypto.randomUUID().replace(/-/g, '');
20            } else if (window.crypto && window.crypto.getRandomValues) {
21                var bytes = new Uint8Array(16);
22                window.crypto.getRandomValues(bytes);
23                token = Array.prototype.map.call(bytes, function (value) {
24                    return value.toString(16).padStart(2, '0');
25                }).join('');
26            } else {
27                token = String(Date.now()) + Math.random().toString(36).slice(2);
28            }
29            window.localStorage.setItem(storageKey, token);
30            return token;
31        } catch (error) {
32            return '';
33        }
34    }
35
36    function pageContext() {
37        return window.location.pathname || '/';
38    }
39
40    function validId(value) {
41        var id = Number(value);
42        return Number.isInteger(id) && id > 0 ? id : 0;
43    }
44
45    function send(eventType, entityId, placement) {
46        entityId = validId(entityId);
47        if (!entityId || !eventType || !placement) return;
48
49        var payload = JSON.stringify({
50            entity_id: entityId,
51            event_type: eventType,
52            placement: placement,
53            page_context: pageContext(),
54            visitor_token: visitorToken()
55        });
56
57        if (navigator.sendBeacon) {
58            try {
59                var blob = new Blob([payload], { type: 'application/json' });
60                if (navigator.sendBeacon(config.relayUrl, blob)) return;
61            } catch (error) {}
62        }
63
64        window.fetch(config.relayUrl, {
65            method: 'POST',
66            headers: { 'Content-Type': 'application/json' },
67            credentials: 'same-origin',
68            keepalive: true,
69            body: payload
70        }).catch(function () {});
71    }
72
73    window.KLOTracking = window.KLOTracking || {};
74    window.KLOTracking.track = function (eventType, entityId, placement) {
75        send(eventType, entityId, placement || 'more_info');
76    };
77
78    function elementPlacement(element, fallback) {
79        if (!element) return fallback || '';
80        if (element.dataset && element.dataset.kloTrackPlacement) return element.dataset.kloTrackPlacement;
81        var parent = element.closest ? element.closest('[data-klo-track-placement]') : null;
82        return parent ? (parent.dataset.kloTrackPlacement || fallback || '') : (fallback || '');
83    }
84
85    function elementEntityId(element) {
86        if (!element) return 0;
87        if (element.dataset && element.dataset.kloTrackEntityId) return validId(element.dataset.kloTrackEntityId);
88        if (element.dataset && element.dataset.entityId) return validId(element.dataset.entityId);
89        var parent = element.closest ? element.closest('[data-entity-id]') : null;
90        return parent ? validId(parent.dataset.entityId) : 0;
91    }
92
93    function impressionKey(entityId, placement) {
94        return String(entityId) + '|' + String(placement);
95    }
96
97    function observeElement(element) {
98        if (!element || observed.has(element)) return;
99        observed.add(element);
100        observer.observe(element);
101    }
102
103    var observer = new IntersectionObserver(function (entries) {
104        entries.forEach(function (entry) {
105            var element = entry.target;
106            var placement = element.dataset.kloTrackImpression || elementPlacement(element, '');
107            var entityId = elementEntityId(element);
108            var key = impressionKey(entityId, placement);
109
110            if (!entityId || !placement || pageSeen.has(key)) {
111                observer.unobserve(element);
112                return;
113            }
114
115            if (entry.isIntersecting && entry.intersectionRatio >= Number(config.observerRatio || 0.25)) {
116                if (impressionTimers.has(element)) return;
117                impressionTimers.set(element, window.setTimeout(function () {
118                    impressionTimers.delete(element);
119                    if (pageSeen.has(key)) return;
120                    pageSeen.add(key);
121                    send('impression', entityId, placement);
122                    observer.unobserve(element);
123                }, Number(config.observerDelay || 500)));
124            } else if (impressionTimers.has(element)) {
125                window.clearTimeout(impressionTimers.get(element));
126                impressionTimers.delete(element);
127            }
128        });
129    }, { threshold: [0, Number(config.observerRatio || 0.25), 0.5, 1] });
130
131    function scan(root) {
132        var scope = root && root.querySelectorAll ? root : document;
133        scope.querySelectorAll('[data-klo-track-impression][data-entity-id]').forEach(observeElement);
134        if (scope.matches && scope.matches('[data-klo-track-impression][data-entity-id]')) observeElement(scope);
135    }
136
137    function rememberDetailSource(link) {
138        var entityId = elementEntityId(link);
139        var placement = elementPlacement(link, '');
140        if (!entityId || !placement) return;
141        try {
142            window.sessionStorage.setItem(detailKey, JSON.stringify({
143                entityId: entityId,
144                placement: placement,
145                at: Date.now()
146            }));
147        } catch (error) {}
148    }
149
150    function detailView() {
151        var detail = document.querySelector('.klo-entity-detail[data-entity-id]');
152        if (!detail) return;
153        var entityId = validId(detail.dataset.entityId);
154        var placement = 'more_info';
155
156        try {
157            var pending = JSON.parse(window.sessionStorage.getItem(detailKey) || 'null');
158            if (pending && Number(pending.entityId) === entityId && Date.now() - Number(pending.at || 0) < 120000) {
159                placement = pending.placement || placement;
160            }
161            window.sessionStorage.removeItem(detailKey);
162        } catch (error) {}
163
164        send('detail_view', entityId, placement);
165    }
166
167    function addUtm(link, entityId, placement) {
168        try {
169            var url = new URL(link.href, window.location.href);
170            url.searchParams.set('utm_source', config.utmSource || 'kentuckylake.com');
171            url.searchParams.set('utm_medium', config.utmMedium || 'referral');
172            url.searchParams.set('utm_campaign', config.utmCampaign || 'expmg_partner');
173            url.searchParams.set('utm_content', 'entity_' + entityId + '_' + placement);
174            link.href = url.toString();
175        } catch (error) {}
176    }
177
178    document.addEventListener('click', function (event) {
179        var detailLink = event.target.closest('[data-klo-track-detail-link]');
180        if (detailLink) rememberDetailSource(detailLink);
181
182        var tracked = event.target.closest('[data-klo-track-event]');
183        if (!tracked) return;
184
185        var eventType = tracked.dataset.kloTrackEvent || '';
186        var entityId = elementEntityId(tracked);
187        var placement = elementPlacement(tracked, 'more_info');
188        if (!entityId || !eventType || !placement) return;
189
190        if (eventType === 'website_click') addUtm(tracked, entityId, placement);
191        send(eventType, entityId, placement);
192    }, true);
193
194    document.addEventListener('klo:planner:entity-added', function (event) {
195        var detail = event.detail || {};
196        send('planner_add', detail.entityId, detail.placement || 'more_info');
197    });
198
199    document.addEventListener('klo:tracking:map-impression', function (event) {
200        var detail = event.detail || {};
201        var entityId = validId(detail.entityId);
202        var key = impressionKey(entityId, 'map');
203        if (!entityId || pageSeen.has(key)) return;
204        pageSeen.add(key);
205        send('impression', entityId, 'map');
206    });
207
208    function initTracking() {
209        scan(document);
210        detailView();
211
212        if (!document.body) return;
213        var mutationObserver = new MutationObserver(function (mutations) {
214            mutations.forEach(function (mutation) {
215                mutation.addedNodes.forEach(function (node) {
216                    if (node.nodeType === 1) scan(node);
217                });
218            });
219        });
220        mutationObserver.observe(document.body, { childList: true, subtree: true });
221    }
222
223    if (document.readyState === 'loading') {
224        document.addEventListener('DOMContentLoaded', initTracking, { once: true });
225    } else {
226        initTracking();
227    }
228})();

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.