Bring back legacy 2.x.x documentation

This commit is contained in:
Dimitry Ivanov 2019-01-12 15:58:24 +03:00
parent b3c685bfbc
commit 7a598829a9
80 changed files with 1451 additions and 1618 deletions

View File

@ -1,5 +1,4 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply from: '../markwon-bundle.gradle'
android { android {
@ -27,12 +26,6 @@ android {
} }
} }
ext.markwon = [
'version': '3.0.0-SNAPSHOT',
'includeAll': true,
'exclude': ['ext-latex', 'core']
]
dependencies { dependencies {
implementation project(':markwon-core') implementation project(':markwon-core')

View File

@ -0,0 +1,13 @@
<template>
<div class="warning custom-block">
<p class="custom-block-title">WARNING</p>
<p>This is documentation for <u>legacy 2.x.x</u> versions. For the most current version <a :href="$withBase('/')">click here.</a></p>
</div>
</template>
<script>
export default {
name: 'LegacyWarning'
}
</script>

View File

@ -0,0 +1,24 @@
<template>
<a :href="mavenSearchUrl()"><img :src="shieldImgageUrl()" :alt="displayLabel"></a>
</template>
<script>
export default {
name: 'MavenBadge2xx',
props: ['artifact', 'label'],
methods: {
mavenSearchUrl: function() {
return `http://search.maven.org/#search|ga|1|g%3A%22ru.noties%22%20AND%20a%3A%22${this.artifact}%22`;
},
shieldImgageUrl: function() {
return `https://img.shields.io/maven-central/v/ru.noties/${this.artifact}.svg?label=${this.displayLabel}`;
}
},
computed: {
displayLabel() {
return this.label || this.artifact;
}
}
}
</script>

View File

@ -0,0 +1,20 @@
<template>
<div>
<MavenBadge2xx :artifact="'markwon'" />
<MavenBadge2xx :artifact="'markwon-image-loader'" />
<MavenBadge2xx :artifact="'markwon-syntax-highlight'"/>
<MavenBadge2xx :artifact="'markwon-view'"/>
</div>
</template>
<script>
import MavenBadge2xx from "./MavenBadge2xx.vue";
export default {
name: "MavenBadges2xx",
components: {
MavenBadge2xx
}
};
</script>

View File

@ -16,38 +16,31 @@ module.exports = {
{ text: 'Sandbox', link: '/sandbox.md' }, { text: 'Sandbox', link: '/sandbox.md' },
{ text: 'Github', link: 'https://github.com/noties/Markwon' } { text: 'Github', link: 'https://github.com/noties/Markwon' }
], ],
sidebar: [ sidebar: {
'/', '/docs/v2/': [
'install.md',
'getting-started.md',
'configure.md',
'theme.md',
'factory.md',
'image-loader.md',
'syntax-highlight.md',
'html.md',
'view.md'
],
'/': [
'',
{ {
title: 'Core', title: 'Core',
children: [ children: [
'/docs/core/getting-started.md' '/docs/core/getting-started.md',
] '/docs/core/theme.md'
},
{
title: 'LaTeX extension',
children: [
'/docs/ext-latex/latex.md'
]
},
{
title: 'Strikethrough extension',
children: [
'/docs/ext-strikethrough/strikethrough.md'
]
},
{
title: 'Tables extension',
children: [
'/docs/ext-tables/tables.md'
]
},
{
title: 'Task list extension',
children: [
'/docs/ext-tasklist/tasklist.md'
] ]
}, },
'/docs/ext-latex/latex.md',
'/docs/ext-strikethrough/strikethrough.md',
'/docs/ext-tables/tables.md',
'/docs/ext-tasklist/tasklist.md',
{ {
title: 'HTML', title: 'HTML',
children: [ children: [
@ -62,21 +55,12 @@ module.exports = {
'/docs/image/svg.md' '/docs/image/svg.md'
] ]
}, },
{ '/docs/recycler/recycler.md',
title: 'Recycler', '/docs/syntax-highlight/syntax-highlight.md',
children: [ '/docs/migration-2-3.md',
'/docs/recycler/recycler.md' ['/docs/v2/install.md', 'Legacy 2.x.x documentation']
] ]
}, },
{
title: 'Syntax highlight',
children: [
'/docs/syntax-highlight/syntax-highlight.md'
]
},
'/docs/migration-2-3.md'
],
sidebarDepth: 2, sidebarDepth: 2,
lastUpdated: true lastUpdated: true
}, },

158
docs/docs/core/theme.md Normal file
View File

@ -0,0 +1,158 @@
# Theme
Here is the list of properties that can be configured via `MarkwonTheme.Builder` class.
## Link color
Controls the color of a [link](#)
<ThemeProperty name="linkColor" type="@ColorInt int" defaults="Default link color of a context where markdown is displayed <sup>*</sup>" />
<sup>*</sup> `TextPaint#linkColor` will be used to determine linkColor of a context
## Block margin
Starting margin before text content for the:
* lists
* blockquotes
* task lists
<ThemeProperty name="blockMargin" type="@Px int" defaults="24dp" />
## Block quote
Customizations for the `blockquote` stripe
> Quote
### Stripe width
Width of a blockquote stripe
<ThemeProperty name="blockQuoteWidth" type="@Px int" defaults="1/4 of the <a href='#block-margin'>block margin</a>" />
### Stripe color
Color of a blockquote stripe
<ThemeProperty name="blockQuoteColor" type="@ColorInt int" defaults="textColor with <code>25</code> (0-255) alpha value" />
## List
### List item color
Controls the color of a list item. For ordered list: leading number,
for unordered list: bullet.
* UL
1. OL
<ThemeProperty name="listItemColor" type="@ColorInt int" defaults="Text color" />
### Bullet item stroke width
Border width of a bullet list item (level 2)
* First
* * Second
* * * Third
<ThemeProperty name="bulletListItemStrokeWidth" type="@Px int" defaults="Stroke width of TextPaint" />
### Bullet width
The width of the bullet item
* First
* Second
* Third
<ThemeProperty name="bulletWidth" type="@Px int" defaults="min(<a href='#block-margin'>blockMargin</a>, lineHeight) / 2" />
## Code
### Inline code text color
The color of the `code` content
<ThemeProperty name="codeTextColor" type="@ColorInt int" defaults="Content text color" />
### Inline code background color
The color of `background` of a code content
<ThemeProperty name="codeBackgroundColor" type="@ColorInt int" defaults="<a href='#inline-code-text-color'>inline code text color</a> with 25 (0-255) alpha" />
### Block code text color
```
The color of code block text
```
<ThemeProperty name="codeBlockTextColor" type="@ColorInt int" defaults="<a href='#inline-code-text-color'>inline code text color</a>" />
### Block code background color
```
The color of background of code block text
```
<ThemeProperty name="codeBlockBackgroundColor" type="@ColorInt int" defaults="<a href='#inline-code-background-color'>inline code background color</a>" />
### Block code leading margin
Leading margin for the block code content
<ThemeProperty name="codeMultilineMargin" type="@Px int" defaults="Width of the space character" />
### Code typeface
Typeface of code content
<ThemeProperty name="codeTypeface" type="android.graphics.Typeface" defaults="Typeface.MONOSPACE" />
### Code text size
Text size of code content
<ThemeProperty name="codeTextSize" type="@Px int" defaults="(Content text size) * 0.87 if no custom <a href='#code-typeface'>Typeface</a> was set, otherwise (content text size)" />
## Heading
### Break height
The height of a brake under H1 &amp; H2
<ThemeProperty name="headingBreakHeight" type="@Px int" defaults="Stroke width of context TextPaint" />
### Break color
The color of a brake under H1 &amp; H2
<ThemeProperty name="headingBreakColor" type="@ColorInt int" defaults="(text color) with 75 (0-255) alpha" />
### Typeface <Badge text="1.1.0" />
The typeface of heading elements
<ThemeProperty name="headingTypeface" type="android.graphics.Typeface" defaults="default text Typeface" />
### Text size <Badge text="1.1.0" />
Array of heading text sizes _ratio_ that is applied to text size
<ThemeProperty name="headingTextSizeMultipliers" type="float[]" defaults="<code>{2.F, 1.5F, 1.17F, 1.F, .83F, .67F}</code> (HTML spec)" />
## Thematic break
### Color
Color of a thematic break
<ThemeProperty name="thematicBreakColor" type="@ColorInt int" defaults="(text color) with 25 (0-255) alpha" />
### Height
Height of a thematic break
<ThemeProperty name="thematicBreakHeight" type="@Px int" defaults="Stroke width of context TextPaint" />

View File

@ -1,7 +1,46 @@
---
title: 'Overview'
---
# LaTeX extension # LaTeX extension
<MavenBadge :artifact="'ext-latex'" /> <MavenBadge :artifact="'ext-latex'" />
This is an extension that will help you display LaTeX formulas in your markdown.
Syntax is pretty simple: pre-fix and post-fix your latex with `$$` (double dollar sign).
`$$` should be the first characters in a line.
```markdown
$$
\\text{A long division \\longdiv{12345}{13}
$$
```
```markdown
$$\\text{A long division \\longdiv{12345}{13}$$
```
```java
Markwon.builder(context)
.use(ImagesPlugin.create(context))
.use(JLatexMathPlugin.create(new Config(textSize))
.build();
```
This extension uses [jlatexmath-android](https://github.com/noties/jlatexmath-android) artifact to create LaTeX drawable. Then it
registers special `latex` image scheme handler and uses `AsyncDrawableLoader` to display
final result
## Config
```java
public static class Config {
protected final float textSize;
protected Drawable background;
@JLatexMathDrawable.Align
protected int align = JLatexMathDrawable.ALIGN_CENTER;
protected boolean fitCanvas = true;
protected int padding;
}
```

View File

@ -1,7 +1,29 @@
---
title: 'Overview'
---
# Strikethrough extension # Strikethrough extension
<MavenBadge :artifact="'ext-strikethrough'" /> <MavenBadge :artifact="'ext-strikethrough'" />
This module adds `strikethrough` functionality to `Markwon` via `StrikethroughPlugin`:
```java
Markwon.builder(context)
.usePlugin(StrikethroughPlugin.create())
```
This plugin registers `SpanFactory` for `Strikethrough` node, so it's possible to customize Strikethrough Span that is used in rendering:
```java
Markwon.builder(context)
.usePlugin(StrikethroughPlugin.create())
.usePlugin(new AbstractMarkwonPlugin() {
@Override
public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) {
builder.setFactory(Strikethrough.class, new SpanFactory() {
@Override
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) {
// will use Underline span instead of Strikethrough
return new UnderlineSpan();
}
});
}
})
```

View File

@ -1,7 +1,83 @@
---
title: 'Overview'
---
# Tables extension # Tables extension
<MavenBadge :artifact="'ext-tables'" /> <MavenBadge :artifact="'ext-tables'" />
This extension adds support for GFM tables.
```java
final Markwon markwon = Markwon.builder(context)
// create default instance of TablePlugin
.usePlugin(TablePlugin.create(context))
```
```java
final TableTheme tableTheme = TableTheme.builder()
.tableBorderColor(Color.RED)
.tableBorderWidth(0)
.tableCellPadding(0)
.tableHeaderRowBackgroundColor(Color.BLACK)
.tableEvenRowBackgroundColor(Color.GREEN)
.tableOddRowBackgroundColor(Color.YELLOW)
.build();
final Markwon markwon = Markwon.builder(context)
.usePlugin(TablePlugin.create(tableTheme))
```
Please note, that _by default_ tables have limitations. For example, there is no support
for images inside table cells. And table contents won't be copied to clipboard if a TextView
has such functionality. Table will always take full width of a TextView in which it is displayed.
All columns will always be the of the same width. So, _default_ implementation provides basic
functionality which can answer some needs. These all come from the limited nature of the TextView
to display such content.
In order to provide full-fledged experience, tables must be displayed in a special widget.
Since version `3.0.0` Markwon provides a special artifact `markwon-recycler` that allows
to render markdown in a set of widgets in a RecyclerView. It also gives ability to change
display widget form TextView to any other.
```java
final Table table = Table.parse(Markwon, TableBlock);
myTableWidget.setTable(table);
```
Unfortunately Markwon does not provide a widget that can be used for tables. But it does
provide API that can be used to achieve desired result.
## Theme
### Cell padding
Padding inside a table cell
<ThemeProperty name="tableCellPadding" type="@Px int" defaults="0" />
### Border color
The color of table borders
<ThemeProperty name="tableBorderColor" type="@ColorInt int" defaults="(text color) with 75 (0-255) alpha" />
### Border width
The width of table borders
<ThemeProperty name="tableBorderWidth" type="@Px int" defaults="Stroke with of context TextPaint" />
### Odd row background
Background of an odd table row
<ThemeProperty name="tableOddRowBackgroundColor" type="@ColorInt int" defaults="(text color) with 22 (0-255) alpha" />
### Even row background <Badge text="1.1.1" />
Background of an even table row
<ThemeProperty name="tableEventRowBackgroundColor" type="@ColorInt int" defaults="0" />
### Header row background <Badge text="1.1.1" />
Background of header table row
<ThemeProperty name="tableHeaderRowBackgroundColor" type="@ColorInt int" defaults="0" />

View File

@ -1,7 +1,3 @@
---
title: 'Overview'
---
# Task list extension # Task list extension
<MavenBadge :artifact="'ext-tasklist'" /> <MavenBadge :artifact="'ext-tasklist'" />

View File

@ -1 +1 @@
# Migration v2 -> v3 # Migration 2.x.x -> 3.x.x

View File

@ -1,7 +1,3 @@
---
title: 'Overview'
---
# Recycler # Recycler
<MavenBadge :artifact="'recycler'" /> <MavenBadge :artifact="'recycler'" />

View File

@ -1,7 +1,69 @@
---
title: 'Overview'
---
# Syntax highlight # Syntax highlight
<MavenBadge :artifact="'syntax-highlight'" /> <MavenBadge :artifact="'syntax-highlight'" />
This is a simple module to add **syntax highlight** functionality to your markdown rendered with `Markwon` library. It is based on [Prism4j](https://github.com/noties/Prism4j) so lead there to understand how to configure `Prism4j` instance.
<img :src="$withBase('/art/markwon-syntax-default.png')" alt="theme-default" width="80%">
<img :src="$withBase('/art/markwon-syntax-darkula.png')" alt="theme-darkula" width="80%">
---
First, we need to obtain an instance of `Prism4jSyntaxHighlight` which implements Markwon's `SyntaxHighlight`:
```java
final SyntaxHighlight highlight =
Prism4jSyntaxHighlight.create(Prism4j, Prism4jTheme);
```
we also can obtain an instance of `Prism4jSyntaxHighlight` that has a _fallback_ option (if a language is not defined in `Prism4j` instance, fallback language can be used):
```java
final SyntaxHighlight highlight =
Prism4jSyntaxHighlight.create(Prism4j, Prism4jTheme, String);
```
Generally obtaining a `Prism4j` instance is pretty easy:
```java
final Prism4j prism4j = new Prism4j(new GrammarLocatorDef());
```
Where `GrammarLocatorDef` is a generated grammar locator (if you use `prism4j-bundler` annotation processor)
`Prism4jTheme` is a specific type that is defined in this module (`prism4j` doesn't know anything about rendering). It has 2 implementations:
* `Prism4jThemeDefault`
* `Prism4jThemeDarkula`
Both of them can be obtained via factory method `create`:
* `Prism4jThemeDefault.create()`
* `Prism4jThemeDarkula.create()`
But of cause nothing is stopping you from defining your own theme:
```java
public interface Prism4jTheme {
@ColorInt
int background();
@ColorInt
int textColor();
void apply(
@NonNull String language,
@NonNull Prism4j.Syntax syntax,
@NonNull SpannableStringBuilder builder,
int start,
int end
);
}
```
:::tip
You can extend `Prism4jThemeBase` which has some helper methods
:::

228
docs/docs/v2/configure.md Normal file
View File

@ -0,0 +1,228 @@
<LegacyWarning />
# Configuration
`SpannableConfiguration` is the core component that controls how markdown is parsed and rendered.
It can be obtained via factory methods:
```java
// creates default implementation
final SpannableConfiguration configuration = SpannableConfiguration.create(context);
```
```java
// creates configurablable instance via `#builder` method
final SpannableConfiguration configuration = SpannableConfiguration.builder(context)
.asyncDrawableLoader(AsyncDrawableLoader.create())
.build();
```
:::tip Note
If `#builder` factory method is used, you do not need to specify default
values as they will be applied automatically
:::
:::warning Images
If you plan on using images inside your markdown/HTML, you will have to **explicitly**
register an implementation of `AsyncDrawable.Loader` via `#asyncDrawableLoader` builder method.
`Markwon` comes with ready implementation for that and it can be found in
`markwon-image-loader` module. Refer to module [documentation](/docs/v2/image-loader.md)
:::
## Theme
`SpannableTheme` controls how markdown is rendered. It has pretty extensive number of
options that can be found [here](/docs/v2/theme.md)
```java
SpannableConfiguration.builder(context)
.theme(SpannableTheme)
.build();
```
If `SpannableTheme` is not provided explicitly, `SpannableTheme.create(context)` will be used
## Images
### Async loader
`AsyncDrawable.Loader` handles images in your markdown and HTML
```java
SpannableConfiguration.builder(context)
.asyncDrawableLoader(AsyncDrawable.Loader)
.build();
```
If `AsyncDrawable.Loader` is not provided explicitly, default **no-op** implementation will be used.
:::tip Implementation
There are no restrictions on what implementation to use, but `Markwon` has artifact that can
answer the most common needs of displaying SVG, GIF and other image formats. It can be found [here](/docs/v2/image-loader.md)
:::
### Size resolver <Badge text="1.0.1" />
`ImageSizeResolver` controls the size of an image to be displayed. Currently it
handles only HTML images (specified via `img` tag).
```java
SpannableConfiguration.builder(context)
.imageSizeResolver(ImageSizeResolver)
.build();
```
If not provided explicitly, default `ImageSizeResolverDef` implementation will be used.
It handles 3 dimention units:
* `%` (percent)
* `em` (relative to text size)
* `px` (absolute size, every dimention that is not `%` or `em` is considered to be _absolute_)
```html
<img width="100%">
<img width="2em" height="10px">
<img style="{width: 100%; height: 8em;}">
```
`ImageSizeResolverDef` keeps the ratio of original image if one of the dimentions is missing.
:::warning Height%
There is no support for `%` units for `height` dimention. This is due to the fact that
height of an TextView in which markdown is displayed is non-stable and changes with time
(for example when image is loaded and applied to a TextView it will _increase_ TextView's height),
so we will have no point-of-refence from which to _calculate_ image height.
:::
## Syntax highlight
`SyntaxHighlight` controls the syntax highlight for code blocks (in markdown).
```java
SpannableConfiguration.builder(context)
.syntaxHighlight(SyntaxHighlight)
.build();
```
If not provided explicitly, default **no-op** implementation will be used.
:::tip Syntax highlight
Although `SyntaxHighlight` interface was included with the very first version
of `Markwon` there were no ready-to-use implementations. But starting with <Badge text="1.1.0" />
`Markwon` provides one. It can be found in `markwon-syntax-highlight` artifact. Refer
to module [documentation](/docs/v2/syntax-highlight.md)
:::
## Link resolver
`LinkSpan.Resolver` is triggered when a link is clicked in markdown/HTML.
```java
SpannableConfiguration.builder(context)
.linkResolver(LinkSpan.Resolver)
.build();
```
If not provided explicitly, default `LinkResolverDef` implementation will be used.
Underneath it constructs an `Intent` and _tries_ to start an Activity associated with it.
It no Activity is found, it will silently fail (no runtime exceptions)
## URL processor
`UrlProcessor` is used to process found URLs in markdown/HTML.
```java
SpannableConfiguration.builder(context)
.urlProcessor(UrlProcessor)
.build();
```
If not provided explicitly, default **no-op** implementation will be used.
`Markwon` provides 2 implementations of `UrlProcessor`:
* `UrlProcessorRelativeToAbsolute`
* `UrlProcessorAndroidAssets`
### UrlProcessorRelativeToAbsolute
`UrlProcessorRelativeToAbsolute` can be used to make relative URL absolute. For example if an image is
defined like this: `![img](./art/image.JPG)` and `UrlProcessorRelativeToAbsolute`
is created with `https://github.com/noties/Markwon/raw/master/` as the base:
`new UrlProcessorRelativeToAbsolute("https://github.com/noties/Markwon/raw/master/")`,
then final image will have `https://github.com/noties/Markwon/raw/master/art/image.JPG`
as the destination.
### UrlProcessorAndroidAssets
`UrlProcessorAndroidAssets` can be used to make processed links to point to Android assets folder.
So an image: `![img](./art/image.JPG)` will have `file:///android_asset/art/image.JPG` as the
destination
## Factory <Badge text="1.1.0" />
`SpannableFactory` is used to control _what_ span implementations to be used
```java
SpannableConfiguration.builder(context)
.factory(SpannableFactory)
.build();
```
If not provided explicitly, default `SpannableFactoryDef` implementation will be used. It is documented
in [this section](/docs/v2/factory.md)
## Soft line break <Badge text="1.1.1" />
`softBreakAddsNewLine` option controls how _soft breaks_ are treated in the final result.
If `true` -> soft break will add a new line, else it will add a ` ` (space) char.
```java
SpannableConfiguration.builder(context)
.softBreakAddsNewLine(boolean)
.build();
```
If not provided explicitly, default `false` value will be used.
<Link name="commonmark-spec#soft-break" displayName="Commonmark specification" />
## HTML <Badge text="2.0.0" />
### Parser
`MarkwonHtmlParser` is used to parse HTML content
```java
SpannableConfiguration.builder(context)
.htmlParser(MarkwonHtmlParser)
.build();
```
if not provided explicitly, default `MarkwonHtmlParserImpl` will be used
**if** it can be found in classpath, otherwise default **no-op** implementation
wiil be used. Refer to [HTML](/docs/v2/html.md#parser) document for more information about this behavior.
### Renderer
`MarkwonHtmlRenderer` controls how parsed HTML content will be rendered.
```java
SpannableConfiguration.builder(context)
.htmlRenderer(MarkwonHtmlRenderer)
.build();
```
If not provided explicitly, default `MarkwonHtmlRenderer` implementation will be used.
It is documented [here](/docs/v2/html.md#renderer)
### HTML allow non-closed tags
`htmlAllowNonClosedTags` option is used to control whether or not to
render non-closed HTML tags
```java
SpannableConfiguration.builder(context)
.htmlAllowNonClosedTags(boolean)
.build();
```
If not provided explicitly, default value `false` will be used (non-closed tags **won't** be rendered).

63
docs/docs/v2/factory.md Normal file
View File

@ -0,0 +1,63 @@
<LegacyWarning />
# Factory <Badge text="1.1.0" />
`SpannableFactory` is used to create Span implementations.
```java
SpannableConfiguration.builder(context)
.factory(SpannableFactory)
.build();
```
`Markwon` provides default `SpannableFactoryDef` implementation that is
used by default.
Spans:
* `strongEmphasis`
* `emphasis`
* `blockQuote`
* `code`
* `orderedListItem`
* `bulletListItem`
* `thematicBreak`
* `heading`
* `strikethrough`
* `taskListItem`
* `tableRow`
* `paragraph` <Badge text="1.1.1" />
* `image`
* `link`
* `superScript` (HTML content only)
* `subScript` (HTML content only)
* `underline` (HTML content only)
:::tip
`SpannableFactory` can be used to ignore some kinds of text markup. If, for example,
you do not wish to apply _emphasis_ styling to your final result, just return `null`
from `emphasis` factory method:
```java
@Nullable
@Override
public Object emphasis() {
return null;
}
```
:::
:::tip
All factory methods in `SpannableFactory` return an `Object`, but you can actually
return an **array of Objects** if you wish to apply multiple Spans to a single styling node.
For example, let's make all _emphasis_ also <span :style="{color: '#F00'}">red</span>:
```java
@Nullable
@Override
public Object emphasis() {
return new Object[] {
super.emphasis(),
new ForegroundColorSpan(Color.RED)
};
}
```
:::

View File

@ -0,0 +1,102 @@
<LegacyWarning />
# Getting started
:::tip Installation
Please follow [installation](/docs/install.md) instructions
to learn how to add `Markwon` to your project
:::
## Quick one
This is the most simple way to set markdown to a `TextView` or any of its siblings:
```java
Markwon.setMarkdown(textView, "**Hello there!**");
```
The most simple way to obtain markdown to be applied _somewhere_ else:
```java
// parsed and styled markdown
final CharSequence markdown = Markwon.markdown(context, "**Hello there!**");
// use it
Toast.makeText(context, markdown, Toast.LENGTH_LONG).show();
```
## Longer one
When you need to customize markdown parsing/rendering you can use [SpannableConfiguration](/docs/configure.md):
```java
final SpannableConfiguration configuration = SpannableConfiguration.builder(context)
.asyncDrawableLoader(AsyncDrawableLoader.create())
.build();
Markwon.setMarkdown(textView, configuration, "Are **you** still there?");
final CharSequence markdown = Markwon.markdown(configuration, "Are **you** still there?");
Toast.makeText(context, markdown, Toast.LENGTH_LONG).show();
```
## No magic one
In order to understand how previous examples work, let's break them down:
* construct a `Parser` (see: <Link name="commonmark-java" />) and parse markdown
* construct a `SpannableConfiguration` (if it's not provided)
* *render* parsed markdown to Spannable (via `SpannableRenderer`)
* prepares TextView to display images, tables and links
* sets text
This flow answers the most simple usage of displaying markdown: one shot parsing
&amp; configuration of relatively small markdown chunks. If your markdown contains
a lot of text or you plan to display multiple UI widgets with markdown you might
consider *stepping in* and taking control of this flow.
The candidate requirements to *step in*:
* parsing and processing of parsed markdown in a background thread
* reusing `Parser` and/or `SpannableConfiguration` between multiple calls
* ignore images or tables specific logic (you know that markdown won't contain them)
So, if we expand `Markwon.setMarkdown(textView, markdown)` method we will see the following:
```java
// create a Parser instance (can be done manually)
// internally creates default Parser instance & registers `strike-through` & `tables` extension
final Parser parser = Markwon.createParser();
// core class to display markdown, can be obtained via this method,
// which creates default instance (no images handling though),
// or via `builder` method, which lets you to configure this instance
final SpannableConfiguration configuration = SpannableConfiguration.create(context);
final SpannableRenderer renderer = new SpannableRenderer();
final Node node = parser.parse(markdown);
final CharSequence text = renderer.render(configuration, node);
// for links in markdown to be clickable
textView.setMovementMethod(LinkMovementMethod.getInstance());
// we need these due to the limited nature of Spannables to invalidate TextView
Markwon.unscheduleDrawables(textView);
Markwon.unscheduleTableRows(textView);
// @since 2.0.1 we must measure ordered list items _before_ they are rendered
OrderedListItemSpan.measure(view, text);
textView.setText(text);
Markwon.scheduleDrawables(textView);
Markwon.scheduleTableRows(textView);
```
:::tip Note
If you are having trouble with `LinkMovementMethod` you can use
`Markwon.setText(textView, markdown, movementMethod)` method <Badge text="1.0.6" /> to specify _no_ movement
method (aka `null`) or own implementation. As an alternative to the system `LinkMovementMethod`
you can use [Better-Link-Movement-Method](https://github.com/saket/Better-Link-Movement-Method).
Please note that `Markwon.setText` method expects _parsed_ markdown as the second argument.
:::

305
docs/docs/v2/html.md Normal file
View File

@ -0,0 +1,305 @@
<LegacyWarning />
# HTML <Badge text="2.0.0" />
Starting with version `2.0.0` `Markwon` brings the whole HTML parsing/rendering
stack _on-site_. The main reason for this are _special_ definitions of HTML nodes
by <Link name="commonmark-spec" />. More specifically: <Link name="commonmark-spec#inline" displayName="inline" />
and <Link name="commonmark-spec#block" displayName="block" />.
These two are _a bit_ different from _native_ HTML understanding.
Well, they are _completely_ different and share only the same names as
<Link name="html-inlines" displayName="HTML-inline"/> and <Link name="html-blocks" displayName="HTML-block"/>
elements. This leads to situations when for example an `<i>` tag is considered
a block when it's used like this:
```markdown
<i>
Hello from italics tag
</i>
```
:::tip A bit of background
<br>
<GithubIssue id="52" displayName="This issue" /> had brought attention to differences between HTML &amp; commonmark implementations. <br><br>
:::
Let's modify code snippet above _a bit_:
```markdown{3}
<i>
Hello from italics tag
</i>
```
We have just added a `new-line` before closing `</i>` tag. And this
changes everything as now, according to the <Link name="commonmark-dingus" />,
we have 2 HtmlBlocks: one before `new-line` (containing open `<i>` tag and text content)
and one after (containing as little as closing `</i>` tag).
If we modify code snippet _a bit_ again:
```markdown{4}
<i>
Hello from italics tag
</i><b>bold></b>
```
We will have 1 HtmlBlock (from previous snippet) and a bunch of HtmlInlines:
* HtmlInline (`<i>`)
* HtmlInline (`<b>`)
* Text (`bold`)
* HtmlInline (`</b>`)
Those _little_ differences render `Html.fromHtml` (which was used in `1.x.x` versions)
useless. And actually it renders most of the HTML parsers implementations useless,
as most of them do not allow processing of HTML fragments in a raw fashion
without _fixing_ content on-the-fly.
Both `TagSoup` and `Jsoup` HTML parsers (that were considered for this project) are built to deal with
_malicious_ HTML code (*all HTML code*? :no_mouth:). So, when supplied
with a `<i>italic` fragment they will make it `<i>italic</i>`.
And it's a good thing, but consider these fragments for the sake of markdown:
* `<i>italic `
* `<b>bold italic`
* `</b><i>`
We will get:
* `<i>italic </i>`
* `<b>bold italic</b>`
_<sup>*</sup> Or to be precise: `<html><head></head><body><i>italic </i></body></html>` &amp;
`<html><head></head><body><b>bold italic</b></body></html>`_
Which will be rendered in a final document:
|expected|actual|
|---|---|
|<i>italic <b>bold italic</b></i>|<i>italic </i><b>bold italic</b>|
This might seem like a minor problem, but add more tags to a document,
introduce some deeply nested structures, spice openning and closing tags up
by adding markdown markup between them and finally write _malicious_ HTML code :laughing:!
There is no such problem on the _frontend_ for which commonmark specification is mostly
aimed as _frontend_ runs in a web-browser environment. After all _parsed_ markdown
will become HTML tags (most common usage). And web-browser will know how to render final result.
We, on the other hand, do not posess HTML heritage (*thank :robot:!*), but still
want to display some HTML to style resulting markdown a bit. That's why `Markwon`
incorporated own HTML parsing logic. It is based on the <Link name="jsoup" /> project.
And makes usage of the `Tokekiser` class that allows to _tokenise_ input HTML.
All other code that doesn't follow this purpose was removed. It's safe to use
in projects that already have `jsoup` dependency as `Markwon` repackaged **jsoup** source classes
(which could be found <Link name="markwon-jsoup" displayName="here"/>)
## Parser
There are no additional steps to configure HTML parsing. It's enabled by default.
If you wish to _exclude_ it, please follow the [exclude](#exclude-html-parsing) section below.
The key class here is: `MarkwonHtmlParser` that is defined in `markwon-html-parser-api` module.
`markwon-html-parser-api` is a simple module that defines HTML parsing contract and
does not provide implementation.
To change what implementation `Markwon` should use, `SpannableConfiguration` can be used:
```java{2}
SpannableConfiguration.builder(context)
.htmlParser(MarkwonHtmlParser)
.build();
```
`markwon-html-parser-impl` on the other hand provides `MarkwonHtmlParser` implementation.
It's called `MarkwonHtmlParserImpl`. It can be created like this:
```java
final MarkwonHtmlParser htmlParser = MarkwonHtmlParserImpl.create();
// or
final MarkwonHtmlParser htmlParser = MarkwonHtmlParserImpl.create(HtmlEmptyTagReplacement);
```
### Empty tag replacement
In order to append text content for self-closing, void or just _empty_ HTML tags,
`HtmlEmptyTagReplacement` can be used. As we cannot set Span for empty content,
we must represent empty tag with text during parsing stage (if we want it to be represented).
Consider this:
* `<img src="me-sad.JPG">`
* `<br />`
* `<who-am-i></who-am-i>`
By default (`HtmlEmptyTagReplacement.create()`) will handle `img` and `br` tags.
`img` will be replaced with `alt` property if it is present and `\uFFFC` if it is not.
And `br` will insert a new line.
### Non-closed tags
It's possible that your HTML can contain non-closed tags. By default `Markwon` will ignore them,
but if you wish to get a bit closer to a web-browser experience, you can allow this behaviour:
```java{2}
SpannableConfiguration.builder(context)
.htmlAllowNonClosedTags(true)
.build();
```
:::warning Note
If there is (for example) an `<i>` tag at the start of a document and it's not closed
and `Markwon` is configured to **not** ignore non-closed tags (`.htmlAllowNonClosedTags(true)`),
it will make the whole document in italics
:::
### Implementation note
`MarkwonHtmlParserImpl` does not create a unified HTML node. Instead it creates
2 collections: inline tags and block tags. Inline tags are represented as a `List`
of inline tags (<Link name="html-inlines" displayName="reference" />). And
block tags are structured in a tree. This helps to achieve _browser_-like behaviour,
when open inline tag is applied to all content (even if inside blocks) until closing tag.
All tags that are not _inline_ are considered to be _block_ ones.
## Renderer
Unlike `MarkwonHtmlParser` `Markwon` comes with a `MarkwonHtmlRenderer` by default.
Default implementation can be obtain like this:
```java
MarkwonHtmlRenderer.create();
```
Default instance have these tags _handled_:
* emphasis
* `i`
* `em`
* `cite`
* `dfn`
* strong emphasis
* `b`
* `strong`
* `sup` (super script)
* `sub` (sub script)
* underline
* `u`
* `ins`
* strike through
* `del`
* `s`
* `strike`
* `a` (link)
* `ul` (unordered list)
* `ol` (ordered list)
* `img` (image)
* `blockquote` (block quote)
* `h{1-6}` (heading)
If you wish to _extend_ default handling (or override existing),
`#builderWithDefaults` factory method can be used:
```java
MarkwonHtmlRenderer.builderWithDefaults();
```
For a completely _clean_ configurable instance `#builder` method can be used:
```java
MarkwonHtmlRenderer.builder();
```
### Custom tag handler
To configure `MarkwonHtmlRenderer` to handle tags differently or
create a new tag handler - `TagHandler` can be used
```java
public abstract class TagHandler {
public abstract void handle(
@NonNull SpannableConfiguration configuration,
@NonNull SpannableBuilder builder,
@NonNull HtmlTag tag
);
}
```
For the most simple _inline_ tag handler a `SimpleTagHandler` can be used:
```java
public abstract class SimpleTagHandler extends TagHandler {
@Nullable
public abstract Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag);
}
```
For example, `EmphasisHandler`:
```java
public class EmphasisHandler extends SimpleTagHandler {
@Nullable
@Override
public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) {
return configuration.factory().emphasis();
}
}
```
If you wish to handle a _block_ HTML node (for example `<ul><li>First<li>Second</ul>`) refer
to `ListHandler` source code for reference.
:::warning
The most important thing when implementing custom `TagHandler` is to know
what type of `HtmlTag` we are dealing with. There are 2: inline &amp; block.
Inline tag cannot contain children. Block _can_ contain children. And they
_most likely_ should also be visited and _handled_ by registered `TagHandler` (if any)
accordingly. See `TagHandler#visitChildren(configuration, builder, child);`
:::
#### Css inline style parser
When implementing own `TagHandler` you might want to inspect inline CSS styles
of a HTML element. `Markwon` provides an utility parser for that purpose:
```java
final CssInlineStyleParser inlineStyleParser = CssInlineStyleParser.create();
for (CssProperty property: inlineStyleParser.parse("width: 100%; height: 100%;")) {
// [0] = CssProperty({width=100%}),
// [1] = CssProperty({height=100%})
}
```
## Exclude HTML parsing
If you wish to exclude HTML parsing altogether, you can manually
exclude `markwon-html-parser-impl` artifact from your projects compile classpath.
This can be beneficial if you know that markdown input won't contain
HTML and/or you wish to ignore it. Excluding HTML parsing
can speed up `Markwon` parsing and will decrease final size of
`Markwon` dependency by around `100kb`.
<MavenBadge :artifact="'markwon'" />
```groovy
dependencies {
implementation("ru.noties:markwon:${markwonVersion}") {
exclude module: 'markwon-html-parser-impl'
}
}
```
Excluding `markwon-html-parser-impl` this way will result in
`MarkwonHtmlParser#noOp` implementation. No further steps are
required.
:::warning Note
Excluding `markwon-html-parser-impl` won't remove *all* the content between
HTML tags. It will if `commonmark` decides that a specific fragment is a
`HtmlBlock`, but it won't if fragment is considered a `HtmlInline` as `HtmlInline`
does not contain content (just a tag definition).
:::

View File

@ -1,3 +1,5 @@
<LegacyWarning />
# Images # Images
By default `Markwon` doesn't handle images. Although `AsyncDrawable.Loader` is By default `Markwon` doesn't handle images. Although `AsyncDrawable.Loader` is
@ -16,12 +18,12 @@ public interface Loader {
## AsyncDrawableLoader ## AsyncDrawableLoader
<MavenBadge artifact="markwon-image-loader" /> <MavenBadge2xx artifact="markwon-image-loader" />
`AsyncDrawableLoader` from `markwon-image-loader` artifact can be used. `AsyncDrawableLoader` from `markwon-image-loader` artifact can be used.
:::tip Install :::tip Install
[Learn how to add](/docs/install.md#image-loader) `markwon-image-loader` to your project [Learn how to add](/docs/v2/install.md#image-loader) `markwon-image-loader` to your project
::: :::
Default instance of `AsyncDrawableLoader` can be obtain like this: Default instance of `AsyncDrawableLoader` can be obtain like this:

79
docs/docs/v2/install.md Normal file
View File

@ -0,0 +1,79 @@
<LegacyWarning />
# Installation
<MavenBadges2xx />
In order to start using `Markwon` add this to your dependencies block
in your projects `build.gradle`:
```groovy
implementation "ru.noties:markwon:${markwonVersion}"
```
This is core artifact that is sufficient to start displaying markdown in your Android applications.
`Markwon` comes with more artifacts that cover additional functionality, but they are
**not** required to be used, as most of them provide implementations for functionality
that is _interfaced_ in the core artifact
```groovy
implementation "ru.noties:markwon-image-loader:${markwonVersion}"
implementation "ru.noties:markwon-syntax-highlight:${markwonVersion}"
implementation "ru.noties:markwon-view:${markwonVersion}"
```
These artifacts share the same _version_ as the core artifact
### Image loader
```groovy
implementation "ru.noties:markwon-image-loader:${markwonVersion}"
```
Provides implementation of `AsyncDrawable.Loader` and comes with support for:
* SVG
* GIF
* Other image formats
Please refer to documentation for [image loader](/docs/v2/image-loader.md) module
### Syntax highlight
```groovy
implementation "ru.noties:markwon-syntax-highlight:${markwonVersion}"
```
Provides implementation of `SyntaxHighlight` and allows various syntax highlighting
in your markdown based Android applications. Comes with 2 ready-to-be-used themes: `light` and `dark`.
Please refer to documentation for [syntax highlight](/docs/v2/syntax-highlight.md) module
### View
```groovy
implementation "ru.noties:markwon-view:${markwonVersion}"
```
Provides 2 widgets to display markdown: `MarkwonView` and `MarkwonViewCompat` (subclasses
of `TextView` and `AppCompatTextView` respectively).
Please refer to documentation for [view](/docs/v2/view.md) module
## Proguard
When using `markwon-image-loader` artifact and Proguard is enabled, add these rules
to your proguard configuration:
```proguard
-dontwarn okhttp3.**
-dontwarn okio.**
-keep class com.caverock.androidsvg.** { *; }
-dontwarn com.caverock.androidsvg.**
```
They come from dependencies that `markwon-image-loader` is using.
:::tip Other artifacts
Other artifacts do not require special Proguard rules
:::

View File

@ -1,6 +1,8 @@
<LegacyWarning />
# Syntax highlight # Syntax highlight
<MavenBadge artifact="markwon-syntax-highlight" /> <MavenBadge2xx artifact="markwon-syntax-highlight" />
This is a simple module to add **syntax highlight** functionality to your markdown rendered with `Markwon` library. It is based on [Prism4j](https://github.com/noties/Prism4j) so lead there to understand how to configure `Prism4j` instance. This is a simple module to add **syntax highlight** functionality to your markdown rendered with `Markwon` library. It is based on [Prism4j](https://github.com/noties/Prism4j) so lead there to understand how to configure `Prism4j` instance.

View File

@ -1,3 +1,5 @@
<LegacyWarning />
# Theme # Theme
Here is the list of properties that can be configured via `SpannableTheme#builder` factory Here is the list of properties that can be configured via `SpannableTheme#builder` factory
@ -209,4 +211,4 @@ Background of header table row
Drawable of task list item Drawable of task list item
<ThemeProperty name="taskListDrawable" type="android.graphics.drawable.Drawable" defaults="ru.noties.markwon.tasklist.TaskListDrawable" /> <ThemeProperty name="taskListDrawable" type="android.graphics.drawable.Drawable" defaults="ru.noties.markwon.spans.TaskListDrawable" />

View File

@ -1,6 +1,8 @@
<LegacyWarning />
# MarkwonView # MarkwonView
<MavenBadge artifact="markwon-view" /> <MavenBadge2xx artifact="markwon-view" />
This is simple library containing 2 views that are able to display markdown: This is simple library containing 2 views that are able to display markdown:
* MarkwonView - extends `android.view.TextView` * MarkwonView - extends `android.view.TextView`
@ -27,7 +29,8 @@ public interface IMarkwonView {
Both views support layout-preview in Android Studio (with some exceptions, for example, bold span is not rendered due to some limitations of layout preview). Both views support layout-preview in Android Studio (with some exceptions, for example, bold span is not rendered due to some limitations of layout preview).
These are XML attributes: These are XML attributes:
```
```xml
app:mv_markdown="string" app:mv_markdown="string"
app:mv_configurationProvider="string" app:mv_configurationProvider="string"
``` ```

View File

@ -1,6 +1,8 @@
# LaTeX # LaTeX
This is a small extension that will help you display LaTeX formulas in your markdown. [![ext-latex](https://img.shields.io/maven-central/v/ru.noties.markwon/ext-latex.svg?label=ext-latex)](http://search.maven.org/#search|ga|1|g%3A%22ru.noties.markwon%22%20AND%20a%3A%22ext-latex%22)
This is an extension that will help you display LaTeX formulas in your markdown.
Syntax is pretty simple: pre-fix and post-fix your latex with `$$` (double dollar sign). Syntax is pretty simple: pre-fix and post-fix your latex with `$$` (double dollar sign).
`$$` should be the first characters in a line. `$$` should be the first characters in a line.
@ -16,7 +18,6 @@ $$\\text{A long division \\longdiv{12345}{13}$$
```java ```java
Markwon.builder(context) Markwon.builder(context)
.use(CorePlugin.create())
.use(ImagesPlugin.create(context)) .use(ImagesPlugin.create(context))
.use(JLatexMathPlugin.create(new Config(textSize)) .use(JLatexMathPlugin.create(new Config(textSize))
.build(); .build();

View File

@ -1,6 +1,6 @@
# Strikethrough # Strikethrough
[![markwon-ext-strikethrough](https://img.shields.io/maven-central/v/ru.noties/markwon-ext-strikethrough.svg?label=markwon-ext-strikethrough)](http://search.maven.org/#search|ga|1|g%3A%22ru.noties%22%20AND%20a%3A%22markwon-ext-strikethrough%22) [![ext-strikethrough](https://img.shields.io/maven-central/v/ru.noties.markwon/ext-strikethrough.svg?label=ext-strikethrough)](http://search.maven.org/#search|ga|1|g%3A%22ru.noties.markwon%22%20AND%20a%3A%22ext-strikethrough%22)
This module adds `strikethrough` functionality to `Markwon` via `StrikethroughPlugin`: This module adds `strikethrough` functionality to `Markwon` via `StrikethroughPlugin`:
@ -13,7 +13,7 @@ This plugin registers `SpanFactory` for `Strikethrough` node, so it's possible t
```java ```java
Markwon.builder(context) Markwon.builder(context)
.usePlugin(StrikethroughPlugin.class) .usePlugin(StrikethroughPlugin.create())
.usePlugin(new AbstractMarkwonPlugin() { .usePlugin(new AbstractMarkwonPlugin() {
@Override @Override
public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) { public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) {

View File

@ -0,0 +1,45 @@
# Tables
[![ext-tables](https://img.shields.io/maven-central/v/ru.noties.markwon/ext-tables.svg?label=ext-tables)](http://search.maven.org/#search|ga|1|g%3A%22ru.noties.markwon%22%20AND%20a%3A%22ext-tables%22)
This extension adds support for GFM tables.
```java
final Markwon markwon = Markwon.builder(context)
// create default instance of TablePlugin
.usePlugin(TablePlugin.create(context))
```
```java
final TableTheme tableTheme = TableTheme.builder()
.tableBorderColor(Color.RED)
.tableBorderWidth(0)
.tableCellPadding(0)
.tableHeaderRowBackgroundColor(Color.BLACK)
.tableEvenRowBackgroundColor(Color.GREEN)
.tableOddRowBackgroundColor(Color.YELLOW)
.build();
final Markwon markwon = Markwon.builder(context)
.usePlugin(TablePlugin.create(tableTheme))
```
Please note, that _by default_ tables have limitations. For example, there is no support
for images inside table cells. And table contents won't be copied to clipboard if a TextView
has such functionality. Table will always take full width of a TextView in which it is displayed.
All columns will always be the of the same width. So, _default_ implementation provides basic
functionality which can answer some needs. These all come from the limited nature of the TextView
to display such content.
In order to provide full-fledged experience, tables must be displayed in a special widget.
Since version `3.0.0` Markwon provides a special artifact `markwon-recycler` that allows
to render markdown in a set of widgets in a RecyclerView. It also gives ability to change
display widget form TextView to any other.
```java
final Table table = Table.parse(Markwon, TableBlock);
myTableWidget.setTable(table);
```
Unfortunately Markwon does not provide a widget that can be used for tables. But it does
provide API that can be used to achieve desired result.

View File

@ -52,6 +52,7 @@ public class TablePlugin extends AbstractMarkwonPlugin {
@Override @Override
public void beforeRender(@NonNull Node node) { public void beforeRender(@NonNull Node node) {
// clear before rendering (as visitor has some internal mutable state)
visitor.clear(); visitor.clear();
} }

View File

@ -1,41 +0,0 @@
# Markwon View
[![maven|markwon-view](https://img.shields.io/maven-central/v/ru.noties/markwon-view.svg?label=maven%7Cmarkwon-view)](http://search.maven.org/#search|ga|1|g%3A%22ru.noties%22%20AND%20a%3A%markwon-view%22)
This is simple library containing 2 views that are able to display markdown:
* MarkwonView - extends `android.view.TextView`
* MarkwonViewCompat - extends `android.support.v7.widget.AppCompatTextView`
Both of them implement common `IMarkwonView` interface:
```java
public interface IMarkwonView {
interface ConfigurationProvider {
@NonNull
SpannableConfiguration provide(@NonNull Context context);
}
void setConfigurationProvider(@NonNull ConfigurationProvider provider);
void setMarkdown(@Nullable String markdown);
void setMarkdown(@Nullable SpannableConfiguration configuration, @Nullable String markdown);
@Nullable
String getMarkdown();
}
```
Both views support layout-preview in Android Studio (with some exceptions, for example, bold span is not rendered due to some limitations of layout preview).
These are XML attributes:
```
app:mv_markdown="string"
app:mv_configurationProvider="string"
```
`mv_markdown` accepts a string and represents raw markdown
`mv_configurationProvider` accepts a string and represents a full class name of a class of type `ConfigurationProvider`,
for example: `com.example.my.package.MyConfigurationProvider` (this class must have an empty constructor
in order to be instantiated via reflection).
Please note that those views parse markdown in main thread, so their usage must be for relatively small markdown portions only

View File

@ -1,25 +0,0 @@
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 {
compileOnly it['support-app-compat']
}
}
registerArtifact(this)

View File

@ -1,31 +0,0 @@
package ru.noties.markwon.view.debug;
import android.content.Context;
import android.support.annotation.NonNull;
import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.core.MarkwonTheme;
import ru.noties.markwon.view.IMarkwonView;
public class DebugConfigurationProvider implements IMarkwonView.ConfigurationProvider {
private MarkwonConfiguration cached;
@NonNull
@Override
public MarkwonConfiguration provide(@NonNull Context context) {
if (cached == null) {
cached = MarkwonConfiguration.builder(context)
.theme(debugTheme(context))
.build();
}
return cached;
}
private static MarkwonTheme debugTheme(@NonNull Context context) {
return MarkwonTheme.builderWithDefaults(context)
.blockQuoteColor(0xFFff0000)
.codeBackgroundColor(0x40FF0000)
.build();
}
}

View File

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ru.noties.markwon.view.MarkwonView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18sp"
android:paddingLeft="16dip"
android:paddingRight="16dip"
android:textColor="#333"
app:mv_configurationProvider="ru.noties.markwon.view.debug.DebugConfigurationProvider"
app:mv_markdown="@string/debug_markdown"/>
</ScrollView>

View File

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ru.noties.markwon.view.MarkwonViewCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18sp"
android:paddingLeft="16dip"
android:paddingRight="16dip"
android:textColor="#333"
app:mv_configurationProvider="ru.noties.markwon.view.debug.DebugConfigurationProvider"
app:mv_markdown="@string/debug_markdown"/>
</ScrollView>

View File

@ -1,39 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="debug_markdown">
<![CDATA[
# Hello
\n
**Bold title, right (layout preview somehow cannot render it)?**
\n
> Quote
\n
>> Quote #2
\n
>>> Quote `#3`
\n
---
\n
```
\n
// this is some amazing code block
\n
```
\n
* First
\n
* Second
\n
* * Second-First
\n
* * Second-Second
\n
* * * Second-Second-First
\n
* And out of blue - Third
]]>
</string>
</resources>

View File

@ -1 +0,0 @@
<manifest package="ru.noties.markwon.view" />

View File

@ -1,23 +0,0 @@
package ru.noties.markwon.view;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import ru.noties.markwon.MarkwonConfiguration;
public interface IMarkwonView {
interface ConfigurationProvider {
@NonNull
MarkwonConfiguration provide(@NonNull Context context);
}
void setConfigurationProvider(@NonNull ConfigurationProvider provider);
void setMarkdown(@Nullable String markdown);
void setMarkdown(@Nullable MarkwonConfiguration configuration, @Nullable String markdown);
@Nullable
String getMarkdown();
}

View File

@ -1,50 +0,0 @@
package ru.noties.markwon.view;
import android.annotation.SuppressLint;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.widget.TextView;
import ru.noties.markwon.MarkwonConfiguration;
@SuppressLint("AppCompatCustomView")
public class MarkwonView extends TextView implements IMarkwonView {
private MarkwonViewHelper helper;
public MarkwonView(Context context) {
super(context);
init(context, null);
}
public MarkwonView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
private void init(Context context, AttributeSet attributeSet) {
helper = MarkwonViewHelper.create(this);
helper.init(context, attributeSet);
}
@Override
public void setConfigurationProvider(@NonNull ConfigurationProvider provider) {
helper.setConfigurationProvider(provider);
}
public void setMarkdown(@Nullable String markdown) {
helper.setMarkdown(markdown);
}
public void setMarkdown(@Nullable MarkwonConfiguration configuration, @Nullable String markdown) {
helper.setMarkdown(configuration, markdown);
}
@Nullable
@Override
public String getMarkdown() {
return helper.getMarkdown();
}
}

View File

@ -1,50 +0,0 @@
package ru.noties.markwon.view;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.AppCompatTextView;
import android.util.AttributeSet;
import ru.noties.markwon.MarkwonConfiguration;
public class MarkwonViewCompat extends AppCompatTextView implements IMarkwonView {
private MarkwonViewHelper helper;
public MarkwonViewCompat(Context context) {
super(context);
init(context, null);
}
public MarkwonViewCompat(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
private void init(Context context, AttributeSet attributeSet) {
helper = MarkwonViewHelper.create(this);
helper.init(context, attributeSet);
}
@Override
public void setConfigurationProvider(@NonNull ConfigurationProvider provider) {
helper.setConfigurationProvider(provider);
}
@Override
public void setMarkdown(@Nullable String markdown) {
helper.setMarkdown(markdown);
}
@Override
public void setMarkdown(@Nullable MarkwonConfiguration configuration, @Nullable String markdown) {
helper.setMarkdown(configuration, markdown);
}
@Nullable
@Override
public String getMarkdown() {
return helper.getMarkdown();
}
}

View File

@ -1,105 +0,0 @@
package ru.noties.markwon.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.widget.TextView;
import ru.noties.markwon.Markwon;
import ru.noties.markwon.MarkwonConfiguration;
public class MarkwonViewHelper implements IMarkwonView {
public static <V extends TextView> MarkwonViewHelper create(@NonNull V view) {
return new MarkwonViewHelper(view);
}
private final TextView textView;
private ConfigurationProvider provider;
private MarkwonConfiguration configuration;
private String markdown;
private MarkwonViewHelper(@NonNull TextView textView) {
this.textView = textView;
}
public void init(Context context, AttributeSet attributeSet) {
if (attributeSet != null) {
final TypedArray array = context.obtainStyledAttributes(attributeSet, R.styleable.MarkwonView);
try {
final String configurationProvider = array.getString(R.styleable.MarkwonView_mv_configurationProvider);
final ConfigurationProvider provider;
if (!TextUtils.isEmpty(configurationProvider)) {
provider = MarkwonViewHelper.obtainProvider(configurationProvider);
} else {
provider = null;
}
if (provider != null) {
setConfigurationProvider(provider);
}
final String markdown = array.getString(R.styleable.MarkwonView_mv_markdown);
if (!TextUtils.isEmpty(markdown)) {
setMarkdown(markdown);
}
} finally {
array.recycle();
}
}
}
@Override
public void setConfigurationProvider(@NonNull ConfigurationProvider provider) {
this.provider = provider;
this.configuration = provider.provide(textView.getContext());
if (!TextUtils.isEmpty(markdown)) {
// invalidate rendered markdown
setMarkdown(markdown);
}
}
@Override
public void setMarkdown(@Nullable String markdown) {
setMarkdown(null, markdown);
}
@Override
public void setMarkdown(@Nullable MarkwonConfiguration configuration, @Nullable String markdown) {
this.markdown = markdown;
if (configuration == null) {
if (this.configuration == null) {
if (provider != null) {
this.configuration = provider.provide(textView.getContext());
} else {
this.configuration = MarkwonConfiguration.create(textView.getContext());
}
}
configuration = this.configuration;
}
Markwon.setMarkdown(textView, configuration, markdown);
}
@Nullable
@Override
public String getMarkdown() {
return markdown;
}
@Nullable
public static IMarkwonView.ConfigurationProvider obtainProvider(@NonNull String className) {
try {
final Class<?> cl = Class.forName(className);
return (IMarkwonView.ConfigurationProvider) cl.newInstance();
} catch (Throwable t) {
t.printStackTrace();
return null;
}
}
}

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MarkwonView">
<attr name="mv_configurationProvider" format="string" />
<attr name="mv_markdown" format="string" />
</declare-styleable>
</resources>

View File

@ -1,26 +0,0 @@
# Custom extension
This module provides a simple implementation for icons that are bundled in your application resources using custom `DelimiterProcessor`. It can be used as a reference when dealing with new functionality based on _delimiters_.
```markdown
# Hello @ic-android-black-24
**Please** click @ic-home-green-24 (home icon) if you want to go home.
```
Here we will substitute elements starting with `@ic-` for icons that we have in our resources:
* `@ic-android-black-24` -> `R.drawable.ic_android_black_24dp`
* `@ic-home-green-24` -> `R.drawable.ic_home_green_24dp`
In order to provide reliable parsing we need to have delimiters _around_ desired content. So, `@ic-home-green-24` would become `@ic-home-green-24@`. This is current limitation of [commonmark-java](https://github.com/atlassian/commonmark-java) library that Markwon uses underneath. There is an ongoing [issue](https://github.com/atlassian/commonmark-java/issues/113) that might change this in future thought.
But as we known the pattern beforehand it's pretty easy to pre-process raw markdown and make it the way we want it. Please refer to `IconProcessor#process` method for the reference.
So, the our steps would be:
* prepare raw markdown (wrap icons with `@` if it's not already)
* construct a Parser with our registered delimiter processor
* parse markdown and obtain a `Node`
* create a node visitor that will additionally visit custom node (`IconNode`)
* use markdown

View File

@ -1,29 +0,0 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion config['compile-sdk']
buildToolsVersion config['build-tools']
defaultConfig {
applicationId "ru.noties.markwon.sample.extension"
// using 21 as minimum only to be able to vector assets
minSdkVersion 21
targetSdkVersion config['target-sdk']
versionCode 1
versionName version
}
}
dependencies {
implementation project(':markwon-core')
implementation project(':markwon-image-svg')
implementation project(':markwon-recycler')
implementation project(':markwon-ext-tables')
implementation project(':markwon-html')
implementation deps['debug']
}

View File

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="ru.noties.markwon.sample.extension">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:ignore="AllowBackup,GoogleAppIndexingWarning,MissingApplicationIcon">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".recycler.MarkwonRecyclerActivity"
android:exported="true" />
</application>
</manifest>

View File

@ -1,313 +0,0 @@
![logo](./art/markwon_logo.png)
# Markwon
[![markwon](https://img.shields.io/maven-central/v/ru.noties/markwon.svg?label=markwon)](http://search.maven.org/#search|ga|1|g%3A%22ru.noties%22%20AND%20a%3A%22markwon%22)
[![markwon-image-loader](https://img.shields.io/maven-central/v/ru.noties/markwon-image-loader.svg?label=markwon-image-loader)](http://search.maven.org/#search|ga|1|g%3A%22ru.noties%22%20AND%20a%3A%22markwon-image-loader%22)
[![markwon-syntax-highlight](https://img.shields.io/maven-central/v/ru.noties/markwon-syntax-highlight.svg?label=markwon-syntax-highlight)](http://search.maven.org/#search|ga|1|g%3A%22ru.noties%22%20AND%20a%3A%22markwon-syntax-highlight%22)
[![markwon-view](https://img.shields.io/maven-central/v/ru.noties/markwon-view.svg?label=markwon-view)](http://search.maven.org/#search|ga|1|g%3A%22ru.noties%22%20AND%20a%3A%22markwon-view%22)
[![Build Status](https://travis-ci.org/noties/Markwon.svg?branch=master)](https://travis-ci.org/noties/Markwon)
**Markwon** is a markdown library for Android. It parses markdown
following [commonmark-spec] with the help of amazing [commonmark-java]
library and renders result as _Android-native_ Spannables. **No HTML**
is involved as an intermediate step. <u>**No WebView** is required</u>.
It's extremely fast, feature-rich and extensible.
It gives ability to display markdown in all TextView widgets
(**TextView**, **Button**, **Switch**, **CheckBox**, etc), **Toasts**
and all other places that accept **Spanned content**. Library provides
reasonable defaults to display style of a markdown content but also
gives all the means to tweak the appearance if desired. All markdown
features listed in [commonmark-spec] are supported
(including support for **inlined/block HTML code**, **markdown tables**,
**images** and **syntax highlight**).
[commonmark-spec]: https://spec.commonmark.org/0.28/
[commonmark-java]: https://github.com/atlassian/commonmark-java/blob/master/README.md
<sup>*</sup>*This file is displayed by default in the [sample-apk] (`markwon-sample-{latest-version}-debug.apk`) application. Which is a generic markdown viewer with support to display markdown via `http`, `https` & `file` schemes and 2 themes included: Light & Dark*
[sample-apk]: https://github.com/noties/Markwon/releases
## Installation
```groovy
implementation "ru.noties:markwon:${markwonVersion}"
implementation "ru.noties:markwon-image-loader:${markwonVersion}" // optional
implementation "ru.noties:markwon-syntax-highlight:${markwonVersion}" // optional
implementation "ru.noties:markwon-view:${markwonVersion}" // optional
```
Please visit [documentation] web-site for further reference
## Supported markdown features:
* Emphasis (`*`, `_`)
* Strong emphasis (`**`, `__`)
* Strike-through (`~~`)
* Headers (`#{1,6}`)
* Links (`[]()` && `[][]`)
* Images
* Thematic break (`---`, `***`, `___`)
* Quotes & nested quotes (`>{1,}`)
* Ordered & non-ordered lists & nested ones
* Inline code
* Code blocks
* Tables (*with limitations*)
* Syntax highlight
* HTML
* Emphasis (`<i>`, `<em>`, `<cite>`, `<dfn>`)
* Strong emphasis (`<b>`, `<strong>`)
* SuperScript (`<sup>`)
* SubScript (`<sub>`)
* Underline (`<u>`, `ins`)
* Strike-through (`<s>`, `<strike>`, `<del>`)
* Link (`a`)
* Lists (`ul`, `ol`)
* Images (`img` will require configured image loader)
* Blockquote (`blockquote`)
* Heading (`h1`, `h2`, `h3`, `h4`, `h5`, `h6`)
* there is support to render any HTML tag
* Task lists:
- [ ] Not _done_
- [X] **Done** with `X`
- [x] ~~and~~ **or** small `x`
---
## Screenshots
Taken with default configuration (except for image loading):
<a href="./art/mw_light_01.png"><img src="./art/mw_light_01.png" width="30%" /></a>
<a href="./art/mw_light_02.png"><img src="./art/mw_light_02.png" width="30%" /></a>
<a href="./art/mw_light_03.png"><img src="./art/mw_light_03.png" width="30%" /></a>
<a href="./art/mw_dark_01.png"><img src="./art/mw_dark_01.png" width="30%" /></a>
By default configuration uses TextView textColor for styling, so changing textColor changes style
---
## Documentation
Please visit [documentation] web-site for reference
[documentation]: https://noties.github.io/Markwon
---
## Applications using Markwon
* [Partiko](https://partiko.app)
* [FairNote Notepad](https://play.google.com/store/apps/details?id=com.rgiskard.fairnote)
---
# Demo
Based on [this cheatsheet][cheatsheet]
---
## Headers
---
# Header 1
## Header 2
### Header 3
#### Header 4
##### Header 5
###### Header 6
---
## Emphasis
Emphasis, aka italics, with *asterisks* or _underscores_.
Strong emphasis, aka bold, with **asterisks** or __underscores__.
Combined emphasis with **asterisks and _underscores_**.
Strikethrough uses two tildes. ~~Scratch this.~~
---
## Lists
1. First ordered list item
2. Another item
* Unordered sub-list.
1. Actual numbers don't matter, just that it's a number
1. Ordered sub-list
4. And another item.
You can have properly indented paragraphs within list items. Notice the blank line above, and the leading spaces (at least one, but we'll use three here to also align the raw Markdown).
To have a line break without a paragraph, you will need to use two trailing spaces.
Note that this line is separate, but within the same paragraph.
(This is contrary to the typical GFM line break behaviour, where trailing spaces are not required.)
* Unordered list can use asterisks
- Or minuses
+ Or pluses
---
## Links
[I'm an inline-style link](https://www.google.com)
[I'm a reference-style link][Arbitrary case-insensitive reference text]
[I'm a relative reference to a repository file](../blob/master/LICENSE)
[You can use numbers for reference-style link definitions][1]
Or leave it empty and use the [link text itself].
---
## Code
Inline `code` has `back-ticks around` it.
```javascript
var s = "JavaScript syntax highlighting";
alert(s);
```
```python
s = "Python syntax highlighting"
print s
```
```java
/**
* Helper method to obtain a Parser with registered strike-through &amp; table extensions
* &amp; task lists (added in 1.0.1)
*
* @return a Parser instance that is supported by this library
* @since 1.0.0
*/
@NonNull
public static Parser createParser() {
return new Parser.Builder()
.extensions(Arrays.asList(
StrikethroughExtension.create(),
TablesExtension.create(),
TaskListExtension.create()
))
.build();
}
```
```xml
<ScrollView
android:id="@+id/scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="?android:attr/actionBarSize">
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dip"
android:lineSpacingExtra="2dip"
android:textSize="16sp"
tools:context="ru.noties.markwon.MainActivity"
tools:text="yo\nman" />
</ScrollView>
```
```
No language indicated, so no syntax highlighting.
But let's throw in a <b>tag</b>.
```
---
## Tables
Colons can be used to align columns.
| Tables | Are | Cool |
| ------------- |:-------------:| -----:|
| col 3 is | right-aligned | $1600 |
| col 2 is | centered | $12 |
| zebra stripes | are neat | $1 |
There must be at least 3 dashes separating each header cell.
The outer pipes (|) are optional, and you don't need to make the
raw Markdown line up prettily. You can also use inline Markdown.
Markdown | Less | Pretty
--- | --- | ---
*Still* | `renders` | **nicely**
1 | 2 | 3
---
## Blockquotes
> Blockquotes are very handy in email to emulate reply text.
> This line is part of the same quote.
Quote break.
> This is a very long line that will still be quoted properly when it wraps. Oh boy let's keep writing to make sure this is long enough to actually wrap for everyone. Oh, you can *put* **Markdown** into a blockquote.
Nested quotes
> Hello!
>> And to you!
---
## Inline HTML
```html
<u><i>H<sup>T<sub>M</sub></sup><b><s>L</s></b></i></u>
```
<u><i>H<sup>T<sub>M</sub></sup><b><s>L</s></b></i></u>
---
## Horizontal Rule
Three or more...
---
Hyphens (`-`)
***
Asterisks (`*`)
___
Underscores (`_`)
## License
```
Copyright 2017 Dimitry Ivanov (mail@dimitryivanov.ru)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
```
[cheatsheet]: https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet
[arbitrary case-insensitive reference text]: https://www.mozilla.org
[1]: http://slashdot.org
[link text itself]: http://www.reddit.com

View File

@ -1,40 +0,0 @@
package ru.noties.markwon.sample.extension;
import android.app.Activity;
import android.graphics.Typeface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.widget.TextView;
import ru.noties.markwon.AbstractMarkwonPlugin;
import ru.noties.markwon.Markwon;
import ru.noties.markwon.core.MarkwonTheme;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView textView = findViewById(R.id.text_view);
final Markwon markwon = Markwon.builder(this)
.usePlugin(IconPlugin.create(IconSpanProvider.create(this, 0)))
.usePlugin(new AbstractMarkwonPlugin() {
@Override
public void configureTheme(@NonNull MarkwonTheme.Builder builder) {
// this part has nothing to do with actual IconPlugin
// this part is used to showcase that headers can be controlled via Theme
final float[] textSizeMultipliers = new float[]{3f, 2f, 1.5f, 1f, .5f, .25f};
builder
.headingTypeface(Typeface.MONOSPACE)
.headingTextSizeMultipliers(textSizeMultipliers);
}
})
.build();
markwon.setMarkdown(textView, getString(R.string.input));
}
}

View File

@ -1,144 +0,0 @@
package ru.noties.markwon.sample.extension.recycler;
import android.app.Activity;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import org.commonmark.ext.gfm.tables.TableBlock;
import org.commonmark.node.FencedCodeBlock;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import ru.noties.debug.AndroidLogDebugOutput;
import ru.noties.debug.Debug;
import ru.noties.markwon.AbstractMarkwonPlugin;
import ru.noties.markwon.Markwon;
import ru.noties.markwon.MarkwonConfiguration;
import ru.noties.markwon.core.CorePlugin;
import ru.noties.markwon.ext.tables.TablePlugin;
import ru.noties.markwon.html.HtmlPlugin;
import ru.noties.markwon.image.ImagesPlugin;
import ru.noties.markwon.image.svg.SvgPlugin;
import ru.noties.markwon.recycler.MarkwonAdapter;
import ru.noties.markwon.recycler.SimpleEntry;
import ru.noties.markwon.sample.extension.R;
import ru.noties.markwon.urlprocessor.UrlProcessor;
import ru.noties.markwon.urlprocessor.UrlProcessorRelativeToAbsolute;
// we will create a standalone `sample` module with all these samples, right now this
// module has unrelated things
public class MarkwonRecyclerActivity extends Activity {
static {
Debug.init(new AndroidLogDebugOutput(true));
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recycler);
final MarkwonAdapter adapter = MarkwonAdapter.builder()
.include(FencedCodeBlock.class, new SimpleEntry(R.layout.adapter_fenced_code_block))
.include(TableBlock.class, new TableEntry())
.defaultEntry(new SimpleEntry(R.layout.adapter_default_entry))
.build();
final RecyclerView recyclerView = findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(adapter);
final Markwon markwon = markwon(this);
adapter.setMarkdown(markwon, loadReadMe(this));
adapter.notifyDataSetChanged();
}
@NonNull
private static Markwon markwon(@NonNull Context context) {
return Markwon.builder(context)
.usePlugin(CorePlugin.create())
.usePlugin(ImagesPlugin.createWithAssets(context))
.usePlugin(SvgPlugin.create(context.getResources()))
.usePlugin(TablePlugin.create(context))
.usePlugin(HtmlPlugin.create())
.usePlugin(new AbstractMarkwonPlugin() {
@Override
public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) {
builder.urlProcessor(new UrlProcessorInitialReadme());
}
})
.build();
}
private static String loadReadMe(@NonNull Context context) {
InputStream stream = null;
try {
stream = context.getAssets().open("README.md");
} catch (IOException e) {
e.printStackTrace();
}
return readStream(stream);
}
private static String readStream(@Nullable InputStream inputStream) {
String out = null;
if (inputStream != null) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(inputStream));
final StringBuilder builder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
builder.append(line)
.append('\n');
}
out = builder.toString();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
// no op
}
}
}
}
return out;
}
private static class UrlProcessorInitialReadme implements UrlProcessor {
private static final String GITHUB_BASE = "https://github.com/noties/Markwon/raw/master/";
private final UrlProcessorRelativeToAbsolute processor
= new UrlProcessorRelativeToAbsolute(GITHUB_BASE);
@NonNull
@Override
public String process(@NonNull String destination) {
String out;
final Uri uri = Uri.parse(destination);
if (TextUtils.isEmpty(uri.getScheme())) {
out = processor.process(destination);
} else {
out = destination;
}
return out;
}
}
}

View File

@ -1,64 +0,0 @@
package ru.noties.markwon.sample.extension.recycler;
import android.support.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import org.commonmark.ext.gfm.tables.TableBlock;
import java.util.HashMap;
import java.util.Map;
import ru.noties.markwon.Markwon;
import ru.noties.markwon.ext.tables.Table;
import ru.noties.markwon.recycler.MarkwonAdapter;
import ru.noties.markwon.sample.extension.R;
// do not use in real applications, this is just a showcase
public class TableEntry implements MarkwonAdapter.Entry<TableEntry.TableNodeHolder, TableBlock> {
private final Map<TableBlock, Table> cache = new HashMap<>(2);
@NonNull
@Override
public TableNodeHolder createHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) {
return new TableNodeHolder(inflater.inflate(R.layout.adapter_table_block, parent, false));
}
@Override
public void bindHolder(@NonNull Markwon markwon, @NonNull TableNodeHolder holder, @NonNull TableBlock node) {
Table table = cache.get(node);
if (table == null) {
table = Table.parse(markwon, node);
cache.put(node, table);
}
if (table != null) {
holder.tableEntryView.setTable(table);
// render table
} // we need to do something with null table...
}
@Override
public long id(@NonNull TableBlock node) {
return node.hashCode();
}
@Override
public void clear() {
cache.clear();
}
static class TableNodeHolder extends MarkwonAdapter.Holder {
final TableEntryView tableEntryView;
TableNodeHolder(@NonNull View itemView) {
super(itemView);
this.tableEntryView = requireView(R.id.table_entry);
}
}
}

View File

@ -1,205 +0,0 @@
package ru.noties.markwon.sample.extension.recycler;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.SpannedString;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
import ru.noties.markwon.ext.tables.Table;
import ru.noties.markwon.sample.extension.R;
public class TableEntryView extends LinearLayout {
// paint and rect to draw borders
private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Rect rect = new Rect();
private LayoutInflater inflater;
private int rowEvenBackgroundColor;
public TableEntryView(Context context) {
super(context);
init(context, null);
}
public TableEntryView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
private void init(Context context, @Nullable AttributeSet attrs) {
inflater = LayoutInflater.from(context);
setOrientation(VERTICAL);
if (attrs != null) {
final TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.TableEntryView);
try {
rowEvenBackgroundColor = array.getColor(R.styleable.TableEntryView_tev_rowEvenBackgroundColor, 0);
final int stroke = array.getDimensionPixelSize(R.styleable.TableEntryView_tev_borderWidth, 0);
// half of requested
final float strokeWidth = stroke > 0
? stroke / 2.F
: context.getResources().getDisplayMetrics().density / 2.F;
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(strokeWidth);
paint.setColor(array.getColor(R.styleable.TableEntryView_tev_borderColor, Color.BLACK));
if (isInEditMode()) {
final String data = array.getString(R.styleable.TableEntryView_tev_debugData);
if (data != null) {
boolean first = true;
final List<Table.Row> rows = new ArrayList<>();
for (String row : data.split("\\|")) {
final List<Table.Column> columns = new ArrayList<>();
for (String column : row.split(",")) {
columns.add(new Table.Column(Table.Alignment.LEFT, new SpannedString(column)));
}
final boolean header = first;
first = false;
rows.add(new Table.Row(header, columns));
}
final Table table = new Table(rows);
setTable(table);
}
}
} finally {
array.recycle();
}
}
setWillNotDraw(false);
}
public void setTable(@NonNull Table table) {
final List<Table.Row> rows = table.rows();
for (int i = 0, size = rows.size(); i < size; i++) {
addRow(i, rows.get(i));
}
}
private void addRow(int index, @NonNull Table.Row row) {
final ViewGroup group = ensureRow(index);
final int backgroundColor = !row.header() && (index % 2) == 0
? rowEvenBackgroundColor
: 0;
group.setBackgroundColor(backgroundColor);
final List<Table.Column> columns = row.columns();
TextView textView;
Table.Column column;
for (int i = 0, size = columns.size(); i < size; i++) {
textView = ensureCell(group, i);
column = columns.get(i);
textView.setTextAlignment(textAlignment(column.alignment()));
textView.setText(column.content());
textView.getPaint().setFakeBoldText(row.header());
}
}
@NonNull
private ViewGroup ensureRow(int index) {
final int count = getChildCount();
if (index >= count) {
// count=0,index=1, diff=2
// count=0,index=5, diff=6
// count=1,index=2, diff=2
int diff = index - count + 1;
while (diff > 0) {
addView(inflater.inflate(R.layout.view_table_entry_row, this, false));
diff -= 1;
}
}
return (ViewGroup) getChildAt(index);
}
@NonNull
private TextView ensureCell(@NonNull ViewGroup group, int index) {
final int count = group.getChildCount();
if (index >= count) {
int diff = index - count + 1;
while (diff > 0) {
group.addView(inflater.inflate(R.layout.view_table_entry_cell, group, false));
diff -= 1;
}
}
return (TextView) group.getChildAt(index);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
final int rows = getChildCount();
if (rows == 0) {
return;
}
// first draw the whole border
rect.set(0, 0, getWidth(), getHeight());
canvas.drawRect(rect, paint);
ViewGroup group;
View view;
int top;
for (int row = 0; row < rows; row++) {
group = (ViewGroup) getChildAt(row);
top = group.getTop();
for (int col = 0, cols = group.getChildCount(); col < cols; col++) {
view = group.getChildAt(col);
rect.set(view.getLeft(), top + view.getTop(), view.getRight(), top + view.getBottom());
canvas.drawRect(rect, paint);
}
}
}
private static int textAlignment(@NonNull Table.Alignment alignment) {
final int out;
switch (alignment) {
case LEFT:
out = TextView.TEXT_ALIGNMENT_TEXT_START;
break;
case CENTER:
out = TextView.TEXT_ALIGNMENT_CENTER;
break;
case RIGHT:
out = TextView.TEXT_ALIGNMENT_TEXT_END;
break;
default:
throw new IllegalStateException("Unexpected alignment: " + alignment);
}
return out;
}
}

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />

View File

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dip"
android:layout_marginRight="16dip"
android:lineSpacingExtra="2dip"
android:paddingTop="8dip"
android:paddingBottom="8dip"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="#000"
android:textSize="16sp" />

View File

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"
android:clipToPadding="false"
android:fillViewport="true"
android:paddingLeft="16dip"
android:paddingRight="16dip"
android:scrollbarStyle="outsideInset">
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:lineSpacingExtra="2dip"
android:paddingTop="8dip"
android:paddingBottom="8dip"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textSize="16sp"
tools:text="# Hello there! and taskjs" />
</HorizontalScrollView>

View File

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--<HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"-->
<!--xmlns:app="http://schemas.android.com/apk/res-auto"-->
<!--android:layout_width="match_parent"-->
<!--android:layout_height="wrap_content"-->
<!--android:clipChildren="false"-->
<!--android:clipToPadding="false"-->
<!--android:fillViewport="true"-->
<!--android:paddingLeft="16dip"-->
<!--android:paddingTop="8dip"-->
<!--android:paddingRight="16dip"-->
<!--android:paddingBottom="8dip">-->
<ru.noties.markwon.sample.extension.recycler.TableEntryView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/table_entry"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tev_debugData="head1,head2,head3|col1,col2,col3|col1,col2,col3|col1,col2,col3"
app:tev_rowEvenBackgroundColor="#40ff0000" />
<!--</HorizontalScrollView>-->

View File

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="0px"
android:layout_height="wrap_content"
android:layout_weight="1"
android:padding="4dip"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="#000"
android:textSize="16sp"
tools:text="Table content" />

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" />

View File

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="TableEntryView">
<attr name="tev_rowEvenBackgroundColor" format="color" />
<attr name="tev_borderColor" format="color" />
<attr name="tev_borderWidth" format="dimension" />
<attr name="tev_debugData" format="string" />
</declare-styleable>
</resources>

View File

@ -1,14 +0,0 @@
<resources>
<string name="app_name">Markwon-SampleCustomExtension</string>
<string name="input"><![CDATA[
# Hello! @ic-android-black-24\n\n
Home 36 black: @ic-home-black-36\n\n
Memory 48 black: @ic-memory-black-48\n\n
### I AM ANOTHER HEADER\n\n
Sentiment Satisfied 64 red: @ic-sentiment_satisfied-red-64
]]>
</string>
</resources>

View File

@ -1,5 +0,0 @@
<resources>
<style name="AppTheme" parent="android:Theme.Material.Light.DarkActionBar"/>
</resources>

View File

@ -1,24 +0,0 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion config['compile-sdk']
buildToolsVersion config['build-tools']
defaultConfig {
applicationId "ru.noties.markwon.sample.jlatexmath"
minSdkVersion config['min-sdk']
targetSdkVersion config['target-sdk']
versionCode 1
versionName version
}
}
dependencies {
implementation project(':markwon-core')
implementation project(':markwon-ext-latex')
// implementation project(':markwon-image-loader')
// implementation 'ru.noties:jlatexmath-android:0.1.0'
}

View File

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="ru.noties.markwon.sample.jlatexmath">
<application
android:allowBackup="true"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -1,58 +0,0 @@
package ru.noties.markwon.sample.jlatexmath;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
import ru.noties.markwon.Markwon;
import ru.noties.markwon.core.CorePlugin;
import ru.noties.markwon.ext.latex.JLatexMathPlugin;
import ru.noties.markwon.image.ImagesPlugin;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView textView = findViewById(R.id.text_view);
String latex = "\\begin{array}{l}";
latex += "\\forall\\varepsilon\\in\\mathbb{R}_+^*\\ \\exists\\eta>0\\ |x-x_0|\\leq\\eta\\Longrightarrow|f(x)-f(x_0)|\\leq\\varepsilon\\\\";
latex += "\\det\\begin{bmatrix}a_{11}&a_{12}&\\cdots&a_{1n}\\\\a_{21}&\\ddots&&\\vdots\\\\\\vdots&&\\ddots&\\vdots\\\\a_{n1}&\\cdots&\\cdots&a_{nn}\\end{bmatrix}\\overset{\\mathrm{def}}{=}\\sum_{\\sigma\\in\\mathfrak{S}_n}\\varepsilon(\\sigma)\\prod_{k=1}^n a_{k\\sigma(k)}\\\\";
latex += "\\sideset{_\\alpha^\\beta}{_\\gamma^\\delta}{\\begin{pmatrix}a&b\\\\c&d\\end{pmatrix}}\\\\";
latex += "\\int_0^\\infty{x^{2n} e^{-a x^2}\\,dx} = \\frac{2n-1}{2a} \\int_0^\\infty{x^{2(n-1)} e^{-a x^2}\\,dx} = \\frac{(2n-1)!!}{2^{n+1}} \\sqrt{\\frac{\\pi}{a^{2n+1}}}\\\\";
latex += "\\int_a^b{f(x)\\,dx} = (b - a) \\sum\\limits_{n = 1}^\\infty {\\sum\\limits_{m = 1}^{2^n - 1} {\\left( { - 1} \\right)^{m + 1} } } 2^{ - n} f(a + m\\left( {b - a} \\right)2^{-n} )\\\\";
latex += "\\int_{-\\pi}^{\\pi} \\sin(\\alpha x) \\sin^n(\\beta x) dx = \\textstyle{\\left \\{ \\begin{array}{cc} (-1)^{(n+1)/2} (-1)^m \\frac{2 \\pi}{2^n} \\binom{n}{m} & n \\mbox{ odd},\\ \\alpha = \\beta (2m-n) \\\\ 0 & \\mbox{otherwise} \\\\ \\end{array} \\right .}\\\\";
latex += "L = \\int_a^b \\sqrt{ \\left|\\sum_{i,j=1}^ng_{ij}(\\gamma(t))\\left(\\frac{d}{dt}x^i\\circ\\gamma(t)\\right)\\left(\\frac{d}{dt}x^j\\circ\\gamma(t)\\right)\\right|}\\,dt\\\\";
latex += "\\begin{array}{rl} s &= \\int_a^b\\left\\|\\frac{d}{dt}\\vec{r}\\,(u(t),v(t))\\right\\|\\,dt \\\\ &= \\int_a^b \\sqrt{u'(t)^2\\,\\vec{r}_u\\cdot\\vec{r}_u + 2u'(t)v'(t)\\, \\vec{r}_u\\cdot\\vec{r}_v+ v'(t)^2\\,\\vec{r}_v\\cdot\\vec{r}_v}\\,\\,\\, dt. \\end{array}\\\\";
latex += "\\end{array}";
// String latex = "\\text{A long division \\longdiv{12345}{13}";
// String latex = "{a \\bangle b} {c \\brace d} {e \\brack f} {g \\choose h}";
// String latex = "\\begin{array}{cc}";
// latex += "\\fbox{\\text{A framed box with \\textdbend}}&\\shadowbox{\\text{A shadowed box}}\\cr";
// latex += "\\doublebox{\\text{A double framed box}}&\\ovalbox{\\text{An oval framed box}}\\cr";
// latex += "\\end{array}";
final JLatexMathPlugin.Config config = new JLatexMathPlugin.Config(textView.getTextSize()) {{
// align = JLatexMathDrawable.ALIGN_RIGHT;
}};
final String markdown = "# Example of LaTeX\n\n$$"
+ latex + "$$\n\n something like **this**";
final Markwon markwon = Markwon.builder(this)
.usePlugin(CorePlugin.create())
// strictly speaking this one is not required as long as JLatexMathPlugin schedules
// drawables on it's own
.usePlugin(ImagesPlugin.create(this))
.usePlugin(JLatexMathPlugin.create(config))
.build();
markwon.setMarkdown(textView, markdown);
}
}

View File

@ -1,14 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false">
<TextView
android:id="@+id/text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dip" />
</ScrollView>

View File

@ -1,3 +0,0 @@
<resources>
<string name="app_name">Markwon-JLatexMath</string>
</resources>

View File

@ -1,6 +0,0 @@
<resources>
<style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
</style>
</resources>

View File

@ -42,6 +42,7 @@ android {
dependencies { dependencies {
implementation project(':markwon-core') implementation project(':markwon-core')
implementation project(':markwon-ext-latex')
implementation project(':markwon-ext-strikethrough') implementation project(':markwon-ext-strikethrough')
implementation project(':markwon-ext-tables') implementation project(':markwon-ext-tables')
implementation project(':markwon-ext-tasklist') implementation project(':markwon-ext-tasklist')

View File

@ -25,6 +25,7 @@
<activity android:name=".customextension.CustomExtensionActivity" /> <activity android:name=".customextension.CustomExtensionActivity" />
<activity android:name=".basicplugins.BasicPluginsActivity" /> <activity android:name=".basicplugins.BasicPluginsActivity" />
<activity android:name=".recycler.RecyclerActivity" /> <activity android:name=".recycler.RecyclerActivity" />
<activity android:name=".theme.ThemeActivity" />
</application> </application>

View File

@ -1,6 +1,36 @@
package ru.noties.markwon.sample.customextension; package ru.noties.markwon.sample.customextension;
import android.app.Activity; import android.app.Activity;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.widget.TextView;
import ru.noties.markwon.Markwon;
import ru.noties.markwon.image.ImagesPlugin;
import ru.noties.markwon.sample.R;
public class CustomExtensionActivity extends Activity { public class CustomExtensionActivity extends Activity {
// please note that this sample won't work on a device with SDK level < 21
// as we are using vector drawables for the sake of brevity. Other than resources
// used, this is fully functional sample on all SDK levels
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_text_view);
final TextView textView = findViewById(R.id.text_view);
// note that we haven't registered CorePlugin, as it's the only one that can be
// implicitly deducted and added automatically. All other plugins require explicit
// `usePlugin` call
final Markwon markwon = Markwon.builder(this)
// try commenting out this line to see runtime dependency resolution
.usePlugin(ImagesPlugin.create(this))
.usePlugin(IconPlugin.create(IconSpanProvider.create(this, 0)))
.build();
markwon.setMarkdown(textView, getString(R.string.input));
}
} }

View File

@ -1,4 +1,4 @@
package ru.noties.markwon.sample.extension; package ru.noties.markwon.sample.customextension;
import org.commonmark.node.CustomNode; import org.commonmark.node.CustomNode;

View File

@ -1,4 +1,4 @@
package ru.noties.markwon.sample.extension; package ru.noties.markwon.sample.customextension;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;

View File

@ -1,4 +1,4 @@
package ru.noties.markwon.sample.extension; package ru.noties.markwon.sample.customextension;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.text.TextUtils; import android.text.TextUtils;
@ -7,6 +7,8 @@ import org.commonmark.parser.Parser;
import ru.noties.markwon.AbstractMarkwonPlugin; import ru.noties.markwon.AbstractMarkwonPlugin;
import ru.noties.markwon.MarkwonVisitor; import ru.noties.markwon.MarkwonVisitor;
import ru.noties.markwon.image.ImagesPlugin;
import ru.noties.markwon.priority.Priority;
public class IconPlugin extends AbstractMarkwonPlugin { public class IconPlugin extends AbstractMarkwonPlugin {
@ -21,6 +23,13 @@ public class IconPlugin extends AbstractMarkwonPlugin {
this.iconSpanProvider = iconSpanProvider; this.iconSpanProvider = iconSpanProvider;
} }
@NonNull
@Override
public Priority priority() {
// define images dependency
return Priority.after(ImagesPlugin.class);
}
@Override @Override
public void configureParser(@NonNull Parser.Builder builder) { public void configureParser(@NonNull Parser.Builder builder) {
builder.customDelimiterProcessor(IconProcessor.create()); builder.customDelimiterProcessor(IconProcessor.create());

View File

@ -1,4 +1,4 @@
package ru.noties.markwon.sample.extension; package ru.noties.markwon.sample.customextension;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.text.TextUtils; import android.text.TextUtils;

View File

@ -1,4 +1,4 @@
package ru.noties.markwon.sample.extension; package ru.noties.markwon.sample.customextension;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Paint; import android.graphics.Paint;

View File

@ -1,4 +1,4 @@
package ru.noties.markwon.sample.extension; package ru.noties.markwon.sample.customextension;
import android.content.Context; import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;

View File

@ -3,6 +3,13 @@ package ru.noties.markwon.sample.latex;
import android.app.Activity; import android.app.Activity;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.widget.TextView;
import ru.noties.markwon.Markwon;
import ru.noties.markwon.core.CorePlugin;
import ru.noties.markwon.ext.latex.JLatexMathPlugin;
import ru.noties.markwon.image.ImagesPlugin;
import ru.noties.markwon.sample.R;
public class LatexActivity extends Activity { public class LatexActivity extends Activity {
@ -10,6 +17,42 @@ public class LatexActivity extends Activity {
public void onCreate(@Nullable Bundle savedInstanceState) { public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_text_view);
final TextView textView = findViewById(R.id.text_view);
String latex = "\\begin{array}{l}";
latex += "\\forall\\varepsilon\\in\\mathbb{R}_+^*\\ \\exists\\eta>0\\ |x-x_0|\\leq\\eta\\Longrightarrow|f(x)-f(x_0)|\\leq\\varepsilon\\\\";
latex += "\\det\\begin{bmatrix}a_{11}&a_{12}&\\cdots&a_{1n}\\\\a_{21}&\\ddots&&\\vdots\\\\\\vdots&&\\ddots&\\vdots\\\\a_{n1}&\\cdots&\\cdots&a_{nn}\\end{bmatrix}\\overset{\\mathrm{def}}{=}\\sum_{\\sigma\\in\\mathfrak{S}_n}\\varepsilon(\\sigma)\\prod_{k=1}^n a_{k\\sigma(k)}\\\\";
latex += "\\sideset{_\\alpha^\\beta}{_\\gamma^\\delta}{\\begin{pmatrix}a&b\\\\c&d\\end{pmatrix}}\\\\";
latex += "\\int_0^\\infty{x^{2n} e^{-a x^2}\\,dx} = \\frac{2n-1}{2a} \\int_0^\\infty{x^{2(n-1)} e^{-a x^2}\\,dx} = \\frac{(2n-1)!!}{2^{n+1}} \\sqrt{\\frac{\\pi}{a^{2n+1}}}\\\\";
latex += "\\int_a^b{f(x)\\,dx} = (b - a) \\sum\\limits_{n = 1}^\\infty {\\sum\\limits_{m = 1}^{2^n - 1} {\\left( { - 1} \\right)^{m + 1} } } 2^{ - n} f(a + m\\left( {b - a} \\right)2^{-n} )\\\\";
latex += "\\int_{-\\pi}^{\\pi} \\sin(\\alpha x) \\sin^n(\\beta x) dx = \\textstyle{\\left \\{ \\begin{array}{cc} (-1)^{(n+1)/2} (-1)^m \\frac{2 \\pi}{2^n} \\binom{n}{m} & n \\mbox{ odd},\\ \\alpha = \\beta (2m-n) \\\\ 0 & \\mbox{otherwise} \\\\ \\end{array} \\right .}\\\\";
latex += "L = \\int_a^b \\sqrt{ \\left|\\sum_{i,j=1}^ng_{ij}(\\gamma(t))\\left(\\frac{d}{dt}x^i\\circ\\gamma(t)\\right)\\left(\\frac{d}{dt}x^j\\circ\\gamma(t)\\right)\\right|}\\,dt\\\\";
latex += "\\begin{array}{rl} s &= \\int_a^b\\left\\|\\frac{d}{dt}\\vec{r}\\,(u(t),v(t))\\right\\|\\,dt \\\\ &= \\int_a^b \\sqrt{u'(t)^2\\,\\vec{r}_u\\cdot\\vec{r}_u + 2u'(t)v'(t)\\, \\vec{r}_u\\cdot\\vec{r}_v+ v'(t)^2\\,\\vec{r}_v\\cdot\\vec{r}_v}\\,\\,\\, dt. \\end{array}\\\\";
latex += "\\end{array}";
// String latex = "\\text{A long division \\longdiv{12345}{13}";
// String latex = "{a \\bangle b} {c \\brace d} {e \\brack f} {g \\choose h}";
// String latex = "\\begin{array}{cc}";
// latex += "\\fbox{\\text{A framed box with \\textdbend}}&\\shadowbox{\\text{A shadowed box}}\\cr";
// latex += "\\doublebox{\\text{A double framed box}}&\\ovalbox{\\text{An oval framed box}}\\cr";
// latex += "\\end{array}";
final JLatexMathPlugin.Config config = new JLatexMathPlugin.Config(textView.getTextSize()) {{
// align = JLatexMathDrawable.ALIGN_RIGHT;
}};
final String markdown = "# Example of LaTeX\n\n$$"
+ latex + "$$\n\n something like **this**";
final Markwon markwon = Markwon.builder(this)
.usePlugin(ImagesPlugin.create(this))
.usePlugin(JLatexMathPlugin.create(config))
.build();
markwon.setMarkdown(textView, markdown);
} }
} }

View File

@ -31,6 +31,7 @@ import ru.noties.markwon.image.svg.SvgPlugin;
import ru.noties.markwon.recycler.MarkwonAdapter; import ru.noties.markwon.recycler.MarkwonAdapter;
import ru.noties.markwon.recycler.SimpleEntry; import ru.noties.markwon.recycler.SimpleEntry;
import ru.noties.markwon.sample.R; import ru.noties.markwon.sample.R;
import ru.noties.markwon.syntax.SyntaxHighlightPlugin;
import ru.noties.markwon.urlprocessor.UrlProcessor; import ru.noties.markwon.urlprocessor.UrlProcessor;
import ru.noties.markwon.urlprocessor.UrlProcessorRelativeToAbsolute; import ru.noties.markwon.urlprocessor.UrlProcessorRelativeToAbsolute;

View File

@ -0,0 +1,17 @@
package ru.noties.markwon.sample.theme;
import android.app.Activity;
import android.os.Bundle;
import android.support.annotation.Nullable;
import ru.noties.markwon.sample.R;
public class ThemeActivity extends Activity {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_text_view);
}
}

View File

@ -1,6 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
@ -12,6 +10,6 @@
android:padding="8dip" android:padding="8dip"
android:textAppearance="?android:attr/textAppearanceMedium" android:textAppearance="?android:attr/textAppearanceMedium"
android:textSize="15sp" android:textSize="15sp"
tools:text="@string/input"/> tools:text="whatever" />
</ScrollView> </ScrollView>

View File

@ -1,3 +1,14 @@
<resources> <resources>
<string name="app_name">MarkwonSample</string> <string name="app_name">MarkwonSample</string>
<string name="input"><![CDATA[
# Hello! @ic-android-black-24\n\n
Home 36 black: @ic-home-black-36\n\n
Memory 48 black: @ic-memory-black-48\n\n
### I AM ANOTHER HEADER\n\n
Sentiment Satisfied 64 red: @ic-sentiment_satisfied-red-64
]]>
</string>
</resources> </resources>

View File

@ -11,6 +11,4 @@ include ':app', ':sample',
':markwon-image-svg', ':markwon-image-svg',
':markwon-recycler', ':markwon-recycler',
':markwon-syntax-highlight', ':markwon-syntax-highlight',
':markwon-test-span', ':markwon-test-span'
':sample-custom-extension',
':sample-latex-math'