a tool for shared writing and social publishing
at refactor/pub-settings 176 lines 5.9 kB view raw
1import { Block } from "components/Blocks/Block"; 2import { ReadTransaction } from "replicache"; 3import { Fact } from "src/replicache"; 4import { scanIndex, scanIndexLocal } from "src/replicache/utils"; 5 6function computeDisplayNumbers(blocks: Block[]): void { 7 let counters = new Map<string, number>(); 8 for (let block of blocks) { 9 if (!block.listData) { 10 counters.clear(); 11 continue; 12 } 13 if (block.listData.listStyle !== "ordered") continue; 14 let parent = block.listData.parent; 15 if (block.listData.listStart !== undefined) { 16 counters.set(parent, block.listData.listStart); 17 } else if (!counters.has(parent)) { 18 counters.set(parent, 1); 19 } 20 block.listData.displayNumber = counters.get(parent)!; 21 counters.set(parent, counters.get(parent)! + 1); 22 } 23} 24 25export const getBlocksWithType = async ( 26 tx: ReadTransaction, 27 entityID: string, 28) => { 29 let initialized = await tx.get("initialized"); 30 if (!initialized) return null; 31 let scan = scanIndex(tx); 32 let blocks = await scan.eav(entityID, "card/block"); 33 34 let result = ( 35 await Promise.all( 36 blocks 37 .sort((a, b) => { 38 if (a.data.position === b.data.position) return a.id > b.id ? 1 : -1; 39 return a.data.position > b.data.position ? 1 : -1; 40 }) 41 .map(async (b) => { 42 let type = (await scan.eav(b.data.value, "block/type"))[0]; 43 let isList = await scan.eav(b.data.value, "block/is-list"); 44 if (!type) return null; 45 // All lists use recursive structure 46 if (isList[0]?.data.value) { 47 const getChildren = async ( 48 root: Fact<"card/block">, 49 parent: string, 50 depth: number, 51 path: { depth: number; entity: string }[], 52 ): Promise<Block[]> => { 53 let children = ( 54 await scan.eav(root.data.value, "card/block") 55 ).sort((a, b) => (a.data.position > b.data.position ? 1 : -1)); 56 let type = (await scan.eav(root.data.value, "block/type"))[0]; 57 let checklist = await scan.eav( 58 root.data.value, 59 "block/check-list", 60 ); 61 let listStyle = (await scan.eav(root.data.value, "block/list-style"))[0]; 62 let listNumber = (await scan.eav(root.data.value, "block/list-number"))[0]; 63 if (!type) return []; 64 let newPath = [...path, { entity: root.data.value, depth }]; 65 let childBlocks = await Promise.all( 66 children.map((c) => 67 getChildren(c, root.data.value, depth + 1, newPath), 68 ), 69 ); 70 return [ 71 { 72 ...root.data, 73 factID: root.id, 74 type: type.data.value, 75 parent: b.entity, 76 listData: { 77 depth: depth, 78 parent, 79 path: newPath, 80 checklist: !!checklist[0], 81 checked: checklist[0]?.data.value, 82 listStyle: listStyle?.data.value, 83 listStart: listNumber?.data.value, 84 }, 85 }, 86 ...childBlocks.flat(), 87 ]; 88 }; 89 return getChildren(b, b.entity, 1, []); 90 } 91 return [ 92 { 93 ...b.data, 94 factID: b.id, 95 type: type.data.value, 96 parent: b.entity, 97 }, 98 ] as Block[]; 99 }), 100 ) 101 ) 102 .flat() 103 .filter((f) => f !== null); 104 105 computeDisplayNumbers(result); 106 return result; 107}; 108 109export const getBlocksWithTypeLocal = ( 110 initialFacts: Fact<any>[], 111 entityID: string, 112) => { 113 let scan = scanIndexLocal(initialFacts); 114 let blocks = scan.eav(entityID, "card/block"); 115 let result = blocks 116 .sort((a, b) => { 117 if (a.data.position === b.data.position) return a.id > b.id ? 1 : -1; 118 return a.data.position > b.data.position ? 1 : -1; 119 }) 120 .map((b) => { 121 let type = scan.eav(b.data.value, "block/type")[0]; 122 let isList = scan.eav(b.data.value, "block/is-list"); 123 if (!type) return null; 124 // All lists use recursive structure 125 if (isList[0]?.data.value) { 126 const getChildren = ( 127 root: Fact<"card/block">, 128 parent: string, 129 depth: number, 130 path: { depth: number; entity: string }[], 131 ): Block[] => { 132 let children = scan 133 .eav(root.data.value, "card/block") 134 .sort((a, b) => (a.data.position > b.data.position ? 1 : -1)); 135 let type = scan.eav(root.data.value, "block/type")[0]; 136 let listStyle = scan.eav(root.data.value, "block/list-style")[0]; 137 let listNumber = scan.eav(root.data.value, "block/list-number")[0]; 138 if (!type) return []; 139 let newPath = [...path, { entity: root.data.value, depth }]; 140 let childBlocks = children.map((c) => 141 getChildren(c, root.data.value, depth + 1, newPath), 142 ); 143 return [ 144 { 145 ...root.data, 146 factID: root.id, 147 type: type.data.value, 148 parent: b.entity, 149 listData: { 150 depth: depth, 151 parent, 152 path: newPath, 153 listStyle: listStyle?.data.value, 154 listStart: listNumber?.data.value, 155 }, 156 }, 157 ...childBlocks.flat(), 158 ]; 159 }; 160 return getChildren(b, b.entity, 1, []); 161 } 162 return [ 163 { 164 ...b.data, 165 factID: b.id, 166 type: type.data.value, 167 parent: b.entity, 168 }, 169 ] as Block[]; 170 }) 171 .flat() 172 .filter((f) => f !== null); 173 174 computeDisplayNumbers(result); 175 return result; 176};