Home Reference Source

src/cmp/cmp.js

import { cpexLog, cpexWarn, cpexError, addTCFStub, loadScript, addElement, setCookie } from '../utils.js'
import { PayOkay } from './pay.js'

/**
 * Consent Management Platform (banner and TCF API), based on iab specs
 */
export default class CMP {
  constructor (main) {
    this.main = main
    this.loaded = false
    this.settings = this.main.settings.cmp
    if (this.settings.enabled) {
      this.addDidomi()
      if (this.settings.payEnabled) {
        this.addPayOkay()
      }
    } else if (!window.__tcfapi) {
      addTCFStub() // Fallback for missing TCF stub
    }
  }

  /**
   * Load Didomi SDK, documentation at developers.didomi.io
   */
  addDidomi () {
    if (window.Didomi || window.didomiLoaded) {
      cpexWarn('CMP: Didomi already loaded')
      this.loaded = true
    } else {
      addTCFStub()

      // Load Didomi SDK
      window.didomiConfig = window.didomiConfig || {}
      window.didomiConfig.sdkPath = window.didomiConfig.sdkPath || 'https://sdk.privacy-center.org/'
      window.didomiEventListeners = window.didomiEventListeners || []
      window.didomiOnReady = window.didomiOnReady || []
      const hostname = this.main.localhost ? 'cpex.cz' : document.location.hostname
      const target = this.settings.didomiTemplate ? '?target_type=notice&target=' + this.settings.didomiTemplate : '?target=' + hostname
      let loaderPath = window.didomiConfig.sdkPath + '9a8e2159-3781-4da1-9590-fbf86806f86e/loader.js' + target
      if (window.didomiConfig.user) {
        const user = window.didomiConfig.user
        const country = user.country
        const region = user.region
        if (country) {
          loaderPath = loaderPath + '&country=' + country
          if (region) { loaderPath = loaderPath + '&region=' + region }
        }
      }

      addElement('link', document.head, { rel: 'preconnect', as: 'script', href: window.didomiConfig.sdkPath })
      addElement('link', document.head, { rel: 'dns-prefetch', as: 'script', href: window.didomiConfig.sdkPath })
      loadScript(document, loaderPath, 'Didomi loader for SDK')
      window.didomiLoaded = true

      window.didomiOnReady.push(() => {
        this.loaded = true
        // Protect against stub misconfiguration
        window.__tcfapi.stubVersion = 2
        cpexLog('CMP: Didomi loaded')
        // Protect against Didomi misconfiguration
        if (window.Didomi.isTCFEnabled() === false) { cpexError('TCF compliance disabled in Didomi console') }
        // Add close button
        if (typeof window.cpexCmpAllowCloseButton !== 'undefined' || window.location.href.indexOf('cpexCmpAllowCloseButton') !== -1) {
          this.addCloseButton()
        }
      })
    }
  }

  /**
   * Load Pay or Okay variant - our custom modal, an extension built on top of Didomi SDK
   */
  addPayOkay () {
    window.didomiOnReady.push((didomi) => { // render once didomi is ready
      if (didomi.isConsentRequired()) { // dont show for bots
        this.pay = new PayOkay(this.main)
        window.didomiEventListeners.push({ event: 'preferences.clicksavechoices', listener: () => { this.pay.hideModal() } })
        window.didomiEventListeners.push({ event: 'preferences.clickagreetoall', listener: () => { this.pay.hideModal() } })
      }
    })
  }

  /**
   * Based on task FED-311: Adds close button to the banner, in specific circumstances
   */
  addCloseButton () {
    const targetEl = document.getElementById('didomi-notice') || document.getElementsByClassName('didomi-popup-notice-logo-container')[0] // For both banner and popup
    if (targetEl) {
      const closeButton = document.createElement('div')
      closeButton.textContent = '×'
      closeButton.style.cssText = 'position: absolute; top: 10px; right: 10px; width: 40px; height: 40px; cursor: pointer; font-size: 20pt; text-align: center; line-height: 40px;'
      closeButton.addEventListener('click', function () { window.Didomi.notice.hide() })
      targetEl.appendChild(closeButton)
    }
  }
}

// Store and CPEx consent with every change
window.didomiEventListeners = window.didomiEventListeners || []
window.didomiEventListeners.push({
  event: 'consent.changed',
  listener: async () => {
    const consent = window.Didomi.getUserConsentStatusForAll()
    if (consent && consent.vendors) {
      window.__tcfapi('addEventListener', 2, (data, success) => {
        if (success === false) { return }
        setCookie('cpxc', 2592000, data.vendor.consents[570] ? '1' : '0') // save consent status for one month
      })
    }
  }
})