Skip to content

Commit

Permalink
Merge pull request #5399 from nextcloud/enh/preview-links
Browse files Browse the repository at this point in the history
Enh/preview links
  • Loading branch information
juliusknorr authored Mar 7, 2024
2 parents b9fc756 + fecb336 commit b5e9ce2
Show file tree
Hide file tree
Showing 18 changed files with 874 additions and 65 deletions.
44 changes: 5 additions & 39 deletions cypress/e2e/nodes/ListItem.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ import ListItem from '@tiptap/extension-list-item'
import TaskList from './../../../src/nodes/TaskList.js'
import TaskItem from './../../../src/nodes/TaskItem.js'
import BulletList from './../../../src/nodes/BulletList.js'
import Markdown, { createMarkdownSerializer } from './../../../src/extensions/Markdown.js'
import { findChildren } from './../../../src/helpers/prosemirrorUtils.js'
import Markdown from './../../../src/extensions/Markdown.js'
import { createCustomEditor } from './../../support/components.js'
import testData from '../../fixtures/ListItem.md'
import markdownit from './../../../src/markdownit/index.js'
import { loadMarkdown, runCommands, expectMarkdown } from './helpers.js'

describe('ListItem extension integrated in the editor', () => {

Expand Down Expand Up @@ -37,42 +36,9 @@ describe('ListItem extension integrated in the editor', () => {
expect(input).to.be.ok
expect(output).to.be.ok
/* eslint-enable no-unused-expressions */
loadMarkdown(input)
runCommands()
expectMarkdown(output.replace(/\n*$/, ''))
loadMarkdown(editor, input)
runCommands(editor)
expectMarkdown(editor, output.replace(/\n*$/, ''))
})
}

const loadMarkdown = (markdown) => {
const stripped = markdown.replace(/\t*/g, '')
editor.commands.setContent(markdownit.render(stripped))
}

const runCommands = () => {
let found
while ((found = findCommand())) {
const { node, pos } = found
const name = node.text
editor.commands.setTextSelection(pos)
editor.commands[name]()
editor.commands.insertContent('did ')
}
}

const findCommand = () => {
const doc = editor.state.doc
return findChildren(doc, child => {
return child.isText && Object.prototype.hasOwnProperty.call(editor.commands, child.text)
})[0]
}

const expectMarkdown = (markdown) => {
const stripped = markdown.replace(/\t*/g, '')
expect(getMarkdown()).to.equal(stripped)
}

const getMarkdown = () => {
const serializer = createMarkdownSerializer(editor.schema)
return serializer.serialize(editor.state.doc)
}
})
189 changes: 189 additions & 0 deletions cypress/e2e/nodes/Preview.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
/* eslint-disable no-unused-expressions */
/**
* @copyright Copyright (c) 2024 Max <max@nextcloud.com>
*
* @author Max <max@nextcloud.com>
*
* @license AGPL-3.0-or-later
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

import Markdown from './../../../src/extensions/Markdown.js'
import Preview from './../../../src/nodes/Preview.js'
import { Italic, Link } from './../../../src/marks/index.js'
import { createCustomEditor } from './../../support/components.js'
import testData from '../../fixtures/Preview.md'
import { loadMarkdown, runCommands, expectMarkdown } from './helpers.js'

describe.only('Preview extension', { retries: 0 }, () => {

const editor = createCustomEditor({
content: '',
extensions: [
Markdown,
Preview,
Link,
Italic,
],
})

describe('setPreview command', { retries: 0 }, () => {

it('is available in commands', () => {
expect(editor.commands).to.have.property('setPreview')
})

it('cannot run on normal paragraph', () => {
prepareEditor('hello\n')
expect(editor.can().setPreview()).to.be.false
})

it('cannot run on a paragraph with a different mark', () => {
prepareEditor('*link text*\n')
expect(editor.can().setPreview()).to.be.false
})

it('cannot run on a paragraph with a link without a href', () => {
prepareEditor('[link text]()\n')
expect(editor.can().setPreview()).to.be.false
})

it('cannot run on a paragraph with an anchor link', () => {
prepareEditor('[link text](#top)\n')
expect(editor.can().setPreview()).to.be.false
})

it('cannot run on a paragraph with other content', () => {
prepareEditor('[link text](https://nextcloud.com) hello\n')
expect(editor.can().setPreview()).to.be.false
})

it('can run on a paragraph with a link', () => {
prepareEditor('[link text](https://nextcloud.com)\n')
expect(editor.can().setPreview()).to.be.true
})

it('can run the second a paragraph with a link', () => {
prepareEditor('hello\n\n[link text](https://nextcloud.com)\n')
editor.commands.setTextSelection(10)
expect(editor.can().setPreview()).to.be.true
})

it('results in a preview node with the href and text with link mark', () => {
prepareEditor('[link text](https://nextcloud.com)\n')
editor.commands.setPreview()
expect(getParentNode().type.name).to.equal('preview')
expect(getParentNode().attrs.href).to.equal('https://nextcloud.com')
expect(getMark().attrs.href).to.equal('https://nextcloud.com')
})

it('cannot run twice', () => {
prepareEditor('[link text](https://nextcloud.com)\n')
editor.commands.setPreview()
expect(editor.can().setPreview()).to.be.false
})

})

describe('unsetPreview command', { retries: 0 }, () => {

it('is available in commands', () => {
expect(editor.commands).to.have.property('unsetPreview')
})

it('cannot run on normal paragraph', () => {
prepareEditor('hello\n')
expect(editor.can().unsetPreview()).to.be.false
})

it('can run on the output of setPreview', () => {
prepareEditor('[link text](https://nextcloud.com)\n')
editor.commands.setPreview()
expect(editor.can().unsetPreview()).to.be.true
})

it('creates a paragraph', () => {
prepareEditor('[link text](https://nextcloud.com)\n')
editor.commands.setPreview()
editor.commands.unsetPreview()
expect(getParentNode().type.name).to.equal('paragraph')
})

it('includes a link', () => {
prepareEditor('[link text](https://nextcloud.com)\n')
editor.commands.setPreview()
editor.commands.unsetPreview()
expect(getMark().attrs.href).to.equal('https://nextcloud.com')
})

})

/**
*
*/
function getParentNode() {
const { state: { selection } } = editor
return selection.$head.parent
}

/**
*
*/
function getMark() {
const { state: { selection } } = editor
console.info(selection.$head)
return selection.$head.nodeAfter.marks[0]
}

/**
*
* @param input
*/
function prepareEditor(input) {
loadMarkdown(editor, input)
editor.commands.setTextSelection(1)
}

})

describe('Markdown tests for Previews in the editor', { retries: 0 }, () => {
const editor = createCustomEditor({
content: '',
extensions: [
Markdown,
Preview,
Link,
],
})

for (const spec of testData.split(/#+\s+/)) {
const [description, ...rest] = spec.split(/\n/)
const [input, output] = rest.join('\n').split(/\n\n---\n\n/)
if (!description) {
continue
}
it(description, () => {
expect(spec).to.include('\n')
/* eslint-disable no-unused-expressions */
expect(input).to.be.ok
expect(output).to.be.ok
/* eslint-enable no-unused-expressions */
loadMarkdown(editor, input)
runCommands(editor)
expectMarkdown(editor, output.replace(/\n*$/, ''))
})
}
})
80 changes: 80 additions & 0 deletions cypress/e2e/nodes/helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
* @copyright Copyright (c) 2024 Max <max@nextcloud.com>
*
* @author Max <max@nextcloud.com>
*
* @license AGPL-3.0-or-later
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

import markdownit from './../../../src/markdownit/index.js'
import { findChildren } from './../../../src/helpers/prosemirrorUtils.js'
import { createMarkdownSerializer } from './../../../src/extensions/Markdown.js'

/**
*
* @param editor
* @param markdown
*/
export function loadMarkdown(editor, markdown) {
const stripped = markdown.replace(/\t*/g, '')
editor.commands.setContent(markdownit.render(stripped))
}

/**
*
* @param editor
*/
export function runCommands(editor) {
let found
while ((found = findCommand(editor))) {
const { node, pos } = found
const name = node.text
editor.commands.setTextSelection(pos)
editor.commands[name]()
editor.commands.insertContent('did ')
}
}

/**
*
* @param editor
*/
function findCommand(editor) {
const doc = editor.state.doc
return findChildren(doc, child => {
return child.isText && Object.prototype.hasOwnProperty.call(editor.commands, child.text)
})[0]
}

/**
*
* @param editor
* @param markdown
*/
export function expectMarkdown(editor, markdown) {
const stripped = markdown.replace(/\t*/g, '')
expect(getMarkdown(editor)).to.equal(stripped)
}

/**
*
* @param editor
*/
function getMarkdown(editor) {
const serializer = createMarkdownSerializer(editor.schema)
return serializer.serialize(editor.state.doc)
}
23 changes: 23 additions & 0 deletions cypress/fixtures/Preview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
## Runs a spec

empty

---

empty

## Preserves a link

[link text](https://nextcloud.com)

---

[link text](https://nextcloud.com)

## Preserves a link preview

[link text](https://nextcloud.com (Preview))

---

[link text](https://nextcloud.com (Preview))
2 changes: 2 additions & 0 deletions sample.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[Test me](https://www.nextcloud.com (preview))

Loading

0 comments on commit b5e9ce2

Please sign in to comment.