PageSourceSearch

https://www.inhealthgroup.com/wp-content/plugins/faz-cookie-manager/frontend/js/faz-dsar.js?ver=1.24.0

js inhealthgroup.com collected 2026-10-09 22:42:02 UTC 8,625 bytes, 260 lines download raw bytes

1/**
2 * DSAR form submit handler — loaded via wp_enqueue_script so it runs even
3 * when a page builder (e.g. Bricks) injects the shortcode HTML dynamically.
4 * Inline scripts inside dynamically-injected HTML are silently ignored by
5 * browsers, so the handler must live in a separately-enqueued file.
6 *
7 * The listener is attached directly to each .faz-dsar-form element (not
8 * delegated from document) so that page-builder event interceptors that call
9 * stopPropagation() at the document level cannot suppress the submit handler.
10 * A MutationObserver covers forms added to the DOM after script execution.
11 *
12 * Data flow:
13 *   ajaxUrl / error strings  — window.fazDsarConfig (set by wp_localize_script)
14 *   nonce + action           — hidden inputs already in form HTML
15 *   form data                — FormData(form) captures all inputs including nonce
16 */
17(function () {
18	/**
19	 * Switch the notice container into "error" mode: role=alert + aria-live=assertive
20	 * so assistive tech announces validation/submit failures immediately. Success
21	 * messages keep the polite role=status (set in setNoticeSuccess()).
22	 */
23	function setNoticeError(notice) {
24		if (!notice) { return; }
25		notice.className = 'faz-dsar-notice error';
26		notice.setAttribute('role', 'alert');
27		notice.setAttribute('aria-live', 'assertive');
28	}
29
30	function setNoticeSuccess(notice) {
31		if (!notice) { return; }
32		notice.className = 'faz-dsar-notice success';
33		notice.setAttribute('role', 'status');
34		notice.setAttribute('aria-live', 'polite');
35	}
36
37	/**
38	 * Remove any prior per-field error markup. Called at the start of every
39	 * submit attempt so stale errors do not linger after the user corrects them.
40	 */
41	function clearFieldErrors(form) {
42		if (!form) { return; }
43		var inputs = form.querySelectorAll('[aria-invalid="true"]');
44		for (var i = 0; i < inputs.length; i++) {
45			inputs[i].removeAttribute('aria-invalid');
46			var describedBy = inputs[i].getAttribute('aria-describedby') || '';
47			// Strip our error IDs (faz-dsar-err-*) but preserve any other describedby tokens.
48			var tokens = describedBy.split(/\s+/).filter(function (tok) {
49				return tok && tok.indexOf('faz-dsar-err-') !== 0;
50			});
51			if (tokens.length) {
52				inputs[i].setAttribute('aria-describedby', tokens.join(' '));
53			} else {
54				inputs[i].removeAttribute('aria-describedby');
55			}
56		}
57		var spans = form.querySelectorAll('.faz-field-error');
58		for (var j = 0; j < spans.length; j++) {
59			spans[j].parentNode.removeChild(spans[j]);
60		}
61	}
62
63	/**
64	 * Mark `input` as invalid: set aria-invalid, render a per-field <span> with
65	 * a stable id, and wire it up via aria-describedby so screen readers
66	 * announce the message when focus enters the field.
67	 */
68	function markFieldInvalid(input, message) {
69		if (!input) { return; }
70		input.setAttribute('aria-invalid', 'true');
71		var errId = input.id ? (input.id + '-err') : ('faz-dsar-err-' + Math.random().toString(36).slice(2, 9));
72		// Reuse our own id namespace to make cleanup deterministic.
73		if (input.id) {
74			errId = 'faz-dsar-err-' + input.id;
75		}
76		var existing = document.getElementById(errId);
77		if (existing && existing.parentNode) {
78			existing.parentNode.removeChild(existing);
79		}
80		var span = document.createElement('span');
81		span.className = 'faz-field-error';
82		span.id = errId;
83		span.textContent = message;
84		// Insert after the input so it is visually adjacent to the field.
85		if (input.parentNode) {
86			input.parentNode.insertBefore(span, input.nextSibling);
87		}
88		var prior = input.getAttribute('aria-describedby');
89		var tokens = prior ? prior.split(/\s+/).filter(Boolean) : [];
90		if (tokens.indexOf(errId) === -1) {
91			tokens.push(errId);
92		}
93		input.setAttribute('aria-describedby', tokens.join(' '));
94	}
95
96	/**
97	 * Move keyboard focus and viewport to the first invalid field so the user
98	 * can correct it immediately without hunting through the form.
99	 */
100	function focusFirstInvalid(form) {
101		if (!form) { return; }
102		var first = form.querySelector('[aria-invalid="true"]');
103		if (!first) { return; }
104		try {
105			first.focus({ preventScroll: true });
106		} catch (err) {
107			first.focus();
108		}
109		if (typeof first.scrollIntoView === 'function') {
110			try {
111				first.scrollIntoView({ behavior: 'smooth', block: 'center' });
112			} catch (err) {
113				first.scrollIntoView();
114			}
115		}
116	}
117
118	function handleSubmit(e) {
119		e.preventDefault();
120
121		var form   = e.currentTarget;
122		var wrap   = form.parentElement;
123		var notice = wrap ? wrap.querySelector('.faz-dsar-notice') : null;
124		var config = window.fazDsarConfig || {};
125		var ajaxUrl = config.ajaxUrl || '';
126		var errMsg  = config.errMsg  || 'An error occurred. Please try again.';
127		var reqMsg  = config.reqMsg  || 'Please fill in all required fields.';
128
129		var nameEl  = form.querySelector('[name="dsar_name"]');
130		var emailEl = form.querySelector('[name="dsar_email"]');
131		var typeEl  = form.querySelector('[name="dsar_type"]');
132		var name    = nameEl  ? nameEl.value.trim()  : '';
133		var email   = emailEl ? emailEl.value.trim() : '';
134		var type    = typeEl  ? typeEl.value         : '';
135
136		// Reset any prior validation markup before re-evaluating.
137		clearFieldErrors(form);
138
139		var missing = [];
140		var nameLabel  = config.nameLabel  || 'Name';
141		var emailLabel = config.emailLabel || 'Email';
142		var typeLabel  = config.typeLabel  || 'Request type';
143		if (!name)  {
144			missing.push(nameLabel);
145			markFieldInvalid(nameEl, reqMsg);
146		}
147		if (!email) {
148			missing.push(emailLabel);
149			markFieldInvalid(emailEl, reqMsg);
150		}
151		if (!type)  {
152			missing.push(typeLabel);
153			markFieldInvalid(typeEl, reqMsg);
154		}
155		if (missing.length) {
156			if (notice) {
157				setNoticeError(notice);
158				notice.textContent   = reqMsg + ' Missing: ' + missing.join(', ') + '.';
159				notice.style.display = 'block';
160			}
161			focusFirstInvalid(form);
162			return;
163		}
164
165		var emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
166		if (!emailPattern.test(email)) {
167			var emailErr = config.emailMsg || 'Please enter a valid email address.';
168			markFieldInvalid(emailEl, emailErr);
169			if (notice) {
170				setNoticeError(notice);
171				notice.textContent   = emailErr;
172				notice.style.display = 'block';
173			}
174			focusFirstInvalid(form);
175			return;
176		}
177
178		var btn = form.querySelector('button');
179		if (btn) { btn.disabled = true; }
180		if (notice) { notice.style.display = 'none'; }
181
182		fetch(ajaxUrl, {
183			method: 'POST',
184			credentials: 'same-origin',
185			body: new FormData(form),
186		})
187		.then(function (r) { return r.json(); })
188		.then(function (res) {
189			var payload = (res && typeof res.data !== 'undefined') ? res.data : null;
190			var payloadMessage = '';
191			if (payload && typeof payload === 'object') {
192				payloadMessage = payload.message ? String(payload.message) : JSON.stringify(payload);
193			} else if (typeof payload === 'string') {
194				payloadMessage = payload;
195			}
196			if (res.success) {
197				form.style.display = 'none';
198				if (notice) {
199					setNoticeSuccess(notice);
200					notice.textContent = payloadMessage || config.successMsg || 'Request sent successfully.';
201				}
202			} else {
203				if (notice) {
204					setNoticeError(notice);
205					notice.textContent = payloadMessage || errMsg;
206				}
207				if (btn) { btn.disabled = false; }
208			}
209			if (notice) {
210				notice.style.display = 'block';
211				notice.focus();
212			}
213		})
214		.catch(function () {
215			if (notice) {
216				setNoticeError(notice);
217				notice.textContent   = errMsg;
218				notice.style.display = 'block';
219				notice.focus();
220			}
221			if (btn) { btn.disabled = false; }
222		});
223	}
224
225	function attachToForm(form) {
226		if (form._fazDsarAttached) { return; }
227		form._fazDsarAttached = true;
228		form.addEventListener('submit', handleSubmit);
229	}
230
231	// Attach to any .faz-dsar-form already in the DOM.
232	var existing = document.querySelectorAll('.faz-dsar-form');
233	for (var i = 0; i < existing.length; i++) {
234		attachToForm(existing[i]);
235	}
236
237	// Watch for forms injected after script execution (page-builder lazy render).
238	if (typeof MutationObserver !== 'undefined') {
239		var observer = new MutationObserver(function (mutations) {
240			for (var m = 0; m < mutations.length; m++) {
241				var added = mutations[m].addedNodes;
242				for (var n = 0; n < added.length; n++) {
243					var node = added[n];
244					if (node.nodeType !== 1) { continue; }
245					if (node.classList && node.classList.contains('faz-dsar-form')) {
246						attachToForm(node);
247					}
248					var nested = node.querySelectorAll ? node.querySelectorAll('.faz-dsar-form') : [];
249					for (var k = 0; k < nested.length; k++) {
250						attachToForm(nested[k]);
251					}
252				}
253			}
254		});
255		observer.observe(document.body || document.documentElement, {
256			childList: true,
257			subtree: true,
258		});
259	}
260}());

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.