a tool for shared writing and social publishing
at main 71 lines 2.2 kB view raw
1import { EditorView } from "prosemirror-view"; 2import { v7 } from "uuid"; 3import { Replicache } from "replicache"; 4import type { ReplicacheMutators } from "src/replicache"; 5import { schema } from "./schema"; 6import { generateKeyBetween } from "fractional-indexing"; 7import { scanIndex } from "src/replicache/utils"; 8 9export async function insertFootnote( 10 view: EditorView, 11 blockID: string, 12 rep: Replicache<ReplicacheMutators>, 13 permissionSet: string, 14) { 15 let footnoteEntityID = v7(); 16 17 let existingFootnotes = await rep.query(async (tx) => { 18 let scan = scanIndex(tx); 19 return scan.eav(blockID, "block/footnote"); 20 }); 21 22 // Build a map from footnoteEntityID to its fractional-index position 23 let positionByEntityID: Record<string, string> = {}; 24 for (let f of existingFootnotes) { 25 positionByEntityID[f.data.value] = f.data.position; 26 } 27 28 // Find footnotes that appear before and after the insertion point in the text 29 let { from } = view.state.selection; 30 let beforePosition: string | null = null; 31 let afterPosition: string | null = null; 32 let foundInsertionPoint = false; 33 34 view.state.doc.descendants((node, pos) => { 35 if (node.type.name === "footnote") { 36 let entityID = node.attrs.footnoteEntityID; 37 let p = positionByEntityID[entityID]; 38 if (p !== undefined) { 39 if (pos < from) { 40 // This footnote is before the insertion point 41 if (beforePosition === null || p > beforePosition) { 42 beforePosition = p; 43 } 44 } else { 45 // This footnote is at or after the insertion point 46 if (!foundInsertionPoint) { 47 afterPosition = p; 48 foundInsertionPoint = true; 49 } else if (afterPosition !== null && p < afterPosition) { 50 afterPosition = p; 51 } 52 } 53 } 54 } 55 }); 56 57 let position = generateKeyBetween(beforePosition, afterPosition); 58 59 await rep.mutate.createFootnote({ 60 footnoteEntityID, 61 blockID, 62 permission_set: permissionSet, 63 position, 64 }); 65 66 let node = schema.nodes.footnote.create({ footnoteEntityID }); 67 let tr = view.state.tr.insert(from, node); 68 view.dispatch(tr); 69 70 return footnoteEntityID; 71}