1// source --> https://tellmamauk.org/wp-content/plugins/cookie-law-info/lite/frontend/js/script.js?ver=3.5.4 2/** 3 * WordPress localize object mapped to a constant. 4 */ 5const _ckyStore = window._ckyConfig; 6const _ckyStyle = window._ckyStyles; 7 8_ckyStore._backupNodes = []; 9_ckyStore._resetConsentID = false; 10_ckyStore._bannerState = false; 11_ckyStore._preferenceOriginTag = false; 12_ckyStore._optoutSuccessCountdownInterval = null; 13_ckyStore._optoutSuccessAutoCloseTimer = null; 14_ckyStore._optoutSuccessSubtextTemplate = ""; 15 16const CKY_OPTOUT_SUCCESS_DISMISS_MS = 15000; 17const CKY_OPTOUT_SUCCESS_SECONDS = 15; 18 19window.cookieyes = window.cookieyes || {}; 20const ref = window.cookieyes; 21ref._ckyConsentStore = new Map(); 22 23ref._ckyGetCookieMap = function () { 24 const cookieMap = {}; 25 try { 26 document.cookie.split(";").map((cookie) => { 27 const [key, value] = cookie.split("="); 28 if (!key) return; 29 cookieMap[key.trim()] = value; 30 return value; 31 }); 32 } catch (error) { } 33 return cookieMap; 34}; 35 36const currentCookieMap = ref._ckyGetCookieMap(); 37ref._ckyGetFromStore = function (key) { 38 return ref._ckyConsentStore.get(key) || ""; 39}; 40 41ref._ckySetInStore = function (key, value) { 42 ref._ckyConsentStore.set(key, value); 43 let cookieStringArray = []; 44 for (const [key, value] of ref._ckyConsentStore) { 45 cookieStringArray.push(`${key}:${value}`); 46 } 47 const scriptExpiry = 48 _ckyStore && _ckyStore._expiry 49 ? _ckyStore._expiry 50 : 365; 51 ref._ckySetCookie( 52 "cookieyes-consent", 53 cookieStringArray.join(","), 54 scriptExpiry 55 ); 56}; 57 58const cookieyesConsentMap = (currentCookieMap["cookieyes-consent"] || "") 59 .split(",") 60 .reduce((prev, curr) => { 61 if (!curr) return prev; 62 const [key, value] = curr.split(":"); 63 prev[key] = value; 64 return prev; 65 }, {}); 66["consentid", "consent", "action"] 67 .concat(_ckyStore._categories.map(({ slug }) => slug)) 68 .map((item) => 69 ref._ckyConsentStore.set(item, cookieyesConsentMap[item] || "") 70 ); 71 72 73/** 74 * Get the value of cookie by it's name. 75 * 76 * @param {string} name Name of the cookie 77 * @returns {string} 78 */ 79ref._ckyGetCookie = function (name) { 80 const value = new RegExp(`${name}=([^;]+)`).exec(document.cookie); 81 return value && Array.isArray(value) && value[1] ? unescape(value[1]) : null; 82} 83 84/** 85 * Set a cookie on document.cookie object. 86 * 87 * @param {*} name Name of the cookie. 88 * @param {*} value Value to be set. 89 * @param {*} days Expiry in days. 90 * @param {*} domain Cookie domain. 91 */ 92ref._ckySetCookie = function (name, value, days = 0, domain = _ckyStore._rootDomain) { 93 const date = new Date(); 94 if (!!domain) { 95 domain = `domain=${domain}`; 96 } 97 const toSetTime = 98 days === 0 ? 0 : date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000); 99 document.cookie = `${name}=${value}; expires=${new Date( 100 toSetTime 101 ).toUTCString()}; path=/;${domain}; SameSite=Strict;`; 102} 103 104function _ckySetConsentID() { 105 const cookieyesID = ref._ckyGetFromStore("consentid"); 106 if (cookieyesID) return; 107 const consentID = ref._ckyRandomString(32); 108 ref._ckySetInStore("consentid", consentID); 109 _ckyStore._resetConsentID = true; 110} 111 112const _revisitCkyConsent = function () { 113 const type = _ckyGetType(); 114 if (type === 'classic') { 115 _ckyShowBanner(); 116 } 117 _ckySetPreferenceAction(); 118 _ckyToggleRevisit(); 119}; 120/** 121 * Search an element by it's data-cky-tag attribute 122 * 123 * @param {string} tag data-cky-tag of an element. 124 * @returns {object} 125 */ 126function _ckyGetElementByTag(tag) { 127 const item = document.querySelector('[data-cky-tag=' + tag + ']'); 128 return item ? item : false; 129} 130 131function _ckyEscapeRegex(literal) { 132 return literal.replace(/[.*+?^${}()[\]\\]/g, "\\$&"); 133} 134 135/** 136 * Bind click event to banner elements. 137 * 138 * @param {string} tag data-cky-tag of the element 139 * @param {function} fn callback function 140 */ 141function _ckyAttachListener(selector, fn) { 142 const item = _ckyFindElement(selector); 143 item && item.addEventListener("click", fn); 144} 145 146function _ckyClassAdd() { 147 return _ckyClassAction("add", ...arguments); 148} 149 150function _ckyClassRemove() { 151 return _ckyClassAction("remove", ...arguments); 152} 153
154function _ckyClassToggle() { 155 return _ckyClassAction("toggle", ...arguments); 156} 157 158function _ckyClassAction(action, selector, className, forParent = true) { 159 const item = _ckyFindElement(selector, forParent); 160 return item && item.classList[action](className); 161} 162 163function _ckyFindElement(selector, forParent) { 164 let createdSelector = selector; 165 switch (true) { 166 case selector.startsWith("="): 167 createdSelector = `[data-cky-tag="${selector.substring(1)}"]`; 168 break; 169 default: 170 break; 171 } 172 const element = document.querySelector(createdSelector); 173 if (!element || (forParent && !element.parentElement)) return null; 174 return forParent ? element.parentElement : element; 175} 176/** 177 * Remove an element from the DOM. 178 * 179 * @param {string} tag data-cky-tag of the element. 180 */ 181function _ckyRemoveElement(tag) { 182 const item = _ckyGetElementByTag(tag); 183 item && item.remove(); 184} 185 186function _ckyFireEvent(responseCategories) { 187 const consentUpdate = new CustomEvent("cookieyes_consent_update", { 188 detail: responseCategories 189 }); 190 document.dispatchEvent(consentUpdate); 191} 192 193/** 194 * Remove styles by it's id. 195 */ 196function _ckyRemoveStyles() { 197 const item = document.getElementById('cky-style-inline'); 198 item && item.remove(); 199} 200 201/** 202 * Generate a random string for logging purposes. 203 * 204 * @param {integer} length Length of the string to be generated. 205 * @returns 206 */ 207ref._ckyRandomString = function (length, allChars = true) { 208 const chars = `${allChars ? `0123456789` : "" 209 }ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghiklmnopqrstuvwxyz`; 210 const response = []; 211 for (let i = 0; i < length; i++) 212 response.push(chars[Math.floor(Math.random() * chars.length)]); 213 if (!allChars) return response.join(""); 214 return btoa(response.join("")).replace(/\=+$/, ""); 215} 216 217/** 218 * Remove banner if necessary. 219 */ 220function _ckyRemoveBanner() { 221 _ckyHideBanner(); 222 if (_ckyStore._bannerConfig.config.revisitConsent.status === true) { 223 _ckyShowRevisit(); 224 } 225} 226 227/** 228 * Initialize the plugin front-end operations. 229 * 230 * @returns {boolean} 231 */ 232function _ckyInitOperations() { 233 _ckyAttachNoticeStyles(); 234 _ckyAttachShortCodeStyles(); 235 _ckyRenderBanner(); 236 _ckySetShowMoreLess(); 237 if (!ref._ckyGetFromStore("action") || _ckyPreviewEnabled()) { 238 _ckyShowBanner(); 239 _ckySetInitialState(); 240 _ckySetConsentID(); 241 } else { 242 _ckyRemoveBanner(); 243 } 244} 245function _ckyPreviewEnabled() { 246 let params = (new URL(document.location)).searchParams; 247 return params.get("cky_preview") && params.get("cky_preview") === 'true'; 248} 249function _ckyToggleAriaExpandStatus(selector, forceDefault = null) { 250 const element = _ckyFindElement(selector); 251 252 if (!element) return; 253 254 if (element.classList.contains('cky-accordion-btn')) { 255 const accordionItem = element.closest('.cky-accordion'); 256 if (accordionItem) { 257 const accordionBody = accordionItem.querySelector('.cky-accordion-body'); 258 if (accordionBody) { 259 // Generate unique ID for the accordion body if it doesn't have one 260 let bodyId = accordionBody.id; 261 if (!bodyId) { 262 bodyId = `ckyDetailCategory${accordionItem.id.replace('ckyDetailCategory', '')}Body`; 263 accordionBody.id = bodyId; 264 } 265 // Always set aria-controls - the relationship is permanent 266 element.setAttribute("aria-controls", bodyId); 267 } 268 } 269 } 270 271 const currentExpanded = element.getAttribute("aria-expanded"); 272 const newExpandedValue = forceDefault || (currentExpanded === "true" ? "false" : "true"); 273 element.setAttribute("aria-expanded", newExpandedValue); 274} 275/** 276 * Sets the initial state of the plugin. 277 */ 278function _ckySetInitialState() { 279 const activeLaw = _ckyGetLaw() 280 ref._ckySetInStore("consent", "no"); 281 const ccpaCheckBoxValue = _ckyFindCheckBoxValue(); 282 const responseCategories = { accepted: [], rejected: [] }; 283 let valueToSet = "yes"; 284 for (const category of _ckyStore._categories) { 285 if ( 286 (activeLaw === "gdpr" && 287 !category.isNecessary && 288 !category.defaultConsent[activeLaw]) || 289 (activeLaw === "ccpa" && 290 ccpaCheckBoxValue && 291 !category.defaultConsent.ccpa) 292 ) { 293 valueToSet = "no"; 294 } 295 if (valueToSet === "no") responseCategories.rejected.push(category.slug); 296 else responseCategories.accepted.push(category.slug); 297 ref._ckySetInStore(`${category.slug}`, valueToSet); 298 } 299 _ckyUnblock(); 300 _ckyFireEvent(responseCategories); 301} 302 303/** 304 * Add a class based on the banner type and position. Eg: 'cky-banner-top' 305 * 306 * @returns {boolean} 307 */ 308function _ckyAddPositionClass() { 309 const notice = _ckyGetElementByTag('notice'); 310 if (!notice) return false;
311 const container = notice.closest('.cky-consent-container'); 312 if (!container) return false; 313 314 container.setAttribute("aria-label", "We value your privacy"); 315 container.setAttribute("role", "region"); 316 317 const type = _ckyStore._bannerConfig.settings.type; 318 let position = _ckyStore._bannerConfig.settings.position; 319 let bannerType = type; 320 if (bannerType === 'popup') { 321 position = 'center'; 322 } 323 bannerType = (_ckyGetPtype() === "pushdown") ? 'classic' : bannerType; 324 const noticeClass = `cky-${bannerType}-${position}`; 325 container.classList.add(noticeClass); 326 const revisitConsent = _ckyGetElementByTag('revisit-consent'); 327 if (!revisitConsent) return false; 328 const revisitPosition = 'cky-revisit-' + _ckyStore._bannerConfig.config.revisitConsent.position; 329 revisitConsent.classList.add(revisitPosition); 330} 331 332/** 333 * Add a class based on the preference center type and position. Eg: 'cky-sidebar-left' 334 * 335 * @returns {boolean} 336 */ 337function _ckyAddPreferenceCenterClass() { 338 const detail = _ckyGetLaw() === 'ccpa' ? _ckyGetElementByTag("optout-popup") : _ckyGetElementByTag("detail"); 339 if (!detail) return false; 340 const modal = detail.closest('.cky-modal'); 341 if (!modal) return false; 342 if (_ckyGetPtype() !== "pushdown" && _ckyGetPtype() !== "popup") { 343 const pType = _ckyStore._bannerConfig.settings.preferenceCenterType; 344 const modalClass = `cky-${pType}`; 345 modal.classList.add(modalClass); 346 } 347 348 // Ensure ARIA attributes are always present on the preference center div 349 const preferenceCenter = modal.querySelector('.cky-preference-center'); 350 if (preferenceCenter) { 351 const preferenceCenterId = _ckyGetLaw() === 'ccpa' ? 'ckyOptoutPreferenceCenter' : 'ckyPreferenceCenter'; 352 preferenceCenter.setAttribute('id', preferenceCenterId); 353 preferenceCenter.setAttribute('role', 'dialog'); 354 preferenceCenter.setAttribute('aria-modal', 'true'); 355 const ariaLabel = _ckyGetLaw() === 'ccpa' ? 'Opt-out Preferences' : 'Customise Consent Preferences'; 356 preferenceCenter.setAttribute('aria-label', ariaLabel); 357 } 358} 359 360/** 361 * Initialize the plugin operations. 362 */ 363async function _ckyInit() { 364 try { 365 _ckyInitOperations(); 366 _ckyRemoveAllDeadCookies(); 367 _ckyWatchBannerElement(); 368 } catch (err) { 369 console.error(err); 370 } 371} 372 373/** 374 * Domready event, alternative to jQuery(document).ready() function 375 * 376 * @param {function} callback 377 * @returns 378 */ 379function _ckyDomReady(callback) { 380 if (typeof document === 'undefined') { 381 return; 382 } 383 if (document.readyState === 'complete' || /** DOMContentLoaded + Images/Styles/etc loaded, so we call directly. */ 384 document.readyState === 'interactive' /** DOMContentLoaded fires at this point, so we call directly. */ 385 ) { 386 return void callback(); 387 } /** DOMContentLoaded has not fired yet, delay callback until then. */ 388 document.addEventListener('DOMContentLoaded', callback); 389} 390 391/** 392 * Callback function to Domready event. 393 */ 394_ckyDomReady(async function () { 395 try { 396 await _ckyInit(); 397 } catch (err) { 398 console.error(err); 399 } 400}); 401 402/** 403 * Register event handler for all the action elements. 404 */ 405function _ckyRegisterListeners() { 406 for (const { slug } of _ckyStore._categories) { 407 _ckyAttachListener('detail-category-title', () => 408 document 409 .getElementById(`ckyCategory${slug}`) 410 .classList.toggle("cky-tab-active") 411 ); 412 } 413 _ckyAttachListener("=settings-button", () => _ckySetPreferenceAction('settings-button')); 414 _ckyAttachListener("=detail-close", () => _ckyHidePreferenceCenter()); 415 _ckyAttachListener("=optout-cancel-button", () => _ckyHidePreferenceCenter()); 416 _ckyAttachListener("=close-button", () => _ckyActionClose()); 417 _ckyAttachListener("=donotsell-button", () => _ckySetPreferenceAction('donotsell-button')); 418 _ckyAttachListener("=reject-button", _ckyAcceptReject("reject")); 419 _ckyAttachListener("=accept-button", _ckyAcceptReject("all")); 420 _ckyAttachListener("=detail-accept-button", _ckyAcceptReject("all")); 421 _ckyAttachListener("=detail-save-button", _ckyAcceptReject()); 422 _ckyAttachListener("=detail-category-preview-save-button", _ckyAcceptReject()); 423 _ckyAttachListener("=optout-confirm-button", _ckyHandleOptoutConfirm()); 424 _ckyAttachListener("=detail-reject-button", _ckyAcceptReject("reject")); 425 _ckyAttachListener("=revisit-consent", () => _revisitCkyConsent()); 426 _ckyAttachListener("=optout-close", () => _ckyHandleOptoutPopupClose()); 427} 428 429function _ckyAttachCategoryListeners() { 430 if (!_ckyStore._bannerConfig.config.auditTable.status) return; 431 const categoryNames = _ckyStore._categories.map(({ slug }) => slug); 432 categoryNames.map((category) => { 433 const selector = `#ckyDetailCategory${category}`; 434 const accordionButtonSelector = `${selector} .cky-accordion-btn`;
435 436 // Set initial aria-controls and aria-expanded for accordion buttons 437 const accordionButton = document.querySelector(accordionButtonSelector); 438 if (accordionButton) { 439 const accordionItem = accordionButton.closest('.cky-accordion'); 440 if (accordionItem) { 441 const accordionBody = accordionItem.querySelector('.cky-accordion-body'); 442 if (accordionBody) { 443 // Generate unique ID for the accordion body if it doesn't have one 444 let bodyId = accordionBody.id; 445 if (!bodyId) { 446 bodyId = `ckyDetailCategory${accordionItem.id.replace('ckyDetailCategory', '')}Body`; 447 accordionBody.id = bodyId; 448 } 449 // Always set aria-controls - the relationship is permanent 450 accordionButton.setAttribute("aria-controls", bodyId); 451 } 452 } 453 } 454 455 _ckyToggleAriaExpandStatus(accordionButtonSelector, "false"); 456 _ckyAttachListener(selector, ({ target: { id } }) => { 457 if ( 458 id === `ckySwitch${category}` || 459 !_ckyClassToggle(selector, "cky-accordion-active", false) 460 ) { 461 _ckyToggleAriaExpandStatus(accordionButtonSelector, "false"); 462 return; 463 } 464 _ckyToggleAriaExpandStatus(accordionButtonSelector, "true"); 465 categoryNames 466 .filter((categoryName) => categoryName !== category) 467 .map(filteredName => { 468 _ckyClassRemove( 469 `#ckyDetailCategory${filteredName}`, 470 "cky-accordion-active", 471 false 472 ); 473 _ckyToggleAriaExpandStatus( 474 `#ckyDetailCategory${filteredName} .cky-accordion-btn`, 475 "false" 476 ); 477 return filteredName; 478 }); 479 }); 480 return category; 481 }); 482} 483/** 484 * Add support for accordion tabs on the privacy overview screen. 485 */ 486function _ckyInitiAccordionTabs() { 487 document.querySelectorAll(".cky-accordion").forEach((item) => ( 488 item.addEventListener('click', function (event) { 489 if (event.target.type === 'checkbox') return; 490 this.classList.toggle('cky-accordion-active'); 491 }) 492 )); 493} 494 495function _ckyToggleBanner(force = false) { 496 const notice = _ckyGetElementByTag('notice'); 497 const container = notice && notice.closest('.cky-consent-container') || false; 498 if (container) { 499 force === true ? container.classList.add('cky-hide') : container.classList.toggle('cky-hide'); 500 } 501 502} 503 504function _ckyToggleRevisit(force = false) { 505 const revisit = _ckyGetRevisit(); 506 if (revisit) { 507 force === true ? _ckyRevisitHide() : revisit.classList.toggle('cky-revisit-hide'); 508 } 509} 510function _ckyGetLaw() { 511 return _ckyStore._bannerConfig.settings.applicableLaw; 512} 513function _ckyGetType() { 514 return _ckyStore._bannerConfig.settings.type; 515} 516function _ckyGetPtype() { 517 if (_ckyGetType() === 'classic') { 518 return 'pushdown'; 519 } 520 return _ckyStore._bannerConfig.settings.preferenceCenterType; 521} 522function _ckyGetBanner() { 523 const notice = _ckyGetElementByTag('notice'); 524 const container = notice && notice.closest('.cky-consent-container') || false; 525 return container && container || false; 526} 527function _ckyHideBanner() { 528 const notice = _ckyGetBanner(); 529 notice && notice.classList.add('cky-hide'); 530} 531function _ckyShowBanner() { 532 const notice = _ckyGetBanner(); 533 notice && notice.classList.remove('cky-hide'); 534} 535function _ckyHideOverLay() { 536 const overlay = document.querySelector('.cky-overlay'); 537 overlay && overlay.classList.add('cky-hide'); 538} 539function _ckyShowOverLay() { 540 const overlay = document.querySelector('.cky-overlay'); 541 overlay && overlay.classList.remove('cky-hide'); 542} 543function _ckyToggleOverLay() { 544 const overlay = document.querySelector('.cky-overlay'); 545 overlay && overlay.classList.toggle('cky-hide'); 546} 547function _ckyGetPreferenceCenter() { 548 if (_ckyGetType() === 'classic') { 549 return _ckyGetBanner(); 550 } 551 let element = _ckyGetLaw() === 'ccpa' ? _ckyGetElementByTag("optout-popup") : _ckyGetElementByTag("detail"); 552 return element && element.closest('.cky-modal') || false; 553} 554function _ckyHidePreferenceCenter() { 555 _ckyResetOptoutSuccessMessage(); 556 const element = _ckyGetPreferenceCenter(); 557 element && element.classList.remove(_ckyGetPreferenceClass()); 558 559 // ARIA attributes remain always present - only aria-expanded on settings button changes 560 // The modal relationship is permanent, only visibility changes 561 562 if (_ckyGetType() !== 'classic') { 563 _ckyHideOverLay();
564 if (!ref._ckyGetFromStore("action")) _ckyShowBanner(); 565 } else { 566 _ckyToggleAriaExpandStatus("=settings-button", "false"); 567 _ckyClassRemove("=notice", "cky-consent-bar-expand"); 568 } 569 if (ref._ckyGetFromStore("action")) _ckyShowRevisit(); 570 const origin = _ckyStore._preferenceOriginTag; 571 origin && _ckySetFocus(origin) 572} 573function _ckyShowPreferenceCenter() { 574 const element = _ckyGetPreferenceCenter(); 575 element && element.classList.add(_ckyGetPreferenceClass()); 576 577 // Ensure ARIA attributes are always present on the preference center div 578 if (element) { 579 const preferenceCenter = element.querySelector('.cky-preference-center'); 580 if (preferenceCenter) { 581 const preferenceCenterId = _ckyGetLaw() === 'ccpa' ? 'ckyOptoutPreferenceCenter' : 'ckyPreferenceCenter'; 582 preferenceCenter.setAttribute('id', preferenceCenterId); 583 preferenceCenter.setAttribute('role', 'dialog'); 584 preferenceCenter.setAttribute('aria-modal', 'true'); 585 const ariaLabel = _ckyGetLaw() === 'ccpa' ? 'Opt-out Preferences' : 'Customise Consent Preferences'; 586 preferenceCenter.setAttribute('aria-label', ariaLabel); 587 } 588 } 589 590 if (_ckyGetType() !== 'classic') { 591 _ckyShowOverLay(); 592 _ckyHideBanner(); 593 } else { 594 _ckyToggleAriaExpandStatus("=settings-button"); 595 _ckyClassAdd("=notice", "cky-consent-bar-expand"); 596 } 597} 598function _ckyTogglePreferenceCenter() { 599 const element = _ckyGetPreferenceCenter(); 600 if (!element) return; 601 element.classList.toggle(_ckyGetPreferenceClass()); 602 if (_ckyGetPtype() !== 'pushdown') _ckyToggleOverLay(); 603 604 const isOpen = element.classList.contains(_ckyGetPreferenceClass()); 605 element.classList.toggle(_ckyGetPreferenceClass()); 606 if (_ckyGetType() === 'classic') { 607 const preferenceCenter = element.querySelector('.cky-preference-center'); 608 if (preferenceCenter) { 609 const preferenceCenterId = _ckyGetLaw() === 'ccpa' ? 'ckyOptoutPreferenceCenter' : 'ckyPreferenceCenter'; 610 preferenceCenter.setAttribute('id', preferenceCenterId); 611 preferenceCenter.setAttribute('role', 'dialog'); 612 preferenceCenter.setAttribute('aria-modal', 'true'); 613 const ariaLabel = _ckyGetLaw() === 'ccpa' ? 'Opt-out Preferences' : 'Customise Consent Preferences'; 614 preferenceCenter.setAttribute('aria-label', ariaLabel); 615 } 616 _ckyToggleAriaExpandStatus("=settings-button"); 617 _ckyClassToggle("=notice", "cky-consent-bar-expand"); 618 } else { 619 if (!isOpen) { 620 _ckyShowOverLay(); 621 _ckyHideBanner(); 622 } else { 623 _ckyHideOverLay(); 624 if (!ref._ckyGetFromStore("action")) _ckyShowBanner(); 625 } 626 } 627 if (ref._ckyGetFromStore("action")) _ckyShowRevisit(); 628 const origin = _ckyStore._preferenceOriginTag; 629 origin && _ckySetFocus(origin) 630} 631function _ckyGetPreferenceClass() { 632 return _ckyGetPtype() === 'pushdown' ? 'cky-consent-bar-expand' : 'cky-modal-open'; 633} 634 635function _ckyGetRevisit() { 636 const revisit = _ckyGetElementByTag('revisit-consent'); 637 return revisit && revisit || false; 638} 639function _ckyHideRevisit() { 640 const revisit = _ckyGetRevisit(); 641 revisit && revisit.classList.add('cky-revisit-hide') 642} 643function _ckyShowRevisit() { 644 const revisit = _ckyGetRevisit(); 645 revisit && revisit.classList.remove('cky-revisit-hide') 646} 647function _ckySetPreferenceAction(tagName = false) { 648 _ckyStore._preferenceOriginTag = tagName; 649 if (_ckyGetType() === 'classic') { 650 _ckyTogglePreferenceCenter(); 651 _ckyToggleAriaExpandStatus("=settings-button"); 652 } else { 653 _ckyShowPreferenceCenter(); 654 } 655} 656function _ckyGetFocusableElements(element) { 657 const wrapperElement = document.querySelector(`[data-cky-tag="${element}"]`); 658 if (!wrapperElement) return []; 659 const focussableElements = Array.from( 660 wrapperElement.querySelectorAll( 661 'a:not([disabled]), button:not([disabled]), [tabindex]:not([disabled]):not([tabindex="-1"])' 662 ) 663 ).filter((element) => element.style.display !== "none"); 664 if (focussableElements.length <= 0) return []; 665 return [ 666 focussableElements[0], 667 focussableElements[focussableElements.length - 1], 668 ]; 669} 670function _ckyLoopFocus() { 671 const activeLaw = _ckyGetLaw(); 672 const bannerType = _ckyGetType(); 673 if (bannerType === "classic") return; 674 if (bannerType === "popup") { 675 const [firstElementBanner, lastElementBanner] = 676 _ckyGetFocusableElements("notice"); 677 _ckyAttachFocusLoop(firstElementBanner, lastElementBanner, true); 678 _ckyAttachFocusLoop(lastElementBanner, firstElementBanner); 679 } 680 const [firstElementPopup, lastElementPopup] = _ckyGetFocusableElements( 681 activeLaw === "ccpa" ? "optout-popup" : "detail" 682 ); 683 _ckyAttachFocusLoop(firstElementPopup, lastElementPopup, true); 684 _ckyAttachFocusLoop(lastElementPopup, firstElementPopup); 685} 686function _ckyAttachFocusLoop(element, targetElement, isReverse = false) { 687 if (!element || !targetElement) return; 688 element.addEventListener("keydown", (event) => { 689 if ( 690 event.which !== 9 || 691 (isReverse && !event.shiftKey) || 692 (!isReverse && event.shiftKey) 693 ) 694 return; 695 event.preventDefault(); 696 targetElement.focus(); 697 }); 698} 699 700/** 701 * Replace footer shadow with current preference center background. 702 * 703 * @param {object} $doc Dom node. 704 * @returns 705 */ 706function _ckySetFooterShadow($doc) { 707 const footer = $doc.querySelector('[data-cky-tag="detail"] .cky-footer-shadow'); 708 const preference = $doc.querySelector('[data-cky-tag="detail"]'); 709 if (!footer) return; 710 const background = preference && preference.style.backgroundColor || '#ffffff'; 711 footer.style.background = `linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, ${background 712 } 100%)`; 713} 714 715/** 716 * Remove all the rejected cookies. 717 * 718 * @param {object} cookies Cookies list. 719 */
720function _ckyRemoveDeadCookies({ cookies }) { 721 const currentCookieMap = ref._ckyGetCookieMap(); 722 for (const { cookieID, domain } of cookies) 723 if (currentCookieMap[cookieID]) 724 [domain, ""].map((cookieDomain) => 725 ref._ckySetCookie(cookieID, "", 0, cookieDomain) 726 ); 727} 728function _ckySetPreferenceCheckBoxStates(revisit = false) { 729 for (const category of _ckyStore._categories) { 730 const cookieValue = ref._ckyGetFromStore(category.slug); 731 const checked = 732 cookieValue === "yes" || 733 (!cookieValue && 734 category.defaultConsent[_ckyGetLaw()]) || category.isNecessary; 735 736 const disabled = category.isNecessary; 737 const shortCodeData = _ckyStore._shortCodes.find( 738 (code) => code.key === 'cky_category_toggle_label' 739 ); 740 const toggleTextFormatted = shortCodeData.content.replace( 741 `[cky_preference_{{category_slug}}_title]`, 742 category.name 743 ); 744 _ckySetCheckboxes( 745 category, 746 checked, 747 disabled, 748 toggleTextFormatted, 749 revisit 750 ); 751 _ckySetPreferenceState(category); 752 } 753} 754 755function _ckySetCheckboxes( 756 category, 757 checked, 758 disabled, 759 formattedLabel, 760 revisit = false 761) { 762 const toggle = _ckyStore._bannerConfig.config.preferenceCenter.toggle; 763 const activeColor = toggle.states.active.styles['background-color']; 764 const inactiveColor = toggle.states.inactive.styles['background-color']; 765 766 [`ckyCategoryDirect`, `ckySwitch`].map((key) => { 767 const boxElem = document.getElementById(`${key}${category.slug}`); 768 if (!boxElem) return; 769 _ckySetCategoryToggle( 770 boxElem, 771 category, 772 revisit); 773 boxElem.checked = checked; 774 boxElem.disabled = disabled; 775 boxElem.style.backgroundColor = checked ? activeColor : inactiveColor; 776 _ckySetCheckBoxAriaLabel(boxElem, checked, formattedLabel); 777 if (revisit) return; 778 boxElem.addEventListener("change", ({ currentTarget: elem }) => { 779 const isChecked = elem.checked; 780 elem.style.backgroundColor = isChecked ? activeColor : inactiveColor; 781 _ckySetCheckBoxAriaLabel(boxElem, isChecked, formattedLabel); 782 }); 783 return boxElem; 784 }); 785} 786function _ckySetCategoryToggle(element, category = {}, revisit = false) { 787 if (revisit) return; 788 if (element.parentElement.getAttribute('data-cky-tag') === 'detail-category-toggle') { 789 _ckySetCategoryPreferenceToggle(element, category); 790 } else if (element.parentElement.getAttribute('data-cky-tag') === 'detail-category-preview-toggle') { 791 _ckySetCategoryPreview(element, category); 792 } 793 if (!category.isNecessary) { 794 const categoryName = category.name; 795 const categoryTitle = document.querySelector(`[data-cky-tag="detail-category-title"][aria-label="${categoryName}"]`); 796 if (categoryTitle) { 797 const toggleContainer = categoryTitle.closest('.cky-accordion-item'); 798 const necessaryText = toggleContainer.querySelector('.cky-always-active'); 799 necessaryText && necessaryText.remove(); 800 } 801 } 802} 803function _ckySetCategoryPreferenceToggle(element, category) { 804 let toggleContainer = element.closest('.cky-accordion-item'); 805 if (!toggleContainer) return; 806 const toggleSwitch = toggleContainer.querySelector('.cky-switch'); 807 if (category.isNecessary) { 808 toggleSwitch && toggleSwitch.remove(); 809 } else { 810 if (_ckyGetType() === 'classic' && _ckyStore._bannerConfig.config.categoryPreview.status || (category.cookies && category.cookies.length === 0)) { 811 toggleSwitch && toggleSwitch.remove(); 812 } 813 } 814} 815function _ckySetPreferenceState(category) { 816 if (_ckyStore._bannerConfig.config.auditTable.status === false) { 817 const tableElement = document.querySelector( 818 `#ckyDetailCategory${category.slug} [data-cky-tag="audit-table"]` 819 ); 820 tableElement && tableElement.remove(); 821 const chevronElement = document.querySelector( 822 `#ckyDetailCategory${category.slug} .cky-accordion-chevron` 823 ); 824 chevronElement && chevronElement.classList.add("cky-accordion-chevron-hide"); 825 } 826} 827function _ckySetCategoryPreview(element, category) {
828 if ((category.cookies && category.cookies.length === 0) && !category.isNecessary) 829 element.parentElement.parentElement.remove(); 830} 831 832function _ckySetCheckBoxAriaLabel(boxElem, isChecked, formattedLabel, isCCPA = false) { 833 834 if (!boxElem) return; 835 const keyName = isChecked ? "disable" : "enable"; 836 const textCode = `cky_${keyName}_${isCCPA ? "optout" : "category"}_label`; 837 const shortCodeData = _ckyStore._shortCodes.find( 838 (code) => code.key === textCode 839 ); 840 if (!shortCodeData) return; 841 const labelText = formattedLabel 842 .replace(/{{status}}/g, keyName) 843 .replace(`[${textCode}]`, shortCodeData.content); 844 boxElem.setAttribute("aria-label", labelText); 845} 846/** 847 * Clear opt-out success countdown timers (interval + timeout). 848 * 849 * @returns {void} 850 */ 851function _ckyClearOptoutSuccessTimers() { 852 if (_ckyStore._optoutSuccessCountdownInterval) { 853 clearInterval(_ckyStore._optoutSuccessCountdownInterval); 854 _ckyStore._optoutSuccessCountdownInterval = null; 855 } 856 if (_ckyStore._optoutSuccessAutoCloseTimer) { 857 clearTimeout(_ckyStore._optoutSuccessAutoCloseTimer); 858 _ckyStore._optoutSuccessAutoCloseTimer = null; 859 } 860} 861 862function _ckyIsOptoutSuccessVisible() { 863 const el = _ckyGetElementByTag("optout-success"); 864 return !!(el && !el.classList.contains("cky-hide")); 865} 866 867function _ckyDismissOptoutSuccessCountdown() { 868 _ckyRemoveBanner(); 869 _ckyHidePreferenceCenter(); 870 _ckyAfterConsent(); 871} 872 873/** 874 * Show opt-out success UI after save, run countdown, then dismiss banner. 875 * 876 * @returns {void} 877 */ 878function _ckyShowOptoutSuccessMessage() { 879 _ckyClearOptoutSuccessTimers(); 880 881 const buttonWrapper = _ckyGetElementByTag("optout-buttons"); 882 const successMessage = _ckyGetElementByTag("optout-success"); 883 const countdownElement = _ckyGetElementByTag("optout-success-subtext"); 884 const ccpaCheckbox = document.getElementById("ckyCCPAOptOut"); 885 886 if (!buttonWrapper || !successMessage) { 887 _ckyDismissOptoutSuccessCountdown(); 888 return; 889 } 890 891 buttonWrapper.style.display = "none"; 892 successMessage.classList.remove("cky-hide"); 893 successMessage.setAttribute("aria-live", "polite"); 894 successMessage.focus(); 895 if (ccpaCheckbox) ccpaCheckbox.disabled = true; 896 _ckyClassAdd("=optout-option", "cky-disabled", false); 897 898 const countdownTimerEl = 899 (countdownElement && 900 countdownElement.querySelector("#ckyCountdownTimer")) || 901 document.getElementById("ckyCountdownTimer"); 902 903 let timeRemaining = CKY_OPTOUT_SUCCESS_SECONDS; 904 if ( 905 countdownElement && 906 !countdownTimerEl && 907 !_ckyStore._optoutSuccessSubtextTemplate 908 ) { 909 _ckyStore._optoutSuccessSubtextTemplate = 910 countdownElement.textContent || 911 `Banner closes automatically in ${CKY_OPTOUT_SUCCESS_SECONDS} s...`; 912 } 913 const template = _ckyStore._optoutSuccessSubtextTemplate; 914 const hasDigit = template && /\d+/.test(template); 915 const updateSubtext = () => { 916 if (!countdownElement) return; 917 if (countdownTimerEl) { 918 countdownTimerEl.textContent = String(timeRemaining); 919 return; 920 } 921 countdownElement.textContent = hasDigit 922 ? template.replace(/\d+/, String(timeRemaining)) 923 : `Banner closes automatically in ${timeRemaining} s...`; 924 }; 925 updateSubtext(); 926 927 _ckyStore._optoutSuccessCountdownInterval = setInterval(() => { 928 timeRemaining -= 1; 929 if (timeRemaining >= 0) updateSubtext(); 930 }, 1000); 931 932 _ckyStore._optoutSuccessAutoCloseTimer = setTimeout( 933 _ckyDismissOptoutSuccessCountdown, 934 CKY_OPTOUT_SUCCESS_DISMISS_MS 935 ); 936} 937 938/** 939 * Reset opt-out success UI (timers, visibility, checkbox, subtext). 940 * 941 * @returns {void} 942 */ 943function _ckyResetOptoutSuccessMessage() { 944 _ckyClearOptoutSuccessTimers(); 945 946 const buttonWrapper = _ckyGetElementByTag("optout-buttons"); 947 const successMessage = _ckyGetElementByTag("optout-success"); 948 const countdownElement = _ckyGetElementByTag("optout-success-subtext"); 949 const ccpaCheckbox = document.getElementById("ckyCCPAOptOut"); 950 951 if (buttonWrapper) buttonWrapper.style.display = ""; 952 if (successMessage) successMessage.classList.add("cky-hide"); 953 if (ccpaCheckbox) ccpaCheckbox.disabled = false;
954 _ckyClassRemove("=optout-option", "cky-disabled", false); 955 const resetTimerEl = 956 (countdownElement && 957 countdownElement.querySelector("#ckyCountdownTimer")) || 958 document.getElementById("ckyCountdownTimer"); 959 if (resetTimerEl) { 960 resetTimerEl.textContent = ""; 961 } else if (countdownElement && _ckyStore._optoutSuccessSubtextTemplate) { 962 countdownElement.textContent = _ckyStore._optoutSuccessSubtextTemplate; 963 } 964} 965 966/** 967 * Opt-out confirm: if CCPA + opted out, save consent then show success + countdown; else normal save/close. 968 * 969 * @returns {Function} Click handler 970 */ 971function _ckyHandleOptoutConfirm() { 972 return () => { 973 if (_ckyGetLaw() !== "ccpa" || !_ckyFindCheckBoxValue()) { 974 _ckyAcceptReject()(); 975 return; 976 } 977 _ckyAcceptCookies(); 978 _ckyShowOptoutSuccessMessage(); 979 }; 980} 981 982/** 983 * Opt-out popup close: dismiss countdown if success is visible, else normal close. 984 * 985 * @returns {void} 986 */ 987function _ckyHandleOptoutPopupClose() { 988 if (_ckyIsOptoutSuccessVisible()) { 989 ref._ckySetInStore("action", "yes"); 990 _ckyDismissOptoutSuccessCountdown(); 991 return; 992 } 993 _ckyHidePreferenceCenter(); 994} 995 996/** 997 * Render banner after processing. 998 */ 999function _ckyRenderBanner() { 1000 const template = document.getElementById('ckyBannerTemplate'); 1001 const templateHtml = template.innerHTML; 1002 const doc = new DOMParser().parseFromString(templateHtml, 'text/html'); 1003 _ckySetFooterShadow(doc); 1004 document.body.insertAdjacentHTML( 1005 "afterbegin", 1006 doc.body.innerHTML 1007 ); 1008 if (_ckyGetType() === "classic") _ckyToggleAriaExpandStatus("=settings-button", "false"); 1009 _ckySetPreferenceCheckBoxStates(); 1010 _ckyAttachCategoryListeners(); 1011 _ckyRegisterListeners(); 1012 _ckySetCCPAOptions(); 1013 _ckySetPlaceHolder(); 1014 _ckyAttachReadMore(); 1015 _ckyAttachShowMoreLessStyles(); 1016 _ckyAttachAlwaysActiveStyles(); 1017 _ckyAttachManualLinksStyles(); 1018 _ckyRemoveStyles(); 1019 _ckyAddPositionClass();
1020 _ckyAddRtlClass(); 1021 _ckySetPoweredBy(); 1022 _ckyLoopFocus(); 1023 _ckyAddPreferenceCenterClass(); 1024} 1025 1026/** 1027 * Accept or reject the consent based on the option. 1028 * 1029 * @param {string} option Type of consent. 1030 * @returns {void} 1031 */ 1032function _ckyAcceptReject(option = "custom") { 1033 return () => { 1034 _ckyAcceptCookies(option); 1035 _ckyRemoveBanner(); 1036 _ckyHidePreferenceCenter(); 1037 _ckyAfterConsent(); 1038 }; 1039} 1040 1041function _ckyActionClose() { 1042 ref._ckySetInStore("action", "yes"); 1043 if (_ckyIsOptoutSuccessVisible()) { 1044 _ckyDismissOptoutSuccessCountdown(); 1045 return; 1046 } 1047 _ckyRemoveBanner(); 1048} 1049/** 1050 * Consent accept callback. 1051 * 1052 * @param {string} choice Type of consent. 1053 */ 1054function _ckyAcceptCookies(choice = "all") { 1055 const activeLaw = _ckyGetLaw(); 1056 const ccpaCheckBoxValue = _ckyFindCheckBoxValue(); 1057 1058 ref._ckySetInStore("action", "yes"); 1059 if (activeLaw === 'gdpr') { 1060 ref._ckySetInStore("consent", choice === "reject" ? "no" : "yes"); 1061 } else { 1062 ref._ckySetInStore("consent", ccpaCheckBoxValue ? "yes" : "no"); 1063 } 1064 const responseCategories = { accepted: [], rejected: [] }; 1065 for (const category of _ckyStore._categories) { 1066 let valueToSet = "no"; 1067 if (activeLaw === 'gdpr') { 1068 valueToSet = 1069 !category.isNecessary && 1070 (choice === "reject" || 1071 (choice === "custom" && !_ckyFindCheckBoxValue(category.slug))) 1072 ? "no" 1073 : "yes"; 1074 } else { 1075 valueToSet = ccpaCheckBoxValue && !category.defaultConsent.ccpa ? "no" : "yes"; 1076 } 1077 ref._ckySetInStore(`${category.slug}`, valueToSet); 1078 if (valueToSet === "no") { 1079 responseCategories.rejected.push(category.slug); 1080 _ckyRemoveDeadCookies(category); 1081 } else responseCategories.accepted.push(category.slug); 1082 } 1083 _ckyUnblock(); 1084 _ckyFireEvent(responseCategories); 1085} 1086function _ckySetShowMoreLess() { 1087 const activeLaw = _ckyGetLaw(); 1088 const showCode = _ckyStore._shortCodes.find( 1089 (code) => code.key === "cky_show_desc" 1090 ); 1091 const hideCode = _ckyStore._shortCodes.find( 1092 (code) => code.key === "cky_hide_desc" 1093 ); 1094 1095 if (!showCode || !hideCode) return; 1096 const hideButtonContent = hideCode.content; 1097 const showButtonContent = showCode.content; 1098 1099 const contentLimit = window.innerWidth < 376 ? 150 : 300; 1100 const element = document.querySelector( 1101 `[data-cky-tag="${activeLaw === "gdpr" ? "detail" : "optout"}-description"]` 1102 ); 1103 if (!element) return; 1104 const content = element.textContent; 1105 if (content.length < contentLimit) return; 1106 const contentHTML = element.innerHTML; 1107 const htmlDoc = new DOMParser().parseFromString(contentHTML, "text/html"); 1108 const innerElements = htmlDoc.querySelectorAll("body > p"); 1109 if (innerElements.length <= 1) return; 1110 let strippedContent = ``; 1111 for (let index = 0; index < innerElements.length; index++) { 1112 if (index === innerElements.length - 1) continue; 1113 const el = innerElements[index]; 1114 if (`${strippedContent}${el.outerHTML}`.length > contentLimit) 1115 el.insertAdjacentHTML("beforeend", `... ${showButtonContent}`); 1116 strippedContent = `${strippedContent}${el.outerHTML}`; 1117 if (strippedContent.length > contentLimit) break; 1118 } 1119 1120 function showMoreHandler() { 1121 element.innerHTML = `${contentHTML}${hideButtonContent}`; 1122 _ckyAttachListener("=hide-desc-button", showLessHandler); 1123 _ckyAttachShowMoreLessStyles(); 1124 } 1125 function showLessHandler() { 1126 element.innerHTML = strippedContent; 1127 _ckyAttachListener("=show-desc-button", showMoreHandler); 1128 _ckyAttachShowMoreLessStyles(); 1129 } 1130 showLessHandler(); 1131} 1132/** 1133 * Toggle show more or less on click event. 1134 * 1135 * @param {object} object Object containing toggle buttons and texts. 1136 * @param {*} element Target element. 1137 */ 1138function _ckyToggleMoreLess(object, element) { 1139 let { 1140 currentTarget, 1141 target 1142 } = element; 1143 if (target && target.tagName.toUpperCase() !== 'BUTTON') return; 1144 const ariaExpanded = currentTarget.getAttribute('aria-expanded'); 1145 const trimmed = ariaExpanded === 'false'; 1146 let btn = object.btnTrim; 1147 let text = object.originalText; 1148 if (!trimmed) { 1149 btn = object.btnExpand; 1150 text = object.truncatedText; 1151 } 1152 currentTarget.innerHTML = `${text}${btn}`; 1153 currentTarget.ariaExpanded = trimmed; 1154} 1155 1156/** 1157 * Add styles to the shortcode HTML rendered outside of the banner. 1158 * 1159 * @returns {void} 1160 */
1161function _ckyAttachShortCodeStyles() { 1162 const shortCodes = _ckyStore._tags; 1163 Array.prototype.forEach.call(shortCodes, function (shortcode) { 1164 document.querySelectorAll('[data-cky-tag=' + shortcode.tag + ']').forEach(function (item) { 1165 let styles = ''; 1166 for (const key in shortcode.styles) { 1167 styles += `${key}: ${shortcode.styles[key]};`; 1168 } 1169 item.style.cssText = styles; 1170 }); 1171 }); 1172} 1173 1174/** Script blocker Version 2 */ 1175 1176const _ckyCreateElementBackup = document.createElement; 1177document.createElement = (...args) => { 1178 const createdElement = _ckyCreateElementBackup.call(document, ...args); 1179 if (createdElement.nodeName.toLowerCase() !== "script") return createdElement; 1180 const originalSetAttribute = createdElement.setAttribute.bind(createdElement); 1181 Object.defineProperties(createdElement, { 1182 src: { 1183 get: function () { 1184 return createdElement.getAttribute("src"); 1185 }, 1186 set: function (value) { 1187 if (_ckyShouldChangeType(createdElement, value)) 1188 originalSetAttribute("type", "javascript/blocked"); 1189 originalSetAttribute("src", value); 1190 return true; 1191 }, 1192 }, 1193 type: { 1194 get: function () { 1195 return createdElement.getAttribute("type"); 1196 }, 1197 set: function (value) { 1198 value = _ckyShouldChangeType(createdElement) 1199 ? "javascript/blocked" 1200 : value; 1201 originalSetAttribute("type", value); 1202 return true; 1203 }, 1204 }, 1205 }); 1206 createdElement.setAttribute = (name, value) => { 1207 if (name === "type" || name === "src") 1208 return (createdElement[name] = value); 1209 originalSetAttribute(name, value); 1210 if (name === "data-cookieyes" && !_ckyShouldChangeType(createdElement)) 1211 originalSetAttribute("type", "text/javascript"); 1212 }; 1213 return createdElement; 1214}; 1215 1216function _ckyMutationObserver(mutations) { 1217 for (const { addedNodes } of mutations) { 1218 for (const node of addedNodes) { 1219 if ( 1220 !node.src || 1221 !node.nodeName || 1222 !["script", "iframe"].includes(node.nodeName.toLowerCase()) 1223 ) 1224 continue; 1225 try { 1226 const urlToParse = node.src.startsWith("//") 1227 ? `${window.location.protocol}${node.src}` 1228 : node.src; 1229 const { hostname, pathname } = new URL(urlToParse); 1230 const cleanedHostname = _ckyCleanHostName(`${hostname}${pathname}`); 1231 _ckyAddProviderToList(node, cleanedHostname); 1232 if (!_ckyShouldBlockProvider(cleanedHostname)) continue; 1233 const uniqueID = ref._ckyRandomString(8, false); 1234 if (node.nodeName.toLowerCase() === "iframe") 1235 _ckyAddPlaceholder(node, uniqueID); 1236 else { 1237 node.type = "javascript/blocked"; 1238 const scriptEventListener = function (event) { 1239 event.preventDefault(); 1240 node.removeEventListener( 1241 "beforescriptexecute", 1242 scriptEventListener 1243 ); 1244 }; 1245 node.addEventListener("beforescriptexecute", scriptEventListener); 1246 } 1247 const position = 1248 document.head.compareDocumentPosition(node) & 1249 Node.DOCUMENT_POSITION_CONTAINED_BY 1250 ? "head" 1251 : "body"; 1252 node.remove(); 1253 _ckyStore._backupNodes.push({ 1254 position: position, 1255 node: node.cloneNode(), 1256 uniqueID, 1257 }); 1258 } catch (error) { 1259 } 1260 } 1261 } 1262} 1263 1264function _ckyUnblock() { 1265 if (navigator.doNotTrack === 1) return; 1266 const ckyconsent = ref._ckyGetFromStore("consent"); 1267 if ( 1268 _ckyGetLaw() === "gdpr" && 1269 (!ckyconsent || ckyconsent !== "yes") 1270 ) 1271 return; 1272 _ckyStore._backupNodes = _ckyStore._backupNodes.filter( 1273 ({ position, node, uniqueID }) => { 1274 try { 1275 if (_ckyShouldBlockProvider(node.src)) return true; 1276 if (node.nodeName.toLowerCase() === "script") { 1277 const scriptNode = document.createElement("script"); 1278 scriptNode.src = node.src; 1279 scriptNode.type = "text/javascript"; 1280 document[position].appendChild(scriptNode); 1281 } else { 1282 const frame = document.getElementById(uniqueID); 1283 if (!frame) return false;
1284 const iframe = document.createElement("iframe"); 1285 iframe.src = node.src; 1286 iframe.width = frame.offsetWidth; 1287 iframe.height = frame.offsetHeight; 1288 frame.parentNode.insertBefore(iframe, frame); 1289 frame.parentNode.removeChild(frame); 1290 } 1291 return false; 1292 } catch (error) { 1293 console.error(error); 1294 return false; 1295 } 1296 } 1297 ); 1298} 1299 1300function _ckyClearListeners() { 1301 _nodeListObserver.disconnect(); 1302 document.createElement = _ckyCreateElementBackup; 1303} 1304function _ckyAddProviderToList(node, cleanedHostname) { 1305 const nodeCategory = 1306 node.hasAttribute("data-cookieyes") && node.getAttribute("data-cookieyes"); 1307 if (!nodeCategory) return; 1308 const categoryName = nodeCategory.replace("cookieyes-", ""); 1309 for (const category of _ckyStore._categories) 1310 if (category.isNecessary && category.slug === categoryName) return; 1311 const provider = _ckyStore._providersToBlock.find( 1312 ({ re }) => re === cleanedHostname 1313 ); 1314 if (!provider) 1315 _ckyStore._providersToBlock.push({ 1316 re: cleanedHostname, 1317 categories: [categoryName], 1318 fullPath: false, 1319 }); 1320 else if (!provider.isOverridden) { 1321 provider.categories = [categoryName]; 1322 provider.isOverridden = true; 1323 } else if (!provider.categories.includes(categoryName)) 1324 provider.categories.push(categoryName); 1325} 1326
1327const _nodeListObserver = new MutationObserver(_ckyMutationObserver); 1328_nodeListObserver.observe(document.documentElement, { 1329 childList: true, 1330 subtree: true, 1331}); 1332function _ckyCleanHostName(name) { 1333 return name.replace(/^www./, ""); 1334} 1335 1336function _ckyIsCategoryToBeBlocked(category) { 1337 const cookieValue = ref._ckyGetFromStore(category); 1338 return ( 1339 cookieValue === "no" || 1340 (!cookieValue && 1341 _ckyStore._categories.some( 1342 (cat) => cat.slug === category && !cat.isNecessary 1343 )) 1344 ); 1345} 1346 1347function _ckyShouldBlockProvider(formattedRE) { 1348 const provider = _ckyStore._providersToBlock.find(({ re }) => 1349 new RegExp(_ckyEscapeRegex(re)).test(formattedRE) 1350 ); 1351 return ( 1352 provider && 1353 provider.categories.some((category) => _ckyIsCategoryToBeBlocked(category)) 1354 ); 1355} 1356function _ckyShouldChangeType(element, src) { 1357 return ( 1358 (element.hasAttribute("data-cookieyes") && 1359 _ckyIsCategoryToBeBlocked( 1360 element.getAttribute("data-cookieyes").replace("cookieyes-", "") 1361 )) || 1362 _ckyShouldBlockProvider(src ? src : element.src) 1363 ); 1364} 1365 1366/** 1367 * Add readmore button to consent notice. 1368 * 1369 * @returns void 1370 */ 1371function _ckyAttachReadMore() { 1372 const readMoreButton = _ckyStore._shortCodes.find( 1373 (code) => code.key === "cky_readmore" 1374 ); 1375 if (!readMoreButton.status) return; 1376 const content = readMoreButton.content; 1377 const styles = _ckyStore._bannerConfig.config.readMore.styles; 1378 const readMoreElement = document.querySelector( 1379 '[data-cky-tag="description"]' 1380 ); 1381 if (!readMoreElement) return; 1382 if (readMoreElement.childNodes.length > 1) { 1383 const innerElement = document.querySelector( 1384 '[data-cky-tag="description"] p:last-child' 1385 ); 1386 innerElement && innerElement.insertAdjacentHTML( 1387 "beforeend", 1388 ` ${content}` 1389 ); 1390 } else { 1391 readMoreElement.insertAdjacentHTML( 1392 "beforeend", 1393 ` ${content}` 1394 ); 1395 } 1396 const placeHolders = document.querySelectorAll( 1397 `[data-cky-tag="readmore-button"]` 1398 ); 1399 if (placeHolders.length < 1) return; 1400 Array.from(placeHolders).forEach((placeHolder) => { 1401 for (const style in styles) { 1402 if (!styles[style]) continue; 1403 placeHolder.style[style] = styles[style]; 1404 } 1405 }); 1406} 1407 1408/** 1409 * Apply styles to show more/show less buttons. 1410 * 1411 * @returns void 1412 */ 1413function _ckyAttachShowMoreLessStyles() { 1414 if (!_ckyStore._bannerConfig.config.showMore || !_ckyStore._bannerConfig.config.showLess) return; 1415 1416 const showMoreStyles = _ckyStore._bannerConfig.config.showMore.styles; 1417 const showLessStyles = _ckyStore._bannerConfig.config.showLess.styles; 1418 1419 if (showMoreStyles) { 1420 const showMoreButtons = document.querySelectorAll('[data-cky-tag="show-desc-button"]'); 1421 if (showMoreButtons.length > 0) { 1422 Array.from(showMoreButtons).forEach((button) => { 1423 for (const style in showMoreStyles) { 1424 if (!showMoreStyles[style]) continue; 1425 button.style[style] = showMoreStyles[style]; 1426 } 1427 }); 1428 } 1429 } 1430 1431 if (showLessStyles) { 1432 const showLessButtons = document.querySelectorAll('[data-cky-tag="hide-desc-button"]'); 1433 if (showLessButtons.length > 0) { 1434 Array.from(showLessButtons).forEach((button) => { 1435 for (const style in showLessStyles) { 1436 if (!showLessStyles[style]) continue; 1437 button.style[style] = showLessStyles[style]; 1438 } 1439 }); 1440 } 1441 } 1442} 1443 1444/** 1445 * Apply styles to Always Active text. 1446 * 1447 * @returns void 1448 */ 1449function _ckyAttachAlwaysActiveStyles() { 1450 if (!_ckyStore._bannerConfig.config.alwaysActive) return; 1451 1452 const alwaysActiveStyles = _ckyStore._bannerConfig.config.alwaysActive.styles; 1453 if (!alwaysActiveStyles) return; 1454 1455 const alwaysActiveElements = document.querySelectorAll('.cky-always-active'); 1456 if (alwaysActiveElements.length < 1) return;
1457 Array.from(alwaysActiveElements).forEach((element) => { 1458 for (const style in alwaysActiveStyles) { 1459 if (!alwaysActiveStyles[style]) continue; 1460 element.style[style] = alwaysActiveStyles[style]; 1461 } 1462 }); 1463} 1464 1465/** 1466 * Apply styles to manually added links. 1467 * 1468 * @returns void 1469 */ 1470function _ckyAttachManualLinksStyles() { 1471 if (!_ckyStore._bannerConfig.config.manualLinks) return; 1472 1473 const manualLinksStyles = _ckyStore._bannerConfig.config.manualLinks.styles; 1474 if (!manualLinksStyles) return; 1475 1476 const manualLinks = document.querySelectorAll('.cky-link, a.cky-link, [data-cky-tag="detail"] a, [data-cky-tag="optout-popup"] a, [data-cky-tag="notice"] a'); 1477 if (manualLinks.length < 1) return; 1478 Array.from(manualLinks).forEach((link) => { 1479 if (link.getAttribute('data-cky-tag') === 'readmore-button') return; 1480 for (const style in manualLinksStyles) { 1481 if (!manualLinksStyles[style]) continue; 1482 link.style[style] = manualLinksStyles[style]; 1483 } 1484 if (manualLinksStyles.color) { 1485 link.style.textDecorationColor = manualLinksStyles.color; 1486 } 1487 }); 1488} 1489 1490function _ckyAfterConsent() { 1491 if (_ckyGetLaw() === 'gdpr') _ckySetPreferenceCheckBoxStates(true); 1492 1493 if (_ckyStore._bannerConfig.behaviours.reloadBannerOnAccept === true) { 1494 window.location.reload(); 1495 } 1496} 1497 1498function _ckyAttachNoticeStyles() { 1499 if (document.getElementById("cky-style") || !_ckyStyle) return; 1500 document.head.insertAdjacentHTML( 1501 "beforeend", 1502 ` <style id="cky-style">${_ckyStyle.css}</style>` 1503 ); 1504} 1505 1506function _ckyFindCheckBoxValue(id = "") { 1507 const elementsToCheck = id 1508 ? [`ckySwitch`, `ckyCategoryDirect`] 1509 : [`ckyCCPAOptOut`]; 1510 return elementsToCheck.some((key) => { 1511 const checkBox = document.getElementById(`${key}${id}`); 1512 return checkBox && checkBox.checked; 1513 }); 1514} 1515 1516function _ckyAddPlaceholder(htmlElm, uniqueID) { 1517 const shortCodeData = _ckyStore._shortCodes.find( 1518 (code) => code.key === 'cky_video_placeholder' 1519 ); 1520 const videoPlaceHolderDataCode = shortCodeData.content; 1521 const { offsetWidth, offsetHeight } = htmlElm; 1522 if (offsetWidth === 0 || offsetHeight === 0) return; 1523 htmlElm.insertAdjacentHTML( 1524 "beforebegin", 1525 `${videoPlaceHolderDataCode}`.replace("[UNIQUEID]", uniqueID) 1526 ); 1527 const addedNode = document.getElementById(uniqueID); 1528 addedNode.style.width = `${offsetWidth}px`; 1529 addedNode.style.height = `${offsetHeight}px`; 1530 const innerTextElement = document.querySelector( 1531 `#${uniqueID} .video-placeholder-text-normal` 1532 ); 1533 innerTextElement.style.display = "none"; 1534 const youtubeID = _ckyGetYoutubeID(htmlElm.src); 1535 if (!youtubeID) return; 1536 addedNode.classList.replace( 1537 "video-placeholder-normal", 1538 "video-placeholder-youtube" 1539 ); 1540 addedNode.style.backgroundImage = `linear-gradient(rgba(76,72,72,.7),rgba(76,72,72,.7)),url('https://img.youtube.com/vi/${youtubeID}/maxresdefault.jpg')`; 1541 innerTextElement.classList.replace( 1542 "video-placeholder-text-normal", 1543 "video-placeholder-text-youtube" 1544 ); 1545} 1546function _ckyGetYoutubeID(src) { 1547 const match = src.match( 1548 /^.*(youtu\.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/ 1549 ); 1550 if (match && Array.isArray(match) && match[2] && match[2].length === 11) 1551 return match[2]; 1552 return false; 1553} 1554 1555function _ckySetPlaceHolder() { 1556 const status = _ckyStore._bannerConfig.config.videoPlaceholder.status; 1557 const styles = _ckyStore._bannerConfig.config.videoPlaceholder.styles; 1558 if (!status) return; 1559 if (!status) return; 1560 const placeHolders = document.querySelectorAll( 1561 `[data-cky-tag="placeholder-title"]` 1562 ); 1563 if (placeHolders.length < 1) return; 1564 Array.from(placeHolders).forEach((placeHolder) => { 1565 placeHolder.style.display = "block"; 1566 placeHolder.addEventListener("click", () => { 1567 if (ref._ckyGetFromStore("action")) _revisitCkyConsent(); 1568 }); 1569 for (const style in styles) { 1570 if (!styles[style]) continue; 1571 placeHolder.style[style] = styles[style]; 1572 } 1573 }); 1574}
1575function _ckyAddRtlClass() { 1576 if (!_ckyStore._rtl) return; 1577 const rtlElements = ['notice', 'detail', 'optout-popup', 'revisit-consent', 'video-placeholder'] 1578 rtlElements.forEach(function (item) { 1579 _ckyGetElementByTag(item) && _ckyGetElementByTag(item).classList.add('cky-rtl'); 1580 }); 1581} 1582 1583function _ckySetFocus(tagName) { 1584 const element = _ckyGetElementByTag(tagName); 1585 if (!element) return; 1586 element.focus(); 1587} 1588 1589function _ckySetPoweredBy() { 1590 let position = 'flex-end'; 1591 ['detail-powered-by', 'optout-powered-by'].map((key) => { 1592 const element = document.querySelector( 1593 `[data-cky-tag="${key}"]` 1594 ); 1595 if (!element) return; 1596 element.style.display = "flex"; 1597 element.style.justifyContent = position; 1598 element.style.alignItems = "center"; 1599 return element; 1600 }); 1601 1602} 1603function _ckyWatchBannerElement() { 1604 document.querySelector("body").addEventListener("click", (event) => { 1605 const selector = ".cky-banner-element, .cky-banner-element *"; 1606 if ( 1607 event.target.matches 1608 ? event.target.matches(selector) 1609 : event.target.msMatchesSelector(selector) 1610 ) 1611 _revisitCkyConsent(); 1612 }); 1613} 1614 1615function _ckyRemoveAllDeadCookies() { 1616 for (const category of _ckyStore._categories) { 1617 if (ref._ckyGetFromStore(category.slug) !== "yes") 1618 _ckyRemoveDeadCookies(category); 1619 } 1620} 1621 1622function _ckySetCCPAOptions() { 1623 const toggle = _ckyStore._bannerConfig.config.optOption.toggle; 1624 const activeColor = toggle.states.active.styles['background-color']; 1625 const inactiveColor = toggle.states.inactive.styles['background-color']; 1626 _ckyClassRemove("=optout-option", "cky-disabled", false); 1627 const toggleDataCode = _ckyStore._shortCodes.find( 1628 (code) => code.key === "cky_optout_toggle_label" 1629 ); 1630 const optOutTitle = _ckyStore._shortCodes.find( 1631 (code) => code.key === "cky_optout_option_title" 1632 ); 1633 const formattedLabel = toggleDataCode.content.replace( 1634 `[cky_optout_option_title]`, 1635 optOutTitle.content 1636 ); 1637 const checked = ref._ckyGetFromStore("consent") === "yes"; 1638 _ckySetCheckBoxInfo( 1639 document.getElementById(`ckyCCPAOptOut`), 1640 formattedLabel, 1641 { 1642 checked, 1643 disabled: false, 1644 addListeners: true, 1645 }, 1646 { activeColor, inactiveColor }, 1647 true 1648 ); 1649} 1650function _ckySetCheckBoxInfo( 1651 boxElem, 1652 formattedLabel, 1653 { checked, disabled, addListeners }, 1654 { activeColor, inactiveColor }, 1655 isCCPA = false 1656) { 1657 if (!boxElem) return; 1658 if (isCCPA && addListeners) 1659 _ckyAttachListener("=optout-option-title", () => boxElem.click()); 1660 boxElem.checked = checked; 1661 boxElem.disabled = disabled; 1662 boxElem.style.backgroundColor = checked ? activeColor : inactiveColor; 1663 _ckySetCheckBoxAriaLabel(boxElem, checked, formattedLabel, isCCPA); 1664 if (!addListeners) return; 1665 boxElem.addEventListener("change", ({ currentTarget: elem }) => { 1666 const isChecked = elem.checked; 1667 elem.style.backgroundColor = isChecked ? activeColor : inactiveColor; 1668 _ckySetCheckBoxAriaLabel(boxElem, isChecked, formattedLabel, isCCPA); 1669 }); 1670} 1671 1672window.revisitCkyConsent = () => _revisitCkyConsent(); 1673 1674window.getCkyConsent = function () { 1675 const cookieConsent = { 1676 activeLaw: "", 1677 categories: {}, 1678 isUserActionCompleted: false, 1679 consentID: "", 1680 languageCode: "" 1681 }; 1682 1683 try { 1684 cookieConsent.activeLaw = _ckyGetLaw(); 1685 1686 _ckyStore._categories.forEach(category => { 1687 cookieConsent.categories[category.slug] = ref._ckyGetFromStore(category.slug) === "yes"; 1688 }); 1689 1690 cookieConsent.isUserActionCompleted = ref._ckyGetFromStore("action") === "yes"; 1691 cookieConsent.consentID = ref._ckyGetFromStore("consentid") || ""; 1692 cookieConsent.languageCode = _ckyStore._language || ""; 1693 } catch (e) { } 1694 1695 return cookieConsent; 1696};
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.