diff --git a/services/web/frontend/js/features/source-editor/extensions/visual/utils/typeset-content.ts b/services/web/frontend/js/features/source-editor/extensions/visual/utils/typeset-content.ts
index 913c045b83..4e0e5efab1 100644
--- a/services/web/frontend/js/features/source-editor/extensions/visual/utils/typeset-content.ts
+++ b/services/web/frontend/js/features/source-editor/extensions/visual/utils/typeset-content.ts
@@ -58,6 +58,26 @@ export function typesetNodeIntoElement(
pushAncestor(document.createElement('em'))
const textArgument = childNode.getChild('TextArgument')
from = textArgument?.getChild('LongArg')?.from ?? childNode.to
+ } else if (isUnknownCommandWithName(childNode, '\\texttt', state)) {
+ const spanElement = document.createElement('span')
+ spanElement.classList.add('ol-cm-command-texttt')
+ pushAncestor(spanElement)
+ const textArgument = childNode.getChild('TextArgument')
+ from = textArgument?.getChild('LongArg')?.from ?? childNode.to
+ } else if (isUnknownCommandWithName(childNode, '\\and', state)) {
+ const spanElement = document.createElement('span')
+ spanElement.classList.add('ol-cm-command-and')
+ pushAncestor(spanElement)
+ const textArgument = childNode.getChild('TextArgument')
+ from = textArgument?.getChild('LongArg')?.from ?? childNode.to
+ } else if (
+ isUnknownCommandWithName(childNode, '\\corref', state) ||
+ isUnknownCommandWithName(childNode, '\\fnref', state) ||
+ isUnknownCommandWithName(childNode, '\\thanks', state)
+ ) {
+ // ignoring these commands
+ from = childNode.to
+ return false
} else if (isNewline(childNode, state)) {
ancestor().appendChild(document.createElement('br'))
from = childNode.to
@@ -65,23 +85,13 @@ export function typesetNodeIntoElement(
},
function leave(childNodeRef) {
const childNode = childNodeRef.node
- if (isUnknownCommandWithName(childNode, '\\textit', state)) {
- const typeSetElement = popAncestor()
- ancestor().appendChild(typeSetElement)
- const textArgument = childNode.getChild('TextArgument')
- const endBrace = textArgument?.getChild('CloseBrace')
- if (endBrace) {
- from = endBrace.to
- }
- } else if (isUnknownCommandWithName(childNode, '\\textbf', state)) {
- const typeSetElement = popAncestor()
- ancestor().appendChild(typeSetElement)
- const textArgument = childNode.getChild('TextArgument')
- const endBrace = textArgument?.getChild('CloseBrace')
- if (endBrace) {
- from = endBrace.to
- }
- } else if (isUnknownCommandWithName(childNode, '\\emph', state)) {
+ if (
+ isUnknownCommandWithName(childNode, '\\and', state) ||
+ isUnknownCommandWithName(childNode, '\\textit', state) ||
+ isUnknownCommandWithName(childNode, '\\textbf', state) ||
+ isUnknownCommandWithName(childNode, '\\emph', state) ||
+ isUnknownCommandWithName(childNode, '\\texttt', state)
+ ) {
const typeSetElement = popAncestor()
ancestor().appendChild(typeSetElement)
const textArgument = childNode.getChild('TextArgument')
diff --git a/services/web/frontend/js/features/source-editor/extensions/visual/visual-widgets/maketitle.ts b/services/web/frontend/js/features/source-editor/extensions/visual/visual-widgets/maketitle.ts
index d121659727..4d6c480ac6 100644
--- a/services/web/frontend/js/features/source-editor/extensions/visual/visual-widgets/maketitle.ts
+++ b/services/web/frontend/js/features/source-editor/extensions/visual/visual-widgets/maketitle.ts
@@ -119,26 +119,32 @@ function buildAuthorsElement(
const authorsElement = document.createElement('div')
authorsElement.classList.add('ol-cm-authors')
- for (const { node, content } of authors) {
- const authorContent = content.slice(1, -1) // trimming the braces
- const authors = authorContent.replaceAll(/\s+/g, ' ').split('\\and')
+ for (const { node } of authors) {
+ const typesettedAuthors = document.createElement('div')
+ typesetNodeIntoElement(node, typesettedAuthors, view.state)
- for (const author of authors) {
- const authorElement = document.createElement('div')
- authorElement.classList.add('ol-cm-author')
+ let currentAuthor = document.createElement('div')
+ currentAuthor.classList.add('ol-cm-author')
+ authorsElement.append(currentAuthor)
- for (const authorInfoItem of author.split('\\\\')) {
- const authorLineElement = document.createElement('div')
- authorLineElement.classList.add('ol-cm-author-line')
- authorLineElement.textContent = authorInfoItem.trim()
- authorElement.appendChild(authorLineElement)
+ while (typesettedAuthors.firstChild) {
+ const child = typesettedAuthors.firstChild
+ if (
+ child instanceof HTMLElement &&
+ child.classList.contains('ol-cm-command-and')
+ ) {
+ currentAuthor = document.createElement('div')
+ currentAuthor.classList.add('ol-cm-author')
+ authorsElement.append(currentAuthor)
+ child.remove()
+ } else {
+ currentAuthor.append(child)
}
-
- authorElement.addEventListener('mouseup', () => {
- selectNode(view, node)
- })
- authorsElement.append(authorElement)
}
+
+ currentAuthor.addEventListener('mouseup', () => {
+ selectNode(view, node)
+ })
}
return authorsElement
diff --git a/services/web/test/frontend/features/source-editor/components/codemirror-editor-visual.spec.tsx b/services/web/test/frontend/features/source-editor/components/codemirror-editor-visual.spec.tsx
index 2b8c59d450..c26afdf8ba 100644
--- a/services/web/test/frontend/features/source-editor/components/codemirror-editor-visual.spec.tsx
+++ b/services/web/test/frontend/features/source-editor/components/codemirror-editor-visual.spec.tsx
@@ -419,6 +419,7 @@ describe(' in Visual mode', function () {
const deleteLine =
'{command}{leftArrow}{shift}{command}{rightArrow}{backspace}'
+ // italic, bold and emph
cy.get('@second-line').type(deleteLine)
cy.get('@second-line').type(
'\\title{{}formatted with \\textit{{}italic} \\textbf{{}bold} \\emph{{}emph}}'
@@ -437,6 +438,24 @@ describe(' in Visual mode', function () {
'title
formated only italic'
)
+ // texttt command
+ cy.get('@second-line').type(deleteLine)
+ cy.get('@second-line').type('\\title{{}title with \\texttt{{}command}}')
+ cy.get('.ol-cm-title').should(
+ 'contain.html',
+ 'title with command'
+ )
+
+ cy.get('@second-line').type(deleteLine)
+ cy.get('@second-line').type(
+ '\\title{{}title with \\texttt{{}\\textbf{{}command}}}'
+ )
+ cy.get('.ol-cm-title').should(
+ 'contain.html',
+ 'title with command'
+ )
+
+ // unsupported commands
cy.get('@second-line').type(deleteLine)
cy.get('@second-line').type('\\title{{}Title with \\& ampersands}')
cy.get('.ol-cm-title').should(
@@ -528,6 +547,25 @@ describe(' in Visual mode', function () {
cy.get('.ol-cm-author').eq(1).should('contain', 'AuthorNeX')
})
+ it('should ignore some commands in author', function () {
+ cy.get('@first-line').type(
+ [
+ '\\author{{}Author with \\corref{{}cor1} and \\fnref{{}label2} in the name}',
+ '\\title{{}Document title}',
+ '\\begin{{}document}',
+ '\\maketitle',
+ '\\end{{}document}',
+ '',
+ ].join('{Enter}')
+ )
+
+ cy.get('.ol-cm-authors').should('have.length', 1)
+ cy.get('.ol-cm-author').should(
+ 'contain.html',
+ 'Author with and in the name'
+ )
+ })
+
describe('handling of special characters', function () {
it('decorates a tilde with a non-breaking space', function () {
cy.get('@first-line').type('Test~test')