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