From b13859e42385d37cb20540d32e7a0ec39619cad1 Mon Sep 17 00:00:00 2001 From: Jonas Date: Thu, 2 Mar 2023 18:29:17 +0100 Subject: [PATCH] Use the href of links for link previews, not `node.textContent` Until now we used node.textContent to determine whether a paragraph is a link that warrants a link preview. Instead, we now check whether the paragraph has a single text node wich is a link and use its href. Text nodes with empty textContent are ignored in order to allow whitespaces before and after the link. This way we ensure to always show the preview of the link target, not of the description text. Both may differ, which has security implications. Also, links with a custom description get a link preview as well. And last but not least, it fixes link previes for URLs with spaces. (Background: for some reason, url-encoded spaces in textContent of links get decoded when they're transformed to markdown and written to a file. Therefore URLs with spaces lost their link preview once the Text session was closed prior to this commit) Fixes: #3871 Signed-off-by: Jonas --- src/nodes/ParagraphView.vue | 43 +++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/src/nodes/ParagraphView.vue b/src/nodes/ParagraphView.vue index 2b0296de740..a62eb2ffca8 100644 --- a/src/nodes/ParagraphView.vue +++ b/src/nodes/ParagraphView.vue @@ -47,7 +47,7 @@ export default { data() { return { text: null, - isLoggedIn: getCurrentUser() + isLoggedIn: getCurrentUser(), } }, watch: { @@ -63,20 +63,51 @@ export default { }, beforeCreate() { this.debouncedUpdateText = debounce((newNode) => { - this.text = this.getTextReference(this.node?.textContent) + this.text = this.getTextReference(this.node) }, 500) }, created() { - this.text = this.getTextReference(this.node?.textContent) + this.text = this.getTextReference(this.node) }, beforeUnmount() { this.debouncedUpdateText?.cancel() }, methods: { - getTextReference(text) { + getTextReference(node) { + if (!node?.childCount) { + return null + } + + // Only regard paragraphs with exactly one text node (ignoring whitespace-only nodes) + let textNode + for (let i = 0; i < node.childCount; i++) { + const childNode = node.child(i) + + // Disregard paragraphs with non-text nodes + if (childNode.type.name !== 'text') { + return null + } + + // Ignore children with empty text + if (!childNode.textContent.trim()) { + continue + } + + // Disregard paragraphs with more than one text nodes + if (textNode) { + return null + } + + textNode = childNode + } + + // Check if the text node is a link + const linkMark = textNode?.marks.find((m) => m.type.name === 'link') + const href = linkMark?.attrs?.href + const PATTERN = /(^)(https?:\/\/)((?:[-A-Z0-9+_]+\.)+[-A-Z]+(?:\/[-A-Z0-9+&@#%?=~_|!:,.;()]*)*)($)/ig - if ((new RegExp(PATTERN)).test(text.trim())) { - return text.trim() + if ((new RegExp(PATTERN)).test(href)) { + return href } return null