[JavaScript] google-code-prettify でのソースコードのハイライト表示についてまとめてみた

[JavaScript] google-code-prettify でのソースコードのハイライト表示についてまとめてみた

現在このブログでは、ソースコードのハイライト表示で google-code-prettify を使っていますが、それについてまとめてみました。

google-code-prettifyの導入

google-code-prettify は <pre></pre> で囲われた整形済みのソースコードなどを自動的に言語判断して、コードカラーリングを行ってくれるものです。
他にもソースコードをハイライト表示できるライブラリで SyntaxHighlighter などがありますが、google-code-prettify の方がシンプルで使い勝手がいいのでこっちを使っています。

ファイルのダウンロード

まずは、http://code.google.com/p/google-code-prettify/ にある Downloads から ライブラリ一式をダウンロードします。
特に中身をいじらなければ軽いファイルがいいので Minimized source files の方を選びます。

google-code-prettify の Downloads ページで prettify-small-1-Jun-2011.tar.bz2 を選択中

ダウンロードされた zipファイル を解凍すると、jsファイル と cssファイル が一式揃ったフォルダが展開されます。

展開された google-code-prettifyフォルダの中身

その中でコアとなる jsファイルは prettify.js で、コードのカラーリングを設定しているのは prettify.css となるので、HTML の <head>内にインクルードするときは、そちらのパスを指定することになります。

ファイルのアップロード

展開した google-code-prettifyフォルダを、好きな場所にそのままフォルダごとアップロードします。
とりあえず今回は、google-code-prettify を使う HTMLファイルと同じ階層にいます。

アップロードした google-code-prettifyフォルダまでのディレクトリ

HTMLのHEAD内の編集

HTML の <head>内に prettify.jsprettify.css のパスを追加します。

<link href="google-code-prettify/prettify.css" type="text/css" rel="stylesheet" />
<script type="text/javascript" src="google-code-prettify/prettify.js"></script>

その後に、HTML が onload したときに prettyPrint() を呼び出します。
このとき、google-code-prettify を紹介してるブログではだいたい <body onload="prettyPrint()"> という感じで onload の呼び出しを使っていますが、そのやり方は他のライブラリとの併用を考えるとあまり良くないのでイベントリスナーを使います。
また、Internet Explorer では addEventListener() メソッドが使えないので、代わりに attachEvent() メソッドを使用します。

<script type="text/javascript">
// <![CDATA[
(function(){
    function init(event){
        prettyPrint();
    }
    if(window.addEventListener)window.addEventListener("load",init,false);
    else if(window.attachEvent)window.attachEvent("onload",init);
})();
// ]]>
</script>

一応ここら辺は Google のリファレンスに従っています。

Javascript code prettifier

HTMLの整形済みのソースコードの記述

あとは、ハイライトしたい PREタグに prettyprint というクラス名を指定することで、ソースコードのカラーリングが適応されます。

<pre class="prettyprint">

Example

google-code-prettifyを使ったサンプル

更に行番号を表示したい場合は、続けて linenums というクラス名を追加して下さい。

<pre class="prettyprint linenums">

Example

google-code-prettifyを使ったサンプル

1行ごとに番号を振りわけるためのCSSの編集

クラス名に linenums を指定して行番号を表示しましたが、このとき、デフォルトの状態だと5行ごとに番号が振られています。
これを 1行ごとに番号を振るようにする場合は、prettify.css にある li.L0…li.L8 の指定をコメントアウトすればできるのですが、自分は元のソースコードをいじくるのがあまり好きじゃないので、新たにCSSを上書きするようにしました。

ライブラリの JavaScript の処理で、PREタグの中身が書き変わると linenums というクラス名のついたOLタグが生成されるので、これを利用します。

<style type="text/css">
ol.linenums li {
    list-style: decimal outside;
}
</style>

Example

google-code-prettifyを使ったサンプル

[blogger]ブログにコードを見やすく貼る。Google-code-prettify導入しました。

見栄えを調整するためのCSSの編集

もう少し見やすくするために番号の横にラインを付け加えたりと、色々調整していきます。
これは好みに合わせて下さい。

<style type="text/css">
pre.prettyprint {
   background-color: rgb(248, 248, 248);
   color: gray;
   padding: 0 0 0 3px;
}
ol.linenums li {
    list-style: decimal outside;
    line-height: 1.5;
    border-left: solid 3px #6CE26C;
    padding-left: 3px;
    margin-left: .7em;
    background-color: white;
}
ol.linenums li.L1,
ol.linenums li.L3,
ol.linenums li.L5,
ol.linenums li.L7,
ol.linenums li.L9 {background-color: rgb(248, 248, 248)}
</style>

Example

google-code-prettifyを使ったサンプル

AutoPagerize対応

Firefox の “Greasemonkey” や “Safari 機能拡張” などに、AutoPagerize というページ分割されたWebサイトを自動的に下に継ぎ足して表示するスクリプトがありますが、これを使われているときに継ぎ足された記事はハイライト表示されません。(当たり前ですが)
で、これに対応させるというマニアックな処理を付け加えたいと思います。

イベントリスナーの登録

AutoPagerize でのページが継ぎ足されたときは AutoPagerize_DOMNodeInserted というイベントが呼び出されるみたいなので、そのイベントリスナーを登録します。
また、今回の場合は Firefox とか Safari での AutoPagerize の対応のため addEventListener() メソッドのみを使用しています。

if(document.body.addEventListener){
    document.body.addEventListener('AutoPagerize_DOMNodeInserted',function(e){
        // ページが継ぎ足されたときの処理
    },false);
}

ページが継ぎ足されたときの処理

ページが継ぎ足されたときに、そのまま prettyPrint() メソッドを呼び出してしまうと、すでにハイライトされたPREタグも含めてハイライト処理がかかってしまうので、一度PREタグのクラス名を全て空にしてから新たに追加されたPREタグのみをハイライト処理します。

  1. 新たに追加されたPREタグのクラス名を一時保存
  2. 全てのPREタグのクラス名を空にする
  3. 新たに追加されたPREタグのクラス名を戻す
  4. ハイライト処理
  5. 全てのPREタグのクラス名を戻す
// 全てのPREタグの情報
var pre=document.getElementsByTagName("pre");
var leng=pre.length;
var tmp=new Array(leng);

// 新たに追加されたPREタグの情報
var new_pre=e.target.getElementsByTagName("pre");
var new_leng=new_pre.length;
var new_tmp=new Array(new_leng);

// 1. 新たに追加されたPREタグのクラス名を一時保存
for(var i=0;i<new_leng;i++){
    new_tmp[i]=new_pre[i].className;
}

// 2. 全てのPREタグのクラス名を空にする
for(var i=0;i<leng;i++){
    tmp[i]=pre[i].className;
    pre[i].className='';
}

// 3. 新たに追加されたPREタグのクラス名を戻す
for(var i=0;i<new_leng;i++){
    new_pre[i].className=new_tmp[i];
}

// 4. ハイライト処理
prettyPrint();

// 5. 全てのPREタグのクラス名を戻す
for(var i=0;i<leng;i++){
    pre[i].className=tmp[i];
}

まとめ

最終的な記述はこれになります。

<script type="text/javascript">
// <![CDATA[
(function(){
    function init(event){
        prettyPrint();
        
        if(document.body.addEventListener){
            document.body.addEventListener('AutoPagerize_DOMNodeInserted',function(e){
                var pre=document.getElementsByTagName("pre");
                var leng=pre.length;
                var tmp=new Array(leng);
                var new_pre=e.target.getElementsByTagName("pre");
                var new_leng=new_pre.length;
                var new_tmp=new Array(new_leng);
                for(var i=0;i<new_leng;i++){
                    new_tmp[i]=new_pre[i].className;
                }
                for(var i=0;i<leng;i++){
                    tmp[i]=pre[i].className;
                    pre[i].className='';
                }
                for(var i=0;i<new_leng;i++){
                    new_pre[i].className=new_tmp[i];
                }
                prettyPrint();
                for(var i=0;i<leng;i++){
                    pre[i].className=tmp[i];
                }
            },false);
        }
    }
    if(window.addEventListener)window.addEventListener("load",init,false);
    else if(window.attachEvent)window.attachEvent("onload",init);
})();
// ]]>
</script>

“Firefox” か “Google Chrome” か “Safari” で AutoPagerize をインストールしたら、以下のページで試してみて下さい。

以上です。