PageSourceSearch

https://www.honeyseed.com/static/js/newsletter_signup.js

js honeyseed.com collected 2026-10-09 22:42:11 UTC 5,987 bytes, 202 lines download raw bytes

1/**
2 * Newsletter Signup Ajax Handler
3 * Handles form submission for newsletter signup forms across all pages
4 */
5(function () {
6  'use strict';
7
8  // Initialize when DOM is ready
9  document.addEventListener('DOMContentLoaded', function () {
10    initNewsletterForm();
11  });
12
13  function initNewsletterForm() {
14    const form = document.querySelector('.newsletter-form');
15    if (!form) return; // No newsletter form on this page
16
17    const emailInput = form.querySelector('input[name="email"]'); // More flexible selector
18    const submitBtn = form.querySelector('.newsletter-btn');
19    const btnText = submitBtn.querySelector('.newsletter-btn-text');
20    const btnLoading = submitBtn.querySelector('.newsletter-btn-loading');
21    const errorContainer = document.getElementById('newsletter-error');
22    const successContainer = document.getElementById('newsletter-success');
23
24    // Handle form submission
25    form.addEventListener('submit', function (e) {
26      e.preventDefault();
27      handleFormSubmission();
28    });
29
30    // Clear errors when user starts typing
31    emailInput.addEventListener('input', function () {
32      clearMessages();
33      emailInput.classList.remove('is-invalid');
34    });
35
36    function handleFormSubmission() {
37      // Get form data
38      const formData = new FormData(form);
39      const ajaxUrl = form.dataset.ajaxUrl;
40
41      if (!ajaxUrl) {
42        console.error('Newsletter form missing data-ajax-url attribute');
43        showError('Configuration error. Please try again later.');
44        return;
45      }
46
47      // Validate email client-side first
48      const email = emailInput.value.trim();
49      if (!email) {
50        showError('Please enter your email address.');
51        emailInput.focus();
52        return;
53      }
54
55      if (!isValidEmail(email)) {
56        showError('Please enter a valid email address.');
57        emailInput.focus();
58        return;
59      }
60
61      // Show loading state
62      setLoadingState(true);
63      clearMessages();
64
65      // Submit form via Ajax
66      fetch(ajaxUrl, {
67        method: 'POST',
68        body: formData,
69        headers: {
70          'X-Requested-With': 'XMLHttpRequest',
71          'X-CSRFToken': getCSRFToken()
72        },
73        credentials: 'same-origin'
74      })
75        .then(response => {
76          if (!response.ok) {
77            throw new Error(`HTTP ${response.status}: ${response.statusText}`);
78          }
79          return response.json();
80        })
81        .then(data => {
82          handleResponse(data);
83        })
84        .catch(error => {
85          console.error('Newsletter signup error:', error);
86          showError('Something went wrong. Please try again later.');
87        })
88        .finally(() => {
89          setLoadingState(false);
90        });
91    }
92
93    function handleResponse(data) {
94      if (data.success) {
95        // Success - clear form and show success message
96        form.reset();
97        showSuccess(data.message || 'Thank you for subscribing!');
98
99        // Optional: Track conversion for analytics
100        if (typeof gtag !== 'undefined') {
101          gtag('event', 'newsletter_signup', {
102            'event_category': 'engagement',
103            'event_label': 'footer_newsletter'
104          });
105        }
106      } else {
107        // Handle errors
108        if (data.form_errors && data.form_errors.email) {
109          showError(data.form_errors.email);
110          emailInput.classList.add('is-invalid');
111        } else {
112          showError(data.error || 'Something went wrong. Please try again.');
113        }
114
115        // Focus back to input for better UX
116        emailInput.focus();
117      }
118    }
119
120    function setLoadingState(loading) {
121      if (loading) {
122        submitBtn.disabled = true;
123        btnText.classList.add('d-none');
124        btnLoading.classList.remove('d-none');
125        emailInput.disabled = true;
126      } else {
127        submitBtn.disabled = false;
128        btnText.classList.remove('d-none');
129        btnLoading.classList.add('d-none');
130        emailInput.disabled = false;
131      }
132    }
133
134    function showError(message) {
135      clearMessages();
136      errorContainer.textContent = message;
137      errorContainer.classList.remove('d-none');
138
139      // Scroll error into view if needed
140      if (!isElementInViewport(errorContainer)) {
141        errorContainer.scrollIntoView({
142          behavior: 'smooth',
143          block: 'center'
144        });
145      }
146    }
147
148    function showSuccess(message) {
149      clearMessages();
150      successContainer.textContent = message;
151      successContainer.classList.remove('d-none');
152
153      // Auto-hide success message after 5 seconds
154      setTimeout(() => {
155        successContainer.classList.add('d-none');
156      }, 5000);
157    }
158
159    function clearMessages() {
160      errorContainer.classList.add('d-none');
161      successContainer.classList.add('d-none');
162      errorContainer.textContent = '';
163      successContainer.textContent = '';
164    }
165
166    function isValidEmail(email) {
167      // Basic email validation - Django form will do the heavy lifting
168      const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
169      return emailRegex.test(email);
170    }
171
172    function getCSRFToken() {
173      // Get CSRF token from form
174      const csrfInput = form.querySelector('[name="csrfmiddlewaretoken"]');
175      if (csrfInput) {
176        return csrfInput.value;
177      }
178
179      // Fallback: get from cookie
180      const cookies = document.cookie.split(';');
181      for (let cookie of cookies) {
182        const [name, value] = cookie.trim().split('=');
183        if (name === 'csrftoken') {
184          return value;
185        }
186      }
187
188      console.warn('CSRF token not found');
189      return '';
190    }
191
192    function isElementInViewport(element) {
193      const rect = element.getBoundingClientRect();
194      return (
195        rect.top >= 0 &&
196        rect.left >= 0 &&
197        rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
198        rect.right <= (window.innerWidth || document.documentElement.clientWidth)
199      );
200    }
201  }
202})();

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.