Add html sample
This commit is contained in:
parent
ffb5848c3c
commit
fdb0f76e13
@ -4,7 +4,7 @@
|
||||
These are _configurable_ properties:
|
||||
* `AsyncDrawableLoader` (back here since <Badge text="4.0.0" />)
|
||||
* `SyntaxHighlight`
|
||||
* `LinkSpan.Resolver`
|
||||
* `LinkResolver` (since <Badge text="4.0.0" />, before — `LinkSpan.Resolver`)
|
||||
* `UrlProcessor`
|
||||
* `ImageSizeResolver`
|
||||
|
||||
@ -37,9 +37,9 @@ final Markwon markwon = Markwon.builder(context)
|
||||
```
|
||||
|
||||
Currently `Markwon` provides 3 implementations for loading images:
|
||||
* [own implementation](/docs/v4/image.md) with SVG, GIF, data uri and android_assets support
|
||||
* [based on Picasso](/docs/v4/image-picasso.md)
|
||||
* [based on Glide](/docs/v4/image-glide.md)
|
||||
* [markwon implementation](/docs/v4/image/) with SVG, GIF, data uri and android_assets support
|
||||
* [based on Picasso](/docs/v4/image-picasso/)
|
||||
* [based on Glide](/docs/v4/image-glide/)
|
||||
|
||||
## SyntaxHighlight
|
||||
|
||||
@ -59,7 +59,7 @@ Use [syntax-highlight](/docs/v4/syntax-highlight/) to add syntax highlighting
|
||||
to your application
|
||||
:::
|
||||
|
||||
## LinkSpan.Resolver
|
||||
## LinkResolver
|
||||
|
||||
React to a link click event. By default `LinkResolverDef` is used,
|
||||
which tries to start an Activity given the `link` argument. If no
|
||||
@ -70,9 +70,9 @@ final Markwon markwon = Markwon.builder(this)
|
||||
.usePlugin(new AbstractMarkwonPlugin() {
|
||||
@Override
|
||||
public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) {
|
||||
builder.linkResolver(new LinkSpan.Resolver() {
|
||||
builder.linkResolver(new LinkResolver() {
|
||||
@Override
|
||||
public void resolve(View view, @NonNull String link) {
|
||||
public void resolve(@NonNull View view, @NonNull String link) {
|
||||
// react to link click here
|
||||
}
|
||||
});
|
||||
@ -119,8 +119,7 @@ will be kept as-is.
|
||||
|
||||
## ImageSizeResolver
|
||||
|
||||
`ImageSizeResolver` controls the size of an image to be displayed. Currently it
|
||||
handles only HTML images (specified via `img` tag).
|
||||
`ImageSizeResolver` controls the size of an image to be displayed.
|
||||
|
||||
```java
|
||||
final Markwon markwon = Markwon.builder(this)
|
||||
@ -130,12 +129,9 @@ final Markwon markwon = Markwon.builder(this)
|
||||
builder.imageSizeResolver(new ImageSizeResolver() {
|
||||
@NonNull
|
||||
@Override
|
||||
public Rect resolveImageSize(
|
||||
@Nullable ImageSize imageSize,
|
||||
@NonNull Rect imageBounds,
|
||||
int canvasWidth,
|
||||
float textSize) {
|
||||
return null;
|
||||
public Rect resolveImageSize(@NonNull AsyncDrawable drawable) {
|
||||
final ImageSize imageSize = drawable.getImageSize();
|
||||
return drawable.getResult().getBounds();
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -168,6 +164,5 @@ so we will have no point-of-reference from which to _calculate_ image height.
|
||||
`ImageSizeResolverDef` also takes care for an image to **not** exceed
|
||||
canvas width. If an image has greater width than a TextView Canvas, then
|
||||
image will be _scaled-down_ to fit the canvas. Please note that this rule
|
||||
applies only if image has no absolute sizes (for example width is specified
|
||||
in pixels).
|
||||
applies only if image has no sizes specified (`ImageSize == null`).
|
||||
:::
|
@ -35,6 +35,8 @@ final Markwon markwon = Markwon.builder(context)
|
||||
.align(JLatexMathDrawable.ALIGN_CENTER)
|
||||
.fitCanvas(true)
|
||||
.padding(paddingPx)
|
||||
// @since 4.0.0 - horizontal and vertical padding
|
||||
.padding(paddingHorizontalPx, paddingVerticalPx)
|
||||
// @since 4.0.0 - change to provider
|
||||
.backgroundProvider(() -> new MyDrawable()))
|
||||
// @since 4.0.0 - optional, by default cached-thread-pool will be used
|
||||
|
@ -104,4 +104,132 @@ If you wish to exclude some of them `TagHandlerNoOp` can be used:
|
||||
|
||||
## TagHandler
|
||||
|
||||
To define a tag-handler that applies style for the whole tag content (from start to end),
|
||||
a `SimpleTagHandler` can be used. For example, let's define `<align>` tag, which can be used
|
||||
like this:
|
||||
|
||||
* `<align center>centered text</align>`
|
||||
* `<align end>this should be aligned at the end (right for LTR locales)</align>`
|
||||
* `<align>regular alignment</align>`
|
||||
|
||||
```java
|
||||
public class AlignTagHandler extends SimpleTagHandler {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getSpans(
|
||||
@NonNull MarkwonConfiguration configuration,
|
||||
@NonNull RenderProps renderProps,
|
||||
@NonNull HtmlTag tag) {
|
||||
|
||||
final Layout.Alignment alignment;
|
||||
|
||||
// html attribute without value, <align center></align>
|
||||
if (tag.attributes().containsKey("center")) {
|
||||
alignment = Layout.Alignment.ALIGN_CENTER;
|
||||
} else if (tag.attributes().containsKey("end")) {
|
||||
alignment = Layout.Alignment.ALIGN_OPPOSITE;
|
||||
} else {
|
||||
// empty value or any other will make regular alignment
|
||||
alignment = Layout.Alignment.ALIGN_NORMAL;
|
||||
}
|
||||
|
||||
return new AlignmentSpan.Standard(alignment);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Collection<String> supportedTags() {
|
||||
return Collections.singleton("align");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
:::tip
|
||||
`SimpleTagHandler` can return an array of spans from `getSpans` method
|
||||
:::
|
||||
|
||||
Then register `AlignTagHandler`:
|
||||
|
||||
```java
|
||||
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();
|
||||
```
|
||||
|
||||
or directly on `HtmlPlugin`:
|
||||
|
||||
```java
|
||||
final Markwon markwon = Markwon.builder(this)
|
||||
.usePlugin(HtmlPlugin.create(plugin -> plugin.addHandler(new AlignTagHandler())))
|
||||
.build();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
If a tag requires special handling `TagHandler` can be used directly. For example
|
||||
let's define an `<enhance>` tag with `start` and `end` arguments, that will mark
|
||||
start and end positions of the text that needs to be enlarged:
|
||||
|
||||
```html
|
||||
<enhance start="5" end="12">This is text that must be enhanced, at least a part of it</enhance>
|
||||
```
|
||||
|
||||
|
||||
```java
|
||||
public class EnhanceTagHandler extends TagHandler {
|
||||
|
||||
private final int enhanceTextSize;
|
||||
|
||||
EnhanceTagHandler(@Px int enhanceTextSize) {
|
||||
this.enhanceTextSize = enhanceTextSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(
|
||||
@NonNull MarkwonVisitor visitor,
|
||||
@NonNull MarkwonHtmlRenderer renderer,
|
||||
@NonNull HtmlTag tag) {
|
||||
|
||||
// we require start and end to be present
|
||||
final int start = parsePosition(tag.attributes().get("start"));
|
||||
final int end = parsePosition(tag.attributes().get("end"));
|
||||
|
||||
if (start > -1 && end > -1) {
|
||||
visitor.builder().setSpan(
|
||||
new AbsoluteSizeSpan(enhanceTextSize),
|
||||
tag.start() + start,
|
||||
tag.start() + end
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Collection<String> supportedTags() {
|
||||
return Collections.singleton("enhance");
|
||||
}
|
||||
|
||||
private static int parsePosition(@Nullable String value) {
|
||||
int position;
|
||||
if (!TextUtils.isEmpty(value)) {
|
||||
try {
|
||||
position = Integer.parseInt(value);
|
||||
} catch (NumberFormatException e) {
|
||||
e.printStackTrace();
|
||||
position = -1;
|
||||
}
|
||||
} else {
|
||||
position = -1;
|
||||
}
|
||||
return position;
|
||||
}
|
||||
}
|
||||
```
|
@ -24,6 +24,7 @@
|
||||
<activity android:name="io.noties.markwon.sample.basicplugins.BasicPluginsActivity" />
|
||||
<activity android:name="io.noties.markwon.sample.recycler.RecyclerActivity" />
|
||||
<activity android:name="io.noties.markwon.sample.theme.ThemeActivity" />
|
||||
<activity android:name=".html.HtmlActivity" />
|
||||
|
||||
</application>
|
||||
|
||||
|
@ -21,6 +21,7 @@ import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.sample.basicplugins.BasicPluginsActivity;
|
||||
import io.noties.markwon.sample.core.CoreActivity;
|
||||
import io.noties.markwon.sample.customextension.CustomExtensionActivity;
|
||||
import io.noties.markwon.sample.html.HtmlActivity;
|
||||
import io.noties.markwon.sample.latex.LatexActivity;
|
||||
import io.noties.markwon.sample.recycler.RecyclerActivity;
|
||||
|
||||
@ -97,6 +98,10 @@ public class MainActivity extends Activity {
|
||||
activity = RecyclerActivity.class;
|
||||
break;
|
||||
|
||||
case HTML:
|
||||
activity = HtmlActivity.class;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalStateException("No Activity is associated with sample-item: " + item);
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ public enum Sample {
|
||||
|
||||
RECYCLER(R.string.sample_recycler),
|
||||
|
||||
;
|
||||
HTML(R.string.sample_html);
|
||||
|
||||
private final int textResId;
|
||||
|
||||
|
@ -0,0 +1,190 @@
|
||||
package io.noties.markwon.sample.html;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.text.Layout;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.AbsoluteSizeSpan;
|
||||
import android.text.style.AlignmentSpan;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.Px;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Random;
|
||||
|
||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.MarkwonConfiguration;
|
||||
import io.noties.markwon.MarkwonVisitor;
|
||||
import io.noties.markwon.RenderProps;
|
||||
import io.noties.markwon.SpannableBuilder;
|
||||
import io.noties.markwon.html.HtmlPlugin;
|
||||
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.R;
|
||||
|
||||
public class HtmlActivity extends Activity {
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.activity_text_view);
|
||||
|
||||
// let's define some custom tag-handlers
|
||||
|
||||
final TextView 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" +
|
||||
"<align center>We are centered</align>\n" +
|
||||
"\n" +
|
||||
"<align end>We are at the end</align>\n" +
|
||||
"\n" +
|
||||
"<align>We should be at the start</align>\n" +
|
||||
"\n" +
|
||||
"<random-char-size>\n" +
|
||||
"This message should have a jumpy feeling because of different sizes of characters\n" +
|
||||
"</random-char-size>\n\n" +
|
||||
"<enhance start=\"5\" end=\"12\">This is text that must be enhanced, at least a part of it</enhance>";
|
||||
|
||||
markwon.setMarkdown(textView, markdown);
|
||||
}
|
||||
|
||||
// we can use `SimpleTagHandler` for _simple_ cases (when the whole tag content
|
||||
// will have spans from start to end)
|
||||
//
|
||||
// we can use any tag name, even not defined in HTML spec
|
||||
private static class AlignTagHandler extends SimpleTagHandler {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getSpans(
|
||||
@NonNull MarkwonConfiguration configuration,
|
||||
@NonNull RenderProps renderProps,
|
||||
@NonNull HtmlTag tag) {
|
||||
|
||||
final Layout.Alignment alignment;
|
||||
|
||||
// html attribute without value, <align center></align>
|
||||
if (tag.attributes().containsKey("center")) {
|
||||
alignment = Layout.Alignment.ALIGN_CENTER;
|
||||
} else if (tag.attributes().containsKey("end")) {
|
||||
alignment = Layout.Alignment.ALIGN_OPPOSITE;
|
||||
} else {
|
||||
// empty value or any other will make regular alignment
|
||||
alignment = Layout.Alignment.ALIGN_NORMAL;
|
||||
}
|
||||
|
||||
return new AlignmentSpan.Standard(alignment);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Collection<String> supportedTags() {
|
||||
return Collections.singleton("align");
|
||||
}
|
||||
}
|
||||
|
||||
// each character will have random size
|
||||
private static class RandomCharSize extends TagHandler {
|
||||
|
||||
private final Random random;
|
||||
private final float base;
|
||||
|
||||
RandomCharSize(@NonNull Random random, float base) {
|
||||
this.random = random;
|
||||
this.base = base;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(
|
||||
@NonNull MarkwonVisitor visitor,
|
||||
@NonNull MarkwonHtmlRenderer renderer,
|
||||
@NonNull HtmlTag tag) {
|
||||
|
||||
final SpannableBuilder builder = visitor.builder();
|
||||
|
||||
// text content is already added, we should only apply spans
|
||||
|
||||
for (int i = tag.start(), end = tag.end(); i < end; i++) {
|
||||
final int size = (int) (base * (random.nextFloat() + 0.5F) + 0.5F);
|
||||
builder.setSpan(new AbsoluteSizeSpan(size, false), i, i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Collection<String> supportedTags() {
|
||||
return Collections.singleton("random-char-size");
|
||||
}
|
||||
}
|
||||
|
||||
private static class EnhanceTagHandler extends TagHandler {
|
||||
|
||||
private final int enhanceTextSize;
|
||||
|
||||
EnhanceTagHandler(@Px int enhanceTextSize) {
|
||||
this.enhanceTextSize = enhanceTextSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(
|
||||
@NonNull MarkwonVisitor visitor,
|
||||
@NonNull MarkwonHtmlRenderer renderer,
|
||||
@NonNull HtmlTag tag) {
|
||||
|
||||
// we require start and end to be present
|
||||
final int start = parsePosition(tag.attributes().get("start"));
|
||||
final int end = parsePosition(tag.attributes().get("end"));
|
||||
|
||||
if (start > -1 && end > -1) {
|
||||
visitor.builder().setSpan(
|
||||
new AbsoluteSizeSpan(enhanceTextSize),
|
||||
tag.start() + start,
|
||||
tag.start() + end
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Collection<String> supportedTags() {
|
||||
return Collections.singleton("enhance");
|
||||
}
|
||||
|
||||
private static int parsePosition(@Nullable String value) {
|
||||
int position;
|
||||
if (!TextUtils.isEmpty(value)) {
|
||||
try {
|
||||
position = Integer.parseInt(value);
|
||||
} catch (NumberFormatException e) {
|
||||
e.printStackTrace();
|
||||
position = -1;
|
||||
}
|
||||
} else {
|
||||
position = -1;
|
||||
}
|
||||
return position;
|
||||
}
|
||||
}
|
||||
}
|
@ -15,4 +15,6 @@
|
||||
<string name="sample_recycler"># \# Recycler\n\nShow how to render markdown in a RecyclerView.
|
||||
Renders code blocks wrapped in a HorizontalScrollView. Renders tables in a custom view.</string>
|
||||
|
||||
<string name="sample_html"># \# Html\n\nShows how to define own tag handlers</string>
|
||||
|
||||
</resources>
|
Loading…
x
Reference in New Issue
Block a user