mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
[visual] Escape special characters in pasted URLs (#14789)
GitOrigin-RevId: 58e0b4b9b902301dbcb34f918ebbfdad0c8a763f
This commit is contained in:
parent
496b30e18e
commit
875ea723ca
3 changed files with 34 additions and 3 deletions
|
@ -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 () {
|
||||
|
|
Loading…
Reference in a new issue