Search code examples
regexexpressnpmmarkdownjavascript-marked

How to transform link in markdown() to link with favicon using Google S2 Converter?


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


Solution

  • 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.