Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions AnkiDroid/src/main/java/com/ichi2/anki/noteeditor/MathJaxFormat.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2026 David Allison <davidallisongithub@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/

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()
}
}
24 changes: 6 additions & 18 deletions AnkiDroid/src/main/java/com/ichi2/anki/noteeditor/Toolbar.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright (c) 2026 David Allison <davidallisongithub@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/

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} \)"""),
)
}
}
Loading