git ssb

16+

Dominic / patchbay



Tree: 4f805f442d6775913d8beb9c969b08250e508767

Files: 4f805f442d6775913d8beb9c969b08250e508767 / router / html / page / thread.js

3365 bytesRaw
1var { h } = require('mutant')
2const nest = require('depnest')
3const pull = require('pull-stream')
4const sort = require('ssb-sort')
5const ref = require('ssb-ref')
6
7exports.gives = nest('router.html.page')
8
9// TODO - seperate out public and private thread rendering
10exports.needs = nest({
11 // 'feed.pull.public': 'first',
12 'keys.sync.id': 'first',
13 'main.html.scroller': 'first',
14 message: {
15 html: {
16 compose: 'first',
17 render: 'first'
18 },
19 'async.name': 'first',
20 'sync.unbox': 'first'
21 },
22 sbot: {
23 'async.get': 'first',
24 'pull.links': 'first'
25 }
26})
27
28exports.create = function (api) {
29 return nest('router.html.page', threadPage)
30
31 function threadPage (id) {
32 if (!ref.isMsg(id)) return
33
34 var meta = {
35 type: 'post',
36 root: id,
37 branch: id // mutated when thread is loaded.
38 }
39 const composer = api.message.html.compose({
40 meta,
41 placeholder: 'Write a reply',
42 shrink: false
43 })
44 const { container, content } = api.main.html.scroller({ append: composer })
45 api.message.async.name(id, (err, name) => {
46 if (err) throw err
47 container.title = name
48 })
49
50 // TODO rewrite with obs
51 pull(
52 api.sbot.pull.links({ rel: 'root', dest: id, keys: true, old: false }),
53 pull.drain(msg => loadThread(), () => {}) // redraw thread
54 )
55
56 function loadThread () {
57 getThread(id, (err, thread) => {
58 if (err) return content.appendChild(h('pre', err.stack))
59
60 // would probably be better keep an id for each message element
61 // (i.e. message key) and then update it if necessary.
62 // also, it may have moved (say, if you received a missing message)
63 content.innerHTML = ''
64
65 // decrypt
66 thread = thread.map(msg => {
67 return typeof msg.value.content === 'string'
68 ? api.message.sync.unbox(msg)
69 : msg
70 })
71
72 sort(thread)
73 .map(api.message.html.render)
74 .filter(Boolean)
75 .forEach(el => content.appendChild(el))
76
77 var branches = sort.heads(thread)
78 meta.branch = branches.length > 1 ? branches : branches[0]
79 meta.root = thread[0].value.content.root || thread[0].key
80 meta.channel = thread[0].value.content.channel
81
82 if (meta.channel) {
83 const channelInput = composer.querySelector('input')
84 channelInput.value = `#${meta.channel}`
85 channelInput.disabled = true
86 }
87
88 const priv = thread[0].value['private']
89 const recps = thread[0].value.content.recps
90 if (priv) {
91 if (recps) meta.recps = recps
92 else meta.recps = [thread[0].value.author, api.keys.sync.id()]
93 }
94 })
95 }
96
97 loadThread()
98
99 return container
100 }
101
102 function getThread (root, cb) {
103 // in this case, it's inconvienent that panel only takes
104 // a stream. maybe it would be better to accept an array?
105
106 api.sbot.async.get(root, (err, value) => {
107 if (err) return cb(err)
108
109 var msg = { key: root, value }
110 // if (value.content.root) return getThread(value.content.root, cb)
111
112 pull(
113 api.sbot.pull.links({ rel: 'root', dest: root, values: true, keys: true }),
114 pull.collect((err, ary) => {
115 if (err) return cb(err)
116 ary.unshift(msg)
117
118 cb(null, ary)
119 })
120 )
121 })
122 }
123}
124
125

Built with git-ssb-web