From 02bfe74c0273e98741997b1d9d8c28a583dffda2 Mon Sep 17 00:00:00 2001 From: Anders Rune Jensen Date: Thu, 11 May 2017 21:34:42 +0200 Subject: [PATCH] Merge styling changes from Andre Staltz --- index.js | 233 ++--------------------------- render.js | 439 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 451 insertions(+), 221 deletions(-) create mode 100644 render.js diff --git a/index.js b/index.js index 0c7cced..34b5f8b 100644 --- a/index.js +++ b/index.js @@ -3,56 +3,29 @@ var http = require('http') var qs = require('querystring') var path = require('path') var crypto = require('crypto') -var cat = require('pull-cat') var pull = require('pull-stream') var paramap = require('pull-paramap') -var marked = require('ssb-marked') var sort = require('ssb-sort') var toPull = require('stream-to-pull-stream') var memo = require('asyncmemo') var lru = require('lrucache') -var htime = require('human-time') -var emojis = require('emoji-named-characters') var serveEmoji = require('emoji-server')() +var { + MdRenderer, + renderEmoji, + formatMsgs, + wrapPage, + renderThread +} = require('./render'); -var emojiDir = path.join(require.resolve('emoji-named-characters'), '../pngs') var appHash = hash([fs.readFileSync(__filename)]) var urlIdRegex = /^(?:\/(([%&@]|%25|%26|%40)(?:[A-Za-z0-9\/+]|%2[Ff]|%2[Bb]){43}(?:=|%3[Dd])\.(?:sha256|ed25519))(?:\.([^?]*))?|(\/.*?))(?:\?(.*))?$/ -function MdRenderer(opts) { - marked.Renderer.call(this, {}) - this.opts = opts -} -MdRenderer.prototype = new marked.Renderer() - -MdRenderer.prototype.urltransform = function (href) { - if (!href) return false - switch (href[0]) { - case '#': return '/channel/' + href.slice(1) - case '%': return this.opts.msg_base + encodeURIComponent(href) - case '@': return this.opts.feed_base + encodeURIComponent(href) - case '&': return this.opts.blob_base + encodeURIComponent(href) - } - if (href.indexOf('javascript:') === 0) return false - return href -} - -MdRenderer.prototype.image = function (href, title, text) { - return '' + text + '' : '>') -} - -function renderEmoji(emoji) { - var opts = this.renderer.opts - return emoji in emojis ? - ':' + escape(emoji) + ':' - : ':' + emoji + ':' +function hash(arr) { + return arr.reduce(function (hash, item) { + return hash.update(String(item)) + }, crypto.createHash('sha256')).digest('base64') } exports.name = 'viewer' @@ -66,6 +39,7 @@ exports.init = function (sbot, config) { var base = conf.base || '/' var defaultOpts = { + base: base, msg_base: conf.msg_base || base, feed_base: conf.feed_base || base, blob_base: conf.blob_base || base, @@ -384,14 +358,6 @@ function getMsgWithValue(sbot, id, cb) { }) } -function escape(str) { - return String(str) - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"') -} - function respond(res, status, message) { res.writeHead(status) res.end(message) @@ -461,178 +427,3 @@ function prepend(fn, arg) { } } } - -function formatMsgs(id, ext, opts) { - switch (ext || 'html') { - case 'html': return pull(renderThread(opts), wrapPage(id)) - case 'js': return pull(renderThread(opts), wrapJSEmbed(opts)) - case 'json': return wrapJSON() - default: return null - } -} - -function wrap(before, after) { - return function (read) { - return cat([pull.once(before), read, pull.once(after)]) - } -} - -function renderThread(opts) { - return pull( - pull.map(renderMsg.bind(this, opts)), - wrap('
', '
') - ) -} - -function wrapPage(id) { - return wrap('' - + '' - + '' + id + ' | ssb-viewer' - + '' - + '' - + '' - + '', - '' - ) -} - -function wrapJSON() { - var first = true - return pull( - pull.map(JSON.stringify), - join(','), - wrap('[', ']') - ) -} - -function wrapJSEmbed(opts) { - return pull( - wrap('', ''), - pull.map(docWrite), - opts.base_token && rewriteBase(new RegExp(opts.base_token, 'g')) - ) -} - - -function rewriteBase(token) { - // detect the origin of the script and rewrite the js/html to use it - return pull( - replace(token, '" + SSB_VIEWER_ORIGIN + "/'), - wrap('var SSB_VIEWER_ORIGIN = (function () {' - + 'var scripts = document.getElementsByTagName("script")\n' - + 'var script = scripts[scripts.length-1]\n' - + 'if (!script) return location.origin\n' - + 'return script.src.replace(/\\/%.*$/, "")\n' - + '}())\n', '') - ) -} - -function join(delim) { - var first = true - return pull.map(function (val) { - if (!first) return delim + String(val) - first = false - return val - }) -} - -function replace(re, rep) { - return pull.map(function (val) { - return String(val).replace(re, rep) - }) -} - -function docWrite(str) { - return 'document.write(' + JSON.stringify(str) + ')\n' -} - -function hash(arr) { - return arr.reduce(function (hash, item) { - return hash.update(String(item)) - }, crypto.createHash('sha256')).digest('base64') -} - -function renderMsg(opts, msg) { - var c = msg.value.content || {} - var name = encodeURIComponent(msg.key) - return '
' - + '' - + '' + msg.author.name + '' - + msgTimestamp(msg, name) - + render(opts, c) - + '
' -} - -function msgTimestamp(msg, name) { - var date = new Date(msg.value.timestamp) - return '' -} - -function formatDate(date) { - // return date.toISOString().replace('T', ' ') - return htime(date) -} - -function render(opts, c) -{ - if (c.type === 'post') { - var channel = c.channel ? ' in #' + c.channel + '' : '' - return channel + renderPost(opts, c) - } else if (c.type == 'vote' && c.vote.expression == 'Dig') { - var channel = c.channel ? ' in #' + c.channel + '' : '' - var linkedText = 'this' - if (typeof c.vote.linkedText != 'undefined') - linkedText = c.vote.linkedText.substring(0, 75) - return ' dug ' + '' + linkedText + '' + channel - } - else if (c.type == 'vote') { - var linkedText = 'this' - if (typeof c.vote.linkedText != 'undefined') - linkedText = c.vote.linkedText.substring(0, 75) - return ' voted ' + linkedText + '' - } - else if (c.type == 'contact' && c.following) { - var name = c.contact - if (typeof c.contactAbout != 'undefined') - name = c.contactAbout.name - return ' followed ' + name + "" - } - else if (c.type == 'contact' && !c.following) { - var name = c.contact - if (typeof c.contactAbout != 'undefined') - name = c.contactAbout.name - return ' unfollowed ' + name + "" - } - else if (typeof c == 'string') - return ' wrote something private ' - else if (c.type == 'about') - return ' changed something in about' - else if (c.type == 'issue') - return ' created an issue' - else if (c.type == 'git-update') - return ' did a git update' - else if (c.type == 'ssb-dns') - return ' updated dns' - else if (c.type == 'pub') - return ' connected to a pub' - else if (c.type == 'channel' && c.subscribed) - return ' subscribed to channel #' + c.channel + "" - else if (c.type == 'channel' && !c.subscribed) - return ' unsubscribed from channel #' + c.channel + "" - else - return renderDefault(c) -} - -function renderPost(opts, c) { - return '
' + marked(c.text, opts.marked) + '
' -} - -function renderDefault(c) { - return '
' + JSON.stringify(c, 0, 2) + '
' -} diff --git a/render.js b/render.js new file mode 100644 index 0000000..e9aac7c --- /dev/null +++ b/render.js @@ -0,0 +1,439 @@ +var path = require('path'); +var pull = require("pull-stream"); +var marked = require("ssb-marked"); +var htime = require("human-time"); +var emojis = require("emoji-named-characters"); +var cat = require("pull-cat"); + +var emojiDir = path.join(require.resolve("emoji-named-characters"), "../pngs"); + +exports.wrapPage = wrapPage; +exports.MdRenderer = MdRenderer; +exports.renderEmoji = renderEmoji; +exports.formatMsgs = formatMsgs; +exports.renderThread = renderThread; + +function MdRenderer(opts) { + marked.Renderer.call(this, {}); + this.opts = opts; +} + +MdRenderer.prototype = new marked.Renderer(); + +MdRenderer.prototype.urltransform = function(href) { + if (!href) return false; + switch (href[0]) { + case "#": + return this.opts.base + "channel/" + href.slice(1); + case "%": + return this.opts.msg_base + encodeURIComponent(href); + case "@": + return this.opts.feed_base + encodeURIComponent(href); + case "&": + return this.opts.blob_base + encodeURIComponent(href); + } + if (href.indexOf("javascript:") === 0) return false; + return href; +}; + +MdRenderer.prototype.image = function(href, title, text) { + return ( + '' +
+    text +
+    '" : ">") + ); +}; + +function renderEmoji(emoji) { + var opts = this.renderer.opts; + return emoji in emojis + ? ':' +
+        escape(emoji) +
+        ':' + : ":" + emoji + ":"; +} + +function escape(str) { + return String(str) + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """); +} + +function formatMsgs(id, ext, opts) { + switch (ext || "html") { + case "html": + return pull(renderThread(opts), wrapPage(id)); + case "js": + return pull(renderThread(opts), wrapJSEmbed(opts)); + case "json": + return wrapJSON(); + default: + return null; + } +} + +function wrap(before, after) { + return function(read) { + return cat([pull.once(before), read, pull.once(after)]); + }; +} + +function renderThread(opts) { + return pull( + pull.map(renderMsg.bind(this, opts)), + wrap( + 'You are reading content from ' + + 'Scuttlebutt' + + '' + + '
', + + '
' + + '' + + 'Join Scuttlebutt now' + + '' + ) + ); +} + +function wrapPage(id) { + return wrap( + "" + + "" + + "" + + id + " | ssb-viewer" + + "" + + '' + + styles + + "", + "" + ); +} + +var styles = ` + +`; + +function wrapJSON() { + var first = true; + return pull(pull.map(JSON.stringify), join(","), wrap("[", "]")); +} + +function wrapJSEmbed(opts) { + return pull( + wrap('', ""), + pull.map(docWrite), + opts.base_token && rewriteBase(new RegExp(opts.base_token, "g")) + ); +} + +function rewriteBase(token) { + // detect the origin of the script and rewrite the js/html to use it + return pull( + replace(token, '" + SSB_VIEWER_ORIGIN + "/'), + wrap( + "var SSB_VIEWER_ORIGIN = (function () {" + + 'var scripts = document.getElementsByTagName("script")\n' + + "var script = scripts[scripts.length-1]\n" + + "if (!script) return location.origin\n" + + 'return script.src.replace(/\\/%.*$/, "")\n' + + "}())\n", + "" + ) + ); +} + +function join(delim) { + var first = true; + return pull.map(function(val) { + if (!first) return delim + String(val); + first = false; + return val; + }); +} + +function replace(re, rep) { + return pull.map(function(val) { + return String(val).replace(re, rep); + }); +} + +function docWrite(str) { + return "document.write(" + JSON.stringify(str) + ")\n"; +} + +function renderMsg(opts, msg) { + var c = msg.value.content || {}; + var name = encodeURIComponent(msg.key); + return ( + '
' + + '
' + + '
' + + '' + + '
' + + '" + msg.author.name + "" + + msgTimestamp(msg, name) + + '
' + + '
' + + '
' + + render(opts, c) + + "
" + ); +} + +function msgTimestamp(msg, name) { + var date = new Date(msg.value.timestamp); + var isoStr = date.toISOString(); + return ( + '' + ); +} + +function formatDate(date) { + // return date.toISOString().replace('T', ' ') + return htime(date); +} + +function render(opts, c) { + var base = opts.base; + if (c.type === "post") { + var channel = c.channel + ? '
#' + c.channel + "
" + : ""; + return channel + renderPost(opts, c); + } else if (c.type == "vote" && c.vote.expression == "Dig") { + var channel = c.channel + ? ' in #' + c.channel + "" + : ""; + var linkedText = "this"; + if (typeof c.vote.linkedText != "undefined") + linkedText = c.vote.linkedText.substring(0, 75); + return ('' + + 'Liked ' + + '' + + linkedText + + "" + + channel + + '' + ); + } else if (c.type == "vote") { + var linkedText = "this"; + if (typeof c.vote.linkedText != "undefined") + linkedText = c.vote.linkedText.substring(0, 75); + return '' + + 'Voted ' + linkedText + "" + + ''; + } else if (c.type == "contact" && c.following) { + var name = c.contact; + if (typeof c.contactAbout != "undefined") name = c.contactAbout.name; + return '' + + 'Followed ' + name + "" + + ''; + } else if (c.type == "contact" && !c.following) { + var name = c.contact; + if (typeof c.contactAbout != "undefined") name = c.contactAbout.name; + return '' + + 'Unfollowed ' + name + "" + + ''; + } else if (typeof c == "string") { + return '' + + "Wrote something private" + + ''; + } + else if (c.type == "about") { + return '' + + "Changed something in about" + + '' + + renderDefault(c); + } + else if (c.type == "issue") { + return '' + + "Created a git issue" + + '' + + renderDefault(c); + } + else if (c.type == "git-update") { + return '' + + "Did a git update" + + '' + + renderDefault(c); + } + else if (c.type == "ssb-dns") { + return '' + + "Updated DNS" + + '' + + renderDefault(c); + } + else if (c.type == "pub") { + return '' + + "Connected to a pub" + + '' + + renderDefault(c); + } + else if (c.type == "channel" && c.subscribed) + return '' + + 'Subscribed to channel #' + + c.channel + + "" + + ''; + else if (c.type == "channel" && !c.subscribed) + return '' + + 'Unsubscribed from channel #' + + c.channel + + "" + + ''; + else return renderDefault(c); +} + +function renderPost(opts, c) { + return '
' + marked(c.text, opts.marked) + "
"; +} + +function renderDefault(c) { + return "
" + JSON.stringify(c, 0, 2) + "
"; +}