ライブドア事件の怒涛の中心で愛をさけぶ
DNA マーカー『M122』を持つ人は、お米が大好き!?

prototype.js で遊んでみた

 先日このブログで公開したばかりの、「ライブドア事件」専用トラックバック・ステーションであるが、毎回ページが開かれるたびにデータベースにアクセスする仕組みで作ったのだが、そんな作りのままではトラフィック増には耐えられない。そこで、良く出来たブログ・サービス(例えばMT)の様に、変更があったときに(つまり、トラックバックが送られてきた時に)、データベース上のデータからHTMLページを生成しておき、閲覧時にはそれを返すように変更することにした。

 その作業を進めているときに、この手法の一つの欠点に気が付いた。MovableType がしているように、ヘッダーも含めた全HTMLページを生成するようにしておくと、その中にスタイルシート(CSS)へのリンクを埋め込むことになるので、スタイル(見た目)が固定化されてしまうのである。これでは面白くない。そこで、複数のスタイルシートを用意しておき、閲覧時に動的に結び付きを決められるようにする方法を幾つか考えてみた。

案1.ページ全体ではなく、HTMLの一部だけを生成しておき、PHPを使って動的にスタイルシートとの結び付けをする。
案2.HTMLではなく、PHPを生成しておき、それを使って動的にスタイルシートとの結び付けをする。
案3.HTMLの一部だけを生成しておき、prototype.js を使ってスタイルシートと結びついた親ページにそれを読み込んでくる。

案1と案2は既にやり方を知っているので、あえて案3の方法でやってみることにした。prototype.js では一度遊んでみたかったので、丁度良い。すると、親ページ(最初にブラウザーがロードするページ)はこんな感じになる。

<html>
  <HEAD>
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
   <link rel ="stylesheet" href ="listview1.css" type="text/css" />
   <script src="prototype-1.4.0.js"></script>
   <script>
     function load() {
       var myAjax = new Ajax.Updater('main', 'cache/livedoor1.html',
         {method: 'get',
         requestHeaders: ['If-Modified-Since','Wed, 15 Nov 1995 00:00:00 GMT'] });
    }
   </script>
  </HEAD>
  <BODY onload="load()">
    <div id="main">
      <div style="width: 100%; text-align: center">Loading...</div>
    </div>
  </BODY>
</HTML> 

 こんな形で作った親ページを、スタイルシートごとに複数用意しておけば(listview1.css の部分だけを変更すれば良い)、ブラウズ時にはサーバー側のスクリプトを走らせることなく、同じHTMLテキスト(このサンプル場合は cache/livedoor1.html)を異なったスタイルで見せることができるのである。サンプルとして、二つの異なるスタイルシート(listview1.css、listview2.css)と結びつけたサンプルを下に貼り付けたので参照していただきたい。

listview1.css を使って表示したもの

listview2.css を使って表示したもの

 「何で同じHTMLなのにこんなに異なる表示が出来るんだ?」と疑問に思う方は、それぞれのCSSファイルを参照してみると良い。XSL/XMLによる view/data の分離と違って、分離が完璧ではないので view の自由度は限られるが、CSS/HTML を分離するだけでもかなり面白いことが出来ることがこの例を見ても良く分かると思う。

 昨晩はこれが IE と Firefox 上でうまく動いたので、「クライアント側でのHTMLとCSSの動的結びつきに成功。これで色々と面白いことができる!」と喜んで寝たのだが、朝、Mac上のSafari からアクセスしてみて、がっくり。漢字が文字化けしてしまうのだ。サーバー上で生成しているHTMLファイルも親ページもどちらもUTF-8でセーブしてあるので、本来ならうまく行くはずなのだが、なぜか文字化けしてしまうのだ。

 少し調べたところ、Safari は親ページが UTF-8 であることを認識しておきながら、Ajax.Update() で取得した文字列を UTF-8 と正しく認識してくれないようである(原因は不明…もし心当たりのある方がいたら、コメントをいただけるとありがたい)。そこで、少し乱暴な手段だが、サーバー側で生成する HTML ファイルの先頭に UTF-8 であることを示すBOM(EF、BB、BF)を付けてみたところやっとちゃんと動いてくれた。BOMを利用しているのは Windows ばっかりだと思っていたが、Safari に BOM を認識するコードが入っているとは少し驚きだ。

 ということで、「ライブドア事件」専用トラックバック・ステーションも無事にアップデート終了。いたって簡単なプロトタイプだが、色々と勉強になった。

Comments

&

先にTBしてくれた方の情報が深いところに隠れてしまいますのでTB昇順(CNETjapanの記事TBのように)という形で表示して、別枠で新着TB数件(あるいは数時間内)という形(listview2.css)と、したほうが良いかもしれませんね。

Satoshi

 ブログに慣れているせいか、新しいものが上の方がしっくり来るのですが…。ちなみに、リストの順番を変えるまではCSSの切り替えでするのはたぶん無理でしょうね(誰か天才的な人がやってしまうかもしれませんが)。そこまでするのであれば、サーバー側では XML(この場合はRSSで十分)を生成しておき、それを読み込んでHTMLを生成するべきでしょうね。

passageiro

昇順・降順の二者選択なら、はじめから二種類のリストを生成しておき、cssの制御で片方だけを表示させるとかでどうでしょう。非常に泥臭い方法ですが。

Fuktommy

原理的には「Ajaxで動くブログ」と同じですね。http://blog.fuktommy.com/

KOTARO

最近やっとスタイルシートをいじりはじめたので、全く分かりません!!(笑)

でもスタイルシートも昔は分からなかったのに今は興奮して眠れないくらいだから・・・できるようになるでしょうか・・どきどき。


とにかくこんなにいろんなことができるのを尊敬します。わくわくしますね!!


http://www.kotaroblog.com

やっち

普通にjavascriptでdocumnet.stylesheet=等で切り替えたら駄目なんですか?親ウィンドウのフレーム名も判別できたはず。
ajaxは必要ないかとおもってます。

Satoshi

 親ウィンドウのフレーム名から判断して異なるCSSファイルを読み込むんですね。それは簡単だ^^。今度試してみますね。

心は萌え

CSSはべつに動的に切り替えずにMTなどであれば、IFタグを使って、
静的生成時にIFで切り替えるのが良いと思います。

PHPを元から使っているのであればダイナミックにという手も有りますが・・・
略式にhtml起動コストを1とするとPHPの起動コストは4 MYSQL付きPHPの起動コストは10ぐらいでした(僕の環境実測)。(なにも動作をしないと仮定して)
4倍のコスト差は意外とでかいですから・・・

Otchy

いつも楽しく拝見しています。

> Ajax.Update() で取得した文字列を UTF-8 と正しく認識してくれないようである(原因は不明…もし心当たりのある方がいたら、コメントをいただけるとありがたい)

詳細なバージョンや条件等を調べたわけではないのですが、Safariでは、XMLHttpRequestオブジェクトで取得した文字列をresponseTextプロパティで解釈した場合、デフォルトで文字コードをUTF-16としているように見えました。

こちらに詳細まで調べた方がいらっしゃいました。
http://jsgt.org/ajax/ref/charset_test/responsetext/test_1_make_table.php
http://jsgt.org/ajax/ref/charset_test/responsexml/test_1_make_table.php

おそらく、Ajax.Update()では内部でresponseTextを使っているのではないでしょうか?

Satoshi

Otchyさん、情報ありがとうございます。これを読む限り、BOMを先頭に付けて UTF-8 で送るという方法はかならずしも「強引な」方法でもないようですね。

Otchy

私が対応した時は、Safariの場合のみUTF-16を送るという方法だったんですが、むしろBOMを付ける方がスマートだったと思います。
目から鱗でした。

Verify your Comment

Previewing your Comment

This is only a preview. Your comment has not yet been posted.

Working...
Your comment could not be posted. Error type:
Your comment has been posted. Post another comment

The letters and numbers you entered did not match the image. Please try again.

As a final step before posting your comment, enter the letters and numbers you see in the image below. This prevents automated programs from posting comments.

Having trouble reading this image? View an alternate.

Working...

Post a comment

Your Information

(Name is required. Email address will not be displayed with the comment.)