1 2// The cookies should bewrapped in an object if more tracking gets added, currently we only enable or disable. 3 4// GA4 measurement id of this site. It comes from the site's VFI_SITES entry ("ga4") and is 5// put on this script tag by index.html.twig; with no id nothing is sent to Google Analytics. 6const gaTarget = (document.currentScript && document.currentScript.dataset.ga4Id) || ''; 7 8// A GTM container on the page (its snippet has already pushed "gtm.start") loads gtag.js by itself 9// for the "config" command below; loading it here as well downloaded the same 175 KB twice. 10const gtmOnPage = (window.dataLayer || []).some((entry) => entry && entry['gtm.start']); 11 12if (gaTarget && !gtmOnPage) { 13 const s = document.createElement('script'); 14 s.async = true; 15 s.src = 'https://www.googletagmanager.com/gtag/js?id=' + gaTarget; 16 document.head.appendChild(s); 17} 18 19window.dataLayer = window.dataLayer || []; 20function gtag() { dataLayer.push(arguments); } 21gtag('js', new Date()); 22 23if (gaTarget) { 24 gtag('config', gaTarget, { 25 'ad_storage': 'denied' 26 }); 27} 28 29function setCookies(val /* boolean */) { 30 if (!gaTarget) { 31 return; 32 } 33 if (val) { 34 gtag('config', gaTarget, { 35 'analytics_storage': 'permitted', 36 'anonymize_ip': false 37 }); 38 } else { 39 gtag('config', gaTarget, { 40 'ad_storage': 'denied', 41 'analytics_storage': 'denied', 42 'anonymize_ip': true 43 }); 44 } 45} 46 47// Policy panel links 48const links = [ 49 { 50 href: '/privacy-policy', 51 text: 'Go to Privacy & Policy' 52 }, 53 { 54 href: '/cookies-and-analytics', 55 text: 'Go to Cookies & Analytics' 56 } 57]; 58 59document.addEventListener('DOMContentLoaded', (event) => { 60 // Initial cookie card 61 var initCookieCard = document.querySelector('.init-cookie-card'); 62 var acceptCookiesBtn = document.querySelector('.accept-cookies'); 63 var neccesaryBtn = document.querySelector('.accept-necessary-cookies'); 64 65 // Settings button
66 var settingsBtn = document.querySelectorAll('.cookie-settings-btn'); 67 68 // Settings overlay, card and elements 69 var cookieSettings = document.querySelector('.cookie-settings-overlay'); 70 var exitBtn = document.querySelector('.cookie-settings-exit-btn'); 71 72 // Navigation buttons 73 var aboutPanelBtn = document.querySelector('.about-panel-btn'); 74 var settingsPanelBtn = document.querySelector('.settings-panel-btn'); 75 var policyPanelBtn = document.querySelector('.privacy-panel-btn'); 76 77 // Panels 78 var aboutPanelDesktop = document.querySelector('.cookie-about-panel-desktop'); 79 // var aboutPanelMobile = document.querySelector('.cookie-about-panel-mobile'); 80 var settingsPanel = document.getElementsByClassName('cookie-settings-panel'); 81 var policyPanel = document.getElementsByClassName('cookie-policy-panel'); 82 83 [].forEach.call(settingsPanel, panel => { 84 85 // Container for wrapping Title and seettings buttons 86 let topContainer = document.createElement('div'); 87 topContainer.classList.add('settings-content-container') 88 89 let title = document.createElement('h1'); 90 title.classList.add('title'); 91 title.innerHTML = 'Settings'; 92 title.appendChild(document.createElement('hr')); 93 topContainer.appendChild(title); 94 95 // Create a container for each toggle switch 96 let checkBoxContainer = document.createElement('div'); 97 checkBoxContainer.classList.add('accept-cookie-container'); 98 99 // Toggle button 100 let checkBox = document.createElement('button'); 101 checkBox.classList.add('accept-cookie-toggle'); 102 103 // Toggle slider 104 let slider = document.createElement('div'); 105 slider.classList.add('slider'); 106 checkBox.appendChild(slider); 107 let text = document.createElement('div'); 108 text.innerHTML = 'Allow third party cookies'; 109 110 checkBoxContainer.appendChild(text); 111 checkBoxContainer.appendChild(checkBox); 112 topContainer.appendChild(checkBoxContainer); 113 114 panel.appendChild(topContainer); 115 116 // Contianer for buttons in settings panel 117 let btnContainer = document.createElement('div'); 118 btnContainer.classList.add('btn-container'); 119 120 // Accept all button 121 let acceptAll = document.createElement('button'); 122 acceptAll.classList.add('accept-all-cookies'); 123 acceptAll.classList.add('btn'); 124 acceptAll.innerHTML = 'Accept all'; 125 126 btnContainer.appendChild(acceptAll); 127 128 // Settings settings button 129 let save = document.createElement('button'); 130 save.classList.add('save-cookie-settings'); 131 save.classList.add('btn'); 132 save.innerHTML = 'Save changes'; 133 134 btnContainer.appendChild(save); 135 136 panel.appendChild(btnContainer); 137 }); 138 139 // Add links to policy panel 140 [].forEach.call(policyPanel, panel => { 141 142 let linkContainer = document.createElement('div'); 143 linkContainer.classList.add('link-container'); 144 145 links.forEach(link => { 146 let a = document.createElement('a'); 147 a.href = link.href; 148 a.target = '_blank'; 149 a.innerHTML = link.text; 150 151 linkContainer.appendChild(a); 152 }); 153 154 panel.appendChild(linkContainer); 155 }); 156 157 158 // Could've stored the checkboxes/toggle-buttons in an array when initalizing them, but this works too. 159 var accpetCheckbox = document.getElementsByClassName('accept-cookie-toggle'); 160 161 // 162 var saveChanges = document.getElementsByClassName('save-cookie-settings'); 163 var acceptAllSettings = document.getElementsByClassName('accept-all-cookies'); 164 165 // Settings change flag
166 let changes = false; 167 168 // Add state for each cookie (currently only Google Analytics) 169 // Could wrap it in a cookie state object 170 let checkState = false; 171 172 // Helper functions for the floating button 173 const btnDisplay = () => { 174 // Displays the floating button 175 settingsBtn.forEach((elm) => { 176 elm.classList.contains('active') ? 177 elm.classList.remove('active') : 178 elm.classList.add('active'); 179 }) 180 } 181 182 const settingsDisplay = () => { 183 // Displays the settings popup 184 cookieSettings.classList.contains('active') ? 185 cookieSettings.classList.remove('active') : 186 cookieSettings.classList.add('active'); 187 } 188 189 // Resetting settings popup when closing 190 const settingsInitReset = () => { 191 [].forEach.call(saveChanges, btn => { 192 btn.classList.remove('changes'); 193 }); 194 195 policyPanelBtn.classList.remove('selected'); 196 197 settingsPanelBtn.classList.remove('selected'); 198 199 aboutPanelBtn.classList.add('selected'); 200 201 // Mobile 202 policyPanelBtn.classList.remove('mobile-selected'); 203 settingsPanelBtn.classList.remove('mobile-selected'); 204 } 205 206 // Checks the state of the users cookies, if not set it will open an initial popup that only gets shown once 207 if (!(localStorage.getItem("cookies") === null)) { 208 btnDisplay(); 209 initCookieCard.classList.remove('active'); 210 211 checkState = (localStorage.getItem("cookies") == 'true'); 212 setCookies(checkState); 213 214 [].forEach.call(accpetCheckbox, btn => { 215 checkState ? btn.classList.add('toggled') : btn.classList.remove('toggled'); 216 }); 217 } else { 218 initCookieCard.classList.add('active'); 219 setCookies(checkState); 220 } 221 222 // Accepts all cookies (Init popup) 223 acceptCookiesBtn.addEventListener("click", (e) => { 224 localStorage.setItem('cookies', true); 225 226 [].forEach.call(accpetCheckbox, btn => { 227 btn.classList.add('toggled'); 228 }); 229 230 checkState = true; 231 232 setCookies(checkState); 233 234 initCookieCard.remove(); 235 btnDisplay(); 236 }); 237 238 // Only accept necessary (Init popup) 239 neccesaryBtn.addEventListener("click", (e) => { 240 localStorage.setItem('cookies', false); 241 242 [].forEach.call(accpetCheckbox, btn => { 243 btn.classList.remove('toggled'); 244 }); 245 246 checkState = false; 247 248 setCookies(checkState); 249 250 initCookieCard.remove(); 251 btnDisplay(); 252 }); 253 254 // Exit cookie settings 255 exitBtn.addEventListener("click", (e) => { 256 changes = false; 257 [].forEach.call(accpetCheckbox, btn => { 258 checkState = (localStorage.getItem("cookies") == 'true'); 259 (localStorage.getItem("cookies") == 'true') ? btn.classList.add('toggled') : btn.classList.remove('toggled'); 260 }); 261 262 // Mobile 263 policyPanel[0].classList.remove('active'); 264 settingsPanel[0].classList.remove('active'); 265 266 // Desktop 267 aboutPanelDesktop.classList.add('active'); 268 policyPanel[1].classList.remove('active'); 269 settingsPanel[1].classList.remove('active'); 270 271 settingsInitReset(); 272 273 settingsDisplay(); 274 btnDisplay(); 275 }); 276 277 // Settings panel / button 278 settingsBtn.forEach((elm) => { 279 elm.addEventListener("click", (e) => { 280 // Opens cookie settings 281 if (elm.classList.contains('link-to-settings')) { 282 initCookieCard.classList.remove('active') 283 } 284 settingsDisplay(); 285 btnDisplay(); 286 }); 287 }) 288 289 // Panels 290 291 aboutPanelBtn.addEventListener("click", (e) => { 292 293 // Desktop 294 aboutPanelDesktop.classList.add('active'); 295 policyPanel[1].classList.remove('active'); 296 settingsPanel[1].classList.remove('active'); 297 298 // Mobile 299 settingsPanel[0].classList.contains('active') ? 300 settingsPanel[0].classList.remove('active') : 301 settingsPanel[0].classList.add('active'); 302 303 settingsPanelBtn.classList.contains('mobile-selected') ? 304 settingsPanelBtn.classList.remove('mobile-selected') : 305 settingsPanelBtn.classList.add('mobile-selected'); 306 307 // Common 308 aboutPanelBtn.classList.add('selected'); 309 settingsPanelBtn.classList.remove('selected'); 310 policyPanelBtn.classList.remove('selected'); 311 312 }); 313 314 settingsPanelBtn.addEventListener("click", (e) => { 315 // Desktop 316 aboutPanelDesktop.classList.remove('active'); 317 policyPanel[1].classList.remove('active'); 318 settingsPanel[1].classList.add('active'); 319 320 // Mobile 321 settingsPanel[0].classList.contains('active') ? 322 settingsPanel[0].classList.remove('active') : 323 settingsPanel[0].classList.add('active'); 324 325 settingsPanelBtn.classList.contains('mobile-selected') ? 326 settingsPanelBtn.classList.remove('mobile-selected') : 327 settingsPanelBtn.classList.add('mobile-selected'); 328 329 // Common 330 aboutPanelBtn.classList.remove('selected'); 331 settingsPanelBtn.classList.add('selected'); 332 policyPanelBtn.classList.remove('selected'); 333 334 }); 335 336 // Policy panel/button 337 policyPanelBtn.addEventListener("click", (e) => { 338 339 // Desktop 340 aboutPanelDesktop.classList.remove('active'); 341 policyPanel[1].classList.add('active'); 342 settingsPanel[1].classList.remove('active'); 343 344 // Mobile 345 policyPanel[0].classList.contains('active') ? 346 policyPanel[0].classList.remove('active') : 347 policyPanel[0].classList.add('active'); 348 349 policyPanelBtn.classList.contains('mobile-selected') ? 350 policyPanelBtn.classList.remove('mobile-selected') : 351 policyPanelBtn.classList.add('mobile-selected'); 352 353 // Common 354 aboutPanelBtn.classList.remove('selected'); 355 settingsPanelBtn.classList.remove('selected'); 356 policyPanelBtn.classList.add('selected'); 357 }); 358 359 // Accept cookie checkbox 360 [].forEach.call(accpetCheckbox, container => { 361 362 container.addEventListener("click", (e) => { 363 checkState = !checkState; 364 365 changes = true; 366 [].forEach.call(accpetCheckbox, btn => { 367 checkState ? btn.classList.add('toggled') : btn.classList.remove('toggled'); 368 }); 369 [].forEach.call(saveChanges, btn => { 370 btn.classList.add('changes'); 371 }); 372 }); 373 }); 374 375 // Accept all cookies button 376 [].forEach.call(acceptAllSettings, btn => { 377 btn.addEventListener("click", (e) => { 378 // Accept all cookies 379 checkState = true;
380 setCookies(checkState); 381 changes = false; 382 localStorage.setItem('cookies', true); 383 [].forEach.call(accpetCheckbox, btn => { 384 btn.classList.add('toggled'); 385 }); 386 387 // Mobile 388 policyPanel[0].classList.remove('active'); 389 settingsPanel[0].classList.remove('active'); 390 391 // Desktop 392 aboutPanelDesktop.classList.add('active'); 393 policyPanel[1].classList.remove('active'); 394 settingsPanel[1].classList.remove('active'); 395 396 settingsInitReset(); 397 398 settingsDisplay(); 399 btnDisplay(); 400 }); 401 }); 402 403 // Save changes button 404 [].forEach.call(saveChanges, btn => { 405 btn.addEventListener("click", (e) => { 406 if (changes) { 407 changes = false; 408 localStorage.setItem('cookies', checkState); 409 410 setCookies(checkState); 411 412 // Mobile 413 policyPanel[0].classList.remove('active'); 414 settingsPanel[0].classList.remove('active'); 415 416 // Desktop 417 aboutPanelDesktop.classList.add('active'); 418 policyPanel[1].classList.remove('active'); 419 settingsPanel[1].classList.remove('active'); 420 421 settingsInitReset(); 422 423 settingsDisplay(); 424 btnDisplay(); 425 } 426 }); 427 }); 428 429 document.querySelector('.nav-tab').addEventListener('click', () => { 430 // Desktop 431 aboutPanelDesktop.classList.remove('active'); 432 policyPanel[1].classList.add('active'); 433 settingsPanel[1].classList.remove('active'); 434 435 // Mobile 436 policyPanel[0].classList.contains('active') ? 437 policyPanel[0].classList.remove('active') : 438 policyPanel[0].classList.add('active'); 439 440 policyPanelBtn.classList.contains('mobile-selected') ? 441 policyPanelBtn.classList.remove('mobile-selected') : 442 policyPanelBtn.classList.add('mobile-selected'); 443 444 // Common 445 aboutPanelBtn.classList.remove('selected'); 446 settingsPanelBtn.classList.remove('selected'); 447 policyPanelBtn.classList.add('selected'); 448 }); 449});
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.