Add extension modules
This commit is contained in:
parent
6eb8e64d75
commit
d48b33e9a5
@ -29,6 +29,9 @@ android {
|
|||||||
dependencies {
|
dependencies {
|
||||||
|
|
||||||
implementation project(':markwon')
|
implementation project(':markwon')
|
||||||
|
implementation project(':markwon-ext-strikethrough')
|
||||||
|
implementation project(':markwon-ext-tables')
|
||||||
|
implementation project(':markwon-ext-tasklist')
|
||||||
implementation project(':markwon-html')
|
implementation project(':markwon-html')
|
||||||
implementation project(':markwon-image-gif')
|
implementation project(':markwon-image-gif')
|
||||||
implementation project(':markwon-image-svg')
|
implementation project(':markwon-image-svg')
|
||||||
|
@ -9,7 +9,7 @@ import android.util.AttributeSet;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import ru.noties.markwon.R;
|
import ru.noties.markwon.R;
|
||||||
import ru.noties.markwon.tasklist.TaskListDrawable;
|
import ru.noties.markwon.ext.tasklist.TaskListDrawable;
|
||||||
|
|
||||||
public class DebugCheckboxDrawableView extends View {
|
public class DebugCheckboxDrawableView extends View {
|
||||||
|
|
||||||
|
@ -13,9 +13,6 @@ import android.widget.TextView;
|
|||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import ru.noties.debug.Debug;
|
import ru.noties.debug.Debug;
|
||||||
import ru.noties.markwon.core.CorePlugin;
|
|
||||||
import ru.noties.markwon.tasklist.TaskListDrawable;
|
|
||||||
import ru.noties.markwon.tasklist.TaskListPlugin;
|
|
||||||
|
|
||||||
public class MainActivity extends Activity {
|
public class MainActivity extends Activity {
|
||||||
|
|
||||||
@ -74,9 +71,9 @@ public class MainActivity extends Activity {
|
|||||||
public void apply(final String text) {
|
public void apply(final String text) {
|
||||||
markdownRenderer.render(MainActivity.this, themes.isLight(), uri(), text, new MarkdownRenderer.MarkdownReadyListener() {
|
markdownRenderer.render(MainActivity.this, themes.isLight(), uri(), text, new MarkdownRenderer.MarkdownReadyListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onMarkdownReady(@NonNull Markwon2 markwon2, CharSequence markdown) {
|
public void onMarkdownReady(@NonNull Markwon markwon, CharSequence markdown) {
|
||||||
|
|
||||||
markwon2.setParsedMarkdown(textView, markdown);
|
markwon.setParsedMarkdown(textView, markdown);
|
||||||
|
|
||||||
Views.setVisible(progress, false);
|
Views.setVisible(progress, false);
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,10 @@ import javax.inject.Inject;
|
|||||||
|
|
||||||
import ru.noties.debug.Debug;
|
import ru.noties.debug.Debug;
|
||||||
import ru.noties.markwon.core.CorePlugin;
|
import ru.noties.markwon.core.CorePlugin;
|
||||||
|
import ru.noties.markwon.ext.strikethrough.StrikethroughPlugin;
|
||||||
|
import ru.noties.markwon.ext.tables.TablePlugin;
|
||||||
|
import ru.noties.markwon.ext.tasklist.TaskListPlugin;
|
||||||
|
import ru.noties.markwon.gif.GifAwarePlugin;
|
||||||
import ru.noties.markwon.html.impl.HtmlPlugin;
|
import ru.noties.markwon.html.impl.HtmlPlugin;
|
||||||
import ru.noties.markwon.image.ImagesPlugin;
|
import ru.noties.markwon.image.ImagesPlugin;
|
||||||
import ru.noties.markwon.image.gif.GifPlugin;
|
import ru.noties.markwon.image.gif.GifPlugin;
|
||||||
@ -22,15 +26,13 @@ import ru.noties.markwon.syntax.Prism4jTheme;
|
|||||||
import ru.noties.markwon.syntax.Prism4jThemeDarkula;
|
import ru.noties.markwon.syntax.Prism4jThemeDarkula;
|
||||||
import ru.noties.markwon.syntax.Prism4jThemeDefault;
|
import ru.noties.markwon.syntax.Prism4jThemeDefault;
|
||||||
import ru.noties.markwon.syntax.SyntaxHighlightPlugin;
|
import ru.noties.markwon.syntax.SyntaxHighlightPlugin;
|
||||||
import ru.noties.markwon.table.TablePlugin;
|
|
||||||
import ru.noties.markwon.tasklist.TaskListPlugin;
|
|
||||||
import ru.noties.prism4j.Prism4j;
|
import ru.noties.prism4j.Prism4j;
|
||||||
|
|
||||||
@ActivityScope
|
@ActivityScope
|
||||||
public class MarkdownRenderer {
|
public class MarkdownRenderer {
|
||||||
|
|
||||||
interface MarkdownReadyListener {
|
interface MarkdownReadyListener {
|
||||||
void onMarkdownReady(@NonNull Markwon2 markwon2, CharSequence markdown);
|
void onMarkdownReady(@NonNull Markwon markwon, CharSequence markdown);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@ -80,7 +82,7 @@ public class MarkdownRenderer {
|
|||||||
? prism4jThemeDefault
|
? prism4jThemeDefault
|
||||||
: prism4JThemeDarkula;
|
: prism4JThemeDarkula;
|
||||||
|
|
||||||
final Markwon2 markwon2 = Markwon2.builder(context)
|
final Markwon markwon = Markwon.builder(context)
|
||||||
.use(CorePlugin.create())
|
.use(CorePlugin.create())
|
||||||
.use(ImagesPlugin.createWithAssets(context))
|
.use(ImagesPlugin.createWithAssets(context))
|
||||||
.use(SvgPlugin.create(context.getResources()))
|
.use(SvgPlugin.create(context.getResources()))
|
||||||
@ -89,6 +91,7 @@ public class MarkdownRenderer {
|
|||||||
.use(GifAwarePlugin.create(context))
|
.use(GifAwarePlugin.create(context))
|
||||||
.use(TablePlugin.create(context))
|
.use(TablePlugin.create(context))
|
||||||
.use(TaskListPlugin.create(context))
|
.use(TaskListPlugin.create(context))
|
||||||
|
.use(StrikethroughPlugin.create())
|
||||||
.use(HtmlPlugin.create())
|
.use(HtmlPlugin.create())
|
||||||
.use(new AbstractMarkwonPlugin() {
|
.use(new AbstractMarkwonPlugin() {
|
||||||
@Override
|
@Override
|
||||||
@ -100,7 +103,7 @@ public class MarkdownRenderer {
|
|||||||
|
|
||||||
final long start = SystemClock.uptimeMillis();
|
final long start = SystemClock.uptimeMillis();
|
||||||
|
|
||||||
final CharSequence text = markwon2.toMarkdown(markdown);
|
final CharSequence text = markwon.toMarkdown(markdown);
|
||||||
|
|
||||||
final long end = SystemClock.uptimeMillis();
|
final long end = SystemClock.uptimeMillis();
|
||||||
|
|
||||||
@ -111,7 +114,7 @@ public class MarkdownRenderer {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (!isCancelled()) {
|
if (!isCancelled()) {
|
||||||
listener.onMarkdownReady(markwon2, text);
|
listener.onMarkdownReady(markwon, text);
|
||||||
task = null;
|
task = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package ru.noties.markwon;
|
package ru.noties.markwon.gif;
|
||||||
|
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
@ -7,8 +7,8 @@ import android.support.annotation.Nullable;
|
|||||||
|
|
||||||
import pl.droidsonroids.gif.GifDrawable;
|
import pl.droidsonroids.gif.GifDrawable;
|
||||||
import ru.noties.markwon.image.AsyncDrawableLoader;
|
import ru.noties.markwon.image.AsyncDrawableLoader;
|
||||||
import ru.noties.markwon.renderer.ImageSize;
|
import ru.noties.markwon.image.ImageSize;
|
||||||
import ru.noties.markwon.renderer.ImageSizeResolver;
|
import ru.noties.markwon.image.ImageSizeResolver;
|
||||||
import ru.noties.markwon.image.AsyncDrawable;
|
import ru.noties.markwon.image.AsyncDrawable;
|
||||||
|
|
||||||
public class GifAwareAsyncDrawable extends AsyncDrawable {
|
public class GifAwareAsyncDrawable extends AsyncDrawable {
|
@ -1,9 +1,13 @@
|
|||||||
package ru.noties.markwon;
|
package ru.noties.markwon.gif;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import ru.noties.markwon.AbstractMarkwonPlugin;
|
||||||
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
|
import ru.noties.markwon.R;
|
||||||
|
|
||||||
public class GifAwarePlugin extends AbstractMarkwonPlugin {
|
public class GifAwarePlugin extends AbstractMarkwonPlugin {
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
@ -1,12 +1,12 @@
|
|||||||
package ru.noties.markwon;
|
package ru.noties.markwon.gif;
|
||||||
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
|
import ru.noties.markwon.SpannableFactoryDef;
|
||||||
import ru.noties.markwon.image.AsyncDrawableLoader;
|
import ru.noties.markwon.image.AsyncDrawableLoader;
|
||||||
import ru.noties.markwon.renderer.ImageSize;
|
import ru.noties.markwon.image.ImageSize;
|
||||||
import ru.noties.markwon.renderer.ImageSizeResolver;
|
import ru.noties.markwon.image.ImageSizeResolver;
|
||||||
import ru.noties.markwon.image.AsyncDrawable;
|
|
||||||
import ru.noties.markwon.spans.AsyncDrawableSpan;
|
import ru.noties.markwon.spans.AsyncDrawableSpan;
|
||||||
import ru.noties.markwon.spans.MarkwonTheme;
|
import ru.noties.markwon.spans.MarkwonTheme;
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package ru.noties.markwon;
|
package ru.noties.markwon.gif;
|
||||||
|
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.ColorFilter;
|
import android.graphics.ColorFilter;
|
@ -1,4 +1,4 @@
|
|||||||
package ru.noties.markwon;
|
package ru.noties.markwon.gif;
|
||||||
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
25
markwon-ext-strikethrough/build.gradle
Normal file
25
markwon-ext-strikethrough/build.gradle
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
apply plugin: 'com.android.library'
|
||||||
|
|
||||||
|
android {
|
||||||
|
|
||||||
|
compileSdkVersion config['compile-sdk']
|
||||||
|
buildToolsVersion config['build-tools']
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
minSdkVersion config['min-sdk']
|
||||||
|
targetSdkVersion config['target-sdk']
|
||||||
|
versionCode 1
|
||||||
|
versionName version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
|
||||||
|
api project(':markwon')
|
||||||
|
|
||||||
|
deps.with {
|
||||||
|
api it['commonmark-strikethrough']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
registerArtifact(this)
|
1
markwon-ext-strikethrough/src/main/AndroidManifest.xml
Normal file
1
markwon-ext-strikethrough/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1 @@
|
|||||||
|
<manifest package="ru.noties.markwon.ext.strikethrough" />
|
@ -0,0 +1,38 @@
|
|||||||
|
package ru.noties.markwon.ext.strikethrough;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.text.style.StrikethroughSpan;
|
||||||
|
|
||||||
|
import org.commonmark.ext.gfm.strikethrough.Strikethrough;
|
||||||
|
import org.commonmark.ext.gfm.strikethrough.StrikethroughExtension;
|
||||||
|
import org.commonmark.parser.Parser;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import ru.noties.markwon.AbstractMarkwonPlugin;
|
||||||
|
import ru.noties.markwon.MarkwonVisitor;
|
||||||
|
|
||||||
|
public class StrikethroughPlugin extends AbstractMarkwonPlugin {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static StrikethroughPlugin create() {
|
||||||
|
return new StrikethroughPlugin();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configureParser(@NonNull Parser.Builder builder) {
|
||||||
|
builder.extensions(Collections.singleton(StrikethroughExtension.create()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) {
|
||||||
|
builder.on(Strikethrough.class, new MarkwonVisitor.NodeVisitor<Strikethrough>() {
|
||||||
|
@Override
|
||||||
|
public void visit(@NonNull MarkwonVisitor visitor, @NonNull Strikethrough strikethrough) {
|
||||||
|
final int length = visitor.length();
|
||||||
|
visitor.visitChildren(strikethrough);
|
||||||
|
visitor.setSpans(length, new StrikethroughSpan());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
25
markwon-ext-tables/build.gradle
Normal file
25
markwon-ext-tables/build.gradle
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
apply plugin: 'com.android.library'
|
||||||
|
|
||||||
|
android {
|
||||||
|
|
||||||
|
compileSdkVersion config['compile-sdk']
|
||||||
|
buildToolsVersion config['build-tools']
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
minSdkVersion config['min-sdk']
|
||||||
|
targetSdkVersion config['target-sdk']
|
||||||
|
versionCode 1
|
||||||
|
versionName version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
|
||||||
|
api project(':markwon')
|
||||||
|
|
||||||
|
deps.with {
|
||||||
|
api it['commonmark-table']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
registerArtifact(this)
|
1
markwon-ext-tables/src/main/AndroidManifest.xml
Normal file
1
markwon-ext-tables/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1 @@
|
|||||||
|
<manifest package="ru.noties.markwon.ext.tables" />
|
@ -1,4 +1,4 @@
|
|||||||
package ru.noties.markwon.table;
|
package ru.noties.markwon.ext.tables;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
@ -1,4 +1,4 @@
|
|||||||
package ru.noties.markwon.table;
|
package ru.noties.markwon.ext.tables;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
@ -1,4 +1,4 @@
|
|||||||
package ru.noties.markwon.table;
|
package ru.noties.markwon.ext.tables;
|
||||||
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
@ -1,4 +1,4 @@
|
|||||||
package ru.noties.markwon.table;
|
package ru.noties.markwon.ext.tables;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
20
markwon-ext-tasklist/build.gradle
Normal file
20
markwon-ext-tasklist/build.gradle
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
apply plugin: 'com.android.library'
|
||||||
|
|
||||||
|
android {
|
||||||
|
|
||||||
|
compileSdkVersion config['compile-sdk']
|
||||||
|
buildToolsVersion config['build-tools']
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
minSdkVersion config['min-sdk']
|
||||||
|
targetSdkVersion config['target-sdk']
|
||||||
|
versionCode 1
|
||||||
|
versionName version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
api project(':markwon')
|
||||||
|
}
|
||||||
|
|
||||||
|
registerArtifact(this)
|
1
markwon-ext-tasklist/src/main/AndroidManifest.xml
Normal file
1
markwon-ext-tasklist/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1 @@
|
|||||||
|
<manifest package="ru.noties.markwon.ext.tasklist" />
|
@ -1,4 +1,4 @@
|
|||||||
package ru.noties.markwon.tasklist;
|
package ru.noties.markwon.ext.tasklist;
|
||||||
|
|
||||||
import org.commonmark.node.CustomBlock;
|
import org.commonmark.node.CustomBlock;
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package ru.noties.markwon.tasklist;
|
package ru.noties.markwon.ext.tasklist;
|
||||||
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
@ -1,4 +1,4 @@
|
|||||||
package ru.noties.markwon.tasklist;
|
package ru.noties.markwon.ext.tasklist;
|
||||||
|
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.ColorFilter;
|
import android.graphics.ColorFilter;
|
@ -1,4 +1,4 @@
|
|||||||
package ru.noties.markwon.tasklist;
|
package ru.noties.markwon.ext.tasklist;
|
||||||
|
|
||||||
import org.commonmark.node.CustomNode;
|
import org.commonmark.node.CustomNode;
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package ru.noties.markwon.tasklist;
|
package ru.noties.markwon.ext.tasklist;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
@ -1,4 +1,4 @@
|
|||||||
package ru.noties.markwon.tasklist;
|
package ru.noties.markwon.ext.tasklist;
|
||||||
|
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
@ -9,7 +9,7 @@ import java.util.Map;
|
|||||||
import ru.noties.markwon.MarkwonConfiguration;
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
import ru.noties.markwon.html.HtmlTag;
|
import ru.noties.markwon.html.HtmlTag;
|
||||||
import ru.noties.markwon.html.impl.CssInlineStyleParser;
|
import ru.noties.markwon.html.impl.CssInlineStyleParser;
|
||||||
import ru.noties.markwon.renderer.ImageSize;
|
import ru.noties.markwon.image.ImageSize;
|
||||||
|
|
||||||
public class ImageHandler extends SimpleTagHandler {
|
public class ImageHandler extends SimpleTagHandler {
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ import java.util.Map;
|
|||||||
|
|
||||||
import ru.noties.markwon.html.impl.CssInlineStyleParser;
|
import ru.noties.markwon.html.impl.CssInlineStyleParser;
|
||||||
import ru.noties.markwon.html.impl.CssProperty;
|
import ru.noties.markwon.html.impl.CssProperty;
|
||||||
import ru.noties.markwon.renderer.ImageSize;
|
import ru.noties.markwon.image.ImageSize;
|
||||||
|
|
||||||
class ImageSizeParserImpl implements ImageHandler.ImageSizeParser {
|
class ImageSizeParserImpl implements ImageHandler.ImageSizeParser {
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package ru.noties.markwon.html.impl.tag;
|
package ru.noties.markwon.html.impl.tag;
|
||||||
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
import android.text.style.StrikethroughSpan;
|
||||||
|
|
||||||
import ru.noties.markwon.MarkwonConfiguration;
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
import ru.noties.markwon.SpannableBuilder;
|
import ru.noties.markwon.SpannableBuilder;
|
||||||
@ -21,7 +22,7 @@ public class StrikeHandler extends TagHandler {
|
|||||||
|
|
||||||
SpannableBuilder.setSpans(
|
SpannableBuilder.setSpans(
|
||||||
builder,
|
builder,
|
||||||
configuration.factory().strikethrough(),
|
new StrikethroughSpan(),
|
||||||
tag.start(),
|
tag.start(),
|
||||||
tag.end()
|
tag.end()
|
||||||
);
|
);
|
||||||
|
@ -13,7 +13,7 @@ import java.util.Collections;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import ru.noties.markwon.renderer.ImageSize;
|
import ru.noties.markwon.image.ImageSize;
|
||||||
import ru.noties.markwon.renderer.html2.CssInlineStyleParser;
|
import ru.noties.markwon.renderer.html2.CssInlineStyleParser;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
@ -14,12 +14,26 @@ public class Prism4jThemeDefault extends Prism4jThemeBase {
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static Prism4jThemeDefault create() {
|
public static Prism4jThemeDefault create() {
|
||||||
return new Prism4jThemeDefault();
|
return new Prism4jThemeDefault(0xFFf5f2f0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public static Prism4jThemeDefault create(@ColorInt int background) {
|
||||||
|
return new Prism4jThemeDefault(background);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final int background;
|
||||||
|
|
||||||
|
public Prism4jThemeDefault(@ColorInt int background) {
|
||||||
|
this.background = background;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int background() {
|
public int background() {
|
||||||
return 0xFFf5f2f0;
|
return background;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -18,8 +18,6 @@ dependencies {
|
|||||||
deps.with {
|
deps.with {
|
||||||
api it['support-annotations']
|
api it['support-annotations']
|
||||||
api it['commonmark']
|
api it['commonmark']
|
||||||
api it['commonmark-strikethrough']
|
|
||||||
api it['commonmark-table']
|
|
||||||
}
|
}
|
||||||
|
|
||||||
deps['test'].with {
|
deps['test'].with {
|
||||||
|
@ -2,216 +2,46 @@ package ru.noties.markwon;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.text.method.LinkMovementMethod;
|
|
||||||
import android.text.method.MovementMethod;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.commonmark.ext.gfm.strikethrough.StrikethroughExtension;
|
|
||||||
import org.commonmark.ext.gfm.tables.TablesExtension;
|
|
||||||
import org.commonmark.node.Node;
|
import org.commonmark.node.Node;
|
||||||
import org.commonmark.parser.Parser;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import ru.noties.markwon.image.AsyncDrawable;
|
|
||||||
//import ru.noties.markwon.image.DrawablesScheduler;
|
|
||||||
import ru.noties.markwon.renderer.SpannableRenderer;
|
|
||||||
import ru.noties.markwon.spans.OrderedListItemSpan;
|
|
||||||
import ru.noties.markwon.table.TableRowSpan;
|
|
||||||
import ru.noties.markwon.tasklist.TaskListExtension;
|
|
||||||
|
|
||||||
@SuppressWarnings({"WeakerAccess", "unused"})
|
|
||||||
public abstract class Markwon {
|
public abstract class Markwon {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static Builder builder(@NonNull Context context) {
|
||||||
|
return new MarkwonBuilderImpl(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public abstract Node parse(@NonNull String input);
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public abstract CharSequence render(@NonNull Node node);
|
||||||
|
|
||||||
|
// parse + render
|
||||||
|
@NonNull
|
||||||
|
public abstract CharSequence toMarkdown(@NonNull String input);
|
||||||
|
|
||||||
|
public abstract void setMarkdown(@NonNull TextView textView, @NonNull String markdown);
|
||||||
|
|
||||||
|
public abstract void setParsedMarkdown(@NonNull TextView textView, @NonNull CharSequence markdown);
|
||||||
|
|
||||||
|
public interface Builder {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method to obtain a Parser with registered strike-through & table extensions
|
* Specify bufferType when applying text to a TextView {@code textView.setText(CharSequence,BufferType)}.
|
||||||
* & task lists (added in 1.0.1)
|
* By default `BufferType.SPANNABLE` is used
|
||||||
*
|
*
|
||||||
* @return a Parser instance that is supported by this library
|
* @param bufferType BufferType
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public static Parser createParser() {
|
Builder bufferType(@NonNull TextView.BufferType bufferType);
|
||||||
return new Parser.Builder()
|
|
||||||
.extensions(Arrays.asList(
|
|
||||||
StrikethroughExtension.create(),
|
|
||||||
TablesExtension.create(),
|
|
||||||
TaskListExtension.create()
|
|
||||||
))
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see #setMarkdown(TextView, MarkwonConfiguration, String)
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
public static void setMarkdown(@NonNull TextView view, @NonNull String markdown) {
|
|
||||||
setMarkdown(view, MarkwonConfiguration.create(view.getContext()), markdown);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses submitted raw toMarkdown, converts it to CharSequence (with Spannables)
|
|
||||||
* and applies it to view
|
|
||||||
*
|
|
||||||
* @param view {@link TextView} to set toMarkdown into
|
|
||||||
* @param configuration a {@link MarkwonConfiguration} instance
|
|
||||||
* @param markdown raw toMarkdown String (for example: {@code `**Hello**`})
|
|
||||||
* @see #markdown(MarkwonConfiguration, String)
|
|
||||||
* @see #setText(TextView, CharSequence)
|
|
||||||
* @see MarkwonConfiguration
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
public static void setMarkdown(
|
|
||||||
@NonNull TextView view,
|
|
||||||
@NonNull MarkwonConfiguration configuration,
|
|
||||||
@NonNull String markdown
|
|
||||||
) {
|
|
||||||
|
|
||||||
setText(view, markdown(configuration, markdown));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper method to apply parsed toMarkdown.
|
|
||||||
* <p>
|
|
||||||
* Since 1.0.6 redirects it\'s call to {@link #setText(TextView, CharSequence, MovementMethod)}
|
|
||||||
* with LinkMovementMethod as an argument to preserve current API.
|
|
||||||
*
|
|
||||||
* @param view {@link TextView} to set toMarkdown into
|
|
||||||
* @param text parsed toMarkdown
|
|
||||||
* @see #setText(TextView, CharSequence, MovementMethod)
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
public static void setText(@NonNull TextView view, CharSequence text) {
|
|
||||||
setText(view, text, LinkMovementMethod.getInstance());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper method to apply parsed toMarkdown with additional argument of a MovementMethod. Used
|
|
||||||
* to workaround problems that occur when using system LinkMovementMethod (for example:
|
|
||||||
* https://issuetracker.google.com/issues/37068143). As a better alternative to it consider
|
|
||||||
* using: https://github.com/saket/Better-Link-Movement-Method
|
|
||||||
*
|
|
||||||
* @param view TextView to set toMarkdown into
|
|
||||||
* @param text parsed toMarkdown
|
|
||||||
* @param movementMethod an implementation if MovementMethod or null
|
|
||||||
* @see #scheduleDrawables(TextView)
|
|
||||||
* @see #scheduleTableRows(TextView)
|
|
||||||
* @since 1.0.6
|
|
||||||
*/
|
|
||||||
public static void setText(@NonNull TextView view, CharSequence text, @Nullable MovementMethod movementMethod) {
|
|
||||||
|
|
||||||
unscheduleDrawables(view);
|
|
||||||
unscheduleTableRows(view);
|
|
||||||
|
|
||||||
// @since 2.0.1 we must measure ordered-list-item-spans before applying text to a TextView.
|
|
||||||
// if toMarkdown has a lot of ordered list items (or text size is relatively big, or block-margin
|
|
||||||
// is relatively small) then this list won't be rendered properly: it will take correct
|
|
||||||
// layout (width and margin) but will be clipped if margin is not _consistent_ between calls.
|
|
||||||
OrderedListItemSpan.measure(view, text);
|
|
||||||
|
|
||||||
// update movement method (for links to be clickable)
|
|
||||||
view.setMovementMethod(movementMethod);
|
|
||||||
view.setText(text);
|
|
||||||
|
|
||||||
// schedule drawables (dynamic drawables that can change bounds/animate will be correctly updated)
|
|
||||||
scheduleDrawables(view);
|
|
||||||
scheduleTableRows(view);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns parsed toMarkdown with default {@link MarkwonConfiguration} obtained from {@link Context}
|
|
||||||
*
|
|
||||||
* @param context {@link Context}
|
|
||||||
* @param markdown raw toMarkdown
|
|
||||||
* @return parsed toMarkdown
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static CharSequence markdown(@NonNull Context context, @NonNull String markdown) {
|
Builder use(@NonNull MarkwonPlugin plugin);
|
||||||
final MarkwonConfiguration configuration = MarkwonConfiguration.create(context);
|
|
||||||
return markdown(configuration, markdown);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns parsed toMarkdown with provided {@link MarkwonConfiguration}
|
|
||||||
*
|
|
||||||
* @param configuration a {@link MarkwonConfiguration}
|
|
||||||
* @param markdown raw toMarkdown
|
|
||||||
* @return parsed toMarkdown
|
|
||||||
* @see MarkwonConfiguration
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static CharSequence markdown(@NonNull MarkwonConfiguration configuration, @NonNull String markdown) {
|
Markwon build();
|
||||||
final Parser parser = createParser();
|
|
||||||
final Node node = parser.parse(markdown);
|
|
||||||
final SpannableRenderer renderer = new SpannableRenderer();
|
|
||||||
return renderer.render(configuration, node);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method adds support for {@link AsyncDrawable} to be used. As
|
|
||||||
* textView seems not to support drawables that change bounds (and gives no means
|
|
||||||
* to update the layout), we create own {@link android.graphics.drawable.Drawable.Callback}
|
|
||||||
* and apply it. So, textView can display drawables, that are: async (loading from disk, network);
|
|
||||||
* dynamic (requires `invalidate`) - GIF, animations.
|
|
||||||
* Please note, that this method should be preceded with {@link #unscheduleDrawables(TextView)}
|
|
||||||
* in order to avoid keeping drawables in memory after they have been removed from layout
|
|
||||||
*
|
|
||||||
* @param view a {@link TextView}
|
|
||||||
* @see AsyncDrawable
|
|
||||||
* @see ru.noties.markwon.spans.AsyncDrawableSpan
|
|
||||||
* @see DrawablesScheduler#schedule(TextView)
|
|
||||||
* @see DrawablesScheduler#unschedule(TextView)
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
public static void scheduleDrawables(@NonNull TextView view) {
|
|
||||||
// DrawablesScheduler.schedule(view);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* De-references previously scheduled {@link ru.noties.markwon.spans.AsyncDrawableSpan}'s
|
|
||||||
*
|
|
||||||
* @param view a {@link TextView}
|
|
||||||
* @see #scheduleDrawables(TextView)
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
public static void unscheduleDrawables(@NonNull TextView view) {
|
|
||||||
// DrawablesScheduler.unschedule(view);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is required in order to use tables. A bit of background:
|
|
||||||
* this library uses a {@link android.text.style.ReplacementSpan} to
|
|
||||||
* render tables, but the flow is not really flexible. We are required
|
|
||||||
* to return `size` (width) of our replacement, but we are not provided
|
|
||||||
* with the total one (canvas width). In order to correctly calculate height of our
|
|
||||||
* table cell text, we must have available width first. This method gives
|
|
||||||
* ability for {@link TableRowSpan} to invalidate
|
|
||||||
* `view` when it encounters such a situation (when available width is not known or have changed).
|
|
||||||
* Precede this call with {@link #unscheduleTableRows(TextView)} in order to
|
|
||||||
* de-reference previously scheduled {@link TableRowSpan}'s
|
|
||||||
*
|
|
||||||
* @param view a {@link TextView}
|
|
||||||
* @see #unscheduleTableRows(TextView)
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
public static void scheduleTableRows(@NonNull TextView view) {
|
|
||||||
// TableRowsScheduler.schedule(view);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* De-references previously scheduled {@link TableRowSpan}'s
|
|
||||||
*
|
|
||||||
* @param view a {@link TextView}
|
|
||||||
* @see #scheduleTableRows(TextView)
|
|
||||||
* @since 1.0.0
|
|
||||||
*/
|
|
||||||
public static void unscheduleTableRows(@NonNull TextView view) {
|
|
||||||
// TableRowsScheduler.unschedule(view);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Markwon() {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
package ru.noties.markwon;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import org.commonmark.node.Node;
|
|
||||||
|
|
||||||
public abstract class Markwon2 {
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static Builder builder(@NonNull Context context) {
|
|
||||||
return new MarkwonBuilderImpl(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public abstract Node parse(@NonNull String input);
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public abstract CharSequence render(@NonNull Node node);
|
|
||||||
|
|
||||||
// parse + render
|
|
||||||
@NonNull
|
|
||||||
public abstract CharSequence toMarkdown(@NonNull String input);
|
|
||||||
|
|
||||||
public abstract void setMarkdown(@NonNull TextView textView, @NonNull String markdown);
|
|
||||||
|
|
||||||
public abstract void setParsedMarkdown(@NonNull TextView textView, @NonNull CharSequence markdown);
|
|
||||||
|
|
||||||
public interface Builder {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify bufferType when applying text to a TextView {@code textView.setText(CharSequence,BufferType)}.
|
|
||||||
* By default `BufferType.SPANNABLE` is used
|
|
||||||
*
|
|
||||||
* @param bufferType BufferType
|
|
||||||
*/
|
|
||||||
@NonNull
|
|
||||||
Builder bufferType(@NonNull TextView.BufferType bufferType);
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
Builder use(@NonNull MarkwonPlugin plugin);
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
Markwon2 build();
|
|
||||||
}
|
|
||||||
}
|
|
@ -13,7 +13,7 @@ import java.util.List;
|
|||||||
import ru.noties.markwon.image.AsyncDrawableLoader;
|
import ru.noties.markwon.image.AsyncDrawableLoader;
|
||||||
import ru.noties.markwon.spans.MarkwonTheme;
|
import ru.noties.markwon.spans.MarkwonTheme;
|
||||||
|
|
||||||
class MarkwonBuilderImpl implements Markwon2.Builder {
|
class MarkwonBuilderImpl implements Markwon.Builder {
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
|
||||||
@ -26,21 +26,21 @@ class MarkwonBuilderImpl implements Markwon2.Builder {
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public Markwon2.Builder bufferType(@NonNull TextView.BufferType bufferType) {
|
public Markwon.Builder bufferType(@NonNull TextView.BufferType bufferType) {
|
||||||
this.bufferType = bufferType;
|
this.bufferType = bufferType;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public Markwon2.Builder use(@NonNull MarkwonPlugin plugin) {
|
public Markwon.Builder use(@NonNull MarkwonPlugin plugin) {
|
||||||
plugins.add(plugin);
|
plugins.add(plugin);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public Markwon2 build() {
|
public Markwon build() {
|
||||||
|
|
||||||
final Parser.Builder parserBuilder = new Parser.Builder();
|
final Parser.Builder parserBuilder = new Parser.Builder();
|
||||||
final MarkwonTheme.Builder themeBuilder = MarkwonTheme.builderWithDefaults(context);
|
final MarkwonTheme.Builder themeBuilder = MarkwonTheme.builderWithDefaults(context);
|
||||||
|
@ -7,8 +7,8 @@ import ru.noties.markwon.html.MarkwonHtmlParser;
|
|||||||
import ru.noties.markwon.html.MarkwonHtmlRenderer;
|
import ru.noties.markwon.html.MarkwonHtmlRenderer;
|
||||||
import ru.noties.markwon.image.AsyncDrawableLoader;
|
import ru.noties.markwon.image.AsyncDrawableLoader;
|
||||||
import ru.noties.markwon.image.AsyncDrawableLoaderNoOp;
|
import ru.noties.markwon.image.AsyncDrawableLoaderNoOp;
|
||||||
import ru.noties.markwon.renderer.ImageSizeResolver;
|
import ru.noties.markwon.image.ImageSizeResolver;
|
||||||
import ru.noties.markwon.renderer.ImageSizeResolverDef;
|
import ru.noties.markwon.image.ImageSizeResolverDef;
|
||||||
import ru.noties.markwon.spans.LinkSpan;
|
import ru.noties.markwon.spans.LinkSpan;
|
||||||
import ru.noties.markwon.spans.MarkwonTheme;
|
import ru.noties.markwon.spans.MarkwonTheme;
|
||||||
|
|
||||||
@ -39,7 +39,6 @@ public class MarkwonConfiguration {
|
|||||||
private final SpannableFactory factory; // @since 1.1.0
|
private final SpannableFactory factory; // @since 1.1.0
|
||||||
private final MarkwonHtmlParser htmlParser; // @since 2.0.0
|
private final MarkwonHtmlParser htmlParser; // @since 2.0.0
|
||||||
private final MarkwonHtmlRenderer htmlRenderer; // @since 2.0.0
|
private final MarkwonHtmlRenderer htmlRenderer; // @since 2.0.0
|
||||||
// private final boolean htmlAllowNonClosedTags; // @since 2.0.0
|
|
||||||
|
|
||||||
private MarkwonConfiguration(@NonNull Builder builder) {
|
private MarkwonConfiguration(@NonNull Builder builder) {
|
||||||
this.theme = builder.theme;
|
this.theme = builder.theme;
|
||||||
@ -51,7 +50,6 @@ public class MarkwonConfiguration {
|
|||||||
this.factory = builder.factory;
|
this.factory = builder.factory;
|
||||||
this.htmlParser = builder.htmlParser;
|
this.htmlParser = builder.htmlParser;
|
||||||
this.htmlRenderer = builder.htmlRenderer;
|
this.htmlRenderer = builder.htmlRenderer;
|
||||||
// this.htmlAllowNonClosedTags = builder.htmlAllowNonClosedTags;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -113,13 +111,6 @@ public class MarkwonConfiguration {
|
|||||||
return htmlRenderer;
|
return htmlRenderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
|
||||||
// * @since 2.0.0
|
|
||||||
// */
|
|
||||||
// public boolean htmlAllowNonClosedTags() {
|
|
||||||
// return htmlAllowNonClosedTags;
|
|
||||||
// }
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
|
|
||||||
@ -134,7 +125,6 @@ public class MarkwonConfiguration {
|
|||||||
private SpannableFactory factory; // @since 1.1.0
|
private SpannableFactory factory; // @since 1.1.0
|
||||||
private MarkwonHtmlParser htmlParser; // @since 2.0.0
|
private MarkwonHtmlParser htmlParser; // @since 2.0.0
|
||||||
private MarkwonHtmlRenderer htmlRenderer; // @since 2.0.0
|
private MarkwonHtmlRenderer htmlRenderer; // @since 2.0.0
|
||||||
// private boolean htmlAllowNonClosedTags; // @since 2.0.0
|
|
||||||
|
|
||||||
Builder(@NonNull Context context) {
|
Builder(@NonNull Context context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
@ -151,7 +141,6 @@ public class MarkwonConfiguration {
|
|||||||
this.factory = configuration.factory;
|
this.factory = configuration.factory;
|
||||||
this.htmlParser = configuration.htmlParser;
|
this.htmlParser = configuration.htmlParser;
|
||||||
this.htmlRenderer = configuration.htmlRenderer;
|
this.htmlRenderer = configuration.htmlRenderer;
|
||||||
// this.htmlAllowNonClosedTags = configuration.htmlAllowNonClosedTags;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@ -208,19 +197,6 @@ public class MarkwonConfiguration {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
|
||||||
// * @param htmlAllowNonClosedTags that indicates if non-closed html tags should be rendered.
|
|
||||||
// * If this argument is true then all non-closed HTML tags
|
|
||||||
// * will be closed at the end of a document. Otherwise they will
|
|
||||||
// * be delivered non-closed {@code HtmlTag#isClosed()}
|
|
||||||
// * @since 2.0.0
|
|
||||||
// */
|
|
||||||
// @NonNull
|
|
||||||
// public Builder htmlAllowNonClosedTags(boolean htmlAllowNonClosedTags) {
|
|
||||||
// this.htmlAllowNonClosedTags = htmlAllowNonClosedTags;
|
|
||||||
// return this;
|
|
||||||
// }
|
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public MarkwonConfiguration build(@NonNull MarkwonTheme theme, @NonNull AsyncDrawableLoader asyncDrawableLoader) {
|
public MarkwonConfiguration build(@NonNull MarkwonTheme theme, @NonNull AsyncDrawableLoader asyncDrawableLoader) {
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ import org.commonmark.parser.Parser;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
class MarkwonImpl extends Markwon2 {
|
class MarkwonImpl extends Markwon {
|
||||||
|
|
||||||
private final TextView.BufferType bufferType;
|
private final TextView.BufferType bufferType;
|
||||||
private final Parser parser;
|
private final Parser parser;
|
||||||
|
@ -4,8 +4,8 @@ import android.support.annotation.NonNull;
|
|||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
import ru.noties.markwon.image.AsyncDrawableLoader;
|
import ru.noties.markwon.image.AsyncDrawableLoader;
|
||||||
import ru.noties.markwon.renderer.ImageSize;
|
import ru.noties.markwon.image.ImageSize;
|
||||||
import ru.noties.markwon.renderer.ImageSizeResolver;
|
import ru.noties.markwon.image.ImageSizeResolver;
|
||||||
import ru.noties.markwon.spans.LinkSpan;
|
import ru.noties.markwon.spans.LinkSpan;
|
||||||
import ru.noties.markwon.spans.MarkwonTheme;
|
import ru.noties.markwon.spans.MarkwonTheme;
|
||||||
|
|
||||||
@ -40,9 +40,6 @@ public interface SpannableFactory {
|
|||||||
@Nullable
|
@Nullable
|
||||||
Object heading(@NonNull MarkwonTheme theme, int level);
|
Object heading(@NonNull MarkwonTheme theme, int level);
|
||||||
|
|
||||||
@Nullable
|
|
||||||
Object strikethrough();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @since 1.1.1
|
* @since 1.1.1
|
||||||
*/
|
*/
|
||||||
|
@ -2,13 +2,11 @@ package ru.noties.markwon;
|
|||||||
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.text.style.StrikethroughSpan;
|
|
||||||
import android.text.style.UnderlineSpan;
|
|
||||||
|
|
||||||
import ru.noties.markwon.image.AsyncDrawable;
|
import ru.noties.markwon.image.AsyncDrawable;
|
||||||
import ru.noties.markwon.image.AsyncDrawableLoader;
|
import ru.noties.markwon.image.AsyncDrawableLoader;
|
||||||
import ru.noties.markwon.renderer.ImageSize;
|
import ru.noties.markwon.image.ImageSize;
|
||||||
import ru.noties.markwon.renderer.ImageSizeResolver;
|
import ru.noties.markwon.image.ImageSizeResolver;
|
||||||
import ru.noties.markwon.spans.AsyncDrawableSpan;
|
import ru.noties.markwon.spans.AsyncDrawableSpan;
|
||||||
import ru.noties.markwon.spans.BlockQuoteSpan;
|
import ru.noties.markwon.spans.BlockQuoteSpan;
|
||||||
import ru.noties.markwon.spans.BulletListItemSpan;
|
import ru.noties.markwon.spans.BulletListItemSpan;
|
||||||
@ -19,8 +17,6 @@ import ru.noties.markwon.spans.LinkSpan;
|
|||||||
import ru.noties.markwon.spans.MarkwonTheme;
|
import ru.noties.markwon.spans.MarkwonTheme;
|
||||||
import ru.noties.markwon.spans.OrderedListItemSpan;
|
import ru.noties.markwon.spans.OrderedListItemSpan;
|
||||||
import ru.noties.markwon.spans.StrongEmphasisSpan;
|
import ru.noties.markwon.spans.StrongEmphasisSpan;
|
||||||
import ru.noties.markwon.spans.SubScriptSpan;
|
|
||||||
import ru.noties.markwon.spans.SuperScriptSpan;
|
|
||||||
import ru.noties.markwon.spans.ThematicBreakSpan;
|
import ru.noties.markwon.spans.ThematicBreakSpan;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -82,12 +78,6 @@ public class SpannableFactoryDef implements SpannableFactory {
|
|||||||
return new HeadingSpan(theme, level);
|
return new HeadingSpan(theme, level);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public Object strikethrough() {
|
|
||||||
return new StrikethroughSpan();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @since 1.1.1
|
* @since 1.1.1
|
||||||
*/
|
*/
|
||||||
|
@ -10,9 +10,6 @@ import android.support.annotation.IntRange;
|
|||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
import ru.noties.markwon.renderer.ImageSize;
|
|
||||||
import ru.noties.markwon.renderer.ImageSizeResolver;
|
|
||||||
|
|
||||||
public class AsyncDrawable extends Drawable {
|
public class AsyncDrawable extends Drawable {
|
||||||
|
|
||||||
private final String destination;
|
private final String destination;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package ru.noties.markwon.renderer;
|
package ru.noties.markwon.image;
|
||||||
|
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package ru.noties.markwon.renderer;
|
package ru.noties.markwon.image;
|
||||||
|
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
@ -1,4 +1,4 @@
|
|||||||
package ru.noties.markwon.renderer;
|
package ru.noties.markwon.image;
|
||||||
|
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
@ -1,529 +0,0 @@
|
|||||||
package ru.noties.markwon.renderer;
|
|
||||||
|
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
|
|
||||||
import org.commonmark.ext.gfm.strikethrough.Strikethrough;
|
|
||||||
import org.commonmark.node.AbstractVisitor;
|
|
||||||
import org.commonmark.node.BlockQuote;
|
|
||||||
import org.commonmark.node.BulletList;
|
|
||||||
import org.commonmark.node.Code;
|
|
||||||
import org.commonmark.node.CustomBlock;
|
|
||||||
import org.commonmark.node.CustomNode;
|
|
||||||
import org.commonmark.node.Emphasis;
|
|
||||||
import org.commonmark.node.FencedCodeBlock;
|
|
||||||
import org.commonmark.node.HardLineBreak;
|
|
||||||
import org.commonmark.node.Heading;
|
|
||||||
import org.commonmark.node.Image;
|
|
||||||
import org.commonmark.node.IndentedCodeBlock;
|
|
||||||
import org.commonmark.node.Link;
|
|
||||||
import org.commonmark.node.ListBlock;
|
|
||||||
import org.commonmark.node.ListItem;
|
|
||||||
import org.commonmark.node.Node;
|
|
||||||
import org.commonmark.node.OrderedList;
|
|
||||||
import org.commonmark.node.Paragraph;
|
|
||||||
import org.commonmark.node.StrongEmphasis;
|
|
||||||
import org.commonmark.node.Text;
|
|
||||||
import org.commonmark.node.ThematicBreak;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import ru.noties.markwon.MarkwonConfiguration;
|
|
||||||
import ru.noties.markwon.SpannableBuilder;
|
|
||||||
import ru.noties.markwon.SpannableFactory;
|
|
||||||
import ru.noties.markwon.spans.MarkwonTheme;
|
|
||||||
import ru.noties.markwon.table.TableRowSpan;
|
|
||||||
import ru.noties.markwon.tasklist.TaskListBlock;
|
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess")
|
|
||||||
public class SpannableMarkdownVisitor extends AbstractVisitor {
|
|
||||||
|
|
||||||
private final MarkwonConfiguration configuration;
|
|
||||||
private final SpannableBuilder builder;
|
|
||||||
// private final MarkwonHtmlParser htmlParser;
|
|
||||||
|
|
||||||
private final MarkwonTheme theme;
|
|
||||||
private final SpannableFactory factory;
|
|
||||||
|
|
||||||
private int blockQuoteIndent;
|
|
||||||
private int listLevel;
|
|
||||||
|
|
||||||
private List<TableRowSpan.Cell> pendingTableRow;
|
|
||||||
private boolean tableRowIsHeader;
|
|
||||||
private int tableRows;
|
|
||||||
|
|
||||||
public SpannableMarkdownVisitor(
|
|
||||||
@NonNull MarkwonConfiguration configuration,
|
|
||||||
@NonNull SpannableBuilder builder
|
|
||||||
) {
|
|
||||||
this.configuration = configuration;
|
|
||||||
this.builder = builder;
|
|
||||||
// this.htmlParser = configuration.htmlParser();
|
|
||||||
|
|
||||||
this.theme = configuration.theme();
|
|
||||||
this.factory = configuration.factory();
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Override
|
|
||||||
// public void visit(Document document) {
|
|
||||||
// super.visit(document);
|
|
||||||
//
|
|
||||||
// configuration.htmlRenderer().render(configuration, builder, htmlParser);
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(Text text) {
|
|
||||||
builder.append(text.getLiteral());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(StrongEmphasis strongEmphasis) {
|
|
||||||
final int length = builder.length();
|
|
||||||
visitChildren(strongEmphasis);
|
|
||||||
setSpan(length, factory.strongEmphasis());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(Emphasis emphasis) {
|
|
||||||
final int length = builder.length();
|
|
||||||
visitChildren(emphasis);
|
|
||||||
setSpan(length, factory.emphasis());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(BlockQuote blockQuote) {
|
|
||||||
|
|
||||||
newLine();
|
|
||||||
if (blockQuoteIndent != 0) {
|
|
||||||
builder.append('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
final int length = builder.length();
|
|
||||||
|
|
||||||
blockQuoteIndent += 1;
|
|
||||||
|
|
||||||
visitChildren(blockQuote);
|
|
||||||
|
|
||||||
setSpan(length, factory.blockQuote(theme));
|
|
||||||
|
|
||||||
blockQuoteIndent -= 1;
|
|
||||||
|
|
||||||
if (hasNext(blockQuote)) {
|
|
||||||
newLine();
|
|
||||||
if (blockQuoteIndent == 0) {
|
|
||||||
builder.append('\n');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(Code code) {
|
|
||||||
|
|
||||||
final int length = builder.length();
|
|
||||||
|
|
||||||
// NB, in order to provide a _padding_ feeling code is wrapped inside two unbreakable spaces
|
|
||||||
// unfortunately we cannot use this for multiline code as we cannot control where a new line break will be inserted
|
|
||||||
builder.append('\u00a0');
|
|
||||||
builder.append(code.getLiteral());
|
|
||||||
builder.append('\u00a0');
|
|
||||||
|
|
||||||
setSpan(length, factory.code(theme, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(FencedCodeBlock fencedCodeBlock) {
|
|
||||||
// @since 1.0.4
|
|
||||||
visitCodeBlock(fencedCodeBlock.getInfo(), fencedCodeBlock.getLiteral(), fencedCodeBlock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @since 1.0.4
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void visit(IndentedCodeBlock indentedCodeBlock) {
|
|
||||||
visitCodeBlock(null, indentedCodeBlock.getLiteral(), indentedCodeBlock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param info tag of a code block
|
|
||||||
* @param code content of a code block
|
|
||||||
* @since 1.0.4
|
|
||||||
*/
|
|
||||||
private void visitCodeBlock(@Nullable String info, @NonNull String code, @NonNull Node node) {
|
|
||||||
|
|
||||||
newLine();
|
|
||||||
|
|
||||||
final int length = builder.length();
|
|
||||||
|
|
||||||
// empty lines on top & bottom
|
|
||||||
builder.append('\u00a0').append('\n');
|
|
||||||
builder.append(
|
|
||||||
configuration.syntaxHighlight()
|
|
||||||
.highlight(info, code)
|
|
||||||
);
|
|
||||||
|
|
||||||
newLine();
|
|
||||||
builder.append('\u00a0');
|
|
||||||
|
|
||||||
setSpan(length, factory.code(theme, true));
|
|
||||||
|
|
||||||
if (hasNext(node)) {
|
|
||||||
newLine();
|
|
||||||
builder.append('\n');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(BulletList bulletList) {
|
|
||||||
visitList(bulletList);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(OrderedList orderedList) {
|
|
||||||
visitList(orderedList);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void visitList(Node node) {
|
|
||||||
|
|
||||||
newLine();
|
|
||||||
|
|
||||||
visitChildren(node);
|
|
||||||
|
|
||||||
if (hasNext(node)) {
|
|
||||||
newLine();
|
|
||||||
if (listLevel == 0 && blockQuoteIndent == 0) {
|
|
||||||
builder.append('\n');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(ListItem listItem) {
|
|
||||||
|
|
||||||
final int length = builder.length();
|
|
||||||
|
|
||||||
blockQuoteIndent += 1;
|
|
||||||
listLevel += 1;
|
|
||||||
|
|
||||||
final Node parent = listItem.getParent();
|
|
||||||
if (parent instanceof OrderedList) {
|
|
||||||
|
|
||||||
final int start = ((OrderedList) parent).getStartNumber();
|
|
||||||
|
|
||||||
visitChildren(listItem);
|
|
||||||
|
|
||||||
setSpan(length, factory.orderedListItem(theme, start));
|
|
||||||
|
|
||||||
// after we have visited the children increment start number
|
|
||||||
final OrderedList orderedList = (OrderedList) parent;
|
|
||||||
orderedList.setStartNumber(orderedList.getStartNumber() + 1);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
visitChildren(listItem);
|
|
||||||
|
|
||||||
setSpan(length, factory.bulletListItem(theme, listLevel - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
blockQuoteIndent -= 1;
|
|
||||||
listLevel -= 1;
|
|
||||||
|
|
||||||
if (hasNext(listItem)) {
|
|
||||||
newLine();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(ThematicBreak thematicBreak) {
|
|
||||||
|
|
||||||
newLine();
|
|
||||||
|
|
||||||
final int length = builder.length();
|
|
||||||
builder.append('\u00a0'); // without space it won't render
|
|
||||||
|
|
||||||
setSpan(length, factory.thematicBreak(theme));
|
|
||||||
|
|
||||||
if (hasNext(thematicBreak)) {
|
|
||||||
newLine();
|
|
||||||
builder.append('\n');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(Heading heading) {
|
|
||||||
|
|
||||||
newLine();
|
|
||||||
|
|
||||||
final int length = builder.length();
|
|
||||||
visitChildren(heading);
|
|
||||||
setSpan(length, factory.heading(theme, heading.getLevel()));
|
|
||||||
|
|
||||||
if (hasNext(heading)) {
|
|
||||||
newLine();
|
|
||||||
// after heading we add another line anyway (no additional checks)
|
|
||||||
builder.append('\n');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Override
|
|
||||||
// public void visit(SoftLineBreak softLineBreak) {
|
|
||||||
// // @since 1.1.1 there is an option to treat soft break as a hard break (thus adding new line)
|
|
||||||
// if (configuration.softBreakAddsNewLine()) {
|
|
||||||
// newLine();
|
|
||||||
// } else {
|
|
||||||
// builder.append(' ');
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(HardLineBreak hardLineBreak) {
|
|
||||||
newLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @since 1.0.1
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void visit(CustomBlock customBlock) {
|
|
||||||
|
|
||||||
if (customBlock instanceof TaskListBlock) {
|
|
||||||
blockQuoteIndent += 1;
|
|
||||||
visitChildren(customBlock);
|
|
||||||
blockQuoteIndent -= 1;
|
|
||||||
|
|
||||||
if (hasNext(customBlock)) {
|
|
||||||
newLine();
|
|
||||||
builder.append('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
super.visit(customBlock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(CustomNode customNode) {
|
|
||||||
|
|
||||||
if (customNode instanceof Strikethrough) {
|
|
||||||
|
|
||||||
final int length = builder.length();
|
|
||||||
visitChildren(customNode);
|
|
||||||
setSpan(length, factory.strikethrough());
|
|
||||||
|
|
||||||
} else {
|
|
||||||
super.visit(customNode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// private boolean handleTableNodes(CustomNode node) {
|
|
||||||
//
|
|
||||||
// final boolean handled;
|
|
||||||
//
|
|
||||||
// if (node instanceof TableBody) {
|
|
||||||
//
|
|
||||||
// visitChildren(node);
|
|
||||||
// tableRows = 0;
|
|
||||||
// handled = true;
|
|
||||||
//
|
|
||||||
// if (hasNext(node)) {
|
|
||||||
// newLine();
|
|
||||||
// builder.append('\n');
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// } else if (node instanceof TableRow || node instanceof TableHead) {
|
|
||||||
//
|
|
||||||
// final int length = builder.length();
|
|
||||||
//
|
|
||||||
// visitChildren(node);
|
|
||||||
//
|
|
||||||
// if (pendingTableRow != null) {
|
|
||||||
//
|
|
||||||
// // @since 2.0.0
|
|
||||||
// // we cannot rely on hasNext(TableHead) as it's not reliable
|
|
||||||
// // we must apply new line manually and then exclude it from tableRow span
|
|
||||||
// final boolean addNewLine;
|
|
||||||
// {
|
|
||||||
// final int builderLength = builder.length();
|
|
||||||
// addNewLine = builderLength > 0
|
|
||||||
// && '\n' != builder.charAt(builderLength - 1);
|
|
||||||
// }
|
|
||||||
// if (addNewLine) {
|
|
||||||
// builder.append('\n');
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // @since 1.0.4 Replace table char with non-breakable space
|
|
||||||
// // we need this because if table is at the end of the text, then it will be
|
|
||||||
// // trimmed from the final result
|
|
||||||
// builder.append('\u00a0');
|
|
||||||
//
|
|
||||||
// final Object span = factory.tableRow(
|
|
||||||
// theme,
|
|
||||||
// pendingTableRow,
|
|
||||||
// tableRowIsHeader,
|
|
||||||
// tableRows % 2 == 1);
|
|
||||||
//
|
|
||||||
// tableRows = tableRowIsHeader
|
|
||||||
// ? 0
|
|
||||||
// : tableRows + 1;
|
|
||||||
//
|
|
||||||
// setSpan(addNewLine ? length + 1 : length, span);
|
|
||||||
//
|
|
||||||
// pendingTableRow = null;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// handled = true;
|
|
||||||
//
|
|
||||||
// } else if (node instanceof TableCell) {
|
|
||||||
//
|
|
||||||
// final TableCell cell = (TableCell) node;
|
|
||||||
// final int length = builder.length();
|
|
||||||
// visitChildren(cell);
|
|
||||||
// if (pendingTableRow == null) {
|
|
||||||
// pendingTableRow = new ArrayList<>(2);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// pendingTableRow.add(new TableRowSpan.Cell(
|
|
||||||
// tableCellAlignment(cell.getAlignment()),
|
|
||||||
// builder.removeFromEnd(length)
|
|
||||||
// ));
|
|
||||||
//
|
|
||||||
// tableRowIsHeader = cell.isHeader();
|
|
||||||
//
|
|
||||||
// handled = true;
|
|
||||||
// } else {
|
|
||||||
// handled = false;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return handled;
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(Paragraph paragraph) {
|
|
||||||
|
|
||||||
final boolean inTightList = isInTightList(paragraph);
|
|
||||||
|
|
||||||
if (!inTightList) {
|
|
||||||
newLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
final int length = builder.length();
|
|
||||||
visitChildren(paragraph);
|
|
||||||
|
|
||||||
// @since 1.1.1 apply paragraph span
|
|
||||||
setSpan(length, factory.paragraph(inTightList));
|
|
||||||
|
|
||||||
if (hasNext(paragraph) && !inTightList) {
|
|
||||||
newLine();
|
|
||||||
if (blockQuoteIndent == 0) {
|
|
||||||
builder.append('\n');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(Image image) {
|
|
||||||
|
|
||||||
final int length = builder.length();
|
|
||||||
|
|
||||||
visitChildren(image);
|
|
||||||
|
|
||||||
// we must check if anything _was_ added, as we need at least one char to render
|
|
||||||
if (length == builder.length()) {
|
|
||||||
builder.append('\uFFFC');
|
|
||||||
}
|
|
||||||
|
|
||||||
final Node parent = image.getParent();
|
|
||||||
final boolean link = parent != null && parent instanceof Link;
|
|
||||||
final String destination = configuration.urlProcessor().process(image.getDestination());
|
|
||||||
|
|
||||||
setSpan(
|
|
||||||
length,
|
|
||||||
factory.image(
|
|
||||||
theme,
|
|
||||||
destination,
|
|
||||||
configuration.asyncDrawableLoader(),
|
|
||||||
configuration.imageSizeResolver(),
|
|
||||||
null,
|
|
||||||
link
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// todo, maybe, if image is not inside a link, we should make it clickable, so
|
|
||||||
// user can open it in external viewer?
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Override
|
|
||||||
// public void visit(HtmlBlock htmlBlock) {
|
|
||||||
// visitHtml(htmlBlock.getLiteral());
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public void visit(HtmlInline htmlInline) {
|
|
||||||
// visitHtml(htmlInline.getLiteral());
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private void visitHtml(@Nullable String html) {
|
|
||||||
// if (html != null) {
|
|
||||||
// htmlParser.processFragment(builder, html);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(Link link) {
|
|
||||||
final int length = builder.length();
|
|
||||||
visitChildren(link);
|
|
||||||
final String destination = configuration.urlProcessor().process(link.getDestination());
|
|
||||||
setSpan(length, factory.link(theme, destination, configuration.linkResolver()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setSpan(int start, @Nullable Object span) {
|
|
||||||
SpannableBuilder.setSpans(builder, span, start, builder.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void newLine() {
|
|
||||||
if (builder.length() > 0
|
|
||||||
&& '\n' != builder.lastChar()) {
|
|
||||||
builder.append('\n');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isInTightList(Paragraph paragraph) {
|
|
||||||
final Node parent = paragraph.getParent();
|
|
||||||
if (parent != null) {
|
|
||||||
final Node gramps = parent.getParent();
|
|
||||||
if (gramps != null && gramps instanceof ListBlock) {
|
|
||||||
ListBlock list = (ListBlock) gramps;
|
|
||||||
return list.isTight();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// @TableRowSpan.Alignment
|
|
||||||
// private static int tableCellAlignment(TableCell.Alignment alignment) {
|
|
||||||
// final int out;
|
|
||||||
// if (alignment != null) {
|
|
||||||
// switch (alignment) {
|
|
||||||
// case CENTER:
|
|
||||||
// out = TableRowSpan.ALIGN_CENTER;
|
|
||||||
// break;
|
|
||||||
// case RIGHT:
|
|
||||||
// out = TableRowSpan.ALIGN_RIGHT;
|
|
||||||
// break;
|
|
||||||
// default:
|
|
||||||
// out = TableRowSpan.ALIGN_LEFT;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// out = TableRowSpan.ALIGN_LEFT;
|
|
||||||
// }
|
|
||||||
// return out;
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @since 2.0.0
|
|
||||||
*/
|
|
||||||
protected static boolean hasNext(@NonNull Node node) {
|
|
||||||
return node.getNext() != null;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
package ru.noties.markwon.renderer;
|
|
||||||
|
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
|
|
||||||
import org.commonmark.node.Node;
|
|
||||||
|
|
||||||
import ru.noties.markwon.MarkwonConfiguration;
|
|
||||||
import ru.noties.markwon.SpannableBuilder;
|
|
||||||
|
|
||||||
public class SpannableRenderer {
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public CharSequence render(@NonNull MarkwonConfiguration configuration, @NonNull Node node) {
|
|
||||||
final SpannableBuilder builder = new SpannableBuilder();
|
|
||||||
node.accept(new SpannableMarkdownVisitor(configuration, builder));
|
|
||||||
return builder.text();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
package ru.noties.markwon.spans;
|
|
||||||
|
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.text.TextPaint;
|
|
||||||
import android.text.style.MetricAffectingSpan;
|
|
||||||
|
|
||||||
public class SubScriptSpan extends MetricAffectingSpan {
|
|
||||||
|
|
||||||
private final MarkwonTheme theme;
|
|
||||||
|
|
||||||
public SubScriptSpan(@NonNull MarkwonTheme theme) {
|
|
||||||
this.theme = theme;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateDrawState(TextPaint tp) {
|
|
||||||
apply(tp);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateMeasureState(TextPaint tp) {
|
|
||||||
apply(tp);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void apply(TextPaint paint) {
|
|
||||||
theme.applySubScriptStyle(paint);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
package ru.noties.markwon.spans;
|
|
||||||
|
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.text.TextPaint;
|
|
||||||
import android.text.style.MetricAffectingSpan;
|
|
||||||
|
|
||||||
public class SuperScriptSpan extends MetricAffectingSpan {
|
|
||||||
|
|
||||||
private final MarkwonTheme theme;
|
|
||||||
|
|
||||||
public SuperScriptSpan(@NonNull MarkwonTheme theme) {
|
|
||||||
this.theme = theme;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateDrawState(TextPaint tp) {
|
|
||||||
apply(tp);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateMeasureState(TextPaint tp) {
|
|
||||||
apply(tp);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void apply(TextPaint paint) {
|
|
||||||
theme.applySuperScriptStyle(paint);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
package ru.noties.markwon.tasklist;
|
|
||||||
|
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
|
|
||||||
import org.commonmark.parser.Parser;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @since 1.0.1
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class TaskListExtension implements Parser.ParserExtension {
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static TaskListExtension create() {
|
|
||||||
return new TaskListExtension();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void extend(Parser.Builder parserBuilder) {
|
|
||||||
parserBuilder.customBlockParserFactory(new TaskListBlockParser.Factory());
|
|
||||||
}
|
|
||||||
}
|
|
@ -8,11 +8,13 @@ import org.junit.runner.RunWith;
|
|||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
import org.robolectric.annotation.Config;
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
import ru.noties.markwon.renderer.ImageSize.Dimension;
|
import ru.noties.markwon.image.ImageSize;
|
||||||
|
import ru.noties.markwon.image.ImageSize.Dimension;
|
||||||
|
import ru.noties.markwon.image.ImageSizeResolverDef;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static ru.noties.markwon.renderer.ImageSizeResolverDef.UNIT_EM;
|
import static ru.noties.markwon.image.ImageSizeResolverDef.UNIT_EM;
|
||||||
import static ru.noties.markwon.renderer.ImageSizeResolverDef.UNIT_PERCENT;
|
import static ru.noties.markwon.image.ImageSizeResolverDef.UNIT_PERCENT;
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
@Config(manifest = Config.NONE)
|
@Config(manifest = Config.NONE)
|
||||||
|
@ -9,6 +9,7 @@ import ru.noties.markwon.UrlProcessor;
|
|||||||
import ru.noties.markwon.html.api.MarkwonHtmlParser;
|
import ru.noties.markwon.html.api.MarkwonHtmlParser;
|
||||||
import ru.noties.markwon.html.MarkwonHtmlRenderer;
|
import ru.noties.markwon.html.MarkwonHtmlRenderer;
|
||||||
import ru.noties.markwon.image.AsyncDrawable;
|
import ru.noties.markwon.image.AsyncDrawable;
|
||||||
|
import ru.noties.markwon.image.ImageSizeResolver;
|
||||||
import ru.noties.markwon.spans.LinkSpan;
|
import ru.noties.markwon.spans.LinkSpan;
|
||||||
import ru.noties.markwon.spans.MarkwonTheme;
|
import ru.noties.markwon.spans.MarkwonTheme;
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ import java.util.Collections;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import ru.noties.markwon.renderer.ImageSize;
|
import ru.noties.markwon.image.ImageSize;
|
||||||
import ru.noties.markwon.renderer.html2.CssInlineStyleParser;
|
import ru.noties.markwon.renderer.html2.CssInlineStyleParser;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
@ -9,8 +9,8 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import ru.noties.markwon.SpannableFactory;
|
import ru.noties.markwon.SpannableFactory;
|
||||||
import ru.noties.markwon.renderer.ImageSize;
|
import ru.noties.markwon.image.ImageSize;
|
||||||
import ru.noties.markwon.renderer.ImageSizeResolver;
|
import ru.noties.markwon.image.ImageSizeResolver;
|
||||||
import ru.noties.markwon.image.AsyncDrawable;
|
import ru.noties.markwon.image.AsyncDrawable;
|
||||||
import ru.noties.markwon.spans.LinkSpan;
|
import ru.noties.markwon.spans.LinkSpan;
|
||||||
import ru.noties.markwon.spans.MarkwonTheme;
|
import ru.noties.markwon.spans.MarkwonTheme;
|
||||||
|
@ -13,7 +13,7 @@ import ru.noties.markwon.Markwon;
|
|||||||
import ru.noties.markwon.MarkwonConfiguration;
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
import ru.noties.markwon.SpannableBuilder;
|
import ru.noties.markwon.SpannableBuilder;
|
||||||
import ru.noties.markwon.il.AsyncDrawableLoader;
|
import ru.noties.markwon.il.AsyncDrawableLoader;
|
||||||
import ru.noties.markwon.renderer.ImageSize;
|
import ru.noties.markwon.image.ImageSize;
|
||||||
import ru.noties.markwon.renderer.SpannableMarkdownVisitor;
|
import ru.noties.markwon.renderer.SpannableMarkdownVisitor;
|
||||||
|
|
||||||
public class MainActivity extends Activity {
|
public class MainActivity extends Activity {
|
||||||
|
@ -1,3 +1,13 @@
|
|||||||
rootProject.name = 'MarkwonProject'
|
rootProject.name = 'MarkwonProject'
|
||||||
include ':app', ':markwon', ':markwon-view', ':sample-custom-extension', ':sample-latex-math', ':markwon-image-svg', ':markwon-image-gif',
|
include ':app',
|
||||||
':markwon-syntax-highlight', ':markwon-html'
|
':markwon',
|
||||||
|
':markwon-ext-strikethrough',
|
||||||
|
':markwon-ext-tables',
|
||||||
|
':markwon-ext-tasklist',
|
||||||
|
':markwon-image-svg',
|
||||||
|
':markwon-image-gif',
|
||||||
|
':markwon-syntax-highlight',
|
||||||
|
':markwon-html',
|
||||||
|
':markwon-view',
|
||||||
|
':sample-custom-extension',
|
||||||
|
':sample-latex-math'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user