Commit 87b4bb69 authored by Enrique Alcantara's avatar Enrique Alcantara Committed by Enrique Alcántara

Add input rules for creating links

Allow to create a link in the Content Editor
using Markdown syntax or by typing a URL

Changelog: changed
parent 295b2ad2
......@@ -2,22 +2,35 @@ import { markInputRule } from '@tiptap/core';
import { Link } from '@tiptap/extension-link';
import { defaultMarkdownSerializer } from 'prosemirror-markdown/src/to_markdown';
const insertLinkInputRuleRegExp = /(?:^|\s)\[([\w|\s|-]+)\]\(.+?\)$/gm;
export const markdownLinkSyntaxInputRuleRegExp = /(?:^|\s)\[([\w|\s|-]+)\]\((?<href>.+?)\)$/gm;
export const tiptapExtension = Link
.extend({
addInputRules() {
return [
markInputRule(insertLinkInputRuleRegExp, this.type, (match) => {
const extractHrefRegExp = /\[([\w|\s|-]+)\]\((?<href>.+?)\)$/gm;
export const urlSyntaxRegExp = /(?:^|\s)(?<href>(?:https?:\/\/|www\.)[\S]+)(?:\s|\n)$/gim;
return extractHrefRegExp.exec(match[0]).groups;
}),
];
}
})
.configure({
openOnClick: false,
});
const extractHrefFromMatch = (match) => {
return { href: match.groups.href };
};
export const extractHrefFromMarkdownLink = (match) => {
/**
* Removes the last capture group from the match to satisfy
* tiptap markInputRule expectation of having the content as
* the last capture group in the match.
*
* https://github.com/ueberdosis/tiptap/blob/main/packages/core/src/inputRules/markInputRule.ts#L11
*/
match.pop();
return extractHrefFromMatch(match);
};
export const tiptapExtension = Link.extend({
addInputRules() {
return [
markInputRule(markdownLinkSyntaxInputRuleRegExp, this.type, extractHrefFromMarkdownLink),
markInputRule(urlSyntaxRegExp, this.type, extractHrefFromMatch),
];
},
}).configure({
openOnClick: false,
});
export const serializer = defaultMarkdownSerializer.marks.link;
import { tiptapExtension as Link } from '~/content_editor/extensions/link';
import { createTestEditor } from '../test_utils';
import {
markdownLinkSyntaxInputRuleRegExp,
urlSyntaxRegExp,
extractHrefFromMarkdownLink,
} from '~/content_editor/extensions/link';
describe('content_editor/extensions/link', () => {
let tiptapEditor;
describe.each`
input | matches
${'[gitlab](https://gitlab.com)'} | ${true}
${'[documentation](readme.md)'} | ${true}
${'[link 123](readme.md)'} | ${true}
${'[link 123](read me.md)'} | ${true}
${'text'} | ${false}
${'documentation](readme.md'} | ${false}
${'https://www.google.com'} | ${false}
`('markdownLinkSyntaxInputRuleRegExp', ({ input, matches }) => {
it(`${matches ? 'matches' : 'does not match'} ${input}`, () => {
const match = new RegExp(markdownLinkSyntaxInputRuleRegExp).exec(input);
beforeEach(() => {
tiptapEditor = createTestEditor({ extensions: [Link] });
expect(Boolean(match?.groups.href)).toBe(matches);
});
});
it.each`
input
${'[gitlab](https://gitlab.com)'}
`('creates a link when the input rule matches $input', ({ input }) => {
const { view } = tiptapEditor;
const { selection } = view.state;
describe.each`
input | matches
${'http://example.com '} | ${true}
${'https://example.com '} | ${true}
${'www.example.com '} | ${true}
${'example.com/ab.html '} | ${false}
${'text'} | ${false}
${' http://example.com '} | ${true}
${'https://www.google.com '} | ${true}
`('urlSyntaxRegExp', ({ input, matches }) => {
it(`${matches ? 'matches' : 'does not match'} ${input}`, () => {
const match = new RegExp(urlSyntaxRegExp).exec(input);
tiptapEditor.chain().insertContent(input).run();
expect(Boolean(match?.groups.href)).toBe(matches);
});
});
describe('extractHrefFromMarkdownLink', () => {
const input = '[gitlab](https://gitlab.com)';
const href = 'https://gitlab.com';
let match;
let result;
/**
* Calls the event handler that executes the input rule
* https://github.com/ProseMirror/prosemirror-inputrules/blob/master/src/inputrules.js#L65
* */
view.someProp('handleTextInput', (f) => f(view, selection.from, selection.to, input));
beforeEach(() => {
match = new RegExp(markdownLinkSyntaxInputRuleRegExp).exec(input);
result = extractHrefFromMarkdownLink(match);
});
const serializedDoc = tiptapEditor.getJSON();
it('extracts the url from a markdown link captured by markdownLinkSyntaxInputRuleRegExp', () => {
expect(result).toEqual({ href });
});
console.log(serializedDoc.content[0].content[0])
it('makes sure that url text is the last capture group', () => {
expect(match[match.length - 1]).toEqual('gitlab');
});
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment