| import { hydrateAttachment } from "/chatclient/media.js"; | |
| const DRAFT_KEY = "oapix.chatclient.draft"; | |
| export function loadDraft() { | |
| try { | |
| const saved = JSON.parse(window.localStorage.getItem(DRAFT_KEY) || "{}"); | |
| return { | |
| editorHtml: typeof saved.editorHtml === "string" ? saved.editorHtml : "", | |
| attachmentMode: saved.attachmentMode === "link" ? "link" : "upload", | |
| attachmentLinkType: saved.attachmentLinkType === "audio" ? "audio" : "image", | |
| attachmentLinkUrl: typeof saved.attachmentLinkUrl === "string" ? saved.attachmentLinkUrl : "", | |
| attachments: sanitizeAttachments(saved.attachments) | |
| }; | |
| } catch (_error) { | |
| window.localStorage.removeItem(DRAFT_KEY); | |
| return emptyDraft(); | |
| } | |
| } | |
| export function saveDraft({ editor, attachmentMode, attachmentLinkType, attachmentLinkUrl, attachments }) { | |
| try { | |
| window.localStorage.setItem(DRAFT_KEY, JSON.stringify({ | |
| editorHtml: editor.innerHTML, | |
| attachmentMode, | |
| attachmentLinkType, | |
| attachmentLinkUrl, | |
| attachments: attachments | |
| .map((attachment) => serializeAttachment(attachment)) | |
| .filter(Boolean) | |
| })); | |
| } catch (_error) { | |
| window.localStorage.setItem(DRAFT_KEY, JSON.stringify({ | |
| editorHtml: editor.innerHTML, | |
| attachmentMode, | |
| attachmentLinkType, | |
| attachmentLinkUrl, | |
| attachments: attachments | |
| .filter((attachment) => attachment.sourceType === "link") | |
| .map((attachment) => serializeAttachment(attachment)) | |
| .filter(Boolean) | |
| })); | |
| } | |
| } | |
| export function clearDraft() { | |
| window.localStorage.removeItem(DRAFT_KEY); | |
| } | |
| function sanitizeAttachments(value) { | |
| if (!Array.isArray(value)) { | |
| return []; | |
| } | |
| return value | |
| .map((attachment) => sanitizeAttachment(attachment)) | |
| .filter(Boolean); | |
| } | |
| function emptyDraft() { | |
| return { | |
| editorHtml: "", | |
| attachmentMode: "upload", | |
| attachmentLinkType: "image", | |
| attachmentLinkUrl: "", | |
| attachments: [] | |
| }; | |
| } | |
| function serializeAttachment(attachment) { | |
| if (!attachment || (attachment.kind !== "image" && attachment.kind !== "audio")) { | |
| return null; | |
| } | |
| if (attachment.sourceType === "link") { | |
| return { | |
| id: attachment.id, | |
| kind: attachment.kind, | |
| name: attachment.name, | |
| sizeLabel: attachment.sizeLabel, | |
| previewUrl: attachment.previewUrl, | |
| sourceType: "link", | |
| url: attachment.url | |
| }; | |
| } | |
| if (attachment.sourceType === "file" && typeof attachment.dataUrl === "string") { | |
| return { | |
| id: attachment.id, | |
| kind: attachment.kind, | |
| name: attachment.name, | |
| sizeLabel: attachment.sizeLabel, | |
| sourceType: "file", | |
| dataUrl: attachment.dataUrl, | |
| mimeType: attachment.mimeType | |
| }; | |
| } | |
| return null; | |
| } | |
| function sanitizeAttachment(attachment) { | |
| if (!attachment || (attachment.kind !== "image" && attachment.kind !== "audio") || typeof attachment.name !== "string") { | |
| return null; | |
| } | |
| if (attachment.sourceType === "link" && typeof attachment.url === "string") { | |
| return hydrateAttachment(attachment); | |
| } | |
| if (attachment.sourceType === "file" && typeof attachment.dataUrl === "string") { | |
| return hydrateAttachment(attachment); | |
| } | |
| return null; | |
| } | |