Files: 7e9e00e59396b9e019862208410ce294016e61ae / router / html / page / thread.js
3369 bytesRaw
1 | var { h } = require('mutant') |
2 | const nest = require('depnest') |
3 | const pull = require('pull-stream') |
4 | const sort = require('ssb-sort') |
5 | const ref = require('ssb-ref') |
6 | |
7 | exports.gives = nest('router.html.page') |
8 | |
9 | exports.needs = nest({ |
10 | // 'feed.pull.public': 'first', |
11 | 'keys.sync.id': 'first', |
12 | 'main.html.scroller': 'first', |
13 | message: { |
14 | html: { |
15 | compose: 'first', |
16 | render: 'first' |
17 | }, |
18 | 'async.name': 'first', |
19 | 'sync.unbox': 'first' |
20 | }, |
21 | sbot: { |
22 | 'async.get': 'first', |
23 | 'pull.links': 'first' |
24 | } |
25 | }) |
26 | |
27 | exports.create = function (api) { |
28 | return nest('router.html.page', threadPage) |
29 | |
30 | function threadPage (id) { |
31 | if (!ref.isMsg(id)) return |
32 | |
33 | var meta = { |
34 | type: 'post', |
35 | root: id, |
36 | branch: id // mutated when thread is loaded. |
37 | } |
38 | const composer = api.message.html.compose({ |
39 | meta, |
40 | placeholder: 'Write a reply', |
41 | shrink: false |
42 | }) |
43 | const { container, content } = api.main.html.scroller({ append: composer }) |
44 | api.message.async.name(id, (err, name) => { |
45 | if (err) throw err |
46 | container.title = name |
47 | }) |
48 | |
49 | // TODO rewrite with obs |
50 | pull( |
51 | api.sbot.pull.links({ rel: 'root', dest: id, keys: true, old: false }), |
52 | pull.drain(msg => loadThread(), () => {}) // redraw thread |
53 | ) |
54 | |
55 | function loadThread () { |
56 | getThread(id, (err, thread) => { |
57 | if (err) return content.appendChild(h('pre', err.stack)) |
58 | |
59 | // would probably be better keep an id for each message element |
60 | // (i.e. message key) and then update it if necessary. |
61 | // also, it may have moved (say, if you received a missing message) |
62 | content.innerHTML = '' |
63 | |
64 | // decrypt |
65 | thread = thread.map(msg => { |
66 | return typeof msg.value.content === 'string' |
67 | ? api.message.sync.unbox(msg) |
68 | : msg |
69 | }) |
70 | |
71 | sort(thread) |
72 | .map(api.message.html.render) |
73 | .filter(Boolean) |
74 | .forEach(el => content.appendChild(el)) |
75 | |
76 | var branches = sort.heads(thread) |
77 | meta.branch = branches.length > 1 ? branches : branches[0] |
78 | meta.root = thread[0].value.content.root || thread[0].key |
79 | meta.channel = thread[0].value.content.channel |
80 | |
81 | // TODO - re-enable with channel-picker |
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