1(function () { 2 'use strict'; 3 4 var script = document.currentScript || (function () { 5 var scripts = document.getElementsByTagName('script'); 6 return scripts[scripts.length - 1]; 7 })(); 8 9 function attr(name, fallback) { 10 if (!script) { 11 return fallback; 12 } 13 var value = script.getAttribute(name); 14 return value === null ? fallback : value; 15 } 16 17 function defaultEndpoint() { 18 if (!script || !script.src) { 19 return 'page-view-counter-track.php'; 20 } 21 return script.src.replace(/page-view-counter-ajax\.js(?:\?.*)?$/, 'page-view-counter-track.php'); 22 } 23 24 function collectBrowserData() { 25 var data = {}; 26 27 if (typeof navigator.hardwareConcurrency !== 'undefined') { 28 data.hardwareConcurrency = navigator.hardwareConcurrency; 29 } 30 if (typeof navigator.language !== 'undefined') { 31 data.language = navigator.language; 32 } 33 if (typeof navigator.languages !== 'undefined') { 34 data.languages = Array.prototype.slice.call(navigator.languages, 0, 10); 35 } 36 if (typeof navigator.maxTouchPoints !== 'undefined') { 37 data.maxTouchPoints = navigator.maxTouchPoints; 38 } 39 if (typeof navigator.pdfViewerEnabled !== 'undefined') { 40 data.pdfViewerEnabled = navigator.pdfViewerEnabled; 41 } 42 if (typeof navigator.webdriver !== 'undefined') { 43 data.webdriver = navigator.webdriver; 44 } 45 if (typeof navigator.userAgent !== 'undefined') { 46 data.userAgent = navigator.userAgent; 47 } 48 49 return data; 50 } 51 52 function safeEndpoint(value, fallback) { 53 try { 54 var url = new URL(value, window.location.href); 55 var fallbackUrl = new URL(fallback, window.location.href); 56 57 // Keine externen Endpunkte erlauben. Sonst könnte ein manipuliertes HTML-Attribut 58 // die aktuelle URL und optionale Browserdaten an fremde Domains schicken. 59 if (url.origin !== window.location.origin) { 60 return fallbackUrl.href; 61 } 62 63 // Nur den vorgesehenen Tracking-Endpunkt akzeptieren. 64 if (!/\/page-view-counter-track\.php$/.test(url.pathname)) { 65 return fallbackUrl.href; 66 } 67 68 return url.href; 69 } catch (e) { 70 return fallback; 71 } 72 } 73 74 var fallbackEndpoint = defaultEndpoint(); 75 var endpoint = safeEndpoint(attr('data-pvc-endpoint', fallbackEndpoint), fallbackEndpoint); 76 var includeBrowserFields = attr('data-pvc-browser-fields', '0') === '1'; 77 78 // Debug-Ausgabe nur, wenn sie ausdrücklich aktiviert wurde. 79 // data-pvc-debug-target alleine reicht nicht mehr. 80 var jsDebugEnabled = attr('data-pvc-debug', '0') === '1'; 81 var debugTargetId = jsDebugEnabled ? attr('data-pvc-debug-target', '') : ''; 82 var debugTarget = debugTargetId ? document.getElementById(debugTargetId) : null; 83 84 var payload = { 85 url: window.location.href, 86 clientTs: Math.round(Date.now() / 1000) 87 }; 88 89 if (includeBrowserFields) { 90 payload.browser = collectBrowserData(); 91 } 92 93 var body = JSON.stringify(payload); 94 95 function showDebug(text) { 96 if (!debugTarget) { 97 return; 98 } 99 debugTarget.textContent = text; 100 } 101 102 function clearDebug() { 103 if (!debugTarget) { 104 return; 105 } 106 debugTarget.textContent = ''; 107 } 108 109 function buildDebugOutput(status, statusText, text) { 110 return ( 111 'HTTP-Status: ' + status + ' ' + (statusText || '') + '\n' + 112 'Endpoint: ' + endpoint + '\n' + 113 'Payload: ' + body + '\n\n' + 114 text 115 ); 116 } 117 118 function sendWithFetch() { 119 if (typeof fetch !== 'function') { 120 return false; 121 } 122 123 clearDebug(); 124 125 fetch(endpoint, { 126 method: 'POST', 127 headers: { 'Content-Type': 'application/json' }, 128 body: body, 129 credentials: 'same-origin', 130 keepalive: true 131 }).then(function (response) { 132 if (!debugTarget) { 133 return null; 134 } 135 136 return response.text().then(function (text) { 137 // Bei PHP-debug=false kommt normalerweise 204 No Content ohne Body zurück. 138 // Dann soll im Debug-Div gar nichts stehen, auch wenn das Div im HTML vorhanden ist. 139 if (!text) { 140 clearDebug(); 141 return; 142 } 143 144 showDebug(buildDebugOutput(response.status, response.statusText, text)); 145 }); 146 }).catch(function (error) {
147 // Netzwerkfehler nur anzeigen, wenn explizit ein Debug-Div vorhanden ist. 148 // Das passiert unabhängig vom PHP-Debug, weil bei Netzwerkfehlern keine PHP-Antwort kommt. 149 if (debugTarget) { 150 showDebug( 151 'Fehler beim Aufruf von: ' + endpoint + '\n' + 152 String(error && error.message ? error.message : error) + '\n\n' + 153 'Payload: ' + body 154 ); 155 } 156 }); 157 158 return true; 159 } 160 161 function sendWithXHR() { 162 var xhr = new XMLHttpRequest(); 163 xhr.open('POST', endpoint, true); 164 xhr.setRequestHeader('Content-Type', 'application/json'); 165 166 clearDebug(); 167 168 xhr.onreadystatechange = function () { 169 if (debugTarget && xhr.readyState === 4) { 170 if (!xhr.responseText) { 171 clearDebug(); 172 return; 173 } 174 175 showDebug(buildDebugOutput(xhr.status, xhr.statusText, xhr.responseText)); 176 } 177 }; 178 xhr.onerror = function () { 179 if (debugTarget) { 180 showDebug('Fehler beim XMLHttpRequest-Aufruf von: ' + endpoint + '\nPayload: ' + body); 181 } 182 }; 183 xhr.send(body); 184 } 185 186 if (!debugTarget && navigator.sendBeacon) { 187 var blob = new Blob([body], { type: 'application/json' }); 188 if (navigator.sendBeacon(endpoint, blob)) { 189 return; 190 } 191 } 192 193 if (!sendWithFetch()) { 194 sendWithXHR(); 195 } 196})();
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.