| Index: third_party/pkg/markdown/lib/src/inline_parser.dart
|
| diff --git a/third_party/pkg/markdown/lib/src/inline_parser.dart b/third_party/pkg/markdown/lib/src/inline_parser.dart
|
| index 392ca69b1904df56e9e9dfa0b18806a6b5424679..6772c8416d95a16ca556b12ea2fc271223f56c4e 100644
|
| --- a/third_party/pkg/markdown/lib/src/inline_parser.dart
|
| +++ b/third_party/pkg/markdown/lib/src/inline_parser.dart
|
| @@ -29,6 +29,7 @@ class InlineParser {
|
|
|
| new AutolinkSyntax(),
|
| new LinkSyntax(),
|
| + new ImageLinkSyntax(),
|
| // "*" surrounded by spaces is left alone.
|
| new TextSyntax(r' \* '),
|
| // "_" surrounded by spaces is left alone.
|
| @@ -83,8 +84,11 @@ class InlineParser {
|
| } else {
|
| syntaxes = defaultSyntaxes;
|
| }
|
| - // Custom link resolver goes after the generic text syntax.
|
| - syntaxes.insert(1, new LinkSyntax(linkResolver: document.linkResolver));
|
| + // Custom link resolvers goes after the generic text syntax.
|
| + syntaxes.insertAll(1, [
|
| + new LinkSyntax(linkResolver: document.linkResolver),
|
| + new ImageLinkSyntax(linkResolver: document.linkResolver)
|
| + ]);
|
| }
|
|
|
| List<Node> parse() {
|
| @@ -214,8 +218,8 @@ class AutolinkSyntax extends InlineSyntax {
|
| bool onMatch(InlineParser parser, Match match) {
|
| final url = match[1];
|
|
|
| - final anchor = new Element.text('a', escapeHtml(url));
|
| - anchor.attributes['href'] = url;
|
| + final anchor = new Element.text('a', escapeHtml(url))
|
| + ..attributes['href'] = url;
|
| parser.addNode(anchor);
|
|
|
| return true;
|
| @@ -267,76 +271,105 @@ class LinkSyntax extends TagSyntax {
|
| // 4: Contains the title, if present, for an inline link.
|
| }
|
|
|
| - LinkSyntax({this.linkResolver})
|
| - : super(r'\[', end: linkPattern);
|
| -
|
| - bool onMatchEnd(InlineParser parser, Match match, TagState state) {
|
| - var url;
|
| - var title;
|
| + LinkSyntax({this.linkResolver, String pattern: r'\['})
|
| + : super(pattern, end: linkPattern);
|
|
|
| + Node createNode(InlineParser parser, Match match, TagState state) {
|
| // If we didn't match refLink or inlineLink, then it means there was
|
| // nothing after the first square bracket, so it isn't a normal markdown
|
| // link at all. Instead, we allow users of the library to specify a special
|
| // resolver function ([linkResolver]) that may choose to handle
|
| // this. Otherwise, it's just treated as plain text.
|
| - if ((match[1] == null) || (match[1] == '')) {
|
| - if (linkResolver == null) return false;
|
| + if (isNullOrEmpty(match[1])) {
|
| + if (linkResolver == null) return null;
|
|
|
| // Only allow implicit links if the content is just text.
|
| // TODO(rnystrom): Do we want to relax this?
|
| - if (state.children.any((child) => child is! Text)) return false;
|
| + if (state.children.any((child) => child is! Text)) return null;
|
| // If there are multiple children, but they are all text, send the
|
| // combined text to linkResolver.
|
| var textToResolve = state.children.fold('',
|
| (oldVal, child) => oldVal + child.text);
|
| +
|
| // See if we have a resolver that will generate a link for us.
|
| - final node = linkResolver(textToResolve);
|
| - if (node == null) return false;
|
| + return linkResolver(textToResolve);
|
| + } else {
|
| + Link link = getLink(parser, match, state);
|
| + if (link == null) return null;
|
|
|
| - parser.addNode(node);
|
| - return true;
|
| + final Element node = new Element('a', state.children)
|
| + ..attributes["href"] = escapeHtml(link.url)
|
| + ..attributes['title'] = escapeHtml(link.title);
|
| +
|
| + cleanMap(node.attributes);
|
| + return node;
|
| }
|
| + }
|
|
|
| + Link getLink(InlineParser parser, Match match, TagState state) {
|
| if ((match[3] != null) && (match[3] != '')) {
|
| // Inline link like [foo](url).
|
| - url = match[3];
|
| - title = match[4];
|
| + var url = match[3];
|
| + var title = match[4];
|
|
|
| // For whatever reason, markdown allows angle-bracketed URLs here.
|
| if (url.startsWith('<') && url.endsWith('>')) {
|
| url = url.substring(1, url.length - 1);
|
| }
|
| +
|
| + return new Link(null, url, title);
|
| } else {
|
| + var id;
|
| // Reference link like [foo] [bar].
|
| - var id = match[2];
|
| - if (id == '') {
|
| + if (match[2] == '')
|
| // The id is empty ("[]") so infer it from the contents.
|
| id = parser.source.substring(state.startPos + 1, parser.pos);
|
| - }
|
| + else
|
| + id = match[2];
|
|
|
| // References are case-insensitive.
|
| id = id.toLowerCase();
|
| + return parser.document.refLinks[id];
|
| + }
|
| + }
|
| +
|
| + bool onMatchEnd(InlineParser parser, Match match, TagState state) {
|
| + Node node = createNode(parser, match, state);
|
| + if (node == null) return false;
|
| + parser.addNode(node);
|
| + return true;
|
| + }
|
| +}
|
|
|
| - // Look up the link.
|
| - final link = parser.document.refLinks[id];
|
| - // If it's an unknown link just emit plaintext.
|
| - if (link == null) return false;
|
| +/// Matches images like `` and
|
| +/// `![alternate text][url reference]`.
|
| +class ImageLinkSyntax extends LinkSyntax {
|
| + Resolver linkResolver;
|
| + ImageLinkSyntax({this.linkResolver})
|
| + : super(pattern: r'!\[');
|
|
|
| - url = link.url;
|
| - title = link.title;
|
| - }
|
| + Node createNode(InlineParser parser, Match match, TagState state) {
|
| + Node node = super.createNode(parser, match, state);
|
| + if (node == null) return null;
|
|
|
| - final anchor = new Element('a', state.children);
|
| - anchor.attributes['href'] = escapeHtml(url);
|
| - if ((title != null) && (title != '')) {
|
| - anchor.attributes['title'] = escapeHtml(title);
|
| - }
|
| + final Element imageElement = new Element.withTag("img")
|
| + ..attributes["src"] = node.attributes["href"]
|
| + ..attributes["title"] = node.attributes["title"]
|
| + ..attributes["alt"] = node.children
|
| + .map((e) => isNullOrEmpty(e) || e is! Text ? '' : e.text)
|
| + .join(' ');
|
|
|
| - parser.addNode(anchor);
|
| - return true;
|
| + cleanMap(imageElement.attributes);
|
| +
|
| + node.children
|
| + ..clear()
|
| + ..add(imageElement);
|
| +
|
| + return node;
|
| }
|
| }
|
|
|
| +
|
| /// Matches backtick-enclosed inline code blocks.
|
| class CodeSyntax extends InlineSyntax {
|
| CodeSyntax(String pattern)
|
|
|