LoginSignup
67
57

More than 5 years have passed since last update.

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

Posted at

初めに

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

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

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

MarkdownのJavaScriptライブラリ達

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

JavaScript - Markdownパーサーのshowdown.js、markdown-js、markedを簡単比較

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

Markdown エディタ の例

marked.jsの使い方

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

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

パースされた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より)

<!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>

上記サンプルはいい感じに動く。

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

<!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のサンプルは下記の通り。

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

とマークダウンを書いた場合、textfugalevel2が入ります。

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

marked.jsの764行目あたりに各マークダウンのHTMLの変換処理が書かれています。

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

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

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

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

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要素を利用しました。

ここから試せます。

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

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

*red/hoge*
*red\/hoge*

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

最後に

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

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

67
57
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
67
57