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

[visual] Handle content in pasted lists with only one item (#14752)

GitOrigin-RevId: 4f0a2d260b04b8f08f2dad7e200309b2611952e6
Alf Eaton 3 лет назад
Родитель
Сommit
13bbea4ced

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

@@ -99,6 +99,9 @@ const htmlToLaTeX = (documentElement: HTMLElement) => {
   // pre-process table elements
   processTables(documentElement)
 
+  // pre-process lists
+  processLists(documentElement)
+
   // protect special characters in non-LaTeX text nodes
   protectSpecialCharacters(documentElement)
 
@@ -214,6 +217,18 @@ const matchingParents = (element: HTMLElement, selector: string) => {
   return matches
 }
 
+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
+    if (list.childElementCount === 1) {
+      const div = document.createElement('div')
+      div.append(...list.firstElementChild!.childNodes)
+      list.before('\n', div, '\n')
+      list.remove()
+    }
+  }
+}
+
 const processTables = (element: HTMLElement) => {
   for (const table of element.querySelectorAll('table')) {
     // create a wrapper element for the table and the caption
@@ -626,11 +641,13 @@ const selectors = [
     end: () => `}\n\n`,
   }),
   createSelector({
+    // selector: 'ul:has(> li:nth-child(2))', // only select lists with at least 2 items (once Firefox supports :has())
     selector: 'ul',
     start: element => `\n\n${listIndent(element)}\\begin{itemize}`,
     end: element => `\n${listIndent(element)}\\end{itemize}\n`,
   }),
   createSelector({
+    // selector: 'ol:has(> li:nth-child(2))', // only select lists with at least 2 items (once Firefox supports :has())
     selector: 'ol',
     start: element => `\n\n${listIndent(element)}\\begin{enumerate}`,
     end: element => `\n${listIndent(element)}\\end{enumerate}\n`,

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

@@ -76,6 +76,19 @@ describe('<CodeMirrorEditor/> paste HTML in Visual mode', function () {
     cy.get('.ol-cm-item').should('have.length', 2)
   })
 
+  it('removes a solitary item from a list', function () {
+    mountEditor()
+
+    const data = '<ul><li>foo</li></ul>'
+
+    const clipboardData = new DataTransfer()
+    clipboardData.setData('text/html', data)
+    cy.get('@content').trigger('paste', { clipboardData })
+
+    cy.get('@content').should('have.text', 'foo')
+    cy.get('.ol-cm-item').should('have.length', 0)
+  })
+
   it('handles a pasted table', function () {
     mountEditor()
 
@@ -337,8 +350,8 @@ describe('<CodeMirrorEditor/> paste HTML in Visual mode', function () {
     const data = [
       'test',
       '<p>foo</p><p>bar</p><p>baz</p>',
-      '<ul><li><p>foo</p></li></ul>',
-      '<ol><li><p>foo</p></li></ol>',
+      '<ul><li><p>foo</p></li><li><p>foo</p></li></ul>',
+      '<ol><li><p>foo</p></li><li><p>foo</p></li></ol>',
       '<table><tbody><tr><td><p>foo</p></td></tr></tbody></table>',
       'test',
     ].join('\n')
@@ -349,9 +362,9 @@ describe('<CodeMirrorEditor/> paste HTML in Visual mode', function () {
 
     cy.get('@content').should(
       'have.text',
-      'testfoobarbaz foo foo\\begin{tabular}{l}foo ↩\\end{tabular}test'
+      'testfoobarbaz foo foo foo foo\\begin{tabular}{l}foo ↩\\end{tabular}test'
     )
-    cy.get('.cm-line').should('have.length', 17)
+    cy.get('.cm-line').should('have.length', 19)
   })
 
   it('handles pasted inline code', function () {