UNPKG

stylescape

Version:

Stylescape is a visual identity framework developed by Scape Agency.

299 lines 11.9 kB
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