@Nullable @Override public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) { final Map<String, String> attributes = tag.attributes(); final String src = attributes.get("src"); if (TextUtils.isEmpty(src)) { return null; } final String destination = configuration.urlProcessor().process(src); // todo: replacement text is link... as we are not at block level // and cannot inspect the parent of this node... (img and a are both inlines) // // but we can look and see if we are inside a LinkSpan (will have to extend TagHandler // to obtain an instance SpannableBuilder for inspection) return configuration.factory().image( configuration.theme(), destination, configuration.asyncDrawableLoader(), configuration.imageSizeResolver(), imageSizeParser.parse(tag.attributes()), false ); } }
/** * @see #setMarkdown(TextView, SpannableConfiguration, String) * @since 1.0.0 */ public static void setMarkdown(@NonNull TextView view, @NonNull String markdown) { setMarkdown(view, SpannableConfiguration.create(view.getContext()), markdown); }
public SpannableMarkdownVisitor( @NonNull SpannableConfiguration configuration, @NonNull SpannableBuilder builder ) { this.configuration = configuration; this.builder = builder; this.htmlParser = configuration.htmlParser(); this.theme = configuration.theme(); this.factory = configuration.factory(); }
@Nullable @Override public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) { final String destination = tag.attributes().get("href"); if (!TextUtils.isEmpty(destination)) { return configuration.factory().link( configuration.theme(), configuration.urlProcessor().process(destination), configuration.linkResolver() ); } return null; } }
@Test public void testNewBuilder() { final SpannableConfiguration configuration = SpannableConfiguration .builder(null) .theme(mock(SpannableTheme.class)) .asyncDrawableLoader(mock(AsyncDrawable.Loader.class)) .newBuilder(null) .build(); assertEquals(configuration.theme(), newConfiguration.theme()); assertEquals(configuration.asyncDrawableLoader(), newConfiguration.asyncDrawableLoader()); assertEquals(configuration.syntaxHighlight(), newConfiguration.syntaxHighlight()); assertEquals(configuration.linkResolver(), newConfiguration.linkResolver()); assertEquals(configuration.urlProcessor(), newConfiguration.urlProcessor()); assertEquals(configuration.imageSizeResolver(), newConfiguration.imageSizeResolver()); assertEquals(configuration.factory(), newConfiguration.factory()); assertEquals(configuration.softBreakAddsNewLine(), newConfiguration.softBreakAddsNewLine()); assertEquals(configuration.htmlParser(), newConfiguration.htmlParser()); assertEquals(configuration.htmlRenderer(), newConfiguration.htmlRenderer()); assertEquals(configuration.htmlAllowNonClosedTags(), newConfiguration.htmlAllowNonClosedTags());
@Override public void visit(Image image) { final int length = builder.length(); visitChildren(image); // we must check if anything _was_ added, as we need at least one char to render if (length == builder.length()) { builder.append('\uFFFC'); } final Node parent = image.getParent(); final boolean link = parent != null && parent instanceof Link; final String destination = configuration.urlProcessor().process(image.getDestination()); setSpan( length, factory.image( theme, destination, configuration.asyncDrawableLoader(), configuration.imageSizeResolver(), null, link ) ); // todo, maybe, if image is not inside a link, we should make it clickable, so // user can open it in external viewer? }
); final SpannableConfiguration configuration = SpannableConfiguration.builder(context) .asyncDrawableLoader(loader) .urlProcessor(urlProcessor)
@Nullable @Override public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) { return configuration.factory().emphasis(); } }
@Override public void visit(Link link) { final int length = builder.length(); visitChildren(link); final String destination = configuration.urlProcessor().process(link.getDestination()); setSpan(length, factory.link(theme, destination, configuration.linkResolver())); }
@Override public void visit(Document document) { super.visit(document); configuration.htmlRenderer().render(configuration, builder, htmlParser); }
if (!configuration.htmlAllowNonClosedTags()) { end = HtmlTag.NO_END; } else {
@SuppressWarnings("ConstantConditions") @NonNull private SpannableConfiguration configuration(@NonNull TestConfig config) { final SpannableFactory factory = new TestFactory(config.hasOption(TestConfig.USE_PARAGRAPHS)); final MarkwonHtmlParser htmlParser = config.hasOption(TestConfig.USE_HTML) ? null : MarkwonHtmlParser.noOp(); final boolean softBreakAddsNewLine = config.hasOption(TestConfig.SOFT_BREAK_ADDS_NEW_LINE); final boolean htmlAllowNonClosedTags = config.hasOption(TestConfig.HTML_ALLOW_NON_CLOSED_TAGS); return SpannableConfiguration.builder(null) .theme(mock(SpannableTheme.class)) .linkResolver(mock(LinkResolverDef.class)) .htmlParser(htmlParser) .factory(factory) .softBreakAddsNewLine(softBreakAddsNewLine) .htmlAllowNonClosedTags(htmlAllowNonClosedTags) .build(); } }
@Nullable @Override public Object getSpans(@NonNull SpannableConfiguration configuration, @NonNull HtmlTag tag) { return configuration.factory().strongEmphasis(); } }
protected static void visitChildren( @NonNull SpannableConfiguration configuration, @NonNull SpannableBuilder builder, @NonNull HtmlTag.Block block) { TagHandler handler; for (HtmlTag.Block child : block.children()) { if (!child.isClosed()) { continue; } handler = configuration.htmlRenderer().tagHandler(child.name()); if (handler != null) { handler.handle(configuration, builder, child); } else { visitChildren(configuration, builder, child); } } } }
@Override public void visit(CustomBlock customBlock) { if (!(customBlock instanceof JLatexMathBlock)) { super.visit(customBlock); return; } final String latex = ((JLatexMathBlock) customBlock).latex(); final int length = builder.length(); builder.append(latex); SpannableBuilder.setSpans( builder, configuration.factory().image( configuration.theme(), JLatexMathMedia.makeDestination(latex), configuration.asyncDrawableLoader(), configuration.imageSizeResolver(), new ImageSize(new ImageSize.Dimension(100, "%"), null), false ), length, builder.length() ); } };
when(factory.code(any(SpannableTheme.class), anyBoolean())).thenReturn(codeSpan); final SpannableConfiguration configuration = SpannableConfiguration.builder(mock(Context.class)) .syntaxHighlight(highlight) .factory(factory)