1// Vanilla replacement for jQuery + jQuery-Validate + form_stuff.js on the 2// registration form. Native HTML5 attributes (required, pattern, minlength, 3// maxlength, type=email) on the inputs do most of the work; this covers 4// what native can't: the username/password character bans, password-match, 5// and the live "already taken" pre-checks. All of it is UX only - 6// register-open.php validates everything server-side regardless of what 7// this file does or doesn't catch. 8(function () { 9 'use strict'; 10 11 var form = document.getElementById('regForm'); 12 if (!form) return; 13 14 var usernamed = document.getElementById('usernamed'); 15 var username = document.getElementById('username'); 16 var password = document.getElementById('pwd'); 17 var passwordc = document.getElementById('passwordc'); 18 var email = document.getElementById('email'); 19 var agree = form.querySelector('input[name="agree"]'); 20 21 var messageBoxes = { 22 usernamed: document.getElementById('message-usernamed'), 23 username: document.getElementById('message-username'), 24 password: document.getElementById('message-password'), 25 passwordc: document.getElementById('message-passwordc'), 26 email: document.getElementById('message-email'), 27 agree: document.getElementById('message-agree') 28 }; 29 30 // Same DOM shape jQuery-Validate used to produce (a <label class="error"> 31 // or <label class="valid"> inside the #message-* span) so the existing 32 // cakestyle.css rules (label.error/label.valid, scoped under #regbox) 33 // keep working with no CSS changes. 34 function showMessage(name, text, ok) { 35 var box = messageBoxes[name]; 36 if (!box) return; 37 box.innerHTML = ''; 38 if (!text) return; 39 var label = document.createElement('label'); 40 label.setAttribute('for', name); 41 label.className = ok ? 'valid' : 'error'; 42 label.textContent = text; 43 box.appendChild(label); 44 } 45 46 function debounce(fn, ms) { 47 var t; 48 return function () { 49 clearTimeout(t); 50 var args = arguments; 51 t = setTimeout(function () { fn.apply(null, args); }, ms); 52 }; 53 } 54 55 // --- character/word bans the old jQuery custom validators enforced --- 56 function checkNotUsername() { 57 if (/^username|www.*|http.*|ftp.*$/.test(username.value)) { 58 username.setCustomValidity('invalid username!'); 59 } else { 60 username.setCustomValidity(''); 61 } 62 } 63 function checkNotPassword(field) { 64 if (/^password$/.test(field.value)) { 65 field.setCustomValidity('"password" is not a password!'); 66 } else { 67 field.setCustomValidity(''); 68 } 69 } 70 function checkPasswordsMatch() { 71 if (passwordc.value && passwordc.value !== password.value) { 72 passwordc.setCustomValidity("passwords don't match!"); 73 } else { 74 passwordc.setCustomValidity(''); 75 } 76 } 77 78 // --- live "already taken" pre-checks, ported from form_stuff.js's 79 // usernameCheck/emailCheck AJAX methods. Debounced like the original 80 // (500ms). A network hiccup here just means no live feedback - the 81 // server checks again on submit either way. --- 82 function checkTaken(field, name, param, takenMsg, okMsg) { 83 // Clear any "taken"/"already registered" customValidity left over 84 // from a PREVIOUS call before checking validity again - otherwise 85 // a stale customError makes checkValidity() false forever and this 86 // never re-fires for whatever new value the user typed next. 87 field.setCustomValidity(''); 88 var value = field.value; 89 if (!value || !field.checkValidity()) return; 90 fetch('check_form.php', { 91 method: 'POST', 92 headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, 93 body: param + '=' + encodeURIComponent(value) 94 }) 95 .then(function (r) { return r.json(); }) 96 .then(function (available) { 97 if (field.value !== value) return; // stale - user kept typing 98 if (available) { 99 field.setCustomValidity(''); 100 showMessage(name, okMsg(value), true); 101 } else { 102 field.setCustomValidity(takenMsg); 103 showMessage(name, takenMsg, false); 104 } 105 }) 106 .catch(function () {}); 107 } 108 109 // checkTaken() itself clears stale customValidity and re-checks native 110 // constraints, so these debounced wrappers don't need to gate on 111 // checkValidity() too - doing it here as well hits the same staleness 112 // trap one level up (a leftover customError would block this outer 113 // check before checkTaken ever gets a chance to clear it). 114 var checkUsernameTaken = debounce(function () { 115 checkTaken(username, 'username', 'username', 'username is taken, sorry!', function (v) { 116 return 'Your URL: http://' + v + '.hotglue.me/'; 117 }); 118 }, 500); 119 120 var checkEmailTaken = debounce(function () { 121 checkTaken(email, 'email', 'email', 'this email is already registered!', function () { 122 return 'looks good!'; 123 }); 124 }, 500); 125 126 // --- map native validity failures to the old messages --- 127 var fieldText = { 128 usernamed: { valueMissing: 'your name, please?', tooShort: 'too short!', tooLong: 'too long!' }, 129 username: { valueMissing: 'your username?', tooShort: 'too short!', tooLong: 'too long!', patternMismatch: "don't understand those funky symbols!" }, 130 email: { valueMissing: 'what is your email?', typeMismatch: 'bad email!', tooLong: 'too long email!' }, 131 password: { valueMissing: 'create a password', tooShort: 'too short!', tooLong: 'too long!' }, 132 passwordc: { valueMissing: 'confirm your password' } 133 }; 134 135 function renderValidity(field, positiveMessage) { 136 var name = field.name;
137 var map = fieldText[name]; 138 if (!map) return; 139 var v = field.validity; 140 if (v.valid) { 141 if (positiveMessage) showMessage(name, positiveMessage, true); 142 return; 143 } 144 // customError (set by the checks above) carries its own message - 145 // field.validationMessage is exactly what was passed to 146 // setCustomValidity(), so no separate lookup table needed for it. 147 if (v.customError) { showMessage(name, field.validationMessage, false); return; } 148 if (v.valueMissing) { showMessage(name, map.valueMissing, false); return; } 149 if (v.tooShort) { showMessage(name, map.tooShort, false); return; } 150 if (v.tooLong) { showMessage(name, map.tooLong, false); return; } 151 if (v.patternMismatch) { showMessage(name, map.patternMismatch, false); return; } 152 if (v.typeMismatch) { showMessage(name, map.typeMismatch, false); return; } 153 } 154 155 usernamed.addEventListener('input', function () { 156 renderValidity(usernamed, usernamed.validity.valid ? 'Greetings, ' + usernamed.value + '!' : null); 157 }); 158 159 username.addEventListener('input', function () { 160 checkNotUsername(); 161 renderValidity(username); 162 // Always schedule the debounced check rather than gating on 163 // validity here - checkTaken() itself decides whether the value is 164 // worth checking, and gating here too would (like the two spots 165 // above) get stuck once a stale "taken" customError is present. 166 checkUsernameTaken(); 167 }); 168 169 password.addEventListener('input', function () { 170 checkNotPassword(password); 171 renderValidity(password, 'looks good!'); 172 checkPasswordsMatch(); 173 }); 174 175 passwordc.addEventListener('input', function () { 176 checkNotPassword(passwordc); 177 checkPasswordsMatch(); 178 renderValidity(passwordc, 'looks good!'); 179 }); 180 181 email.addEventListener('input', function () { 182 renderValidity(email); 183 checkEmailTaken(); 184 }); 185 186 agree.addEventListener('change', function () { 187 showMessage('agree', agree.checked ? '' : 'you must accept our Terms of Service', false); 188 }); 189})();
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.