ImageDestinationProcessor (before UrlProcessor), limit usage to images only
This commit is contained in:
		
							parent
							
								
									21152f368f
								
							
						
					
					
						commit
						171b6d40a0
					
				| @ -9,6 +9,7 @@ | ||||
| * Expose `enabledBlockTypes` in `CorePlugin` | ||||
| * Update `jlatexmath-android` dependency ([#225]) | ||||
| * Update `image-coil` module (Coil version `0.10.1`) ([#244])<br>Thanks to [@tylerbwong] | ||||
| * Rename `UrlProcessor` to `ImageDestinationProcessor` (`io.noties.markwon.urlprocessor` -> `io.noties.markwon.image.destination`) and limit its usage to process **only** destination URL of images (was used to also process links before)  | ||||
| 
 | ||||
| [#235]: https://github.com/noties/Markwon/issues/235 | ||||
| [#225]: https://github.com/noties/Markwon/issues/225 | ||||
|  | ||||
| @ -5,15 +5,15 @@ import android.text.TextUtils; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| 
 | ||||
| import io.noties.markwon.urlprocessor.UrlProcessor; | ||||
| import io.noties.markwon.urlprocessor.UrlProcessorRelativeToAbsolute; | ||||
| import io.noties.markwon.image.destination.ImageDestinationProcessor; | ||||
| import io.noties.markwon.image.destination.ImageDestinationProcessorRelativeToAbsolute; | ||||
| 
 | ||||
| class UrlProcessorInitialReadme implements UrlProcessor { | ||||
| class ImageDestinationProcessorInitialReadme extends ImageDestinationProcessor { | ||||
| 
 | ||||
|     private static final String GITHUB_BASE = "https://github.com/noties/Markwon/raw/master/"; | ||||
| 
 | ||||
|     private final UrlProcessorRelativeToAbsolute processor | ||||
|             = new UrlProcessorRelativeToAbsolute(GITHUB_BASE); | ||||
|     private final ImageDestinationProcessorRelativeToAbsolute processor | ||||
|             = new ImageDestinationProcessorRelativeToAbsolute(GITHUB_BASE); | ||||
| 
 | ||||
|     @NonNull | ||||
|     @Override | ||||
| @ -24,6 +24,8 @@ import io.noties.markwon.ext.tables.TablePlugin; | ||||
| import io.noties.markwon.ext.tasklist.TaskListPlugin; | ||||
| import io.noties.markwon.html.HtmlPlugin; | ||||
| import io.noties.markwon.image.ImagesPlugin; | ||||
| import io.noties.markwon.image.destination.ImageDestinationProcessor; | ||||
| import io.noties.markwon.image.destination.ImageDestinationProcessorRelativeToAbsolute; | ||||
| import io.noties.markwon.image.file.FileSchemeHandler; | ||||
| import io.noties.markwon.image.gif.GifMediaDecoder; | ||||
| import io.noties.markwon.image.network.OkHttpNetworkSchemeHandler; | ||||
| @ -31,8 +33,6 @@ import io.noties.markwon.syntax.Prism4jTheme; | ||||
| import io.noties.markwon.syntax.Prism4jThemeDarkula; | ||||
| import io.noties.markwon.syntax.Prism4jThemeDefault; | ||||
| import io.noties.markwon.syntax.SyntaxHighlightPlugin; | ||||
| import io.noties.markwon.urlprocessor.UrlProcessor; | ||||
| import io.noties.markwon.urlprocessor.UrlProcessorRelativeToAbsolute; | ||||
| import io.noties.prism4j.Prism4j; | ||||
| 
 | ||||
| @ActivityScope | ||||
| @ -86,11 +86,11 @@ public class MarkdownRenderer { | ||||
|             } | ||||
| 
 | ||||
|             private void execute() { | ||||
|                 final UrlProcessor urlProcessor; | ||||
|                 final ImageDestinationProcessor imageDestinationProcessor; | ||||
|                 if (uri == null) { | ||||
|                     urlProcessor = new UrlProcessorInitialReadme(); | ||||
|                     imageDestinationProcessor = new ImageDestinationProcessorInitialReadme(); | ||||
|                 } else { | ||||
|                     urlProcessor = new UrlProcessorRelativeToAbsolute(uri.toString()); | ||||
|                     imageDestinationProcessor = new ImageDestinationProcessorRelativeToAbsolute(uri.toString()); | ||||
|                 } | ||||
| 
 | ||||
|                 final Prism4jTheme prism4jTheme = isLightTheme | ||||
| @ -119,7 +119,7 @@ public class MarkdownRenderer { | ||||
|                         .usePlugin(new AbstractMarkwonPlugin() { | ||||
|                             @Override | ||||
|                             public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) { | ||||
|                                 builder.urlProcessor(urlProcessor); | ||||
|                                 builder.imageDestinationProcessor(imageDestinationProcessor); | ||||
|                             } | ||||
|                         }) | ||||
|                         .build(); | ||||
|  | ||||
| @ -5,7 +5,7 @@ These are _configurable_ properties: | ||||
| * `AsyncDrawableLoader` (back here since <Badge text="4.0.0" />) | ||||
| * `SyntaxHighlight` | ||||
| * `LinkResolver` (since <Badge text="4.0.0" />, before — `LinkSpan.Resolver`) | ||||
| * `UrlProcessor` | ||||
| * `ImageDestinationProcessor` (since <Badge text="4.4.0" />, before — `UrlProcessor`) | ||||
| * `ImageSizeResolver` | ||||
| 
 | ||||
| :::tip | ||||
| @ -36,10 +36,11 @@ final Markwon markwon = Markwon.builder(context) | ||||
|         .build(); | ||||
| ``` | ||||
| 
 | ||||
| Currently `Markwon` provides 3 implementations for loading images: | ||||
| Currently `Markwon` provides 4 implementations for loading images: | ||||
| * [markwon implementation](/docs/v4/image/) with SVG, GIF, data uri and android_assets support | ||||
| * [based on Picasso](/docs/v4/image-picasso/) | ||||
| * [based on Glide](/docs/v4/image-glide/) | ||||
| * [base on Coil](/docs/v4/image-coil/) | ||||
| 
 | ||||
| ## SyntaxHighlight | ||||
| 
 | ||||
| @ -87,32 +88,32 @@ if there is none registered. if you wish to register own instance of a `Movement | ||||
| apply it directly to a TextView or use [MovementMethodPlugin](/docs/v4/core/movement-method-plugin.md) | ||||
| ::: | ||||
| 
 | ||||
| ## UrlProcessor | ||||
| ## ImageDestinationProcessor | ||||
| 
 | ||||
| Process URLs in your markdown (for links and images). If not provided explicitly,  | ||||
| Process destinations (URLs) of images in your markdown. If not provided explicitly,  | ||||
| default **no-op** implementation will be used, which does not modify URLs (keeping them as-is). | ||||
| 
 | ||||
| `Markwon` provides 2 implementations of `UrlProcessor`: | ||||
| * `UrlProcessorRelativeToAbsolute` | ||||
| * `UrlProcessorAndroidAssets` | ||||
| * `ImageDestinationProcessorRelativeToAbsolute` | ||||
| * `ImageDestinationProcessorAssets` | ||||
| 
 | ||||
| ### UrlProcessorRelativeToAbsolute | ||||
| ### ImageDestinationProcessorRelativeToAbsolute | ||||
| 
 | ||||
| `UrlProcessorRelativeToAbsolute` can be used to make relative URL absolute. For example if an image is | ||||
| defined like this: `` and `UrlProcessorRelativeToAbsolute` | ||||
| `ImageDestinationProcessorRelativeToAbsolute` can be used to make relative URL absolute. For example if an image is | ||||
| defined like this: `` and `ImageDestinationProcessorRelativeToAbsolute` | ||||
| is created with `https://github.com/noties/Markwon/raw/master/` as the base:  | ||||
| `new UrlProcessorRelativeToAbsolute("https://github.com/noties/Markwon/raw/master/")`, | ||||
| `new ImageDestinationProcessorRelativeToAbsolute("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 | ||||
| ### ImageDestinationProcessorAssets | ||||
| 
 | ||||
| `UrlProcessorAndroidAssets` can be used to make processed links to point to Android assets folder. | ||||
| `ImageDestinationProcessorAssets` can be used to make processed destinations to point to Android assets folder. | ||||
| So an image: `` will have `file:///android_asset/art/image.JPG` as the | ||||
| destination. | ||||
| 
 | ||||
| :::tip | ||||
| Please note that `UrlProcessorAndroidAssets` will process only URLs that have no `scheme` information, | ||||
| Please note that `ImageDestinationProcessorAssets` will process only URLs that have no `scheme` information, | ||||
| so a `./art/image.png` will become `file:///android_asset/art/image.JPG` whilst `https://so.me/where.png` | ||||
| will be kept as-is. | ||||
| ::: | ||||
|  | ||||
| @ -6,15 +6,13 @@ import io.noties.markwon.core.MarkwonTheme; | ||||
| import io.noties.markwon.image.AsyncDrawableLoader; | ||||
| import io.noties.markwon.image.ImageSizeResolver; | ||||
| import io.noties.markwon.image.ImageSizeResolverDef; | ||||
| import io.noties.markwon.image.destination.ImageDestinationProcessor; | ||||
| import io.noties.markwon.syntax.SyntaxHighlight; | ||||
| import io.noties.markwon.syntax.SyntaxHighlightNoOp; | ||||
| import io.noties.markwon.urlprocessor.UrlProcessor; | ||||
| import io.noties.markwon.urlprocessor.UrlProcessorNoOp; | ||||
| 
 | ||||
| /** | ||||
|  * since 3.0.0 renamed `SpannableConfiguration` -> `MarkwonConfiguration` | ||||
|  */ | ||||
| @SuppressWarnings("WeakerAccess") | ||||
| public class MarkwonConfiguration { | ||||
| 
 | ||||
|     @NonNull | ||||
| @ -26,7 +24,8 @@ public class MarkwonConfiguration { | ||||
|     private final AsyncDrawableLoader asyncDrawableLoader; | ||||
|     private final SyntaxHighlight syntaxHighlight; | ||||
|     private final LinkResolver linkResolver; | ||||
|     private final UrlProcessor urlProcessor; | ||||
|     // @since $nap; | ||||
|     private final ImageDestinationProcessor imageDestinationProcessor; | ||||
|     private final ImageSizeResolver imageSizeResolver; | ||||
| 
 | ||||
|     // @since 3.0.0 | ||||
| @ -37,7 +36,7 @@ public class MarkwonConfiguration { | ||||
|         this.asyncDrawableLoader = builder.asyncDrawableLoader; | ||||
|         this.syntaxHighlight = builder.syntaxHighlight; | ||||
|         this.linkResolver = builder.linkResolver; | ||||
|         this.urlProcessor = builder.urlProcessor; | ||||
|         this.imageDestinationProcessor = builder.imageDestinationProcessor; | ||||
|         this.imageSizeResolver = builder.imageSizeResolver; | ||||
|         this.spansFactory = builder.spansFactory; | ||||
|     } | ||||
| @ -62,9 +61,12 @@ public class MarkwonConfiguration { | ||||
|         return linkResolver; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @since $nap; | ||||
|      */ | ||||
|     @NonNull | ||||
|     public UrlProcessor urlProcessor() { | ||||
|         return urlProcessor; | ||||
|     public ImageDestinationProcessor imageDestinationProcessor() { | ||||
|         return imageDestinationProcessor; | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
| @ -87,7 +89,8 @@ public class MarkwonConfiguration { | ||||
|         private AsyncDrawableLoader asyncDrawableLoader; | ||||
|         private SyntaxHighlight syntaxHighlight; | ||||
|         private LinkResolver linkResolver; | ||||
|         private UrlProcessor urlProcessor; | ||||
|         // @since $nap; | ||||
|         private ImageDestinationProcessor imageDestinationProcessor; | ||||
|         private ImageSizeResolver imageSizeResolver; | ||||
|         private MarkwonSpansFactory spansFactory; | ||||
| 
 | ||||
| @ -115,9 +118,12 @@ public class MarkwonConfiguration { | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
|         /** | ||||
|          * @since $nap; | ||||
|          */ | ||||
|         @NonNull | ||||
|         public Builder urlProcessor(@NonNull UrlProcessor urlProcessor) { | ||||
|             this.urlProcessor = urlProcessor; | ||||
|         public Builder imageDestinationProcessor(@NonNull ImageDestinationProcessor imageDestinationProcessor) { | ||||
|             this.imageDestinationProcessor = imageDestinationProcessor; | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
| @ -151,8 +157,9 @@ public class MarkwonConfiguration { | ||||
|                 linkResolver = new LinkResolverDef(); | ||||
|             } | ||||
| 
 | ||||
|             if (urlProcessor == null) { | ||||
|                 urlProcessor = new UrlProcessorNoOp(); | ||||
|             // @since $nap; | ||||
|             if (imageDestinationProcessor == null) { | ||||
|                 imageDestinationProcessor = ImageDestinationProcessor.noOp(); | ||||
|             } | ||||
| 
 | ||||
|             if (imageSizeResolver == null) { | ||||
|  | ||||
| @ -320,7 +320,7 @@ public class CorePlugin extends AbstractMarkwonPlugin { | ||||
|                 final boolean link = parent instanceof Link; | ||||
| 
 | ||||
|                 final String destination = configuration | ||||
|                         .urlProcessor() | ||||
|                         .imageDestinationProcessor() | ||||
|                         .process(image.getDestination()); | ||||
| 
 | ||||
|                 final RenderProps props = visitor.renderProps(); | ||||
| @ -524,8 +524,7 @@ public class CorePlugin extends AbstractMarkwonPlugin { | ||||
|                 final int length = visitor.length(); | ||||
|                 visitor.visitChildren(link); | ||||
| 
 | ||||
|                 final MarkwonConfiguration configuration = visitor.configuration(); | ||||
|                 final String destination = configuration.urlProcessor().process(link.getDestination()); | ||||
|                 final String destination = link.getDestination(); | ||||
| 
 | ||||
|                 CoreProps.LINK_DESTINATION.set(visitor.renderProps(), destination); | ||||
| 
 | ||||
|  | ||||
| @ -0,0 +1,27 @@ | ||||
| package io.noties.markwon.image.destination; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| 
 | ||||
| /** | ||||
|  * Process destination of image nodes | ||||
|  * | ||||
|  * @since $nap; | ||||
|  */ | ||||
| public abstract class ImageDestinationProcessor { | ||||
|     @NonNull | ||||
|     public abstract String process(@NonNull String destination); | ||||
| 
 | ||||
|     @NonNull | ||||
|     public static ImageDestinationProcessor noOp() { | ||||
|         return new NoOp(); | ||||
|     } | ||||
| 
 | ||||
|     private static class NoOp extends ImageDestinationProcessor { | ||||
| 
 | ||||
|         @NonNull | ||||
|         @Override | ||||
|         public String process(@NonNull String destination) { | ||||
|             return destination; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,59 @@ | ||||
| package io.noties.markwon.image.destination; | ||||
| 
 | ||||
| import android.net.Uri; | ||||
| import android.text.TextUtils; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
| 
 | ||||
| /** | ||||
|  * {@link ImageDestinationProcessor} that treats all destinations <strong>without scheme</strong> | ||||
|  * information as pointing to the {@code assets} folder of an application. Please note that this | ||||
|  * processor only adds required {@code file:///android_asset/} prefix to destinations and | ||||
|  * actual image loading must take that into account (implement this functionality). | ||||
|  * <p> | ||||
|  * {@code FileSchemeHandler} from the {@code image} module supports asset images when created with | ||||
|  * {@code createWithAssets} factory method | ||||
|  * | ||||
|  * @since $nap; | ||||
|  */ | ||||
| public class ImageDestinationProcessorAssets extends ImageDestinationProcessor { | ||||
| 
 | ||||
|     @NonNull | ||||
|     public static ImageDestinationProcessorAssets create(@Nullable ImageDestinationProcessor parent) { | ||||
|         return new ImageDestinationProcessorAssets(parent); | ||||
|     } | ||||
| 
 | ||||
|     static final String MOCK = "https://android.asset/"; | ||||
|     static final String BASE = "file:///android_asset/"; | ||||
| 
 | ||||
|     private final ImageDestinationProcessorRelativeToAbsolute assetsProcessor | ||||
|             = new ImageDestinationProcessorRelativeToAbsolute(MOCK); | ||||
| 
 | ||||
|     private final ImageDestinationProcessor processor; | ||||
| 
 | ||||
|     public ImageDestinationProcessorAssets() { | ||||
|         this(null); | ||||
|     } | ||||
| 
 | ||||
|     public ImageDestinationProcessorAssets(@Nullable ImageDestinationProcessor parent) { | ||||
|         this.processor = parent; | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @Override | ||||
|     public String process(@NonNull String destination) { | ||||
|         final String out; | ||||
|         final Uri uri = Uri.parse(destination); | ||||
|         if (TextUtils.isEmpty(uri.getScheme())) { | ||||
|             out = assetsProcessor.process(destination).replace(MOCK, BASE); | ||||
|         } else { | ||||
|             if (processor != null) { | ||||
|                 out = processor.process(destination); | ||||
|             } else { | ||||
|                 out = destination; | ||||
|             } | ||||
|         } | ||||
|         return out; | ||||
|     } | ||||
| } | ||||
| @ -1,4 +1,4 @@ | ||||
| package io.noties.markwon.urlprocessor; | ||||
| package io.noties.markwon.image.destination; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
| @ -6,15 +6,30 @@ import androidx.annotation.Nullable; | ||||
| import java.net.MalformedURLException; | ||||
| import java.net.URL; | ||||
| 
 | ||||
| @SuppressWarnings("WeakerAccess") | ||||
| public class UrlProcessorRelativeToAbsolute implements UrlProcessor { | ||||
| /** | ||||
|  * @since $nap; | ||||
|  */ | ||||
| public class ImageDestinationProcessorRelativeToAbsolute extends ImageDestinationProcessor { | ||||
| 
 | ||||
|     @NonNull | ||||
|     public static ImageDestinationProcessorRelativeToAbsolute create(@NonNull String base) { | ||||
|         return new ImageDestinationProcessorRelativeToAbsolute(base); | ||||
|     } | ||||
| 
 | ||||
|     public static ImageDestinationProcessorRelativeToAbsolute create(@NonNull URL base) { | ||||
|         return new ImageDestinationProcessorRelativeToAbsolute(base); | ||||
|     } | ||||
| 
 | ||||
|     private final URL base; | ||||
| 
 | ||||
|     public UrlProcessorRelativeToAbsolute(@NonNull String base) { | ||||
|     public ImageDestinationProcessorRelativeToAbsolute(@NonNull String base) { | ||||
|         this.base = obtain(base); | ||||
|     } | ||||
| 
 | ||||
|     public ImageDestinationProcessorRelativeToAbsolute(@NonNull URL base) { | ||||
|         this.base = base; | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @Override | ||||
|     public String process(@NonNull String destination) { | ||||
| @ -1,8 +0,0 @@ | ||||
| package io.noties.markwon.urlprocessor; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| 
 | ||||
| public interface UrlProcessor { | ||||
|     @NonNull | ||||
|     String process(@NonNull String destination); | ||||
| } | ||||
| @ -1,49 +0,0 @@ | ||||
| package io.noties.markwon.urlprocessor; | ||||
| 
 | ||||
| import android.net.Uri; | ||||
| import android.text.TextUtils; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
| 
 | ||||
| /** | ||||
|  * Processor that will <em>assume</em> that an URL without scheme points to android assets folder. | ||||
|  * URL with a scheme will be processed by {@link #processor} (if it is specified) or returned `as-is`. | ||||
|  */ | ||||
| @SuppressWarnings({"unused", "WeakerAccess"}) | ||||
| public class UrlProcessorAndroidAssets implements UrlProcessor { | ||||
| 
 | ||||
| 
 | ||||
|     static final String MOCK = "https://android.asset/"; | ||||
|     static final String BASE = "file:///android_asset/"; | ||||
| 
 | ||||
|     private final UrlProcessorRelativeToAbsolute assetsProcessor | ||||
|             = new UrlProcessorRelativeToAbsolute(MOCK); | ||||
| 
 | ||||
|     private final UrlProcessor processor; | ||||
| 
 | ||||
|     public UrlProcessorAndroidAssets() { | ||||
|         this(null); | ||||
|     } | ||||
| 
 | ||||
|     public UrlProcessorAndroidAssets(@Nullable UrlProcessor parent) { | ||||
|         this.processor = parent; | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @Override | ||||
|     public String process(@NonNull String destination) { | ||||
|         final String out; | ||||
|         final Uri uri = Uri.parse(destination); | ||||
|         if (TextUtils.isEmpty(uri.getScheme())) { | ||||
|             out = assetsProcessor.process(destination).replace(MOCK, BASE); | ||||
|         } else { | ||||
|             if (processor != null) { | ||||
|                 out = processor.process(destination); | ||||
|             } else { | ||||
|                 out = destination; | ||||
|             } | ||||
|         } | ||||
|         return out; | ||||
|     } | ||||
| } | ||||
| @ -1,11 +0,0 @@ | ||||
| package io.noties.markwon.urlprocessor; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| 
 | ||||
| public class UrlProcessorNoOp implements UrlProcessor { | ||||
|     @NonNull | ||||
|     @Override | ||||
|     public String process(@NonNull String destination) { | ||||
|         return destination; | ||||
|     } | ||||
| } | ||||
| @ -1,4 +1,4 @@ | ||||
| package io.noties.markwon.urlprocessor; | ||||
| package io.noties.markwon.image.destination; | ||||
| 
 | ||||
| import org.junit.Before; | ||||
| import org.junit.Test; | ||||
| @ -6,18 +6,18 @@ import org.junit.runner.RunWith; | ||||
| import org.robolectric.RobolectricTestRunner; | ||||
| import org.robolectric.annotation.Config; | ||||
| 
 | ||||
| import static io.noties.markwon.image.destination.ImageDestinationProcessorAssets.BASE; | ||||
| import static org.junit.Assert.assertEquals; | ||||
| import static io.noties.markwon.urlprocessor.UrlProcessorAndroidAssets.BASE; | ||||
| 
 | ||||
| @RunWith(RobolectricTestRunner.class) | ||||
| @Config(manifest = Config.NONE) | ||||
| public class UrlProcessorAndroidAssetsTest { | ||||
| public class ImageDestinationProcessorAssetsTest { | ||||
| 
 | ||||
|     private UrlProcessorAndroidAssets processor; | ||||
|     private ImageDestinationProcessorAssets processor; | ||||
| 
 | ||||
|     @Before | ||||
|     public void before() { | ||||
|         processor = new UrlProcessorAndroidAssets(); | ||||
|         processor = new ImageDestinationProcessorAssets(); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
| @ -1,4 +1,4 @@ | ||||
| package io.noties.markwon.urlprocessor; | ||||
| package io.noties.markwon.image.destination; | ||||
| 
 | ||||
| import org.junit.Test; | ||||
| import org.junit.runner.RunWith; | ||||
| @ -9,39 +9,39 @@ import static org.junit.Assert.*; | ||||
| 
 | ||||
| @RunWith(RobolectricTestRunner.class) | ||||
| @Config(manifest = Config.NONE) | ||||
| public class UrlProcessorRelativeToAbsoluteTest { | ||||
| public class ImageDestinationProcessorRelativeToAbsoluteTest { | ||||
| 
 | ||||
|     @Test | ||||
|     public void malformed_base_do_not_process() { | ||||
|         final UrlProcessorRelativeToAbsolute processor = new UrlProcessorRelativeToAbsolute("!@#$%^&*("); | ||||
|         final ImageDestinationProcessorRelativeToAbsolute processor = new ImageDestinationProcessorRelativeToAbsolute("!@#$%^&*("); | ||||
|         final String destination = "../hey.there.html"; | ||||
|         assertEquals(destination, processor.process(destination)); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void access_root() { | ||||
|         final UrlProcessorRelativeToAbsolute processor = new UrlProcessorRelativeToAbsolute("https://ro.ot/hello/"); | ||||
|         final ImageDestinationProcessorRelativeToAbsolute processor = new ImageDestinationProcessorRelativeToAbsolute("https://ro.ot/hello/"); | ||||
|         final String url = "/index.html"; | ||||
|         assertEquals("https://ro.ot/index.html", processor.process(url)); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void access_same_directory() { | ||||
|         final UrlProcessorRelativeToAbsolute processor = new UrlProcessorRelativeToAbsolute("https://ro.ot/hello/"); | ||||
|         final ImageDestinationProcessorRelativeToAbsolute processor = new ImageDestinationProcessorRelativeToAbsolute("https://ro.ot/hello/"); | ||||
|         final String url = "./.htaccess"; | ||||
|         assertEquals("https://ro.ot/hello/.htaccess", processor.process(url)); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void asset_directory_up() { | ||||
|         final UrlProcessorRelativeToAbsolute processor = new UrlProcessorRelativeToAbsolute("http://ro.ot/first/second/"); | ||||
|         final ImageDestinationProcessorRelativeToAbsolute processor = new ImageDestinationProcessorRelativeToAbsolute("http://ro.ot/first/second/"); | ||||
|         final String url = "../cat.JPG"; | ||||
|         assertEquals("http://ro.ot/first/cat.JPG", processor.process(url)); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void change_directory_inside_destination() { | ||||
|         final UrlProcessorRelativeToAbsolute processor = new UrlProcessorRelativeToAbsolute("http://ro.ot/first/"); | ||||
|         final ImageDestinationProcessorRelativeToAbsolute processor = new ImageDestinationProcessorRelativeToAbsolute("http://ro.ot/first/"); | ||||
|         final String url = "../first/../second/./thi.rd"; | ||||
|         assertEquals( | ||||
|                 "http://ro.ot/second/thi.rd", | ||||
| @ -51,7 +51,7 @@ public class UrlProcessorRelativeToAbsoluteTest { | ||||
| 
 | ||||
|     @Test | ||||
|     public void with_query_arguments() { | ||||
|         final UrlProcessorRelativeToAbsolute processor = new UrlProcessorRelativeToAbsolute("http://ro.ot/first/"); | ||||
|         final ImageDestinationProcessorRelativeToAbsolute processor = new ImageDestinationProcessorRelativeToAbsolute("http://ro.ot/first/"); | ||||
|         final String url = "../index.php?ROOT=1"; | ||||
|         assertEquals( | ||||
|                 "http://ro.ot/index.php?ROOT=1", | ||||
| @ -62,7 +62,7 @@ public class ImageHandler extends SimpleTagHandler { | ||||
|             return null; | ||||
|         } | ||||
| 
 | ||||
|         final String destination = configuration.urlProcessor().process(src); | ||||
|         final String destination = configuration.imageDestinationProcessor().process(src); | ||||
|         final ImageSize imageSize = imageSizeParser.parse(tag.attributes()); | ||||
| 
 | ||||
|         // todo: replacement text is link... as we are not at block level | ||||
|  | ||||
| @ -27,7 +27,8 @@ public class LinkHandler extends SimpleTagHandler { | ||||
| 
 | ||||
|                 CoreProps.LINK_DESTINATION.set( | ||||
|                         renderProps, | ||||
|                         configuration.urlProcessor().process(destination)); | ||||
|                         destination | ||||
|                 ); | ||||
| 
 | ||||
|                 return spanFactory.getSpans(configuration, renderProps); | ||||
|             } | ||||
|  | ||||
| @ -3,11 +3,12 @@ package io.noties.markwon.image.file; | ||||
| import android.content.Context; | ||||
| import android.content.res.AssetManager; | ||||
| import android.net.Uri; | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
| import android.text.TextUtils; | ||||
| import android.webkit.MimeTypeMap; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
| 
 | ||||
| import java.io.BufferedInputStream; | ||||
| import java.io.File; | ||||
| import java.io.FileInputStream; | ||||
| @ -18,7 +19,6 @@ import java.util.Collection; | ||||
| import java.util.Collections; | ||||
| import java.util.List; | ||||
| 
 | ||||
| import io.noties.markwon.urlprocessor.UrlProcessorAndroidAssets; | ||||
| import io.noties.markwon.image.ImageItem; | ||||
| import io.noties.markwon.image.SchemeHandler; | ||||
| 
 | ||||
| @ -30,7 +30,7 @@ public class FileSchemeHandler extends SchemeHandler { | ||||
|     public static final String SCHEME = "file"; | ||||
| 
 | ||||
|     /** | ||||
|      * @see UrlProcessorAndroidAssets | ||||
|      * @see io.noties.markwon.image.destination.ImageDestinationProcessorAssets | ||||
|      */ | ||||
|     @NonNull | ||||
|     public static FileSchemeHandler createWithAssets(@NonNull AssetManager assetManager) { | ||||
| @ -39,7 +39,7 @@ public class FileSchemeHandler extends SchemeHandler { | ||||
| 
 | ||||
|     /** | ||||
|      * @see #createWithAssets(AssetManager) | ||||
|      * @see UrlProcessorAndroidAssets | ||||
|      * @see io.noties.markwon.image.destination.ImageDestinationProcessorAssets | ||||
|      * @since 4.0.0 | ||||
|      */ | ||||
|     @NonNull | ||||
|  | ||||
| @ -5,6 +5,7 @@ import android.net.Uri; | ||||
| import android.os.Bundle; | ||||
| import android.text.TextUtils; | ||||
| import android.text.style.ForegroundColorSpan; | ||||
| import android.view.View; | ||||
| import android.widget.ScrollView; | ||||
| import android.widget.TextView; | ||||
| 
 | ||||
| @ -20,6 +21,7 @@ import java.util.Collections; | ||||
| 
 | ||||
| import io.noties.markwon.AbstractMarkwonPlugin; | ||||
| import io.noties.markwon.BlockHandlerDef; | ||||
| import io.noties.markwon.LinkResolverDef; | ||||
| import io.noties.markwon.Markwon; | ||||
| import io.noties.markwon.MarkwonConfiguration; | ||||
| import io.noties.markwon.MarkwonSpansFactory; | ||||
| @ -153,7 +155,7 @@ public class BasicPluginsActivity extends ActivityWithMenuOptions { | ||||
|      * <ul> | ||||
|      * <li>SyntaxHighlight</li> | ||||
|      * <li>LinkSpan.Resolver</li> | ||||
|      * <li>UrlProcessor</li> | ||||
|      * <li>ImageDestinationProcessor</li> | ||||
|      * <li>ImageSizeResolver</li> | ||||
|      * </ul> | ||||
|      * <p> | ||||
| @ -173,12 +175,18 @@ public class BasicPluginsActivity extends ActivityWithMenuOptions { | ||||
|                     public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) { | ||||
|                         // for example if specified destination has no scheme info, we will | ||||
|                         // _assume_ that it's network request and append HTTPS scheme | ||||
|                         builder.urlProcessor(destination -> { | ||||
|                             final Uri uri = Uri.parse(destination); | ||||
|                             if (TextUtils.isEmpty(uri.getScheme())) { | ||||
|                                 return "https://" + destination; | ||||
|                         builder.linkResolver(new LinkResolverDef() { | ||||
|                             @Override | ||||
|                             public void resolve(@NonNull View view, @NonNull String link) { | ||||
|                                 final String destination; | ||||
|                                 final Uri uri = Uri.parse(link); | ||||
|                                 if (TextUtils.isEmpty(uri.getScheme())) { | ||||
|                                     destination = "https://" + link; | ||||
|                                 } else { | ||||
|                                     destination = link; | ||||
|                                 } | ||||
|                                 super.resolve(view, destination); | ||||
|                             } | ||||
|                             return destination; | ||||
|                         }); | ||||
|                     } | ||||
|                 }) | ||||
|  | ||||
| @ -34,6 +34,8 @@ import io.noties.markwon.MarkwonVisitor; | ||||
| import io.noties.markwon.core.CorePlugin; | ||||
| import io.noties.markwon.html.HtmlPlugin; | ||||
| import io.noties.markwon.image.ImagesPlugin; | ||||
| import io.noties.markwon.image.destination.ImageDestinationProcessor; | ||||
| import io.noties.markwon.image.destination.ImageDestinationProcessorRelativeToAbsolute; | ||||
| import io.noties.markwon.image.file.FileSchemeHandler; | ||||
| import io.noties.markwon.image.network.OkHttpNetworkSchemeHandler; | ||||
| import io.noties.markwon.image.svg.SvgMediaDecoder; | ||||
| @ -42,8 +44,6 @@ import io.noties.markwon.recycler.SimpleEntry; | ||||
| import io.noties.markwon.recycler.table.TableEntry; | ||||
| import io.noties.markwon.recycler.table.TableEntryPlugin; | ||||
| import io.noties.markwon.sample.R; | ||||
| import io.noties.markwon.urlprocessor.UrlProcessor; | ||||
| import io.noties.markwon.urlprocessor.UrlProcessorRelativeToAbsolute; | ||||
| 
 | ||||
| public class RecyclerActivity extends Activity { | ||||
| 
 | ||||
| @ -100,7 +100,7 @@ public class RecyclerActivity extends Activity { | ||||
|                 .usePlugin(new AbstractMarkwonPlugin() { | ||||
|                     @Override | ||||
|                     public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) { | ||||
|                         builder.urlProcessor(new UrlProcessorInitialReadme()); | ||||
|                         builder.imageDestinationProcessor(new ImageDestinationProcessorInitialReadme()); | ||||
|                     } | ||||
| 
 | ||||
|                     @Override | ||||
| @ -182,12 +182,12 @@ public class RecyclerActivity extends Activity { | ||||
|         return out; | ||||
|     } | ||||
| 
 | ||||
|     private static class UrlProcessorInitialReadme implements UrlProcessor { | ||||
|     private static class ImageDestinationProcessorInitialReadme extends ImageDestinationProcessor { | ||||
| 
 | ||||
|         private static final String GITHUB_BASE = "https://github.com/noties/Markwon/raw/master/"; | ||||
| 
 | ||||
|         private final UrlProcessorRelativeToAbsolute processor | ||||
|                 = new UrlProcessorRelativeToAbsolute(GITHUB_BASE); | ||||
|         private final ImageDestinationProcessorRelativeToAbsolute processor | ||||
|                 = new ImageDestinationProcessorRelativeToAbsolute(GITHUB_BASE); | ||||
| 
 | ||||
|         @NonNull | ||||
|         @Override | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Dimitry Ivanov
						Dimitry Ivanov