MarkwonInlineParserPlugin
This commit is contained in:
		
							parent
							
								
									a80ff09e15
								
							
						
					
					
						commit
						74682ae605
					
				| @ -14,6 +14,7 @@ android { | ||||
| } | ||||
| 
 | ||||
| dependencies { | ||||
|     api project(':markwon-core') | ||||
|     api deps['x-annotations'] | ||||
|     api deps['commonmark'] | ||||
| 
 | ||||
|  | ||||
| @ -0,0 +1,59 @@ | ||||
| package io.noties.markwon.inlineparser; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| 
 | ||||
| import org.commonmark.parser.Parser; | ||||
| 
 | ||||
| import io.noties.markwon.AbstractMarkwonPlugin; | ||||
| 
 | ||||
| /** | ||||
|  * @since 4.3.0-SNAPSHOT | ||||
|  */ | ||||
| public class MarkwonInlineParserPlugin extends AbstractMarkwonPlugin { | ||||
| 
 | ||||
|     public interface BuilderConfigure<B extends MarkwonInlineParser.FactoryBuilder> { | ||||
|         void configureBuilder(@NonNull B factoryBuilder); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     public static MarkwonInlineParserPlugin create() { | ||||
|         return create(MarkwonInlineParser.factoryBuilder()); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     public static MarkwonInlineParserPlugin create(@NonNull BuilderConfigure<MarkwonInlineParser.FactoryBuilder> configure) { | ||||
|         final MarkwonInlineParser.FactoryBuilder factoryBuilder = MarkwonInlineParser.factoryBuilder(); | ||||
|         configure.configureBuilder(factoryBuilder); | ||||
|         return new MarkwonInlineParserPlugin(factoryBuilder); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     public static MarkwonInlineParserPlugin create(@NonNull MarkwonInlineParser.FactoryBuilder factoryBuilder) { | ||||
|         return new MarkwonInlineParserPlugin(factoryBuilder); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     public static <B extends MarkwonInlineParser.FactoryBuilder> MarkwonInlineParserPlugin create( | ||||
|             @NonNull B factoryBuilder, | ||||
|             @NonNull BuilderConfigure<B> configure) { | ||||
|         configure.configureBuilder(factoryBuilder); | ||||
|         return new MarkwonInlineParserPlugin(factoryBuilder); | ||||
|     } | ||||
| 
 | ||||
|     private final MarkwonInlineParser.FactoryBuilder factoryBuilder; | ||||
| 
 | ||||
|     @SuppressWarnings("WeakerAccess") | ||||
|     MarkwonInlineParserPlugin(@NonNull MarkwonInlineParser.FactoryBuilder factoryBuilder) { | ||||
|         this.factoryBuilder = factoryBuilder; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void configureParser(@NonNull Parser.Builder builder) { | ||||
|         builder.inlineParserFactory(factoryBuilder.build()); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     public MarkwonInlineParser.FactoryBuilder factoryBuilder() { | ||||
|         return factoryBuilder; | ||||
|     } | ||||
| } | ||||
| @ -13,6 +13,14 @@ public abstract class ActivityWithMenuOptions extends Activity { | ||||
|     @NonNull | ||||
|     public abstract MenuOptions menuOptions(); | ||||
| 
 | ||||
|     protected void beforeOptionSelected(@NonNull String option) { | ||||
|         // no op, override to customize | ||||
|     } | ||||
| 
 | ||||
|     protected void afterOptionSelected(@NonNull String option) { | ||||
|         // no op, override to customize | ||||
|     } | ||||
| 
 | ||||
|     private MenuOptions menuOptions; | ||||
| 
 | ||||
|     @Override | ||||
| @ -29,6 +37,13 @@ public abstract class ActivityWithMenuOptions extends Activity { | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean onOptionsItemSelected(MenuItem item) { | ||||
|         return menuOptions.onOptionsItemSelected(item); | ||||
|         final MenuOptions.Option option = menuOptions.onOptionsItemSelected(item); | ||||
|         if (option != null) { | ||||
|             beforeOptionSelected(option.title); | ||||
|             option.action.run(); | ||||
|             afterOptionSelected(option.title); | ||||
|             return true; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -4,6 +4,7 @@ import android.view.Menu; | ||||
| import android.view.MenuItem; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
| 
 | ||||
| import java.util.LinkedHashMap; | ||||
| import java.util.Map; | ||||
| @ -15,6 +16,16 @@ public class MenuOptions { | ||||
|         return new MenuOptions(); | ||||
|     } | ||||
| 
 | ||||
|     static class Option { | ||||
|         final String title; | ||||
|         final Runnable action; | ||||
| 
 | ||||
|         Option(@NonNull String title, @NonNull Runnable action) { | ||||
|             this.title = title; | ||||
|             this.action = action; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // to preserve order use LinkedHashMap | ||||
|     private final Map<String, Runnable> actions = new LinkedHashMap<>(); | ||||
| 
 | ||||
| @ -34,13 +45,13 @@ public class MenuOptions { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     boolean onOptionsItemSelected(MenuItem item) { | ||||
|     @Nullable | ||||
|     Option onOptionsItemSelected(MenuItem item) { | ||||
|         final String title = String.valueOf(item.getTitle()); | ||||
|         final Runnable action = actions.get(title); | ||||
|         if (action != null) { | ||||
|             action.run(); | ||||
|             return true; | ||||
|             return new Option(title, action); | ||||
|         } | ||||
|         return false; | ||||
|         return null; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -5,6 +5,7 @@ import android.text.Editable; | ||||
| import android.text.SpannableStringBuilder; | ||||
| import android.text.Spanned; | ||||
| import android.text.TextPaint; | ||||
| import android.text.TextUtils; | ||||
| import android.text.method.LinkMovementMethod; | ||||
| import android.text.style.ForegroundColorSpan; | ||||
| import android.text.style.MetricAffectingSpan; | ||||
| @ -40,6 +41,7 @@ import io.noties.markwon.inlineparser.BangInlineProcessor; | ||||
| import io.noties.markwon.inlineparser.EntityInlineProcessor; | ||||
| import io.noties.markwon.inlineparser.HtmlInlineProcessor; | ||||
| import io.noties.markwon.inlineparser.MarkwonInlineParser; | ||||
| import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin; | ||||
| import io.noties.markwon.linkify.LinkifyPlugin; | ||||
| import io.noties.markwon.sample.ActivityWithMenuOptions; | ||||
| import io.noties.markwon.sample.MenuOptions; | ||||
| @ -48,6 +50,7 @@ import io.noties.markwon.sample.R; | ||||
| public class EditorActivity extends ActivityWithMenuOptions { | ||||
| 
 | ||||
|     private EditText editText; | ||||
|     private String pendingInput; | ||||
| 
 | ||||
|     @NonNull | ||||
|     @Override | ||||
| @ -58,16 +61,41 @@ public class EditorActivity extends ActivityWithMenuOptions { | ||||
|                 .add("customPunctuationSpan", this::custom_punctuation_span) | ||||
|                 .add("additionalEditSpan", this::additional_edit_span) | ||||
|                 .add("additionalPlugins", this::additional_plugins) | ||||
|                 .add("multipleEditSpans", this::multiple_edit_spans); | ||||
|                 .add("multipleEditSpans", this::multiple_edit_spans) | ||||
|                 .add("multipleEditSpansPlugin", this::multiple_edit_spans_plugin) | ||||
|                 .add("pluginRequire", this::plugin_require) | ||||
|                 .add("pluginNoDefaults", this::plugin_no_defaults); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void beforeOptionSelected(@NonNull String option) { | ||||
|         // we cannot _clear_ editText of text-watchers without keeping a reference to them... | ||||
|         pendingInput = editText != null | ||||
|                 ? editText.getText().toString() | ||||
|                 : null; | ||||
| 
 | ||||
|         createView(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void afterOptionSelected(@NonNull String option) { | ||||
|         if (!TextUtils.isEmpty(pendingInput)) { | ||||
|             editText.setText(pendingInput); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private void createView() { | ||||
|         setContentView(R.layout.activity_editor); | ||||
| 
 | ||||
|         this.editText = findViewById(R.id.edit_text); | ||||
| 
 | ||||
|         initBottomBar(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onCreate(@Nullable Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         setContentView(R.layout.activity_editor); | ||||
| 
 | ||||
|         this.editText = findViewById(R.id.edit_text); | ||||
|         initBottomBar(); | ||||
|         createView(); | ||||
| 
 | ||||
|         multiple_edit_spans(); | ||||
|     } | ||||
| @ -219,6 +247,76 @@ public class EditorActivity extends ActivityWithMenuOptions { | ||||
|                 editor, Executors.newSingleThreadExecutor(), editText)); | ||||
|     } | ||||
| 
 | ||||
|     private void multiple_edit_spans_plugin() { | ||||
|         // inline parsing is configured via MarkwonInlineParserPlugin | ||||
| 
 | ||||
|         // for links to be clickable | ||||
|         editText.setMovementMethod(LinkMovementMethod.getInstance()); | ||||
| 
 | ||||
|         final Markwon markwon = Markwon.builder(this) | ||||
|                 .usePlugin(StrikethroughPlugin.create()) | ||||
|                 .usePlugin(LinkifyPlugin.create()) | ||||
|                 .usePlugin(MarkwonInlineParserPlugin.create(builder -> { | ||||
|                     builder | ||||
|                             .excludeInlineProcessor(BangInlineProcessor.class) | ||||
|                             .excludeInlineProcessor(HtmlInlineProcessor.class) | ||||
|                             .excludeInlineProcessor(EntityInlineProcessor.class); | ||||
|                 })) | ||||
|                 .build(); | ||||
| 
 | ||||
|         final LinkEditHandler.OnClick onClick = (widget, link) -> markwon.configuration().linkResolver().resolve(widget, link); | ||||
| 
 | ||||
|         final MarkwonEditor editor = MarkwonEditor.builder(markwon) | ||||
|                 .useEditHandler(new EmphasisEditHandler()) | ||||
|                 .useEditHandler(new StrongEmphasisEditHandler()) | ||||
|                 .useEditHandler(new StrikethroughEditHandler()) | ||||
|                 .useEditHandler(new CodeEditHandler()) | ||||
|                 .useEditHandler(new BlockQuoteEditHandler()) | ||||
|                 .useEditHandler(new LinkEditHandler(onClick)) | ||||
|                 .build(); | ||||
| 
 | ||||
|         editText.addTextChangedListener(MarkwonEditorTextWatcher.withPreRender( | ||||
|                 editor, Executors.newSingleThreadExecutor(), editText)); | ||||
|     } | ||||
| 
 | ||||
|     private void plugin_require() { | ||||
|         // usage of plugin from other plugins | ||||
| 
 | ||||
|         final Markwon markwon = Markwon.builder(this) | ||||
|                 .usePlugin(MarkwonInlineParserPlugin.create()) | ||||
|                 .usePlugin(new AbstractMarkwonPlugin() { | ||||
|                     @Override | ||||
|                     public void configure(@NonNull Registry registry) { | ||||
|                         registry.require(MarkwonInlineParserPlugin.class) | ||||
|                                 .factoryBuilder() | ||||
|                                 .excludeInlineProcessor(HtmlInlineProcessor.class); | ||||
|                     } | ||||
|                 }) | ||||
|                 .build(); | ||||
| 
 | ||||
|         final MarkwonEditor editor = MarkwonEditor.create(markwon); | ||||
| 
 | ||||
|         editText.addTextChangedListener(MarkwonEditorTextWatcher.withPreRender( | ||||
|                 editor, Executors.newSingleThreadExecutor(), editText)); | ||||
|     } | ||||
| 
 | ||||
|     private void plugin_no_defaults() { | ||||
|         // a plugin with no defaults registered | ||||
| 
 | ||||
|         final Markwon markwon = Markwon.builder(this) | ||||
|                 .usePlugin(MarkwonInlineParserPlugin.create(MarkwonInlineParser.factoryBuilderNoDefaults())) | ||||
| //                .usePlugin(MarkwonInlineParserPlugin.create(MarkwonInlineParser.factoryBuilderNoDefaults(), factoryBuilder -> { | ||||
| //                    // if anything, they can be included here | ||||
| ////                    factoryBuilder.includeDefaults() | ||||
| //                })) | ||||
|                 .build(); | ||||
| 
 | ||||
|         final MarkwonEditor editor = MarkwonEditor.create(markwon); | ||||
| 
 | ||||
|         editText.addTextChangedListener(MarkwonEditorTextWatcher.withPreRender( | ||||
|                 editor, Executors.newSingleThreadExecutor(), editText)); | ||||
|     } | ||||
| 
 | ||||
|     private void initBottomBar() { | ||||
|         // all except block-quote wraps if have selection, or inserts at current cursor position | ||||
| 
 | ||||
|  | ||||
| @ -29,7 +29,7 @@ | ||||
| 
 | ||||
|     <string name="sample_inline_parser"># \# Inline Parser\n\nUsage of custom inline parser</string> | ||||
| 
 | ||||
|     <string name="sample_html_details"># \# HTML <details> tag\n\n<details> tag parsed and rendered</string> | ||||
|     <string name="sample_html_details"># \# HTML\n\n`details` tag parsed and rendered</string> | ||||
| 
 | ||||
|     <string name="sample_task_list"># \# TaskList\n\nUsage of TaskListPlugin</string> | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Dimitry Ivanov
						Dimitry Ivanov