1/** 2 * Newsletter Signup functionality - PoolDial Newsletter 3 * Handles subscription with email confirmation via Netlify function 4 */ 5document.addEventListener('DOMContentLoaded', function() { 6 const newsletterForm = document.querySelector('.sidebar-newsletter form'); 7 8 // Article starter-kit forms handle their own submit flow and should not get 9 // a newsletter Turnstile widget injected. 10 if (!newsletterForm || newsletterForm.classList.contains('sidebar-starter-form')) return; 11 12 // Inject honeypot field (hidden from real users, bots will fill it) 13 const honeypot = document.createElement('input'); 14 honeypot.type = 'text'; 15 honeypot.name = 'company_url'; 16 honeypot.style.cssText = 'position:absolute;left:-9999px;opacity:0;height:0;width:0;z-index:-1'; 17 honeypot.tabIndex = -1; 18 honeypot.autocomplete = 'off'; 19 newsletterForm.appendChild(honeypot); 20 21 // Record when form was loaded 22 const formLoadTime = Date.now(); 23 24 function loadTurnstile(callback) { 25 if (window.turnstile) { 26 callback(); 27 return; 28 } 29 30 var existingScript = document.querySelector('script[src*="challenges.cloudflare.com/turnstile"]'); 31 if (!existingScript) { 32 existingScript = document.createElement('script'); 33 existingScript.src = 'https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit'; 34 existingScript.async = true; 35 existingScript.defer = true; 36 document.head.appendChild(existingScript); 37 } 38 39 let attempts = 0; 40 const timer = setInterval(() => { 41 attempts++; 42 if (window.turnstile) { 43 clearInterval(timer); 44 callback(); 45 } else if (attempts > 50) { 46 clearInterval(timer); 47 } 48 }, 200); 49 } 50 51 // Render Turnstile widget 52 let turnstileWidgetId = null; 53 const turnstileContainer = document.createElement('div'); 54 turnstileContainer.style.cssText = 'display:flex;justify-content:center;margin:8px 0'; 55 newsletterForm.insertBefore(turnstileContainer, newsletterForm.querySelector('button[type="submit"]')); 56 57 loadTurnstile(() => { 58 turnstileWidgetId = window.turnstile.render(turnstileContainer, { 59 sitekey: '0x4AAAAAAC_dXKnb427jBVws' 60 }); 61 }); 62 63 newsletterForm.addEventListener('submit', async function(e) { 64 e.preventDefault(); 65 66 const emailInput = this.querySelector('input[type="email"]'); 67 const submitButton = this.querySelector('button[type="submit"]'); 68 const formContainer = this.parentElement; 69 const email = emailInput.value.trim(); 70 const botField = honeypot.value; 71 72 if (!email) return; 73 74 // Disable form while submitting 75 emailInput.disabled = true; 76 submitButton.disabled = true; 77 submitButton.textContent = 'Subscribing...'; 78 79 try { 80 const response = await fetch('/api/subscribe', { 81 method: 'POST', 82 headers: { 83 'Content-Type': 'application/json', 84 }, 85 body: JSON.stringify({ email, botField, formLoadTime, turnstileToken: (window.turnstile && turnstileWidgetId !== null) ? (window.turnstile.getResponse(turnstileWidgetId) || '') : '' }) 86 }); 87 88 const data = await response.json(); 89 90 if (response.ok && data.success) { 91 // Track Pool Brief subscription for Meta Ads 92 if (window.poolDialAnalytics && window.poolDialAnalytics.trackPoolBriefSubscribe) { 93 window.poolDialAnalytics.trackPoolBriefSubscribe({ source: 'sidebar_newsletter' }); 94 } 95 96 // Show success message - subscribed immediately 97 formContainer.innerHTML = ` 98 <h3>You're subscribed!</h3> 99 <p class="success-message">Check your inbox for a welcome email.</p> 100 `; 101 } else { 102 throw new Error(data.error || 'Subscription failed'); 103 } 104 } catch (error) { 105 console.error('Newsletter subscription error:', error); 106 // Show error but allow retry 107 emailInput.disabled = false;
108 submitButton.disabled = false; 109 submitButton.textContent = 'Subscribe'; 110 111 // Show error message 112 let errorEl = formContainer.querySelector('.error-message'); 113 if (!errorEl) { 114 errorEl = document.createElement('p'); 115 errorEl.className = 'error-message'; 116 newsletterForm.appendChild(errorEl); 117 } 118 errorEl.textContent = 'Something went wrong. Please try again.'; 119 } 120 }); 121});
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.