Files: afc9955231b5cf72a19ab39b8e1fba3713fdf6ac / views.js
16323 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 hyperfile = require('hyperfile') |
6 | var dataurl = require('dataurl-') |
7 | var More = require('pull-more') |
8 | var stream = require('hyperloadmore/stream') |
9 | var h = require('hyperscript') |
10 | var render = require('./render') |
11 | var ref = require('ssb-ref') |
12 | var client = require('ssb-client') |
13 | |
14 | var Next = require('pull-next-query') |
15 | |
16 | var config = require('./config')() |
17 | |
18 | var tools = require('./tools') |
19 | var avatar = require('./avatar') |
20 | var id = require('./keys').id |
21 | |
22 | var ssbKeys = require('ssb-keys') |
23 | var keys = require('./keys') |
24 | |
25 | var compose = require('./compose') |
26 | |
27 | var labelStream = function (label){ |
28 | var content = h('div.content') |
29 | var screen = document.getElementById('screen') |
30 | screen.appendChild(hyperscroll(content)) |
31 | content.appendChild(h('div.breadcrumbs.message', h('a', {href: '/'}, 'label'), ' // ' , h('a', {href: '/#label/' + label}, label))) |
32 | function createStream (opts) { |
33 | return pull( |
34 | Next(sbot.query, opts, ['value', 'timestamp']), |
35 | pull.map(function (msg){ |
36 | if (msg.value) { |
37 | sbot.get(msg.value.content.link, function (err, data) { |
38 | if (data) { |
39 | var message = {} |
40 | message.value = data |
41 | message.key = msg.value.content.link |
42 | content.appendChild(render(message)) |
43 | } |
44 | }) |
45 | } |
46 | }) |
47 | ) |
48 | } |
49 | |
50 | pull( |
51 | createStream({ |
52 | limit: 10, |
53 | reverse: true, |
54 | live: false, |
55 | query: [{$filter: { value: { content: {type: 'label', label: label }, timestamp: { $gt: 0 }}}}] |
56 | }), |
57 | stream.bottom(content) |
58 | ) |
59 | |
60 | pull( |
61 | createStream({ |
62 | limit: 10, |
63 | old: false, |
64 | live: true, |
65 | query: [{$filter: { value: { content: {type: 'label', label: label }, timestamp: { $gt: 0 }}}}] |
66 | }), |
67 | stream.top(content) |
68 | ) |
69 | } |
70 | |
71 | |
72 | var privateStream = function () { |
73 | var screen = document.getElementById('screen') |
74 | var content = h('div.content') |
75 | |
76 | screen.appendChild(hyperscroll(content)) |
77 | |
78 | function createStream (opts) { |
79 | return pull( |
80 | Next(sbot.query, opts, ['value', 'timestamp']), |
81 | pull.filter(function (msg) { |
82 | return ((msg.value.private == true) || ('string' == typeof msg.value.content)) |
83 | }), |
84 | pull.map(function (msg) { |
85 | /*if (msg.value.private != true) { |
86 | var unboxed = ssbKeys.unbox(msg.value.content, keys) |
87 | if (unboxed) { |
88 | msg.value.content = unboxed |
89 | msg.value.private = true |
90 | return render(msg) |
91 | } else { |
92 | return render(msg) |
93 | } |
94 | } else {return render(msg)}*/ |
95 | return render(msg) |
96 | }) |
97 | ) |
98 | } |
99 | |
100 | pull( |
101 | createStream({ |
102 | limit: 100, |
103 | reverse: true, |
104 | live: false, |
105 | query: [{$filter: { value: { timestamp: { $gt: 0 }}}}] |
106 | }), |
107 | stream.bottom(content) |
108 | ) |
109 | |
110 | pull( |
111 | createStream({ |
112 | limit: 100, |
113 | old: false, |
114 | live: true, |
115 | query: [{$filter: { value: { timestamp: { $gt: 0 }}}}] |
116 | }), |
117 | stream.top(content) |
118 | ) |
119 | } |
120 | |
121 | var queueStream = function () { |
122 | var content = h('div.content') |
123 | var screen = document.getElementById('screen') |
124 | screen.appendChild(hyperscroll(content)) |
125 | |
126 | pull( |
127 | sbot.query({query: [{$filter: { value: {author: id, content: {type: 'queue'}}}}]}), |
128 | pull.drain(function (msg) { |
129 | if (msg.value) { |
130 | if (ref.isMsg(msg.value.content.message)) { |
131 | if (msg.value.content.queue == true) { |
132 | sbot.get(msg.value.content.message, function (err, data) { |
133 | if (data) { |
134 | var message = {} |
135 | message.value = data |
136 | message.key = msg.value.content.message |
137 | content.appendChild(render(message)) |
138 | } |
139 | }) |
140 | } |
141 | if (msg.value.content.queue == false) { |
142 | setTimeout(function () { |
143 | var gotIt = document.getElementById(msg.value.content.message.substring(0,44)) |
144 | if (gotIt != null) { |
145 | gotIt.outerHTML = '' |
146 | } |
147 | }, 100) |
148 | } |
149 | } |
150 | } |
151 | }) |
152 | ) |
153 | } |
154 | |
155 | var mentionsStream = function (src) { |
156 | var content = h('div.content') |
157 | |
158 | var screen = document.getElementById('screen') |
159 | |
160 | screen.appendChild(hyperscroll(content)) |
161 | |
162 | function createStream (opts) { |
163 | return pull( |
164 | Next(sbot.backlinks, opts, ['value', 'timestamp']), |
165 | pull.map(function (msg) { |
166 | if (msg.value.private == true) return h('div.private') |
167 | return render(msg) |
168 | }) |
169 | ) |
170 | } |
171 | |
172 | pull( |
173 | createStream({ |
174 | limit: 10, |
175 | reverse: true, |
176 | index: 'DTA', |
177 | live: false, |
178 | query: [{$filter: {dest: src}}] |
179 | }), |
180 | stream.bottom(content) |
181 | ) |
182 | |
183 | pull( |
184 | createStream({ |
185 | limit: 10, |
186 | old: false, |
187 | index: 'DTA', |
188 | live: true, |
189 | query: [{$filter: {dest: src}}] |
190 | }), |
191 | stream.top(content) |
192 | ) |
193 | } |
194 | |
195 | var userStream = function (src) { |
196 | var content = h('div.content') |
197 | var screen = document.getElementById('screen') |
198 | |
199 | screen.appendChild(hyperscroll(content)) |
200 | |
201 | function createStream (opts) { |
202 | return pull( |
203 | Next(sbot.query, opts, ['value', 'timestamp']), |
204 | pull.map(function (msg) { |
205 | if (msg.value) { |
206 | return render(msg) |
207 | } |
208 | }) |
209 | ) |
210 | } |
211 | |
212 | pull( |
213 | createStream({ |
214 | limit: 10, |
215 | reverse: true, |
216 | live: false, |
217 | query: [{$filter: { value: {author: src, content: {type: 'git-update'}, timestamp: { $gt: 0 }}}}] |
218 | }), |
219 | stream.bottom(content) |
220 | ) |
221 | |
222 | pull( |
223 | createStream({ |
224 | limit: 10, |
225 | old: false, |
226 | live: true, |
227 | query: [{$filter: { value: {author: src, content: {type: 'git-update'}, timestamp: { $gt: 0 }}}}] |
228 | }), |
229 | stream.top(content) |
230 | ) |
231 | |
232 | |
233 | var profile = h('div.content#profile', h('div.message')) |
234 | |
235 | if (screen.firstChild.firstChild) { |
236 | screen.firstChild.insertBefore(profile, screen.firstChild.firstChild) |
237 | } else { |
238 | screen.firstChild.appendChild(profile) |
239 | } |
240 | |
241 | var name = avatar.name(src) |
242 | |
243 | var editname = h('span', |
244 | avatar.name(src), |
245 | h('button.btn', 'New name', { |
246 | onclick: function () { |
247 | var nameput = h('input', {placeholder: name.textContent}) |
248 | var nameedit = |
249 | h('span', nameput, |
250 | h('button.btn', 'Preview', { |
251 | onclick: function () { |
252 | if (nameput.value[0] != '@') |
253 | tobename = nameput.value |
254 | else |
255 | tobename = nameput.value.substring(1, 100) |
256 | var newname = h('span', h('a', {href: '#' + src}, '@' + tobename), h('button.btn', 'Publish', { |
257 | onclick: function () { |
258 | var donename = h('span', h('a', {href: '#' + src}, '@' + tobename)) |
259 | sbot.publish({type: 'about', about: src, name: tobename}) |
260 | localStorage[src + 'name'] = tobename |
261 | newname.parentNode.replaceChild(donename, newname) |
262 | } |
263 | })) |
264 | nameedit.parentNode.replaceChild(newname, nameedit) |
265 | } |
266 | }) |
267 | ) |
268 | editname.parentNode.replaceChild(nameedit, editname) |
269 | } |
270 | }) |
271 | ) |
272 | |
273 | var editimage = h('span', |
274 | h('button.btn', 'New image', { |
275 | onclick: function () { |
276 | var upload = |
277 | h('span', |
278 | hyperfile.asDataURL(function (data) { |
279 | if(data) { |
280 | //img.src = data |
281 | var _data = dataurl.parse(data) |
282 | pull( |
283 | pull.once(_data.data), |
284 | sbot.addblob(function (err, hash) { |
285 | if(err) return alert(err.stack) |
286 | selected = { |
287 | link: hash, |
288 | size: _data.data.length, |
289 | type: _data.mimetype |
290 | } |
291 | }) |
292 | ) |
293 | } |
294 | }), |
295 | h('button.btn', 'Preview image', { |
296 | onclick: function() { |
297 | if (selected) { |
298 | console.log(selected) |
299 | var oldImage = document.getElementById('profileImage') |
300 | var newImage = h('span.avatar--medium', h('img', {src: config.blobsUrl + selected.link})) |
301 | var publish = h('button.btn', 'Publish image', { |
302 | onclick: function () { |
303 | sbot.publish({ |
304 | type: 'about', |
305 | about: src, |
306 | image: selected |
307 | }, function (err, published) { |
308 | console.log(published) |
309 | }) |
310 | } |
311 | }) |
312 | upload.parentNode.replaceChild(publish, upload) |
313 | oldImage.parentNode.replaceChild(newImage, oldImage) |
314 | } |
315 | /*if(selected) { |
316 | api.message_confirm({ |
317 | type: 'about', |
318 | about: id, |
319 | image: selected |
320 | }) |
321 | } else { alert('select an image before hitting preview')}*/ |
322 | } |
323 | }) |
324 | ) |
325 | editimage.parentNode.replaceChild(upload, editimage) |
326 | } |
327 | }) |
328 | ) |
329 | |
330 | var avatars = h('div.avatars', |
331 | h('a', {href: '#' + src}, |
332 | h('span.avatar--medium#profileImage', avatar.image(src)), |
333 | editname, |
334 | h('br'), |
335 | editimage |
336 | ) |
337 | ) |
338 | |
339 | pull( |
340 | sbot.userStream({id: src, reverse: false, limit: 1}), |
341 | pull.drain(function (msg) { |
342 | var howlong = h('span', h('br'), ' arrived ', human(new Date(msg.value.timestamp))) |
343 | avatars.appendChild(howlong) |
344 | console.log(msg) |
345 | }) |
346 | ) |
347 | |
348 | |
349 | var buttons = h('div.buttons') |
350 | |
351 | profile.firstChild.appendChild(avatars) |
352 | profile.firstChild.appendChild(buttons) |
353 | buttons.appendChild(tools.mute(src)) |
354 | |
355 | var writeMessage = h('button.btn', 'Public message ', avatar.name(src), { |
356 | onclick: function () { |
357 | opts = {} |
358 | opts.type = 'post' |
359 | opts.mentions = '[' + name.textContent + '](' + src + ')' |
360 | var composer = h('div#composer', h('div.message', compose(opts))) |
361 | profile.appendChild(composer) |
362 | } |
363 | }) |
364 | |
365 | var writePrivate = h('button.btn', 'Private message ', avatar.name(src), { |
366 | onclick: function () { |
367 | opts = {} |
368 | opts.type = 'post' |
369 | opts.mentions = '[' + name.textContent + '](' + src + ')' |
370 | opts.recps = [src, id] |
371 | var composer = h('div#composer', h('div.message', compose(opts))) |
372 | profile.appendChild(composer) |
373 | } |
374 | }) |
375 | |
376 | buttons.appendChild(writeMessage) |
377 | buttons.appendChild(writePrivate) |
378 | buttons.appendChild(tools.follow(src)) |
379 | buttons.appendChild(h('a', {href: '#wall/' + src}, h('button.btn', avatar.name(src), "'s wall"))) |
380 | } |
381 | |
382 | var msgThread = function (src) { |
383 | |
384 | var content = h('div.content') |
385 | var screen = document.getElementById('screen') |
386 | screen.appendChild(hyperscroll(content)) |
387 | |
388 | pull( |
389 | sbot.query({query: [{$filter: { value: { content: {root: src}, timestamp: { $gt: 1 }}}}], live: true}), |
390 | pull.drain(function (msg) { |
391 | if (msg.value) { |
392 | content.appendChild(render(msg)) |
393 | } |
394 | }) |
395 | ) |
396 | |
397 | |
398 | sbot.get(src, function (err, data) { |
399 | if (err) { |
400 | var message = h('div.message', 'Missing message!') |
401 | content.appendChild(message) |
402 | } |
403 | if (data) { |
404 | var message = {} |
405 | message.value = data |
406 | message.key = src |
407 | console.log(message) |
408 | var rootMsg = render(message) |
409 | |
410 | if (content.firstChild) { |
411 | content.insertBefore(rootMsg, content.firstChild) |
412 | } else { |
413 | content.appendChild(rootMsg) |
414 | } |
415 | if (message.value.content.type == 'git-repo') { |
416 | pull( |
417 | sbot.backlinks({query: [{$filter: {value: {content: {type: 'git-update'}}, dest: src}}]}), |
418 | pull.drain(function (msg) { |
419 | if (msg.value) { |
420 | content.appendChild(render(msg)) |
421 | } |
422 | }) |
423 | ) |
424 | } |
425 | |
426 | } |
427 | }) |
428 | } |
429 | |
430 | var keyPage = function () { |
431 | var screen = document.getElementById('screen') |
432 | |
433 | var importKey = h('textarea.import', {placeholder: 'Import a new public/private key', name: 'textarea', style: 'width: 97%; height: 100px;'}) |
434 | |
435 | var content = h('div.content', |
436 | h('div.message#key', |
437 | h('h1', 'Your Key'), |
438 | h('p', {innerHTML: 'Your public/private key is: <pre><code>' + localStorage[config.caps.shs + '/secret'] + '</code></pre>'}, |
439 | h('button.btn', {onclick: function (e){ |
440 | localStorage[config.caps.shs +'/secret'] = '' |
441 | alert('Your public/private key has been deleted') |
442 | e.preventDefault() |
443 | location.hash = "" |
444 | location.reload() |
445 | }}, 'Delete Key') |
446 | ), |
447 | h('hr'), |
448 | h('form', |
449 | importKey, |
450 | h('button.btn', {onclick: function (e){ |
451 | if(importKey.value) { |
452 | localStorage[config.caps.shs + '/secret'] = importKey.value.replace(/\s+/g, ' ') |
453 | e.preventDefault() |
454 | alert('Your public/private key has been updated') |
455 | } |
456 | location.hash = "" |
457 | location.reload() |
458 | }}, 'Import key'), |
459 | ) |
460 | ) |
461 | ) |
462 | |
463 | screen.appendChild(hyperscroll(content)) |
464 | } |
465 | |
466 | function gitStream () { |
467 | |
468 | var screen = document.getElementById('screen') |
469 | var content = h('div.content') |
470 | |
471 | screen.appendChild(hyperscroll(content)) |
472 | |
473 | function createStream (opts) { |
474 | return pull( |
475 | Next(sbot.query, opts, ['value', 'timestamp']), |
476 | pull.map(function (msg) { |
477 | if (msg.value) { |
478 | return render(msg) |
479 | } |
480 | }) |
481 | ) |
482 | } |
483 | |
484 | pull( |
485 | createStream({ |
486 | limit: 10, |
487 | reverse: true, |
488 | live: false, |
489 | query: [{$filter: { value: { content: {type: 'git-update'}, timestamp: { $gt: 0 }}}}] |
490 | }), |
491 | stream.bottom(content) |
492 | ) |
493 | |
494 | pull( |
495 | createStream({ |
496 | limit: 10, |
497 | old: false, |
498 | live: true, |
499 | query: [{$filter: { value: { content: {type: 'git-update'}, timestamp: { $gt: 0 }}}}] |
500 | }), |
501 | stream.top(content) |
502 | ) |
503 | } |
504 | |
505 | |
506 | |
507 | |
508 | function backchannel () { |
509 | |
510 | var screen = document.getElementById('screen') |
511 | var content = h('div.content') |
512 | |
513 | screen.appendChild(hyperscroll(content)) |
514 | |
515 | var chatbox = h('input', {placeholder: 'Backchannel'}) |
516 | |
517 | var chat = h('div.content') |
518 | |
519 | var publish = h('button.btn', 'Publish', { |
520 | onclick: function () { |
521 | if (chatbox.value) { |
522 | var content = { |
523 | text: chatbox.value, |
524 | type: 'scat_message' |
525 | } |
526 | sbot.publish(content, function (err, msg) { |
527 | if (err) throw err |
528 | chatbox.value = '' |
529 | console.log('Published!', msg) |
530 | }) |
531 | } |
532 | } |
533 | }) |
534 | |
535 | chat.appendChild(h('div.message', chatbox, publish)) |
536 | |
537 | if (screen.firstChild.firstChild) { |
538 | screen.firstChild.insertBefore(chat, screen.firstChild.firstChild) |
539 | } else { |
540 | screen.firstChild.appendChild(chat) |
541 | } |
542 | |
543 | function createStream (opts) { |
544 | return pull( |
545 | Next(sbot.query, opts, ['value', 'timestamp']), |
546 | pull.map(function (msg) { |
547 | if (msg.value) { |
548 | return render(msg) |
549 | } |
550 | }) |
551 | ) |
552 | } |
553 | |
554 | pull( |
555 | createStream({ |
556 | limit: 10, |
557 | reverse: true, |
558 | live: false, |
559 | query: [{$filter: { value: { content: {type: 'scat_message'}, timestamp: { $gt: 0 }}}}] |
560 | }), |
561 | stream.bottom(content) |
562 | ) |
563 | |
564 | pull( |
565 | createStream({ |
566 | limit: 10, |
567 | old: false, |
568 | live: true, |
569 | query: [{$filter: { value: { content: {type: 'scat_message'}, timestamp: { $gt: 0 }}}}] |
570 | }), |
571 | stream.top(content) |
572 | ) |
573 | } |
574 | |
575 | function search (src) { |
576 | console.log('search' + src) |
577 | |
578 | var content = h('div.content') |
579 | var screen = document.getElementById('screen') |
580 | screen.appendChild(hyperscroll(content)) |
581 | |
582 | pull( |
583 | sbot.search.query({query: src, limit: 100}), |
584 | pull.drain(function (search) { |
585 | content.appendChild(render(search)) |
586 | }) |
587 | ) |
588 | |
589 | } |
590 | |
591 | function hash () { |
592 | return window.location.hash.substring(1) |
593 | } |
594 | |
595 | module.exports = function () { |
596 | var src = hash() |
597 | |
598 | if (src.substring(52, 59) == '?unbox=') { |
599 | privateMsg(src) |
600 | } else if (ref.isFeed(src)) { |
601 | userStream(src) |
602 | } else if (ref.isMsg(src)) { |
603 | msgThread(src) |
604 | } else if (ref.isFeed(src.substring(5))) { |
605 | mentionsStream(src.substring(5)) |
606 | } else if (src.substring(0, 6) === 'label/') { |
607 | labelStream(src.substring(6)) |
608 | } else if (src == 'queue') { |
609 | queueStream() |
610 | } else if (src == 'backchannel') { |
611 | backchannel() |
612 | } else if (src == 'private') { |
613 | privateStream() |
614 | } else if (src == 'key') { |
615 | keyPage() |
616 | } else { |
617 | gitStream() |
618 | } |
619 | |
620 | } |
621 |
Built with git-ssb-web