From 4ee97dfaa67cc8ab77bbac574f0d05c6d60f4e37 Mon Sep 17 00:00:00 2001 From: cel Date: Wed, 25 Mar 2020 10:57:51 -0400 Subject: Render descriptions as diffs in gathering threads --- lib/app.js | 4 ++++ lib/render-msg.js | 40 +++++++++++++++++++++++++++++++++++++--- lib/render.js | 44 ++++++++++++++++++++++++++++++++++++++++++++ lib/serve.js | 6 +++++- 4 files changed, 90 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/app.js b/lib/app.js index 4fac422..b62a1d2 100644 --- a/lib/app.js +++ b/lib/app.js @@ -30,6 +30,10 @@ var zeros = new Buffer(24); zeros.fill(0) module.exports = App +function getKey(msg) { + return msg && msg.key +} + function App(sbot, config) { this.sbot = sbot this.config = config diff --git a/lib/render-msg.js b/lib/render-msg.js index 68ea4d7..3a55a3b 100644 --- a/lib/render-msg.js +++ b/lib/render-msg.js @@ -19,13 +19,17 @@ function RenderMsg(render, app, msg, opts) { this.isMissing = !content this.hasFullLink = this.c.type === 'chess_move' || - this.c.type === 'ssb_chess_move' + this.c.type === 'ssb_chess_move' || + (this.c.type === 'about' && this.c.about == this.value.author + && typeof this.c.description === 'string') if (typeof opts === 'boolean') opts = {raw: opts} this.opts = opts || {} this.shouldWrap = this.opts.wrap !== false var ts = this.value.timestamp this.date = ts ? new Date(ts) : null + this.thread = opts.links || [] + this.single = opts.single } RenderMsg.prototype.getMsg = function (id, cb) { @@ -645,6 +649,7 @@ var knownAboutProps = { } RenderMsg.prototype.about = function (cb) { + var self = this var keys = Object.keys(this.c).filter(function (k) { return k !== 'about' && k !== 'type' && k !== 'recps' }).sort().join() @@ -702,6 +707,15 @@ RenderMsg.prototype.about = function (cb) { var target = this.c.about var pwh = this.c.publicWebHosting + function descriptionOrDiff(cb) { + // show diff for self-description and gathering thread. + // otherwise it might require a more expensive query + var prevMsg = !self.opts.full && self.getPreviousAboutInThreadSync() + cb() + if (prevMsg) return self.render.textEditDiffTable(prevMsg, self.msg) + return h('div', {innerHTML: self.render.markdown(self.c.description)}) + } + this.wrap([ this.c.root && this.c.root !== target ? h('div', h('small', '→ ', this.link1(this.c.root, done())) @@ -731,8 +745,7 @@ RenderMsg.prototype.about = function (cb) { ]) : '', this.c.genre ? h('div', ['genre: ', h('u', u.toString(this.c.genre))]) : '', this.c.shelve ? h('div', ['shelf: ', h('u', u.toString(this.c.shelve))]) : '', - this.c.description ? h('div', - {innerHTML: this.render.markdown(this.c.description)}) : '', + this.c.description ? descriptionOrDiff(done()) : '', this.c.review ? h('blockquote', {innerHTML: this.render.markdown(this.c.review)}) : '', this.c.attendee ? h('div', @@ -763,6 +776,27 @@ RenderMsg.prototype.about = function (cb) { done(cb) } +RenderMsg.prototype.getPreviousAboutInThreadSync = function () { + var self = this + var root = this.thread[0] + if (!root) return + if (this.c.about !== root.key) { + // probably won't work + return + } + var i = this.thread.indexOf(this.msg) + var target = this.c.about + if (i === -1) return + for (var j = i-1; j >= 0; j--) { + var msg = this.thread[j] + var c = msg && msg.value && msg.value.content + if (c && c.type === 'about' && c.about === target + && typeof c.description === 'string') { + return msg + } + } +} + RenderMsg.prototype.aboutRating = function (cb) { var rating = Number(this.c.rating) var max = Number(this.c.ratingMax) diff --git a/lib/render.js b/lib/render.js index 5d8fd66..7c2cf64 100644 --- a/lib/render.js +++ b/lib/render.js @@ -13,6 +13,7 @@ var multicb = require('multicb') var RenderMsg = require('./render-msg') var Highlight = require('highlight.js') var md = require('ssb-markdown') +var Diff = require('diff') module.exports = Render @@ -719,3 +720,46 @@ Render.prototype.friendsList = function (prefix) { } ) } + +Render.prototype.textEditDiffTable = function (oldMsg, newMsg) { + var oldC = oldMsg && oldMsg.value.content || {} + var newC = newMsg && newMsg.value.content || {} + var oldText = String(oldC.text || oldC.description || '') + var newText = String(newC.text || newC.description || '') + var diff = Diff.structuredPatch('', '', oldText, newText) + var self = this + return h('table', [ + diff.hunks.map(function (hunk) { + var oldLine = hunk.oldStart + var newLine = hunk.newStart + return [ + h('tr', [ + h('td', {colspan: 2}), + h('td', h('pre', + '@@ -' + oldLine + ',' + hunk.oldLines + ' ' + + '+' + newLine + ',' + hunk.newLines + ' @@')) + ]), + hunk.lines.map(function (line) { + var s = line[0] + if (s == '\\') return + var lineNums = [s == '+' ? '' : oldLine++, s == '-' ? '' : newLine++] + return [ + h('tr', { + class: s == '+' ? 'diff-new' : s == '-' ? 'diff-old' : '' + }, [ + lineNums.map(function (num, i) { + return h('td', String(num)) + }), + h('td', {innerHTML: + h('code', s).outerHTML + + u.unwrapP(self.markdown(line.substr(1), + s == '-' ? oldC.mentions : newC.mentions)) + }) + ]) + ] + }) + ] + }) + ]) +} + diff --git a/lib/serve.js b/lib/serve.js index e593f64..c35d4c9 100644 --- a/lib/serve.js +++ b/lib/serve.js @@ -1927,6 +1927,7 @@ Serve.prototype.streamThreadWithComposer = function (opts) { self.renderThread({ msgId: id, branches: branches, + links: links, }), self.wrapMessages(), self.wrapThread({ @@ -1950,7 +1951,8 @@ Serve.prototype.streamMsg = function (id) { return pull( self.app.pullGetMsg(id), self.renderThread({ - msgId: id + msgId: id, + single: self.query.single != null }), self.wrapMessages() ) @@ -2236,6 +2238,8 @@ Serve.prototype.renderThread = function (opts) { filter: this.query.filter, limit: Number(this.query.limit), serve: this, + links: opts && opts.links, + single: opts && opts.single, branches: opts && opts.branches, }), pull.map(u.toHTML) -- cgit v1.2.3