PageSourceSearch

https://www.freelancermap.com/blog/wp-content/mu-plugins/footer-scripts/js/metrics.js?ver=1780475782

js freelancermap.com collected 2026-10-02 02:26:27 UTC 6,218 bytes, 245 lines download raw bytes

1/**
2 *  Trackt erst nach Zustimmung zu OneTrust-Kategorie C0002 – und stoppt bei Widerruf.
3 */
4(function () {
5  'use strict';
6
7  var CONSENT_GROUP = 'C0002';
8  var ENDPOINT      = '/api/click_trackings';
9
10  var active = false;
11
12  function hasConsent() {
13    return typeof window.OnetrustActiveGroups === 'string'
14        && window.OnetrustActiveGroups.includes(',' + CONSENT_GROUP + ',');
15  }
16
17  function checkConsent() {
18    if (hasConsent()) {
19      startTracking();
20    } else {
21      stopTracking();
22    }
23  }
24
25  function startTracking() {
26    if (active) return;
27    active = true;
28    window.addEventListener('mousedown', debounceHandleClickEvent);
29    window.addEventListener('keydown', debounceHandleKeyEvent);
30  }
31
32  function stopTracking() {
33    if (!active) return;
34    active = false;
35    window.removeEventListener('mousedown', debounceHandleClickEvent);
36    window.removeEventListener('keydown', debounceHandleKeyEvent);
37  }
38
39  function getElementFromLabel(element) {
40    if (element.control) {
41      return element.control;
42    }
43    var input = element.querySelector('input');
44    if (!input && element.parentElement) {
45      input = element.parentElement.querySelector('input');
46    }
47    if (input) {
48      return input;
49    }
50    return element;
51  }
52
53  function findElementOfInterest(element) {
54    if (!element || ['BODY'].includes(element.tagName)) {
55      return null;
56    }
57
58    var tagNames = ['A', 'BUTTON', 'INPUT', 'SUMMARY', 'SELECT'];
59
60    if (element.tagName === 'INPUT' &&
61        !['submit', 'checkbox', 'radio', 'range'].includes(element.type)) {
62      return null;
63    }
64
65    if (tagNames.includes(element.tagName)) {
66      return element;
67    }
68
69    var attributeNames = [
70      {name: 'role', value: 'button'},
71      {name: 'tabindex', value: '0'},
72      {name: 'data-toggle', value: 'dropdown'},
73      {name: 'data-toggle', value: 'modal'}
74    ];
75
76    for (var i = 0; i < attributeNames.length; i++) {
77      if (element.getAttribute('data-id')) {
78        return element;
79      }
80      if (element.getAttribute(attributeNames[i].name) === attributeNames[i].value) {
81        return element;
82      }
83    }
84
85    if (element.tagName === 'LABEL') {
86      return getElementFromLabel(element);
87    }
88
89    if (typeof element.onclick === 'function') {
90      return element;
91    }
92
93    var currentElement = element;
94    while (currentElement.parentElement) {
95      currentElement = currentElement.parentElement;
96      if (tagNames.includes(currentElement.tagName)) {
97        return currentElement;
98      }
99      for (var j = 0; j < attributeNames.length; j++) {
100        if (currentElement.getAttribute('data-id')) {
101          return currentElement;
102        }
103        if (currentElement.getAttribute(attributeNames[j].name) === attributeNames[j].value) {
104          return currentElement;
105        }
106        if (currentElement.tagName === 'LABEL') {
107          return getElementFromLabel(currentElement);
108        }
109      }
110    }
111  }
112
113  function getDataFromElement(element, withText) {
114    var elementData = {
115      element: {
116        tagName: element.tagName.toLowerCase()
117      }
118    };
119
120    if (element.attributes.length) {
121      elementData.element.attributes = [];
122    }
123
124    Array.from(element.attributes).forEach(function (attr) {
125      if (attr.name === 'data-id') {
126        elementData.element.trackingId = attr.nodeValue;
127      }
128      if (!elementData.element.attributes) {
129        elementData.element.attributes = [];
130      }
131      elementData.element.attributes.push({
132        name: attr.name,
133        value: attr.nodeValue
134      });
135    });
136
137    if (!withText) {
138      return elementData;
139    }
140
141    var text = element.tagName === 'I'
142      ? (element.parentElement.innerText || element.parentElement.textContent || '')
143      : (element.innerText || element.textContent || '');
144    if (text) {
145      elementData.element.text = text;
146    }
147
148    return elementData;
149  }
150
151  function getBrowserData() {
152    return {
153      path: window.location.pathname,
154      referrer: document.referrer,
155      screenWidth: window.screen.width
156    };
157  }
158
159  function getDataFromEvent(event, element) {
160    var parentElements = event.composedPath();
161    var isParentElement = false;
162
163    parentElements = parentElements.map(function (item) {
164      if (isParentElement && item.tagName && item.tagName !== 'BODY' && item.tagName !== 'HTML') {
165        return getDataFromElement(item).element;
166      }
167      if (item === element) {
168        isParentElement = true;
169      }
170      return '';
171    });
172
173    parentElements = parentElements.filter(function (item) { return item !== ''; });
174
175    return {
176      parentElements: parentElements.reverse()
177    };
178  }
179
180  function sendTrackingData(data) {
181    if (!data || Object.keys(data).length === 0) {
182      return;
183    }
184    var bodyData = JSON.stringify(data);
185    if (!bodyData || bodyData === '{}' || bodyData === '[]' || bodyData === '""' || bodyData === 'null') {
186      return;
187    }
188
189    fetch(ENDPOINT, {
190      method: 'POST',
191      headers: { 'Content-Type': 'application/json' },
192      body: bodyData,
193      keepalive: true,
194      credentials: 'include'
195    }).catch(function () { /* fire-and-forget */ });
196  }
197
198  function handleEvent(event) {
199    if (typeof window !== 'object') {
200      return;
201    }
202
203    var element = findElementOfInterest(event.target);
204    if (!element) {
205      return;
206    }
207
208    var data = Object.assign(
209      {},
210      getDataFromElement(element, true),
211      getBrowserData(),
212      getDataFromEvent(event, element),
213      { eventType: event.type }
214    );
215
216    sendTrackingData(data);
217  }
218
219  function debounce(func, timeout) {
220    if (timeout === undefined) timeout = 500;
221    var timer;
222    return function () {
223      var args = arguments;
224      if (!timer) {
225        func.apply(null, args);
226      }
227      clearTimeout(timer);
228      timer = setTimeout(function () { timer = undefined; }, timeout);
229    };
230  }
231
232  var debounceHandleClickEvent = debounce(function (event) {
233    handleEvent(event);
234  });
235
236  var debounceHandleKeyEvent = debounce(function (event) {
237    if (event.key === 'Enter') {
238      handleEvent(event);
239    }
240  });
241
242  checkConsent();  
243  window.addEventListener('OneTrustGroupsUpdated', checkConsent); 
244})();
245

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.