Files: 20dac953590fa5c36d143ac2af6eaf37a9e19fc3 / views.js
11365 bytesRaw
1 | var pull = require('pull-stream') |
2 | var human = require('human-time') |
3 | var sbot = require('./scuttlebot') |
4 | var hyperscroll = require('hyperscroll') |
5 | var More = require('pull-more') |
6 | var stream = require('hyperloadmore/stream') |
7 | var h = require('hyperscript') |
8 | var render = require('./render') |
9 | var ref = require('ssb-ref') |
10 | var client = require('ssb-client') |
11 | |
12 | var Next = require('pull-next-query') |
13 | |
14 | var config = require('./config')() |
15 | |
16 | var tools = require('./tools') |
17 | var avatar = require('./avatar') |
18 | var id = require('./keys').id |
19 | |
20 | var ssbKeys = require('ssb-keys') |
21 | var keys = require('./keys') |
22 | |
23 | var compose = require('./compose') |
24 | |
25 | var about = function () { |
26 | var screen = document.getElementById('screen') |
27 | |
28 | var about = require('./about') |
29 | |
30 | var content = h('div.content', about) |
31 | |
32 | screen.appendChild(hyperscroll(content)) |
33 | } |
34 | |
35 | var privateStream = function () { |
36 | var content = h('div.content') |
37 | var screen = document.getElementById('screen') |
38 | screen.appendChild(hyperscroll(content)) |
39 | |
40 | function createStream (opts) { |
41 | return pull( |
42 | More(sbot.createLogStream, opts), |
43 | pull.filter(function (msg) { |
44 | return 'string' == typeof msg.value.content |
45 | }), |
46 | pull.filter(function (msg) { |
47 | var unboxed = ssbKeys.unbox(msg.value.content, keys) |
48 | if (unboxed) { |
49 | msg.value.content = unboxed |
50 | msg.value.private = true |
51 | return msg |
52 | } |
53 | }), |
54 | pull.map(function (msg) { |
55 | return render(msg) |
56 | }) |
57 | ) |
58 | } |
59 | |
60 | pull( |
61 | createStream({old: false, limit: 1000}), |
62 | stream.top(content) |
63 | ) |
64 | |
65 | pull( |
66 | createStream({reverse: true, live: false, limit: 1000}), |
67 | stream.bottom(content) |
68 | ) |
69 | } |
70 | |
71 | var mentionsStream = function () { |
72 | var content = h('div.content') |
73 | |
74 | var screen = document.getElementById('screen') |
75 | |
76 | screen.appendChild(hyperscroll(content)) |
77 | |
78 | function createStream (opts) { |
79 | return pull( |
80 | Next(sbot.backlinks, opts, ['value', 'timestamp']), |
81 | pull.map(function (msg) { |
82 | if (msg.value.private == true) return |
83 | return render(msg) |
84 | }) |
85 | ) |
86 | } |
87 | |
88 | pull( |
89 | createStream({ |
90 | limit: 10, |
91 | reverse: true, |
92 | index: 'DTA', |
93 | live: false, |
94 | query: [{$filter: {dest: id}}] |
95 | }), |
96 | stream.bottom(content) |
97 | ) |
98 | |
99 | pull( |
100 | createStream({ |
101 | limit: 10, |
102 | old: false, |
103 | index: 'DTA', |
104 | live: true, |
105 | query: [{$filter: {dest: id}}] |
106 | }), |
107 | stream.top(content) |
108 | ) |
109 | } |
110 | |
111 | var userStream = function (src) { |
112 | var content = h('div.content') |
113 | var screen = document.getElementById('screen') |
114 | screen.appendChild(hyperscroll(content)) |
115 | function createStream (opts) { |
116 | return pull( |
117 | More(sbot.userStream, opts, ['value', 'sequence']), |
118 | pull.map(function (msg) { |
119 | return render(msg) |
120 | }) |
121 | ) |
122 | } |
123 | |
124 | pull( |
125 | createStream({old: false, limit: 10, id: src}), |
126 | stream.top(content) |
127 | ) |
128 | |
129 | pull( |
130 | createStream({reverse: true, live: false, limit: 10, id: src}), |
131 | stream.bottom(content) |
132 | ) |
133 | |
134 | var profile = h('div.content#profile', h('div.message')) |
135 | |
136 | if (screen.firstChild.firstChild) { |
137 | screen.firstChild.insertBefore(profile, screen.firstChild.firstChild) |
138 | } else { |
139 | screen.firstChild.appendChild(profile) |
140 | } |
141 | |
142 | var avatars = h('div.avatars', |
143 | h('a', {href: '#' + src}, |
144 | h('span.avatar--medium', avatar.image(src)), |
145 | avatar.name(src) |
146 | ) |
147 | ) |
148 | |
149 | pull( |
150 | sbot.userStream({id: src, reverse: false, limit: 1}), |
151 | pull.drain(function (msg) { |
152 | var howlong = h('span', ' arrived ', human(new Date(msg.value.timestamp))) |
153 | avatars.appendChild(howlong) |
154 | console.log(msg) |
155 | }) |
156 | ) |
157 | |
158 | var name = avatar.name(src) |
159 | |
160 | var buttons = h('div.buttons') |
161 | |
162 | profile.firstChild.appendChild(avatars) |
163 | profile.firstChild.appendChild(buttons) |
164 | buttons.appendChild(tools.mute(src)) |
165 | |
166 | var writeMessage = h('button.btn', 'Public message ', avatar.name(src), { |
167 | onclick: function () { |
168 | opts = {} |
169 | opts.type = 'post' |
170 | opts.mentions = '[' + name.textContent + '](' + src + ')' |
171 | var composer = h('div#composer', h('div.message', compose(opts))) |
172 | profile.appendChild(composer) |
173 | } |
174 | }) |
175 | |
176 | var writePrivate = h('button.btn', 'Private message ', avatar.name(src), { |
177 | onclick: function () { |
178 | opts = {} |
179 | opts.type = 'post' |
180 | opts.mentions = '[' + name.textContent + '](' + src + ')' |
181 | opts.recps = [src, id] |
182 | var composer = h('div#composer', h('div.message', compose(opts))) |
183 | profile.appendChild(composer) |
184 | } |
185 | }) |
186 | |
187 | buttons.appendChild(writeMessage) |
188 | buttons.appendChild(writePrivate) |
189 | buttons.appendChild(tools.follow(src)) |
190 | |
191 | profile.firstChild.appendChild(tools.getFollowing(src)) |
192 | profile.firstChild.appendChild(tools.getFollowers(src)) |
193 | } |
194 | |
195 | var msgThread = function (src) { |
196 | |
197 | var content = h('div.content') |
198 | var screen = document.getElementById('screen') |
199 | screen.appendChild(hyperscroll(content)) |
200 | |
201 | pull( |
202 | sbot.query({query: [{$filter: { value: { content: {root: src}, timestamp: { $gt: 1 }}}}], live: true}), |
203 | pull.drain(function (msg) { |
204 | if (msg.value) { |
205 | content.appendChild(render(msg)) |
206 | } |
207 | }) |
208 | ) |
209 | |
210 | sbot.get(src, function (err, data) { |
211 | if (err) {console.log('could not find message')} |
212 | data.value = data |
213 | data.key = src |
214 | console.log(data) |
215 | var rootMsg = render(data) |
216 | |
217 | if (content.firstChild) { |
218 | content.insertBefore(rootMsg, content.firstChild) |
219 | } else { |
220 | content.appendChild(rootMsg) |
221 | } |
222 | }) |
223 | } |
224 | |
225 | var keyPage = function () { |
226 | var screen = document.getElementById('screen') |
227 | |
228 | var importKey = h('textarea.import', {placeholder: 'Import a new public/private key', name: 'textarea', style: 'width: 97%; height: 100px;'}) |
229 | |
230 | var content = h('div.content', |
231 | h('div.message#key', |
232 | h('h1', 'Your Key'), |
233 | h('p', {innerHTML: 'Your public/private key is: <pre><code>' + localStorage[config.caps.shs + '/secret'] + '</code></pre>'}, |
234 | h('button.btn', {onclick: function (e){ |
235 | localStorage[config.caps.shs +'/secret'] = '' |
236 | alert('Your public/private key has been deleted') |
237 | e.preventDefault() |
238 | location.hash = "" |
239 | location.reload() |
240 | }}, 'Delete Key') |
241 | ), |
242 | h('hr'), |
243 | h('form', |
244 | importKey, |
245 | h('button.btn', {onclick: function (e){ |
246 | if(importKey.value) { |
247 | localStorage[config.caps.shs + '/secret'] = importKey.value.replace(/\s+/g, ' ') |
248 | e.preventDefault() |
249 | alert('Your public/private key has been updated') |
250 | } |
251 | location.hash = "" |
252 | location.reload() |
253 | }}, 'Import key'), |
254 | ) |
255 | ) |
256 | ) |
257 | |
258 | screen.appendChild(hyperscroll(content)) |
259 | } |
260 | |
261 | function everythingStream () { |
262 | |
263 | var screen = document.getElementById('screen') |
264 | var content = h('div.content') |
265 | |
266 | screen.appendChild(hyperscroll(content)) |
267 | |
268 | function createStream (opts) { |
269 | return pull( |
270 | Next(sbot.query, opts, ['value', 'timestamp']), |
271 | pull.map(function (msg) { |
272 | if (msg.value) { |
273 | return render(msg) |
274 | } |
275 | }) |
276 | ) |
277 | } |
278 | |
279 | pull( |
280 | createStream({ |
281 | limit: 10, |
282 | reverse: true, |
283 | live: false, |
284 | query: [{$filter: { value: { timestamp: { $gt: 0 }}}}] |
285 | }), |
286 | stream.bottom(content) |
287 | ) |
288 | |
289 | pull( |
290 | createStream({ |
291 | limit: 10, |
292 | old: false, |
293 | live: true, |
294 | query: [{$filter: { value: { timestamp: { $gt: 0 }}}}] |
295 | }), |
296 | stream.top(content) |
297 | ) |
298 | } |
299 | |
300 | function backchannel () { |
301 | |
302 | var screen = document.getElementById('screen') |
303 | var content = h('div.content') |
304 | |
305 | screen.appendChild(hyperscroll(content)) |
306 | |
307 | var chatbox = h('input', {placeholder: 'Backchannel'}) |
308 | |
309 | var chat = h('div.content') |
310 | |
311 | var publish = h('button.btn', 'Publish', { |
312 | onclick: function () { |
313 | if (chatbox.value) { |
314 | var content = { |
315 | text: chatbox.value, |
316 | type: 'scat_message' |
317 | } |
318 | sbot.publish(content, function (err, msg) { |
319 | if (err) throw err |
320 | chatbox.value = '' |
321 | console.log('Published!', msg) |
322 | }) |
323 | } |
324 | } |
325 | }) |
326 | |
327 | chat.appendChild(h('div.message', chatbox, publish)) |
328 | |
329 | if (screen.firstChild.firstChild) { |
330 | screen.firstChild.insertBefore(chat, screen.firstChild.firstChild) |
331 | } else { |
332 | screen.firstChild.appendChild(chat) |
333 | } |
334 | |
335 | function createStream (opts) { |
336 | return pull( |
337 | Next(sbot.query, opts, ['value', 'timestamp']), |
338 | pull.map(function (msg) { |
339 | if (msg.value) { |
340 | return render(msg) |
341 | } |
342 | }) |
343 | ) |
344 | } |
345 | |
346 | pull( |
347 | createStream({ |
348 | limit: 10, |
349 | reverse: true, |
350 | live: false, |
351 | query: [{$filter: { value: { content: {type: 'scat_message'}, timestamp: { $gt: 0 }}}}] |
352 | }), |
353 | stream.bottom(content) |
354 | ) |
355 | |
356 | pull( |
357 | createStream({ |
358 | limit: 10, |
359 | old: false, |
360 | live: true, |
361 | query: [{$filter: { value: { content: {type: 'scat_message'}, timestamp: { $gt: 0 }}}}] |
362 | }), |
363 | stream.top(content) |
364 | ) |
365 | } |
366 | |
367 | |
368 | function hash () { |
369 | return window.location.hash.substring(1) |
370 | } |
371 | |
372 | module.exports = function () { |
373 | var src = hash() |
374 | |
375 | if (ref.isFeed(src)) { |
376 | userStream(src) |
377 | } else if (ref.isMsg(src)) { |
378 | msgThread(src) |
379 | } else if (src == 'mentions') { |
380 | mentionsStream() |
381 | } else if (src == 'about') { |
382 | about() |
383 | } else if (src == 'backchannel') { |
384 | backchannel() |
385 | } else if (src == 'private') { |
386 | privateStream() |
387 | } else if (src == 'key') { |
388 | keyPage() |
389 | } else { |
390 | everythingStream() |
391 | } |
392 | |
393 | |
394 | function parseInvite (invite) { |
395 | return ref.parseInvite(invite) |
396 | } |
397 | |
398 | // TODO: this should really only pop up if you have no friends |
399 | var currentScreen = document.getElementById('screen') |
400 | var invitebox = h('input', {placeholder: 'Invite Code Here'}) |
401 | invitebox.value = config.invite |
402 | var invite = h('div.content', h('div.message#inviter', |
403 | 'Hey, no one follows you. Your secure-scuttlebutt feed may not replicate unless a pub follows you. Either ', h('a', {href: '#key'}, 'import your key'), ' or use a pub invite:', |
404 | h('br'), |
405 | invitebox, |
406 | h('button', 'Accept', {onclick: function (e) { |
407 | var data = parseInvite(invitebox.value) |
408 | console.log(data) |
409 | e.preventDefault() |
410 | //sbot.gossip.connect(data.remote, function (err) { |
411 | |
412 | //}) |
413 | |
414 | client(keys, { |
415 | remote: data.invite, |
416 | caps: config.caps, |
417 | manifest: {invite: {use: 'async'}, getAddress: 'async'} |
418 | }, function (err, remotebot) { |
419 | if (err) throw err |
420 | remotebot.invite.use({feed: id}, function (_err, msg) { |
421 | if (msg) { |
422 | sbot.publish({ |
423 | type: 'contact', |
424 | contact: data.key, |
425 | following: true |
426 | }) |
427 | } |
428 | }) |
429 | setTimeout(function () { |
430 | location.hash = '#' + id |
431 | location.hash = '#' |
432 | }, 100) |
433 | }) |
434 | }}) |
435 | )) |
436 | if (currentScreen.firstChild.firstChild) { |
437 | currentScreen.firstChild.insertBefore(invite, currentScreen.firstChild.firstChild) |
438 | } else { |
439 | currentScreen.firstChild.appendChild(invite) |
440 | } |
441 | sbot.friends.get({dest: id}, function (err, follows) { |
442 | for (var i in follows) { |
443 | if (follows[i] === true) { |
444 | var getInvite = document.getElementById('inviter') |
445 | |
446 | if (getInvite) { |
447 | getInvite.parentNode.removeChild(getInvite) |
448 | } |
449 | } |
450 | } |
451 | }) |
452 | } |
453 |
Built with git-ssb-web