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