Working with realtive urls
This commit is contained in:
		
							parent
							
								
									9fbf5ff1b1
								
							
						
					
					
						commit
						250dd7677d
					
				| @ -97,6 +97,8 @@ Lorem ipsum `dolor` sit amet | ||||
| Lorem ipsum dolor `sit` amet | ||||
| Lorem ipsum dolor sit `amet` | ||||
| 
 | ||||
| `Lorem ipsum dolor sit amet` | ||||
| 
 | ||||
| ### Code block | ||||
| // todo syntax higlight | ||||
| ``` | ||||
|  | ||||
| @ -55,8 +55,8 @@ class AppModule { | ||||
| 
 | ||||
|     @Singleton | ||||
|     @Provides | ||||
|     UrlProvider urlProvider() { | ||||
|         return new UrlProviderImpl(); | ||||
|     UriProcessor uriProcessor() { | ||||
|         return new UriProcessorImpl(); | ||||
|     } | ||||
| 
 | ||||
|     @Provides | ||||
|  | ||||
							
								
								
									
										12
									
								
								app/src/main/java/ru/noties/markwon/CollectionUtils.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								app/src/main/java/ru/noties/markwon/CollectionUtils.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| package ru.noties.markwon; | ||||
| 
 | ||||
| import java.util.Collection; | ||||
| 
 | ||||
| public abstract class CollectionUtils { | ||||
| 
 | ||||
|     public static boolean isEmpty(Collection<?> collection) { | ||||
|         return collection == null || collection.size() == 0; | ||||
|     } | ||||
| 
 | ||||
|     private CollectionUtils() {} | ||||
| } | ||||
| @ -27,6 +27,9 @@ public class MainActivity extends Activity { | ||||
|     @Inject | ||||
|     Themes themes; | ||||
| 
 | ||||
|     @Inject | ||||
|     UriProcessor uriProcessor; | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
| @ -38,9 +41,13 @@ public class MainActivity extends Activity { | ||||
|         themes.apply(this); | ||||
| 
 | ||||
|         // how can we obtain SpannableConfiguration after theme was applied? | ||||
|         // as we inject `themes` we won't be able to inject configuration, as it requires theme set | ||||
| 
 | ||||
|         setContentView(R.layout.activity_main); | ||||
| 
 | ||||
|         // we process additionally github urls, as if url has in path `blob`, we won't receive | ||||
|         // desired file, but instead rendered html | ||||
|         checkUri(); | ||||
| 
 | ||||
|         final AppBarItem.Renderer appBarRenderer | ||||
|                 = new AppBarItem.Renderer(findViewById(R.id.app_bar), new View.OnClickListener() { | ||||
| @ -59,7 +66,7 @@ public class MainActivity extends Activity { | ||||
|         markdownLoader.load(uri(), new MarkdownLoader.OnMarkdownTextLoaded() { | ||||
|             @Override | ||||
|             public void apply(String text) { | ||||
|                 markdownRenderer.render(MainActivity.this, text, new MarkdownRenderer.MarkdownReadyListener() { | ||||
|                 markdownRenderer.render(MainActivity.this, uri(), text, new MarkdownRenderer.MarkdownReadyListener() { | ||||
|                     @Override | ||||
|                     public void onMarkdownReady(CharSequence markdown) { | ||||
|                         Markwon.setText(textView, markdown); | ||||
| @ -80,8 +87,6 @@ public class MainActivity extends Activity { | ||||
| 
 | ||||
|         final Uri uri = uri(); | ||||
| 
 | ||||
|         Debug.i(uri); | ||||
| 
 | ||||
|         if (uri != null) { | ||||
|             title = uri.getLastPathSegment(); | ||||
|             subtitle = uri.toString(); | ||||
| @ -93,6 +98,13 @@ public class MainActivity extends Activity { | ||||
|         return new AppBarItem.State(title, subtitle); | ||||
|     } | ||||
| 
 | ||||
|     private void checkUri() { | ||||
|         final Uri uri = uri(); | ||||
|         if (uri != null) { | ||||
|             getIntent().setData(uriProcessor.process(uri)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private Uri uri() { | ||||
|         final Intent intent = getIntent(); | ||||
|         return intent != null | ||||
|  | ||||
| @ -45,9 +45,6 @@ public class MarkdownLoader { | ||||
|     @Inject | ||||
|     OkHttpClient client; | ||||
| 
 | ||||
|     @Inject | ||||
|     UrlProvider urlProvider; | ||||
| 
 | ||||
|     private Future<?> task; | ||||
| 
 | ||||
|     @Inject | ||||
| @ -130,10 +127,8 @@ public class MarkdownLoader { | ||||
| 
 | ||||
|     private String loadExternalUrl(@NonNull Uri uri) { | ||||
| 
 | ||||
|         final String url = urlProvider.provide(uri); | ||||
| 
 | ||||
|         final Request request = new Request.Builder() | ||||
|                 .url(url) | ||||
|                 .url(uri.toString()) | ||||
|                 .build(); | ||||
| 
 | ||||
|         Response response = null; | ||||
|  | ||||
| @ -1,14 +1,23 @@ | ||||
| package ru.noties.markwon; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.net.Uri; | ||||
| import android.os.Handler; | ||||
| import android.support.annotation.NonNull; | ||||
| import android.support.annotation.Nullable; | ||||
| 
 | ||||
| import org.commonmark.ext.gfm.strikethrough.StrikethroughExtension; | ||||
| import org.commonmark.node.Node; | ||||
| import org.commonmark.parser.Parser; | ||||
| 
 | ||||
| import java.util.Collections; | ||||
| import java.util.concurrent.ExecutorService; | ||||
| import java.util.concurrent.Future; | ||||
| 
 | ||||
| import javax.inject.Inject; | ||||
| 
 | ||||
| import ru.noties.markwon.renderer.SpannableRenderer; | ||||
| 
 | ||||
| @ActivityScope | ||||
| public class MarkdownRenderer { | ||||
| 
 | ||||
| @ -31,15 +40,37 @@ public class MarkdownRenderer { | ||||
|     MarkdownRenderer() { | ||||
|     } | ||||
| 
 | ||||
|     public void render(@NonNull final Context context, @NonNull final String markdown, @NonNull final MarkdownReadyListener listener) { | ||||
|     public void render( | ||||
|             @NonNull final Context context, | ||||
|             @Nullable final Uri uri, | ||||
|             @NonNull final String markdown, | ||||
|             @NonNull final MarkdownReadyListener listener) { | ||||
|         cancel(); | ||||
|         task = service.submit(new Runnable() { | ||||
|             @Override | ||||
|             public void run() { | ||||
| 
 | ||||
|                 final UrlProcessor urlProcessor; | ||||
|                 if (uri == null) { | ||||
|                     urlProcessor = null; | ||||
|                 } else { | ||||
|                     urlProcessor = new UrlProcessorRelativeToAbsolute(uri.toString()); | ||||
|                 } | ||||
| 
 | ||||
|                 final SpannableConfiguration configuration = SpannableConfiguration.builder(context) | ||||
|                         .asyncDrawableLoader(loader) | ||||
|                         .urlProcessor(urlProcessor) | ||||
|                         .build(); | ||||
|                 final CharSequence text = Markwon.markdown(configuration, markdown); | ||||
| 
 | ||||
|                 final Parser parser = Parser.builder() | ||||
|                         .extensions(Collections.singleton(StrikethroughExtension.create())) | ||||
|                         .build(); | ||||
| 
 | ||||
|                 final Node node = parser.parse(markdown); | ||||
|                 final SpannableRenderer renderer = new SpannableRenderer(); | ||||
|                 final CharSequence text = renderer.render(configuration, node); | ||||
| 
 | ||||
| //                final CharSequence text = Markwon.markdown(configuration, markdown); | ||||
|                 handler.post(new Runnable() { | ||||
|                     @Override | ||||
|                     public void run() { | ||||
|  | ||||
							
								
								
									
										9
									
								
								app/src/main/java/ru/noties/markwon/UriProcessor.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								app/src/main/java/ru/noties/markwon/UriProcessor.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| package ru.noties.markwon; | ||||
| 
 | ||||
| import android.net.Uri; | ||||
| import android.support.annotation.NonNull; | ||||
| 
 | ||||
| @SuppressWarnings("WeakerAccess") | ||||
| public interface UriProcessor { | ||||
|     Uri process(@NonNull Uri uri); | ||||
| } | ||||
| @ -5,25 +5,33 @@ import android.support.annotation.NonNull; | ||||
| 
 | ||||
| import java.util.List; | ||||
| 
 | ||||
| class UrlProviderImpl implements UrlProvider { | ||||
| class UriProcessorImpl implements UriProcessor { | ||||
| 
 | ||||
|     private static final String GITHUB = "github.com"; | ||||
| 
 | ||||
|     @Override | ||||
|     public String provide(@NonNull Uri uri) { | ||||
|     public Uri process(@NonNull final Uri uri) { | ||||
| 
 | ||||
|         // hm... github, even having a README.md in path will return rendered HTML | ||||
| 
 | ||||
|         final Uri out; | ||||
| 
 | ||||
|         if (GITHUB.equals(uri.getAuthority())) { | ||||
| 
 | ||||
|             final List<String> segments = uri.getPathSegments(); | ||||
|             if (segments != null | ||||
|                     && segments.contains("blob")) { | ||||
|             final int size = segments != null | ||||
|                     ? segments.size() | ||||
|                     : 0; | ||||
| 
 | ||||
|             if (size > 0) { | ||||
| 
 | ||||
|                 // we need to modify the final uri | ||||
|                 final Uri.Builder builder = new Uri.Builder() | ||||
|                         .scheme(uri.getScheme()) | ||||
|                         .authority(uri.getAuthority()) | ||||
|                         .fragment(uri.getFragment()) | ||||
|                         .query(uri.getQuery()); | ||||
| 
 | ||||
|                 for (String segment: segments) { | ||||
|                     final String part; | ||||
|                     if ("blob".equals(segment)) { | ||||
| @ -33,10 +41,14 @@ class UrlProviderImpl implements UrlProvider { | ||||
|                     } | ||||
|                     builder.appendPath(part); | ||||
|                 } | ||||
|                 uri = builder.build(); | ||||
|                 out = builder.build(); | ||||
|             } else { | ||||
|                 out = uri; | ||||
|             } | ||||
|         } else { | ||||
|             out = uri; | ||||
|         } | ||||
| 
 | ||||
|         return uri.toString(); | ||||
|         return out; | ||||
|     } | ||||
| } | ||||
| @ -1,8 +0,0 @@ | ||||
| package ru.noties.markwon; | ||||
| 
 | ||||
| import android.net.Uri; | ||||
| import android.support.annotation.NonNull; | ||||
| 
 | ||||
| public interface UrlProvider { | ||||
|     String provide(@NonNull Uri uri); | ||||
| } | ||||
| @ -24,6 +24,7 @@ public class SpannableConfiguration { | ||||
|     private final AsyncDrawable.Loader asyncDrawableLoader; | ||||
|     private final SyntaxHighlight syntaxHighlight; | ||||
|     private final LinkSpan.Resolver linkResolver; | ||||
|     private final UrlProcessor urlProcessor; | ||||
|     private final SpannableHtmlParser htmlParser; | ||||
| 
 | ||||
|     private SpannableConfiguration(Builder builder) { | ||||
| @ -31,6 +32,7 @@ public class SpannableConfiguration { | ||||
|         this.asyncDrawableLoader = builder.asyncDrawableLoader; | ||||
|         this.syntaxHighlight = builder.syntaxHighlight; | ||||
|         this.linkResolver = builder.linkResolver; | ||||
|         this.urlProcessor = builder.urlProcessor; | ||||
|         this.htmlParser = builder.htmlParser; | ||||
|     } | ||||
| 
 | ||||
| @ -50,6 +52,10 @@ public class SpannableConfiguration { | ||||
|         return linkResolver; | ||||
|     } | ||||
| 
 | ||||
|     public UrlProcessor urlProcessor() { | ||||
|         return urlProcessor; | ||||
|     } | ||||
| 
 | ||||
|     public SpannableHtmlParser htmlParser() { | ||||
|         return htmlParser; | ||||
|     } | ||||
| @ -61,6 +67,7 @@ public class SpannableConfiguration { | ||||
|         private AsyncDrawable.Loader asyncDrawableLoader; | ||||
|         private SyntaxHighlight syntaxHighlight; | ||||
|         private LinkSpan.Resolver linkResolver; | ||||
|         private UrlProcessor urlProcessor; | ||||
|         private SpannableHtmlParser htmlParser; | ||||
| 
 | ||||
|         public Builder(Context context) { | ||||
| @ -87,6 +94,11 @@ public class SpannableConfiguration { | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
|         public Builder urlProcessor(UrlProcessor urlProcessor) { | ||||
|             this.urlProcessor = urlProcessor; | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
|         public Builder htmlParser(SpannableHtmlParser htmlParser) { | ||||
|             this.htmlParser = htmlParser; | ||||
|             return this; | ||||
| @ -105,8 +117,11 @@ public class SpannableConfiguration { | ||||
|             if (linkResolver == null) { | ||||
|                 linkResolver = new LinkResolverDef(); | ||||
|             } | ||||
|             if (urlProcessor == null) { | ||||
|                 urlProcessor = new UrlProcessorNoOp(); | ||||
|             } | ||||
|             if (htmlParser == null) { | ||||
|                 htmlParser = SpannableHtmlParser.create(theme, asyncDrawableLoader); | ||||
|                 htmlParser = SpannableHtmlParser.create(theme, asyncDrawableLoader, urlProcessor); | ||||
|             } | ||||
|             return new SpannableConfiguration(this); | ||||
|         } | ||||
|  | ||||
| @ -0,0 +1,8 @@ | ||||
| package ru.noties.markwon; | ||||
| 
 | ||||
| import android.support.annotation.NonNull; | ||||
| 
 | ||||
| public interface UrlProcessor { | ||||
|     @NonNull | ||||
|     String process(@NonNull String destination); | ||||
| } | ||||
| @ -0,0 +1,11 @@ | ||||
| package ru.noties.markwon; | ||||
| 
 | ||||
| import android.support.annotation.NonNull; | ||||
| 
 | ||||
| public class UrlProcessorNoOp implements UrlProcessor { | ||||
|     @NonNull | ||||
|     @Override | ||||
|     public String process(@NonNull String destination) { | ||||
|         return destination; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,43 @@ | ||||
| package ru.noties.markwon; | ||||
| 
 | ||||
| import android.support.annotation.NonNull; | ||||
| import android.support.annotation.Nullable; | ||||
| 
 | ||||
| import java.net.MalformedURLException; | ||||
| import java.net.URL; | ||||
| 
 | ||||
| public class UrlProcessorRelativeToAbsolute implements UrlProcessor { | ||||
| 
 | ||||
|     private final URL base; | ||||
| 
 | ||||
|     public UrlProcessorRelativeToAbsolute(@NonNull String base) { | ||||
|         this.base = obtain(base); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @Override | ||||
|     public String process(@NonNull String destination) { | ||||
| 
 | ||||
|         String out = destination; | ||||
| 
 | ||||
|         if (base != null) { | ||||
|             try { | ||||
|                 final URL u = new URL(base, destination); | ||||
|                 out = u.toString(); | ||||
|             } catch (MalformedURLException e) { | ||||
|                 e.printStackTrace(); | ||||
|             } | ||||
|         } | ||||
|         return out; | ||||
|     } | ||||
| 
 | ||||
|     @Nullable | ||||
|     private static URL obtain(String base) { | ||||
|         try { | ||||
|             return new URL(base); | ||||
|         } catch (MalformedURLException e) { | ||||
|             e.printStackTrace(); | ||||
|             return null; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -51,7 +51,7 @@ import ru.noties.markwon.spans.ThematicBreakSpan; | ||||
| @SuppressWarnings("WeakerAccess") | ||||
| public class SpannableMarkdownVisitor extends AbstractVisitor { | ||||
| 
 | ||||
|     private static final String HTML_CONTENT = "<%1$s>%2$s</%1$s>"; | ||||
|     private static final String HTML_CONTENT = "<%1$s>%2$s</%3$s>"; | ||||
| 
 | ||||
|     private final SpannableConfiguration configuration; | ||||
|     private final SpannableStringBuilder builder; | ||||
| @ -253,7 +253,8 @@ public class SpannableMarkdownVisitor extends AbstractVisitor { | ||||
| 
 | ||||
|     @Override | ||||
|     public void visit(SoftLineBreak softLineBreak) { | ||||
|         newLine(); | ||||
|         // at first here was a new line, but here should be a space char | ||||
|         builder.append(' '); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
| @ -306,13 +307,14 @@ public class SpannableMarkdownVisitor extends AbstractVisitor { | ||||
| 
 | ||||
|         final Node parent = image.getParent(); | ||||
|         final boolean link = parent != null && parent instanceof Link; | ||||
|         final String destination = configuration.urlProcessor().process(image.getDestination()); | ||||
| 
 | ||||
|         setSpan( | ||||
|                 length, | ||||
|                 new AsyncDrawableSpan( | ||||
|                         configuration.theme(), | ||||
|                         new AsyncDrawable( | ||||
|                                 image.getDestination(), | ||||
|                                 destination, | ||||
|                                 configuration.asyncDrawableLoader() | ||||
|                         ), | ||||
|                         AsyncDrawableSpan.ALIGN_BOTTOM, | ||||
| @ -351,7 +353,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor { | ||||
|                             setSpan(item.start, span); | ||||
|                         } else { | ||||
|                             final String content = builder.subSequence(start, builder.length()).toString(); | ||||
|                             final String html = String.format(HTML_CONTENT, item.tag, content); | ||||
|                             final String html = String.format(HTML_CONTENT, item.tag, content, tag.name()); | ||||
|                             final Object[] spans = htmlParser.htmlSpans(html); | ||||
|                             final int length = spans != null | ||||
|                                     ? spans.length | ||||
| @ -382,7 +384,8 @@ public class SpannableMarkdownVisitor extends AbstractVisitor { | ||||
|     public void visit(Link link) { | ||||
|         final int length = builder.length(); | ||||
|         visitChildren(link); | ||||
|         setSpan(length, new LinkSpan(configuration.theme(), link.getDestination(), configuration.linkResolver())); | ||||
|         final String destination = configuration.urlProcessor().process(link.getDestination()); | ||||
|         setSpan(length, new LinkSpan(configuration.theme(), destination, configuration.linkResolver())); | ||||
|     } | ||||
| 
 | ||||
|     private void setSpan(int start, @NonNull Object span) { | ||||
|  | ||||
| @ -2,20 +2,30 @@ package ru.noties.markwon.renderer.html; | ||||
| 
 | ||||
| import android.graphics.drawable.Drawable; | ||||
| import android.support.annotation.NonNull; | ||||
| import android.support.annotation.Nullable; | ||||
| import android.text.Html; | ||||
| 
 | ||||
| import ru.noties.markwon.UrlProcessor; | ||||
| import ru.noties.markwon.spans.AsyncDrawable; | ||||
| 
 | ||||
| class HtmlImageGetter implements Html.ImageGetter { | ||||
| 
 | ||||
|     private final AsyncDrawable.Loader loader; | ||||
|     private final UrlProcessor urlProcessor; | ||||
| 
 | ||||
|     HtmlImageGetter(@NonNull AsyncDrawable.Loader loader) { | ||||
|     HtmlImageGetter(@NonNull AsyncDrawable.Loader loader, @Nullable UrlProcessor urlProcessor) { | ||||
|         this.loader = loader; | ||||
|         this.urlProcessor = urlProcessor; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public Drawable getDrawable(String source) { | ||||
|         return new AsyncDrawable(source, loader); | ||||
|         final String destination; | ||||
|         if (urlProcessor == null) { | ||||
|             destination = source; | ||||
|         } else { | ||||
|             destination = urlProcessor.process(source); | ||||
|         } | ||||
|         return new AsyncDrawable(destination, loader); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -13,6 +13,8 @@ import java.util.HashSet; | ||||
| import java.util.Map; | ||||
| import java.util.Set; | ||||
| 
 | ||||
| import ru.noties.debug.Debug; | ||||
| import ru.noties.markwon.UrlProcessor; | ||||
| import ru.noties.markwon.spans.AsyncDrawable; | ||||
| import ru.noties.markwon.spans.SpannableTheme; | ||||
| 
 | ||||
| @ -22,8 +24,20 @@ public class SpannableHtmlParser { | ||||
|     // we need to handle images independently (in order to parse alt, width, height, etc) | ||||
| 
 | ||||
|     // creates default parser | ||||
|     public static SpannableHtmlParser create(@NonNull SpannableTheme theme, @NonNull AsyncDrawable.Loader loader) { | ||||
|         return builderWithDefaults(theme, loader) | ||||
|     public static SpannableHtmlParser create( | ||||
|             @NonNull SpannableTheme theme, | ||||
|             @NonNull AsyncDrawable.Loader loader | ||||
|     ) { | ||||
|         return builderWithDefaults(theme, loader, null) | ||||
|                 .build(); | ||||
|     } | ||||
| 
 | ||||
|     public static SpannableHtmlParser create( | ||||
|             @NonNull SpannableTheme theme, | ||||
|             @NonNull AsyncDrawable.Loader loader, | ||||
|             @NonNull UrlProcessor urlProcessor | ||||
|     ) { | ||||
|         return builderWithDefaults(theme, loader, urlProcessor) | ||||
|                 .build(); | ||||
|     } | ||||
| 
 | ||||
| @ -33,7 +47,8 @@ public class SpannableHtmlParser { | ||||
| 
 | ||||
|     public static Builder builderWithDefaults( | ||||
|             @NonNull SpannableTheme theme, | ||||
|             @Nullable AsyncDrawable.Loader asyncDrawableLoader | ||||
|             @Nullable AsyncDrawable.Loader asyncDrawableLoader, | ||||
|             @Nullable UrlProcessor urlProcessor | ||||
|     ) { | ||||
| 
 | ||||
|         final BoldProvider boldProvider = new BoldProvider(); | ||||
| @ -42,7 +57,7 @@ public class SpannableHtmlParser { | ||||
| 
 | ||||
|         final HtmlParser parser; | ||||
|         if (asyncDrawableLoader != null) { | ||||
|             parser = DefaultHtmlParser.create(new HtmlImageGetter(asyncDrawableLoader), null); | ||||
|             parser = DefaultHtmlParser.create(new HtmlImageGetter(asyncDrawableLoader, urlProcessor), null); | ||||
|         } else { | ||||
|             parser = DefaultHtmlParser.create(null, null); | ||||
|         } | ||||
| @ -71,9 +86,12 @@ public class SpannableHtmlParser { | ||||
| 
 | ||||
|     public interface HtmlParser { | ||||
|         Object[] getSpans(@NonNull String html); | ||||
| 
 | ||||
|         Spanned parse(@NonNull String html); | ||||
|     } | ||||
| 
 | ||||
|     private static final String LINK_START = "<a "; | ||||
| 
 | ||||
|     private final Map<String, SpanProvider> customTags; | ||||
|     private final Set<String> voidTags; | ||||
|     private final HtmlParser parser; | ||||
| @ -97,7 +115,7 @@ public class SpannableHtmlParser { | ||||
|         if (length < 3) { | ||||
|             tag = null; | ||||
|         } else { | ||||
|             // okay, we will consider a tag a void one if it's in our void list tag or if it ends with `/>` | ||||
|             // okay, we will consider a tag a void one if it's in our void list tag | ||||
|             final boolean closing = '<' == html.charAt(0) && '/' == html.charAt(1); | ||||
|             final boolean voidTag; | ||||
|             if (closing) { | ||||
| @ -144,10 +162,14 @@ public class SpannableHtmlParser { | ||||
|     @Nullable | ||||
|     public Object[] htmlSpans(String html) { | ||||
|         // todo, additional handling of: image & link | ||||
|         Debug.i("html: %s", html); | ||||
|         return parser.getSpans(html); | ||||
|     } | ||||
| 
 | ||||
|     // this is called when we encounter `void` tag | ||||
|     // `img` is a void tag | ||||
|     public Spanned html(String html) { | ||||
|         Debug.i("html: %s", html); | ||||
|         return parser.parse(html); | ||||
|     } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Dimitry Ivanov
						Dimitry Ivanov