aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoop Kiefte <ikojba@gmail.com>2020-02-01 03:01:40 +0100
committerJoop Kiefte <ikojba@gmail.com>2020-02-01 03:01:40 +0100
commitd5aa1cc524d34f112298f0d4cac0d6ccfb8817b1 (patch)
tree401bf3520bdbb2fcc69259bc57717434586739c5
parent908e4d9c762957876b8babee2b58c7ffd8c53a1e (diff)
parentd9325369c27eb5d96522d045004f32f1b01049f8 (diff)
Merge new contents and translate as much as possible TODO: translate settings.js
-rw-r--r--app.js67
-rw-r--r--bog.js133
-rw-r--r--composer.js11
-rw-r--r--css/style.css69
-rw-r--r--gossip.js417
-rw-r--r--identify.js233
-rw-r--r--index.html3
-rw-r--r--package-lock.json417
-rw-r--r--package.json6
-rw-r--r--render.js215
-rw-r--r--server.js256
-rw-r--r--settings.js102
-rw-r--r--views.js352
13 files changed, 1531 insertions, 750 deletions
diff --git a/app.js b/app.js
index 757e62f..b908bf8 100644
--- a/app.js
+++ b/app.js
@@ -8,53 +8,8 @@ function route (keys) {
var screen = document.getElementById('screen')
screen.appendChild(scroller)
- function nameCheck (id) {
- localforage.getItem('name:' + id).then(name => {
- if (!name) {
- var identify = h('div', {id: 'identify', classList: 'message'})
- scroller.appendChild(identify)
- identify.appendChild(h('span', {innerHTML: marked("Saluton [" + keys.publicKey.substring(0, 10) + "...](#"+ keys.publicKey +")! Bonvenon al Interskri.be. Se vi havas ajnan demandon, sentu vin libera demandi ĉe [@LaPingvino](#@gl6HzjWL8SndhDGpN1mtLkf6OXdBQi67vaAyCoCnsCU=).")}))
-
- identify.appendChild(h('span', {innerHTML: marked("Via nuna publika ŝlosilo ankoraŭ ne havas nomon. Vi povas ĉu importi vian ekzistantant identecon en la [ŝlosilo](#key)-paĝo, aŭ identigi vin per la suba kesto. Ne estas ajna devigo identigi vin, sed vi vidos ĉi tiun bonvenigon dum vi ne donis nomon al vi.")}))
-
- var input = h('input', {placeholder: 'Donu nomon por vi'})
-
- identify.appendChild(h('div', [
- input,
- h('button', {
- onclick: function () {
- if (input.value) {
- content = {
- type: 'name',
- named: id,
- name: input.value
- }
- publish(content, keys)
- setTimeout(function () {
- getName(id, keys)
- setTimeout(function () {
- location.reload()
- }, 1000)
- }, 1000)
- }
- }
- }, ['Identigi'])
- ]))
-
- identify.appendChild(h('span', {innerHTML: marked("Sekve, certigu ke via paro de publika kaj privata ŝlosilo de la [ŝlosilo](#key)-paĝo estu konservita en sekura loko por ke vi povu uzadi la saman identecon. Nur vi povas aliri vian privatan ŝlosilon, do nur vi povas restarigi la eblon afiŝi al ĉi tiu identeco. Se vi perdas vian ŝlosilon, vi perdas vian kapablon afiŝi al ĉi tiu identeco por ĉiam.")}))
-
- identify.appendChild(h('span', {innerHTML: marked("Fine, la fontkodo de ĉi tiu paĝo troveblas en [mia persona kod-deponejo](https://git.kiefte.eu/lapingvino/bogbook-esperanto)")}))
-
- }
- })
- }
-
- nameCheck(keys.publicKey)
-
- if (src === 'key') {
- keyPage(keys)
- } else if (src === 'pubs') {
- pubs()
+ if (src === 'settings') {
+ settingsPage(keys)
} else if (src[0] === '@') {
profilePage(src, keys)
} else if (src[0] === '?') {
@@ -71,11 +26,19 @@ keys().then(key => {
var navbar = h('div', {classList: 'navbar'}, [
h('div', {classList: 'internal'}, [
- h('li', [h('a', {href: '#'}, ['Hejmo'])]),
- h('li', [h('a', {href: '#' + key.publicKey}, [getName(key.publicKey, keys)])]),
- h('li', [h('a', {href: '#key'}, ['Ŝlosilo'])]),
- h('li', [h('a', {href: '#pubs'}, ['Konigejoj'])]),
- h('li', {classList: 'right'}, [h('a', {href: 'https://git.kiefte.eu/lapingvino/bogbook-esperanto'}, ['Fontkodo'])]),
+ h('li', [h('a', {href: '#' + key.publicKey},
+ [
+ getImage(key.publicKey, keys),
+ ])
+ ]),
+ h('li', [h('a', {href: '#' + key.publicKey},
+ [
+ getName(key.publicKey, keys)
+ ])
+ ]),
+ h('li', [h('a', {href: '#'}, ['Ĉiuj'])]),
+ h('li', [h('a', {href: '#?' + key.publicKey}, ['Mencioj'])]),
+ h('li', {classList: 'right'}, [h('a', {href: '#settings'}, ['Agordoj'])]),
h('form', { classList: 'search',
onsubmit: function (e) {
window.location.hash = '?' + search.value
diff --git a/bog.js b/bog.js
index 1aff354..2170216 100644
--- a/bog.js
+++ b/bog.js
@@ -12,7 +12,6 @@ if ((typeof process !== 'undefined') && (process.release.name === 'node')) {
// EX: open(msg).then(content => { console.log(content) })
async function open (msg) {
-
var pubkey = nacl.util.decodeBase64(msg.author.substring(1))
var sig = nacl.util.decodeBase64(msg.signature)
var opened = await JSON.parse(nacl.util.encodeUTF8(nacl.sign.open(sig, pubkey)))
@@ -77,11 +76,10 @@ async function unbox (boxed, sender, keys) {
var nonceMsg = nacl.util.decodeBase64(boxed)
var nonce = nonceMsg.slice(0, nacl.box.nonceLength)
var msg = nonceMsg.slice(nacl.box.nonceLength, nonceMsg.length)
- var message = nacl.box.open(msg, nonce, ed2curve.convertPublicKey(nacl.util.decodeBase64(sender.substring(1))), ed2curve.convertSecretKey(nacl.util.decodeBase64(keys.privateKey)))
+ var message = nacl.util.encodeUTF8(nacl.box.open(msg, nonce, ed2curve.convertPublicKey(nacl.util.decodeBase64(sender.substring(1))), ed2curve.convertSecretKey(nacl.util.decodeBase64(keys.privateKey))))
return message
}
-
// bog.get -- iterates over log and returns a post.
// EX: get('%x5T7KZ5haR2F59ynUuCggwEdFXlLHEtFoBQIyKYppZYerq9oMoIqH76YzXQpw2DnYiM0ugEjePXv61g3E4l/Gw==').then(msg => { console.log(msg)})
@@ -96,35 +94,40 @@ async function get (key) {
}
}
+async function getTitle (key) {
+ var log = await localforage.getItem('log')
+ if (log != null) {
+ for (var i = log.length - 1; i >= 0; --i) {
+ if (log[i].key === key) {
+ return log[i].text.substring(0, 15) + '…'
+ }
+ }
+ }
+}
+
+
// bog.getImage
-function getImage (id, keys) {
- var image = h('img', {classList: 'avatar'})
+function getImage (id, keys, classList) {
+ if (classList) {
+ var image = h('img', {classList: classList})
+ } else {
+ var image = h('img', {classList: 'avatar'})
+ }
- localforage.getItem('image:' + id).then(cache => {
- if (cache) {
- console.log('GOT IMAGE FROM CACHE: ' + cache)
- return image.src = cache
- } else {
- bog().then(log => {
- if (log) {
- for (var i = 0; i < log.length; i++) {
- if ((log[i].imaged === id) && (log[i].author === keys.publicKey)) {
- // if you've identified someone as something else show that something else
- localforage.setItem('image:' + id, log[i].image)
- console.log('FINDING IMAGE AND SAVING TO CACHE: ' + log[i].image)
- image.src = cache
- return image.src = cache
- } else if ((log[i].imaged === id) && (log[i].author === id)) {
- // else if show the image they gave themselves
- localforage.setItem('image:' + id, log[i].image)
- console.log('FINDING IMAGE AND SAVING TO CACHE: ' + log[i].image)
- image.src = cache
- return image.src = cache
- }
- }
+ bog().then(log => {
+ if (log) {
+ for (var i = 0; i < log.length; i++) {
+ if ((log[i].imaged === id) && (log[i].author === keys.publicKey)) {
+ // if you've identified someone as something else show that something else
+ localforage.setItem('image:' + id, log[i].image)
+ return image.src = log[i].image
+ } else if ((log[i].imaged === id) && (log[i].author === id)) {
+ // else if show the image they gave themselves
+ localforage.setItem('image:' + id, log[i].image)
+ return image.src = log[i].image
}
- })
+ }
}
})
return image
@@ -137,34 +140,59 @@ function getName (id, keys) {
name.textContent = id.substring(0, 10) + '...'
- localforage.getItem('name:' + id).then(cache => {
+ bog().then(log => {
+ if (log) {
+ for (var i = 0; i < log.length; i++ ) {
+ if ((log[i].named === id) && (log[i].author === keys.publicKey)) {
+ // if you've identified someone as something else show that something else
+ localforage.setItem('name:' + id, log[i].name)
+ return name.textContent = '@' + log[i].name
+ } else if ((log[i].named === id) && (log[i].author === id)) {
+ // else if show the name they gave themselves
+ localforage.setItem('name:' + id, log[i].name)
+ return name.textContent = '@' + log[i].name
+ }
+ // there should probably be some sort of sybil attack resiliance here (weight avatar name based on number of times used by individuals), but this will do for now.
+ }
+ }
+ })
+ return name
+}
+
+function getQuickImage (id, keys) {
+ var image = h('img', {classList: 'avatar'})
+
+ localforage.getItem('image:' + id).then(cache => {
if (cache) {
- console.log('GOT NAME FROM CACHE: ' + cache)
- return name.textContent = '@' + cache
- } else {
- bog().then(log => {
- if (log) {
- for (var i = 0; i < log.length; i++ ) {
- if ((log[i].named === id) && (log[i].author === keys.publicKey)) {
- // if you've identified someone as something else show that something else
- localforage.setItem('name:' + id, log[i].name)
- console.log('FINDING NAME AND SAVING TO CACHE: ' + log[i].name)
- return name.textContent = '@' + log[i].name
- } else if ((log[i].named === id) && (log[i].author === id)) {
- // else if show the name they gave themselves
- localforage.setItem('name:' + id, log[i].name)
- console.log('FINDING NAME AND SAVING TO CACHE: ' + log[i].name)
- return name.textContent = '@' + log[i].name
- }
- // there should probably be some sort of sybil attack resiliance here (weight avatar name based on number of times used by individuals), but this will do for now.
- }
- }
- })
+ image.src = cache
}
})
+
+ return image
+}
+
+function getQuickName (id, keys) {
+ var name = h('span', [id.substring(0, 10)])
+
+ localforage.getItem('name:' + id).then(cache => {
+ if (cache) {
+ name.textContent = '@' + cache
+ }
+ })
+
return name
}
+async function quickName (id, keys) {
+ var cache = await localforage.getItem('name:' + id)
+
+ if (cache) {
+ return '@' + cache
+ } else {
+ return id.substring(0, 10)
+ }
+}
+
// bog.regenerate -- regenerates main log by taking all of the feed logs, combinging them, and then sorting them
function regenerate (home) {
@@ -174,7 +202,7 @@ function regenerate (home) {
if (key[0] == '@') {
newlog = newlog.concat(value)
}
- console.log(newlog)
+ //console.log(newlog)
}).then(function () {
newlog.forEach(function (msg) {
var pubkey = nacl.util.decodeBase64(msg.author.substring(1))
@@ -184,7 +212,7 @@ function regenerate (home) {
openedlog.push(opened)
})
- console.log(openedlog)
+ //console.log(openedlog)
openedlog.sort((a, b) => a.timestamp - b.timestamp)
@@ -203,7 +231,6 @@ function regenerate (home) {
// EX: bog().then(log => { console.log(log)})
// EX: bog('@ExE3QXmBhYQlGVA3WM2BD851turNzwhruWbIpMd7rbQ=').then(log => { console.log(log)})
-
async function bog (feed) {
if (feed) {
var log = await localforage.getItem(feed)
diff --git a/composer.js b/composer.js
index 661b617..1da7d1b 100644
--- a/composer.js
+++ b/composer.js
@@ -6,7 +6,7 @@ function composer (keys, reply, gotName, edit) {
console.log(reply)
var textarea = h('textarea', [reply.text])
} else if (gotName) {
- var textarea = h('textarea', ['[' + gotName.textContent + '](' + reply.author + ')'])
+ var textarea = h('textarea', ['[' + gotName + '](' + reply.author + ')'])
} else {
var textarea = h('textarea', {placeholder: 'Verki novan afiŝon... La afiŝo kiun vi verkas ĉi tie aldoniĝos al la bog-reto subskribita per via ŝlosilo. Ĉu vi jam sekure konservis ĝin ie?'})
}
@@ -54,8 +54,9 @@ function composer (keys, reply, gotName, edit) {
if (edit) {
console.log('APPENDING EDIT')
var gotit = document.getElementById(reply.key)
- gotit.appendChild(h('div', {classList: 'submessage'}, [render(msg, keys)]))
+ //gotit.appendChild(h('div', {classList: 'submessage'}, [render(msg, keys)]))
var newContent = h('div', {innerHTML: marked(msg.text)})
+ //console.log(gotit.childNodes.length)
gotit.firstChild.replaceChild(newContent, gotit.firstChild.childNodes[1])
}
if (reply) {
@@ -66,15 +67,15 @@ function composer (keys, reply, gotName, edit) {
messageDiv.removeChild(messageDiv.firstChild)
messageDiv = h('div')
messageDiv.appendChild(cache)
- scroller.insertBefore(messageDiv, scroller.childNodes[2])
- scroller.insertBefore(render(msg, keys), scroller.childNodes[3])
+ scroller.insertBefore(messageDiv, scroller.childNodes[1])
+ scroller.insertBefore(render(msg, keys), scroller.childNodes[2])
} else {
messageDiv.appendChild(render(msg, keys))
}
})
})
}
- }, ['Publikigi']))
+ }, ['Afiŝi']))
})
})
}
diff --git a/css/style.css b/css/style.css
index 0e27c1e..113e061 100644
--- a/css/style.css
+++ b/css/style.css
@@ -9,7 +9,7 @@ body {
}
p {
- margin-top: 1ex;
+ margin-top: .5ex;
margin-bottom: 1ex;
font-size: 1em;
}
@@ -36,35 +36,73 @@ hr {
margin-bottom: .9em;
}
-
#screen {
position: absolute;
- top: 35px;
+ top: 40px;
right: 0;
left: 0;
bottom: 0;
}
#scroller {
- max-width: 50em;
+ max-width: 680px;
margin-right: auto;
margin-left: auto;
}
+@media only screen and (max-width: 480px) {
+ #screen { top: 57px; right: 5px; left: 5px; }
+}
+
.right { float: right;}
+.banner {height: 10px; }
+
.message, .profile {
border: 1px solid #ddd;
background: white;
- margin-top: .5em;
padding: .3em .5em;
+}
+
+.message {
+ margin-top: .5em;
border-radius: 5px;
}
-.message, .message > *, .navbar, .navbar > * {
+#scroller:last-child { margin-bottom: 10em; }
+
+.message, .message > *, .navbar, .navbar > *, #ad, #ad > *, #viewer > * {
animation: fadein .5s;
}
+#ad, #pm {
+ background: white;
+ font-size: .8em;
+ border: 1px solid #ddd;
+ border-radius: 5px;
+ position: fixed;
+ padding: .3em .5em;
+ bottom: 5px;
+ width: 250px;
+}
+
+#ad {
+ left: 5px;
+}
+
+#pm {
+ right: 5px;
+}
+
+#ad button, #pm button {
+ font-size: .8em;
+ margin: 0;
+ padding: 0;
+ padding-left: 5px; padding-right: 5px;
+ position: absolute;
+ bottom: 2px; right: 2px;
+}
+
@keyframes fadein {
from { opacity: 0; }
to { opacity: 1; }
@@ -146,7 +184,7 @@ textarea {
position: fixed;
z-index: 1000;
margin: 0;
- padding-top: .3em;
+ padding-top: .4em;
padding-bottom: .3em;
left: 0; right: 0;
top: 0;
@@ -167,17 +205,18 @@ textarea {
}
form.search, input.search {
- width: 100px;
+ width: 175px;
float: right;
margin: 0;
padding: 0;
+ padding-left: .1em;
color: #f5f5f5;
background: #444;
border-radius: 3px;
}
form.search {
- margin-top: .3em;
+ margin-top: .20em;
}
.navbar li.right {
@@ -187,7 +226,6 @@ form.search {
margin-right: 1.7em;
float: right;
list-style-type: none;
- background: #333;
border-radius: 100%;
}
@@ -202,13 +240,20 @@ form.search {
text-decoration: none;
}
-.avatar { width: 25px; height: 25px; vertical-align: middle; border-radius: 5px; margin-right: .2em; }
+.profileAvatar { width: 95px; height: 95px; vertical-align: top; border-radius: 5px; object-fit: cover; margin-right: .25em; margin-bottom: .25em;}
+.avatar { width: 25px; height: 25px; vertical-align: middle; object-fit: cover; border-radius: 5px; margin-right: .5em; }
+
+.image { width: 75px; height: 75px; object-fit: cover; margin-right: .2em; border-radius: 5px; cursor: pointer;}
+
+#viewer {position: fixed; left: 2em; top: 3em; background: white; padding: .5em; border: 1px solid #ddd; border-radius: 5px;}
+
+#viewer img { border-radius: 5px; margin-left: auto; margin-right: auto; cursor: pointer;}
button {
display: inline-block;
*display: inline;
padding: 4px 12px;
- margin-top: 0;
+ margin-top: 5px;
margin-bottom: 0;
*margin-left: .3em;
font-size: 14px;
diff --git a/gossip.js b/gossip.js
index d6785c0..8fdf55f 100644
--- a/gossip.js
+++ b/gossip.js
@@ -1,267 +1,200 @@
-function blobSync (blob, author, keys, needs) {
- console.log(needs)
+function processreq (req, pubkey, connection, keys) {
+ if (req.seq === 0 || req.seq) {
+ bog(req.author).then(feed => {
+ if (feed) {
+ open(feed[0]).then(msg => {
+ if (req.seq > msg.seq) {
+ var reqdiff = JSON.stringify({author: req.author, seq: msg.seq})
+ box(reqdiff, pubkey, keys).then(boxed => {
+ connection.send(JSON.stringify({
+ requester: keys.publicKey,
+ box: boxed
+ }))
+ })
+ }
- var wsServers
+ if (req.seq < msg.seq) {
+ var endrange = feed.length - req.seq - 25
+ if (endrange < 0) {
+ endrange = feed.length - req.seq - 1
+ }
+ var baserange = feed.length - req.seq
+ var diff = JSON.stringify(
+ feed.slice(
+ endrange,
+ baserange)
+ )
+ box(diff, pubkey, keys).then(boxed => {
+ connection.send(JSON.stringify({
+ requester: keys.publicKey,
+ box: boxed
+ }))
+ })
+ }
+ })
+ }
+ })
+ }
- // duplicate code, we should abstract this
- localforage.getItem('securepubs').then(function (servers) {
- if (servers) {
- wsServers = servers
- } else {
- servers = ['wss://interskri.be/ws', 'ws://localhost:8080', 'wss://interskri.be/bogbook', 'ws://bogbook.com']
- var pubs = []
- servers.forEach(server => {
- var ws = new WebSocket(server)
- ws.onopen = function () {
- ws.send(JSON.stringify({requester: keys.publicKey, sendpub: true}))
- }
- ws.onmessage = function (message) {
- pubs.push(server + '/~' + message.data)
- localforage.setItem('securepubs', pubs)
- }
+ if (req.latest) {
+ var latest
+ latest = document.getElementById('latest')
+ var src = window.location.hash.substring(1)
+ if ((!latest) && (src == req.latest)) {
+ latest = h('div', {id: 'latest'})
+ latest.appendChild(h('div', {classList: 'message', innerHTML: marked('**Ankoraŭ sinkronigas la fluon**. Intertempe jen la lastaj kvin mesaĝoj...')
+ }))
+ req.feed.forEach(post => {
+ open(post).then(msg => {
+ latest.appendChild(render(msg, keys))
+ })
})
- wsServers = pubs
- }
- }).then(function () {
- wsServers.forEach(function (server, index) {
- setTimeout(function () {
- var split = server.split('~')
- var serverurl = split[0]
- var serverpub = split[1]
- var ws = new WebSocket(serverurl)
+ scroller.firstChild.appendChild(latest)
- console.log('requesting ' + blob + ' from ' + server)
- ws.onopen = function () {
- var req = {
- blob: blob,
- needs: needs
- }
+ var timer = setInterval(function () {
+ localforage.getItem(req.latest).then(feed => {
+ open(feed[0]).then(msg => {
+ open(req.feed[0]).then(latestmsg => {
+ src = window.location.hash.substring(1)
+ if (msg.seq >= latestmsg.seq) {
+ latest.parentNode.removeChild(latest)
+ clearInterval(timer)
+ //console.log('we are caught up, deleting latest div')
+ }
+ if (src != req.latest) {
+ clearInterval(timer)
+ //console.log('we navigated away')
+ }
+ })
+ })
+ })
+ //console.log('checking to see if we have caught up')
+ }, 5000)
+ }
+ }
- box(JSON.stringify(req), serverpub, keys).then(boxed => {
- var obj = {
- requester: keys.publicKey,
- box: boxed
+ if (Array.isArray(req)) {
+ open(req[0]).then(msg => {
+ localforage.getItem(msg.author).then(feed => {
+ if (!feed) {
+ localforage.setItem(msg.author, req)
+ localforage.getItem('log').then(log => {
+ if (!log) { var log = [] }
+ for (var i = req.length -1; i >= 0; --i) {
+ open(req[i]).then(opened => {
+ log.unshift(opened)
+ var src = window.location.hash.substring(1)
+ if ((src === msg.author) || (src === '')) {
+ var scroller = document.getElementById('scroller')
+ scroller.insertBefore(render(opened, keys), scroller.childNodes[1])
+ }
+ if (opened.seq === req.length) {
+ localforage.setItem('log', log)
+ }
+ })
}
- ws.send(JSON.stringify(obj))
})
- }
- ws.onmessage = function (message) {
- var serverreq = JSON.parse(message.data)
- unbox(serverreq.box, serverreq.requester, keys).then(unboxed => {
-
- var unboxedreq = JSON.parse(nacl.util.encodeUTF8(unboxed))
- //console.log(unboxedreq)
- if (unboxedreq.blobFile) {
- var openedimg = nacl.sign.open(nacl.util.decodeBase64(unboxedreq.blobFile), nacl.util.decodeBase64(author.substring(1)))
- if (openedimg) {
- localforage.setItem(unboxedreq.blob, unboxedreq.blobFile)
- }
- } else {
- localforage.getItem(unboxedreq.blob).then(blob => {
- if (blob) {
- var nextreq = {
- author: author,
- blob: unboxedreq.blob,
- blobFile: blob
- }
- box(JSON.stringify(nextreq), serverreq.requester, keys).then(boxed => {
- var obj = {
- requester: keys.publicKey,
- box: boxed
+ }
+ if (feed) {
+ open(feed[0]).then(lastmsg => {
+ if (req.length + lastmsg.seq === msg.seq) {
+ var newlog = req.concat(feed)
+ localforage.setItem(msg.author, newlog)
+ localforage.getItem('log').then(log => {
+ if (!log) { var log = [] }
+ for (var i = req.length -1; i >= 0; --i) {
+ open(req[i]).then(opened => {
+ log.unshift(opened)
+ var src = window.location.hash.substring(1)
+ if ((src === msg.author) || (src === '')) {
+ var scroller = document.getElementById('scroller')
+ scroller.insertBefore(render(opened, keys), scroller.childNodes[1])
+ }
+ if (req.length + lastmsg.seq === opened.seq) {
+ localforage.setItem('log', log)
}
- ws.send(JSON.stringify(obj))
})
}
})
}
})
}
- }, index * 10000)
+ })
})
- })
+ }
}
-function sync (subs, keys) {
+function getpubkey (connection, keys) {
+ connection.onopen = () => {
+ connection.send(JSON.stringify({
+ requester: keys.publicKey, sendpub: true
+ }))
+ }
- var wsServers
+ connection.onmessage = (m) => {
+ localforage.setItem(m.origin, m.data)
+ }
+}
- localforage.getItem('securepubs').then(function (servers) {
- if (servers) {
- wsServers = servers
- } else {
- servers = ['wss://interskri.be/ws', 'ws://localhost:8080', 'wss://interskri.be/bogbook', 'ws://bogbook.com']
- var pubs = []
- servers.forEach(server => {
- var ws = new WebSocket(server)
- ws.onopen = function () {
- ws.send(JSON.stringify({requester: keys.publicKey, sendpub: true}))
- }
- ws.onmessage = function (message) {
- pubs.push(server + '/~' + message.data)
- localforage.setItem('securepubs', pubs)
- }
+function getfeed (feed, pubkey, connection, keys) {
+ bog(feed).then(log => {
+ var logseq = 0
+ connection.onopen = () => {
+ if (log) {
+ open(log[0]).then(msg => {
+ var string = JSON.stringify(msg)
+ box(string, pubkey, keys).then(boxed => {
+ connection.send(JSON.stringify({
+ requester: keys.publicKey,
+ box: boxed
+ }))
+ })
+ logseq = msg.seq
+ })
+ } else {
+ var msg = {
+ author: feed,
+ seq: logseq
+ }
+ box(JSON.stringify(msg), pubkey, keys).then(boxed => {
+ connection.send(JSON.stringify({
+ requester: keys.publicKey,
+ box: boxed
+ }))
+ })
+ }
+ }
+ connection.onmessage = (m) => {
+ var req = JSON.parse(m.data)
+ unbox(req.box, req.requester, keys).then(unboxed => {
+ var unboxedreq = JSON.parse(unboxed)
+ processreq(unboxedreq, pubkey, connection, keys)
})
- wsServers = pubs
}
- }).then(function () {
- subs.forEach(function (sub) {
- wsServers.forEach(function (server, index) {
- setTimeout(function () {
- console.log('SYNCING WITH: ' + server + ' to fetch ' + sub)
- var split = server.split('~')
- var serverurl = split[0]
- var serverpub = split[1]
- var ws = new WebSocket(serverurl)
-
- bog(sub).then(srclog => {
- if (srclog) {
- open(srclog[0]).then(msg => {
- ws.onopen = function () {
- var message = JSON.stringify(msg)
- // if we have a log then send the latest log and see if we get anything back
- box(message, serverpub, keys).then(boxed => {
- var obj = {
- requester: keys.publicKey,
- box: boxed
- }
- ws.send(JSON.stringify(obj))
- })
- }
- ws.onmessage = function (message) {
- var req = JSON.parse(message.data)
- console.log(req)
- unbox(req.box, req.requester, keys).then(unboxed => {
- var unboxedreq = JSON.parse(nacl.util.encodeUTF8(unboxed))
- console.log(unboxedreq)
- if (unboxedreq.seq === 0) {
- var stringedfeed = JSON.stringify(srclog)
- box(stringedfeed, serverpub, keys).then(boxed => {
- var obj = {
- requester: keys.publicKey,
- box: boxed
- }
- console.log('Sending entire log of ' + msg.author + ' to ' + serverpub)
- console.log(obj)
- ws.send(JSON.stringify(obj))
- })
- }
-
- if (unboxedreq.seq > msg.seq) {
- console.log('server feed is longer, requesting diff from server')
- var reqdiff = JSON.stringify({author: unboxedreq.author, seq: msg.seq})
- box(reqdiff, serverpub, keys).then(boxed => {
- var obj = {
- requester: keys.publicKey,
- box: boxed
- }
- ws.send(JSON.stringify(obj))
- })
- }
-
- if (unboxedreq.seq < msg.seq) {
- console.log('server feed is shorter, sending diff to server')
- var diff = JSON.stringify(srclog.slice(0, msg.seq - unboxedreq.seq))
- box(diff, serverpub, keys).then(boxed => {
- var obj = {
- requester: keys.publicKey,
- box: boxed
- }
- ws.send(JSON.stringify(obj))
- })
- }
+ })
+}
- if (Array.isArray(unboxedreq)) {
- console.log('received diff from server')
- open(unboxedreq[0]).then(msg => {
- localforage.getItem(msg.author).then(feed => {
- open(feed[0]).then(lastmsg => {
- if (unboxedreq.length + lastmsg.seq === msg.seq) {
- var newlog = unboxedreq.concat(feed)
- localforage.setItem(msg.author, newlog).then(success => {
- console.log('combined existing feed of ' + msg.author + ' with diff and saved to client')
- })
- localforage.getItem('log').then(log => {
- if (!log) {
- var log = []
- }
- for (var i = unboxedreq.length -1; i >= 0; --i) {
- open(unboxedreq[i]).then(opened => {
- log.unshift(opened)
- var scroller = document.getElementById('scroller')
- scroller.insertBefore(render(opened, keys), scroller.childNodes[2])
- if (unboxedreq.length + lastmsg.seq === opened.seq) {
- log.sort((a, b) => a.timestamp - b.timestamp)
- var reversed = log.reverse()
- localforage.setItem('log', reversed).then(success => {
- console.log('saved log with ' + opened.author + ' prepended to localForage')
- })
- }
- })
- }
- })
- }
- })
- })
- })
-
- }
-
- })
- }
- })
- } else {
- console.log('NO LOG IN CLIENT')
- ws.onopen = function () {
- var reqwhole = JSON.stringify({author: sub, seq: 0})
- box(reqwhole, serverpub, keys).then(boxed => {
- var obj = {
- requester: keys.publicKey,
- box: boxed
- }
- ws.send(JSON.stringify(obj))
- })
- }
- ws.onmessage = function (message) {
- var req = JSON.parse(message.data)
- console.log('received message from ' + req.requester)
- unbox(req.box, req.requester, keys).then(unboxed => {
- var unboxedreq = JSON.parse(nacl.util.encodeUTF8(unboxed))
- if (Array.isArray(unboxedreq)) {
- open(unboxedreq[0]).then(msg => {
- localforage.getItem(msg.author).then(feed => {
- if (!feed) {
- localforage.setItem(msg.author, unboxedreq).then(success => {
- console.log('saved log of ' + msg.author + ' to localforage')
- })
- localforage.getItem('log').then(log => {
- if (!log) {
- var log = []
- }
- for (var i = unboxedreq.length -1; i >= 0; --i) {
- open(unboxedreq[i]).then(opened => {
- log.unshift(opened)
- var scroller = document.getElementById('scroller')
- scroller.insertBefore(render(opened, keys), scroller.childNodes[2])
- if (opened.seq === unboxedreq.length) {
- log.sort((a, b) => a.timestamp - b.timestamp)
- var reversed = log.reverse()
- localforage.setItem('log', reversed).then(success => {
- console.log('saved log with ' + opened.author + ' prepended to localForage')
- })
- }
- })
- }
- })
- }
- })
- })
- }
- })
- }
- }
- })
- }, index * 100000)
- })
+function sync (feeds, keys) {
+ var pubs
+ localforage.getItem('pubs').then(pubs => {
+ if (!pubs) {
+ pubs = ['ws://' + location.hostname + ':8080', 'ws://bogbook.com']
+ localforage.setItem('pubs', pubs)
+ }
+ pubs.forEach(function (pub, index) {
+ setTimeout(function () {
+ var connection = new WebSocket(pub)
+ localforage.getItem(pub).then(pubkey => {
+ if (!pubkey) {
+ getpubkey(connection, keys)
+ }
+ if (pubkey) {
+ feeds.forEach(feed => {
+ getfeed(feed, pubkey, connection, keys)
+ })
+ }
+ })
+ }, index * 5000)
})
})
}
diff --git a/identify.js b/identify.js
index 83191e1..17e3f6c 100644
--- a/identify.js
+++ b/identify.js
@@ -1,21 +1,90 @@
-function identify (src, profile, keys) {
+function identify (src, profile, keys, name) {
var identifyDiv = h('div')
- if (src != keys.publicKey) {
- identifyDiv.appendChild(h('p', ['Atentu: ' + src + ' ne estas vi.']))
+ if ((src[0] == '@') && (src != keys.publicKey)) {
+ identifyDiv.appendChild(h('p', [
+ 'Atentu: ' + src.substring(0, 10) + '... ne estas vi. Vi estas: ',
+ h('a', {href: '#' + keys.publicKey}, [keys.publicKey.substring(0, 10) + '...'])
+ ]))
}
var photoURL = {}
+ // this could be a hell of a lot dry-er
+
+ // also we need to get rid of UI glitches when you hit the cancel button (it should return to the same state it started in)
+
+ var newBackground = h('span', [
+ h('input', {id: 'input', type: 'file',
+ onclick: function () {
+ var canvas = document.getElementById("canvas")
+ var ctx = canvas.getContext("2d")
+
+ var maxW
+ var maxH
+
+ var input = document.getElementById('input')
+ input.addEventListener('change', handleFiles)
+
+ function handleFiles(e) {
+ var img = new Image
+ img.onload = function() {
+ var iw = img.width
+ var ih = img.height
+
+ maxW = 800
+ maxH = 800
+
+ var scale = Math.min((maxW/iw), (maxH/ih))
+ var iwScaled = iw*scale
+ var ihScaled = ih*scale
+ canvas.width = iwScaled
+ canvas.height = ihScaled
+ ctx.drawImage(img, 0, 0, iwScaled, ihScaled)
+ photoURL.value = canvas.toDataURL('image/jpeg', 0.7)
+ }
+ img.src = URL.createObjectURL(e.target.files[0])
+ }
+ }
+ }),
+ h('canvas', {id: 'canvas', width: '0', height: '0'}),
+ h('button', {
+ onclick: function () {
+ identifyDiv.appendChild(identifyButtons)
+ newBackground.parentNode.removeChild(newBackground)
+ }
+ }, ['Cancel']),
+ h('button', {
+ onclick: function () {
+ if (photoURL.value) {
+ content = {
+ type: 'background',
+ backgrounded: src,
+ background: photoURL.value
+ }
+ localforage.removeItem('image:' + src)
+ publish(content, keys).then(post => {
+ open(post).then(msg => {
+ nameInput.value = ''
+ scroller.insertBefore(render(msg, keys), scroller.childNodes[1])
+ })
+ })
+ newBackground.parentNode.removeChild(newBackground)
+ identifyDiv.appendChild(identifyButton)
+ }
+ }
+ }, ['Afiŝi'])
+ ])
+
var newPhoto = h('span', [
h('input', {id: 'input', type: 'file',
onclick: function () {
var canvas = document.getElementById("canvas")
var ctx = canvas.getContext("2d")
- var maxW = 250
- var maxH = 250
+ var maxW
+ var maxH
var input = document.getElementById('input')
input.addEventListener('change', handleFiles)
@@ -24,29 +93,42 @@ function identify (src, profile, keys) {
var img = new Image
img.onload = function() {
var iw = img.width
+ console.log(iw)
var ih = img.height
+ console.log(ih)
+
+ if (iw > ih) {
+ maxW = 680
+ maxH = 500
+ }
+ if (iw < ih) {
+ maxW = 500
+ maxH = 680
+ }
+ if (iw == ih) {
+ maxW = 500
+ maxH = 500
+ }
+
var scale = Math.min((maxW/iw), (maxH/ih))
var iwScaled = iw*scale
var ihScaled = ih*scale
canvas.width = iwScaled
canvas.height = ihScaled
ctx.drawImage(img, 0, 0, iwScaled, ihScaled)
- console.log(canvas.toDataURL('image/jpeg', 0.9))
photoURL.value = canvas.toDataURL('image/jpeg', 0.9)
- //identifyDiv.appendChild(h('img', {src: photoURL.value}))
}
img.src = URL.createObjectURL(e.target.files[0])
}
}
}),
- h('p', ['Ni rekomendas alŝuti kvadratan foton. Ĝi aŭtomate tranĉiĝas al 250 je 250 px.']),
h('canvas', {id: 'canvas', width: '0', height: '0'}),
h('button', {
onclick: function () {
identifyDiv.appendChild(identifyButtons)
newPhoto.parentNode.removeChild(newPhoto)
}
- }, ['Cancel']),
+ }, ['Nuligi']),
h('button', {
onclick: function () {
if (photoURL.value) {
@@ -55,7 +137,6 @@ function identify (src, profile, keys) {
imaged: src,
image: photoURL.value
}
- console.log(content)
localforage.removeItem('image:' + src)
publish(content, keys).then(post => {
open(post).then(msg => {
@@ -67,7 +148,69 @@ function identify (src, profile, keys) {
identifyDiv.appendChild(identifyButton)
}
}
- }, ['Publikigi'])
+ }, ['Afiŝi'])
+ ])
+
+ var descInput = h('textarea', {placeholder: 'Nova priskribo'})
+
+ var newDescription = h('div', [
+ descInput,
+ h('button', {
+ onclick: function () {
+ if (descInput.value) {
+ content = {
+ type: 'description',
+ descripted: src,
+ description: descInput.value
+ }
+ publish(content, keys).then(post => {
+ open(post).then(msg => {
+ descInput.value = ''
+ scroller.insertBefore(render(msg, keys), scroller.childNodes[1])
+ })
+ })
+ newDescription.parentNode.removeChild(newDescription)
+ identifyDiv.appendChild(identifyButton)
+ }
+ }
+ }, ['Afiŝi']),
+ h('button', {
+ onclick: function () {
+ identifyDiv.appendChild(identifyButtons)
+ newDescription.parentNode.removeChild(newDescription)
+ }
+ }, ['Nuligi'])
+ ])
+
+ var locInput = h('input', {placeholder: 'Nova loko'})
+
+ var newLocation = h('div', [
+ locInput,
+ h('button', {
+ onclick: function () {
+ if (locInput.value) {
+ content = {
+ type: 'location',
+ located: src,
+ loc: locInput.value
+ }
+ publish(content, keys).then(post => {
+ open(post).then(msg => {
+ locationInput.value = ''
+ scroller.insertBefore(render(msg, keys), scroller.childNodes[1])
+ })
+ })
+ newLocation.parentNode.removeChild(newLocation)
+ identifyDiv.appendChild(identifyButton)
+ }
+ }
+ }, ['Afiŝi']),
+ h('button', {
+ onclick: function () {
+ identifyDiv.appendChild(identifyButtons)
+ newLocation.parentNode.removeChild(newLocation)
+ }
+ }, ['Nuligi'])
])
var nameInput = h('input', {placeholder: 'Nova nomo'})
@@ -93,7 +236,7 @@ function identify (src, profile, keys) {
identifyDiv.appendChild(identifyButton)
}
}
- }, ['Publikigi']),
+ }, ['Afiŝi']),
h('button', {
onclick: function () {
identifyDiv.appendChild(identifyButtons)
@@ -102,35 +245,71 @@ function identify (src, profile, keys) {
}, ['Nuligi'])
])
- var identifyButtons = h('span', [
- h('button', {
+ var identifyButtons = h('span')
+
+ if (src[0] == '@') {
+ identifyButtons.appendChild(h('button', {
onclick: function () {
identifyDiv.appendChild(newName)
identifyButtons.parentNode.removeChild(identifyButtons)
}
- }, ['Identigi ' + src.substring(0, 10) + '... per nova nomo']),
- h('button', {
+ }, ['Nova nomo']))
+ identifyButtons.appendChild(h('button', {
onclick: function () {
- identifyDiv.appendChild(newPhoto)
+ identifyDiv.appendChild(newBackground)
identifyButtons.parentNode.removeChild(identifyButtons)
}
- }, ['Identigi ' + src.substring(0, 10) + '... per nova foto']),
- h('button', {
+ }, ['Nova fono']))
+ identifyButtons.appendChild(h('button', {
onclick: function () {
- identifyDiv.appendChild(identifyButton)
+ identifyDiv.appendChild(newDescription)
identifyButtons.parentNode.removeChild(identifyButtons)
}
- }, ['Nuligi'])
- ])
+ }, ['Nova priskribo']))
- var identifyButton = h('button', {
+ }
+ //}, ['Identify ' + src.substring(0, 10) + '... with a new name']),
+ identifyButtons.appendChild(h('button', {
onclick: function () {
- profile.appendChild(identifyDiv)
- profile.appendChild(identifyButtons)
- identifyButton.parentNode.removeChild(identifyButton)
+ identifyDiv.appendChild(newPhoto)
+ identifyButtons.parentNode.removeChild(identifyButtons)
}
- },['Identigi ' + src.substring(0, 10) + '...'])
+ }, ['Nova bildo']))
+ identifyButtons.appendChild(h('button', {
+ onclick: function () {
+ identifyDiv.appendChild(newLocation)
+ identifyButtons.parentNode.removeChild(identifyButtons)
+ }
+ }, ['Nova loko']))
+
+
+ //}, ['Identify ' + src.substring(0, 10) + '... with a new photo']),
+ identifyButtons.appendChild(h('button', {
+ onclick: function () {
+ identifyDiv.appendChild(identifyButton)
+ identifyButtons.parentNode.removeChild(identifyButtons)
+ }
+ }, ['Nuligi']))
+ /*if (src[0] == '@') {
+ var identifyButton = h('button', {
+ onclick: function () {
+ profile.appendChild(identifyDiv)
+ profile.appendChild(identifyButtons)
+ identifyButton.parentNode.removeChild(identifyButton)
+ }
+ }, ['Identify ' + name])
+ } else { */
+ var identifyButton = h('button', {
+ onclick: function () {
+ profile.appendChild(identifyDiv)
+ profile.appendChild(identifyButtons)
+ identifyButton.parentNode.removeChild(identifyButton)
+ }
+ //}, ['Add to ' + src.substring(0, 10) + '...'])
+ }, ['+'])
+ //}
+
return identifyButton
}
diff --git a/index.html b/index.html
index ba26d88..09384da 100644
--- a/index.html
+++ b/index.html
@@ -16,9 +16,10 @@
<script src="./lib/misc.js"></script>
<script src="bog.js"></script>
<script src="composer.js"></script>
+ <script src="settings.js"></script>
<script src="identify.js"></script>
- <script src="gossip.js"></script>
<script src="render.js"></script>
+ <script src="gossip.js"></script>
<script src="views.js"></script>
<script src="app.js"></script>
</body>
diff --git a/package-lock.json b/package-lock.json
index 799f9d0..e17dee8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,32 +1,99 @@
{
"name": "bogbook",
- "version": "1.5.0",
+ "version": "1.8.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
+ "accepts": {
+ "version": "1.3.7",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
+ "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
+ "requires": {
+ "mime-types": "~2.1.24",
+ "negotiator": "0.6.2"
+ }
+ },
+ "any-promise": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
+ "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8="
+ },
"async-limiter": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
- "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg=="
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
+ "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="
},
- "charset": {
+ "cache-content-type": {
"version": "1.0.1",
- "resolved": "https://registry.npmjs.org/charset/-/charset-1.0.1.tgz",
- "integrity": "sha512-6dVyOOYjpfFcL1Y4qChrAoQLRHvj2ziyhcm0QJlhOcAhykL/k1kTUPbeo+87MNRTRdk2OIIsIXbuF3x2wi5EXg=="
- },
- "ecstatic": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-4.1.2.tgz",
- "integrity": "sha512-lnrAOpU2f7Ra8dm1pW0D1ucyUxQIEk8RjFrvROg1YqCV0ueVu9hzgiSEbSyROqXDDiHREdqC4w3AwOTb23P4UQ==",
- "requires": {
- "charset": "^1.0.1",
- "he": "^1.1.1",
- "mime": "^2.4.1",
- "minimist": "^1.1.0",
- "on-finished": "^2.3.0",
- "url-join": "^4.0.0"
+ "resolved": "https://registry.npmjs.org/cache-content-type/-/cache-content-type-1.0.1.tgz",
+ "integrity": "sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA==",
+ "requires": {
+ "mime-types": "^2.1.18",
+ "ylru": "^1.2.0"
+ }
+ },
+ "co": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
+ "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
+ },
+ "content-disposition": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
+ "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
+ "requires": {
+ "safe-buffer": "5.1.2"
}
},
+ "content-type": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+ "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
+ },
+ "cookies": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.8.0.tgz",
+ "integrity": "sha512-8aPsApQfebXnuI+537McwYsDtjVxGm8gTIzQI3FDW6t5t/DAhERxtnbEPN/8RX+uZthoz4eCOgloXaE5cYyNow==",
+ "requires": {
+ "depd": "~2.0.0",
+ "keygrip": "~1.1.0"
+ },
+ "dependencies": {
+ "depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
+ }
+ }
+ },
+ "debug": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+ "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "deep-equal": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
+ "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU="
+ },
+ "delegates": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
+ "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
+ },
+ "depd": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+ "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
+ },
+ "destroy": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
+ "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
+ },
"ed2curve": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/ed2curve/-/ed2curve-0.2.1.tgz",
@@ -47,25 +114,187 @@
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
},
- "he": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
- "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
+ "encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
+ },
+ "error-inject": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/error-inject/-/error-inject-1.0.0.tgz",
+ "integrity": "sha1-4rPZG1Su1nLzCdlQ0VSFD6EdTzc="
+ },
+ "escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
+ },
+ "fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
+ },
+ "http-assert": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/http-assert/-/http-assert-1.4.1.tgz",
+ "integrity": "sha512-rdw7q6GTlibqVVbXr0CKelfV5iY8G2HqEUkhSk297BMbSpSL8crXC+9rjKoMcZZEsksX30le6f/4ul4E28gegw==",
+ "requires": {
+ "deep-equal": "~1.0.1",
+ "http-errors": "~1.7.2"
+ }
+ },
+ "http-errors": {
+ "version": "1.7.3",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz",
+ "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==",
+ "requires": {
+ "depd": "~1.1.2",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.1.1",
+ "statuses": ">= 1.5.0 < 2",
+ "toidentifier": "1.0.0"
+ }
+ },
+ "inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
+ "is-generator-function": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.7.tgz",
+ "integrity": "sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw=="
},
"is-wsl": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz",
"integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0="
},
- "mime": {
- "version": "2.4.3",
- "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.3.tgz",
- "integrity": "sha512-QgrPRJfE+riq5TPZMcHZOtm8c6K/yYrMbKIoRfapfiGLxS8OTeIfRhUGW5LU7MlRa52KOAGCfUNruqLrIBvWZw=="
+ "keygrip": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz",
+ "integrity": "sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==",
+ "requires": {
+ "tsscmp": "1.0.6"
+ }
+ },
+ "koa": {
+ "version": "2.11.0",
+ "resolved": "https://registry.npmjs.org/koa/-/koa-2.11.0.tgz",
+ "integrity": "sha512-EpR9dElBTDlaDgyhDMiLkXrPwp6ZqgAIBvhhmxQ9XN4TFgW+gEz6tkcsNI6BnUbUftrKDjVFj4lW2/J2aNBMMA==",
+ "requires": {
+ "accepts": "^1.3.5",
+ "cache-content-type": "^1.0.0",
+ "content-disposition": "~0.5.2",
+ "content-type": "^1.0.4",
+ "cookies": "~0.8.0",
+ "debug": "~3.1.0",
+ "delegates": "^1.0.0",
+ "depd": "^1.1.2",
+ "destroy": "^1.0.4",
+ "encodeurl": "^1.0.2",
+ "error-inject": "^1.0.0",
+ "escape-html": "^1.0.3",
+ "fresh": "~0.5.2",
+ "http-assert": "^1.3.0",
+ "http-errors": "^1.6.3",
+ "is-generator-function": "^1.0.7",
+ "koa-compose": "^4.1.0",
+ "koa-convert": "^1.2.0",
+ "on-finished": "^2.3.0",
+ "only": "~0.0.2",
+ "parseurl": "^1.3.2",
+ "statuses": "^1.5.0",
+ "type-is": "^1.6.16",
+ "vary": "^1.1.2"
+ }
+ },
+ "koa-compose": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-4.1.0.tgz",
+ "integrity": "sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw=="
},
- "minimist": {
+ "koa-convert": {
"version": "1.2.0",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
- "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
+ "resolved": "https://registry.npmjs.org/koa-convert/-/koa-convert-1.2.0.tgz",
+ "integrity": "sha1-2kCHXfSd4FOQmNFwC1CCDOvNIdA=",
+ "requires": {
+ "co": "^4.6.0",
+ "koa-compose": "^3.0.0"
+ },
+ "dependencies": {
+ "koa-compose": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-3.2.1.tgz",
+ "integrity": "sha1-qFzLQLfZhtjlo0Wzoazo6rz1Tec=",
+ "requires": {
+ "any-promise": "^1.1.0"
+ }
+ }
+ }
+ },
+ "koa-send": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/koa-send/-/koa-send-5.0.0.tgz",
+ "integrity": "sha512-90ZotV7t0p3uN9sRwW2D484rAaKIsD8tAVtypw/aBU+ryfV+fR2xrcAwhI8Wl6WRkojLUs/cB9SBSCuIb+IanQ==",
+ "requires": {
+ "debug": "^3.1.0",
+ "http-errors": "^1.6.3",
+ "mz": "^2.7.0",
+ "resolve-path": "^1.4.0"
+ }
+ },
+ "koa-static-server": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/koa-static-server/-/koa-static-server-1.4.0.tgz",
+ "integrity": "sha512-ZkGzD9+2OZubOL458GL8p7vEGfaneGGKSKIUJw9ftXzn36capQw3Wu5A//o7S10tQNgD1oYs96LGPtqtkcuXbQ==",
+ "requires": {
+ "koa-send": "^5.0.0",
+ "upath": "^1.0.2"
+ }
+ },
+ "media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
+ },
+ "mime-db": {
+ "version": "1.42.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz",
+ "integrity": "sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ=="
+ },
+ "mime-types": {
+ "version": "2.1.25",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.25.tgz",
+ "integrity": "sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg==",
+ "requires": {
+ "mime-db": "1.42.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ },
+ "mz": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
+ "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
+ "requires": {
+ "any-promise": "^1.0.0",
+ "object-assign": "^4.0.1",
+ "thenify-all": "^1.0.0"
+ }
+ },
+ "negotiator": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
+ "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
},
"on-finished": {
"version": "2.3.0",
@@ -75,30 +304,102 @@
"ee-first": "1.1.1"
}
},
+ "only": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/only/-/only-0.0.2.tgz",
+ "integrity": "sha1-Kv3oTQPlC5qO3EROMGEKcCle37Q="
+ },
"open": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/open/-/open-6.2.0.tgz",
- "integrity": "sha512-Vxf6HJkwrqmvh9UAID3MnMYXntbTxKLOSfOnO7LJdzPf3NE3KQYFNV0/Lcz2VAndbRFil58XVCyh8tiX11fiYw==",
+ "version": "6.4.0",
+ "resolved": "https://registry.npmjs.org/open/-/open-6.4.0.tgz",
+ "integrity": "sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==",
"requires": {
"is-wsl": "^1.1.0"
}
},
- "sanitize-filename": {
- "version": "1.6.3",
- "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz",
- "integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==",
+ "parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
+ },
+ "resolve-path": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/resolve-path/-/resolve-path-1.4.0.tgz",
+ "integrity": "sha1-xL2p9e+y/OZSR4c6s2u02DT+Fvc=",
"requires": {
- "truncate-utf8-bytes": "^1.0.0"
+ "http-errors": "~1.6.2",
+ "path-is-absolute": "1.0.1"
+ },
+ "dependencies": {
+ "http-errors": {
+ "version": "1.6.3",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
+ "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
+ "requires": {
+ "depd": "~1.1.2",
+ "inherits": "2.0.3",
+ "setprototypeof": "1.1.0",
+ "statuses": ">= 1.4.0 < 2"
+ }
+ },
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+ },
+ "setprototypeof": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
+ "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="
+ }
}
},
- "truncate-utf8-bytes": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz",
- "integrity": "sha1-QFkjkJWS1W94pYGENLC3hInKXys=",
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ },
+ "setprototypeof": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
+ "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
+ },
+ "statuses": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+ "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
+ },
+ "thenify": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.0.tgz",
+ "integrity": "sha1-5p44obq+lpsBCCB5eLn2K4hgSDk=",
"requires": {
- "utf8-byte-length": "^1.0.1"
+ "any-promise": "^1.0.0"
}
},
+ "thenify-all": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
+ "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=",
+ "requires": {
+ "thenify": ">= 3.1.0 < 4"
+ }
+ },
+ "toidentifier": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
+ "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
+ },
+ "tsscmp": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz",
+ "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA=="
+ },
"tweetnacl": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.1.tgz",
@@ -109,15 +410,24 @@
"resolved": "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.0.tgz",
"integrity": "sha1-RXbBzuXi1j0gf+5S8boCgZSAvHU="
},
- "url-join": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.0.tgz",
- "integrity": "sha1-TTNA6AfTdzvamZH4MFrNzCpmXSo="
+ "type-is": {
+ "version": "1.6.18",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "requires": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ }
},
- "utf8-byte-length": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz",
- "integrity": "sha1-9F8VDExm7uloGGUFq5P8u4rWv2E="
+ "upath": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz",
+ "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg=="
+ },
+ "vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
},
"ws": {
"version": "6.2.1",
@@ -126,6 +436,11 @@
"requires": {
"async-limiter": "~1.0.0"
}
+ },
+ "ylru": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/ylru/-/ylru-1.2.1.tgz",
+ "integrity": "sha512-faQrqNMzcPCHGVC2aaOINk13K+aaBDUPjGWl0teOXywElLjyVAB6Oe2jj62jHYtwsU49jXhScYbvPENK+6zAvQ=="
}
}
}
diff --git a/package.json b/package.json
index 5632bad..437d4c7 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bogbook",
- "version": "1.5.0",
+ "version": "1.8.1",
"description": "secure blockchain logging (blogging, without the l) -- bogging",
"main": "server.js",
"scripts": {
@@ -10,10 +10,10 @@
"author": "Ev Bogue <ev@evbogue.com>",
"license": "MIT",
"dependencies": {
- "ecstatic": "^4.1.2",
"ed2curve": "^0.2.1",
+ "koa": "^2.11.0",
+ "koa-static-server": "^1.4.0",
"open": "^6.2.0",
- "sanitize-filename": "^1.6.3",
"tweetnacl": "^1.0.1",
"tweetnacl-util": "^0.15.0",
"ws": "^6.2.1"
diff --git a/render.js b/render.js
index a6fe7b2..4a1391b 100644
--- a/render.js
+++ b/render.js
@@ -15,6 +15,8 @@ function getHeader (post, keys, mini) {
var head = h('span', [
h('p', {classList: 'right'}, [
+ getLoc(post),
+ ' ',
h('a', {href: '#' + post.key}, [
human(new Date(post.timestamp)),
]),
@@ -23,8 +25,8 @@ function getHeader (post, keys, mini) {
]),
h('p', [
h('a', {href: '#' + post.author}, [
- getImage(post.author, keys),
- getName(post.author, keys)
+ getQuickImage(post.author, keys),
+ getQuickName(post.author, keys)
]),
mini
])
@@ -46,10 +48,10 @@ function render (msg, keys, preview) {
msg.text = nextPost.text
var editedcontents = h('span', {id : 'content:' + msg.key, innerHTML: marked(nextPost.text)})
-
- msgcontents.parentNode.replaceChild(editedcontents, msgcontents)
-
- message.appendChild(h('div', [
+ if (msgcontents) {
+ msgcontents.parentNode.replaceChild(editedcontents, msgcontents)
+ }
+ message.firstChild.appendChild(h('div', [
'redaktita en:',
h('a', {href: '#' + nextPost.key}, [nextPost.key.substring(0, 10) + '...'])
]))
@@ -63,18 +65,67 @@ function render (msg, keys, preview) {
if (!messageExists) {
messageDiv.appendChild(h('div', {classList: 'submessage'}, [render(nextPost, keys)]))
}
+ }
+
+ if (nextPost.imaged == msg.key) {
+
+ var img = h('img', {
+ src: nextPost.image,
+ classList: 'image',
+ onclick: function () {
+ var viewimg = h('div', {id: 'viewer', onclick: function () {
+ var viewer = document.getElementById('viewer')
+ viewer.parentNode.removeChild(viewer)
+ }}, [
+ h('img', {
+ src: nextPost.image
+ })
+ ])
+ document.body.appendChild(viewimg)
+ }
+ })
+
+ message.insertBefore(img, message.childNodes[message.childNodes.length - 1])
}
})
}
})
var renderer = new marked.Renderer();
- renderer.link = function(href, title, text) {
- if ((href[0] == '@') || (href[0] == '%')) {
- href = '#' + href
+ renderer.paragraph = function (paragraph) {
+ console.log(paragraph)
+ var array = paragraph.split(' ')
+ console.log(array)
+
+ for (i = 0; i < array.length; i++) {
+ word = array[i]
+ if (word.startsWith('#')) {
+ let end
+ //console.log(word + ' is a hashtag')
+ if ((word[word.length -1] === '.') || word[word.length - 1] === ',') {
+ //console.log('and it ends with a ' + word[word.length - 1])
+ end = word[word.length - 1]
+ word = word.substring(0, word.length - 1)
+ }
+ var hashtag = "<a href='#?" + word + "'>" + word + "</a>"
+ if (end) {
+ hashtag = hashtag + end
+ }
+ //console.log(hashtag)
+ array[i] = hashtag
}
- var link = marked.Renderer.prototype.link.call(this, href, title, text);
- return link
+ }
+
+ newgraph = array.join(' ')
+
+ return newgraph + '<br /><br />'
+ }
+ renderer.link = function (href, title, text) {
+ if ((href[0] == '@') || (href[0] == '%')) {
+ href = '#' + href
+ }
+ var link = marked.Renderer.prototype.link.call(this, href, title, text);
+ return link
}
marked.setOptions({
@@ -84,7 +135,7 @@ function render (msg, keys, preview) {
if (msg.type == 'edit') {
message.appendChild(getHeader(msg, keys))
- message.appendChild(h('span', [
+ message.firstChild.appendChild(h('span', [
'redaktita: ',
h('a', {href: '#' + msg.edited}, [msg.edited.substring(0, 10) + '...'])
]))
@@ -93,69 +144,117 @@ function render (msg, keys, preview) {
message.appendChild(contents)
get(msg.edited).then(previous => {
- fragment = document.createDocumentFragment()
- var diff = JsDiff.diffWords(previous.text, msg.text)
- diff.forEach(function (part) {
- if (part.added === true) {
- color = 'blue'
- } else if (part.removed === true) {
- color = 'gray'
- } else {color = '#333'}
- var span = h('span')
- span.style.color = color
- if (part.removed === true) {
- span.appendChild(h('del', document.createTextNode(part.value)))
- } else {
- span.appendChild(document.createTextNode(part.value))
- }
- fragment.appendChild(span)
- })
- contents.appendChild(h('code', [fragment]))
+ if (previous) {
+ fragment = document.createDocumentFragment()
+ var diff = JsDiff.diffWords(previous.text, msg.text)
+ diff.forEach(function (part) {
+ if (part.added === true) {
+ color = 'blue'
+ } else if (part.removed === true) {
+ color = 'gray'
+ } else {color = '#333'}
+ var span = h('span')
+ span.style.color = color
+ if (part.removed === true) {
+ span.appendChild(h('del', document.createTextNode(part.value)))
+ } else {
+ span.appendChild(document.createTextNode(part.value))
+ }
+ fragment.appendChild(span)
+ })
+ contents.appendChild(h('code', [fragment]))
+ }
})
}
if (msg.type == 'post') {
- message.appendChild(getHeader(msg, keys))
+ var mini = h('span', [' '])
+
+ message.appendChild(getHeader(msg, keys, mini))
if (msg.reply) {
- message.appendChild(h('span', [
- 're: ',
- h('a', {href: '#' + msg.reply}, [msg.reply.substring(0, 10) + '...'])
- ]))
+ getTitle(msg.reply).then(title => {
+ if (!title) {
+ title = msg.reply.substring(0, 15) + '…'
+ }
+ mini.appendChild(h('span', [
+ '↳ ',
+ h('a', {href: '#' + msg.reply}, [title])
+ ]))
+
+ })
}
- var gotName = getName(msg.author, keys)
+
+
message.appendChild(h('div',{id: 'content:' + msg.key, innerHTML: marked(msg.text)}))
+ var buttons = h('div')
if (!preview) {
- message.appendChild(h('button', {
+ buttons.appendChild(h('button', {
onclick: function () {
- if (messageDiv.firstChild) {
- messageDiv.insertBefore(h('div', {classList: 'submessage'}, [composer(keys, msg, gotName)]), messageDiv.childNodes[1])
- } else {
- messageDiv.appendChild(h('div', {classList: 'submessage'}, [composer(keys, msg, gotName)]))
- }
+ quickName(msg.author).then(name => {
+ var compose = h('div', {classList: 'submessage'}, [composer(keys, msg, name)])
+ if (messageDiv.firstChild) {
+ messageDiv.insertBefore(compose, messageDiv.childNodes[1])
+ } else {
+ messageDiv.appendChild(compose)
+ }
+ })
}
}, ['Respondi']))
if (msg.author === keys.publicKey) {
- message.appendChild(h('button', {
+ buttons.appendChild(h('button', {
onclick: function () {
- var editor = h('div', [composer(keys, msg, {gotName: false}, {edit: true})])
- message.appendChild(editor)
+ var editor = h('div', {classList: 'submessage'}, [composer(keys, msg, {name: false}, {edit: true})])
+ messageDiv.appendChild(editor)
}
- }, ['Redakti']))
+ }, ['Edit']))
+ buttons.appendChild(identify(msg.key, message, keys))
}
+
+ message.appendChild(buttons)
}
- } else if (msg.type == 'name') {
- message.appendChild(getHeader(msg, keys))
- message.appendChild(h('span', ['identifigis ', h('a', {href: '#' + msg.named }, [msg.named.substring(0, 10) + '...']), ' as ' + msg.name]))
- } else if (msg.type == 'image') {
- message.appendChild(getHeader(msg, keys))
- message.appendChild(h('span', [
- 'identifigis ',
- h('a', { href: '#' + msg.imaged }, [msg.imaged.substring(0, 10) + '...']),
- ' as ',
- h('img', {src: msg.image})
- ]))
- }
+ } if (msg.type == 'name') {
+ var mini = h('span', [' identigis ', h('a', {href: '#' + msg.named }, [msg.named.substring(0, 10) + '...']), ' kiel ' + msg.name])
+ message.appendChild(getHeader(msg, keys, mini))
+
+ } if (msg.type == 'image') {
+ var mini = h('span', [
+ ' aldonis bildon al ',
+ h('a', { href: '#' + msg.imaged }, [
+ msg.imaged.substring(0, 10) + '...',
+ ' ',
+ h('img', {src: msg.image, classList: 'avatar'})
+ ])
+ ])
+ message.appendChild(getHeader(msg, keys, mini))
+
+ } if (msg.type == 'background') {
+ var mini = h('span', [
+ ' aldonis fonon al ',
+ h('a', { href: '#' + msg.backgrounded }, [msg.backgrounded.substring(0, 10) + '...']),
+ ' ',
+ h('img', {src: msg.background, classList: 'avatar'})
+ ])
+ message.appendChild(getHeader(msg, keys, mini))
+
+ } if (msg.type == 'description') {
+ var mini = h('span', [
+ ' aldonis priskribon al ',
+ h('a', { href: '#' + msg.descripted }, [msg.descripted.substring(0, 10) + '...']),
+ ' ',
+ h('div', {innerHTML: marked(msg.description)})
+ ])
+ message.appendChild(getHeader(msg, keys, mini))
+
+ } if (msg.type == 'location') {
+ var mini = h('span', [
+ ' aldonis lokon al ',
+ h('a', { href: '#' + msg.located }, [msg.located.substring(0, 10) + '...']),
+ ': ',
+ msg.loc
+ ])
+ message.appendChild(getHeader(msg, keys, mini))
+ }
messageDiv.appendChild(message)
return messageDiv
diff --git a/server.js b/server.js
index 6cd0a38..a4f563f 100644
--- a/server.js
+++ b/server.js
@@ -1,34 +1,130 @@
+var fs = require('fs')
+var homedir = require('os').homedir()
+
+var path = homedir + '/.bogbook/'
+var bogdir = path + 'bogs/'
+var confpath = path + 'config.json'
+
+if (!fs.existsSync(homedir + '/.bogbook/')) {fs.mkdirSync(homedir + '/.bogbook/')}
+if (!fs.existsSync(bogdir)){fs.mkdirSync(bogdir)}
+
+if (fs.existsSync(confpath)) {
+ console.log('loading config from ' + confpath)
+ var config = require(confpath)
+} else {
+ var config = {
+ port: '8089',
+ wsport: '8080',
+ url: 'localhost',
+ author: '@Q++V5BbvWIg8B+TqtC9ZKFhetruuw+nOgxEqfjlOZI0='
+ }
+ config.fullurl = 'http://' + config.url + ':' + config.port + '/'
+ fs.writeFileSync(confpath, JSON.stringify(config), 'utf-8')
+}
+
+console.log(config)
+
+if (process.argv[2] === 'verbose') {
+ var VERBOSE = true
+} else {
+ var VERBOSE = false
+}
+
+console.log('Verbose output is ' + VERBOSE + ' run with `node server verbose` to see all output')
+
+// log messages
+
+function printAsk(req, unboxedreq) {
+ if (VERBOSE) {
+ console.log(req.requester + ' asked for feed ' + unboxedreq.author + ' after sequence ' + unboxedreq.seq)
+ }
+}
+
+function printNewFeed (msg, req) {
+ if (VERBOSE)
+ console.log('Saved full log of ' + msg.author + ' sent by ' + req.requester)
+ else
+ console.log('NEW FEED from ' + msg.author)
+}
+
+function printUpdateFeed (msg, req) {
+ if (VERBOSE)
+ console.log('combined existing feed of ' + msg.author + ' sent from ' + req.requester + ' with diff and saved to server')
+ else
+ console.log('NEW UPDATE from ' + msg.author)
+}
+
+function printNoFeed (msg, req) {
+ if (VERBOSE) {
+ console.log('We don\'t have the log on the server, requesting log from ' + req.requester )
+ }
+}
+
+function printClientLonger (msg, req) {
+ if (VERBOSE) {
+ console.log(req.requester + '\'s feed of ' + msg.author + ' is longer, requesting diff from ' + req.requester)
+ }
+}
+
+function printClientShorter (msg, req, baserange, endrange) {
+ if (VERBOSE) {
+ console.log(req.requester + ' feed of ' + msg.author + ' is shorter, sending from ' + baserange + ' to ' + endrange + ' to ' + req.requester)
+ }
+}
+
+function printFeedIdentical (msg, req) {
+ if (VERBOSE) {
+ console.log(msg.author + '\'s feed sent from ' + req.requester + ' is identical')
+ }
+}
+
// static server (8089)
-var http = require('http')
-var serve = require('ecstatic')
+var serve = require('koa-static-server')
+var koa = require('koa')
var open = require('open')
-http.createServer(
- serve({ root: __dirname})
-).listen(8089)
+var app = new koa()
+
+// namespace redirect -- add namespaces to ~/.bogbook/names.json
+app.use(async function (ctx, next) {
+ if (ctx.request.url[1] != '#') {
+ var name = ctx.request.url.substring(1)
+
+ if (!fs.existsSync(path + 'names.json')) {
+ var obj = {
+ ev: '@Q++V5BbvWIg8B+TqtC9ZKFhetruuw+nOgxEqfjlOZI0=',
+ mil3s: '@531mT2x1FnQdpYJxVrG8YD9wiE767xO88kKRhi5A3Yg=',
+ g: '@WVBPY53Bl4aUIngt2TXV8nW+IGKvCTqhv88EvktOX9s='
+ }
+ fs.writeFileSync(path + 'names.json', JSON.stringify(obj), 'UTF-8')
+ }
+
+ var obj = JSON.parse(fs.readFileSync(path + 'names.json', 'UTF-8'))
+
+ for (var property in obj) {
+ if ((name === property) || (name === property + '/')) {
+ ctx.redirect('/#' + obj[property])
+ }
+ }
+ }
+ return await next()
+})
+
+app.use(serve({rootDir: '.', notFoundFile: 'index.html'}))
+
+app.listen(config.port)
-open('http://localhost:8089')
+open(config.fullurl)
-// ws server (8080)
+console.log('Bogbook is running at: ' + config.fullurl)
var bog = require('./bog')
var WS = require('ws')
-var fs = require('fs')
var nacl = require('tweetnacl')
nacl.util = require('tweetnacl-util')
-var homedir = require('os').homedir()
-var sanitize = require('sanitize-filename')
-
-var bogdir = homedir + '/.bogbook/bogs/'
-var blobdir = homedir + '/.bogbook/blobs/'
-
-if (!fs.existsSync(homedir + '/.bogbook/')) {fs.mkdirSync(homedir + '/.bogbook/')}
-if (!fs.existsSync(bogdir)){fs.mkdirSync(bogdir)}
-if (!fs.existsSync(blobdir)){fs.mkdirSync(blobdir)}
-
-var wserve = new WS.Server({ port: 8080 })
+var wserve = new WS.Server({ port: config.wsport })
bog.keys().then(key => {
wserve.on('connection', function (ws) {
@@ -36,87 +132,23 @@ bog.keys().then(key => {
var req = JSON.parse(message)
if (req.sendpub) {
ws.send(key.publicKey)
- }
- else {
+ ws.close()
+ } else {
bog.unbox(req.box, req.requester, key).then(unboxed => {
- var unboxedreq = JSON.parse(nacl.util.encodeUTF8(unboxed))
+ var unboxedreq = JSON.parse(unboxed)
//console.log(unboxedreq)
- if (unboxedreq.blobFile) {
- var openedimg = nacl.sign.open(nacl.util.decodeBase64(unboxedreq.blobFile), nacl.util.decodeBase64(unboxedreq.author.substring(1)))
- if (openedimg) {
- //console.log(openedimg)
- fs.writeFileSync(blobdir + '/' + sanitize(unboxedreq.blob), unboxedreq.blobFile, 'UTF-8')
- console.log('received blob ' + unboxedreq.blob + ' from ' + req.requester + ' and saved to blobs folder')
- }
- }
- if (unboxedreq.blob) {
- console.log(req.requester + ' has requested the blob ' + unboxedreq.blob)
- var blobExists = fs.existsSync(blobdir + '/' + sanitize(unboxedreq.blob))
- if (unboxedreq.needs) {
- console.log(req.requester + ' needs ' + unboxedreq.blob + ' do we have it?')
- if (blobExists) {
- console.log('We have it, so send it to the client')
- var blobToSend = fs.readFileSync(blobdir + '/' + sanitize(unboxedreq.blob), 'UTF-8')
- var sendblob = {
- blob: unboxedreq.blob,
- blobFile: blobToSend
- }
- console.log(sendblob)
- bog.box(JSON.stringify(sendblob), req.requester, key).then(boxed => {
- var obj = {
- requester: key.publicKey,
- box: boxed
- }
- ws.send(JSON.stringify(obj))
- })
- }
- } else {
- console.log(req.requester + ' has ' + unboxedreq.blob + ' do we need it?')
- if (!blobExists) {
- console.log('We need it, so request it from the client')
- var blobreq = { blob: unboxedreq.blob, needs: true }
- bog.box(JSON.stringify(blobreq), req.requester, key).then(boxed => {
- var obj = {
- requester: key.publicKey,
- box: boxed
- }
- ws.send(JSON.stringify(obj))
- })
- }
- }
- }
- if (unboxedreq.seq === 0) {
- console.log(req.requester + ' asked the full log of ' + unboxedreq.author)
+ if (unboxedreq.seq >= 0) {
+ printAsk(req, unboxedreq)
fs.readFile(bogdir + unboxedreq.author, 'UTF-8', function (err, data) {
if (data) {
- //var feed = JSON.stringify(data)
- var feed = data
- bog.box(feed, req.requester, key).then(boxed => {
- var obj = {
- requester: key.publicKey,
- box: boxed
- }
- ws.send(JSON.stringify(obj))
- console.log('Sent full log of ' + unboxedreq.author + ' to ' + req.requester)
- })
- }
- })
- }
- if (unboxedreq.seq) {
- console.log(req.requester + ' asked for feed ' + unboxedreq.author + ' after sequence ' + unboxedreq.seq)
- // check to see if we have the feed on disk
- fs.readFile(bogdir + unboxedreq.author, 'UTF-8', function (err, data) {
- if (data) {
- // TODO open the latest message, and check the sequence number
var feed = JSON.parse(data)
bog.open(feed[0]).then(msg => {
if (unboxedreq.seq === msg.seq) {
- console.log(unboxedreq.author + '\'s feed is identical, sending nothing to client')
- }
-
+ printFeedIdentical(msg, req)
+ ws.close()
+ }
if (unboxedreq.seq > msg.seq) {
- // right now the client is still sending the entire log, which works just fine but isn't optimal
- console.log('client feed is longer, requesting diff from client')
+ printClientLonger(msg, req)
var reqdiff = JSON.stringify({author: unboxedreq.author, seq: msg.seq})
bog.box(reqdiff, req.requester, key).then(boxed => {
var obj = {
@@ -126,22 +158,46 @@ bog.keys().then(key => {
ws.send(JSON.stringify(obj))
})
}
-
if (unboxedreq.seq < msg.seq) {
- console.log('client feed is shorter, sending diff to client')
- var diff = JSON.stringify(feed.slice(0, msg.seq - unboxedreq.seq))
+ var endrange = feed.length - unboxedreq.seq - Math.floor(Math.random() * 50 + 1)
+ if (endrange < 0) {
+ endrange = 0
+ }
+ var baserange = feed.length - unboxedreq.seq
+ printClientShorter(msg, req, baserange, endrange)
+ if (baserange > 50) {
+ var latest = JSON.stringify({
+ latest: unboxedreq.author,
+ feed: feed.slice(0, 5)
+ })
+ bog.box(latest, req.requester, key).then(boxed => {
+ var obj = {
+ requester: key.publicKey,
+ box: boxed
+ }
+ //console.log('sending latest ' + unboxedreq.author)
+ ws.send(JSON.stringify(obj))
+ })
+ }
+
+ var diff = JSON.stringify(
+ feed.slice(
+ endrange,
+ baserange
+ )
+ )
bog.box(diff, req.requester, key).then(boxed => {
var obj = {
requester: key.publicKey,
box: boxed
}
ws.send(JSON.stringify(obj))
+ ws.close()
})
}
})
} else {
- // if we don't have the feed, request the feed from the client and save
- console.log('We don\'t have the log on the server, requesting log from ' + req.requester )
+ printNoFeed(unboxedreq, req)
var reqwhole = JSON.stringify({author: unboxedreq.author, seq: 0})
bog.box(reqwhole, req.requester, key).then(boxed => {
@@ -154,11 +210,10 @@ bog.keys().then(key => {
}
})
} else if (Array.isArray(unboxedreq)) {
- // first check to make sure that we have an entire log
bog.open(unboxedreq[0]).then(msg => {
if (msg.seq === unboxedreq.length) {
fs.writeFile(bogdir + msg.author, JSON.stringify(unboxedreq), 'UTF-8', function (err, success) {
- console.log('Saved full log of ' + msg.author + ' sent by ' + req.requester)
+ printNewFeed(msg, req)
})
} if (msg.seq > unboxedreq.length) {
fs.readFile(bogdir + msg.author, 'UTF-8', function (err, data) {
@@ -167,9 +222,10 @@ bog.keys().then(key => {
if (unboxedreq.length + lastmsg.seq === msg.seq) {
var newlog = unboxedreq.concat(feed)
fs.writeFile(bogdir + msg.author, JSON.stringify(newlog), 'UTF-8', function (err, success) {
- console.log('combined existing feed of ' + msg.author + ' with diff and saved to server')
+ printUpdateFeed(msg, req)
})
}
+ ws.close()
})
})
}
diff --git a/settings.js b/settings.js
new file mode 100644
index 0000000..3c175b3
--- /dev/null
+++ b/settings.js
@@ -0,0 +1,102 @@
+function settingsPage (keys) {
+ var welcome = h('div', {classList: 'message'})
+
+ welcome.appendChild(h('p', {innerHTML: marked('### About Bogbook \n\n[Bogbook](http://bogbook.com) is a distributed social network built using secure-gossiped blockchain logging (blogging), but we call them "bogs".\n\n With bogbook you can create your own secure social network that is easily replicated between browsers via bogbook pubs.\n\n To try bogbook, type a message into the [compose box](/) on the bogbook instance you are using, then press preview and publish.\n\n You can view the bogbook code at [git.sr.ht/~ev/bogbook](https://git.sr.ht/~ev/bogbook) or clone it directly from our server:\n```\ngit clone http://git.bogbook.com/bogbook.git\n```\n Please communicate errors, bugs, and pull-requests to [@ev](http://bogbook.com/#@Q++V5BbvWIg8B+TqtC9ZKFhetruuw+nOgxEqfjlOZI0=) using Bogbook or via email: [ev@evbogue.com](mailto:ev@evbogue.com)\n\n Here\'s a video of Bogbook in the early days:')}))
+
+ welcome.appendChild(h('div', {innerHTML: '<video width="100%" controls><source src="http://evbogue.com/e-bogbook-explanation.webm" type="video/webm"></video>'}))
+
+ var keyDiv = h('div', {classList: 'message'})
+
+ keyDiv.appendChild(h('p', {innerHTML: marked('### Your keypair \n\n This is your [ed25519](https://ed25519.cr.yp.to/) keypair. It was generated using [TweetNaCl.js](https://tweetnacl.js.org/#/). \n\n Bogbook does not use logins and passwords, instead you are able to post by signing messages with your keypair. \n\n Because Bogbook uses keypairs for identities, keep your keypair safe so no one can post to your feed (or delete your posts) without your permission. \n\n**Save your key** in a safe place so that you can continue to use the same identity.')}))
+
+ keyDiv.appendChild(h('pre', {style: 'width: 80%'}, [h('code', [JSON.stringify(keys)])]))
+
+ keyDiv.appendChild(h('button', {
+ onclick: function () {
+ localforage.removeItem('id', function () {
+ location.hash = ''
+ location.reload()
+ })
+ }
+ }, ['Delete Key']))
+
+ var textarea = h('textarea', {placeholder: 'Import your existing ed25519 keypair'})
+ keyDiv.appendChild(textarea)
+ keyDiv.appendChild(h('button', {
+ onclick: function () {
+ if (textarea.value) {
+ localforage.setItem('id', JSON.parse(textarea.value)).then(function () { location.reload() })
+ }
+ }
+ }, ['Import Key']))
+
+ var everything = h('div', {classList: 'message'})
+
+ everything.appendChild(h('p', {innerHTML: marked('### Delete everything \n\n Sometimes you may want to delete all of your bogbook data in the browser. When you click this button, Bogbook will erase everything that you\'ve stored in the browser.\n\n **NOTE**: This will not delete Bogbook posts that you have already gossiped with others.\n\n **WARNING**: This will delete your Bogbook keypair as well as all data stored in the browser. If you want to continue to use the same key, make sure you\'ve backed up your keypair!')}))
+
+ everything.appendChild(h('button', {
+ onclick: function () {
+ localforage.clear().then(function () {location.reload()})
+ }
+ }, ['Delete Everything']))
+
+ /* we probably don't need this anymore
+ var regenerate = h('div', {classList: 'message'})
+
+ regenerate.appendChild(h('p', {innerHTML: marked('The regenerate button will create a new bogbook log in your browser from all of the feeds that you\'ve collected in your browser. While it is rare, you may use this button to troubleshoot if Bogbook is throwing strange database errors in your console.')}))
+
+ regenerate.appendChild(h('button', {
+ onclick: function () {
+ regenerate()
+ }
+ }, ['Regenerate']))*/
+
+
+ var pubs = h('div', {classList: 'message'})
+
+ pubs.appendChild(h('p', {innerHTML: marked('### Bogbook Pubs \n\n These are your bogbook pubs. Bogbook will gossip with these pubs to publish your messages and check for new messages from your subscriptions. You should have at least one Bogbook pub in order to gossip your messages. If you don\'t see a bogbook pub below, try clicking "Reset Pubs" or add \n```\nws://bogbook.com\n```\n to your pubs list.')}))
+
+ var add = h('input', {placeholder: 'Add a pub'})
+
+ localforage.getItem('pubs').then(function (servers) {
+ pubs.appendChild(h('div', [
+ add,
+ h('button', {
+ onclick: function () {
+ if (add.value) {
+ servers.push(add.value)
+ localforage.setItem('pubs', servers).then(function () { location.hash = '' })
+ }
+ }
+ }, ['Add a pub'])
+ ]))
+
+ servers.forEach(function (pub) {
+ pubs.appendChild(h('p', [
+ pub,
+ h('button', {
+ onclick: function () {
+ var newServers = servers.filter(item => item !== pub)
+ localforage.setItem('pubs', newServers).then(function () { location.hash = '' })
+ }
+ }, ['Remove'])
+ ]))
+ })
+ })
+
+ pubs.appendChild(h('button', {
+ onclick: function () {
+ localforage.removeItem('securepubs').then(function () {
+ location.hash = ''
+ location.reload()
+ })
+ }
+ }, ['Reset pubs']))
+
+ scroller.appendChild(keyDiv)
+ scroller.appendChild(pubs)
+ scroller.appendChild(everything)
+ scroller.appendChild(welcome)
+ //scroller.appendChild(regenerate)
+}
+
diff --git a/views.js b/views.js
index 36bff70..e6ea28e 100644
--- a/views.js
+++ b/views.js
@@ -4,67 +4,163 @@ function threadPage (src, keys) {
})
}
-function profilePage (src, keys) {
-
- var profile = h('div', {classList: 'profile'})
+function getLoc (src) {
+ var loc = h('span')
+ bog().then(log => {
+ if (log) {
+ for (var i = 0; i < log.length; i++) {
+ if (((log[i].located === src) && (log[i].author === src)) || ((log[i].located === src.key) && (log[i].author === src.author))) {
+ // if you've identified someone as something else show that something else
+ return loc.textContent = log[i].loc
+ }
+ }
+ }
+ })
+ return loc
+}
- scroller.appendChild(profile)
+function profilePage (src, keys) {
- if (src != keys.publicKey) {
- reply = { author: src }
- scroller.appendChild(composer(keys, reply))
- } else {
- scroller.appendChild(composer(keys))
+ var timer = setInterval(function () {
+ if (window.location.hash.substring(1) != src) {
+ clearInterval(timer)
+ //console.log('stop syncing')
+ }
+ sync([src], keys)
+ //console.log('syncing ' + src)
+ }, 5000)
+
+ /*timer = function() {
+ if (src === window.location.hash.substring(1)) {
+ //if (interval < 10000) { interval = interval + 50 }
+ sync([src], keys)
+ setTimeout(timer, interval)
+ }
}
- var subs = [src]
-
- sync(subs, keys)
+ timer()*/
- profile.appendChild(h('a', {href: '#' + src}, [getName(src, keys)]))
- profile.appendChild(h('br'))
+ var msg = {}
+ msg.author = src
- var mentionsButton = h('button', {
- onclick: function () {
- location.href = '#?' + src
- }
- }, ['Mencioj'])
+ var profileDiv = h('div')
+ var profile = h('div', {classList: 'profile'})
+ var banner = h('div', {classList: 'banner'})
+
+ function getDesc (src) {
+ var desc = h('span')
+ bog().then(log => {
+ if (log) {
+ for (var i = 0; i < log.length; i++) {
+ if ((log[i].descripted === src) && (log[i].author === src)) {
+ // if you've identified someone as something else show that something else
+ return desc.innerHTML = marked(log[i].description)
+ }
+ }
+ }
+ })
+ return desc
+ }
- profile.appendChild(identify(src, profile, keys))
- profile.appendChild(mentionsButton)
+ function getBg (src, profile) {
+ bog().then(log => {
+ if (log) {
+ for (var i = 0; i < log.length; i++) {
+ if ((log[i].backgrounded === src) && (log[i].author === src)) {
+ // if you've identified someone as something else show that something else
+ banner.style.height = '300px'
+ return banner.style.background = 'fixed top/680px no-repeat url(' + log[i].background + ')'
+ }
+ }
+ }
+ })
+ }
- localforage.getItem('subscriptions').then(function (subs) {
- if (subs.includes(src)) {
- profile.appendChild(h('button', {
- onclick: function () {
- subs = subs.filter(a => a !== src)
- localforage.setItem('subscriptions', subs).then(function () { location.reload() })
+ getBg(src, profile)
+
+ profileDiv.appendChild(banner)
+ profileDiv.appendChild(profile)
+ scroller.appendChild(profileDiv)
+
+ profile.appendChild(h('span', {classList: 'right'}, [getLoc(src)]))
+ profile.appendChild(h('div', [
+ h('a', {href: '#' + src}, [
+ getImage(src, keys, 'profileAvatar'),
+ getName(src, keys)
+ ]),
+ profile.appendChild(getDesc(src))
+ ]))
+
+ quickName(src).then(name => {
+ var mentionsButton = h('button', {
+ onclick: function () {
+ location.href = '#?' + src
+ }
+ }, ['Mencioj de '+ name])
+ profile.appendChild(mentionsButton)
+ var respond = h('button', {
+ onclick: function () {
+ scroller.insertBefore(composer(keys, msg, name), scroller.childNodes[1])
+ }
+ }, ['Respondi al ' + name])
+ profile.appendChild(respond)
+
+ profile.appendChild(h('button', {
+ onclick: function () {
+ localforage.removeItem(src).then(function () {
+ var home = true
+ regenerate(home)
+ })
+ }
+ }, ['Delete ' + name + '\'s feed']))
+
+ if (src != keys.publicKey) {
+ localforage.getItem('subscriptions').then(function (subs) {
+ if (subs.includes(src)) {
+ profile.appendChild(h('button', {
+ onclick: function () {
+ subs = subs.filter(a => a !== src)
+ localforage.setItem('subscriptions', subs).then(function () { location.hash = '' })
+ }
+ }, ['Unsubscribe from ' + name]))
+ } else {
+ profile.appendChild(h('button', {
+ onclick: function () {
+ subs.push(src)
+ localforage.setItem('subscriptions', subs).then(function () { location.hash = '' })
+ }
+ }, ['Subscribe to ' + name]))
}
- }, ['Ne plu sekvi']))
+ profile.appendChild(identify(src, profile, keys))
+ })
} else {
- profile.appendChild(h('button', {
- onclick: function () {
- subs.push(src)
- localforage.setItem('subscriptions', subs).then(function () { location.reload() })
- }
- }, ['Sekvi']))
+ profile.appendChild(identify(src, profile, keys))
}
+ //profile.appendChild(identify(src, profile, keys, name))
})
-
- profile.appendChild(h('button', {
- onclick: function () {
- localforage.removeItem(src).then(function () {
- var home = true
- regenerate(home)
- })
- }
- }, ['Forigi fluon']))
-
+
+
+ async function addPosts (posts, keys) {
+ posts.forEach(function (msg) {
+ if (msg.author === src) {
+ scroller.appendChild(render(msg, keys))
+ }
+ })
+ }
bog().then(log => {
+ var index = 0
if (log) {
- log.forEach(function (msg) {
- if (msg.author === src) {
- scroller.appendChild(render(msg, keys))
+ var posts = log.slice(index, index + 33)
+ addPosts(posts, keys).then(done => {
+ index = index + 33
+ window.onscroll = function(ev) {
+ //console.log(document.body.scrollHeight)
+ if (((window.innerHeight + window.scrollY) >= (document.body.scrollHeight - 2500)) && (window.location.hash.substring(1) === src)) {
+ posts = log.slice(index, index + 33)
+ index = index + 33
+ addPosts(posts, keys)
+ //console.log("Bottom of page")
+ }
}
})
}
@@ -74,12 +170,27 @@ function profilePage (src, keys) {
function searchPage (src, keys) {
var search = src.substring(1).replace("%20"," ").toUpperCase()
+ async function addPosts (posts, keys) {
+ posts.forEach(function (msg) {
+ if (msg.text) {
+ if (msg.text.toUpperCase().includes(search)) {
+ scroller.appendChild(render(msg, keys))
+ }
+ }
+ })
+ }
bog().then(log => {
+ var index = 0
if (log) {
- log.forEach(function (msg) {
- if (msg.text) {
- if (msg.text.toUpperCase().includes(search)) {
- scroller.appendChild(render(msg, keys))
+ var posts = log.slice(index, index + 33)
+ addPosts(posts, keys).then(done => {
+ index = index + 33
+ window.onscroll = function(ev) {
+ if (((window.innerHeight + window.scrollY) >= document.body.scrollHeight - 2500) && (window.location.hash.substring(1) === src)) {
+ posts = log.slice(index, index + 33)
+ index = index + 33
+ addPosts(posts, keys)
+ //console.log("Bottom of page")
}
}
})
@@ -89,114 +200,63 @@ function searchPage (src, keys) {
function publicPage (keys) {
- localforage.getItem('subscriptions').then(function (subs) {
+ localforage.getItem('log').then(log => {
+ log.sort((a, b) => a.timestamp - b.timestamp)
+ var reversed = log.reverse()
+ localforage.setItem('log', reversed)
+ })
+
+ localforage.getItem('subscriptions').then(subs => {
if (subs) {
- sync(subs, keys)
+ // the next two lines just fix a bug where the first sub was being set to null. Delete this code after March 2020.
+
+ subs.forEach(function (sub, index) {
+ var timer = setInterval(function () {
+ setTimeout(function () {
+ if (window.location.hash.substring(1) != '') {
+ clearInterval(timer)
+ //console.log('stop syncing')
+ }
+ sync([sub], keys)
+ //console.log('syncing ' + sub)
+ }, 1000 * index)
+ }, 2500)
+
+ if ((sub == null) || (sub == undefined)) {
+ var subs = [keys.publicKey]
+ localforage.setItem('subscriptions', subs)
+ }
+ })
} else {
var subs = [keys.publicKey]
+ console.log(subs)
localforage.setItem('subscriptions', subs)
- sync(subs, keys)
}
})
- var div = h('div')
-
- div.appendChild(h('button', {
- onclick: function () {
- localforage.clear().then(function () {location.reload()})
- }
- }, ['Forviŝi ĉion']))
-
- div.appendChild(h('button', {
- onclick: function () {
- regenerate()
- }
- }, ['Regeneri']))
+ scroller.appendChild(composer(keys))
- scroller.appendChild(div)
+ async function addPosts (posts, keys) {
+ posts.forEach(function (msg) {
+ scroller.appendChild(render(msg, keys))
+ })
+ }
- scroller.appendChild(composer(keys))
bog().then(log => {
+ var index = 0
if (log) {
- log.forEach(function (msg) {
- scroller.appendChild(render(msg, keys))
- })
- }
- })
-}
-
-function keyPage (keys) {
- var message = h('div', {classList: 'message'})
-
- message.appendChild(h('p', {innerHTML: marked('Jen via ŝlosilparo de ed25519-norma publika kaj privata ŝlosilo. Ĝi estas kreita per [TweetNaCl.js](https://tweetnacl.js.org/#/). Via publika ŝlosilo estas via identeco dum vi uzas [Interskri.be](https://interskri.be) (aŭ [Bogbook](http://bogbook.com/), la ĉefa projekto, se vi elektas tion), konservu vian ŝlosilon en sekura loko por ke vi povu uzadi la saman identecon.')}))
-
- message.appendChild(h('pre', {style: 'width: 80%'}, [h('code', [JSON.stringify(keys)])]))
-
- message.appendChild(h('button', {
- onclick: function () {
- localforage.removeItem('id', function () {
- location.hash = ''
- location.reload()
- })
- }
- }, ['Forigi ŝlosilon']))
-
- var textarea = h('textarea', {placeholder: 'Ĉi tie vi povas importi vian ekzistantan ed25519-ŝlosilparon'})
- message.appendChild(textarea)
- message.appendChild(h('button', {
- onclick: function () {
- if (textarea.value) {
- localforage.setItem('id', JSON.parse(textarea.value)).then(function () { location.reload() })
- }
- }
- }, ['Importi ŝlosilon']))
-
- scroller.appendChild(message)
-}
-
-function pubs () {
- var message = h('div', {classList: 'message'})
-
- message.appendChild(h('p', {innerHTML: marked('Jen la Bogbook-konigejoj al kiuj via foliumilo konektiĝas por kontroli pri novaj mesaĝoj de viaj sekvataj personoj, kiam vi afiŝas novajn aferojn kaj kiam vi surklakas fluojn.\n\nAldonu aŭ forigu ĉi tie konigejojn por decidi kien afiŝas la retejo. Se vi loke instalis kaj ruligas Bogbook, ĝi ankaŭ uzas tion kiel publikigo-celo. Atentu ke la kreinto de Bogbook ne ŝatas https, do ĉi tie malkiel en [Bogbook](http://bogbook.com) nur funkcias wss-konigejoj krom se via retumilo permesas konektiĝi de https al nesekuraj ws-konektoj. Vi povas loke instali kaj ruligi Bogbook [klonante la deponejon](https://git.kiefte.eu/lapingvino/bogbook-esperanto).')}))
-
- var add = h('input', {placeholder: 'Aldoni konigejon'})
-
- localforage.getItem('securepubs').then(function (servers) {
-
- message.appendChild(h('div', [
- add,
- h('button', {
- onclick: function () {
- if (add.value) {
- servers.push(add.value)
- localforage.setItem('securepubs', servers).then(function () { location.reload() })
+ var posts = log.slice(index, index + 25)
+ addPosts(posts, keys).then(done => {
+ index = index + 25
+ window.onscroll = function(ev) {
+ if (((window.innerHeight + window.scrollY) >= document.body.scrollHeight) && window.location.hash.substring(1) === '') {
+ posts = log.slice(index, index + 25)
+ index = index + 25
+ addPosts(posts, keys)
+ console.log("Bottom of page")
}
}
- }, ['Aldoni konigejon'])
- ]))
-
- servers.forEach(function (pub) {
- message.appendChild(h('p', [
- pub,
- h('button', {
- onclick: function () {
- var newServers = servers.filter(item => item !== pub)
- localforage.setItem('securepubs', newServers).then(function () { location.reload() })
- }
- }, ['Forigi'])
- ]))
- })
- })
-
- message.appendChild(h('button', {
- onclick: function () {
- localforage.removeItem('securepubs').then(function () {
- location.hash = ''
- location.reload()
})
}
- }, ['Restarigi konigejojn']))
-
- scroller.appendChild(message)
+ })
}
-