GitHub の Markdown に TOC (目次) を付けるブックマークレット (vanilla JS 編)

  • 14
    いいね
  • 2
    コメント

はじめに

皆さん、GitHub で Markdown 読む機会、意外と多いですよね。長い README とか、目次が欲しくなってきます。
そで、kobake@github さんによる GitHub の Markdown に TOC (目次) を付けるブックマークレット という記事を以前見つけてありがたく利用していたのですが、どうやら最近 GitHub の各ページから jQuery にアクセスできなくなったようでした。なので、こちらのブックマークレットを vanilla JS で書き直してみました。何か問題・ご意見・ご指摘等があればコメントお願いします!

Bookmarklet

a. 適当なページをブックマークします
b. URL を以下に変更(コピペ)します

bookmarklet
javascript:(function(){var e=(function(){/*.toc{border: 1px solid #aaa;padding: 4px 12px;margin-bottom: 12px;position: relative;padding-top: 30px;}.toc-title{display: inline-block;width: auto;background-color: #ccc;position: absolute;left: 0px;top: 0px;font-size: 8pt;padding: 2px 4px;padding-right: 8px;color: #666;}.toc-h{font-size: 11pt;}.toc-h1{}.toc-h2{margin-left: 20px;}.toc-h3{margin-left: 40px;}*/}).toString().match(/[^]*\/\*([^]*)\*\/\}$/)[1];var f=document.createElement('style');f.classList.add("toc-style");f.innerHTML='\n'+e+'\n';document.head.appendChild(f);var g=document.createElement('div');g.classList.add('toc');var i=document.createElement('div');i.classList.add('toc-title');i.innerHTML='TOC';g.appendChild(i);var j=document.querySelectorAll('.markdown-body')[0];j.insertBefore(g,j.firstChild);document.querySelectorAll('.markdown-body h1, .markdown-body h2, .markdown-body h3').forEach(function(a){var b=a.tagName.toLowerCase();var c=document.createElement("div");c.classList.add("toc-h");c.classList.add("toc-"+b);var d=document.createElement("a");c.appendChild(d);d.innerHTML="- "+a.childNodes[1].textContent;d.href=a.querySelectorAll('a')[0].href;g.appendChild(c)})})();

c. お好みの GitHub の markdown でブックマークを開きます(実行します)
d. ご覧あれ(例は facebook/react の README)

github-toc.gif

圧縮前コード

javascript: (function() {
    var style = (function () {/*
        .toc{
            border: 1px solid #aaa;
            padding: 4px 12px;
            margin-bottom: 12px;
            position: relative;
            padding-top: 30px;
        }
        .toc-title{
            display: inline-block;
            width: auto;
            background-color: #ccc;
            position: absolute;
            left: 0px;
            top: 0px;
            font-size: 8pt;
            padding: 2px 4px;
            padding-right: 8px;
            color: #666;
        }
        .toc-h{
            font-size: 11pt;
        }
        .toc-h1{
        }
        .toc-h2{
            margin-left: 20px;
        }
        .toc-h3{
            margin-left: 40px;
        }
    */}).toString().match(/[^]*\/\*([^]*)\*\/\}$/)[1];

    var styleEl = document.createElement('style');
    styleEl.classList.add('toc-style');
    styleEl.innerHTML = '\n' + style + '\n';
    document.head.appendChild(styleEl);

    var tocDiv = document.createElement('div');
    tocDiv.classList.add('toc');
    var tocTitleDiv = document.createElement('div');
    tocTitleDiv.classList.add('toc-title');
    tocTitleDiv.innerHTML = 'TOC';
    tocDiv.appendChild(tocTitleDiv);

    var markdownBody = document.querySelector('.markdown-body');
    markdownBody.insertBefore(tocDiv, markdownBody.firstChild);

    Array.prototype.forEach.call(document.querySelectorAll('.markdown-body h1, .markdown-body h2, .markdown-body h3'), function(node){
        // level
        var tagName = node.tagName.toLowerCase();

        // link div
        var linkDiv = document.createElement('div');
        linkDiv.classList.add('toc-h');
        linkDiv.classList.add('toc-' + tagName);

        // link
        var aEl = document.createElement('a');
        aEl.innerHTML = '- ' + node.childNodes[1].textContent;
        aEl.href = node.querySelector('a').href;
        linkDiv.appendChild(aEl);

        // append
        tocDiv.appendChild(linkDiv);
    });
})();

備考

  • style はkobake@githubさんのものを流用させていただきました。問題あればコメントお願いします。
  • aEl.innerHTML = "- " + node.childNodes[1].textContent の部分を調整すれば各見出しの見た目をいじれます。
  • querySelectorAll は比較的新しいですが、IE8以上で動くと思います(確認はしてない)
  • 動作確認は Chrome だけ行ってます。
  • 今後また GitHub 上の構造変化がある可能性もありますので、その際はまたコメント等でお知らせください。

TODO

  • jQuery の remove の部分は条件分岐面倒だったのでスキップしてる。必要なら書く。
  • 圧縮前コードを GitHub or Gist に移動します

history

  • querySelectorAll である必要がない部分を querySelector に変更した
  • quotation の種類を統一した
  • Array.prototype.forEach
  • Minify の方法少し変更