PageSourceSearch

https://v2.fi/js/cookiebanner.js

js v2.fi collected 2026-10-02 07:16:39 UTC 17,489 bytes, 484 lines download raw bytes

1/*global window:false, setTimeout:true, console:true */
2/*
3Copyright (C) 2013-2015 Good Code and Cookie Banner contributors
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21THE SOFTWARE.
22*/
23
24(function(context) {
25    'use strict';
26
27    var win = context, doc = win.document;
28
29    var global_instance_name = 'cbinstance';
30
31    /*!
32     * contentloaded.js
33     *
34     * Author: Diego Perini (diego.perini at gmail.com)
35     * Summary: cross-browser wrapper for DOMContentLoaded
36     * Updated: 20101020
37     * License: MIT
38     * Version: 1.2
39     *
40     * URL:
41     * http://javascript.nwbox.com/ContentLoaded/
42     * http://javascript.nwbox.com/ContentLoaded/MIT-LICENSE
43     *
44     */
45    // @win window reference
46    // @fn function reference
47    function contentLoaded(win, fn) {
48        var done = false, top = true,
49        doc = win.document, root = doc.documentElement,
50
51        add = doc.addEventListener ? 'addEventListener' : 'attachEvent',
52        rem = doc.addEventListener ? 'removeEventListener' : 'detachEvent',
53        pre = doc.addEventListener ? '' : 'on',
54
55        init = function(e) {
56            if (e.type == 'readystatechange' && doc.readyState != 'complete') return;
57            (e.type == 'load' ? win : doc)[rem](pre + e.type, init, false);
58            if (!done && (done = true)) fn.call(win, e.type || e);
59        },
60
61        poll = function() {
62            try { root.doScroll('left'); } catch(e) { setTimeout(poll, 50); return; }
63            init('poll');
64        };
65
66        if (doc.readyState == 'complete') fn.call(win, 'lazy');
67        else {
68            if (doc.createEventObject && root.doScroll) {
69                try { top = !win.frameElement; } catch(e) { }
70                if (top) poll();
71            }
72            doc[add](pre + 'DOMContentLoaded', init, false);
73            doc[add](pre + 'readystatechange', init, false);
74            win[add](pre + 'load', init, false);
75        }
76    }
77
78    var Cookies = {
79        get: function (key) {
80            return decodeURIComponent(doc.cookie.replace(new RegExp('(?:(?:^|.*;)\\s*' + encodeURIComponent(key).replace(/[\-\.\+\*]/g, '\\$&') + '\\s*\\=\\s*([^;]*).*$)|^.*$'), '$1')) || null;
81        },
82        set: function (key, val, end, path, domain, secure) {
83            if (!key || /^(?:expires|max\-age|path|domain|secure)$/i.test(key)) {
84                return false;
85            }
86            var expires = '';
87            if (end) {
88                switch (end.constructor) {
89                    case Number:
90                        expires = end === Infinity ? '; expires=Fri, 31 Dec 9999 23:59:59 GMT' : '; max-age=' + end;
91                        break;
92                    case String:
93                        expires = '; expires=' + end;
94                    break;
95                    case Date:
96                        expires = '; expires=' + end.toUTCString();
97                    break;
98                }
99            }
100            doc.cookie = encodeURIComponent(key) + '=' + encodeURIComponent(val) + expires + (domain ? '; domain=' + domain : '') + (path ? '; path=' + path : '') + (secure ? '; secure' : '');
101            return true;
102        },
103        has: function (key) {
104            return (new RegExp('(?:^|;\\s*)' + encodeURIComponent(key).replace(/[\-\.\+\*]/g, '\\$&') + '\\s*\\=')).test(doc.cookie);
105        },
106        remove: function (key, path, domain) {
107            if (!key || !this.has(key)) { return false; }
108            doc.cookie = encodeURIComponent(key) + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT' + ( domain ? '; domain=' + domain : '') + ( path ? '; path=' + path : '');
109            return true;
110        }
111    };
112
113    var Utils = {
114
115        // merge objects and whatnot
116        merge: function(){
117            var obj = {},
118                i = 0,
119                al = arguments.length,
120                key;
121            if (0 === al) {
122                return obj;
123            }
124            for (; i < al; i++) {
125                for (key in arguments[i]) {
126                    if (Object.prototype.hasOwnProperty.call(arguments[i], key)) {
127                        obj[key] = arguments[i][key];
128                    }
129                }
130            }
131            return obj;
132        },
133
134        str2bool: function(str) {
135            str = '' + str;
136            switch (str.toLowerCase()) {
137                case 'false':
138                case 'no':
139                case '0':
140                case '':
141                    return false;
142                default:
143                    return true;
144                }
145        },
146
147        fade_in: function(el) {
148            if (el.style.opacity < 1) {
149                el.style.opacity = (parseFloat(el.style.opacity) + 0.05).toFixed(2);
150                win.setTimeout(function(){
151                    Utils.fade_in(el);
152                }, 50);
153            }
154        },
155
156        get_data_attribs: function(script) {
157            var data = {};
158            if (Object.prototype.hasOwnProperty.call(script, 'dataset')) {
159                data = script.dataset;
160            } else {
161                var attribs = script.attributes;
162                var key;
163                for (key in attribs) {
164                    if (Object.prototype.hasOwnProperty.call(attribs, key)) {
165                        var attr = attribs[key];
166                        if (/^data-/.test(attr.name)) {
167                            var camelized = Utils.camelize(attr.name.substr(5));
168                            data[camelized] = attr.value;
169                        }
170                    }
171                }
172            }
173            return data;
174        },
175
176        /**
177        * "Standardizes" the options keys by converting and removing
178        * any potential "dashed-property-name" into "dashedPropertyName".
179        * In case both are present, the dashedPropertyName wins.
180        */
181        normalize_keys: function(options_object) {
182            var camelized = {};
183            for (var key in options_object) {
184                if (Object.prototype.hasOwnProperty.call(options_object, key)) {
185                    var camelized_key = Utils.camelize(key);
186                    // TODO: could this break for "falsy" values within options_object?
187                    // avoiding "dashed-property-name" overriding a potentially existing "dashedPropertyName"
188                    camelized[camelized_key] = options_object[camelized_key] ? options_object[camelized_key] : options_object[key];
189                }
190            }
191            return camelized;
192        },
193
194        camelize: function(str) {
195            var separator = '-',
196                match = str.indexOf(separator);
197            while (match != -1) {
198                var last = (match === (str.length - 1)),
199                    next = last ? '' : str[match + 1],
200                    upnext = next.toUpperCase(),
201                    sep_substr =  last ? separator : separator + next;
202                str = str.replace(sep_substr, upnext);
203                match = str.indexOf(separator);
204            }
205            return str;
206        },
207
208        find_script_by_id: function(id) {
209            var scripts = doc.getElementsByTagName('script');
210            for (var i = 0, l = scripts.length; i < l; i++) {
211                if (id === scripts[i].id) {
212                    return scripts[i];
213                }
214            }
215            return null;
216        }
217
218    };
219
220    var script_el_invoker = Utils.find_script_by_id('cookiebanner');
221
222    var Cookiebanner = context.Cookiebanner = function(opts) {
223        this.init(opts);
224    };
225
226    Cookiebanner.prototype = {
227
228        // for testing stuff from the outside mostly
229        cookiejar: Cookies,
230
231        init: function(opts) {
232
233            this.inserted = false;
234            this.closed = false;
235            this.test_mode = false; // TODO: implement
236
237            var default_text = 'We use cookies to enhance your experience. ' +
238                'By continuing to visit this site you agree to our use of cookies.';
239            var default_link = 'Learn more';
240
241            this.default_options = {
242                // autorun: true,
243                cookie: 'cookiebanner-accepted',
244                closeText: '&#10006;',
245                cookiePath: '/',
246                debug: false,
247                expires: Infinity,
248                zindex: 255,
249                mask: false,
250                maskOpacity: 0.5,
251                maskBackground: '#000',
252                height: 'auto',
253                minHeight: '21px',
254                bg: '#000',
255                fg: '#ddd',
256                link: '#aaa',
257                position: 'bottom',
258                message: default_text,
259                linkmsg: default_link,
260                moreinfo: 'http://aboutcookies.org',
261                effect: null,
262                fontSize: '14px',
263                fontFamily: 'arial, sans-serif',
264                instance: global_instance_name,
265                textAlign: 'center',
266                acceptOnScroll: false
267            };
268
269            this.options = this.default_options;
270            this.script_el = script_el_invoker;
271
272            if (this.script_el) {
273                var data_options = Utils.get_data_attribs(this.script_el);
274                this.options = Utils.merge(this.options, data_options);
275            }
276
277            // allowing opts passed to the ctor to override everything
278            if (opts) {
279                // mimics the "data-option-name" HTML attribute becoming
280                // this.options.optionName
281                opts = Utils.normalize_keys(opts);
282                this.options = Utils.merge(this.options, opts);
283            }
284
285            // allows customizing the global instance name via options too
286            global_instance_name = this.options.instance;
287
288            // TODO: parse/validate other options that can benefit
289            this.options.zindex = parseInt(this.options.zindex, 10);
290            this.options.mask = Utils.str2bool(this.options.mask);
291
292            // check for a possible global callback specified as a string
293            if ('string' === typeof this.options.expires) {
294                if ('function' === typeof context[this.options.expires]) {
295                    this.options.expires = context[this.options.expires];
296                }
297            }
298
299            // check if expires is a callback
300            if ('function' === typeof this.options.expires) {
301                // TODO: this might not always be as simple as this
302                this.options.expires = this.options.expires();
303            }
304
305            // Proceed with our plans only if we're invoked via a <script> element
306            // that has the required id attribute.
307            // For manually created instances one must call run() explicitly.
308            if (this.script_el) {
309                this.run();
310            }
311        },
312
313        log: function(){
314            if ('undefined' !== typeof console) {
315                console.log.apply(console, arguments);
316            }
317        },
318
319        run: function() {
320            if (!this.agreed()) {
321                var self = this;
322                contentLoaded(win, function(){
323                    self.insert();
324                });
325            }
326        },
327
328        build_viewport_mask: function() {
329            var mask = null;
330            if (true === this.options.mask) {
331                var mask_opacity = this.options.maskOpacity;
332                var bg = this.options.maskBackground;
333                var mask_markup = '<div id="cookiebanner-mask" style="' +
334                    'position:fixed;top:0;left:0;width:100%;height:100%;' +
335                    'background:' + bg + ';zoom:1;filter:alpha(opacity=' +
336                    (mask_opacity * 100) +');opacity:' + mask_opacity +';' +
337                    'z-index:' + this.options.zindex +';"></div>';
338                var el = doc.createElement('div');
339                el.innerHTML = mask_markup;
340                mask = el.firstChild;
341            }
342            return mask;
343        },
344
345        agree: function() {
346            this.cookiejar.set(this.options.cookie, 1, this.options.expires, this.options.cookiePath);
347            return true;
348        },
349
350        agreed: function(){
351            return this.cookiejar.has(this.options.cookie);
352        },
353
354        close: function() {
355            if (this.inserted) {
356                if (!this.closed) {
357                    if (this.element) {
358                        this.element.parentNode.removeChild(this.element);
359                    }
360                    if (this.element_mask) {
361                        this.element_mask.parentNode.removeChild(this.element_mask);
362                    }
363                    this.closed = true;
364                }
365            }/* else {
366                throw new Error("Not inserted but closing?!");
367            }*/
368            return this.closed;
369        },
370
371        agree_and_close:function() {
372            this.agree();
373            return this.close();
374        },
375
376        // close and remove every trace of ourselves completely
377        cleanup: function() {
378            this.close();
379            return this.unload();
380        },
381
382        unload: function() {
383            if (this.script_el) {
384                this.script_el.parentNode.removeChild(this.script_el);
385            }
386            context[global_instance_name] = undefined;
387            // delete context[global_instance_name];
388            return true;
389        },
390
391        insert: function() {
392            this.element_mask = this.build_viewport_mask();
393
394            var zidx = this.options.zindex;
395
396            if (this.element_mask) {
397                // bump notice element's zindex so it's above the mask
398                zidx += 1;
399            }
400
401            var el = doc.createElement('div');
402            el.className = 'cookiebanner';
403            el.style.position = 'fixed';
404            el.style.left = 0;
405            el.style.right = 0;
406            el.style.height = this.options.height;
407            el.style.minHeight = this.options.minHeight;
408            el.style.zIndex = zidx;
409            el.style.background = this.options.bg;
410            el.style.color = this.options.fg;
411            el.style.lineHeight = el.style.minHeight;
412
413            el.style.padding = '5px 16px';
414
415            el.style.fontFamily = this.options.fontFamily;
416            el.style.fontSize = this.options.fontSize;
417            el.style.textAlign = this.options.textAlign;
418
419            if ('top' === this.options.position) {
420                el.style.top = 0;
421            } else {
422                el.style.bottom = 0;
423            }
424
425            el.innerHTML = '<div class="cookiebanner-close" style="float:right;padding-left:5px;">' +
426                this.options.closeText + '</div>' +
427                '<span>' + this.options.message + ' <a>' + this.options.linkmsg + '</a></span>';
428
429            this.element = el;
430
431            var el_a = el.getElementsByTagName('a')[0];
432            el_a.href = this.options.moreinfo;
433            el_a.target = '_blank';
434            el_a.style.textDecoration = 'none';
435            el_a.style.color = this.options.link;
436
437            var el_x = el.getElementsByTagName('div')[0];
438            el_x.style.cursor = 'pointer';
439
440            function on(el, ev, fn) {
441                var add = el.addEventListener ? 'addEventListener' : 'attachEvent',
442                    pre = el.addEventListener ? '' : 'on';
443                el[add](pre + ev, fn, false);
444            }
445
446            var self = this;
447            on(el_x, 'click', function(){
448                self.agree_and_close();
449            });
450
451            if (this.element_mask) {
452                on(this.element_mask, 'click', function(){
453                    self.agree_and_close();
454                });
455                doc.body.appendChild(this.element_mask);
456            }
457
458            // Agree and close banner on window scroll if `acceptOnScroll` option is set `true`
459            if (this.options.acceptOnScroll) {
460              on(window, 'scroll', function(){
461                self.agree_and_close();
462              });
463            }
464
465            doc.body.appendChild(this.element);
466            this.inserted = true;
467
468            if ('fade' === this.options.effect) {
469                this.element.style.opacity = 0;
470                Utils.fade_in(this.element);
471            } else {
472                this.element.style.opacity = 1;
473            }
474        }
475
476    };
477
478    if (script_el_invoker) {
479        if (!context[global_instance_name]) {
480            context[global_instance_name] = new Cookiebanner();
481        }
482    }
483
484})(window);

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.