From 327290e971817102f686fc1dc9aa1c0a34b159f2 Mon Sep 17 00:00:00 2001 From: Cadence Ember Date: Sun, 8 Nov 2020 00:49:12 +1300 Subject: [PATCH] Autolink URLs in messages --- src/js/basic.js | 10 ++++----- src/js/events/message.js | 35 ++++++++++++++++++++++++------- src/sass/components/messages.sass | 1 + 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/js/basic.js b/src/js/basic.js index 7108662..38d413c 100644 --- a/src/js/basic.js +++ b/src/js/basic.js @@ -19,12 +19,12 @@ const qa = s => document.querySelectorAll(s); */ class ElemJS { constructor(type) { - if (type instanceof HTMLElement) { - // If passed an existing element, bind to it - this.bind(type); - } else { - // Otherwise, create a new detached element to bind to + if (typeof type === "string") { + // Passed a tag name; create an element to bind to this.bind(document.createElement(type)); + } else { + // Passed an existing element; bind to it + this.bind(type); } this.children = []; } diff --git a/src/js/events/message.js b/src/js/events/message.js index 1b39c8a..2bd69ed 100644 --- a/src/js/events/message.js +++ b/src/js/events/message.js @@ -68,9 +68,7 @@ function cleanHTML(html) { } // Here we put all the processing of the messages that isn't as likely to potentially lead to security issues -function postProcessElements(rootNode) { - const element = rootNode.element - +function postProcessElements(element) { element.querySelectorAll("pre").forEach(n => { new HighlightedCode(n) }) @@ -95,13 +93,11 @@ class HTMLMessage extends MatrixEvent { this.clearChildren() let html = this.data.content.formatted_body - const content = ejs("div") const fragment = cleanHTML(html) - content.element.appendChild(fragment) - postProcessElements(content) + postProcessElements(fragment) - this.child(content) + this.child(ejs(fragment)) super.render() } @@ -121,10 +117,33 @@ class HTMLMessage extends MatrixEvent { } } +function autoLinkText(text) { + const fragment = ejs(new DocumentFragment()) + let lastIndex = 0 + text.replace(/https?:\/\/(?:[A-Za-z-]+\.)+[A-Za-z]{1,10}(?::[0-9]{1,6})?(?:\/[^ ]*)?/g, (url, index) => { + // add text before URL + fragment.addText(text.slice(lastIndex, index)) + // add URL + fragment.child( + ejs("a") + .attribute("target", "_blank") + .attribute("noopener", "") + .attribute("href", url) + .addText(url) + ) + // update state + lastIndex = index + url.length + }) + // add final text + fragment.addText(text.slice(lastIndex)) + return fragment +} + class TextMessage extends MatrixEvent { render() { this.clearChildren() - this.text(this.data.content.body) + const fragment = autoLinkText(this.data.content.body) + this.child(fragment) super.render() } diff --git a/src/sass/components/messages.sass b/src/sass/components/messages.sass index 341fd82..ffc1517 100644 --- a/src/sass/components/messages.sass +++ b/src/sass/components/messages.sass @@ -49,6 +49,7 @@ overflow-wrap: anywhere opacity: 1 transition: opacity 0.2s ease-out + white-space: pre-wrap &--pending opacity: 0.5