stylescape
Version:
Stylescape is a visual identity framework developed by Scape Agency.
299 lines • 11.9 kB
JavaScript
export class CookieConsentManager {
constructor(options = {}) {
this.bannerElement = null;
this.settingsPanel = null;
this.options = {
message: options.message ??
"We use cookies to enhance your experience. By continuing to visit this site you agree to our use of cookies.",
acceptAllText: options.acceptAllText ?? "Accept All",
acceptNecessaryText: options.acceptNecessaryText ?? "Necessary Only",
settingsText: options.settingsText ?? "Cookie Settings",
cssClass: options.cssClass ?? "ss-cookie-consent",
storageKey: options.storageKey ?? "ss-cookie-consent",
position: options.position ?? "bottom",
categories: options.categories ?? [
"necessary",
"analytics",
"marketing",
"preferences",
],
privacyPolicyUrl: options.privacyPolicyUrl ?? "",
expirationDays: options.expirationDays ?? 365,
onAccept: options.onAccept,
onChange: options.onChange,
autoShow: options.autoShow ?? true,
showSettings: options.showSettings ?? true,
};
this.consentState = this.loadConsent() ?? {
necessary: true,
analytics: false,
marketing: false,
preferences: false,
};
if (this.options.autoShow && !this.hasConsent()) {
this.show();
}
}
hasConsent() {
return this.loadConsent() !== null;
}
getConsent() {
return { ...this.consentState };
}
isAllowed(category) {
return this.consentState[category] ?? false;
}
acceptAll() {
this.consentState = {
necessary: true,
analytics: true,
marketing: true,
preferences: true,
timestamp: Date.now(),
};
this.saveConsent();
this.hide();
this.options.onAccept?.(this.consentState);
this.activateCategoryScripts();
}
acceptNecessary() {
this.consentState = {
necessary: true,
analytics: false,
marketing: false,
preferences: false,
timestamp: Date.now(),
};
this.saveConsent();
this.hide();
this.options.onAccept?.(this.consentState);
}
saveCustomConsent(consent) {
this.consentState = {
necessary: true,
analytics: consent.analytics ?? false,
marketing: consent.marketing ?? false,
preferences: consent.preferences ?? false,
timestamp: Date.now(),
};
this.saveConsent();
this.hide();
this.options.onAccept?.(this.consentState);
this.options.onChange?.(this.consentState);
this.activateCategoryScripts();
}
revokeConsent() {
localStorage.removeItem(this.options.storageKey);
this.consentState = {
necessary: true,
analytics: false,
marketing: false,
preferences: false,
};
this.show();
}
show() {
if (this.bannerElement) {
this.bannerElement.style.display = "block";
return;
}
this.createBanner();
}
hide() {
if (this.bannerElement) {
this.bannerElement.style.display = "none";
}
this.hideSettings();
}
showSettings() {
if (!this.settingsPanel) {
this.createSettingsPanel();
}
if (this.settingsPanel) {
this.settingsPanel.style.display = "block";
}
}
hideSettings() {
if (this.settingsPanel) {
this.settingsPanel.style.display = "none";
}
}
destroy() {
this.bannerElement?.remove();
this.settingsPanel?.remove();
this.bannerElement = null;
this.settingsPanel = null;
}
static init() {
const element = document.querySelector('[data-ss="cookie-consent"]');
if (!element) {
return new CookieConsentManager();
}
return new CookieConsentManager({
message: element.dataset.ssCookieMessage,
position: element.dataset.ssCookiePosition,
privacyPolicyUrl: element.dataset.ssCookiePrivacyUrl,
cssClass: element.dataset.ssCookieClass,
showSettings: element.dataset.ssCookieShowSettings !== "false",
});
}
loadConsent() {
try {
const stored = localStorage.getItem(this.options.storageKey);
if (!stored)
return null;
const consent = JSON.parse(stored);
if (consent.timestamp) {
const expirationMs = this.options.expirationDays * 24 * 60 * 60 * 1000;
if (Date.now() - consent.timestamp > expirationMs) {
localStorage.removeItem(this.options.storageKey);
return null;
}
}
return consent;
}
catch {
return null;
}
}
saveConsent() {
localStorage.setItem(this.options.storageKey, JSON.stringify(this.consentState));
}
createBanner() {
const banner = document.createElement("div");
banner.className = `${this.options.cssClass} ${this.options.cssClass}--${this.options.position}`;
banner.setAttribute("role", "dialog");
banner.setAttribute("aria-label", "Cookie Consent");
banner.setAttribute("aria-describedby", `${this.options.cssClass}-message`);
const privacyLink = this.options.privacyPolicyUrl
? `<a href="${this.options.privacyPolicyUrl}" class="${this.options.cssClass}__link">Privacy Policy</a>`
: "";
banner.innerHTML = `
<div class="${this.options.cssClass}__content">
<p id="${this.options.cssClass}-message" class="${this.options.cssClass}__message">
${this.options.message}
${privacyLink}
</p>
<div class="${this.options.cssClass}__actions">
${this.options.showSettings
? `<button type="button" class="${this.options.cssClass}__button ${this.options.cssClass}__button--settings">
${this.options.settingsText}
</button>`
: ""}
<button type="button" class="${this.options.cssClass}__button ${this.options.cssClass}__button--necessary">
${this.options.acceptNecessaryText}
</button>
<button type="button" class="${this.options.cssClass}__button ${this.options.cssClass}__button--accept">
${this.options.acceptAllText}
</button>
</div>
</div>
`;
document.body.appendChild(banner);
this.bannerElement = banner;
banner
.querySelector(`.${this.options.cssClass}__button--accept`)
?.addEventListener("click", () => this.acceptAll());
banner
.querySelector(`.${this.options.cssClass}__button--necessary`)
?.addEventListener("click", () => this.acceptNecessary());
banner
.querySelector(`.${this.options.cssClass}__button--settings`)
?.addEventListener("click", () => this.showSettings());
}
createSettingsPanel() {
const panel = document.createElement("div");
panel.className = `${this.options.cssClass}-settings`;
panel.setAttribute("role", "dialog");
panel.setAttribute("aria-label", "Cookie Settings");
const categoryLabels = {
necessary: {
title: "Necessary Cookies",
description: "Required for the website to function properly. Cannot be disabled.",
},
analytics: {
title: "Analytics Cookies",
description: "Help us understand how visitors interact with our website.",
},
marketing: {
title: "Marketing Cookies",
description: "Used to track visitors across websites for advertising purposes.",
},
preferences: {
title: "Preference Cookies",
description: "Allow the website to remember choices you make.",
},
};
const categoriesHtml = this.options.categories
.map((cat) => {
const info = categoryLabels[cat];
const isNecessary = cat === "necessary";
const isChecked = this.consentState[cat];
return `
<div class="${this.options.cssClass}-settings__category">
<label class="${this.options.cssClass}-settings__label">
<input type="checkbox"
name="${cat}"
${isChecked ? "checked" : ""}
${isNecessary ? "disabled" : ""}>
<span class="${this.options.cssClass}-settings__title">${info.title}</span>
</label>
<p class="${this.options.cssClass}-settings__description">${info.description}</p>
</div>
`;
})
.join("");
panel.innerHTML = `
<div class="${this.options.cssClass}-settings__overlay"></div>
<div class="${this.options.cssClass}-settings__panel">
<h2 class="${this.options.cssClass}-settings__heading">Cookie Settings</h2>
<div class="${this.options.cssClass}-settings__categories">
${categoriesHtml}
</div>
<div class="${this.options.cssClass}-settings__actions">
<button type="button" class="${this.options.cssClass}-settings__button--cancel">Cancel</button>
<button type="button" class="${this.options.cssClass}-settings__button--save">Save Preferences</button>
</div>
</div>
`;
document.body.appendChild(panel);
this.settingsPanel = panel;
panel
.querySelector(`.${this.options.cssClass}-settings__button--cancel`)
?.addEventListener("click", () => this.hideSettings());
panel
.querySelector(`.${this.options.cssClass}-settings__overlay`)
?.addEventListener("click", () => this.hideSettings());
panel
.querySelector(`.${this.options.cssClass}-settings__button--save`)
?.addEventListener("click", () => this.saveFromSettings());
}
saveFromSettings() {
if (!this.settingsPanel)
return;
const checkboxes = this.settingsPanel.querySelectorAll("input[type='checkbox']");
const consent = { necessary: true };
checkboxes.forEach((checkbox) => {
const category = checkbox.name;
consent[category] = checkbox.checked;
});
this.saveCustomConsent(consent);
}
activateCategoryScripts() {
document
.querySelectorAll("script[data-ss-cookie-category]")
.forEach((script) => {
const category = script.dataset
.ssCookieCategory;
if (this.isAllowed(category) &&
!script.dataset.ssCookieActivated) {
const newScript = document.createElement("script");
newScript.src = script.src;
newScript.dataset.ssCookieActivated = "true";
document.head.appendChild(newScript);
}
});
}
}
export default CookieConsentManager;
//# sourceMappingURL=CookieConsentManager.js.map