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