PageSourceSearch

https://www.theteacherscorner.net/includes/js/registration-modal-validation.js?v=1790345372

js theteacherscorner.net collected 2026-09-25 14:09:44 UTC 13,000 bytes, 375 lines download raw bytes

1/**
2 * Registration Modal - Validation Logic
3 */
4
5// Global validation state
6window.isStripeElementComplete = false;
7
8let validationState = {
9	fname: false,
10	lname: false,
11	username: false,
12	email: false,
13	confirm_email: false,
14	password: false,
15	password2: false,
16	payment_method: false
17};
18
19// Real-time validation functions
20function setupRealTimeValidation() {
21	const fields = ['reg_fname', 'reg_lname', 'reg_username', 'reg_email', 'reg_confirm_email', 'reg_password', 'reg_password2'];
22	
23	fields.forEach(fieldId => {
24		const field = document.getElementById(fieldId);
25		if (field) {
26			field.addEventListener('input', () => {
27				const fieldName = fieldId.replace('reg_', '');
28				clearValidation(fieldName);
29				checkFormValidity();
30			});
31			
32			field.addEventListener('blur', () => {
33				const fieldName = fieldId.replace('reg_', '');
34				validateField(fieldName, field.value);
35			});
36		}
37	});
38}
39
40function validateField(fieldName, value) {
41	switch(fieldName) {
42		case 'fname':
43		case 'lname':
44			validateRequiredField(fieldName, value);
45			break;
46		case 'username':
47			validateUsername(value);
48			break;
49		case 'email':
50			validateEmail(value);
51			break;
52		case 'confirm_email':
53			validateEmailConfirmation();
54			break;
55		case 'password':
56			validatePassword(value);
57			break;
58		case 'password2':
59			validatePasswordConfirmation();
60			break;
61	}
62}
63
64function validateRequiredField(fieldName, value) {
65	if (!value || value.trim().length === 0) {
66		showValidationMessage(fieldName, 'error', 'This field is required');
67		validationState[fieldName] = false;
68	} else {
69		showValidationMessage(fieldName, 'success', '✓');
70		validationState[fieldName] = true;
71	}
72	checkFormValidity();
73}
74
75function validateUsername(username) {
76	if (!username || username.length < 8) {
77		showValidationMessage('username', 'error', 'Username must be at least 8 characters long');
78		validationState.username = false;
79		checkFormValidity();
80		return;
81	}
82	
83	if (username.length > 32) {
84		showValidationMessage('username', 'error', 'Username must be 32 characters or less');
85		validationState.username = false;
86		checkFormValidity();
87		return;
88	}
89	
90	showValidationMessage('username', 'checking', '<span class="validation-spinner"></span>Checking username availability...');
91	
92	const formData = new FormData();
93	formData.append('action', 'check_availability');
94	formData.append('type', 'username');
95	formData.append('value', username);
96	
97	fetch('https://www.theteacherscorner.net/member/registration_api.php', {
98		method: 'POST',
99        credentials: 'include',
100		body: formData
101	})
102	.then(response => response.json())
103	.then(data => {
104		if (data.success) {
105			if (data.available) {
106				showValidationMessage('username', 'success', data.message);
107				validationState.username = true;
108			} else {
109				showValidationMessage('username', 'error', data.message);
110				validationState.username = false;
111			}
112		} else {
113			showValidationMessage('username', 'error', data.message);
114			validationState.username = false;
115		}
116		checkFormValidity();
117	})
118	.catch(error => {
119		showValidationMessage('username', 'error', 'Error checking username availability');
120		validationState.username = false;
121		checkFormValidity();
122	});
123}
124
125function validatePassword(password) {
126	if (!password || password.length < 8) {
127		showValidationMessage('password', 'error', 'Password must be at least 8 characters long');
128		validationState.password = false;
129		checkFormValidity();
130		return;
131	}
132	
133	const hasLetter = /[a-zA-Z]/.test(password);
134	const hasSpecial = /[^a-zA-Z0-9]/.test(password);
135	
136	if (!hasLetter || !hasSpecial) {
137		showValidationMessage('password', 'error', 'Password must contain at least one letter and one special character');
138		validationState.password = false;
139	} else {
140		showValidationMessage('password', 'success', 'Password meets requirements');
141		validationState.password = true;
142		const confirmPassword = document.getElementById('reg_password2').value;
143		if (confirmPassword) {
144			validatePasswordConfirmation();
145		}
146	}
147	checkFormValidity();
148}
149
150function validatePasswordConfirmation() {
151	const passwordField = document.getElementById('reg_password');
152	const confirmPasswordField = document.getElementById('reg_password2');
153	
154	if (!passwordField || !confirmPasswordField) return;
155	
156	const password = passwordField.value;
157	const confirmPassword = confirmPasswordField.value;
158	
159	if (!confirmPassword) {
160		clearValidation('password2');
161		validationState.password2 = false;
162		checkFormValidity();
163		return;
164	}
165	
166	if (password !== confirmPassword) {
167		showValidationMessage('password2', 'error', 'Passwords do not match');
168		validationState.password2 = false;
169	} else {
170		showValidationMessage('password2', 'success', 'Passwords match');
171		validationState.password2 = true;
172	}
173	checkFormValidity();
174}
175
176function validateEmail(email) {
177	if (!email || !isValidEmailFormat(email)) {
178		showValidationMessage('email', 'error', 'Please enter a valid email address');
179		validationState.email = false;
180		checkFormValidity();
181		return;
182	}
183	
184	showValidationMessage('email', 'checking', '<span class="validation-spinner"></span>Checking email availability...');
185	
186	const formData = new FormData();
187	formData.append('action', 'check_availability');
188	formData.append('type', 'email');
189	formData.append('value', email);
190	
191	fetch('https://www.theteacherscorner.net/member/registration_api.php', {
192		method: 'POST',
193        credentials: 'include',
194		body: formData
195	})
196	.then(response => response.json())
197	.then(data => {
198		if (data.success) {
199			if (data.available) {
200				showValidationMessage('email', 'success', data.message);
201				validationState.email = true;
202			} else {
203				const loginTooltipText = 'Logging in to your existing account keeps your saved info and saved slots. Creating a new account with a different email will not have access to your existing saved data.';
204				const loginMessage = `Email address is already registered. Please <a href="#" class="registration-login-link" onclick="event.preventDefault(); showLoginModal();">log in</a> first, THEN purchase a subscription <span class="registration-login-help" title="${loginTooltipText}" style="display:inline-block;margin-left:4px;width:14px;
204height:14px;line-height:14px;text-align:center;border-radius:50%;background:#0074d9;color:#ffffff;font-size:10px;font-weight:bold;vertical-align:text-top;cursor:help;">?</span>`;
205				showValidationMessage('email', 'error', loginMessage);
206				validationState.email = false;
207			}
208		} else {
209			showValidationMessage('email', 'error', data.message);
210			validationState.email = false;
211		}
212		checkFormValidity();
213	})
214	.catch(error => {
215		showValidationMessage('email', 'error', 'Error checking email availability');
216		validationState.email = false;
217		checkFormValidity();
218	});
219}
220
221function validateEmailConfirmation() {
222	const emailField = document.getElementById('reg_email');
223	const confirmEmailField = document.getElementById('reg_confirm_email');
224	
225	if (!emailField || !confirmEmailField) return;
226	
227	const email = emailField.value;
228	const confirmEmail = confirmEmailField.value;
229	
230	if (!confirmEmail) {
231		clearValidation('confirm_email');
232		validationState.confirm_email = false;
233		checkFormValidity();
234		return;
235	}
236	
237	if (email !== confirmEmail) {
238		showValidationMessage('confirm_email', 'error', 'Email addresses do not match');
239		validationState.confirm_email = false;
240	} else {
241		showValidationMessage('confirm_email', 'success', 'Email addresses match');
242		validationState.confirm_email = true;
243	}
244	checkFormValidity();
245}
246
247function checkFormValidity() {
248    const submitBtn = document.querySelector('.swal2-confirm');
249    if (!submitBtn) {
250        return;
251    }
252
253    // Determine if we are in the new user registration flow by checking if the registration form is visible
254    const registrationForm = document.getElementById('registration-form-fields');
255    const isNewUserFlow = registrationForm && window.getComputedStyle(registrationForm).display !== 'none';
256
257    let basicFieldsValid = true;
258    // Only validate the basic registration fields if we are in the new user flow
259    if (isNewUserFlow) {
260        basicFieldsValid = checkBasicFieldsHaveValues();
261    }
262
263    const paymentMethodSelected = document.querySelector('input[name="payment_method"]:checked') !== null || document.querySelector('input[name="subscription_payment_method"]:checked') !== null;
264    const stripeFieldsValid = checkStripeFieldsIfNeeded();
265
266    const shouldEnable = basicFieldsValid && paymentMethodSelected && stripeFieldsValid;
267
268    submitBtn.disabled = !shouldEnable;
269    submitBtn.style.opacity = shouldEnable ? '1' : '0.5';
270    submitBtn.style.cursor = shouldEnable ? 'pointer' : 'not-allowed';
271}
272
273function checkBasicFieldsHaveValues() {
274	const requiredFields = ['reg_fname', 'reg_lname', 'reg_username', 'reg_email', 'reg_confirm_email', 'reg_password', 'reg_password2'];
275	
276	return requiredFields.every(fieldId => {
277		const field = document.getElementById(fieldId);
278		return field && field.value.trim().length > 0;
279	});
280}
281
282function checkStripeFieldsIfNeeded() {
283    // Check both possible Stripe field containers
284    const regStripeContainer = document.getElementById('stripe-fields');
285    const subStripeContainer = document.getElementById('subscription-stripe-fields');
286
287    const isRegStripeActive = regStripeContainer && regStripeContainer.classList.contains('active');
288    const isSubStripeActive = subStripeContainer && window.getComputedStyle(subStripeContainer).display !== 'none';
289
290    // If either Stripe form is active, its validity depends on the completeness of the Stripe Element.
291    if (isRegStripeActive || isSubStripeActive) {
292        return window.isStripeElementComplete;
293    }
294
295    // If no Stripe form is active, this validation check passes.
296    return true;
297}
298
299function showValidationMessage(fieldName, type, message) {
300	const field = document.getElementById('reg_' + fieldName);
301	const messageDiv = document.getElementById(fieldName + '_validation');
302	
303	if (!field || !messageDiv) return;
304	
305	field.className = field.className.replace(/\b(valid|invalid|checking)\b/g, '');
306	field.classList.add(type === 'success' ? 'valid' : type === 'error' ? 'invalid' : 'checking');
307	
308	messageDiv.className = 'validation-message ' + (type === 'success' ? 'success' : type === 'error' ? 'error' : 'checking');
309	messageDiv.innerHTML = message;
310}
311
312function clearValidation(fieldName) {
313	const field = document.getElementById('reg_' + fieldName);
314	const messageDiv = document.getElementById(fieldName + '_validation');
315	
316	if (field) {
317		field.className = field.className.replace(/\b(valid|invalid|checking)\b/g, '');
318	}
319	
320	if (messageDiv) {
321		messageDiv.className = 'validation-message';
322		messageDiv.innerHTML = '';
323	}
324	
325	if (validationState.hasOwnProperty(fieldName)) {
326		validationState[fieldName] = false;
327	}
328}
329
330function isValidEmailFormat(email) {
331	const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
332	return emailRegex.test(email);
333}
334
335function addFormValidationListeners() {
336	const basicFields = ['reg_fname', 'reg_lname', 'reg_username', 'reg_email', 'reg_confirm_email', 'reg_password', 'reg_password2'];
337	
338	basicFields.forEach(fieldId => {
339		const field = document.getElementById(fieldId);
340		if (field) {
341			field.addEventListener('input', checkFormValidity);
342			field.addEventListener('blur', checkFormValidity);
343		}
344	});
345	
346	const paymentRadios = document.querySelectorAll('input[name="payment_method"]');
347	paymentRadios.forEach(radio => {
348		radio.addEventListener('change', checkFormValidity);
349	});
350}
351
352/**
353 * Triggers validation for all fields and returns true if all are valid.
354 * Used before submitting a form via an external button like PayPal.
355 */
356function validateAllFields() {
357    // Trigger validation on all fields to show messages for any empty fields
358    validateField('fname', document.getElementById('reg_fname').value);
359    validateField('lname', document.getElementById('reg_lname').value);
360    validateField('username', document.getElementById('reg_username').value);
361    validateField('email', document.getElementById('reg_email').value);
362    validateField('confirm_email', document.getElementById('reg_confirm_email').value);
363    validateField('password', document.getElementById('reg_password').value);
364    validateField('password2', document.getElementById('reg_password2').value);
365
366    // Check the final state of all validations
367    for (const field in validationState) {
368        // We don't validate payment_method here as it's handled separately
369        if (field !== 'payment_method' && !validationState[field]) {
370            return false;
370 // If any field is invalid, return false
371        }
372    }
373
374    return true; // All fields are valid
375}

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.