@el7ven/cookie-kit 0.2.21 → 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 +1 -1
- package/src/core/analytics.js +101 -10
- package/src/core/index.js +7 -7
- package/src/index.js +1 -1
- package/src/js/CookieConsent.js +0 -1
- package/src/vue/CookieConsent.vue +1 -1
- package/src/vue/CookieDrawer.vue +4 -4
package/package.json
CHANGED
package/src/core/analytics.js
CHANGED
|
@@ -127,27 +127,115 @@ export function loadYandexMetrica(counterId) {
|
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
/**
|
|
130
|
-
* Block
|
|
131
|
-
*
|
|
132
|
-
*
|
|
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>
|
|
133
137
|
*/
|
|
134
|
-
export function
|
|
138
|
+
export function blockScriptsBeforeConsent() {
|
|
135
139
|
if (typeof document === 'undefined') return
|
|
136
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
|
|
137
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 => {
|
|
138
190
|
const category = script.getAttribute('data-cookie-category')
|
|
139
191
|
if (categories[category]) {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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) {
|
|
143
203
|
newScript.src = script.dataset.originalSrc
|
|
144
204
|
newScript.async = true
|
|
145
|
-
|
|
205
|
+
} else if (script.textContent) {
|
|
206
|
+
newScript.textContent = script.textContent
|
|
146
207
|
}
|
|
208
|
+
|
|
209
|
+
newScript.type = 'text/javascript'
|
|
210
|
+
script.parentNode.replaceChild(newScript, script)
|
|
147
211
|
}
|
|
148
212
|
})
|
|
149
213
|
}
|
|
150
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
|
+
|
|
151
239
|
/**
|
|
152
240
|
* Create analytics manager that auto-integrates with cookie consent
|
|
153
241
|
* @param {Object} config - { ga4: 'G-XXX', gtm: 'GTM-XXX', metaPixel: 'XXX', yandexMetrica: 'XXX' }
|
|
@@ -160,6 +248,9 @@ export function createAnalyticsManager(config = {}) {
|
|
|
160
248
|
if (initialized) return
|
|
161
249
|
initialized = true
|
|
162
250
|
|
|
251
|
+
// Block scripts before consent
|
|
252
|
+
blockScriptsBeforeConsent()
|
|
253
|
+
|
|
163
254
|
// Always init Google Consent Mode first (denied by default)
|
|
164
255
|
initGoogleConsentMode()
|
|
165
256
|
|
|
@@ -181,8 +272,8 @@ export function createAnalyticsManager(config = {}) {
|
|
|
181
272
|
if (config.metaPixel) loadMetaPixel(config.metaPixel)
|
|
182
273
|
}
|
|
183
274
|
|
|
184
|
-
//
|
|
185
|
-
|
|
275
|
+
// Unblock scripts for consented categories
|
|
276
|
+
unblockConsentedScripts(categories)
|
|
186
277
|
}
|
|
187
278
|
|
|
188
279
|
const connectToCookieConsent = () => {
|
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
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
export { createCookieKit, CookieKitCore, DEFAULT_CONFIG } from './core/index.js'
|
|
10
10
|
|
|
11
11
|
// Analytics integration
|
|
12
|
-
export { createAnalyticsManager, initGoogleConsentMode, updateGoogleConsent, loadGTM, loadGA4, loadMetaPixel, loadYandexMetrica, manageScriptBlocking } from './core/analytics.js'
|
|
12
|
+
export { createAnalyticsManager, initGoogleConsentMode, updateGoogleConsent, loadGTM, loadGA4, loadMetaPixel, loadYandexMetrica, blockScriptsBeforeConsent, unblockConsentedScripts, manageScriptBlocking } from './core/analytics.js'
|
|
13
13
|
|
|
14
14
|
// Import for default export
|
|
15
15
|
import { createCookieKit, CookieKitCore, DEFAULT_CONFIG } from './core/index.js'
|
package/src/js/CookieConsent.js
CHANGED
|
@@ -206,7 +206,7 @@ const handleSelectTab = (tabId) => {
|
|
|
206
206
|
|
|
207
207
|
const handleToggleCategory = (categoryId) => {
|
|
208
208
|
const cat = mergedConfig.value.categories[categoryId]
|
|
209
|
-
if (cat && !cat.
|
|
209
|
+
if (cat && !cat.disabled && !cat.required) {
|
|
210
210
|
categories.value[categoryId] = !categories.value[categoryId]
|
|
211
211
|
}
|
|
212
212
|
}
|
package/src/vue/CookieDrawer.vue
CHANGED
|
@@ -71,14 +71,14 @@
|
|
|
71
71
|
:id="`drawer-category-${category.id}`"
|
|
72
72
|
:checked="categories[category.id]"
|
|
73
73
|
@change="toggleCategory(category.id)"
|
|
74
|
-
:disabled="category.
|
|
74
|
+
:disabled="category.disabled"
|
|
75
75
|
class="cookie-drawer__toggle-input"
|
|
76
76
|
/>
|
|
77
77
|
<label
|
|
78
78
|
:for="`drawer-category-${category.id}`"
|
|
79
79
|
:class="[
|
|
80
80
|
'cookie-drawer__toggle-label',
|
|
81
|
-
{ 'cookie-drawer__toggle-label--disabled': category.
|
|
81
|
+
{ 'cookie-drawer__toggle-label--disabled': category.disabled }
|
|
82
82
|
]"
|
|
83
83
|
></label>
|
|
84
84
|
</div>
|
|
@@ -154,14 +154,14 @@
|
|
|
154
154
|
:id="`settings-category-${currentTab}`"
|
|
155
155
|
:checked="categories[currentTab]"
|
|
156
156
|
@change="toggleCategory(currentTab)"
|
|
157
|
-
:disabled="currentCategoryData.
|
|
157
|
+
:disabled="currentCategoryData.disabled"
|
|
158
158
|
class="cookie-drawer__toggle-input"
|
|
159
159
|
/>
|
|
160
160
|
<label
|
|
161
161
|
:for="`settings-category-${currentTab}`"
|
|
162
162
|
:class="[
|
|
163
163
|
'cookie-drawer__toggle-label',
|
|
164
|
-
{ 'cookie-drawer__toggle-label--disabled': currentCategoryData.
|
|
164
|
+
{ 'cookie-drawer__toggle-label--disabled': currentCategoryData.disabled }
|
|
165
165
|
]"
|
|
166
166
|
></label>
|
|
167
167
|
</div>
|