a demonstration replicated social networking web app built with anproto
wiredove.net/
social
ed25519
protocols
1import { normalizeTimestamp } from './utils.js'
2
3const timestampInsertState = new WeakMap()
4
5const buildTimestampState = (container) => {
6 const entries = []
7 const children = Array.from(container.children)
8 for (const child of children) {
9 if (!child || !child.dataset) { continue }
10 const childTs = normalizeTimestamp(child.dataset.ts)
11 if (!childTs) { continue }
12 entries.push({ ts: childTs, node: child })
13 }
14 entries.sort((a, b) => b.ts - a.ts)
15 return {
16 entries,
17 childCount: children.length
18 }
19}
20
21const getTimestampState = (container) => {
22 const existing = timestampInsertState.get(container)
23 const currentChildCount = container.children.length
24 if (existing && existing.childCount === currentChildCount) {
25 return existing
26 }
27 const next = buildTimestampState(container)
28 timestampInsertState.set(container, next)
29 return next
30}
31
32const findInsertIndex = (entries, stamp) => {
33 let lo = 0
34 let hi = entries.length
35 while (lo < hi) {
36 const mid = Math.floor((lo + hi) / 2)
37 if (entries[mid].ts >= stamp) {
38 lo = mid + 1
39 } else {
40 hi = mid
41 }
42 }
43 return lo
44}
45
46const removeEntryForNode = (entries, node) => {
47 const idx = entries.findIndex((entry) => entry.node === node)
48 if (idx >= 0) {
49 entries.splice(idx, 1)
50 }
51}
52
53export const insertByTimestamp = (container, hash, ts, hashFn) => {
54 if (!container || !hash) { return null }
55 const stamp = normalizeTimestamp(ts)
56 if (!stamp) { return null }
57 const state = getTimestampState(container)
58 const entries = state.entries
59 let div = document.getElementById(hash)
60 if (!div) {
61 div = hashFn(hash)
62 }
63 if (!div) { return null }
64 div.dataset.ts = stamp.toString()
65 if (div.parentNode === container) {
66 removeEntryForNode(entries, div)
67 container.removeChild(div)
68 }
69 const insertIdx = findInsertIndex(entries, stamp)
70 const beforeNode = insertIdx < entries.length ? entries[insertIdx].node : null
71 if (beforeNode && beforeNode.parentNode === container) {
72 container.insertBefore(div, beforeNode)
73 } else {
74 const sentinel = container.querySelector('.scroll-sentinel')
75 if (sentinel && sentinel.parentNode === container) {
76 container.insertBefore(div, sentinel)
77 } else {
78 container.appendChild(div)
79 }
80 }
81 entries.splice(insertIdx, 0, { ts: stamp, node: div })
82 state.childCount = container.children.length
83 return div
84}