var pull = require('pull-stream') var human = require('human-time') var sbot = require('./scuttlebot') var hyperscroll = require('hyperscroll') var More = require('pull-more') var stream = require('hyperloadmore/stream') var h = require('hyperscript') var render = require('./render') var ref = require('ssb-ref') var client = require('ssb-client') var Next = require('pull-next-query') var config = require('./config')() var tools = require('./tools') var avatar = require('./avatar') var id = require('./keys').id var ssbKeys = require('ssb-keys') var keys = require('./keys') var compose = require('./compose') var about = function () { var screen = document.getElementById('screen') var about = require('./about') var content = h('div.content', about) screen.appendChild(hyperscroll(content)) } var privateStream = function () { var content = h('div.content') var screen = document.getElementById('screen') screen.appendChild(hyperscroll(content)) function createStream (opts) { return pull( More(sbot.createLogStream, opts), pull.filter(function (msg) { return 'string' == typeof msg.value.content }), pull.filter(function (msg) { var unboxed = ssbKeys.unbox(msg.value.content, keys) if (unboxed) { msg.value.content = unboxed msg.value.private = true return msg } }), pull.map(function (msg) { return render(msg) }) ) } pull( createStream({old: false, limit: 1000}), stream.top(content) ) pull( createStream({reverse: true, live: false, limit: 1000}), stream.bottom(content) ) } var mentionsStream = function () { var content = h('div.content') var screen = document.getElementById('screen') screen.appendChild(hyperscroll(content)) function createStream (opts) { return pull( Next(sbot.backlinks, opts, ['value', 'timestamp']), pull.map(function (msg) { if (msg.value.private == true) return return render(msg) }) ) } pull( createStream({ limit: 10, reverse: true, index: 'DTA', live: false, query: [{$filter: {dest: id}}] }), stream.bottom(content) ) pull( createStream({ limit: 10, old: false, index: 'DTA', live: true, query: [{$filter: {dest: id}}] }), stream.top(content) ) } var userStream = function (src) { var content = h('div.content') var screen = document.getElementById('screen') screen.appendChild(hyperscroll(content)) function createStream (opts) { return pull( More(sbot.userStream, opts, ['value', 'sequence']), pull.map(function (msg) { return render(msg) }) ) } pull( createStream({old: false, limit: 10, id: src}), stream.top(content) ) pull( createStream({reverse: true, live: false, limit: 10, id: src}), stream.bottom(content) ) var profile = h('div.content#profile', h('div.message')) if (screen.firstChild.firstChild) { screen.firstChild.insertBefore(profile, screen.firstChild.firstChild) } else { screen.firstChild.appendChild(profile) } var avatars = h('div.avatars', h('a', {href: '#' + src}, h('span.avatar--medium', avatar.image(src)), avatar.name(src) ) ) pull( sbot.userStream({id: src, reverse: false, limit: 1}), pull.drain(function (msg) { var howlong = h('span', ' arrived ', human(new Date(msg.value.timestamp))) avatars.appendChild(howlong) console.log(msg) }) ) var name = avatar.name(src) var buttons = h('div.buttons') profile.firstChild.appendChild(avatars) profile.firstChild.appendChild(buttons) buttons.appendChild(tools.mute(src)) var writeMessage = h('button.btn', 'Public message ', avatar.name(src), { onclick: function () { opts = {} opts.type = 'post' opts.mentions = '[' + name.textContent + '](' + src + ')' var composer = h('div#composer', h('div.message', compose(opts))) profile.appendChild(composer) } }) var writePrivate = h('button.btn', 'Private message ', avatar.name(src), { onclick: function () { opts = {} opts.type = 'post' opts.mentions = '[' + name.textContent + '](' + src + ')' opts.recps = [src, id] var composer = h('div#composer', h('div.message', compose(opts))) profile.appendChild(composer) } }) buttons.appendChild(writeMessage) buttons.appendChild(writePrivate) buttons.appendChild(tools.follow(src)) profile.firstChild.appendChild(tools.getFollowing(src)) profile.firstChild.appendChild(tools.getFollowers(src)) } var msgThread = function (src) { var content = h('div.content') var screen = document.getElementById('screen') screen.appendChild(hyperscroll(content)) pull( sbot.query({query: [{$filter: { value: { content: {root: src}, timestamp: { $gt: 1 }}}}], live: true}), pull.drain(function (msg) { if (msg.value) { content.appendChild(render(msg)) } }) ) sbot.get(src, function (err, data) { if (err) {console.log('could not find message')} data.value = data data.key = src console.log(data) var rootMsg = render(data) if (content.firstChild) { content.insertBefore(rootMsg, content.firstChild) } else { content.appendChild(rootMsg) } }) } var keyPage = function () { var screen = document.getElementById('screen') var importKey = h('textarea.import', {placeholder: 'Import a new public/private key', name: 'textarea', style: 'width: 97%; height: 100px;'}) var content = h('div.content', h('div.message#key', h('h1', 'Your Key'), h('p', {innerHTML: 'Your public/private key is:
' + localStorage[config.caps.shs + '/secret'] + '
'},
h('button.btn', {onclick: function (e){
localStorage[config.caps.shs +'/secret'] = ''
alert('Your public/private key has been deleted')
e.preventDefault()
location.hash = ""
location.reload()
}}, 'Delete Key')
),
h('hr'),
h('form',
importKey,
h('button.btn', {onclick: function (e){
if(importKey.value) {
localStorage[config.caps.shs + '/secret'] = importKey.value.replace(/\s+/g, ' ')
e.preventDefault()
alert('Your public/private key has been updated')
}
location.hash = ""
location.reload()
}}, 'Import key'),
)
)
)
screen.appendChild(hyperscroll(content))
}
function everythingStream () {
var screen = document.getElementById('screen')
var content = h('div.content')
screen.appendChild(hyperscroll(content))
function createStream (opts) {
return pull(
Next(sbot.query, opts, ['value', 'timestamp']),
pull.map(function (msg) {
if (msg.value) {
return render(msg)
}
})
)
}
pull(
createStream({
limit: 10,
reverse: true,
live: false,
query: [{$filter: { value: { timestamp: { $gt: 0 }}}}]
}),
stream.bottom(content)
)
pull(
createStream({
limit: 10,
old: false,
live: true,
query: [{$filter: { value: { timestamp: { $gt: 0 }}}}]
}),
stream.top(content)
)
}
function backchannel () {
var screen = document.getElementById('screen')
var content = h('div.content')
screen.appendChild(hyperscroll(content))
var chatbox = h('input', {placeholder: 'Backchannel'})
var chat = h('div.content')
var publish = h('button.btn', 'Publish', {
onclick: function () {
if (chatbox.value) {
var content = {
text: chatbox.value,
type: 'scat_message'
}
sbot.publish(content, function (err, msg) {
if (err) throw err
chatbox.value = ''
console.log('Published!', msg)
})
}
}
})
chat.appendChild(h('div.message', chatbox, publish))
if (screen.firstChild.firstChild) {
screen.firstChild.insertBefore(chat, screen.firstChild.firstChild)
} else {
screen.firstChild.appendChild(chat)
}
function createStream (opts) {
return pull(
Next(sbot.query, opts, ['value', 'timestamp']),
pull.map(function (msg) {
if (msg.value) {
return render(msg)
}
})
)
}
pull(
createStream({
limit: 10,
reverse: true,
live: false,
query: [{$filter: { value: { content: {type: 'scat_message'}, timestamp: { $gt: 0 }}}}]
}),
stream.bottom(content)
)
pull(
createStream({
limit: 10,
old: false,
live: true,
query: [{$filter: { value: { content: {type: 'scat_message'}, timestamp: { $gt: 0 }}}}]
}),
stream.top(content)
)
}
function hash () {
return window.location.hash.substring(1)
}
module.exports = function () {
var src = hash()
if (ref.isFeed(src)) {
userStream(src)
} else if (ref.isMsg(src)) {
msgThread(src)
} else if (src == 'mentions') {
mentionsStream()
} else if (src == 'about') {
about()
} else if (src == 'backchannel') {
backchannel()
} else if (src == 'private') {
privateStream()
} else if (src == 'key') {
keyPage()
} else {
everythingStream()
}
function parseInvite (invite) {
return ref.parseInvite(invite)
}
// TODO: this should really only pop up if you have no friends
var currentScreen = document.getElementById('screen')
var invitebox = h('input', {placeholder: 'Invite Code Here'})
invitebox.value = config.invite
var invite = h('div.content', h('div.message#inviter',
'Hey, no one follows you. Your secure-scuttlebutt feed may not replicate unless a pub follows you. Either ', h('a', {href: '#key'}, 'import your key'), ' or use a pub invite:',
h('br'),
invitebox,
h('button', 'Accept', {onclick: function (e) {
var data = parseInvite(invitebox.value)
console.log(data)
e.preventDefault()
//sbot.gossip.connect(data.remote, function (err) {
//})
client(keys, {
remote: data.invite,
caps: config.caps,
manifest: {invite: {use: 'async'}, getAddress: 'async'}
}, function (err, remotebot) {
if (err) throw err
remotebot.invite.use({feed: id}, function (_err, msg) {
if (msg) {
sbot.publish({
type: 'contact',
contact: data.key,
following: true
})
}
})
setTimeout(function () {
location.hash = '#' + id
location.hash = '#'
}, 100)
})
}})
))
if (currentScreen.firstChild.firstChild) {
currentScreen.firstChild.insertBefore(invite, currentScreen.firstChild.firstChild)
} else {
currentScreen.firstChild.appendChild(invite)
}
sbot.friends.get({dest: id}, function (err, follows) {
for (var i in follows) {
if (follows[i] === true) {
var getInvite = document.getElementById('inviter')
if (getInvite) {
getInvite.parentNode.removeChild(getInvite)
}
}
}
})
}