PageSourceSearch

https://www.univie.ac.at/typo3temp/assets/compressed/consent-a94312c7f2e42f009d9974f27fffecfa.js?1790158233

js univie.ac.at collected 2026-09-24 08:24:40 UTC 104,379 bytes, 2,478 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|lighthouse/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                    block_title_btn2.setAttribute('role', 'button');
689                    var block_switch2 = category.querySelector(".expand-button");
690                    block_switch2.setAttribute('role', 'checkbox');
691
692                    var block_switch_span2 = category.querySelector(".c-tg");
693
694                    // These 2 spans will contain each 2 pseudo-elements to generate 'tick' and 'x' icons
695                    block_title_btn2.innerText = categories[ii]["title"];
696
697                    if (isExpandable) {
698                        block_title_btn2.setAttribute('aria-expanded', 'false');
699                        block_title_btn2.setAttribute('aria-controls', accordion_id2);
700                    }
701
702                    //block_switch2.type = 'checkbox';
703                    //block_switch_span2.setAttribute('aria-hidden', 'true');
704                    block_switch2.value = categories[ii]["category"];
705
706                    /**
707                     * Set toggle as readonly if true (disable checkbox)
708                     */
709                    if (categories[ii]["toggle"]["readonly"]) {
710                        block_switch2.disabled = true;
711                        _addClass(block_switch_span2, 'c-ro');
712                    }
713
714                    /**
715                     * Set toggle as required if true
716                     */
717                    if(categories[ii]["toggle"]["enabled"]){
718                        block_switch2.checked = true;
719                    }
720
721                    // Add label for toggle
722                    var block_switchlabel = category.querySelector(".t-lb");
723                    block_switchlabel.innerText = categories[ii]["title"];
724
725                    //category.setAttribute('aria-hidden', 'true');
726
727                    /**
728                     * On button click handle the following :=> aria-expanded, aria-hidden and act class for current block
729                    */
730                    (function (accordion2, block_section2, btn2) {
731                        _addEvent(block_title_btn2, 'click', function () {
732                            if (!_hasClass(block_section2, 'opencategory')) {
733                                _addClass(block_section2, 'opencategory');
734                                _addClass(btn2, 'act');
735                                btn2.setAttribute('aria-expanded', 'true');
736                                accordion2.setAttribute('aria-hidden', 'false');
737                            } else {
738                                _removeClass(block_section2, 'opencategory');
739                                _removeClass(btn2, 'act');
740                                btn2.setAttribute('aria-expanded', 'false');
741                                accordion2.setAttribute('aria-hidden', 'true');
742                            }
743                        }, false);
744                    }
744)(category, category.querySelector(".block-section"), block_title_btn2);
745
746                }
747
748                cf_category_list_full.push(category);
749            }
750            /* CF HOOK  END*/
751
752
753            // Create settings modal content (blocks)
754            for (var i = 0; i < n_blocks; ++i) {
755
756                var title_data = all_blocks[i]['title'],
757                    description_data = all_blocks[i]['description'],
758                    toggle_data = all_blocks[i]['toggle'],
759                    cookie_table_data = all_blocks[i]['cookie_table'],
760                    remove_cookie_tables = user_config['remove_cookie_tables'] === true,
761                    isExpandable = (description_data && 'truthy') || (!remove_cookie_tables && (cookie_table_data && 'truthy'));
762
763
764                // Create title
765                var block_section = _createNode('div');
766                var block_table_container = _createNode('div');
767
768                // Create description
769                if (description_data) {
770                    var block_desc = _createNode('div');
771                    block_desc.className = 'p';
772                    block_desc.insertAdjacentHTML('beforeend', description_data);
773                }
774
775                var block_title_container = _createNode('div');
776                block_title_container.className = 'title';
777
778                block_section.className = 'c-bl';
779                block_table_container.className = 'desc';
780
781
782                // Create toggle if specified (opt in/out)
783                if (typeof toggle_data !== 'undefined') {
784                    var accordion_id = "c-ac-" + i;
785
786                    // Create button (to collapse/expand block description)
787                    var block_title_btn = isExpandable ? _createNode('button') : _createNode('div');
788                    var block_switch_label = _createNode('label');
789                    var block_switch = _createNode('input');
790                    var block_switch_span = _createNode('span');
791                    var label_text_span = _createNode('span');
792
793                    // These 2 spans will contain each 2 pseudo-elements to generate 'tick' and 'x' icons
794                    var block_switch_span_on_icon = _createNode('span');
795                    var block_switch_span_off_icon = _createNode('span');
796
797                    block_title_btn.className = isExpandable ? 'b-tl exp' : 'b-tl';
798                    block_title_btn.setAttribute('role', 'button');
799                    block_switch_label.className = 'b-tg';
800                    block_switch.className = 'c-tgl';
801                    block_switch_span_on_icon.className = 'on-i';
802                    block_switch_span_off_icon.className = 'off-i';
803                    block_switch_span.className = 'c-tg';
804                    label_text_span.className = "t-lb";
805
806                    if (isExpandable) {
807                        block_title_btn.setAttribute('aria-expanded', 'false');
808                        block_title_btn.setAttribute('aria-controls', accordion_id);
809                    }
810
811                    block_switch.type = 'checkbox';
812                    block_switch_span.setAttribute('aria-hidden', 'true');
813
814                    var cookie_category = toggle_data.value;
815                    block_switch.value = cookie_category;
816
817                    label_text_span.textContent = title_data;
818                    block_title_btn.insertAdjacentHTML('beforeend', title_data);
819
820                    block_title_container.appendChild(block_title_btn);
821                    block_switch_span.appendChild(block_switch_span_on_icon);
822                    block_switch_span.appendChild(block_switch_span_off_icon);
823
824                    /**
825                     * If consent is valid => retrieve category states from cookie
826                     * Otherwise use states defined in the user_config. object
827                     */
828
829                    if (!invalid_consent) {
830                        if (_inArray(saved_cookie_content['categories'], cookie_category) > -1) {
831                            block_switch.checked = true;
832                            !new_settings_blocks && toggle_states.push(true);
833                        } else {
834                            !new_settings_blocks && toggle_states.push(false);
835                        }
836                    } else if (toggle_data['enabled']) {
837
838                        block_switch.checked = true;
839                        !new_settings_blocks && toggle_states.push(true);
840
841                        /**
842                         * Keep track of categories enabled by default (useful when mode=='opt-out')
843                         */
844                        if (toggle_data['enabled'])
845                            !new_settings_blocks && default_enabled_categories.push(cookie_category);
846
847                    } else if (toggle_data["enabled_by_default"]){
848                        block_switch.checked = true;
849                        !new_settings_blocks && toggle_states.push(true);
850
851                        /**
852                         * Keep track of categories enabled by default (useful when mode=='opt-out')
853                         */
854                        if (toggle_data['enabled'])
855                            !new_settings_blocks && default_enabled_categories.push(cookie_category);
856                    } else {
857                        !new_settings_blocks && toggle_states.push(false);
858                    }
859
860                    !new_settings_blocks && all_categories.push(cookie_category);
861
862                    /**
863                     * Set toggle as readonly if true (disable checkbox)
864                     */
865                    if (toggle_data['readonly']) {
866                        block_switch.disabled = true;
867                        _addClass(block_switch_span, 'c-ro');
868                        !new_settings_blocks && readonly_categories.push(true);
869                    } else {
870                        !new_settings_blocks && readonly_categories.push(false);
871                    }
872
873                    if(toggle_data["enabled"]){
874                        block_switch.checked = true;
875                    }
876
877                    block_switch.setAttribute("data-cfcookie-category", all_blocks[i]["category"]);
878                    if (_categorysSelected[all_blocks[i]["category"]] === false || _categorysSelected[all_blocks[i]["category"]] === undefined) {
879                        _categorysSelected[all_blocks[i]["category"]] = block_switch.checked;
880                    }
881
882
883                    _addClass(block_table_container, 'b-acc');
884                    _addClass(block_title_container, 'b-bn');
885                    _addClass(block_section, 'b-ex');
886                    _addClass(block_section, all_blocks[i]["category"]);
887
888                    block_table_container.id = accordion_id;
889                    block_table_container.setAttribute('aria-hidden', 'true');
890
891                    block_switch_label.appendChild(block_switch);
892                    block_switch_label.appendChild(block_switch_span);
893                    block_switch_label.appendChild(label_text_span);
894                    block_title_container.appendChild(block_switch_label);
895
896                    /**
897                     * On button click handle the following :=> aria-expanded, aria-hidden and act class for current block
898                     */
899
900                    isExpandable && (function (accordion, block_section, btn) {
901                        _addEvent(block_title_btn, 'click', function () {
902                            if (!_hasClass(block_section, 'act')) {
903                                _addClass(block_section, 'act');
904                                btn.setAttribute('aria-expanded', 'true');
905                                accordion.setAttribute('aria-hidden', 'false');
906                            } else {
907                                _removeClass(block_section, 'act');
908                                btn.setAttribute('aria-expanded', 'false');
909                                accordion.setAttribute('aria-hidden', 'true');
910                            }
911                        }, false);
912                    })(block_table_container, block_section, block_title_btn);
913
914                } else {
915                    /**
916                     * If block is not a button (no toggle defined),
917                     * create a simple div instead
918                     */
919                    if (title_data) {
920                        var block_title = _createNode('div');
921                        block_title.className = 'b-tl freaking';
922                        block_title.setAttribute('role', 'heading');
923                        block_title.setAttribute('aria-level', '3');
924                        block_title.insertAdjacentHTML('beforeend', title_data);
925                        block_title_container.appendChild(block_title);
926                    }
927                }
928
929                title_data && block_section.appendChild(block_title_container);
930                description_data && block_table_container.appendChild(block_desc);
931                all_modals_container.querySelector("#cf-category-wrapper").appendChild(block_section);
932                // if cookie table found, generate table for this block
933                if (!remove_cookie_tables && typeof cookie_table_data !== 'undefined' && cookie_table_data.length > 0) {
934                    var tr_tmp_fragment = document.createDocumentFragment();
935
936                    /**
937                     * Use custom table headers
938                     */
939                    for (var p = 0; p < all_table_headers.length; ++p) {
940                        // create new header
941                        var th1 = _createNode('th');
942                        var obj = all_table_headers[p];
943                        th1.setAttribute('scope', 'col');
944
945                        // get custom header content
946                        if (obj) {
947                            var new_column_key = obj && _getKeys(obj)[0];
948                            th1.textContent = all_table_headers[p][new_column_key];
949                            tr_tmp_fragment.appendChild(th1);
950                        }
951                    }
952
953                    var tr_tmp = _createNode('tr');
954                    tr_tmp.appendChild(tr_tmp_fragment);
955
956                    // create table header & append fragment
957                    var thead = _createNode('thead');
958                    thead.appendChild(tr_tmp);
959
960                    // append header to table
961                    var block_table = _createNode('table');
962                    block_table.appendChild(thead);
963
964                    var tbody_fragment = document.createDocumentFragment();
965
966                    // create table content
967                    for (var n = 0; n < cookie_table_data.length; n++) {
968                        var tr = _createNode('tr');
969                        tr.setAttribute("class","cookie-item");
970
971                        var tr_description = _createNode('tr');
972                        tr_description.setAttribute("class", "cookie-additional-description");
973                        tr_description.setAttribute("aria-hidden", "true");
974                        tr_description.setAttribute("id", 'c-cookie-desc-' + Math.random().toString(36).substr(2));
975
976                        for (var g = 0; g < all_table_headers.length; ++g) {
977                            // get custom header content
978                            obj = all_table_headers[g];
979                            if (obj) {
980                                new_column_key = _getKeys(obj)[0];
981
982                                var td_tmp = _createNode('td');
983                                // Allow html inside table cells
984                                td_tmp.insertAdjacentHTML('beforeend', cookie_table_data[n][new_column_key]);
985                                td_tmp.setAttribute('data-column', obj[new_column_key]);
986
987                                tr.appendChild(td_tmp);
988                                // hydrate cookie info button
989                                let cookieInfoBtn = tr.getElementsByClassName('cookie-info-btn')[0];
990                                if (cookieInfoBtn) {
991                                    cookieInfoBtn.setAttribute("aria-expanded", "false");
992                                    cookieInfoBtn.setAttribute("aria-controls", tr_description.getAttribute("id"));
993                                    _addEvent(cookieInfoBtn, 'click', function () {
994                                        // get table row
995                                        let tr = this.parentNode.parentNode;
996                                        if (_hasClass(tr.nextSibling, "cookie-description-active") === false) {
997                                            tr.setAttribute("class", "cookie-additional-header cookie-item");
998                                            tr.nextSibling.setAttribute("aria-hidden", "false");
999                                            this.setAttribute("aria-expanded", "true");
1000                                            _addClass(tr.nextSibling, "cookie-description-active");
1001                                        } else {
1002                                            _removeClass(tr.nextSibling, "cookie-description-active");
1003                                            tr.nextSibling.setAttribute("aria-hidden", "true");
1004                                            this.setAttribute("aria-expanded", "false");
1005                                        }
1006                                    });
1007                                }
1008                            }
1009                        }
1010
1011                        var td_tmp_description = _createNode('td');
1012                        td_tmp_description.setAttribute('colspan', all_table_headers.length);
1013                        td_tmp_description.setAttribute('class', "cookie-informations");
1014
1015                        var description_html_box = _createNode('div');
1016                        for (const key in cookie_table_data[n]["additional_information"]) {
1017                            if(cookie_table_data[n]["additional_information"][key]["value"] === "" || cookie_table_data[n]["additional_information"][key]["value"] === 0) continue;
1018                            let text = _createNode('p');
1019                            text.setAttribute('data-key', key);
1020                            text.insertAdjacentHTML('beforeend', "<span class='cookie-title'>" + cookie_table_data[n]["additional_information"][key]["title"] + ":</span>  " + cookie_table_data[n]["additional_information"][key]["value"]);
1021                            description_html_box.appendChild(text);
1022                        }
1023
1024                        td_tmp_description.insertAdjacentHTML("beforeend",  description_html_box.innerHTML);
1025                        tr_description.appendChild(td_tmp_description);
1026
1027                        tbody_fragment.appendChild(tr);
1028                        tbody_fragment.appendChild(tr_description);
1029                    }
1030
1031                    // append tbody_fragment to tbody & append the latter into the table
1032                    var tbody = _createNode('tbody');
1033                    tbody.appendChild(tbody_fragment);
1034                    block_table.appendChild(tbody);
1035                    block_table_container.appendChild(block_table);
1036
1037                }
1038
1039                /**
1040                 * Append only if is either:
1041                 * - togglable div with title
1042                 * - a simple div with at least a title or description
1043                 */
1044                if (toggle_data && title_data || (!toggle_data && (title_data || description_data))) {
1045                    block_section.appendChild(block_table_container);
1046
1047                    /*CF HOOK */
1048                    for (var iii = 0; iii < cf_category_list_full.length; ++iii) {
1049
1050                        if (block_section.classList.contains(cf_category_list_full[iii].id)) {
1051                            cf_category_list_full[iii].children[1].appendChild(block_section);
1052                        }
1053                    }
1054
1055                    for (var iiii = 0; iiii < cf_category_list_full.length; ++iiii) {
1056
1057                        all_modals_container.querySelector("#cf-category-wrapper").appendChild(cf_category_list_full[iiii]);
1058
1059                    }
1060
1061                    /*CF HOOK END */
1062                    //if(new_settings_blocks)
1063                    //  new_settings_blocks.appendChild(cf_category_container);
1064                    //  else
1065                    //   settings_blocks.appendChild(cf_category_container);
1066                }
1067            }
1068
1069
1070            _addEvent(all_modals_container.querySelector("#s-all-bn"), 'click', function () {
1071                _cookieconsent.hideSettings();
1072                _cookieconsent.hide();
1073                _cookieconsent.accept('all');
1074            });
1075
1076
1077            all_modals_container.querySelector("#s-all-bn").innerHTML = user_config.languages[lang]['settings_modal']['accept_all_btn'];
1078
1079            var reject_all_btn_text = user_config.languages[lang]['settings_modal']['reject_all_btn'];
1080
1081            // Add third [optional] reject all button if provided
1082            _addEvent(all_modals_container.querySelector("#s-rall-bn"), 'click', function () {
1083                _cookieconsent.hideSettings();
1084                _cookieconsent.hide();
1085                _cookieconsent.accept([]);
1086            });
1087            all_modals_container.querySelector("#s-rall-bn").innerHTML = reject_all_btn_text;
1088
1089
1090            // Add save preferences button onClick event
1091            // Hide both settings modal and consent modal
1092            _addEvent(all_modals_container.querySelector("#s-sv-bn"), 'click', function () {
1093                _cookieconsent.hideSettings();
1094                _cookieconsent.hide();
1095                _cookieconsent.accept();
1096            });
1097
1098            all_modals_container.querySelector("#s-sv-bn").innerHTML = user_config.languages[lang]['settings_modal']['s
1098ave_settings_btn'];
1099
1100            /*
1101                        if(new_settings_blocks) {
1102                            // replace entire existing cookie category blocks with the new cookie categories new blocks (in a different language)
1103                            settings_inner.replaceChild(new_settings_blocks, settings_blocks);
1104                            settings_blocks = new_settings_blocks;
1105                            return;
1106                        };
1107            */
1108        }
1109
1110        /**
1111         * Generate cookie consent html markup
1112         */
1113        var _createCookieConsentHTML = function () {
1114
1115            // Create main container which holds both consent modal & settings modal
1116            main_container = _createNode('div');
1117            main_container.id = 'cc--main';
1118
1119            // Fix layout flash
1120            main_container.style.position = "fixed";
1121            main_container.style.zIndex = "2147483647";
1122            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]-->'
1123            all_modals_container = main_container.children[0];
1124
1125            // Get current language
1126            var lang = _config.current_lang;
1127
1128            // Create consent modal
1129            if (consent_modal_exists)
1130                _createConsentModal(lang);
1131
1132            // Always create settings modal
1133            _createSettingsModal(lang);
1134
1135            for (const key in _categorysSelected) {
1136                if (_categorysSelected[key] === true || _categorysSelected[key] === "true") {
1137                    main_container.querySelector(".expand-button[value=" + key + "]").setAttribute("checked", "checked");
1138                }
1139
1140            }
1141            // Finally append everything (main_container holds both modals)
1142            (root || document.body).appendChild(main_container);
1143        }
1144
1145        /**
1146         * Update/change modals language
1147         * @param {String} lang new language
1148         * @param {Boolean} [force] update language fields forcefully
1149         * @returns {Boolean}
1150         */
1151        _cookieconsent.updateLanguage = function (lang, force) {
1152
1153            if (typeof lang !== 'string') return;
1154
1155            /**
1156             * Validate language to avoid errors
1157             */
1158            var new_validated_lang = _getValidatedLanguage(lang, user_config.languages);
1159
1160            /**
1161             * Set language only if it differs from current
1162             */
1163            if (new_validated_lang !== _config.current_lang || force === true) {
1164                _config.current_lang = new_validated_lang;
1165
1166                if (consent_modal_exists) {
1167                    _createConsentModal(new_validated_lang);
1168                }
1169
1170                _createSettingsModal(new_validated_lang);
1171
1172                _log("CookieConsent [LANGUAGE]: curr_lang: '" + new_validated_lang + "'");
1173
1174                return true;
1175            }
1176
1177            return false;
1178        }
1179
1180        /**
1181         * Delete all cookies which are unused (based on selected preferences)
1182         *
1183         * @param {boolean} [clearOnFirstAction]
1184         */
1185        var _autoclearCookies = function (clearOnFirstAction) {
1186
1187            // Get number of blocks
1188            var len = all_blocks.length;
1189            var count = -1;
1190
1191            // reset reload state
1192            reload_page = false;
1193
1194            // Retrieve all cookies
1195            var all_cookies_array = _getCookie('', 'all');
1196
1197            // delete cookies on 'www.domain.com' and '.www.domain.com' (can also be without www)
1198            var domains = [_config.cookie_domain, '.' + _config.cookie_domain];
1199
1200
1201
1202            // if domain has www, delete cookies also for 'domain.com' and '.domain.com'
1203            if (_config.cookie_domain.slice(0, 4) === 'www.') {
1204                var non_www_domain = _config.cookie_domain.substr(4);  // remove first 4 chars (www.)
1205                domains.push(non_www_domain);
1206                domains.push('.' + non_www_domain);
1207            }
1208
1209
1210            // For each block
1211            for (var i = 0; i < len; i++) {
1212
1213                // Save current block (local scope & less accesses -> ~faster value retrieval)
1214                var curr_block = all_blocks[i];
1215
1216                // If current block has a toggle for opt in/out
1217                if (Object.prototype.hasOwnProperty.call(curr_block, "toggle")) {
1218
1219                    // if current block has a cookie table, an off toggle,
1220                    // and its preferences were just changed => delete cookies
1221                    var category_just_disabled = _inArray(changed_settings, curr_block['toggle']['value']) > -1;
1222                    if (
1223                        !toggle_states[++count] &&
1224                        Object.prototype.hasOwnProperty.call(curr_block, "cookie_table") &&
1225                        (clearOnFirstAction || category_just_disabled)
1226                    ) {
1227                        var curr_cookie_table = curr_block['cookie_table'];
1228
1229                        // Get first property name
1230                        var ckey = _getKeys(all_table_headers[0])[0];
1231
1232                        // Get number of cookies defined in cookie_table
1233                        var clen = curr_cookie_table.length;
1234
1235                        // set "reload_page" to true if reload=on_disable
1236                        if (curr_block['toggle']['reload'] === 'on_disable')
1237                            category_just_disabled && (reload_page = true);
1238
1239                        // for each row defined in the cookie table
1240                        for (var j = 0; j < clen; j++) {
1241                            var curr_domains = domains;
1242
1243                            // Get current row of table (corresponds to all cookie params)
1244                            var curr_row = curr_cookie_table[j], found_cookies = [];
1245                            var curr_cookie_name = curr_row[ckey];
1246                            var is_regex = curr_row['is_regex'] || false;
1247                            var curr_cookie_domain = curr_row['domain'] || null;
1248                            var curr_cookie_path = curr_row['path'] || false;
1249
1250                            // set domain to the specified domain
1251                            curr_cookie_domain && (curr_domains = [curr_cookie_domain, '.' + curr_cookie_domain]);
1252
1253
1254                            // If regex provided => filter cookie array
1255                            if (is_regex) {
1256                                for (var n = 0; n < all_cookies_array.length; n++) {
1257                                    if (all_cookies_array[n].match(curr_cookie_name)) {
1258                                        found_cookies.push(all_cookies_array[n]);
1259                                    }
1260                                }
1261                            } else {
1262                                var found_index = _inArray(all_cookies_array, curr_cookie_name);
1263                                if (found_index > -1) found_cookies.push(all_cookies_array[found_index]);
1264                            }
1265
1266                            _log("CookieConsent [AUTOCLEAR]: search cookie: '" + curr_cookie_name + "', found:", found_cookies);
1267
1268                            // If cookie exists -> delete it
1269                            if (found_cookies.length > 0) {
1270                                _eraseCookies(found_cookies, curr_cookie_path, curr_domains);
1271                                curr_block['toggle']['reload'] === 'on_clear' && (reload_page = true);
1272                            }
1273                        }
1274                    }
1275                }
1276            }
1277        }
1278
1279        /**
1280         * Set toggles/checkboxes based on accepted categories and save cookie
1281         * @param {string[]} accepted_categories - Array of categories to accept
1282         */
1283        var _saveCookiePreferences = function (accepted_categories) {
1284
1285            changed_settings = [];
1286
1287            // Retrieve all toggle/checkbox values
1288            var category_toggles = document.querySelectorAll('.c-tgl') || [];
1289
1290            // If there are opt in/out toggles ...
1291            if (category_toggles.length > 0) {
1292                for (var i = 0; i < category_toggles.length; i++) {
1293                    var categoryContainer = all_modals_container.querySelector('#'+category_toggles[i].getAttribute("data-cfcookie-category")).querySelector(".expand-button");
1294                    if (_inArray(accepted_categories, all_categories[i]) !== -1) {
1295                        categoryContainer.checked = true;
1296                        category_toggles[i].checked = true;
1297                        if (!toggle_states[i]) {
1298                            changed_settings.push(all_categories[i]);
1299                            toggle_states[i] = true;
1300                        }
1301                    } else {
1302                        category_toggles[i].checked = false;
1303                        if (toggle_states[i]) {
1304                            changed_settings.push(all_categories[i]);
1305                            toggle_states[i] = false;
1306                        }
1307
1308                        var isActive = all_modals_container.querySelector('#'+category_toggles[i].getAttribute("data-cfcookie-category")).querySelectorAll(".block-section input:checked");
1309                        if(!!isActive){
1310                            //categoryContainer.checked = true;
1311                            if(isActive.length === 0){
1312                                categoryContainer.checked = false;
1313                            }
1314                        }
1315                    }
1316                }
1317            }
1318
1319
1320
1321
1322            /**
1323             * Clear cookies when settings/preferences change
1324             */
1325            if (!invalid_consent && _config.autoclear_cookies && changed_settings.length > 0)
1326                _autoclearCookies();
1327
1328            if (!consent_date) consent_date = new Date();
1329            if (!consent_uuid) consent_uuid = _uuidv4();
1330
1331            saved_cookie_content = {
1332                "categories": accepted_categories,
1333                "level": accepted_categories, // Copy of the `categories` property for compatibility purposes with version v2.8.0 and below.
1334                "revision": _config.revision,
1335                "data": cookie_data,
1336                "rfc_cookie": _config.use_rfc_cookie,
1337                "consent_date": consent_date.toISOString(),
1338                "consent_uuid": consent_uuid
1339            }
1340
1341            // save cookie with preferences 'categories' (only if never accepted or settings were updated)
1342            if (invalid_consent || changed_settings.length > 0) {
1343                valid_revision = true;
1344
1345
1346                /**
1347                 * Update "last_consent_update" only if it is invalid (after t)
1348                 */
1349                if (!last_consent_update)
1350                    last_consent_update = consent_date;
1351                else
1352                    last_consent_update = new Date();
1353
1354                saved_cookie_content['last_consent_update'] = last_consent_update.toISOString();
1355
1356                /**
1357                 * Update accept type
1358                 */
1359                accept_type = _getAcceptType(_getCurrentCategoriesState());
1360
1361                _setCookie(_config.cookie_name, JSON.stringify(saved_cookie_content));
1362                _manageExistingScripts();
1363            }
1364
1365            if (invalid_consent) {
1366
1367                /**
1368                 * Delete unused/"zombie" cookies if consent is not valid (not yet expressed or cookie has expired)
1369                 */
1370                if (_config.autoclear_cookies)
1371                    _autoclearCookies(true);
1372
1373                if (typeof onFirstAction === 'function')
1374                    onFirstAction(_cookieconsent.getUserPreferences(), saved_cookie_content);
1375
1376                if (typeof onAccept === 'function')
1377                    onAccept(saved_cookie_content);
1378
1379                /**
1380                 * Set consent as valid
1381                 */
1382                invalid_consent = false;
1383
1384                if (_config.mode === 'opt-in') return;
1385            }
1386
1387            // fire onChange only if settings were changed
1388            if (typeof onChange === "function" && changed_settings.length > 0)
1389                onChange(saved_cookie_content, changed_settings);
1390
1391            /**
1392             * reload page if needed
1393             */
1394            if (reload_page)
1395                window.location.reload();
1396        }
1397
1398        /**
1399         * Returns index of found element inside array, otherwise -1
1400         * @param {Array} arr
1401         * @param {Object} value
1402         * @returns {number}
1403         */
1404        var _inArray = function (arr, value) {
1405            return arr.indexOf(value);
1406        }
1407
1408        /**
1409         * Helper function which prints info (console.log())
1410         * @param {Object} print_msg
1411         * @param {Object} [optional_param]
1412         */
1413        var _log = function (print_msg, optional_param, error) {
1414            ENABLE_LOGS && (!error ? console.log(print_msg, optional_param !== undefined ? optional_param : ' ') : console.error(print_msg, optional_param || ""));
1415        }
1416
1417        /**
1418         * Helper function which creates an HTMLElement object based on 'type' and returns it.
1419         * @param {string} type
1420         * @returns {HTMLElement}
1421         */
1422        var _createNode = function (type) {
1423            var el = document.createElement(type);
1424            if (type === 'button') {
1425                el.setAttribute('type', type);
1426            }
1427            return el;
1428        }
1429
1430        /**
1431         * Generate RFC4122-compliant UUIDs.
1432         * https://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid?page=1&tab=votes#tab-top
1433         * @returns {string}
1434         */
1435        var _uuidv4 = function () {
1436            return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, function (c) {
1437                try {
1438                    return (c ^ (window.crypto || window.msCrypto).getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
1439                } catch (e) {
1440                    return '';
1441                }
1442            });
1443        }
1444
1445        /**
1446         * Resolve which language should be used.
1447         *
1448         * @param {Object} languages Object with language translations
1449         * @param {string} [requested_language] Language specified by given configuration parameters
1450         * @returns {string}
1451         */
1452        var _resolveCurrentLang = function (languages, requested_language) {
1453
1454            if (_config.auto_language === 'browser') {
1455                return _getValidatedLanguage(_getBrowserLang(), languages);
1456            } else if (_config.auto_language === 'document') {
1457                return _getValidatedLanguage(document.documentElement.lang, languages);
1458            } else {
1459                if (typeof requested_language === 'string') {
1460                    return _config.current_lang = _getValidatedLanguage(requested_language, languages);
1461                }
1462            }
1463
1464            _log("CookieConsent [LANG]: setting current_lang = '" + _config.current_lang + "'");
1465            return _config.current_lang; // otherwise return default
1466        }
1467
1468        /**
1469         * Get current client's browser language
1470         * @returns {string}
1471         */
1472        var _getBrowserLang = function () {
1473            var browser_lang = navigator.language || navigator.browserLanguage;
1474            browser_lang.length > 2 && (browser_lang = browser_lang[0] + browser_lang[1]);
1475            _log("CookieConsent [LANG]: detected_browser_lang = '" + browser_lang + "'");
1476            return browser_lang.toLowerCase()
1477        }
1478
1479        /**
1480         * Trap focus inside modal and focus the first
1481         * focusable element of current active modal
1482         */
1483        var _handleFocusTrap = function () {
1484            var tabbedOutsideDiv = false;
1485            var tabbedInsideModal = false;
1486
1487            _addEvent(document, 'keydown', function (e) {
1488                e = e || window.event;
1489
1490                // If is tab key => ok
1491                if (e.key !== 'Tab') return;
1492
1493                // If there is any modal to focus
1494                if (current_modal_focusable) {
1495                    // If reached natural end of the tab sequence => restart
1496                    if (e.shiftKey) {
1497                        if (document.activeElement === current_modal_focusable[0]) {
1498                            current_modal_focusable[1].focus();
1499                            e.preventDefault();
1500                        }
1501                    } else {
1502                        if (document.activeElement === current_modal_focusable[1]) {
1503                            current_modal_focusable[0].focus();
1504                            e.preventDefault();
1505                        }
1506                    }
1507
1508                    // If have not yet used tab (or shift+tab) and modal is open ...
1509                    // Focus the first focusable element
1510                    if (!tabbedInsideModal && !clicked_inside_modal) {
1511                        tabbedInsideModal = true;
1512                        !tabbedOutsideDiv && e.preventDefault();
1513
1514                        if (e.shiftKey) {
1515                            if (current_modal_focusable[3]) {
1516                                if (!current_modal_focusable[2]) {
1517                                    current_modal_focusable[0].focus();
1518                                } else {
1519                                    current_modal_focusable[2].focus();
1520                                }
1521                            } else {
1522                                current_modal_focusable[1].focus();
1523                            }
1524                        } else {
1525                            if (current_modal_focusable[3]) {
1526                                current_modal_focusable[3].focus();
1527                            } else {
1528                                current_modal_focusable[0].focus();
1529                            }
1530                        }
1531                    }
1532                }
1533
1534                !tabbedInsideModal && (tabbedOutsideDiv = true);
1535            });
1536
1537
1538            if (document.contains) {
1539                _addEvent(main_container, 'click', function (e) {
1540                    e = e || window.event;
1541                    /**
1542                     * If click is on the foreground overlay (and not inside settings_modal),
1543                     * hide settings modal
1544                     *
1545                     * Notice: click on div is not supported in IE
1546                     */
1547
1548                    if (_hasClass(e.target, "c-tgl")) {
1549                        var categoryIdentifier = e.target.getAttribute("data-cfcookie-category");
1550                        var categoriesSwitchButton = main_container.querySelector("#" + e.target.getAttribute("data-cfcookie-category")).querySelector(".expand-button");
1551                        var services = main_container.querySelector("#" + categoryIdentifier).querySelectorAll(".block-section ." + categoryIdentifier);
1552
1553
1554                        var isServiceActive = false;
1555                        for (var i = 0; i < services.length; i++) {
1556                            if (services[i].querySelector("input").checked === true) {
1557                                isServiceActive = true;
1558                            }
1559                        }
1560
1561                        if (isServiceActive === false) {
1562                            /* All Services are Disabled */
1563                            categoriesSwitchButton.checked = false;
1564                        } else {
1565                            categoriesSwitchButton.checked = true;
1566                        }
1567
1568
1569                    }
1570
1571                    if (_hasClass(e.target, "expand-button")) {
1572                        /** IF Category Switch button **/
1573                        var services = main_container.querySelector("#" + e.target.value).querySelectorAll(".block-section ." + e.target.value);
1574                        for (var i = 0; i < services.length; i++) {
1575                            if (e.target.checked === true && services[i].querySelector("input").disabled === false) {
1576                                services[i].querySelector("input").checked = true;
1577                            } else if(services[i].querySelector("input").disabled === false){
1578                                services[i].querySelector("input").checked = false;
1579                            }
1580                        }
1581                    }
1582
1583                    if (settings_modal_visible) {
1584                        if (!all_modals_container.querySelector("#s-inr").contains(e.target)) {
1585                            _cookieconsent.hideSettings(0);
1586                            clicked_inside_modal = false;
1587                        } else {
1588                            clicked_inside_modal = true;
1589                        }
1590                    } else if (consent_modal_visible) {
1591                        if (all_modals_container.querySelector("#cm").contains(e.target)) {
1592                            clicked_inside_modal = true;
1593                        }
1594                    }
1595
1596                }, true);
1597            }
1598        }
1599
1600        /**
1601         * Manage each modal's layout
1602         * @param {Object} gui_options
1603         */
1604        var _guiManager = function (gui_options, only_consent_modal) {
1605
1606            // If gui_options is not object => exit
1607            if (typeof gui_options !== 'object') return;
1608
1609            var consent_modal_options = gui_options['consent_modal'];
1610            var settings_modal_options = gui_options['settings_modal'];
1611
1612            /**
1613             * Helper function which adds layout and
1614             * position classes to given modal
1615             *
1616             * @param {HTMLElement} modal
1617             * @param {string[]} allowed_layouts
1618             * @param {string[]} allowed_positions
1619             * @param {string} layout
1620             * @param {string[]} position
1621             */
1622            function _setLayout(modal, allowed_layouts, allowed_positions, allowed_transitions, layout, position, transition) {
1623                position = (position && position.split(" ")) || [];
1624                // Check if specified layout is valid
1625                if (_inArray(allowed_layouts, layout) > -1) {
1626
1627                    // Add layout classes
1628                    _addClass(modal, layout);
1629
1630                    // Add position class (if specified)
1631                    if (!(layout === 'bar' && position[0] === 'middle') && _inArray(allowed_positions, position[0]) > -1) {
1632                        for (var i = 0; i < position.length; i++) {
1633                            _addClass(modal, position[i]);
1634                        }
1635                    }
1636                }
1637
1638                // Add transition class
1639                (_inArray(allowed_transitions, transition) > -1) && _addClass(modal, transition);
1640            }
1641
1642            if (consent_modal_exists && consent_modal_options) {
1643                _setLayout(
1644                    all_modals_container.querySelector("#cm"),
1645                    ['box', 'bar', 'cloud'],
1646                    ['top', 'middle', 'bottom'],
1647                    ['zoom', 'slide'],
1648                    consent_modal_options['layout'],
1649                    consent_modal_options['position'],
1650                    consent_modal_options['transition']
1651                );
1652            }
1653
1654            if (!only_consent_modal && settings_modal_options) {
1655                _setLayout(
1656                    all_modals_container.querySelector("#s-cnt"),
1657                    ['bar'],
1658                    ['left', 'right'],
1659                    ['zoom', 'slide'],
1660                    settings_modal_options['layout'],
1661                    settings_modal_options['position'],
1662                    settings_modal_options['transition']
1663                );
1664            }
1665        }
1666
1667        /**
1668         * Returns true if cookie category is accepted by the user
1669         * @param {string} cookie_category
1670         * @returns {boolean}
1671         */
1672        _cookieconsent.allowedCategory = function (cookie_category) {
1673
1674            if (!invalid_consent || _config.mode === 'opt-in')
1675                var allowed_categories = JSON.parse(_getCookie(_config.cookie_name, 'one', true) || '{}')['categories'] || []
1676            else  // mode is 'opt-out'
1677                var allowed_categories = default_enabled_categories;
1678
1679            return _inArray(allowed_categories, cookie_category) > -1;
1680        }
1681
1682        /**
1683         * "Init" method. Will run once and only if modals do not exist
1684         */
1685        _cookieconsent.run = function (user_config) {
1686
1687            if (!document.getElementById('cc_div')) {
1688
1689                // configure all parameters
1690                _setConfig(user_config);
1691
1692                // if is bot, don't run plugin
1693                if (is_bot) return;
1694
1695                // Retrieve cookie value (if set)
1696                saved_cookie_content = JSON.parse(_getCookie(_config.cookie_name, 'one', true) || "{}");
1697
1698
1699                // Retrieve "consent_uuid"
1700                consent_uuid = saved_cookie_content['consent_uuid'];
1701
1702                // If "consent_uuid" is present => assume that consent was previously given
1703                var cookie_consent_accepted = consent_uuid !== undefined;
1704
1705                // Retrieve "consent_date"
1706                consent_date = saved_cookie_content['consent_date'];
1707                consent_date && (consent_date = new Date(consent_date));
1708
1709                // Retrieve "last_consent_update"
1710                last_consent_update = saved_cookie_content['last_consent_update'];
1711                last_consent_update && (last_consent_update = new Date(last_consent_update));
1712
1713                // Retrieve "data"
1714                cookie_data = saved_cookie_content['data'] !== undefined ? saved_cookie_content['data'] : null;
1715
1716                // If revision is enabled and current value !== saved value inside the cookie =>
1716 revision is not valid
1717                if(typeof saved_cookie_content['revision'] !== "undefined" && revision_enabled && saved_cookie_content['revision'] !== _config.revision){
1718                    //user has a cookie
1719                    valid_revision = false;
1720                }else if(saved_cookie_content['revision'] !== _config.revision && typeof saved_cookie_content['revision'] !== "undefined"){
1721                    valid_revision = true;
1722                }
1723
1724                // If consent is not valid => create consent modal
1725                consent_modal_exists = invalid_consent = (!cookie_consent_accepted || !valid_revision || !consent_date || !last_consent_update || !consent_uuid);
1726
1727                // Generate cookie-settings dom (& consent modal)
1728                _createCookieConsentHTML();
1729
1730                  _getModalFocusableData();
1731
1732                _guiManager(user_config['gui_options']);
1733                _addDataButtonListeners();
1734
1735                if (_config.autorun && consent_modal_exists) {
1736                    _cookieconsent.show(user_config['delay'] || 0);
1737                }
1738
1739                // Add class to enable animations/transitions
1740                setTimeout(function () {
1741                    _addClass(main_container, 'c--anim');
1742                }, 30);
1743
1744                // Accessibility :=> if tab pressed => trap focus inside modal
1745                setTimeout(function () {
1746                    _handleFocusTrap();
1747                }, 100);
1748
1749                // If consent is valid
1750                if (!invalid_consent) {
1751                    var rfc_prop_exists = typeof saved_cookie_content['rfc_cookie'] === "boolean";
1752
1753                    /*
1754                     * Convert cookie to rfc format (if `use_rfc_cookie` is enabled)
1755                     */
1756                    if (!rfc_prop_exists || (rfc_prop_exists && saved_cookie_content['rfc_cookie'] !== _config.use_rfc_cookie)) {
1757                        saved_cookie_content['rfc_cookie'] = _config.use_rfc_cookie;
1758                        _setCookie(_config.cookie_name, JSON.stringify(saved_cookie_content));
1759                    }
1760
1761                    /**
1762                     * Update accept type
1763                     */
1764                    accept_type = _getAcceptType(_getCurrentCategoriesState());
1765
1766                    _manageExistingScripts();
1767
1768                    if (typeof onAccept === 'function')
1769                        onAccept(saved_cookie_content);
1770
1771                    _log("CookieConsent [NOTICE]: consent already given!", saved_cookie_content);
1772
1773                } else {
1774                    if (_config.mode === 'opt-out') {
1775                        _log("CookieConsent [CONFIG] mode='" + _config.mode + "', default enabled categories:", default_enabled_categories);
1776                        _manageExistingScripts(default_enabled_categories);
1777                    }
1778                    _log("CookieConsent [NOTICE]: ask for consent!");
1779                }
1780            } else {
1781                _log("CookieConsent [NOTICE]: cookie consent already attached to body!");
1782            }
1783        }
1784
1785        /**
1786         * Show settings modal (with optional delay)
1787         * @param {number} delay
1788         */
1789        _cookieconsent.showSettings = function (delay) {
1790            setTimeout(function () {
1791                _addClass(html_dom, "show--settings");
1792                all_modals_container.querySelector("#s-cnt").setAttribute('aria-hidden', 'false');
1793                settings_modal_visible = true;
1794                /**
1795                 * Set focus to the first focusable element inside settings modal
1796                 */
1797                setTimeout(function () {
1798                    // If there is no consent-modal, keep track of the last focused elem.
1799                    if (!consent_modal_visible) {
1800                        last_elem_before_modal = document.activeElement;
1801                    } else {
1802                        last_consent_modal_btn_focus = document.activeElement;
1803                    }
1804
1805                    if (settings_modal_focusable.length === 0) return;
1806
1807                    if (settings_modal_focusable[3]) {
1808                        settings_modal_focusable[3].focus();
1809                    } else {
1810                        settings_modal_focusable[0].focus();
1811                    }
1812                    current_modal_focusable = settings_modal_focusable;
1813                }, 200);
1814
1815                _log("CookieConsent [SETTINGS]: show settings_modal");
1816            }, delay > 0 ? delay : 0);
1817        }
1818
1819        /**
1820         * This function handles the loading/activation logic of the already
1821         * existing scripts based on the current accepted cookie categories
1822         *
1823         * @param {string[]} [must_enable_categories]
1824         */
1825        var _manageExistingScripts = function (must_enable_categories) {
1826
1827            if (!_config.page_scripts) return;
1828
1829            // get all the scripts with "cookie-category" attribute
1830            var scripts = document.querySelectorAll('script[' + _config.script_selector + ']');
1831            var accepted_categories = must_enable_categories || saved_cookie_content['categories'] || [];
1832
1833            /**
1834             * Load scripts (sequentially), using a recursive function
1835             * which loops through the scripts array
1836             * @param {Element[]} scripts scripts to load
1837             * @param {number} index current script to load
1838             */
1839            var _loadScripts = function (scripts, index) {
1840                if (index < scripts.length) {
1841
1842                    var curr_script = scripts[index];
1843                    var curr_script_category = curr_script.getAttribute(_config.script_selector);
1844
1845                    /**
1846                     * If current script's category is on the array of categories
1847                     * accepted by the user => load script
1848                     */
1849
1850                    if (_inArray(accepted_categories, curr_script_category) > -1) {
1851
1852                        curr_script.type = 'text/javascript';
1853                        curr_script.removeAttribute(_config.script_selector);
1854
1855                        // get current script data-src
1856                        var src = curr_script.getAttribute('data-src');
1857
1858                        // some scripts (like ga) might throw warning if data-src is present
1859                        src && curr_script.removeAttribute('data-src');
1860
1861                        // create fresh script (with the same code)
1862                        var fresh_script = _createNode('script');
1863                        fresh_script.textContent = curr_script.innerHTML;
1864
1865                        // Copy attributes over to the new "revived" script
1866                        (function (destination, source) {
1867                            var attributes = source.attributes;
1868                            var len = attributes.length;
1869                            for (var i = 0; i < len; i++) {
1870                                var attr_name = attributes[i].nodeName;
1871                                destination.setAttribute(attr_name, source[attr_name] || source.getAttribute(attr_name));
1872                            }
1873                        })(fresh_script, curr_script);
1874
1875                        // set src (if data-src found)
1876                        src ? (fresh_script.src = src) : (src = curr_script.src);
1877
1878                        // if script has "src" attribute
1879                        // try loading it sequentially
1880                        if (src) {
1881                            // load script sequentially => the next script will not be loaded
1882                            // until the current's script onload event triggers
1883                            if (fresh_script.readyState) {  // only required for IE <9
1884                                fresh_script.onreadystatechange = function () {
1885                                    if (fresh_script.readyState === "loaded" || fresh_script.readyState === "complete") {
1886                                        fresh_script.onreadystatechange = null;
1887                                        _loadScripts(scripts, ++index);
1888                                    }
1889                                };
1890                            } else {  // others
1891                                fresh_script.onload = function () {
1892                                    fresh_script.onload = null;
1893                                    _loadScripts(scripts, ++index);
1894                                };
1895                            }
1896                        }
1897
1898
1899                        // Replace current "sleeping" script with the new "revived" one
1900                        curr_script.parentNode.replaceChild(fresh_script, curr_script);
1901
1902                        /**
1903                         * If we managed to get here and scr is still set, it means that
1904                         * the script is loading/loaded sequentially so don't go any further
1905                         */
1906                        if (src) return;
1907                    }
1908
1909                    // Go to next script right away
1910                    _loadScripts(scripts, ++index);
1911                }
1912            }
1913
1914            _loadScripts(scripts, 0);
1915        }
1916
1917        /**
1918         * Save custom data inside cookie
1919         * @param {object|string} new_data
1920         * @param {string} [mode]
1921         * @returns {boolean}
1922         */
1923        var _setCookieData = function (new_data, mode) {
1924
1925            var set = false;
1926            /**
1927             * If mode is 'update':
1928             * add/update only the specified props.
1929             */
1930            if (mode === 'update') {
1931                cookie_data = _cookieconsent.get('data');
1932                var same_type = typeof cookie_data === typeof new_data;
1933
1934                if (same_type && typeof cookie_data === "object") {
1935                    !cookie_data && (cookie_data = {});
1936
1937                    for (var prop in new_data) {
1938                        if (cookie_data[prop] !== new_data[prop]) {
1939                            cookie_data[prop] = new_data[prop]
1940                            set = true;
1941                        }
1942                    }
1943                } else if ((same_type || !cookie_data) && cookie_data !== new_data) {
1944                    cookie_data = new_data;
1945                    set = true;
1946                }
1947            } else {
1948                cookie_data = new_data;
1949                set = true;
1950            }
1951
1952            if (set) {
1953                saved_cookie_content['data'] = cookie_data;
1954                _setCookie(_config.cookie_name, JSON.stringify(saved_cookie_content));
1955            }
1956
1957            return set;
1958        }
1959
1960        /**
1961         * Helper method to set a variety of fields
1962         * @param {string} field
1963         * @param {object} data
1964         * @returns {boolean}
1965         */
1966        _cookieconsent.set = function (field, data) {
1967            switch (field) {
1968                case 'data':
1969                    return _setCookieData(data['value'], data['mode']);
1970                default:
1971                    return false;
1972            }
1973        }
1974
1975        /**
1976         * Retrieve data from existing cookie
1977         * @param {string} field
1978         * @param {string} [cookie_name]
1979         * @returns {any}
1980         */
1981        _cookieconsent.get = function (field, cookie_name) {
1982            var cookie = JSON.parse(_getCookie(cookie_name || _config.cookie_name, 'one', true) || "{}");
1983
1984            return cookie[field];
1985        }
1986
1987        /**
1988         * Read current configuration value
1989         * @returns {any}
1990         */
1991        _cookieconsent.getConfig = function (field) {
1992            return _config[field] || user_config[field];
1993        }
1994
1995        /**
1996         * Obtain accepted and rejected categories
1997         * @returns {{accepted: string[], rejected: string[]}}
1998         */
1999        var _getCurrentCategoriesState = function () {
2000
2001            // get accepted categories
2002            accepted_categories = saved_cookie_content['categories'] || [];
2003
2004            // calculate rejected categories (all_categories - accepted_categories)
2005            rejected_categories = all_categories.filter(function (category) {
2006                return (_inArray(accepted_categories, category) === -1);
2007            });
2008
2009            return {
2010                accepted: accepted_categories,
2011                rejected: rejected_categories
2012            }
2013        }
2014
2015        /**
2016         * Calculate "accept type" given current categories state
2017         * @param {{accepted: string[], rejected: string[]}} currentCategoriesState
2018         * @returns {string}
2019         */
2020        var _getAcceptType = function (currentCategoriesState) {
2021
2022            var type = 'custom';
2023
2024            // number of categories marked as necessary/readonly
2025            var necessary_categories_length = readonly_categories.filter(function (readonly) {
2026                return readonly === true;
2027            }).length;
2028
2029            // calculate accept type based on accepted/rejected categories
2030            if (currentCategoriesState.accepted.length === all_categories.length)
2031                type = 'all';
2032            else if (currentCategoriesState.accepted.length === necessary_categories_length)
2033                type = 'necessary'
2034
2035            return type;
2036        }
2037
2038        /**
2039         * @typedef {object} userPreferences
2040         * @property {string} accept_type
2041         * @property {string[]} accepted_categories
2042         * @property {string[]} rejected_categories
2043         */
2044
2045        /**
2046         * Retrieve current user preferences (summary)
2047         * @returns {userPreferences}
2048         */
2049        _cookieconsent.getUserPreferences = function () {
2050            var currentCategoriesState = _getCurrentCategoriesState();
2051            var accept_type = _getAcceptType(currentCategoriesState);
2052
2053            return {
2054                'accept_type': accept_type,
2055                'accepted_categories': currentCategoriesState.accepted,
2056                'rejected_categories': currentCategoriesState.rejected
2057            }
2058        }
2059
2060        /**
2061         * Function which will run after script load
2062         * @callback scriptLoaded
2063         */
2064
2065        /**
2066         * Dynamically load script (append to head)
2067         * @param {string} src
2068         * @param {scriptLoaded} callback
2069         * @param {object[]} [attrs] Custom attributes
2070         */
2071        _cookieconsent.loadScript = function (src, callback, attrs) {
2072
2073            var function_defined = typeof callback === 'function';
2074
2075            // Load script only if not already loaded
2076            if (!document.querySelector('script[src="' + src + '"]')) {
2077
2078                var script = _createNode('script');
2079
2080                // if an array is provided => add custom attributes
2081                if (attrs && attrs.length > 0) {
2082                    for (var i = 0; i < attrs.length; ++i) {
2083                        attrs[i] && script.setAttribute(attrs[i]['name'], attrs[i]['value']);
2084                    }
2085                }
2086
2087                // if callback function defined => run callback onload
2088                if (function_defined) {
2089                    script.onload = callback;
2090                }
2091
2092                script.src = src;
2093
2094                /**
2095                 * Append script to head
2096                 */
2097                document.head.appendChild(script);
2098            } else {
2099                function_defined && callback();
2100            }
2101        }
2102
2103        /**
2104         * Manage dynamically loaded scripts: https://github.com/orestbida/cookieconsent/issues/101
2105         * If plugin has already run, call this method to enable
2106         * the newly added scripts based on currently selected preferences
2107         */
2108        _cookieconsent.updateScripts = function () {
2109            _manageExistingScripts();
2110        }
2111
2112        /**
2113         * Show cookie consent modal (with delay parameter)
2114         * @param {number} [delay]
2115         * @param {boolean} [create_modal] create modal if it doesn't exist
2116         */
2117        _cookieconsent.show = function (delay, create_modal) {
2118
2119            if (create_modal === true)
2120                _createConsentModal(_config.current_lang);
2121
2122            if (consent_modal_exists) {
2123                setTimeout(function () {
2124                    _addClass(html_dom, "show--consent");
2125
2126                    /**
2127                     * Update attributes/internal statuses
2128                     */
2129                    all_modals_container.querySelector("#cm").setAttribute('aria-hidden', 'false');
2130                    consent_modal_visible = true;
2131
2132                    setTimeout(function () {
2133                        last_elem_before_modal = document.activeElement;
2134                        current_modal_focusable = consent_modal_focusable;
2135                    }, 200);
2136
2137                    _log("CookieConsent [MODAL]: show consent_modal");
2138                }, delay > 0 ? delay : (create_modal ? 30 : 0));
2139            }
2140        }
2141
2142        /**
2143         * Hide consent modal
2144         */
2145        _cookieconsent.hide = function () {
2146            if (consent_modal_exists) {
2147                _removeClass(html_dom, "show--consent");
2148                all_modals_container.querySelector("#cm").setAttribute('aria-hidden', 'true');
2149                consent_modal_visible = false;
2150
2151                setTimeout(function () {
2152                    //restore focus to the last page element which had focus before modal opening
2153                    last_elem_before_modal.focus();
2154                    current_modal_focusable = null;
2155                }, 200);
2156
2157                _log("CookieConsent [MODAL]: hide");
2158            }
2159        }
2160
2161        /**
2162         * Hide settings modal
2163         */
2164        _cookieconsent.hideSettings = function () {
2165            _removeClass(html_dom, "show--settings");
2166            settings_modal_visible = false;
2167            all_modals_container.querySelector("#s-cnt").setAttribute('aria-hidden', 'true');
2168
2169
2170            setTimeout(function () {
2171                /**
2172                 * If consent modal is visible, focus him (instead of page document)
2173                 */
2174                if (consent_modal_visible) {
2175                    last_consent_modal_btn_focus && last_consent_modal_btn_focus.focus();
2176                    current_modal_focusable = consent_modal_focusable;
2177                } else {
2178                    /**
2179                     * Restore focus to last page element which had focus before modal opening
2180                     */
2181                    last_elem_before_modal && last_elem_before_modal.focus();
2182                    current_modal_focusable = null;
2183                }
2184
2185                clicked_inside_modal = false;
2186            }, 200);
2187
2188            _log("CookieConsent [SETTINGS]: hide settings_modal");
2189        }
2190
2191        /**
2192         * Accept cookieconsent function API
2193         * @param {string[]|string} _categories - Categories to accept
2194         * @param {string[]} [_exclusions] - Excluded categories [optional]
2195         */
2196        _cookieconsent.accept = function (_categories, _exclusions) {
2197            var categories = _categories || undefined;
2198            var exclusions = _exclusions || [];
2199            var to_accept = [];
2200
2201            /**
2202             * Get all accepted categories
2203             * @returns {string[]}
2204             */
2205            var _getCurrentPreferences = function () {
2206                var toggles = document.querySelectorAll('.c-tgl') || [];
2207                var states = [];
2208
2209                for (var i = 0; i < toggles.length; i++) {
2210                    if (toggles[i].checked) {
2211                        states.push(toggles[i].value);
2212                    }
2213                }
2214                return states;
2215            }
2216
2217            if (!categories) {
2218                to_accept = _getCurrentPreferences();
2219            } else {
2220                if (
2221                    typeof categories === "object" &&
2222                    typeof categories.length === "number"
2223                ) {
2224                    for (var i = 0; i < categories.length; i++) {
2225                        if (_inArray(all_categories, categories[i]) !== -1)
2226                            to_accept.push(categories[i]);
2227                    }
2228                } else if (typeof categories === "string") {
2229                    if (categories === 'all')
2230                        to_accept = all_categories.slice();
2231                    else {
2232                        if (_inArray(all_categories, categories) !== -1)
2233                            to_accept.push(categories);
2234                    }
2235                }
2236            }
2237
2238            // Remove excluded categories
2239            if (exclusions.length >= 1) {
2240                for (i = 0; i < exclusions.length; i++) {
2241                    to_accept = to_accept.filter(function (item) {
2242                        return item !== exclusions[i]
2243                    })
2244                }
2245            }
2246
2247            // Add back all the categories set as "readonly/required"
2248            for (i = 0; i < all_categories.length; i++) {
2249                if (
2250                    readonly_categories[i] === true &&
2251                    _inArray(to_accept, all_categories[i]) === -1
2252                ) {
2253                    to_accept.push(all_categories[i]);
2254                }
2255            }
2256
2257            _saveCookiePreferences(to_accept);
2258        }
2259
2260        /**
2261         * API function to easily erase cookies
2262         * @param {(string|string[])} _cookies
2263         * @param {string} [_path] - optional
2264         * @param {string} [_domain] - optional
2265         */
2266        _cookieconsent.eraseCookies = function (_cookies, _path, _domain) {
2267            var cookies = [];
2268            var domains = _domain
2269                ? [_domain, "." + _domain]
2270                : [_config.cookie_domain, "." + _config.cookie_domain];
2271
2272            if (typeof _cookies === "object" && _cookies.length > 0) {
2273                for (var i = 0; i < _cookies.length; i++) {
2274                    this.validCookie(_cookies[i]) && cookies.push(_cookies[i]);
2275                }
2276            } else {
2277                this.validCookie(_cookies) && cookies.push(_cookies);
2278            }
2279
2280            _eraseCookies(cookies, _path, domains);
2281        }
2282
2283        /**
2284         * Set cookie, by specifying name and value
2285         * @param {string} name
2286         * @param {string} value
2287         */
2288        var _setCookie = function (name, value) {
2289
2290            var cookie_expiration = _config.cookie_expiration;
2291
2292            if (typeof _config.cookie_necessary_only_expiration === 'number' && accept_type === 'necessary')
2293                cookie_expiration = _config.cookie_necessary_only_expiration;
2294
2295            value = _config.use_rfc_cookie ? encodeURIComponent(value) : value;
2296
2297            var date = new Date();
2298            date.setTime(date.getTime() + (1000 * (cookie_expiration * 24 * 60 * 60)));
2299            var expires = "; expires=" + date.toUTCString();
2300
2301            var cookieStr = name + "=" + (value || "") + expires + "; Path=" + _config.cookie_path + ";";
2302            cookieStr += " SameSite=" + _config.cookie_same_site + ";";
2303
2304            // assures cookie works with localhost (=> don't specify domain if on localhost)
2305            if (window.location.hostname.indexOf(".") > -1) {
2306                cookieStr += " Domain=" + _config.cookie_domain + ";";
2307            }
2308
2309            if (window.location.protocol === "https:") {
2310                cookieStr += " Secure;";
2311            }
2312
2313            document.cookie = cookieStr;
2314            _log("CookieConsent [SET_COOKIE]: '" + name + "' expires after " + cookie_expiration + " day(s)");
2315        }
2316
2317        /**
2318         * Get cookie value by name,
2319         * returns the cookie value if found (or an array
2320         * of cookies if filter provided), otherwise empty string: ""
2321         * @param {string} name
2322         * @param {string} filter 'one' or 'all'
2323         * @param {boolean} [get_value] set to true to obtain its value
2324         * @returns {string|string[]}
2325         */
2326        var _getCookie = function (name, filter, get_value) {
2327            var found;
2328
2329            if (filter === 'one') {
2330                found = document.cookie.match("(^|;)\\s*" + name + "\\s*=\\s*([^;]+)");
2331                found = found ? (get_value ? found.pop() : name) : "";
2332
2333                if (found && name === _config.cookie_name) {
2334                    try {
2335                        found = JSON.parse(found)
2336                    } catch (e) {
2337                        try {
2338                            found = JSON.parse(decodeURIComponent(found))
2339                        } catch (e) {
2340                            // if I got here => cookie value is not a valid json string
2341                            found = {};
2342                        }
2343                    }
2344                    found = JSON.stringify(found);
2345                } else {
2346                    //Undetected Cookies
2347                }
2348            } else if (filter === 'all') {
2349                // array of names of all existing cookies
2350                var cookies = document.cookie.split(/;\s*/);
2351                found = [];
2352                for (var i = 0; i < cookies.length; i++) {
2353                    found.push(cookies[i].split("=")[0]);
2354                }
2355            }
2356
2357            return found;
2358        }
2359
2360        /**
2361         * Delete cookie by name & path
2362         * @param {string[]} cookies
2363         * @param {string} [custom_path] - optional
2364         * @param {string[]} domains - example: ['domain.com', '.domain.com']
2365         */
2366        var _eraseCookies = function (cookies, custom_path, domains) {
2367            var path = custom_path ? custom_path : '/';
2368            var expires = 'Expires=Thu, 01 Jan 1970 00:00:01 GMT;';
2369
2370            for (var i = 0; i < cookies.length; i++) {
2371                for (var j = 0; j < domains.length; j++) {
2372                    var d = window.location.hostname.split(".");
2373                    while (d.length > 0) {
2374                        var cookieBase = encodeURIComponent(cookie
2374s[i].split(";")[0].split("=")[0]) + '=; expires=Thu, 01-Jan-1970 00:00:01 GMT; domain=' + d.join('.') + ' ;path=';
2375                        var p = location.pathname.split('/');
2376                        document.cookie = cookieBase + '/';
2377                        while (p.length > 0) {
2378                            document.cookie = cookieBase + p.join('/');
2379                            p.pop();
2380                        };
2381                        d.shift();
2382                    }
2383                    document.cookie = cookies[i] + '=; path=' + path + (domains[j].indexOf('.') == 0 ? '; domain=' + domains[j] : "") + '; ' + expires;
2384                }
2385                _log("CookieConsent [AUTOCLEAR]: deleting cookie: '" + cookies[i] + "' path: '" + path + "' domain:", domains);
2386            }
2387        }
2388
2389        /**
2390         * Returns true if cookie was found and has valid value (not empty string)
2391         * @param {string} cookie_name
2392         * @returns {boolean}
2393         */
2394        _cookieconsent.validCookie = function (cookie_name) {
2395            return _getCookie(cookie_name, 'one', true) !== "";
2396        }
2397
2398        /**
2399         * Function to run when event is fired
2400         * @callback eventFired
2401         */
2402
2403        /**
2404         * Add event listener to dom object (cross browser function)
2405         * @param {Element} elem
2406         * @param {string} event
2407         * @param {eventFired} fn
2408         * @param {boolean} [isPassive]
2409         */
2410        var _addEvent = function (elem, event, fn, isPassive) {
2411            elem.addEventListener(event, fn, isPassive === true ? {passive: true} : false);
2412        }
2413
2414        /**
2415         * Get all prop. keys defined inside object
2416         * @param {Object} obj
2417         */
2418        var _getKeys = function (obj) {
2419            if (typeof obj === "object") {
2420                return Object.keys(obj);
2421            }
2422        }
2423
2424        /**
2425         * Append class to the specified dom element
2426         * @param {HTMLElement} elem
2427         * @param {string} classname
2428         */
2429        var _addClass = function (elem, classname) {
2430            if(typeof elem !== "undefined"){
2431                elem.classList.add(classname);
2432            }
2433        }
2434
2435        /**
2436         * Remove specified class from dom element
2437         * @param {HTMLElement} elem
2438         * @param {string} classname
2439         */
2440        var _removeClass = function (el, className) {
2441            el.classList.remove(className);
2442        }
2443
2444        /**
2445         * Check if html element has class
2446         * @param {HTMLElement} el
2447         * @param {string} className
2448         */
2449        var _hasClass = function (el, className) {
2450            return el.classList.contains(className);
2451        }
2452
2453
2454        /**
2455         * Replace all link placeholders in the cookiemanager temp html
2456         * @param token
2457         * @param link
2458         */
2459        function _replaceLink(token, link) {
2460            for (const element of all_modals_container.querySelectorAll("#s-cnt *, #cm *")) {
2461                if (element.textContent.includes(token)) {
2462                    element.innerHTML = element.innerHTML.replace(token, link);
2463                }
2464            }
2465        }
2466
2467
2468        return _cookieconsent;
2469    };
2470
2471    var init = 'initCookieConsent';
2472    /**
2473     * Make CookieConsent object accessible globally
2474     */
2475    if (typeof window !== 'undefined' && typeof window[init] !== 'function') {
2476        window[init] = CookieConsent
2477    }
2478})();

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.