Skip to content

Commit

Permalink
text-added-listener for core-plugin and linkify module
Browse files Browse the repository at this point in the history
  • Loading branch information
noties committed Jun 2, 2019
1 parent 2e35ef5 commit cedb397
Show file tree
Hide file tree
Showing 10 changed files with 185 additions and 7 deletions.
5 changes: 4 additions & 1 deletion _CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@
* `JLatex` plugin now is not dependent on ImagesPlugin
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
internally caches latest state and skips scheduling if drawables are already processed
* configure with registry
* removed priority
* images-plugin moved to standalone again
1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/ru/noties/markwon/MarkdownRenderer.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
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;
Expand Down Expand Up @@ -107,6 +108,7 @@ public void configureImages(@NonNull ImagesPlugin plugin) {
.addMediaDecoder(SvgMediaDecoder.create());
}
}))
.usePlugin(LinkifyPlugin.create())
.usePlugin(SyntaxHighlightPlugin.create(prism4j, prism4jTheme))
.usePlugin(GifAwarePlugin.create(context))
.usePlugin(TablePlugin.create(context))
Expand Down
8 changes: 4 additions & 4 deletions app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
59 changes: 57 additions & 2 deletions markwon-core/src/main/java/ru/noties/markwon/core/CorePlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
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;
Expand All @@ -51,14 +54,57 @@
*/
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);
Expand Down Expand Up @@ -114,11 +160,20 @@ public void afterSetText(@NonNull TextView textView) {
}
}

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);
}
}
});
}
Expand Down
20 changes: 20 additions & 0 deletions markwon-linkify/build.gradle
Original file line number Diff line number Diff line change
@@ -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 changes: 4 additions & 0 deletions markwon-linkify/gradle.properties
Original file line number Diff line number Diff line change
@@ -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 change: 1 addition & 0 deletions markwon-linkify/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<manifest package="ru.noties.markwon.linkify" />
Original file line number Diff line number Diff line change
@@ -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));
}
}
}
}
}
}
1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down

0 comments on commit cedb397

Please sign in to comment.