Update HTML plugin to reflect latest API changes

This commit is contained in:
Dimitry Ivanov 2018-12-22 16:20:39 +03:00
parent 9dd3d4a94d
commit 107246c573
19 changed files with 203 additions and 114 deletions

View File

@ -10,7 +10,11 @@ import org.commonmark.parser.Parser;
import java.util.Collections;
import ru.noties.markwon.AbstractMarkwonPlugin;
import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.MarkwonSpansFactory;
import ru.noties.markwon.MarkwonVisitor;
import ru.noties.markwon.RenderProps;
import ru.noties.markwon.SpanFactory;
public class StrikethroughPlugin extends AbstractMarkwonPlugin {
@ -24,6 +28,16 @@ public class StrikethroughPlugin extends AbstractMarkwonPlugin {
builder.extensions(Collections.singleton(StrikethroughExtension.create()));
}
@Override
public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) {
builder.setFactory(Strikethrough.class, new SpanFactory() {
@Override
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps context) {
return new StrikethroughSpan();
}
});
}
@Override
public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) {
builder.on(Strikethrough.class, new MarkwonVisitor.NodeVisitor<Strikethrough>() {
@ -31,7 +45,7 @@ public class StrikethroughPlugin extends AbstractMarkwonPlugin {
public void visit(@NonNull MarkwonVisitor visitor, @NonNull Strikethrough strikethrough) {
final int length = visitor.length();
visitor.visitChildren(strikethrough);
visitor.setSpans(length, new StrikethroughSpan());
visitor.setSpansForNode(strikethrough, length);
}
});
}

View File

@ -20,6 +20,12 @@ dependencies {
deps.with {
api it['support-annotations']
api it['commonmark']
// add a compileOnly dependency, so if this artifact is present
// we will try to obtain a SpanFactory for a Strikethrough node and use
// it to be consistent with markdown (please note that we do not use markwon plugin
// for that in case if different implementation is used)
compileOnly it['commonmark-strikethrough']
}
deps.test.with {

View File

@ -3,7 +3,6 @@ package ru.noties.markwon.html;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import org.commonmark.node.Document;
import org.commonmark.node.HtmlBlock;
import org.commonmark.node.HtmlInline;
import org.commonmark.node.Node;
@ -43,7 +42,7 @@ public class HtmlPlugin extends AbstractMarkwonPlugin {
@Override
public void afterRender(@NonNull Node node, @NonNull MarkwonVisitor visitor) {
renderer.render(visitor.configuration(), visitor.builder(), parser);
renderer.render(visitor, parser);
}
@Override

View File

@ -3,25 +3,15 @@ package ru.noties.markwon.html;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.SpannableBuilder;
import ru.noties.markwon.MarkwonVisitor;
/**
* @since 2.0.0
*/
public abstract class MarkwonHtmlRenderer {
/**
* @since 3.0.0
*/
@NonNull
public static MarkwonHtmlRenderer noOp() {
return new MarkwonHtmlRendererNoOp();
}
public abstract void render(
@NonNull MarkwonConfiguration configuration,
@NonNull SpannableBuilder builder,
@NonNull MarkwonVisitor visitor,
@NonNull MarkwonHtmlParser parser
);

View File

@ -9,8 +9,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.SpannableBuilder;
import ru.noties.markwon.MarkwonVisitor;
import ru.noties.markwon.html.tag.BlockquoteHandler;
import ru.noties.markwon.html.tag.EmphasisHandler;
import ru.noties.markwon.html.tag.HeadingHandler;
@ -100,15 +99,14 @@ public class MarkwonHtmlRendererImpl extends MarkwonHtmlRenderer {
@Override
public void render(
@NonNull final MarkwonConfiguration configuration,
@NonNull final SpannableBuilder builder,
@NonNull final MarkwonVisitor visitor,
@NonNull MarkwonHtmlParser parser) {
final int end;
if (!allowNonClosedTags) {
end = HtmlTag.NO_END;
} else {
end = builder.length();
end = visitor.length();
}
parser.flushInlineTags(end, new MarkwonHtmlParser.FlushAction<HtmlTag.Inline>() {
@ -126,7 +124,7 @@ public class MarkwonHtmlRendererImpl extends MarkwonHtmlRenderer {
handler = tagHandler(inline.name());
if (handler != null) {
handler.handle(configuration, MarkwonHtmlRendererImpl.this, builder, inline);
handler.handle(visitor, MarkwonHtmlRendererImpl.this, inline);
}
}
}
@ -146,7 +144,7 @@ public class MarkwonHtmlRendererImpl extends MarkwonHtmlRenderer {
handler = tagHandler(block.name());
if (handler != null) {
handler.handle(configuration, MarkwonHtmlRendererImpl.this, builder, block);
handler.handle(visitor, MarkwonHtmlRendererImpl.this, block);
} else {
// see if any of children can be handled
apply(block.children());

View File

@ -1,21 +0,0 @@
package ru.noties.markwon.html;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.SpannableBuilder;
class MarkwonHtmlRendererNoOp extends MarkwonHtmlRenderer {
@Override
public void render(@NonNull MarkwonConfiguration configuration, @NonNull SpannableBuilder builder, @NonNull MarkwonHtmlParser parser) {
}
@Nullable
@Override
public TagHandler tagHandler(@NonNull String tagName) {
return null;
}
}

View File

@ -2,22 +2,19 @@ package ru.noties.markwon.html;
import android.support.annotation.NonNull;
import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.SpannableBuilder;
import ru.noties.markwon.MarkwonVisitor;
public abstract class TagHandler {
public abstract void handle(
@NonNull MarkwonConfiguration configuration,
@NonNull MarkwonVisitor visitor,
@NonNull MarkwonHtmlRenderer renderer,
@NonNull SpannableBuilder builder,
@NonNull HtmlTag tag
);
protected static void visitChildren(
@NonNull MarkwonConfiguration configuration,
@NonNull MarkwonVisitor visitor,
@NonNull MarkwonHtmlRenderer renderer,
@NonNull SpannableBuilder builder,
@NonNull HtmlTag.Block block) {
TagHandler handler;
@ -30,9 +27,9 @@ public abstract class TagHandler {
handler = renderer.tagHandler(child.name());
if (handler != null) {
handler.handle(configuration, renderer, builder, child);
handler.handle(visitor, renderer, child);
} else {
visitChildren(configuration, renderer, builder, child);
visitChildren(visitor, renderer, child);
}
}
}

View File

@ -2,7 +2,11 @@ package ru.noties.markwon.html.tag;
import android.support.annotation.NonNull;
import org.commonmark.node.BlockQuote;
import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.MarkwonVisitor;
import ru.noties.markwon.SpanFactory;
import ru.noties.markwon.SpannableBuilder;
import ru.noties.markwon.html.HtmlTag;
import ru.noties.markwon.html.MarkwonHtmlRenderer;
@ -12,20 +16,23 @@ public class BlockquoteHandler extends TagHandler {
@Override
public void handle(
@NonNull MarkwonConfiguration configuration,
@NonNull MarkwonVisitor visitor,
@NonNull MarkwonHtmlRenderer renderer,
@NonNull SpannableBuilder builder,
@NonNull HtmlTag tag) {
if (tag.isBlock()) {
visitChildren(configuration, renderer, builder, tag.getAsBlock());
visitChildren(visitor, renderer, tag.getAsBlock());
}
SpannableBuilder.setSpans(
builder,
configuration.factory().blockQuote(configuration.theme()),
tag.start(),
tag.end()
);
final MarkwonConfiguration configuration = visitor.configuration();
final SpanFactory factory = configuration.spansFactory().get(BlockQuote.class);
if (factory != null) {
SpannableBuilder.setSpans(
visitor.builder(),
factory.getSpans(configuration, visitor.renderProps()),
tag.start(),
tag.end()
);
}
}
}

View File

@ -3,13 +3,24 @@ package ru.noties.markwon.html.tag;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import org.commonmark.node.Emphasis;
import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.RenderProps;
import ru.noties.markwon.SpanFactory;
import ru.noties.markwon.html.HtmlTag;
public class EmphasisHandler extends SimpleTagHandler {
@Nullable
@Override
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull HtmlTag tag) {
return configuration.factory().emphasis();
public Object getSpans(
@NonNull MarkwonConfiguration configuration,
@NonNull RenderProps renderProps,
@NonNull HtmlTag tag) {
final SpanFactory spanFactory = configuration.spansFactory().get(Emphasis.class);
if (spanFactory == null) {
return null;
}
return spanFactory.getSpans(configuration, renderProps);
}
}

View File

@ -3,7 +3,12 @@ package ru.noties.markwon.html.tag;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import org.commonmark.node.Heading;
import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.RenderProps;
import ru.noties.markwon.SpanFactory;
import ru.noties.markwon.core.CoreProps;
import ru.noties.markwon.html.HtmlTag;
public class HeadingHandler extends SimpleTagHandler {
@ -16,7 +21,18 @@ public class HeadingHandler extends SimpleTagHandler {
@Nullable
@Override
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull HtmlTag tag) {
return configuration.factory().heading(configuration.theme(), level);
public Object getSpans(
@NonNull MarkwonConfiguration configuration,
@NonNull RenderProps renderProps,
@NonNull HtmlTag tag) {
final SpanFactory factory = configuration.spansFactory().get(Heading.class);
if (factory == null) {
return null;
}
CoreProps.HEADING_LEVEL.set(renderProps, level);
return factory.getSpans(configuration, renderProps);
}
}

View File

@ -4,11 +4,16 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import org.commonmark.node.Image;
import java.util.Map;
import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.html.HtmlTag;
import ru.noties.markwon.RenderProps;
import ru.noties.markwon.SpanFactory;
import ru.noties.markwon.html.CssInlineStyleParser;
import ru.noties.markwon.html.HtmlTag;
import ru.noties.markwon.image.ImageProps;
import ru.noties.markwon.image.ImageSize;
public class ImageHandler extends SimpleTagHandler {
@ -31,7 +36,10 @@ public class ImageHandler extends SimpleTagHandler {
@Nullable
@Override
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull HtmlTag tag) {
public Object getSpans(
@NonNull MarkwonConfiguration configuration,
@NonNull RenderProps renderProps,
@NonNull HtmlTag tag) {
final Map<String, String> attributes = tag.attributes();
final String src = attributes.get("src");
@ -39,7 +47,13 @@ public class ImageHandler extends SimpleTagHandler {
return null;
}
final SpanFactory spanFactory = configuration.spansFactory().get(Image.class);
if (spanFactory == null) {
return null;
}
final String destination = configuration.urlProcessor().process(src);
final ImageSize imageSize = imageSizeParser.parse(tag.attributes());
// todo: replacement text is link... as we are not at block level
// and cannot inspect the parent of this node... (img and a are both inlines)
@ -47,15 +61,10 @@ public class ImageHandler extends SimpleTagHandler {
// but we can look and see if we are inside a LinkSpan (will have to extend TagHandler
// to obtain an instance SpannableBuilder for inspection)
return null;
ImageProps.DESTINATION.set(renderProps, destination);
ImageProps.IMAGE_SIZE.set(renderProps, imageSize);
ImageProps.REPLACEMENT_TEXT_IS_LINK.set(renderProps, false);
// return configuration.factory().image(
// configuration.theme(),
// destination,
// configuration.asyncDrawableLoader(),
// configuration.imageSizeResolver(),
// imageSizeParser.parse(tag.attributes()),
// false
// );
return spanFactory.getSpans(configuration, renderProps);
}
}

View File

@ -4,20 +4,29 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import org.commonmark.node.Link;
import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.RenderProps;
import ru.noties.markwon.SpanFactory;
import ru.noties.markwon.core.CoreProps;
import ru.noties.markwon.html.HtmlTag;
public class LinkHandler extends SimpleTagHandler {
@Nullable
@Override
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull HtmlTag tag) {
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps renderProps, @NonNull HtmlTag tag) {
final String destination = tag.attributes().get("href");
if (!TextUtils.isEmpty(destination)) {
return configuration.factory().link(
configuration.theme(),
configuration.urlProcessor().process(destination),
configuration.linkResolver()
);
final SpanFactory spanFactory = configuration.spansFactory().get(Link.class);
if (spanFactory != null) {
CoreProps.LINK_DESTINATION.set(
renderProps,
configuration.urlProcessor().process(destination));
return spanFactory.getSpans(configuration, renderProps);
}
}
return null;
}

View File

@ -2,8 +2,14 @@ package ru.noties.markwon.html.tag;
import android.support.annotation.NonNull;
import org.commonmark.node.ListItem;
import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.MarkwonVisitor;
import ru.noties.markwon.RenderProps;
import ru.noties.markwon.SpanFactory;
import ru.noties.markwon.SpannableBuilder;
import ru.noties.markwon.core.CoreProps;
import ru.noties.markwon.html.HtmlTag;
import ru.noties.markwon.html.MarkwonHtmlRenderer;
import ru.noties.markwon.html.TagHandler;
@ -12,9 +18,8 @@ public class ListHandler extends TagHandler {
@Override
public void handle(
@NonNull MarkwonConfiguration configuration,
@NonNull MarkwonVisitor visitor,
@NonNull MarkwonHtmlRenderer renderer,
@NonNull SpannableBuilder builder,
@NonNull HtmlTag tag) {
if (!tag.isBlock()) {
@ -29,29 +34,33 @@ public class ListHandler extends TagHandler {
return;
}
final MarkwonConfiguration configuration = visitor.configuration();
final RenderProps renderProps = visitor.renderProps();
final SpanFactory spanFactory = configuration.spansFactory().get(ListItem.class);
int number = 1;
final int bulletLevel = currentBulletListLevel(block);
Object spans;
for (HtmlTag.Block child : block.children()) {
visitChildren(configuration, renderer, builder, child);
visitChildren(visitor, renderer, child);
if (spanFactory != null && "li".equals(child.name())) {
if ("li".equals(child.name())) {
// insert list item here
if (ol) {
spans = configuration.factory().orderedListItem(
configuration.theme(),
number++
);
CoreProps.LIST_ITEM_TYPE.set(renderProps, CoreProps.ListItemType.ORDERED);
CoreProps.ORDERED_LIST_ITEM_NUMBER.set(renderProps, number++);
} else {
spans = configuration.factory().bulletListItem(
configuration.theme(),
bulletLevel
);
CoreProps.LIST_ITEM_TYPE.set(renderProps, CoreProps.ListItemType.BULLET);
CoreProps.BULLET_LIST_ITEM_LEVEL.set(renderProps, bulletLevel);
}
SpannableBuilder.setSpans(builder, spans, child.start(), child.end());
SpannableBuilder.setSpans(
visitor.builder(),
spanFactory.getSpans(configuration, renderProps),
child.start(),
child.end());
}
}
}

View File

@ -4,6 +4,8 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.MarkwonVisitor;
import ru.noties.markwon.RenderProps;
import ru.noties.markwon.SpannableBuilder;
import ru.noties.markwon.html.HtmlTag;
import ru.noties.markwon.html.MarkwonHtmlRenderer;
@ -12,13 +14,16 @@ import ru.noties.markwon.html.TagHandler;
public abstract class SimpleTagHandler extends TagHandler {
@Nullable
public abstract Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull HtmlTag tag);
public abstract Object getSpans(
@NonNull MarkwonConfiguration configuration,
@NonNull RenderProps renderProps,
@NonNull HtmlTag tag);
@Override
public void handle(@NonNull MarkwonConfiguration configuration, @NonNull MarkwonHtmlRenderer renderer, @NonNull SpannableBuilder builder, @NonNull HtmlTag tag) {
final Object spans = getSpans(configuration, tag);
public void handle(@NonNull MarkwonVisitor visitor, @NonNull MarkwonHtmlRenderer renderer, @NonNull HtmlTag tag) {
final Object spans = getSpans(visitor.configuration(), visitor.renderProps(), tag);
if (spans != null) {
SpannableBuilder.setSpans(builder, spans, tag.start(), tag.end());
SpannableBuilder.setSpans(visitor.builder(), spans, tag.start(), tag.end());
}
}
}

View File

@ -1,9 +1,12 @@
package ru.noties.markwon.html.tag;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.style.StrikethroughSpan;
import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.MarkwonVisitor;
import ru.noties.markwon.SpanFactory;
import ru.noties.markwon.SpannableBuilder;
import ru.noties.markwon.html.HtmlTag;
import ru.noties.markwon.html.MarkwonHtmlRenderer;
@ -11,22 +14,47 @@ import ru.noties.markwon.html.TagHandler;
public class StrikeHandler extends TagHandler {
// flag to detect if commonmark-java-strikethrough is in classpath, so we use SpanFactory
// to obtain strikethrough span
private static final boolean HAS_MARKDOWN_IMPLEMENTATION;
static {
boolean hasMarkdownImplementation;
try {
org.commonmark.ext.gfm.strikethrough.Strikethrough.class.getName();
hasMarkdownImplementation = true;
} catch (Throwable t) {
hasMarkdownImplementation = false;
}
HAS_MARKDOWN_IMPLEMENTATION = hasMarkdownImplementation;
}
@Override
public void handle(
@NonNull MarkwonConfiguration configuration,
@NonNull MarkwonVisitor visitor,
@NonNull MarkwonHtmlRenderer renderer,
@NonNull SpannableBuilder builder,
@NonNull HtmlTag tag) {
if (tag.isBlock()) {
visitChildren(configuration, renderer, builder, tag.getAsBlock());
visitChildren(visitor, renderer, tag.getAsBlock());
}
SpannableBuilder.setSpans(
builder,
new StrikethroughSpan(),
visitor.builder(),
HAS_MARKDOWN_IMPLEMENTATION ? getMarkdownSpans(visitor) : new StrikethroughSpan(),
tag.start(),
tag.end()
);
}
@Nullable
private static Object getMarkdownSpans(@NonNull MarkwonVisitor visitor) {
final MarkwonConfiguration configuration = visitor.configuration();
final SpanFactory spanFactory = configuration.spansFactory()
.get(org.commonmark.ext.gfm.strikethrough.Strikethrough.class);
if (spanFactory == null) {
return null;
}
return spanFactory.getSpans(configuration, visitor.renderProps());
}
}

View File

@ -3,13 +3,24 @@ package ru.noties.markwon.html.tag;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import org.commonmark.node.StrongEmphasis;
import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.RenderProps;
import ru.noties.markwon.SpanFactory;
import ru.noties.markwon.html.HtmlTag;
public class StrongEmphasisHandler extends SimpleTagHandler {
@Nullable
@Override
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull HtmlTag tag) {
return configuration.factory().strongEmphasis();
public Object getSpans(
@NonNull MarkwonConfiguration configuration,
@NonNull RenderProps renderProps,
@NonNull HtmlTag tag) {
final SpanFactory spanFactory = configuration.spansFactory().get(StrongEmphasis.class);
if (spanFactory == null) {
return null;
}
return spanFactory.getSpans(configuration, renderProps);
}
}

View File

@ -4,13 +4,14 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.RenderProps;
import ru.noties.markwon.html.HtmlTag;
import ru.noties.markwon.html.span.SubScriptSpan;
public class SubScriptHandler extends SimpleTagHandler {
@Nullable
@Override
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull HtmlTag tag) {
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps renderProps, @NonNull HtmlTag tag) {
return new SubScriptSpan();
}
}

View File

@ -4,13 +4,14 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.RenderProps;
import ru.noties.markwon.html.HtmlTag;
import ru.noties.markwon.html.span.SuperScriptSpan;
public class SuperScriptHandler extends SimpleTagHandler {
@Nullable
@Override
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull HtmlTag tag) {
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps renderProps, @NonNull HtmlTag tag) {
return new SuperScriptSpan();
}
}

View File

@ -3,7 +3,7 @@ package ru.noties.markwon.html.tag;
import android.support.annotation.NonNull;
import android.text.style.UnderlineSpan;
import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.MarkwonVisitor;
import ru.noties.markwon.SpannableBuilder;
import ru.noties.markwon.html.HtmlTag;
import ru.noties.markwon.html.MarkwonHtmlRenderer;
@ -13,20 +13,19 @@ public class UnderlineHandler extends TagHandler {
@Override
public void handle(
@NonNull MarkwonConfiguration configuration,
@NonNull MarkwonVisitor visitor,
@NonNull MarkwonHtmlRenderer renderer,
@NonNull SpannableBuilder builder,
@NonNull HtmlTag tag) {
// as parser doesn't treat U tag as an inline one,
// thus doesn't allow children, we must visit them first
if (tag.isBlock()) {
visitChildren(configuration, renderer, builder, tag.getAsBlock());
visitChildren(visitor, renderer, tag.getAsBlock());
}
SpannableBuilder.setSpans(
builder,
visitor.builder(),
new UnderlineSpan(),
tag.start(),
tag.end()