1/* /js/email-check.js â "Did you mean [email protected]?" under every email box 2 (3 Oct 2026: Joe typed ".om" for ".com" and his receipt bounced). 3 Watches every <input type="email"> on the page. When someone leaves the box 4 with a likely typo of a common provider (gmial.com, yahoo.con) or ending 5 (.om, .con), it shows the fix with a "Yes, fix it" button. It never changes 6 the address by itself. The server makes the same check, and also refuses an 7 address whose domain cannot receive mail (functions/email-domain.js: keep 8 PROVIDERS and TLD_FIX the same in both files). */ 9(function () { 10 'use strict'; 11 var PROVIDERS = ['gmail.com', 'yahoo.com', 'hotmail.com', 'outlook.com', 'icloud.com', 'aol.com', 'live.com', 'msn.com', 'me.com', 'mac.com', 'protonmail.com', 'proton.me', 'comcast.net', 'att.net', 'verizon.net', 'ymail.com', 'googlemail.com', 'riddimbank.com']; 12 var TLD_FIX = { om: 'com', con: 'com', cmo: 'com', ocm: 'com', vom: 'com', xom: 'com', comm: 'com', coom: 'com', cpm: 'com', cm: 'com', nte: 'net', ner: 'net', nett: 'net', ogr: 'org', orh: 'org' }; 13 function lev(a, b) { 14 var m = a.length, n = b.length, d = [], i, j; 15 for (i = 0; i <= m; i++) d[i] = [i]; 16 for (j = 1; j <= n; j++) d[0][j] = j; 17 for (i = 1; i <= m; i++) for (j = 1; j <= n; j++) { 18 d[i][j] = Math.min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1)); 19 if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + 1); 20 } 21 return d[m][n]; 22 } 23 function suggest(email) { 24 var e = String(email || '').trim().toLowerCase(), at = e.lastIndexOf('@'); 25 if (at < 1) return null; 26 var user = e.slice(0, at), dom = e.slice(at + 1); 27 if (!dom || PROVIDERS.indexOf(dom) !== -1) return null; 28 var best = null, bestD = 3; 29 PROVIDERS.forEach(function (p) { var d = lev(dom, p); if (d < bestD) { best = p; bestD = d; } }); 30 if (best && bestD <= 2) return user + '@' + best; 31 var dot = dom.lastIndexOf('.'); 32 if (dot > 0 && TLD_FIX[dom.slice(dot + 1)]) return user + '@' + dom.slice(0, dot + 1) + TLD_FIX[dom.slice(dot + 1)]; 33 return null; 34 } 35 window.rbEmailSuggest = suggest; // for the tests 36 /* Not an email at all (4 Oct 2026: Joe typed anything and got no warning). */ 37 var FORMAT = /^[^@\s]+@[^@\s]+\.[^@\s]{2,}$/; 38 function incomplete(email) { var e = String(email || '').trim(); return e !== '' && !FORMAT.test(e); } 39 window.rbEmailIncomplete = incomplete; 40 41 function attach(input) { 42 if (input.dataset.rbEmailCheck) return; 43 input.dataset.rbEmailCheck = '1'; 44 var hint = document.createElement('div'); 45 hint.className = 'rb-email-hint'; 46 hint.style.cssText = 'display:none;margin-top:6px;font-size:14px;color:#FFA726;'; 47 input.insertAdjacentElement('afterend', hint); 48 function check() { 49 if (incomplete(input.value)) { 50 hint.textContent = 'That doesn\u2019t look like a complete email address (like [email protected]).'; 51 hint.style.display = 'block'; 52 return; 53 } 54 var fix = suggest(input.value); 55 if (!fix) { hint.style.display = 'none'; return; } 56 hint.textContent = 'Did you mean ' + fix + '? '; 57 var b = document.createElement('button'); 58 b.type = 'button'; 59 b.textContent = 'Yes, fix it'; 60 b.style.cssText = 'background:none;border:0;padding:0;color:#1DB954;font-weight:bold;cursor:pointer;text-decoration:underline;font-size:14px;'; 61 b.onclick = function () { input.value = fix; hint.style.display = 'none'; input.dispatchEvent(new Event('input', { bubbles: true })); }; 62 hint.appendChild(b); 63 hint.style.display = 'block'; 64 } 65 input.addEventListener('blur', check); 66 input.addEventListener('change', check); 67 input.addEventListener('input', function () { if (hint.style.display !== 'none') check(); }); 68 } 69 function scan() { Array.prototype.forEach.call(document.querySelectorAll('input[type="email"]'), attach); } 70 if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', scan); else scan(); 71})();
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.