diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/noteeditor/MathJaxFormat.kt b/AnkiDroid/src/main/java/com/ichi2/anki/noteeditor/MathJaxFormat.kt new file mode 100644 index 000000000000..499bb93bf100 --- /dev/null +++ b/AnkiDroid/src/main/java/com/ichi2/anki/noteeditor/MathJaxFormat.kt @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2026 David Allison + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 3 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +package com.ichi2.anki.noteeditor + +import com.ichi2.anki.CollectionManager.TR + +/** Options for inserting MathJax equation types via the toolbar */ +enum class MathJaxFormat( + val prefix: String, + val suffix: String, +) { + /** Display-math block: `\[ E=mc^2 \]` */ + BLOCK(prefix = "\\[", suffix = "\\]"), + + /** + * [mhchem](https://mhchem.github.io/MathJax-mhchem/) chemistry equation: `\( \ce{ H2O } \)` + */ + CHEMISTRY(prefix = "\\( \\ce{", suffix = "} \\)"), + ; + + fun toTextWrapper() = Toolbar.TextWrapper(prefix = prefix, suffix = suffix) + + fun label(): String = + when (this) { + BLOCK -> TR.editingMathjaxBlock() + CHEMISTRY -> TR.editingMathjaxChemistry() + } +} diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/noteeditor/Toolbar.kt b/AnkiDroid/src/main/java/com/ichi2/anki/noteeditor/Toolbar.kt index ec980bd9a621..379afa213d9e 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/noteeditor/Toolbar.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/noteeditor/Toolbar.kt @@ -48,7 +48,6 @@ import androidx.core.view.children import androidx.core.view.isVisible import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat import com.ichi2.anki.AnkiDroidApp -import com.ichi2.anki.CollectionManager.TR import com.ichi2.anki.NoteEditorFragment import com.ichi2.anki.R import com.ichi2.anki.compat.CompatHelper @@ -322,22 +321,11 @@ class Toolbar : FrameLayout { * Displays a dialog that allows the user to insert a MathJax equation in different formats. */ private fun displayInsertMathJaxEquationsDialog() { - data class MathJaxOption( - val label: String, - val prefix: String, - val suffix: String, - ) { - fun toTextWrapper() = TextWrapper(prefix = this.prefix, suffix = this.suffix) - } - - val mathjaxOptions = - arrayOf( - MathJaxOption(TR.editingMathjaxBlock(), prefix = "\\[\\", suffix = "\\]"), - MathJaxOption(TR.editingMathjaxChemistry(), prefix = "\\( \\ce{", suffix = "} \\)"), - ) + val options = MathJaxFormat.entries + val labels = options.map { it.label() }.toTypedArray() AlertDialog.Builder(context).show { - setItems(mathjaxOptions.map(MathJaxOption::label).toTypedArray()) { _, index -> - onFormat(mathjaxOptions[index].toTextWrapper()) + setItems(labels) { _, index -> + onFormat(options[index].toTextWrapper()) } title(R.string.insert_mathjax) } @@ -429,8 +417,8 @@ class Toolbar : FrameLayout { /** * A [TextFormatter] which wraps the selected string with [prefix] and [suffix] - * If there's no selected, the cursor is in the middle of the prefix and suffix - * If there is text selected, the whole string is selected + * If there's no selection, the cursor is placed in the middle of the prefix and suffix + * If text is selected and wrapped, the whole string is selected */ class TextWrapper( private val prefix: String, diff --git a/AnkiDroid/src/test/java/com/ichi2/anki/noteeditor/MathJaxFormatTest.kt b/AnkiDroid/src/test/java/com/ichi2/anki/noteeditor/MathJaxFormatTest.kt new file mode 100644 index 000000000000..593e3f0c3f3c --- /dev/null +++ b/AnkiDroid/src/test/java/com/ichi2/anki/noteeditor/MathJaxFormatTest.kt @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2026 David Allison + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 3 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +package com.ichi2.anki.noteeditor + +import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers.equalTo +import org.junit.Test + +class MathJaxFormatTest { + @Test + fun `block wraps text in display-math delimiters`() { + assertThat( + MathJaxFormat.BLOCK + .toTextWrapper() + .format("E=mc^2") + .result, + equalTo("""\[E=mc^2\]"""), + ) + } + + @Test + fun `chemistry wraps text in mhchem ce delimiters`() { + assertThat( + MathJaxFormat.CHEMISTRY + .toTextWrapper() + .format("H2O") + .result, + equalTo("""\( \ce{H2O} \)"""), + ) + } +}