git ssb

16+

Dominic / patchbay



Tree: a41e049ca3755ddfd97e7f53c9da830711e636f1

Files: a41e049ca3755ddfd97e7f53c9da830711e636f1 / app / page / thread.js

3614 bytesRaw
1const { h, Struct, Value, when, computed, map, resolve, onceTrue } = require('mutant')
2const nest = require('depnest')
3const get = require('lodash/get')
4const { isFeed } = require('ssb-ref')
5
6exports.gives = nest('app.page.thread')
7
8exports.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
24exports.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 = h('section.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(msg, (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 return container
91
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 tabs.currentPage().scroll('first')
103 const msg = tabs.currentPage().querySelector(`[data-id='${id}']`)
104 if (msg === null) return setTimeout(locateKey, 200)
105
106 ;(msg.scrollIntoViewIfNeeded || msg.scrollIntoView).call(msg)
107 msg.focus()
108 }
109 }
110 }
111}
112
113

Built with git-ssb-web