From 172fd44dd5ca8fc2d3ee7473949ea21cc7c3c2e5 Mon Sep 17 00:00:00 2001 From: f0x Date: Sat, 20 Apr 2019 12:24:48 +0200 Subject: [PATCH] displaying replies nicely --- components/chat.js | 4 +-- components/events/Event.js | 61 ++++++++++++++++++++++++++++++++++---- components/events/image.js | 4 +-- components/events/text.js | 8 ++--- components/input.js | 7 +++-- public/scss/style.scss | 46 ++++++++++++++++++---------- 6 files changed, 97 insertions(+), 33 deletions(-) diff --git a/components/chat.js b/components/chat.js index bcb15bd..6504bec 100644 --- a/components/chat.js +++ b/components/chat.js @@ -99,7 +99,7 @@ let chat = create({ messageGroups.groups.push(messageGroups.current) events = messageGroups.groups.map((events, id) => { - return + return }) } //TODO: replace with something that only renders events in view @@ -145,7 +145,7 @@ let EventGroup = create({ render: function() { let events = this.props.events.map((event, key) => { - return + return }) return
{this.state.avatar} diff --git a/components/events/Event.js b/components/events/Event.js index 8d4fa68..730842c 100644 --- a/components/events/Event.js +++ b/components/events/Event.js @@ -4,34 +4,83 @@ const ReactDOM = require('react-dom') const create = require('create-react-class') const defaultValue = require('default-value') +const riot = require('../../lib/riot-utils.js') + const elements = { "m.text": require('./text.js'), "m.image": require('./image.js') } +const mxReplyRegex = /(.+)<\/mx-reply>/ + let Event = create({ displayName: "Event", render: function() { + let event = this.props.event let state = "" + let reply = "" + let element = "unsupported event" - if (this.props.event.local) { + if (event.local) { state = " local" } + if (event.type == "m.room.message") { + let msgtype = event.content.msgtype; + let formattedEvent = getEvent(event) + let parsedBody = formattedEvent.body + + let parsedReply = formattedEvent.parsedReply + if (parsedReply.isReply) { + let repliedEvent = this.props.room.findEventById(parsedReply.to) + let shortText = getEvent(repliedEvent.event).body + if (shortText.length > 50) { + shortText = shortText.substr(0, 50) + "..." + } + reply = ( +
+ {shortText} +
+ ) + } + element = React.createElement(defaultValue(elements[msgtype], elements["m.text"]), {body: parsedBody, event: event, client: this.props.client}) + } + return (
- {getRenderedEvent(this.props.event, this.props.client)} + {reply} + {element}
) } }) -function getRenderedEvent(event, client) { - if (event.type == "m.room.message") { - let msgtype = event.content.msgtype; - return React.createElement(defaultValue(elements[msgtype], elements["m.text"]), {event: event, client: client}) +function getEvent(event) { + let body = event.content.body + if (event.content.format == "org.matrix.custom.html") { + body = riot.sanitize(event.content.formatted_body) + } + let parsedReply = parseReply(event, body) + if (parsedReply.isReply) { + body = parsedReply.body + } + return {body: body, parsedReply: parsedReply} +} + +function parseReply(event, body) { + let replyTo + try { + replyTo = event.content['m.relates_to']['m.in_reply_to'].event_id + if (replyTo) { + // strip from message if it exists + body = body.replace(mxReplyRegex, "") + } + } catch(err) { + // no reply + return {isReply: false} } + return {isReply: true, body: body, to: replyTo} } module.exports = Event diff --git a/components/events/image.js b/components/events/image.js index a5381de..fd15b47 100644 --- a/components/events/image.js +++ b/components/events/image.js @@ -28,14 +28,14 @@ let Event = create({ }, render: function() { - return
+ return ( -
+ ) } }) diff --git a/components/events/text.js b/components/events/text.js index 75c3c8f..01dea58 100644 --- a/components/events/text.js +++ b/components/events/text.js @@ -15,20 +15,20 @@ let Event = create({ let eventBody if (event.content.format == "org.matrix.custom.html") { - let html = riot.sanitize(event.content.formatted_body) + //let html = riot.sanitize(event.content.formatted_body) eventBody =
} else { eventBody =
- {event.content.body} + {this.props.body}
} - let eventClass = "event" + let eventClass = "" if (event.local) { eventClass += " local" } diff --git a/components/input.js b/components/input.js index 67ab36e..65d1bd7 100644 --- a/components/input.js +++ b/components/input.js @@ -4,6 +4,7 @@ const ReactDOM = require('react-dom') const create = require('create-react-class') const Promise = require('bluebird') const colorConvert = require('color-convert') +const sanitize = require('sanitize-html') let input = create({ displayName: "Input", @@ -77,7 +78,7 @@ let input = create({ sendHTML: function(html) { let content = { - body: html, // this should probably be stripped to plaintext + body: sanitize(html, {allowedTags: []}), formatted_body: html, format: "org.matrix.custom.html", msgtype: "m.text" @@ -99,8 +100,8 @@ function handleCommands(command, parts) { if (parts.length < 2) { return } - let string = "" - for(let i=1; i < parts.length; i++) { + let string = parts[1] + for(let i=2; i < parts.length; i++) { string += " " + parts[i] } let html = rainbowTransform(string) diff --git a/public/scss/style.scss b/public/scss/style.scss index 78e8f73..c580111 100644 --- a/public/scss/style.scss +++ b/public/scss/style.scss @@ -276,7 +276,6 @@ body { #name { font-weight: bold; - padding-left: $spacing/2; } #avatar { @@ -298,26 +297,41 @@ body { grid-area: content; padding-left: $spacing * 1.2; - .local { - color: $bg4; + .reply + .event { + margin-bottom: $spacing; } - .body { - padding: $spacing/4; - padding-left: $spacing/2; - white-space: pre-wrap; + .event { + .reply { + border-left: $borderwidth solid $blue; + padding-left: 1/2 * $spacing; + margin-top: $spacing; + } - img { - max-height: 40vh; - max-width: 90%; - object-fit: contain; + &:nth-child(2) .reply { + margin-top: 0; + } + + .body { + padding: $spacing/4 0; + white-space: pre-wrap; + + img { + max-height: 40vh; + max-width: 90%; + object-fit: contain; + } + } + + &:hover { + border-radius: 0.1rem; + background-color: hsla(0, 100%, 100%, 0.05); + transition: 0.1s; } - } - .body:hover { - border-radius: 0.1rem; - background-color: hsla(0, 100%, 100%, 0.05); - transition: 0.1s; + & .local { + color: $bg4; + } } } }