1/** 2 * Form Override â jQuery Validate sites (Approach B2) 3 * 4 * Orchard Orthodontics uses jQuery 1.11.1 + jQuery Validate via 5 * spam-protection-2023.js. Every form.ajax_form is validated and, on success, 6 * $.ajax()'d to its `.action_path` value (/application/themes/_spam_protect.php) 7 * which does not exist in the static export. 8 * 9 * This prefilter intercepts those _spam_protect.php POSTs and: 10 * 1. rewrites the URL to prm.tio.work 11 * 2. adds the TDS-API-KEY header 12 * 3. forces dataType/dataTypes = "text" (avoids the jQuery 1.x JSON auto-parse 13 * bug that turns a 2xx into an error and skips the redirect) 14 * 4. strips the C5 `prm-note-` field-name prefix and adds `prm-note=prm-note` 15 * so PRM builds a readable contact note from the dentist-referral fields 16 * 5. drops empty `name="...[]"` array fields (they crash PRM's note builder 17 * with "Array to string conversion" â 500) 18 * 6. overrides success/error to redirect to the form's own `thanks` value 19 * (PRM captures the lead before any response-build 500, so recover on error) 20 */ 21(function () { 22 var cfg = window.__PRM_CONFIG__; 23 if (!cfg || typeof jQuery === "undefined") return; 24 25 var PRM_ENDPOINT = cfg.endpoint; 26 var TDS_API_KEY = cfg.tdsApiKey; 27 28 function thanksFrom(data) { 29 try { 30 return new URLSearchParams(data || "").get("thanks") || ""; 31 } catch (e) { 32 return ""; 33 } 34 } 35 36 function cleanData(data) { 37 if (!data) return data; 38 // strip prm-note- prefix so fields become readable PRM note labels 39 var stripped = data.replace(/prm-note-/g, ""); 40 // Collapse ALL array-bracket fields (name="â¦[]" â checkboxes, upload slots) 41 // to a single comma-joined scalar. PRM's note builder concatenates each field 42 // value as a string (PRMService.php:143) and 500s ("Array to string conversion") 43 // on ANY array â even a single checked checkbox like Contacted_Whatsapp[]=No. 44 // Empty array fields are dropped entirely. 45 var params = new URLSearchParams(stripped); 46 var out = new URLSearchParams(); 47 var arrays = {}; 48 params.forEach(function (value, key) { 49 var m = key.match(/^(.*)\[\]$/); 50 if (m) { 51 if (value !== "") (arrays[m[1]] = arrays[m[1]] || []).push(value); 52 } else { 53 out.append(key, value); 54 } 55 }); 56 Object.keys(arrays).forEach(function (base) { 57 out.append(base, arrays[base].join(", ")); 58 }); 59 60 // C5 "send_all_email" â PRM v4-tds GDPR email path. The old _spam_protect.php 61 // emailed the WHOLE form to email_recipient (+ multi_email + a copy to the 62 // dentist when send_copy_gdp). v4-tds does the same via handleGdprEmailV2, but 63 // only when `gdpr` is set and recipients are given as local_part[]/domain[]. 64 // So derive those here â otherwise the referral email is silently never sent. 65 if (out.get("send_all_email") && !out.get("gdpr")) { 66 var recips = []; 67 var push = function (addr) { 68 if (addr && addr.indexOf("@") > 0 && recips.indexOf(addr) === -1) recips.push(addr); 69 }; 70 push(out.get("email_recipient")); 71 var multi = out.get("multi_email"); 72 if (multi) multi.split(",").forEach(function (a) { push(a.trim()); }); 73 if (out.get("send_copy_gdp")) push(out.get("Dentist_Email") || out.get("dentist_email")); 74 recips.forEach(function (addr, i) { 75 var at = addr.indexOf("@"); 76 out.append("local_part[" + i + "]", addr.slice(0, at)); 77 out.append("domain[" + i + "]", addr.slice(at + 1)); 78 }); 79 if (recips.length) { 80 out.set("gdpr", "gdpr"); 81 if (!out.get("gdpr_email_subject")) { 82 out.set("gdpr_email_subject", out.get("email_subject") || "Form Submission"); 83 } 84 } 85 } 86 87 var s = out.toString(); 88 // ensure prm-note flag present (needed for non-standard fields to land in PRM) 89 if (s.indexOf("prm-note=") === -1) s += "&prm-note=prm-note"; 90 return s; 91 } 92 93 jQuery(document).ready(function ($) { 94 $.ajaxPrefilter(function (options /*, originalOptions, jqXHR */) { 95 if (!options.url || options.url.indexOf("_spam_protect") === -1) return; 96 97 var thanks = thanksFrom(options.data); 98 options.url = PRM_ENDPOINT; 99 options.data = cleanData(options.data); 100 options.dataType = "text"; 101 options.dataTypes = ["text"]; 102 103 var origBeforeSend = options.beforeSend; 104 options.beforeSend = function (xhr) { 105 if (TDS_API_KEY) xhr.setRequestHeader("TDS-API-KEY", TDS_API_KEY); 106 if (origBeforeSend) origBeforeSend.apply(this, arguments); 107 }; 108 109 options.success = function () { 110 window.location.href = thanks || "/"; 111 }; 112 113 options.error = function (xhr) { 114 // PRM creates the lead + sends email before any response-build 500, 115 // so a non-empty 500 body means the submission succeeded server-side. 116 if (xhr && xhr.status === 500 && (xhr.responseText || "").length > 0) { 117 window.location.href = thanks || "/"; 118 return; 119 } 120 // Genuine failure (network / 4xx) â re-enable the form, surface an error. 121 var $btn = jQuery("form.ajax_form").find('button[type="submit"], input[type="submit"]'); 122 $btn.prop("disabled", false); 123 alert("Sorry, something went wrong sending your enquiry. Please try again or call us."); 124 }; 125 }); 126 }); 127})();
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.