PageSourceSearch

https://www.ndww-freiberg.de/typo3temp/assets/compressed/fnn-cooki…736ce64965194a3e9ccd182db1c68.js?1719146951

js ndww-freiberg.de collected 2026-10-06 19:07:07 UTC 28,158 bytes, 649 lines download raw bytes

1/*****************************************************
2 *
3 *  FnnCookieManager prototype system
4 *
5 ******************************************************/
6var proto_methods = {
7    find: function(selector) {
8        const node = this.node;
9        return node.querySelectorAll(selector);
10    },
11
12    /***************************************************
13     * create a cookie (lifetime in days)
14     ***************************************************/
15    setCookie: function(cookieName, cookieValue, lifetime) {
16        const d = new Date();
17        d.setTime(d.getTime() + (lifetime*24*60*60*1000));
18        const expires = "expires="+ d.toUTCString();
19        document.cookie = cookieName + "=" + cookieValue + ";" + expires + ";path=/";
20    },
21
22    /***************************************************
23     * get a cookie value
24     ***************************************************/
25    getCookie: function(cookieName) {
26        const name = cookieName + "=";
27        const decodedCookie = decodeURIComponent(document.cookie);
28        const ca = decodedCookie.split(';');
29        for(let i = 0; i <ca.length; i++) {
30            let c = ca[i];
31            while (c.charAt(0) == ' ') {
32                c = c.substring(1);
33            }
34            if (c.indexOf(name) == 0) {
35                return c.substring(name.length, c.length);
36            }
37        }
38        return "";
39    },
40
41    /***************************************************
42     * check if the cookie has value
43     ***************************************************/
44    checkCookie: function(cookieName) {
45        return fnncm().getCookie(cookieName) == '' ? false : true;
46    },
47
48    /***************************************************
49     * remove cookie
50     ***************************************************/
51    removeCookie: function(cookieName,cookieDomain) {
52        document.cookie = cookieName + '=; expires=Thu, 01 Jan 1970 00:00:01 GMT;domain='+cookieDomain;
53    },
54
55    /***************************************************
56     * Shows the cookie bar
57     ***************************************************/
58    showCookiebar: function() {
59        document.querySelector('body').classList.add('fnn-cookiemanager-deactivate');
60        document.querySelector('.fnn-cookiemanager').setAttribute('style', 'display:block;opacity:1;');
61        if (document.querySelector('.fnn-cookiemanager').classList.contains('layout-middle-overlay')) {
62            fnncm().showCookieManager();
63        } else {
64            document.querySelector('.fnn-cookiemanager .cm-cookiebar').setAttribute('style', 'display:block;');
65        }
66    },
67
68    /***************************************************
69     * Shows the cookie manager
70     ***************************************************/
71    showCookieManager: function() {
72        // Deactivate cookiebar
73        document.querySelector('.fnn-cookiemanager .cm-cookiebar').setAttribute('style', 'display:none;');
74        document.querySelector('.fnn-cookiemanager .cm-cookiebar').setAttribute('aria-modal', 'false');
75
76
77        // remove existing code elements
78        fnncm().removeCode();
79
80        // set selected buttons
81        const cookieConsentData = fnncm().getCookie('fnncmCookieConsent');
82        if (cookieConsentData !== '') {
83            const cookieConsent = JSON.parse(cookieConsentData);
84            let servicesGroupId;
85            for (servicesGroupId in cookieConsent) {
86                if (document.querySelector('[data-group-id="'+servicesGroupId+'"]') != null) {
87                    if (cookieConsent[servicesGroupId] === 'yes') {
88                        document.querySelector('[data-group-id="'+servicesGroupId+'"] [data-value="no"]').setAttribute('data-selected','no');
89                        document.querySelector('[data-group-id="'+servicesGroupId+'"] [data-value="yes"]').setAttribute('data-selected','yes');
90                    } else {
91                        document.querySelector('[data-group-id="'+servicesGroupId+'"] [data-value="no"]').setAttribute('data-selected','yes');
92                        document.querySelector('[data-group-id="'+servicesGroupId+'"] [data-value="yes"]').setAttribute('data-selected','no');
93                    }
94                }
95            }
96        }
97
98        // scroll to top and show cookie manager form
99        window.scrollTo(0, 0);
100        document.querySelector('body').classList.add('fnn-cookiemanager-deactivate');
101        document.querySelector('.fnn-cookiemanager').setAttribute('style', 'display:block;opacity:1;');
102        document.querySelector('.fnn-cookiemanager .cm-modal').setAttribute('style', 'display:block;');
103        document.querySelector('.fnn-cookiemanager .cm-modal .cm-modal-description a').focus();
104        document.body.parentNode.style.overflow = 'hidden';
105    },
106
107    /***************************************************
108     * hide cookie bar and cookie manager
109     ***************************************************/
110    hide: function() {
111        document.body.parentNode.style.overflow = 'initial';
112        document.querySelector('.fnn-cookiemanager .cm-cookiebar').setAttribute('style', 'display:none;');
113        document.querySelector('.fnn-cookiemanager .cm-modal').setAttribute('style', 'display:none;');
114        document.querySelector('.fnn-cookiemanager').setAttribute('style', 'display:none;');
115        document.querySelector('body').classList.remove('fnn-cookiemanager-deactivate');
116    },
117
118    /***************************************************
119     * hide cookie manager only
120     ***************************************************/
121    hideCookieManager: function() {
122        document.querySelector('.fnn-cookiemanager .cm-modal').setAttribute('style', 'display:none;');
123        if (fnncm().checkCookie('fnncmCookieConsent')) {
124            document.querySelector('.fnn-cookiemanager').setAttribute('style', 'display:none;');
125            document.querySelector('body').classList.remove('fnn-cookiemanager-deactivate');
126        }
127    },
128
129    /***************************************************
130     * prepend html into element
131     ***************************************************/
132    prepend: function(html,tag) {
133        const node = this.node;
134        const s = document.createElement(tag);
135        s.async = true;
136        s.setAttribute('data-cm-code','fnncm');
137        s.innerHTML = html;
138        node.insertBefore(s, node.firstChild);
139    },
140
141    /***************************************************
142     * append html into element
143     ***************************************************/
144    append: function(html,tag) {
145        const node = this.node;
146        const s = document.createElement(tag);
147        s.async = true;
148        s.setAttribute('data-cm-code','fnncm');
149        s.innerHTML = html;
150        node.appendChild(s);
151    },
152
153    /***************************************************
154     * get js from url and execute callback
155     ***************************************************/
156    getScript: function(source, callback) {
157        const node = this.node;
158        let s = document.createElement('script');
159        s.async = true;
160        s.onload = s.onreadystatechange = function( _, isAbort ) {
161            if(isAbort || !s.readyState || /loaded|complete/.test(s.readyState) ) {
162                s.onload = s.onreadystatechange = null;
163                s = undefined;
164
165                if(!isAbort && callback) setTimeout(callback, 0);
166            }
167        };
168        s.src = source;
169        node.insertBefore(s, node.firstChild);
170    },
171
172    /***************************************************
173     * remove all code blocks
174     ***************************************************/
175    removeCode: function() {
176        const codeElements = document.querySelectorAll('[data-cm-code="fnncm"]');
177        codeElements.forEach(function(currentElement, currentIndex, listObj) {
178            currentElement.remove();
179        });
180    },
181
182    /***************************************************
183     * remove all service cookies
184     ***************************************************/
185    removeCookiesByServiceId: function(id) {
186        // remove cookies
187        const service = fnncm().getServiceData(null,id);
188        if (service === null) { return; }
189
190        service.cookies.forEach(function (cookie) {
191            fnncm().removeCookie(cookie.title,cookie.domain);
192        });
193    },
194
195    /***************************************************
196     * check for new services
197     ***************************************************/
198    checkForNewServices: function() {
199        const cookieConsent = JSON.parse(fnncm().getCookie('fnncmCookieConsent'));
200        for (let id in cmJsonData) {
201            const services = cmJsonData[id].services;
202
203            for (let s = 0; s < services.length; s++) {
204                if(cookieConsent[services[s].uid] === undefined) {
205                    return false;
206                }
207            }
208        }
209        return true;
210    },
211
212    //<editor-fold desc="Init elements functions">
213    /***************************************************
214     * initialize all tabs
215     ***************************************************/
216    initTabs: function() {
217        const node = this.node;
218        // find all tabs
219        const elements = node.querySelectorAll('.cm-tab-item input');
220
221        if (elements != null) {
222            // set height of tab content to 0 and register click events
223            elements.forEach(function(currentElement, currentIndex, listObj) {
224                // register expand click events
225                currentElement.addEventListener("click", function(clickEvent) {
226                    const target = clickEvent.target || clickEvent.srcElement;
227                    const tabContentId = target.getAttribute('data-cm-tab-content');
228
229                    if (tabContentId !== null) {
230                        node.querySelectorAll('.cm-tab-content [data-tab-content]').forEach(function(tabItemContent) {
231                            tabItemContent.setAttribute('style', 'display:none;');
232                        });
233
234                        node.querySelector('.cm-tab-content [data-tab-content="'+tabContentId+'"]').setAttribute('style', 'display:block');
235                    }
236                }, false);
237
238                // set all secondary tab content height to 0
239                const tabContentId = currentElement.getAttribute('data-cm-tab-content');
240                if (tabContentId !== '1') {
241                    node.querySelector('.cm-tab-content [data-tab-content="'+ tabContentId +'"]').setAttribute('style', 'display:none;');
242                }
243            });
244        }
245        return 'ok';
246    },
247
248    /***************************************************
249     * initialize all expandable containers
250     ***************************************************/
251    initExpandables: function() {
252        const node = this.node;
253        // find all expandable elements
254        const elements = node.querySelectorAll('[data-expandable]');
255
256        if (elements != null) {
257            // set height of expandable elements to 0 and register click events
258            elements.forEach(function(currentElement, currentIndex, listObj) {
259                // register expand click events
260                currentElement.addEventListener("click", function(clickEvent){
261                    const target = clickEvent.target || clickEvent.srcElement;
262                    const expandableNodeName = target.getAttribute('data-expandable');
263                    const expandableNode = target.parentNode.querySelector(expandableNodeName);
264                    if (expandableNode.getAttribute('data-state') == 'minimized') {
265                        target.classList.add('open');
266                        expandableNode.setAttribute('style', 'he
266ight:unset;display:bock;');
267                        expandableNode.setAttribute('data-state', 'expanded');
268                    } else {
269                        target.classList.remove('open');
270                        expandableNode.setAttribute('style', 'height:0;display:none;');
271                        expandableNode.setAttribute('data-state', 'minimized');
272                    }
273                }, false);
274
275                const expandableNodeName = currentElement.getAttribute('data-expandable');
276                const expandableNode = currentElement.parentNode.querySelector(expandableNodeName);
277                expandableNode.setAttribute('style', 'height:0;display:none;');
278                expandableNode.setAttribute('data-state', 'minimized');
279            });
280        }
281        return 'ok';
282    },
283
284    /***************************************************
285     * initialize all tri-state toggles
286     ***************************************************/
287    initTrieStateToggles: function() {
288        const node = this.node;
289
290        // find all toggle buttons
291        const toggleButtons = node.querySelectorAll('.cm-tri-state-toggle:not([disabled])');
292
293        if (toggleButtons != null) {
294
295            let cookieConsent;
296            // check cookie consent
297            if (fnncm().checkCookie('fnncmCookieConsent') && fnncm().checkForNewServices()) {
298                cookieConsent = JSON.parse(fnncm().getCookie('fnncmCookieConsent'));
299            }
300
301            // register click event for tri-state toggles
302            toggleButtons.forEach(function(currentElement, currentIndex, listObj) {
303                // set state by cookieconsent
304                if (cookieConsent !== undefined && currentElement.getAttribute('data-parent-id') !== '0') {
305                    if (cookieConsent[currentElement.getAttribute('data-service-id')] === 1) {
306                        currentElement.checked = true;
307                        fnncm().toggleParentSwitch(currentElement.getAttribute('data-parent-id'));
308                    }
309                }
310
311
312                // register change event
313                currentElement.addEventListener("change", function(clickEvent) {
314                    const target = clickEvent.target || clickEvent.srcElement;
315                    target.setAttribute('data-has-changed', '1');
316
317                    // Set parent state
318                    let parentId = target.getAttribute('data-parent-id');
319                    fnncm().toggleParentSwitch(parentId);
320
321                    // Set child states
322                    parentId = target.getAttribute('data-service-id');
323                    document.querySelectorAll('[data-parent-id="' + parentId + '"]').forEach(function(groupedCheckBox) {
324                        if (target.checked) {
325                            groupedCheckBox.checked = true;
326                        } else {
327                            groupedCheckBox.checked = false;
328                        }
329                    });
330
331                }, false);
332            });
333        }
334    },
335    //</editor-fold>
336
337
338    /*****************************************************************
339     * Sets switch to the state he should have based on his children.
340     ****************************************************************/
341    toggleParentSwitch: function(parentId) {
342        if (parentId !== '0') {
343            // Count of selected checkboxes in same group
344            const selectedGroupedCheckboxes = document.querySelectorAll('[data-parent-id="' + parentId + '"]:checked').length;
345
346            // Total count of checkboxes in same group
347            const groupedCheckboxes = document.querySelectorAll('[data-parent-id="' + parentId + '"]').length;
348
349            // Parent toggle of grouped checkboxes
350            const parentToggle = document.getElementById('cm-tri-state-0-' + parentId);
351
352            if (selectedGroupedCheckboxes === 0) {
353                parentToggle.checked = false;
354                parentToggle.indeterminate = false;
355            } else if (selectedGroupedCheckboxes === groupedCheckboxes) {
356                parentToggle.checked = true;
357                parentToggle.indeterminate = false;
358            } else {
359                parentToggle.checked = true;
360                parentToggle.indeterminate = true;
361            }
362        }
363    },
364
365
366    /***************************************************
367     * Executes the service with the passed Uid
368     ***************************************************/
369    acceptService: function(serviceId) {
370        // check cookie consent
371        if (fnncm().checkCookie('fnncmCookieConsent')) {
372            const consentLifetime = document.querySelector('[data-cookie-consent-lifetime]').getAttribute('data-cookie-consent-lifetime');
373            let cookieConsent = JSON.parse(fnncm().getCookie('fnncmCookieConsent'));
374
375            // Set service as accepted
376            cookieConsent[serviceId] = 1;
377
378            // Parse cookie consent object to JSON and store in the consent cookie
379            fnncm('head').setCookie('fnncmCookieConsent', JSON.stringify(cookieConsent), consentLifetime);
380        }
381
382        // Find service data
383        const service = fnncm().getServiceData(null, serviceId);
384        if (service === null) { return; }
385
386        // Insert script blocks and replace placeholders
387        fnncm().insertCodeByService(service);
388    },
389
390    /***************************************************
391     * insert code blocks into the dom for a single service
392     ***************************************************/
393    insertCodeByService: function(service) {
394        // Log runtime
395        let insertStart;
396        fnncmRuntime['service_' + service.uid] = {};
397
398        // If it is a standalone service that does not depend on external services, its code sections are included in the dom.
399        if (!service.dataExternal) {
400            // For the external content, the placeholders and script blocks must also be converted back.
401            if (service.externalContent && service.elementIdentifier !== '') {
402                // Remove placeholders
403                fnncm('body').find('[data-cm-content-consent-type-id="' + service.uid + '"]').forEach(function (placeholderNode) {
404                    placeholderNode.remove();
405                });
406
407                // Reset elements
408                fnncm('body').find('[cm-element-identifier="' + service.elementIdentifier.replace(/`/g,"'") + '"]').forEach(function (elementScriptNode) {
409                    elementScriptNode.parentElement.innerHTML = elementScriptNode.innerText;
410                });
411                fnncm('body').find('[cm-script-identifier="' + service.scriptIdentifier.replace(/`/g,"'") + '"]').forEach(function (elementScriptNode) {
412                    fnncm('head').append(elementScriptNode.innerText);
413                });
414            }
415
416            // Include the standard code blocks
417            if(service.dataHead !== '') {
418                insertStart = Date.now();
419                fnncm('head').append(service.dataHead.replace(/`/g,"'"),'script');
420                fnncmRuntime['service_' + service.uid]['head'] = (Date.now() - insertStart) + 'ms';
421            }
422            if(service.dataBodyBegin !== '') {
423                insertStart = Date.now();
424                fnncm('body').prepend(service.dataBodyBegin.replace(/`/g,"'"),'script');
425                fnncmRuntime['service_' + service.uid]['bodyBegin'] = (Date.now() - insertStart) + 'ms';
426            }
427            if(service.dataBodyEnd !== '') {
428                insertStart = Date.now();
429                fnncm('body').append(service.dataBodyEnd.replace(/`/g,"'"),'script');
430                fnncmRuntime['service_' + service.uid]['bodyEnd'] = (Date.now() - insertStart) + 'ms';
431            }
432            if(service.noscript !== '') {
433                insertStart = Date.now();
434                fnncm('body').append(service.noscript,'noscript');
435                fnncmRuntime['service_' + service.uid]['noscript'] = (Date.now() - insertStart) + 'ms';
436            }
437
438        } else {
439
440        }
441    },
442
443    /***************************************************
444     * insert code blocks into the dom for all accept services
445     ***************************************************/
446    insertCode: function() {
447        // Get cookie consent from cookie
448        const cookieConsent = JSON.parse(fnncm().getCookie('fnncmCookieConsent'));
449
450        const serviceStart = Date.now();
451
452        let serviceId;
453        for (serviceId in cookieConsent) {
454            // Gets service data from JSON object
455            const service = fnncm().getServiceData(null, serviceId);
456
457            // If there is no data for the service, further processing for this service is aborted.
458            if (service === null) { continue; }
459
460            // If the service was not accepted, further processing for this service will be cancelled.
461            if (cookieConsent[serviceId] !== 1) {
462                // Show placeholders from service
463                if (service.externalContent) {
464                    fnncm('body').find('[data-cm-content-consent-type-id="' + service.uid + '"]').forEach(function (placeholderNode) {
465                        placeholderNode.style.display = 'block';
466                    });
467                }
468
469                continue;
470            }
471
472            // Insert code by service
473            fnncm().insertCodeByService(service);
474
475            fnncmRuntime['service_' + serviceId]['complete'] = (Date.now() - serviceStart) + 'ms';
476        }
477    },
478
479    /***************************************************
480     * gets service data from cmJsonData
481     ***************************************************/
482    getServiceData: function(serviceGroupUid, serviceUid) {
483        if (serviceGroupUid !== null) {
484            const services = cmJsonData[serviceGroupUid].services;
485
486            for (let i = 0; i < services.length; i++) {
487                if (services[i].uid === parseInt(serviceUid)) {
488                    return services[i];
489                }
490            }
491
492            console.warn('CookieManage - Data for service ' + serviceUid + ' not found! (1627374292)');
493            return null;
494        } else {
495            // Gets the object keys
496            const serviceGroupsKeys = Object.keys(cmJsonData);
497
498            // Goes through the service groups
499            for (let sg = 0; sg < serviceGroupsKeys.length; sg++) {
500                //Goes through the services
501                for (let s = 0; s < cmJsonData[serviceGroupsKeys[sg]].services.length; s++) {
502                    if (cmJsonData[serviceGroupsKeys[sg]].services[s].uid === parseInt(serviceUid)) {
503                        return cmJsonData[serviceGroupsKeys[sg]].services[s];
504                    }
505                }
506            }
507
508            console.warn('CookieManage - Data for service ' + serviceUid + ' not found! (1627374340)');
509            return null;
510        }
511    },
512
513    /***************************************************
514     * save cookie settings in cookie consent
515     ***************************************************/
516    saveCookieSettings: function() {
517        // Get cookie consent lifetime
518        const consentLifetime = document.querySelector('[data-cookie-consent-lifetime]').getAttribute('data-cookie-consent-lifetime');
519
520        let cookieConsent = {};
521        let reload = false;
522        let disabledGroups = [];
523
524        // Find all service switches
525        const switches = fnncm('.cm-modal').find('.cm-service input[type="checkbox"].cm-tri-state-toggle');
526
527        switches.forEach(function(service) {
528            // Set value to cookie consent object, this object is parsed to a JSON object and stored in the cookie.
529            cookieConsent[service.getAttribute('data-service-id')] = service.checked ? 1 : 0;
530
531            // If the status has changed and the service has been deactivated, the service will be remembered and a page reload will be scheduled
532            if (service.getAttribute('data-has-changed') === '1' && !service.checked) {
533                reload = true;
534                disabledGroups.push(service.getAttribute('data-service-id'));
535            }
536
537            // For external services (like GoogleTagManager) the specified code is inserted here
538            if (service.dataExternal && service.dataAfterApproval !== '') {
539                // The "setTimeout" should ensure that all dependencies are loaded and the code is executed only then.
540                setTimeout(function() {
541                    fnncm('body').append(service.dataAfterApproval.replace(/`/g,"'"),'script');
542                }, 200);
543            }
544        });
545
546        // Parse cookie consent object to JSON and store in the consent cookie
547        fnncm().setCookie('fnncmCookieConsent', JSON.stringify(cookieConsent), consentLifetime);
548
549        if (reload) {
550            fnncm().removeCode();
551            // Unnecessary or deselected cookies of the own domain are removed.
552            disabledGroups.forEach(function (groupId) {
553                fnncm().removeCookiesByServiceId(groupId);
554            });
555
556            // If a page reload is needed this is initialized here
557            location.reload();
558        } else {
559            fnncm().hide();
560            // Inserts all necessary code blocks and replaces the placeholders of the external content
561            fnncm().insertCode();
562        }
563    },
564
565    /***************************************************
566     * set all service groups to "yes" and save settings
567     ***************************************************/
568    acceptAll: function() {
569        const switches = fnncm('.cm-modal').find('input[type="checkbox"].cm-tri-state-toggle');
570        switches.forEach(function(currentElement, currentIndex, listObj) {
571            currentElement.checked = true;
572        });
573        fnncm().saveCookieSettings();
574    },
575
576    /***************************************************
577     * set all service groups to "no" and save settings
578     ***************************************************/
579    rejectAll: function() {
580        const switches = fnncm('.cm-modal').find('input[type="checkbox"].cm-tri-state-toggle:not([disabled])');
581        switches.forEach(function(currentElement, currentIndex, listObj) {
582            currentElement.checked = false;
583        });
584        fnncm().saveCookieSettings();
585    },
586
587    /***************************************************
588     * init fnn cookie manager
589     ***************************************************/
590    init: function() {
591        fnncm('.cm-settings-popup').initTabs();
592        fnncm('.cm-tab-content').initExpandables();
593        fnncm('.cm-tab-content').initTrieStateToggles();
594
595        // register click event for save button
596        document.querySelector('.cm-btn-save').addEventListener("click", function(clickEvent){
597            const target = clickEvent.target || clickEvent.srcElement;
598            if (target.getAttribute('data-ready') === 'yes') {
599                fnncm().saveCookieSettings();
600                return;
601            }
602        }, false);
603
604        // check cookie consent
605        if (fnncm().checkCookie('fnncmCookieConsent') && fnncm().checkForNewServices()) {
606            // cookie consent is set
607            fnncm().hide();
608            fnncm().insertCode();
609        } else {
610            // cookie consent not set
611            fnncm().showCookiebar();
612        }
613    }
614}, fnncm, _fnncm;
615
616_fnncm = function(selector) { this.node = document.querySelector(selector); };
617_fnncm.prototype = proto_methods;
618
619fnncm = function(selector) {
620    return new _fnncm(selector);
621};
622
623let fnncmRuntime = {};
624
625
626/*****************************************************
627 *
628 *  FnnCookieManager init
629 *
630 ******************************************************/
631document.addEventListener('DOMContentLoaded', function(event) {
632
633    // polyfill-ie11-nodelist-foreach
634    if ('NodeList' in window && !NodeList.prototype.forEach) {
635        NodeList.prototype.forEach = function (callback, thisArg) {
636            thisArg = thisArg || window;
637            for (var i = 0; i < this.length; i++) {
638                callback.call(thisArg, this[i], i, this);
639            }
640        };
641    }
642
643    const fnncmOpeners = document.getElementsByClassName('fnn-cookiemanager-open');
644    for (let i = 0; i < fnncmOpeners.length; i++) {
645        fnncmOpeners[i].addEventListener('click', function() { fnncm().showCookieManager(); }, false);
646    }
647
648    fnncm().init();
649});

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.