git ssb

16+

Dominic / patchbay



Tree: 8a51c32a71a79eaf5aacc86fda73831f1a6356dc

Files: 8a51c32a71a79eaf5aacc86fda73831f1a6356dc / app / page / thread.js

3714 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 = 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