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

GitOrigin-RevId: 4f0a2d260b04b8f08f2dad7e200309b2611952e6
This commit is contained in:
Alf Eaton 2023-09-11 10:59:59 +01:00 committed by Copybot
parent 1e3f305ba3
commit 13bbea4ced
2 changed files with 34 additions and 4 deletions

View file

@ -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`,

View file

@ -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 () {