1/*! 2 * Forked from CookieConsent v2.8.9 3 * https://www.github.com/orestbida/cookieconsent 4 * Author Orest Bida 5 * Released under the MIT License 6 * Modified by Codingfreaks for Typo3 CMS integration 7 */ 8(function () { 9 'use strict'; 10 /** 11 * @param {HTMLElement} [root] - [optional] element where the cookieconsent will be appended 12 * @returns {Object} cookieconsent object with API 13 */ 14 var CookieConsent = function (root) { 15 16 /** 17 * CHANGE THIS FLAG FALSE TO DISABLE console.log() 18 */ 19 var ENABLE_LOGS = false; 20 21 var _config = { 22 'mode': 'opt-in', // 'opt-in', 'opt-out' 23 'current_lang': 0, // Set Default SySLanguage UID (0 = System Default Language) 24 'auto_language': null, 25 'autorun': true, // run as soon as loaded 26 'page_scripts': true, 27 'hide_from_bots': true, 28 'cookie_name': 'cf_cookie', 29 'cookie_expiration': 182, // default: 6 months (in days) 30 'cookie_domain': window.location.hostname, // default: current domain 31 'cookie_path': '/', 32 'cookie_same_site': 'Lax', 33 'use_rfc_cookie': false, 34 'autoclear_cookies': true, 35 'revision': 0, 36 'script_selector': 'data-service' 37 }; 38 39 var 40 /** 41 * Object which holds the main methods/API (.show, .run, ...) 42 */ 43 _cookieconsent = {}, 44 /** 45 * Object which holds the main Categorys selected) 46 */ 47 _categorysSelected = {}, 48 49 /** 50 * Global user configuration object 51 */ 52 user_config, 53 54 /** 55 * Internal state variables 56 */ 57 saved_cookie_content = {}, 58 cookie_data = null, 59 60 /** 61 * @type {Date} 62 */ 63 consent_date, 64 65 /** 66 * @type {Date} 67 */ 68 last_consent_update, 69 70 /** 71 * @type {string} 72 */ 73 consent_uuid, 74 75 /** 76 * @type {boolean} 77 */ 78 invalid_consent = true, 79 80 consent_modal_exists = false, 81 consent_modal_visible = false, 82 83 settings_modal_visible = false, 84 clicked_inside_modal = false, 85 current_modal_focusable, 86 87 all_table_headers, 88 all_blocks, 89 90 // Helper callback functions 91 // (avoid calling "user_config['onAccept']" all the time) 92 onAccept, 93 onChange, 94 onFirstAction, 95 96 revision_enabled = false, 97 valid_revision = true, 98 revision_message = '', 99 100 // State variables for the autoclearCookies function 101 changed_settings = [], 102 reload_page = false; 103 104 /** 105 * Accept type: 106 * - "all" 107 * - "necessary" 108 * - "custom" 109 * @type {string} 110 */ 111 var accept_type; 112 113 /** 114 * Contains all accepted categories 115 * @type {string[]} 116 */ 117 var accepted_categories = []; 118 119 /** 120 * Contains all non-accepted (rejected) categories 121 * @type {string[]} 122 */ 123 var rejected_categories = []; 124 125 /** 126 * Contains all categories enabled by default 127 * @type {string[]} 128 */ 129 var default_enabled_categories = []; 130 131 // Don't run plugin (to avoid indexing its text content) if bot detected 132 var is_bot = false; 133 134 /** 135 * Save reference to the last focused element on the page 136 * (used later to restore focus when both modals are closed) 137 */ 138 var last_elem_before_modal; 139 var last_consent_modal_btn_focus; 140 141 /** 142 * Both of the arrays below have the same structure: 143 * [0] => holds reference to the FIRST focusable element inside modal 144 * [1] => holds reference to the LAST focusable element inside modal 145 */ 146 var consent_modal_focusable = []; 147 var settings_modal_focusable = []; 148 149 /** 150 * Keep track of enabled/disabled categories 151 * @type {boolean[]} 152 */ 153 var toggle_states = []; 154 155 /** 156 * Stores all available categories 157 * @type {string[]} 158 */ 159 var all_categories = []; 160 161 /** 162 * Keep track of readonly toggles 163 * @type {boolean[]} 164 */ 165 var readonly_categories = []; 166 167 /** 168 * Pointers to main dom elements (to avoid retrieving them later using document.getElementById) 169 */ 170 var 171 /** @type {HTMLElement} */ html_dom = document.documentElement, 172 /** @type {HTMLElement} */ main_container, 173 /** @type {HTMLElement} */ all_modals_container, 174 /** @type {HTMLElement} */ consent_modal, 175 /** @type {HTMLElement} */ settings_container, 176 /** @type {HTMLElement} */ new_settings_blocks; 177 178 179 180 /** 181 * Update config settings 182 * @param {Object} user_config 183 */ 184 var _setConfig = function (_user_config) { 185 /** 186 * Make user configuration globally available 187 */ 188 user_config = _user_config; 189 190 _log("CookieConsent [CONFIG]: received_config_settings ", user_config); 191 192 if (typeof user_config['cookie_expiration'] === "number") 193 _config.cookie_expiration = user_config['cookie_expiration']; 194 195 if (typeof user_config['cookie_necessary_only_expiration'] === "number") 196 _config.cookie_necessary_only_expiration = user_config['cookie_necessary_only_expiration']; 197 198 if (typeof user_config['autorun'] === "boolean") 199 _config.autorun = user_config['autorun']; 200 201 if (typeof user_config['cookie_domain'] === "string") 202 _config.cookie_domain = user_config['cookie_domain']; 203 204 if (typeof user_config['cookie_same_site'] === "string") 205 _config.cookie_same_site = user_config['cookie_same_site']; 206 207 if (typeof user_config['cookie_path'] === "string") 208 _config.cookie_path = user_config['cookie_path']; 209 210 if (typeof user_config['cookie_name'] === "string") 211 _config.cookie_name = user_config['cookie_name']; 212 213 if (typeof user_config['onAccept'] === "function") 214 onAccept = user_config['onAccept']; 215 216 if (typeof user_config['onFirstAction'] === "function") 217 onFirstAction = user_config['onFirstAction']; 218 219 if (typeof user_config['onChange'] === "function") 220 onChange = user_config['onChange']; 221 222 if (user_config['mode'] === 'opt-out') 223 _config.mode = 'opt-out'; 224
225 if (typeof user_config['revision'] === "number") { 226 user_config['revision'] > -1 && (_config.revision = user_config['revision']); 227 revision_enabled = true; 228 } 229 230 if (typeof user_config['autoclear_cookies'] === "boolean") 231 _config.autoclear_cookies = user_config['autoclear_cookies']; 232 233 if (user_config['use_rfc_cookie'] === true) 234 _config.use_rfc_cookie = true; 235 236 if (typeof user_config['hide_from_bots'] === "boolean") { 237 _config.hide_from_bots = user_config['hide_from_bots']; 238 } 239 240 if (_config.hide_from_bots) { 241 is_bot = navigator && 242 ((navigator.userAgent && /bot|crawl|spider|slurp|teoma/i.test(navigator.userAgent)) || ( navigator.webdriver && navigator.userAgent.indexOf("CF-CookieScanner") === -1)); 243 } 244 245 _config.page_scripts = user_config['page_scripts'] === true; 246 247 if (user_config['auto_language'] === 'browser' || user_config['auto_language'] === true) { 248 _config.auto_language = 'browser'; 249 } else if (user_config['auto_language'] === 'document') { 250 _config.auto_language = 'document'; 251 } 252 253 _log("CookieConsent [LANG]: auto_language strategy is '" + _config.auto_language + "'"); 254 255 _config.current_lang = _resolveCurrentLang(user_config.languages, user_config['current_lang']); 256 } 257 258 /** 259 * Add an onClick listeners to all html elements with data-cc attribute 260 */ 261 var _addDataButtonListeners = function (elem) { 262 263 var _a = 'accept-'; 264 265 var show_settings = _getElements('c-settings'); 266 var accept_all = _getElements(_a + 'all'); 267 var accept_necessary = _getElements(_a + 'necessary'); 268 var accept_custom_selection = _getElements(_a + 'custom'); 269 270 for (var i = 0; i < show_settings.length; i++) { 271 show_settings[i].setAttribute('aria-haspopup', 'dialog'); 272 _addEvent(show_settings[i], 'click', function (event) { 273 event.preventDefault(); 274 _cookieconsent.showSettings(0); 275 }); 276 } 277 278 for (i = 0; i < accept_all.length; i++) { 279 _addEvent(accept_all[i], 'click', function (event) { 280 _acceptAction(event, 'all'); 281 }); 282 } 283 284 for (i = 0; i < accept_custom_selection.length; i++) { 285 _addEvent(accept_custom_selection[i], 'click', function (event) { 286 _acceptAction(event); 287 }); 288 } 289 290 for (i = 0; i < accept_necessary.length; i++) { 291 _addEvent(accept_necessary[i], 'click', function (event) { 292 _acceptAction(event, []); 293 }); 294 } 295 296 /** 297 * Return all elements with given data-cc role 298 * @param {string} data_role 299 * @returns {NodeListOf<Element>} 300 */ 301 function _getElements(data_role) { 302 return (elem || document).querySelectorAll('a[data-cc="' + data_role + '"], button[data-cc="' + data_role + '"]'); 303 } 304 305 /** 306 * Helper function: accept and then hide modals 307 * @param {PointerEvent} e source event 308 * @param {string} [accept_type] 309 */ 310 function _acceptAction(e, accept_type) { 311 e.preventDefault(); 312 _cookieconsent.accept(accept_type); 313 _cookieconsent.hideSettings(); 314 _cookieconsent.hide(); 315 } 316 } 317 318 /** 319 * Get a valid language (at least 1 must be defined) 320 * @param {string} lang - desired language 321 * @param {Object} all_languages - all defined languages 322 * @returns {string} validated language 323 */ 324 var _getValidatedLanguage = function (lang, all_languages) { 325 if (Object.prototype.hasOwnProperty.call(all_languages, lang)) { 326 return lang; 327 } else if (_getKeys(all_languages).length > 0) { 328 if (Object.prototype.hasOwnProperty.call(all_languages, _config.current_lang)) { 329 return _config.current_lang; 330 } else { 331 return _getKeys(all_languages)[0]; 332 } 333 } 334 } 335 336 /** 337 * Save reference to first and last focusable elements inside each modal 338 * to prevent losing focus while navigating with TAB 339 */ 340 var _getModalFocusableData = function () { 341 342 /** 343 * Note: any of the below focusable elements, which has the attribute tabindex="-1" AND is either 344 * the first or last element of the modal, won't receive focus during "open/close" modal 345 */ 346 var allowed_focusable_types = ['[href]', 'button', 'input', 'details', '[tabindex="0"]']; 347 348 function _getAllFocusableElements(modal, _array) { 349 var focus_later = false, focus_first = false;
350 // ie might throw exception due to complex unsupported selector => a:not([tabindex="-1"]) 351 try { 352 var focusable_elems = modal.querySelectorAll(allowed_focusable_types.join(':not([tabindex="-1"]), ')); 353 var attr, len = focusable_elems.length, i = 0; 354 355 while (i < len) { 356 357 attr = focusable_elems[i].getAttribute('data-focus'); 358 359 if (!focus_first && attr === "1") { 360 focus_first = focusable_elems[i]; 361 362 } else if (attr === "0") { 363 focus_later = focusable_elems[i]; 364 if (!focus_first && focusable_elems[i + 1].getAttribute('data-focus') !== "0") { 365 focus_first = focusable_elems[i + 1]; 366 } 367 } 368 369 i++; 370 } 371 372 } catch (e) { 373 return modal.querySelectorAll(allowed_focusable_types.join(', ')); 374 } 375 376 /** 377 * Save first and last elements (used to lock/trap focus inside modal) 378 */ 379 _array[0] = focusable_elems[0]; 380 _array[1] = focusable_elems[focusable_elems.length - 1]; 381 _array[2] = focus_later; 382 _array[3] = focus_first; 383 } 384 385 /** 386 * Get settings modal'S all focusable elements 387 * Save first and last elements (used to lock/trap focus inside modal) 388 */ 389 _getAllFocusableElements(all_modals_container.querySelector("#s-inr"), settings_modal_focusable); 390 391 /** 392 * If consent modal exists, do the same 393 */ 394 if (consent_modal_exists) { 395 _getAllFocusableElements(all_modals_container, consent_modal_focusable); 396 } 397 } 398 399 var _createConsentModal = function (lang) { 400 401 if (user_config['force_consent'] === true) 402 _addClass(html_dom, 'force--consent'); 403 404 // Create modal if it doesn't exist 405 if (!consent_modal) { 406 const consent_modal = _createNode('div'); 407 408 if(typeof CF_CONSENTMODAL_TEMPLATE !== "undefined"){ 409 consent_modal.innerHTML = CF_CONSENTMODAL_TEMPLATE; 410 }else{ 411 consent_modal.innerHTML = ` 412 <div id="cm" role="dialog" aria-modal="true" aria-hidden="false" aria-labelledby="c-ttl" aria-describedby="c-txt" style="visibility: hidden;"> 413 <div id="c-inr"> 414 <div id="c-inr-i"> 415 <div id="c-ttl" role="heading" aria-level="2"></div> 416 <div id="c-txt"></div> 417 </div> 418 <div id="c-bns"><button type="button" id="c-p-bn" class="c-bn"></button><button type="button" id="c-s-bn" class="c-bn c_link"></button><button type="button" id="c-t-bn" class="c-bn c_settings"></button></div> 419 </div> 420 <div id="c-footer"><div class="c-links"><div class="c-link-group">[##linkPrivacy##] [##linkImpress##]</div></div></div> 421 </div>`; 422 423 } 424 425 var overlay = _createNode('div'); 426 overlay.id = 'cm-ov'; 427 // Append consent modal to main container 428 all_modals_container.appendChild(consent_modal); 429 all_modals_container.appendChild(overlay); 430 /** 431 * Make modal by default hidden to prevent weird page jumps/flashes (shown only once css is loaded) 432 */ 433 consent_modal.style.visibility = overlay.style.visibility = "hidden"; 434 overlay.style.opacity = 0; 435 } 436 437 // Use insertAdjacentHTML instead of innerHTML 438 var consent_modal_title_value = user_config.languages[lang]['consent_modal']['title']; 439 440 // Add title (if valid) 441 if (consent_modal_title_value) { 442 all_modals_container.querySelector("#c-ttl").innerHTML = consent_modal_title_value; 443 } 444 445 var description = user_config.languages[lang]['consent_modal']['description']; 446 var impress_link = user_config.languages[lang]['consent_modal']['impress_link']; 447 var data_policy_link = user_config.languages[lang]['consent_modal']['data_policy_link']; 448 449 450 if(data_policy_link.length === 0 && impress_link.length === 0){ 451 all_modals_container.querySelector("#c-footer").style.display = "none"; 452 } 453 454 if (data_policy_link.length > 0) { 455 _replaceLink("[##linkPrivacy##]", data_policy_link); 456 } else { 457 _replaceLink("[##linkPrivacy##]", ""); 458 } 459 460 461 if (impress_link.length > 0) { 462 _replaceLink("[##linkImpress##]", impress_link); 463 } else { 464 _replaceLink("[##linkImpress##]", ""); 465 } 466 467 468 if (revision_enabled) { 469 if (!valid_revision) { 470 description = description.replace("{{revision_message}}", revision_message || user_config.languages[lang]['consent_modal']['revision_message'] || ""); 471 }else{ 472 description = description.replace("{{revision_message}}", ""); 473 } 474 }else{ 475 description = description.replace("{{revision_message}}", ""); 476 } 477 478 // Set description content 479 all_modals_container.querySelector("#c-txt").innerHTML = description; 480 481 var primary_btn_data = user_config.languages[lang]['consent_modal']['primary_btn'], // accept current selection 482 secondary_btn_data = user_config.languages[lang]['consent_modal']['secondary_btn'], 483 tertiary_btn_data = user_config.languages[lang]['consent_modal']['tertiary_btn']; 484 485 // Add primary button if not falsy 486 if (primary_btn_data) { 487 if (primary_btn_data['role'] === 'display_none') { 488 all_modals_container.querySelector("#c-p-bn").style.display = "none"; 489 }else if(primary_btn_data['role'] === "accept_all"){ 490 _addEvent(all_modals_container.querySelector("#c-p-bn"), "click", function () { 491 _cookieconsent.hide(); 492 _cookieconsent.accept("all"); 493 }); 494 } else if (primary_btn_data['role'] === 'accept_necessary') { 495 _addEvent(all_modals_container.querySelector("#c-p-bn"), 'click', function () { 496 _cookieconsent.hide(); 497 _cookieconsent.accept([]); // accept necessary only 498 }); 499 } else { 500 _addEvent(all_modals_container.querySelector("#c-p-bn"), 'click', function () { 501 _cookieconsent.showSettings(0); 502 }); 503 } 504 all_modals_container.querySelector("#c-p-bn").innerHTML = user_config.languages[lang]['consent_modal']['primary_btn']['text']; 505 } 506 507 // Add secondary button if not falsy 508 if (secondary_btn_data) { 509 if (secondary_btn_data['role'] === 'display_none') { 510 all_modals_container.querySelector("#c-s-bn").style.display = "none"; 511 }else if(secondary_btn_data['role'] === "accept_all"){ 512 _addEvent(all_modals_container.querySelector("#c-s-bn"), "click", function () { 513 _cookieconsent.hide(); 514 _cookieconsent.accept("all"); 515 }); 516 } else if (secondary_btn_data['role'] === 'accept_necessary') { 517 _addEvent(all_modals_container.querySelector("#c-s-bn"), 'click', function () { 518 _cookieconsent.hide(); 519 _cookieconsent.accept([]); // accept necessary only 520 }); 521 } else { 522 _addEvent(all_modals_container.querySelector("#c-s-bn"), 'click', function () { 523 _cookieconsent.showSettings(0); 524 }); 525 } 526 all_modals_container.querySelector("#c-s-bn").innerHTML = user_config.languages[lang]['consent_modal']['secondary_btn']['text']; 527 } 528 529 530 531 // Add tertiary button if not falsy c-t-bn 532 if(tertiary_btn_data){ 533 if (tertiary_btn_data['role'] === 'display_none') { 534 all_modals_container.querySelector("#c-t-bn").style.display = "none"; 535 }else if(tertiary_btn_data['role'] === "accept_all"){ 536 _addEvent(all_modals_container.querySelector("#c-t-bn"), "click", function () { 537 _cookieconsent.hide(); 538 _cookieconsent.accept("all"); 539 }); 540 } else if (tertiary_btn_data['role'] === 'accept_necessary') { 541 _addEvent(all_modals_container.querySelector("#c-t-bn"), 'click', function () { 542 _cookieconsent.hide(); 543 _cookieconsent.accept([]); // accept necessary only 544 }); 545 } else { 546 _addEvent(all_modals_container.querySelector("#c-t-bn"), 'click', function () { 547 _cookieconsent.showSettings(0); 548 }); 549 } 550 all_modals_container.querySelector("#c-t-bn").innerHTML = user_config.languages[lang]['consent_modal']['tertiary_btn']['text']; 551 552 } 553 554 555 consent_modal_exists = true; 556 557 _addDataButtonListeners(all_modals_container); 558 } 559 560 561 var _createSettingsModal = function (lang) { 562 /** 563 * Create all consent_modal elements 564 */ 565 566 if(typeof CF_SETTINGSMODAL_TEMPLATE !== "undefined"){ 567 var settingsHTML = CF_SETTINGSMODAL_TEMPLATE; 568 }else{ 569 var settingsHTML = ` 570 <div id="s-cnt" role="dialog" aria-modal="true" aria-hidden="true" aria-labelledby="s-ttl" style="visibility: hidden;"> 571 <div id="c-vln"> 572 <div id="cs"> 573 <div id="c-s-in"> 574 <div id="s-inr" class="bns-t"> 575 <div id="s-hdr"> 576 <div id="s-ttl" role="heading">Cookie Settings</div> 577 <div id="s-c-bnc"> 578 <button type="button" id="s-c-bn" class="c-bn" aria-label=""></button> 579 </div> 580 </div> 581 <div id="s-bl"> 582 <div id="cf-category-wrapper" class="cf-category-wrapper"> 583 584 </div> 585 </div> 586 <div id="s-bns"> 587 <button type="button" id="s-all-bn" class="c-bn">Accept All</button> 588 <button type="button" id="s-rall-bn" class="c-bn">Reject All</button> 589 <button type="button" id="s-sv-bn" class="c-bn">Save</button> 590 </div> 591 </div> 592 </div> 593 </div> 594 </div> 595 </div> 596 `; 597 } 598 599 const settings_modal = _createNode('div'); 600 settings_modal.innerHTML = settingsHTML; 601 all_modals_container.appendChild(settings_modal); 602 603 var impress_link = user_config.languages[lang]['consent_modal']['impress_link']; 604 var data_policy_link = user_config.languages[lang]['consent_modal']['data_policy_link']; 605 606 607 608 if (data_policy_link.length > 0) { 609 _replaceLink("[##linkPrivacy##]", data_policy_link); 610 } else { 611 _replaceLink("[##linkPrivacy##]", ""); 612 } 613 614 615 if (impress_link.length > 0) { 616 _replaceLink("[##linkImpress##]", impress_link); 617 } else { 618 _replaceLink("[##linkImpress##]", ""); 619 } 620 621 if (!settings_container) { 622 // If 'esc' key is pressed inside settings_container div => hide settings 623 _addEvent(all_modals_container.querySelector("#c-vln"), 'keydown', function (evt) { 624 evt = evt || window.event; 625 if (evt.keyCode === 27) { 626 _cookieconsent.hideSettings(0); 627 } 628 }, true); 629 630 _addEvent(all_modals_container.querySelector("#s-c-bn"), 'click', function () { 631 _cookieconsent.hideSettings(0); 632 }); 633 } else { 634 new_settings_blocks = _createNode('div'); 635 new_settings_blocks.id = 's-bl'; 636 } 637 638 // Add label to close button 639 all_modals_container.querySelector("#s-c-bn").setAttribute('aria-label', user_config.languages[lang]['settings_modal']['close_btn_label'] || 'Close'); 640 641 all_blocks = user_config.languages[lang]['settings_modal']['blocks']; 642 all_table_headers = user_config.languages[lang]['settings_modal']['co
642okie_table_headers']; 643 644 var n_blocks = all_blocks.length; 645 // Set settings modal title 646 all_modals_container.querySelector("#s-ttl").innerHTML = user_config.languages[lang]['settings_modal']['title']; 647 /* CF HOOK */ 648 649 if(typeof CF_SETTINGSMODAL_CATEGORY_TEMPLATE !== "undefined"){ 650 var categoryHTML = CF_SETTINGSMODAL_CATEGORY_TEMPLATE; 651 }else{ 652 var categoryHTML = ` 653 <div class="titlecategory b-bn"> 654 <button type="button" class="b-tl exp" aria-expanded="false" aria-controls="">Externe Medien</button> 655 <label class="expand-button-cfwrapper b-tg"><input class="expand-button " type="checkbox" value=""> 656 <span class="c-tg" aria-hidden="true"> 657 <span class="on-i"></span> 658 <span class="off-i"></span> 659 </span> 660 <span class="t-lb"></span> 661 </label> 662 </div> 663 <div class="block-section b-ex"> 664 <div class="cf-category-description"></div> 665 </div> 666 `; 667 } 668 669 670 var categories = user_config.languages[lang]['settings_modal']['categories']; 671 var n_categories = categories.length; 672 var cf_category_list_full = []; 673 for (var ii = 0; ii < n_categories; ++ii) { 674 var category; 675 category = _createNode('div'); 676 category.id = categories[ii]["category"]; 677 category.className = categories[ii]["category"] + "-cfwrapper cfwrapper"; 678 category.innerHTML = categoryHTML; 679 680 category.querySelector(".cf-category-description").insertAdjacentHTML('beforeend', categories[ii]["description"]); 681 // Create toggle if specified (opt in/out) 682 isExpandable = true; 683 if (true) { 684 var accordion_id2 = "c-acc-" + ii; 685 686 // Create button (to collapse/expand block description) 687 var block_title_btn2 = category.querySelector(".b-tl"); 688 var block_switch2 = category.querySelector(".expand-button"); 689 var block_switch_span2 = category.querySelector(".c-tg"); 690 691 // These 2 spans will contain each 2 pseudo-elements to generate 'tick' and 'x' icons 692 block_title_btn2.innerText = categories[ii]["title"]; 693 694 if (isExpandable) { 695 block_title_btn2.setAttribute('aria-expanded', 'false'); 696 block_title_btn2.setAttribute('aria-controls', accordion_id2); 697 } 698 699 //block_switch2.type = 'checkbox'; 700 block_switch_span2.setAttribute('aria-hidden', 'true'); 701 block_switch2.value = categories[ii]["category"]; 702 703 /** 704 * Set toggle as readonly if true (disable checkbox) 705 */ 706 if (categories[ii]["toggle"]["readonly"]) { 707 block_switch2.disabled = true; 708 _addClass(block_switch_span2, 'c-ro'); 709 } 710 711 /** 712 * Set toggle as required if true 713 */ 714 if(categories[ii]["toggle"]["enabled"]){ 715 block_switch2.checked = true; 716 } 717 718 category.setAttribute('aria-hidden', 'true'); 719 720 /** 721 * On button click handle the following :=> aria-expanded, aria-hidden and act class for current block 722 */ 723 (function (accordion2, block_section2, btn2) { 724 _addEvent(block_title_btn2, 'click', function () { 725 if (!_hasClass(block_section2, 'opencategory')) { 726 _addClass(block_section2, 'opencategory'); 727 _addClass(btn2, 'act'); 728 btn2.setAttribute('aria-expanded', 'true'); 729 accordion2.setAttribute('aria-hidden', 'false'); 730 } else { 731 _removeClass(block_section2, 'opencategory'); 732 _removeClass(btn2, 'act'); 733 btn2.setAttribute('aria-expanded', 'false'); 734 accordion2.setAttribute('aria-hidden', 'true'); 735 } 736 }, false); 737 }
737)(category, category.querySelector(".block-section"), block_title_btn2); 738 739 } 740 741 cf_category_list_full.push(category); 742 } 743 /* CF HOOK END*/ 744 745 746 // Create settings modal content (blocks) 747 for (var i = 0; i < n_blocks; ++i) { 748 749 var title_data = all_blocks[i]['title'], 750 description_data = all_blocks[i]['description'], 751 toggle_data = all_blocks[i]['toggle'], 752 cookie_table_data = all_blocks[i]['cookie_table'], 753 remove_cookie_tables = user_config['remove_cookie_tables'] === true, 754 isExpandable = (description_data && 'truthy') || (!remove_cookie_tables && (cookie_table_data && 'truthy')); 755 756 757 // Create title 758 var block_section = _createNode('div'); 759 var block_table_container = _createNode('div'); 760 761 // Create description 762 if (description_data) { 763 var block_desc = _createNode('div'); 764 block_desc.className = 'p'; 765 block_desc.insertAdjacentHTML('beforeend', description_data); 766 } 767 768 var block_title_container = _createNode('div'); 769 block_title_container.className = 'title'; 770 771 block_section.className = 'c-bl'; 772 block_table_container.className = 'desc'; 773 774 775 // Create toggle if specified (opt in/out) 776 if (typeof toggle_data !== 'undefined') { 777 //console.log(toggle_data); 778 var accordion_id = "c-ac-" + i; 779 780 // Create button (to collapse/expand block description) 781 var block_title_btn = isExpandable ? _createNode('button') : _createNode('div'); 782 var block_switch_label = _createNode('label'); 783 var block_switch = _createNode('input'); 784 var block_switch_span = _createNode('span'); 785 var label_text_span = _createNode('span'); 786 787 // These 2 spans will contain each 2 pseudo-elements to generate 'tick' and 'x' icons 788 var block_switch_span_on_icon = _createNode('span'); 789 var block_switch_span_off_icon = _createNode('span'); 790 791 block_title_btn.className = isExpandable ? 'b-tl exp' : 'b-tl'; 792 block_switch_label.className = 'b-tg'; 793 block_switch.className = 'c-tgl'; 794 block_switch_span_on_icon.className = 'on-i'; 795 block_switch_span_off_icon.className = 'off-i'; 796 block_switch_span.className = 'c-tg'; 797 label_text_span.className = "t-lb"; 798 799 if (isExpandable) { 800 block_title_btn.setAttribute('aria-expanded', 'false'); 801 block_title_btn.setAttribute('aria-controls', accordion_id); 802 } 803 804 block_switch.type = 'checkbox'; 805 block_switch_span.setAttribute('aria-hidden', 'true'); 806 807 var cookie_category = toggle_data.value; 808 block_switch.value = cookie_category; 809 810 label_text_span.textContent = title_data; 811 block_title_btn.insertAdjacentHTML('beforeend', title_data); 812 813 block_title_container.appendChild(block_title_btn); 814 block_switch_span.appendChild(block_switch_span_on_icon); 815 block_switch_span.appendChild(block_switch_span_off_icon); 816 817 /** 818 * If consent is valid => retrieve category states from cookie 819 * Otherwise use states defined in the user_config. object 820 */ 821 822 if (!invalid_consent) { 823 if (_inArray(saved_cookie_content['categories'], cookie_category) > -1) { 824 block_switch.checked = true; 825 !new_settings_blocks && toggle_states.push(true); 826 } else { 827 !new_settings_blocks && toggle_states.push(false); 828 } 829 } else if (toggle_data['enabled']) { 830 831 block_switch.checked = true; 832 !new_settings_blocks && toggle_states.push(true); 833 834 /** 835 * Keep track of categories enabled by default (useful when mode=='opt-out') 836 */ 837 if (toggle_data['enabled']) 838 !new_settings_blocks && default_enabled_categories.push(cookie_category); 839 840 } else { 841 !new_settings_blocks && toggle_states.push(false); 842 } 843 844 !new_settings_blocks && all_categories.push(cookie_category); 845 846 /** 847 * Set toggle as readonly if true (disable checkbox) 848 */ 849 if (toggle_data['readonly']) { 850 block_switch.disabled = true; 851 _addClass(block_switch_span, 'c-ro'); 852 !new_settings_blocks && readonly_categories.push(true); 853 } else { 854 !new_settings_blocks && readonly_categories.push(false); 855 } 856 857 if(toggle_data["enabled"]){ 858 block_switch.checked = true; 859 } 860 861 block_switch.setAttribute("data-cfcookie-category", all_blocks[i]["category"]); 862 if (_categorysSelected[all_blocks[i]["category"]] === false || _categorysSelected[all_blocks[i]["category"]] === undefined) { 863 _categorysSelected[all_blocks[i]["category"]] = block_switch.checked; 864 } 865 866 867 _addClass(block_table_container, 'b-acc'); 868 _addClass(block_title_container, 'b-bn'); 869 _addClass(block_section, 'b-ex'); 870 _addClass(block_section, all_blocks[i]["category"]); 871
872 block_table_container.id = accordion_id; 873 block_table_container.setAttribute('aria-hidden', 'true'); 874 875 block_switch_label.appendChild(block_switch); 876 block_switch_label.appendChild(block_switch_span); 877 block_switch_label.appendChild(label_text_span); 878 block_title_container.appendChild(block_switch_label); 879 880 /** 881 * On button click handle the following :=> aria-expanded, aria-hidden and act class for current block 882 */ 883 884 isExpandable && (function (accordion, block_section, btn) { 885 _addEvent(block_title_btn, 'click', function () { 886 if (!_hasClass(block_section, 'act')) { 887 _addClass(block_section, 'act'); 888 btn.setAttribute('aria-expanded', 'true'); 889 accordion.setAttribute('aria-hidden', 'false'); 890 } else { 891 _removeClass(block_section, 'act'); 892 btn.setAttribute('aria-expanded', 'false'); 893 accordion.setAttribute('aria-hidden', 'true'); 894 } 895 }, false); 896 })(block_table_container, block_section, block_title_btn); 897 898 } else { 899 /** 900 * If block is not a button (no toggle defined), 901 * create a simple div instead 902 */ 903 if (title_data) { 904 var block_title = _createNode('div'); 905 block_title.className = 'b-tl freaking'; 906 block_title.setAttribute('role', 'heading'); 907 block_title.setAttribute('aria-level', '3'); 908 block_title.insertAdjacentHTML('beforeend', title_data); 909 block_title_container.appendChild(block_title); 910 } 911 } 912 913 title_data && block_section.appendChild(block_title_container); 914 description_data && block_table_container.appendChild(block_desc); 915 all_modals_container.querySelector("#cf-category-wrapper").appendChild(block_section); 916 // if cookie table found, generate table for this block 917 if (!remove_cookie_tables && typeof cookie_table_data !== 'undefined' && cookie_table_data.length > 0) { 918 var tr_tmp_fragment = document.createDocumentFragment(); 919 920 /** 921 * Use custom table headers 922 */ 923 for (var p = 0; p < all_table_headers.length; ++p) { 924 // create new header 925 var th1 = _createNode('th'); 926 var obj = all_table_headers[p]; 927 th1.setAttribute('scope', 'col'); 928 929 // get custom header content 930 if (obj) { 931 var new_column_key = obj && _getKeys(obj)[0]; 932 th1.textContent = all_table_headers[p][new_column_key]; 933 tr_tmp_fragment.appendChild(th1); 934 } 935 } 936 937 var tr_tmp = _createNode('tr'); 938 tr_tmp.appendChild(tr_tmp_fragment); 939 940 // create table header & append fragment 941 var thead = _createNode('thead'); 942 thead.appendChild(tr_tmp); 943 944 // append header to table 945 var block_table = _createNode('table'); 946 block_table.appendChild(thead); 947 948 var tbody_fragment = document.createDocumentFragment(); 949 950 // create table content 951 for (var n = 0; n < cookie_table_data.length; n++) { 952 var tr = _createNode('tr'); 953 tr.setAttribute("class","cookie-item"); 954 var tr_description = _createNode('tr'); 955 //tr_description.style.display = "none"; 956 tr_description.setAttribute("class", "cookie-additional-description"); 957 _addEvent(tr, 'click', function () { 958 /* Hide all open Descriptions, only once can be opened */ 959 Array.from(all_modals_container.querySelectorAll(".cookie-additional-header")) 960 .forEach(function(val) { 961 val.setAttribute("class", "cookie-item"); 962 }); 963 if (_hasClass(this.nextSibling, "cookie-description-active") === false) { 964 Array.from(all_modals_container.querySelectorAll(".cookie-additional-description")) 965 .forEach(function(val) {
966 _removeClass(val, "cookie-description-active"); 967 }); 968 this.setAttribute("class", "cookie-additional-header cookie-item"); 969 _addClass(this.nextSibling, "cookie-description-active"); 970 } else { 971 _removeClass(this.nextSibling, "cookie-description-active"); 972 973 } 974 }); 975 for (var g = 0; g < all_table_headers.length; ++g) { 976 // get custom header content 977 obj = all_table_headers[g]; 978 if (obj) { 979 new_column_key = _getKeys(obj)[0]; 980 981 var td_tmp = _createNode('td'); 982 // Allow html inside table cells 983 td_tmp.insertAdjacentHTML('beforeend', cookie_table_data[n][new_column_key]); 984 td_tmp.setAttribute('data-column', obj[new_column_key]); 985 986 987 tr.appendChild(td_tmp); 988 } 989 } 990 991 var td_tmp_description = _createNode('td'); 992 td_tmp_description.setAttribute('colspan', all_table_headers.length); 993 td_tmp_description.setAttribute('class', "cookie-informations"); 994 995 var description_html_box = _createNode('div'); 996 for (const key in cookie_table_data[n]["additional_information"]) { 997 if(cookie_table_data[n]["additional_information"][key]["value"] === "" || cookie_table_data[n]["additional_information"][key]["value"] === 0) continue; 998 let text = _createNode('p'); 999 text.setAttribute('data-key', key); 1000 text.insertAdjacentHTML('beforeend', "<span class='cookie-title'>" + cookie_table_data[n]["additional_information"][key]["title"] + ":</span> " + cookie_table_data[n]["additional_information"][key]["value"]); 1001 description_html_box.appendChild(text); 1002 } 1003 1004 td_tmp_description.insertAdjacentHTML("beforeend", description_html_box.innerHTML); 1005 tr_description.appendChild(td_tmp_description); 1006 1007 tbody_fragment.appendChild(tr); 1008 tbody_fragment.appendChild(tr_description); 1009 } 1010 1011 // append tbody_fragment to tbody & append the latter into the table 1012 var tbody = _createNode('tbody'); 1013 tbody.appendChild(tbody_fragment); 1014 block_table.appendChild(tbody); 1015 block_table_container.appendChild(block_table); 1016 1017 } 1018 1019 /** 1020 * Append only if is either: 1021 * - togglable div with title 1022 * - a simple div with at least a title or description 1023 */ 1024 if (toggle_data && title_data || (!toggle_data && (title_data || description_data))) { 1025 block_section.appendChild(block_table_container); 1026 1027 /*CF HOOK */ 1028 for (var iii = 0; iii < cf_category_list_full.length; ++iii) { 1029 1030 if (block_section.classList.contains(cf_category_list_full[iii].id)) { 1031 cf_category_list_full[iii].children[1].appendChild(block_section); 1032 } 1033 } 1034 1035 for (var iiii = 0; iiii < cf_category_list_full.length; ++iiii) { 1036 1037 all_modals_container.querySelector("#cf-category-wrapper").appendChild(cf_category_list_full[iiii]); 1038 1039 } 1040 1041 /*CF HOOK END */ 1042 //if(new_settings_blocks) 1043 // new_settings_blocks.appendChild(cf_category_container); 1044 // else 1045 // settings_blocks.appendChild(cf_category_container); 1046 } 1047 } 1048 1049 1050 _addEvent(all_modals_container.querySelector("#s-all-bn"), 'click', function () { 1051 _cookieconsent.hideSettings(); 1052 _cookieconsent.hide(); 1053 _cookieconsent.accept('all'); 1054 }); 1055 1056 1057 all_modals_container.querySelector("#s-all-bn").innerHTML = user_config.languages[lang]['settings_modal']['accept_all_btn']; 1058 1059 var reject_all_btn_text = user_config.languages[lang]['settings_modal']['reject_all_btn']; 1060 1061 // Add third [optional] reject all button if provided 1062 _addEvent(all_modals_container.querySelector("#s-rall-bn"), 'click', function () { 1063 _cookieconsent.hideSettings(); 1064 _cookieconsent.hide(); 1065 _cookieconsent.accept([]); 1066 }); 1067 all_modals_container.querySelector("#s-rall-bn").innerHTML = reject_all_btn_text; 1068 1069 1070 // Add save preferences button onClick event 1071 // Hide both settings modal and consent modal 1072 _addEvent(all_modals_container.querySelector("#s-sv-bn"), 'click', function () { 1073 _cookieconsent.hideSettings(); 1074 _cookieconsent.hide(); 1075 _cookieconsent.accept(); 1076 }); 1077 1078 all_modals_container.querySelector("#s-sv-bn").innerHTML = user_config.languages[lang]['settings_modal']['s
1078ave_settings_btn']; 1079 1080 /* 1081 if(new_settings_blocks) { 1082 // replace entire existing cookie category blocks with the new cookie categories new blocks (in a different language) 1083 settings_inner.replaceChild(new_settings_blocks, settings_blocks); 1084 settings_blocks = new_settings_blocks; 1085 return; 1086 }; 1087 */ 1088 } 1089 1090 /** 1091 * Generate cookie consent html markup 1092 */ 1093 var _createCookieConsentHTML = function () { 1094 1095 // Create main container which holds both consent modal & settings modal 1096 main_container = _createNode('div'); 1097 main_container.id = 'cc--main'; 1098 1099 // Fix layout flash 1100 main_container.style.position = "fixed"; 1101 main_container.style.zIndex = "2147483647"; 1102 main_container.innerHTML = '<!--[if lt IE 9 ]><div id="cc_div" class="cc_div ie"></div><![endif]--><!--[if (gt IE 8)|!(IE)]><!--><div id="cc_div" class="cc_div"></div><!--<![endif]-->' 1103 all_modals_container = main_container.children[0]; 1104 1105 // Get current language 1106 var lang = _config.current_lang; 1107 1108 // Create consent modal 1109 if (consent_modal_exists) 1110 _createConsentModal(lang); 1111 1112 // Always create settings modal 1113 _createSettingsModal(lang); 1114 1115 for (const key in _categorysSelected) { 1116 if (_categorysSelected[key] === true || _categorysSelected[key] === "true") { 1117 main_container.querySelector(".expand-button[value=" + key + "]").setAttribute("checked", "checked"); 1118 } 1119 1120 } 1121 // Finally append everything (main_container holds both modals) 1122 (root || document.body).appendChild(main_container); 1123 } 1124 1125 /** 1126 * Update/change modals language 1127 * @param {String} lang new language 1128 * @param {Boolean} [force] update language fields forcefully 1129 * @returns {Boolean} 1130 */ 1131 _cookieconsent.updateLanguage = function (lang, force) { 1132 1133 if (typeof lang !== 'string') return; 1134 1135 /** 1136 * Validate language to avoid errors 1137 */ 1138 var new_validated_lang = _getValidatedLanguage(lang, user_config.languages); 1139 1140 /** 1141 * Set language only if it differs from current 1142 */ 1143 if (new_validated_lang !== _config.current_lang || force === true) { 1144 _config.current_lang = new_validated_lang; 1145 1146 if (consent_modal_exists) { 1147 _createConsentModal(new_validated_lang); 1148 } 1149 1150 _createSettingsModal(new_validated_lang); 1151 1152 _log("CookieConsent [LANGUAGE]: curr_lang: '" + new_validated_lang + "'"); 1153 1154 return true; 1155 } 1156 1157 return false; 1158 } 1159 1160 /** 1161 * Delete all cookies which are unused (based on selected preferences) 1162 * 1163 * @param {boolean} [clearOnFirstAction] 1164 */ 1165 var _autoclearCookies = function (clearOnFirstAction) { 1166 1167 // Get number of blocks 1168 var len = all_blocks.length; 1169 var count = -1; 1170 1171 // reset reload state 1172 reload_page = false; 1173 1174 // Retrieve all cookies 1175 var all_cookies_array = _getCookie('', 'all'); 1176 1177 // delete cookies on 'www.domain.com' and '.www.domain.com' (can also be without www) 1178 var domains = [_config.cookie_domain, '.' + _config.cookie_domain]; 1179 1180 1181 1182 // if domain has www, delete cookies also for 'domain.com' and '.domain.com' 1183 if (_config.cookie_domain.slice(0, 4) === 'www.') { 1184 var non_www_domain = _config.cookie_domain.substr(4); // remove first 4 chars (www.) 1185 domains.push(non_www_domain); 1186 domains.push('.' + non_www_domain); 1187 } 1188 1189 1190 // For each block 1191 for (var i = 0; i < len; i++) { 1192 1193 // Save current block (local scope & less accesses -> ~faster value retrieval) 1194 var curr_block = all_blocks[i]; 1195 1196 // If current block has a toggle for opt in/out 1197 if (Object.prototype.hasOwnProperty.call(curr_block, "toggle")) { 1198 1199 // if current block has a cookie table, an off toggle, 1200 // and its preferences were just changed => delete cookies 1201 var category_just_disabled = _inArray(changed_settings, curr_block['toggle']['value']) > -1; 1202 if ( 1203 !toggle_states[++count] && 1204 Object.prototype.hasOwnProperty.call(curr_block, "cookie_table") && 1205 (clearOnFirstAction || category_just_disabled) 1206 ) { 1207 var curr_cookie_table = curr_block['cookie_table']; 1208 1209 // Get first property name 1210 var ckey = _getKeys(all_table_headers[0])[0]; 1211 1212 // Get number of cookies defined in cookie_table 1213 var clen = curr_cookie_table.length; 1214 1215 // set "reload_page" to true if reload=on_disable 1216 if (curr_block['toggle']['reload'] === 'on_disable') 1217 category_just_disabled && (reload_page = true); 1218 1219 // for each row defined in the cookie table 1220 for (var j = 0; j < clen; j++) { 1221 var curr_domains = domains; 1222 1223 // Get current row of table (corresponds to all cookie params) 1224 var curr_row = curr_cookie_table[j], found_cookies = []; 1225 var curr_cookie_name = curr_row[ckey]; 1226 var is_regex = curr_row['is_regex'] || false; 1227 var curr_cookie_domain = curr_row['domain'] || null; 1228 var curr_cookie_path = curr_row['path'] || false; 1229 1230 // set domain to the specified domain 1231 curr_cookie_domain && (curr_domains = [curr_cookie_domain, '.' + curr_cookie_domain]); 1232 1233 1234 // If regex provided => filter cookie array 1235 if (is_regex) { 1236 for (var n = 0; n < all_cookies_array.length; n++) { 1237 if (all_cookies_array[n].match(curr_cookie_name)) { 1238 found_cookies.push(all_cookies_array[n]); 1239 } 1240 } 1241 } else { 1242 var found_index = _inArray(all_cookies_array, curr_cookie_name); 1243 if (found_index > -1) found_cookies.push(all_cookies_array[found_index]); 1244 } 1245 1246 _log("CookieConsent [AUTOCLEAR]: search cookie: '" + curr_cookie_name + "', found:", found_cookies); 1247 1248 // If cookie exists -> delete it 1249 if (found_cookies.length > 0) { 1250 _eraseCookies(found_cookies, curr_cookie_path, curr_domains); 1251 curr_block['toggle']['reload'] === 'on_clear' && (reload_page = true); 1252 } 1253 } 1254 } 1255 } 1256 } 1257 } 1258 1259 /** 1260 * Set toggles/checkboxes based on accepted categories and save cookie 1261 * @param {string[]} accepted_categories - Array of categories to accept 1262 */ 1263 var _saveCookiePreferences = function (accepted_categories) { 1264 1265 changed_settings = []; 1266 1267 // Retrieve all toggle/checkbox values 1268 var category_toggles = document.querySelectorAll('.c-tgl') || []; 1269 1270 // If there are opt in/out toggles ... 1271 if (category_toggles.length > 0) { 1272 for (var i = 0; i < category_toggles.length; i++) { 1273 var categoryContainer = all_modals_container.querySelector('#'+category_toggles[i].getAttribute("data-cfcookie-category")).querySelector(".expand-button"); 1274 if (_inArray(accepted_categories, all_categories[i]) !== -1) { 1275 categoryContainer.checked = true; 1276 category_toggles[i].checked = true; 1277 if (!toggle_states[i]) { 1278 changed_settings.push(all_categories[i]); 1279 toggle_states[i] = true; 1280 } 1281 } else { 1282 category_toggles[i].checked = false;
1283 if (toggle_states[i]) { 1284 changed_settings.push(all_categories[i]); 1285 toggle_states[i] = false; 1286 } 1287 1288 var isActive = all_modals_container.querySelector('#'+category_toggles[i].getAttribute("data-cfcookie-category")).querySelectorAll(".block-section input:checked"); 1289 if(!!isActive){ 1290 //categoryContainer.checked = true; 1291 if(isActive.length === 0){ 1292 categoryContainer.checked = false; 1293 } 1294 } 1295 } 1296 } 1297 } 1298 1299 1300 1301 1302 /** 1303 * Clear cookies when settings/preferences change 1304 */ 1305 if (!invalid_consent && _config.autoclear_cookies && changed_settings.length > 0) 1306 _autoclearCookies(); 1307 1308 if (!consent_date) consent_date = new Date(); 1309 if (!consent_uuid) consent_uuid = _uuidv4(); 1310 1311 saved_cookie_content = { 1312 "categories": accepted_categories, 1313 "level": accepted_categories, // Copy of the `categories` property for compatibility purposes with version v2.8.0 and below. 1314 "revision": _config.revision, 1315 "data": cookie_data, 1316 "rfc_cookie": _config.use_rfc_cookie, 1317 "consent_date": consent_date.toISOString(), 1318 "consent_uuid": consent_uuid 1319 } 1320 1321 // save cookie with preferences 'categories' (only if never accepted or settings were updated) 1322 if (invalid_consent || changed_settings.length > 0) { 1323 valid_revision = true; 1324 1325 1326 /** 1327 * Update "last_consent_update" only if it is invalid (after t) 1328 */ 1329 if (!last_consent_update) 1330 last_consent_update = consent_date; 1331 else 1332 last_consent_update = new Date(); 1333 1334 saved_cookie_content['last_consent_update'] = last_consent_update.toISOString(); 1335 1336 /** 1337 * Update accept type 1338 */ 1339 accept_type = _getAcceptType(_getCurrentCategoriesState()); 1340 1341 _setCookie(_config.cookie_name, JSON.stringify(saved_cookie_content)); 1342 _manageExistingScripts(); 1343 } 1344 1345 if (invalid_consent) { 1346 1347 /** 1348 * Delete unused/"zombie" cookies if consent is not valid (not yet expressed or cookie has expired) 1349 */ 1350 if (_config.autoclear_cookies) 1351 _autoclearCookies(true); 1352 1353 if (typeof onFirstAction === 'function') 1354 onFirstAction(_cookieconsent.getUserPreferences(), saved_cookie_content); 1355 1356 if (typeof onAccept === 'function') 1357 onAccept(saved_cookie_content); 1358 1359 /** 1360 * Set consent as valid 1361 */ 1362 invalid_consent = false; 1363 1364 if (_config.mode === 'opt-in') return; 1365 } 1366 1367 // fire onChange only if settings were changed 1368 if (typeof onChange === "function" && changed_settings.length > 0) 1369 onChange(saved_cookie_content, changed_settings); 1370 1371 /** 1372 * reload page if needed 1373 */ 1374 if (reload_page) 1375 window.location.reload(); 1376 } 1377 1378 /** 1379 * Returns index of found element inside array, otherwise -1 1380 * @param {Array} arr 1381 * @param {Object} value 1382 * @returns {number} 1383 */ 1384 var _inArray = function (arr, value) { 1385 return arr.indexOf(value); 1386 } 1387 1388 /** 1389 * Helper function which prints info (console.log()) 1390 * @param {Object} print_msg 1391 * @param {Object} [optional_param] 1392 */ 1393 var _log = function (print_msg, optional_param, error) { 1394 ENABLE_LOGS && (!error ? console.log(print_msg, optional_param !== undefined ? optional_param : ' ') : console.error(print_msg, optional_param || "")); 1395 } 1396 1397 /** 1398 * Helper function which creates an HTMLElement object based on 'type' and returns it. 1399 * @param {string} type 1400 * @returns {HTMLElement} 1401 */ 1402 var _createNode = function (type) { 1403 var el = document.createElement(type); 1404 if (type === 'button') { 1405 el.setAttribute('type', type); 1406 } 1407 return el; 1408 } 1409 1410 /** 1411 * Generate RFC4122-compliant UUIDs. 1412 * https://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid?page=1&tab=votes#tab-top 1413 * @returns {string} 1414 */ 1415 var _uuidv4 = function () { 1416 return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, function (c) { 1417 try { 1418 return (c ^ (window.crypto || window.msCrypto).getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16) 1419 } catch (e) { 1420 return ''; 1421 } 1422 }); 1423 } 1424 1425 /** 1426 * Resolve which language should be used. 1427 * 1428 * @param {Object} languages Object with language translations 1429 * @param {string} [requested_language] Language specified by given configuration parameters 1430 * @returns {string} 1431 */ 1432 var _resolveCurrentLang = function (languages, requested_language) { 1433 1434 if (_config.auto_language === 'browser') { 1435 return _getValidatedLanguage(_getBrowserLang(), languages); 1436 } else if (_config.auto_language === 'document') { 1437 return _getValidatedLanguage(document.documentElement.lang, languages); 1438 } else { 1439 if (typeof requested_language === 'string') { 1440 return _config.current_lang = _getValidatedLanguage(requested_language, languages); 1441 } 1442 } 1443 1444 _log("CookieConsent [LANG]: setting current_lang = '" + _config.current_lang + "'"); 1445 return _config.current_lang; // otherwise return default 1446 } 1447 1448 /** 1449 * Get current client's browser language 1450 * @returns {string} 1451 */ 1452 var _getBrowserLang = function () { 1453 var browser_lang = navigator.language || navigator.browserLanguage; 1454 browser_lang.length > 2 && (browser_lang = browser_lang[0] + browser_lang[1]); 1455 _log("CookieConsent [LANG]: detected_browser_lang = '" + browser_lang + "'"); 1456 return browser_lang.toLowerCase() 1457 } 1458 1459 /** 1460 * Trap focus inside modal and focus the first 1461 * focusable element of current active modal 1462 */ 1463 var _handleFocusTrap = function () { 1464 var tabbedOutsideDiv = false;
1465 var tabbedInsideModal = false; 1466 1467 _addEvent(document, 'keydown', function (e) { 1468 e = e || window.event; 1469 1470 // If is tab key => ok 1471 if (e.key !== 'Tab') return; 1472 1473 // If there is any modal to focus 1474 if (current_modal_focusable) { 1475 // If reached natural end of the tab sequence => restart 1476 if (e.shiftKey) { 1477 if (document.activeElement === current_modal_focusable[0]) { 1478 current_modal_focusable[1].focus(); 1479 e.preventDefault(); 1480 } 1481 } else { 1482 if (document.activeElement === current_modal_focusable[1]) { 1483 current_modal_focusable[0].focus(); 1484 e.preventDefault(); 1485 } 1486 } 1487 1488 // If have not yet used tab (or shift+tab) and modal is open ... 1489 // Focus the first focusable element 1490 if (!tabbedInsideModal && !clicked_inside_modal) { 1491 tabbedInsideModal = true; 1492 !tabbedOutsideDiv && e.preventDefault(); 1493 1494 if (e.shiftKey) { 1495 if (current_modal_focusable[3]) { 1496 if (!current_modal_focusable[2]) { 1497 current_modal_focusable[0].focus(); 1498 } else { 1499 current_modal_focusable[2].focus(); 1500 } 1501 } else { 1502 current_modal_focusable[1].focus(); 1503 } 1504 } else { 1505 if (current_modal_focusable[3]) { 1506 current_modal_focusable[3].focus(); 1507 } else { 1508 current_modal_focusable[0].focus(); 1509 } 1510 } 1511 } 1512 } 1513 1514 !tabbedInsideModal && (tabbedOutsideDiv = true); 1515 }); 1516 1517 1518 if (document.contains) { 1519 _addEvent(main_container, 'click', function (e) { 1520 e = e || window.event; 1521 /** 1522 * If click is on the foreground overlay (and not inside settings_modal), 1523 * hide settings modal 1524 * 1525 * Notice: click on div is not supported in IE 1526 */ 1527 1528 if (_hasClass(e.target, "c-tgl")) { 1529 var categoryIdentifier = e.target.getAttribute("data-cfcookie-category"); 1530 var categoriesSwitchButton = main_container.querySelector("#" + e.target.getAttribute("data-cfcookie-category")).querySelector(".expand-button"); 1531 var services = main_container.querySelector("#" + categoryIdentifier).querySelectorAll(".block-section ." + categoryIdentifier); 1532 1533 1534 var isServiceActive = false; 1535 for (var i = 0; i < services.length; i++) { 1536 if (services[i].querySelector("input").checked === true) { 1537 isServiceActive = true; 1538 } 1539 } 1540 1541 if (isServiceActive === false) { 1542 /* All Services are Disabled */ 1543 categoriesSwitchButton.checked = false; 1544 } else { 1545 categoriesSwitchButton.checked = true; 1546 } 1547 1548 1549 } 1550 1551 if (_hasClass(e.target, "expand-button")) { 1552 /** IF Category Switch button **/ 1553 var services = main_container.querySelector("#" + e.target.value).querySelectorAll(".block-section ." + e.target.value); 1554 for (var i = 0; i < services.length; i++) { 1555 if (e.target.checked === true) { 1556 services[i].querySelector("input").checked = true; 1557 } else { 1558 services[i].querySelector("input").checked = false;
1559 } 1560 } 1561 } 1562 1563 if (settings_modal_visible) { 1564 if (!all_modals_container.querySelector("#s-inr").contains(e.target)) { 1565 _cookieconsent.hideSettings(0); 1566 clicked_inside_modal = false; 1567 } else { 1568 clicked_inside_modal = true; 1569 } 1570 } else if (consent_modal_visible) { 1571 if (all_modals_container.querySelector("#cm").contains(e.target)) { 1572 clicked_inside_modal = true; 1573 } 1574 } 1575 1576 }, true); 1577 } 1578 } 1579 1580 /** 1581 * Manage each modal's layout 1582 * @param {Object} gui_options 1583 */ 1584 var _guiManager = function (gui_options, only_consent_modal) { 1585 1586 // If gui_options is not object => exit 1587 if (typeof gui_options !== 'object') return; 1588 1589 var consent_modal_options = gui_options['consent_modal']; 1590 var settings_modal_options = gui_options['settings_modal']; 1591 1592 /** 1593 * Helper function which adds layout and 1594 * position classes to given modal 1595 * 1596 * @param {HTMLElement} modal 1597 * @param {string[]} allowed_layouts 1598 * @param {string[]} allowed_positions 1599 * @param {string} layout 1600 * @param {string[]} position 1601 */ 1602 function _setLayout(modal, allowed_layouts, allowed_positions, allowed_transitions, layout, position, transition) { 1603 position = (position && position.split(" ")) || []; 1604 // Check if specified layout is valid 1605 if (_inArray(allowed_layouts, layout) > -1) { 1606 1607 // Add layout classes 1608 _addClass(modal, layout); 1609 1610 // Add position class (if specified) 1611 if (!(layout === 'bar' && position[0] === 'middle') && _inArray(allowed_positions, position[0]) > -1) { 1612 for (var i = 0; i < position.length; i++) { 1613 _addClass(modal, position[i]); 1614 } 1615 } 1616 } 1617 1618 // Add transition class 1619 (_inArray(allowed_transitions, transition) > -1) && _addClass(modal, transition); 1620 } 1621 1622 if (consent_modal_exists && consent_modal_options) { 1623 _setLayout( 1624 all_modals_container.querySelector("#cm"), 1625 ['box', 'bar', 'cloud'], 1626 ['top', 'middle', 'bottom'], 1627 ['zoom', 'slide'], 1628 consent_modal_options['layout'], 1629 consent_modal_options['position'], 1630 consent_modal_options['transition'] 1631 ); 1632 } 1633 1634 if (!only_consent_modal && settings_modal_options) { 1635 _setLayout( 1636 all_modals_container.querySelector("#s-cnt"), 1637 ['bar'], 1638 ['left', 'right'], 1639 ['zoom', 'slide'], 1640 settings_modal_options['layout'], 1641 settings_modal_options['position'], 1642 settings_modal_options['transition'] 1643 ); 1644 } 1645 } 1646 1647 /** 1648 * Returns true if cookie category is accepted by the user 1649 * @param {string} cookie_category 1650 * @returns {boolean} 1651 */ 1652 _cookieconsent.allowedCategory = function (cookie_category) { 1653 1654 if (!invalid_consent || _config.mode === 'opt-in') 1655 var allowed_categories = JSON.parse(_getCookie(_config.cookie_name, 'one', true) || '{}')['categories'] || [] 1656 else // mode is 'opt-out' 1657 var allowed_categories = default_enabled_categories; 1658 1659 return _inArray(allowed_categories, cookie_category) > -1; 1660 } 1661 1662 /** 1663 * "Init" method. Will run once and only if modals do not exist 1664 */ 1665 _cookieconsent.run = function (user_config) { 1666 1667 if (!document.getElementById('cc_div')) { 1668 1669 // configure all parameters 1670 _setConfig(user_config); 1671 1672 // if is bot, don't run plugin 1673 if (is_bot) return; 1674 1675 // Retrieve cookie value (if set) 1676 saved_cookie_content = JSON.parse(_getCookie(_config.cookie_name, 'one', true) || "{}"); 1677 1678 1679 // Retrieve "consent_uuid" 1680 consent_uuid = saved_cookie_content['consent_uuid']; 1681 1682 // If "consent_uuid" is present => assume that consent was previously given 1683 var cookie_consent_accepted = consent_uuid !== undefined; 1684 1685 // Retrieve "consent_date" 1686 consent_date = saved_cookie_content['consent_date']; 1687 consent_date && (consent_date = new Date(consent_date)); 1688 1689 // Retrieve "last_consent_update" 1690 last_consent_update = saved_cookie_content['last_consent_update']; 1691 last_consent_update && (last_consent_update = new Date(last_consent_update)); 1692 1693 // Retrieve "data" 1694 cookie_data = saved_cookie_content['data'] !== undefined ? saved_cookie_content['data'] : null; 1695 1696 // If revision is enabled and current value !== saved value inside the cookie =>
1696 revision is not valid 1697 if(typeof saved_cookie_content['revision'] !== "undefined" && revision_enabled && saved_cookie_content['revision'] !== _config.revision){ 1698 //user has a cookie 1699 valid_revision = false; 1700 }else if(saved_cookie_content['revision'] !== _config.revision && typeof saved_cookie_content['revision'] !== "undefined"){ 1701 valid_revision = true; 1702 } 1703 1704 // If consent is not valid => create consent modal 1705 consent_modal_exists = invalid_consent = (!cookie_consent_accepted || !valid_revision || !consent_date || !last_consent_update || !consent_uuid); 1706 1707 // Generate cookie-settings dom (& consent modal) 1708 _createCookieConsentHTML(); 1709 1710 _getModalFocusableData(); 1711 1712 _guiManager(user_config['gui_options']); 1713 _addDataButtonListeners(); 1714 1715 if (_config.autorun && consent_modal_exists) { 1716 _cookieconsent.show(user_config['delay'] || 0); 1717 } 1718 1719 // Add class to enable animations/transitions 1720 setTimeout(function () { 1721 _addClass(main_container, 'c--anim'); 1722 }, 30); 1723 1724 // Accessibility :=> if tab pressed => trap focus inside modal 1725 setTimeout(function () { 1726 _handleFocusTrap(); 1727 }, 100); 1728 1729 // If consent is valid 1730 if (!invalid_consent) { 1731 var rfc_prop_exists = typeof saved_cookie_content['rfc_cookie'] === "boolean"; 1732 1733 /* 1734 * Convert cookie to rfc format (if `use_rfc_cookie` is enabled) 1735 */ 1736 if (!rfc_prop_exists || (rfc_prop_exists && saved_cookie_content['rfc_cookie'] !== _config.use_rfc_cookie)) { 1737 saved_cookie_content['rfc_cookie'] = _config.use_rfc_cookie; 1738 _setCookie(_config.cookie_name, JSON.stringify(saved_cookie_content)); 1739 } 1740 1741 /** 1742 * Update accept type 1743 */ 1744 accept_type = _getAcceptType(_getCurrentCategoriesState()); 1745 1746 _manageExistingScripts(); 1747 1748 if (typeof onAccept === 'function') 1749 onAccept(saved_cookie_content); 1750 1751 _log("CookieConsent [NOTICE]: consent already given!", saved_cookie_content); 1752 1753 } else { 1754 if (_config.mode === 'opt-out') { 1755 _log("CookieConsent [CONFIG] mode='" + _config.mode + "', default enabled categories:", default_enabled_categories); 1756 _manageExistingScripts(default_enabled_categories); 1757 } 1758 _log("CookieConsent [NOTICE]: ask for consent!"); 1759 } 1760 } else { 1761 _log("CookieConsent [NOTICE]: cookie consent already attached to body!"); 1762 } 1763 } 1764 1765 /** 1766 * Show settings modal (with optional delay) 1767 * @param {number} delay 1768 */ 1769 _cookieconsent.showSettings = function (delay) { 1770 setTimeout(function () { 1771 _addClass(html_dom, "show--settings"); 1772 all_modals_container.querySelector("#s-cnt").setAttribute('aria-hidden', 'false'); 1773 settings_modal_visible = true; 1774 /** 1775 * Set focus to the first focusable element inside settings modal 1776 */ 1777 setTimeout(function () { 1778 // If there is no consent-modal, keep track of the last focused elem. 1779 if (!consent_modal_visible) { 1780 last_elem_before_modal = document.activeElement; 1781 } else { 1782 last_consent_modal_btn_focus = document.activeElement; 1783 } 1784 1785 if (settings_modal_focusable.length === 0) return; 1786 1787 if (settings_modal_focusable[3]) { 1788 settings_modal_focusable[3].focus(); 1789 } else { 1790 settings_modal_focusable[0].focus(); 1791 } 1792 current_modal_focusable = settings_modal_focusable; 1793 }, 200); 1794 1795 _log("CookieConsent [SETTINGS]: show settings_modal"); 1796 }, delay > 0 ? delay : 0); 1797 } 1798 1799 /** 1800 * This function handles the loading/activation logic of the already 1801 * existing scripts based on the current accepted cookie categories 1802 * 1803 * @param {string[]} [must_enable_categories] 1804 */ 1805 var _manageExistingScripts = function (must_enable_categories) { 1806 1807 if (!_config.page_scripts) return; 1808 1809 // get all the scripts with "cookie-category" attribute 1810 var scripts = document.querySelectorAll('script[' + _config.script_selector + ']'); 1811 var accepted_categories = must_enable_categories || saved_cookie_content['categories'] || []; 1812 1813 /** 1814 * Load scripts (sequentially), using a recursive function 1815 * which loops through the scripts array 1816 * @param {Element[]} scripts scripts to load 1817 * @param {number} index current script to load 1818 */ 1819 var _loadScripts = function (scripts, index) { 1820 if (index < scripts.length) { 1821 1822 var curr_script = scripts[index]; 1823 var curr_script_category = curr_script.getAttribute(_config.script_selector); 1824 1825 /** 1826 * If current script's category is on the array of categories 1827 * accepted by the user => load script 1828 */ 1829 1830 if (_inArray(accepted_categories, curr_script_category) > -1) { 1831 1832 curr_script.type = 'text/javascript'; 1833 curr_script.removeAttribute(_config.script_selector); 1834 1835 // get current script data-src 1836 var src = curr_script.getAttribute('data-src'); 1837 1838 // some scripts (like ga) might throw warning if data-src is present 1839 src && curr_script.removeAttribute('data-src'); 1840 1841 // create fresh script (with the same code) 1842 var fresh_script = _createNode('script'); 1843 fresh_script.textContent = curr_script.innerHTML; 1844 1845 // Copy attributes over to the new "revived" script 1846 (function (destination, source) { 1847 var attributes = source.attributes; 1848 var len = attributes.length; 1849 for (var i = 0; i < len; i++) { 1850 var attr_name = attributes[i].nodeName; 1851 destination.setAttribute(attr_name, source[attr_name] || source.getAttribute(attr_name)); 1852 } 1853 })(fresh_script, curr_script); 1854 1855 // set src (if data-src found) 1856 src ? (fresh_script.src = src) : (src = curr_script.src); 1857 1858 // if script has "src" attribute 1859 // try loading it sequentially 1860 if (src) { 1861 // load script sequentially => the next script will not be loaded 1862 // until the current's script onload event triggers 1863 if (fresh_script.readyState) { // only required for IE <9 1864 fresh_script.onreadystatechange = function () { 1865 if (fresh_script.readyState === "loaded" || fresh_script.readyState === "complete") { 1866 fresh_script.onreadystatechange = null; 1867 _loadScripts(scripts, ++index); 1868 } 1869 }; 1870 } else { // others 1871 fresh_script.onload = function () { 1872 fresh_script.onload = null; 1873 _loadScripts(scripts, ++index); 1874 }; 1875 } 1876 } 1877 1878 1879 // Replace current "sleeping" script with the new "revived" one 1880 curr_script.parentNode.replaceChild(fresh_script, curr_script); 1881 1882 /** 1883 * If we managed to get here and scr is still set, it means that 1884 * the script is loading/loaded sequentially so don't go any further 1885 */ 1886 if (src) return; 1887 } 1888 1889 // Go to next script right away 1890 _loadScripts(scripts, ++index); 1891 } 1892 } 1893 1894 _loadScripts(scripts, 0); 1895 } 1896 1897 /** 1898 * Save custom data inside cookie 1899 * @param {object|string} new_data 1900 * @param {string} [mode] 1901 * @returns {boolean} 1902 */
1903 var _setCookieData = function (new_data, mode) { 1904 1905 var set = false; 1906 /** 1907 * If mode is 'update': 1908 * add/update only the specified props. 1909 */ 1910 if (mode === 'update') { 1911 cookie_data = _cookieconsent.get('data'); 1912 var same_type = typeof cookie_data === typeof new_data; 1913 1914 if (same_type && typeof cookie_data === "object") { 1915 !cookie_data && (cookie_data = {}); 1916 1917 for (var prop in new_data) { 1918 if (cookie_data[prop] !== new_data[prop]) { 1919 cookie_data[prop] = new_data[prop] 1920 set = true; 1921 } 1922 } 1923 } else if ((same_type || !cookie_data) && cookie_data !== new_data) { 1924 cookie_data = new_data; 1925 set = true; 1926 } 1927 } else { 1928 cookie_data = new_data; 1929 set = true; 1930 } 1931 1932 if (set) { 1933 saved_cookie_content['data'] = cookie_data; 1934 _setCookie(_config.cookie_name, JSON.stringify(saved_cookie_content)); 1935 } 1936 1937 return set; 1938 } 1939 1940 /** 1941 * Helper method to set a variety of fields 1942 * @param {string} field 1943 * @param {object} data 1944 * @returns {boolean} 1945 */ 1946 _cookieconsent.set = function (field, data) { 1947 switch (field) { 1948 case 'data': 1949 return _setCookieData(data['value'], data['mode']); 1950 default: 1951 return false; 1952 } 1953 } 1954 1955 /** 1956 * Retrieve data from existing cookie 1957 * @param {string} field 1958 * @param {string} [cookie_name] 1959 * @returns {any} 1960 */ 1961 _cookieconsent.get = function (field, cookie_name) { 1962 var cookie = JSON.parse(_getCookie(cookie_name || _config.cookie_name, 'one', true) || "{}"); 1963 1964 return cookie[field]; 1965 } 1966 1967 /** 1968 * Read current configuration value 1969 * @returns {any} 1970 */ 1971 _cookieconsent.getConfig = function (field) { 1972 return _config[field] || user_config[field]; 1973 } 1974 1975 /** 1976 * Obtain accepted and rejected categories 1977 * @returns {{accepted: string[], rejected: string[]}} 1978 */ 1979 var _getCurrentCategoriesState = function () { 1980 1981 // get accepted categories 1982 accepted_categories = saved_cookie_content['categories'] || []; 1983 1984 // calculate rejected categories (all_categories - accepted_categories) 1985 rejected_categories = all_categories.filter(function (category) { 1986 return (_inArray(accepted_categories, category) === -1); 1987 }); 1988 1989 return { 1990 accepted: accepted_categories, 1991 rejected: rejected_categories 1992 } 1993 } 1994 1995 /** 1996 * Calculate "accept type" given current categories state 1997 * @param {{accepted: string[], rejected: string[]}} currentCategoriesState 1998 * @returns {string} 1999 */ 2000 var _getAcceptType = function (currentCategoriesState) { 2001 2002 var type = 'custom'; 2003 2004 // number of categories marked as necessary/readonly 2005 var necessary_categories_length = readonly_categories.filter(function (readonly) { 2006 return readonly === true; 2007 }).length; 2008 2009 // calculate accept type based on accepted/rejected categories 2010 if (currentCategoriesState.accepted.length === all_categories.length) 2011 type = 'all'; 2012 else if (currentCategoriesState.accepted.length === necessary_categories_length) 2013 type = 'necessary' 2014 2015 return type; 2016 } 2017 2018 /** 2019 * @typedef {object} userPreferences 2020 * @property {string} accept_type 2021 * @property {string[]} accepted_categories 2022 * @property {string[]} rejected_categories 2023 */ 2024 2025 /** 2026 * Retrieve current user preferences (summary) 2027 * @returns {userPreferences} 2028 */ 2029 _cookieconsent.getUserPreferences = function () { 2030 var currentCategoriesState = _getCurrentCategoriesState(); 2031 var accept_type = _getAcceptType(currentCategoriesState); 2032 2033 return { 2034 'accept_type': accept_type, 2035 'accepted_categories': currentCategoriesState.accepted, 2036 'rejected_categories': currentCategoriesState.rejected 2037 } 2038 } 2039 2040 /** 2041 * Function which will run after script load 2042 * @callback scriptLoaded 2043 */ 2044 2045 /** 2046 * Dynamically load script (append to head) 2047 * @param {string} src 2048 * @param {scriptLoaded} callback 2049 * @param {object[]} [attrs] Custom attributes 2050 */ 2051 _cookieconsent.loadScript = function (src, callback, attrs) { 2052 2053 var function_defined = typeof callback === 'function'; 2054 2055 // Load script only if not already loaded 2056 if (!document.querySelector('script[src="' + src + '"]')) { 2057 2058 var script = _createNode('script'); 2059 2060 // if an array is provided => add custom attributes 2061 if (attrs && attrs.length > 0) { 2062 for (var i = 0; i < attrs.length; ++i) { 2063 attrs[i] && script.setAttribute(attrs[i]['name'], attrs[i]['value']); 2064 } 2065 } 2066 2067 // if callback function defined => run callback onload 2068 if (function_defined) { 2069 script.onload = callback; 2070 } 2071 2072 script.src = src; 2073 2074 /** 2075 * Append script to head 2076 */ 2077 document.head.appendChild(script); 2078 } else { 2079 function_defined && callback(); 2080 } 2081 } 2082 2083 /** 2084 * Manage dynamically loaded scripts: https://github.com/orestbida/cookieconsent/issues/101 2085 * If plugin has already run, call this method to enable 2086 * the newly added scripts based on currently selected preferences 2087 */ 2088 _cookieconsent.updateScripts = function () { 2089 _manageExistingScripts(); 2090 } 2091 2092 /** 2093 * Show cookie consent modal (with delay parameter) 2094 * @param {number} [delay] 2095 * @param {boolean} [create_modal] create modal if it doesn't exist 2096 */ 2097 _cookieconsent.show = function (delay, create_modal) { 2098 2099 if (create_modal === true) 2100 _createConsentModal(_config.current_lang); 2101 2102 if (consent_modal_exists) { 2103 setTimeout(function () { 2104 _addClass(html_dom, "show--consent"); 2105 2106 /** 2107 * Update attributes/internal statuses 2108 */ 2109 all_modals_container.querySelector("#cm").setAttribute('aria-hidden', 'false'); 2110 consent_modal_visible = true; 2111 2112 setTimeout(function () { 2113 last_elem_before_modal = document.activeElement; 2114 current_modal_focusable = consent_modal_focusable; 2115 }, 200); 2116 2117 _log("CookieConsent [MODAL]: show consent_modal"); 2118 }, delay > 0 ? delay : (create_modal ? 30 : 0)); 2119 } 2120 } 2121 2122 /** 2123 * Hide consent modal 2124 */ 2125 _cookieconsent.hide = function () { 2126 if (consent_modal_exists) { 2127 _removeClass(html_dom, "show--consent"); 2128 all_modals_container.querySelector("#cm").setAttribute('aria-hidden', 'true'); 2129 consent_modal_visible = false;
2130 2131 setTimeout(function () { 2132 //restore focus to the last page element which had focus before modal opening 2133 last_elem_before_modal.focus(); 2134 current_modal_focusable = null; 2135 }, 200); 2136 2137 _log("CookieConsent [MODAL]: hide"); 2138 } 2139 } 2140 2141 /** 2142 * Hide settings modal 2143 */ 2144 _cookieconsent.hideSettings = function () { 2145 _removeClass(html_dom, "show--settings"); 2146 settings_modal_visible = false; 2147 all_modals_container.querySelector("#s-cnt").setAttribute('aria-hidden', 'true'); 2148 2149 2150 setTimeout(function () { 2151 /** 2152 * If consent modal is visible, focus him (instead of page document) 2153 */ 2154 if (consent_modal_visible) { 2155 last_consent_modal_btn_focus && last_consent_modal_btn_focus.focus(); 2156 current_modal_focusable = consent_modal_focusable; 2157 } else { 2158 /** 2159 * Restore focus to last page element which had focus before modal opening 2160 */ 2161 last_elem_before_modal && last_elem_before_modal.focus(); 2162 current_modal_focusable = null; 2163 } 2164 2165 clicked_inside_modal = false; 2166 }, 200); 2167 2168 _log("CookieConsent [SETTINGS]: hide settings_modal"); 2169 } 2170 2171 /** 2172 * Accept cookieconsent function API 2173 * @param {string[]|string} _categories - Categories to accept 2174 * @param {string[]} [_exclusions] - Excluded categories [optional] 2175 */ 2176 _cookieconsent.accept = function (_categories, _exclusions) { 2177 var categories = _categories || undefined; 2178 var exclusions = _exclusions || []; 2179 var to_accept = []; 2180 2181 /** 2182 * Get all accepted categories 2183 * @returns {string[]} 2184 */ 2185 var _getCurrentPreferences = function () { 2186 var toggles = document.querySelectorAll('.c-tgl') || []; 2187 var states = []; 2188 2189 for (var i = 0; i < toggles.length; i++) { 2190 if (toggles[i].checked) { 2191 states.push(toggles[i].value); 2192 } 2193 } 2194 return states; 2195 } 2196 2197 if (!categories) { 2198 to_accept = _getCurrentPreferences(); 2199 } else { 2200 if ( 2201 typeof categories === "object" && 2202 typeof categories.length === "number" 2203 ) { 2204 for (var i = 0; i < categories.length; i++) { 2205 if (_inArray(all_categories, categories[i]) !== -1) 2206 to_accept.push(categories[i]); 2207 } 2208 } else if (typeof categories === "string") { 2209 if (categories === 'all') 2210 to_accept = all_categories.slice(); 2211 else { 2212 if (_inArray(all_categories, categories) !== -1) 2213 to_accept.push(categories); 2214 } 2215 } 2216 } 2217 2218 // Remove excluded categories 2219 if (exclusions.length >= 1) { 2220 for (i = 0; i < exclusions.length; i++) { 2221 to_accept = to_accept.filter(function (item) { 2222 return item !== exclusions[i] 2223 }) 2224 } 2225 } 2226 2227 // Add back all the categories set as "readonly/required" 2228 for (i = 0; i < all_categories.length; i++) { 2229 if ( 2230 readonly_categories[i] === true && 2231 _inArray(to_accept, all_categories[i]) === -1 2232 ) { 2233 to_accept.push(all_categories[i]); 2234 } 2235 } 2236 2237 _saveCookiePreferences(to_accept); 2238 } 2239 2240 /** 2241 * API function to easily erase cookies 2242 * @param {(string|string[])} _cookies 2243 * @param {string} [_path] - optional 2244 * @param {string} [_domain] - optional 2245 */
2246 _cookieconsent.eraseCookies = function (_cookies, _path, _domain) { 2247 var cookies = []; 2248 var domains = _domain 2249 ? [_domain, "." + _domain] 2250 : [_config.cookie_domain, "." + _config.cookie_domain]; 2251 2252 if (typeof _cookies === "object" && _cookies.length > 0) { 2253 for (var i = 0; i < _cookies.length; i++) { 2254 this.validCookie(_cookies[i]) && cookies.push(_cookies[i]); 2255 } 2256 } else { 2257 this.validCookie(_cookies) && cookies.push(_cookies); 2258 } 2259 2260 _eraseCookies(cookies, _path, domains); 2261 } 2262 2263 /** 2264 * Set cookie, by specifying name and value 2265 * @param {string} name 2266 * @param {string} value 2267 */ 2268 var _setCookie = function (name, value) { 2269 2270 var cookie_expiration = _config.cookie_expiration; 2271 2272 if (typeof _config.cookie_necessary_only_expiration === 'number' && accept_type === 'necessary') 2273 cookie_expiration = _config.cookie_necessary_only_expiration; 2274 2275 value = _config.use_rfc_cookie ? encodeURIComponent(value) : value; 2276 2277 var date = new Date(); 2278 date.setTime(date.getTime() + (1000 * (cookie_expiration * 24 * 60 * 60))); 2279 var expires = "; expires=" + date.toUTCString(); 2280 2281 var cookieStr = name + "=" + (value || "") + expires + "; Path=" + _config.cookie_path + ";"; 2282 cookieStr += " SameSite=" + _config.cookie_same_site + ";"; 2283 2284 // assures cookie works with localhost (=> don't specify domain if on localhost) 2285 if (window.location.hostname.indexOf(".") > -1) { 2286 cookieStr += " Domain=" + _config.cookie_domain + ";"; 2287 } 2288 2289 if (window.location.protocol === "https:") { 2290 cookieStr += " Secure;"; 2291 } 2292 2293 document.cookie = cookieStr; 2294 2295 _log("CookieConsent [SET_COOKIE]: '" + name + "' expires after " + cookie_expiration + " day(s)"); 2296 } 2297 2298 /** 2299 * Get cookie value by name, 2300 * returns the cookie value if found (or an array 2301 * of cookies if filter provided), otherwise empty string: "" 2302 * @param {string} name 2303 * @param {string} filter 'one' or 'all' 2304 * @param {boolean} [get_value] set to true to obtain its value 2305 * @returns {string|string[]} 2306 */ 2307 var _getCookie = function (name, filter, get_value) { 2308 var found; 2309 2310 if (filter === 'one') { 2311 found = document.cookie.match("(^|;)\\s*" + name + "\\s*=\\s*([^;]+)"); 2312 found = found ? (get_value ? found.pop() : name) : ""; 2313 2314 if (found && name === _config.cookie_name) { 2315 try { 2316 found = JSON.parse(found) 2317 } catch (e) { 2318 try { 2319 found = JSON.parse(decodeURIComponent(found)) 2320 } catch (e) { 2321 // if I got here => cookie value is not a valid json string 2322 found = {}; 2323 } 2324 } 2325 found = JSON.stringify(found); 2326 } else { 2327 //Undetected Cookies 2328 } 2329 } else if (filter === 'all') { 2330 // array of names of all existing cookies 2331 var cookies = document.cookie.split(/;\s*/); 2332 found = []; 2333 for (var i = 0; i < cookies.length; i++) { 2334 found.push(cookies[i].split("=")[0]); 2335 } 2336 } 2337 2338 return found; 2339 } 2340 2341 /** 2342 * Delete cookie by name & path 2343 * @param {string[]} cookies 2344 * @param {string} [custom_path] - optional 2345 * @param {string[]} domains - example: ['domain.com', '.domain.com'] 2346 */ 2347 var _eraseCookies = function (cookies, custom_path, domains) { 2348 var path = custom_path ? custom_path : '/'; 2349 var expires = 'Expires=Thu, 01 Jan 1970 00:00:01 GMT;'; 2350 2351 for (var i = 0; i < cookies.length; i++) { 2352 for (var j = 0; j < domains.length; j++) { 2353 var d = window.location.hostname.split("."); 2354 while (d.length > 0) { 2355 var cookieBase = encodeURIComponent(cookie
2355s[i].split(";")[0].split("=")[0]) + '=; expires=Thu, 01-Jan-1970 00:00:01 GMT; domain=' + d.join('.') + ' ;path='; 2356 var p = location.pathname.split('/'); 2357 document.cookie = cookieBase + '/'; 2358 while (p.length > 0) { 2359 document.cookie = cookieBase + p.join('/'); 2360 p.pop(); 2361 }; 2362 d.shift(); 2363 } 2364 document.cookie = cookies[i] + '=; path=' + path + (domains[j].indexOf('.') == 0 ? '; domain=' + domains[j] : "") + '; ' + expires; 2365 } 2366 _log("CookieConsent [AUTOCLEAR]: deleting cookie: '" + cookies[i] + "' path: '" + path + "' domain:", domains); 2367 } 2368 } 2369 2370 /** 2371 * Returns true if cookie was found and has valid value (not empty string) 2372 * @param {string} cookie_name 2373 * @returns {boolean} 2374 */ 2375 _cookieconsent.validCookie = function (cookie_name) { 2376 return _getCookie(cookie_name, 'one', true) !== ""; 2377 } 2378 2379 /** 2380 * Function to run when event is fired 2381 * @callback eventFired 2382 */ 2383 2384 /** 2385 * Add event listener to dom object (cross browser function) 2386 * @param {Element} elem 2387 * @param {string} event 2388 * @param {eventFired} fn 2389 * @param {boolean} [isPassive] 2390 */ 2391 var _addEvent = function (elem, event, fn, isPassive) { 2392 elem.addEventListener(event, fn, isPassive === true ? {passive: true} : false); 2393 } 2394 2395 /** 2396 * Get all prop. keys defined inside object 2397 * @param {Object} obj 2398 */ 2399 var _getKeys = function (obj) { 2400 if (typeof obj === "object") { 2401 return Object.keys(obj); 2402 } 2403 } 2404 2405 /** 2406 * Append class to the specified dom element 2407 * @param {HTMLElement} elem 2408 * @param {string} classname 2409 */ 2410 var _addClass = function (elem, classname) { 2411 if(typeof elem !== "undefined"){ 2412 elem.classList.add(classname); 2413 } 2414 } 2415 2416 /** 2417 * Remove specified class from dom element 2418 * @param {HTMLElement} elem 2419 * @param {string} classname 2420 */ 2421 var _removeClass = function (el, className) { 2422 el.classList.remove(className); 2423 } 2424 2425 /** 2426 * Check if html element has class 2427 * @param {HTMLElement} el 2428 * @param {string} className 2429 */ 2430 var _hasClass = function (el, className) { 2431 return el.classList.contains(className); 2432 } 2433 2434 2435 /** 2436 * Replace all link placeholders in the cookiemanager temp html 2437 * @param token 2438 * @param link 2439 */ 2440 function _replaceLink(token, link) { 2441 for (const element of all_modals_container.querySelectorAll("#s-cnt *, #cm *")) { 2442 if (element.textContent.includes(token)) { 2443 element.innerHTML = element.innerHTML.replace(token, link); 2444 console.log("Replace??"); 2445 } 2446 } 2447 } 2448 2449 2450 return _cookieconsent; 2451 }; 2452 2453 var init = 'initCookieConsent'; 2454 /** 2455 * Make CookieConsent object accessible globally 2456 */ 2457 if (typeof window !== 'undefined' && typeof window[init] !== 'function') { 2458 window[init] = CookieConsent 2459 } 2460})();
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.