UNPKG

@68publishers/cookie-consent

Version:

Cookie consent wrapper based on orestbida/cookieconsent with GTM integration.

434 lines (335 loc) 15.1 kB
import 'vanilla-cookieconsent/src/cookieconsent.js'; import pkg from '../package.json'; import { Config } from './Config/Config.mjs'; import { Storage } from './Storage/Storage.mjs'; import { StoragePool } from './Storage/StoragePool.mjs'; import { ConsentManager } from './ConsentManager.mjs'; import { Dictionary } from './Translation/Dictionary.mjs'; import { StylesheetLoader } from './Ui/StylesheetLoader.mjs'; import { ModalTriggerFactory } from './Ui/ModalTriggerFactory.mjs'; import { EventBus } from './EventBus/EventBus.mjs'; import { Events } from './EventBus/Events.mjs'; import { EventTrigger } from './Storage/EventTrigger.mjs'; import { User } from './User/User.mjs'; import { ThirdButtonAppender } from './Ui/ThirdButtonAppender.mjs'; import { CookieTables } from './CookieTable/CookieTables.mjs'; import { integrateCmpApi } from './Integration/CmpApiIntegration.mjs'; import sha256 from 'crypto-js/sha256.js'; import { checkVisibility } from './Ui/Utils.mjs'; const version = pkg.version; export class CookieConsentWrapper { constructor(gtag) { this._initializationTriggered = false; this._initialized = false; this._gtag = gtag; /** * @type {(CookieConsent & { * __updateModalFocusableData: () => void, * __getFocusableEdges: () => HTMLElement[]|undefined, * __generateFocusSpan: (number) => HTMLElement, * __isConsentModalExists: () => boolean, * __getFocusedModal: () => HTMLElement, * })|null} */ this._cookieConsent = null; this._scriptBasePath = ''; if (document.currentScript && document.currentScript.src) { const url = new URL(document.currentScript.src, window.location.origin); const pathname = url.pathname.substring(0, url.pathname.lastIndexOf('/')); this._scriptBasePath = url.origin + pathname; } this._config = new Config(this._scriptBasePath); this._storagePool = new StoragePool(); this._dictionary = new Dictionary(); this._eventBus = new EventBus(); this._cookieTables = new CookieTables(); this._eventTriggers = {}; this._user = User.createDefault(); this.utils = { checkVisibility, }; } get version() { return version; } get user() { return this._user; } get configurationExport() { let configuration = { version: this.version, config: this._config, storages: {}, dictionary: this._dictionary._catalogues, }; const storages = this._storagePool.all(); for (let index in storages) { const storage = storages[index]; configuration.storages[storage.name] = storage.config; } const configurationString = JSON.stringify(configuration); configuration = JSON.parse(configurationString); return { configuration: configuration, checksum: sha256(configurationString).toString(), }; } get cookieTables() { return this._cookieTables; } get consentCookieValue() { if (!this._cookieConsent.validConsent()) { return null; } const cookieName = this._config.pluginOptions.cookie_name; let cookieValue = document.cookie.match("(^|;)\\s*" + cookieName + "\\s*=\\s*([^;]+)"); return cookieValue ? cookieValue.pop() : null; } get consentCookieData() { const cookieName = this._config.pluginOptions.cookie_name; let cookieValue = document.cookie.match("(^|;)\\s*" + cookieName + "\\s*=\\s*([^;]+)"); cookieValue = cookieValue ? cookieValue.pop() : null; if (null === cookieValue) { return null; } try{ cookieValue = JSON.parse(cookieValue) } catch (e) { // eslint-disable-line no-unused-vars try { cookieValue = JSON.parse(decodeURIComponent(cookieValue)) } catch (e) { // eslint-disable-line no-unused-vars cookieValue = null; } } return cookieValue; } setStaticUserIdentity(id) { this._user = this.user.withStaticIdentity(id); } setPluginOptions(options) { this._config.pluginOptions.merge(options || {}); } setAutoClearOptions(options) { this._config.autoClearOptions.merge(options || {}); } setConsentModalOptions(options) { this._config.consentModalOptions.merge(options || {}); } setSettingsModalOptions(options) { this._config.settingsModalOptions.merge(options || {}); } setUiOptions(options) { this._config.uiOptions.merge(options || {}); } setCmpApiOptions(options) { this._config.cmpApiOptions.merge(options || {}); } addStorage(config) { this._storagePool.add(new Storage(config || {})); } addEventTrigger(name, storageNames, type = EventTrigger.TYPE_OR) { this._eventTriggers[name] = new EventTrigger(name, storageNames, type); } translate(locale, key) { return this._dictionary.translate(locale, key); } addTranslations(locale, translations) { this._dictionary.addTranslations(locale, translations || {}); } loadTranslations(localeOrUrl, override = false) { let url; let locale; if (localeOrUrl.startsWith('https://') || localeOrUrl.startsWith('http://')) { locale = localeOrUrl.split('/').pop().split('.').shift(); locale = 2 < locale.length ? locale[0] + locale[1] : locale; url = localeOrUrl; } else { locale = localeOrUrl; locale = 2 < locale.length ? locale[0] + locale[1] : locale; url = `${this._scriptBasePath}/translations/${locale}.json`; } return this._dictionary.loadTranslations(locale, url, override); } unwrap() { if (null === this._cookieConsent) { throw new Error('Cookie consent is not created, please call method CookieConsentWrapper.init().'); } return this._cookieConsent; } allowedCategory(name) { return this.unwrap().allowedCategory(name); } changeLocale(locale, force) { const plugin = this.unwrap(); this._eventBus.dispatch(Events.ON_LOCALE_CHANGE, locale); plugin.updateLanguage(locale, force); } on(event, callback, scope = null) { if (Events.ON_INIT === event && this._initialized && null !== this._cookieConsent) { callback.call(scope); return function () {}; } return this._eventBus.subscribe(event, callback, scope); } init(window, document) { if (this._initializationTriggered) { return; } const self = this; window.CookieConsentWrapper = self; if (!document) { return; } this._initializationTriggered = true; // load stylesheets StylesheetLoader.loadFromConfig(document, self._config.uiOptions); const doInitCookieConsent = async function () { // init cookie consent // noinspection JSValidateTypes self._cookieConsent = window.initCookieConsent(); const runOriginal = self._cookieConsent.run; const updateLanguageOriginal = self._cookieConsent.updateLanguage; const acceptOriginal = self._cookieConsent.accept; const hideSettingsOriginal = self._cookieConsent.hideSettings; const processVisibleReadonlyDisabledStorages = () => { const container = document.getElementById('s-bl'); if (!container) { return; } const storages = self._storagePool.findVisibleReadonlyDisabled(); for (let i in storages) { const storage = storages[i]; const input = container.querySelector(`input[value="${storage.name}"].c-tgl`); const span = container.querySelector(`input[value="${storage.name}"].c-tgl ~ .c-tg`); if (!input || !span) { continue; } input.disabled = true; input.checked = false; !span.classList.contains('c-ro') && (span.classList.add('c-ro')); } }; self._cookieConsent.run = (function (config) { runOriginal(config); if (self._config.consentModalOptions.show_third_button) { const appender = new ThirdButtonAppender(); appender.append(self, document); } requestAnimationFrame(() => { self.#reorderSettingsModalButtons(); }); if (self._config.pluginOptions.autorun && self._cookieConsent.__isConsentModalExists()) { const delay = self._config.pluginOptions.delay; setTimeout(function() { self._cookieConsent.show(0); }, delay > 0 ? delay : 0); } processVisibleReadonlyDisabledStorages(); }).bind(self._cookieConsent); self._cookieConsent.updateLanguage = (function (lang, force) { const focusedElement = document.activeElement; if (updateLanguageOriginal(lang, force)) { self._cookieConsent.__updateModalFocusableData(); const focusedModal = self._cookieConsent.__getFocusedModal(); if (focusedModal && !focusedModal.contains(focusedElement)) { self._cookieConsent.__getFocusableEdges()[0]?.focus(); } } processVisibleReadonlyDisabledStorages(); }).bind(self._cookieConsent); self._cookieConsent.accept = (function (_categories, _exclusions) { const storages = self._storagePool.findVisibleReadonlyDisabled().map(storage => storage.name); if (0 < storages.length) { _exclusions = Array.isArray(_exclusions) ? _exclusions : []; for (let i in storages) { -1 === _exclusions.indexOf(storages[i]) && (_exclusions.push(storages[i])); } } acceptOriginal(_categories, _exclusions); }).bind(self._cookieConsent); self._cookieConsent.hideSettings = (function () { hideSettingsOriginal(); // close opened storage descriptions setTimeout(() => { Array.from(document.querySelectorAll('#s-bl .b-tl.exp[aria-expanded="true"]')).forEach(blockTitleBtn => { const blockSection = blockTitleBtn.closest('.c-bl.act'); const accordionId = blockTitleBtn.getAttribute('aria-controls'); const accordion = accordionId ? document.getElementById(accordionId) : null; blockTitleBtn.setAttribute('aria-expanded', 'false'); blockSection && blockSection.classList.remove('act'); accordion && accordion.setAttribute('aria-hidden', 'true'); }); }, 250); }).bind(self._cookieConsent); const consentManager = new ConsentManager(self._cookieConsent, self._eventBus, self._config, self._storagePool, Object.values(self._eventTriggers), self._gtag); // build cookie consent config const config = self._config.exportCookieConsentConfig(); config.onFirstAction = (userPreferences) => consentManager.onFirstAction(userPreferences); config.onAccept = () => consentManager.onAccept(); config.onChange = (cookie, changedCategories) => consentManager.onChange(cookie, changedCategories); config.languages = await self._dictionary .addPlaceholder('user_identity', self.user.identity.toString()) .exportTranslations(self._storagePool, self._config); self._cookieTables.appendCookieTables(config.languages); integrateCmpApi(self, self._config.cmpApiOptions); // run cookie consent self._cookieConsent.run(config); self._initialized = true; self._eventBus.dispatch(Events.ON_INIT); }; const doInitSettingsModalTrigger = () => { if (!document || 'string' !== typeof self._config.settingsModalOptions.modal_trigger_selector) { return; } const modalTriggerFactory = new ModalTriggerFactory(document, self._dictionary); const modalTriggerElements = modalTriggerFactory.create( self._config.settingsModalOptions.modal_trigger_selector, self._config.pluginOptions.current_lang || document.documentElement.lang, ); // re-translate modal trigger if (modalTriggerElements && modalTriggerElements.textElement) { modalTriggerElements.textElement.innerHTML = self.translate(self._cookieConsent.getConfig('current_lang'), 'modal_trigger_title'); } }; let initPromise = null; if (!this._config.pluginOptions.init_after_dom_content_loaded && document.body) { initPromise = doInitCookieConsent(); } if ('loading' !== document.readyState) { null === initPromise && (initPromise = doInitCookieConsent()); initPromise.then(doInitSettingsModalTrigger); } else { document.addEventListener('DOMContentLoaded', () => { null === initPromise && (initPromise = doInitCookieConsent()); initPromise.then(doInitSettingsModalTrigger); }); } } #reorderSettingsModalButtons() { const container = document.getElementById('s-bns'); if (!container) { return; } const buttons = Array.from(container.querySelectorAll('button')); if (0 === buttons.length) { return; } const withOrder = buttons.map(button => { const orderStr = getComputedStyle(button).order; const order = parseInt(orderStr, 10); return { button, originalOrder: isNaN(order) ? 0 : order, }; }); const hasCustomOrder = withOrder.some(item => 0 !== item.originalOrder); if (!hasCustomOrder) { return; } withOrder.sort((a, b) => a.originalOrder - b.originalOrder); withOrder.forEach(({ button }) => { container.appendChild(button); button.style.order = ''; }); } }