From c582b723bd4f29ebf5fccf168abdffeca4a46708 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Wed, 7 Jul 2021 23:40:16 -0700 Subject: [PATCH] Start working on images. --- .../session/room/timeline/MessageBody.js | 9 +++++++ .../session/room/timeline/deserialize.js | 27 ++++++++++++++++--- .../session/room/timeline/tiles/TextTile.js | 2 +- .../session/room/timeline/TextMessageView.js | 6 +++++ 4 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/domain/session/room/timeline/MessageBody.js b/src/domain/session/room/timeline/MessageBody.js index f2c2d534..d232c021 100644 --- a/src/domain/session/room/timeline/MessageBody.js +++ b/src/domain/session/room/timeline/MessageBody.js @@ -80,6 +80,15 @@ export class FormatPart { get type() { return "format"; } } +export class ImagePart { + constructor(src, properties) { + this.src = src; + this.properties = properties; + } + + get type() { return "image"; } +}; + export class LinkPart { constructor(url, inlines) { this.url = url; diff --git a/src/domain/session/room/timeline/deserialize.js b/src/domain/session/room/timeline/deserialize.js index 420d0010..d7d11184 100644 --- a/src/domain/session/room/timeline/deserialize.js +++ b/src/domain/session/room/timeline/deserialize.js @@ -1,4 +1,4 @@ -import { MessageBody, HeaderBlock, ListBlock, CodeBlock, FormatPart, NewLinePart, RulePart, TextPart, LinkPart } from "./MessageBody.js" +import { MessageBody, HeaderBlock, ListBlock, CodeBlock, FormatPart, NewLinePart, RulePart, TextPart, LinkPart, ImagePart } from "./MessageBody.js" /* At the time of writing (Jul 1 2021), Matrix Spec recommends @@ -71,8 +71,27 @@ function parseCodeBlock(result, node) { return new CodeBlock(language, codeNode.textContent); } +// TODO: duplicated from MediaRepository. Extract somewhere. +function parseMxcUrl(url) { + const prefix = "mxc://"; + if (url.startsWith(prefix)) { + return url.substr(prefix.length).split("/", 2); + } else { + return null; + } +} + function parseImage(result, node) { - return null; + const src = result.getAttributeValue(node, "src") || ""; + // We just ignore non-mxc `src` attributes. + if (!parseMxcUrl(src)) { + return null; + } + const width = result.getAttributeValue(node, "width"); + const height = result.getAttributeValue(node, "height"); + const alt = result.getAttributeValue(node, "alt"); + const title = result.getAttributeValue(node, "title"); + return new ImagePart(src, { width, height, alt, title }); } function buildNodeMap() { @@ -135,7 +154,7 @@ function parseNodes(result, nodes) { return parsed; } -export function parseHTMLBody(platform, html) { +export function parseHTMLBody({ mediaRepository, platform }, html) { const parseResult = platform.parseHTML(html); const parts = parseNodes(parseResult, parseResult.rootNodes); return new MessageBody(html, parts); @@ -187,7 +206,7 @@ const platform = { export function tests() { function test(assert, input, output) { - assert.deepEqual(parseHTMLBody(platform, input), new MessageBody(input, output)); + assert.deepEqual(parseHTMLBody({ mediaRepository: null, platform }, input), new MessageBody(input, output)); } return { diff --git a/src/domain/session/room/timeline/tiles/TextTile.js b/src/domain/session/room/timeline/tiles/TextTile.js index cbd35b72..0d25cc14 100644 --- a/src/domain/session/room/timeline/tiles/TextTile.js +++ b/src/domain/session/room/timeline/tiles/TextTile.js @@ -46,7 +46,7 @@ export class TextTile extends BaseTextTile { _parseBody(body) { const string = body.string; if (body.format === "html") { - return parseHTMLBody(this.platform, string); + return parseHTMLBody({ mediaRepository: this._mediaRepository, platform: this.platform }, string); } else { return parsePlainBody(string); } diff --git a/src/platform/web/ui/session/room/timeline/TextMessageView.js b/src/platform/web/ui/session/room/timeline/TextMessageView.js index f87e79dd..c8048fa2 100644 --- a/src/platform/web/ui/session/room/timeline/TextMessageView.js +++ b/src/platform/web/ui/session/room/timeline/TextMessageView.js @@ -41,6 +41,11 @@ function renderList(listBlock) { return tag.ul({}, items); } } + +function renderImage(imagePart) { + return text(imagePart.src); +} + /** * Map from part to function that outputs DOM for the part */ @@ -53,6 +58,7 @@ const formatFunction = { link: linkPart => tag.a({ href: linkPart.url, target: "_blank", rel: "noopener" }, renderParts(linkPart.inlines)), format: formatPart => tag[formatPart.format]({}, renderParts(formatPart.children)), list: renderList, + image: renderImage, newline: () => tag.br() };