gdpr-consent
Version:
GDPR banner to comply with the European cookie law. Inspired by tarteaucitronjs.
405 lines (404 loc) • 17.7 kB
JavaScript
import { escape, trigger, updateCSSOfElement } from "@lesjoursfr/browser-tools";
import { DefaulGDPRConsentParameters } from "./gdpr-consent-parameters.js";
import { getLanguage } from "./languages/index.js";
import { activate, checkCount, closePanel, create, hashchangeEvent, isActivated, keydownEvent, openAlert, openPanel, order, read, respond, respondAll, respondEffect, toggle, } from "./modules/index.js";
class GDPRConsentInstance {
user;
lang;
services;
added;
state;
launch;
parameters;
reloadThePage;
alreadyLaunch;
loaded;
languagesLoader;
servicesLoader;
job;
constructor() {
this.user = {};
this.services = {};
this.added = {};
this.state = {};
this.launch = {};
this.reloadThePage = false;
this.alreadyLaunch = 0;
this.loaded = false;
}
withLanguages(loader) {
this.languagesLoader = loader;
}
withServices(loader) {
this.servicesLoader = loader;
}
init(params = {}) {
// Get params
this.parameters = Object.assign({}, structuredClone(DefaulGDPRConsentParameters), structuredClone(params));
// Launch
if (this.alreadyLaunch === 0) {
this.alreadyLaunch = 1;
// Bind events listeners
window.addEventListener("keydown", (evt) => keydownEvent(this, evt), false);
window.addEventListener("hashchange", () => hashchangeEvent(this), false);
// Check if the DOM is already loaded
if (window.document.readyState === "complete") {
this.load();
}
else {
window.addEventListener("load", () => this.load(), false);
}
}
}
load() {
// Check if we have loaders
if (typeof this.languagesLoader !== "function") {
throw new Error("Missing languages loader !");
}
if (typeof this.servicesLoader !== "function") {
throw new Error("Missing services loader !");
}
// Load language and services
const lang = getLanguage(this.languagesLoader());
if (lang === undefined) {
throw new Error("Missing english translation !");
}
this.lang = lang;
this.services = this.servicesLoader(this.user);
// Delete loaders
delete this.languagesLoader;
delete this.servicesLoader;
const body = document.body;
const div = document.createElement("div");
let html = "";
let index;
let cat = ["ads", "analytic", "api", "comment", "social", "support", "video", "other"];
let i;
cat = cat.sort((a, b) => {
if (this.lang[a].title > this.lang[b].title) {
return 1;
}
if (this.lang[a].title < this.lang[b].title) {
return -1;
}
return 0;
});
// Prepare the html
// For the Pannel
html +=
'<button type="button" id="tarteaucitron-back" onclick="GDPRConsent.closePanel();" aria-label="' +
this.lang.close +
'"></button>';
html += '<div id="tarteaucitron" role="dialog" aria-labelledby="dialogTitle">';
html += ' <button type="button" id="tarteaucitron-close-panel" onclick="GDPRConsent.closePanel();">X</button>';
html += ' <div id="tarteaucitron-services">';
// L'en-tête des services
html += ' <div id="tarteaucitron-services-top">';
html +=
' <span class="tarteaucitron-h1" role="heading" aria-level="1" id="dialogTitle">' +
this.lang.title +
"</span>";
html += ' <div id="tarteaucitron-info">';
html += " " + this.lang.disclaimer;
if (this.parameters.websiteName) {
html += " " + this.lang.disclaimerWebsite + " " + escape(this.parameters.websiteName) + ".";
}
html += " </div>";
// Accepter tout ou interdire tout
html += ' <div class="tarteaucitron-line">';
html += ' <span class="tarteaucitron-h3" role="heading" aria-level="2">' + this.lang.all + "</span>";
html += ' <div class="tarteaucitron-ask">';
html +=
' <button type="button" id="tarteaucitron-all-allowed" class="tarteaucitron-allow" onclick="GDPRConsent.respondAll(true, true);">';
html += " ✓ " + this.lang.allowAll;
html += " </button> ";
html +=
' <button type="button" id="tarteaucitron-all-denied" class="tarteaucitron-deny" onclick="GDPRConsent.respondAll(false, true);">';
html += " ✗ " + this.lang.denyAll;
html += " </button>";
html += " </div>";
html += " </div>";
html += " </div>";
// La liste des Services
html += ' <div id="tarteaucitron-services-list">';
html += ' <div class="clear"></div>';
if (this.parameters.mandatory === true) {
html += '<div class="tarteaucitron-cookie-group">';
html += ' <div class="tarteaucitron-cookie-text">';
html +=
' <span class="tarteaucitron-h3" role="heading" aria-level="2">' + this.lang.mandatoryTitle + "</span>";
html += ' <span class="tarteaucitron-description">' + this.lang.mandatoryText + "</span>";
html += " </div>";
html += ' <div class="tarteaucitron-cookie-buttons">';
html += ' <button type="button" class="tarteaucitron-allow solo">';
html += " ✓ " + this.lang.allow;
html += " </button> ";
html += " </div>";
html += "</div>";
}
for (i = 0; i < cat.length; i += 1) {
html += ' <li id="tarteaucitron-services-title_' + cat[i] + '" class="tarteaucitron-hidden">';
html += ' <div class="tarteaucitron-title">';
html +=
' <button type="button" onclick="GDPRConsent.toggle(\'tarteaucitron-details' +
cat[i] +
"', 'tarteaucitron-info-box');return false\">✛ " +
this.lang[cat[i]].title +
"</button>";
html += " </div>";
html +=
' <div id="tarteaucitron-details' +
cat[i] +
'" class="tarteaucitron-details tarteaucitron-info-box">';
html += " " + this.lang[cat[i]].details;
html += " </div>";
html += ' <ul id="tarteaucitron-services_' + cat[i] + '"></ul></li>';
}
html +=
' <li id="tarteaucitron-no-services-title" class="tarteaucitron-line">' +
this.lang.noServices +
"</li>";
html += " </ul>";
html += ' <div id="tarteaucitron-services-bottom">';
html +=
' <button type="button" id="tarteaucitron-save-responses" onclick="GDPRConsent.closePanel();">' +
this.lang.save +
"</button>";
html += " </div>";
html += " </div>";
html += " </div>";
html += "</div>";
// For the Banner
if (!this.parameters.acceptAllCta) {
html += '<div id="tarteaucitron-alert-big" class="tarteaucitron-alert-big-bottom">';
if (this.parameters.siteDisclaimerTitle !== "" && this.parameters.siteDisclaimerMessage !== "") {
html += '<div id="tarteaucitron-wrapper">';
html += ' <div id="tarteaucitron-disclaimer-texte">';
html += ' <span id="tarteaucitron-site-disclaimer-title">';
html += " " + this.parameters.siteDisclaimerTitle;
html += " </span>";
html += ' <span id="tarteaucitron-site-disclaimer-message">';
html += " " + this.parameters.siteDisclaimerMessage + "<br />";
html += " </span>";
}
html += ' <span id="tarteaucitron-disclaimer-alert">';
html += " " + this.lang.alertBigPrivacy;
html += " </span>";
html += " </div>";
html += ' <div id="tarteaucitron-disclaimer-buttons">';
html += ' <button type="button" id="tarteaucitron-personalize" onclick="GDPRConsent.openPanel();">';
html += " " + this.lang.personalize;
html += " </button>";
html += " </div>";
html += " </div>";
html += "</div>";
}
else {
html += '<div id="tarteaucitron-alert-big" class="tarteaucitron-alert-big-bottom">';
if (this.parameters.siteDisclaimerTitle !== "" && this.parameters.siteDisclaimerMessage !== "") {
html += '<div id="tarteaucitron-wrapper">';
html += ' <div id="tarteaucitron-disclaimer-texte">';
html += ' <span id="tarteaucitron-site-disclaimer-title">';
html += " " + this.parameters.siteDisclaimerTitle;
html += " </span>";
html += ' <span id="tarteaucitron-site-disclaimer-message">';
html += " " + this.parameters.siteDisclaimerMessage + "<br />";
html += " </span>";
}
html += ' <span id="tarteaucitron-disclaimer-alert">';
html += " " + this.lang.alertBigPrivacy;
html += " </span>";
html += " </div>";
html += ' <div id="tarteaucitron-disclaimer-buttons">';
html +=
' <button type="button" id="tarteaucitron-continue" onclick="GDPRConsent.alertRespondAll(false);">';
html += " → " + this.lang.continue;
html += " </button>";
html += ' <div id="tarteaucitron-group-buttons">';
html +=
' <button type="button" id="tarteaucitron-personalize" onclick="GDPRConsent.alertRespondAll(true);">';
html += " ✓ " + this.lang.acceptAll;
html += " </button>";
html +=
' <button type="button" id="tarteaucitron-close-alert" onclick="GDPRConsent.alertOpenPanel();">';
html += " " + this.lang.personalize;
html += " </button>";
html += " </div>";
html += " </div>";
html += " </div>";
html += "</div>";
}
div.id = "tarteaucitron-root";
// Append tarteaucitron: #tarteaucitron-root last-child of the body
body.appendChild(div);
div.innerHTML = html;
// Send an event
trigger(window, "tac.root_available");
if (this.job !== undefined) {
this.job = this.cleanArray(this.job);
for (index = 0; index < this.job.length; index += 1) {
this.addService(this.job[index]);
}
}
else {
this.job = [];
}
this.job.push = (id) => {
if (this.job.indexOf(id) === -1) {
Array.prototype.push.call(this.job, id);
}
this.launch[id] = false;
this.addService(id);
return this.job.length;
};
if (document.location.hash === this.parameters.hashtag) {
openPanel(this);
}
this.loaded = true;
// Send an event
trigger(window, "tac.loaded");
}
addService(serviceId) {
const s = this.services;
const service = s[serviceId];
const cookie = read(this.parameters);
const isDenied = cookie.indexOf(service.key + "=false") >= 0;
const isAllowed = cookie.indexOf(service.key + "=true") >= 0 ||
(!service.needConsent && cookie.indexOf(service.key + "=false") < 0);
const isResponded = cookie.indexOf(service.key + "=false") >= 0 || cookie.indexOf(service.key + "=true") >= 0;
let html = "";
if (this.added[service.key] !== true) {
this.added[service.key] = true;
html += '<div id="' + service.key + '-line" class="tarteaucitron-cookie-group">';
html += ' <div class="tarteaucitron-cookie-text">';
html += ' <span class="tarteaucitron-h3" role="heading" aria-level="3">' + service.name + "</span>";
html += ' <span id="tacCL' + service.key + '" class="tarteaucitron-description"></span>';
if (this.parameters.moreInfoLink === true) {
html +=
' <a href="' +
service.uri +
'" target="_blank" rel="noreferrer noopener" title="' +
service.name +
" " +
this.lang.newWindow +
'">';
html += " " + this.lang.source;
html += " </a>";
}
html += " </div>";
html += ' <div class="tarteaucitron-cookie-buttons">';
html +=
' <span id="' +
service.key +
'Allowed" class="tarteaucitron-switch-state" onclick="GDPRConsent.respond(this, event);">' +
this.lang.allow +
"</span>";
html +=
' <div class="tarteaucitron-switch" id="' +
service.key +
'Switch" onclick="GDPRConsent.respond(this, event);">';
html += ' <button type="button" class="tarteaucitron-switch-button"></button>';
html += " </div> ";
html +=
' <span id="' +
service.key +
'Denied" class="tarteaucitron-switch-state" onclick="GDPRConsent.respond(this, event);">' +
this.lang.deny +
"</span>";
html += " </div>";
html += "</li>";
updateCSSOfElement("tarteaucitron-services-title_" + service.type, "display", "block");
const serviceTypeEl = document.getElementById("tarteaucitron-services_" + service.type);
if (serviceTypeEl !== null) {
serviceTypeEl.innerHTML += html;
}
updateCSSOfElement("tarteaucitron-no-services-title", "display", "none");
order(service.type, this);
}
if (isAllowed) {
if (this.launch[service.key] !== true) {
this.launch[service.key] = true;
service.js();
trigger(window, service.key + "_loaded");
}
this.state[service.key] = true;
}
else if (isDenied) {
if (typeof service.fallback === "function") {
service.fallback(this.lang);
}
this.state[service.key] = false;
}
else if (!isResponded) {
create(service.key, "wait", this.parameters);
if (typeof service.fallback === "function") {
service.fallback(this.lang);
}
if (service.lazyConsent !== true) {
openAlert();
}
}
checkCount(service.key, service, this.lang);
trigger(window, service.key + "_added");
}
cleanArray(arr) {
const s = this.services;
const len = arr.length;
let out = [];
const obj = {};
for (let i = 0; i < len; i += 1) {
if (!obj[arr[i]]) {
obj[arr[i]] = true;
if (s[arr[i]] !== undefined) {
out.push(arr[i]);
}
}
}
out = out.sort(function (a, b) {
if (s[a].type + s[a].key > s[b].type + s[b].key) {
return 1;
}
if (s[a].type + s[a].key < s[b].type + s[b].key) {
return -1;
}
return 0;
});
return out;
}
closePanel() {
closePanel(this);
}
openPanel() {
openPanel(this);
}
respondEffect(key, status) {
respondEffect(key, status, this);
}
respondAll(status, closePanelAfter) {
respondAll(status, this, this.parameters);
if (closePanelAfter) {
closePanel(this);
}
}
respond(el, evt) {
respond(el, this, this.parameters, evt);
}
activate(id) {
activate(id, this, this.parameters);
}
isActivated(id) {
return isActivated(id, this);
}
toggle(id, closeClass) {
toggle(id, closeClass);
}
alertOpenPanel() {
openPanel(this);
trigger(window, "tac.alert_outcome", { outcome: "personalize" });
}
alertRespondAll(status) {
respondAll(status, this, this.parameters);
trigger(window, "tac.alert_outcome", { outcome: status === true ? "acceptAll" : "denyAll" });
}
}
export const GDPRConsent = new GDPRConsentInstance();