@el7ven/cookie-kit 0.2.20 → 0.3.1
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/package.json +4 -2
- package/src/core/analytics.js +311 -0
- package/src/core/index.js +7 -7
- package/src/index.js +5 -0
- package/src/js/CookieConsent.js +0 -1
- package/src/vue/CookieConsent.vue +165 -62
- package/src/vue/CookieConsentDebug.vue +168 -0
- package/src/vue/CookieDrawer.vue +274 -104
- package/src/vue/index.js +5 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@el7ven/cookie-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./src/index.js",
|
|
6
6
|
"module": "./src/index.js",
|
|
@@ -11,8 +11,10 @@
|
|
|
11
11
|
"./dist/styles": "./dist/styles/index.css",
|
|
12
12
|
"./react": "./src/react/index.js",
|
|
13
13
|
"./vue": "./src/vue/index.js",
|
|
14
|
-
"./
|
|
14
|
+
"./analytics": "./src/core/analytics.js",
|
|
15
|
+
"./config": "./src/core/index.js",
|
|
15
16
|
"./composables/useCookieConsent": "./src/vue/composables/useCookieConsent.js",
|
|
17
|
+
"./src/composables/useCookieConsent": "./src/vue/composables/useCookieConsent.js",
|
|
16
18
|
"./package.json": "./package.json"
|
|
17
19
|
},
|
|
18
20
|
"files": [
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @el7ven/cookie-kit - Analytics Integration Module
|
|
3
|
+
* Google Consent Mode v2, GTM, GA4, Meta Pixel, Yandex Metrica
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Initialize Google Consent Mode v2 with default denied state
|
|
8
|
+
*/
|
|
9
|
+
export function initGoogleConsentMode() {
|
|
10
|
+
if (typeof window === 'undefined') return
|
|
11
|
+
|
|
12
|
+
window.dataLayer = window.dataLayer || []
|
|
13
|
+
window.gtag = window.gtag || function gtag() { window.dataLayer.push(arguments) }
|
|
14
|
+
|
|
15
|
+
// Set default consent state - all denied until user consents
|
|
16
|
+
window.gtag('consent', 'default', {
|
|
17
|
+
ad_storage: 'denied',
|
|
18
|
+
ad_user_data: 'denied',
|
|
19
|
+
ad_personalization: 'denied',
|
|
20
|
+
analytics_storage: 'denied',
|
|
21
|
+
functionality_storage: 'denied',
|
|
22
|
+
personalization_storage: 'denied',
|
|
23
|
+
security_storage: 'granted' // Always granted for security
|
|
24
|
+
})
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Update Google Consent Mode based on cookie consent categories
|
|
29
|
+
* @param {Object} categories - { analytics: true, marketing: false, preferences: true }
|
|
30
|
+
*/
|
|
31
|
+
export function updateGoogleConsent(categories = {}) {
|
|
32
|
+
if (typeof window === 'undefined' || !window.gtag) return
|
|
33
|
+
|
|
34
|
+
const consentUpdate = {
|
|
35
|
+
analytics_storage: categories.analytics ? 'granted' : 'denied',
|
|
36
|
+
ad_storage: categories.marketing ? 'granted' : 'denied',
|
|
37
|
+
ad_user_data: categories.marketing ? 'granted' : 'denied',
|
|
38
|
+
ad_personalization: categories.marketing ? 'granted' : 'denied',
|
|
39
|
+
functionality_storage: categories.preferences ? 'granted' : 'denied',
|
|
40
|
+
personalization_storage: categories.preferences ? 'granted' : 'denied',
|
|
41
|
+
security_storage: 'granted'
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
window.gtag('consent', 'update', consentUpdate)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Load Google Tag Manager
|
|
49
|
+
* @param {string} gtmId - GTM container ID (e.g., 'GTM-XXXXX')
|
|
50
|
+
*/
|
|
51
|
+
export function loadGTM(gtmId) {
|
|
52
|
+
if (!gtmId || typeof document === 'undefined') return
|
|
53
|
+
|
|
54
|
+
const script = document.createElement('script')
|
|
55
|
+
script.async = true
|
|
56
|
+
script.src = `https://www.googletagmanager.com/gtm.js?id=${gtmId}`
|
|
57
|
+
document.head.appendChild(script)
|
|
58
|
+
|
|
59
|
+
window.dataLayer = window.dataLayer || []
|
|
60
|
+
window.dataLayer.push({
|
|
61
|
+
'gtm.start': new Date().getTime(),
|
|
62
|
+
event: 'gtm.js'
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Load Google Analytics 4
|
|
68
|
+
* @param {string} ga4Id - GA4 measurement ID (e.g., 'G-XXXXX')
|
|
69
|
+
*/
|
|
70
|
+
export function loadGA4(ga4Id) {
|
|
71
|
+
if (!ga4Id || typeof document === 'undefined') return
|
|
72
|
+
|
|
73
|
+
const script = document.createElement('script')
|
|
74
|
+
script.async = true
|
|
75
|
+
script.src = `https://www.googletagmanager.com/gtag/js?id=${ga4Id}`
|
|
76
|
+
document.head.appendChild(script)
|
|
77
|
+
|
|
78
|
+
window.dataLayer = window.dataLayer || []
|
|
79
|
+
window.gtag = window.gtag || function gtag() { window.dataLayer.push(arguments) }
|
|
80
|
+
window.gtag('js', new Date())
|
|
81
|
+
window.gtag('config', ga4Id)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Load Meta (Facebook) Pixel
|
|
86
|
+
* @param {string} pixelId - Meta Pixel ID
|
|
87
|
+
*/
|
|
88
|
+
export function loadMetaPixel(pixelId) {
|
|
89
|
+
if (!pixelId || typeof window === 'undefined') return
|
|
90
|
+
|
|
91
|
+
/* eslint-disable */
|
|
92
|
+
!function(f,b,e,v,n,t,s)
|
|
93
|
+
{if(f.fbq)return;n=f.fbq=function(){n.callMethod?
|
|
94
|
+
n.callMethod.apply(n,arguments):n.queue.push(arguments)};
|
|
95
|
+
if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
|
|
96
|
+
n.queue=[];t=b.createElement(e);t.async=!0;
|
|
97
|
+
t.src=v;s=b.getElementsByTagName(e)[0];
|
|
98
|
+
s.parentNode.insertBefore(t,s)}(window, document,'script',
|
|
99
|
+
'https://connect.facebook.net/en_US/fbevents.js');
|
|
100
|
+
/* eslint-enable */
|
|
101
|
+
|
|
102
|
+
window.fbq('init', pixelId)
|
|
103
|
+
window.fbq('track', 'PageView')
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Load Yandex Metrica
|
|
108
|
+
* @param {string} counterId - Yandex Metrica counter ID
|
|
109
|
+
*/
|
|
110
|
+
export function loadYandexMetrica(counterId) {
|
|
111
|
+
if (!counterId || typeof document === 'undefined') return
|
|
112
|
+
|
|
113
|
+
/* eslint-disable */
|
|
114
|
+
(function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
|
|
115
|
+
m[i].l=1*new Date();
|
|
116
|
+
for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }}
|
|
117
|
+
k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})
|
|
118
|
+
(window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym");
|
|
119
|
+
/* eslint-enable */
|
|
120
|
+
|
|
121
|
+
window.ym(counterId, 'init', {
|
|
122
|
+
clickmap: true,
|
|
123
|
+
trackLinks: true,
|
|
124
|
+
accurateTrackBounce: true,
|
|
125
|
+
webvisor: true
|
|
126
|
+
})
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Block all scripts with data-cookie-category BEFORE consent.
|
|
131
|
+
* Call this as early as possible (before DOMContentLoaded).
|
|
132
|
+
* Rewrites script type to text/plain so they don't execute.
|
|
133
|
+
*
|
|
134
|
+
* Usage in HTML:
|
|
135
|
+
* <script data-cookie-category="analytics" src="..."></script>
|
|
136
|
+
* <script data-cookie-category="marketing">inline code</script>
|
|
137
|
+
*/
|
|
138
|
+
export function blockScriptsBeforeConsent() {
|
|
139
|
+
if (typeof document === 'undefined') return
|
|
140
|
+
|
|
141
|
+
// MutationObserver to catch dynamically added scripts
|
|
142
|
+
const observer = new MutationObserver((mutations) => {
|
|
143
|
+
for (const mutation of mutations) {
|
|
144
|
+
for (const node of mutation.addedNodes) {
|
|
145
|
+
if (node.tagName === 'SCRIPT' && node.getAttribute('data-cookie-category')) {
|
|
146
|
+
const category = node.getAttribute('data-cookie-category')
|
|
147
|
+
// Check if consent already given for this category
|
|
148
|
+
if (!_hasConsentFor(category)) {
|
|
149
|
+
node.type = 'text/plain'
|
|
150
|
+
if (node.src) {
|
|
151
|
+
node.dataset.originalSrc = node.src
|
|
152
|
+
node.removeAttribute('src')
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
observer.observe(document.documentElement, { childList: true, subtree: true })
|
|
161
|
+
|
|
162
|
+
// Also block any scripts already in the DOM
|
|
163
|
+
document.querySelectorAll('script[data-cookie-category]').forEach(script => {
|
|
164
|
+
const category = script.getAttribute('data-cookie-category')
|
|
165
|
+
if (!_hasConsentFor(category)) {
|
|
166
|
+
if (!script.dataset.blocked) {
|
|
167
|
+
script.dataset.blocked = 'true'
|
|
168
|
+
// Already executed scripts can't be un-executed,
|
|
169
|
+
// but we mark them so future loads respect consent
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
// Store observer reference for cleanup
|
|
175
|
+
if (typeof window !== 'undefined') {
|
|
176
|
+
window.__cookieKitScriptObserver = observer
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return observer
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Unblock and execute scripts for consented categories.
|
|
184
|
+
* @param {Object} categories - { analytics: true, marketing: false }
|
|
185
|
+
*/
|
|
186
|
+
export function unblockConsentedScripts(categories = {}) {
|
|
187
|
+
if (typeof document === 'undefined') return
|
|
188
|
+
|
|
189
|
+
document.querySelectorAll('script[data-cookie-category][type="text/plain"]').forEach(script => {
|
|
190
|
+
const category = script.getAttribute('data-cookie-category')
|
|
191
|
+
if (categories[category]) {
|
|
192
|
+
const newScript = document.createElement('script')
|
|
193
|
+
|
|
194
|
+
// Copy attributes
|
|
195
|
+
for (const attr of script.attributes) {
|
|
196
|
+
if (attr.name !== 'type' && attr.name !== 'data-original-src') {
|
|
197
|
+
newScript.setAttribute(attr.name, attr.value)
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Restore src or inline content
|
|
202
|
+
if (script.dataset.originalSrc) {
|
|
203
|
+
newScript.src = script.dataset.originalSrc
|
|
204
|
+
newScript.async = true
|
|
205
|
+
} else if (script.textContent) {
|
|
206
|
+
newScript.textContent = script.textContent
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
newScript.type = 'text/javascript'
|
|
210
|
+
script.parentNode.replaceChild(newScript, script)
|
|
211
|
+
}
|
|
212
|
+
})
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Check localStorage for existing consent for a category
|
|
217
|
+
* @private
|
|
218
|
+
*/
|
|
219
|
+
function _hasConsentFor(category) {
|
|
220
|
+
if (typeof localStorage === 'undefined') return false
|
|
221
|
+
try {
|
|
222
|
+
const stored = localStorage.getItem('cookie_consent')
|
|
223
|
+
if (!stored) return false
|
|
224
|
+
const consent = JSON.parse(stored)
|
|
225
|
+
return consent?.categories?.[category] === true
|
|
226
|
+
} catch {
|
|
227
|
+
return false
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Legacy alias
|
|
233
|
+
* @param {Object} categories - { analytics: true, marketing: false }
|
|
234
|
+
*/
|
|
235
|
+
export function manageScriptBlocking(categories = {}) {
|
|
236
|
+
unblockConsentedScripts(categories)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Create analytics manager that auto-integrates with cookie consent
|
|
241
|
+
* @param {Object} config - { ga4: 'G-XXX', gtm: 'GTM-XXX', metaPixel: 'XXX', yandexMetrica: 'XXX' }
|
|
242
|
+
* @returns {Object} Analytics manager instance
|
|
243
|
+
*/
|
|
244
|
+
export function createAnalyticsManager(config = {}) {
|
|
245
|
+
let initialized = false
|
|
246
|
+
|
|
247
|
+
const init = () => {
|
|
248
|
+
if (initialized) return
|
|
249
|
+
initialized = true
|
|
250
|
+
|
|
251
|
+
// Block scripts before consent
|
|
252
|
+
blockScriptsBeforeConsent()
|
|
253
|
+
|
|
254
|
+
// Always init Google Consent Mode first (denied by default)
|
|
255
|
+
initGoogleConsentMode()
|
|
256
|
+
|
|
257
|
+
// Load GTM if configured (it respects consent mode)
|
|
258
|
+
if (config.gtm) loadGTM(config.gtm)
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const onConsentUpdate = (categories = {}) => {
|
|
262
|
+
// Update Google Consent Mode
|
|
263
|
+
updateGoogleConsent(categories)
|
|
264
|
+
|
|
265
|
+
// Load analytics scripts based on consent
|
|
266
|
+
if (categories.analytics) {
|
|
267
|
+
if (config.ga4) loadGA4(config.ga4)
|
|
268
|
+
if (config.yandexMetrica) loadYandexMetrica(config.yandexMetrica)
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (categories.marketing) {
|
|
272
|
+
if (config.metaPixel) loadMetaPixel(config.metaPixel)
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Unblock scripts for consented categories
|
|
276
|
+
unblockConsentedScripts(categories)
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const connectToCookieConsent = () => {
|
|
280
|
+
if (typeof window === 'undefined') return
|
|
281
|
+
|
|
282
|
+
// Wait for CookieConsent to be available
|
|
283
|
+
const checkInterval = setInterval(() => {
|
|
284
|
+
if (window.CookieConsent) {
|
|
285
|
+
clearInterval(checkInterval)
|
|
286
|
+
|
|
287
|
+
// Check if consent already given
|
|
288
|
+
const currentConsent = window.CookieConsent.getConsent()
|
|
289
|
+
if (currentConsent?.categories) {
|
|
290
|
+
onConsentUpdate(currentConsent.categories)
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Listen for future changes
|
|
294
|
+
window.CookieConsent.on('consentChanged', ({ consent }) => {
|
|
295
|
+
if (consent?.categories) {
|
|
296
|
+
onConsentUpdate(consent.categories)
|
|
297
|
+
}
|
|
298
|
+
})
|
|
299
|
+
}
|
|
300
|
+
}, 100)
|
|
301
|
+
|
|
302
|
+
// Stop checking after 10 seconds
|
|
303
|
+
setTimeout(() => clearInterval(checkInterval), 10000)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
return {
|
|
307
|
+
init,
|
|
308
|
+
onConsentUpdate,
|
|
309
|
+
connectToCookieConsent
|
|
310
|
+
}
|
|
311
|
+
}
|
package/src/core/index.js
CHANGED
|
@@ -32,7 +32,7 @@ const DEFAULT_CONFIG = {
|
|
|
32
32
|
label: 'Necesare',
|
|
33
33
|
description: 'Cookie-uri esențiale pentru funcționarea site-ului',
|
|
34
34
|
required: true,
|
|
35
|
-
|
|
35
|
+
disabled: true,
|
|
36
36
|
enabled: true
|
|
37
37
|
},
|
|
38
38
|
analytics: {
|
|
@@ -40,24 +40,24 @@ const DEFAULT_CONFIG = {
|
|
|
40
40
|
label: 'Analiză',
|
|
41
41
|
description: 'Cookie-uri pentru analiza traficului și comportamentului utilizatorilor',
|
|
42
42
|
required: false,
|
|
43
|
-
|
|
44
|
-
enabled:
|
|
43
|
+
disabled: false,
|
|
44
|
+
enabled: false
|
|
45
45
|
},
|
|
46
46
|
marketing: {
|
|
47
47
|
id: 'marketing',
|
|
48
48
|
label: 'Marketing',
|
|
49
49
|
description: 'Cookie-uri pentru publicitate personalizată',
|
|
50
50
|
required: false,
|
|
51
|
-
|
|
52
|
-
enabled:
|
|
51
|
+
disabled: false,
|
|
52
|
+
enabled: false
|
|
53
53
|
},
|
|
54
54
|
preferences: {
|
|
55
55
|
id: 'preferences',
|
|
56
56
|
label: 'Preferințe',
|
|
57
57
|
description: 'Cookie-uri pentru salvarea preferințelor utilizatorului',
|
|
58
58
|
required: false,
|
|
59
|
-
|
|
60
|
-
enabled:
|
|
59
|
+
disabled: false,
|
|
60
|
+
enabled: false
|
|
61
61
|
}
|
|
62
62
|
},
|
|
63
63
|
|
package/src/index.js
CHANGED
|
@@ -8,8 +8,12 @@
|
|
|
8
8
|
// Core functionality
|
|
9
9
|
export { createCookieKit, CookieKitCore, DEFAULT_CONFIG } from './core/index.js'
|
|
10
10
|
|
|
11
|
+
// Analytics integration
|
|
12
|
+
export { createAnalyticsManager, initGoogleConsentMode, updateGoogleConsent, loadGTM, loadGA4, loadMetaPixel, loadYandexMetrica, blockScriptsBeforeConsent, unblockConsentedScripts, manageScriptBlocking } from './core/analytics.js'
|
|
13
|
+
|
|
11
14
|
// Import for default export
|
|
12
15
|
import { createCookieKit, CookieKitCore, DEFAULT_CONFIG } from './core/index.js'
|
|
16
|
+
import { createAnalyticsManager } from './core/analytics.js'
|
|
13
17
|
import { initCookieKit } from './js/index.js'
|
|
14
18
|
import { VERSION } from './core/version.js'
|
|
15
19
|
|
|
@@ -62,6 +66,7 @@ export function autoCookieConsent(config = {}) {
|
|
|
62
66
|
export default {
|
|
63
67
|
createCookieKit,
|
|
64
68
|
createCookieConsent,
|
|
69
|
+
createAnalyticsManager,
|
|
65
70
|
autoCookieConsent,
|
|
66
71
|
initCookieKit,
|
|
67
72
|
CookieKitCore,
|
package/src/js/CookieConsent.js
CHANGED