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