PageSourceSearch

https://www.museum-joanneum.at/typo3temp/assets/compressed/consent…15000b05b60f55f1910369ed9671a.js?1790764415

js museum-joanneum.at collected 2026-10-01 10:11:53 UTC 102,949 bytes, 2,460 lines download raw bytes

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.