Working on core module documentation
This commit is contained in:
		
							parent
							
								
									02e7539881
								
							
						
					
					
						commit
						d91f367e0a
					
				| @ -17,7 +17,7 @@ | ||||
|       </p> | ||||
|       <p> | ||||
|         <em> | ||||
|           ** For a little more sophisticated commonmark sandbox editor | ||||
|           ** For a more sophisticated commonmark sandbox editor | ||||
|           <a href="https://spec.commonmark.org/dingus/">the dingus</a> can be used. | ||||
|         </em> | ||||
|       </p> | ||||
|  | ||||
| @ -1,24 +1,33 @@ | ||||
| module.exports = { | ||||
|     base: '/Markwon/', | ||||
|     title: 'Markwon', | ||||
|     description: 'Android markdown library based on commonmark specification', | ||||
|     description: 'Android markdown library based on commonmark specification that renders markdown as system-native Spannables (no WebView)', | ||||
|     head: [ | ||||
|         ['link', { rel: 'apple-touch-icon', sizes: '180x180', href: '/apple-touch-icon.png?v=1' }], | ||||
|         ['link', { rel: 'icon', type: 'image/png', sizes: '16x16', href: '/favicon-16x16.png?v=1' }], | ||||
|         ['link', { rel: 'icon', href: '/favicon.ico?v=1' }], | ||||
|         ['link', { rel: 'icon', type: 'image/png', sizes: '32x32', href: '/favicon-32x32.png?v=1' }], | ||||
|         ['link', { rel: 'manifest', href: '/manifest.json?v=1' }], | ||||
|         ['meta', { name: 'keywords', content: 'android,markdown,library,spannable,markwon,commonmark' }] | ||||
|     ], | ||||
|     themeConfig: { | ||||
|         nav: [ | ||||
|             { text: 'Install', link: '/docs/install.md' }, | ||||
|             { text: 'Changelog', link: '/CHANGELOG.md' }, | ||||
|             { | ||||
|                 text: 'API Version', | ||||
|                 items: [ | ||||
|                     { text: 'Current (3.x.x)', link: '/' }, | ||||
|                     { text: 'Legacy (2.x.x)', link: '/docs/v2/' } | ||||
|                 ] | ||||
|             }, | ||||
|             { text: 'Sandbox', link: '/sandbox.md' }, | ||||
|             { text: 'Donate', link: '/donate.md' }, | ||||
|             { text: 'Github', link: 'https://github.com/noties/Markwon' } | ||||
|         ], | ||||
|         sidebar: { | ||||
|             '/docs/v2/': [ | ||||
|                 'install.md', | ||||
|                 '', | ||||
|                 'getting-started.md', | ||||
|                 'configure.md', | ||||
|                 'theme.md', | ||||
| @ -34,7 +43,13 @@ module.exports = { | ||||
|                     title: 'Core', | ||||
|                     children: [ | ||||
|                         '/docs/core/getting-started.md', | ||||
|                         '/docs/core/theme.md' | ||||
|                         '/docs/core/plugins.md', | ||||
|                         '/docs/core/theme.md', | ||||
|                         '/docs/core/images.md', | ||||
|                         '/docs/core/configuration.md', | ||||
|                         '/docs/core/visitor.md', | ||||
|                         '/docs/core/spans-factory.md', | ||||
|                         '/docs/core/html-renderer.md' | ||||
|                     ] | ||||
|                 }, | ||||
|                 '/docs/ext-latex/', | ||||
| @ -57,8 +72,7 @@ module.exports = { | ||||
|                 }, | ||||
|                 '/docs/recycler/recycler.md', | ||||
|                 '/docs/syntax-highlight/syntax-highlight.md', | ||||
|                 '/docs/migration-2-3.md', | ||||
|                 ['/docs/v2/install.md', 'Legacy 2.x.x documentation'] | ||||
|                 '/docs/migration-2-3.md' | ||||
|             ] | ||||
|         }, | ||||
|         sidebarDepth: 2, | ||||
|  | ||||
| @ -1,226 +0,0 @@ | ||||
| # 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/image-loader.md) | ||||
| ::: | ||||
| 
 | ||||
| ## Theme | ||||
| 
 | ||||
| `SpannableTheme` controls how markdown is rendered. It has pretty extensive number of | ||||
| options that can be found [here](/docs/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/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/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: `` 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: `` 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/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/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/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). | ||||
							
								
								
									
										1
									
								
								docs/docs/core/configuration.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								docs/docs/core/configuration.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| # Configuration | ||||
| @ -81,39 +81,28 @@ rawInput = plugins.reduce(rawInput, (input, plugin) -> plugin.processMarkdown(in | ||||
| // 1. after input is processed it's being parsed to a Node | ||||
| node = parser.parse(rawInput); | ||||
| 
 | ||||
| // 2. each plugin will configure RenderProps | ||||
| plugins.forEach(plugin -> plugin.configureRenderProps(renderProps)); | ||||
| 
 | ||||
| // 3. each plugin will be able to inspect or manipulate resulting Node | ||||
| // 2. each plugin will be able to inspect or manipulate resulting Node | ||||
| //  before rendering | ||||
| plugins.forEach(plugin -> plugin.beforeRender(node)); | ||||
| 
 | ||||
| // 4. node is being visited by a visitor | ||||
| // 3. node is being visited by a visitor | ||||
| node.accept(visitor); | ||||
| 
 | ||||
| // 5. each plugin will be called after node is being visited (aka rendered) | ||||
| // 4. each plugin will be called after node is being visited (aka rendered) | ||||
| plugins.forEach(plugin -> plugin.afterRender(node, visitor)); | ||||
| 
 | ||||
| // 6. styled markdown ready at this point | ||||
| // 5. styled markdown ready at this point | ||||
| final Spanned markdown = visitor.markdown(); | ||||
| 
 | ||||
| // 7. each plugin will be called before styled markdown is applied to a TextView | ||||
| // 6. each plugin will be called before styled markdown is applied to a TextView | ||||
| plugins.forEach(plugin -> plugin.beforeSetText(textView, markdown)); | ||||
| 
 | ||||
| // 8. markdown is applied to a TextView | ||||
| // 7. markdown is applied to a TextView | ||||
| textView.setText(markdown); | ||||
| 
 | ||||
| // 9. each plugin will be called after markdown is applied to a TextView | ||||
| // 8. each plugin will be called after markdown is applied to a TextView | ||||
| plugins.forEach(plugin -> plugin.afterSetText(textView)); | ||||
| ``` | ||||
| 
 | ||||
| As you can see a `plugin` is what lifts the most weight. We will cover | ||||
| plugins next. | ||||
| 
 | ||||
| :::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. | ||||
| ::: | ||||
							
								
								
									
										1
									
								
								docs/docs/core/html-renderer.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								docs/docs/core/html-renderer.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| # HTML Renderer | ||||
							
								
								
									
										1
									
								
								docs/docs/core/images.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								docs/docs/core/images.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| # Images | ||||
							
								
								
									
										424
									
								
								docs/docs/core/plugins.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										424
									
								
								docs/docs/core/plugins.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,424 @@ | ||||
| # Plugins <Badge text="3.0.0" /> | ||||
| 
 | ||||
| Since <Badge text="3.0.0" /> `MarkwonPlugin` takes the key role in | ||||
| processing and rendering markdown. Even **core** functionaly is abstracted | ||||
| into a `CorePlugin`. So it's still possible to use `Markwon` with a completely | ||||
| own set of plugins. | ||||
| 
 | ||||
| To register a plugin `Markwon.Builder` must be used: | ||||
| 
 | ||||
| ```java | ||||
| Markwon.builder(context) | ||||
|     .usePlugin(CorePlugin.create()) | ||||
|     .build(); | ||||
| ``` | ||||
| 
 | ||||
| All the process of transforming _raw_ markdown into a styled text (Spanned) | ||||
| will go through plugins. A plugin can: | ||||
| 
 | ||||
| * [configure commonmark-java `Parser`](#parser) | ||||
| * [configure `MarkwonTheme`](#markwontheme) | ||||
| * [configure `AsyncDrawableLoader` (used to display images in markdown)](#images) | ||||
| * [configure `MarkwonConfiguration`](#configuration) | ||||
| * [configure `MarkwonVisitor` (extensible commonmark-java Node visitor)](#visitor) | ||||
| * [configure `MarkwonSpansFactory` (factory to hold spans information for each Node)](#spans-factory) | ||||
| * [configure `MarkwonHtmlRenderer` (utility to properly display HTML in markdown)](#html-renderer) | ||||
| 
 | ||||
| --- | ||||
| 
 | ||||
| * [declare a dependency on another plugin (will be used as a runtime validator)](#priority) | ||||
| 
 | ||||
| --- | ||||
| 
 | ||||
| * [process raw input markdown before parsing it](#process-markdown) | ||||
| * [inspect/modify commonmark-java Node after it's been parsed, but before rendering](#inspect-modify-node) | ||||
| * [inspect commonmark-java Node after it's been rendered](#inspect-node-after-render) | ||||
| * [prepare TextView to display markdown _before_ markdown is applied to a TextView](#prepare-textview) | ||||
| * [post-process TextView _after_ markdown was applied](#textview-after-markdown-applied) | ||||
| 
 | ||||
| :::tip | ||||
| if you need to override only few methods of `MarkwonPlugin` (since it is an interface), | ||||
| `AbstractMarkwonPlugin` can be used. | ||||
| ::: | ||||
| 
 | ||||
| ## Parser | ||||
| 
 | ||||
| For example, let's register a new commonmark-java Parser extension: | ||||
| 
 | ||||
| ```java | ||||
| final Markwon markwon = Markwon.builder(context) | ||||
|         .usePlugin(CorePlugin.create()) | ||||
|         .usePlugin(new AbstractMarkwonPlugin() { | ||||
|             @Override | ||||
|             public void configureParser(@NonNull Parser.Builder builder) { | ||||
|                 // no need to call `super.configureParser(builder)` | ||||
|                 builder.extensions(Collections.singleton(StrikethroughExtension.create())); | ||||
|             } | ||||
|         }) | ||||
|         .build(); | ||||
| ``` | ||||
| 
 | ||||
| There are no limitations on what to do with commonmark-java Parser. For more info | ||||
| _what_ can be done please refer to <Link name="commonmark-java" displayName="commonmark-java documentation" />. | ||||
| 
 | ||||
| ## MarkwonTheme | ||||
| 
 | ||||
| Starting <Badge text="3.0.0" /> `MarkwonTheme` represents _core_ theme. Aka theme for | ||||
| things core module knows of. For example it doesn't know anything about `strikethrough` | ||||
| or `tables` (as they belong to different modules). | ||||
| 
 | ||||
| ```java | ||||
| final Markwon markwon = Markwon.builder(context) | ||||
|         .usePlugin(new AbstractMarkwonPlugin() { | ||||
|             @Override | ||||
|             public void configureTheme(@NonNull MarkwonTheme.Builder builder) { | ||||
|                 builder | ||||
|                         .codeTextColor(Color.BLACK) | ||||
|                         .codeBackgroundColor(Color.GREEN); | ||||
|             } | ||||
|         }) | ||||
|         .build(); | ||||
| ``` | ||||
| 
 | ||||
| :::warning | ||||
| `CorePlugin` has special handling - it will be **implicitly** added | ||||
| if a plugin declares dependency on it. This is why in previous example we haven't | ||||
| added CorePlugin _explicitly_ as `AbstractMarkwonPlugin` declares a dependency on it. | ||||
| If it's not desireable override `AbstractMarkwonPlugin#priority` method to specify own rules. | ||||
| ::: | ||||
| 
 | ||||
| More information about `MarkwonTheme` can be found [here](/docs/core/theme.md). | ||||
| 
 | ||||
| 
 | ||||
| ## Images | ||||
| 
 | ||||
| Since <Badge text="3.0.0" /> core images functionality moved to the `core` module. | ||||
| Now `Markwon` comes bundled with support for regular images (no `SVG` or `GIF`, they | ||||
| defined in standalone modules now). And 3(4) schemes supported by default: | ||||
| * http (+https; using system built-in `HttpURLConnection`) | ||||
| * file (including Android assets) | ||||
| * data (image inline, `data:image/svg+xml;base64,!@#$%^&*(`) | ||||
| 
 | ||||
| ```java | ||||
| final Markwon markwon = Markwon.builder(context) | ||||
|         .usePlugin(ImagesPlugin.create()) | ||||
|         .usePlugin(new AbstractMarkwonPlugin() { | ||||
|             @Override | ||||
|             public void configureImages(@NonNull AsyncDrawableLoader.Builder builder) { | ||||
|                 // sorry, these are not bundled with the library | ||||
|                 builder | ||||
|                         .addSchemeHandler("ftp", new FtpSchemeHandler("root", "")) | ||||
|                         .addMediaDecoder("text/plain", new AnsiiMediaDecoder()); | ||||
|             } | ||||
|         }) | ||||
|         .build(); | ||||
| ``` | ||||
| 
 | ||||
| :::warning | ||||
| Although `ImagesPlugin` is bundled with the `core` artifact, it is **not** used by default | ||||
| and one must **explicitly** add it: | ||||
| 
 | ||||
| ```java | ||||
| Markwon.builder(context) | ||||
|         .usePlugin(ImagesPlugin.create(context)); | ||||
| ``` | ||||
| 
 | ||||
| Without explicit usage of `ImagesPlugin` all image configuration will be ignored (no-op'ed) | ||||
| ::: | ||||
| 
 | ||||
| More information about dealing with images can be found [here](/docs/core/images.md) | ||||
| 
 | ||||
| 
 | ||||
| ## Configuration | ||||
| 
 | ||||
| `MarkwonConfiguration` is a set of common tools that are used by different parts | ||||
| of `Markwon`. It allows configurations of these: | ||||
| 
 | ||||
| * `SyntaxHighlight` (highlighting code blocks) | ||||
| * `LinkResolver` (opens links in markdown) | ||||
| * `UrlProcessor` (process URLs in markdown for both links and images) | ||||
| * `MarkwonHtmlParser` (HTML parser) | ||||
| * `ImageSizeResolver` (resolve image sizes, like `fit-to-canvas`, etc) | ||||
| 
 | ||||
| ```java | ||||
| final Markwon markwon = Markwon.builder(context) | ||||
|         .usePlugin(new AbstractMarkwonPlugin() { | ||||
|             @Override | ||||
|             public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) { | ||||
|                 // MarkwonHtmlParserImpl is defined in `markwon-html` artifact | ||||
|                 builder.htmlParser(MarkwonHtmlParserImpl.create()); | ||||
|             } | ||||
|         }) | ||||
|         .build(); | ||||
| ``` | ||||
| 
 | ||||
| More information about `MarkwonConfiguration` can be found [here](/docs/core/configuration.md) | ||||
| 
 | ||||
| 
 | ||||
| ## Visitor | ||||
| 
 | ||||
| `MarkwonVisitor` <Badge text="3.0.0" /> is commonmark-java Visitor that allows | ||||
| configuration of how each Node is visited. There is no longer need to create | ||||
| own subclass of Visitor and override required methods (like in `2.x.x` versions). | ||||
| `MarkwonVisitor` also allows registration of Nodes, that `core` module knows | ||||
| nothing about (instead of relying on `visit(CustomNode)` method)). | ||||
| 
 | ||||
| For example, let's add `strikethrough` Node visitor: | ||||
| 
 | ||||
| ```java | ||||
| final Markwon markwon = Markwon.builder(context) | ||||
|         .usePlugin(new AbstractMarkwonPlugin() { | ||||
|             @Override | ||||
|             public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) { | ||||
|                 builder | ||||
|                         .on(Strikethrough.class, new MarkwonVisitor.NodeVisitor<Strikethrough>() { | ||||
|                             @Override | ||||
|                             public void visit(@NonNull MarkwonVisitor visitor, @NonNull Strikethrough strikethrough) { | ||||
|                                 final int length = visitor.length(); | ||||
|                                 visitor.visitChildren(strikethrough); | ||||
|                                 visitor.setSpansForNodeOptional(strikethrough, length); | ||||
|                             } | ||||
|                         }); | ||||
|             } | ||||
|         }) | ||||
|         .build(); | ||||
| ``` | ||||
| 
 | ||||
| :::tip | ||||
| `MarkwonVisitor` also allows _overriding_ already registered nodes. For example, | ||||
| we can disable `Heading` Node rendering: | ||||
| 
 | ||||
| ```java | ||||
| builder.on(Heading.class, null); | ||||
| ``` | ||||
| 
 | ||||
| Please note that `Priority` plays nicely here to ensure that your | ||||
| custom Node override/disable happens _after_ some plugin defines it. | ||||
| ::: | ||||
| 
 | ||||
| More information about `MarkwonVisitor` can be found [here](/docs/core/visitor.md) | ||||
| 
 | ||||
| 
 | ||||
| ## Spans Factory | ||||
| 
 | ||||
| `MarkwonSpansFactory` <Badge text="3.0.0" /> is an abstract factory (factory that produces other factories) | ||||
| for spans that `Markwon` uses. It controls what spans to use for certain Nodes. | ||||
| 
 | ||||
| ```java | ||||
| final Markwon markwon = Markwon.builder(context) | ||||
|         .usePlugin(new AbstractMarkwonPlugin() { | ||||
|             @Override | ||||
|             public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) { | ||||
|                 // override emphasis factory to make all emphasis nodes underlined | ||||
|                 builder.setFactory(Emphasis.class, new SpanFactory() { | ||||
|                     @Override | ||||
|                     public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) { | ||||
|                         return new UnderlineSpan(); | ||||
|                     } | ||||
|                 }); | ||||
|             } | ||||
|         }) | ||||
|         .build(); | ||||
| ``` | ||||
| 
 | ||||
| :::tip | ||||
| `SpanFactory` allows to return an _array_ of spans to apply multiple spans | ||||
| for a Node: | ||||
| 
 | ||||
| ```java | ||||
| @Override | ||||
| public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) { | ||||
|     // make underlined and set text color to red | ||||
|     return new Object[]{ | ||||
|             new UnderlineSpan(), | ||||
|             new ForegroundColorSpan(Color.RED) | ||||
|     }; | ||||
| } | ||||
| ``` | ||||
| ::: | ||||
| 
 | ||||
| More information about spans factory can be found [here](/docs/core/spans-factory.md) | ||||
| 
 | ||||
| 
 | ||||
| ## HTML Renderer | ||||
| 
 | ||||
| `MarkwonHtmlRenderer` controls how HTML is rendered in markdown. | ||||
| 
 | ||||
| ```java | ||||
| final Markwon markwon = Markwon.builder(context) | ||||
|         .usePlugin(HtmlPlugin.create()) | ||||
|         .usePlugin(new AbstractMarkwonPlugin() { | ||||
|             @Override | ||||
|             public void configureHtmlRenderer(@NonNull MarkwonHtmlRenderer.Builder builder) { | ||||
|                 // <center> tag handling (deprecated but valid in our case) | ||||
|                 // can be any tag name, there is no connection with _real_ HTML tags, | ||||
|                 // <just-try-to-not-go-crazy-and-remember-about-portability> | ||||
|                 builder.addHandler("center", new SimpleTagHandler() { | ||||
|                     @Override | ||||
|                     public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps renderProps, @NonNull HtmlTag tag) { | ||||
|                         return new AlignmentSpan() { | ||||
|                             @Override | ||||
|                             public Layout.Alignment getAlignment() { | ||||
|                                 return Layout.Alignment.ALIGN_CENTER; | ||||
|                             } | ||||
|                         }; | ||||
|                     } | ||||
|                 }); | ||||
|             } | ||||
|         }) | ||||
|         .build(); | ||||
| ``` | ||||
| 
 | ||||
| :::danger | ||||
| Although `MarkwonHtmlRenderer` is bundled with `core` artifact, actual | ||||
| HTML parser is placed in a standalone artifact and must be added to your | ||||
| project **explicitly** and then registered via `Markwon.Builder#usePlugin(HtmlPlugin.create())`. | ||||
| If not done so, no HTML will be parsed nor rendered. | ||||
| ::: | ||||
| 
 | ||||
| More information about HTML rendering can be found [here](/docs/core/html-renderer.md) | ||||
| 
 | ||||
| 
 | ||||
| ## Priority | ||||
| 
 | ||||
| `Priority` is an abstraction to _state_ dependency connection between plugins. It is | ||||
| also used as a runtime graph validator. If a plugin defines a dependency on other, but | ||||
| _other_ is not in resulting `Markwon` instance, then a runtime exception will be thrown. | ||||
| `Priority` is also defines the order in which plugins will be placed. So, if a plugin `A` | ||||
| states a plugin `B` as a dependency, then plugin `A` will come **after** plugin `B`. | ||||
| 
 | ||||
| ```java | ||||
| final Markwon markwon = Markwon.builder(context) | ||||
|         .usePlugin(new AbstractMarkwonPlugin() { | ||||
|             @NonNull | ||||
|             @Override | ||||
|             public Priority priority() { | ||||
|                 return Priority.after(CorePlugin.class); | ||||
|             } | ||||
|         }) | ||||
|         .build(); | ||||
| ``` | ||||
| 
 | ||||
| :::warning | ||||
| Please note that `AbstractMarkwonPlugin` _implicitly_ defines `CorePlugin` | ||||
| as a dependency (`return Priority.after(CorePlugin.class);`). This will | ||||
| also add `CorePlugin` to a `Markwon` instance, because it will be added | ||||
| _implicitly_ if a plugin defines it as a dependency.  | ||||
| ::: | ||||
| 
 | ||||
| Use one of the factory methods to create a `Priority` instance: | ||||
| 
 | ||||
| ```java | ||||
| // none | ||||
| Priority.none(); | ||||
| 
 | ||||
| // single dependency | ||||
| Priority.after(CorePlugin.class); | ||||
| 
 | ||||
| // 2 dependencies | ||||
| Priority.after(CorePlugin.class, ImagesPlugin.class); | ||||
| 
 | ||||
| // for a number >2, use #builder | ||||
| Priority.builder() | ||||
|         .after(CorePlugin.class) | ||||
|         .after(ImagesPlugin.class) | ||||
|         .after(StrikethroughPlugin.class) | ||||
|         .build(); | ||||
| ``` | ||||
| 
 | ||||
| ## Process markdown | ||||
| 
 | ||||
| A plugin can be used to _pre-process_ input markdown (this will be called before _parsing_): | ||||
| 
 | ||||
| ```java | ||||
| final Markwon markwon = Markwon.builder(context) | ||||
|         .usePlugin(new AbstractMarkwonPlugin() { | ||||
|             @NonNull | ||||
|             @Override | ||||
|             public String processMarkdown(@NonNull String markdown) { | ||||
|                 return markdown.replaceAll("foo", "bar"); | ||||
|             } | ||||
|         }) | ||||
|         .build(); | ||||
| ``` | ||||
| 
 | ||||
| ## Inspect/modify Node | ||||
| 
 | ||||
| A plugin can inspect/modify commonmark-java Node _before_ it's being rendered. | ||||
| 
 | ||||
| ```java | ||||
| final Markwon markwon = Markwon.builder(context) | ||||
|         .usePlugin(new AbstractMarkwonPlugin() { | ||||
|             @Override | ||||
|             public void beforeRender(@NonNull Node node) { | ||||
| 
 | ||||
|                 // for example inspect it with custom visitor | ||||
|                 node.accept(new MyVisitor()); | ||||
| 
 | ||||
|                 // or modify (you know what you are doing, right?) | ||||
|                 node.appendChild(new Text("Appended")); | ||||
|             } | ||||
|         }) | ||||
|         .build(); | ||||
| ``` | ||||
| 
 | ||||
| ## Inspect Node after render | ||||
| 
 | ||||
| A plugin can inspect commonmark-java Node after it's been rendered. | ||||
| Modifying Node at this point makes not much sense (it's already been | ||||
| rendered and all modifications won't change anything). But this method can be used, | ||||
| for example, to clean-up some internal state (after rendering). Generally | ||||
| speaking, a plugin must be stateless, but if it cannot, then this method is | ||||
| the best place to clean-up. | ||||
| 
 | ||||
| ```java | ||||
| final Markwon markwon = Markwon.builder(context) | ||||
|         .usePlugin(new AbstractMarkwonPlugin() { | ||||
|             @Override | ||||
|             public void afterRender(@NonNull Node node, @NonNull MarkwonVisitor visitor) { | ||||
|                 cleanUp(); | ||||
|             } | ||||
|         }) | ||||
|         .build(); | ||||
| ``` | ||||
| 
 | ||||
| ## Prepare TextView | ||||
| 
 | ||||
| A plugin can _prepare_ a TextView before markdown is applied. For example `images` | ||||
| unschedules all previously scheduled `AsyncDrawableSpans` (if any) here. This way | ||||
| when new markdown (and set of Spannables) arrives, previous set won't be kept in | ||||
| memory and could be garbage-collected. | ||||
| 
 | ||||
| ```java | ||||
| final Markwon markwon = Markwon.builder(context) | ||||
|         .usePlugin(new AbstractMarkwonPlugin() { | ||||
|             @Override | ||||
|             public void beforeSetText(@NonNull TextView textView, @NonNull Spanned markdown) { | ||||
|                 // clean-up previous | ||||
|                 AsyncDrawableScheduler.unschedule(textView); | ||||
|             } | ||||
|         }) | ||||
|         .build(); | ||||
| ``` | ||||
| 
 | ||||
| ## TextView after markdown applied | ||||
| 
 | ||||
| A plugin will receive a callback _after_ markdown is applied to a TextView. | ||||
| For example `images` uses this callback to schedule new set of Spannables. | ||||
| 
 | ||||
| ```java | ||||
| final Markwon markwon = Markwon.builder(context) | ||||
|         .usePlugin(new AbstractMarkwonPlugin() { | ||||
|             @Override | ||||
|             public void afterSetText(@NonNull TextView textView) { | ||||
|                 AsyncDrawableScheduler.schedule(textView); | ||||
|             } | ||||
|         }) | ||||
|         .build(); | ||||
| ``` | ||||
| 
 | ||||
| :::tip | ||||
| Please note that unlike `#beforeSetText`, `#afterSetText` won't receive | ||||
| `Spanned` markdown. This happens because at this point spans must be | ||||
| queried directly from a TextView. | ||||
| ::: | ||||
							
								
								
									
										1
									
								
								docs/docs/core/spans-factory.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								docs/docs/core/spans-factory.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| # Spans Factory | ||||
							
								
								
									
										1
									
								
								docs/docs/core/visitor.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								docs/docs/core/visitor.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| # Visitor | ||||
| @ -1,61 +0,0 @@ | ||||
| # 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) | ||||
|     }; | ||||
| } | ||||
| ``` | ||||
| ::: | ||||
| @ -1 +1,8 @@ | ||||
| # Migration 2.x.x -> 3.x.x | ||||
| # Migration 2.x.x -> 3.x.x | ||||
| 
 | ||||
| * strikethrough moved to standalone module | ||||
| * tables moved to standalone module | ||||
| * core functionality of `AsyncDrawableLoader` moved to `core` module | ||||
| * * Handling of GIF and SVG media moved to standalone modules (`gif` and `svg` respectively) | ||||
| * * OkHttpClient to download images moved to standalone module | ||||
| * HTML no longer _implicitly_ added to core functionality, it must be specified __explicitly__ (as an artifact) | ||||
							
								
								
									
										7
									
								
								docs/donate.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								docs/donate.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| # Donations | ||||
| 
 | ||||
| If you find this library useful consider making a donation  | ||||
| to your local [environmental](https://en.wikipedia.org/wiki/List_of_environmental_organizations)  | ||||
| or [human rights](https://en.wikipedia.org/wiki/List_of_human_rights_organisations) organization. | ||||
| 
 | ||||
| Thank you | ||||
| @ -57,11 +57,6 @@ public abstract class AbstractMarkwonPlugin implements MarkwonPlugin { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void configureRenderProps(@NonNull RenderProps renderProps) { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @Override | ||||
|     public Priority priority() { | ||||
|  | ||||
| @ -46,14 +46,7 @@ class MarkwonImpl extends Markwon { | ||||
|     @Override | ||||
|     public Spanned render(@NonNull Node node) { | ||||
| 
 | ||||
|         final RenderProps renderProps = visitor.renderProps(); | ||||
| 
 | ||||
|         for (MarkwonPlugin plugin : plugins) { | ||||
| 
 | ||||
|             // let plugins apply render properties before rendering (as we will clear | ||||
|             // renderProps after rendering) | ||||
|             plugin.configureRenderProps(renderProps); | ||||
| 
 | ||||
|             plugin.beforeRender(node); | ||||
|         } | ||||
| 
 | ||||
|  | ||||
| @ -82,19 +82,6 @@ public interface MarkwonPlugin { | ||||
|      */ | ||||
|     void configureHtmlRenderer(@NonNull MarkwonHtmlRenderer.Builder builder); | ||||
| 
 | ||||
|     /** | ||||
|      * A method to store some arbitrary data in {@link RenderProps}. Although it won\'t make | ||||
|      * much sense to use existing {@link Prop} keys for {@link SpanFactory}, it can be helpful | ||||
|      * to establish a communication channel between multiple plugins in decoupled way (provide | ||||
|      * some initial properties for example or indicate that certain plugin is registered). | ||||
|      * <p> | ||||
|      * This method will be called before <em>each</em> rendering step (after rendering {@link RenderProps} | ||||
|      * will be cleared. This method <strong>won\'t</strong> be called during initialization stage. | ||||
|      * | ||||
|      * @see RenderProps | ||||
|      */ | ||||
|     void configureRenderProps(@NonNull RenderProps renderProps); | ||||
| 
 | ||||
|     @NonNull | ||||
|     Priority priority(); | ||||
| 
 | ||||
|  | ||||
| @ -3,6 +3,8 @@ package ru.noties.markwon.html; | ||||
| import android.support.annotation.NonNull; | ||||
| import android.support.annotation.Nullable; | ||||
| 
 | ||||
| import java.util.Collection; | ||||
| 
 | ||||
| import ru.noties.markwon.MarkwonVisitor; | ||||
| 
 | ||||
| /** | ||||
| @ -39,19 +41,11 @@ public abstract class MarkwonHtmlRenderer { | ||||
|         @NonNull | ||||
|         Builder allowNonClosedTags(boolean allowNonClosedTags); | ||||
| 
 | ||||
|         /** | ||||
|          * Please note that if there is already a {@link TagHandler} registered with specified | ||||
|          * {@code tagName} it will be replaced with newly supplied one. | ||||
|          * | ||||
|          * @param tagHandler {@link TagHandler} | ||||
|          * @param tagName    name of a tag | ||||
|          * @return self | ||||
|          */ | ||||
|         @NonNull | ||||
|         Builder addHandler(@NonNull TagHandler tagHandler, @NonNull String tagName); | ||||
|         Builder addHandler(@NonNull String tagName, @NonNull TagHandler tagHandler); | ||||
| 
 | ||||
|         @NonNull | ||||
|         Builder addHandler(@NonNull TagHandler tagHandler, String... tagNames); | ||||
|         Builder addHandler(@NonNull Collection<String> tagNames, @NonNull TagHandler tagHandler); | ||||
| 
 | ||||
|         @NonNull | ||||
|         Builder removeHandler(@NonNull String tagName); | ||||
|  | ||||
| @ -3,6 +3,7 @@ package ru.noties.markwon.html; | ||||
| import android.support.annotation.NonNull; | ||||
| import android.support.annotation.Nullable; | ||||
| 
 | ||||
| import java.util.Collection; | ||||
| import java.util.Collections; | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| @ -99,14 +100,14 @@ class MarkwonHtmlRendererImpl extends MarkwonHtmlRenderer { | ||||
| 
 | ||||
|         @NonNull | ||||
|         @Override | ||||
|         public Builder addHandler(@NonNull TagHandler tagHandler, @NonNull String tagName) { | ||||
|         public Builder addHandler(@NonNull String tagName, @NonNull TagHandler tagHandler) { | ||||
|             tagHandlers.put(tagName, tagHandler); | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
|         @NonNull | ||||
|         @Override | ||||
|         public Builder addHandler(@NonNull TagHandler tagHandler, String... tagNames) { | ||||
|         public Builder addHandler(@NonNull Collection<String> tagNames, @NonNull TagHandler tagHandler) { | ||||
|             for (String tagName : tagNames) { | ||||
|                 if (tagName != null) { | ||||
|                     tagHandlers.put(tagName, tagHandler); | ||||
|  | ||||
| @ -223,7 +223,6 @@ public class MarkwonBuilderImplTest { | ||||
|         verify(plugin, atLeast(1)).priority(); | ||||
| 
 | ||||
|         // note, no render props -> they must be configured on render stage | ||||
|         verify(plugin, times(0)).configureRenderProps(any(RenderProps.class)); | ||||
|         verify(plugin, times(0)).processMarkdown(anyString()); | ||||
|         verify(plugin, times(0)).beforeRender(any(Node.class)); | ||||
|         verify(plugin, times(0)).afterRender(any(Node.class), any(MarkwonVisitor.class)); | ||||
|  | ||||
| @ -107,8 +107,6 @@ public class MarkwonImplTest { | ||||
|                 // mark this flag (we must ensure that this method body is executed) | ||||
|                 flag.set(true); | ||||
| 
 | ||||
|                 //noinspection ConstantConditions | ||||
|                 verify(plugin, times(1)).configureRenderProps(null); | ||||
|                 verify(plugin, times(1)).beforeRender(eq(node)); | ||||
|                 verify(plugin, times(0)).afterRender(any(Node.class), any(MarkwonVisitor.class)); | ||||
| 
 | ||||
| @ -175,8 +173,6 @@ public class MarkwonImplTest { | ||||
| 
 | ||||
|                 flag.set(true); | ||||
| 
 | ||||
|                 verify(visitor, times(1)).renderProps(); | ||||
|                 verify(plugin, times(1)).configureRenderProps(eq(renderProps)); | ||||
|                 verify(renderProps, times(0)).clearAll(); | ||||
| 
 | ||||
|                 return null; | ||||
|  | ||||
| @ -186,6 +186,7 @@ public class CorePluginTest { | ||||
|             add("configureVisitor"); | ||||
|             add("configureSpansFactory"); | ||||
|             add("beforeSetText"); | ||||
|             add("afterSetText"); | ||||
|             add("priority"); | ||||
|         }}; | ||||
| 
 | ||||
|  | ||||
| @ -22,6 +22,8 @@ import ru.noties.markwon.html.tag.SubScriptHandler; | ||||
| import ru.noties.markwon.html.tag.SuperScriptHandler; | ||||
| import ru.noties.markwon.html.tag.UnderlineHandler; | ||||
| 
 | ||||
| import static java.util.Arrays.asList; | ||||
| 
 | ||||
| /** | ||||
|  * @since 3.0.0 | ||||
|  */ | ||||
| @ -41,18 +43,41 @@ public class HtmlPlugin extends AbstractMarkwonPlugin { | ||||
| 
 | ||||
|     @Override | ||||
|     public void configureHtmlRenderer(@NonNull MarkwonHtmlRenderer.Builder builder) { | ||||
| 
 | ||||
|         builder | ||||
|                 .addHandler(new EmphasisHandler(), "i", "em", "cite", "dfn") | ||||
|                 .addHandler(new StrongEmphasisHandler(), "b", "strong") | ||||
|                 .addHandler(new SuperScriptHandler(), "sup") | ||||
|                 .addHandler(new SubScriptHandler(), "sub") | ||||
|                 .addHandler(new UnderlineHandler(), "u", "ins") | ||||
|                 .addHandler(new StrikeHandler(), "s", "del") | ||||
|                 .addHandler(new LinkHandler(), "a") | ||||
|                 .addHandler(new ListHandler(), "ul", "ol") | ||||
|                 .addHandler(ImageHandler.create(), "img") | ||||
|                 .addHandler(new BlockquoteHandler(), "blockquote") | ||||
|                 .addHandler(new HeadingHandler(), "h1", "h2", "h3", "h4", "h5", "h6"); | ||||
|                 .addHandler( | ||||
|                         "img", | ||||
|                         ImageHandler.create()) | ||||
|                 .addHandler( | ||||
|                         "a", | ||||
|                         new LinkHandler()) | ||||
|                 .addHandler( | ||||
|                         "blockquote", | ||||
|                         new BlockquoteHandler()) | ||||
|                 .addHandler( | ||||
|                         "sub", | ||||
|                         new SubScriptHandler()) | ||||
|                 .addHandler( | ||||
|                         "sup", | ||||
|                         new SuperScriptHandler()) | ||||
|                 .addHandler( | ||||
|                         asList("b", "strong"), | ||||
|                         new StrongEmphasisHandler()) | ||||
|                 .addHandler( | ||||
|                         asList("s", "del"), | ||||
|                         new StrikeHandler()) | ||||
|                 .addHandler( | ||||
|                         asList("u", "ins"), | ||||
|                         new UnderlineHandler()) | ||||
|                 .addHandler( | ||||
|                         asList("ul", "ol"), | ||||
|                         new ListHandler()) | ||||
|                 .addHandler( | ||||
|                         asList("i", "em", "cite", "dfn"), | ||||
|                         new EmphasisHandler()) | ||||
|                 .addHandler( | ||||
|                         asList("h1", "h2", "h3", "h4", "h5", "h6"), | ||||
|                         new HeadingHandler()); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Dimitry Ivanov
						Dimitry Ivanov