// Silktide Consent Manager - https://silktide.com/consent-manager/ class SilktideCookieBanner { constructor(config) { this.config = config; // Save config to the instance this.wrapper = null; this.banner = null; this.modal = null; this.cookieIcon = null; this.backdrop = null; this.createWrapper(); if (this.shouldShowBackdrop()) { this.createBackdrop(); } this.createCookieIcon(); this.createModal(); if (this.shouldShowBanner()) { this.createBanner(); this.showBackdrop(); } else { this.showCookieIcon(); } this.setupEventListeners(); if (this.hasSetInitialCookieChoices()) { this.loadRequiredCookies(); this.runAcceptedCookieCallbacks(); } } destroyCookieBanner() { // Remove all cookie banner elements from the DOM if (this.wrapper && this.wrapper.parentNode) { this.wrapper.parentNode.removeChild(this.wrapper); } // Restore scrolling this.allowBodyScroll(); // Clear all references this.wrapper = null; this.banner = null; this.modal = null; this.cookieIcon = null; this.backdrop = null; } // ---------------------------------------------------------------- // Wrapper // ---------------------------------------------------------------- createWrapper() { this.wrapper = document.createElement('div'); this.wrapper.id = 'silktide-wrapper'; document.body.insertBefore(this.wrapper, document.body.firstChild); } // ---------------------------------------------------------------- // Wrapper Child Generator // ---------------------------------------------------------------- createWrapperChild(htmlContent, id) { // Create child element const child = document.createElement('div'); child.id = id; child.innerHTML = htmlContent; // Ensure wrapper exists if (!this.wrapper || !document.body.contains(this.wrapper)) { this.createWrapper(); } // Append child to wrapper this.wrapper.appendChild(child); return child; } // ---------------------------------------------------------------- // Backdrop // ---------------------------------------------------------------- createBackdrop() { this.backdrop = this.createWrapperChild(null, 'silktide-backdrop'); } showBackdrop() { if (this.backdrop) { this.backdrop.style.display = 'block'; } // Trigger optional onBackdropOpen callback if (typeof this.config.onBackdropOpen === 'function') { this.config.onBackdropOpen(); } } hideBackdrop() { if (this.backdrop) { this.backdrop.style.display = 'none'; } // Trigger optional onBackdropClose callback if (typeof this.config.onBackdropClose === 'function') { this.config.onBackdropClose(); } } shouldShowBackdrop() { return this.config?.background?.showBackground || false; } // update the checkboxes in the modal with the values from localStorage updateCheckboxState(saveToStorage = false) { const preferencesSection = this.modal.querySelector('#cookie-preferences'); const checkboxes = preferencesSection.querySelectorAll('input[type="checkbox"]'); checkboxes.forEach((checkbox) => { const [, cookieId] = checkbox.id.split('cookies-'); const cookieType = this.config.cookieTypes.find(type => type.id === cookieId); if (!cookieType) return; if (saveToStorage) { // Save the current state to localStorage and run callbacks const currentState = checkbox.checked; if (cookieType.required) { localStorage.setItem( `silktideCookieChoice_${cookieId}${this.getBannerSuffix()}`, 'true' ); } else { localStorage.setItem( `silktideCookieChoice_${cookieId}${this.getBannerSuffix()}`, currentState.toString() ); // Run appropriate callback if (currentState && typeof cookieType.onAccept === 'function') { cookieType.onAccept(); } else if (!currentState && typeof cookieType.onReject === 'function') { cookieType.onReject(); } } } else { // When reading values (opening modal) if (cookieType.required) { checkbox.checked = true; checkbox.disabled = true; } else { const storedValue = localStorage.getItem( `silktideCookieChoice_${cookieId}${this.getBannerSuffix()}` ); if (storedValue !== null) { checkbox.checked = storedValue === 'true'; } else { checkbox.checked = !!cookieType.defaultValue; } } } }); } setInitialCookieChoiceMade() { window.localStorage.setItem(`silktideCookieBanner_InitialChoice${this.getBannerSuffix()}`, 1); } // ---------------------------------------------------------------- // Consent Handling // ---------------------------------------------------------------- handleCookieChoice(accepted) { // We set that an initial choice was made regardless of what it was so we don't show the banner again this.setInitialCookieChoiceMade(); this.removeBanner(); this.hideBackdrop(); this.toggleModal(false); this.showCookieIcon(); this.config.cookieTypes.forEach((type) => { // Set localStorage and run accept/reject callbacks if (type.required == true) { localStorage.setItem(`silktideCookieChoice_${type.id}${this.getBannerSuffix()}`, 'true'); if (typeof type.onAccept === 'function') { type.onAccept() } } else { localStorage.setItem( `silktideCookieChoice_${type.id}${this.getBannerSuffix()}`, accepted.toString(), ); if (accepted) { if (typeof type.onAccept === 'function') { type.onAccept(); } } else { if (typeof type.onReject === 'function') { type.onReject(); } } } }); // Trigger optional onAcceptAll/onRejectAll callbacks if (accepted && typeof this.config.onAcceptAll === 'function') { if (typeof this.config.onAcceptAll === 'function') { this.config.onAcceptAll(); } } else if (typeof this.config.onRejectAll === 'function') { if (typeof this.config.onRejectAll === 'function') { this.config.onRejectAll(); } } // finally update the checkboxes in the modal with the values from localStorage this.updateCheckboxState(); } getAcceptedCookies() { return (this.config.cookieTypes || []).reduce((acc, cookieType) => { acc[cookieType.id] = localStorage.getItem(`silktideCookieChoice_${cookieType.id}${this.getBannerSuffix()}`) === 'true'; return acc; }, {}); } runAcceptedCookieCallbacks() { if (!this.config.cookieTypes) return; const acceptedCookies = this.getAcceptedCookies(); this.config.cookieTypes.forEach((type) => { if (type.required) return; // we run required cookies separately in loadRequiredCookies if (acceptedCookies[type.id] && typeof type.onAccept === 'function') { if (typeof type.onAccept === 'function') { type.onAccept(); } } }); } runRejectedCookieCallbacks() { if (!this.config.cookieTypes) return; const rejectedCookies = this.getRejectedCookies(); this.config.cookieTypes.forEach((type) => { if (rejectedCookies[type.id] && typeof type.onReject === 'function') { if (typeof type.onReject === 'function') { type.onReject(); } } }); } /** * Run through all of the cookie callbacks based on the current localStorage values */ runStoredCookiePreferenceCallbacks() { this.config.cookieTypes.forEach((type) => { const accepted = localStorage.getItem(`silktideCookieChoice_${type.id}${this.getBannerSuffix()}`) === 'true'; // Set localStorage and run accept/reject callbacks if (accepted) { if (typeof type.onAccept === 'function') { type.onAccept(); } } else { if (typeof type.onReject === 'function') { type.onReject(); } } }); } loadRequiredCookies() { if (!this.config.cookieTypes) return; this.config.cookieTypes.forEach((cookie) => { if (cookie.required && typeof cookie.onAccept === 'function') { if (typeof cookie.onAccept === 'function') { cookie.onAccept(); } } }); } // ---------------------------------------------------------------- // Banner // ---------------------------------------------------------------- getBannerContent() { const bannerDescription = this.config.text?.banner?.description || "
We use cookies on our site to enhance your user experience, provide personalized content, and analyze our traffic.
"; // Accept button const acceptAllButtonText = this.config.text?.banner?.acceptAllButtonText || 'Accept all'; const acceptAllButtonLabel = this.config.text?.banner?.acceptAllButtonAccessibleLabel; const acceptAllButton = ``; // Reject button const rejectNonEssentialButtonText = this.config.text?.banner?.rejectNonEssentialButtonText || 'Reject non-essential'; const rejectNonEssentialButtonLabel = this.config.text?.banner?.rejectNonEssentialButtonAccessibleLabel; const rejectNonEssentialButton = ``; // Preferences button const preferencesButtonText = this.config.text?.banner?.preferencesButtonText || 'Preferences'; const preferencesButtonLabel = this.config.text?.banner?.preferencesButtonAccessibleLabel; const preferencesButton = ``; // Silktide logo link const silktideLogo = ` `; const bannerContent = ` ${bannerDescription}We respect your right to privacy. You can choose not to allow some types of cookies. Your cookie preferences will apply across our website.
"; // Preferences button const preferencesButtonLabel = this.config.text?.banner?.preferencesButtonAccessibleLabel; const closeModalButton = ``; const cookieTypes = this.config.cookieTypes || []; const acceptedCookieMap = this.getAcceptedCookies(); // Accept button const acceptAllButtonText = this.config.text?.banner?.acceptAllButtonText || 'Accept all'; const acceptAllButtonLabel = this.config.text?.banner?.acceptAllButtonAccessibleLabel; const acceptAllButton = ``; // Reject button const rejectNonEssentialButtonText = this.config.text?.banner?.rejectNonEssentialButtonText || 'Reject non-essential'; const rejectNonEssentialButtonLabel = this.config.text?.banner?.rejectNonEssentialButtonAccessibleLabel; const rejectNonEssentialButton = ``; // Credit link const creditLinkText = this.config.text?.preferences?.creditLinkText || 'Get this banner for free'; const creditLinkAccessibleLabel = this.config.text?.preferences?.creditLinkAccessibleLabel; const creditLink = `${creditLinkText}`; const modalContent = `