PageSourceSearch

https://www.orchardortho.com/js/form-override.js

js orchardortho.com collected 2026-10-04 13:25:16 UTC 5,363 bytes, 127 lines download raw bytes

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.