'use strict'; (function () { // Polyfill for IE missing custom javascript events --------------------------------------------- // (see: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent#Polyfill) ----- if (typeof window.CustomEvent === 'function') return false; function CustomEvent(event, params) { let customEvent = document.createEvent('CustomEvent'); params = params || { bubbles: false, cancelable: false, detail: null }; customEvent.initCustomEvent(event, params.bubbles, params.cancelable, params.detail); return customEvent; } window.CustomEvent = CustomEvent; //----------------------------------------------------------------------------------------------- // Polyfill for IE not supporting forEach on nodelists if (typeof NodeList.prototype.forEach === 'undefined') { NodeList.prototype.forEach = Array.prototype.forEach; } //----------------------------------------------------------------------------------------------- // Polyfill for closest selector ---------------------------------------------------------------- // (see: https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill) ------------- if (!Element.prototype.matches) { Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector; } if (!Element.prototype.closest) { Element.prototype.closest = function (selector) { let element = this; do { if (Element.prototype.matches.call(element, selector)) { return element; } element = element.parentElement || element.parentNode; } while (element !== null && element.nodeType === 1); return null; }; } //----------------------------------------------------------------------------------------------- })(); (function (cookieConsentConfiguration) { const _cookieConsent = { cookieName: 'cookie_consent', settingsClass: '', openButtonClass: 'cookie-consent-open', detailsOpenContainerSelector: '.detail, .show-details, .consent-modal', consentVariableName: 'cookieConsent', containerDisplayStyle: 'block', expiryDays: 365, modalContainer: null, modalForm: null, saveButton: null, selectAllButton: null, isSelectAll: false, hideOnInit: false, pushConsentToTagManager: false, lazyloading: false, lazyloadingTimeout: 120000, lazyloadingEvents: ['mousedown', 'mousemove', 'keydown', 'scroll', 'touchstart'], consentButtons: [], consentScripts: [], /** * @param {object} configuration */ init: function (configuration) { const that = this; this.cookieName = 'cookieName' in configuration ? configuration.cookieName : this.cookieName; this.openButtonClass = 'openButtonClass' in configuration ? configuration.openButtonClass : this.openButtonClass; this.expiryDays = 'expiryDays' in configuration ? parseInt(configuration.expiryDays) : this.expiryDays; this.hideOnInit = 'hideOnInit' in configuration ? Boolean(configuration.hideOnInit) : this.hideOnInit; this.pushConsentToTagManager = 'pushConsentToTagManager' in configuration ? Boolean(configuration.pushConsentToTagManager) : false; this.lazyloading = 'lazyloading' in configuration ? Boolean(configuration.lazyloading) : this.lazyloading; this.lazyloadingTimeout = 'lazyloadingTimeout' in configuration ? parseInt(configuration.lazyloadingTimeout) * 1000 : this.lazyloadingTimeout; this.updateConsentButtons(); window[this.consentVariableName] = { consent: false, options: [] }; window.cookieConsentModalToggle = function () { that.modalContainer.style.display = 'none' === that.modalContainer.style.display ? that.containerDisplayStyle : 'none'; }; if ('containerId' in configuration) { try { this.modalContainer = document.querySelector('#' + configuration.containerId); } catch (exception) { throw new Error('invalid container selector'); } } if (null !== this.modalContainer) { this.saveButton = this.modalContainer.querySelector('button.save, input.save'); this.selectAllButton = this.modalContainer.querySelector('button.select-all, input.select-all'); this.registerButtonEvents(this.modalContainer); this.modalForm = this.modalContainer.querySelector('form'); } if (true === this.hasCookie()) { this.consentEventDispatch(); } else if (false === this.hideOnInit && false === this.lazyloading) { this.openModal(this.modalContainer); } else if (true === this.lazyloading) { this.lazyOpenModal(this.modalContainer); } document.querySelectorAll('.' + this.openButtonClass).forEach(function (openButton) { openButton.addEventListener('click', function (event) { event.preventDefault(); that.modalContainer.style.display = that.containerDisplayStyle; }); }); this.consentButtons.forEach(function (acceptButton) { acceptButton.addEventListener('click', function () { let cookie = that.getCookie(); let cookieOpions = null !== cookie ? cookie.options : []; cookieOpions.push(this.getAttribute('data-identifier')); that.setConsentCookie(cookieOpions); that.replaceConsentButtons(this.getAttribute('data-identifier')); }); }); this.modalForm.querySelectorAll('.option').forEach(function (optionCheckbox) { optionCheckbox.addEventListener('change', function () { const parentOptionCheckbox = this; const cookieOptionsList = that.modalForm.querySelector('.cookieoptions[data-parent="#' + this.id + '"]'); cookieOptionsList.querySelectorAll('input[type="checkbox"]').forEach(function (cookieOptionCheckbox) { cookieOptionCheckbox.checked = parentOptionCheckbox.checked; }); that.updateParentOptionState(cookieOptionsList); }); }); this.modalForm.querySelectorAll('.cookieoptions input[type="checkbox"]').forEach(function (cookieOptionCheckbox) { cookieOptionCheckbox.addEventListener('change', function () { const cookieOptionsList = this.closest('.cookieoptions'); if (cookieOptionsList instanceof Element) { that.updateParentOptionState(cookieOptionsList); } }); }); }, /** * @param {HTMLElement} container */ lazyOpenModal: function (container) { const that = this; let lazyloadingTimeout = null; if (0 < this.lazyloadingTimeout) { lazyloadingTimeout = setTimeout(function () {that.openModal(container);}, this.lazyloadingTimeout); } const interactionEventListener = function () { that.openModal(container); clearTimeout(lazyloadingTimeout); that.lazyloadingEvents.forEach(function (eventName) { document.removeEventListener(eventName, interactionEventListener); }); }; this.lazyloadingEvents.forEach(function (eventName) { document.addEventListener(eventName, interactionEventListener); }); }, updateConsentButtons: function () { this.consentButtons = document.querySelectorAll('.cookie-consent-replacement .accept'); }, /** * @param {string} cookieOption */ replaceConsentButtons: function (cookieOption) { const that = this; this.consentButtons.forEach(function (acceptButton) { const consentReplacement = acceptButton.closest('.cookie-consent-replacement'); const textArea = document.createElement('textarea'); const replacement = document.createElement('div'); if (cookieOption === acceptButton.getAttribute('data-identifier')) { textArea.innerHTML = consentReplacement.getAttribute('data-replacement'); replacement.innerHTML = textArea.innerText; consentReplacement.parentNode.replaceChild(replacement, consentReplacement); that.updateConsentButtons(); } if (true === consentReplacement.hasAttribute('data-scripts')) { const scripts = JSON.parse(consentReplacement.getAttribute('data-scripts')); for (let key in scripts) { let async = false; let defer = false; let src = undefined; let eventName = undefined; if (typeof key === 'string') { eventName = key; } if (typeof scripts[key] === 'string') { src = scripts[key]; } else { src = scripts[key]['src']; async = scripts[key]['async']; defer = scripts[key]['defer']; } if (-1 === that.consentScripts.indexOf(src)) { that.consentScripts.push(src); that.addScript(src, async, defer, eventName); } } } }); }, /** * @param {string} src * @param {boolean} async * @param {boolean} defer * @param {string} eventName */ addScript: function (src, async, defer, eventName) { const script = document.createElement('script'); script.async = async; script.defer = defer; if (typeof eventName === 'string') { script.onload = script.onreadystatechange = function (_, isAbort) { if (isAbort || !this.readyState || /loaded|complete/.test(this.readyState)) { this.onload = null; this.onreadystatechange = null; if (!isAbort) { window.dispatchEvent(new CustomEvent(eventName)); } } }; } script.src = src; document.body.appendChild(script); }, /** * @param {HTMLElement} container */ registerButtonEvents: function (container) { const that = this; const showDetailsButton = container.querySelector('.show-details'); if (null !== this.selectAllButton) { this.selectAllButton.addEventListener('click', function (event) { that.isSelectAll = true; that.toggleFormDisabledState(true); that.modalForm.querySelectorAll('input[type="checkbox"]').forEach(function (checkbox) { checkbox.checked = true; }); // Workaround for older edge versions not supporting URLSearchParams if (typeof URLSearchParams === 'undefined') { that.fallbackSubmitForm(); return; } else { event.preventDefault(); } that.submitForm(); }); } if (null !== this.saveButton) { this.saveButton.addEventListener('click', function (event) { // Workaround for older edge versions not supporting URLSearchParams if (typeof URLSearchParams === 'undefined') { that.fallbackSubmitForm(); return; } else { event.preventDefault(); } that.toggleFormDisabledState(true); that.submitForm(); }); } if (null !== showDetailsButton) { showDetailsButton.addEventListener('click', function (event) { event.preventDefault(); that.toggleModalDetails(container); }); } }, /** * @param {HTMLElement} container */ toggleModalDetails: function (container) { container.querySelectorAll(this.detailsOpenContainerSelector).forEach(function (element) { element.classList.toggle('open'); }); }, /** * @param {HTMLElement} container */ openModalDetails: function (container) { container.querySelectorAll(this.detailsOpenContainerSelector).forEach(function (element) { element.classList.add('open'); }); }, /** * @param {HTMLElement} container */ closeModalDetails: function (container) { container.querySelectorAll(this.detailsOpenContainerSelector).forEach(function (element) { element.classList.remove('open'); }); }, /** * @returns {boolean} */ hasCookie: function () { return null !== this.getCookie() && this.getCookie() instanceof Object && true === this.getCookie()['consent']; }, /** * @returns {object|null} */ getCookie: function () { const cookie = document.cookie.match('(^|[^;]+)\\s*' + this.cookieName + '\\s*=\\s*([^;]+)'); const consent = null !== cookie ? JSON.parse(decodeURIComponent(cookie.pop())) : null; if (null !== consent) { consent['hasOption'] = function (identifier) { return 0 <= this.options.indexOf(identifier); }; } return consent; }, submitForm: function () { const that = this; this.setXhrSubmit(this.modalForm, true); setTimeout(function () { that.closeModal(that.modalContainer); }, 200); try { const formData = new FormData(); this.modalForm.querySelectorAll('input').forEach(function (input) { if ('checkbox' !== input.type || true === input.checked) { formData.append(input.name, input.value); } }); const parameters = new URLSearchParams(); const formDataEntries = formData.entries(); let formDataEntry = formDataEntries.next(); while (false === formDataEntry.done) { parameters.append(formDataEntry.value[0], formDataEntry.value[1]); formDataEntry = formDataEntries.next(); } if (true === this.isSelectAll) { parameters.append(this.modalForm.querySelector('.select-all').getAttribute('name'), '1'); } fetch( this.modalForm.getAttribute('action'), { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: parameters } ).then(function (response) { if (200 !== response.status) { throw new Error('xhr request failed: ' + response.status + ' - reason: "' + response.statusText + '"'); } that.isSelectAll = false; that.toggleFormDisabledState(false); }).catch(function (error) { that.toggleFormDisabledState(false); console.error(error); }); } catch (error) { that.toggleFormDisabledState(false); console.error(error); } this.setConsentCookie(); }, fallbackSubmitForm: function () { this.setXhrSubmit(this.modalForm, false); if (true === this.isSelectAll) { const input = document.createElement('input'); input.type = 'hidden'; input.name = this.modalForm.querySelector('.select-all').getAttribute('name'); input.value = '1'; this.modalForm.appendChild(input); } this.setConsentCookie(); }, /** * @param {array} [cookieOptions] */ setConsentCookie: function (cookieOptions) { const that = this; const expiryDate = new Date(); expiryDate.setDate(expiryDate.getDate() + this.expiryDays); if (false === Array.isArray(cookieOptions)) { cookieOptions = []; this.modalForm.querySelectorAll('input[type="checkbox"]').forEach(function (checkbox) { if (true === checkbox.checked && null !== checkbox.getAttribute('data-identifier')) { cookieOptions.push(checkbox.getAttribute('data-identifier')); } }); } if ( true === this.pushConsentToTagManager && window.dataLayer instanceof Object && window.dataLayer.push instanceof Function ) { window.dataLayer.push({ 'event': 'cookieConsent', 'options': cookieOptions }); } document.cookie = that.cookieName + '=' + encodeURI(JSON.stringify({ consent: true, options: cookieOptions })) + ';expires=' + expiryDate.toUTCString() + ';samesite=strict' + ';path=/'; this.consentEventDispatch(); }, /** * @param {HTMLElement} form * @param {boolean} enable */ setXhrSubmit: function (form, enable) { if (null !== form) { form.querySelector('.is-ajax').value = true === enable ? 1 : 0; } }, /** * @param {boolean} state */ toggleFormDisabledState: function (state) { if (null !== this.selectAllButton) { this.selectAllButton.disabled = state; } this.saveButton.disabled = state; this.modalForm.querySelectorAll('input[type="checkbox"]:not(.option-necessary)').forEach(function (checkbox) { checkbox.disabled = state; }); }, /** * @param {HTMLElement} container * @return {boolean} */ isModalOpen: function (container) { return container.style.display === this.containerDisplayStyle; }, /** * @param {HTMLElement} container */ openModal: function (container) { container.style.display = this.containerDisplayStyle; this.closeModalDetails(container); }, /** * @param {HTMLElement} container */ closeModal: function (container) { container.style.display = 'none'; this.closeModalDetails(container); }, consentEventDispatch: function () { const that = this; if (false === this.hasCookie()) { throw new Error('Can\'t do event dispatch if the necessary cookie hasn\'t been set'); } window[this.consentVariableName] = this.getCookie(); window.dispatchEvent( new CustomEvent('cookieConsent', { detail: this.getCookie() }) ); this.modalForm.querySelectorAll('input[type="checkbox"]').forEach(function (checkbox) { if (true === that.getCookie().hasOption(checkbox.getAttribute('data-identifier'))) { checkbox.checked = true; } }); this.modalForm.querySelectorAll('.cookieoptions').forEach(function (cookieOptionsList) { that.updateParentOptionState(cookieOptionsList); }); this.getCookie().options.forEach(function (cookieOption) { that.replaceConsentButtons(cookieOption); }); }, /** * @param {object} cookieOptionsList */ updateParentOptionState: function (cookieOptionsList) { const parentCheckbox = this.modalForm.querySelector(cookieOptionsList.getAttribute('data-parent')); const parentCheckboxLabel = parentCheckbox.closest('.label'); const checkboxes = cookieOptionsList.querySelectorAll('input[type="checkbox"]'); const checkedCheckboxes = cookieOptionsList.querySelectorAll('input[type="checkbox"]:checked'); if (0 === checkedCheckboxes.length) { parentCheckboxLabel.classList.remove('partially-checked'); parentCheckbox.checked = false; } else if (checkboxes.length === checkedCheckboxes.length) { parentCheckboxLabel.classList.remove('partially-checked'); parentCheckbox.checked = true; } else { parentCheckboxLabel.classList.add('partially-checked'); parentCheckbox.checked = false; } } }; document.addEventListener('DOMContentLoaded', function () { try { _cookieConsent.init(cookieConsentConfiguration); } catch (exception) { console.error('Cookie Consent: ' + exception); } }); })(typeof cookieConsentConfiguration === 'object' ? cookieConsentConfiguration : {}); // Example // window.addEventListener('cookieConsent', function (event) { // console.debug('Cookie Consent:') // console.debug(event.detail.options) // });