aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcel <cel@f/6sQ6d2CMxRUhLpspgGIulDxDCwYD7DzFzPNr7u5AU=.ed25519>2017-05-29 06:38:49 -1000
committercel <cel@f/6sQ6d2CMxRUhLpspgGIulDxDCwYD7DzFzPNr7u5AU=.ed25519>2017-05-30 09:58:53 -1000
commit35a3dedeb8b9670721bd363031083cc2c90fa085 (patch)
tree96fca1e6767d22556f096ab8bb535aa2cfbe2265
parent9e859f9fe19da67e9688bd4310bd2bae75b3d5c1 (diff)
downloadpatchfoo-35a3dedeb8b9670721bd363031083cc2c90fa085.tar.gz
patchfoo-35a3dedeb8b9670721bd363031083cc2c90fa085.zip
Implement custom emoji rendering and uploading
-rw-r--r--lib/app.js5
-rw-r--r--lib/render.js21
-rw-r--r--lib/serve.js59
-rw-r--r--lib/util.js16
4 files changed, 89 insertions, 12 deletions
diff --git a/lib/app.js b/lib/app.js
index 825bd91..10a8a07 100644
--- a/lib/app.js
+++ b/lib/app.js
@@ -38,6 +38,7 @@ function App(sbot, config) {
this._getAbout.bind(this))
this.unboxContent = memo({cache: lru(100)}, sbot.private.unbox)
this.reverseNameCache = lru(500)
+ this.reverseEmojiNameCache = lru(500)
this.unboxMsg = this.unboxMsg.bind(this)
@@ -233,6 +234,10 @@ App.prototype.getReverseNameSync = function (name) {
return id
}
+App.prototype.getReverseEmojiNameSync = function (name) {
+ return this.reverseEmojiNameCache.get(name)
+}
+
App.prototype.getNameSync = function (name) {
var about = this.aboutCache.get(name)
return about && about.name
diff --git a/lib/render.js b/lib/render.js
index 2c2278c..0135205 100644
--- a/lib/render.js
+++ b/lib/render.js
@@ -88,13 +88,26 @@ function Render(app, opts) {
Render.prototype.emoji = function (emoji) {
var name = ':' + emoji + ':'
- return emoji in emojis ?
- h('img.ssb-emoji', {
+ if (emoji in emojis) {
+ return h('img.ssb-emoji', {
src: this.opts.emoji_base + emoji + '.png',
alt: name,
height: 17,
title: name,
- }) : name
+ })
+ }
+ var link = this._mentions[name]
+ if (link && link.link) {
+ this.app.reverseEmojiNameCache.set(emoji, link.link)
+ return h('img.ssb-emoji', {
+ src: this.opts.img_base + link.link,
+ alt: name
+ + (link.size != null ? ' (' + this.formatSize(link.size) + ')' : ''),
+ height: 17,
+ title: name,
+ })
+ }
+ return name
}
/* disabled until it can be done safely without breaking html
@@ -113,6 +126,8 @@ Render.prototype.markdown = function (text, mentions) {
var mentionsByLink = this._mentionsByLink = {}
if (Array.isArray(mentions)) mentions.forEach(function (link) {
if (!link) return
+ else if (link.emoji)
+ mentionsObj[':' + link.name + ':'] = link
else if (link.name)
mentionsObj['@' + link.name] = link.link
else if (link.host === 'http://localhost:7777')
diff --git a/lib/serve.js b/lib/serve.js
index 9d907e0..e0c089c 100644
--- a/lib/serve.js
+++ b/lib/serve.js
@@ -74,6 +74,11 @@ Serve.prototype.go = function () {
filesCb(function (err) {
gotData(err, data)
})
+ function addField(name, value) {
+ if (!(name in data)) data[name] = value
+ else if (Array.isArray(data[name])) data[name].push(value)
+ else data[name] = [data[name], value]
+ }
busboy.on('file', function (fieldname, file, filename, encoding, mimetype) {
var done = multicb({pluck: 1, spread: true})
var cb = filesCb()
@@ -85,14 +90,13 @@ Serve.prototype.go = function () {
done(function (err, size, id) {
if (err) return cb(err)
if (size === 0 && !filename) return cb()
- data[fieldname] = {link: id, name: filename, type: mimetype, size: size}
+ addField(fieldname,
+ {link: id, name: filename, type: mimetype, size: size})
cb()
})
})
busboy.on('field', function (fieldname, val, fieldnameTruncated, valTruncated, encoding, mimetype) {
- if (!(fieldname in data)) data[fieldname] = val
- else if (Array.isArray(data[fieldname])) data[fieldname].push(val)
- else data[fieldname] = [data[fieldname], val]
+ addField(fieldname, val)
})
this.req.pipe(busboy)
} else {
@@ -1921,6 +1925,20 @@ Serve.prototype.composer = function (opts, cb) {
formNames[mentionNames[i]] = u.extractFeedIds(mentionIds[i])[0]
}
+ var formEmojiNames = {}
+ var emojiIds = u.toArray(data.emoji_id)
+ var emojiNames = u.toArray(data.emoji_name)
+ var emojiUploads = u.toArray(data.emoji_upload)
+ for (var i = 0; i < emojiIds.length && i < emojiNames.length; i++) {
+ var upload = emojiUploads[i]
+ formEmojiNames[emojiNames[i]] =
+ (upload && upload.link) || u.extractBlobIds(emojiIds[i])[0]
+ if (upload) blobs[upload.link] = {
+ type: upload.type,
+ size: upload.size,
+ }
+ }
+
if (data.upload) {
// TODO: be able to change the content-type
var isImage = /^image\//.test(data.upload.type)
@@ -1931,7 +1949,8 @@ Serve.prototype.composer = function (opts, cb) {
// get bare feed names
var unknownMentionNames = {}
- var unknownMentions = ssbMentions(data.text, {bareFeedNames: true})
+ var mentions = ssbMentions(data.text, {bareFeedNames: true, emoji: true})
+ var unknownMentions = mentions
.filter(function (mention) {
return mention.link === '@'
})
@@ -1944,6 +1963,15 @@ Serve.prototype.composer = function (opts, cb) {
return {name: name, id: id}
})
+ var emoji = mentions
+ .filter(function (mention) { return mention.emoji })
+ .map(function (mention) { return mention.name })
+ .filter(uniques())
+ .map(function (name) {
+ var id = formEmojiNames[name] || self.app.getReverseEmojiNameSync(name)
+ return {name: name, id: id}
+ })
+
// strip content other than feed ids from the recps field
if (data.recps) {
data.recps = u.extractFeedIds(data.recps).filter(uniques()).join(', ')
@@ -1982,7 +2010,19 @@ Serve.prototype.composer = function (opts, cb) {
h('input', {name: 'mention_name', type: 'hidden',
value: mention.name}),
h('input.id-input', {name: 'mention_id', size: 60,
- value: mention.id, placeholder: 'id'}))
+ value: mention.id, placeholder: '@id'}))
+ }))
+ ] : '',
+ emoji.length > 0 ? [
+ h('div', h('em', 'emoji:')),
+ h('ul.mentions', emoji.map(function (link) {
+ return h('li',
+ h('code', link.name), ': ',
+ h('input', {name: 'emoji_name', type: 'hidden',
+ value: link.name}),
+ h('input.id-input', {name: 'emoji_id', size: 60,
+ value: link.id, placeholder: '&id'}), ' ',
+ h('input', {type: 'file', name: 'emoji_upload'}))
}))
] : '',
h('table.ssb-msgs',
@@ -2013,8 +2053,13 @@ Serve.prototype.composer = function (opts, cb) {
type: 'post',
text: data.text,
}
- var mentions = ssbMentions(data.text, {bareFeedNames: true})
+ var mentions = ssbMentions(data.text, {bareFeedNames: true, emoji: true})
.filter(function (mention) {
+ if (mention.emoji) {
+ mention.link = formEmojiNames[mention.name]
+ || self.app.getReverseEmojiNameSync(mention.name)
+ if (!mention.link) return false
+ }
var blob = blobs[mention.link]
if (blob) {
if (!isNaN(blob.size))
diff --git a/lib/util.js b/lib/util.js
index d25ecaf..f8da640 100644
--- a/lib/util.js
+++ b/lib/util.js
@@ -72,7 +72,7 @@ u.linkDest = function (link) {
}
u.toArray = function (x) {
- return !x ? [] : Array.isArray(x) ? x : [x]
+ return x == null ? [] : Array.isArray(x) ? x : [x]
}
u.fromArray = function (arr) {
@@ -102,7 +102,7 @@ u.tryDecodeJSON = function (json) {
}
}
-u.extractFeedIds = function (str) {
+u.extractRefs = function (str) {
var ids = []
String(str).replace(u.ssbRefRegex, function (id) {
ids.push(id)
@@ -110,6 +110,18 @@ u.extractFeedIds = function (str) {
return ids
}
+u.extractFeedIds = function (str) {
+ return u.extractRefs(str).filter(function (ref) {
+ return ref[0] === '@'
+ })
+}
+
+u.extractBlobIds = function (str) {
+ return u.extractRefs(str).filter(function (ref) {
+ return ref[0] === '&'
+ })
+}
+
u.isMsgReadable = function (msg) {
var c = msg && msg.value && msg.value.content
return typeof c === 'object' && c !== null