Remove old html code
This commit is contained in:
parent
9246a53891
commit
20c92ddd5e
@ -3,7 +3,6 @@ package ru.noties.markwon.renderer;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.commonmark.ext.gfm.strikethrough.Strikethrough;
|
||||
import org.commonmark.ext.gfm.tables.TableBody;
|
||||
@ -35,16 +34,13 @@ import org.commonmark.node.StrongEmphasis;
|
||||
import org.commonmark.node.Text;
|
||||
import org.commonmark.node.ThematicBreak;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Deque;
|
||||
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;
|
||||
import ru.noties.markwon.tasklist.TaskListBlock;
|
||||
|
@ -1,22 +0,0 @@
|
||||
package ru.noties.markwon.renderer.html;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import ru.noties.markwon.SpannableFactory;
|
||||
|
||||
class BoldProvider implements SpannableHtmlParser.SpanProvider {
|
||||
|
||||
private final SpannableFactory factory;
|
||||
|
||||
/**
|
||||
* @since 1.1.0
|
||||
*/
|
||||
BoldProvider(@NonNull SpannableFactory factory) {
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object provide(@NonNull SpannableHtmlParser.Tag tag) {
|
||||
return factory.strongEmphasis();
|
||||
}
|
||||
}
|
@ -1,224 +0,0 @@
|
||||
package ru.noties.markwon.renderer.html;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.SpannableString;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import ru.noties.markwon.SpannableFactory;
|
||||
import ru.noties.markwon.UrlProcessor;
|
||||
import ru.noties.markwon.renderer.ImageSize;
|
||||
import ru.noties.markwon.renderer.ImageSizeResolver;
|
||||
import ru.noties.markwon.spans.AsyncDrawable;
|
||||
import ru.noties.markwon.spans.SpannableTheme;
|
||||
|
||||
class ImageProviderImpl implements SpannableHtmlParser.ImageProvider {
|
||||
|
||||
private final SpannableFactory factory;
|
||||
private final SpannableTheme theme;
|
||||
private final AsyncDrawable.Loader loader;
|
||||
private final UrlProcessor urlProcessor;
|
||||
private final ImageSizeResolver imageSizeResolver;
|
||||
|
||||
ImageProviderImpl(
|
||||
@NonNull SpannableFactory factory,
|
||||
@NonNull SpannableTheme theme,
|
||||
@NonNull AsyncDrawable.Loader loader,
|
||||
@NonNull UrlProcessor urlProcessor,
|
||||
@NonNull ImageSizeResolver imageSizeResolver
|
||||
) {
|
||||
this.factory = factory;
|
||||
this.theme = theme;
|
||||
this.loader = loader;
|
||||
this.urlProcessor = urlProcessor;
|
||||
this.imageSizeResolver = imageSizeResolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spanned provide(@NonNull SpannableHtmlParser.Tag tag) {
|
||||
|
||||
final Spanned spanned;
|
||||
|
||||
final Map<String, String> attributes = tag.attributes();
|
||||
final String src = attributes.get("src");
|
||||
final String alt = attributes.get("alt");
|
||||
|
||||
if (!TextUtils.isEmpty(src)) {
|
||||
|
||||
final String destination = urlProcessor.process(src);
|
||||
|
||||
final String replacement;
|
||||
if (!TextUtils.isEmpty(alt)) {
|
||||
replacement = alt;
|
||||
} else {
|
||||
replacement = "\uFFFC";
|
||||
}
|
||||
|
||||
final Object span = factory.image(
|
||||
theme,
|
||||
destination,
|
||||
loader,
|
||||
imageSizeResolver,
|
||||
parseImageSize(attributes),
|
||||
false);
|
||||
|
||||
final SpannableString string = new SpannableString(replacement);
|
||||
|
||||
if (span != null) {
|
||||
final int length = string.length();
|
||||
if (span.getClass().isArray()) {
|
||||
for (Object o : ((Object[]) span)) {
|
||||
string.setSpan(o, 0, length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
} else {
|
||||
string.setSpan(span, 0, length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
}
|
||||
|
||||
spanned = string;
|
||||
} else {
|
||||
spanned = null;
|
||||
}
|
||||
|
||||
return spanned;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ImageSize parseImageSize(@NonNull Map<String, String> attributes) {
|
||||
|
||||
final ImageSize imageSize;
|
||||
|
||||
final StyleProvider styleProvider = new StyleProvider(attributes.get("style"));
|
||||
|
||||
final ImageSize.Dimension width = parseDimension(extractDimension("width", attributes, styleProvider));
|
||||
final ImageSize.Dimension height = parseDimension(extractDimension("height", attributes, styleProvider));
|
||||
|
||||
if (width == null
|
||||
&& height == null) {
|
||||
imageSize = null;
|
||||
} else {
|
||||
imageSize = new ImageSize(width, height);
|
||||
}
|
||||
|
||||
return imageSize;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String extractDimension(@NonNull String name, @NonNull Map<String, String> attributes, @NonNull StyleProvider styleProvider) {
|
||||
|
||||
final String out;
|
||||
|
||||
final String inline = attributes.get(name);
|
||||
if (!TextUtils.isEmpty(inline)) {
|
||||
out = inline;
|
||||
} else {
|
||||
out = extractDimensionFromStyle(name, styleProvider);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String extractDimensionFromStyle(@NonNull String name, @NonNull StyleProvider styleProvider) {
|
||||
return styleProvider.attributes().get(name);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ImageSize.Dimension parseDimension(@Nullable String raw) {
|
||||
|
||||
// a set of digits, then dimension unit (allow floating)
|
||||
|
||||
final ImageSize.Dimension dimension;
|
||||
|
||||
final int length = raw != null
|
||||
? raw.length()
|
||||
: 0;
|
||||
|
||||
if (length == 0) {
|
||||
dimension = null;
|
||||
} else {
|
||||
|
||||
// first digit to find -> unit is finished (can be null)
|
||||
|
||||
int index = -1;
|
||||
|
||||
for (int i = length - 1; i >= 0; i--) {
|
||||
if (Character.isDigit(raw.charAt(i))) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// no digits -> no dimension
|
||||
if (index == -1) {
|
||||
dimension = null;
|
||||
} else {
|
||||
|
||||
final String value;
|
||||
final String unit;
|
||||
|
||||
// no unit is specified
|
||||
if (index == length - 1) {
|
||||
value = raw;
|
||||
unit = null;
|
||||
} else {
|
||||
value = raw.substring(0, index + 1);
|
||||
unit = raw.substring(index + 1);
|
||||
}
|
||||
|
||||
ImageSize.Dimension inner;
|
||||
try {
|
||||
final float floatValue = Float.parseFloat(value);
|
||||
inner = new ImageSize.Dimension(floatValue, unit);
|
||||
} catch (NumberFormatException e) {
|
||||
inner = null;
|
||||
}
|
||||
|
||||
dimension = inner;
|
||||
}
|
||||
}
|
||||
|
||||
return dimension;
|
||||
}
|
||||
|
||||
private static class StyleProvider {
|
||||
|
||||
private final String style;
|
||||
private Map<String, String> attributes;
|
||||
|
||||
StyleProvider(@Nullable String style) {
|
||||
this.style = style;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
Map<String, String> attributes() {
|
||||
final Map<String, String> out;
|
||||
if (attributes != null) {
|
||||
out = attributes;
|
||||
} else {
|
||||
if (TextUtils.isEmpty(style)) {
|
||||
out = attributes = Collections.emptyMap();
|
||||
} else {
|
||||
final String[] split = style.split(";");
|
||||
final Map<String, String> map = new HashMap<>(split.length);
|
||||
String[] parts;
|
||||
for (String s : split) {
|
||||
if (!TextUtils.isEmpty(s)) {
|
||||
parts = s.split(":");
|
||||
if (parts.length == 2) {
|
||||
map.put(parts[0].trim(), parts[1].trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
out = attributes = map;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
package ru.noties.markwon.renderer.html;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import ru.noties.markwon.SpannableFactory;
|
||||
|
||||
class ItalicsProvider implements SpannableHtmlParser.SpanProvider {
|
||||
|
||||
private final SpannableFactory factory;
|
||||
|
||||
/**
|
||||
* @since 1.1.0
|
||||
*/
|
||||
ItalicsProvider(@NonNull SpannableFactory factory) {
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object provide(@NonNull SpannableHtmlParser.Tag tag) {
|
||||
return factory.emphasis();
|
||||
}
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
package ru.noties.markwon.renderer.html;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import ru.noties.markwon.SpannableFactory;
|
||||
import ru.noties.markwon.UrlProcessor;
|
||||
import ru.noties.markwon.spans.LinkSpan;
|
||||
import ru.noties.markwon.spans.SpannableTheme;
|
||||
|
||||
class LinkProvider implements SpannableHtmlParser.SpanProvider {
|
||||
|
||||
private final SpannableFactory factory;
|
||||
private final SpannableTheme theme;
|
||||
private final UrlProcessor urlProcessor;
|
||||
private final LinkSpan.Resolver resolver;
|
||||
|
||||
LinkProvider(
|
||||
@NonNull SpannableFactory factory,
|
||||
@NonNull SpannableTheme theme,
|
||||
@NonNull UrlProcessor urlProcessor,
|
||||
@NonNull LinkSpan.Resolver resolver) {
|
||||
this.factory = factory;
|
||||
this.theme = theme;
|
||||
this.urlProcessor = urlProcessor;
|
||||
this.resolver = resolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object provide(@NonNull SpannableHtmlParser.Tag tag) {
|
||||
|
||||
final Object span;
|
||||
|
||||
final Map<String, String> attributes = tag.attributes();
|
||||
final String href = attributes.get("href");
|
||||
if (!TextUtils.isEmpty(href)) {
|
||||
|
||||
final String destination = urlProcessor.process(href);
|
||||
span = factory.link(theme, destination, resolver);
|
||||
|
||||
} else {
|
||||
span = null;
|
||||
}
|
||||
|
||||
return span;
|
||||
}
|
||||
}
|
@ -1,332 +0,0 @@
|
||||
package ru.noties.markwon.renderer.html;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.Html;
|
||||
import android.text.Spanned;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import ru.noties.markwon.LinkResolverDef;
|
||||
import ru.noties.markwon.SpannableFactory;
|
||||
import ru.noties.markwon.UrlProcessor;
|
||||
import ru.noties.markwon.UrlProcessorNoOp;
|
||||
import ru.noties.markwon.renderer.ImageSizeResolver;
|
||||
import ru.noties.markwon.renderer.ImageSizeResolverDef;
|
||||
import ru.noties.markwon.spans.AsyncDrawable;
|
||||
import ru.noties.markwon.spans.LinkSpan;
|
||||
import ru.noties.markwon.spans.SpannableTheme;
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public class SpannableHtmlParser {
|
||||
|
||||
/**
|
||||
* @since 1.1.0
|
||||
*/
|
||||
@NonNull
|
||||
public static SpannableHtmlParser create(
|
||||
@NonNull SpannableFactory factory,
|
||||
@NonNull SpannableTheme theme,
|
||||
@NonNull AsyncDrawable.Loader loader,
|
||||
@NonNull UrlProcessor urlProcessor,
|
||||
@NonNull LinkSpan.Resolver resolver,
|
||||
@NonNull ImageSizeResolver imageSizeResolver
|
||||
) {
|
||||
return builderWithDefaults(factory, theme, loader, urlProcessor, resolver, imageSizeResolver).build();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.1.0
|
||||
*/
|
||||
@NonNull
|
||||
public static Builder builderWithDefaults(@NonNull SpannableFactory factory, @NonNull SpannableTheme theme) {
|
||||
return builderWithDefaults(
|
||||
factory,
|
||||
theme,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updated in 1.0.1: added imageSizeResolverArgument
|
||||
* Updated in 1.1.0: add SpannableFactory
|
||||
*/
|
||||
@NonNull
|
||||
public static Builder builderWithDefaults(
|
||||
@NonNull SpannableFactory factory,
|
||||
@NonNull SpannableTheme theme,
|
||||
@Nullable AsyncDrawable.Loader asyncDrawableLoader,
|
||||
@Nullable UrlProcessor urlProcessor,
|
||||
@Nullable LinkSpan.Resolver resolver,
|
||||
@Nullable ImageSizeResolver imageSizeResolver
|
||||
) {
|
||||
|
||||
if (urlProcessor == null) {
|
||||
urlProcessor = new UrlProcessorNoOp();
|
||||
}
|
||||
|
||||
if (resolver == null) {
|
||||
resolver = new LinkResolverDef();
|
||||
}
|
||||
|
||||
final BoldProvider boldProvider = new BoldProvider(factory);
|
||||
final ItalicsProvider italicsProvider = new ItalicsProvider(factory);
|
||||
final StrikeProvider strikeProvider = new StrikeProvider(factory);
|
||||
|
||||
final ImageProvider imageProvider;
|
||||
if (asyncDrawableLoader != null) {
|
||||
|
||||
if (imageSizeResolver == null) {
|
||||
imageSizeResolver = new ImageSizeResolverDef();
|
||||
}
|
||||
|
||||
imageProvider = new ImageProviderImpl(
|
||||
factory,
|
||||
theme,
|
||||
asyncDrawableLoader,
|
||||
urlProcessor,
|
||||
imageSizeResolver);
|
||||
} else {
|
||||
imageProvider = null;
|
||||
}
|
||||
|
||||
return new Builder()
|
||||
.simpleTag("b", boldProvider)
|
||||
.simpleTag("strong", boldProvider)
|
||||
.simpleTag("i", italicsProvider)
|
||||
.simpleTag("em", italicsProvider)
|
||||
.simpleTag("cite", italicsProvider)
|
||||
.simpleTag("dfn", italicsProvider)
|
||||
.simpleTag("sup", new SuperScriptProvider(factory, theme))
|
||||
.simpleTag("sub", new SubScriptProvider(factory, theme))
|
||||
.simpleTag("u", new UnderlineProvider(factory))
|
||||
.simpleTag("del", strikeProvider)
|
||||
.simpleTag("s", strikeProvider)
|
||||
.simpleTag("strike", strikeProvider)
|
||||
.simpleTag("a", new LinkProvider(factory, theme, urlProcessor, resolver))
|
||||
.imageProvider(imageProvider);
|
||||
}
|
||||
|
||||
// for simple tags without arguments
|
||||
// <b>, <i>, etc
|
||||
public interface SpanProvider {
|
||||
Object provide(@NonNull Tag tag);
|
||||
}
|
||||
|
||||
public interface ImageProvider {
|
||||
Spanned provide(@NonNull Tag tag);
|
||||
}
|
||||
|
||||
public interface HtmlParser {
|
||||
|
||||
// returns span for a simple content
|
||||
Object getSpan(@NonNull String html);
|
||||
|
||||
Spanned parse(@NonNull String html);
|
||||
}
|
||||
|
||||
private final Map<String, SpanProvider> simpleTags;
|
||||
private final ImageProvider imageProvider;
|
||||
private final HtmlParser parser;
|
||||
private final TagParser tagParser;
|
||||
|
||||
private SpannableHtmlParser(Builder builder) {
|
||||
this.simpleTags = builder.simpleTags;
|
||||
this.imageProvider = builder.imageProvider;
|
||||
this.parser = builder.parser;
|
||||
this.tagParser = new TagParser();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Tag parseTag(String html) {
|
||||
return tagParser.parse(html);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Object getSpanForTag(@NonNull Tag tag) {
|
||||
|
||||
// check if we have specific handler for tag.name
|
||||
|
||||
final Object out;
|
||||
|
||||
final SpanProvider provider = simpleTags.get(tag.name);
|
||||
if (provider != null) {
|
||||
out = provider.provide(tag);
|
||||
} else {
|
||||
// let's prepare mock content & extract spans from it
|
||||
// actual content doesn't matter, here it's just `abc`
|
||||
final String mock = tag.raw + "abc" + "</" + tag.name + ">";
|
||||
out = parser.getSpan(mock);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
// if tag is NULL, then it's HtmlBlock... else just a void tag
|
||||
public Spanned getSpanned(@Nullable Tag tag, String html) {
|
||||
final Spanned spanned;
|
||||
if (tag != null && "img".equals(tag.name) && imageProvider != null) {
|
||||
spanned = imageProvider.provide(tag);
|
||||
} else {
|
||||
spanned = parser.parse(html);
|
||||
}
|
||||
return spanned;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
private final Map<String, SpanProvider> simpleTags = new HashMap<>(3);
|
||||
|
||||
private ImageProvider imageProvider;
|
||||
private HtmlParser parser;
|
||||
|
||||
@NonNull
|
||||
Builder simpleTag(@NonNull String tag, @NonNull SpanProvider provider) {
|
||||
simpleTags.put(tag, provider);
|
||||
return this;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Builder imageProvider(@Nullable ImageProvider imageProvider) {
|
||||
this.imageProvider = imageProvider;
|
||||
return this;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Builder parser(@NonNull HtmlParser parser) {
|
||||
this.parser = parser;
|
||||
return this;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public SpannableHtmlParser build() {
|
||||
if (parser == null) {
|
||||
parser = DefaultHtmlParser.create();
|
||||
}
|
||||
return new SpannableHtmlParser(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Tag {
|
||||
|
||||
private final String raw;
|
||||
private final String name;
|
||||
private final Map<String, String> attributes;
|
||||
|
||||
private final boolean opening;
|
||||
private final boolean voidTag;
|
||||
|
||||
public Tag(String raw, String name, @NonNull Map<String, String> attributes, boolean opening, boolean voidTag) {
|
||||
this.raw = raw;
|
||||
this.name = name;
|
||||
this.attributes = attributes;
|
||||
this.opening = opening;
|
||||
this.voidTag = voidTag;
|
||||
}
|
||||
|
||||
public String raw() {
|
||||
return raw;
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Map<String, String> attributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
public boolean opening() {
|
||||
return opening;
|
||||
}
|
||||
|
||||
public boolean voidTag() {
|
||||
return voidTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Tag{" +
|
||||
"raw='" + raw + '\'' +
|
||||
", name='" + name + '\'' +
|
||||
", attributes=" + attributes +
|
||||
", opening=" + opening +
|
||||
", voidTag=" + voidTag +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
public static abstract class DefaultHtmlParser implements HtmlParser {
|
||||
|
||||
public static DefaultHtmlParser create() {
|
||||
final DefaultHtmlParser parser;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
parser = new Parser24();
|
||||
} else {
|
||||
parser = new ParserPre24();
|
||||
}
|
||||
return parser;
|
||||
}
|
||||
|
||||
Object getSpan(Spanned spanned) {
|
||||
|
||||
final Object out;
|
||||
|
||||
final Object[] spans;
|
||||
final int length = spanned != null ? spanned.length() : 0;
|
||||
if (length == 0) {
|
||||
spans = null;
|
||||
} else {
|
||||
spans = spanned.getSpans(0, length, Object.class);
|
||||
}
|
||||
|
||||
if (spans != null
|
||||
&& spans.length > 0) {
|
||||
out = spans[0];
|
||||
} else {
|
||||
out = null;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private static class ParserPre24 extends DefaultHtmlParser {
|
||||
|
||||
@Override
|
||||
public Object getSpan(@NonNull String html) {
|
||||
return getSpan(parse(html));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spanned parse(@NonNull String html) {
|
||||
return Html.fromHtml(html, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.N)
|
||||
private static class Parser24 extends DefaultHtmlParser {
|
||||
|
||||
@Override
|
||||
public Object getSpan(@NonNull String html) {
|
||||
return getSpan(parse(html));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spanned parse(@NonNull String html) {
|
||||
return Html.fromHtml(html, Html.FROM_HTML_MODE_COMPACT, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
package ru.noties.markwon.renderer.html;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import ru.noties.markwon.SpannableFactory;
|
||||
|
||||
class StrikeProvider implements SpannableHtmlParser.SpanProvider {
|
||||
|
||||
private final SpannableFactory factory;
|
||||
|
||||
/**
|
||||
* @since 1.1.0
|
||||
*/
|
||||
StrikeProvider(@NonNull SpannableFactory factory) {
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object provide(@NonNull SpannableHtmlParser.Tag tag) {
|
||||
return factory.strikethrough();
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
package ru.noties.markwon.renderer.html;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import ru.noties.markwon.SpannableFactory;
|
||||
import ru.noties.markwon.spans.SpannableTheme;
|
||||
|
||||
class SubScriptProvider implements SpannableHtmlParser.SpanProvider {
|
||||
|
||||
private final SpannableFactory factory;
|
||||
private final SpannableTheme theme;
|
||||
|
||||
SubScriptProvider(@NonNull SpannableFactory factory, @NonNull SpannableTheme theme) {
|
||||
this.factory = factory;
|
||||
this.theme = theme;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object provide(@NonNull SpannableHtmlParser.Tag tag) {
|
||||
return factory.subScript(theme);
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
package ru.noties.markwon.renderer.html;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import ru.noties.markwon.SpannableFactory;
|
||||
import ru.noties.markwon.spans.SpannableTheme;
|
||||
|
||||
class SuperScriptProvider implements SpannableHtmlParser.SpanProvider {
|
||||
|
||||
private final SpannableFactory factory;
|
||||
private final SpannableTheme theme;
|
||||
|
||||
SuperScriptProvider(@NonNull SpannableFactory factory, @NonNull SpannableTheme theme) {
|
||||
this.factory = factory;
|
||||
this.theme = theme;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object provide(@NonNull SpannableHtmlParser.Tag tag) {
|
||||
return factory.superScript(theme);
|
||||
}
|
||||
}
|
@ -1,155 +0,0 @@
|
||||
package ru.noties.markwon.renderer.html;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
class TagParser {
|
||||
|
||||
|
||||
private static final Set<String> VOID_TAGS;
|
||||
static {
|
||||
final String[] tags = {
|
||||
"area", "base", "br", "col", "embed", "hr", "img", "input",
|
||||
"keygen", "link", "meta", "param", "source", "track", "wbr"
|
||||
};
|
||||
final Set<String> set = new HashSet<>(tags.length);
|
||||
Collections.addAll(set, tags);
|
||||
VOID_TAGS = Collections.unmodifiableSet(set);
|
||||
}
|
||||
|
||||
|
||||
TagParser() {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
SpannableHtmlParser.Tag parse(String html) {
|
||||
|
||||
final SpannableHtmlParser.Tag tag;
|
||||
|
||||
final int length = html != null
|
||||
? html.length()
|
||||
: 0;
|
||||
|
||||
// absolutely minimum (`<i>`)
|
||||
if (length < 3) {
|
||||
tag = null;
|
||||
} else {
|
||||
|
||||
// // okay, we will consider a tag a void one if it's in our void list tag
|
||||
|
||||
final boolean closing = '<' == html.charAt(0) && '/' == html.charAt(1);
|
||||
final boolean voidTag;
|
||||
|
||||
Map<String, String> attributes = null;
|
||||
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
|
||||
String name = null;
|
||||
String pendingAttribute = null;
|
||||
|
||||
char c;
|
||||
char valueDelimiter = '\0';
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
|
||||
c = html.charAt(i);
|
||||
|
||||
// no more handling
|
||||
if ('>' == c
|
||||
|| '\\' == c) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (name == null) {
|
||||
if (Character.isSpaceChar(c)) {
|
||||
//noinspection StatementWithEmptyBody
|
||||
if (builder.length() == 0) {
|
||||
// ignore it, we must wait until we have tagName
|
||||
} else {
|
||||
|
||||
name = builder.toString();
|
||||
|
||||
// clear buffer
|
||||
builder.setLength(0);
|
||||
}
|
||||
} else {
|
||||
if (Character.isLetterOrDigit(c)) {
|
||||
builder.append(c);
|
||||
} /*else {
|
||||
// we allow non-letter-digit only if builder.length == 0
|
||||
// if we have already started
|
||||
}*/
|
||||
}
|
||||
} else if (pendingAttribute == null) {
|
||||
// we start checking for attribute
|
||||
// ignore non-letter-digits before
|
||||
if (Character.isLetterOrDigit(c)) {
|
||||
builder.append(c);
|
||||
} else /*if ('=' == c)*/ {
|
||||
|
||||
// attribute name is finished (only if we have already added something)
|
||||
// else it's trailing chars that we are not interested in
|
||||
if (builder.length() > 0) {
|
||||
pendingAttribute = builder.toString();
|
||||
builder.setLength(0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// first char that we will meet will be the delimiter
|
||||
if (valueDelimiter == '\0') {
|
||||
valueDelimiter = c;
|
||||
} else {
|
||||
if (c == valueDelimiter) {
|
||||
if (attributes == null) {
|
||||
attributes = new HashMap<>(3);
|
||||
}
|
||||
attributes.put(pendingAttribute, builder.toString());
|
||||
pendingAttribute = null;
|
||||
valueDelimiter = '\0';
|
||||
builder.setLength(0);
|
||||
} else {
|
||||
builder.append(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (builder.length() > 0) {
|
||||
if (name == null) {
|
||||
name = builder.toString();
|
||||
} else if (pendingAttribute != null) {
|
||||
if (attributes == null) {
|
||||
attributes = new HashMap<>(3);
|
||||
}
|
||||
attributes.put(pendingAttribute, builder.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// in case of wrong parsing
|
||||
if (name == null) {
|
||||
tag = null;
|
||||
} else {
|
||||
|
||||
voidTag = !closing && VOID_TAGS.contains(name);
|
||||
|
||||
final Map<String, String> attributesMap;
|
||||
if (attributes == null
|
||||
|| attributes.size() == 0) {
|
||||
//noinspection unchecked
|
||||
attributesMap = Collections.EMPTY_MAP;
|
||||
} else {
|
||||
attributesMap = Collections.unmodifiableMap(attributes);
|
||||
}
|
||||
|
||||
tag = new SpannableHtmlParser.Tag(html, name, attributesMap, !closing, voidTag);
|
||||
}
|
||||
}
|
||||
|
||||
return tag;
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
package ru.noties.markwon.renderer.html;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import ru.noties.markwon.SpannableFactory;
|
||||
|
||||
class UnderlineProvider implements SpannableHtmlParser.SpanProvider {
|
||||
|
||||
private final SpannableFactory factory;
|
||||
|
||||
/**
|
||||
* @since 1.1.0
|
||||
*/
|
||||
UnderlineProvider(@NonNull SpannableFactory factory) {
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object provide(@NonNull SpannableHtmlParser.Tag tag) {
|
||||
return factory.underline();
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user