Просмотр исходного кода

[visual] Improve pasting of a table containing a caption (#14322)

GitOrigin-RevId: 6d7676a9412c5614f85c17e16509c80ad937cc40
Alf Eaton 3 лет назад
Родитель
Сommit
a55bb9c4b2

+ 33 - 8
services/web/frontend/js/features/source-editor/extensions/visual/paste-html.ts

@@ -30,7 +30,9 @@ export const pasteHtml = Prec.highest(
         )
 
         return true
-      } catch {
+      } catch (error) {
+        console.error(error)
+
         // fall back to the default paste handler
         return false
       }
@@ -54,6 +56,9 @@ const htmlToLaTeX = (html: string) => {
   // remove style elements
   removeUnwantedElements(documentElement, 'style')
 
+  // pre-process table elements
+  processTables(documentElement)
+
   // protect special characters in non-LaTeX text nodes
   protectSpecialCharacters(documentElement)
 
@@ -147,6 +152,24 @@ const matchingParents = (element: HTMLElement, selector: string) => {
   return matches
 }
 
+const processTables = (element: HTMLElement) => {
+  for (const table of element.querySelectorAll('table')) {
+    // create a wrapper element for the table and the caption
+    const container = document.createElement('div')
+    container.className = 'ol-table-wrap'
+    table.after(container)
+
+    // move the caption (if it exists) into the container before the table
+    const caption = table.querySelector('caption')
+    if (caption) {
+      container.append(caption)
+    }
+
+    // move the table into the container
+    container.append(table)
+  }
+}
+
 const tabular = (element: HTMLTableElement) => {
   const options = []
 
@@ -335,13 +358,15 @@ export const selectors = [
     start: () => `\n\n\\begin{verbatim}\n`,
     end: () => `\n\\end{verbatim}\n\n`,
   }),
+  createSelector({
+    selector: '.ol-table-wrap',
+    start: element => `\n\n\\begin{table}\n\\centering\n`,
+    end: () => `\n\\end{table}\n\n`,
+  }),
   createSelector({
     selector: 'table',
-    start: element =>
-      `\n\n\\begin{table}\n\\centering\n\\begin{tabular}{${tabular(
-        element
-      )}}\n`,
-    end: () => `\n\\end{tabular}\n\\end{table}\n\n`,
+    start: element => `\n\\begin{tabular}{${tabular(element)}}\n`,
+    end: () => `\n\\end{tabular}\n`,
   }),
   createSelector({
     selector: 'thead',
@@ -386,8 +411,8 @@ export const selectors = [
     },
   }),
   createSelector({
-    selector: 'table > caption',
-    start: () => `\n\n\\caption{\\label{tab:example}`,
+    selector: 'caption',
+    start: () => `\n\n\\caption{`,
     end: () => `}\n\n`,
   }),
   createSelector({

+ 17 - 0
services/web/test/frontend/features/source-editor/components/codemirror-editor-visual-paste-html.spec.tsx

@@ -132,6 +132,23 @@ describe('<CodeMirrorEditor/> paste HTML in Visual mode', function () {
     )
   })
 
+  it('handles a pasted table with a caption', function () {
+    mountEditor()
+
+    const data =
+      '<table><caption>A table</caption><tbody><tr><td>foo</td><td>bar</td></tr></tbody></table>'
+
+    const clipboardData = new DataTransfer()
+    clipboardData.setData('text/html', data)
+    cy.spy(clipboardData, 'getData').as('get-data')
+    cy.get('@content').trigger('paste', { clipboardData })
+
+    cy.get('@content').should(
+      'have.text',
+      'A table\\begin{tabular}{c c}foo & bar ↩\\end{tabular}'
+    )
+  })
+
   it('handles a pasted link', function () {
     mountEditor()