Files: 625f7819b686f7a94242c8ea945e8b013dbbed7b / app / page / thread.js
3714 bytesRaw
1 | const { h, Struct, Value, when, computed, map, resolve, onceTrue } = require('mutant') |
2 | const nest = require('depnest') |
3 | const get = require('lodash/get') |
4 | const { isFeed } = require('ssb-ref') |
5 | |
6 | exports.gives = nest('app.page.thread') |
7 | |
8 | exports.needs = nest({ |
9 | 'about.html.avatar': 'first', |
10 | 'app.html.scroller': 'first', |
11 | 'app.html.tabs': 'first', |
12 | 'app.sync.locationId': 'first', |
13 | 'contact.obs.following': 'first', |
14 | 'feed.obs.thread': 'first', |
15 | 'keys.sync.id': 'first', |
16 | 'message.html.compose': 'first', |
17 | 'message.html.render': 'first', |
18 | 'message.async.name': 'first', |
19 | 'message.sync.unbox': 'first', |
20 | 'sbot.async.get': 'first', |
21 | 'sbot.pull.links': 'first' |
22 | }) |
23 | |
24 | exports.create = function (api) { |
25 | return nest('app.page.thread', threadPage) |
26 | |
27 | function threadPage (location) { |
28 | const root = get(location, 'value.content.root', location.key) |
29 | const msg = location.key |
30 | if (msg !== root) scrollDownToMessage(msg) |
31 | |
32 | const myId = api.keys.sync.id() |
33 | const ImFollowing = api.contact.obs.following(myId) |
34 | const { messages, isPrivate, rootId, lastId, channel, recps } = api.feed.obs.thread(root) |
35 | const meta = Struct({ |
36 | type: 'post', |
37 | root: rootId, |
38 | branch: lastId, |
39 | channel, |
40 | recps |
41 | }) |
42 | const contactWarning = Value(false) |
43 | const header = when(isPrivate, [ |
44 | h('section.recipients', map(recps, r => { |
45 | const id = isFeed(r) ? r : r.link |
46 | |
47 | var className |
48 | if (contactIsTrouble(id)) { |
49 | className = 'warning' |
50 | contactWarning.set(true) |
51 | } |
52 | return h('div', { className }, api.about.html.avatar(id)) |
53 | })), |
54 | when(contactWarning, |
55 | h('section.info -warning', 'There is a person in this thread you do not follow (bordered in red). If you think you know this person it might be worth checking their profile to confirm they are who they say they are.'), |
56 | h('section.info', 'These are the other participants in this thread. Once a private thread is started you cannot add people to it.') |
57 | ) |
58 | ]) |
59 | function contactIsTrouble (id) { |
60 | if (id === myId) return false |
61 | if (Array.from(ImFollowing()).includes(id)) return false |
62 | return true |
63 | } |
64 | |
65 | const composer = api.message.html.compose({ |
66 | meta, |
67 | location, |
68 | feedIdsInThread: computed(messages, msgs => msgs.map(m => m.value.author)), |
69 | placeholder: 'Write a reply', |
70 | shrink: false |
71 | }) |
72 | const content = map(messages, m => { |
73 | return api.message.html.render(resolve(m), {pageId: root}) |
74 | }) |
75 | const { container } = api.app.html.scroller({ prepend: header, content, append: composer }) |
76 | |
77 | container.classList.add('Thread') |
78 | container.title = msg |
79 | api.message.async.name(root, (err, name) => { |
80 | if (err) throw err |
81 | container.title = name |
82 | }) |
83 | |
84 | onceTrue(channel, ch => { |
85 | const channelInput = composer.querySelector('input') |
86 | channelInput.value = `#${ch}` |
87 | channelInput.disabled = true |
88 | }) |
89 | |
90 | container.scrollDownToMessage = scrollDownToMessage |
91 | return container |
92 | |
93 | function scrollDownToMessage (id) { |
94 | const locationId = api.app.sync.locationId(location) |
95 | const tabs = api.app.html.tabs() |
96 | locateKey() |
97 | |
98 | function locateKey () { |
99 | // wait till we're on the right page |
100 | if (tabs.currentPage().id !== locationId) return setTimeout(locateKey, 200) |
101 | |
102 | if (!tabs.currentPage().scroll) return setTimeout(locateKey, 200) |
103 | |
104 | tabs.currentPage().scroll('first') |
105 | const msg = tabs.currentPage().querySelector(`[data-id='${id}']`) |
106 | if (!msg) return setTimeout(locateKey, 200) |
107 | |
108 | ;(msg.scrollIntoViewIfNeeded || msg.scrollIntoView).call(msg) |
109 | msg.focus() |
110 | } |
111 | } |
112 | } |
113 | } |
114 |
Built with git-ssb-web