Skip to content

Commit

Permalink
Use the href of links for link previews, not node.textContent
Browse files Browse the repository at this point in the history
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 <jonas@freesources.org>
  • Loading branch information
mejo- committed Mar 8, 2023
1 parent f143baf commit b13859e
Showing 1 changed file with 37 additions and 6 deletions.
43 changes: 37 additions & 6 deletions src/nodes/ParagraphView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export default {
data() {
return {
text: null,
isLoggedIn: getCurrentUser()
isLoggedIn: getCurrentUser(),
}
},
watch: {
Expand All @@ -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
Expand Down

0 comments on commit b13859e

Please sign in to comment.