Add HtmlRenderer asbtraction
This commit is contained in:
parent
84a50be0dd
commit
617a1c8d8f
@ -45,6 +45,16 @@ public interface HtmlTag {
|
||||
@NonNull
|
||||
Map<String, String> attributes();
|
||||
|
||||
boolean isInline();
|
||||
|
||||
boolean isBlock();
|
||||
|
||||
@NonNull
|
||||
Inline getAsInline();
|
||||
|
||||
@NonNull
|
||||
Block getAsBlock();
|
||||
|
||||
/**
|
||||
* Represents <em>really</em> inline HTML tags (unlile commonmark definitions)
|
||||
*/
|
||||
|
@ -79,6 +79,28 @@ abstract class HtmlTagImpl implements HtmlTag {
|
||||
", attributes=" + attributes +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInline() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBlock() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Inline getAsInline() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Block getAsBlock() {
|
||||
throw new ClassCastException("Cannot cast Inline instance to Block");
|
||||
}
|
||||
}
|
||||
|
||||
static class BlockImpl extends HtmlTagImpl implements Block {
|
||||
@ -151,6 +173,28 @@ abstract class HtmlTagImpl implements HtmlTag {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInline() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBlock() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Inline getAsInline() {
|
||||
throw new ClassCastException("Cannot cast Block instance to Inline");
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Block getAsBlock() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BlockImpl{" +
|
||||
|
@ -2,6 +2,7 @@ package ru.noties.markwon.html.impl;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
@ -41,7 +42,8 @@ public class MarkwonHtmlParserImpl extends MarkwonHtmlParser {
|
||||
}
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTML/Inline_elements
|
||||
private static final Set<String> INLINE_TAGS;
|
||||
@VisibleForTesting
|
||||
static final Set<String> INLINE_TAGS;
|
||||
|
||||
private static final Set<String> VOID_TAGS;
|
||||
|
||||
|
@ -42,22 +42,7 @@ public class MarkwonHtmlParserImplTest {
|
||||
});
|
||||
|
||||
// all inline tags are parsed as ones
|
||||
final List<String> tags = Arrays.asList(
|
||||
"a", "abbr", "acronym",
|
||||
"b", "bdo", "big", "br", "button",
|
||||
"cite", "code",
|
||||
"dfn",
|
||||
"em",
|
||||
"i", "img", "input",
|
||||
"kbd",
|
||||
"label",
|
||||
"map",
|
||||
"object",
|
||||
"q",
|
||||
"samp", "script", "select", "small", "span", "strong", "sub", "sup",
|
||||
"textarea", "time", "tt",
|
||||
"var"
|
||||
);
|
||||
final List<String> tags = new ArrayList<>(MarkwonHtmlParserImpl.INLINE_TAGS);
|
||||
|
||||
final StringBuilder html = new StringBuilder();
|
||||
for (String tag : tags) {
|
||||
|
@ -15,6 +15,9 @@ android {
|
||||
|
||||
dependencies {
|
||||
|
||||
api project(':markwon-html-parser-api')
|
||||
api project(':markwon-html-parser-impl')
|
||||
|
||||
deps.with {
|
||||
api it['support-annotations']
|
||||
api it['commonmark']
|
||||
|
@ -3,9 +3,10 @@ package ru.noties.markwon;
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import ru.noties.markwon.html.api.MarkwonHtmlParser;
|
||||
import ru.noties.markwon.renderer.ImageSizeResolver;
|
||||
import ru.noties.markwon.renderer.ImageSizeResolverDef;
|
||||
import ru.noties.markwon.renderer.html.SpannableHtmlParser;
|
||||
import ru.noties.markwon.renderer.html2.MarkwonHtmlRenderer;
|
||||
import ru.noties.markwon.spans.AsyncDrawable;
|
||||
import ru.noties.markwon.spans.LinkSpan;
|
||||
import ru.noties.markwon.spans.SpannableTheme;
|
||||
@ -29,11 +30,13 @@ public class SpannableConfiguration {
|
||||
private final SyntaxHighlight syntaxHighlight;
|
||||
private final LinkSpan.Resolver linkResolver;
|
||||
private final UrlProcessor urlProcessor;
|
||||
private final SpannableHtmlParser htmlParser;
|
||||
// private final SpannableHtmlParser htmlParser;
|
||||
private final ImageSizeResolver imageSizeResolver;
|
||||
private final SpannableFactory factory; // @since 1.1.0
|
||||
private final boolean softBreakAddsNewLine; // @since 1.1.1
|
||||
private final boolean trimWhiteSpaceEnd; // @since 2.0.0
|
||||
private final MarkwonHtmlParser htmlParser; // @since 2.0.0
|
||||
private final MarkwonHtmlRenderer htmlRenderer; // @since 2.0.0
|
||||
|
||||
private SpannableConfiguration(@NonNull Builder builder) {
|
||||
this.theme = builder.theme;
|
||||
@ -41,11 +44,13 @@ public class SpannableConfiguration {
|
||||
this.syntaxHighlight = builder.syntaxHighlight;
|
||||
this.linkResolver = builder.linkResolver;
|
||||
this.urlProcessor = builder.urlProcessor;
|
||||
this.htmlParser = builder.htmlParser;
|
||||
// this.htmlParser = builder.htmlParser;
|
||||
this.imageSizeResolver = builder.imageSizeResolver;
|
||||
this.factory = builder.factory;
|
||||
this.softBreakAddsNewLine = builder.softBreakAddsNewLine;
|
||||
this.trimWhiteSpaceEnd = builder.trimWhiteSpaceEnd;
|
||||
this.htmlParser = builder.htmlParser;
|
||||
this.htmlRenderer = builder.htmlRenderer;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@ -73,10 +78,10 @@ public class SpannableConfiguration {
|
||||
return urlProcessor;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public SpannableHtmlParser htmlParser() {
|
||||
return htmlParser;
|
||||
}
|
||||
// @NonNull
|
||||
// public SpannableHtmlParser htmlParser() {
|
||||
// return htmlParser;
|
||||
// }
|
||||
|
||||
@NonNull
|
||||
public ImageSizeResolver imageSizeResolver() {
|
||||
@ -104,6 +109,22 @@ public class SpannableConfiguration {
|
||||
return trimWhiteSpaceEnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@NonNull
|
||||
public MarkwonHtmlParser htmlParser() {
|
||||
return htmlParser;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@NonNull
|
||||
public MarkwonHtmlRenderer htmlRenderer() {
|
||||
return htmlRenderer;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static class Builder {
|
||||
|
||||
@ -113,11 +134,13 @@ public class SpannableConfiguration {
|
||||
private SyntaxHighlight syntaxHighlight;
|
||||
private LinkSpan.Resolver linkResolver;
|
||||
private UrlProcessor urlProcessor;
|
||||
private SpannableHtmlParser htmlParser;
|
||||
// private SpannableHtmlParser htmlParser;
|
||||
private ImageSizeResolver imageSizeResolver;
|
||||
private SpannableFactory factory; // @since 1.1.0
|
||||
private boolean softBreakAddsNewLine; // @since 1.1.1
|
||||
private boolean trimWhiteSpaceEnd = true; // @since 2.0.0
|
||||
private MarkwonHtmlParser htmlParser; // @since 2.0.0
|
||||
private MarkwonHtmlRenderer htmlRenderer; // @since 2.0.0
|
||||
|
||||
Builder(@NonNull Context context) {
|
||||
this.context = context;
|
||||
@ -153,11 +176,11 @@ public class SpannableConfiguration {
|
||||
return this;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Builder htmlParser(@NonNull SpannableHtmlParser htmlParser) {
|
||||
this.htmlParser = htmlParser;
|
||||
return this;
|
||||
}
|
||||
// @NonNull
|
||||
// public Builder htmlParser(@NonNull SpannableHtmlParser htmlParser) {
|
||||
// this.htmlParser = htmlParser;
|
||||
// return this;
|
||||
// }
|
||||
|
||||
/**
|
||||
* @since 1.0.1
|
||||
@ -202,6 +225,24 @@ public class SpannableConfiguration {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@NonNull
|
||||
public Builder htmlParser(@NonNull MarkwonHtmlParser htmlParser) {
|
||||
this.htmlParser = htmlParser;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@NonNull
|
||||
public Builder htmlRenderer(@NonNull MarkwonHtmlRenderer htmlRenderer) {
|
||||
this.htmlRenderer = htmlRenderer;
|
||||
return this;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public SpannableConfiguration build() {
|
||||
|
||||
@ -234,16 +275,31 @@ public class SpannableConfiguration {
|
||||
factory = SpannableFactoryDef.create();
|
||||
}
|
||||
|
||||
// @since 2.0.0
|
||||
if (htmlParser == null) {
|
||||
htmlParser = SpannableHtmlParser.create(
|
||||
factory,
|
||||
theme,
|
||||
asyncDrawableLoader,
|
||||
urlProcessor,
|
||||
linkResolver,
|
||||
imageSizeResolver);
|
||||
try {
|
||||
// if impl artifact was excluded -> fallback to no-op implementation
|
||||
htmlParser = ru.noties.markwon.html.impl.MarkwonHtmlParserImpl.create();
|
||||
} catch (Throwable t) {
|
||||
htmlParser = MarkwonHtmlParser.noOp();
|
||||
}
|
||||
}
|
||||
|
||||
// @since 2.0.0
|
||||
if (htmlRenderer == null) {
|
||||
htmlRenderer = MarkwonHtmlRenderer.create();
|
||||
}
|
||||
|
||||
// if (htmlParser == null) {
|
||||
// htmlParser = SpannableHtmlParser.create(
|
||||
// factory,
|
||||
// theme,
|
||||
// asyncDrawableLoader,
|
||||
// urlProcessor,
|
||||
// linkResolver,
|
||||
// imageSizeResolver);
|
||||
// }
|
||||
|
||||
return new SpannableConfiguration(this);
|
||||
}
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ import java.util.List;
|
||||
import ru.noties.markwon.SpannableBuilder;
|
||||
import ru.noties.markwon.SpannableConfiguration;
|
||||
import ru.noties.markwon.SpannableFactory;
|
||||
import ru.noties.markwon.html.api.MarkwonHtmlParser;
|
||||
import ru.noties.markwon.renderer.html.SpannableHtmlParser;
|
||||
import ru.noties.markwon.spans.SpannableTheme;
|
||||
import ru.noties.markwon.spans.TableRowSpan;
|
||||
@ -54,7 +55,8 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
||||
|
||||
private final SpannableConfiguration configuration;
|
||||
private final SpannableBuilder builder;
|
||||
private final Deque<HtmlInlineItem> htmlInlineItems;
|
||||
private final MarkwonHtmlParser htmlParser;
|
||||
// private final Deque<HtmlInlineItem> htmlInlineItems;
|
||||
|
||||
private final SpannableTheme theme;
|
||||
private final SpannableFactory factory;
|
||||
@ -72,7 +74,8 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
||||
) {
|
||||
this.configuration = configuration;
|
||||
this.builder = builder;
|
||||
this.htmlInlineItems = new ArrayDeque<>(2);
|
||||
this.htmlParser = configuration.htmlParser();
|
||||
// this.htmlInlineItems = new ArrayDeque<>(2);
|
||||
|
||||
this.theme = configuration.theme();
|
||||
this.factory = configuration.factory();
|
||||
@ -82,6 +85,8 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
||||
public void visit(Document document) {
|
||||
super.visit(document);
|
||||
|
||||
configuration.htmlRenderer().render(configuration, builder, htmlParser);
|
||||
|
||||
if (configuration.trimWhiteSpaceEnd()) {
|
||||
builder.trimWhiteSpaceEnd();
|
||||
}
|
||||
@ -445,47 +450,59 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
||||
|
||||
@Override
|
||||
public void visit(HtmlBlock htmlBlock) {
|
||||
// http://spec.commonmark.org/0.18/#html-blocks
|
||||
final Spanned spanned = configuration.htmlParser().getSpanned(null, htmlBlock.getLiteral());
|
||||
if (!TextUtils.isEmpty(spanned)) {
|
||||
builder.append(spanned);
|
||||
}
|
||||
// // http://spec.commonmark.org/0.18/#html-blocks
|
||||
// final Spanned spanned = configuration.htmlParser().getSpanned(null, htmlBlock.getLiteral());
|
||||
// if (!TextUtils.isEmpty(spanned)) {
|
||||
// builder.append(spanned);
|
||||
// }
|
||||
// htmlParser.processFragment(builder, htmlBlock.getLiteral());
|
||||
visitHtml(htmlBlock.getLiteral());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(HtmlInline htmlInline) {
|
||||
|
||||
final SpannableHtmlParser htmlParser = configuration.htmlParser();
|
||||
final SpannableHtmlParser.Tag tag = htmlParser.parseTag(htmlInline.getLiteral());
|
||||
visitHtml(htmlInline.getLiteral());
|
||||
|
||||
if (tag != null) {
|
||||
// htmlParser.processFragment(builder, htmlInline.getLiteral());
|
||||
|
||||
final boolean voidTag = tag.voidTag();
|
||||
if (!voidTag && tag.opening()) {
|
||||
// push in stack
|
||||
htmlInlineItems.push(new HtmlInlineItem(tag, builder.length()));
|
||||
visitChildren(htmlInline);
|
||||
} else {
|
||||
// final SpannableHtmlParser htmlParser = configuration.htmlParser();
|
||||
// final SpannableHtmlParser.Tag tag = htmlParser.parseTag(htmlInline.getLiteral());
|
||||
//
|
||||
// if (tag != null) {
|
||||
//
|
||||
// final boolean voidTag = tag.voidTag();
|
||||
// if (!voidTag && tag.opening()) {
|
||||
// // push in stack
|
||||
// htmlInlineItems.push(new HtmlInlineItem(tag, builder.length()));
|
||||
// visitChildren(htmlInline);
|
||||
// } else {
|
||||
//
|
||||
// if (!voidTag) {
|
||||
// if (htmlInlineItems.size() > 0) {
|
||||
// final HtmlInlineItem item = htmlInlineItems.pop();
|
||||
// final Object span = htmlParser.getSpanForTag(item.tag);
|
||||
// setSpan(item.start, span);
|
||||
// }
|
||||
// } else {
|
||||
//
|
||||
// final Spanned html = htmlParser.getSpanned(tag, htmlInline.getLiteral());
|
||||
// if (!TextUtils.isEmpty(html)) {
|
||||
// builder.append(html);
|
||||
// }
|
||||
//
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// // todo, should we append just literal?
|
||||
//// builder.append(htmlInline.getLiteral());
|
||||
// visitChildren(htmlInline);
|
||||
// }
|
||||
}
|
||||
|
||||
if (!voidTag) {
|
||||
if (htmlInlineItems.size() > 0) {
|
||||
final HtmlInlineItem item = htmlInlineItems.pop();
|
||||
final Object span = htmlParser.getSpanForTag(item.tag);
|
||||
setSpan(item.start, span);
|
||||
}
|
||||
} else {
|
||||
|
||||
final Spanned html = htmlParser.getSpanned(tag, htmlInline.getLiteral());
|
||||
if (!TextUtils.isEmpty(html)) {
|
||||
builder.append(html);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// todo, should we append just literal?
|
||||
// builder.append(htmlInline.getLiteral());
|
||||
visitChildren(htmlInline);
|
||||
private void visitHtml(@Nullable String html) {
|
||||
if (html != null) {
|
||||
htmlParser.processFragment(builder, html);
|
||||
}
|
||||
}
|
||||
|
||||
@ -552,14 +569,14 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
|
||||
return out;
|
||||
}
|
||||
|
||||
private static class HtmlInlineItem {
|
||||
|
||||
final SpannableHtmlParser.Tag tag;
|
||||
final int start;
|
||||
|
||||
HtmlInlineItem(SpannableHtmlParser.Tag tag, int start) {
|
||||
this.tag = tag;
|
||||
this.start = start;
|
||||
}
|
||||
}
|
||||
// private static class HtmlInlineItem {
|
||||
//
|
||||
// final SpannableHtmlParser.Tag tag;
|
||||
// final int start;
|
||||
//
|
||||
// HtmlInlineItem(SpannableHtmlParser.Tag tag, int start) {
|
||||
// this.tag = tag;
|
||||
// this.start = start;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
@ -0,0 +1,82 @@
|
||||
package ru.noties.markwon.renderer.html2;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import ru.noties.markwon.SpannableBuilder;
|
||||
import ru.noties.markwon.SpannableConfiguration;
|
||||
import ru.noties.markwon.html.api.MarkwonHtmlParser;
|
||||
import ru.noties.markwon.renderer.html2.tag.EmphasisHandler;
|
||||
import ru.noties.markwon.renderer.html2.tag.LinkHandler;
|
||||
import ru.noties.markwon.renderer.html2.tag.StrikeHandler;
|
||||
import ru.noties.markwon.renderer.html2.tag.StrongEmphasisHandler;
|
||||
import ru.noties.markwon.renderer.html2.tag.SubScriptHandler;
|
||||
import ru.noties.markwon.renderer.html2.tag.SuperScriptHandler;
|
||||
import ru.noties.markwon.renderer.html2.tag.TagHandler;
|
||||
import ru.noties.markwon.renderer.html2.tag.UnderlineHandler;
|
||||
|
||||
/**
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public abstract class MarkwonHtmlRenderer {
|
||||
|
||||
public abstract void render(
|
||||
@NonNull SpannableConfiguration configuration,
|
||||
@NonNull SpannableBuilder builder,
|
||||
@NonNull MarkwonHtmlParser parser
|
||||
);
|
||||
|
||||
@Nullable
|
||||
public abstract TagHandler tagHandler(@NonNull String tagName);
|
||||
|
||||
@NonNull
|
||||
public static MarkwonHtmlRenderer create() {
|
||||
|
||||
final EmphasisHandler emphasisHandler = new EmphasisHandler();
|
||||
final StrongEmphasisHandler strongEmphasisHandler = new StrongEmphasisHandler();
|
||||
final StrikeHandler strikeHandler = new StrikeHandler();
|
||||
|
||||
return builder()
|
||||
.handler("i", emphasisHandler)
|
||||
.handler("em", emphasisHandler)
|
||||
.handler("cite", emphasisHandler)
|
||||
.handler("dfn", emphasisHandler)
|
||||
.handler("b", strongEmphasisHandler)
|
||||
.handler("strong", strongEmphasisHandler)
|
||||
.handler("sup", new SuperScriptHandler())
|
||||
.handler("sub", new SubScriptHandler())
|
||||
.handler("u", new UnderlineHandler())
|
||||
.handler("del", strikeHandler)
|
||||
.handler("s", strikeHandler)
|
||||
.handler("strike", strikeHandler)
|
||||
.handler("a", new LinkHandler())
|
||||
.build();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
private final Map<String, TagHandler> tagHandlers = new HashMap<>(2);
|
||||
|
||||
public Builder handler(@NonNull String tagName, @NonNull TagHandler tagHandler) {
|
||||
tagHandlers.put(tagName.toLowerCase(Locale.US), tagHandler);
|
||||
return this;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public MarkwonHtmlRenderer build() {
|
||||
return new MarkwonHtmlRendererImpl(
|
||||
Collections.unmodifiableMap(tagHandlers)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package ru.noties.markwon.renderer.html2;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.Spanned;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import ru.noties.markwon.SpannableBuilder;
|
||||
import ru.noties.markwon.SpannableConfiguration;
|
||||
import ru.noties.markwon.html.api.HtmlTag;
|
||||
import ru.noties.markwon.html.api.MarkwonHtmlParser;
|
||||
import ru.noties.markwon.renderer.html2.tag.TagHandler;
|
||||
|
||||
class MarkwonHtmlRendererImpl extends MarkwonHtmlRenderer {
|
||||
|
||||
private final Map<String, TagHandler> tagHandlers;
|
||||
|
||||
MarkwonHtmlRendererImpl(@NonNull Map<String, TagHandler> tagHandlers) {
|
||||
this.tagHandlers = tagHandlers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(
|
||||
@NonNull final SpannableConfiguration configuration,
|
||||
@NonNull final SpannableBuilder builder,
|
||||
@NonNull MarkwonHtmlParser parser) {
|
||||
|
||||
final int length = builder.length();
|
||||
|
||||
parser.flushInlineTags(length, new MarkwonHtmlParser.FlushAction<HtmlTag.Inline>() {
|
||||
@Override
|
||||
public void apply(@NonNull List<HtmlTag.Inline> tags) {
|
||||
TagHandler handler;
|
||||
for (HtmlTag.Inline inline : tags) {
|
||||
handler = tagHandler(inline.name());
|
||||
if (handler != null) {
|
||||
setSpans(builder, handler.getSpans(configuration, inline), inline.start(), inline.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
parser.flushBlockTags(length, new MarkwonHtmlParser.FlushAction<HtmlTag.Block>() {
|
||||
@Override
|
||||
public void apply(@NonNull List<HtmlTag.Block> tags) {
|
||||
TagHandler handler;
|
||||
for (HtmlTag.Block block : tags) {
|
||||
handler = tagHandler(block.name());
|
||||
if (handler != null) {
|
||||
setSpans(builder, handler.getSpans(configuration, block), block.start(), block.end());
|
||||
} else {
|
||||
// see if any of children can be handled
|
||||
apply(block.children());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
parser.reset();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TagHandler tagHandler(@NonNull String tagName) {
|
||||
return tagHandlers.get(tagName);
|
||||
}
|
||||
|
||||
private static void setSpans(@NonNull SpannableBuilder builder, @Nullable Object spans, int start, int end) {
|
||||
if (spans != null) {
|
||||
if (spans.getClass().isArray()) {
|
||||
for (Object o : ((Object[]) spans)) {
|
||||
builder.setSpan(o, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
} else {
|
||||
builder.setSpan(spans, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package ru.noties.markwon.renderer.html2.tag;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import ru.noties.markwon.SpannableConfiguration;
|
||||
import ru.noties.markwon.html.api.HtmlTag;
|
||||
|
||||
public class EmphasisHandler implements TagHandler {
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) {
|
||||
return configuration.factory().emphasis();
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package ru.noties.markwon.renderer.html2.tag;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import ru.noties.markwon.SpannableConfiguration;
|
||||
import ru.noties.markwon.html.api.HtmlTag;
|
||||
|
||||
public class LinkHandler implements TagHandler {
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) {
|
||||
final String destination = tag.attributes().get("src");
|
||||
if (!TextUtils.isEmpty(destination)) {
|
||||
return configuration.factory().link(
|
||||
configuration.theme(),
|
||||
configuration.urlProcessor().process(destination),
|
||||
configuration.linkResolver()
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package ru.noties.markwon.renderer.html2.tag;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import ru.noties.markwon.SpannableConfiguration;
|
||||
import ru.noties.markwon.html.api.HtmlTag;
|
||||
|
||||
public class StrikeHandler implements TagHandler {
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) {
|
||||
return configuration.factory().strikethrough();
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package ru.noties.markwon.renderer.html2.tag;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import ru.noties.markwon.SpannableConfiguration;
|
||||
import ru.noties.markwon.html.api.HtmlTag;
|
||||
|
||||
public class StrongEmphasisHandler implements TagHandler {
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) {
|
||||
return configuration.factory().strongEmphasis();
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package ru.noties.markwon.renderer.html2.tag;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import ru.noties.markwon.SpannableConfiguration;
|
||||
import ru.noties.markwon.html.api.HtmlTag;
|
||||
|
||||
public class SubScriptHandler implements TagHandler {
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) {
|
||||
return configuration.factory().subScript(configuration.theme());
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package ru.noties.markwon.renderer.html2.tag;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import ru.noties.markwon.SpannableConfiguration;
|
||||
import ru.noties.markwon.html.api.HtmlTag;
|
||||
|
||||
public class SuperScriptHandler implements TagHandler {
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) {
|
||||
return configuration.factory().superScript(configuration.theme());
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package ru.noties.markwon.renderer.html2.tag;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import ru.noties.markwon.SpannableConfiguration;
|
||||
import ru.noties.markwon.html.api.HtmlTag;
|
||||
|
||||
public interface TagHandler {
|
||||
|
||||
@Nullable
|
||||
Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag);
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package ru.noties.markwon.renderer.html2.tag;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import ru.noties.markwon.SpannableConfiguration;
|
||||
import ru.noties.markwon.html.api.HtmlTag;
|
||||
|
||||
public class UnderlineHandler implements TagHandler {
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) {
|
||||
return configuration.factory().underline();
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user