diff --git a/README.md b/README.md index 96bcb0a..e0660dd 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ This module currently supports the following providers - CookieBot - CookieInformation +- CookieScript ## Documentation diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index ff638c1..8d7e673 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -39,6 +39,10 @@ export default defineConfig({ text: 'CookieInformation', link: '/documentation/providers/cookieinformation', }, + { + text: 'CookieScript', + link: '/documentation/providers/cookiescript', + }, ], }, ], diff --git a/docs/documentation.md b/docs/documentation.md index abc3efb..54722b9 100644 --- a/docs/documentation.md +++ b/docs/documentation.md @@ -59,4 +59,14 @@ export default defineNuxtConfig({ } }) ``` + +```typescript [CookieScript] +export default defineNuxtConfig({ + modules: ['@weareheavy/nuxt-cookie-consent'] + cookieConsent: { + provider: 'cookiescript', + id: '00000000000000000000000000000000' // Replace with you "id" from CookieScript + } +}) +``` ::: \ No newline at end of file diff --git a/docs/documentation/configuration.md b/docs/documentation/configuration.md index 2317d37..9e4b8b4 100644 --- a/docs/documentation/configuration.md +++ b/docs/documentation/configuration.md @@ -2,14 +2,14 @@ To start using the module you have to have [configured a provider](/documentation#configure-your-provider). -Currently this module supports [Cookieinformation](https://cookieinformation.com) and [CookieBot](https://cookiebot.com). An account for the respective service is required. +Currently this module supports [Cookieinformation](https://cookieinformation.com), [CookieBot](https://cookiebot.com) and [CookieScript](https://cookiescript.com). An account for the respective service is required. ## General configuration -| Property |  Type | Default |  Description | -| -------- | ---------- | ------- | -------------------------------------- | -| init | `Boolean` |  `true` | Initialize the provider script on load | -|  dev |  `Boolean` | `false` | Run code when in development mode | +| Property |  Type | Default |  Description | +| -------- | --------- | ------- | -------------------------------------- | +| dev | `Boolean` | `false` | Run code when in development mode | +| init | `Boolean` | `true` | Initialize the provider script on load | ## Type declaration <<< @/../src/runtime/types/types.d.ts#moduleGeneralOptions{typescript} diff --git a/docs/documentation/providers.md b/docs/documentation/providers.md index fff84dc..7ec8743 100644 --- a/docs/documentation/providers.md +++ b/docs/documentation/providers.md @@ -2,10 +2,11 @@ This module aims to support as many providers as possible, and currently have implementations for these: -|  Provider | Alias |  Website | -| --------------------------------------------------------------- | ------------------- | ------------------------------------------------------ | -| [CookieBot](/documentation/providers/cookiebot) | `cookiebot` | [https://cookiebot.com](https://cookiebot.com) | -| [CookieInformation](/documentation/providers/cookieinformation) | `cookieinformation` | [https://cookieinformation.com](https://cookiebot.com) | +|  Provider | Alias |  Website | +| --------------------------------------------------------------- | ------------------- | -------------------------------------------------------------- | +| [CookieBot](/documentation/providers/cookiebot) | `cookiebot` | [https://cookiebot.com](https://cookiebot.com) | +| [CookieInformation](/documentation/providers/cookieinformation) | `cookieinformation` | [https://cookieinformation.com](https://cookieinformation.com) | +| [CookieScript](/documentation/providers/cookiescript) | `cookiescript` | [https://cookiescript.com](https://cookiescript.com) |
diff --git a/docs/documentation/providers/cookiescript.md b/docs/documentation/providers/cookiescript.md new file mode 100644 index 0000000..9f44c71 --- /dev/null +++ b/docs/documentation/providers/cookiescript.md @@ -0,0 +1,23 @@ +# CookieScript + +Websie: [cookiescript.com](https://cookiescript.com) + + +## Configuration + +```typescript +export default defineNuxtConfig({ + cookieConsent: { + provider: 'cookiescript', + id: '00000000000000000000000000000000', // Replace with you own id + } +}) +``` + +## Consent mode +By default CookieScript enables Consent Mode (opt-out). + +[Read more about Google Consent Mode in CookieScript →](https://help.cookie-script.com/en/google-analytics/google-consent-mode-implementation-instructions) + +## Type Declaration +<<< @/../src/runtime/types/types.d.ts#moduleGeneralOptionsCookieScript{typescript} diff --git a/playground/nuxt.config.ts b/playground/nuxt.config.ts index 84e4716..fce1169 100644 --- a/playground/nuxt.config.ts +++ b/playground/nuxt.config.ts @@ -2,7 +2,8 @@ export default defineNuxtConfig({ modules: ['../src/module'], devtools: { enabled: true }, cookieConsent: { - provider: 'cookieinformation', + provider: 'cookiescript', + id: '00000000000000000000000000000000', // cbid: '00000000-0000-0000-0000-000000000000', dev: true, scripts: { diff --git a/src/module.ts b/src/module.ts index 9c840a6..c01c35a 100644 --- a/src/module.ts +++ b/src/module.ts @@ -12,7 +12,11 @@ import type { NuxtCookieConsentOptionsProviderCookieInformation, } from './runtime/types/types' -export const nuxtConsentProviders = ['cookieinformation', 'cookiebot'] +export const nuxtConsentProviders = [ + 'cookieinformation', + 'cookiebot', + 'cookiescript', +] const module: NuxtModule = defineNuxtModule({ diff --git a/src/runtime/components/ConsentPolicy.cookiescript.client.ts b/src/runtime/components/ConsentPolicy.cookiescript.client.ts new file mode 100644 index 0000000..a38885b --- /dev/null +++ b/src/runtime/components/ConsentPolicy.cookiescript.client.ts @@ -0,0 +1,30 @@ +import { defineComponent, h, Fragment } from 'vue' +import { useRuntimeConfig } from '#imports' + +export default defineComponent( + () => { + return () => { + const { cookieConsent: config } = useRuntimeConfig().public + + // @ts-ignore + const id = config.id + + if (!id) { + return h(Fragment, { key: 'CookiePolicy' }) + } + + return h(Fragment, { key: 'CookiePolicy' }, [ + h('script', { + id: 'CookiePolicy', + src: `https://report.cookie-script.com/r/${id}.js`, + type: 'text/javascript', + 'data-cookiescriptreport': 'report', + charset: 'UTF-8', + }), + ]) + } + }, + { + props: [], + }, +) diff --git a/src/runtime/composables/useCookieConsent.ts b/src/runtime/composables/useCookieConsent.ts index ab5c637..f23cfc1 100644 --- a/src/runtime/composables/useCookieConsent.ts +++ b/src/runtime/composables/useCookieConsent.ts @@ -22,12 +22,20 @@ export function useCookieConsent(): NuxtCookieConsentUseCookieConsent { export function cookieConsentRenew(): void { if (import.meta.client) { - window?.CookieConsent?.renew?.() + if (typeof window?.CookieScript?.instance?.show === 'function') { + window?.CookieScript?.instance?.show?.() + } else { + window?.CookieConsent?.renew?.() + } } } export function cookieConsentShow(): void { if (import.meta.client) { - window?.CookieConsent?.show?.() + if (typeof window?.CookieScript?.instance?.show === 'function') { + window?.CookieScript?.instance?.show?.() + } else { + window?.CookieConsent?.show?.() + } } } diff --git a/src/runtime/plugins/cookiescript.plugin.ts b/src/runtime/plugins/cookiescript.plugin.ts new file mode 100644 index 0000000..8b34f1d --- /dev/null +++ b/src/runtime/plugins/cookiescript.plugin.ts @@ -0,0 +1,112 @@ +import { + defineNuxtPlugin, + useCookie, + useCookieConsent, + useHead, + useRuntimeConfig, +} from '#imports' +import consola from 'consola' +import type { CookieScriptPayload } from '../types/types' +import { loadScripts } from '../utils/script.loader' +import { updateState } from '../utils/update.state' + +export default defineNuxtPlugin(() => { + const { cookieConsent: config } = useRuntimeConfig().public + + if (!config.init || (!config.dev && process.dev)) { + return + } + + if (config.init) { + // @ts-ignore + const id = config.id + + if (!id) { + consola.warn( + 'Unable to initialize CookieScript script: No CookieScript id provided. Please set the `id` option in "cookieConsent" in `nuxt.config.js`', + ) + } else { + useHead({ + script: [ + { + id: 'CookieScript', + src: `https://cdn.cookie-script.com/s/${id}.js`, + type: 'text/javascript', + tagPriority: 5, + }, + ], + }) + } + } + + const cookie = useCookie('CookieScriptConsent', { + decode: (value: string) => + JSON.parse( + decodeURIComponent(value || '{ "categories": [] }'), + ) as CookieScriptPayload | null, + }) + + const { state } = useCookieConsent() + + if (cookie.value) { + updateState(state, { + necessary: true, + functional: + cookie.value.categories?.includes('functionality') || + (cookie.value.categories == undefined && + cookie.value.action === 'accept') || + false, + statistic: + cookie.value.categories?.includes('performance') || + (cookie.value.categories == undefined && + cookie.value.action === 'accept') || + false, + marketing: + cookie.value.categories?.includes('targeting') || + (cookie.value.categories == undefined && + cookie.value.action === 'accept') || + false, + unclassified: + cookie.value.categories?.includes('unclassified') || + (cookie.value.categories == undefined && + cookie.value.action === 'accept') || + false, + }) + } + + if (import.meta.client) { + window.addEventListener('CookieScriptAccept', (e: any) => { + const categories = e.detail?.categories || [] + + updateState(state, { + necessary: true, + functional: categories.includes('functionality') || false, + statistic: categories.includes('performance') || false, + marketing: categories.includes('targeting') || false, + unclassified: categories.includes('unclassified') || false, + }) + }) + + window.addEventListener('CookieScriptReject', () => { + updateState(state, { + necessary: true, + functional: false, + statistic: false, + marketing: false, + unclassified: false, + }) + }) + + window.addEventListener('CookieScriptAcceptAll', () => { + updateState(state, { + necessary: true, + functional: true, + statistic: true, + marketing: true, + unclassified: true, + }) + }) + } + + loadScripts(config) +}) diff --git a/src/runtime/types/dom.d.ts b/src/runtime/types/dom.d.ts index 271c956..0e7a32c 100644 --- a/src/runtime/types/dom.d.ts +++ b/src/runtime/types/dom.d.ts @@ -2,6 +2,20 @@ interface Window { CookieInformation: CookieInformation CookieConsent: WindowCookieConsentInteractions Cookiebot: CookieBot + CookieScript: CookieScript +} + +// @see https://help.cookie-script.com/en/javascript-code-documentation/custom-functions +interface CookieScript { + instance: { + show: () => void + hide: () => void + currentState: () => void + categories: () => void + acceptAllAction: () => void + rejectAllAction: () => void + acceptAction: () => void + } } interface CookieInformation { diff --git a/src/runtime/types/types.d.ts b/src/runtime/types/types.d.ts index 76c745e..b07964b 100644 --- a/src/runtime/types/types.d.ts +++ b/src/runtime/types/types.d.ts @@ -17,6 +17,20 @@ interface CookieInformationPayload { user_agent: string } +interface CookieScriptPayload { + googleconsentmap: { + ad_storage: 'targeting' + analytics_storage: 'performance' + ad_personalization: 'targeting' + ad_user_data: 'targeting' + functionality_storage: 'functionality' + personalization_storage: 'functionality' + security_storage: 'functionality' + } + action?: 'accept' | 'reject' + categories?: string[] +} + // #region consentState export interface NuxtCookieConsentState { necessary: boolean @@ -147,9 +161,17 @@ export type NuxtCookieConsentOptionsProviderCookieBot = { } // #endregion moduleGeneralOptionsCookieBot +// #region moduleGeneralOptionsCookieScript +export type NuxtCookieConsentOptionsCookieScript = { + provider: 'cookiescript' + id: string +} +// #endregion moduleGeneralOptionsCookieScript + export type NuxtCookieConsentOptionsProvider = | NuxtCookieConsentOptionsProviderCookieBot | NuxtCookieConsentOptionsProviderCookieInformation + | NuxtCookieConsentOptionsCookieScript export type NuxtCookieConsentOptions = NuxtCookieConsentOptionsProvider & NuxtCookieConsentOptionsScripts &