git ssb

0+

alanz / patchwork



forked from Matt McKegg / patchwork

Tree: 700173f9df1724b50186a5ea9deb34c3a2c3b697

Files: 700173f9df1724b50186a5ea9deb34c3a2c3b697 / modules / feed / html / rollup.js

6495 bytesRaw
1var Value = require('mutant/value')
2var when = require('mutant/when')
3var computed = require('mutant/computed')
4var h = require('mutant/h')
5var MutantArray = require('mutant/array')
6var Abortable = require('pull-abortable')
7var pull = require('pull-stream')
8var nest = require('depnest')
9
10var onceTrue = require('mutant/once-true')
11var Scroller = require('pull-scroll')
12
13exports.needs = nest({
14 'message.html': {
15 render: 'first',
16 link: 'first'
17 },
18 'sbot.async.get': 'first',
19 'keys.sync.id': 'first',
20 feed: {
21 'html.rollup': 'first',
22 'pull.summary': 'first'
23 },
24 profile: {
25 'html.person': 'first',
26 'html.manyPeople': 'first',
27 'obs.names': 'first'
28 }
29})
30
31exports.gives = nest({
32 'feed.html': ['rollup']
33})
34
35exports.create = function (api) {
36 return nest({
37 'feed.html': { rollup }
38 })
39 function rollup (getStream, opts) {
40 var sync = Value(false)
41 var updates = Value(0)
42
43 var filter = opts && opts.filter
44 var bumpFilter = opts && opts.bumpFilter
45 var windowSize = opts && opts.windowSize
46 var waitFor = opts && opts.waitFor || true
47
48 var updateLoader = h('a', {
49 className: 'Notifier -loader',
50 href: '#',
51 'ev-click': refresh
52 }, [
53 'Show ',
54 h('strong', [updates]), ' ',
55 when(computed(updates, a => a === 1), 'update', 'updates')
56 ])
57
58 var content = h('section.content', {
59 hidden: computed(sync, s => !s)
60 })
61
62 var container = h('div', {
63 className: 'Scroller',
64 style: { overflow: 'auto' },
65 }, [
66 h('div.wrapper', [
67 h('section.prepend', opts.prepend),
68 when(sync, null, h('div', {className: 'Loading -large'})),
69 content
70 ])
71 ])
72
73 setTimeout(refresh, 10)
74
75 onceTrue(waitFor, () => {
76 pull(
77 getStream({old: false}),
78 pull.drain((item) => {
79 var type = item && item.value && item.value.content.type
80 if (type && type !== 'vote') {
81 if (item.value && item.value.author === api.keys.sync.id() && !updates()) {
82 return refresh()
83 }
84 if (filter) {
85 var update = (item.value.content.type === 'post' && item.value.content.root) ? {
86 type: 'message',
87 messageId: item.value.content.root,
88 channel: item.value.content.channel
89 } : {
90 type: 'message',
91 author: item.value.author,
92 channel: item.value.content.channel,
93 messageId: item.key
94 }
95
96 ensureAuthor(update, (err, update) => {
97 if (!err) {
98 if (filter(update)) {
99 updates.set(updates() + 1)
100 }
101 }
102 })
103 } else {
104 updates.set(updates() + 1)
105 }
106 }
107 })
108 )
109 })
110
111 var abortLastFeed = null
112
113 var result = MutantArray([
114 when(updates, updateLoader),
115 container
116 ])
117
118 result.reload = refresh
119 result.pendingUpdates = updates
120
121 return result
122
123 // scoped
124
125 function refresh () {
126 if (abortLastFeed) {
127 abortLastFeed()
128 }
129 updates.set(0)
130 sync.set(false)
131 content.innerHTML = ''
132
133 var abortable = Abortable()
134 abortLastFeed = abortable.abort
135
136 pull(
137 api.feed.pull.summary(getStream, {windowSize, bumpFilter}, () => {
138 sync.set(true)
139 }),
140 pull.asyncMap(ensureAuthor),
141 pull.filter((item) => {
142 if (filter) {
143 return filter(item)
144 } else {
145 return true
146 }
147 }),
148 abortable,
149 Scroller(container, content, renderItem, false, false)
150 )
151 }
152 }
153
154 function ensureAuthor (item, cb) {
155 if (item.type === 'message' && !item.message) {
156 api.sbot.async.get(item.messageId, (_, value) => {
157 if (value) {
158 item.author = value.author
159 }
160 cb(null, item)
161 })
162 } else {
163 cb(null, item)
164 }
165 }
166
167 function renderItem (item) {
168 if (item.type === 'message') {
169 var meta = null
170 var previousId = item.messageId
171 var replies = item.replies.slice(-4).map((msg) => {
172 var result = api.message.html.render(msg, {inContext: true, inSummary: true, previousId})
173 previousId = msg.key
174 return result
175 })
176 var renderedMessage = item.message ? api.message.html.render(item.message, {inContext: true}) : null
177 if (renderedMessage) {
178 if (item.lastUpdateType === 'reply' && item.repliesFrom.size) {
179 meta = h('div.meta', {
180 title: api.profile.obs.names(item.repliesFrom)
181 }, [
182 api.profile.html.manyPeople(item.repliesFrom), ' replied'
183 ])
184 } else if (item.lastUpdateType === 'dig' && item.digs.size) {
185 meta = h('div.meta', {
186 title: api.profile.obs.names(item.digs)
187 }, [
188 api.profile.html.manyPeople(item.digs), ' dug this message'
189 ])
190 }
191
192 return h('div', {className: 'FeedEvent'}, [
193 meta,
194 renderedMessage,
195 when(replies.length, [
196 when(item.replies.length > replies.length,
197 h('a.full', {href: item.messageId}, ['View full thread'])
198 ),
199 h('div.replies', replies)
200 ])
201 ])
202 } else {
203 if (item.lastUpdateType === 'reply' && item.repliesFrom.size) {
204 meta = h('div.meta', {
205 title: api.profile.obs.names(item.repliesFrom)
206 }, [
207 api.profile.html.manyPeople(item.repliesFrom), ' replied to ', api.message.html.link(item.messageId)
208 ])
209 } else if (item.lastUpdateType === 'dig' && item.digs.size) {
210 meta = h('div.meta', {
211 title: api.profile.obs.names(item.digs)
212 }, [
213 api.profile.html.manyPeople(item.digs), ' dug ', api.message.html.link(item.messageId)
214 ])
215 }
216
217 if (meta || replies.length) {
218 return h('div', {className: 'FeedEvent'}, [
219 meta, h('div.replies', replies)
220 ])
221 }
222 }
223 } else if (item.type === 'follow') {
224 return h('div', {className: 'FeedEvent -follow'}, [
225 h('div.meta', {
226 title: api.profile.obs.names(item.contacts)
227 }, [
228 api.profile.html.person(item.id), ' followed ', api.profile.html.manyPeople(item.contacts)
229 ])
230 ])
231 }
232
233 return h('div')
234 }
235}
236

Built with git-ssb-web