diff --git a/Readme.md b/Readme.md
index 44b4230c..35411db4 100644
--- a/Readme.md
+++ b/Readme.md
@@ -12,7 +12,7 @@ changes. Thanks and credits to [Orest Bida](https://github.com/orestbida/cookiec
-A __lightweight__ & __gdpr compliant__ cookie consent plugin written in plain javascript. An "all-in-one" solution which also allows you to write your cookie policy inside it without the need of having a dedicated page.
+A __lightweight__ & __gdpr compliant__ cookie consent plugin written in plain javascript.
@@ -22,17 +22,20 @@ A __lightweight__ & __gdpr compliant__ cookie consent plugin written in plain ja
## Table of contents
-1. [Key features](#key-features)
-2. [Installation & Usage](#installation--usage)
-4. [Layout options & customization](#layout-options--customization)
-5. [API methods](#api-methods)
-6. [Available callbacks](#available-callbacks)
-7. [All configuration options](#all-configuration-options)
-8. [How to block/manage scripts](#how-to-blockmanage-scripts)
-9. [Configuration examples](#full-example-configurations)
-10. [How to enable/manage revisions](#how-to-enablemanage-revisions)
-11. [FAQ](#faq)
-12. [License](#license)
+- [Table of contents](#table-of-contents)
+- [Key features](#key-features)
+- [Installation & Usage](#installation--usage)
+- [Layout options & customization](#layout-options--customization)
+- [How to block/manage scripts](#how-to-blockmanage-scripts)
+- [API methods](#api-methods)
+- [Available `data-cc` actions](#available-data-cc-actions)
+- [Available callbacks](#available-callbacks)
+ - [All configuration options](#all-configuration-options)
+- [Full example configurations](#full-example-configurations)
+ - [How to configure languages & cookie settings](#how-to-configure-languages--cookie-settings)
+- [How to enable/manage revisions](#how-to-enablemanage-revisions)
+- [FAQ](#faq)
+- [License](#license)
## Key features
- __Lightweight__
@@ -49,8 +52,8 @@ A __lightweight__ & __gdpr compliant__ cookie consent plugin written in plain ja
```bash
# CDN links
- https://cdn.jsdelivr.net/gh/orestbida/cookieconsent@v2.8.0/dist/cookieconsent.js
- https://cdn.jsdelivr.net/gh/orestbida/cookieconsent@v2.8.0/dist/cookieconsent.css
+ https://cdn.jsdelivr.net/gh/orestbida/cookieconsent@v2.8.1/dist/cookieconsent.js
+ https://cdn.jsdelivr.net/gh/orestbida/cookieconsent@v2.8.1/dist/cookieconsent.css
```
Thanks to [Till Sanders](https://github.com/tillsanders) for bringing the plugin on npm.
@@ -63,14 +66,18 @@ A __lightweight__ & __gdpr compliant__ cookie consent plugin written in plain ja
1. Import the plugin: add a `script` tag pointing to `cookieconsent.js`
```html
-
+
+
+
+
+
```
- Note: replace `` with a valid path!
+ Note: replace `` and `` with valid paths!
3. Configure and run
diff --git a/dist/cookieconsent.js b/dist/cookieconsent.js
index 5b9be8b9..ce524ec9 100644
--- a/dist/cookieconsent.js
+++ b/dist/cookieconsent.js
@@ -1,43 +1,43 @@
/*
- CookieConsent v3.0.0-beta.1
+ CookieConsent v2.8.1
https://www.github.com/orestbida/cookieconsent
Author Orest Bida
Released under the MIT License
*/
-(function(){var hb=function(ab){var f={mode:"opt-in",current_lang:"en",auto_language:null,autorun:!0,page_scripts:!0,hide_from_bots:!0,cookie_name:"cc_cookie",cookie_expiration:182,cookie_domain:window.location.hostname,cookie_path:"/",cookie_same_site:"Lax",use_rfc_cookie:!1,autoclear_cookies:!0,revision:0,script_selector:"data-cookiecategory"},n={},g,u={},B=null,J=!1,O=!1,ma=!1,Ba=!1,na=!1,v,X,T,oa,Ca,Da,Qa=!1,ha=!0,U=[],wa=!1,Ea,Fa=[],Ra=[],Ga=[],Sa=!1,pa,Ha,Ia=[],ia=[],P=[],G=[],xa=[],qa=document.documentElement,
-Q,ra,x,Y,sa,V,R,S,Z,E,K,ta,ja,ka,y,aa,ba,ca,da,Ta=function(a){function b(l){return(a||document).querySelectorAll('a[data-cc="'+l+'"], button[data-cc="'+l+'"]')}function c(l,q){l.preventDefault?l.preventDefault():l.returnValue=!1;n.accept(q);n.hideSettings();n.hide()}for(var d=b("c-settings"),e=b("accept-all"),m=b("accept-necessary"),p=b("accept-custom"),k=0;k\x3c!--\x3e\x3c!--\x3c!--\x3e\x3c!-->a/4).toString(16)})},gb=function(a,b){return"browser"===e.auto_language?(b=navigator.language||navigator.browserLanguage,
+2 retrieve category states from cookie
+ * If consent is valid => retrieve category states from cookie
* Otherwise use states defined in the user_config. object
*/
- if(cookie_consent_accepted){
+ if(!invalid_consent){
if(_inArray(saved_cookie_content['categories'], cookie_category) > -1){
block_switch.checked = true;
!new_settings_blocks && toggle_states.push(true);
@@ -1115,20 +1152,35 @@
/**
* Clear cookies when settings/preferences change
*/
- if(cookie_consent_accepted && _config.autoclear_cookies && changed_settings.length > 0)
+ if(!invalid_consent && _config.autoclear_cookies && changed_settings.length > 0)
_autoclearCookies();
+ if(!consent_date) consent_date = new Date();
+ if(!consent_uuid) consent_uuid = _uuidv4();
+
saved_cookie_content = {
"categories": accepted_categories,
"revision": _config.revision,
"data": cookie_data,
- "rfc_cookie": _config.use_rfc_cookie
+ "rfc_cookie": _config.use_rfc_cookie,
+ "consent_date": consent_date.toISOString(),
+ "consent_uuid": consent_uuid
}
// save cookie with preferences 'categories' (only if never accepted or settings were updated)
- if(!cookie_consent_accepted || changed_settings.length > 0 || !valid_revision){
+ if(invalid_consent || changed_settings.length > 0){
valid_revision = true;
+ /**
+ * Update "last_consent_update" only if it is invalid (after t)
+ */
+ if(!last_consent_update)
+ last_consent_update = consent_date;
+ else
+ last_consent_update = new Date();
+
+ saved_cookie_content['last_consent_update'] = last_consent_update.toISOString();
+
/**
* Update accept type
*/
@@ -1136,12 +1188,14 @@
_setCookie(_config.cookie_name, JSON.stringify(saved_cookie_content));
_manageExistingScripts();
+
+ //_printConsentDateHTML();
}
- if(!cookie_consent_accepted){
+ if(invalid_consent){
/**
- * Delete unused/"zombie" cookies the very-first time
+ * Delete unused/"zombie" cookies if consent is not valid (not yet expressed or cookie has expired)
*/
if(_config.autoclear_cookies)
_autoclearCookies(true);
@@ -1152,7 +1206,10 @@
if(typeof onAccept === 'function')
onAccept(saved_cookie_content);
- cookie_consent_accepted = true;
+ /**
+ * Set consent as valid
+ */
+ invalid_consent = false;
if(_config.mode === 'opt-in') return;
}
@@ -1200,6 +1257,17 @@
return el;
}
+ /**
+ * Generate RFC4122-compliant UUIDs.
+ * https://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid?page=1&tab=votes#tab-top
+ * @returns {string}
+ */
+ var _uuidv4 = function(){
+ return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, function(c){
+ return (c ^ (window.crypto || window.msCrypto).getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
+ });
+ }
+
/**
* Resolve which language should be used.
*
@@ -1393,7 +1461,7 @@
*/
_cookieconsent.allowedCategory = function(cookie_category){
- if(cookie_consent_accepted || _config.mode === 'opt-in')
+ if(!invalid_consent || _config.mode === 'opt-in')
var allowed_categories = JSON.parse(_getCookie(_config.cookie_name, 'one', true) || '{}')['categories'] || []
else // mode is 'opt-out'
var allowed_categories = default_enabled_categories;
@@ -1415,25 +1483,31 @@
// Retrieve cookie value (if set)
saved_cookie_content = JSON.parse(_getCookie(_config.cookie_name, 'one', true) || "{}");
- cookie_consent_accepted = saved_cookie_content['categories'] !== undefined;
- /**
- * Immediately retrieve the 'data' field from cookie
- * (since this value is allowed to be accessed/used before the .run method)
- */
+ // Retrieve "consent_uuid"
+ consent_uuid = saved_cookie_content['consent_uuid'];
+
+ // If "consent_uuid" is present => assume that consent was previously given
+ var cookie_consent_accepted = consent_uuid !== undefined;
+
+ // Retrieve "consent_date"
+ consent_date = saved_cookie_content['consent_date'];
+ consent_date && (consent_date = new Date(consent_date));
+
+ // Retrieve "last_consent_update"
+ last_consent_update = saved_cookie_content['last_consent_update'];
+ last_consent_update && (last_consent_update = new Date(last_consent_update));
+
+ // Retrieve "data"
cookie_data = saved_cookie_content['data'] !== undefined ? saved_cookie_content['data'] : null;
- // Compare current revision with the one retrieved from cookie
- valid_revision = typeof user_config['revision'] === "number"
- ? cookie_consent_accepted
- ? user_config['revision'] > -1
- ? saved_cookie_content['revision'] === _config.revision
- : true
- : true
- : true;
+ // If revision is enabled and current value !== saved value inside the cookie => revision is not valid
+ if(revision_enabled && saved_cookie_content['revision'] !== _config.revision){
+ valid_revision = false;
+ }
- // If invalid revision or cookie is empty => create consent modal
- consent_modal_exists = (!cookie_consent_accepted || !valid_revision);
+ // If consent is not valid => create consent modal
+ consent_modal_exists = invalid_consent = (!cookie_consent_accepted || !valid_revision || !consent_date || !last_consent_update || !consent_uuid);
// Generate cookie-settings dom (& consent modal)
_createCookieConsentHTML();
@@ -1452,7 +1526,8 @@
// Accessibility :=> if tab pressed => trap focus inside modal
setTimeout(function(){_handleFocusTrap();}, 100);
- if(cookie_consent_accepted && valid_revision){
+ // If consent is valid
+ if(!invalid_consent){
var rfc_prop_exists = typeof saved_cookie_content['rfc_cookie'] === "boolean";
/*
@@ -1473,10 +1548,14 @@
if(typeof onAccept === 'function')
onAccept(saved_cookie_content);
+ _log("CookieConsent [NOTICE]: consent already given!", saved_cookie_content);
- }else if(_config.mode === 'opt-out'){
- _log("CookieConsent [CONFIG] mode='" + _config.mode + "', default enabled categories:", default_enabled_categories);
- _manageExistingScripts(default_enabled_categories);
+ }else{
+ if(_config.mode === 'opt-out'){
+ _log("CookieConsent [CONFIG] mode='" + _config.mode + "', default enabled categories:", default_enabled_categories);
+ _manageExistingScripts(default_enabled_categories);
+ }
+ _log("CookieConsent [NOTICE]: ask for consent!");
}
}else{
_log("CookieConsent [NOTICE]: cookie consent already attached to body!");
@@ -1657,43 +1736,6 @@
return set;
}
- /**
- * Forcefully set a specific revision and show consent modal
- * @param {number} new_revision
- * @param {boolean} [prompt_consent]
- * @returns {boolean}
- */
- var _setRevision = function(new_revision, prompt_consent, message){
-
- // If plugin has been initialized and new revision is valid
- if(
- main_container
- && typeof new_revision === "number"
- && saved_cookie_content['revision'] !== new_revision
- ){
-
- revision_enabled = true;
- revision_message = message;
- valid_revision = false;
- _config.revision = new_revision;
-
- // Show consent modal ?
- if(prompt_consent === true){
- _createConsentModal(user_config);
- _guiManager(user_config['gui_options'], true);
- _getModalFocusableData();
- _cookieconsent.show();
- }else {
- // If revision was modified, save cookie with the new revision
- _cookieconsent.accept();
- }
-
- return true;
- }
-
- return false;
- }
-
/**
* Helper method to set a variety of fields
* @param {string} field
@@ -1801,7 +1843,7 @@
* Dynamically load script (append to head)
* @param {string} src
* @param {scriptLoaded} callback
- * @param {string[]} attrs
+ * @param {object[]} [attrs] Custom attributes
*/
_cookieconsent.loadScript = function(src, callback, attrs){
@@ -1821,16 +1863,7 @@
// if callback function defined => run callback onload
if(function_defined){
- if(script.readyState) { // only required for IE <9
- script.onreadystatechange = function() {
- if ( script.readyState === "loaded" || script.readyState === "complete" ) {
- script.onreadystatechange = null;
- callback();
- }
- };
- }else{ //Others
- script.onload = callback;
- }
+ script.onload = callback;
}
script.src = src;
@@ -1838,7 +1871,7 @@
/**
* Append script to head
*/
- (document.head ? document.head : document.getElementsByTagName('head')[0]).appendChild(script);
+ document.head.appendChild(script);
}else{
function_defined && callback();
}
@@ -2056,7 +2089,8 @@
document.cookie = cookieStr;
- _log("CookieConsent [SET_COOKIE]: cookie "+ name + "='" + value + "' was set! Expires after " + cookie_expiration + " days");
+ _log("CookieConsent [SET_COOKIE]: cookie '" + name + "'=", JSON.parse(value));
+ _log("CookieConsent [SET_COOKIE]: '" + name + "' expires after " + cookie_expiration + " day(s)");
}
/**
@@ -2064,8 +2098,8 @@
* returns the cookie value if found (or an array
* of cookies if filter provided), otherwise empty string: ""
* @param {string} name
- * @param {string} filter - 'one' or 'all'
- * @param {boolean} get_value - set to true to obtain its value
+ * @param {string} filter 'one' or 'all'
+ * @param {boolean} [get_value] set to true to obtain its value
* @returns {string|string[]}
*/
var _getCookie = function(name, filter, get_value) {
@@ -2137,20 +2171,10 @@
* @param {Element} elem
* @param {string} event
* @param {eventFired} fn
- * @param {boolean} passive
+ * @param {boolean} [isPassive]
*/
- var _addEvent = function(elem, event, fn, _passive) {
- var passive = _passive === true;
-
- if (elem.addEventListener) {
- passive ? elem.addEventListener(event, fn , { passive: true }) : elem.addEventListener(event, fn, false);
- } else {
- /**
- * For old browser, add 'on' before event:
- * 'click':=> 'onclick'
- */
- elem.attachEvent("on" + event, fn);
- }
+ var _addEvent = function(elem, event, fn, isPassive) {
+ elem.addEventListener(event, fn , isPassive === true ? { passive: true } : false);
}
/**
@@ -2159,10 +2183,7 @@
*/
var _getKeys = function(obj){
if(typeof obj === "object"){
- var keys = [], i = 0;
- for (var key in obj)
- keys[i++] = key;
- return keys;
+ return Object.keys(obj);
}
}
@@ -2172,12 +2193,7 @@
* @param {string} classname
*/
var _addClass = function (elem, classname){
- if(elem.classList)
- elem.classList.add(classname)
- else{
- if(!_hasClass(elem, classname))
- elem.className += ' '+classname;
- }
+ elem.classList.add(classname);
}
/**
@@ -2186,7 +2202,7 @@
* @param {string} classname
*/
var _removeClass = function (el, className) {
- el.classList ? el.classList.remove(className) : el.className = el.className.replace(new RegExp('(\\s|^)' + className + '(\\s|$)'), ' ');
+ el.classList.remove(className);
}
/**
@@ -2195,10 +2211,7 @@
* @param {string} className
*/
var _hasClass = function(el, className) {
- if (el.classList) {
- return el.classList.contains(className);
- }
- return !!el.className.match(new RegExp('(\\s|^)' + className + '(\\s|$)'));
+ return el.classList.contains(className);
}
return _cookieconsent;
@@ -2208,7 +2221,7 @@
/**
* Make CookieConsent object accessible globally
*/
- if(typeof window[init] !== 'function'){
+ if(typeof window !== 'undefined' && typeof window[init] !== 'function'){
window[init] = CookieConsent
}
})();
\ No newline at end of file
diff --git a/types/types.d.ts b/types/types.d.ts
new file mode 100644
index 00000000..650abf93
--- /dev/null
+++ b/types/types.d.ts
@@ -0,0 +1,146 @@
+export {}
+
+declare global {
+ type MODE = 'opt-in' | 'opt-out'
+
+ type AUTO_LANGUAGE_ORIGIN = 'browser' | 'document'
+
+ type ModalLayout = 'box' | 'cloud' | 'bar'
+
+ type ModalPosition = 'bottom left' | 'bottom right' | 'bottom center' | 'middle left' | 'middle right' | 'middle center' | 'top left' | 'top right' | 'top center'
+
+ type GUITransition = 'zoom' | 'slide'
+
+ type SettingLayout = 'box' | 'bar'
+
+ type SettingPosition = 'left' | 'right'
+
+ interface SavedCookieContent {
+ categories: string[]
+ revision: number
+ data?: null | Record | string>
+ rfc_cookie: boolean
+ consent_date: string
+ consent_uuid: string
+ last_consent_update: string
+ }
+
+ interface GUIOptions {
+ consent_modal?: {
+ layout?: ModalLayout
+ position?: ModalPosition
+ transition?: GUITransition
+ swap_buttons?: boolean
+ },
+ settings_modal?: {
+ layout?: SettingLayout
+ position?: SettingPosition
+ transition?: GUITransition
+ }
+ }
+
+ interface UserPreferences {
+ accept_type: string
+ accepted_categories: string[]
+ rejected_categories: string[]
+ }
+
+ type PrimaryButtonRole = 'accept_selected' | 'accept_all'
+
+ type SecondaryButtonRole = 'settings' | 'accept_necessary'
+
+ interface ButtonSetting {
+ text: string
+ role: Role
+ }
+
+ interface ConsentModalLanguageSetting {
+ title?: string
+ description?: string
+ primary_btn?: ButtonSetting
+ secondary_btn?: ButtonSetting
+ revision_message?: string
+ }
+
+ interface ToggleSetting {
+ value: string
+ enabled?: boolean
+ readonly?: boolean
+ }
+
+ interface BlockSetting {
+ title: string
+ description: string
+ toggle?: ToggleSetting
+ cookie_table_headers?: Record[]
+ cookie_table?: Record[]
+ }
+
+ interface SettingsModalLanguageSetting {
+ title?: string
+ save_settings_btn?: string
+ accept_all_btn?: string
+ reject_all_btn?: string
+ blocks?: BlockSetting[]
+ }
+
+ interface LanguageSetting {
+ consent_modal?: ConsentModalLanguageSetting
+ settings_modal?: SettingsModalLanguageSetting
+ }
+
+ interface UserConfig {
+ autorun?: boolean
+ delay?: number
+ mode?: MODE
+ cookie_expiration?: number
+ cookie_necessary_only_expiration?: number
+ cookie_path?: string
+ cookie_domain?: string
+ cookie_same_site?: string
+ use_rfc_cookie?: boolean
+ force_consent?: boolean
+ revision?: number
+ current_lang?: string
+ auto_language?: AUTO_LANGUAGE_ORIGIN
+ autoclear_cookies?: boolean
+ page_scripts?: boolean
+ remove_cookie_tables?: boolean
+ hide_from_bots?: boolean
+ gui_options?: GUIOptions
+ onAccept?: (savedCookieContent: SavedCookieContent) => void
+ onChange?: (cookie: SavedCookieContent, changedCookieCategories: string[]) => void
+ onFirstAction? :(userPreferences: UserPreferences, cookie: SavedCookieContent) => void
+ languages?: Record
+ }
+
+ interface ScriptAttribute {
+ name: string
+ value: any
+ }
+
+ interface CookieConsent {
+ run(config: UserConfig): void
+ showSettings(delay: number): void
+ accept(_categories: string | string[], _exclusions?: string[]): void
+ hideSettings(): void
+ hide(): void
+ updateLanguage(lang: string, force: boolean): boolean
+ getUserPreferences(): UserPreferences
+ loadScript(src: string, callback: () => void | typeof onload, attrs?: ScriptAttribute[]): void
+ updateScripts(): void
+ show(delay?: number, create_modal?: boolean): void
+ eraseCookies(_cookies: string | string[], _path?: string, _domain?: string): void
+ validCookie(cookie_name: string): boolean
+ allowedCategory(cookie_category: string): boolean
+ set(field: string, data: Record): boolean
+ get(field: string, cookie_name?: string): Record
+ getConfig(field: Field): UserConfig[Field]
+ }
+
+ function initCookieConsent(root?: HTMLElement): CookieConsent
+
+ interface Window {
+ initCookieConsent: typeof initCookieConsent
+ }
+}
\ No newline at end of file