import { post } from "./api.js"; import { h, replace, showAlert } from "./dom.js"; export const imageDrafts = new Map(); const imageTypes = ["image/png", "image/jpeg", "image/gif", "image/webp"]; const maxImageBytes = 5 << 20; export function imageTray(drop, input, key, onCount) { const el = h("div", { class: "compose-images" }); const render = () => { const imgs = imageDrafts.get(key) ?? []; onCount(imgs.length); el.hidden = imgs.length === 0; replace(el, ...imgs.map((img) => { const remove = h("button", { type: "button", class: "remove", title: "Remove image" }, "×"); remove.onclick = () => { URL.revokeObjectURL(img.url); const rest = (imageDrafts.get(key) ?? []).filter((i) => i !== img); if (rest.length > 0) { imageDrafts.set(key, rest); } else { imageDrafts.delete(key); } render(); }; return h("div", { class: "thumb" }, h("img", { src: img.url, alt: "attached image" }), remove); })); }; const add = (files) => { const added = []; for (const f of files) { if (!imageTypes.includes(f.type)) { void showAlert(`${f.name || "That file"} isn't a PNG, JPEG, GIF or WebP image.`); continue; } if (f.size > maxImageBytes) { void showAlert(`${f.name || "That image"} is over ${maxImageBytes >> 20} MiB.`); continue; } added.push({ file: f, url: URL.createObjectURL(f) }); } if (added.length === 0) { return false; } imageDrafts.set(key, [...(imageDrafts.get(key) ?? []), ...added]); render(); return true; }; input.addEventListener("paste", (e) => { const files = [...(e.clipboardData?.files ?? [])].filter((f) => f.type.startsWith("image/")); if (files.length > 0) { e.preventDefault(); add(files); } }); drop.addEventListener("dragover", (e) => { if (e.dataTransfer?.types.includes("Files")) { e.preventDefault(); drop.classList.add("dropping"); } }); drop.addEventListener("dragleave", (e) => { if (!drop.contains(e.relatedTarget)) { drop.classList.remove("dropping"); } }); drop.addEventListener("drop", (e) => { drop.classList.remove("dropping"); const files = [...(e.dataTransfer?.files ?? [])]; if (files.length > 0) { e.preventDefault(); add(files); } }); render(); return { el, take: () => { const imgs = imageDrafts.get(key) ?? []; imageDrafts.delete(key); render(); return imgs; }, restore: (imgs) => { if (imgs.length > 0) { imageDrafts.set(key, [...imgs, ...(imageDrafts.get(key) ?? [])]); } render(); }, }; } export async function uploadImages(imgs) { if (imgs.length === 0) { return undefined; } const ids = []; for (const img of imgs) { const blob = await post("/api/blobs", { body: img.file }); ids.push(blob.id); } return ids; } export function releaseImages(imgs) { for (const img of imgs) { URL.revokeObjectURL(img.url); } } //# sourceMappingURL=images.js.map