1(function () { 2 'use strict'; 3 4 // ============================================ 5 // 1) CONFIG & STATE 6 // ============================================ 7 const CONFIG = { 8 debug: false, 9 cookieExpiry: 365, 10 botKeywords: [ 11 'bot', 'googlebot', 'applebot', 'bingbot', 'crawler', 'spider', 12 'mediapartners', 'adsbot', 'baiduspider', 'yandex', 'duckduckbot', 13 'facebot', 'facebookexternalhit', 'ia_archiver', 'headless', 'puppeteer', 14 'selenium', 'webdriver' 15 ] 16 }; 17 18 const isUserLoggedIn = /wordpress_logged_in_/.test(document.cookie); 19 const isLocalHost = (window.location.hostname === 'localhost'); 20 21 // ============================================ 22 // 2) SIMPLE LOGGER 23 // ============================================ 24 function debugLog(message, type = 'info') { 25 if (!CONFIG.debug) return; 26 const colors = { 27 info: 'color: #007bff;', 28 success: 'color: #08c753;', 29 warn: 'color: #FF5100;', 30 error: 'color: #EC2361;' 31 }; 32 console.log(`%c[DEBUG] ${message}`, colors[type] || colors.info); 33 } 34 35 // ============================================ 36 // 3) UTILITIES 37 // ============================================ 38 function getCookie(name) { 39 const value = `; ${document.cookie}`; 40 const parts = value.split(`; ${name}=`); 41 if (parts.length === 2) return decodeURIComponent(parts.pop().split(';').shift()); 42 return null; 43 } 44 45 function setCookie(name, value, days) { 46 debugLog(`Setting cookie: ${name}=${value}`, 'info'); 47 const date = new Date(); 48 date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); 49 let cookieStr = `${name}=${encodeURIComponent(value)};expires=${date.toUTCString()};path=/;SameSite=Lax`; 50 if (location.protocol === 'https:') cookieStr += ";Secure"; 51 document.cookie = cookieStr; 52 } 53 54 function isBot() { 55 const ua = navigator.userAgent.toLowerCase(); 56 return CONFIG.botKeywords.some(keyword => ua.indexOf(keyword) !== -1); 57 } 58 59 function isMobile() { 60 return /android|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent); 61 } 62 63 // ============================================ 64 // 4) SCRIPT LOADERS 65 // ============================================ 66 67 function loadGoogleAnalytics(context = 'general_load') { 68 if (document.getElementById('google-gtag-script')) return; 69 70 debugLog(`Initializing GA4 via context: ${context}`, 'info'); 71 72 // 1. DataLayer Setup 73 window.dataLayer = window.dataLayer || []; 74 window.gtag = function(){ dataLayer.push(arguments); }; 75 76 gtag('js', new Date()); 77 gtag('config', 'G-042W6VTM7G'); 78 79 // 2. Log Privacy Event 80 gtag('event', 'privacy_consent_load', { 81 'event_category': 'privacy', 82 'event_label': context 83 }); 84 85 // 3. Inject Library 86 const ga = document.createElement('script'); 87 ga.id = 'google-gtag-script'; 88 ga.async = true; 89 ga.src = 'https://www.googletagmanager.com/gtag/js?id=G-042W6VTM7G'; 90 document.head.appendChild(ga); 91 } 92 93 function loadBeacon() { 94 if (!document.querySelector('.blocktype-form') || document.getElementById('beacon-js-sdk')) return; 95 debugLog('Loading Beacon CRM...'); 96 const js = document.createElement('script'); 97 js.id = 'beacon-js-sdk'; 98 js.src = 'https://static.beaconproducts.co.uk/js-sdk/production/beaconcrm.min.js'; 99 document.head.appendChild(js); 100 } 101 102 function loadAssistant() { 103 if (document.querySelector('.assistant-trigger')) return; 104 debugLog('Injecting Assistant markup...'); 105 const div = document.createElement('div'); 106 div.className = 'assistant-trigger'; 107 div.innerHTML = ` 108 <button aria-label="Open Cybersmile Assistant"> 109 <svg class="icon" fill="currentColor" aria-hidden="true" focusable="false"> 110 <use xlink:href="#icon-logo-square"></use> 111 </svg>
112 <span class="sr-only">Open Assistant</span> 113 </button> 114 <span class="arrow-right"></span>`; 115 document.body.appendChild(div); 116 } 117 118 function removeMailerLiteDiv() { 119 const mailerLiteDiv = document.getElementById('mailerlite'); 120 if (mailerLiteDiv) { 121 debugLog('Removing MailerLite div.'); 122 mailerLiteDiv.parentNode.removeChild(mailerLiteDiv); 123 } 124 } 125 126 function loadMailerLite() { 127 const mailerLiteDiv = document.getElementById('mailerlite'); 128 if (!mailerLiteDiv || document.getElementById('mailerlite-script')) return; 129 debugLog('Loading MailerLite scripts...'); 130 const nonce = document.querySelector('script[nonce]')?.nonce || ''; 131 const sdk = document.createElement('script'); 132 sdk.id = 'mailerlite-script'; 133 sdk.src = 'https://groot.mailerlite.com/js/w/webforms.min.js?v176e10baa5e7ed80d35ae235be3d5024'; 134 if (nonce) sdk.setAttribute('nonce', nonce); 135 document.head.appendChild(sdk); 136 } 137 138 function runAllScripts(context) { 139 debugLog(`Executing runAllScripts from: ${context}`, 'success'); 140 141 if (!isMobile()) loadAssistant(); 142 143 if (!isUserLoggedIn && !isLocalHost) { 144 loadGoogleAnalytics(context); 145 } else { 146 debugLog('Skipping GA (Logged in or Localhost).'); 147 } 148 149 loadBeacon(); 150 loadMailerLite(); 151 } 152 153 // ============================================ 154 // 5) CONSENT UI (BANNER) 155 // ============================================ 156 function showCookieBanner() { 157 if (document.getElementById('siteCookiesWrapper')) return; 158 debugLog('Attempting to show cookie banner...', 'info'); 159 160 const html = ` 161 <div id="siteCookiesWrapper" class="site-cookies--wrapper" role="alertdialog" aria-modal="true" aria-labelledby="siteCookiesTitle"> 162 <div class="site-cookies--overlay"></div> 163 <div class="site-cookies"> 164 <div class="site-cookies--body"> 165 <button class="site-cookies--close" data-action="deny-cookies">â</button> 166 <div id="siteCookiesTitle" class="site-cookies--headline">We value your privacy.</div> 167 <div class="site-cookies--description"> 168 <p>Our website uses cookies to provide you with a better online experience. By acknowledging this notice, you accept the use of cookies on this site.</p> 169 <p>If you wish to view and adjust your privacy settings, you can click <span style="font-weight:500;">Manage My Consent</span> at any time in the website footer. You can <a href="https://www.cybersmile.org/cookie-policy/">read our privacy policy here</a>.</p> 170 </div> 171 </div> 172 <div class="site-cookies--actions"> 173 <button class="site-cookies--action" data-action="accept-cookies">Accept All</button> 174 <button class="site-cookies--action" data-action="deny-cookies">Reject All</button> 175 </div> 176 </div> 177 </div>`; 178 179 document.body.insertAdjacentHTML('beforeend', html); 180 181 document.getElementById('siteCookiesWrapper').addEventListener('click', (e) => { 182 const action = e.target.closest('[data-action]')?.dataset.action; 183 if (!action) return; 184 185 if (action === 'accept-cookies') { 186 debugLog('User accepted cookies. Reloading...', 'success'); 187 setCookie('cy-consent', 'true', CONFIG.cookieExpiry); 188 location.reload(); 189 } else { 190 debugLog('User denied cookies. Hiding banner.', 'warn'); 191 setCookie('cy-consent', 'false', CONFIG.cookieExpiry); 192 removeMailerLiteDiv(); 193 document.getElementById('siteCookiesWrapper').remove(); 194 } 195 }); 196 } 197 198 // ============================================ 199 // 6) CORE LOGIC 200 // ============================================
201 function init() { 202 debugLog(`Script started. isUserLoggedIn=${isUserLoggedIn}`, 'info'); 203 204 const userConsent = getCookie('cy-consent'); 205 const edgeFlag = getCookie('cy-requires-consent'); 206 207 if (userConsent === 'true') { 208 runAllScripts('returning_user'); 209 return; 210 } 211 212 if (userConsent === 'false') { 213 debugLog('Consent previously denied. Skipping scripts.', 'warn'); 214 removeMailerLiteDiv(); 215 return; 216 } 217 218 if (isBot()) { 219 setCookie('cy-consent', 'true', CONFIG.cookieExpiry); 220 runAllScripts('bot_bypass'); 221 return; 222 } 223 224 if (isUserLoggedIn) { 225 runAllScripts('auth_bypass'); 226 return; 227 } 228 229 if (edgeFlag === 'false') { 230 setCookie('cy-consent', 'true', CONFIG.cookieExpiry); 231 runAllScripts('geo_bypass'); 232 } else { 233 showCookieBanner(); 234 } 235 } 236 237 init(); 238 239 document.addEventListener('DOMContentLoaded', () => { 240 const manageLink = document.getElementById('manage-consent-link'); 241 if (manageLink) { 242 manageLink.addEventListener('click', (e) => { 243 e.preventDefault(); 244 showCookieBanner(); 245 }); 246 } 247 }); 248 249})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.