Commit 5894f602 authored by lechuck's avatar lechuck Committed by lucha

Add custom plugin to display Cookie Banner to comply to EU directive

parent 75e2d83a
<?php
/*
* Plugin Name: Ai - Eu compliant banner
* Plugin URI:
* Description: AI - Cookie Banner
* Version: 1.0
* Author: lechuck
* Author URI: http://noblogs.org
**/
/**
* Proper way to enqueue scripts and styles
*/
function load_banner() {
wp_enqueue_script( 'cookiebanner', plugins_url( '/js/cookiebanner.js' , __FILE__ ), array(), '1.0.0', true );
}
add_action( 'wp_enqueue_scripts', 'load_banner' );
add_filter( 'script_loader_tag', function ( $tag, $handle ) {
if ( 'cookiebanner' !== $handle )
return $tag;
$stringa = ' id="cookiebanner" data-moreinfo="https://noblogs.org/privacy" data-message="To comply to EU Privacy Laws we inform you that some of the third party services used on some of our blogs could use cookies" ';
return str_replace( ' src', "$stringa src", $tag );
}, 10, 2 );
/*global window:false, setTimeout:true, console:true */
(function(context) {
'use strict';
var win = context, doc = win.document;
var global_instance_name = 'cbinstance';
/*!
* contentloaded.js
*
* Author: Diego Perini (diego.perini at gmail.com)
* Summary: cross-browser wrapper for DOMContentLoaded
* Updated: 20101020
* License: MIT
* Version: 1.2
*
* URL:
* http://javascript.nwbox.com/ContentLoaded/
* http://javascript.nwbox.com/ContentLoaded/MIT-LICENSE
*
*/
// @win window reference
// @fn function reference
function contentLoaded(win, fn) {
var done = false, top = true,
doc = win.document, root = doc.documentElement,
add = doc.addEventListener ? 'addEventListener' : 'attachEvent',
rem = doc.addEventListener ? 'removeEventListener' : 'detachEvent',
pre = doc.addEventListener ? '' : 'on',
init = function(e) {
if (e.type == 'readystatechange' && doc.readyState != 'complete') return;
(e.type == 'load' ? win : doc)[rem](pre + e.type, init, false);
if (!done && (done = true)) fn.call(win, e.type || e);
},
poll = function() {
try { root.doScroll('left'); } catch(e) { setTimeout(poll, 50); return; }
init('poll');
};
if (doc.readyState == 'complete') fn.call(win, 'lazy');
else {
if (doc.createEventObject && root.doScroll) {
try { top = !win.frameElement; } catch(e) { }
if (top) poll();
}
doc[add](pre + 'DOMContentLoaded', init, false);
doc[add](pre + 'readystatechange', init, false);
win[add](pre + 'load', init, false);
}
}
var Cookies = {
get: function (key) {
return decodeURIComponent(doc.cookie.replace(new RegExp('(?:(?:^|.*;)\\s*' + encodeURIComponent(key).replace(/[\-\.\+\*]/g, '\\$&') + '\\s*\\=\\s*([^;]*).*$)|^.*$'), '$1')) || null;
},
set: function (key, val, end, path, domain, secure) {
if (!key || /^(?:expires|max\-age|path|domain|secure)$/i.test(key)) {
return false;
}
var expires = '';
if (end) {
switch (end.constructor) {
case Number:
expires = end === Infinity ? '; expires=Fri, 31 Dec 9999 23:59:59 GMT' : '; max-age=' + end;
break;
case String:
expires = '; expires=' + end;
break;
case Date:
expires = '; expires=' + end.toUTCString();
break;
}
}
doc.cookie = encodeURIComponent(key) + '=' + encodeURIComponent(val) + expires + (domain ? '; domain=' + domain : '') + (path ? '; path=' + path : '') + (secure ? '; secure' : '');
return true;
},
has: function (key) {
return (new RegExp('(?:^|;\\s*)' + encodeURIComponent(key).replace(/[\-\.\+\*]/g, '\\$&') + '\\s*\\=')).test(doc.cookie);
},
remove: function (key, path, domain) {
if (!key || !this.has(key)) { return false; }
doc.cookie = encodeURIComponent(key) + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT' + ( domain ? '; domain=' + domain : '') + ( path ? '; path=' + path : '');
return true;
}
};
var Utils = {
// merge objects and whatnot
merge: function(){
var obj = {},
i = 0,
al = arguments.length,
key;
if (0 === al) {
return obj;
}
for (; i < al; i++) {
for (key in arguments[i]) {
if (Object.prototype.hasOwnProperty.call(arguments[i], key)) {
obj[key] = arguments[i][key];
}
}
}
return obj;
},
str2bool: function(str) {
str = '' + str;
switch (str.toLowerCase()) {
case 'false':
case 'no':
case '0':
case '':
return false;
default:
return true;
}
},
fade_in: function(el) {
if (el.style.opacity < 1) {
el.style.opacity = (parseFloat(el.style.opacity) + 0.05).toFixed(2);
win.setTimeout(function(){
Utils.fade_in(el);
}, 50);
}
},
get_data_attribs: function(script) {
var data = {};
if (Object.prototype.hasOwnProperty.call(script, 'dataset')) {
data = script.dataset;
} else {
var attribs = script.attributes;
var key;
for (key in attribs) {
if (Object.prototype.hasOwnProperty.call(attribs, key)) {
var attr = attribs[key];
if (/^data-/.test(attr.name)) {
var camelized = Utils.camelize(attr.name.substr(5));
data[camelized] = attr.value;
}
}
}
}
return data;
},
/**
* "Standardizes" the options keys by converting and removing
* any potential "dashed-property-name" into "dashedPropertyName".
* In case both are present, the dashedPropertyName wins.
*/
normalize_keys: function(options_object) {
var camelized = {};
for (var key in options_object) {
if (Object.prototype.hasOwnProperty.call(options_object, key)) {
var camelized_key = Utils.camelize(key);
// TODO: could this break for "falsy" values within options_object?
// avoiding "dashed-property-name" overriding a potentially existing "dashedPropertyName"
camelized[camelized_key] = options_object[camelized_key] ? options_object[camelized_key] : options_object[key];
}
}
return camelized;
},
camelize: function(str) {
var separator = '-',
match = str.indexOf(separator);
while (match != -1) {
var last = (match === (str.length - 1)),
next = last ? '' : str[match + 1],
upnext = next.toUpperCase(),
sep_substr = last ? separator : separator + next;
str = str.replace(sep_substr, upnext);
match = str.indexOf(separator);
}
return str;
},
find_script_by_id: function(id) {
var scripts = doc.getElementsByTagName('script');
for (var i = 0, l = scripts.length; i < l; i++) {
if (id === scripts[i].id) {
return scripts[i];
}
}
return null;
}
};
var script_el_invoker = Utils.find_script_by_id('cookiebanner');
var Cookiebanner = context.Cookiebanner = function(opts) {
this.init(opts);
};
Cookiebanner.prototype = {
// for testing stuff from the outside mostly
cookiejar: Cookies,
init: function(opts) {
this.inserted = false;
this.closed = false;
this.test_mode = false; // TODO: implement
var default_text = 'We use cookies to enhance your experience. ' +
'By continuing to visit this site you agree to our use of cookies.';
var default_link = 'Learn more';
this.default_options = {
// autorun: true,
cookie: 'cookiebanner-accepted',
closeText: '&#10006;',
cookiePath: '/',
debug: false,
expires: Infinity,
zindex: 255,
mask: false,
maskOpacity: 0.5,
maskBackground: '#000',
height: 'auto',
minHeight: '21px',
bg: '#000',
fg: '#ddd',
link: '#aaa',
position: 'bottom',
message: default_text,
linkmsg: default_link,
moreinfo: 'http://aboutcookies.org',
effect: null,
fontSize: '14px',
fontFamily: 'arial, sans-serif',
instance: global_instance_name,
textAlign: 'center'
};
this.options = this.default_options;
this.script_el = script_el_invoker;
if (this.script_el) {
var data_options = Utils.get_data_attribs(this.script_el);
this.options = Utils.merge(this.options, data_options);
}
// allowing opts passed to the ctor to override everything
if (opts) {
// mimics the "data-option-name" HTML attribute becoming
// this.options.optionName
opts = Utils.normalize_keys(opts);
this.options = Utils.merge(this.options, opts);
}
// allows customizing the global instance name via options too
global_instance_name = this.options.instance;
// TODO: parse/validate other options that can benefit
this.options.zindex = parseInt(this.options.zindex, 10);
this.options.mask = Utils.str2bool(this.options.mask);
// check for a possible global callback specified as a string
if ('string' === typeof this.options.expires) {
if ('function' === typeof context[this.options.expires]) {
this.options.expires = context[this.options.expires];
}
}
// check if expires is a callback
if ('function' === typeof this.options.expires) {
// TODO: this might not always be as simple as this
this.options.expires = this.options.expires();
}
// Proceed with our plans only if we're invoked via a <script> element
// that has the required id attribute.
// For manually created instances one must call run() explicitly.
if (this.script_el) {
this.run();
}
},
log: function(){
if ('undefined' !== typeof console) {
console.log.apply(console, arguments);
}
},
run: function() {
if (!this.agreed()) {
var self = this;
contentLoaded(win, function(){
self.insert();
});
}
},
build_viewport_mask: function() {
var mask = null;
if (true === this.options.mask) {
var mask_opacity = this.options.maskOpacity;
var bg = this.options.maskBackground;
var mask_markup = '<div id="cookiebanner-mask" style="' +
'position:fixed;top:0;left:0;width:100%;height:100%;' +
'background:' + bg + ';zoom:1;filter:alpha(opacity=' +
(mask_opacity * 100) +');opacity:' + mask_opacity +';' +
'z-index:' + this.options.zindex +';"></div>';
var el = doc.createElement('div');
el.innerHTML = mask_markup;
mask = el.firstChild;
}
return mask;
},
agree: function() {
this.cookiejar.set(this.options.cookie, 1, this.options.expires, this.options.cookiePath);
return true;
},
agreed: function(){
return this.cookiejar.has(this.options.cookie);
},
close: function() {
if (this.inserted) {
if (!this.closed) {
if (this.element) {
this.element.parentNode.removeChild(this.element);
}
if (this.element_mask) {
this.element_mask.parentNode.removeChild(this.element_mask);
}
this.closed = true;
}
}/* else {
throw new Error("Not inserted but closing?!");
}*/
return this.closed;
},
agree_and_close:function() {
this.agree();
return this.close();
},
// close and remove every trace of ourselves completely
cleanup: function() {
this.close();
return this.unload();
},
unload: function() {
if (this.script_el) {
this.script_el.parentNode.removeChild(this.script_el);
}
context[global_instance_name] = undefined;
// delete context[global_instance_name];
return true;
},
insert: function() {
this.element_mask = this.build_viewport_mask();
var zidx = this.options.zindex;
if (this.element_mask) {
// bump notice element's zindex so it's above the mask
zidx += 1;
}
var el = doc.createElement('div');
el.className = 'cookiebanner';
el.style.position = 'fixed';
el.style.left = 0;
el.style.right = 0;
el.style.height = this.options.height;
el.style.minHeight = this.options.minHeight;
el.style.zIndex = zidx;
el.style.background = this.options.bg;
el.style.color = this.options.fg;
el.style.lineHeight = el.style.minHeight;
el.style.padding = '5px 16px';
el.style.fontFamily = this.options.fontFamily;
el.style.fontSize = this.options.fontSize;
el.style.textAlign = this.options.textAlign;
if ('top' === this.options.position) {
el.style.top = 0;
} else {
el.style.bottom = 0;
}
el.innerHTML = '<div class="cookiebanner-close" style="float:right;padding-left:5px;">' +
this.options.closeText + '</div>' +
'<span>' + this.options.message + ' <a>' + this.options.linkmsg + '</a></span>';
this.element = el;
var el_a = el.getElementsByTagName('a')[0];
el_a.href = this.options.moreinfo;
el_a.target = '_blank';
el_a.style.textDecoration = 'none';
el_a.style.color = this.options.link;
var el_x = el.getElementsByTagName('div')[0];
el_x.style.cursor = 'pointer';
function on(el, ev, fn) {
var add = el.addEventListener ? 'addEventListener' : 'attachEvent',
pre = el.addEventListener ? '' : 'on';
el[add](pre + ev, fn, false);
}
var self = this;
on(el_x, 'click', function(){
self.agree_and_close();
});
if (this.element_mask) {
on(this.element_mask, 'click', function(){
self.agree_and_close();
});
doc.body.appendChild(this.element_mask);
}
doc.body.appendChild(this.element);
this.inserted = true;
if ('fade' === this.options.effect) {
this.element.style.opacity = 0;
Utils.fade_in(this.element);
} else {
this.element.style.opacity = 1;
}
}
};
if (script_el_invoker) {
if (!context[global_instance_name]) {
context[global_instance_name] = new Cookiebanner();
}
}
})(window);
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment