@el7ven/cookie-kit 0.2.21 → 0.3.2
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 +21 -1
- package/src/core/AnalyticsManager.js +400 -0
- package/src/core/ConsentManager.js +710 -0
- package/src/core/ConsentMode.js +109 -0
- package/src/core/FocusTrap.js +130 -0
- package/src/core/GeoDetector.js +144 -0
- package/src/core/ScriptLoader.js +229 -0
- package/src/core/StorageAdapter.js +179 -0
- package/src/core/analytics.js +101 -10
- package/src/core/index.js +7 -7
- package/src/geo/GeoDetector.js +536 -0
- package/src/geo/RegionRules.js +126 -0
- package/src/geo/index.js +16 -0
- package/src/index.js +56 -18
- package/src/js/CookieConsent.js +0 -1
- package/src/locales/en.js +54 -0
- package/src/locales/index.js +20 -0
- package/src/locales/ro.js +54 -0
- package/src/plugins/CMPPlugin.js +187 -0
- package/src/plugins/PluginManager.js +234 -0
- package/src/plugins/index.js +7 -0
- package/src/providers/GoogleConsentModeProvider.js +278 -0
- package/src/providers/index.js +6 -0
- package/src/rewriting/ScriptRewriter.js +278 -0
- package/src/rewriting/index.js +6 -0
- package/src/scripts/ScriptLoader.js +310 -0
- package/src/scripts/ScriptManager.js +278 -0
- package/src/scripts/ScriptRegistry.js +175 -0
- package/src/scripts/ScriptScanner.js +178 -0
- package/src/scripts/index.js +9 -0
- package/src/trackers/TrackerDetector.js +488 -0
- package/src/trackers/TrackerPatterns.js +307 -0
- package/src/trackers/TrackerRegistry.js +172 -0
- package/src/trackers/index.js +15 -0
- package/src/utils/cookies.js +37 -0
- package/src/utils/dom.js +58 -0
- package/src/utils/helpers.js +89 -0
- package/src/vue/CookieConsent.vue +1 -1
- package/src/vue/CookieDrawer.vue +4 -4
package/src/index.js
CHANGED
|
@@ -1,38 +1,80 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @el7ven/cookie-kit - Unified Cookie Consent Management
|
|
3
3
|
* GDPR compliant cookie consent with React and Vue support
|
|
4
|
-
* @version
|
|
4
|
+
* @version 0.4.0
|
|
5
5
|
* @author Igor Semionov
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
// Core
|
|
8
|
+
// ─── Core (lite) ───
|
|
9
9
|
export { createCookieKit, CookieKitCore, DEFAULT_CONFIG } from './core/index.js'
|
|
10
10
|
|
|
11
|
-
//
|
|
12
|
-
export {
|
|
11
|
+
// ─── Core (full) ───
|
|
12
|
+
export { ConsentManager } from './core/ConsentManager.js'
|
|
13
|
+
export { StorageAdapter } from './core/StorageAdapter.js'
|
|
14
|
+
export { ConsentMode, CONSENT_MODE_DEFAULTS, CATEGORY_MAPPING } from './core/ConsentMode.js'
|
|
15
|
+
export { FocusTrap } from './core/FocusTrap.js'
|
|
16
|
+
export { ScriptLoader } from './core/ScriptLoader.js'
|
|
17
|
+
export { AnalyticsManager, ANALYTICS_PROVIDERS } from './core/AnalyticsManager.js'
|
|
18
|
+
export { GeoDetector as CoreGeoDetector } from './core/GeoDetector.js'
|
|
13
19
|
|
|
14
|
-
//
|
|
20
|
+
// ─── Analytics helpers ───
|
|
21
|
+
export { createAnalyticsManager, initGoogleConsentMode, updateGoogleConsent, loadGTM, loadGA4, loadMetaPixel, loadYandexMetrica, blockScriptsBeforeConsent, unblockConsentedScripts, manageScriptBlocking } from './core/analytics.js'
|
|
22
|
+
|
|
23
|
+
// ─── Geo detection ───
|
|
24
|
+
export { GeoDetector } from './geo/GeoDetector.js'
|
|
25
|
+
export { REGION_RULES, isEU, isEEA, isUK, requiresGDPR, getRegion, requiresConsentBanner, getRegulation, isEssentialOnly } from './geo/RegionRules.js'
|
|
26
|
+
|
|
27
|
+
// ─── Locales / i18n ───
|
|
28
|
+
export { locales, getLocale } from './locales/index.js'
|
|
29
|
+
|
|
30
|
+
// ─── Providers ───
|
|
31
|
+
export { GoogleConsentModeProvider } from './providers/GoogleConsentModeProvider.js'
|
|
32
|
+
|
|
33
|
+
// ─── Plugins ───
|
|
34
|
+
export { CMPPlugin } from './plugins/CMPPlugin.js'
|
|
35
|
+
export { PluginManager } from './plugins/PluginManager.js'
|
|
36
|
+
|
|
37
|
+
// ─── Trackers ───
|
|
38
|
+
export { TrackerDetector } from './trackers/TrackerDetector.js'
|
|
39
|
+
export { TrackerRegistry } from './trackers/TrackerRegistry.js'
|
|
40
|
+
|
|
41
|
+
// ─── Script rewriting ───
|
|
42
|
+
export { ScriptRewriter } from './rewriting/ScriptRewriter.js'
|
|
43
|
+
|
|
44
|
+
// ─── Scripts (advanced) ───
|
|
45
|
+
export { ScriptLoader as AdvancedScriptLoader } from './scripts/ScriptLoader.js'
|
|
46
|
+
export { ScriptManager } from './scripts/ScriptManager.js'
|
|
47
|
+
export { ScriptRegistry } from './scripts/ScriptRegistry.js'
|
|
48
|
+
export { ScriptScanner } from './scripts/ScriptScanner.js'
|
|
49
|
+
|
|
50
|
+
// ─── Utils ───
|
|
51
|
+
export { getCookie, setCookie, deleteCookie, getAllCookies } from './utils/cookies.js'
|
|
52
|
+
export { getFocusableElements, trapFocus, lockBodyScroll, unlockBodyScroll, onEscape } from './utils/dom.js'
|
|
53
|
+
export { generateUUID, debounce, throttle, deepMerge, isSSR, isMobile, getRegionFromTimezone } from './utils/helpers.js'
|
|
54
|
+
|
|
55
|
+
// ─── Imports for default export ───
|
|
15
56
|
import { createCookieKit, CookieKitCore, DEFAULT_CONFIG } from './core/index.js'
|
|
16
57
|
import { createAnalyticsManager } from './core/analytics.js'
|
|
58
|
+
import { ConsentManager } from './core/ConsentManager.js'
|
|
17
59
|
import { initCookieKit } from './js/index.js'
|
|
18
60
|
import { VERSION } from './core/version.js'
|
|
19
61
|
|
|
20
|
-
// Vanilla JS components
|
|
62
|
+
// ─── Vanilla JS components ───
|
|
21
63
|
export { initCookieKit, mountCookieConsent } from './js/index.js'
|
|
22
64
|
|
|
23
|
-
// React components
|
|
65
|
+
// ─── React components ───
|
|
24
66
|
export * from './react/index.js'
|
|
25
67
|
|
|
26
|
-
// Vue components
|
|
68
|
+
// ─── Vue components ───
|
|
27
69
|
export * from './vue/index.js'
|
|
28
70
|
|
|
29
|
-
// Vue composable
|
|
71
|
+
// ─── Vue composable ───
|
|
30
72
|
export { useCookieConsent } from './vue/composables/useCookieConsent.js'
|
|
31
73
|
|
|
32
|
-
// Version info
|
|
74
|
+
// ─── Version info ───
|
|
33
75
|
export { VERSION, getVersion, getVersionInfo, logVersion } from './core/version.js'
|
|
34
76
|
|
|
35
|
-
// Unified factory
|
|
77
|
+
// ─── Unified factory ───
|
|
36
78
|
export function createCookieConsent(config = {}) {
|
|
37
79
|
const { framework = 'js', ...restConfig } = config
|
|
38
80
|
|
|
@@ -46,23 +88,18 @@ export function createCookieConsent(config = {}) {
|
|
|
46
88
|
}
|
|
47
89
|
}
|
|
48
90
|
|
|
49
|
-
// Auto-detect framework
|
|
91
|
+
// Auto-detect framework
|
|
50
92
|
export function autoCookieConsent(config = {}) {
|
|
51
|
-
// Detect React
|
|
52
93
|
if (typeof window !== 'undefined' && window.React) {
|
|
53
94
|
return createCookieConsent({ ...config, framework: 'react' })
|
|
54
95
|
}
|
|
55
|
-
|
|
56
|
-
// Detect Vue
|
|
57
96
|
if (typeof window !== 'undefined' && window.Vue) {
|
|
58
97
|
return createCookieConsent({ ...config, framework: 'vue' })
|
|
59
98
|
}
|
|
60
|
-
|
|
61
|
-
// Default to vanilla JS
|
|
62
99
|
return createCookieConsent({ ...config, framework: 'js' })
|
|
63
100
|
}
|
|
64
101
|
|
|
65
|
-
// Default export
|
|
102
|
+
// Default export
|
|
66
103
|
export default {
|
|
67
104
|
createCookieKit,
|
|
68
105
|
createCookieConsent,
|
|
@@ -70,6 +107,7 @@ export default {
|
|
|
70
107
|
autoCookieConsent,
|
|
71
108
|
initCookieKit,
|
|
72
109
|
CookieKitCore,
|
|
110
|
+
ConsentManager,
|
|
73
111
|
DEFAULT_CONFIG,
|
|
74
112
|
VERSION
|
|
75
113
|
}
|
package/src/js/CookieConsent.js
CHANGED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* English translations
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
essential: {
|
|
7
|
+
title: 'Cookies',
|
|
8
|
+
message: 'We use cookies to improve your experience on our site.',
|
|
9
|
+
button: 'I understand'
|
|
10
|
+
},
|
|
11
|
+
gdpr: {
|
|
12
|
+
title: 'Cookie Preferences',
|
|
13
|
+
message: 'We use cookies to provide you with the best experience. Choose which types of cookies you accept.',
|
|
14
|
+
buttons: {
|
|
15
|
+
acceptAll: 'Accept all',
|
|
16
|
+
rejectAll: 'Reject all',
|
|
17
|
+
acceptSelection: 'Accept selection',
|
|
18
|
+
settings: 'Settings'
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
settings: {
|
|
22
|
+
title: 'Cookie Settings',
|
|
23
|
+
tabs: {
|
|
24
|
+
privacy: 'Privacy'
|
|
25
|
+
},
|
|
26
|
+
buttons: {
|
|
27
|
+
acceptAll: 'Accept all',
|
|
28
|
+
rejectAll: 'Reject all',
|
|
29
|
+
acceptSelection: 'Save selection'
|
|
30
|
+
},
|
|
31
|
+
links: {
|
|
32
|
+
moreInfo: 'More information',
|
|
33
|
+
cookieDetails: 'Cookie details'
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
categories: {
|
|
37
|
+
necessary: {
|
|
38
|
+
label: 'Necessary',
|
|
39
|
+
description: 'Essential cookies for site functionality'
|
|
40
|
+
},
|
|
41
|
+
analytics: {
|
|
42
|
+
label: 'Analytics',
|
|
43
|
+
description: 'Cookies for traffic and user behavior analysis'
|
|
44
|
+
},
|
|
45
|
+
marketing: {
|
|
46
|
+
label: 'Marketing',
|
|
47
|
+
description: 'Cookies for personalized advertising'
|
|
48
|
+
},
|
|
49
|
+
preferences: {
|
|
50
|
+
label: 'Preferences',
|
|
51
|
+
description: 'Cookies for saving user preferences'
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* i18n support for cookie consent
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import en from './en.js'
|
|
6
|
+
import ro from './ro.js'
|
|
7
|
+
|
|
8
|
+
export const locales = {
|
|
9
|
+
en,
|
|
10
|
+
ro
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function getLocale(lang = 'ro') {
|
|
14
|
+
return locales[lang] || locales.ro
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default {
|
|
18
|
+
locales,
|
|
19
|
+
getLocale
|
|
20
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Romanian translations
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
essential: {
|
|
7
|
+
title: 'Cookie-uri',
|
|
8
|
+
message: 'Folosim cookie-uri pentru a îmbunătăți experiența ta pe site.',
|
|
9
|
+
button: 'Am înțeles'
|
|
10
|
+
},
|
|
11
|
+
gdpr: {
|
|
12
|
+
title: 'Preferințe Cookie-uri',
|
|
13
|
+
message: 'Folosim cookie-uri pentru a-ți oferi cea mai bună experiență. Alege ce tipuri de cookie-uri accepți.',
|
|
14
|
+
buttons: {
|
|
15
|
+
acceptAll: 'Acceptă toate',
|
|
16
|
+
rejectAll: 'Respinge toate',
|
|
17
|
+
acceptSelection: 'Acceptă selecția',
|
|
18
|
+
settings: 'Setări'
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
settings: {
|
|
22
|
+
title: 'Setări Cookie-uri',
|
|
23
|
+
tabs: {
|
|
24
|
+
privacy: 'Confidențialitate'
|
|
25
|
+
},
|
|
26
|
+
buttons: {
|
|
27
|
+
acceptAll: 'Acceptă toate',
|
|
28
|
+
rejectAll: 'Respinge toate',
|
|
29
|
+
acceptSelection: 'Salvează selecția'
|
|
30
|
+
},
|
|
31
|
+
links: {
|
|
32
|
+
moreInfo: 'Mai multe informații',
|
|
33
|
+
cookieDetails: 'Detalii cookie-uri'
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
categories: {
|
|
37
|
+
necessary: {
|
|
38
|
+
label: 'Necesare',
|
|
39
|
+
description: 'Cookie-uri esențiale pentru funcționarea site-ului'
|
|
40
|
+
},
|
|
41
|
+
analytics: {
|
|
42
|
+
label: 'Analiză',
|
|
43
|
+
description: 'Cookie-uri pentru analiza traficului și comportamentului utilizatorilor'
|
|
44
|
+
},
|
|
45
|
+
marketing: {
|
|
46
|
+
label: 'Marketing',
|
|
47
|
+
description: 'Cookie-uri pentru publicitate personalizată'
|
|
48
|
+
},
|
|
49
|
+
preferences: {
|
|
50
|
+
label: 'Preferințe',
|
|
51
|
+
description: 'Cookie-uri pentru salvarea preferințelor utilizatorului'
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CMP Plugin Base Class
|
|
3
|
+
* @module CMPPlugin
|
|
4
|
+
*
|
|
5
|
+
* Base class for all CMP plugins
|
|
6
|
+
* Plugins can extend CMP functionality without modifying core
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export class CMPPlugin {
|
|
10
|
+
constructor(config = {}) {
|
|
11
|
+
this.config = config
|
|
12
|
+
this.cmp = null
|
|
13
|
+
this.isInitialized = false
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Get plugin name
|
|
18
|
+
* @returns {string}
|
|
19
|
+
*/
|
|
20
|
+
get name() {
|
|
21
|
+
return this.constructor.name
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Get plugin version
|
|
26
|
+
* @returns {string}
|
|
27
|
+
*/
|
|
28
|
+
get version() {
|
|
29
|
+
return '1.0.0'
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Initialize plugin
|
|
34
|
+
* Called when plugin is registered
|
|
35
|
+
* @param {Object} cmpInstance - CMP instance
|
|
36
|
+
*/
|
|
37
|
+
init(cmpInstance) {
|
|
38
|
+
this.cmp = cmpInstance
|
|
39
|
+
this.isInitialized = true
|
|
40
|
+
this._debug('Plugin initialized')
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Lifecycle: Before CMP initialization
|
|
45
|
+
*/
|
|
46
|
+
beforeInit() {
|
|
47
|
+
// Override in subclass
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Lifecycle: After CMP initialization
|
|
52
|
+
*/
|
|
53
|
+
afterInit() {
|
|
54
|
+
// Override in subclass
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Lifecycle: Before consent banner shown
|
|
59
|
+
*/
|
|
60
|
+
beforeBannerShow() {
|
|
61
|
+
// Override in subclass
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Lifecycle: After consent banner shown
|
|
66
|
+
*/
|
|
67
|
+
afterBannerShow() {
|
|
68
|
+
// Override in subclass
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Lifecycle: Before consent saved
|
|
73
|
+
* @param {Object} consent - Consent data
|
|
74
|
+
* @returns {Object} Modified consent (or original)
|
|
75
|
+
*/
|
|
76
|
+
beforeConsentSave(consent) {
|
|
77
|
+
// Override in subclass
|
|
78
|
+
return consent
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Lifecycle: After consent saved
|
|
83
|
+
* @param {Object} consent - Saved consent data
|
|
84
|
+
*/
|
|
85
|
+
afterConsentSave(consent) {
|
|
86
|
+
// Override in subclass
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Event: Consent changed
|
|
91
|
+
* @param {Object} data - { consent, categories }
|
|
92
|
+
*/
|
|
93
|
+
onConsentChange(data) {
|
|
94
|
+
// Override in subclass
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Event: Consent accepted
|
|
99
|
+
* @param {Object} data - { consent, categories }
|
|
100
|
+
*/
|
|
101
|
+
onConsentAccepted(data) {
|
|
102
|
+
// Override in subclass
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Event: Consent rejected
|
|
107
|
+
* @param {Object} data - { consent, categories }
|
|
108
|
+
*/
|
|
109
|
+
onConsentRejected(data) {
|
|
110
|
+
// Override in subclass
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Event: Consent expired
|
|
115
|
+
*/
|
|
116
|
+
onConsentExpired() {
|
|
117
|
+
// Override in subclass
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Event: Script loaded
|
|
122
|
+
* @param {Object} script - Script info
|
|
123
|
+
*/
|
|
124
|
+
onScriptLoaded(script) {
|
|
125
|
+
// Override in subclass
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Event: Tracker detected
|
|
130
|
+
* @param {Object} tracker - Tracker info
|
|
131
|
+
*/
|
|
132
|
+
onTrackerDetected(tracker) {
|
|
133
|
+
// Override in subclass
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Cleanup plugin
|
|
138
|
+
* Called when plugin is unregistered
|
|
139
|
+
*/
|
|
140
|
+
destroy() {
|
|
141
|
+
this.isInitialized = false
|
|
142
|
+
this.cmp = null
|
|
143
|
+
this._debug('Plugin destroyed')
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Get CMP API
|
|
148
|
+
* @returns {Object}
|
|
149
|
+
*/
|
|
150
|
+
getAPI() {
|
|
151
|
+
return this.cmp?.api || {}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Get consent
|
|
156
|
+
* @returns {Object|null}
|
|
157
|
+
*/
|
|
158
|
+
getConsent() {
|
|
159
|
+
return this.cmp?.getConsent() || null
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Check category consent
|
|
164
|
+
* @param {string} category
|
|
165
|
+
* @returns {boolean}
|
|
166
|
+
*/
|
|
167
|
+
hasCategoryConsent(category) {
|
|
168
|
+
return this.cmp?.hasCategoryConsent(category) || false
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Emit custom event
|
|
173
|
+
* @param {string} eventName
|
|
174
|
+
* @param {Object} data
|
|
175
|
+
*/
|
|
176
|
+
emit(eventName, data = {}) {
|
|
177
|
+
if (typeof window !== 'undefined') {
|
|
178
|
+
window.dispatchEvent(new CustomEvent(`cmp:plugin:${eventName}`, {
|
|
179
|
+
detail: { plugin: this.name, ...data }
|
|
180
|
+
}))
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
_debug(...args) {
|
|
185
|
+
// Debug disabled
|
|
186
|
+
}
|
|
187
|
+
}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin Manager
|
|
3
|
+
* @module PluginManager
|
|
4
|
+
*
|
|
5
|
+
* Manages CMP plugins lifecycle and events
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export class PluginManager {
|
|
9
|
+
constructor(cmpInstance) {
|
|
10
|
+
this.cmp = cmpInstance
|
|
11
|
+
this.plugins = new Map() // name -> plugin instance
|
|
12
|
+
this.hooks = {
|
|
13
|
+
beforeInit: [],
|
|
14
|
+
afterInit: [],
|
|
15
|
+
beforeBannerShow: [],
|
|
16
|
+
afterBannerShow: [],
|
|
17
|
+
beforeConsentSave: [],
|
|
18
|
+
afterConsentSave: []
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Register plugin
|
|
24
|
+
* @param {CMPPlugin} plugin - Plugin instance
|
|
25
|
+
* @returns {boolean}
|
|
26
|
+
*/
|
|
27
|
+
register(plugin) {
|
|
28
|
+
if (!plugin || !plugin.name) return false
|
|
29
|
+
if (this.plugins.has(plugin.name)) return false
|
|
30
|
+
|
|
31
|
+
// Initialize plugin
|
|
32
|
+
plugin.init(this.cmp)
|
|
33
|
+
|
|
34
|
+
// Store plugin
|
|
35
|
+
this.plugins.set(plugin.name, plugin)
|
|
36
|
+
|
|
37
|
+
// Register lifecycle hooks
|
|
38
|
+
this._registerHooks(plugin)
|
|
39
|
+
|
|
40
|
+
// Setup event listeners
|
|
41
|
+
this._setupEventListeners(plugin)
|
|
42
|
+
|
|
43
|
+
this._debug(`Plugin "${plugin.name}" registered`)
|
|
44
|
+
return true
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Unregister plugin
|
|
49
|
+
* @param {string} pluginName
|
|
50
|
+
* @returns {boolean}
|
|
51
|
+
*/
|
|
52
|
+
unregister(pluginName) {
|
|
53
|
+
const plugin = this.plugins.get(pluginName)
|
|
54
|
+
if (!plugin) {
|
|
55
|
+
return false
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Cleanup plugin
|
|
59
|
+
plugin.destroy()
|
|
60
|
+
|
|
61
|
+
// Remove from hooks
|
|
62
|
+
this._unregisterHooks(plugin)
|
|
63
|
+
|
|
64
|
+
// Remove plugin
|
|
65
|
+
this.plugins.delete(pluginName)
|
|
66
|
+
|
|
67
|
+
this._debug(`Plugin "${pluginName}" unregistered`)
|
|
68
|
+
return true
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Get plugin by name
|
|
73
|
+
* @param {string} pluginName
|
|
74
|
+
* @returns {CMPPlugin|null}
|
|
75
|
+
*/
|
|
76
|
+
get(pluginName) {
|
|
77
|
+
return this.plugins.get(pluginName) || null
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Get all plugins
|
|
82
|
+
* @returns {Array}
|
|
83
|
+
*/
|
|
84
|
+
getAll() {
|
|
85
|
+
return Array.from(this.plugins.values())
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Check if plugin is registered
|
|
90
|
+
* @param {string} pluginName
|
|
91
|
+
* @returns {boolean}
|
|
92
|
+
*/
|
|
93
|
+
has(pluginName) {
|
|
94
|
+
return this.plugins.has(pluginName)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Execute lifecycle hook
|
|
99
|
+
* @param {string} hookName
|
|
100
|
+
* @param {*} data
|
|
101
|
+
* @returns {*}
|
|
102
|
+
*/
|
|
103
|
+
async executeHook(hookName, data = null) {
|
|
104
|
+
const hooks = this.hooks[hookName] || []
|
|
105
|
+
|
|
106
|
+
let result = data
|
|
107
|
+
|
|
108
|
+
for (const hook of hooks) {
|
|
109
|
+
try {
|
|
110
|
+
const hookResult = await hook(result)
|
|
111
|
+
// For beforeConsentSave, allow modification
|
|
112
|
+
if (hookName === 'beforeConsentSave' && hookResult !== undefined) {
|
|
113
|
+
result = hookResult
|
|
114
|
+
}
|
|
115
|
+
} catch (error) {
|
|
116
|
+
// Silent error
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return result
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Register plugin hooks
|
|
125
|
+
* @private
|
|
126
|
+
*/
|
|
127
|
+
_registerHooks(plugin) {
|
|
128
|
+
// beforeInit
|
|
129
|
+
if (typeof plugin.beforeInit === 'function') {
|
|
130
|
+
this.hooks.beforeInit.push(() => plugin.beforeInit())
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// afterInit
|
|
134
|
+
if (typeof plugin.afterInit === 'function') {
|
|
135
|
+
this.hooks.afterInit.push(() => plugin.afterInit())
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// beforeBannerShow
|
|
139
|
+
if (typeof plugin.beforeBannerShow === 'function') {
|
|
140
|
+
this.hooks.beforeBannerShow.push(() => plugin.beforeBannerShow())
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// afterBannerShow
|
|
144
|
+
if (typeof plugin.afterBannerShow === 'function') {
|
|
145
|
+
this.hooks.afterBannerShow.push(() => plugin.afterBannerShow())
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// beforeConsentSave
|
|
149
|
+
if (typeof plugin.beforeConsentSave === 'function') {
|
|
150
|
+
this.hooks.beforeConsentSave.push((consent) => plugin.beforeConsentSave(consent))
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// afterConsentSave
|
|
154
|
+
if (typeof plugin.afterConsentSave === 'function') {
|
|
155
|
+
this.hooks.afterConsentSave.push((consent) => plugin.afterConsentSave(consent))
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Unregister plugin hooks
|
|
161
|
+
* @private
|
|
162
|
+
*/
|
|
163
|
+
_unregisterHooks(plugin) {
|
|
164
|
+
Object.keys(this.hooks).forEach(hookName => {
|
|
165
|
+
this.hooks[hookName] = this.hooks[hookName].filter(hook => {
|
|
166
|
+
// Remove hooks that belong to this plugin
|
|
167
|
+
return hook.toString().indexOf(plugin.name) === -1
|
|
168
|
+
})
|
|
169
|
+
})
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Setup event listeners for plugin
|
|
174
|
+
* @private
|
|
175
|
+
*/
|
|
176
|
+
_setupEventListeners(plugin) {
|
|
177
|
+
// Consent changed
|
|
178
|
+
if (typeof plugin.onConsentChange === 'function') {
|
|
179
|
+
this.cmp.on('consentChanged', (data) => plugin.onConsentChange(data))
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Consent accepted
|
|
183
|
+
if (typeof plugin.onConsentAccepted === 'function') {
|
|
184
|
+
this.cmp.on('consentAccepted', (data) => plugin.onConsentAccepted(data))
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Consent rejected
|
|
188
|
+
if (typeof plugin.onConsentRejected === 'function') {
|
|
189
|
+
this.cmp.on('consentRejected', (data) => plugin.onConsentRejected(data))
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Consent expired
|
|
193
|
+
if (typeof plugin.onConsentExpired === 'function') {
|
|
194
|
+
this.cmp.on('consentExpired', () => plugin.onConsentExpired())
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Script loaded
|
|
198
|
+
if (typeof plugin.onScriptLoaded === 'function') {
|
|
199
|
+
if (typeof window !== 'undefined') {
|
|
200
|
+
window.addEventListener('cookie-consent:script-loaded', (e) => {
|
|
201
|
+
plugin.onScriptLoaded(e.detail)
|
|
202
|
+
})
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Tracker detected
|
|
207
|
+
if (typeof plugin.onTrackerDetected === 'function') {
|
|
208
|
+
if (typeof window !== 'undefined') {
|
|
209
|
+
window.addEventListener('cookie-consent:tracker-detected', (e) => {
|
|
210
|
+
plugin.onTrackerDetected(e.detail)
|
|
211
|
+
})
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Get plugin stats
|
|
218
|
+
* @returns {Object}
|
|
219
|
+
*/
|
|
220
|
+
getStats() {
|
|
221
|
+
return {
|
|
222
|
+
total: this.plugins.size,
|
|
223
|
+
plugins: this.getAll().map(p => ({
|
|
224
|
+
name: p.name,
|
|
225
|
+
version: p.version,
|
|
226
|
+
initialized: p.isInitialized
|
|
227
|
+
}))
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
_debug(...args) {
|
|
232
|
+
// Debug disabled
|
|
233
|
+
}
|
|
234
|
+
}
|