Skip to content

Commit

Permalink
Merge pull request #2 from generoi/feature/tcf-api
Browse files Browse the repository at this point in the history
Feature/tcf api
  • Loading branch information
oxyc authored Jun 13, 2024
2 parents 629e8a9 + 3227bb9 commit 2437671
Show file tree
Hide file tree
Showing 17 changed files with 204 additions and 28 deletions.
12 changes: 7 additions & 5 deletions assets/scripts/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export const NECESSARY_COOKIES = [
* @returns {boolean} if user has granted all the consents
*/
export function hasConsent(...consents) {
const consentData = getConsentData();
const consentData = window.gdsCmp.getConsentData();

return consents.every((consent) => {
return consentData.consents?.[consent] === true;
Expand All @@ -49,6 +49,8 @@ export function hasConsent(...consents) {

/**
* Return the consent data object read from the current cookie.
*
* @returns {ConsentData}
*/
export function getConsentData() {
return parseConsentString(
Expand Down Expand Up @@ -139,7 +141,7 @@ export function updateConsentMode(synchronous = false) {
* @returns {void}
*/
export function googleConsentMode() {
const consentData = getConsentData();
const consentData = window.gdsCmp.getConsentData();

const gtmConsents = {
ad_storage: 'denied',
Expand Down Expand Up @@ -177,7 +179,7 @@ export function metaConsentMode() {
return;
}

if (hasConsent(AD_STORAGE_CONSENT, ANALYTICS_STORAGE_CONSENT)) {
if (window.gdsCmp.hasConsent(AD_STORAGE_CONSENT, ANALYTICS_STORAGE_CONSENT)) {
window.fbq('consent', 'grant');
console.debug('meta pixel consent granted');
} else {
Expand All @@ -196,7 +198,7 @@ export function tiktokConsentMode() {
return;
}

if (hasConsent(AD_STORAGE_CONSENT, ANALYTICS_STORAGE_CONSENT)) {
if (window.gdsCmp.hasConsent(AD_STORAGE_CONSENT, ANALYTICS_STORAGE_CONSENT)) {
window.ttq.enableCookie();
console.debug('tiktok enable cookies.');
} else {
Expand All @@ -222,7 +224,7 @@ export function wpConsentMode() {

window.wp_set_consent(
consent.wpConsentApiCategory,
hasConsent(consent.id) ? 'allow' : 'deny'
window.gdsCmp.hasConsent(consent.id) ? 'allow' : 'deny'
);
}
}
30 changes: 23 additions & 7 deletions assets/scripts/embed/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { EVENT_CONSENT, NECESSARY_STORAGE_CONSENT } from '../api';
import './index.scss';

const EVENT_BEFORE_REPLACE = 'gds-cmp-embed.before-replace';
const EVENT_REPLACED = 'gds-cmp-embed.replaced';
const DEFAULT_CONSENT = NECESSARY_STORAGE_CONSENT;
const DEFAULT_TAG_NAME = 'iframe';
Expand All @@ -17,14 +18,16 @@ export class CmpEmbed extends HTMLElement {
connectedCallback() {
this.render();

if (window.gdsCmp?.hasConsent && window.gdsCmp.hasConsent(...this.consent)) {
const onConsentEvent = () => {
if (window.gdsCmp.hasConsent(...this.consent)) {
this.onConsentGiven();
}
}

window.addEventListener(EVENT_CONSENT, onConsentEvent);
// If consent has already been given
if (window.gdsCmp?.hasConsent?.(...this.consent)) {
this.onConsentGiven();
} else {
window.addEventListener(EVENT_CONSENT, () => {
if (window.gdsCmp.hasConsent(...this.consent)) {
this.onConsentGiven();
}
});
}
}

Expand Down Expand Up @@ -57,6 +60,19 @@ export class CmpEmbed extends HTMLElement {
}

onConsentGiven() {
const isReplaceAllowed = this.dispatchEvent(new CustomEvent(EVENT_BEFORE_REPLACE, {
cancelable: true,
bubbles: true,
}));

if (!isReplaceAllowed) {
console.debug('embed replace cancelled');
return;
}
this.replaceElement();
}

replaceElement() {
const newTag = document.createElement(this.as);
for (const attribute of this.getAttributeNames()) {
if (['consent', 'as'].includes(attribute)) {
Expand Down
18 changes: 10 additions & 8 deletions assets/scripts/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,17 @@ function ready(fn) {
document.addEventListener('DOMContentLoaded', fn);
}

window.gdsCmp = {
hasConsent,
getConsentData,
evaluateTags,
...(window.gdsCmp || {}),
};

ready(() => {
// Initialize the cookie consent banenr and expose window.gdsCmp object.
const cookieConsentContainer = document.querySelector('.cookie-consent');
if (cookieConsentContainer) {
window.gdsCmp = {
...(window.gdsCmp || {}),
hasConsent,
evaluateTags,
};
window.gdsCmp = {
...window.gdsCmp,
...cookieConsent(cookieConsentContainer),
Expand All @@ -38,15 +40,15 @@ ready(() => {
for (const link of document.querySelectorAll('.js-gds-cmp-show')) {
link.addEventListener('click', function (e) {
e.preventDefault();
cookieConsentContainer.show();
window.gdCmp.show?.();
});
}

// Attach open click listeners to all elements with data-gds-cmp-trigger="show|hide|withdraw"
document.addEventListener('click', function ({target}) {
if (target.matches('[data-gds-cmp-trigger]')) {
const trigger = target.dataset.gdsCmpTrigger;
cookieConsentContainer[trigger]?.();
window.gdCmp[trigger]?.();
}
}, {passive: true});
});
Expand Down Expand Up @@ -91,7 +93,7 @@ window.addEventListener(EVENT_CONSENT, () => evaluateTags());

// Add has-gds-cmp-consent--{'marketing'|'analytics'|'necessary'} classes to the body element
window.addEventListener(EVENT_CONSENT, () => {
const consentData = getConsentData();
const consentData = window.gdsCmp.getConsentData();

for (const [consent, value] of Object.entries(consentData.consents)) {
document.body.classList.toggle(`has-gds-cmp-consent--${consent}`, value);
Expand Down
103 changes: 103 additions & 0 deletions assets/scripts/tcfapi.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import {
AD_STORAGE_CONSENT,
ANALYTICS_STORAGE_CONSENT,
EVENT_CONSENT,
NECESSARY_STORAGE_CONSENT,
PREFERENCES_STORAGE_CONSENT
} from './api';

/**
* @param {TCData} tcData
* @returns {ConsentData}
*/
function getTcfMappedConsentData({purpose}) {
const {consents} = purpose;

const hasStorageConsent = consents[1];
const hasRegularAdsConsent = consents[2];
const hasPersonalizedAdProfileConsent = consents[3];
const hasPersonalizedAdsConsent = consents[4];
const hasPersonalizedContentProfileConsent = consents[5];
const hasPersonalizedSelectionConsent = consents[6];
const hasAdMeasurementConsent = consents[7];
const hasContentMeasurementConsent = consents[8];
const hasMarketResearchConsent = consents[9];
const hasProductDevelopmentConsent = consents[10];

const hasNecessaryConsent = (
true
);

const hasPreferencesConsent = (
hasStorageConsent
);

const hasStatisticsConsent = (
hasStorageConsent &&
hasAdMeasurementConsent &&
// hasContentMeasurementConsent &&
hasMarketResearchConsent
);

const hasMarketingConsent = (
hasStorageConsent &&
hasRegularAdsConsent &&
hasPersonalizedAdProfileConsent &&
hasPersonalizedAdsConsent
)

return {
consents: {
[NECESSARY_STORAGE_CONSENT]: hasNecessaryConsent,
[PREFERENCES_STORAGE_CONSENT]: hasPreferencesConsent,
[AD_STORAGE_CONSENT]: hasMarketingConsent,
[ANALYTICS_STORAGE_CONSENT]: hasStatisticsConsent,
},
version: undefined,
}
}

function getConsentData() {
return window.gdsCmp?.tcfMappedConsents;
}

function tcfapi() {
if (!window.__tcfapi) {
return setTimeout(() => tcfapi(...arguments), 100);
}
window.__tcfapi(...arguments);
}

function runEvent() {
window.dispatchEvent(new CustomEvent(EVENT_CONSENT));
for (const [consent, value] of Object.entries(getConsentData().consents)) {
if (value) {
window.dispatchEvent(new CustomEvent(`${EVENT_CONSENT}.${consent}`));
}
}
}

window.gdsCmp = {
...(window.gdsCmp || {}),
tcfMappedConsents: {
version: undefined,
consents: {},
},
getConsentData,
show() {
tcfapi('displayConsentUi', 2, () => {});
},
hide() {
tcfapi('displayConsentUi', 2, () => {});
},
withdraw() {
// @TODO
}
}

tcfapi('addEventListener', 2, (tcData, success) => {
if (success && ['tcloaded', 'useractioncomplete'].includes(tcData.eventStatus)) {
window.gdsCmp.tcfMappedConsents = getTcfMappedConsentData(tcData);
runEvent();
}
});
2 changes: 1 addition & 1 deletion dist/editor.asset.php
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<?php return array('dependencies' => array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => 'e064a2729d9d042442a81e09bf0482eb');
<?php return array('dependencies' => array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => 'a50f67649c9c1c5300c2d05e245f7589');
2 changes: 1 addition & 1 deletion dist/editor.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 2437671

Please sign in to comment.