tag. It must load after the Klaviyo script, which is why it goes at the bottom. --------------------------------------------------------------------------- */ (function () { "use strict"; /* --- the domain corrections. left = wrong, right = what they meant ------ */ var FIX = { "gmail.con":"gmail.com","gmail.co":"gmail.com","gmail.cm":"gmail.com", "gmail.om":"gmail.com","gmail.ocm":"gmail.com","gmail.cpm":"gmail.com", "gmailc.om":"gmail.com","gmial.com":"gmail.com","gmai.com":"gmail.com", "gmil.com":"gmail.com","gmaail.com":"gmail.com","gmaill.com":"gmail.com", "gamil.com":"gmail.com","gnail.com":"gmail.com","gmall.com":"gmail.com", "gmsil.com":"gmail.com","gmeil.com":"gmail.com","gml.com":"gmail.com", "fmail.com":"gmail.com","hmail.com":"gmail.com", "yahoo.con":"yahoo.com","yahoo.co":"yahoo.com","yahoo.cm":"yahoo.com", "yahooo.com":"yahoo.com","yaho.com":"yahoo.com","yhaoo.com":"yahoo.com", "yahho.com":"yahoo.com", "hotmail.con":"hotmail.com","hotmail.co":"hotmail.com", "hotmial.com":"hotmail.com","hotmil.com":"hotmail.com", "hotmai.com":"hotmail.com","hotmaill.com":"hotmail.com", "outlok.com":"outlook.com","outllok.com":"outlook.com", "outlook.co":"outlook.com", "iclod.com":"icloud.com","icloud.co":"icloud.com", "iclould.com":"icloud.com","icoud.com":"icloud.com", "aol.con":"aol.com","aol.co":"aol.com","aoll.com":"aol.com" }; /* --- addresses to refuse outright -------------------------------------- */ var JUNK_WORDS = ["test","testing","asdf","qwerty","none","no","na","nah", "nope","nothing","noemail","fake","fakeemail","notreal","spam","junk", "x","xx","xxx","xyz","abc","a","aa","ab","email","myemail","youremail", "example","sample","user","anonymous","idk","whatever","blah","blahblah", "poop","fart","butt","yomama","yourmom","urmom","stop","ok","okay","ily", "wassup","wasssup","myworld","random","randomemail","givemewifi"]; var JUNK_DOMAINS = ["xyz.com","test.com","testing.com","example.com", "fake.com","none.com","no.com","no.co","nope.com","abc.com","aaa.com", "poop.com","pee.com","fart.com","yomama.com","whatever.com","domain.com", "a.com","x.com","mailinator.com","guerrillamail.com","10minutemail.com", "tempmail.com","yopmail.com","sharklasers.com","trashmail.com", "maildrop.cc","getnada.com","dispostable.com"]; var VOWELS = "aeiou"; function localPart(e){ return e.split("@")[0].replace(/\+.*$/,""); } function domainPart(e){ return e.split("@").pop().toLowerCase(); } /* mash test - deliberately conservative. it must never refuse a real person. initials-style addresses (msmith4976, nkwright18) pass. */ function isMash(local) { var core = local.toLowerCase().replace(/[^a-z]/g, ""); if (core.length < 4) return false; var distinct = new Set(core.split("")).size; var vowels = 0, i; for (i = 0; i < core.length; i++) if (VOWELS.indexOf(core[i]) > -1) vowels++; var vratio = vowels / core.length; if (distinct === 1) return true; // hhhh, aaaaaa if (/(.)\1{5,}/.test(core)) return true; // 6+ same in a row if (core.length >= 7 && distinct <= 2) return true; // nananan if (core.length >= 5 && distinct <= 2 && vratio < 0.3) return true; if (core.length >= 6 && distinct <= 3 && vratio < 0.3) return true; // gtygggy var rows = ["qwertyuiop","asdfghjkl","zxcvbnm","poiuytrewq","lkjhgfdsa"]; for (i = 0; i < rows.length; i++) { for (var n = core.length; n > 4; n--) { for (var j = 0; j + n <= core.length; j++) { if (rows[i].indexOf(core.substr(j, n)) > -1) return true; } } } return false; } /* returns null if fine, otherwise a short message for the shopper */ function problemWith(email) { var e = (email || "").trim().toLowerCase(); if (!e || e.indexOf("@") === -1) return null; // let Klaviyo handle empty if (!/^[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,}$/.test(e)) return "That doesn't look like a complete email address."; var d = domainPart(e), l = localPart(e); if (JUNK_DOMAINS.indexOf(d) > -1) return "We need a real email address to send your code to."; if (JUNK_WORDS.indexOf(l.replace(/[^a-z0-9]/g, "")) > -1) return "We need a real email address to send your code to."; if (isMash(l)) return "That address doesn't look quite right — mind checking it?"; return null; } /* --- UI helpers --------------------------------------------------------- */ function note(input, text, tone) { clearNote(input); var d = document.createElement("div"); d.className = "nytc-guard-note"; d.textContent = text; d.style.cssText = "font-size:13px;line-height:1.35;margin:6px 0 0;" + "color:" + (tone === "fix" ? "#8a5a00" : "#b00020") + ";"; input.parentNode.appendChild(d); } function clearNote(input) { var old = input.parentNode.querySelector(".nytc-guard-note"); if (old) old.remove(); } function emailInputsIn(root) { return Array.prototype.slice.call( root.querySelectorAll('input[type="email"], input[name*="email" i]')); } /* --- 1. live domain correction ----------------------------------------- */ function watchForTypos(form) { emailInputsIn(form).forEach(function (input) { if (input.__nytcWatched) return; input.__nytcWatched = true; input.addEventListener("blur", function () { var v = input.value.trim(); if (v.indexOf("@") === -1) return; var d = domainPart(v); if (FIX[d]) { var fixed = v.slice(0, v.lastIndexOf("@") + 1) + FIX[d]; input.value = fixed; input.dispatchEvent(new Event("input", { bubbles: true })); input.dispatchEvent(new Event("change", { bubbles: true })); note(input, "We corrected this to " + FIX[d] + " — change it back if that's wrong.", "fix"); } else { clearNote(input); } }); input.addEventListener("input", function () { clearNote(input); }); }); } /* --- 2. block the junk on submit ---------------------------------------- */ document.addEventListener("click", function (ev) { var form = ev.target.closest && ev.target.closest('[class*="klaviyo-form"]'); if (!form) return; var btn = ev.target.closest('button, [role="button"], input[type="submit"]'); if (!btn) return; var inputs = emailInputsIn(form); for (var i = 0; i < inputs.length; i++) { var msg = problemWith(inputs[i].value); if (msg) { ev.preventDefault(); ev.stopPropagation(); ev.stopImmediatePropagation(); note(inputs[i], msg, "error"); inputs[i].focus(); return false; } } }, true); // capture phase - runs before Klaviyo's own handler /* --- wire up whenever a Klaviyo form appears ---------------------------- */ window.addEventListener("klaviyoForms", function (e) { if (e.detail && (e.detail.type === "open" || e.detail.type === "stepSubmit")) { setTimeout(function () { document.querySelectorAll('[class*="klaviyo-form"]').forEach(watchForTypos); }, 250); } }); // also catch embedded (non-popup) forms already on the page document.addEventListener("DOMContentLoaded", function () { setTimeout(function () { document.querySelectorAll('[class*="klaviyo-form"]').forEach(watchForTypos); }, 1200); }); })();