1// â Business email validation 2function businessmailValidation(email) { 3 const emailLower = email.toLowerCase(); 4 5 // Basic format check (same as before) 6 const re = /^[a-zA-Z0-9._%+-]+@([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/; 7 if (!re.test(emailLower)) return false; 8 9 const domain = emailLower.split('@')[1]; 10 const emailDomain = "@" + domain; 11 12 // Free email domains list (from both functions combined) 13 const freeDomains = [ 14 'gmail.com', 'yahoo.com', 'hotmail.com', 'aol.com', 15 'outlook.com', 'icloud.com', 'protonmail.com', 'zoho.com', 16 'mail.com', 'gmx.com', 'yandex.com', 'live.com', 'msn.com', 17 'proton.me', 'yahoo.co.uk', 'hotmail.co.uk', '50pros.com', 18 'ymail.com' 19 ]; 20 21 // Free email regex (from your jQuery validator) 22 const freeEmailRegex = /@(yahoo\.com|hotmail\.com|outlook\.com|live\.com|aol\.com|icloud\.com|protonmail\.com|mail\.com|ymail\.com|zoho\.com|gmx\.com)$/i; 23 24 // Disposable email patterns (your original) 25 const disposablePatterns = ['tempmail', 'trashmail', '10minutemail']; 26 const isDisposable = disposablePatterns.some(pattern => domain.includes(pattern)); 27 28 // Blocked specific emails (added from validator) 29 const blockedEmails = new Set([ 30 "[email protected]", "[email protected]", "[email protected]", "[email protected]", 31 "[email protected]", "[email protected]", "[email protected]", "[email protected]", 32 "[email protected]", "[email protected]", "[email protected]", "[email protected]", 33 "[email protected]", '[email protected]', '[email protected]', 34 '[email protected]', '[email protected]', '[email protected]', 35 '[email protected]', '[email protected]', '[email protected]', 36 '[email protected]', '[email protected]', '[email protected]', 37 '[email protected]', '[email protected]', '[email protected]' 38 ]); 39 40 // Blocked domains (added from validator) 41 const blockedDomains = new Set([ 42 "@test.com", "@example.com", "@demo.com", "@abc.com", "@email.com", 43 "@theguestpostshop.com", "@sharklasers.com", "@guerrillamail.com", 44 "@guerrillamailblock.com", "@guerrillamail.net", "@guerrillamail.de", 45 "@spam4.me", "@maildrop.cc", "@10minutemail.com", "@dispostable.com", 46 "@mailinator.com", "@technodreamoutsourcing.com", "@guestpostmate.com", 47 "@50pros.com", "@sbcglobal.net", "@web.de" 48 ]); 49 50 // Your business TLD requirement 51 const knownBusinessTLDs = ['.com', '.org', '.edu', '.gov', '.co', '.biz', '.net', '.in']; 52 const hasValidTLD = knownBusinessTLDs.some(tld => domain.endsWith(tld)); 53 54 // Final logic (keeps original structure & adds new checks) 55 return ( 56 !freeDomains.includes(domain) && 57 !freeEmailRegex.test(emailLower) && 58 !isDisposable && 59 !blockedEmails.has(emailLower) && 60 !blockedDomains.has(emailDomain) && 61 hasValidTLD 62 ); 63} 64 65function validName(value) { 66 return /^[A-Za-z\s']+$/.test(value) && value.length >= 2; 67} 68 69function meaningfulMessage(value) { 70 var message = value.trim(); 71 72 // 1. Minimum length (allow very short but meaningful messages) 73 if (message.length < 2) return false; 74 75 // 2. At least 2 words (split by whitespace) 76 var words = message.split(/\s+/); 77 if (words.length < 2) return false; 78 79 // 3. Count "valid" words (letters only, length >= 2) 80 var validWords = words.filter(function (word) { 81 return word.length >= 2 && /^[a-zA-Z]+$/.test(word); 82 }); 83 // For "I am" â validWords = ["am"] (length 1) â fails if we require 2. 84 // So we lower the requirement: at least 1 valid word for short messages? 85 // Actually "I am" has two words, but only "am" qualifies. To allow it, 86 // we can either accept messages with total words >=2 and at least one 87 // valid word, or we simply skip this check for very short messages. 88 // Let's be pragmatic: if total words >=2, we already pass the word count, 89 // so we don't need an extra validWords check. Instead, we rely on the 90 // gibberish detection below. 91 // I'll remove the validWords requirement entirely to avoid blocking "I am". 92
93 // 4. Block repeated characters (aaaa, hhhhh) 94 if (/(.)\1{3,}/.test(message)) return false; 95 96 // 5. Block allâsameâword messages (e.g., "hello hello hello") 97 var distinctWords = new Set(words.map(w => w.toLowerCase())); 98 if (distinctWords.size === 1) return false; 99 100 // 6. Vowel ratio (letters only) 101 var letters = message.replace(/[^a-zA-Z]/g, ""); 102 if (letters.length === 0) return false; 103 var vowels = letters.match(/[aeiouAEIOU]/g) || []; 104 var vowelRatio = vowels.length / letters.length; 105 if (vowelRatio < 0.2) return false; // too few vowels â gibberish 106 107 // 7. Caseâswitching pattern (like "iHhTt") 108 var switches = 0; 109 for (var i = 1; i < letters.length; i++) { 110 if (/[A-Z]/.test(letters[i]) !== /[A-Z]/.test(letters[i - 1])) { 111 switches++; 112 } 113 } 114 if (letters.length > 0 && switches / letters.length > 0.35) { 115 return false; // too much random casing â gibberish 116 } 117 118 // 8. Optional: check for common English words (like your PHP code) 119 var commonWords = /\b(the|and|for|you|need|want|data|scrap|price|quote|help|hi|hello|project|website|please|can|would|looking|interested|am|is|are|was|were|have|has|do|does|did|will|would|could|should|may|might|must|shall)\b/i; 120 if (!commonWords.test(message)) { 121 // This would reject "I am" because it contains "am"? Actually "am" is in the list, so it would pass. 122 // Good. 123 } 124 125 // If all checks pass, it's meaningful 126 return true; 127} 128 129 130// â Phone number validation 131function validatenumber(phone) { 132 const re = /^\+?\d{10,15}$/; 133 return re.test(phone); 134} 135 136document.addEventListener("DOMContentLoaded", function () { 137 const datasetOpenpopBtn = document.getElementById("dataset-download"); 138 const datasetsClosepopBtn = document.getElementById("sets-btn-close"); 139 const datasetsPopupForm = document.getElementById("sets-popup-box"); 140 141 if (datasetOpenpopBtn) { 142 datasetOpenpopBtn.addEventListener("click", function () { 143 datasetsPopupForm.style.display = "block"; 144 }); 145 } 146 147 if (datasetsClosepopBtn) { 148 datasetsClosepopBtn.addEventListener("click", function () { 149 datasetsPopupForm.style.display = "none"; 150 }); 151 } 152 153 window.addEventListener("click", function (event) { 154 if (event.target === datasetsPopupForm) { 155 datasetsPopupForm.style.display = "none"; 156 } 157 }); 158 159 const form = document.getElementById("dataset-pop-up-form"); 160 if (form) { 161 form.addEventListener("submit", function (event) { 162 event.preventDefault(); 163 164 const submitBtn = form.querySelector('button[type="submit"]'); 165 const originalBtnText = submitBtn.textContent; 166 167 submitBtn.disabled = true; 168 submitBtn.textContent = "Submitting..."; 169 170 let errorCount = 0; 171 const formData = new FormData(form); 172 const withErrors = form.querySelectorAll(".with-errors"); 173 const borderDanger = form.querySelectorAll(".border-danger"); 174 175 // Clear previous errors 176 withErrors.forEach((el) => el.remove()); 177 borderDanger.forEach((el) => el.classList.remove("border-danger")); 178 179 // Validate fields 180 form.querySelectorAll(".mandatory").forEach((element) => { 181 const val = element.value.trim(); 182 const id = element.id; 183 184 if (val === "") { 185 element.classList.add("border-danger"); 186 element.insertAdjacentHTML( 187 "afterend", 188 `<div class="with-errors">This field is required</div>` 189 ); 190 errorCount++; 191 } else if (id === "contactEmail" && !businessmailValidation(val)) { 192 element.classList.add("border-danger"); 193 element.insertAdjacentHTML( 194 "afterend", 195 `<div class="with-errors">Please enter a valid business email address</div>` 196 ); 197 errorCount++; 198 } 199 else if (id === "contactPhone" && !validatenumber(val)) { 200 element.classList.add("border-danger"); 201 element.insertAdjacentHTML( 202 "afterend", 203 `<div class="with-errors">Please enter a valid phone number</div>` 204 ); 205 errorCount++; 206 } 207 else if (id === "contactName" && !validName(val)) { 208 element.classList.add("border-danger"); 209 element.insertAdjacentHTML( 210 "afterend", 211 `<div class="with-errors">Avoid random characters or keyboard patterns.</div>` 212 ); 213 errorCount++; 214 } 215 else if (id === "contactMessage" && !meaningfulMessage(val)) { 216 element.classList.add("border-danger"); 217 element.insertAdjacentHTML( 218 "afterend", 219 `<div class="with-errors">Avoid random characters or keyboard patterns.</div>` 220 ); 221 errorCount++; 222 } 223 }); 224 225 if (errorCount > 0) { 226 submitBtn.disabled = false; 227 submitBtn.textContent = originalBtnText; 228 return; 229 } 230 231 // Show loader
232 document.querySelector(".loader").style.display = "block"; 233 234 // const filename = datasetOpenpopBtn.getAttribute("data-download-filename"); 235 var filename = document.getElementById('dataset-download').getAttribute('data-download-filename'); 236 var link = document.createElement('a'); 237 formData.append('resourcesDownload1', 'https://www.iwebdatascraping.com/'+filename); 238 239 fetch("contact-form-submit-backend.php", { 240 method: "POST", 241 body: formData, 242 }) 243 .then((response) => { 244 if (!response.ok) throw new Error("Network response was not ok"); 245 return response.text(); 246 }) 247 .then((response) => { 248 const data = JSON.parse(response); 249 if (data.status === "success") { 250 // File will be emailed now instead of downloaded 251 form.reset(); 252 datasetsPopupForm.style.display = "none"; 253 254 link.href = filename; 255 link.setAttribute('download', ''); 256 link.style.display = 'none'; 257 document.body.appendChild(link); 258 // link.click(); 259 document.body.removeChild(link); 260 document.getElementById('dataset-pop-up-form').reset(); 261 datasetsPopupForm.style.display = "none"; 262 263 264 const backgroundData = { 265 last_id: data.last_id, 266 attachmentFileName: data.attachmentFileName, 267 attachmentFile: data.attachmentFile, 268 }; 269 270 setTimeout(() => { 271 document.querySelector(".loader").style.display = "none"; 272 let timerInterval; 273 Swal.fire({ 274 title: "Thank you for downloading the dataset", 275 html: "We will share the dataset with you shortly via email.<br><b>Closing in <span id='countdown'>5</span> seconds...</b>", 276 icon: "success", 277 timer: 5000,
278 showConfirmButton: false, 279 timerProgressBar: true, 280 didOpen: () => { 281 const countdownEl = 282 Swal.getHtmlContainer().querySelector("#countdown"); 283 let timeLeft = 5; 284 timerInterval = setInterval(() => { 285 timeLeft--; 286 if (countdownEl) countdownEl.textContent = timeLeft; 287 }, 1000); 288 }, 289 willClose: () => { 290 clearInterval(timerInterval); 291 }, 292 }); 293 }, 1000); 294 295 // navigator.sendBeacon( 296 // "background-worker.php", 297 // new Blob([JSON.stringify(backgroundData)], { 298 // type: "application/json", 299 // }) 300 // ); 301 302 setTimeout(() => { 303 window.location.href = "thank-you.php"; 304 }, 5000); 305 } else { 306 alert("Something went wrong, please try again."); 307 submitBtn.disabled = false; 308 submitBtn.textContent = originalBtnText; 309 document.querySelector(".loader").style.display = "none"; 310 } 311 }) 312 .catch((error) => { 313 console.error("Error:", error); 314 alert("An error occurred, please try again."); 315 submitBtn.disabled = false; 316 submitBtn.textContent = originalBtnText; 317 document.querySelector(".loader").style.display = "none"; 318 }); 319 }); 320 321 // Live validation for all mandatory fields on input, keypress, and paste 322 form.querySelectorAll(".mandatory").forEach((element) => { 323 const validateField = () => { 324 const id = element.id; 325 const val = element.value.trim(); 326 const nextSibling = element.nextElementSibling; 327 328 // Remove previous error 329 element.classList.remove("border-danger"); 330 if (nextSibling && nextSibling.classList.contains("with-errors")) { 331 nextSibling.remove(); 332 } 333 334 // Live validation 335 if (val === "") { 336 element.classList.add("border-danger"); 337 element.insertAdjacentHTML( 338 "afterend", 339 `<div class="with-errors">This field is required</div>` 340 ); 341 } else if (id === "contactEmail" && !businessmailValidation(val)) { 342 element.classList.add("border-danger"); 343 element.insertAdjacentHTML( 344 "afterend", 345 `<div class="with-errors">Please enter a valid business email</div>` 346 ); 347 } else if (id === "contactPhone" && !validatenumber(val)) { 348 element.classList.add("border-danger"); 349 element.insertAdjacentHTML( 350 "afterend", 351 `<div class="with-errors">Please enter a valid phone number</div>` 352 ); 353 } 354 }; 355 356 element.addEventListener("input", validateField); 357 // element.addEventListener("keypress", validateField); 358 // element.addEventListener("paste", validateField); 359 }); 360 } 361});
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.