3

I'd like markdown links to have a favicon within the transformed link.

https://www.google.com/s2/favicons?domain=http://cnn.com - will return the favicon from any domain.

Marked (https://github.com/chjj/marked) - will turn all links in my code to a href's

So, How would I modify marked.js so that - http://cnn.com

will become <a href="http://cnn.com"><img src="https://www.google.com/s2/favicons?domain=http://cnn.com">http://cnn.com</a>

I do see this line 452 marked.js autolink: /^<([^ >]+(@|:\/)[^ >]+)>/, Ref: https://github.com/chjj/marked/blob/master/lib/marked.js

I'm using expressjs and NodeJS

Thanks Rob

mrmccormack
  • 143
  • 1
  • 10

2 Answers2

0

You don't have to mess with marked source code.

This simple regexp should do the trick:

const markedOutput = '<a href="http://cnn.com">http://cnn.com</a>';
const withFavIcons = markedOutput.replace(/(<a[^>]+>)(https?:\/\/[^<]+)(<\/a>)/gi, (m, open, url, close) => {
    const favicon = '<img src="https://www.google.com/s2/favicons?domain=' + url + '">';
    const truncated = url.length > 50 ? url.slice(0, 47) + '...' : url;
    return open + favicon + truncated + close;
});
Jake
  • 1,339
  • 9
  • 14
  • I updated my answer to meet the new requirements. Don't have enough reputation to comment anything but this post though. – Jake Oct 19 '17 at 21:03
  • Your updated answer worked perfectly. I'm not sure which approach to take, the override a render method or yours. I think lots of people may want this as a built in feature in marked() . For my app, I only have simple web links. – mrmccormack Oct 19 '17 at 21:20
  • Well if you ask me I would still stick with this one since I don't like duplication of code. However the other variant is more preferable if performance is the issue, since there is no additional overhead of using regexp. – Jake Oct 19 '17 at 21:32
  • I wonder if a YouTube thumbnail could be used for the image instead of favicon, thumbs are easy to fetch. http://img.youtube.com/vi/erLk59H86ww/1.jpg is the thumb for video link: http://www.youtube.com/watch?v=erLk59H86ww Thanks, – mrmccormack Oct 19 '17 at 21:58
  • Well this is getting kind of offtopic. – Jake Oct 19 '17 at 22:10
0

You can override a renderer method.

Marked works in two steps: (1) it parses the Markdown into a bunch of tokens and (2) it renders those tokens to HTML. As you don't want to alter the Markdown parsing (it already properly identifies links), but you do want to alter the HTML output, you want to override the renderer for links.

var renderer = new marked.Renderer();

get_favicon = function (text) {
    // return replacement text here...
    var out = '<img src="https://www.google.com/s2/favicons?domain='
    out += text + '">' + text + '</a>'
    return out
}

renderer.link = function (href, title, text) {
  if (this.options.sanitize) {
    try {
      var prot = decodeURIComponent(unescape(href))
        .replace(/[^\w:]/g, '')
        .toLowerCase();
    } catch (e) {
      return '';
    }
    if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0 || prot.indexOf('data:') === 0) {
      return '';
    }
  }
  var out = '<a href="' + href + '"';
  if (title) {
    out += ' title="' + title + '"';
  }
  out += '>' + get_favicon(text) + '</a>';
  return out;
};
}

// Pass the custom renderer to marked with the input.
markdown(input, renderer=renderer)

Note that I just took the default link method and altered it slightly to pass text through the get_favicon function. The get_favicon function accepts a text string and returns the replacement text (an image in this case). It could probably be improved as not all links will only have a domain as their text content. If the text contained more that the domain (path, fragment, query string, etc), then only use the domain for the favicon link. Or if the text did not contain a link at all (as the same renderer is used for all links, not just auto links) then the text should be returned unaltered. I'll leave those improvements as an exercise for the reader.

Waylan
  • 37,164
  • 12
  • 83
  • 109