diff --git a/docs/roadmap.md b/docs/roadmap.md index 6ee830c..5ee5ba1 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -33,7 +33,7 @@ - [ ] Posts - [x] New - [x] Reply - - [x] Reply all + - [x] Comment - [ ] Pre-publish preview - [ ] Add blob attachment(s) - [x] Correctly set `branch` diff --git a/src/app.js b/src/app.js index 1b880b8..46883b0 100644 --- a/src/app.js +++ b/src/app.js @@ -23,9 +23,9 @@ const likesPage = require('./pages/likes') const meta = require('./pages/meta') const mentions = require('./pages/mentions') const reply = require('./pages/reply') -const replyAll = require('./pages/reply-all') +const comment = require('./pages/comment') const publishReply = require('./pages/publish-reply') -const publishReplyAll = require('./pages/publish-reply-all') +const publishComment = require('./pages/publish-comment') const image = require('./pages/image') const blob = require('./pages/blob') const publish = require('./pages/publish') @@ -189,9 +189,9 @@ module.exports = (config) => { const { message } = ctx.params ctx.body = await reply(message) }) - .get('/reply-all/:message', async (ctx) => { + .get('/comment/:message', async (ctx) => { const { message } = ctx.params - ctx.body = await replyAll(message) + ctx.body = await comment(message) }) .post('/reply/:message', koaBody(), async (ctx) => { const { message } = ctx.params @@ -199,10 +199,10 @@ module.exports = (config) => { ctx.body = await publishReply({ message, text }) ctx.redirect(`/thread/${encodeURIComponent(message)}`) }) - .post('/reply-all/:message', koaBody(), async (ctx) => { + .post('/comment/:message', koaBody(), async (ctx) => { const { message } = ctx.params const text = String(ctx.request.body.text) - ctx.body = await publishReplyAll({ message, text }) + ctx.body = await publishComment({ message, text }) ctx.redirect(`/thread/${encodeURIComponent(message)}`) }) .post('/publish/', koaBody(), async (ctx) => { diff --git a/src/pages/comment.js b/src/pages/comment.js new file mode 100644 index 0000000..17b2994 --- /dev/null +++ b/src/pages/comment.js @@ -0,0 +1,26 @@ +'use strict' + +const post = require('./models/post') +const meta = require('./models/meta') +const commentView = require('./views/comment') +const ssbRef = require('ssb-ref') + +module.exports = async function commentPage (parentId) { + const parentMessage = await post.get(parentId) + const myFeedId = await meta.myFeedId() + + const hasRoot = typeof parentMessage.value.content.root === 'string' && ssbRef.isMsg(parentMessage.value.content.root) + const hasFork = typeof parentMessage.value.content.fork === 'string' && ssbRef.isMsg(parentMessage.value.content.fork) + + const rootMessage = hasRoot + ? hasFork + ? parentMessage + : await post.get(parentMessage.value.content.root) + : parentMessage + + const messages = await post.threadReplies(rootMessage.key) + + messages.push(rootMessage) + + return commentView({ messages, myFeedId, parentMessage }) +} diff --git a/src/pages/models/post.js b/src/pages/models/post.js index c2df2a0..3965042 100644 --- a/src/pages/models/post.js +++ b/src/pages/models/post.js @@ -150,11 +150,15 @@ const transform = (ssb, messages, myFeedId) => url: avatarUrl }) - if (isRoot(msg)) { + const isPost = lodash.get(msg, 'value.content.type') === 'post' && lodash.get(msg, 'value.content.text') != null + const hasRoot = lodash.get(msg, 'value.content.root') != null + const hasFork = lodash.get(msg, 'value.content.fork') != null + + if (isPost && hasRoot === false && hasFork === false) { lodash.set(msg, 'value.meta.postType', 'post') - } else if (isReply(msg)) { - lodash.set(msg, 'value.meta.postType', 'replyAll') - } else if (isNestedReply(msg)) { + } else if (isPost && hasRoot && hasFork === false) { + lodash.set(msg, 'value.meta.postType', 'comment') + } else if (isPost && hasRoot && hasFork) { lodash.set(msg, 'value.meta.postType', 'reply') } else { lodash.set(msg, 'value.meta.postType', 'mystery') @@ -232,7 +236,7 @@ const post = { return messages }, - fromRoot: async (rootId, customOptions = {}) => { + threadReplies: async (rootId, customOptions = {}) => { const ssb = await cooler.connect() const myFeedId = ssb.id @@ -248,11 +252,11 @@ const post = { customOptions, ssb, query, - filter: (msg) => msg.value.content.root === rootId + filter: (msg) => + msg.value.content.root === rootId && + msg.value.content.fork == null }) - console.log(messages) - return messages }, likes: async ({ feed }, customOptions = {}) => { @@ -692,16 +696,23 @@ const post = { return post.publish(message) }, - replyAll: async ({ parent, message }) => { - const fork = parent.key - const root = lodash.get(parent, 'value.content.root', parent.key) - message.root = fork || root + comment: async ({ parent, message }) => { + // Set `root` to `parent`'s root. + // If `parent` doesn't have a root, use the parent's key. + // If `parent` has a fork, you must use the parent's key. + const parentKey = parent.key + const parentFork = lodash.get(parent, 'value.content.fork') + const parentRoot = lodash.get(parent, 'value.content.root', parentKey) + + const parentHasFork = parentFork != null + + message.root = parentHasFork ? parentKey : parentRoot message.branch = await post.branch({ root: parent.key }) message.type = 'post' // redundant but used for validation if (isReply(message) !== true) { const messageString = JSON.stringify(message, null, 2) - throw new Error(`message should be valid replyAll: ${messageString}`) + throw new Error(`message should be valid comment: ${messageString}`) } return post.publish(message) diff --git a/src/pages/publish-reply-all.js b/src/pages/publish-comment.js similarity index 79% rename from src/pages/publish-reply-all.js rename to src/pages/publish-comment.js index 196b67d..ffe7b7b 100644 --- a/src/pages/publish-reply-all.js +++ b/src/pages/publish-comment.js @@ -4,14 +4,14 @@ const ssbMentions = require('ssb-mentions') const post = require('./models/post') const meta = require('./models/post') -module.exports = async function publishReplyAllPage ({ message, text }) { +module.exports = async function publishCommentPage ({ message, text }) { // TODO: rename `message` to `parent` or `ancestor` or similar const mentions = ssbMentions(text).filter((mention) => mention != null ) || undefined const parent = await meta.get(message) - return post.replyAll({ + return post.comment({ parent, message: { text, mentions } }) diff --git a/src/pages/reply-all.js b/src/pages/reply-all.js deleted file mode 100644 index 79fc2e9..0000000 --- a/src/pages/reply-all.js +++ /dev/null @@ -1,25 +0,0 @@ -'use strict' - -const post = require('./models/post') -const meta = require('./models/meta') -const replyAllView = require('./views/reply-all') -const ssbRef = require('ssb-ref') - -module.exports = async function replyPage (parentId) { - const parentMessage = await post.get(parentId) - const myFeedId = await meta.myFeedId() - - const hasRoot = typeof parentMessage.value.content.root === 'string' && ssbRef.isMsg(parentMessage.value.content.root) - - const rootMessage = hasRoot - ? await post.get(parentMessage.value.content.root) - : parentMessage - - const messages = hasRoot - ? await post.fromRoot(parentMessage.value.content.root) - : await post.fromRoot(parentId) - - messages.push(rootMessage) - - return replyAllView({ messages, myFeedId, parentMessage }) -} diff --git a/src/pages/reply.js b/src/pages/reply.js index f5f9f13..a7fd4b3 100644 --- a/src/pages/reply.js +++ b/src/pages/reply.js @@ -10,9 +10,7 @@ module.exports = async function replyPage (parentId) { const myFeedId = await meta.myFeedId() debug('%O', rootMessage) - const messages = await post.fromRoot(rootMessage.key) - - messages.push(rootMessage) + const messages = [rootMessage] return replyView({ messages, myFeedId }) } diff --git a/src/pages/views/reply-all.js b/src/pages/views/comment.js similarity index 67% rename from src/pages/views/reply-all.js rename to src/pages/views/comment.js index 095e04f..c46bcbc 100644 --- a/src/pages/views/reply-all.js +++ b/src/pages/views/comment.js @@ -1,12 +1,15 @@ 'use strict' const { + a, button, form, - textarea + textarea, + p, + strong } = require('hyperaxe') -const debug = require('debug')('oasis:views:reply-all') +const debug = require('debug')('oasis:views:comment') const template = require('./components/template') const post = require('./components/post') @@ -28,11 +31,19 @@ module.exports = async ({ messages, myFeedId, parentMessage }) => { }) ) - const action = `/reply-all/${encodeURIComponent(messages[0].key)}` + const action = `/comment/${encodeURIComponent(messages[0].key)}` const method = 'post' return template( messageElements, + p('Write a ', + strong('public comment'), + ' on this thread with ', + a({ href: 'https://commonmark.org/help/' }, 'Markdown'), + '. Messages cannot be edited or deleted. To respond to an individual message, select ', + strong('reply'), + ' instead.' + ), form({ action, method }, textarea({ autofocus: true, @@ -41,6 +52,6 @@ module.exports = async ({ messages, myFeedId, parentMessage }) => { }, markdownMention), button({ type: 'submit' - }, 'reply all')) + }, 'comment')) ) } diff --git a/src/pages/views/components/post.js b/src/pages/views/components/post.js index 61dc2d2..9db8d7a 100644 --- a/src/pages/views/components/post.js +++ b/src/pages/views/components/post.js @@ -34,7 +34,7 @@ module.exports = ({ msg }) => { avatar: msg.value.meta.author.avatar.url, json: `/json/${encoded.key}`, reply: `/reply/${encoded.key}`, - replyAll: `/reply-all/${encoded.key}` + comment: `/comment/${encoded.key}` } const isPrivate = Boolean(msg.value.meta.private) @@ -81,8 +81,8 @@ module.exports = ({ msg }) => { const postOptions = { post: null, - replyAll: [ - 'replied to ', + comment: [ + 'commented on ', a({ href: url.parent }, ' thread') ], reply: [ @@ -151,7 +151,7 @@ module.exports = ({ msg }) => { }, `❤ ${likeCount}`)), (isPrivate || isRoot) ? null : a({ href: url.reply }, 'reply'), - isPrivate ? null : a({ href: url.replyAll }, 'reply all'), + isPrivate ? null : a({ href: url.comment }, 'comment'), a({ href: url.json }, 'json') )) diff --git a/src/pages/views/reply.js b/src/pages/views/reply.js index dfc441b..e480d0a 100644 --- a/src/pages/views/reply.js +++ b/src/pages/views/reply.js @@ -1,6 +1,9 @@ 'use strict' const { + p, + a, + strong, button, form, textarea @@ -11,7 +14,7 @@ const template = require('./components/template') const post = require('./components/post') module.exports = async ({ messages, myFeedId }) => { - const likeForm = `/reply/${encodeURIComponent(messages[0].key)}` + const replyForm = `/reply/${encodeURIComponent(messages[messages.length - 1].key)}` let markdownMention @@ -32,7 +35,15 @@ module.exports = async ({ messages, myFeedId }) => { return template( messageElements, - form({ action: likeForm, method: 'post' }, + p('Write a ', + strong('public reply'), + ' to this message with ', + a({ href: 'https://commonmark.org/help/' }, 'Markdown'), + '. Messages cannot be edited or deleted. To respond to an entire thread, select ', + strong('comment'), + ' instead.' + ), + form({ action: replyForm, method: 'post' }, textarea({ autofocus: true, required: true,