@schibsted/sourcepoint
Version:
Package containing scripts used by Schibsteds' sites to integrate with Sourcepoint CMP
185 lines (157 loc) • 6.57 kB
JavaScript
import { debug } from '../utils.js';
import { onInitPrivacyManagerView, getConsentObjectForBrands } from '../pulse/index.js';
export function createConsentApi(_window, config, type) {
if (!config || !config.groupPmId) {
throw new Error('groupPmId is required');
}
const CMP = {
ADVERTISING: 'CMP:advertising',
ANALYTICS: 'CMP:analytics',
MARKETING: 'CMP:marketing',
PERSONALISATION: 'CMP:personalisation',
PERFORMANCE_MARKETING: 'CMP:performance_marketing',
};
let anySubscribers = [];
const subscribers = {};
subscribers[CMP.ADVERTISING] = [];
subscribers[CMP.ANALYTICS] = [];
subscribers[CMP.MARKETING] = [];
subscribers[CMP.PERSONALISATION] = [];
subscribers[CMP.PERFORMANCE_MARKETING] = [];
function getPermissionFromCache(category) {
debug(`${type}: getPermissionFromCache(category=${category})`);
return _window.localStorage.getItem(category);
}
let notifyAnyTimerFlag = null; // Variable to keep track of the timer
/**
* Notify all anySubscribers, debounce by 10ms to make sure it triggers only once for each change
* @returns
*/
function throttledNotifyAnyChange() {
// If there is already a timer running, return
if (notifyAnyTimerFlag !== null) {
return;
}
notifyAnyTimerFlag = setTimeout(() => {
const _subscribers = anySubscribers;
for (let i = 0; i < _subscribers.length; i++) {
_subscribers[i]();
}
// Set a timer to clear the timerFlag after the specified delay
notifyAnyTimerFlag = null; // Clear the timerFlag to allow the main function to be executed again
}, 10);
}
const self = {
subscribers: subscribers,
consentedCallback: [],
TCFCallbacks: [],
showPrivacyManager: function () {
debug('${type}: showPrivacyManager()');
onInitPrivacyManagerView();
_window._sp_.gdpr.loadPrivacyManagerModal(config.groupPmId);
},
getPermissionSync: function (category) {
debug(`${type}: getPermissionSync(category=${category})`);
return getPermissionFromCache(category);
},
getPermission: function (category, callback) {
debug(`${type}: getPermission(category=${category})`);
const unsub = self.subscribe(
category,
(function () {
let beenCalled = false;
return (permissionValue) => {
if (beenCalled) {
if (typeof unsub === 'function') {
unsub();
}
return;
}
beenCalled = true;
callback(permissionValue);
callback = function () {};
};
})()
);
},
notify: (function (prevValues) {
return (category, value) => {
if (prevValues[category] === value) {
debug(`${type}: notify(category=${category}, value=${value}) - IGNORED`);
return;
}
throttledNotifyAnyChange();
debug(`${type}: notify(category=${category}, value=${value})`);
prevValues[category] = value;
const _subscribers = self.subscribers[category];
for (let i = 0; i < _subscribers.length; i++) {
_subscribers[i](value);
}
};
})({
[CMP.ADVERTISING]: getPermissionFromCache(CMP.ADVERTISING),
[CMP.ANALYTICS]: getPermissionFromCache(CMP.ANALYTICS),
[CMP.MARKETING]: getPermissionFromCache(CMP.MARKETING),
[CMP.PERSONALISATION]: getPermissionFromCache(CMP.PERSONALISATION),
[CMP.PERFORMANCE_MARKETING]: getPermissionFromCache(CMP.PERFORMANCE_MARKETING),
}),
subscribe: function (category, callback) {
debug(`${type}: subscribe(category=${category})`);
if (!self.subscribers[category]) {
console.error('Unable to subscribe - undefined consent category!');
return;
}
self.subscribers[category].push(callback);
const value = getPermissionFromCache(category);
if (value !== null) {
callback(value);
}
return () => {
self.subscribers[category] = self.subscribers[category].filter(
(cb) => cb !== callback
);
};
},
subscribeAny: function (callback) {
debug(`subscribeAny`);
anySubscribers.push(callback);
return () => {
anySubscribers = anySubscribers.filter((cb) => cb !== callback);
};
},
getCachedOrDefaultConsentsForPulse: function (obj) {
return getConsentObjectForBrands(_window, obj);
},
isConsentedToAll: function (callback) {
self.consentedCallback.push(callback);
},
getConsentedToAllSync: function () {
const consentString = `_sp_user_consent_${config.propertyId}`;
const userConsentCookie = getPermissionFromCache(consentString);
try {
const schibstedConsents = Object.keys(localStorage).filter((e) =>
e.startsWith('CMP:')
);
// isConsentedAll initial value is false and we return null if no consent was given
if (schibstedConsents.length === 0) {
return null;
}
const consentStatus = JSON.parse(userConsentCookie)?.gdpr?.consentStatus;
const isVLChange =
consentStatus?.vendorListAdditions || consentStatus?.legalBasisChanges;
if (isVLChange) {
return null;
}
const consentedValue = consentStatus?.consentedAll;
return consentedValue === undefined ? null : consentedValue;
} catch {
return null;
}
},
onTcfReady: function (callback) {
self.TCFCallbacks.push(callback);
},
};
_window._SourcePoint_Consent_Callback = self.notify;
return self;
}