diff --git a/sample/src/main/java/io/noties/markwon/sample/basicplugins/BasicPluginsActivity.java b/sample/src/main/java/io/noties/markwon/sample/basicplugins/BasicPluginsActivity.java
index 632c94ec..ce73a7f8 100644
--- a/sample/src/main/java/io/noties/markwon/sample/basicplugins/BasicPluginsActivity.java
+++ b/sample/src/main/java/io/noties/markwon/sample/basicplugins/BasicPluginsActivity.java
@@ -3,8 +3,12 @@ package io.noties.markwon.sample.basicplugins;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
+import android.text.Spannable;
+import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.ForegroundColorSpan;
+import android.view.View;
+import android.widget.ScrollView;
import android.widget.TextView;
import androidx.annotation.NonNull;
@@ -19,6 +23,7 @@ import java.util.Collections;
import io.noties.markwon.AbstractMarkwonPlugin;
import io.noties.markwon.BlockHandlerDef;
+import io.noties.markwon.LinkResolverDef;
import io.noties.markwon.Markwon;
import io.noties.markwon.MarkwonConfiguration;
import io.noties.markwon.MarkwonSpansFactory;
@@ -26,6 +31,7 @@ import io.noties.markwon.MarkwonVisitor;
import io.noties.markwon.SoftBreakAddsNewLinePlugin;
import io.noties.markwon.core.CoreProps;
import io.noties.markwon.core.MarkwonTheme;
+import io.noties.markwon.core.spans.HeadingSpan;
import io.noties.markwon.core.spans.LastLineSpacingSpan;
import io.noties.markwon.image.ImageItem;
import io.noties.markwon.image.ImagesPlugin;
@@ -39,6 +45,7 @@ import io.noties.markwon.sample.R;
public class BasicPluginsActivity extends ActivityWithMenuOptions {
private TextView textView;
+ private ScrollView scrollView;
@NonNull
@Override
@@ -54,7 +61,8 @@ public class BasicPluginsActivity extends ActivityWithMenuOptions {
.add("additionalSpacing", this::additionalSpacing)
.add("headingNoSpace", this::headingNoSpace)
.add("headingNoSpaceBlockHandler", this::headingNoSpaceBlockHandler)
- .add("allBlocksNoForcedLine", this::allBlocksNoForcedLine);
+ .add("allBlocksNoForcedLine", this::allBlocksNoForcedLine)
+ .add("anchor", this::anchor);
}
@Override
@@ -63,6 +71,7 @@ public class BasicPluginsActivity extends ActivityWithMenuOptions {
setContentView(R.layout.activity_text_view);
textView = findViewById(R.id.text_view);
+ scrollView = findViewById(R.id.scroll_view);
paragraphSpan();
//
@@ -403,4 +412,96 @@ public class BasicPluginsActivity extends ActivityWithMenuOptions {
// rendering lifecycle (before/after)
// renderProps
// process
+
+ private static class AnchorSpan {
+ final String anchor;
+
+ AnchorSpan(@NonNull String anchor) {
+ this.anchor = anchor;
+ }
+ }
+
+ @NonNull
+ private String createAnchor(@NonNull CharSequence content) {
+ return String.valueOf(content)
+ .replaceAll("[^\\w]", "")
+ .toLowerCase();
+ }
+
+ private static class AnchorLinkResolver extends LinkResolverDef {
+
+ interface ScrollTo {
+ void scrollTo(@NonNull View view, int top);
+ }
+
+ private final ScrollTo scrollTo;
+
+ AnchorLinkResolver(@NonNull ScrollTo scrollTo) {
+ this.scrollTo = scrollTo;
+ }
+
+ @Override
+ public void resolve(@NonNull View view, @NonNull String link) {
+ if (link.startsWith("#")) {
+ final TextView textView = (TextView) view;
+ final Spanned spanned = (Spannable) textView.getText();
+ final AnchorSpan[] spans = spanned.getSpans(0, spanned.length(), AnchorSpan.class);
+ if (spans != null) {
+ final String anchor = link.substring(1);
+ for (AnchorSpan span: spans) {
+ if (anchor.equals(span.anchor)) {
+ final int start = spanned.getSpanStart(span);
+ final int line = textView.getLayout().getLineForOffset(start);
+ final int top = textView.getLayout().getLineTop(line);
+ scrollTo.scrollTo(textView, top);
+ return;
+ }
+ }
+ }
+ }
+ super.resolve(view, link);
+ }
+ }
+
+ private void anchor() {
+ final String lorem = getString(R.string.lorem);
+ final String md = "" +
+ "Hello [there](#there)!\n\n\n" +
+ lorem + "\n\n" +
+ "# There!\n\n" +
+ lorem;
+
+ final Markwon markwon = Markwon.builder(this)
+ .usePlugin(new AbstractMarkwonPlugin() {
+ @Override
+ public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) {
+ builder.linkResolver(new AnchorLinkResolver((view, top) -> {
+ scrollView.smoothScrollTo(0, top);
+ }));
+ }
+
+ @Override
+ public void afterSetText(@NonNull TextView textView) {
+ final Spannable spannable = (Spannable) textView.getText();
+ // obtain heading spans
+ final HeadingSpan[] spans = spannable.getSpans(0, spannable.length(), HeadingSpan.class);
+ if (spans != null) {
+ for (HeadingSpan span : spans) {
+ final int start = spannable.getSpanStart(span);
+ final int end = spannable.getSpanEnd(span);
+ final int flags = spannable.getSpanFlags(span);
+ spannable.setSpan(
+ new AnchorSpan(createAnchor(spannable.subSequence(start, end))),
+ start,
+ end,
+ flags
+ );
+ }
+ }
+ }
+ })
+ .build();
+
+ markwon.setMarkdown(textView, md);
+ }
}
diff --git a/sample/src/main/java/io/noties/markwon/sample/html/HtmlActivity.java b/sample/src/main/java/io/noties/markwon/sample/html/HtmlActivity.java
index 21613985..eecd1c3b 100644
--- a/sample/src/main/java/io/noties/markwon/sample/html/HtmlActivity.java
+++ b/sample/src/main/java/io/noties/markwon/sample/html/HtmlActivity.java
@@ -1,6 +1,5 @@
package io.noties.markwon.sample.html;
-import android.app.Activity;
import android.os.Bundle;
import android.text.Layout;
import android.text.TextUtils;
@@ -27,9 +26,22 @@ import io.noties.markwon.html.HtmlTag;
import io.noties.markwon.html.MarkwonHtmlRenderer;
import io.noties.markwon.html.TagHandler;
import io.noties.markwon.html.tag.SimpleTagHandler;
+import io.noties.markwon.sample.ActivityWithMenuOptions;
+import io.noties.markwon.sample.MenuOptions;
import io.noties.markwon.sample.R;
-public class HtmlActivity extends Activity {
+public class HtmlActivity extends ActivityWithMenuOptions {
+
+ @NonNull
+ @Override
+ public MenuOptions menuOptions() {
+ return MenuOptions.create()
+ .add("align", this::align)
+ .add("randomCharSize", this::randomCharSize)
+ .add("enhance", this::enhance);
+ }
+
+ private TextView textView;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
@@ -39,35 +51,9 @@ public class HtmlActivity extends Activity {
// let's define some custom tag-handlers
- final TextView textView = findViewById(R.id.text_view);
+ textView = findViewById(R.id.text_view);
- final Markwon markwon = Markwon.builder(this)
- .usePlugin(HtmlPlugin.create())
- .usePlugin(new AbstractMarkwonPlugin() {
- @Override
- public void configure(@NonNull Registry registry) {
- registry.require(HtmlPlugin.class, htmlPlugin -> htmlPlugin
- .addHandler(new AlignTagHandler())
- .addHandler(new RandomCharSize(new Random(42L), textView.getTextSize()))
- .addHandler(new EnhanceTagHandler((int) (textView.getTextSize() * 2 + .05F))));
- }
- })
- .build();
-
- final String markdown = "# Hello, HTML\n" +
- "\n" +
- "We are centered\n" +
- "\n" +
- "We are at the end\n" +
- "\n" +
- "We should be at the start\n" +
- "\n" +
- "\n" +
- "This message should have a jumpy feeling because of different sizes of characters\n" +
- "\n\n" +
- "This is text that must be enhanced, at least a part of it";
-
- markwon.setMarkdown(textView, markdown);
+ align();
}
// we can use `SimpleTagHandler` for _simple_ cases (when the whole tag content
@@ -105,6 +91,31 @@ public class HtmlActivity extends Activity {
}
}
+ private void align() {
+
+ final String md = "" +
+ "We are centered\n" +
+ "\n" +
+ "We are at the end\n" +
+ "\n" +
+ "We should be at the start\n" +
+ "\n";
+
+
+ final Markwon markwon = Markwon.builder(this)
+ .usePlugin(HtmlPlugin.create())
+ .usePlugin(new AbstractMarkwonPlugin() {
+ @Override
+ public void configure(@NonNull Registry registry) {
+ registry.require(HtmlPlugin.class, htmlPlugin -> htmlPlugin
+ .addHandler(new AlignTagHandler()));
+ }
+ })
+ .build();
+
+ markwon.setMarkdown(textView, md);
+ }
+
// each character will have random size
private static class RandomCharSize extends TagHandler {
@@ -139,6 +150,27 @@ public class HtmlActivity extends Activity {
}
}
+ private void randomCharSize() {
+
+ final String md = "" +
+ "\n" +
+ "This message should have a jumpy feeling because of different sizes of characters\n" +
+ "\n\n";
+
+ final Markwon markwon = Markwon.builder(this)
+ .usePlugin(HtmlPlugin.create())
+ .usePlugin(new AbstractMarkwonPlugin() {
+ @Override
+ public void configure(@NonNull Registry registry) {
+ registry.require(HtmlPlugin.class, htmlPlugin -> htmlPlugin
+ .addHandler(new RandomCharSize(new Random(42L), textView.getTextSize())));
+ }
+ })
+ .build();
+
+ markwon.setMarkdown(textView, md);
+ }
+
private static class EnhanceTagHandler extends TagHandler {
private final int enhanceTextSize;
@@ -187,4 +219,24 @@ public class HtmlActivity extends Activity {
return position;
}
}
+
+ private void enhance() {
+
+ final String md = "" +
+ "This is text that must be enhanced, at least a part of it";
+
+
+ final Markwon markwon = Markwon.builder(this)
+ .usePlugin(HtmlPlugin.create())
+ .usePlugin(new AbstractMarkwonPlugin() {
+ @Override
+ public void configure(@NonNull Registry registry) {
+ registry.require(HtmlPlugin.class, htmlPlugin -> htmlPlugin
+ .addHandler(new EnhanceTagHandler((int) (textView.getTextSize() * 2 + .05F))));
+ }
+ })
+ .build();
+
+ markwon.setMarkdown(textView, md);
+ }
}
diff --git a/sample/src/main/res/layout/activity_text_view.xml b/sample/src/main/res/layout/activity_text_view.xml
index 9828f257..c3904e70 100644
--- a/sample/src/main/res/layout/activity_text_view.xml
+++ b/sample/src/main/res/layout/activity_text_view.xml
@@ -1,5 +1,6 @@
diff --git a/sample/src/main/res/values/strings.xml b/sample/src/main/res/values/strings.xml
index 5505eb0c..36d27f2a 100644
--- a/sample/src/main/res/values/strings.xml
+++ b/sample/src/main/res/values/strings.xml
@@ -12,4 +12,16 @@ Sentiment Satisfied 64 red: @ic-sentiment_satisfied-red-64
]]>
+
+