PageSourceSearch

https://pooldial.com/resources/newsletter.js

js pooldial.com collected 2026-10-02 10:00:41 UTC 4,703 bytes, 121 lines download raw bytes

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.