1// Consent class 2const serviceConfigs = JSON.parse(JSON.stringify(allServiceSettings)); 3 4// Function to retrieve a cookie by its name 5function getCookie(name) { 6 var nameEQ = name + "="; 7 var ca = document.cookie.split(';'); 8 for (var i = 0; i < ca.length; i++) { 9 var c = ca[i]; 10 while (c.charAt(0) == ' ') c = c.substring(1); 11 if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length); 12 } 13 return null; 14} 15 16// Function to set a cookie with a specified name, value, and expiration date 17function setCookie(name, value, daysToExpire) { 18 var expires = ""; 19 if (daysToExpire) { 20 var date = new Date(); 21 date.setTime(date.getTime() + (daysToExpire * 24 * 60 * 60 * 1000)); 22 expires = "; expires=" + date.toUTCString(); 23 } 24 document.cookie = name + "=" + (value || "") + expires + "; path=/"; 25} 26 27// Function to evaluate the final consent value based on service settings 28function evaluateFinalValue(serviceSettings, settingKey) { 29 let hasGranted = false; 30 let hasDenied = false; 31 32 // Iterate through all services and check their consent settings 33 serviceSettings.forEach(settings => { 34 if (settings[settingKey] === 'granted') 35 if (settings[settingKey] === 'granted') hasGranted = true; 36 else if (settings[settingKey] === 'denied') hasDenied = true; 37 }); 38 39 // If there is at least one "denied" value, return "denied" 40 if (hasDenied) return 'denied'; 41 42 // If there is only one "granted" value, return "granted" 43 if (hasGranted) return 'granted'; 44 45 // If all values are "not set" or there are no explicit "granted"/"denied" values, return "denied" 46 return 'denied'; 47} 48 49// Function to update the cookie with the final consent values 50function updateCookieWithFinalConsent(name, daysToExpire, services) { 51 const cookieValue = getCookie(name); 52 if (cookieValue !== null) { 53 const obj = JSON.parse(decodeURIComponent(cookieValue)); 54 55 // Evaluate and set the final values for each consent setting 56 ['ad_storage','analytics_storage','ad_user_data','ad_personalization', 57 'personalization_storage','functionality_storage','security_storage'] 58 .forEach(key => { 59 obj[key] = evaluateFinalValue(services, key); 60 }); 61 62 setCookie(name, encodeURIComponent(JSON.stringify(obj)), daysToExpire); 63 pushTriggerAfterConsentChanged(obj); 64 } else { 65 console.log("Cookie name '" + name + "' does not exist."); 66 } 67} 68 69// Function to push the trigger for gtm after consent changed 70function pushTriggerAfterConsentChanged(changes) { 71 window.dataLayer = window.dataLayer || []; 72 window.dataLayer.push({ 73 event: 'cmp_we_cookie_consent_changed', // Custom-Event-Name 74 we_consent_state: { // Add all final states 75 ad_storage : changes.ad_storage, 76 analytics_storage : changes.analytics_storage, 77 ad_user_data : changes.ad_user_data, 78 ad_personalization : changes.ad_personalization, 79 personalization_storage: changes.personalization_storage, 80 functionality_storage : changes.functionality_storage, 81 security_storage : changes.security_storage 82 } 83 }); 84} 85 86// Debug function to log all stored service settings 87function getAllServiceSettings() { 88 // Log all service settings to the console 89 console.log(allServiceSettings); 90 // Optionally return allServiceSettings; 91 // return allServiceSettings; 92} 93 94// main controller 95let ConsentApp = new function ConsentController() { 96 // public functions 97 /** 98 * Callback function for GoogleTagManager Script to handle consent state changes and fire the dataLayer trigger 99 * @param bool state 100 * @param object service 101 */ 102 this.consentChanged = function(state, service) { 103 // Check if the service is related to Google Tag Manager 104 const isGTM = service.name.indexOf('google-tagmanager-service') !== -1; 105 if (isGTM) { 106 // A) Remap all services - only the service that has just been changed receives either its config values (if state=true) or "denied" all-over. 107 allServiceSettings = allServiceSettings.map(tempSettings => { 108 if (tempSettings.serviceId !== service.name) { 109 // Unmodified copy 110 return { 111 serviceId: tempSettings.serviceId, 112 serviceConsent: tempSettings.serviceConsent, 113 ad_storage: tempSettings.ad_storage, 114 analytics_storage: tempSettings.analytics_storage, 115 ad_user_data: tempSettings.ad_user_data, 116 ad_personalization: tempSettings.ad_personalization, 117 functionality_storage: tempSettings.functionality_storage, 118 personalization_storage: tempSettings.personalization_storage, 119 security_storage: tempSettings.security_storage 120 }; 121 } 122 123 // Get the original config 124 const originalConfig = serviceConfigs.find(original => original.serviceId === tempSettings.serviceId); 125 const updated = { serviceId: tempSettings.serviceId, serviceConsent: state }; 126 127 // For every consent type 128 ['ad_storage','analytics_storage','ad_user_data','ad_personalization', 129 'personalization_storage','functionality_storage','security_storage'] 130 .forEach(key => { 131 // if consent is granted: accept from config 132 // if consent is denied: always 'denied' 133 updated[key] = state ? originalConfig[key] : 'denied'; 134 }); 135 136 return updated; 137 }); 138 139 // B) Evaluate only the granted services 140 // Filter allServiceSettings to include only services with serviceConsent = true 141 // Update cookie 142 const relevantServices = allServiceSettings.filter(relevant => relevant.serviceConsent); 143 updateCookieWithFinalConsent(storageName, cookieExpiresAfterDays, relevantServices); 144 145 // C) dataLayer-Push based on the state 146 window.dataLayer = window.dataLayer || []; 147 window.dataLayer.push({ 148 event: service.gtm.trigger, 149 [service.gtm.variable]: state 150 }); 151 } 152 153 // D) Check if the own callback function is allready defined 154 if (service.ownCallback) { 155 if (typeof window[service.ownCallback] === 'function') { 156 window[service.ownCallback](state, service); 157 } else { 158 console.error('The Callback function ' + service.ownCallback + ' is not yet defined. Please create it first.'); 159 } 160 } 161 }; 162 163 // constructor (modal and safari) 164 (function contruct() { 165 document.addEventListener('DOMContentLoaded', function () { 166 // Listener for the button on the privacy page, to edit the consent 167 document.addEventListener('click', function (event) { 168 if (event.target.closest('.js-showConsentModal')) { 169 event.preventDefault(); 170 klaro.show(); 171 } 172 }); 173 }); 174 })(); 175 176 const isSafari = navigator.vendor && 177 navigator.vendor.indexOf('Apple') > -1 && 178 navigator.userAgent && 179 navigator.userAgent.indexOf('CriOS') == -1 && 180 navigator.userAgent.indexOf('FxiOS') == -1; 181 182 document.addEventListener('DOMContentLoaded', function() { 183 setTimeout(function() { 184 if (isSafari!==true) { 185 document.getElementById('klaro').classList.remove('safari'); 186 } else { 187 document.getElementById('klaro').classList.add('safari'); 188 } 189 }) 190 }); 191}; 192// End main controller 193 194var optOutLink = document.getElementById("ga-opt-out"); 195 196if(optOutLink) { 197 optOutLink.onclick = function() { 198 document.cookie = 'ga-opt-out=true; expires=Thu, 31 Dec 2099 23:59:59 UTC; path=/'; 199 this.innerHTML = "Google Analytics opt-out successful"; 200 return false;
201 } 202} 203 204// Functions after window.load(): 205window.addEventListener('load', function () { 206 const iframes = document.querySelectorAll('iframe'); 207 208 if (iframes.length > 0) { 209 iframes.forEach(function (iframe) { 210 let attrDataSrc = iframe.getAttribute('src'); 211 if (!attrDataSrc) { 212 attrDataSrc = iframe.getAttribute('data-src'); 213 } 214 215 if (attrDataSrc && (attrDataSrc.includes('youtube') || attrDataSrc.includes('vimeo'))) { 216 // Adjust measures for videoOverlay similar to iframe: 217 const parent = iframe.parentElement; 218 const contextNotice = parent.querySelector('.klaro.cm-as-context-notice'); 219 220 if (contextNotice) { 221 iframe.style.display = 'block'; 222 223 // Set the width of .klaro.cm-as-context-notice to the iframe's width 224 contextNotice.style.width = iframe.offsetWidth + 'px'; 225 226 if (iframe.offsetHeight < contextNotice.offsetHeight) { 227 const cmButtons = contextNotice.querySelector('.cm-buttons'); 228 if (cmButtons) { 229 cmButtons.style.marginTop = '1em'; 230 } 231 } 232 } 233 } 234 }); 235 } 236 237 // Add class for small context-notice box: if video integration within small iframes (width < 300px) 238 document.querySelectorAll('.klaro.we_cookie_consent.cm-as-context-notice').forEach(function(element) { 239 if (element.offsetWidth <= 300) { 240 element.classList.add('notice--minified'); 241 } 242 }); 243 244 // Add class to avoid Google to crawl consent info text 245 document.querySelectorAll('.klaro.we_cookie_consent .cn-body').forEach(function(element) { 246 element.setAttribute('data-nosnippet', 'data-nosnippet'); 247 }); 248});
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.