mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-06-01 21:31:36 +02:00
[visual] Escape special characters in pasted URLs (#14789)
GitOrigin-RevId: 58e0b4b9b902301dbcb34f918ebbfdad0c8a763f
This commit is contained in:
@@ -102,6 +102,7 @@ export const HrefTooltipContent: FC = () => {
|
||||
bsStyle="link"
|
||||
className="ol-cm-command-tooltip-link"
|
||||
onClick={() => {
|
||||
// TODO: unescape content
|
||||
window.open(url, '_blank')
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -217,6 +217,25 @@ const matchingParents = (element: HTMLElement, selector: string) => {
|
||||
return matches
|
||||
}
|
||||
|
||||
const urlCharacterReplacements = new Map<string, string>([
|
||||
['\\', '\\\\'],
|
||||
['#', '\\#'],
|
||||
['%', '\\%'],
|
||||
['{', '%7B'],
|
||||
['}', '%7D'],
|
||||
])
|
||||
|
||||
const protectUrlCharacters = (url: string) => {
|
||||
// NOTE: add new characters to both this regex and urlCharacterReplacements
|
||||
return url.replaceAll(/[\\#%{}]/g, match => {
|
||||
const replacement = urlCharacterReplacements.get(match)
|
||||
if (!replacement) {
|
||||
throw new Error(`No replacement found for ${match}`)
|
||||
}
|
||||
return replacement
|
||||
})
|
||||
}
|
||||
|
||||
const processLists = (element: HTMLElement) => {
|
||||
for (const list of element.querySelectorAll('ol,ul')) {
|
||||
// if the list has only one item, replace the list with an element containing the contents of the item
|
||||
@@ -519,8 +538,11 @@ const selectors = [
|
||||
createSelector({
|
||||
selector: 'a',
|
||||
match: element => !!element.href && hasContent(element),
|
||||
start: (element: HTMLAnchorElement) => `\\href{${element.href}}{`,
|
||||
end: element => `}`,
|
||||
start: (element: HTMLAnchorElement) => {
|
||||
const url = protectUrlCharacters(element.href)
|
||||
return `\\href{${url}}{`
|
||||
},
|
||||
end: () => `}`,
|
||||
}),
|
||||
createSelector({
|
||||
selector: 'h1',
|
||||
|
||||
@@ -277,7 +277,8 @@ describe('<CodeMirrorEditor/> paste HTML in Visual mode', function () {
|
||||
it('handles a pasted link', function () {
|
||||
mountEditor()
|
||||
|
||||
const data = '<a href="https://example.com/">foo</a>'
|
||||
const data =
|
||||
'<a href="https://example.com/?q=$foo_~bar&x=\\bar#fragment{y}%2">foo</a>'
|
||||
|
||||
const clipboardData = new DataTransfer()
|
||||
clipboardData.setData('text/html', data)
|
||||
@@ -285,6 +286,13 @@ describe('<CodeMirrorEditor/> paste HTML in Visual mode', function () {
|
||||
|
||||
cy.get('@content').should('have.text', '{foo}')
|
||||
cy.get('.ol-cm-command-href').should('have.length', 1)
|
||||
|
||||
cy.get('.cm-line').eq(0).type('{leftArrow}')
|
||||
cy.findByLabelText('URL').should(
|
||||
'have.value',
|
||||
'https://example.com/?q=$foo_~bar&x=\\\\bar\\#fragment%7By%7D\\%2'
|
||||
)
|
||||
// TODO: assert that the "Go to page" link has been unescaped
|
||||
})
|
||||
|
||||
it('handles a pasted code block', function () {
|
||||
|
||||
Reference in New Issue
Block a user