0
0
mirror of https://github.com/wagtail/wagtail.git synced 2024-11-29 01:22:07 +01:00

Account for terminal punctuation right after a pasted URL within text

This commit is contained in:
Thibaud Colas 2024-10-21 15:22:31 +01:00 committed by Sage Abdullah
parent b31319934a
commit 6b04961654
No known key found for this signature in database
GPG Key ID: EB1A33CC51CC0217
3 changed files with 94 additions and 2 deletions

View File

@ -144,7 +144,14 @@ const insertContentWithLinks = (editorState, htmlOrText) => {
const pattern = new RegExp(linkPatternSource, 'ig'); const pattern = new RegExp(linkPatternSource, 'ig');
// Find matches in the block, confirm the URL, create the entity, store the range. // Find matches in the block, confirm the URL, create the entity, store the range.
const matches = Array.from(blockText.matchAll(pattern), (match) => { const matches = Array.from(blockText.matchAll(pattern), (match) => {
const url = getValidLinkURL(match[1]); // Account for punctuation chars valid in URLs but unlikely to be intended.
// For example "Go to https://example.com."
// Terminal Punctuation class: see https://www.unicode.org/review/pr-23.html.
const cleanURLPattern = match[1].replace(
/\p{Terminal_Punctuation}$/u,
'',
);
const url = getValidLinkURL(cleanURLPattern);
if (!url) return {}; if (!url) return {};
@ -152,7 +159,7 @@ const insertContentWithLinks = (editorState, htmlOrText) => {
return { return {
start: match.index, start: match.index,
end: match.index + match[1].length, end: match.index + cleanURLPattern.length,
key: content.getLastCreatedEntityKey(), key: content.getLastCreatedEntityKey(),
}; };
}); });

View File

@ -276,4 +276,45 @@ describe('onPasteLink', () => {
1: { data: { url: 'http://test.co/' } }, 1: { data: { url: 'http://test.co/' } },
}); });
}); });
it('skips linking punctuation chars', () => {
const punctuation = {
// Characters that will be removed.
'.': '',
'?': '',
'!': '',
':': '',
';': '',
',': '',
// Syriac Harklean Metobelus
'܌': '',
'؟': '',
'،': '',
'‼': '',
'﹒': '',
// Characters that will be preserved.
'…': '…',
'-': '-',
'_': '_',
'': '',
'+': '+',
'=': '=',
};
const input = Object.keys(punctuation)
.map((punc) => `<p><span>http://a.co/t${punc}/${punc}</span></p>`)
.join(' ');
const raw = testOnPasteOutput(input.replace(/<[^>]+/g), input);
expect(raw.blocks.map(({ text }) => text)).toMatchSnapshot();
expect(
Object.values(raw.entityMap).map((entity) => entity.data.url),
).toMatchSnapshot();
const expectedLength = Object.keys(punctuation).map(
(punc) => `http://a.co/t${punc}/`.length + punctuation[punc].length,
);
expect(
raw.blocks.map(({ entityRanges }) => entityRanges[0].length),
).toEqual(expectedLength);
});
}); });

View File

@ -67,3 +67,47 @@ exports[`Link works 1`] = `
test test
</TooltipEntity> </TooltipEntity>
`; `;
exports[`onPasteLink skips linking punctuation chars 1`] = `
[
"http://a.co/t./.",
"http://a.co/t?/?",
"http://a.co/t!/!",
"http://a.co/t:/:",
"http://a.co/t;/;",
"http://a.co/t,/,",
"http://a.co/t܌/܌",
"http://a.co/t؟/؟",
"http://a.co/t،/،",
"http://a.co/t‼/‼",
"http://a.co/t﹒/﹒",
"http://a.co/t…/…",
"http://a.co/t-/-",
"http://a.co/t_/_",
"http://a.co/t/",
"http://a.co/t+/+",
"http://a.co/t=/=hello",
]
`;
exports[`onPasteLink skips linking punctuation chars 2`] = `
[
"http://a.co/t./",
"http://a.co/t?/",
"http://a.co/t!/",
"http://a.co/t:/",
"http://a.co/t;/",
"http://a.co/t,/",
"http://a.co/t܌/",
"http://a.co/t؟/",
"http://a.co/t،/",
"http://a.co/t‼/",
"http://a.co/t﹒/",
"http://a.co/t…/…",
"http://a.co/t-/-",
"http://a.co/t_/_",
"http://a.co/t/",
"http://a.co/t+/+",
"http://a.co/t=/=",
]
`;