schedule2018-07-30

Markdownを「Marked.js」を使ってHTMLに変換する方法

はじめに

markedを使ってマークダウン記法でHTMLに変換できるフォームを作成しました。

QiitaやはてなでもMarkdownを使って、記事が書けるようになっていますね。

本ブログでも、Markdownで記事の管理をしています。 また、コードを載せるためsyntax hilightが効くように、highlight.jsをmarked.jsに連携させています。

動くサンプルはこちらにあるので、実際どう動くのかお確かめください。

利用方法

marked

ここから、marked.min.jsをダウンロードしてお使いください。 npmを使っては、npm install -g markedでできるようです。

公式のサンプルは以下のようになっています。

<!doctype html>
<html>
<head>
  <meta charset="utf-8"/>
  <title>Marked in the browser</title>
</head>
<body>
  <div id="content"></div>
  <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
  <script>
    document.getElementById('content').innerHTML =
      marked('# Marked in the browserRendered by **marked**.');
  </script>
</body>
</html>

marked()に渡したMarkdown文字列をHTMLに変換します。

マークダウンの書き方はこちらです。

準備

この項から、こちらのサンプルの解説を行います。

<link rel="stylesheet" href="{{url_for('static',filename='css/github.css')}}">

<script src="/js/lib/marked.min.js"></script>
<script src="/js/lib/highlight.pack.js"></script>

ダウンロードしておいた、marked.jshighlight.jsをインポートします。
highlight.jsは、コードのシンタックスハイライトのために利用します。 コードのスタイルシートは、githubと同じものです。これも、highlight.jsのページにあります。

あとは、jQueryとBootstrapを使っているので、適宜利用してください。

HTML

<h2>Markdownの入力フォーム</h2>
<div class="col-md-12 ml-auto mr-auto text-left">
    <form id="editor-form" class="">

        <div class="form-group border border-default">
            <textarea type="textarea" class="form-control" name="markdown" placeholder="markdown" rows="15" required>
            ## Markedjsを使った簡易エディタ[markedjs](https://github.com/evilstreak/markdown-js)を使ってマークダウン記法でHTMLに変換できるフォームを作成しました。
            </textarea>
        </div>
    </form>
    <div class="d-flex pt-4">
        <div class="mr-auto p-2">
            <button class="btn btn-primary  btn-simple" type="button" onclick="draw_preview()">Preview</button>
            <span>このボタンで変換しますよ</span>
        </div>
    </div>
</div>

<h2>HTMLに変換した結果</h2>
<div class="col-md-12 ml-auto mr-auto text-left" style="border: 3px solid #ebebeb;">
    <div class="preview" id="marked-preview"></div>
</div>

<h2>目次を自動生成</h2>
<div class="preview" id="headline-preview"></div>
<div class="preview" id="headline" hidden></div>

テキストエリアに書かれたマークダウンを、Previewボタンで変換してid="marked-preview"にHTMLを入れます。

draw_preview()で変換の処理をしています。

同時に、見出し#の行の目次を作るため、id="headline-preview"も用意しました。

MarkdownからHTMLに変換する

function draw_preview() {
    var markdown = $('#editor-form [name=markdown]').val();
    // html
    var html = marked(markdown)
    // 目次を作成する
    headline(markdown);

    $('#marked-preview').html(html);
    
}

jQueryでtextareaに書かれた文字列を渡しています。 Markdownへの変換はmarked()だけです。簡単ですね。

headlineは、見出しを取り出す自作の関数です。後で説明します。

markedの拡張

marked.Renderer()を上書きすることで、書き方を拡張することができます。

window.onload = function () {
    marked_js_render();
};

/*
 * 拡張の追加
 */
function marked_js_render(){
    // marked.js + highlight.js
    var renderer = new marked.Renderer()

    // code syntax hilightの編集
    renderer.code = function (code, language) {
        return '<pre' + '><code class="hljs">' + hljs.highlightAuto(code).value + '</code></pre>';
    };
    // tableタグ
    renderer.table = function(header, body) {
        if (body) body = '<tbody>' + body + '</tbody>';
    
        return '<table class="table table-hover">'
        + '<thead>'
        + header
        + '</thead>'
        + body
        + '</table>';
    };
    marked.setOptions({
        renderer: renderer,
    });
}

コードのシンタックスハイライトが効くように、highlitejsのhighlightAutoでコードを変換します。 また、クラスにhljsをつけてCSSが効くようのしました。

テーブルは、 Bootstrapのクラス名を当てて、スタイルが変化するようにしています。 他のデザインテンプレートへも、同じようにクラス名を当てることが出来ます。

目次の自動生成

ちょっと蛇足ですが、目次の自動生成も同時に行います。 #の行を見出しとして、抽出します。

コードの中にも#があるため、判定して無視するようにしました。

function headline(markdown){
    lines = markdown.split(/\r|\r|/);
    var headline = [];
    var in_code = false;
    for(var it in lines){
        if(lines[it].match(/^```.?/)){
            // コードの行内の場合は外す
            in_code = in_code ? false : true;
        }
        if(lines[it][0] == '#' && !in_code){
            // 先頭の#とスペースを削除して追加
            headline.push(lines[it].replace(/^#+/, '').trim());
        }
    }
    console.log(headline)

    // 表示用のリスト構文
    var preview = "<ul>";
    for(var it in headline){
        preview += "<li>" 
                +  headline[it]
                + "</li>";
    }
    preview += "</ul>"
    // 確認用
    $('#headline-preview').html(preview);
    // 更新用
    $('#headline').html(headline.join(','));
}

おわりに

marked.jsを使うと、簡単にHTMLへパースする処理を組み込むことが出来ました。 最初から拡張のしやすい形になっているため、ご自身の好みに合わせてどんどん拡張してください。 もっといろんなところに、Markdownが広がることを願っています。

動くサンプルはこちらにあるので、実際どう動くのかお確かめください。

また、npmのコマンドを使ってマークダウンから変換する方法についても書いていますので、そちらもどうぞ。

コマンドでマークダウンを変換するprocessmd | npm

参考