/** * TigerStyle Whiskers - Cookie Consent JavaScript * Feline finesse in consent management */ (function($) { 'use strict'; // Main consent management object window.tigerstyleWhiskersConsent = { // Configuration config: { cookieName: 'tigerstyle_whiskers_consent', cookieExpiry: 365, // days bannerSelector: '#tigerstyle-whiskers-consent-overlay', categoriesSelector: '#tw-consent-categories' }, // Current consent state consentState: { necessary: true, analytics: false, marketing: false, preferences: false, timestamp: null, version: null }, // Initialize consent management init: function() { this.loadCurrentConsent(); this.bindEvents(); this.detectBoundaries(); // Update client-side boundary detection if (typeof tigerstyleWhiskers !== 'undefined') { this.updateBoundaryDetection(); } console.log('🐱 TigerStyle Whiskers: Consent management initialized with feline precision!'); }, // Load current consent from cookie loadCurrentConsent: function() { const consentCookie = this.getCookie(this.config.cookieName); if (consentCookie) { try { this.consentState = Object.assign(this.consentState, JSON.parse(consentCookie)); } catch (e) { console.warn('TigerStyle Whiskers: Invalid consent cookie, resetting...'); this.clearConsent(); } } }, // Bind event handlers bindEvents: function() { const self = this; // Category toggle handlers $(document).on('change', '.tw-consent-category input[type="checkbox"]', function() { const category = $(this).attr('name').replace('consent_', ''); const isChecked = $(this).is(':checked'); // Animate the change self.animateToggle($(this).closest('.tw-consent-category'), isChecked); }); // Keyboard navigation $(document).on('keydown', this.config.bannerSelector, function(e) { if (e.key === 'Escape') { self.acceptNecessary(); } }); // Focus management for accessibility $(document).on('focus', '.tw-consent-switch input', function() { $(this).closest('.tw-consent-category').addClass('tw-focused'); }).on('blur', '.tw-consent-switch input', function() { $(this).closest('.tw-consent-category').removeClass('tw-focused'); }); }, // Detect client-side boundaries detectBoundaries: function() { const boundaries = { technical: { cookies_enabled: navigator.cookieEnabled, javascript_enabled: true, local_storage_available: typeof(Storage) !== "undefined", session_storage_available: typeof(sessionStorage) !== "undefined", do_not_track: navigator.doNotTrack === "1" || window.doNotTrack === "1", screen_width: screen.width, screen_height: screen.height, color_depth: screen.colorDepth, timezone: this.getTimezone(), connection_type: this.getConnectionType(), device_memory: navigator.deviceMemory || 'unknown', hardware_concurrency: navigator.hardwareConcurrency || 'unknown' }, user_preferences: { language: navigator.language, languages: navigator.languages || [], prefers_reduced_motion: window.matchMedia('(prefers-reduced-motion: reduce)').matches, prefers_dark_mode: window.matchMedia('(prefers-color-scheme: dark)').matches, prefers_high_contrast: window.matchMedia('(prefers-contrast: high)').matches }, privacy_signals: { global_privacy_control: navigator.globalPrivacyControl || false, do_not_track: navigator.doNotTrack === "1", ad_blocker_detected: this.detectAdBlocker() } }; // Store enhanced boundaries if (boundaries.technical.local_storage_available) { localStorage.setItem('tigerstyle_whiskers_client_boundaries', JSON.stringify(boundaries)); } return boundaries; }, // Update boundary detection with server updateBoundaryDetection: function() { const boundaries = this.detectBoundaries(); // Send to server via AJAX $.ajax({ url: tigerstyleWhiskersConsent.ajaxurl, type: 'POST', data: { action: 'tigerstyle_whiskers_update_boundaries', nonce: tigerstyleWhiskersConsent.nonce, boundaries: JSON.stringify(boundaries) }, success: function(response) { console.log('🐱 TigerStyle Whiskers: Boundary detection updated'); } }); }, // Get timezone getTimezone: function() { try { return Intl.DateTimeFormat().resolvedOptions().timeZone; } catch (e) { return 'unknown'; } }, // Get connection type getConnectionType: function() { if (navigator.connection) { return { effective_type: navigator.connection.effectiveType, downlink: navigator.connection.downlink, rtt: navigator.connection.rtt, save_data: navigator.connection.saveData }; } return 'unknown'; }, // Detect ad blocker detectAdBlocker: function() { // Simple ad blocker detection const adBlockTest = document.createElement('div'); adBlockTest.innerHTML = ' '; adBlockTest.className = 'adsbox'; adBlockTest.style.position = 'absolute'; adBlockTest.style.left = '-999px'; document.body.appendChild(adBlockTest); const isBlocked = adBlockTest.offsetHeight === 0; document.body.removeChild(adBlockTest); return isBlocked; }, // Show consent banner showBanner: function() { const $banner = $(this.config.bannerSelector); // Set focus for accessibility $banner.attr('role', 'dialog'); $banner.attr('aria-labelledby', 'tw-consent-title'); $banner.attr('aria-describedby', 'tw-consent-message'); $banner.fadeIn(300, function() { // Focus first interactive element $banner.find('.tw-btn').first().focus(); }); // Track banner shown event this.trackEvent('consent_banner_shown'); }, // Hide consent banner hideBanner: function() { $(this.config.bannerSelector).fadeOut(300); this.trackEvent('consent_banner_hidden'); }, // Show category customization showCategories: function() { const $categories = $(this.config.categoriesSelector); if ($categories.is(':visible')) { $categories.slideUp(300); $('.tw-btn-customize').text(tigerstyleWhiskersConsent.strings.customize); } else { $categories.slideDown(300); $('.tw-btn-customize').text(tigerstyleWhiskersConsent.strings.save_preferences); $('.tw-btn-customize').off('click').on('click', () => this.saveCustomPreferences()); // Set current values this.setCurrentValues(); } this.trackEvent('consent_categories_toggled'); }, // Set current values in form setCurrentValues: function() { const self = this; Object.keys(this.consentState).forEach(function(category) { if (typeof self.consentState[category] === 'boolean') { const $checkbox = $(`#consent_${category}`); $checkbox.prop('checked', self.consentState[category]); } }); }, // Accept all cookies acceptAll: function() { this.consentState = { necessary: true, analytics: true, marketing: true, preferences: true, timestamp: Date.now(), version: tigerstyleWhiskersConsent.current_consent.version || '1.0' }; this.saveConsent(); this.hideBanner(); this.triggerConsentCallbacks(); this.trackEvent('consent_all_accepted'); // Show success message this.showSuccessMessage(tigerstyleWhiskersConsent.strings.accept_all); }, // Accept necessary only acceptNecessary: function() { this.consentState = { necessary: true, analytics: false, marketing: false, preferences: false, timestamp: Date.now(), version: tigerstyleWhiskersConsent.current_consent.version || '1.0' }; this.saveConsent(); this.hideBanner(); this.triggerConsentCallbacks(); this.trackEvent('consent_necessary_only'); // Show success message this.showSuccessMessage(tigerstyleWhiskersConsent.strings.accept_necessary); }, // Save custom preferences saveCustomPreferences: function() { const self = this; // Get values from form Object.keys(this.consentState).forEach(function(category) { if (typeof self.consentState[category] === 'boolean') { const $checkbox = $(`#consent_${category}`); if ($checkbox.length) { self.consentState[category] = $checkbox.is(':checked'); } } }); this.consentState.timestamp = Date.now(); this.consentState.version = tigerstyleWhiskersConsent.current_consent.version || '1.0'; this.saveConsent(); this.hideBanner(); this.triggerConsentCallbacks(); this.trackEvent('consent_custom_saved'); // Show success message this.showSuccessMessage(tigerstyleWhiskersConsent.strings.save_preferences); }, // Save consent to cookie and server saveConsent: function() { // Save to cookie this.setCookie(this.config.cookieName, JSON.stringify(this.consentState), this.config.cookieExpiry); // Send to server $.ajax({ url: tigerstyleWhiskersConsent.ajaxurl, type: 'POST', data: { action: 'tigerstyle_whiskers_update_consent', nonce: tigerstyleWhiskersConsent.nonce, analytics: this.consentState.analytics, marketing: this.consentState.marketing, preferences: this.consentState.preferences }, success: function(response) { console.log('🐱 TigerStyle Whiskers: Consent saved with feline precision!'); }, error: function() { console.warn('🐱 TigerStyle Whiskers: Failed to save consent to server'); } }); }, // Trigger consent change callbacks triggerConsentCallbacks: function() { // Dispatch custom event const event = new CustomEvent('tigerstyleWhiskersConsentChanged', { detail: this.consentState }); document.dispatchEvent(event); // Legacy callback support if (typeof window.onTigerstyleWhiskersConsentChanged === 'function') { window.onTigerstyleWhiskersConsentChanged(this.consentState); } // Initialize analytics if consent given if (this.consentState.analytics && typeof tigerstyleWhiskersInitAnalytics === 'function') { tigerstyleWhiskersInitAnalytics(); } }, // Check if analytics consent is given hasAnalyticsConsent: function() { return this.consentState.analytics === true; }, // Check if marketing consent is given hasMarketingConsent: function() { return this.consentState.marketing === true; }, // Check if preferences consent is given hasPreferencesConsent: function() { return this.consentState.preferences === true; }, // Get consent for specific category getConsent: function(category) { return this.consentState[category] || false; }, // Show success message showSuccessMessage: function(message) { const $message = $('