1/* plg_system_cookienotice */ 2(function () { 3 "use strict"; 4 5 var CATEGORIES = ["preferences", "analytics", "marketing"]; 6 7 function parseConfig(root) { 8 var node = root.querySelector(".jt-cookie-config"); 9 10 if (!node) { 11 return null; 12 } 13 14 try { 15 return JSON.parse(node.textContent || "{}"); 16 } catch (error) { 17 return null; 18 } 19 } 20 21 function getCookieValue(name) { 22 var encodedName = encodeURIComponent(name) + "="; 23 var cookies = document.cookie ? document.cookie.split(";") : []; 24 25 for (var i = 0; i < cookies.length; i += 1) { 26 var cookie = cookies[i].trim(); 27 28 if (cookie.indexOf(encodedName) === 0) { 29 try { 30 return decodeURIComponent(cookie.substring(encodedName.length)); 31 } catch (error) { 32 return ""; 33 } 34 } 35 } 36 37 return ""; 38 } 39 40 function createChoices(value) { 41 return { 42 necessary: true, 43 preferences: value === true, 44 analytics: value === true, 45 marketing: value === true 46 }; 47 } 48 49 function createState(config, choices) { 50 return { 51 version: 1, 52 revision: String(config.revision || "1"), 53 timestamp: new Date().toISOString(), 54 choices: { 55 necessary: true, 56 preferences: choices.preferences === true, 57 analytics: choices.analytics === true, 58 marketing: choices.marketing === true 59 } 60 }; 61 } 62 63 function readState(config) { 64 var raw = getCookieValue(config.cookieName); 65 66 if (!raw) { 67 return null; 68 } 69 70 try { 71 var state = JSON.parse(raw); 72 var choices = state && state.choices; 73 74 if ( 75 !state 76 || state.version !== 1 77 || String(state.revision) !== String(config.revision) 78 || !choices 79 || choices.necessary !== true 80 || typeof choices.preferences !== "boolean" 81 || typeof choices.analytics !== "boolean" 82 || typeof choices.marketing !== "boolean" 83 ) { 84 return null; 85 } 86 87 return state; 88 } catch (error) { 89 return null; 90 } 91 } 92 93 function writeState(config, state) { 94 var maxAge = Number.parseInt(String(config.maxAge || "15552000"), 10); 95 96 if (!Number.isFinite(maxAge) || maxAge < 1) { 97 maxAge = 15552000; 98 } 99 100 var cookie = encodeURIComponent(config.cookieName) + "=" + encodeURIComponent(JSON.stringify(state)) 101 + "; max-age=" + String(maxAge) 102 + "; path=/; samesite=lax"; 103 104 if (window.location.protocol === "https:") { 105 cookie += "; secure"; 106 } 107 108 document.cookie = cookie; 109 } 110 111 function removeConsentCookie(config) { 112 document.cookie = encodeURIComponent(config.cookieName) + "=; max-age=0; path=/; samesite=lax"; 113 } 114 115 function wildcardMatch(value, pattern) { 116 var expression = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*"); 117 118 return new RegExp("^" + expression + "$").test(value); 119 } 120 121 function visibleCookieNames() { 122 if (!document.cookie) { 123 return []; 124 } 125 126 return document.cookie.split(";").map(function (item) { 127 var name = item.split("=")[0].trim(); 128 129 try { 130 return decodeURIComponent(name); 131 } catch (error) { 132 return name; 133 } 134 }); 135 } 136 137 function cookiePaths() { 138 var paths = ["/"]; 139 var parts = window.location.pathname.split("/").filter(Boolean); 140 141 for (var i = 1; i <= parts.length; i += 1) { 142 paths.push("/" + parts.slice(0, i).join("/") + "/"); 143 } 144 145 return paths; 146 } 147 148 function cookieDomains() { 149 var hostname = window.location.hostname; 150 var parts = hostname.split("."); 151 var domains = [""]; 152 153 if (!hostname || hostname === "localhost" || /^[0-9.]+$/.test(hostname)) { 154 return domains; 155 } 156 157 domains.push(hostname); 158 159 for (var i = 1; i < parts.length - 1; i += 1) { 160 domains.push("." + parts.slice(i).join(".")); 161 } 162 163 return domains; 164 } 165 166 function expireCookie(name) { 167 var paths = cookiePaths(); 168 var domains = cookieDomains(); 169 170 for (var i = 0; i < paths.length; i += 1) { 171 for (var j = 0; j < domains.length; j += 1) { 172 var cookie = encodeURIComponent(name) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; max-age=0; path=" + paths[i]; 173 174 if (domains[j]) { 175 cookie += "; domain=" + domains[j]; 176 } 177 178 document.cookie = cookie + "; samesite=lax"; 179 } 180 } 181 } 182 183 function cleanupRevokedCookies(config, previousState, nextState) { 184 if (!previousState) { 185 return false;
186 } 187 188 var names = visibleCookieNames(); 189 var revoked = false; 190 191 CATEGORIES.forEach(function (category) { 192 if (previousState.choices[category] !== true || nextState.choices[category] === true) { 193 return; 194 } 195 196 revoked = true; 197 var patterns = (config.cleanupCookies && config.cleanupCookies[category]) || []; 198 199 names.forEach(function (name) { 200 if (patterns.some(function (pattern) { return wildcardMatch(name, pattern); })) { 201 expireCookie(name); 202 } 203 }); 204 }); 205 206 return revoked; 207 } 208 209 function copyScript(source) { 210 var script = document.createElement("script"); 211 var sourceType = source.getAttribute("type"); 212 213 for (var i = 0; i < source.attributes.length; i += 1) { 214 var attribute = source.attributes[i]; 215 216 if ( 217 attribute.name !== "type" 218 && attribute.name !== "data-cookie-category" 219 && attribute.name !== "data-cookie-src" 220 && attribute.name !== "data-cookie-activated" 221 ) { 222 script.setAttribute(attribute.name, attribute.value); 223 } 224 } 225 226 var sourceUrl = source.getAttribute("data-cookie-src"); 227 228 if (sourceType && sourceType.toLowerCase() !== "text/plain") { 229 script.type = sourceType; 230 } 231 232 if (sourceUrl) { 233 script.src = sourceUrl; 234 } 235 236 if (script.src && !source.hasAttribute("async")) { 237 script.async = false; 238 } 239 240 script.text = source.textContent || ""; 241 242 return script; 243 } 244 245 function activateAnnotatedElements(category) { 246 var selector = "[data-cookie-category=\"" + category + "\"]:not([data-cookie-activated])"; 247 var elements = document.querySelectorAll(selector); 248 249 for (var i = 0; i < elements.length; i += 1) { 250 var element = elements[i]; 251 252 if (element.tagName === "SCRIPT") { 253 element.setAttribute("data-cookie-activated", "true"); 254 element.parentNode.replaceChild(copyScript(element), element); 255 continue; 256 } 257 258 var sourceUrl = element.getAttribute("data-cookie-src"); 259 var sourceSet = element.getAttribute("data-cookie-srcset"); 260 261 if (sourceUrl) { 262 element.setAttribute("src", sourceUrl); 263 } 264 265 if (sourceSet) { 266 element.setAttribute("srcset", sourceSet); 267 } 268 269 element.setAttribute("data-cookie-activated", "true"); 270 } 271 } 272 273 function activateSnippet(root, config, category) { 274 var snippet = config.snippets && config.snippets[category]; 275 276 if (!snippet || root.getAttribute("data-jt-snippet-" + category) === "active") { 277 return; 278 } 279 280 root.setAttribute("data-jt-snippet-" + category, "active"); 281 282 var template = document.createElement("template"); 283 template.innerHTML = snippet; 284 285 var scripts = template.content.querySelectorAll("script"); 286 287 for (var i = 0; i < scripts.length; i += 1) { 288 scripts[i].parentNode.replaceChild(copyScript(scripts[i]), scripts[i]); 289 } 290 291 var container = document.createElement("div"); 292 container.className = "jt-cookie-injected"; 293 container.setAttribute("data-jt-cookie-injected", category); 294 container.appendChild(template.content); 295 document.body.appendChild(container); 296 } 297 298 function activateAllowedContent(root, config, state) { 299 if (!state) { 300 return; 301 } 302 303 CATEGORIES.forEach(function (category) { 304 if (state.choices[category] === true) { 305 activateAnnotatedElements(category); 306 activateSnippet(root, config, category); 307 } 308 }); 309 } 310 311 function dispatchConsentEvent(name, state) { 312 document.dispatchEvent(new CustomEvent(name, { detail: state })); 313 } 314 315 function init(root) { 316 var config = parseConfig(root); 317 318 if (!config || !config.cookieName) { 319 return; 320 } 321 322 var banner = root.querySelector(".jt-cookie-notice"); 323 var launcher = root.querySelector(".jt-cookie-launcher"); 324 var backdrop = root.querySelector("[data-jt-cookie-preferences]"); 325 var dialog = root.querySelector(".jt-cookie-preferences"); 326 var currentState = readState(config); 327 var returnFocus = null; 328 329 function showBanner() { 330 if (banner) { 331 banner.classList.add("show"); 332 } 333 } 334 335 function hideBanner() { 336 if (banner) { 337 banner.classList.remove("show"); 338 } 339 } 340 341 function updateLauncher() { 342 if (launcher) { 343 launcher.hidden = !(currentState && config.showLauncher !== false); 344 } 345 } 346 347 function setPreferenceInputs(choices) { 348 var inputs = root.querySelectorAll("[data-jt-cookie-category]"); 349 350 for (var i = 0; i < inputs.length; i += 1) {
351 var category = inputs[i].getAttribute("data-jt-cookie-category"); 352 inputs[i].checked = choices[category] === true; 353 } 354 } 355 356 function openPreferences() { 357 if (!backdrop || !dialog) { 358 return; 359 } 360 361 returnFocus = document.activeElement; 362 setPreferenceInputs(currentState ? currentState.choices : createChoices(false)); 363 hideBanner(); 364 backdrop.hidden = false; 365 document.documentElement.classList.add("jt-cookie-preferences-open"); 366 dialog.focus(); 367 } 368 369 function closePreferences() { 370 if (!backdrop) { 371 return; 372 } 373 374 backdrop.hidden = true; 375 document.documentElement.classList.remove("jt-cookie-preferences-open"); 376 377 if (!currentState) { 378 showBanner(); 379 } 380 381 if (currentState && launcher && !launcher.hidden) { 382 launcher.focus(); 383 } else if ( 384 returnFocus 385 && typeof returnFocus.focus === "function" 386 && (!currentState || !banner || !banner.contains(returnFocus)) 387 ) { 388 returnFocus.focus(); 389 } 390 } 391 392 function saveChoices(choices) { 393 var previousState = currentState; 394 var nextState = createState(config, choices); 395 var needsReload = cleanupRevokedCookies(config, previousState, nextState); 396 397 writeState(config, nextState); 398 currentState = nextState; 399 hideBanner(); 400 updateLauncher(); 401 closePreferences(); 402 activateAllowedContent(root, config, currentState); 403 dispatchConsentEvent("jt:cookie-consent:change", currentState); 404 405 if (needsReload) { 406 window.location.reload(); 407 } 408 } 409 410 function selectedChoices() { 411 var choices = createChoices(false); 412 var inputs = root.querySelectorAll("[data-jt-cookie-category]"); 413 414 for (var i = 0; i < inputs.length; i += 1) { 415 choices[inputs[i].getAttribute("data-jt-cookie-category")] = inputs[i].checked === true; 416 } 417 418 return choices; 419 } 420 421 root.addEventListener("click", function (event) { 422 var button = event.target.closest("[data-jt-cookie-action]"); 423 424 if (!button || !root.contains(button)) { 425 return; 426 } 427 428 var action = button.getAttribute("data-jt-cookie-action"); 429 430 if (action === "accept") { 431 saveChoices(createChoices(true)); 432 } else if (action === "reject") { 433 saveChoices(createChoices(false)); 434 } else if (action === "save") { 435 saveChoices(selectedChoices()); 436 } else if (action === "preferences" || action === "open") { 437 openPreferences(); 438 } else if (action === "close") { 439 closePreferences(); 440 } 441 }); 442 443 if (backdrop) { 444 backdrop.addEventListener("click", function (event) { 445 if (event.target === backdrop) { 446 closePreferences(); 447 } 448 }); 449 450 backdrop.addEventListener("keydown", function (event) { 451 if (event.key === "Escape") { 452 event.preventDefault(); 453 closePreferences(); 454 return; 455 } 456 457 if (event.key !== "Tab" || !dialog) { 458 return; 459 } 460 461 var focusable = dialog.querySelectorAll("a[href], button:not([disabled]), input:not([disabled]), [tabindex]:not([tabindex=\"-1\"])"); 462 463 if (!focusable.length) { 464 return; 465 } 466 467 var first = focusable[0]; 468 var last = focusable[focusable.length - 1]; 469 470 if (event.shiftKey && document.activeElement === first) { 471 event.preventDefault(); 472 last.focus(); 473 } else if (!event.shiftKey && document.activeElement === last) { 474 event.preventDefault(); 475 first.focus(); 476 } 477 }); 478 } 479 480 window.JTCookieConsent = { 481 getState: function () { 482 return currentState ? JSON.parse(JSON.stringify(currentState)) : null; 483 }, 484 hasConsent: function (category) { 485 return category === "necessary" || Boolean(currentState && currentState.choices[category] === true); 486 }, 487 openPreferences: openPreferences, 488 reset: function () { 489 removeConsentCookie(config); 490 window.location.reload(); 491 } 492 }; 493 494 if (currentState) { 495 activateAllowedContent(root, config, currentState); 496 updateLauncher(); 497 } else {
498 var delay = Number.parseInt(String(config.delay || "0"), 10); 499 500 if (!Number.isFinite(delay) || delay < 0) { 501 delay = 0; 502 } 503 504 if (delay > 0) { 505 window.setTimeout(showBanner, delay); 506 } else { 507 showBanner(); 508 } 509 } 510 511 dispatchConsentEvent("jt:cookie-consent:ready", currentState); 512 } 513 514 function initAll() { 515 var roots = document.querySelectorAll("[data-jt-cookie-consent-root]"); 516 517 for (var i = 0; i < roots.length; i += 1) { 518 init(roots[i]); 519 } 520 } 521 522 if (document.readyState === "loading") { 523 document.addEventListener("DOMContentLoaded", initAll); 524 } else { 525 initAll(); 526 } 527})();
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.