たくあんメモ

だいたいプログラム開発のメモです

Markedカスタマイズ:テーブルの1列目をヘッダーにする

概要

Markedを使ってマークダウンでテーブルの1列目をthタグにするために、独自構文+renderメソッドで関数定義することで対応した。

Markedとは

マークダウン構文で書いたテキストをhtmlに変換するjavascriptライブラリ。

github.com

簡単な使い方

  • マークダウンを記述(タグにid属性を書いておく)
  • jsを読み込む
  • maked関数でid指定して、htmlに変換して表示する
<div id="markdownText">
|   | A | B | C | D | E | F | G | H  |
|---|---|---|---|---|---|---|---|----|
| A | H | F | E | C | D | G | B | A! |
| B | - | H | D | A | C | D | E | B! |
| C | - | - | H | F | G | B | A | C! |
| D | - | - | - | H | B | E | G | D! |
| E | - | - | - | - | H | A | F | E! |
| F | - | - | - | - | - | H | C | F! |
| G | - | - | - | - | - | - | H | G! |
| H | - | - | - | - | - | - | - | -  |
</div>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script>
document.getElementById("markdownText").innerHTML = marked(document.getElementById("markdownText").innerHTML.trim());
</script>

実行すると、以下のような表示になる。

A B C D E F G H
A H F E C D G B A!
B - H D A C D E B!
C - - H F G B A C!
D - - - H B E G D!
E - - - - H A F E!
F - - - - - H C F!
G - - - - - - H G!
H - - - - - - - -

htmlは以下のようなソースになっている。

<div id="markdownText"><table>
<thead>
<tr>
<th></th>
<th>A</th>
<th>B</th>
<th>C</th>
<th>D</th>
<th>E</th>
<th>F</th>
<th>G</th>
<th>H</th>
</tr>
</thead>
<tbody><tr>
<td>A</td>
<td>H</td>
<td>F</td>
<td>E</td>
<td>C</td>
<td>D</td>
<td>G</td>
<td>B</td>
<td>A!</td>
</tr>
(中略)
</tbody></table>
</div>

1列目をthタグにしたい

マークダウンで1列目をthタグにするような構文は定義されていない?ので、Markedのrendererメソッドで拡張した。

1: 独自構文の定義

Markedのrendererメソッドでは "n列目" という情報を取得できなかったので、
まずは独自の構文を定義した。

以下のように、先頭に「:」をつけたものをthタグでレンダリングする事とする。

|   | A | B | C | D | E | F | G | H  |
|---|---|---|---|---|---|---|---|----|
| :A | H | F | E | C | D | G | B | A! |
| :B | - | H | D | A | C | D | E | B! |
| :C | - | - | H | F | G | B | A | C! |
| :D | - | - | - | H | B | E | G | D! |
| :E | - | - | - | - | H | A | F | E! |
| :F | - | - | - | - | - | H | C | F! |
| :G | - | - | - | - | - | - | H | G! |
| :H | - | - | - | - | - | - | - | -  |

2: Markedのrendererメソッドで拡張

詳しくはドキュメントを参照するとして、renderer.tablecellでテーブルセルの生成をカスタマイズ可能。 marked.js.org

あとはrenderer.tablecellメソッドで、
tbodyのセルのときだけテキストの先頭1文字目が「:」の場合は、thタグで生成するように書く。

var renderer = new marked.Renderer();

// tableタグ
renderer.tablecell = function(content, flags) {
    //thead
    if (flags.header) {
        return '<th>' + content + '</th>';
    }
    //tbody
    if (content.substring(0, 1) === ':') {
        return '<th>' + content.substring(1) + '</th>';
    }
    return '<td>' + content + '</td>';
};
marked.setOptions({
    renderer: renderer,
});

document.getElementById("markdownText").innerHTML = marked(document.getElementById("markdownText").innerHTML.trim());

これを実行すると以下のような表示になる。

ABCDEFGH
AHFECDGBA!
B-HDACDEB!
C--HFGBAC!
D---HBEGD!
E----HAFE!
F-----HCF!
G------HG!
H--------

生成するhtmlは以下のようになっており、1列目がthタグになっている。

<div id="markdownText"><table>
<thead>
<tr>
<th></th>
<th>A</th>
<th>B</th>
<th>C</th>
<th>D</th>
<th>E</th>
<th>F</th>
<th>G</th>
<th>H</th>
</tr>
</thead>
<tbody><tr>
<th>A</th>
<th>H</th>
<th>F</th>
<th>E</th>
<th>C</th>
<th>D</th>
<th>G</th>
<th>B</th>
<th>A!</th>
</tr>
(中略)
</tbody></table>
</div>

 

※html/js全文

<div id="markdownText">
|   | A | B | C | D | E | F | G | H  |
|---|---|---|---|---|---|---|---|----|
| :A | H | F | E | C | D | G | B | A! |
| :B | - | H | D | A | C | D | E | B! |
| :C | - | - | H | F | G | B | A | C! |
| :D | - | - | - | H | B | E | G | D! |
| :E | - | - | - | - | H | A | F | E! |
| :F | - | - | - | - | - | H | C | F! |
| :G | - | - | - | - | - | - | H | G! |
| :H | - | - | - | - | - | - | - | -  |
</div>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script>
var renderer = new marked.Renderer();

// tableタグ
renderer.tablecell = function(content, flags) {
    //thead
    if (flags.header) {
        return '<th>' + content + '</th>';
    }
    //tbody
    if (content.substring(0, 1) === ':') {
        return '<th>' + content.substring(1) + '</th>';
    }
    return '<td>' + content + '</td>';
};
marked.setOptions({
    renderer: renderer,
});

document.getElementById("markdownText").innerHTML = marked(document.getElementById("markdownText").innerHTML.trim());
</script>