From f3161a235456742403e3749bfe7dc4f800e8a143 Mon Sep 17 00:00:00 2001 From: Max Date: Mon, 4 Mar 2024 16:39:10 +0100 Subject: [PATCH] enh(Preview): split togglePreview in setPreview and unsetPreview They actually need to do different things due to the different structure. On the one hand we have the preview node with plain text content. And on the other hand a paragraph node with the text wrapped in a link mark. Signed-off-by: Max --- cypress/e2e/nodes/Preview.spec.js | 63 ++++++++++++++++++++++++------- src/nodes/ParagraphView.vue | 2 +- src/nodes/Preview.js | 30 ++++++++++++--- src/nodes/Preview.vue | 4 +- 4 files changed, 79 insertions(+), 20 deletions(-) diff --git a/cypress/e2e/nodes/Preview.spec.js b/cypress/e2e/nodes/Preview.spec.js index ff1c29897c1..0271ad4ee06 100644 --- a/cypress/e2e/nodes/Preview.spec.js +++ b/cypress/e2e/nodes/Preview.spec.js @@ -39,55 +39,86 @@ describe.only('Preview extension', { retries: 0 }, () => { ], }) - describe('togglePreview command', { retries: 0 }, () => { + describe('setPreview command', { retries: 0 }, () => { it('is available in commands', () => { - expect(editor.commands).to.have.property('togglePreview') + expect(editor.commands).to.have.property('setPreview') }) it('cannot run on normal paragraph', () => { prepareEditor('hello\n') - expect(editor.can().togglePreview()).to.be.false + expect(editor.can().setPreview()).to.be.false }) it('cannot run on a paragraph with a different mark', () => { prepareEditor('*link text*\n') - expect(editor.can().togglePreview()).to.be.false + 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().togglePreview()).to.be.false + 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().togglePreview()).to.be.false + 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().togglePreview()).to.be.false + 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().togglePreview()).to.be.true + expect(editor.can().setPreview()).to.be.true }) it('results in a preview node with the href', () => { prepareEditor('[link text](https://nextcloud.com)\n') - editor.commands.togglePreview() + editor.commands.setPreview() expect(getParentNode().type.name).to.equal('preview') expect(getParentNode().attrs.href).to.equal('https://nextcloud.com') }) - it('reverts when toggled twice', () => { + it('cannot run twice', () => { prepareEditor('[link text](https://nextcloud.com)\n') - editor.commands.togglePreview() - editor.commands.togglePreview() + 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') - expect(getParentNode().attrs.href).to.equal('https://nextcloud.com') + }) + + 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') }) }) @@ -97,6 +128,12 @@ describe.only('Preview extension', { retries: 0 }, () => { return selection.$head.parent } + function getMark() { + const { state: { selection } } = editor + console.info(selection.$head) + return selection.$head.nodeAfter.marks[0] + } + function prepareEditor(input) { loadMarkdown(editor, input) editor.commands.setTextSelection(1) diff --git a/src/nodes/ParagraphView.vue b/src/nodes/ParagraphView.vue index 04d32b3d3b2..9a5f25de329 100644 --- a/src/nodes/ParagraphView.vue +++ b/src/nodes/ParagraphView.vue @@ -80,7 +80,7 @@ export default { this.$editor.chain() .focus() .setTextSelection(this.getPos()) - .togglePreview({ href: this.href }) + .setPreview({ href: this.href }) .run() }, getTextReference(node) { diff --git a/src/nodes/Preview.js b/src/nodes/Preview.js index 89550b3cc58..d6ca1677c16 100644 --- a/src/nodes/Preview.js +++ b/src/nodes/Preview.js @@ -20,7 +20,7 @@ * */ -import { Node } from '@tiptap/core' +import { Node, isNodeActive, getNodeType } from '@tiptap/core' import { domHref, parseHref } from './../helpers/links.js' import { VueNodeViewRenderer } from '@tiptap/vue-2' @@ -78,20 +78,35 @@ export default Node.create({ addCommands() { return { + /** * Turn a paragraph that contains a single link - * into a preview and vice versa. + * into a preview. * */ - togglePreview: () => ({ state, commands }) => { + setPreview: () => ({ state, commands }) => { const { selection } = state return previewPossible(selection) - && commands.toggleNode( + && commands.setNode( this.name, - 'paragraph', previewAttributesFromSelection(selection), ) }, + + /** + * Turn a preview back into a paragraph + * that contains a single link. + * + */ + unsetPreview: () => ({ state, chain }) => { + const { selection } = state + return isPreview(this.name, this.attributes, state) + && chain() + .setNode('paragraph') + .setLink(this.attributes) + .run() + }, + } }, }) @@ -101,6 +116,11 @@ function previewAttributesFromSelection({ $from }) { return { href, title: 'preview' } } +function isPreview(typeOrName, attributes, state) { + const type = getNodeType(typeOrName, state.schema) + return isNodeActive(state, type, attributes) +} + function previewPossible({ $from }) { if (childCount($from.parent) > 1) { return false diff --git a/src/nodes/Preview.vue b/src/nodes/Preview.vue index 1c90d69a8e0..efc3df6be67 100644 --- a/src/nodes/Preview.vue +++ b/src/nodes/Preview.vue @@ -37,6 +37,7 @@ import { nodeViewProps, NodeViewWrapper, NodeViewContent } from '@tiptap/vue-2' import { NcReferenceList } from '@nextcloud/vue/dist/Components/NcRichText.js' import PreviewOptions from '../components/Editor/PreviewOptions.vue' +import { useEditorMixin } from '../components/Editor.provider.js' export default { name: 'Preview', @@ -52,13 +53,14 @@ export default { value: 'link-preview', } }, + mixins: [ useEditorMixin ], methods: { convertToParagraph(...args) { console.info(...args) this.$editor.chain() .focus() .setTextSelection(this.getPos()) - .setNode('paragaph') + .unsetPreview() .run() }, },