a tool for shared writing and social publishing
at feature/footnotes 138 lines 4.2 kB view raw
1import { Replicache } from "replicache"; 2import { ReplicacheMutators } from "src/replicache"; 3import { useUIState } from "src/useUIState"; 4import { scanIndex } from "src/replicache/utils"; 5import { getBlocksWithType } from "src/replicache/getBlocks"; 6import { focusBlock } from "src/utils/focusBlock"; 7import { UndoManager } from "src/undoManager"; 8 9export async function deleteBlock( 10 entities: string[], 11 rep: Replicache<ReplicacheMutators>, 12 undoManager?: UndoManager, 13) { 14 // get what pagess we need to close as a result of deleting this block 15 let pagesToClose = [] as string[]; 16 17 for (let entity of entities) { 18 let [type] = await rep.query((tx) => 19 scanIndex(tx).eav(entity, "block/type"), 20 ); 21 if (type.data.value === "card") { 22 let [childPages] = await rep?.query( 23 (tx) => scanIndex(tx).eav(entity, "block/card") || [], 24 ); 25 pagesToClose = [childPages?.data.value]; 26 } 27 if (type.data.value === "mailbox") { 28 let [archive] = await rep?.query( 29 (tx) => scanIndex(tx).eav(entity, "mailbox/archive") || [], 30 ); 31 let [draft] = await rep?.query( 32 (tx) => scanIndex(tx).eav(entity, "mailbox/draft") || [], 33 ); 34 pagesToClose = [archive?.data.value, draft?.data.value]; 35 } 36 } 37 38 // the next and previous blocks in the block list 39 // if the focused thing is a page and not a block, return 40 let focusedBlock = useUIState.getState().focusedEntity; 41 let parent = 42 focusedBlock?.entityType === "page" 43 ? focusedBlock.entityID 44 : focusedBlock?.parent; 45 46 if (parent) { 47 let parentType = await rep?.query((tx) => 48 scanIndex(tx).eav(parent, "page/type"), 49 ); 50 // if the page is a canvas, focus the page 51 if (parentType[0]?.data.value === "canvas") { 52 useUIState 53 .getState() 54 .setFocusedBlock({ entityType: "page", entityID: parent }); 55 useUIState.getState().setSelectedBlocks([]); 56 } else { 57 // if the page is a doc, focus the previous block (or if there isn't a prev block, focus the next block) 58 let siblings = 59 (await rep?.query((tx) => getBlocksWithType(tx, parent))) || []; 60 61 let selectedBlocks = useUIState.getState().selectedBlocks; 62 let firstSelected = selectedBlocks[0]; 63 let lastSelected = selectedBlocks[entities.length - 1]; 64 65 let prevBlock = 66 siblings?.[ 67 siblings.findIndex((s) => s.value === firstSelected?.value) - 1 68 ]; 69 let prevBlockType = await rep?.query((tx) => 70 scanIndex(tx).eav(prevBlock?.value, "block/type"), 71 ); 72 73 let nextBlock = 74 siblings?.[ 75 siblings.findIndex((s) => s.value === lastSelected.value) + 1 76 ]; 77 let nextBlockType = await rep?.query((tx) => 78 scanIndex(tx).eav(nextBlock?.value, "block/type"), 79 ); 80 81 if (prevBlock) { 82 useUIState.getState().setSelectedBlock({ 83 value: prevBlock.value, 84 parent: prevBlock.parent, 85 }); 86 87 focusBlock( 88 { 89 value: prevBlock.value, 90 type: prevBlockType?.[0].data.value, 91 parent: prevBlock.parent, 92 }, 93 { type: "end" }, 94 ); 95 } else { 96 useUIState.getState().setSelectedBlock({ 97 value: nextBlock.value, 98 parent: nextBlock.parent, 99 }); 100 101 focusBlock( 102 { 103 value: nextBlock.value, 104 type: nextBlockType?.[0]?.data.value, 105 parent: nextBlock.parent, 106 }, 107 { type: "start" }, 108 ); 109 } 110 } 111 } 112 113 // close the pages 114 pagesToClose.forEach((page) => page && useUIState.getState().closePage(page)); 115 116 // Clean up footnotes from blocks being deleted 117 for (let entity of entities) { 118 let footnotes = await rep.query((tx) => 119 scanIndex(tx).eav(entity, "block/footnote"), 120 ); 121 for (let fn of footnotes) { 122 await rep.mutate.deleteFootnote({ 123 footnoteEntityID: fn.data.value, 124 blockID: entity, 125 }); 126 } 127 } 128 129 await Promise.all( 130 entities.map((entity) => 131 rep?.mutate.removeBlock({ 132 blockEntity: entity, 133 }), 134 ), 135 ); 136 137 undoManager && undoManager.endGroup(); 138}