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