import { type } from "@heydovetail/assert"; import { NodeSpec } from "prosemirror-model"; import { AttrsSpec } from "../types"; import { AttachmentAttrs } from "./schema"; export type TypeName = "at"; export interface AttachmentAttrs { /** * "File Name" * * The name of the attachment's underlying file. */ fn?: string; /** * "ID" * * The backend storage ID for the attachment. */ id: string; /** * "Hide Preview" * * If `true`, indicates that no preview for the attachment should be * displayed, instead being displayed as a simple card. */ hp?: boolean; /** * "Natural Height" * * For image attachments, the height dimension (in display pixels). For * high-DPI images the value is in display dimensions (not bitmap dimensions). * For example given an `image@2x.jpg` file with size 120×30, the height is 15. */ nh?: number; /** * "Natural Width" * * For image attachments, the width dimension (in display pixels). For * high-DPI images the value is in display dimensions (not bitmap dimensions). * For example given an `image@2x.jpg` file with size 120×30, the width is 60. */ nw?: number; /** * "Type" * * The type of attachment. This is used to choose an appropriate attachment * previewer. It's also used to determine the size of a placeholder based on * the natural size. */ t?: string; } export const typeName: TypeName = "at"; export const domDataAttrType = "data-dovetail-type"; export const domDataAttrAttrs = "data-dovetail-attrs"; export const nodeSpec: NodeSpec = { attrs: type>({ fn: { default: undefined }, id: {}, hp: { default: undefined }, nh: { default: undefined }, nw: { default: undefined }, t: { default: undefined } }), draggable: true, group: "block", parseDOM: [ { tag: `div[${domDataAttrType}=${typeName}][${domDataAttrAttrs}]`, getAttrs: dom => { const element = dom as Element; // Validate attrs before accepting them. They could come from anywhere, // and be invalid (e.g. from a different version of the editor, or from // a name-clash). const attrsJson = element.getAttribute(domDataAttrAttrs); if (attrsJson !== null) { try { const { fn, id, hp, nh, nw, t } = JSON.parse(attrsJson) as { [P in keyof AttachmentAttrs]?: {} | null | string | number | boolean }; if (typeof id === "string") { return { id, ...(typeof fn === "string" ? { fn } : null), ...(typeof hp === "boolean" ? { hp } : null), ...(typeof nh === "number" && typeof nw === "number" ? { nh, nw } : null), ...(typeof t === "string" ? { t } : null) } as AttachmentAttrs; } } catch {} } return false; } } ], toDOM(node) { return ["div", { [domDataAttrType]: typeName, [domDataAttrAttrs]: JSON.stringify(node.attrs) }]; } };