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.