101 lines
3.0 KiB
JavaScript
101 lines
3.0 KiB
JavaScript
// 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]}`;
|
|
}
|
|
}
|
|
}
|
|
}
|