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