mirror of
https://github.com/overleaf/overleaf.git
synced 2025-02-07 08:33:51 +00:00
Handle pasted HTML from Office even if there's an image file on the clipboard (#14852)
GitOrigin-RevId: f0413391ec421c845b435e1392140d265a528ee7
This commit is contained in:
parent
61e49d3644
commit
a2bb8a3ecd
2 changed files with 50 additions and 7 deletions
|
@ -36,17 +36,18 @@ export const pasteHtml = [
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// allow pasting an image to create a figure, if the HTML doesn't contain a table
|
|
||||||
// (because desktop Excel puts both an image and the HTML table on the clipboard)
|
|
||||||
if (clipboardData.files.length > 0 && !html.includes('<table')) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert the HTML to LaTeX
|
// convert the HTML to LaTeX
|
||||||
try {
|
try {
|
||||||
const parser = new DOMParser()
|
const parser = new DOMParser()
|
||||||
const { documentElement } = parser.parseFromString(html, 'text/html')
|
const { documentElement } = parser.parseFromString(html, 'text/html')
|
||||||
|
|
||||||
|
// fall back to creating a figure when there's an image on the clipoard,
|
||||||
|
// unless the HTML indicates that it came from an Office application
|
||||||
|
// (which also puts an image on the clipboard)
|
||||||
|
if (clipboardData.files.length > 0 && !hasProgId(documentElement)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// if the only content is in a code block, use the plain text version
|
// if the only content is in a code block, use the plain text version
|
||||||
if (onlyCode(documentElement)) {
|
if (onlyCode(documentElement)) {
|
||||||
return false
|
return false
|
||||||
|
@ -55,7 +56,7 @@ export const pasteHtml = [
|
||||||
const latex = htmlToLaTeX(documentElement)
|
const latex = htmlToLaTeX(documentElement)
|
||||||
|
|
||||||
// if there's no formatting, use the plain text version
|
// if there's no formatting, use the plain text version
|
||||||
if (latex === text) {
|
if (latex === text && clipboardData.files.length === 0) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,6 +113,13 @@ const onlyCode = (documentElement: HTMLElement) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hasProgId = (documentElement: HTMLElement) => {
|
||||||
|
const meta = documentElement.querySelector<HTMLMetaElement>(
|
||||||
|
'meta[name="ProgId"]'
|
||||||
|
)
|
||||||
|
return meta && meta.content.trim().length > 0
|
||||||
|
}
|
||||||
|
|
||||||
const htmlToLaTeX = (documentElement: HTMLElement) => {
|
const htmlToLaTeX = (documentElement: HTMLElement) => {
|
||||||
// remove style elements
|
// remove style elements
|
||||||
removeUnwantedElements(documentElement, 'style')
|
removeUnwantedElements(documentElement, 'style')
|
||||||
|
|
|
@ -29,6 +29,7 @@ describe('<CodeMirrorEditor/> paste HTML in Visual mode', function () {
|
||||||
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
window.metaAttributesCache.set('ol-preventCompileOnLoad', true)
|
||||||
window.metaAttributesCache.set('ol-splitTestVariants', {
|
window.metaAttributesCache.set('ol-splitTestVariants', {
|
||||||
'paste-html': 'enabled',
|
'paste-html': 'enabled',
|
||||||
|
'figure-modal': 'enabled',
|
||||||
})
|
})
|
||||||
cy.interceptEvents()
|
cy.interceptEvents()
|
||||||
cy.interceptSpelling()
|
cy.interceptSpelling()
|
||||||
|
@ -659,4 +660,38 @@ describe('<CodeMirrorEditor/> paste HTML in Visual mode', function () {
|
||||||
|
|
||||||
cy.get('.cm-line').should('have.length', 8)
|
cy.get('.cm-line').should('have.length', 8)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('treats a pasted image as a figure even if there is HTML', function () {
|
||||||
|
mountEditor()
|
||||||
|
|
||||||
|
cy.fixture<Uint8Array>('images/gradient.png').then(image => {
|
||||||
|
const file = new File([image], 'gradient.png', { type: 'image/png' })
|
||||||
|
const html = `<meta charset="utf-8"><img src="https://example.com/gradient.png" alt="gradient">`
|
||||||
|
|
||||||
|
const clipboardData = new DataTransfer()
|
||||||
|
clipboardData.setData('text/html', html)
|
||||||
|
clipboardData.items.add(file)
|
||||||
|
cy.get('.cm-content').trigger('paste', { clipboardData })
|
||||||
|
|
||||||
|
// figure modal paste handler should appear
|
||||||
|
cy.findByText('Upload from computer').should('be.visible')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does not treat a pasted image as a figure if there is Office HTML', function () {
|
||||||
|
mountEditor()
|
||||||
|
|
||||||
|
cy.fixture<Uint8Array>('images/gradient.png').then(image => {
|
||||||
|
const file = new File([image], 'gradient.png', { type: 'image/png' })
|
||||||
|
const html = `<meta charset="utf-8"><meta name="ProgId" content="MS.Word"><img src="https://example.com/gradient.png" alt="gradient">`
|
||||||
|
|
||||||
|
const clipboardData = new DataTransfer()
|
||||||
|
clipboardData.setData('text/html', html)
|
||||||
|
clipboardData.items.add(file)
|
||||||
|
cy.get('.cm-content').trigger('paste', { clipboardData })
|
||||||
|
|
||||||
|
// paste options button should appear
|
||||||
|
cy.findByLabelText('Paste options').should('be.visible')
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue