diff --git a/src/extensions/markdown/Link/paste-plugin.test.ts b/src/extensions/markdown/Link/paste-plugin.test.ts new file mode 100644 index 000000000..7f27f9117 --- /dev/null +++ b/src/extensions/markdown/Link/paste-plugin.test.ts @@ -0,0 +1,57 @@ +import {EditorState, TextSelection} from 'prosemirror-state'; +import {builders} from 'prosemirror-test-builder'; +import {EditorView} from 'prosemirror-view'; + +import {dispatchPasteEvent} from '../../../../tests/dispatch-event'; +import {createMarkupChecker} from '../../../../tests/sameMarkup'; +import {ExtensionsManager} from '../../../core'; +import {LoggerFacet} from '../../../core/utils/logger'; +import {Logger2} from '../../../logger'; +import {BaseNode, BaseSchemaSpecs} from '../../base/specs'; + +import {LinkAttr, LinkSpecs, linkMarkName} from './LinkSpecs'; +import {linkPasteEnhance} from './paste-plugin'; + +const logger = new Logger2(); +const { + schema, + plugins, + markupParser: parser, + serializer, +} = new ExtensionsManager({ + extensions: (builder) => { + builder.use(BaseSchemaSpecs, {}).use(LinkSpecs); + builder.addPlugin(linkPasteEnhance, builder.Priority.High); + }, + logger, +}).build(); +plugins.unshift(LoggerFacet.of(logger)); + +const {doc, p, lnk} = builders<'doc' | 'p' | 'lnk'>(schema, { + doc: {nodeType: BaseNode.Doc}, + p: {nodeType: BaseNode.Paragraph}, + lnk: {markType: linkMarkName, [LinkAttr.Href]: 'http://example.com?'}, +}); + +const {same} = createMarkupChecker({parser, serializer}); + +describe('link paste plugin', () => { + it('parser does not include trailing question mark in matchLinks', () => { + const match = parser.matchLinks('http://example.com?'); + expect(match?.[0]?.raw).toBe('http://example.com'); + }); + + it('pastes url ending with question mark as link for selected text', () => { + const startDoc = doc(p('test text')); + const state = EditorState.create({ + schema, + doc: startDoc, + selection: TextSelection.create(startDoc, startDoc.tag.a, startDoc.tag.b), + plugins, + }); + const view = new EditorView(null, {state}); + dispatchPasteEvent(view, {'text/plain': 'http://example.com?'}); + expect(view.state.doc).toMatchNode(doc(p(lnk('test text')))); + same('[test text](http://example.com?)', view.state.doc); + }); +}); diff --git a/src/extensions/markdown/Link/paste-plugin.ts b/src/extensions/markdown/Link/paste-plugin.ts index 52d8abac3..27a96e2ea 100644 --- a/src/extensions/markdown/Link/paste-plugin.ts +++ b/src/extensions/markdown/Link/paste-plugin.ts @@ -80,6 +80,12 @@ function getUrl(data: DataTransfer | null, parser: Parser): string | null { // TODO: should we process HTML here? const text = data.getData(DataTransferType.Text); const match = parser.matchLinks(text); - if (match?.[0]?.raw === text) return match[0].url; + if (match?.[0]) { + const {raw, url} = match[0]; + if (raw === text) return url; + if (text.endsWith('?') && raw + '?' === text && parser.validateLink(text)) { + return parser.normalizeLink(text); + } + } return null; }