Files: 70fb8c8a016f2f59cb6933d6505c3d65dd426581 / router / html / page / thread.js
3365 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 | // TODO - seperate out public and private thread rendering |
10 | exports.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 | |
28 | exports.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