1/** 2 * PPC Form Submission Handler 3 * Submits PPC form directly to HubSpot API (no AJAX/backend required) 4 */ 5 6(function ($) { 7 'use strict'; 8 9 /** 10 * Lightweight client-side sanitizers to avoid pushing unsafe/unexpected values 11 * into 3rd-party APIs. Server-side sanitization should still be enforced. 12 */ 13 function sanitizePlainText(value, maxLen = 250) { 14 if (value === null || value === undefined) return ''; 15 let str = String(value); 16 // Strip HTML tags 17 str = str.replace(/<[^>]*>/g, ''); 18 // Remove ASCII control chars 19 str = str.replace(/[\u0000-\u001F\u007F]/g, ''); 20 // Collapse whitespace 21 str = str.replace(/\s+/g, ' ').trim(); 22 if (maxLen && str.length > maxLen) str = str.slice(0, maxLen); 23 return str; 24 } 25 26 function sanitizeEmail(value) { 27 const email = sanitizePlainText(value, 320).toLowerCase(); 28 return email.replace(/\s+/g, ''); 29 } 30 31 function sanitizePhoneIN(value) { 32 const digits = String(value ?? '').replace(/\D/g, ''); 33 return digits.length <= 10 ? digits : digits.slice(-10); 34 } 35 36 function sanitizeUrl(value) { 37 const raw = sanitizePlainText(value, 2000); 38 if (!raw) return ''; 39 try { 40 const u = new URL(raw, window.location.origin); 41 if (u.protocol !== 'http:' && u.protocol !== 'https:') return ''; 42 return u.href; 43 } catch (e) { 44 return ''; 45 } 46 } 47 48 function sanitizePpcFormData(formData) { 49 const safe = { ...(formData || {}) }; 50 51 safe.ppc_email = sanitizeEmail(safe.ppc_email); 52 safe.phone_ppc = sanitizePhoneIN(safe.phone_ppc); 53 safe.city = sanitizePlainText(safe.city, 120); 54 safe.state_code = sanitizePlainText(safe.state_code, 50); 55 safe.number_of_employee_v1 = sanitizePlainText(safe.number_of_employee_v1, 50); 56 57 safe.utm_source = sanitizePlainText(safe.utm_source, 120); 58 safe.utm_medium = sanitizePlainText(safe.utm_medium, 120); 59 safe.utm_campaign = sanitizePlainText(safe.utm_campaign, 120); 60 safe.utm_content = sanitizePlainText(safe.utm_content, 120); 61 safe.utm_term = sanitizePlainText(safe.utm_term, 120); 62 63 safe.permalink = sanitizeUrl(safe.permalink); 64 safe.page_title = sanitizePlainText(safe.page_title, 200); 65 66 return safe; 67 } 68 69 // HubSpot API Configuration 70 const HUBSPOT_PORTAL_ID = '7277696'; 71 const HUBSPOT_FORM_GUID = '0a36628e-332f-49ac-925e-3c568d8c4353'; 72 const HUBSPOT_API_URL = 'https://api.hsforms.com/submissions/v3/integration/submit/' + HUBSPOT_PORTAL_ID + '/' + HUBSPOT_FORM_GUID; 73 74 $(document).ready(function () { 75 // PPC Form Submit Handler - handle both form submit and button click 76 $("#ppcform").on('submit', function (event) { 77 event.preventDefault(); 78 // Trigger the click handler logic 79 $("#submitppc").trigger('click'); 80 }); 81 82 $("#submitppc").click(function (event) { 83 event.preventDefault(); 84 85 var state = $('#input-box-city').attr('data-state'); 86 var isValid = true; 87 var email = $('#ppc_email').val(); 88 var phoneNum = $('#phone_ppc').val(); 89 90 // Check if base domains are loaded (for email validation) 91 if (typeof baseDomainsLoaded !== 'undefined' && !baseDomainsLoaded) { 92 $('.email_error').html('Please wait while the email domains are being loaded. Try again.'); 93 isValid = false; 94 } 95 96 // Validate required text/email fields (but skip hidden fields) 97 $(this).closest('form').find("input[type='text']:not(.hidden), input[type='email']").each(function () { 98 if ($(this).val().trim() === '' && $(this).attr('required')) { 99 isValid = false; 100 $(this).addClass('error'); 101 } else { 102 $(this).removeClass('error'); 103 } 104 }); 105 106 // Validate phone 107 var phoneRegex = /^[6-9]\d{9}$/; 108 if (!phoneRegex.test(phoneNum)) { 109 $('#phone_ppc').addClass('error'); 110 // Handle both phone_error and phone_error_PPC selectors 111 $('.phone_error, .phone_error_PPC').html('Insert a valid number '); 112 isValid = false;
113 } else { 114 $('#phone_ppc').removeClass('error'); 115 $('.phone_error, .phone_error_PPC').html(''); 116 } 117 118 // Validate email 119 if (email.length > 0) { 120 var email = $('#ppc_email').val().trim().toLowerCase(); 121 if (typeof validateEmail !== 'undefined' && !validateEmail(email)) { 122 $('#ppc_email').addClass('error'); 123 $('.email_error').html('Please insert valid work email. '); 124 isValid = false; 125 } else { 126 $('#ppc_email').removeClass('error'); 127 $('.email_error').html(''); 128 } 129 } 130 131 // Validate city using global autocomplete data 132 function validateCity() { 133 if (typeof inputBox !== 'undefined' && typeof availableKeywords !== 'undefined') { 134 const inputCity = inputBox.value.trim(); 135 const cityExists = availableKeywords.some(({ city }) => city === inputCity); 136 if (!cityExists) { 137 $(inputBox).addClass('error'); 138 $('.city-error').html('City not found in the list. Please select a valid city.'); 139 return false; 140 } else { 141 $('.city-error').html(''); 142 } 143 } 144 return true; 145 } 146 147 if (!validateCity()) { 148 isValid = false; 149 } 150 151 // Validate employee count 152 var formId = $(this).closest("form").attr("id"); 153 var form = document.getElementById(formId); 154 var no_of_employee_exists = form && form.querySelector('#no_of_employee') !== null; 155 if (no_of_employee_exists) { 156 var no_of_employee_field = $('#no_of_employee'); 157 if (no_of_employee_field.length > 0) { 158 var no_of_employee = no_of_employee_field.val(); 159 // Also check the value attribute for floating form selects (they set value attribute on click) 160 var selectValue = no_of_employee || no_of_employee_field.attr('value') || ''; 161 if (!selectValue || selectValue === '') { 162 isValid = false; 163 no_of_employee_field.addClass('error'); 164 $('.employee_error').html('Please select the number of employees.'); 165 } else { 166 no_of_employee_field.removeClass('error'); 167 $('.employee_error').html(''); 168 } 169 } 170 } 171 172 if (!isValid) { 173 return false; 174 } 175 176 // Capture form data for this specific form 177 const formData = captureFormData('ppcform'); 178 formData.state_code = state; 179 const sanitizedFormData = sanitizePpcFormData(formData); 180 181 // Debug: Log form data to verify all fields are captured 182 // console.log('PPC Form Data (sanitized):', sanitizedFormData); 183 184 const hasAnyValue = Object.values(sanitizedFormData).some(value => value !== ''); 185 186 if (!hasAnyValue) { 187 console.log('No form data found'); 188 return false; 189 } 190 191 document.getElementById("submitppc").disabled = true; 192 var loaderEl = document.getElementById("loaderpopup3"); 193 if (loaderEl) { 194 loaderEl.style.display = "block"; 195 } 196 197 // Get HubSpot tracking cookie (hubspotutk) for API context 198 function getCookie(name) { 199 const value = `; ${document.cookie}`; 200 const parts = value.split(`; ${name}=`); 201 if (parts.length === 2) return parts.pop().split(';').shift(); 202 return ''; 203 } 204 205 const hubspotCookie = getCookie('hubspotutk') || ''; 206 207 // PPC form doesn't have a name field, so we'll use email prefix as firstname or leave empty 208 // Extract first part of email as firstname if needed 209 const emailValue = sanitizedFormData.ppc_email || ''; 210 let firstname = ''; 211 let lastname = ''; 212 if (emailValue) { 213 const emailPrefix = emailValue.split('@')[0]; 214 // Use email prefix as firstname (optional - can be left empty) 215 firstname = emailPrefix || ''; 216 } 217 218 // Prepare data for HubSpot API 219 const hubspotData = { 220 "submittedAt": new Date().toISOString(), 221 "fields": [ 222 { "objectTypeId": "0-1", "name": "firstname", "value": firstname }, 223 { "objectTypeId": "0-1", "name": "lastname", "value": lastname }, 224 { "objectTypeId": "0-1", "name": "email", "value": sanitizedFormData.ppc_email || '' }, 225 { "objectTypeId": "0-1", "name": "phone", "value": "+91" + (sanitizedFormData.phone_ppc || '') }, 226 { "objectTypeId": "0-1", "name": "city", "value": sanitizedFormData.city || '' }, 227 { "objectTypeId": "0-1", "name": "state_sap__cloned_", "value": state || '' }, 228 { "objectTypeId": "0-1", "name": "country", "value": "India" }, 229 { "objectTypeId": "0-1", "name": "number_of_employee_v1", "value": sanitizedFormData.number_of_employee_v1 || '' }, 230 { "objectTypeId": "0-1", "name": "utm_source", "value": sanitizedFormData.utm_source || '' }, 231 { "objectTypeId": "0-1", "name": "utm_medium", "value": sanitizedFormData.utm_medium || '' }, 232 { "objectTypeId": "0-1", "name": "utm_campaign", "value": sanitizedFormData.utm_campaign || '' }, 233 { "objectTypeId": "0-1", "name": "utm_content", "value": sanitizedFormData.utm_content || '' }, 234 { "objectTypeId": "0-1", "name": "utm_term", "value": sanitizedFormData.utm_term || '' } 235 ], 236 "context": { 237 "hutk": hubspotCookie, 238 "pageUri": sanitizedFormData.permalink || window.location.href, 239 "pageName": sanitizedFormData.page_title || document.title 240 }, 241 "legalConsentOptions": { 242 "consent": { 243 "consentToProcess": true, 244 "text": "I agree to allow HROne to store and process my personal data." 245 } 246 } 247 }; 248 249 // Submit directly to HubSpot API (no AJAX/backend) 250 fetch(HUBSPOT_API_URL, { 251 method: 'POST', 252 headers: { 253 'Content-Type': 'application/json' 254 }, 255 body: JSON.stringify(hubspotData) 256 }) 257 .then(response => response.json()) 258 .then(data => { 259 // Reset form and hide loader 260 if ($('#ppcform').length) { 261 $('#ppcform')[0].reset(); 262 } 263 document.getElementById("submitppc").disabled = false;
264 if (loaderEl) { 265 loaderEl.style.display = "none"; 266 } 267 268 // Optional success message (can be styled as needed) 269 if (data.inlineMessage) { 270 // You can add success message display here if needed 271 // Similar to product form if there's a container for it 272 } 273 274 // Redirect to thank you page 275 setTimeout(function () { 276 const thankYouUrl = (typeof hronePpcForm !== 'undefined' && hronePpcForm.thankYouUrl) 277 ? hronePpcForm.thankYouUrl 278 : window.location.origin + '/thankyou'; 279 window.location.href = thankYouUrl; 280 }, 1000); 281 }) 282 .catch(error => { 283 console.error('Error submitting PPC form:', error); 284 document.getElementById("submitppc").disabled = false; 285 if (loaderEl) { 286 loaderEl.style.display = "none"; 287 } 288 // Display error message 289 const errorMsg = '<div class="hm-banner-msg"><div class="error-msg"><h2>Error!</h2>There was an error submitting your form. Please try again.</div></div>'; 290 // Try to find a container to show error, otherwise use alert 291 if ($('.ppc-from').length) { 292 $('.ppc-from').prepend(errorMsg); 293 } else { 294 alert('There was an error submitting your form. Please try again.'); 295 } 296 }); 297 }); 298 }); 299 300})(jQuery); 301
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.