Sanitize latex text placeholder (no new lines)
This commit is contained in:
parent
85f201702e
commit
8daa59709b
@ -8,7 +8,7 @@ android.enableJetifier=true
|
|||||||
android.enableBuildCache=true
|
android.enableBuildCache=true
|
||||||
android.buildCacheDir=build/pre-dex-cache
|
android.buildCacheDir=build/pre-dex-cache
|
||||||
|
|
||||||
VERSION_NAME=4.0.1
|
VERSION_NAME=4.0.2-SNAPSHOT
|
||||||
|
|
||||||
GROUP=io.noties.markwon
|
GROUP=io.noties.markwon
|
||||||
POM_DESCRIPTION=Markwon markdown for Android
|
POM_DESCRIPTION=Markwon markdown for Android
|
||||||
|
@ -16,8 +16,14 @@ android {
|
|||||||
dependencies {
|
dependencies {
|
||||||
|
|
||||||
api project(':markwon-core')
|
api project(':markwon-core')
|
||||||
api project(':markwon-image')
|
|
||||||
api deps['jlatexmath-android']
|
api deps['jlatexmath-android']
|
||||||
|
|
||||||
|
deps['test'].with {
|
||||||
|
testImplementation it['junit']
|
||||||
|
testImplementation it['robolectric']
|
||||||
|
testImplementation it['mockito']
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
registerArtifact(this)
|
registerArtifact(this)
|
@ -12,6 +12,7 @@ import android.widget.TextView;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.Px;
|
import androidx.annotation.Px;
|
||||||
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
import org.commonmark.parser.Parser;
|
import org.commonmark.parser.Parser;
|
||||||
|
|
||||||
@ -84,8 +85,8 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
|
|||||||
|
|
||||||
// @since 4.0.0
|
// @since 4.0.0
|
||||||
private final int paddingHorizontal;
|
private final int paddingHorizontal;
|
||||||
// @since 4.0.0
|
|
||||||
|
|
||||||
|
// @since 4.0.0
|
||||||
private final int paddingVertical;
|
private final int paddingVertical;
|
||||||
|
|
||||||
// @since 4.0.0
|
// @since 4.0.0
|
||||||
@ -132,7 +133,10 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
|
|||||||
|
|
||||||
final int length = visitor.length();
|
final int length = visitor.length();
|
||||||
|
|
||||||
visitor.builder().append(latex);
|
// @since 4.0.2 we cannot append _raw_ latex as a placeholder-text,
|
||||||
|
// because Android will draw formula for each line of text, thus
|
||||||
|
// leading to formula duplicated (drawn on each line of text)
|
||||||
|
visitor.builder().append(prepareLatexTextPlaceholder(latex));
|
||||||
|
|
||||||
final MarkwonConfiguration configuration = visitor.configuration();
|
final MarkwonConfiguration configuration = visitor.configuration();
|
||||||
|
|
||||||
@ -161,6 +165,13 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
|
|||||||
AsyncDrawableScheduler.schedule(textView);
|
AsyncDrawableScheduler.schedule(textView);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @since 4.0.2
|
||||||
|
@VisibleForTesting
|
||||||
|
@NonNull
|
||||||
|
static String prepareLatexTextPlaceholder(@NonNull String latex) {
|
||||||
|
return latex.replace('\n', ' ').trim();
|
||||||
|
}
|
||||||
|
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
|
|
||||||
private final float textSize;
|
private final float textSize;
|
||||||
@ -350,6 +361,8 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
|
|||||||
final Rect imageBounds = drawable.getResult().getBounds();
|
final Rect imageBounds = drawable.getResult().getBounds();
|
||||||
final int canvasWidth = drawable.getLastKnownCanvasWidth();
|
final int canvasWidth = drawable.getLastKnownCanvasWidth();
|
||||||
|
|
||||||
|
// todo: scale down when formula is greater than width (keep ratio and apply height)
|
||||||
|
|
||||||
if (fitCanvas
|
if (fitCanvas
|
||||||
&& imageBounds.width() < canvasWidth) {
|
&& imageBounds.width() < canvasWidth) {
|
||||||
// we increase only width (keep height as-is)
|
// we increase only width (keep height as-is)
|
||||||
|
@ -0,0 +1,113 @@
|
|||||||
|
package io.noties.markwon.ext.latex;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import org.commonmark.parser.Parser;
|
||||||
|
import org.commonmark.parser.block.BlockParserFactory;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
|
||||||
|
import io.noties.markwon.MarkwonConfiguration;
|
||||||
|
import io.noties.markwon.MarkwonVisitor;
|
||||||
|
import io.noties.markwon.SpannableBuilder;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
@Config(manifest = Config.NONE)
|
||||||
|
public class JLatexMathPluginTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void latex_text_placeholder() {
|
||||||
|
// text placeholder cannot have new-line characters and should be trimmed from ends
|
||||||
|
|
||||||
|
final String[] in = {
|
||||||
|
"hello",
|
||||||
|
"he\nllo",
|
||||||
|
" hello\n\n",
|
||||||
|
"\n\nhello\n\n",
|
||||||
|
"\n",
|
||||||
|
" \nhello\n "
|
||||||
|
};
|
||||||
|
|
||||||
|
for (String latex : in) {
|
||||||
|
final String placeholder = JLatexMathPlugin.prepareLatexTextPlaceholder(latex);
|
||||||
|
assertTrue(placeholder, placeholder.indexOf('\n') < 0);
|
||||||
|
if (placeholder.length() > 0) {
|
||||||
|
assertFalse(placeholder, Character.isWhitespace(placeholder.charAt(0)));
|
||||||
|
assertFalse(placeholder, Character.isWhitespace(placeholder.charAt(placeholder.length() - 1)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void block_parser_registered() {
|
||||||
|
final JLatexMathPlugin plugin = JLatexMathPlugin.create(0);
|
||||||
|
final Parser.Builder builder = mock(Parser.Builder.class);
|
||||||
|
plugin.configureParser(builder);
|
||||||
|
verify(builder, times(1)).customBlockParserFactory(any(BlockParserFactory.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void visitor_registered() {
|
||||||
|
final JLatexMathPlugin plugin = JLatexMathPlugin.create(0);
|
||||||
|
final MarkwonVisitor.Builder builder = mock(MarkwonVisitor.Builder.class);
|
||||||
|
plugin.configureVisitor(builder);
|
||||||
|
//noinspection unchecked
|
||||||
|
verify(builder, times(1))
|
||||||
|
.on(eq(JLatexMathBlock.class), any(MarkwonVisitor.NodeVisitor.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void visit() {
|
||||||
|
final JLatexMathPlugin plugin = JLatexMathPlugin.create(0, new JLatexMathPlugin.BuilderConfigure() {
|
||||||
|
@Override
|
||||||
|
public void configureBuilder(@NonNull JLatexMathPlugin.Builder builder) {
|
||||||
|
// no async in test (nooped for this test)
|
||||||
|
builder.executorService(mock(ExecutorService.class));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
final MarkwonVisitor.Builder builder = mock(MarkwonVisitor.Builder.class);
|
||||||
|
final ArgumentCaptor<MarkwonVisitor.NodeVisitor> captor =
|
||||||
|
ArgumentCaptor.forClass(MarkwonVisitor.NodeVisitor.class);
|
||||||
|
plugin.configureVisitor(builder);
|
||||||
|
//noinspection unchecked
|
||||||
|
verify(builder, times(1))
|
||||||
|
.on(eq(JLatexMathBlock.class), captor.capture());
|
||||||
|
final MarkwonVisitor.NodeVisitor nodeVisitor = captor.getValue();
|
||||||
|
|
||||||
|
final MarkwonVisitor visitor = mock(MarkwonVisitor.class);
|
||||||
|
final JLatexMathBlock block = mock(JLatexMathBlock.class);
|
||||||
|
when(block.latex()).thenReturn(" first\nsecond\n ");
|
||||||
|
|
||||||
|
final SpannableBuilder spannableBuilder = mock(SpannableBuilder.class);
|
||||||
|
when(visitor.builder()).thenReturn(spannableBuilder);
|
||||||
|
when(visitor.configuration()).thenReturn(mock(MarkwonConfiguration.class));
|
||||||
|
|
||||||
|
//noinspection unchecked
|
||||||
|
nodeVisitor.visit(visitor, block);
|
||||||
|
|
||||||
|
verify(block, times(1)).latex();
|
||||||
|
verify(visitor, times(1)).length();
|
||||||
|
|
||||||
|
final ArgumentCaptor<String> stringArgumentCaptor = ArgumentCaptor.forClass(String.class);
|
||||||
|
verify(spannableBuilder, times(1)).append(stringArgumentCaptor.capture());
|
||||||
|
|
||||||
|
final String placeholder = stringArgumentCaptor.getValue();
|
||||||
|
assertTrue(placeholder, placeholder.indexOf('\n') < 0);
|
||||||
|
|
||||||
|
verify(visitor, times(1)).setSpans(eq(0), any());
|
||||||
|
}
|
||||||
|
}
|
@ -68,20 +68,23 @@ public class LatexActivity extends Activity {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
final String l = "$$\n" +
|
// final String l = "$$\n" +
|
||||||
" P(X=r)=\\frac{\\lambda^r e^{-\\lambda}}{r!}\n" +
|
// " P(X=r)=\\frac{\\lambda^r e^{-\\lambda}}{r!}\n" +
|
||||||
"$$\n" +
|
// "$$\n" +
|
||||||
"\n" +
|
// "\n" +
|
||||||
"$$\n" +
|
// "$$\n" +
|
||||||
" P(X<r)=P(X<r-1)\n" +
|
// " P(X<r)=P(X<r-1)\n" +
|
||||||
"$$\n" +
|
// "$$\n" +
|
||||||
"\n" +
|
// "\n" +
|
||||||
"$$\n" +
|
// "$$\n" +
|
||||||
" P(X>r)=1-P(X<r=1)\n" +
|
// " P(X>r)=1-P(X<r=1)\n" +
|
||||||
"$$\n" +
|
// "$$\n" +
|
||||||
"\n" +
|
// "\n" +
|
||||||
"$$\n" +
|
// "$$\n" +
|
||||||
" \\text{Variance} = \\lambda\n" +
|
// " \\text{Variance} = \\lambda\n" +
|
||||||
|
// "$$";
|
||||||
|
final String l = "$$ \n" +
|
||||||
|
" \\sigma_T^2 = \\frac{1-p}{p^2}\n" +
|
||||||
"$$";
|
"$$";
|
||||||
markwon.setMarkdown(textView, l);
|
markwon.setMarkdown(textView, l);
|
||||||
return;
|
return;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user