ぼくのかんがえたさいきょうのマークダウン（marked.jsを魔改造）

# 初めに

ちょっとしたメモをとるのに便利なマークダウンは世界中で使われていて、自分もよく使ってます。

ただ、最近マークダウンで書いた文字に色をつけたいな〜となりいろいろ調べてました（HTMLをべた書きしたり・・・）

自分でマークダウンの変換を作ったほうが早い！？と迷走したりもしましたが、最終的にJavaScriptのライブラリたちを改造するのに落ち着きました。

# MarkdownのJavaScriptライブラリ達

軽く調べたところ、showdown.js、markdown-js、marked.jsの3種類がよくヒットして、これらは、下記の記事で詳しく比較されてました。

[JavaScript - Markdownパーサーのshowdown.js、markdown-js、markedを簡単比較](http://kannokanno.hatenablog.com/entry/2013/06/19/132042)

marked.jsに選んだのはvue.jsに簡単なサンプルがあったのでvue.jsの勉強も兼ねて選んでみました。

[Markdown エディタ の例](http://jp.vuejs.org/examples/)

# marked.jsの使い方

使い方は簡単でmarked.jsを読み込み下記の様に実行すればconsoleにパースされたHTMLが出て来る。（公式より）

```javascript
console.log(marked('I am using __markdown__.'));
```

パースされたHTMLが変えるためそれをそのまま要素に入れてあげればいい。（公式より）

```html
<!doctype html>
<html>
<head>
  <meta charset="utf-8"/>
  <title>Marked in the browser</title>
  <script src="lib/marked.js"></script>
</head>
<body>
  <div id="content"></div>
  <script>
    document.getElementById('content').innerHTML =
      marked('# Marked in browser\n\nRendered by **marked**.');
  </script>
</body>
</html>
```

ただ、これだと一般的なマークダウンエディタのように、左側で編集、右側にビューとできないのでキー入力され、離れた時にパースを実行させてみる。（CSSはvue.jsより）


```html
<!doctype html>
<html>
<head>
  <meta charset="utf-8"/>
  <title>Sample</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.6/marked.min.js"></script>
  <style type="text/css">
    html,body,#editor {
        margin: 0;
        height: 100%;
        font-family: 'Helvetica Neue', Arial, sans-serif;
        color: #333;
    }
    
    textarea,#editor div {
        display: inline-block;
        width: 49%;
        height: 100%;
        vertical-align: top;
        -webkit-box-sizing: border-box;
        -moz-box-sizing: border-box;
        box-sizing: border-box;
        padding: 0 20px;
    }
    
    textarea {
        border: none;
        border-right: 1px solid #ccc;
        resize: none;
        outline: none;
        background-color: #f6f6f6;
        font-size: 14px;
        font-family: 'Monaco', courier, monospace;
        padding: 20px;
    }
    
    code {
        color: #f66;
    }
  </style>
</head>
<body>
  <div id="editor">
    <textarea id="input"># hoge</textarea>
    <div id="result"></div>
  </div>
  <script>
    document.getElementById('input').onkeyup = function(e) {
      document.getElementById('result').innerHTML =
        marked(document.getElementById('input').value);
    };
  </script>
</body>
</html>
```

[上記サンプル](https://theimaginationwasunbroken.com/marked-js-custom/sample.html)はいい感じに動く。

vue.jsのサンプルは下記の通り。

```html
<!doctype html>
<html>
<head>
  <meta charset="utf-8"/>
  <title>Vue-Sample</title>
　　　　<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.28/vue.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.6/marked.min.js"></script>
  <style type="text/css">
    html,body,#editor {
        margin: 0;
        height: 100%;
        font-family: 'Helvetica Neue', Arial, sans-serif;
        color: #333;
    }
    
    textarea,#editor div {
        display: inline-block;
        width: 49%;
        height: 100%;
        vertical-align: top;
        -webkit-box-sizing: border-box;
        -moz-box-sizing: border-box;
        box-sizing: border-box;
        padding: 0 20px;
    }
    
    textarea {
        border: none;
        border-right: 1px solid #ccc;
        resize: none;
        outline: none;
        background-color: #f6f6f6;
        font-size: 14px;
        font-family: 'Monaco', courier, monospace;
        padding: 20px;
    }
    
    code {
        color: #f66;
    }
  </style>
</head>
<body>
  <div id="editor">
    <textarea v-model="input" debounce="300"></textarea>
    <div v-html="input | marked"></div>
  </div>
  <script>
    new Vue({
      el: '#editor',
      data: {
        input: '# hello'
      },
      filters: {
        marked: marked
      }
    })
  </script>
</body>
</html>
```

うーん。JavaScriptがスッキリしている。

# オリジナルの記法の実装

では、marked.jsを弄ってオリジナルの記法を実装していきたいと思います。

marked.jsはrenderをoverrideすることができます。

公式のoverrideのサンプルは下記の通り。

```javascript
var marked = require('marked');
var renderer = new marked.Renderer();

renderer.heading = function (text, level) {
  var escapedText = text.toLowerCase().replace(/[^\w]+/g, '-');

  return '<h' + level + '><a name="' +
                escapedText +
                 '" class="anchor" href="#' +
                 escapedText +
                 '"><span class="header-link"></span></a>' +
                  text + '</h' + level + '>';
},

console.log(marked('# heading+', { renderer: renderer }));
```

重要なのは`var renderer = new marked.Renderer();`でRnederオブジェクトを作成し、`renderer.heading`でh1,h2要素などのレンダーを上書きをしている点です。

`function(text,level)`の引数は

```
## fuga
```

とマークダウンを書いた場合、`text`に`fuga`、`level`に`2`が入ります。



marked.jsは読み込んだテキストをパースして、Renderオブジェクトの各関数によってHTMLに変換をしています。

[marked.js](https://github.com/chjj/marked/blob/master/lib/marked.js)の764行目あたりに各マークダウンのHTMLの変換処理が書かれています。

`strong`などインライン要素はわかりやすいです。

```javascript
Renderer.prototype.strong = function(text) {
  return '<strong>' + text + '</strong>';
};
```

本当はオリジナルの記法を追加したかったですが、marked.jsがrenderのoverrideを提供しているのでこれを利用します。

書いたコードがこちらです。

```javascript
renderer.em = function(text) {
    var indexNumber = text.indexOf('/');
    if (indexNumber !== -1 && text.substr(indexNumber - 1, 1) !== "\\") {
        return '<span style="color:' + text.substr(0, indexNumber) + ';">' + text.substr(indexNumber + 1) + '</span>';
    }
    return '<em>' + text.replace('\\/', '/') + '</em>';
};
```

今回はem要素を利用しました。

[ここ](https://theimaginationwasunbroken.com/marked-js-custom/)から試せます。

使い方は下記のように色を最初に書き、「/」で区切りテキストを記述することで色を指定できます。

また、「/」を表示したい場合のためにエスケープを実装しています。エスケープは「\」を「/」の前に入れます。

```
*red/hoge*
*red\/hoge*
```

これで、なんとか実装ができました。

# 最後に

marked.jsはコードのハイライトもできたりサーバーサイドでも使えるため、いろいろできる幅が広がりそうです。

いいマークダウンライフを！