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