1(() => { 2 "use strict"; 3 const stagingPreview = window.location.hostname.endsWith(".workers.dev") 4 || ["localhost", "127.0.0.1"].includes(window.location.hostname); 5 if (stagingPreview) window["ga-disable-G-27P7B6LY38"] = true; 6 7 const formSecurity = new WeakMap(); 8 let turnstileScriptPromise; 9 10 const showState = (form, ok, message) => { 11 const wrapper = form.closest(".w-form"); 12 if (!wrapper) return; 13 const done = wrapper.querySelector(".w-form-done"); 14 const fail = wrapper.querySelector(".w-form-fail"); 15 form.style.display = ok ? "none" : ""; 16 if (done) done.style.display = ok ? "block" : "none"; 17 if (fail) { 18 fail.style.display = ok ? "none" : "block"; 19 const text = fail.querySelector("div"); 20 if (text && message) text.textContent = message; 21 } 22 }; 23 24 const loadTurnstile = () => { 25 if (window.turnstile) return Promise.resolve(); 26 if (turnstileScriptPromise) return turnstileScriptPromise; 27 turnstileScriptPromise = new Promise((resolve, reject) => { 28 const script = document.createElement("script"); 29 script.src = "https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit"; 30 script.async = true; 31 script.defer = true; 32 script.onload = () => window.turnstile ? resolve() : reject(new Error("ã»ãã¥ãªãã£ç¢ºèªãéå§ã§ãã¾ããã§ããã")); 33 script.onerror = () => reject(new Error("ã»ãã¥ãªãã£ç¢ºèªãèªã¿è¾¼ãã¾ããã§ããã")); 34 document.head.append(script); 35 }); 36 return turnstileScriptPromise; 37 }; 38 39 const securityStatus = (form) => { 40 let status = form.querySelector(".form-security-status"); 41 if (status) return status; 42 status = document.createElement("div"); 43 status.className = "form-security-status"; 44 status.setAttribute("role", "status"); 45 status.setAttribute("aria-live", "polite"); 46 status.hidden = true; 47 const submit = form.querySelector('[type="submit"]'); 48 if (submit) submit.insertAdjacentElement("beforebegin", status); 49 else form.append(status); 50 return status; 51 }; 52 53 const initializeTurnstile = async (form) => { 54 const query = new URLSearchParams({ 55 path: window.location.pathname, 56 formName: form.dataset.name || "", 57 elementId: form.dataset.wfElementId || "" 58 }); 59 const response = await fetch(`/api/forms/config?${query}`, { headers: { accept: "application/json" }, cache: "no-store" }); 60 const result = await response.json().catch(() => ({})); 61 if (!response.ok || !result.turnstile?.configured || !result.turnstile.siteKey || !result.turnstile.action) { 62 throw new Error(result.error || "ã»ãã¥ãªãã£ç¢ºèªãå©ç¨ã§ãã¾ãããæéãããã¦å度ã試ããã ããã"); 63 } 64 await loadTurnstile(); 65 const status = securityStatus(form); 66 const container = document.createElement("div"); 67 container.className = "form-turnstile"; 68 container.style.width = "100%"; 69 const submit = form.querySelector('[type="submit"]'); 70 if (submit) submit.insertAdjacentElement("beforebegin", container); 71 else form.append(container); 72 const state = { widgetId: null, resolve: null, reject: null }; 73 state.widgetId = window.turnstile.render(container, { 74 sitekey: result.turnstile.siteKey, 75 action: result.turnstile.action, 76 execution: "execute", 77 appearance: "interaction-only", 78 size: "flexible", 79 callback: (token) => { 80 status.hidden = true; 81 status.textContent = ""; 82 const resolve = state.resolve; 83 state.resolve = null; 84 state.reject = null; 85 if (resolve) resolve(token); 86 }, 87 "expired-callback": () => { 88 status.hidden = false; 89 status.textContent = "ã»ãã¥ãªãã£ç¢ºèªã®æå¹æéãåãã¾ãããããä¸åº¦ç¢ºèªãã¦ãã ããã"; 90 const reject = state.reject; 91 state.resolve = null; 92 state.reject = null; 93 if (reject) reject(new Error(status.textContent)); 94 }, 95 "error-callback": () => { 96 status.hidden = false; 97 status.textContent = "ã»ãã¥ãªãã£ç¢ºèªãå®äºã§ãã¾ããã§ãããããä¸åº¦ã試ããã ããã"; 98 const reject = state.reject; 99 state.resolve = null; 100 state.reject = null; 101 if (reject) reject(new Error(status.textContent)); 102 } 103 }); 104 return state; 105 }; 106 107 const turnstileToken = (state) => {
108 const ready = window.turnstile.getResponse(state.widgetId); 109 if (ready) return Promise.resolve(ready); 110 return new Promise((resolve, reject) => { 111 state.resolve = resolve; 112 state.reject = reject; 113 window.turnstile.execute(state.widgetId); 114 }); 115 }; 116 117 const prepare = (form) => { 118 if (form.dataset.cloudflareMigrated === "true") return; 119 form.dataset.cloudflareMigrated = "true"; 120 const website = document.createElement("input"); 121 website.type = "text"; 122 website.name = "website"; 123 website.tabIndex = -1; 124 website.autocomplete = "off"; 125 website.setAttribute("aria-hidden", "true"); 126 website.style.cssText = "position:absolute;left:-10000px;width:1px;height:1px;overflow:hidden"; 127 form.append(website); 128 const started = document.createElement("input"); 129 started.type = "hidden"; 130 started.name = "_started_at"; 131 started.value = String(Date.now()); 132 form.append(started); 133 const formName = document.createElement("input"); 134 formName.type = "hidden"; 135 formName.name = "_form_name"; 136 formName.value = form.dataset.name || ""; 137 form.append(formName); 138 const elementId = document.createElement("input"); 139 elementId.type = "hidden"; 140 elementId.name = "_form_element_id"; 141 elementId.value = form.dataset.wfElementId || ""; 142 form.append(elementId); 143 securityStatus(form); 144 formSecurity.set(form, initializeTurnstile(form) 145 .then((state) => ({ state })) 146 .catch((error) => ({ error }))); 147 }; 148 149 const semanticFormData = (form) => { 150 const data = new FormData(); 151 for (const field of form.elements) { 152 if (!(field instanceof HTMLInputElement || field instanceof HTMLTextAreaElement || field instanceof HTMLSelectElement)) continue; 153 if (!field.name || field.disabled || field.type === "submit" || field.type === "button") continue; 154 if ((field.type === "radio" || field.type === "checkbox") && !field.checked) continue; 155 const name = field.dataset.name || field.name; 156 if (field instanceof HTMLInputElement && field.type === "file") { 157 for (const file of field.files || []) data.append(name, file); 158 } else if (field instanceof HTMLSelectElement && field.multiple) { 159 for (const option of field.selectedOptions) data.append(name, option.value); 160 } else data.append(name, field.value); 161 } 162 return data; 163 }; 164 165 document.addEventListener("DOMContentLoaded", () => { 166 document.querySelectorAll(".w-form form").forEach(prepare); 167 }); 168 169 document.addEventListener("submit", async (event) => { 170 const form = event.target; 171 if (!(form instanceof HTMLFormElement) || !form.closest(".w-form")) return; 172 event.preventDefault(); 173 event.stopImmediatePropagation(); 174 prepare(form); 175 if (form.dataset.cloudflarePending === "true") return; 176 form.dataset.cloudflarePending = "true"; 177 form.setAttribute("aria-busy", "true"); 178 const submitControls = [...form.querySelectorAll('[type="submit"]')]; 179 const disabledBefore = submitControls.map((control) => control.disabled); 180 submitControls.forEach((control) => { control.disabled = true; }); 181 let state; 182 let succeeded = false; 183 try { 184 const security = await formSecurity.get(form); 185 if (security.error) throw security.error; 186 state = security.state; 187 const token = await turnstileToken(state); 188 const body = semanticFormData(form); 189 body.set("cf-turnstile-response", token); 190 const response = await fetch("/api/forms/submit", { method: "POST", body, headers: { accept: "application/json" } }); 191 const result = await response.json().catch(() => ({})); 192 if (!response.ok) { 193 const retryAfter = Number(result.retryAfterSeconds || response.headers.get("retry-after") || 0); 194 const guidance = response.status === 429 && retryAfter > 0 ? `ï¼ç´${Math.max(1, Math.ceil(retryAfter / 60))}åå¾ã«å度ã試ããã ãããï¼` : ""; 195 throw new Error(`${result.error || "éä¿¡ã«å¤±æãã¾ãããæéãããã¦å度ã試ããã ããã"}${guidance}`); 196 } 197 succeeded = true; 198 showState(form, true); 199 } catch (error) { 200 showState(form, false, error instanceof Error ? error.message : "éä¿¡ã«å¤±æãã¾ããã");
201 if (state?.widgetId != null && window.turnstile) window.turnstile.reset(state.widgetId); 202 } finally { 203 if (!succeeded) { 204 delete form.dataset.cloudflarePending; 205 form.removeAttribute("aria-busy"); 206 submitControls.forEach((control, index) => { control.disabled = disabledBefore[index]; }); 207 } 208 } 209 }, true); 210})();
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.