text-added-listener for core-plugin and linkify module
This commit is contained in:
parent
2e35ef53bb
commit
cedb3971a0
@ -4,3 +4,6 @@
|
||||
also accepts a ExecutorService (optional, by default cachedThreadPool is used)
|
||||
* AsyncDrawableScheduler now can be called by multiple plugins without penalty
|
||||
internally caches latest state and skips scheduling if drawables are already processed
|
||||
* configure with registry
|
||||
* removed priority
|
||||
* images-plugin moved to standalone again
|
@ -34,6 +34,7 @@ dependencies {
|
||||
implementation project(':markwon-ext-tasklist')
|
||||
implementation project(':markwon-html')
|
||||
implementation project(':markwon-image')
|
||||
implementation project(':markwon-linkify')
|
||||
implementation project(':markwon-syntax-highlight')
|
||||
|
||||
deps.with {
|
||||
|
@ -25,6 +25,7 @@ import ru.noties.markwon.image.file.FileSchemeHandler;
|
||||
import ru.noties.markwon.image.gif.GifMediaDecoder;
|
||||
import ru.noties.markwon.image.network.OkHttpNetworkSchemeHandler;
|
||||
import ru.noties.markwon.image.svg.SvgMediaDecoder;
|
||||
import ru.noties.markwon.linkify.LinkifyPlugin;
|
||||
import ru.noties.markwon.syntax.Prism4jTheme;
|
||||
import ru.noties.markwon.syntax.Prism4jThemeDarkula;
|
||||
import ru.noties.markwon.syntax.Prism4jThemeDefault;
|
||||
@ -107,6 +108,7 @@ public class MarkdownRenderer {
|
||||
.addMediaDecoder(SvgMediaDecoder.create());
|
||||
}
|
||||
}))
|
||||
.usePlugin(LinkifyPlugin.create())
|
||||
.usePlugin(SyntaxHighlightPlugin.create(prism4j, prism4jTheme))
|
||||
.usePlugin(GifAwarePlugin.create(context))
|
||||
.usePlugin(TablePlugin.create(context))
|
||||
|
@ -8,11 +8,11 @@
|
||||
android:id="@+id/scroll_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="16dip"
|
||||
android:clipToPadding="false"
|
||||
android:layout_marginTop="?android:attr/actionBarSize"
|
||||
android:clipChildren="false"
|
||||
android:scrollbarStyle="outsideOverlay"
|
||||
android:layout_marginTop="?android:attr/actionBarSize">
|
||||
android:clipToPadding="false"
|
||||
android:padding="16dip"
|
||||
android:scrollbarStyle="outsideOverlay">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text"
|
||||
|
@ -27,6 +27,9 @@ import org.commonmark.node.StrongEmphasis;
|
||||
import org.commonmark.node.Text;
|
||||
import org.commonmark.node.ThematicBreak;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ru.noties.markwon.AbstractMarkwonPlugin;
|
||||
import ru.noties.markwon.MarkwonConfiguration;
|
||||
import ru.noties.markwon.MarkwonSpansFactory;
|
||||
@ -51,14 +54,57 @@ import ru.noties.markwon.image.ImageProps;
|
||||
*/
|
||||
public class CorePlugin extends AbstractMarkwonPlugin {
|
||||
|
||||
/**
|
||||
* @see #addOnTextAddedListener(OnTextAddedListener)
|
||||
* @since 4.0.0-SNAPSHOT
|
||||
*/
|
||||
public interface OnTextAddedListener {
|
||||
|
||||
/**
|
||||
* Will be called when new text is added to resulting {@link ru.noties.markwon.SpannableBuilder}.
|
||||
* Please note that only text represented by {@link Text} node will trigger this callback
|
||||
* (text inside code and code-blocks won\'t trigger it).
|
||||
* <p>
|
||||
* Please note that if you wish to add spans you must use {@code start} parameter
|
||||
* in order to place spans correctly ({@code start} represents the index at which {@code text}
|
||||
* was added). So, to set a span for the whole length of the text added one should use:
|
||||
* <p>
|
||||
* {@code
|
||||
* visitor.builder().setSpan(new MySpan(), start, start + text.length(), 0);
|
||||
* }
|
||||
*
|
||||
* @param visitor {@link MarkwonVisitor}
|
||||
* @param text literal that had been added
|
||||
* @param start index in {@code visitor} as which text had been added
|
||||
* @see #addOnTextAddedListener(OnTextAddedListener)
|
||||
*/
|
||||
void onTextAdded(@NonNull MarkwonVisitor visitor, @NonNull String text, int start);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static CorePlugin create() {
|
||||
return new CorePlugin();
|
||||
}
|
||||
|
||||
// @since 4.0.0-SNAPSHOT
|
||||
private final List<OnTextAddedListener> onTextAddedListeners = new ArrayList<>(0);
|
||||
|
||||
protected CorePlugin() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be useful to post-process text added. For example for auto-linking capabilities.
|
||||
*
|
||||
* @see OnTextAddedListener
|
||||
* @since 4.0.0-SNAPSHOT
|
||||
*/
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
@NonNull
|
||||
public CorePlugin addOnTextAddedListener(@NonNull OnTextAddedListener onTextAddedListener) {
|
||||
onTextAddedListeners.add(onTextAddedListener);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) {
|
||||
text(builder);
|
||||
@ -114,11 +160,20 @@ public class CorePlugin extends AbstractMarkwonPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
private static void text(@NonNull MarkwonVisitor.Builder builder) {
|
||||
private void text(@NonNull MarkwonVisitor.Builder builder) {
|
||||
builder.on(Text.class, new MarkwonVisitor.NodeVisitor<Text>() {
|
||||
@Override
|
||||
public void visit(@NonNull MarkwonVisitor visitor, @NonNull Text text) {
|
||||
visitor.builder().append(text.getLiteral());
|
||||
|
||||
final int length = visitor.length();
|
||||
final String literal = text.getLiteral();
|
||||
|
||||
visitor.builder().append(literal);
|
||||
|
||||
// @since 4.0.0-SNAPSHOT
|
||||
for (OnTextAddedListener onTextAddedListener : onTextAddedListeners) {
|
||||
onTextAddedListener.onTextAdded(visitor, literal, length);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
20
markwon-linkify/build.gradle
Normal file
20
markwon-linkify/build.gradle
Normal file
@ -0,0 +1,20 @@
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
|
||||
compileSdkVersion config['compile-sdk']
|
||||
buildToolsVersion config['build-tools']
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion config['min-sdk']
|
||||
targetSdkVersion config['target-sdk']
|
||||
versionCode 1
|
||||
versionName version
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api project(':markwon-core')
|
||||
}
|
||||
|
||||
registerArtifact(this)
|
4
markwon-linkify/gradle.properties
Normal file
4
markwon-linkify/gradle.properties
Normal file
@ -0,0 +1,4 @@
|
||||
POM_NAME=Linkify
|
||||
POM_ARTIFACT_ID=linkify
|
||||
POM_DESCRIPTION=Markwon plugin to linkify text (based on Android Linkify)
|
||||
POM_PACKAGING=aar
|
1
markwon-linkify/src/main/AndroidManifest.xml
Normal file
1
markwon-linkify/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1 @@
|
||||
<manifest package="ru.noties.markwon.linkify" />
|
@ -0,0 +1,91 @@
|
||||
package ru.noties.markwon.linkify;
|
||||
|
||||
import android.support.annotation.IntDef;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.util.Linkify;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
import ru.noties.markwon.AbstractMarkwonPlugin;
|
||||
import ru.noties.markwon.MarkwonVisitor;
|
||||
import ru.noties.markwon.SpannableBuilder;
|
||||
import ru.noties.markwon.core.CorePlugin;
|
||||
|
||||
public class LinkifyPlugin extends AbstractMarkwonPlugin {
|
||||
|
||||
@IntDef(flag = true, value = {
|
||||
Linkify.EMAIL_ADDRESSES,
|
||||
Linkify.PHONE_NUMBERS,
|
||||
Linkify.WEB_URLS,
|
||||
Linkify.ALL
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@interface LinkifyMask {
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static LinkifyPlugin create() {
|
||||
return create(Linkify.EMAIL_ADDRESSES | Linkify.PHONE_NUMBERS | Linkify.WEB_URLS);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static LinkifyPlugin create(@LinkifyMask int mask) {
|
||||
return new LinkifyPlugin(mask);
|
||||
}
|
||||
|
||||
private final int mask;
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
LinkifyPlugin(@LinkifyMask int mask) {
|
||||
this.mask = mask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(@NonNull Registry registry) {
|
||||
registry.require(CorePlugin.class, new Action<CorePlugin>() {
|
||||
@Override
|
||||
public void apply(@NonNull CorePlugin corePlugin) {
|
||||
corePlugin.addOnTextAddedListener(new LinkifyTextAddedListener(mask));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static class LinkifyTextAddedListener implements CorePlugin.OnTextAddedListener {
|
||||
|
||||
private final int mask;
|
||||
private final SpannableStringBuilder builder;
|
||||
|
||||
LinkifyTextAddedListener(int mask) {
|
||||
this.mask = mask;
|
||||
this.builder = new SpannableStringBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextAdded(@NonNull MarkwonVisitor visitor, @NonNull String text, int start) {
|
||||
|
||||
// clear previous state
|
||||
builder.clear();
|
||||
builder.clearSpans();
|
||||
|
||||
// append text to process
|
||||
builder.append(text);
|
||||
|
||||
if (Linkify.addLinks(builder, mask)) {
|
||||
final Object[] spans = builder.getSpans(0, builder.length(), Object.class);
|
||||
if (spans != null
|
||||
&& spans.length > 0) {
|
||||
final SpannableBuilder spannableBuilder = visitor.builder();
|
||||
for (Object span : spans) {
|
||||
spannableBuilder.setSpan(
|
||||
span,
|
||||
start + builder.getSpanStart(span),
|
||||
start + builder.getSpanEnd(span),
|
||||
builder.getSpanFlags(span));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ include ':app', ':sample',
|
||||
':markwon-image',
|
||||
':markwon-image-glide',
|
||||
':markwon-image-picasso',
|
||||
':markwon-linkify',
|
||||
':markwon-recycler',
|
||||
':markwon-recycler-table',
|
||||
':markwon-syntax-highlight',
|
||||
|
Loading…
x
Reference in New Issue
Block a user