(file, confirmBtn, previewEl, statusEl)
| 1714 | } |
| 1715 | |
| 1716 | async function uploadReference(file, confirmBtn, previewEl, statusEl) { |
| 1717 | if (!file.type.startsWith("image/")) { |
| 1718 | statusEl.textContent = t("upload.only_images"); |
| 1719 | return null; |
| 1720 | } |
| 1721 | |
| 1722 | confirmBtn.disabled = true; |
| 1723 | statusEl.textContent = t("upload.uploading"); |
| 1724 | |
| 1725 | const formData = new FormData(); |
| 1726 | formData.append("file", file); |
| 1727 | |
| 1728 | try { |
| 1729 | const response = await fetch("/api/upload", { |
| 1730 | method: "POST", |
| 1731 | body: formData, |
| 1732 | }); |
| 1733 | |
| 1734 | if (!response.ok) { |
| 1735 | const text = await response.text(); |
| 1736 | throw new Error(text || "Upload failed"); |
| 1737 | } |
| 1738 | |
| 1739 | const data = await response.json(); |
| 1740 | const isImport = statusEl?.id === "importFigureStatus"; |
| 1741 | statusEl.textContent = t( |
| 1742 | isImport ? "upload.uploaded_stage1" : "upload.uploaded_reference", |
| 1743 | { name: data.name } |
| 1744 | ); |
| 1745 | if (previewEl) { |
| 1746 | previewEl.src = data.url || ""; |
| 1747 | previewEl.classList.add("visible"); |
| 1748 | } |
| 1749 | return { |
| 1750 | path: data.path || null, |
| 1751 | url: data.url || "", |
| 1752 | name: data.name || "", |
| 1753 | }; |
| 1754 | } catch (err) { |
| 1755 | statusEl.textContent = err.message || t("upload.upload_failed"); |
| 1756 | return null; |
| 1757 | } finally { |
| 1758 | confirmBtn.disabled = false; |
| 1759 | } |
| 1760 | } |
| 1761 | |
| 1762 | async function initCanvasPage() { |
| 1763 | const params = new URLSearchParams(window.location.search); |
no test coverage detected