// URL prefill UI; output is always built with DOM nodes so remote text never becomes markup. const csrf = () => document.cookie .split("; ") .find((v) => v.startsWith("rp_csrf=")) ?.split("=")[1] || ""; function message(target, text, error = false) { const p = document.createElement("p"); p.textContent = text; if (error) p.style.color = "#a8371a"; target.replaceChildren(p); } export function initPrefillPanel({ state, renderFormFromPlan, recompute }) { const urlInput = document.getElementById("prefill-url"), overwriteBox = document.getElementById("prefill-overwrite"), goBtn = document.getElementById("prefill-go"), undoBtn = document.getElementById("prefill-undo"), resultEl = document.getElementById("prefill-result"); let snapshot = null; goBtn.addEventListener("click", async () => { const url = urlInput.value.trim(); if (!url) return; goBtn.disabled = true; message(resultEl, "Fetching…"); try { const res = await fetch("/api/prefill", { method: "POST", headers: { "content-type": "application/json", "x-csrf-token": csrf() }, body: JSON.stringify({ url }), }); const body = await res.json(); if (!body.ok) { message(resultEl, body.error ?? body.code, true); return; } snapshot = structuredClone(state.plan); let applied = 0; for (const [id, value] of Object.entries(body.fields ?? {})) { if (!overwriteBox.checked && (state.plan.fields[id] ?? "") !== "") continue; state.plan.fields[id] = value; applied++; } renderFormFromPlan(); markPrefilled(Object.keys(body.fields ?? {}), body.provenance ?? {}); recompute(); undoBtn.disabled = false; const p = document.createElement("p"), link = document.createElement("a"); link.href = body.source.finalUrl; link.target = "_blank"; link.rel = "noopener"; link.textContent = body.source.finalUrl; p.append( `Applied ${applied} field${applied === 1 ? "" : "s"} from `, link, ".", ); const children = [p]; if (body.warnings?.length) { const ul = document.createElement("ul"); ul.className = "warnings"; for (const warning of body.warnings) { const li = document.createElement("li"); li.textContent = warning; ul.append(li); } children.push(ul); } resultEl.replaceChildren(...children); } catch (err) { message(resultEl, err.message, true); } finally { goBtn.disabled = false; } }); undoBtn.addEventListener("click", () => { if (!snapshot) return; state.plan = snapshot; snapshot = null; undoBtn.disabled = true; renderFormFromPlan(); for (const el of document.querySelectorAll(".prefilled")) { el.classList.remove("prefilled"); el.removeAttribute("title"); } recompute(); message(resultEl, "Prefill undone."); }); function markPrefilled(ids, provenance) { for (const id of ids) { const el = document.querySelector(`[name="${CSS.escape(id)}"]`); if (el) { el.classList.add("prefilled"); if (provenance[id]) el.title = `from: ${provenance[id]}`; } } } }