PageSourceSearch

https://mightygreen.com/wp-content/plugins/tmb-site-manager-client…/tracking-subscription-form.js?ver=1.149.0

js mightygreen.com collected 2026-10-04 18:57:58 UTC 3,672 bytes, 106 lines download raw bytes

1/**
2 * Nexus Client — Public Subscribe Form
3 *
4 * Intercepts submissions for any `.tmb-subscribe-form` on the page, validates
5 * email, POSTs to /tmb-client/v1/tracking/subscribe, and surfaces success /
6 * error state via `.tmb-subscribe-status`. Also emits tracking events through
7 * the shared TMBClientBeacon.
8 */
9(function () {
10	'use strict';
11
12	if (typeof document === 'undefined') return;
13
14	var cfg  = window.TMBClientBeacon || {};
15	var i18n = cfg.i18n || {};
16	var SUBSCRIBE_URL = (cfg.restRoot || '').replace(/\/+$/, '') + '/tracking/subscribe';
17	var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/;
18
19	function setStatus($status, text, state) {
20		if (!$status) return;
21		$status.textContent = text || '';
22		$status.classList.remove('is-success', 'is-error');
23		if (state) $status.classList.add('is-' + state);
24	}
25
26	function trackSafe(event, ctx, metrics) {
27		if (typeof cfg.track === 'function') {
28			try { cfg.track(event, ctx || {}, metrics || {}); } catch (e) {}
29		}
30	}
31
32	function handleSubmit(e) {
33		var form = e.target;
34		if (!form || !form.classList || !form.classList.contains('tmb-subscribe-form')) return;
35		e.preventDefault();
36
37		var emailInput = form.querySelector('input[name="email"]');
38		var zipInput   = form.querySelector('input[name="zip"]');
39		var sourceInput = form.querySelector('input[name="source"]');
40		var submitBtn  = form.querySelector('button[type="submit"]');
41		var status     = form.querySelector('.tmb-subscribe-status');
42
43		var email  = emailInput ? String(emailInput.value || '').trim()  : '';
44		var zip    = zipInput   ? String(zipInput.value   || '').trim()  : '';
45		var source = sourceInput? String(sourceInput.value|| '').trim()  : (form.getAttribute('data-source') || 'inline');
46
47		if (!email || !EMAIL_RE.test(email)) {
48			setStatus(status, i18n.emailInvalid || 'Please enter a valid email address.', 'error');
49			if (emailInput) {
50				emailInput.setAttribute('aria-invalid', 'true');
51				emailInput.focus();
52			}
53			trackSafe('subscription.invalid', { reason: 'invalid_email' });
54			return;
55		}
56		if (emailInput) emailInput.removeAttribute('aria-invalid');
57
58		if (submitBtn) submitBtn.disabled = true;
59		setStatus(status, '…', null);
60
61		trackSafe('subscription.attempt', { source: source, has_zip: !!zip });
62
63		fetch(SUBSCRIBE_URL, {
64			method: 'POST',
65			credentials: 'same-origin',
66			headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
67			body: JSON.stringify({
68				email:   email,
69				zip:     zip,
70				source:  source,
71				consent: cfg.consent || 'unknown'
72			})
73		}).then(function (res) {
74			return res.json().then(function (data) {
75				return { ok: res.ok, data: data };
76			}).catch(function () {
77				return { ok: res.ok, data: null };
78			});
79		}).then(function (out) {
80			if (out.ok && out.data && out.data.success !== false) {
81				setStatus(status, i18n.subscribeOk || 'You\'re subscribed.', 'success');
82				trackSafe('subscription.success', { source: source });
83				form.reset();
84			} else {
85				setStatus(status, i18n.subscribeErr || 'Something went wrong. Try again.', 'error');
86				trackSafe('subscription.failed', { source: source });
87			}
88		}).catch(function () {
89			setStatus(status, i18n.subscribeErr || 'Something went wrong. Try again.', 'error');
90			trackSafe('subscription.failed', { source: source, error: 'network' });
91		}).then(function () {
92			if (submitBtn) submitBtn.disabled = false;
93		});
94	}
95
96	function bind() {
97		// Delegate so dynamically-injected forms also work.
98		document.addEventListener('submit', handleSubmit, true);
99	}
100
101	if (document.readyState === 'loading') {
102		document.addEventListener('DOMContentLoaded', bind, { once: true });
103	} else {
104		bind();
105	}
106})();

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.