2010年11月24日水曜日

50音別インデックスの実装

 Aozoramazonでは、作者毎に50音別の作品名インデックスを用意してあります。青空文庫には全作者を網羅した長大な50音別作品リストがありますが、Aozoramazonでは表示するリストを小分けにする必要がありました。これは、Aozoramazonを動かしているGoogle App Engineでは、1000件を超えるエントリーを一度に取り出せないと言う制限があるためです。この制限と折り合いを付けるために、全作者ではなく作者毎の50音別リストにしました。

前準備として、作者毎に作品頭文字リストを用意します。

  • 作品情報の更新時に青空文庫の図書カードを解析して作品の読みを取得する
  • 作品読みの頭文字を、作者情報の頭文字リストに追加する。リストに存在する文字なら何もしない。
こうすると、例えば菊池寛の作者情報に作品頭文字リスト「あいきくみえむおらせしたちとわかなへやさこふて」が出来上がります。並び順に意味は無いので、ソートは行いません。

表示の際の強調の有無は、CSSのclassで区別します。考え方としては、強調のclassを与えるのではなく、非強調のclassを取り除く事で相対的にリストにある文字だけが強調されて見えるようにします。一見、逆(有効な文字を強調する)でも良いように思えますが、不要な文字が普通のリンクとして見えては都合が悪いため、不要な文字にも目立たせないためのスタイル指定が必要になります。したがって、必要な文字だけ非強調のclassを取り除く方が近道です。

まず、非強調用のCSSクラス"gapCell"を指定した50音表を用意します。(gapCellという名前に深い意味はありません。元々は文字の無いセルを目立たなくするために用意したCSSクラスでした。)
各文字のセルはUTF-8をベースにしたIDで識別できるようにしておきます。

<table class="novelInitialTable"> 
       <caption>作品名インデックス</caption> 
       <tr> 
  <td class="gapCell" id="i_e38182">
  <a href="/person?authorId=83&amp;initial=%e3%81%82">あ</a>
  </td> 
  <td class="gapCell" id="i_e38184">
  <a href="/person?authorId=83&amp;initial=%e3%81%84">い</a>
  </td> 
  <td class="gapCell" id="i_e38186">
  <a href="/person?authorId=83&amp;initial=%e3%81%86">う</a>
  </td> 
  <td class="gapCell" id="i_e38188">
  <a href="/person?authorId=83&amp;initial=%e3%81%88">え</a>
  </td> 
  <td class="gapCell" id="i_e3818a">
  <a href="/person?authorId=83&amp;initial=%e3%81%8a">お</a>
  </td> 
  <td class="gapCell">&nbsp;</td> 
  <td class="gapCell" id="i_e381af">
  <a href="/person?authorId=83&amp;initial=%e3%81%af">は</a>
  </td> 
      ...

CSSの中では、非強調用のgapCellクラスを背景に対して目立たない色で定義します。

td.gapCell a:link {
    color: gray;
}
td.gapCell a:visited {
    color: gray;
}
td.gapCell a:hover {
    color: gray;
}

ページがロードされた直後に実行されるJavaScriptで、強調したい文字のgapCellクラスを取り除きます。
非強調が解除される、すなわち、非強調に対比して強調されているように見えるようになります。

$(document).ready(function(){      
      $("#i_e38182").removeClass("gapCell");      
      $("#i_e38184").removeClass("gapCell");      
      $("#i_e3818d").removeClass("gapCell");
      ...

テンプレートの中で、指定された文字に対してのみremoveClass()するJavaScriptを出力します。テンプレートを処理すると、上のようなJavaScriptソースになります。

$(document).ready(function(){
      {% for i in initialList %}
      $("#i_{{i}}").removeClass("gapCell");
      {% endfor %}

PythonのCGIでは、作品頭文字リストをテンプレートに渡します。
HTMLで表示できるように、UTF-8を16進表記にしてエスケープ文字(\x)を取り除いた文字列のリストとして渡しています。

initialList = []
if author.initialList:
    initialList = [c.encode('utf-8').encode('string-escape').replace('\\x', '') for c in author.initialList]
template_values['initialList'] = initialList

最終的に、下のような表示になります。

0 件のコメント:

コメントを投稿