1(function($) { 2 'use strict'; 3 4 // DISABLED FOR TESTING 5 // let turnstileWidgetId = null; 6 // window.onloadTurnstileCallback = function() { 7 // if ($('.rsra-modal-overlay').hasClass('is-visible')) { renderTurnstile(); } 8 // }; 9 // function renderTurnstile() { 10 // if (typeof turnstile !== 'undefined' && typeof rsra_form_ajax !== 'undefined' && rsra_form_ajax.turnstile_site_key && $('.cf-turnstile-widget').length && !turnstileWidgetId) { 11 // turnstileWidgetId = turnstile.render('.cf-turnstile-widget', { sitekey: rsra_form_ajax.turnstile_site_key, callback: function(token) {} }); 12 // } 13 // } 14 let turnstileWidgetId = null; // kept so resetUI references don't break 15 16 // Domains allowed to embed this form in an iframe and receive postMessage. 17 const allowedParentDomains = ['codesignery.com', 'tamko.com', 'rsa.pro']; 18 19 /** 20 * Redirect after successful submission. 21 * If running inside an iframe from an allowed domain, sends a postMessage 22 * to the parent instead of redirecting the iframe itself. 23 * Falls back to normal redirect in all other cases. 24 */ 25 function handleRedirect(url, meta) { 26 meta = meta || {}; 27 if (window !== window.top) { 28 try { 29 const ref = document.referrer; 30 const isAllowed = allowedParentDomains.some(d => ref.indexOf(d) !== -1); 31 if (isAllowed) { 32 let parentOrigin = '*'; 33 try { parentOrigin = new URL(ref).origin; } catch (e) {} 34 window.parent.postMessage({ 35 type: 'rsra_form_success', 36 redirect: url, 37 role: meta.role || '' 38 }, parentOrigin); 39 return; 40 } 41 } catch (e) {} 42 } 43 window.location.href = url; 44 } 45 46 $(function() { 47 48 // --- Custom Popup Logic --- 49 function showPopup(title, message, type = 'error') { 50 const overlay = $('#rsra-message-overlay'); 51 const box = overlay.find('.rsra-message-box'); 52 const iconContainer = $('#rsra-message-icon'); 53 54 $('#rsra-message-title').text(title); 55 $('#rsra-message-text').text(message); 56 57 box.removeClass('rsra-msg-error rsra-msg-success'); 58 59 if (type === 'success') { 60 box.addClass('rsra-msg-success'); 61 iconContainer.html('â'); 62 } else { 63 box.addClass('rsra-msg-error'); 64 iconContainer.html('â '); 65 } 66 67 overlay.addClass('is-active'); 68 } 69 70 $('#rsra-message-close').on('click', function() { 71 $('#rsra-message-overlay').removeClass('is-active'); 72 }); 73 74 // --- Time Trap --- 75 const formLoadTime = Math.floor(Date.now() / 1000); 76 77 const modalOverlay = $('.rsra-modal-overlay'); 78 const form = $('#rsra-contractor-form'); 79 const submitButton = form.find('.rsra-submit-button'); 80 let phoneInputInstance = null; 81 let debounceTimer; 82 83 const roleDisplayMap = { 84 'sole-owner': 'Sole Owner', 85 'co-owner': 'Co-Owner', 86 'manager': 'Manager', 87 'sales-rep': 'Sales Rep' 88 }; 89 90 const formNameMap = { 91 'cf5': 'Contractors Join Data v5', 92 'ftc5': 'Contractors Join FTC Data v5', 93 'rmr2': 'Contractors Join RMR v2', 94 'rmsp': 'Contractors Join RMSP' 95 }; 96 97 function setCookie(name, value, days) { 98 let expires = ""; 99 if (days) { 100 const date = new Date(); 101 date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); 102 expires = "; expires=" + date.toUTCString(); 103 } 104 document.cookie = name + "=" + (value || "") + expires + "; path=/"; 105 } 106 107 function getCookie(name) { 108 const nameEQ = name + "="; 109 const ca = document.cookie.split(';'); 110 for (let i = 0; i < ca.length; i++) { 111 let c = ca[i]; 112 while (c.charAt(0) === ' ') c = c.substring(1, c.length); 113 if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length); 114 } 115 return null; 116 } 117
118 function eraseCookie(name) { 119 document.cookie = name + '=; Path=/; Expires=Thu, 01 Jan 1900 00:00:01 GMT;'; 120 } 121 122 function generateUniqueId() { 123 return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15); 124 } 125 126 function getDynamicLocalStorageKey() { 127 const formId = $('#rsra-form-id').val(); 128 return formId ? 'rsra_form_progress_' + formId : null; 129 } 130 131 function initializePhoneInput(selector) { 132 if (!$(selector).length) return null; 133 return window.intlTelInput(document.querySelector(selector), { 134 initialCountry: "auto", 135 separateDialCode: true, 136 dropdownContainer: document.body, 137 showSearchInput: true, 138 geoIpLookup: function(callback) { 139 $.get("https://ipapi.co/json", function() {}, "jsonp").always(function(resp) { 140 var countryCode = (resp && resp.country_code) ? resp.country_code : "us"; 141 callback(countryCode); 142 }); 143 }, 144 utilsScript: "https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/17.0.13/js/utils.js", 145 }); 146 } 147 148 function openModal() { 149 $('body').addClass('rsra-modal-open'); 150 modalOverlay.addClass('is-visible'); 151 if (!phoneInputInstance) { 152 phoneInputInstance = initializePhoneInput("#rsra-phone"); 153 } 154 loadProgress(); 155 renderTurnstile(); 156 } 157 158 function closeModal() { 159 $('body').removeClass('rsra-modal-open'); 160 modalOverlay.removeClass('is-visible'); 161 } 162 163 function validateForm() { 164 const inputs = form.find('input:visible[required], select:visible[required]'); 165 let isValid = true; 166 inputs.each(function() { 167 if ($(this).attr('name') === 'rsra_honeypot') { return true; } 168 if (!this.checkValidity()) { isValid = false; return false; } 169 }); 170 171 // DISABLED FOR TESTING 172 // const turnstileResponse = form.find('[name="cf-turnstile-response"]').val(); 173 // if (!turnstileResponse) { isValid = false; } 174 175 // SMS consent is a single required checkbox - it must be ticked. 176 var consentChecked = form.find('[name="sms_consent"]').is(':checked'); 177 if (!consentChecked) { 178 form.find('.rsra-sms-consent-required').show(); 179 return false; 180 } 181 form.find('.rsra-sms-consent-required').hide(); 182 183 var tamkoProVal = form.find('[name="tamko_pro_status"]:checked').val(); 184 if (!tamkoProVal) { 185 form.find('.rsra-tamko-pro-required').show(); 186 isValid = false; 187 return false; 188 } 189 form.find('.rsra-tamko-pro-required').hide(); 190 191 if (!isValid) { 192 let firstInvalid = null; 193 inputs.each(function() { 194 if (!this.checkValidity() && $(this).attr('name') !== 'rsra_honeypot') { 195 firstInvalid = this; 196 return false; 197 } 198 }); 199 if(firstInvalid){ form[0].reportValidity(); } 200 } 201 return isValid; 202 } 203 204 function collectFormData() { 205 return { 206 role: $('#rsra-role-select').val(), 207 firstName: $('#rsra-first-name').val(), 208 lastName: $('#rsra-last-name').val(), 209 email: $('#rsra-email').val(), 210 phone: phoneInputInstance ? phoneInputInstance.getNumber() : '', 211 smsConsent: form.find('[name="sms_consent"]:checked').val() || '', 212 tamkoPro: form.find('[name="tamko_pro_status"]:checked').val() || '' 213 }; 214 } 215 216 function getHtmlFormattedData(data) { 217 const properRoleName = roleDisplayMap[data.role] || data.role || ''; 218 let html = `<div><b><span>1.</span>Select Your Role*: </b>${properRoleName}</div>`; 219 html += `<div><b><span>2.</span>What is Your First Name?*: </b>${data.firstName || ''}</div>`; 220 html += `<div><b><span>
2203.</span>What is Your Last Name?*: </b>${data.lastName || ''}</div>`; 221 html += `<div><b><span>4.</span>What is Your Email Address?*: </b>${data.email || ''}</div>`; 222 html += `<div><b><span>5.</span>What is Your Best Contact Number?*: </b>${data.phone || ''}</div>`; 223 html += `<div><b><span>6.</span>SMS Consent: </b>${data.smsConsent || ''}</div>`; 224 html += `<div><b><span>7.</span>TAMKO PRO GOLD/PLATINUM/DIAMOND Contractor: </b>${data.tamkoPro || ''}</div>`; 225 return html; 226 } 227 228 function getDynamicCookieName() { 229 const formId = $('#rsra-form-id').val(); 230 return formId ? 'cf_cookie_' + formId : null; 231 } 232 233 function saveProgress() { 234 const localStorageKey = getDynamicLocalStorageKey(); 235 if (!localStorageKey) return; 236 const formData = collectFormData(); 237 const jsonString = JSON.stringify(formData); 238 try { 239 localStorage.setItem(localStorageKey, jsonString); 240 } catch (e) { console.error('Could not save to local storage.', e); } 241 saveProgressToDB(formData); 242 } 243 244 function saveProgressToDB(formData) { 245 const formId = $('#rsra-form-id').val(); 246 const cookieName = getDynamicCookieName(); 247 if (!cookieName) return; 248 const cookieId = getCookie(cookieName); 249 if (!cookieId) return; 250 251 $.ajax({ 252 url: rsra_form_ajax.ajax_url, 253 type: 'POST', 254 data: { 255 action: 'rsra_save_form_progress', 256 nonce: rsra_form_ajax.nonce, 257 form_id: formId, 258 cf_cookie: cookieId, 259 cf_data: JSON.stringify(formData), 260 cf_data_all: getHtmlFormattedData(formData) 261 } 262 }); 263 } 264 265 function populateFormFromJSON(jsonString) { 266 try { 267 const data = jsonString ? JSON.parse(jsonString) : {}; 268 $('#rsra-role-select').val(data.role || ''); 269 $('#rsra-first-name').val(data.firstName || ''); 270 $('#rsra-last-name').val(data.lastName || ''); 271 $('#rsra-email').val(data.email || ''); 272 if (phoneInputInstance) { 273 phoneInputInstance.setNumber(data.phone || ''); 274 } 275 } catch (e) { console.error("Error parsing form data from JSON:", e); } 276 } 277 278 function loadProgress() { 279 const localStorageKey = getDynamicLocalStorageKey(); 280 if (!localStorageKey) { populateFormFromJSON(null); return; } 281 282 try { 283 const localData = localStorage.getItem(localStorageKey); 284 if (localData) { populateFormFromJSON(localData); return; } 285 } catch (e) { console.error('Could not read from local storage.', e); } 286 287 const cookieName = getDynamicCookieName(); 288 const cookieId = getCookie(cookieName); 289 if (!cookieId) { populateFormFromJSON(null); return; }; 290 291 $.ajax({ 292 url: rsra_form_ajax.ajax_url, 293 type: 'POST', 294 data: { 295 action: 'rsra_get_form_progress', 296 nonce: rsra_form_ajax.nonce, 297 form_id: $('#rsra-form-id').val(), 298 cf_cookie: cookieId, 299 }, 300 success: function(response) { 301 if (response.success && response.data) { populateFormFromJSON(response.data); } 302 else { populateFormFromJSON(null); } 303 }, 304 error: function() { populateFormFromJSON(null); } 305 }); 306 } 307 308 $(document).on('click', '.rsraContractorsForm', function(e) { 309 e.preventDefault(); 310 modalOverlay.find('.rsra-modal-title').text('Get Your Private Tour'); 311 form.show(); 312 let formId = null; 313 const classes = $(this).attr('class').split(' ');
314 classes.forEach(function(className) { 315 if (className.startsWith('form-id-')) { formId = className.replace('form-id-', ''); } 316 }); 317 if (!formId) { formId = $(this).data('form-id'); } 318 if (!formId) { 319 modalOverlay.find('.rsra-modal-title').text('Configuration Error'); 320 form.hide(); 321 modalOverlay.addClass('is-visible'); 322 return; 323 } 324 $('#rsra-form-id').val(formId); 325 const cookieName = getDynamicCookieName(); 326 let cookieId = getCookie(cookieName); 327 if (!cookieId) { 328 cookieId = generateUniqueId(); 329 setCookie(cookieName, cookieId, 30); 330 } 331 openModal(); 332 }); 333 334 $('.rsra-close-button').on('click', function(e) { e.preventDefault(); closeModal(); }); 335 modalOverlay.on('click', function(e) { if ($(e.target).is(modalOverlay)) { closeModal(); } }); 336 337 form.on('mousedown', 'select', function() { 338 if ($(this).find('option[value=""]').length > 0) { 339 $(this).find('option[value=""]').remove(); 340 } 341 }); 342 343 form.on('input change', 'input, select', function() { clearTimeout(debounceTimer); debounceTimer = setTimeout(saveProgress, 500); }); 344 form.on('change', '[name="sms_consent"]', function() { 345 form.find('.rsra-sms-consent-required').toggle(!this.checked); 346 }); 347 form.on('change', '[name="tamko_pro_status"]', function() { 348 form.find('.rsra-tamko-pro-required').hide(); 349 }); 350 351 form.on('submit', function(e) { 352 e.preventDefault(); 353 354 if (!validateForm()) { return; } 355 356 const originalButtonText = submitButton.html(); 357 submitButton.prop('disabled', true).html('<span class="rsra-spinner"></span> Submitting...'); 358 form.addClass('form-loading'); 359 360 // const siteKey = rsra_recaptcha_data.site_key; // DISABLED FOR TESTING 361 // grecaptcha.ready(function() { // DISABLED FOR TESTING 362 // grecaptcha.execute(siteKey, {action: 'submit'}).then(function(recaptchaToken) { // DISABLED FOR TESTING 363 (function() { 364 var recaptchaToken = ''; 365 $('#rsra_recaptcha_token').val(recaptchaToken); 366 367 const cookieName = getDynamicCookieName(); 368 const localStorageKey = getDynamicLocalStorageKey(); 369 const cookieId = getCookie(cookieName); 370 let formData = collectFormData(); 371 372 const honeypotValue = form.find('input[name="rsra_honeypot"]').val(); 373 const turnstileResponse = form.find('[name="cf-turnstile-response"]').val(); 374 375 // --- Define Zapier Logic (To be called later) --- 376 const formId = $('#rsra-form-id').val(); 377 const selectedRole = formData.role; 378 const tamkoPro = formData.tamkoPro || ''; 379 const tamkoProZapierUrl = (rsra_form_ajax.tamko_pro_zapier_url || ''); 380 let zapierUrl = null; 381 382 if (tamkoPro === 'yes' && tamkoProZapierUrl) { 383 zapierUrl = tamkoProZapierUrl; 384 } else if (selectedRole === 'sales-rep') { 385 zapierUrl = 'https://hooks.zapier.com/hooks/catch/809273/u5evq9r/'; 386 } else { 387 if (formId === 'cf5') { zapierUrl = 'https://hooks.zapier.com/hooks/catch/809273/u1n0eku/'; } 388 else if (formId === 'ftc5') { zapierUrl = 'https://hooks.zapier.com/hooks/catch/809273/u5c9jz9/'; } 389 else if (formId === 'rmr2') { zapierUrl = 'https://hooks.zapier.com/hooks/catch/809273/u5c5ymn/'; } 390 else if (formId === 'rmsp') { zapierUrl = 'https://hooks.zapier.com/hooks/catch/809273/uc12eal/'; } 391 } 392 393 const zapierData = { 394 'Unique Id': cookieId, 395 'Form': formNameMap[formId] || formId, 396 'Role': roleDisplayMap[formData.role] || formData.role, 397 firstName: formData.firstName, 398 lastName: formData.lastName, 399 email: formData.email, 400 'Contact Number': formData.phone, 401 'SMS Consent': formData.smsConsent, 402 'TAMKO PRO Contractor': tamkoPro, 403 }; 404 405 // --- Define Submit to WordPress --- 406 const submitToWordPress = () => { 407 $.ajax({ 408 url: rsra_form_ajax.ajax_url, 409 type: 'POST', 410 data: { 411 action: 'rsra_submit_form', 412 nonce: rsra_form_ajax.nonce, 413 form_id: $('#rsra-form-id').val(), 414 cf_cookie: cookieId, 415 cf_data: JSON.stringify(formData), 416 cf_data_all: getHtmlFormattedData(formData), 417 rsra_honeypot: honeypotValue, 418 'cf-turnstile-response': turnstileResponse, 419 'rsra_recaptcha_token': recaptchaToken, 420 rsra_form_load_time: formLoadTime 421 }, 422 success: function(response) { 423 if (response.success && response.data.redirect) { 424 425 // 1. Success! Clean Up Local State 426 if (localStorageKey) { 427 try { localStorage.removeItem(localStorageKey); } catch (e) { console.error(e); } 428 } 429 eraseCookie(cookieName); 430 form[0].reset(); 431 if (typeof turnstile !== 'undefined' && turnstileWidgetId) { turnstile.reset(turnstileWidgetId); } 432 433 // 2. NOW Send to Zapier (Only because WordPress gave success/green light) 434 if(zapierUrl){ 435 fetch(zapierUrl, { 436 method: 'POST', 437 body: JSON.stringify(zapierData) 438 }) 439 .then(() => { 440 // 3a. Redirect after Zapier 441 handleRedirect(response.data.redirect, { role: formData.role }); 442 }) 443 .catch(error => { 444 // 3b. Redirect even if Zapier fails (don't block user) 445 console.error('Zapier Error:', error); 446 handleRedirect(response.data.redirect, { role: formData.role }); 447 }); 448 } else { 449 // 3c. Redirect immediately if no Zapier 450 handleRedirect(response.data.redirect, { role: formData.role }); 451 } 452 453 } else { 454 // Error State (Spam/Block) -> Do NOT send to Zapier 455 showPopup('Submission Issue', response.data || 'Please try again.', 'error'); 456 resetUI(); 457 } 458 }, 459 error: function(xhr) { 460 let errorMsg = 'An unexpected error occurred.'; 461 if(xhr.responseJSON && xhr.responseJSON.data){ errorMsg = xhr.responseJSON.data; } 462 showPopup('Notice', errorMsg, 'error'); 463 resetUI(); 464 } 465 }); 466 }; 467 468 function resetUI() { 469 submitButton.prop('disabled', false).html(originalButtonText); 470 form.removeClass('form-loading'); 471 if (typeof turnstile !== 'undefined' && turnstileWidgetId) { turnstile.reset(turnstileWidgetId); } 472 } 473 474 // --- EXECUTE: Call WordPress FIRST --- 475 submitToWordPress(); 476 477 // }); // DISABLED FOR TESTING 478 // }); // DISABLED FOR TESTING 479 })(); 480 }); 481 482 window.addEventListener('pageshow', function(event) { 483 if (event.persisted) { 484 const originalButtonText = 'Submit'; 485 submitButton.prop('disabled', false).html(originalButtonText); 486 form.removeClass('form-loading'); 487 form[0].reset(); 488 try { 489 localStorage.removeItem(getDynamicLocalStorageKey()); 490 } catch (e) { console.error(e); } 491 populateFormFromJSON(null); 492 if (typeof turnstile !== 'undefined' && turnstileWidgetId) { 493 $('.cf-turnstile-widget').empty(); 494 turnstileWidgetId = null; 495 renderTurnstile(); 496 } 497 } 498 }); 499 500 }); 501 502})(jQuery);
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.