iframe_consent-1.0.x-dev/js/iframe-consent.js
js/iframe-consent.js
/**
* @file
* Do not load iframes until user accept cookies.
*/
/**
* Manage iframe load according given consent groups.
*
* @param {array} consentGroups
* Consent groups list.
*
* @constructor
*/
function IframeConsent(consentGroups) {
this.consentGroups = consentGroups;
this.manageCookiesCallback = null;
this.acceptedCategories = [];
this.placeholderWrapperClass = 'iframe-consent-placeholder-wrapper';
this.placeholderWrapperSelector = '.iframe-consent-placeholder-wrapper';
this.consentListWrapperSelector =
'.iframe-consent-placeholder__required-consents';
this.manageButtonSelector = '.iframe-consent-placeholder-button--manage';
this.acceptButtonSelector = '.iframe-consent-placeholder-button--accept';
this.initializedClass = 'iframe-consent--initialized';
this.initializedSelector = '.iframe-consent--initialized';
}
/**
* Callback that allow third parties set the consent banner.
*
* @param {function} callback
* Callback that show the consent banner.
*/
IframeConsent.prototype.setManageCookiesCallback = function (callback) {
this.manageCookiesCallback = callback;
};
/**
* Update the accepted categories.
*
* @param {array} categories
* Array of accepted categories.
*/
IframeConsent.prototype.setAcceptedCategories = function (categories) {
this.acceptedCategories = categories;
this.processAllIframes();
};
/**
* Check if given categories are accepted.
*
* @param {array} requiredCategories
* The categories array to be checked.
*/
IframeConsent.prototype.checkIfCategoriesAreAccepted = function (
requiredCategories,
) {
if (requiredCategories.length === 0) {
return true;
}
let requiredCategoriesArray = requiredCategories.split(',');
requiredCategoriesArray = requiredCategoriesArray.filter((category) => {
return this.acceptedCategories.indexOf(category) === -1;
});
return requiredCategoriesArray.length === 0;
};
/**
* Open consent banner on preferences button is clicked.
*/
IframeConsent.prototype.onManageConsentClick = function (event) {
if (this.manageCookiesCallback !== null) {
this.manageCookiesCallback();
}
};
/**
* Action when accept button is clicked.
*
* @param event
* Event object.
*/
IframeConsent.prototype.onAcceptClick = function (event) {
const placeholderWrapper = event.target.closest(
this.placeholderWrapperSelector,
);
const iframe = placeholderWrapper.parentNode.querySelector(
this.initializedSelector,
);
this.disableIframeConsent(iframe);
};
/**
* Process all iframes.
*/
IframeConsent.prototype.processAllIframes = function () {
const iframes = document.querySelectorAll('iframe.iframe-consent');
iframes.forEach((iframe) => {
this.processIframe(iframe);
});
};
/**
* Process iframe.
*
* @param {object} iframe
* Element that contains the iframe.
*/
IframeConsent.prototype.processIframe = function (iframe) {
const iframeStatus = iframe.getAttribute('data-iframe-consent-status') ?? '';
if (iframeStatus === 'allowed') {
return;
}
const requiredConsents = iframe.getAttribute('data-required-consents') ?? '';
if (this.checkIfCategoriesAreAccepted(requiredConsents)) {
if (iframeStatus === 'processed') {
this.disableIframeConsent(iframe);
} else {
this.restoreIframeSrc(iframe);
}
iframe.setAttribute('data-iframe-consent-status', 'allowed');
} else if (iframeStatus !== 'processed') {
this.enableIframeConsent(iframe);
iframe.setAttribute('data-iframe-consent-status', 'processed');
}
};
/**
* Restore the iframe src.
*
* @param {object} iframe
* Iframe object.
*/
IframeConsent.prototype.restoreIframeSrc = function (iframe) {
const src = iframe.getAttribute('data-src');
iframe.setAttribute('src', src);
iframe.removeAttribute('data-src');
};
/**
* Set the iframe/container to his initial state.
*
* @param {object} iframe
* Iframe element.
*/
IframeConsent.prototype.disableIframeConsent = function (iframe) {
const iframeParent = iframe.parentNode;
iframeParent.querySelector(this.placeholderWrapperSelector).remove();
this.restoreIframeSrc(iframe);
iframe.setAttribute('data-iframe-consent-status', 'allowed');
iframe.classList.remove(this.initializedClass);
};
/**
* Enable the Iframe consent on the given iframe.
*
* @param {object} iframe
* Iframe element.
*/
IframeConsent.prototype.enableIframeConsent = function (iframe) {
const template =
iframe.getAttribute('data-placeholder-template') ?? 'default';
const hash = iframe.getAttribute('data-hash') ?? Math.random(10);
const iframeParent = iframe.parentNode;
const placeholderWrapper = document.createElement('div');
placeholderWrapper.classList.add(this.placeholderWrapperClass);
placeholderWrapper.id = `iframe-consent-placeholder--${hash}`;
iframeParent.insertBefore(placeholderWrapper, iframe);
Drupal.ajax({
url: Drupal.url(`/ajax/iframe-consent/placeholder/${template}/${hash}`),
}).execute();
const observer = new MutationObserver((mutationsList) => {
mutationsList.forEach((mutation) => {
if (mutation.addedNodes.length > 0) {
// Add buttons actions.
const manageButton = placeholderWrapper.querySelector(this.manageButtonSelector);
if (manageButton) {
manageButton.addEventListener('click', this.onManageConsentClick.bind(this));
}
const acceptButton = placeholderWrapper.querySelector(this.acceptButtonSelector);
if (acceptButton) {
acceptButton.addEventListener('click', this.onAcceptClick.bind(this));
}
// Add required consents text.
const requiredConsents = iframe.getAttribute('data-required-consents');
const requiredConsentsArray = requiredConsents.split(',');
const requiredConsentsWrapper = placeholderWrapper.querySelector(
this.consentListWrapperSelector,
);
const consentItem = document.createElement('span');
let count = 0;
requiredConsentsArray.forEach((consent) => {
const consentLabel = this.consentGroups[consent];
if (consentLabel) {
if (count > 0) {
consentItem.innerText += ', ';
}
consentItem.innerText += consentLabel;
count++;
}
});
if (count > 0) {
requiredConsentsWrapper.appendChild(consentItem);
}
iframe.classList.add(this.initializedClass);
observer.disconnect();
}
});
});
observer.observe(placeholderWrapper, { childList: true });
};
/**
* Initialize Iframe consent.
*/
(function (Drupal, drupalSettings, once) {
if (typeof drupalSettings.iframeConsent === 'object') {
Drupal.iframeConsent = new IframeConsent(
drupalSettings.iframeConsent.consentGroups,
);
}
Drupal.behaviors.iframeConsent = {
attach(context) {
once('iframe-consent', 'iframe.iframe-consent', context).forEach(
(iframe) => {
Drupal.iframeConsent.processIframe(iframe);
},
);
},
};
})(Drupal, drupalSettings, once);
