«前の日記(2006-01-27 (金)) 最新 次の日記(2006-02-01 (水))»  

まちゅダイアリー


2006-01-28 (土)

JavaScript による PukiWiki 自動リンク

Wiki の話。 Wiki の面白さの一つは、複数のページが自動的に繋がる(あるページに他のページの名前が含まれていた場合に、そのページへのリンクが勝手に張られる)ことだと思っている。

  • WikiName: 先頭を大文字にした単語を2つ以上繋げたページ名とする
  • BracketName: リンク先のページ名を明示的に括弧で括る
  • AutoLink(自動リンク): 既存ページの一覧から自動的にリンクを生成する

使う側としては、自動リンクが一番使いやすいんだけど、本文中にページ名が含まれていないかどうかを調べるために、サーバにも一番負荷がかかってしまうのが欠点。 そこで、負荷がかかるのなら、クライアントにやらせればいいんじゃないかと思い、デモを作ってみた。

デモ

「自動リンクを有効にする」というボタンをクリックすると、サーバからページ一覧を取得し、自動リンクを生成するようにしている。 これはサンプルだから毎回ボタンをクリックするようにしているけど、有効・無効を Cookie に記憶させておけば、2回目からはページ読み込み時に自動リンクを自動的に生成させることもできるはず。

ソースコード

function autolink() {
 url = 'autolink.dat';
 options = {
               onComplete: function(req) {
                       do_autolink($('body'), new RegExp(req.responseText.replace(/\n/g, ''), 'g'));
               }
       };
 new Ajax.Request(url, options);
       $('autolink').disabled = 'true';
}

function do_autolink(element, regex) {
       for (var i = 0; i < element.childNodes.length; i++) {
               var node = element.childNodes[i];
               if(node.nodeType == 3) {
                       var new_value = node.nodeValue.replace(regex, replace)
                       if(new_value != node.nodeValue) {
                               var new_node = document.createElement('span');
                               new_node.innerHTML = new_value;
                               node.parentNode.replaceChild(new_node, node);
                       }
               }
               else if(node.nodeType == 1) {
                       do_autolink(node, regex);
               }
       }
}

function replace(str) {
       var url;
       url = str;
       return '<a href="' + EscapeEUCJP(url) + '.html">' + str + '</a>';
}

これ以外にも、 prototype.jsEscape Codec Library (EUC-JP で URL エンコーディング)を使っている。 作るのに時間かかったけど、処理として特に難しいところは無いはず。 responseText に含まれる改行を取り除く必要があるとか、置換する時は span 要素に置き換えているとか、それくらいか。

autolink.dat の中身は正規表現。基本的には PukiWiki が生成する cache/autolink.dat の文字コードを UTF-8 に置き換えたものでいい。このサンプルは Ruby で生成しているけど。

課題

  • IE だとページを開いた瞬間が少し重い。 FireFox だとそうでもない。ライブラリのロードに時間がかかっている?
  • autolink.dat に含まれるページ数が増えるとブラクラになる(苦笑)
  • Sleipnir だと動作するのに、素の IE だと動かない…何故?

その他メモや構想

そもそもの発端は、 PukiWiki の負荷を軽減しつつ、使い勝手を損なわないようにしたいと思ったことから。

PukiWiki での自動リンク生成は、以下の手順でやっているみたい。

  1. ページ一覧にマッチする正規表現 (cache/autolink.dat) を生成する(ページ編集時)
  2. ページに含まれる他ページへのリンクを抽出し、 AutoLink と ReverseLink のキャッシュ(.rel, .ref)を生成する(ページ編集時)
  3. キャッシュから自動リンクを生成する(ページ閲覧時)

この負荷を軽減するために

  • cache/autolink.dat は1日に1回だけ、 cron で生成する
  • 自動リンクの生成をクライアントで実行させる

としたい。

今回のデモでは、リンクの抽出と生成をクライアントで実行させた。 ただこの方式でも、ページ数が増えすぎるとクライアントの負荷が耐え切れなくなってしまう。 本当は、ma.laさんのアイデアみたいに、クライアントで抽出した結果をサーバに送り、次からはそのキャッシュを使うようにしたい。

やっぱり、分散コンピューティングっぽいことをやろうと思う。ユーザーの側でオートリンク箇所を調べて、サーバーに報告する。報告されたデータを元にして、リンク処理を行う。 リンクされている箇所を報告することで、全体のリンクマップが形成できる。どのみちリンクマップのような機能は必要になるので、そういったアプローチが良いだろうと思う。

セキュリティを重視しなければ、実装はそれほど難しくないと思う。 「リンク元、リンク先、確認日」からなる DB のテーブルを作って、そこに放り込んでいけばいいのだから。 リンク元で select すれば自動リンクの一覧になるし、リンク先で select すれば ReverseLink の生成に使える。 ただ、悪戯や悪意のある攻撃を防ごうと考えると、少し難しいかもね…。

参考ページ