PageSourceSearch

https://www.sanitaetshaus-rosenhaeger.de/js/_essentials/privacyControl-2.js

js sanitaetshaus-rosenhaeger.de collected 2026-10-04 03:09:58 UTC 23,519 bytes, 696 lines download raw bytes

1/** 
2* @author Dominik Kressler
3* @version 2.4.0
4* @date 2021-11-12
5* @description control scripts and iframes that cause in gdpr related problems
6* @dependencies [email protected], [email protected]
7**/
8
9function PrivacyControl(args)
10{
11    _this = this
12
13    if(window.pCinit !== undefined) 
14    {
15        alert("*** PricacyControl Error! ***\n\nPlease don't call PrivacyControl twice!\nPrivacyControl bitte nicht doppelt aufrufen!")
16        return false
17    }
18    else window.pCinit = true
19
20    /**
21     * internal helper to merge the given deps object to the defaults
22     * the function removes deps from obj1 which are set to false in obj2  
23     */
24    var mergeDeps = function(obj1, obj2) {
25        for (var dependency in obj2) {
26            if(obj2[dependency] === false) delete obj1[dependency]
27        }
28        return obj1
29    }
30
31    var params = 
32    {
33        deps:false,
34        sessionName: 'privacy-ctrl',
35        force: false,
36        badge: true,
37        placeholder: '/privacyControl-2.0.placeholder.html',
38        legal_page: {
39            de: '/impressum.php',
40            en: '/legal-notice.php'
41        },
42        privacy_page: {
43            de: '/datenschutzerklaerung.php',
44            en: '/privacy-policy.php'
45        },
46        storage: localStorage
47    },
48    loaded = []
49    _this.options = {},
50    _this.options = J.merge(params, args),
51    _this.frames = []
52    _this.storage = params.storage || localStorage
53    _this.options.deps = mergeDeps(_this.options.deps, args.deps)
54
55    if(_this.options.deps === false) return _this
56
57    var docLang = document.documentElement.lang.split('_')[0].toLowerCase()
58    docLang = document.documentElement.lang.split('-')[0].toLowerCase()
59
60    _this.lang = (_this.options.lang === undefined) ? docLang : _this.options.lang
61    if(pCl10n[_this.lang] === undefined) _this.lang = 'en'
62
63    var init = function()
64    {
65        if(_this.options.badge) addBadge()
66        normalizeServices()
67        createMarkup()
68        _this.apply()
69        iframePlaceholder()
70        bindEvents()
71        
72        if(_this.options.force === false || interacted() === true) _this.container.parentElement.parentElement.classList.add('hide')
73
74        return _this
75    };
76
77    var normalizeServices = function()
78    {
79        for(var key in _this.options.deps)
80        {
81            if (typeof _this.options.deps[key] == 'boolean' && pCServiceTemplates[key] !== undefined) 
82            {
83                _this.options.deps[key] = pCServiceTemplates[key]
84            }
85            else if (typeof _this.options.deps[key] == 'object' && pCServiceTemplates[key] !== undefined)
86            {
87                _this.options.deps[key] = J.merge(pCServiceTemplates[key], _this.options.deps[key])
88            }
89        }
90
91        return _this;
92    }
93
94    var getText = function(key, service)
95    {
96        var string = ''
97        try {
98            if(service !== undefined && _this.options.deps[service].l10n[_this.lang][key] !== undefined)
99            {
100                string = _this.options.deps[service].l10n[_this.lang][key]
101            }
102            else if(typeof _this.options[key] === 'object' && _this.options[key][_this.lang] !== undefined)
103            {
104                string = _this.options[key][_this.lang]
105            }
106            else if (pCl10n[_this.lang][key] !== undefined)
107            {
108                string = pCl10n[_this.lang][key]
109            }
110        } catch (error) {
111            console.log('Translation string missing for: '+key);
112        }
113        
114        return string;
115    };
116
117    var createMarkup = function()
118    {
119        _this.container = customTag('privacy-controller')
120        _this.container.id = 'privacy-controller'
121
122        var pheader = customTag('privacy-header', _this.container)
123        pheader.id = 'privacy-header'
124        var ptext = customTag('privacy-text', pheader)
125        ptext.innerHTML = getText('intro')
126
127        var btns = customTag('privacy-buttons', pheader)
128
129        var btn1 = customTag('privacy-btn', btns)
130        btn1.id = 'privacy-open'
131        btn1.setAttribute('href', '#privacy-controller')
132        btn1.innerHTML = getText('settings')
133        
134        var btn2 = customTag('privacy-btn', btns)
135        btn2.id = 'privacy-confirm'
136        btn2.setAttribute('href', '#privacy-confirm')
137        btn2.innerHTML = getText('confirm')
138
139        var fields = customTag('privacy-fields')
140        fields.id = 'privacy-fields'
141        var services = _this.options.deps
142        for (var key in services)
143        {
144            try {
145                var cb = document.createElement('input')
146                cb.type =  'checkbox'
147                cb.setAttribute('name', key)
148                var id = _this.options.sessionName+':'+key
149    
150                var row = customTag('privacy-row', fields)
151    
152                customCells(getText('accept'), '<label for="'+id+'"><input id="'+id+'" name="'+key+'" type="checkbox"><span data-on="'+getText('on')+'" data-off="'+getText('off')+'"></span></label>', row)
153    
154                if(typeof services[key].name !== 'undefined') customCells(getText('name'), services[key].name, row)
155                if(typeof services[key].provider !== 'undefined') customCells(getText('provider'), services[key].provider, row)
156                if(typeof services[key].l10n[_this.lang].description !== 'undefined') customCells(getText('purpose'), services[key].l10n[_this.lang].description, row)
157                if(typeof services[key].l10n[_this.lang].policy !== 'undefined') customCells(getText('policy'), '<a href="'+services[key].l10n[_this.lang].policy+'" target="_blank">Link</a>', row)
158            } catch (error) {
159                console.log('It is missing some properties for that service: '+key)
160            }
161        }
162
163        _this.container.appendChild(fields)
164
165        var footer = customTag('privacy-footer', _this.container)
166        var reset = customTag('privacy-link', footer)
167        reset.id = 'privacy-reset'
168        reset.classList.add('privacy-reset')
169        reset.innerHTML = getText('reset')
170
171        var legal_page = getText('legal_page')
172        if (legal_page && legal_page != '')
173        {
174            var imprint = customTag('privacy-link', footer)
175            imprint.setAttribute('href', legal_page)
176            imprint.innerHTML = getText('legal_notice')
177        }
178
179        var privacy_page = getText('privacy_page')
180        if(privacy_page && privacy_page != '')
181        {
182            var policy = customTag('privacy-link', footer)
183            policy.setAttribute('href', privacy_page)
184            policy.innerHTML = getText('policy')
185        }
186
187        notification.add({id: _this.options.sessionName, message: _this.container, saveState: !_this.options.force, remove: false})
188
189        _this.elms = {}
190        _this.elms.open = btn1
191        _this.elms.submit = btn2
192
193        return _this
194    }
195
196    var customCells = function(cell1, cell2, target)
197    {
198        var cells = []
199        cells[0] = customTag('privacy-cell', target)
200        cells[0].innerHTML = cell1
201        cells[1] = customTag('privacy-cell', target)
202        cells[1].innerHTML = cell2
203        return cells
204    }
205    var customTag = function(name, target)
206    {
207        var elm = document.createElement(name)
208        elm.classList.add(name)
209        if(target) target.appendChild(elm)
210        return elm
211    }
212
213    var open = function()
214    {
215        _this.container.classList.add('open')
216        _this.container.parentElement.parentElement.classList.remove('hide')
217        document.body.classList.add('privacy-control-is-open')
218        _this.elms.open.classList.add('hide')
219        return
220    }
221
222    var close = function()
223    {
224        _this.container.classList.remove('open');
225        document.body.classList.remove('privacy-control-is-open');
226        _this.elms.open.classList.remove('hide');
227        notification.close(_this.options.sessionName);
228        return;
229    }
230
231    var interacted = function()
232    {
233        let storage = getStorage();
234
235        for (let s in storage)
236        {
237            if (storage[s] === true) return true
238        }
239
240        return false
241    };
242
243    var activateButtons = function(key) 
244    {
245        let btns = document.querySelectorAll('[data-privacy-control
245="'+key+'"]')
246        btns.forEach(function (btn, i) {
247            btn.classList.add('granted', 'activated')
248            btn.dataset.privacyControlConsent = 'true'
249        })
250    }
251
252    var bindEvents = function()
253    {
254        document.addEventListener('click', function(e)
255        {
256            closeInfoBox(true)
257        })
258
259        var buttons = document.querySelectorAll('[data-privacy-control]')
260        for(var i=0; i < buttons.length; i++)
261        {
262            buttons[i].addEventListener('click', function(e)
263            {
264                e.preventDefault()
265
266                var key = this.dataset.privacyControl
267                
268                if(key == '')
269                {
270                    open()
271                }
272                else
273                {
274                    activateButtons(key)
275                    _this.set(key, true)
276                    _this.apply()
277                }
278            })
279        }
280
281        var extraHandler = document.querySelectorAll('[href="#privacy-controller"]')
282        for(var i=0; i < extraHandler.length; i++)
283        {
284            extraHandler[i].addEventListener('click', function(e)
285            {
286                e.preventDefault()
287                open()
288            })
289        }
290
291        var checks = _this.container.querySelectorAll('[type=checkbox]')
292        for(var i = 0; i < checks.length; i++)
293        {
294            checks[i].addEventListener('change', function(e)
295            {
296                if(this.checked) _this.set(this.name, true)
297                else _this.set(this.name, false)
298                
299                _this.apply()
300            })
301        }
302
303        _this.elms.submit.addEventListener('click', function(e)
304        {
305            e.preventDefault()
306
307            _this.set('all', true)
308            _this.apply()
309            close()
310        })
311
312        var resets = document.querySelectorAll('.privacy-reset')
313        for(var i = 0; i < resets.length; i++)
314        {
315            resets[i].addEventListener('click', function(e)
316            {                
317                _this.reset()
318            });
319        }
320
321        _this.container.parentElement.parentElement.querySelector('.close').addEventListener('click', close)
322
323        var links = document.querySelectorAll('.privacy-link')
324        for(var i = 0; i < links.length; i++)
325        {
326            links[i].addEventListener('click', function(e)
327            {                
328                var href = this.getAttribute('href')
329                if(href !== null) 
330                {
331                    var win = window.open(href, '_blank')
332                    win.focus()
333                }
334            })
335        }
336
337        return _this
338    }
339
340    var addBadge = function()
341    {
342        var badge = document.createElement('A')
343        badge.href = '#privacy-controller'
344        badge.classList.add('privacy-control-badge')
345        var span = document.createElement('SPAN')
346        span.innerText = getText('badge')
347        badge.appendChild(span)
348        document.body.appendChild(badge)
349        return badge
350    }
351
352    var iframePlaceholder = function()
353    {
354        var services = _this.options.deps
355
356        for(var key in services)
357        {
358            if(services[key].type == 'iframe')
359            {
360                var elms = document.querySelectorAll('iframe[data-pc-service='+key+']:not(.enabled), iframe[data-iframe='+key+']:not(.enabled)')
361
362                for(var i = 0; i < elms.length; i++)
363                {
364                    var frame = elms[i]
365                    frame.addEventListener('load', function()
366                    {
367                        try {
368                            if(this.classList.contains('enabled')) return false
369                            var frame = this
370                            key = frame.dataset.pcService || frame.dataset.iframe,
371                            doc = frame.contentDocument ? frame.contentDocument : frame.contentWindow.document;
372    
373                            _this.frames.push(frame)
374                            
375                            var policy = (services[key].l10n[_this.lang].policy) ? '<a href="'+services[key].l10n[_this.lang].policy+'" target="_blank">'+services[key].l10n[_this.lang].policy+'</a>' : ''
376                            doc.body.innerHTML = doc.body.innerHTML.replaceAll('{{policy}}', policy)
377                            doc.body.innerHTML = doc.body.innerHTML.replaceAll('{{name}}', services[key].name)
378                            doc.body.innerHTML = doc.body.innerHTML.replaceAll('{{activate}}', getText('activate'))
379                            doc.body.innerHTML = doc.body.innerHTML.replaceAll('{{msg}}', services[key].l10n[_this.lang].description)
380                            doc.body.innerHTML = doc.body.innerHTML.replaceAll('{{provider}}', getText('provider'))
381                            doc.body.innerHTML = doc.body.innerHTML.replaceAll('{{providerName}}', services[key].provider)
382                            doc.body.innerHTML = doc.body.innerHTML.replaceAll('{{key}}', key)
383                            doc.head.innerHTML = doc.head.innerHTML.replaceAll('{{key}}', key)
384                            doc.body.id = key
385                            doc.body.classList.add('enabled')
386        
387                            doc.querySelector('html').lang = _this.lang
388                            
389                            if(services[key].css) doc.head.innerHTML += '<link rel="stylesheet" href="'+services[key].css+'"></link>'
390                            bindInFrameEvent(doc)
391                        } catch (error) {
392                            console.log("Can't handle the placeholder. The service options are broken: "+key)
393                        }
394                    });
395                    frame.dataset.lang = document.querySelector('html').lang
396                    frame.src = _this.options.placeholder+'?key='+key
397                }
398            }
399        }
400    }
401
402    var bindInFrameEvent = function(doc)
403    {
404        var infoOpen = doc.querySelectorAll('.infoOpen')
405        for(var i = 0, c = infoOpen.length; i < c; i++)
406        {
407            infoOpen[i].addEventListener('click', function(e)
408            {
409                e.preventDefault()
410                
411                var frame = document.activeElement
412                var doc = frame.contentDocument ? frame.contentDocument : frame.contentWindow.document
413                
414                doc.querySelector('.infoBox').classList.add('open')
415                doc.querySelector('.infoOpen').classList.add('hide')
416            })
417        }
418
419        var infoClose = doc.querySelectorAll('.infoClose')
420        for(var i = 0, c = infoClose.length; i < c; i++)
421        {
422            infoClose[i].addEventListener('click', closeInfoBox)
423        }
424
425        doc.addEventListener('keydown', function(e)
426        {
427            if (e.keyCode == 27) closeInfoBox()
428            return
429        });
430
431        var btn = doc.querySelector('.accept')
432        btn.addEventListener('click', function(e)
433        {
434            e.preventDefault()
435            e.stopPropagation()
436            
437            var key = document.activeElement.dataset.iframe || document.activeElement.dataset.pcService
438
439            _this.set(key, true)
440            _this.apply()
441
442            return
443        }, false)
444    }
445
446    var closeInfoBox = function(all)
447    {
448        var frames = (all === null || all === false) ? [document.activeElement] : _this.frames
449
450        for(var i in frames)
451        {
452            try {
453                doc = frames[i].contentDocument ? frames[i].contentDocument : frames[i].contentWindow.document
454
455                doc.querySelector('.infoBox').classList.remove('open')
456                doc.querySelector('.infoOpen').classList.remove('hide')
457            } catch (error) {
458            }
459        }
460    }
461
462    var applyInterface = function()
463    {
464        for(var key in _this.options.deps)
465        {
466            var val = _this.options.deps[key]
467            var status = _this.get(key)
468
469            if(status === undefined) 
470            {
471                status = false
472                _this.set(key, status)
473            }
474            
475            var id = _this.options.sessionName+':'+key
476            var input = document.getElementById(id)
477            input.checked = status
478        }
479
480        return _this
481    }
482
483    var loadDep = function(key, type)
484    {
485        if(loaded[key] === true) return false;
486        switch(type)
487        {
488            case "script":
489
490                try
491                {
492                    if(_this.options.deps[key].src !== undefined)
493                    {
494                        var srcs = _this.options.deps[key].src;
495                        if(typeof srcs != 'object')
496                        {
497                            srcs = [srcs];
498                        }
499
500                        rIt({
501                            "*": {
502                                "assets": srcs,
503                                "function": _this.options.deps[key].callback
504                            }                            
505                        });
506                    }
507                    else
508                    {
509                        var scripts = document.querySelectorAll('script[data-script="'+key+'"], script[data-pc-service="'+key+'"]');
510                        for(var i = 0, l = scripts.length; i < l; i++)
511                        {
512                            if(i==l-1) scripts[i].addEventListener('load', _this.options.deps[key].callback);
513                            scripts[i].src = scripts[i].dataset.pcAsset;
514                        }
515                    }
516                    
517                } catch (error) {
518                    console.log('Could not load script for '+key+', no src defined.');
519                }
520
521            break;
522            case "iframe":
523
524                var iframes = document.querySelectorAll('[data-iframe="'+key+'"], iframe[data-pc-service="'+key+'"]');
525
526                for (var i in iframes)
527                {
528                    if(typeof iframes[i] == 'object' && iframes[i].dataset) 
529                    {
530                        var placeholder = iframes[i].pcAsset;
531                        var src = iframes[i].dataset.pcAsset || iframes[i].dataset.src;
532
533                        iframes[i].dataset.pcAsset = placeholder;
534                        iframes[i].src = src;
535                        iframes[i].classList.add('enabled', 'pc-loaded');
536                        iframes[i].classList.remove('pc-unloaded');
537                        iframes[i].dataset.frameId = (new Date()).getTime();
538                    }
539                }
540
541            break;
542            case "image":
543
544                let images = document.querySelectorAll('img[data-pc-service="'+key+'"]');
545                for(let img of images)
546                {
547                    let temp = img.src;
548                    img.src = img.dataset.pcAsset;
549                    img.dataset.pcAsset = temp;
550                    img.classList.add('pc-loaded');
551                    img.classList.remove('pc-unloaded');
552                }
553
554            break;
555        }
556
557        loaded[key] = true;
558
559        activateButtons(key);
560
561        return true;
562    };
563
564    var unloadDep = function(key, type)
565    {
566        if(loaded[key] === false) return false;
567        switch(type)
568        {
569            case "iframe":
570
571                var iframes = document.querySelectorAll('[data-iframe="'+key+'"], iframe[data-pc-service="'+key+'"]');
572                for (var i in iframes)
573                {
574                    if(typeof iframes[i] == 'object' && iframes[i].dataset) 
575                    {
576                        var placeholder = iframes[i].dataset.src;
577                        var src = iframes[i].src;
578
579                        iframes[i].classList.remove('enabled', 'pc-loaded');
580                        iframes[i].classList.add('pc-unloaded');
581                        iframes[i].dataset.pcAsset = src;
582                        iframes[i].src = placeholder;
583                        iframePlaceholder();
584                    }
585                }
586
587            break;
588            case "image":
589                let images = document.querySelectorAll('img[data-pc-service="'+key+'"]');
590                for(let img of images)
591                {
592                    let temp = img.src;
593                    img.src = img.dataset.pcAsset;
594                    img.dataset.pcAsset = temp;
595                    img.classList.remove('pc-loaded');
596                    img.classList.add('pc-unloaded');
597                }
598            break;
599        }
600
601        loaded[key] = false;
602
603        return true;        
604    };
605
606    var getStorage = function()
607    {
608        var storage = _this.storage.getItem(_this.options.sessionName);
609        storage = (storage === null || storage === '' || storage === false) ? {} : JSON.parse(storage);
610
611        return storage;
612    };
613
614    _this.apply = function()
615    {
616        var storage = _this.get('all');
617
618        for(var key in storage)
619        {
620            if(_this.options.deps[key] === undefined) continue;
621            var type = _this.options.deps[key].type;
622
623            if(_this.options.deps[key] === undefined || storage[key] === false)
624            {
625                if(key !== undefined && loaded[key] === true) unloadDep(key, type);
626            }
627            else
628            {
629                if(key !== undefined) loadDep(key, type);
630            }
631        }
632
633        applyInterface();
634        return _this;
635    };
636
637    _this.set = function(key, status)
638    {
639        var storage = getStorage();
640        if(key === 'all')
641        {
642            for(var i in storage)
643            {
644                _this.set(i, status);
645            }
646        }
647        else
648        {
649            storage[key] = status;
650            try {
651                _this.storage.setItem(_this.options.sessionName, JSON.stringify(storage));
652                if(!_this.options.deps[key]) throw new Error("Key "+key+" is missing in the PrivacyControl deps configuration object.");
653                if(_this.options.deps[key].forceReload !== undefined && _this.options.deps[key].forceReload === true && document.readyState === 'complete') window.location.reload();
654            } catch (error) {
655                console.error(error);
656            }
657        }
658
659        return storage;
660    };
661
662    _this.get = function(key)
663    {
664        var storage = getStorage();
665        if(key == 'all') return storage;
666        return storage[key];
667    };
668
669    _this.reset = function()
670    {
671        _this.storage.setItem(_this.options.sessionName, '{}');
672        _this.storage.removeItem('note-'+_this.options.sessionName);
673
674        location.reload(); 
675        return _this.get('all');
676    };
677
678    _this.please = function()
679    {
680        _this.set('all', true);
681        console.info("%c Hello my dear, I appreciate that you ask me to enable all services now and you're welcome. But keep in mind, you should not!", 'background: #222; color: #bada55');
682        _this.apply();
683
684        return "This is a shortcut for set('all', true) and apply()";
685    }
686
687    return init();
688}
689
690if(String.prototype.replaceAll === undefined)
691{
692    String.prototype.replaceAll = function(search, replacement) {
693        var target = this;
694        return target.replace(new RegExp(search, 'g'), replacement);
695    };
696}

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.