但し書き

純粋なMarkdownのリンクの記法にはtarget="_blank"を付けるようなものはない。なので<a href="http://google.com" target="_blank">google</a>と書かないといけない。外部サービスでそういうことをしようと思ったら、そのサービスで対応してればその方法を使い、なければ諦めてこうしてhtmlをベタ書きするしかない。

そして自分のサイトでこれをやるには、一般的には変換後のDOMを書き換えたり、リンクのクリックイベントに引っ掛けるのが主流である。しかしMarkdownのパーサーにmarked.jsを使っているなら、少しだけ気分よくtarget="_blank"を付与することができる

やりたいこと

  • hrefが/スラッシュから始まるなら内部リンクとする
  • そうでなければtarget="_blank"を付与して、外部リンクを示すアイコンを付ける
  • リンクのテキストがhttp://hoge.comみたいに完全なURLならアイコンは付けない

これを変換のついでに行うようにしてみる。

コード

marked = require 'marked'

renderer = new marked.Renderer()
renderer.link = (href, title, text)->
    external = not /^\//.test href
    usePrefix = external and not /^http/.test text
    target = if external then ' target="_blank"' else ''
    prefix = if usePrefix then "<i class=\"fa fa-fw fa-external-link\"></i> " else ''
    title = if title then " title=\"#{title}\"" else ''
    href= " href=\"#{href}\""

    "<a#{href}#{target}#{title}>#{prefix}#{text}</a>"

marked.setOptions
    renderer: renderer

このコードはサーバーでもブラウザでも使える。ちなみにこのサイトではブラウザ側で変換している。これを初期化時にやっておけば、あとは普通に変換すれば良い。

表示例

* 内部リンク ... [トップ](/)
* 外部リンク ... [外部リンク](http://google.com)
* 明示的な外部リンク ... http://google.com

が、

<ul>
<li>内部リンク ... <a href="/">トップ</a></li>
<li>外部リンク ... <a href="http://google.com" target="_blank"><i class="fa fa-fw fa-external-link"></i> 外部リンク</a></li>
<li>明示的な外部リンク ... <a href="http://google.com" target="_blank">http://google.com</a></li>
</ul>

こうなって、

こうなる。

おまけ

highlight.jsを使ってコードスニペットのハイライトをする。

marked = require 'marked'
hljs = require 'highlight.js'

marked.setOptions
    highlight: (code, lang, callback)->
        if lang
            try
                hljs.highlight(lang, code).value
            catch
                code
        else
            code

try catchしてるのは、```langみたいにバッククオートのあとに指定した言語がhighlight.jsで対応してなかった時に、例外を起こして変換に失敗するので、その対処である。highlight.jsのdocには「言語は自動で識別するよ」的ことをなことが書いてあるが、それは嘘である。ほとんど期待した言語でハイライトしてくれないので、ちゃんと頭で言語を指定するべきである。