{"version":3,"file":"turn-json.js","names":["form","turnInput","error","copyButton","downloadButton","showError","message","fetchRequest","url","key","value","res","body","name","whileBusy","work","download","a","filename","request","r","err","fetchError","text","write","t"],"sources":["src/turn-json.ts"],"sourcesContent":["// Turn JSON form on the game page (routes/game/view.rs).\n//\n// Without JS the form is a plain GET whose attachment response downloads in\n// place, and an error (a 404 like \"eliminated on turn N...\") replaces the page\n// with its plain-text reason. This script layers on top of that:\n// - keeps the turn input on the turn the board iframe is showing,\n// - downloads through fetch, so errors show inline under the form,\n// - reveals a Copy button that puts the JSON on the clipboard.\n(function () {\n  \"use strict\";\n  const form = document.getElementById(\"move-request-form\") as HTMLFormElement | null;\n  if (!form) return;\n  const turnInput = document.getElementById(\"move-request-turn\") as HTMLInputElement;\n  const error = document.getElementById(\"move-request-error\") as HTMLElement;\n  const copyButton = document.getElementById(\"move-request-copy\") as HTMLButtonElement;\n  const downloadButton = form.querySelector<HTMLButtonElement>(\"button[type=submit]\")!;\n\n  // The board posts {event: \"TURN\", data: {turn}} on every playback change.\n  window.addEventListener(\"message\", (e) => {\n    if (e.origin !== \"https://board.battlesnake.com\") return;\n    if (e.source !== document.querySelector<HTMLIFrameElement>(\"#board-viewer\")?.contentWindow) return;\n    if (e.data && e.data.event === \"TURN\") turnInput.value = String(e.data.data.turn);\n  });\n\n  function showError(message: string): void {\n    error.textContent = message;\n    error.hidden = false;\n  }\n\n  // The request for the form's turn and snake. Rejects with the server's\n  // plain-text reason, or a network message.\n  async function fetchRequest() {\n    error.hidden = true;\n    const url = form!.action + \"?\" + new URLSearchParams(Array.from(new FormData(form!).entries()).map(([key, value]) => [key, String(value)]));\n    let res;\n    try {\n      res = await fetch(url);\n    } catch (e) {\n      throw new Error(\"Couldn't reach Battlesnake. Try again.\");\n    }\n    const body = await res.text();\n    if (!res.ok) throw new Error(body || `Request failed (${res.status}).`);\n    const name = /filename=\"([^\"]+)\"/.exec(res.headers.get(\"Content-Disposition\") || \"\");\n    return { body, filename: name ? name[1] : \"move-request.json\" };\n  }\n\n  async function whileBusy(button: HTMLButtonElement, work: Promise<unknown>): Promise<void> {\n    button.disabled = true;\n    try {\n      await work;\n    } finally {\n      button.disabled = false;\n    }\n  }\n\n  function download(body: string, filename: string): void {\n    const a = document.createElement(\"a\");\n    a.href = URL.createObjectURL(new Blob([body], { type: \"application/json\" }));\n    a.download = filename;\n    document.body.appendChild(a);\n    a.click();\n    a.remove();\n    setTimeout(() => URL.revokeObjectURL(a.href), 10000);\n  }\n\n  form.addEventListener(\"submit\", (e) => {\n    e.preventDefault();\n    const request = fetchRequest();\n    whileBusy(downloadButton, request).catch(() => {});\n    request.then((r) => download(r.body, r.filename), (err) => showError(err.message));\n  });\n\n  if (!window.isSecureContext || !navigator.clipboard) return;\n  copyButton.hidden = false;\n  copyButton.addEventListener(\"click\", () => {\n    if (!form.reportValidity()) return;\n    let fetchError: Error | null = null;\n    const text = fetchRequest().then(\n      (r) => r.body,\n      (err: Error) => {\n        fetchError = err;\n        throw err;\n      },\n    );\n    // Safari only allows clipboard writes during the click itself, so hand it\n    // an item that resolves once the fetch does.\n    const write = window.ClipboardItem && navigator.clipboard.write\n      ? navigator.clipboard.write([\n        new ClipboardItem({ \"text/plain\": text.then((t) => new Blob([t], { type: \"text/plain\" })) }),\n      ])\n      : text.then((t) => navigator.clipboard.writeText(t));\n    whileBusy(copyButton, write).then(\n      () => {\n        copyButton.textContent = \"Copied!\";\n        setTimeout(() => { copyButton.textContent = \"Copy\"; }, 1500);\n      },\n      () => showError(fetchError ? (fetchError as Error).message : \"Couldn't copy to the clipboard. Try Download.\"),\n    );\n  });\n})();\n"],"mappings":"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"}