cookiecraft 1.0.6 → 1.0.8
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/README.md +171 -304
- package/dist/cookiecraft.css +1 -1
- package/dist/cookiecraft.esm.js +224 -137
- package/dist/cookiecraft.esm.js.map +1 -1
- package/dist/cookiecraft.js +224 -137
- package/dist/cookiecraft.js.map +1 -1
- package/dist/cookiecraft.min.js +1 -1
- package/dist/cookiecraft.min.js.map +1 -1
- package/dist/stats.html +1 -1
- package/dist/types/blocking/CategoryManager.d.ts +1 -0
- package/dist/types/core/ConsentManager.d.ts +1 -1
- package/dist/types/core/CookieConsent.d.ts +5 -4
- package/dist/types/core/EventEmitter.d.ts +3 -2
- package/dist/types/integrations/GTMConsentMode.d.ts +0 -6
- package/dist/types/types/index.d.ts +3 -7
- package/dist/types/ui/Banner.d.ts +6 -0
- package/dist/types/ui/PreferenceCenter.d.ts +1 -0
- package/package.json +1 -1
package/dist/cookiecraft.esm.js
CHANGED
|
@@ -43,13 +43,20 @@ class StorageManager {
|
|
|
43
43
|
* Clear consent record from localStorage
|
|
44
44
|
*/
|
|
45
45
|
clear() {
|
|
46
|
-
|
|
46
|
+
try {
|
|
47
|
+
localStorage.removeItem(StorageManager.STORAGE_KEY);
|
|
48
|
+
}
|
|
49
|
+
catch (e) {
|
|
50
|
+
console.error('Failed to clear consent:', e);
|
|
51
|
+
}
|
|
47
52
|
}
|
|
48
53
|
/**
|
|
49
54
|
* Check if consent record has expired
|
|
50
55
|
*/
|
|
51
56
|
isExpired(consent) {
|
|
52
57
|
const expiry = new Date(consent.expiresAt);
|
|
58
|
+
if (isNaN(expiry.getTime()))
|
|
59
|
+
return true;
|
|
53
60
|
return expiry < new Date();
|
|
54
61
|
}
|
|
55
62
|
/**
|
|
@@ -60,7 +67,6 @@ class StorageManager {
|
|
|
60
67
|
typeof data.version === 'number' &&
|
|
61
68
|
typeof data.timestamp === 'string' &&
|
|
62
69
|
typeof data.categories === 'object' &&
|
|
63
|
-
typeof data.userAgent === 'string' &&
|
|
64
70
|
typeof data.expiresAt === 'string');
|
|
65
71
|
}
|
|
66
72
|
/**
|
|
@@ -76,11 +82,20 @@ class StorageManager {
|
|
|
76
82
|
const now = new Date();
|
|
77
83
|
const expiryDate = new Date(now);
|
|
78
84
|
expiryDate.setMonth(expiryDate.getMonth() + StorageManager.EXPIRY_MONTHS);
|
|
85
|
+
// Coerce category values to booleans
|
|
86
|
+
const rawCategories = record.categories;
|
|
87
|
+
const categories = {
|
|
88
|
+
necessary: rawCategories.necessary === true,
|
|
89
|
+
analytics: rawCategories.analytics === true,
|
|
90
|
+
marketing: rawCategories.marketing === true,
|
|
91
|
+
};
|
|
92
|
+
if ('preferences' in rawCategories) {
|
|
93
|
+
categories.preferences = rawCategories.preferences === true;
|
|
94
|
+
}
|
|
79
95
|
return {
|
|
80
96
|
version: typeof record.version === 'number' ? record.version : 1,
|
|
81
97
|
timestamp: typeof record.timestamp === 'string' ? record.timestamp : now.toISOString(),
|
|
82
|
-
categories
|
|
83
|
-
userAgent: typeof record.userAgent === 'string' ? record.userAgent : navigator.userAgent,
|
|
98
|
+
categories,
|
|
84
99
|
expiresAt: typeof record.expiresAt === 'string' ? record.expiresAt : expiryDate.toISOString(),
|
|
85
100
|
};
|
|
86
101
|
}
|
|
@@ -95,6 +110,7 @@ StorageManager.EXPIRY_MONTHS = 13;
|
|
|
95
110
|
*/
|
|
96
111
|
class ConsentManager {
|
|
97
112
|
constructor(config) {
|
|
113
|
+
this.consent = null;
|
|
98
114
|
this.config = config;
|
|
99
115
|
}
|
|
100
116
|
/**
|
|
@@ -113,6 +129,10 @@ class ConsentManager {
|
|
|
113
129
|
}
|
|
114
130
|
}
|
|
115
131
|
}
|
|
132
|
+
// Coerce all values to booleans
|
|
133
|
+
for (const key of Object.keys(categories)) {
|
|
134
|
+
categories[key] = categories[key] === true;
|
|
135
|
+
}
|
|
116
136
|
return true;
|
|
117
137
|
}
|
|
118
138
|
/**
|
|
@@ -129,13 +149,12 @@ class ConsentManager {
|
|
|
129
149
|
* Check if user needs to give consent
|
|
130
150
|
*/
|
|
131
151
|
needsConsent() {
|
|
132
|
-
return this.consent ===
|
|
152
|
+
return this.consent === null;
|
|
133
153
|
}
|
|
134
154
|
/**
|
|
135
155
|
* Check if stored consent needs update due to policy change
|
|
136
156
|
*/
|
|
137
157
|
needsUpdate(storedConsent) {
|
|
138
|
-
// Check if policy version has changed
|
|
139
158
|
return storedConsent.version < this.config.revision;
|
|
140
159
|
}
|
|
141
160
|
/**
|
|
@@ -155,7 +174,6 @@ class ConsentManager {
|
|
|
155
174
|
version: this.config.revision,
|
|
156
175
|
timestamp: now.toISOString(),
|
|
157
176
|
categories: Object.assign({}, categories),
|
|
158
|
-
userAgent: navigator.userAgent,
|
|
159
177
|
expiresAt: expiryDate.toISOString(),
|
|
160
178
|
};
|
|
161
179
|
}
|
|
@@ -396,7 +414,6 @@ class ScriptBlocker {
|
|
|
396
414
|
class CategoryManager {
|
|
397
415
|
constructor() {
|
|
398
416
|
this.categories = new Map();
|
|
399
|
-
// Initialize with common patterns
|
|
400
417
|
this.initializeDefaultPatterns();
|
|
401
418
|
}
|
|
402
419
|
/**
|
|
@@ -433,11 +450,11 @@ class CategoryManager {
|
|
|
433
450
|
}
|
|
434
451
|
/**
|
|
435
452
|
* Initialize default URL patterns for common tracking services
|
|
453
|
+
* Note: GTM is NOT auto-categorized — it should be managed via GTM Consent Mode v2
|
|
436
454
|
*/
|
|
437
455
|
initializeDefaultPatterns() {
|
|
438
456
|
this.categories.set('analytics', [
|
|
439
457
|
'google-analytics.com',
|
|
440
|
-
'googletagmanager.com',
|
|
441
458
|
'analytics.google.com',
|
|
442
459
|
'plausible.io',
|
|
443
460
|
'matomo.org',
|
|
@@ -447,6 +464,7 @@ class CategoryManager {
|
|
|
447
464
|
'amplitude.com',
|
|
448
465
|
]);
|
|
449
466
|
this.categories.set('marketing', [
|
|
467
|
+
'googletagmanager.com',
|
|
450
468
|
'facebook.net',
|
|
451
469
|
'facebook.com/tr',
|
|
452
470
|
'connect.facebook.net',
|
|
@@ -458,6 +476,7 @@ class CategoryManager {
|
|
|
458
476
|
'adroll.com',
|
|
459
477
|
'taboola.com',
|
|
460
478
|
'outbrain.com',
|
|
479
|
+
'tiktok.com',
|
|
461
480
|
]);
|
|
462
481
|
this.categories.set('necessary', []);
|
|
463
482
|
}
|
|
@@ -508,18 +527,47 @@ function sanitizeColor(color) {
|
|
|
508
527
|
// Allow hsl/hsla
|
|
509
528
|
if (/^hsla?\(\s*[\d\s,./%deg]+\)$/.test(trimmed))
|
|
510
529
|
return trimmed;
|
|
511
|
-
// Allow CSS named colors (basic set)
|
|
512
|
-
|
|
530
|
+
// Allow CSS named colors (basic set) but block CSS keywords that could be abused
|
|
531
|
+
const CSS_KEYWORDS = ['inherit', 'initial', 'unset', 'revert', 'revert-layer'];
|
|
532
|
+
if (/^[a-zA-Z]+$/.test(trimmed) && !CSS_KEYWORDS.includes(trimmed.toLowerCase())) {
|
|
513
533
|
return trimmed;
|
|
534
|
+
}
|
|
514
535
|
return '';
|
|
515
536
|
}
|
|
516
537
|
|
|
538
|
+
/**
|
|
539
|
+
* Normalize any supported color format to 6-digit hex
|
|
540
|
+
* Supports: #RGB, #RRGGBB, #RRGGBBAA, named colors
|
|
541
|
+
* Returns null if conversion fails
|
|
542
|
+
*/
|
|
543
|
+
function normalizeToHex6(color) {
|
|
544
|
+
const trimmed = color.trim();
|
|
545
|
+
// Already 6-digit hex
|
|
546
|
+
if (/^#[0-9a-fA-F]{6}$/.test(trimmed)) {
|
|
547
|
+
return trimmed;
|
|
548
|
+
}
|
|
549
|
+
// 3-digit hex → expand to 6-digit
|
|
550
|
+
if (/^#[0-9a-fA-F]{3}$/.test(trimmed)) {
|
|
551
|
+
const r = trimmed[1];
|
|
552
|
+
const g = trimmed[2];
|
|
553
|
+
const b = trimmed[3];
|
|
554
|
+
return `#${r}${r}${g}${g}${b}${b}`;
|
|
555
|
+
}
|
|
556
|
+
// 8-digit hex (with alpha) → strip alpha
|
|
557
|
+
if (/^#[0-9a-fA-F]{8}$/.test(trimmed)) {
|
|
558
|
+
return trimmed.substring(0, 7);
|
|
559
|
+
}
|
|
560
|
+
return null;
|
|
561
|
+
}
|
|
517
562
|
/**
|
|
518
563
|
* Adjust a hex color brightness by a percentage
|
|
519
564
|
* Negative = darker, positive = lighter
|
|
520
565
|
*/
|
|
521
566
|
function adjustColorBrightness(color, percent) {
|
|
522
|
-
const
|
|
567
|
+
const hex6 = normalizeToHex6(color);
|
|
568
|
+
if (!hex6)
|
|
569
|
+
return color;
|
|
570
|
+
const hex = hex6.replace('#', '');
|
|
523
571
|
const r = parseInt(hex.substring(0, 2), 16);
|
|
524
572
|
const g = parseInt(hex.substring(2, 4), 16);
|
|
525
573
|
const b = parseInt(hex.substring(4, 6), 16);
|
|
@@ -539,8 +587,13 @@ function adjustColorBrightness(color, percent) {
|
|
|
539
587
|
function buildColorStyle(safeColor) {
|
|
540
588
|
if (!safeColor)
|
|
541
589
|
return '';
|
|
542
|
-
|
|
543
|
-
|
|
590
|
+
// Only generate hover color for hex colors
|
|
591
|
+
const hex6 = normalizeToHex6(safeColor);
|
|
592
|
+
if (!hex6) {
|
|
593
|
+
return `--cc-primary: ${safeColor};`;
|
|
594
|
+
}
|
|
595
|
+
const hover = adjustColorBrightness(hex6, -15);
|
|
596
|
+
return `--cc-primary: ${hex6}; --cc-primary-hover: ${hover};`;
|
|
544
597
|
}
|
|
545
598
|
|
|
546
599
|
/**
|
|
@@ -549,6 +602,8 @@ function buildColorStyle(safeColor) {
|
|
|
549
602
|
class Banner {
|
|
550
603
|
constructor(config, eventEmitter) {
|
|
551
604
|
this.element = null;
|
|
605
|
+
this.hideTimeout = null;
|
|
606
|
+
this.previousActiveElement = null;
|
|
552
607
|
this.config = config;
|
|
553
608
|
this.eventEmitter = eventEmitter;
|
|
554
609
|
}
|
|
@@ -556,8 +611,14 @@ class Banner {
|
|
|
556
611
|
* Show the banner
|
|
557
612
|
*/
|
|
558
613
|
show() {
|
|
614
|
+
// Clear any pending hide timeout
|
|
615
|
+
if (this.hideTimeout) {
|
|
616
|
+
clearTimeout(this.hideTimeout);
|
|
617
|
+
this.hideTimeout = null;
|
|
618
|
+
}
|
|
559
619
|
const append = () => {
|
|
560
620
|
if (!this.element) {
|
|
621
|
+
this.previousActiveElement = document.activeElement;
|
|
561
622
|
this.element = this.createDOM();
|
|
562
623
|
document.body.appendChild(this.element);
|
|
563
624
|
this.attachListeners();
|
|
@@ -570,9 +631,9 @@ class Banner {
|
|
|
570
631
|
// Disable page interaction if configured
|
|
571
632
|
if (this.config.disablePageInteraction) {
|
|
572
633
|
document.body.style.overflow = 'hidden';
|
|
634
|
+
this.trapFocus();
|
|
573
635
|
}
|
|
574
636
|
};
|
|
575
|
-
// Wait for body if not yet available
|
|
576
637
|
if (!document.body) {
|
|
577
638
|
document.addEventListener('DOMContentLoaded', append);
|
|
578
639
|
return;
|
|
@@ -585,22 +646,30 @@ class Banner {
|
|
|
585
646
|
hide() {
|
|
586
647
|
var _a;
|
|
587
648
|
(_a = this.element) === null || _a === void 0 ? void 0 : _a.classList.remove('is-visible');
|
|
588
|
-
// Re-enable page interaction
|
|
589
649
|
if (this.config.disablePageInteraction) {
|
|
590
650
|
document.body.style.overflow = '';
|
|
591
651
|
}
|
|
592
|
-
setTimeout(() => {
|
|
652
|
+
this.hideTimeout = setTimeout(() => {
|
|
593
653
|
this.destroy();
|
|
594
|
-
}, 300);
|
|
654
|
+
}, 300);
|
|
595
655
|
}
|
|
596
656
|
/**
|
|
597
657
|
* Destroy the banner
|
|
598
658
|
*/
|
|
599
659
|
destroy() {
|
|
660
|
+
if (this.hideTimeout) {
|
|
661
|
+
clearTimeout(this.hideTimeout);
|
|
662
|
+
this.hideTimeout = null;
|
|
663
|
+
}
|
|
600
664
|
if (this.element) {
|
|
601
665
|
this.element.remove();
|
|
602
666
|
this.element = null;
|
|
603
667
|
}
|
|
668
|
+
// Restore focus
|
|
669
|
+
if (this.previousActiveElement && document.contains(this.previousActiveElement)) {
|
|
670
|
+
this.previousActiveElement.focus();
|
|
671
|
+
this.previousActiveElement = null;
|
|
672
|
+
}
|
|
604
673
|
}
|
|
605
674
|
/**
|
|
606
675
|
* Create DOM structure for banner
|
|
@@ -611,12 +680,14 @@ class Banner {
|
|
|
611
680
|
const position = this.config.position || 'bottom';
|
|
612
681
|
const layout = this.config.layout || 'bar';
|
|
613
682
|
const backdropBlur = this.config.backdropBlur !== false;
|
|
683
|
+
const isModal = this.config.disablePageInteraction;
|
|
614
684
|
const safeColor = this.config.primaryColor ? sanitizeColor(this.config.primaryColor) : '';
|
|
615
685
|
const colorStyle = buildColorStyle(safeColor);
|
|
616
686
|
const template = `
|
|
617
687
|
<div
|
|
618
688
|
class="cc-banner cc-banner--${escapeHtml(position)} cc-banner--${escapeHtml(layout)} ${backdropBlur ? 'cc-backdrop-blur' : ''}"
|
|
619
|
-
role="region"
|
|
689
|
+
role="${isModal ? 'dialog' : 'region'}"
|
|
690
|
+
${isModal ? 'aria-modal="true"' : ''}
|
|
620
691
|
aria-label="Cookie consent"
|
|
621
692
|
aria-live="polite"
|
|
622
693
|
data-theme="${escapeHtml(theme)}"
|
|
@@ -625,7 +696,7 @@ class Banner {
|
|
|
625
696
|
<div class="cc-banner__container">
|
|
626
697
|
<div class="cc-banner__content">
|
|
627
698
|
<h2 class="cc-banner__title">
|
|
628
|
-
${escapeHtml(translations.title || '
|
|
699
|
+
${escapeHtml(translations.title || 'We use cookies')}
|
|
629
700
|
</h2>
|
|
630
701
|
<p class="cc-banner__description">
|
|
631
702
|
${this.getDescriptionHTML()}
|
|
@@ -635,23 +706,23 @@ class Banner {
|
|
|
635
706
|
<button
|
|
636
707
|
class="cc-btn cc-btn--ghost"
|
|
637
708
|
data-action="reject"
|
|
638
|
-
aria-label="${escapeHtml(translations.rejectAll || '
|
|
709
|
+
aria-label="${escapeHtml(translations.rejectAll || 'Essentials only')}"
|
|
639
710
|
>
|
|
640
|
-
${escapeHtml(translations.rejectAll || '
|
|
711
|
+
${escapeHtml(translations.rejectAll || 'Essentials only')}
|
|
641
712
|
</button>
|
|
642
713
|
<button
|
|
643
714
|
class="cc-btn cc-btn--tertiary"
|
|
644
715
|
data-action="customize"
|
|
645
|
-
aria-label="${escapeHtml(translations.customize || '
|
|
716
|
+
aria-label="${escapeHtml(translations.customize || 'Customize')}"
|
|
646
717
|
>
|
|
647
|
-
${escapeHtml(translations.customize || '
|
|
718
|
+
${escapeHtml(translations.customize || 'Customize')}
|
|
648
719
|
</button>
|
|
649
720
|
<button
|
|
650
721
|
class="cc-btn cc-btn--accept"
|
|
651
722
|
data-action="accept"
|
|
652
|
-
aria-label="${escapeHtml(translations.acceptAll || '
|
|
723
|
+
aria-label="${escapeHtml(translations.acceptAll || 'Accept all')}"
|
|
653
724
|
>
|
|
654
|
-
${escapeHtml(translations.acceptAll || '
|
|
725
|
+
${escapeHtml(translations.acceptAll || 'Accept all')}
|
|
655
726
|
</button>
|
|
656
727
|
</div>
|
|
657
728
|
</div>
|
|
@@ -683,10 +754,8 @@ class Banner {
|
|
|
683
754
|
break;
|
|
684
755
|
}
|
|
685
756
|
});
|
|
686
|
-
// Keyboard support
|
|
687
757
|
(_b = this.element) === null || _b === void 0 ? void 0 : _b.addEventListener('keydown', (e) => {
|
|
688
758
|
if (e.key === 'Escape' && this.config.disablePageInteraction) {
|
|
689
|
-
// Allow ESC to close if page interaction is disabled
|
|
690
759
|
this.handleRejectAll();
|
|
691
760
|
}
|
|
692
761
|
});
|
|
@@ -695,36 +764,24 @@ class Banner {
|
|
|
695
764
|
* Handle accept all action
|
|
696
765
|
*/
|
|
697
766
|
handleAcceptAll() {
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
marketing: true,
|
|
703
|
-
};
|
|
704
|
-
// Only add preferences if it's configured
|
|
705
|
-
if ((_a = this.config.categories) === null || _a === void 0 ? void 0 : _a.preferences) {
|
|
706
|
-
allCategories.preferences = true;
|
|
767
|
+
const allCategories = { necessary: true, analytics: true, marketing: true };
|
|
768
|
+
// Add all configured categories
|
|
769
|
+
for (const key of Object.keys(this.config.categories)) {
|
|
770
|
+
allCategories[key] = true;
|
|
707
771
|
}
|
|
708
772
|
this.eventEmitter.emit('consent:accept', allCategories);
|
|
709
|
-
(_c = (_b = this.config).onAccept) === null || _c === void 0 ? void 0 : _c.call(_b, allCategories);
|
|
710
773
|
this.hide();
|
|
711
774
|
}
|
|
712
775
|
/**
|
|
713
776
|
* Handle reject all action
|
|
714
777
|
*/
|
|
715
778
|
handleRejectAll() {
|
|
716
|
-
|
|
717
|
-
const
|
|
718
|
-
necessary
|
|
719
|
-
|
|
720
|
-
marketing: false,
|
|
721
|
-
};
|
|
722
|
-
// Only add preferences if it's configured
|
|
723
|
-
if ((_a = this.config.categories) === null || _a === void 0 ? void 0 : _a.preferences) {
|
|
724
|
-
necessaryOnly.preferences = false;
|
|
779
|
+
const necessaryOnly = { necessary: true, analytics: false, marketing: false };
|
|
780
|
+
for (const key of Object.keys(this.config.categories)) {
|
|
781
|
+
if (key !== 'necessary')
|
|
782
|
+
necessaryOnly[key] = false;
|
|
725
783
|
}
|
|
726
784
|
this.eventEmitter.emit('consent:reject', necessaryOnly);
|
|
727
|
-
(_c = (_b = this.config).onReject) === null || _c === void 0 ? void 0 : _c.call(_b);
|
|
728
785
|
this.hide();
|
|
729
786
|
}
|
|
730
787
|
/**
|
|
@@ -734,17 +791,41 @@ class Banner {
|
|
|
734
791
|
this.eventEmitter.emit('preferences:show');
|
|
735
792
|
this.hide();
|
|
736
793
|
}
|
|
794
|
+
/**
|
|
795
|
+
* Trap focus within banner (when disablePageInteraction is true)
|
|
796
|
+
*/
|
|
797
|
+
trapFocus() {
|
|
798
|
+
var _a, _b;
|
|
799
|
+
const focusableElements = (_a = this.element) === null || _a === void 0 ? void 0 : _a.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
|
|
800
|
+
if (!focusableElements || focusableElements.length === 0)
|
|
801
|
+
return;
|
|
802
|
+
const firstFocusable = focusableElements[0];
|
|
803
|
+
const lastFocusable = focusableElements[focusableElements.length - 1];
|
|
804
|
+
firstFocusable === null || firstFocusable === void 0 ? void 0 : firstFocusable.focus();
|
|
805
|
+
(_b = this.element) === null || _b === void 0 ? void 0 : _b.addEventListener('keydown', (e) => {
|
|
806
|
+
if (e.key === 'Tab') {
|
|
807
|
+
if (e.shiftKey && document.activeElement === firstFocusable) {
|
|
808
|
+
e.preventDefault();
|
|
809
|
+
lastFocusable.focus();
|
|
810
|
+
}
|
|
811
|
+
else if (!e.shiftKey && document.activeElement === lastFocusable) {
|
|
812
|
+
e.preventDefault();
|
|
813
|
+
firstFocusable.focus();
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
});
|
|
817
|
+
}
|
|
737
818
|
/**
|
|
738
819
|
* Generate description HTML with privacy policy link
|
|
739
820
|
*/
|
|
740
821
|
getDescriptionHTML() {
|
|
741
822
|
const translations = this.config.translations || {};
|
|
742
|
-
const defaultDescription = '
|
|
823
|
+
const defaultDescription = 'We use cookies to improve your experience on our site. You can choose which cookies you accept.';
|
|
743
824
|
const description = escapeHtml(translations.description || defaultDescription);
|
|
744
825
|
if (translations.privacyPolicyUrl) {
|
|
745
826
|
const safeUrl = sanitizeUrl(translations.privacyPolicyUrl);
|
|
746
827
|
if (safeUrl) {
|
|
747
|
-
const linkLabel = escapeHtml(translations.privacyPolicyLabel || '
|
|
828
|
+
const linkLabel = escapeHtml(translations.privacyPolicyLabel || 'Privacy Policy');
|
|
748
829
|
return `${description} <a href="${safeUrl}" target="_blank" rel="noopener noreferrer">${linkLabel}</a>`;
|
|
749
830
|
}
|
|
750
831
|
}
|
|
@@ -758,6 +839,7 @@ class Banner {
|
|
|
758
839
|
class PreferenceCenter {
|
|
759
840
|
constructor(config, eventEmitter, currentConsent) {
|
|
760
841
|
this.element = null;
|
|
842
|
+
this.previousActiveElement = null;
|
|
761
843
|
this.config = config;
|
|
762
844
|
this.eventEmitter = eventEmitter;
|
|
763
845
|
this.currentConsent = currentConsent;
|
|
@@ -768,13 +850,13 @@ class PreferenceCenter {
|
|
|
768
850
|
show() {
|
|
769
851
|
const append = () => {
|
|
770
852
|
if (!this.element) {
|
|
853
|
+
this.previousActiveElement = document.activeElement;
|
|
771
854
|
this.element = this.createDOM();
|
|
772
855
|
document.body.appendChild(this.element);
|
|
773
856
|
this.attachListeners();
|
|
774
857
|
}
|
|
775
858
|
this.element.classList.add('is-visible');
|
|
776
859
|
this.trapFocus();
|
|
777
|
-
// Prevent body scroll
|
|
778
860
|
document.body.style.overflow = 'hidden';
|
|
779
861
|
};
|
|
780
862
|
if (!document.body) {
|
|
@@ -790,6 +872,11 @@ class PreferenceCenter {
|
|
|
790
872
|
var _a;
|
|
791
873
|
(_a = this.element) === null || _a === void 0 ? void 0 : _a.classList.remove('is-visible');
|
|
792
874
|
document.body.style.overflow = '';
|
|
875
|
+
// Restore focus to triggering element
|
|
876
|
+
if (this.previousActiveElement && document.contains(this.previousActiveElement)) {
|
|
877
|
+
this.previousActiveElement.focus();
|
|
878
|
+
this.previousActiveElement = null;
|
|
879
|
+
}
|
|
793
880
|
setTimeout(() => {
|
|
794
881
|
this.destroy();
|
|
795
882
|
}, 300);
|
|
@@ -824,7 +911,7 @@ class PreferenceCenter {
|
|
|
824
911
|
<polyline points="15 3 21 3 21 9"/>
|
|
825
912
|
<line x1="10" y1="14" x2="21" y2="3"/>
|
|
826
913
|
</svg>
|
|
827
|
-
${escapeHtml(translations.privacyPolicyLabel || '
|
|
914
|
+
${escapeHtml(translations.privacyPolicyLabel || 'Privacy Policy')}
|
|
828
915
|
</a>
|
|
829
916
|
`;
|
|
830
917
|
})()
|
|
@@ -838,21 +925,12 @@ class PreferenceCenter {
|
|
|
838
925
|
data-theme="${escapeHtml(theme)}"
|
|
839
926
|
style="${colorStyle}"
|
|
840
927
|
>
|
|
841
|
-
<div class="cc-modal__overlay"
|
|
928
|
+
<div class="cc-modal__overlay"></div>
|
|
842
929
|
<div class="cc-modal__content">
|
|
843
930
|
<div class="cc-modal__header">
|
|
844
931
|
<h2 id="cc-modal-title">
|
|
845
|
-
${escapeHtml(translations.preferencesTitle || translations.title || '
|
|
932
|
+
${escapeHtml(translations.preferencesTitle || translations.title || 'Cookie Preferences')}
|
|
846
933
|
</h2>
|
|
847
|
-
<button
|
|
848
|
-
class="cc-modal__close"
|
|
849
|
-
aria-label="Fermer"
|
|
850
|
-
data-action="close"
|
|
851
|
-
>
|
|
852
|
-
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
|
853
|
-
<path d="M18 6L6 18M6 6l12 12" stroke-width="2" stroke-linecap="round"/>
|
|
854
|
-
</svg>
|
|
855
|
-
</button>
|
|
856
934
|
</div>
|
|
857
935
|
|
|
858
936
|
<div class="cc-modal__body">
|
|
@@ -868,13 +946,13 @@ class PreferenceCenter {
|
|
|
868
946
|
class="cc-btn cc-btn--secondary"
|
|
869
947
|
data-action="reject"
|
|
870
948
|
>
|
|
871
|
-
${escapeHtml(translations.essentialsOnly || '
|
|
949
|
+
${escapeHtml(translations.essentialsOnly || 'Essentials only')}
|
|
872
950
|
</button>
|
|
873
951
|
<button
|
|
874
952
|
class="cc-btn cc-btn--primary"
|
|
875
953
|
data-action="save"
|
|
876
954
|
>
|
|
877
|
-
${escapeHtml(translations.savePreferences || '
|
|
955
|
+
${escapeHtml(translations.savePreferences || 'Save preferences')}
|
|
878
956
|
</button>
|
|
879
957
|
</div>
|
|
880
958
|
</div>
|
|
@@ -892,7 +970,7 @@ class PreferenceCenter {
|
|
|
892
970
|
const categories = Object.entries(this.config.categories);
|
|
893
971
|
return categories
|
|
894
972
|
.map(([key, config]) => {
|
|
895
|
-
const checked = this.currentConsent[key];
|
|
973
|
+
const checked = this.currentConsent[key] === true;
|
|
896
974
|
const disabled = config.readOnly;
|
|
897
975
|
return `
|
|
898
976
|
<div class="cc-category">
|
|
@@ -921,40 +999,34 @@ class PreferenceCenter {
|
|
|
921
999
|
* Attach event listeners
|
|
922
1000
|
*/
|
|
923
1001
|
attachListeners() {
|
|
924
|
-
var _a
|
|
1002
|
+
var _a;
|
|
925
1003
|
(_a = this.element) === null || _a === void 0 ? void 0 : _a.addEventListener('click', (e) => {
|
|
926
1004
|
const target = e.target.closest('[data-action]');
|
|
927
1005
|
if (!target)
|
|
928
1006
|
return;
|
|
929
1007
|
const action = target.getAttribute('data-action');
|
|
930
|
-
if (action === '
|
|
931
|
-
this.hide();
|
|
932
|
-
}
|
|
933
|
-
else if (action === 'save') {
|
|
1008
|
+
if (action === 'save') {
|
|
934
1009
|
this.handleSave();
|
|
935
1010
|
}
|
|
936
1011
|
else if (action === 'reject') {
|
|
937
1012
|
this.handleRejectAll();
|
|
938
1013
|
}
|
|
939
1014
|
});
|
|
940
|
-
// Keyboard shortcuts
|
|
941
|
-
(_b = this.element) === null || _b === void 0 ? void 0 : _b.addEventListener('keydown', (e) => {
|
|
942
|
-
if (e.key === 'Escape') {
|
|
943
|
-
this.hide();
|
|
944
|
-
}
|
|
945
|
-
});
|
|
946
1015
|
}
|
|
947
1016
|
/**
|
|
948
1017
|
* Handle save preferences
|
|
949
1018
|
*/
|
|
950
1019
|
handleSave() {
|
|
951
|
-
var _a
|
|
1020
|
+
var _a;
|
|
952
1021
|
const checkboxes = (_a = this.element) === null || _a === void 0 ? void 0 : _a.querySelectorAll('input[data-category]');
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
1022
|
+
// Initialize all configured categories to false
|
|
1023
|
+
const categories = { necessary: true, analytics: false, marketing: false };
|
|
1024
|
+
for (const key of Object.keys(this.config.categories)) {
|
|
1025
|
+
if (key !== 'necessary') {
|
|
1026
|
+
categories[key] = false;
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
// Override with actual checkbox values
|
|
958
1030
|
checkboxes === null || checkboxes === void 0 ? void 0 : checkboxes.forEach((checkbox) => {
|
|
959
1031
|
if (checkbox instanceof HTMLInputElement) {
|
|
960
1032
|
const category = checkbox.getAttribute('data-category');
|
|
@@ -964,22 +1036,16 @@ class PreferenceCenter {
|
|
|
964
1036
|
}
|
|
965
1037
|
});
|
|
966
1038
|
this.eventEmitter.emit('consent:update', categories);
|
|
967
|
-
(_c = (_b = this.config).onChange) === null || _c === void 0 ? void 0 : _c.call(_b, categories);
|
|
968
1039
|
this.hide();
|
|
969
1040
|
}
|
|
970
1041
|
/**
|
|
971
1042
|
* Handle reject all
|
|
972
1043
|
*/
|
|
973
1044
|
handleRejectAll() {
|
|
974
|
-
|
|
975
|
-
const
|
|
976
|
-
necessary
|
|
977
|
-
|
|
978
|
-
marketing: false,
|
|
979
|
-
};
|
|
980
|
-
// Only add preferences if it's configured
|
|
981
|
-
if ((_a = this.config.categories) === null || _a === void 0 ? void 0 : _a.preferences) {
|
|
982
|
-
necessaryOnly.preferences = false;
|
|
1045
|
+
const necessaryOnly = { necessary: true, analytics: false, marketing: false };
|
|
1046
|
+
for (const key of Object.keys(this.config.categories)) {
|
|
1047
|
+
if (key !== 'necessary')
|
|
1048
|
+
necessaryOnly[key] = false;
|
|
983
1049
|
}
|
|
984
1050
|
this.eventEmitter.emit('consent:reject', necessaryOnly);
|
|
985
1051
|
this.hide();
|
|
@@ -994,9 +1060,7 @@ class PreferenceCenter {
|
|
|
994
1060
|
return;
|
|
995
1061
|
const firstFocusable = focusableElements[0];
|
|
996
1062
|
const lastFocusable = focusableElements[focusableElements.length - 1];
|
|
997
|
-
// Focus first element
|
|
998
1063
|
firstFocusable === null || firstFocusable === void 0 ? void 0 : firstFocusable.focus();
|
|
999
|
-
// Trap focus
|
|
1000
1064
|
(_b = this.element) === null || _b === void 0 ? void 0 : _b.addEventListener('keydown', (e) => {
|
|
1001
1065
|
if (e.key === 'Tab') {
|
|
1002
1066
|
if (e.shiftKey && document.activeElement === firstFocusable) {
|
|
@@ -1084,7 +1148,7 @@ class FloatingWidget {
|
|
|
1084
1148
|
<div
|
|
1085
1149
|
class="cc-widget cc-widget--${escapeHtml(widgetPosition)} cc-widget--${escapeHtml(widgetStyle)}"
|
|
1086
1150
|
role="button"
|
|
1087
|
-
aria-label="${escapeHtml(translations.cookieSettings || '
|
|
1151
|
+
aria-label="${escapeHtml(translations.cookieSettings || 'Cookie settings')}"
|
|
1088
1152
|
tabindex="0"
|
|
1089
1153
|
data-theme="${escapeHtml(theme)}"
|
|
1090
1154
|
style="${colorStyle}"
|
|
@@ -1135,11 +1199,6 @@ class FloatingWidget {
|
|
|
1135
1199
|
|
|
1136
1200
|
/**
|
|
1137
1201
|
* GTMConsentMode - Full integration with Google Consent Mode v2
|
|
1138
|
-
*
|
|
1139
|
-
* Implements all required signals:
|
|
1140
|
-
* - ad_storage, ad_user_data, ad_personalization, analytics_storage (core GCM v2)
|
|
1141
|
-
* - functionality_storage, personalization_storage, security_storage (non-core)
|
|
1142
|
-
* - wait_for_update, url_passthrough, ads_data_redaction (advanced features)
|
|
1143
1202
|
*/
|
|
1144
1203
|
class GTMConsentMode {
|
|
1145
1204
|
constructor(dataLayerManager, config) {
|
|
@@ -1159,15 +1218,13 @@ class GTMConsentMode {
|
|
|
1159
1218
|
analytics_storage: 'denied',
|
|
1160
1219
|
functionality_storage: 'denied',
|
|
1161
1220
|
personalization_storage: 'denied',
|
|
1162
|
-
security_storage: 'granted',
|
|
1221
|
+
security_storage: 'granted',
|
|
1163
1222
|
};
|
|
1164
|
-
// Add wait_for_update to give CMP time to restore returning visitor consent
|
|
1165
1223
|
const waitForUpdate = (_a = this.config.gtmWaitForUpdate) !== null && _a !== void 0 ? _a : 500;
|
|
1166
1224
|
if (waitForUpdate > 0) {
|
|
1167
1225
|
defaults['wait_for_update'] = waitForUpdate;
|
|
1168
1226
|
}
|
|
1169
1227
|
this.dataLayerManager.pushConsent('default', defaults);
|
|
1170
|
-
// Set advanced features via gtag('set', ...)
|
|
1171
1228
|
if (this.config.gtmUrlPassthrough) {
|
|
1172
1229
|
this.dataLayerManager.pushSet('url_passthrough', true);
|
|
1173
1230
|
}
|
|
@@ -1177,7 +1234,6 @@ class GTMConsentMode {
|
|
|
1177
1234
|
}
|
|
1178
1235
|
/**
|
|
1179
1236
|
* Update consent state based on user choices
|
|
1180
|
-
* Called both on new consent and on page load for returning visitors
|
|
1181
1237
|
*/
|
|
1182
1238
|
updateConsent(categories) {
|
|
1183
1239
|
const gtmConsent = this.mapCategoriesToGTM(categories);
|
|
@@ -1187,14 +1243,19 @@ class GTMConsentMode {
|
|
|
1187
1243
|
* Map consent categories to GTM Consent Mode v2 format
|
|
1188
1244
|
*/
|
|
1189
1245
|
mapCategoriesToGTM(categories) {
|
|
1246
|
+
// When preferences category is not configured, default functionality to granted
|
|
1247
|
+
const hasPreferencesCategory = 'preferences' in this.config.categories;
|
|
1248
|
+
const preferencesGranted = hasPreferencesCategory
|
|
1249
|
+
? categories.preferences === true
|
|
1250
|
+
: true;
|
|
1190
1251
|
return {
|
|
1191
1252
|
ad_storage: categories.marketing ? 'granted' : 'denied',
|
|
1192
1253
|
ad_user_data: categories.marketing ? 'granted' : 'denied',
|
|
1193
1254
|
ad_personalization: categories.marketing ? 'granted' : 'denied',
|
|
1194
1255
|
analytics_storage: categories.analytics ? 'granted' : 'denied',
|
|
1195
|
-
functionality_storage:
|
|
1196
|
-
personalization_storage:
|
|
1197
|
-
security_storage: 'granted',
|
|
1256
|
+
functionality_storage: preferencesGranted ? 'granted' : 'denied',
|
|
1257
|
+
personalization_storage: preferencesGranted ? 'granted' : 'denied',
|
|
1258
|
+
security_storage: 'granted',
|
|
1198
1259
|
};
|
|
1199
1260
|
}
|
|
1200
1261
|
}
|
|
@@ -1339,6 +1400,16 @@ class CookieConsent {
|
|
|
1339
1400
|
this.preferenceCenter = null;
|
|
1340
1401
|
this.floatingWidget = null;
|
|
1341
1402
|
this.gtmIntegration = null;
|
|
1403
|
+
this.hideTimeout = null;
|
|
1404
|
+
// SSR guard
|
|
1405
|
+
if (typeof window === 'undefined') {
|
|
1406
|
+
this.config = config;
|
|
1407
|
+
this.consentManager = null;
|
|
1408
|
+
this.storageManager = null;
|
|
1409
|
+
this.eventEmitter = null;
|
|
1410
|
+
this.scriptBlocker = null;
|
|
1411
|
+
return;
|
|
1412
|
+
}
|
|
1342
1413
|
this.config = this.validateConfig(config);
|
|
1343
1414
|
this.consentManager = new ConsentManager(this.config);
|
|
1344
1415
|
this.storageManager = new StorageManager();
|
|
@@ -1347,25 +1418,32 @@ class CookieConsent {
|
|
|
1347
1418
|
if (this.config.gtmConsentMode) {
|
|
1348
1419
|
this.gtmIntegration = new GTMConsentMode(new DataLayerManager(), this.config);
|
|
1349
1420
|
}
|
|
1350
|
-
// Listen for
|
|
1351
|
-
this.eventEmitter.on('preferences:show', () => {
|
|
1352
|
-
this.showPreferences();
|
|
1353
|
-
});
|
|
1354
|
-
// Listen for consent updates
|
|
1421
|
+
// Listen for consent events — callbacks are fired AFTER consent is persisted
|
|
1355
1422
|
this.eventEmitter.on('consent:accept', (categories) => {
|
|
1423
|
+
var _a, _b;
|
|
1356
1424
|
this.updateConsent(categories);
|
|
1425
|
+
(_b = (_a = this.config).onAccept) === null || _b === void 0 ? void 0 : _b.call(_a, categories);
|
|
1357
1426
|
});
|
|
1358
1427
|
this.eventEmitter.on('consent:reject', (categories) => {
|
|
1428
|
+
var _a, _b;
|
|
1359
1429
|
this.updateConsent(categories);
|
|
1430
|
+
(_b = (_a = this.config).onReject) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
1360
1431
|
});
|
|
1361
1432
|
this.eventEmitter.on('consent:update', (categories) => {
|
|
1433
|
+
var _a, _b;
|
|
1362
1434
|
this.updateConsent(categories);
|
|
1435
|
+
(_b = (_a = this.config).onChange) === null || _b === void 0 ? void 0 : _b.call(_a, categories);
|
|
1436
|
+
});
|
|
1437
|
+
this.eventEmitter.on('preferences:show', () => {
|
|
1438
|
+
this.showPreferences();
|
|
1363
1439
|
});
|
|
1364
1440
|
}
|
|
1365
1441
|
/**
|
|
1366
1442
|
* Initialize the cookie consent system
|
|
1367
1443
|
*/
|
|
1368
1444
|
init() {
|
|
1445
|
+
if (typeof window === 'undefined')
|
|
1446
|
+
return;
|
|
1369
1447
|
// 1. Start blocking scripts immediately
|
|
1370
1448
|
this.scriptBlocker.init();
|
|
1371
1449
|
// 2. Set GTM default consent BEFORE checking storage
|
|
@@ -1375,35 +1453,28 @@ class CookieConsent {
|
|
|
1375
1453
|
// 3. Check for existing consent
|
|
1376
1454
|
const storedConsent = this.storageManager.load();
|
|
1377
1455
|
if (storedConsent && !this.storageManager.isExpired(storedConsent)) {
|
|
1378
|
-
// Valid consent exists
|
|
1379
1456
|
if (this.consentManager.needsUpdate(storedConsent)) {
|
|
1380
|
-
// Policy updated, show banner again
|
|
1381
1457
|
if (this.config.autoShow) {
|
|
1382
1458
|
this.showBanner();
|
|
1383
1459
|
}
|
|
1384
1460
|
}
|
|
1385
1461
|
else {
|
|
1386
|
-
// Apply stored consent
|
|
1387
1462
|
this.applyConsent(storedConsent.categories);
|
|
1388
|
-
// Restore GTM consent for returning visitors (within wait_for_update window)
|
|
1389
1463
|
if (this.gtmIntegration) {
|
|
1390
1464
|
this.gtmIntegration.updateConsent(storedConsent.categories);
|
|
1391
1465
|
}
|
|
1392
1466
|
this.eventEmitter.emit('consent:load', storedConsent);
|
|
1393
|
-
// Show floating widget if enabled
|
|
1394
1467
|
if (this.config.showWidget) {
|
|
1395
1468
|
this.showFloatingWidget();
|
|
1396
1469
|
}
|
|
1397
1470
|
}
|
|
1398
1471
|
}
|
|
1399
1472
|
else {
|
|
1400
|
-
// No consent or expired
|
|
1401
1473
|
if (this.config.autoShow) {
|
|
1402
1474
|
this.showBanner();
|
|
1403
1475
|
}
|
|
1404
1476
|
}
|
|
1405
|
-
// Store instance globally
|
|
1406
|
-
// when used without a variable (e.g. new CookieConsent({}).init())
|
|
1477
|
+
// Store instance globally
|
|
1407
1478
|
window.cookieConsent = this;
|
|
1408
1479
|
this.eventEmitter.emit('consent:init');
|
|
1409
1480
|
}
|
|
@@ -1426,14 +1497,18 @@ class CookieConsent {
|
|
|
1426
1497
|
showPreferences() {
|
|
1427
1498
|
var _a;
|
|
1428
1499
|
const stored = (_a = this.storageManager.load()) === null || _a === void 0 ? void 0 : _a.categories;
|
|
1429
|
-
// Default to all ON when no prior consent
|
|
1500
|
+
// Default to all ON when no prior consent
|
|
1430
1501
|
const currentConsent = stored || {
|
|
1431
1502
|
necessary: true,
|
|
1432
1503
|
analytics: true,
|
|
1433
1504
|
marketing: true,
|
|
1434
|
-
preferences: true,
|
|
1435
1505
|
};
|
|
1436
|
-
//
|
|
1506
|
+
// Add any configured categories not in current consent
|
|
1507
|
+
for (const key of Object.keys(this.config.categories)) {
|
|
1508
|
+
if (!(key in currentConsent)) {
|
|
1509
|
+
currentConsent[key] = key === 'necessary';
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1437
1512
|
if (this.preferenceCenter) {
|
|
1438
1513
|
this.preferenceCenter.destroy();
|
|
1439
1514
|
}
|
|
@@ -1450,11 +1525,11 @@ class CookieConsent {
|
|
|
1450
1525
|
if (this.gtmIntegration) {
|
|
1451
1526
|
this.gtmIntegration.updateConsent(categories);
|
|
1452
1527
|
}
|
|
1453
|
-
// Show floating widget after consent is given
|
|
1528
|
+
// Show floating widget after consent is given
|
|
1454
1529
|
if (this.config.showWidget) {
|
|
1455
1530
|
setTimeout(() => {
|
|
1456
1531
|
this.showFloatingWidget();
|
|
1457
|
-
}, 400);
|
|
1532
|
+
}, 400);
|
|
1458
1533
|
}
|
|
1459
1534
|
}
|
|
1460
1535
|
/**
|
|
@@ -1467,14 +1542,19 @@ class CookieConsent {
|
|
|
1467
1542
|
* Reset consent (clear stored data and show banner)
|
|
1468
1543
|
*/
|
|
1469
1544
|
reset() {
|
|
1545
|
+
var _a, _b;
|
|
1470
1546
|
this.storageManager.clear();
|
|
1471
1547
|
this.scriptBlocker.block();
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1548
|
+
const denied = { necessary: true, analytics: false, marketing: false };
|
|
1549
|
+
for (const key of Object.keys(this.config.categories)) {
|
|
1550
|
+
if (key !== 'necessary')
|
|
1551
|
+
denied[key] = false;
|
|
1552
|
+
}
|
|
1553
|
+
clearDeniedCookies(denied);
|
|
1475
1554
|
if (this.gtmIntegration) {
|
|
1476
|
-
this.gtmIntegration.updateConsent(
|
|
1555
|
+
this.gtmIntegration.updateConsent(denied);
|
|
1477
1556
|
}
|
|
1557
|
+
(_b = (_a = this.config).onReject) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
1478
1558
|
this.showBanner();
|
|
1479
1559
|
}
|
|
1480
1560
|
/**
|
|
@@ -1494,6 +1574,10 @@ class CookieConsent {
|
|
|
1494
1574
|
*/
|
|
1495
1575
|
destroy() {
|
|
1496
1576
|
var _a, _b, _c, _d;
|
|
1577
|
+
if (this.hideTimeout) {
|
|
1578
|
+
clearTimeout(this.hideTimeout);
|
|
1579
|
+
this.hideTimeout = null;
|
|
1580
|
+
}
|
|
1497
1581
|
(_a = this.banner) === null || _a === void 0 ? void 0 : _a.destroy();
|
|
1498
1582
|
this.banner = null;
|
|
1499
1583
|
(_b = this.preferenceCenter) === null || _b === void 0 ? void 0 : _b.destroy();
|
|
@@ -1501,6 +1585,10 @@ class CookieConsent {
|
|
|
1501
1585
|
(_c = this.floatingWidget) === null || _c === void 0 ? void 0 : _c.destroy();
|
|
1502
1586
|
this.floatingWidget = null;
|
|
1503
1587
|
(_d = this.scriptBlocker) === null || _d === void 0 ? void 0 : _d.destroy();
|
|
1588
|
+
this.eventEmitter.clear();
|
|
1589
|
+
if (window.cookieConsent === this) {
|
|
1590
|
+
window.cookieConsent = undefined;
|
|
1591
|
+
}
|
|
1504
1592
|
}
|
|
1505
1593
|
/**
|
|
1506
1594
|
* Show the banner
|
|
@@ -1526,7 +1614,6 @@ class CookieConsent {
|
|
|
1526
1614
|
*/
|
|
1527
1615
|
applyConsent(categories) {
|
|
1528
1616
|
this.scriptBlocker.unblock(categories);
|
|
1529
|
-
// CNIL/GDPR: actively delete cookies for denied categories
|
|
1530
1617
|
clearDeniedCookies(categories);
|
|
1531
1618
|
}
|
|
1532
1619
|
/**
|
|
@@ -1537,22 +1624,22 @@ class CookieConsent {
|
|
|
1537
1624
|
necessary: {
|
|
1538
1625
|
enabled: true,
|
|
1539
1626
|
readOnly: true,
|
|
1540
|
-
label: '
|
|
1541
|
-
description: '
|
|
1627
|
+
label: 'Essential',
|
|
1628
|
+
description: 'Required for the website to function properly.',
|
|
1542
1629
|
},
|
|
1543
1630
|
analytics: {
|
|
1544
1631
|
enabled: true,
|
|
1545
1632
|
readOnly: false,
|
|
1546
|
-
label: '
|
|
1547
|
-
description: '
|
|
1633
|
+
label: 'Analytics',
|
|
1634
|
+
description: 'Help us understand how you use our site.',
|
|
1548
1635
|
},
|
|
1549
1636
|
marketing: {
|
|
1550
1637
|
enabled: true,
|
|
1551
1638
|
readOnly: false,
|
|
1552
1639
|
label: 'Marketing',
|
|
1553
|
-
description: '
|
|
1640
|
+
description: 'Used to deliver relevant advertisements.',
|
|
1554
1641
|
},
|
|
1555
|
-
}, mode: config.mode || 'opt-in', autoShow: config.autoShow !== undefined ? config.autoShow : true, revision: config.revision || 1, gtmConsentMode: config.gtmConsentMode
|
|
1642
|
+
}, mode: config.mode || 'opt-in', autoShow: config.autoShow !== undefined ? config.autoShow : true, revision: config.revision || 1, gtmConsentMode: config.gtmConsentMode || false, disablePageInteraction: config.disablePageInteraction || false, theme: config.theme || 'light', position: config.position || 'bottom-left', layout: config.layout || 'box', backdropBlur: config.backdropBlur !== false, animationStyle: config.animationStyle || 'smooth', preferencesPosition: config.preferencesPosition || 'center', showWidget: config.showWidget !== undefined ? config.showWidget : true, widgetPosition: config.widgetPosition || 'bottom-left', widgetStyle: config.widgetStyle || 'compact' });
|
|
1556
1643
|
}
|
|
1557
1644
|
}
|
|
1558
1645
|
|