Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
enh: add extractLinkParagraphs
Signed-off-by: Max <max@nextcloud.com>
  • Loading branch information
max-nextcloud authored and mejo- committed Sep 23, 2024
commit c4d27a4b06f232e3ee05ebafd5543f70787ec8d3
70 changes: 70 additions & 0 deletions src/plugins/extractLinkParagraphs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import { isLinkToSelfWithHash } from './../helpers/links.js'

/**
* Get a list of all paragraphs that can be converted into a preview.
*
* @param {Document} doc - the prosemirror doc
* @return {Array} paragraphs with one link only found in the doc
*/
export default function extractLinkParagraphs(doc) {
const counter = new Map()
const paragraphs = []

doc.descendants((node, offset) => {
if (node.type.name !== 'paragraph') {
return
}
// ignore paragraphs that cannot be converted
if (!previewPossible(node)) return
paragraphs.push(Object.freeze({
offset,
}))
})

return paragraphs
}

/**
* Is it possible to convert the currently selected node into a preview?
* @param {object} state current editor state
* @param {object} state.selection current selection
* @return {boolean}
*/
function previewPossible(node) {
if (hasOtherContent(node)) {
return false
}
const href = extractHref(node.firstChild)
if (!href || isLinkToSelfWithHash(href)) {
return false
}
return true
}

/**
* Does the node contain more content than the first child
* @param {object} node node to inspect
* @return {boolean}
*/
function hasOtherContent(node) {
return node.childCount > 2
|| (node.childCount === 2 && node.lastChild.textContent.trim())
}

/**
* Get the link href of the given node
* @param {object} node to inspect
* @return {string} The href of the link mark of the node
*/
function extractHref(node) {
if (!node) {
return undefined
}
const link = node.marks.find(mark => mark.type.name === 'link')
return link?.attrs.href
}
84 changes: 84 additions & 0 deletions src/tests/plugins/extractLinkParagraphs.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import extractLinkParagraphs from '../../plugins/extractLinkParagraphs.js'
import Link from '../../marks/Link.js'
import { createCustomEditor } from '../helpers.js'

describe('extractLinkParagraphs', () => {

it('returns an empty array for an empty doc', () => {
const doc = prepareDoc('')
const paragraphs = extractLinkParagraphs(doc)
expect(paragraphs).toEqual([])
})

it('returns paragraphs with a single link', () => {
const content = '<p><a href="https://nextcloud.com">Link</a></p>'
const doc = prepareDoc(content)
const paragraphs = extractLinkParagraphs(doc)
expect(paragraphs).toEqual([
{ offset: 0 }
])
})

it('returns paragraphs with a single link and whitespace', () => {
const content = '<p><a href="https://nextcloud.com">Link</a> </p>'
const doc = prepareDoc(content)
const paragraphs = extractLinkParagraphs(doc)
expect(paragraphs).toEqual([
{ offset: 0 }
])
})

it('returns multiple paragraphs with a single link', () => {
const paragraph = '<p><a href="https://nextcloud.com">Link</a></p>'
const content = paragraph + paragraph
const doc = prepareDoc(content)
const paragraphs = extractLinkParagraphs(doc)
expect(paragraphs).toEqual([
{ offset: 0 },
{ offset: 6 }
])
})

it('ignores an empty paragraph', () => {
const content = '<p></p>'
const doc = prepareDoc(content)
const paragraphs = extractLinkParagraphs(doc)
expect(paragraphs).toEqual([])
})

it('ignores paragraphs with text after the link', () => {
const content = '<p><a href="https://nextcloud.com">Link</a> Hello</p>'
const doc = prepareDoc(content)
const paragraphs = extractLinkParagraphs(doc)
expect(paragraphs).toEqual([])
})

it('ignores paragraphs with text before the link', () => {
const content = '<p>bla <a href="https://nextcloud.com">Link</a></p>'
const doc = prepareDoc(content)
const paragraphs = extractLinkParagraphs(doc)
expect(paragraphs).toEqual([])
})

it('ignores paragraphs with multiple links', () => {
const link = '<a href="https://nextcloud.com">Link</a>'
const content = `<p>${link} ${link}</p>`
const doc = prepareDoc(content)
const paragraphs = extractLinkParagraphs(doc)
expect(paragraphs).toEqual([])
})

})

function prepareDoc(content) {
const editor = createCustomEditor({
content,
extensions: [ Link ]
})
return editor.state.doc
}