MarkwonSpansFactory append-prepend methods
This commit is contained in:
		
							parent
							
								
									f7f8f6d1ee
								
							
						
					
					
						commit
						976dfa3162
					
				| @ -3,9 +3,11 @@ | ||||
| # 4.2.2-SNAPSHOT | ||||
| * Fixed `AsyncDrawable` display when it has placeholder with empty bounds ([#189]) | ||||
| * Fixed `syntax-highlight` where code input is empty string ([#192]) | ||||
| * Add `appendFactory`/`prependFactory` in `MarkwonSpansFactory.Builder` for more explicit `SpanFactory` ordering ([#193]) | ||||
| 
 | ||||
| [#189]: https://github.com/noties/Markwon/issues/189 | ||||
| [#192]: https://github.com/noties/Markwon/issues/192 | ||||
| [#193]: https://github.com/noties/Markwon/issues/193 | ||||
| 
 | ||||
| # 4.2.1 | ||||
| * Fix SpannableBuilder `subSequence` method | ||||
|  | ||||
| @ -62,7 +62,12 @@ builder.setFactory(Link.class, new SpanFactory() { | ||||
| 
 | ||||
| --- | ||||
| 
 | ||||
| Since <Badge text="3.0.1" /> you can _add_ multiple `SpanFactory` for a single node: | ||||
| :::warning | ||||
| Deprecated in <Badge text="4.2.2" type="error" vertical="middle" />. Use `appendFactory` or `prependFactory` for | ||||
| more explicit factories ordering. `addFactories` behaves like new `prependFactory` method. | ||||
| ::: | ||||
| 
 | ||||
| Since <Badge text="3.0.1" /><Badge text="4.2.2" type="error" /> you can _add_ multiple `SpanFactory` for a single node: | ||||
| 
 | ||||
| ```java | ||||
| final Markwon markwon = Markwon.builder(context) | ||||
| @ -81,6 +86,22 @@ final Markwon markwon = Markwon.builder(context) | ||||
|         .build(); | ||||
| ``` | ||||
| 
 | ||||
| ## appendFactory/prependFactory <Badge text="4.2.2" /> | ||||
| 
 | ||||
| * use `appendFactory` if you wish to add a factory **after** original (can be used to post-process original factory) | ||||
| * use `prependFactory` if you wish to add a factory **before** original (original factory will be applied after this one) | ||||
| 
 | ||||
| ```java | ||||
| @Override | ||||
| public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) { | ||||
|     // `RemoveUnderlineSpan` will be added AFTER original, thus it will remove underline applied by original | ||||
|     builder.appendFactory(Link.class, (configuration, props) -> new RemoveUnderlineSpan()); | ||||
| 
 | ||||
|     // will be added BEFORE origin (origin can override this) | ||||
|     builder.prependFactory(Link.class, (configuration, props) -> new AbsoluteSizeSpan(48, true)); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| --- | ||||
| 
 | ||||
| If you wish to inspect existing factory you can use: | ||||
|  | ||||
| @ -39,10 +39,34 @@ public interface MarkwonSpansFactory { | ||||
|          * {@link SpanFactory} with the specified one. | ||||
|          * | ||||
|          * @since 3.0.1 | ||||
|          * @deprecated 4.2.2-SNAPSHOT consider using {@link #appendFactory(Class, SpanFactory)} or | ||||
|          * {@link #prependFactory(Class, SpanFactory)} methods for more explicit factory ordering. | ||||
|          * `addFactory` behaved like {@link #prependFactory(Class, SpanFactory)}, so | ||||
|          * this method call can be replaced with it | ||||
|          */ | ||||
|         @NonNull | ||||
|         @Deprecated | ||||
|         <N extends Node> Builder addFactory(@NonNull Class<N> node, @NonNull SpanFactory factory); | ||||
| 
 | ||||
|         /** | ||||
|          * Append a factory to existing one (or make the first one for specified node). Specified factory | ||||
|          * will be called <strong>after</strong> original (if present) factory. Can be used to | ||||
|          * <em>change</em> behavior or original span factory. | ||||
|          * | ||||
|          * @since 4.2.2-SNAPSHOT | ||||
|          */ | ||||
|         @NonNull | ||||
|         <N extends Node> Builder appendFactory(@NonNull Class<N> node, @NonNull SpanFactory factory); | ||||
| 
 | ||||
|         /** | ||||
|          * Prepend a factory to existing one (or make the first one for specified node). Specified factory | ||||
|          * will be called <string>before</string> original (if present) factory. | ||||
|          * | ||||
|          * @since 4.2.2-SNAPSHOT | ||||
|          */ | ||||
|         @NonNull | ||||
|         <N extends Node> Builder prependFactory(@NonNull Class<N> node, @NonNull SpanFactory factory); | ||||
| 
 | ||||
|         /** | ||||
|          * Can be useful when <em>enhancing</em> an already defined SpanFactory with another one. | ||||
|          */ | ||||
|  | ||||
| @ -56,7 +56,32 @@ class MarkwonSpansFactoryImpl implements MarkwonSpansFactory { | ||||
| 
 | ||||
|         @NonNull | ||||
|         @Override | ||||
|         @Deprecated | ||||
|         public <N extends Node> Builder addFactory(@NonNull Class<N> node, @NonNull SpanFactory factory) { | ||||
|             return prependFactory(node, factory); | ||||
|         } | ||||
| 
 | ||||
|         @NonNull | ||||
|         @Override | ||||
|         public <N extends Node> Builder appendFactory(@NonNull Class<N> node, @NonNull SpanFactory factory) { | ||||
|             final SpanFactory existing = factories.get(node); | ||||
|             if (existing == null) { | ||||
|                 factories.put(node, factory); | ||||
|             } else { | ||||
|                 if (existing instanceof CompositeSpanFactory) { | ||||
|                     ((CompositeSpanFactory) existing).factories.add(0, factory); | ||||
|                 } else { | ||||
|                     final CompositeSpanFactory compositeSpanFactory = | ||||
|                             new CompositeSpanFactory(factory, existing); | ||||
|                     factories.put(node, compositeSpanFactory); | ||||
|                 } | ||||
|             } | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
|         @NonNull | ||||
|         @Override | ||||
|         public <N extends Node> Builder prependFactory(@NonNull Class<N> node, @NonNull SpanFactory factory) { | ||||
|             // if there is no factory registered for this node -> just add it | ||||
|             final SpanFactory existing = factories.get(node); | ||||
|             if (existing == null) { | ||||
|  | ||||
| @ -113,6 +113,7 @@ public class MarkwonSpansFactoryImplTest { | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     @Deprecated | ||||
|     public void builder_add_factory() { | ||||
|         // here is what we should validate: | ||||
|         // * if we call addFactory and there is none already -> supplied factory | ||||
| @ -146,4 +147,74 @@ public class MarkwonSpansFactoryImplTest { | ||||
|         assertEquals(compositeSpanFactory, builder.getFactory(node)); | ||||
|         assertEquals(Arrays.asList(first, second, third), compositeSpanFactory.factories); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void builder_prepend_factory() { | ||||
|         // here is what we should validate: | ||||
|         // * if we call prependFactory and there is none already -> supplied factory | ||||
|         // * if there is | ||||
|         // * * if not composite -> make composite | ||||
|         // * * if composite -> add to it | ||||
| 
 | ||||
|         final MarkwonSpansFactoryImpl.BuilderImpl builder = new MarkwonSpansFactoryImpl.BuilderImpl(); | ||||
| 
 | ||||
|         final SpanFactory first = mock(SpanFactory.class); | ||||
|         final SpanFactory second = mock(SpanFactory.class); | ||||
|         final SpanFactory third = mock(SpanFactory.class); | ||||
| 
 | ||||
|         final Class<Node> node = Node.class; | ||||
| 
 | ||||
|         // assert none yet | ||||
|         assertNull(builder.getFactory(node)); | ||||
| 
 | ||||
|         // add first, none yet -> it should be added without modifications | ||||
|         builder.prependFactory(node, first); | ||||
|         assertEquals(first, builder.getFactory(node)); | ||||
| 
 | ||||
|         // add second -> composite factory will be created | ||||
|         builder.prependFactory(node, second); | ||||
|         final MarkwonSpansFactoryImpl.CompositeSpanFactory compositeSpanFactory = | ||||
|                 (MarkwonSpansFactoryImpl.CompositeSpanFactory) builder.getFactory(node); | ||||
|         assertNotNull(compositeSpanFactory); | ||||
|         assertEquals(Arrays.asList(first, second), compositeSpanFactory.factories); | ||||
| 
 | ||||
|         builder.prependFactory(node, third); | ||||
|         assertEquals(compositeSpanFactory, builder.getFactory(node)); | ||||
|         assertEquals(Arrays.asList(first, second, third), compositeSpanFactory.factories); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void builder_append_factory() { | ||||
|         // here is what we should validate: | ||||
|         // * if we call appendFactory and there is none already -> supplied factory | ||||
|         // * if there is | ||||
|         // * * if not composite -> make composite | ||||
|         // * * if composite -> add to it | ||||
| 
 | ||||
|         final MarkwonSpansFactoryImpl.BuilderImpl builder = new MarkwonSpansFactoryImpl.BuilderImpl(); | ||||
| 
 | ||||
|         final SpanFactory first = mock(SpanFactory.class); | ||||
|         final SpanFactory second = mock(SpanFactory.class); | ||||
|         final SpanFactory third = mock(SpanFactory.class); | ||||
| 
 | ||||
|         final Class<Node> node = Node.class; | ||||
| 
 | ||||
|         // assert none yet | ||||
|         assertNull(builder.getFactory(node)); | ||||
| 
 | ||||
|         // add first, none yet -> it should be added without modifications | ||||
|         builder.appendFactory(node, first); | ||||
|         assertEquals(first, builder.getFactory(node)); | ||||
| 
 | ||||
|         // add second -> composite factory will be created | ||||
|         builder.appendFactory(node, second); | ||||
|         final MarkwonSpansFactoryImpl.CompositeSpanFactory compositeSpanFactory = | ||||
|                 (MarkwonSpansFactoryImpl.CompositeSpanFactory) builder.getFactory(node); | ||||
|         assertNotNull(compositeSpanFactory); | ||||
|         assertEquals(Arrays.asList(second, first), compositeSpanFactory.factories); | ||||
| 
 | ||||
|         builder.appendFactory(node, third); | ||||
|         assertEquals(compositeSpanFactory, builder.getFactory(node)); | ||||
|         assertEquals(Arrays.asList(third, second, first), compositeSpanFactory.factories); | ||||
|     } | ||||
| } | ||||
| @ -166,6 +166,18 @@ public class CorePluginTest { | ||||
|                 throw new RuntimeException(); | ||||
|             } | ||||
| 
 | ||||
|             @NonNull | ||||
|             @Override | ||||
|             public <N extends Node> MarkwonSpansFactory.Builder appendFactory(@NonNull Class<N> node, @NonNull SpanFactory factory) { | ||||
|                 throw new RuntimeException(); | ||||
|             } | ||||
| 
 | ||||
|             @NonNull | ||||
|             @Override | ||||
|             public <N extends Node> MarkwonSpansFactory.Builder prependFactory(@NonNull Class<N> node, @NonNull SpanFactory factory) { | ||||
|                 throw new RuntimeException(); | ||||
|             } | ||||
| 
 | ||||
|             @Nullable | ||||
|             @Override | ||||
|             public <N extends Node> SpanFactory getFactory(@NonNull Class<N> node) { | ||||
|  | ||||
| @ -3,10 +3,12 @@ package io.noties.markwon.sample.recycler; | ||||
| import android.app.Activity; | ||||
| import android.content.Context; | ||||
| import android.graphics.drawable.ColorDrawable; | ||||
| import android.graphics.drawable.Drawable; | ||||
| import android.net.Uri; | ||||
| import android.os.Bundle; | ||||
| import android.text.TextPaint; | ||||
| import android.text.TextUtils; | ||||
| import android.text.style.CharacterStyle; | ||||
| import android.text.style.UpdateAppearance; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
| @ -15,6 +17,7 @@ import androidx.recyclerview.widget.RecyclerView; | ||||
| 
 | ||||
| import org.commonmark.ext.gfm.tables.TableBlock; | ||||
| import org.commonmark.node.FencedCodeBlock; | ||||
| import org.commonmark.node.Link; | ||||
| 
 | ||||
| import java.io.BufferedReader; | ||||
| import java.io.IOException; | ||||
| @ -26,14 +29,13 @@ import io.noties.debug.Debug; | ||||
| import io.noties.markwon.AbstractMarkwonPlugin; | ||||
| import io.noties.markwon.Markwon; | ||||
| import io.noties.markwon.MarkwonConfiguration; | ||||
| import io.noties.markwon.MarkwonSpansFactory; | ||||
| import io.noties.markwon.MarkwonVisitor; | ||||
| import io.noties.markwon.core.CorePlugin; | ||||
| import io.noties.markwon.html.HtmlPlugin; | ||||
| import io.noties.markwon.image.AsyncDrawable; | ||||
| import io.noties.markwon.image.ImagesPlugin; | ||||
| import io.noties.markwon.image.file.FileSchemeHandler; | ||||
| import io.noties.markwon.image.network.OkHttpNetworkSchemeHandler; | ||||
| import io.noties.markwon.image.picasso.PicassoImagesPlugin; | ||||
| import io.noties.markwon.image.svg.SvgMediaDecoder; | ||||
| import io.noties.markwon.recycler.MarkwonAdapter; | ||||
| import io.noties.markwon.recycler.SimpleEntry; | ||||
| @ -114,10 +116,24 @@ public class RecyclerActivity extends Activity { | ||||
|                             visitor.builder().append(code); | ||||
|                         }); | ||||
|                     } | ||||
| 
 | ||||
|                     @Override | ||||
|                     public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) { | ||||
|                         // `RemoveUnderlineSpan` will be added AFTER original, thus it will remove underline applied by original | ||||
|                         builder.appendFactory(Link.class, (configuration, props) -> new RemoveUnderlineSpan()); | ||||
|                     } | ||||
|                 }) | ||||
|                 .build(); | ||||
|     } | ||||
| 
 | ||||
|     private static class RemoveUnderlineSpan extends CharacterStyle implements UpdateAppearance { | ||||
| 
 | ||||
|         @Override | ||||
|         public void updateDrawState(TextPaint tp) { | ||||
|             tp.setUnderlineText(false); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     private static String loadReadMe(@NonNull Context context) { | ||||
|         InputStream stream = null; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Dimitry Ivanov
						Dimitry Ivanov