1(function () { 2 if (window.__dcwContactFormsLoaded) return; 3 window.__dcwContactFormsLoaded = true; 4 5 const ENDPOINT = "/dcw-contact-api/contact"; 6 7 function isVisible(el) { 8 if (!el) return false; 9 const rect = el.getBoundingClientRect(); 10 const style = window.getComputedStyle(el); 11 12 return ( 13 rect.width > 0 && 14 rect.height > 0 && 15 style.display !== "none" && 16 style.visibility !== "hidden" && 17 style.opacity !== "0" 18 ); 19 } 20 21 function clean(value) { 22 return String(value || "").trim(); 23 } 24 25 function visibleInputs() { 26 return Array.from(document.querySelectorAll("input")) 27 .filter(isVisible) 28 .filter((el) => { 29 const type = (el.getAttribute("type") || "text").toLowerCase(); 30 return !["hidden", "button", "submit", "reset", "checkbox", "radio"].includes(type); 31 }); 32 } 33 34 function visibleTextareas() { 35 return Array.from(document.querySelectorAll("textarea")).filter(isVisible); 36 } 37 38 function getFormData() { 39 const inputs = visibleInputs(); 40 const textareas = visibleTextareas(); 41 42 const nameEl = 43 inputs.find((el) => /name/i.test(el.name || el.id || el.placeholder || "")) || 44 inputs[0] || 45 null; 46 47 const emailEl = 48 inputs.find((el) => (el.type || "").toLowerCase() === "email") || 49 inputs.find((el) => /email/i.test(el.name || el.id || el.placeholder || "")) || 50 inputs.find((el) => clean(el.value).includes("@")) || 51 inputs[1] || 52 null; 53 54 const messageEl = 55 textareas.find((el) => clean(el.value)) || 56 textareas.find((el) => /message|feedback/i.test(el.name || el.id || el.placeholder || "")) || 57 textareas[0] || 58 null; 59 60 const data = { 61 name: nameEl ? clean(nameEl.value) : "", 62 email: emailEl ? clean(emailEl.value) : "", 63 message: messageEl ? clean(messageEl.value) : "", 64 page: window.location.href, 65 formType: window.location.pathname.includes("feedback") 66 ? "Feedback form" 67 : "Contact form" 68 }; 69 70 console.log("DCW contact form data:", data); 71 return data; 72 } 73 74 function isContactSubmit(el) { 75 const text = clean(el.innerText || el.value || "").toLowerCase(); 76 return ( 77 text.includes("send message") || 78 text.includes("send feedback") || 79 text.includes("submit") 80 ); 81 } 82 83 async function submitContactForm(event, submitter) { 84 event.preventDefault(); 85 event.stopPropagation(); 86 87 const data = getFormData(); 88 89 const button = 90 submitter || 91 document.querySelector("button[type='submit'], button, input[type='submit']"); 92 93 const originalText = button ? button.innerText || button.value : ""; 94 95 const missing = []; 96 if (!data.name) missing.push("name"); 97 if (!data.email) missing.push("email"); 98 if (!data.message) missing.push("message"); 99 100 if (missing.length) { 101 alert("Missing: " + missing.join(", ")); 102 return; 103 } 104 105 try { 106 if (button) { 107 button.disabled = true; 108 if ("value" in button) button.value = "Sending..."; 109 else button.innerText = "Sending..."; 110 } 111 112 const response = await fetch(ENDPOINT, { 113 method: "POST", 114 headers: { 115 "Content-Type": "application/json" 116 }, 117 body: JSON.stringify(data) 118 }); 119 120 const result = await response.json().catch(() => ({})); 121 122 if (!response.ok || !result.ok) { 123 throw new Error(result.error || "Message could not be sent."); 124 } 125 126 document.querySelectorAll("input, textarea").forEach((el) => { 127 if (!el.disabled && !el.readOnly) { 128 const type = (el.getAttribute("type") || "text").toLowerCase(); 129 if (!["hidden", "button", "submit", "reset"].includes(type)) { 130 el.value = ""; 131 el.dispatchEvent(new Event("input", { bubbles: true })); 132 el.dispatchEvent(new Event("change", { bubbles: true })); 133 } 134 } 135 }); 136 137 if (button) { 138 if ("value" in button) button.value = "Message sent!"; 139 else button.innerText = "Message sent!"; 140 } 141 142 setTimeout(function () { 143 if (button) { 144 if ("value" in button) button.value = originalText; 145 else button.innerText = originalText; 146 } 147 }, 3500); 148 } catch (error) { 149 alert(error.message || "Message could not be sent right now."); 150 151 if (button) { 152 if ("value" in button) button.value = originalText; 153 else button.innerText = originalText; 154 } 155 } finally { 156 if (button) button.disabled = false;
157 } 158 } 159 160 document.addEventListener( 161 "click", 162 function (event) { 163 const button = event.target.closest("button, input[type='submit']"); 164 if (!button || !isContactSubmit(button)) return; 165 166 const hasFields = 167 visibleInputs().length >= 2 && 168 visibleTextareas().length >= 1; 169 170 if (!hasFields) return; 171 172 submitContactForm(event, button); 173 }, 174 true 175 ); 176 177 document.addEventListener( 178 "submit", 179 function (event) { 180 const hasFields = 181 visibleInputs().length >= 2 && 182 visibleTextareas().length >= 1; 183 184 if (!hasFields) return; 185 186 const submitter = 187 event.submitter || 188 event.target.querySelector("button[type='submit'], button, input[type='submit']"); 189 190 submitContactForm(event, submitter); 191 }, 192 true 193 ); 194})();
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.