···18 let scan = scanIndex(tx);
19 return scan.eav(blockID, "block/footnote");
20 });
21- let lastPosition =
22- existingFootnotes.length > 0
23- ? existingFootnotes
24- .map((f) => f.data.position)
25- .sort()
26- .at(-1)!
27- : null;
28- let position = generateKeyBetween(lastPosition, null);
000000000000000000000000000002930 await rep.mutate.createFootnote({
31 footnoteEntityID,
···35 });
3637 let node = schema.nodes.footnote.create({ footnoteEntityID });
38- let { from } = view.state.selection;
39 let tr = view.state.tr.insert(from, node);
40 view.dispatch(tr);
41
···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);
5859 await rep.mutate.createFootnote({
60 footnoteEntityID,
···64 });
6566 let node = schema.nodes.footnote.create({ footnoteEntityID });
067 let tr = view.state.tr.insert(from, node);
68 view.dispatch(tr);
69