diff --git a/services/web/frontend/js/features/source-editor/extensions/visual/paste-html.ts b/services/web/frontend/js/features/source-editor/extensions/visual/paste-html.ts index ff2c1e8ff7..822ea19365 100644 --- a/services/web/frontend/js/features/source-editor/extensions/visual/paste-html.ts +++ b/services/web/frontend/js/features/source-editor/extensions/visual/paste-html.ts @@ -36,17 +36,18 @@ export const pasteHtml = [ 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(' 0 && !hasProgId(documentElement)) { + return false + } + // if the only content is in a code block, use the plain text version if (onlyCode(documentElement)) { return false @@ -55,7 +56,7 @@ export const pasteHtml = [ const latex = htmlToLaTeX(documentElement) // if there's no formatting, use the plain text version - if (latex === text) { + if (latex === text && clipboardData.files.length === 0) { return false } @@ -112,6 +113,13 @@ const onlyCode = (documentElement: HTMLElement) => { ) } +const hasProgId = (documentElement: HTMLElement) => { + const meta = documentElement.querySelector( + 'meta[name="ProgId"]' + ) + return meta && meta.content.trim().length > 0 +} + const htmlToLaTeX = (documentElement: HTMLElement) => { // remove style elements removeUnwantedElements(documentElement, 'style') diff --git a/services/web/test/frontend/features/source-editor/components/codemirror-editor-visual-paste-html.spec.tsx b/services/web/test/frontend/features/source-editor/components/codemirror-editor-visual-paste-html.spec.tsx index 0a3896b400..01a7800977 100644 --- a/services/web/test/frontend/features/source-editor/components/codemirror-editor-visual-paste-html.spec.tsx +++ b/services/web/test/frontend/features/source-editor/components/codemirror-editor-visual-paste-html.spec.tsx @@ -29,6 +29,7 @@ describe(' paste HTML in Visual mode', function () { window.metaAttributesCache.set('ol-preventCompileOnLoad', true) window.metaAttributesCache.set('ol-splitTestVariants', { 'paste-html': 'enabled', + 'figure-modal': 'enabled', }) cy.interceptEvents() cy.interceptSpelling() @@ -659,4 +660,38 @@ describe(' paste HTML in Visual mode', function () { 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('images/gradient.png').then(image => { + const file = new File([image], 'gradient.png', { type: 'image/png' }) + const html = `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('images/gradient.png').then(image => { + const file = new File([image], 'gradient.png', { type: 'image/png' }) + const html = `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') + }) + }) })