1 2console.log("TYPO3 LOVE ðº"); 3document.addEventListener("DOMContentLoaded", function () { 4 5 /** 6 * 7 * Accordion Header 8 */ 9 10 function createAccordion(id,header,content,on=false) { 11 if (!header || !content) return; 12 // Bootstrap-Klassen setzen 13 content.classList.add("collapse"); 14 if(on) { 15 content.classList.add("show"); 16 }else{ 17 header.classList.add("collapsed"); 18 } 19 content.id = "collapse-" + id; 20 21 // Toggle-Attribute für Bootstrap hinzufügen 22 header.setAttribute("data-bs-toggle", "collapse"); 23 header.setAttribute("data-bs-target", "#collapse-" + id); 24 header.style.cursor = "pointer"; // Optional für UX 25 } 26 27 document.querySelectorAll( 28 ".frame-type-menu_card_list.frame-layout-accordion, .frame-type-menu_card_list.frame-layout-accordion-on" 29 ).forEach((item) => { 30 const id = item.id; 31 const header = item.querySelector(".frame-header"); 32 const content = item.querySelector(".card-carousel"); 33 34 const isOpen = item.classList.contains("frame-layout-accordion-on"); 35 createAccordion(id, header, content, isOpen); 36 }); 37 38 document.querySelectorAll( 39 ".frame-type-card_group.frame-layout-accordion, .frame-type-card_group.frame-layout-accordion-on" 40 ).forEach((item) => { 41 const id = item.id; 42 const header = item.querySelector(".frame-header"); 43 const content = item.querySelector(".card-group-element"); 44 45 const isOpen = item.classList.contains("frame-layout-accordion-on"); 46 createAccordion(id, header, content, isOpen); 47 }); 48 49 50 51 52 53}); 54 55 56// Consent class 57const serviceConfigs = JSON.parse(JSON.stringify(allServiceSettings)); 58 59// Function to retrieve a cookie by its name 60function getCookie(name) { 61 var nameEQ = name + "="; 62 var ca = document.cookie.split(';'); 63 for (var i = 0; i < ca.length; i++) { 64 var c = ca[i]; 65 while (c.charAt(0) == ' ') c = c.substring(1); 66 if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length); 67 } 68 return null; 69} 70 71// Function to set a cookie with a specified name, value, and expiration date 72function setCookie(name, value, daysToExpire) { 73 var expires = ""; 74 if (daysToExpire) { 75 var date = new Date(); 76 date.setTime(date.getTime() + (daysToExpire * 24 * 60 * 60 * 1000)); 77 expires = "; expires=" + date.toUTCString(); 78 } 79 document.cookie = name + "=" + (value || "") + expires + "; path=/"; 80} 81 82// Function to evaluate the final consent value based on service settings 83function evaluateFinalValue(serviceSettings, settingKey) { 84 let hasGranted = false; 85 let hasDenied = false; 86 87 // Iterate through all services and check their consent settings 88 serviceSettings.forEach(settings => { 89 if (settings[settingKey] === 'granted') 90 if (settings[settingKey] === 'granted') hasGranted = true; 91 else if (settings[settingKey] === 'denied') hasDenied = true; 92 }); 93 94 // If there is at least one "denied" value, return "denied" 95 if (hasDenied) return 'denied'; 96 97 // If there is only one "granted" value, return "granted" 98 if (hasGranted) return 'granted'; 99 100 // If all values are "not set" or there are no explicit "granted"/"denied" values, return "denied" 101 return 'denied'; 102} 103 104// Function to update the cookie with the final consent values 105function updateCookieWithFinalConsent(name, daysToExpire, services) { 106 const cookieValue = getCookie(name); 107 if (cookieValue !== null) { 108 const obj = JSON.parse(decodeURIComponent(cookieValue)); 109 110 // Evaluate and set the final values for each consent setting 111 ['ad_storage','analytics_storage','ad_user_data','ad_personalization', 112 'personalization_storage','functionality_storage','security_storage'] 113 .forEach(key => { 114 obj[key] = evaluateFinalValue(services, key); 115 }); 116 117 setCookie(name, encodeURIComponent(JSON.stringify(obj)), daysToExpire); 118 pushTriggerAfterConsentChanged(obj); 119 } else { 120 console.log("Cookie name '" + name + "' does not exist."); 121 } 122} 123 124// Function to push the trigger for gtm after consent changed 125function pushTriggerAfterConsentChanged(changes) { 126 window.dataLayer = window.dataLayer || []; 127 window.dataLayer.push({ 128 event: 'cmp_we_cookie_consent_changed', // Custom-Event-Name 129 we_consent_state: { // Add all final states 130 ad_storage : changes.ad_storage, 131 analytics_storage : changes.analytics_storage, 132 ad_user_data : changes.ad_user_data, 133 ad_personalization : changes.ad_personalization, 134 personalization_storage: changes.personalization_storage, 135 functionality_storage : changes.functionality_storage, 136 security_storage : changes.security_storage 137 } 138 }); 139} 140 141// Debug function to log all stored service settings 142function getAllServiceSettings() { 143 // Log all service settings to the console 144 console.log(allServiceSettings); 145 // Optionally return allServiceSettings; 146 // return allServiceSettings; 147} 148 149// main controller 150let ConsentApp = new function ConsentController() { 151 // public functions 152 /** 153 * Callback function for GoogleTagManager Script to handle consent state changes and fire the dataLayer trigger 154 * @param bool state 155 * @param object service 156 */ 157 this.consentChanged = function(state, service) { 158 // Check if the service is related to Google Tag Manager 159 const isGTM = service.name.indexOf('google-tagmanager-service') !== -1; 160 if (isGTM) { 161 // A) Remap all services - only the service that has just been changed receives either its config values (if state=true) or "denied" all-over. 162 allServiceSettings = allServiceSettings.map(tempSettings => { 163 if (tempSettings.serviceId !== service.name) { 164 // Unmodified copy 165 return { 166 serviceId: tempSettings.serviceId, 167 serviceConsent: tempSettings.serviceConsent, 168 ad_storage: tempSettings.ad_storage, 169 analytics_storage: tempSettings.analytics_storage, 170 ad_user_data: tempSettings.ad_user_data, 171 ad_personalization: tempSettings.ad_personalization, 172 functionality_storage: tempSettings.functionality_storage, 173 personalization_storage: tempSettings.personalization_storage, 174 security_storage: tempSettings.security_storage 175 }; 176 } 177 178 // Get the original config 179 const originalConfig = serviceConfigs.find(original => original.serviceId === tempSettings.serviceId); 180 const updated = { serviceId: tempSettings.serviceId, serviceConsent: state }; 181 182 // For every consent type 183 ['ad_storage','analytics_storage','ad_user_data','ad_personalization', 184 'personalization_storage','functionality_storage','security_storage'] 185 .forEach(key => { 186 // if consent is granted: accept from config 187 // if consent is denied: always 'denied' 188 updated[key] = state ? originalConfig[key] : 'denied'; 189 }); 190 191 return updated; 192 }); 193 194 // B) Evaluate only the granted services 195 // Filter allServiceSettings to include only services with serviceConsent = true 196 // Update cookie 197 const relevantServices = allServiceSettings.filter(relevant => relevant.serviceConsent); 198 updateCookieWithFinalConsent(storageName, cookieExpiresAfterDays, relevantServices); 199 200 // C) dataLayer-Push based on the state 201 window.dataLayer = window.dataLayer || []; 202 window.dataLayer.push({ 203 event: service.gtm.trigger, 204 [service.gtm.variable]: state 205 }); 206 } 207 208 // D) Check if the own callback function is allready defined 209 if (service.ownCallback) { 210 if (typeof window[service.ownCallback] === 'function') { 211 window[service.ownCallback](state, service); 212 } else { 213 console.error('The Callback function ' + service.ownCallback + ' is not yet defined. Please create it first.'); 214 } 215 } 216 }; 217 218 // constructor (modal and safari) 219 (function contruct() { 220 document.addEventListener('DOMContentLoaded', function () { 221 // Listener for the button on the privacy page, to edit the consent 222 document.addEventListener('click', function (event) { 223 if (event.target.closest('.js-showConsentModal')) { 224 event.preventDefault(); 225 klaro.show(); 226 } 227 }); 228 }); 229 })(); 230 231 const isSafari = navigator.vendor && 232 navigator.vendor.indexOf('Apple') > -1 && 233 navigator.userAgent && 234 navigator.userAgent.indexOf('CriOS') == -1 && 235 navigator.userAgent.indexOf('FxiOS') == -1; 236 237 document.addEventListener('DOMContentLoaded', function() { 238 setTimeout(function() { 239 240 setServiceSuccessVarBtn(); 241 242 document.addEventListener('click', function (event) { 243 if (event.target.matches('.cn-decline')) { 244 setServiceSuccessVarBtn(); 245 } 246 }); 247 248 document.addEventListener('click', function (event) {
249 if (event.target.matches('.cm-btn-accept')) { 250 setServiceSuccessVarBtn(); 251 } 252 }); 253 254 document.addEventListener('click', function (event) { 255 if (event.target.matches('.cm-btn-decline')) { 256 setServiceSuccessVarBtn(); 257 } 258 }); 259 260 if (isSafari!==true) { 261 document.getElementById('klaro').classList.remove('safari'); 262 } else { 263 document.getElementById('klaro').classList.add('safari'); 264 } 265 }) 266 }); 267}; 268// End main controller 269 270var optOutLink = document.getElementById("ga-opt-out"); 271 272if(optOutLink) { 273 optOutLink.onclick = function() { 274 document.cookie = 'ga-opt-out=true; expires=Thu, 31 Dec 2099 23:59:59 UTC; path=/'; 275 this.innerHTML = "Google Analytics opt-out successful"; 276 return false; 277 } 278} 279 280// Functions after window.load(): 281window.addEventListener('load', function () { 282 const iframes = document.querySelectorAll('iframe'); 283 284 if (iframes.length > 0) { 285 iframes.forEach(function (iframe) { 286 let attrDataSrc = iframe.getAttribute('src'); 287 if (!attrDataSrc) { 288 attrDataSrc = iframe.getAttribute('data-src'); 289 } 290 291 if (attrDataSrc && (attrDataSrc.includes('youtube') || attrDataSrc.includes('vimeo'))) { 292 // Adjust measures for videoOverlay similar to iframe: 293 const parent = iframe.parentElement; 294 const contextNotice = parent.querySelector('.klaro.cm-as-context-notice'); 295 296 if (contextNotice) { 297 iframe.style.display = 'block'; 298 299 // Set the width of .klaro.cm-as-context-notice to the iframe's width 300 contextNotice.style.width = iframe.offsetWidth + 'px'; 301 302 if (iframe.offsetHeight < contextNotice.offsetHeight) { 303 const cmButtons = contextNotice.querySelector('.cm-buttons'); 304 if (cmButtons) { 305 cmButtons.style.marginTop = '1em'; 306 } 307 } 308 } 309 } 310 }); 311 } 312 313 // Add class for small context-notice box: if video integration within small iframes (width < 300px) 314 document.querySelectorAll('.klaro.we_cookie_consent.cm-as-context-notice').forEach(function(element) { 315 if (element.offsetWidth <= 300) { 316 element.classList.add('notice--minified'); 317 } 318 }); 319 320 // Add class to avoid Google to crawl consent info text 321 document.querySelectorAll('.klaro.we_cookie_consent .cn-body').forEach(function(element) { 322 element.setAttribute('data-nosnippet', 'data-nosnippet'); 323 }); 324}); 325 326// Workaround: Show "Always" Button for overlay (for example youtube videos) only when the klaro cookie is set 327function setServiceSuccessVarBtn() 328{ 329 const klaroCookie = getCookie('klaro'); 330 331 if (klaroCookie) { 332 const allServiceSuccessVarBtn = document.querySelectorAll('.cm-btn-success-var'); 333 if (allServiceSuccessVarBtn.length > 0) {
334 allServiceSuccessVarBtn.forEach((serviceSuccessVarBtn) => { 335 serviceSuccessVarBtn.style.setProperty('display', 'block', 'important'); 336 } 337 ) 338 } 339 } 340} 341 342document.addEventListener('DOMContentLoaded', function () { 343 344 if (checkCookieExists('klaro')) { 345 createTooltip(); 346 } 347 348 setTimeout(function () { 349 const klaroDiv = document.getElementById('klaro'); 350 const buttons = klaroDiv.querySelectorAll('button'); 351 352 function handleClick(event) { 353 createTooltip(); 354 if (document.querySelector('#klaro .cookie-notice') == null && document.querySelector('#klaro .cookie-modal') == null) { 355 } 356 } 357 358 buttons.forEach(button => { 359 button.addEventListener('click', handleClick); 360 }); 361 }); 362 363 setTimeout(function () { 364 if (document.querySelector('.cm-link')) { 365 document.querySelector('.cm-link').addEventListener('click', function () { 366 if (document.querySelector('.cm-btn-success')) { 367 document.querySelector('.cm-btn-success').addEventListener('click', function () { 368 createTooltip(); 369 }); 370 } 371 372 if (document.querySelector('.cn-decline')) { 373 document.querySelector('.cn-decline').addEventListener('click', function () { 374 createTooltip(); 375 }); 376 } 377 378 if (document.querySelector('.cm-btn-accept-all')) { 379 document.querySelector('.cm-btn-accept-all').addEventListener('click', function () { 380 createTooltip(); 381 }); 382 } 383 }); 384 } 385 }, 1000); 386}); 387 388function checkCookieExists(cookieName) { 389 let cookies = document.cookie.split(';'); 390 391 for (let i = 0; i < cookies.length; i++) { 392 let cookie = cookies[i]; 393 // Remove leading spaces (if any) 394 while (cookie.charAt(0) == ' ') { 395 cookie = cookie.substring(1); 396 } 397 // Check if the cookie name matches 398 if (cookie.indexOf(cookieName + '=') == 0) { 399 return true; 400 } 401 } 402 return false; 403} 404 405function createTooltip() { 406 if (cookieIconPermanentlyAvailable === '1') { 407 let iconTooltip = document.createElement('div'); 408 let iconImgTag = document.createElement('img'); 409 let iconBtn = document.createElement('button'); 410 let iconContainer = document.createElement('div'); 411 412 // Button 413 iconBtn.type = 'button'; 414 iconBtn.className = 'consent-trigger js-showConsentModal'; 415 iconBtn.setAttribute('aria-label', translatedButtonTextCookieSettings); 416 iconBtn.setAttribute('aria-haspopup', 'dialog'); 417 418 // Image 419 iconImgTag.src = cookieSettingsImgPathDefault; 420 iconImgTag.alt = ''; 421 iconImgTag.setAttribute('aria-hidden', 'true'); 422 iconImgTag.width = 85; iconImgTag.height = 85; 423 iconImgTag.style.cssText = 'margin-right:0px;width:85px;height:85px;'; 424 425 // Hover/Fokus (Image & Tooltip) 426 function showTip(){ iconTooltip.style.display = 'block'; iconImgTag.src = cookieSettingsImgPathHover; } 427 function hideTip(){ iconTooltip.style.display = 'none'; iconImgTag.src = cookieSettingsImgPathDefault; } 428 429 iconBtn.addEventListener('mouseover', showTip); 430 iconBtn.addEventListener('mouseout', hideTip); 431 iconBtn.addEventListener('focusin', showTip); 432 iconBtn.addEventListener('focusout', hideTip); 433 434 // Tooltip 435 iconTooltip.textContent = translatedButtonTextCookieSettings; 436 iconTooltip.classList.add('consent-cookie-text'); 437 iconTooltip.style.cssText = 'display:none;'; 438 // (optional ARIA) 439 // tooltip.id = 'consent-tooltip'; 440 // tooltip.setAttribute('role', 'tooltip'); 441 // btn.setAttribute('aria-describedby', 'consent-tooltip'); 442 443 // Container 444 iconContainer.classList.add('consent-cookie'); 445 iconContainer.style.cssText = 'display:flex;'; 446 447 // DOM 448 iconBtn.appendChild(iconImgTag); 449 iconContainer.appendChild(iconBtn); 450 iconContainer.appendChild(iconTooltip); 451 document.body.appendChild(iconContainer); 452 } 453}
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.