@jarijokinen/consent 0.0.4 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.txt +1 -1
- package/README.md +15 -15
- package/package.json +2 -2
- package/src/consent-loader.js +39 -0
- package/src/consent.js +46 -82
package/LICENSE.txt
CHANGED
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# consent
|
|
2
2
|
|
|
3
|
-
A zero-dependency, vanilla JavaScript consent manager with native
|
|
4
|
-
support.
|
|
3
|
+
A zero-dependency, vanilla JavaScript consent manager with native Google
|
|
4
|
+
Consent Mode v2 support.
|
|
5
5
|
|
|
6
6
|
## Installation
|
|
7
7
|
|
|
@@ -9,13 +9,18 @@ NPM:
|
|
|
9
9
|
|
|
10
10
|
npm install @jarijokinen/consent
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
## Usage
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
Load the consent-loader.js in the HEAD section deferred before any GTM tags.
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
<head>
|
|
17
|
+
<script src="path/to/consent-loader.js" defer></script>
|
|
18
|
+
<script>
|
|
19
|
+
// GTM and any other scripts
|
|
20
|
+
</script>
|
|
21
|
+
</head>
|
|
17
22
|
|
|
18
|
-
|
|
23
|
+
Import consent from the npm package and initialize it later on the page.
|
|
19
24
|
|
|
20
25
|
import { consent } from '@jarijokinen/consent';
|
|
21
26
|
|
|
@@ -25,7 +30,7 @@ Initialization:
|
|
|
25
30
|
|
|
26
31
|
Add link that opens the dialog:
|
|
27
32
|
|
|
28
|
-
<a href="#" class="consent-settings
|
|
33
|
+
<a href="#" class="consent-settings">Cookie Settings</a>
|
|
29
34
|
|
|
30
35
|
## Configuration
|
|
31
36
|
|
|
@@ -48,15 +53,10 @@ argument to the consent() function.
|
|
|
48
53
|
<div class="consent-fields"></div>
|
|
49
54
|
<div class="consent-buttons"></div>
|
|
50
55
|
`,
|
|
51
|
-
dialogTitle: 'Cookies',
|
|
52
|
-
dialogMessage: 'We would like to get your permission to use cookies for:',
|
|
53
56
|
dialogClass: 'consent',
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
'DE', 'GR', 'HU', 'IE', 'IT', 'LV', 'LT', 'LU', 'MT', 'NL',
|
|
58
|
-
'PL', 'PT', 'RO', 'SK', 'SI', 'ES', 'SE', 'IS', 'LI', 'NO',
|
|
59
|
-
'GB', 'CH', 'MC', 'SM', 'VA', 'JE', 'GG', 'IM']
|
|
57
|
+
dialogTitle: 'Cookie Consent',
|
|
58
|
+
dialogMessage: 'This website uses cookies for:',
|
|
59
|
+
settingsLinkSelector: '.consent-settings'
|
|
60
60
|
};
|
|
61
61
|
|
|
62
62
|
consent(options);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jarijokinen/consent",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "A zero-dependency, vanilla JavaScript consent manager with native Consent Mode support.",
|
|
3
|
+
"version": "0.0.5",
|
|
4
|
+
"description": "A zero-dependency, vanilla JavaScript consent manager with native Google Consent Mode v2 support.",
|
|
5
5
|
"main": "src/consent.js",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
window.dataLayer = window.dataLayer || [];
|
|
2
|
+
function gtag() { dataLayer.push(arguments); }
|
|
3
|
+
|
|
4
|
+
window.consent = window.consent || {};
|
|
5
|
+
window.consent.countries = window.consent.countries || [
|
|
6
|
+
'AT', 'BE', 'BG', 'HR', 'CY', 'CZ', 'DK', 'EE', 'FI', 'FR', 'DE', 'GR', 'HU',
|
|
7
|
+
'IS', 'IE', 'IT', 'LV', 'LI', 'LT', 'LU', 'MT', 'NL', 'NO', 'PL', 'PT', 'RO',
|
|
8
|
+
'SK', 'SI', 'ES', 'SE', 'UK', 'GB', 'CH'
|
|
9
|
+
];
|
|
10
|
+
window.consent.consentMissing = true
|
|
11
|
+
window.consent.state = {
|
|
12
|
+
analytics_storage: null,
|
|
13
|
+
ad_storage: null,
|
|
14
|
+
ad_user_data: null,
|
|
15
|
+
ad_personalization: null
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
Object.keys(window.consent.state).forEach(k => {
|
|
19
|
+
try {
|
|
20
|
+
const v = localStorage.getItem('consent_' + k);
|
|
21
|
+
if (v === 'granted' || v === 'denied') {
|
|
22
|
+
window.consent.state[k] = v;
|
|
23
|
+
window.consent.consentMissing = false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
catch (e) {
|
|
27
|
+
window.consent.state[k] = null;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const country = document.cookie.split(/(?:^|;\s*)cc=/).pop().split(';')[0]
|
|
32
|
+
.trim().toUpperCase();
|
|
33
|
+
const countryDefault = !country || window.consent.countries.includes(country)
|
|
34
|
+
? 'denied' : 'granted';
|
|
35
|
+
|
|
36
|
+
gtag('consent', 'default', {
|
|
37
|
+
...Object.fromEntries(Object.entries(window.consent.state).map(([k, v]) =>
|
|
38
|
+
[k, v ?? countryDefault]))
|
|
39
|
+
});
|
package/src/consent.js
CHANGED
|
@@ -5,9 +5,9 @@ export const consent = (options) => {
|
|
|
5
5
|
ad_storage: 'Marketing'
|
|
6
6
|
},
|
|
7
7
|
actions: {
|
|
8
|
-
|
|
8
|
+
allowAll: 'Allow All',
|
|
9
9
|
allowSelected: 'Allow Selected',
|
|
10
|
-
|
|
10
|
+
denyAll: 'Deny All'
|
|
11
11
|
},
|
|
12
12
|
dialogMarkup: `
|
|
13
13
|
<h2 class="consent-title"></h2>
|
|
@@ -15,76 +15,18 @@ export const consent = (options) => {
|
|
|
15
15
|
<div class="consent-fields"></div>
|
|
16
16
|
<div class="consent-buttons"></div>
|
|
17
17
|
`,
|
|
18
|
-
dialogTitle: 'Cookies',
|
|
19
|
-
dialogMessage: 'We would like to get your permission to use cookies for:',
|
|
20
18
|
dialogClass: 'consent',
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
'DE', 'GR', 'HU', 'IE', 'IT', 'LV', 'LT', 'LU', 'MT', 'NL',
|
|
25
|
-
'PL', 'PT', 'RO', 'SK', 'SI', 'ES', 'SE', 'IS', 'LI', 'NO',
|
|
26
|
-
'GB', 'CH', 'MC', 'SM', 'VA', 'JE', 'GG', 'IM'],
|
|
19
|
+
dialogTitle: 'Cookie Consent',
|
|
20
|
+
dialogMessage: 'This website uses cookies for:',
|
|
21
|
+
settingsLinkSelector: '.consent-settings',
|
|
27
22
|
...options
|
|
28
23
|
};
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
ad_storage: 'denied',
|
|
32
|
-
analytics_storage: 'denied',
|
|
33
|
-
functionality_storage: 'denied',
|
|
34
|
-
personalization_storage: 'denied',
|
|
35
|
-
security_storage: 'denied'
|
|
36
|
-
};
|
|
24
|
+
|
|
25
|
+
function gtag() { dataLayer.push(arguments); }
|
|
37
26
|
|
|
38
27
|
let dialog = document.createElement('div');
|
|
39
28
|
dialog.classList.add(opts.dialogClass);
|
|
40
29
|
|
|
41
|
-
const detectCountry = () => {
|
|
42
|
-
const country = document.cookie.split('; ').find(r =>
|
|
43
|
-
r.startsWith(opts.countryCookie + '=')
|
|
44
|
-
)?.split('=')[1];
|
|
45
|
-
if (country ? opts.countries.includes(country) : true) {
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
Object.keys(opts.storages).forEach((storage) => {
|
|
49
|
-
consentState[storage] = 'granted';
|
|
50
|
-
});
|
|
51
|
-
updateConsent();
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
const getConsent = (storage) => {
|
|
55
|
-
return localStorage.getItem('consent_' + storage);
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
const updateConsent = () => {
|
|
59
|
-
Object.keys(opts.storages).forEach((storage) => {
|
|
60
|
-
localStorage.setItem('consent_' + storage, consentState[storage]);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
if (typeof gtag === 'function') {
|
|
64
|
-
gtag('consent', 'update', consentState);
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
const updateFields = () => {
|
|
69
|
-
Object.keys(opts.storages).forEach((storage) => {
|
|
70
|
-
dialog.querySelector('#consent-field-' + storage).checked =
|
|
71
|
-
consentState[storage] == 'granted' ? true : false;
|
|
72
|
-
});
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
const loadConsentState = () => {
|
|
76
|
-
Object.keys(opts.storages).forEach((storage) => {
|
|
77
|
-
consentState[storage] = getConsent(storage);
|
|
78
|
-
if (consentState[storage] === null) {
|
|
79
|
-
showDialog();
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
if (typeof gtag === 'function') {
|
|
84
|
-
gtag('consent', 'update', consentState);
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
|
|
88
30
|
const createDialog = () => {
|
|
89
31
|
dialog.innerHTML = opts.dialogMarkup;
|
|
90
32
|
dialog.querySelector('.consent-title').innerText = opts.dialogTitle;
|
|
@@ -96,7 +38,7 @@ export const consent = (options) => {
|
|
|
96
38
|
checkbox.setAttribute('type', 'checkbox');
|
|
97
39
|
checkbox.setAttribute('name', 'consent-field-' + storage);
|
|
98
40
|
checkbox.setAttribute('id', 'consent-field-' + storage);
|
|
99
|
-
if (
|
|
41
|
+
if (window.consent.state[storage] === 'granted') {
|
|
100
42
|
checkbox.setAttribute('checked', 'checked');
|
|
101
43
|
}
|
|
102
44
|
const label = document.createElement('label');
|
|
@@ -115,34 +57,31 @@ export const consent = (options) => {
|
|
|
115
57
|
switch (action) {
|
|
116
58
|
case 'denyAll':
|
|
117
59
|
button.onclick = () => {
|
|
118
|
-
Object.keys(opts.storages).forEach(
|
|
119
|
-
|
|
60
|
+
Object.keys(opts.storages).forEach(k => {
|
|
61
|
+
window.consent.state[k] = 'denied'
|
|
120
62
|
});
|
|
121
|
-
|
|
63
|
+
saveState();
|
|
122
64
|
updateFields();
|
|
123
65
|
hideDialog();
|
|
124
66
|
};
|
|
125
67
|
break;
|
|
126
68
|
case 'allowSelected':
|
|
127
69
|
button.onclick = () => {
|
|
128
|
-
Object.keys(opts.storages).forEach(
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
).checked
|
|
132
|
-
? 'granted'
|
|
133
|
-
: 'denied';
|
|
70
|
+
Object.keys(opts.storages).forEach(k => {
|
|
71
|
+
const el = document.querySelector('#consent-field-' + k);
|
|
72
|
+
window.consent.state[k] = el.checked ? 'granted' : 'denied';
|
|
134
73
|
});
|
|
135
|
-
|
|
74
|
+
saveState();
|
|
136
75
|
updateFields();
|
|
137
76
|
hideDialog();
|
|
138
77
|
};
|
|
139
78
|
break;
|
|
140
79
|
case 'allowAll':
|
|
141
80
|
button.onclick = () => {
|
|
142
|
-
Object.keys(opts.storages).forEach(
|
|
143
|
-
|
|
81
|
+
Object.keys(opts.storages).forEach(k => {
|
|
82
|
+
window.consent.state[k] = 'granted';
|
|
144
83
|
});
|
|
145
|
-
|
|
84
|
+
saveState();
|
|
146
85
|
updateFields();
|
|
147
86
|
hideDialog();
|
|
148
87
|
};
|
|
@@ -155,6 +94,26 @@ export const consent = (options) => {
|
|
|
155
94
|
document.querySelector('body').appendChild(dialog);
|
|
156
95
|
};
|
|
157
96
|
|
|
97
|
+
const saveState = () => {
|
|
98
|
+
Object.keys(window.consent.state).forEach(k => {
|
|
99
|
+
try {
|
|
100
|
+
localStorage.setItem('consent_' + k, window.consent.state[k]);
|
|
101
|
+
}
|
|
102
|
+
catch (e) {
|
|
103
|
+
console.log('Unable to save consent to local storage');
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
gtag('consent', 'update', window.consent.state);
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const updateFields = () => {
|
|
111
|
+
Object.keys(opts.storages).forEach(k => {
|
|
112
|
+
dialog.querySelector('#consent-field-' + k).checked =
|
|
113
|
+
window.consent.state[k] === 'granted' ? true : false;
|
|
114
|
+
});
|
|
115
|
+
};
|
|
116
|
+
|
|
158
117
|
const showDialog = () => {
|
|
159
118
|
dialog.style.display = 'block';
|
|
160
119
|
};
|
|
@@ -162,13 +121,18 @@ export const consent = (options) => {
|
|
|
162
121
|
const hideDialog = () => {
|
|
163
122
|
dialog.style.display = 'none';
|
|
164
123
|
};
|
|
165
|
-
|
|
124
|
+
|
|
166
125
|
document.querySelector(opts.settingsLinkSelector).onclick = (ev) => {
|
|
167
126
|
ev.preventDefault();
|
|
168
127
|
showDialog();
|
|
169
128
|
};
|
|
170
129
|
|
|
171
|
-
detectCountry();
|
|
172
|
-
loadConsentState();
|
|
173
130
|
createDialog();
|
|
131
|
+
|
|
132
|
+
if (window.consent.consentMissing) {
|
|
133
|
+
showDialog();
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
hideDialog();
|
|
137
|
+
}
|
|
174
138
|
};
|