2011年07月25日

Hello, javascript

あなたはホームページを運用するうちに、ページ来訪者と大いに語らう場を作りたくなりました。そこで、ブラウザ上で動くチャットルームを作ることにします。チャットルームには発言者の名前と、最新から20個の発言が順に表示されます。
まずはデータの格納先を定義しましょう。ユーザーの名前と、投稿テキストを格納する先を作ります。

// chatは投稿者名とテキストからなる
db /chat : {name: string; text: string}


Opaのデータベースは、実はデータベースに格納された過去値をすべて覚えています。そのため、これだけで「最新のn件」が取得可能です。この辺の仕様は誤って上書きしたデータを簡単に復元できるなど便利なことがある反面、データ容量や個人情報保護などの観点から問題が起きることもありますので、運用の際には注意してください。

  recents = Db.history(@/chat, 0, -num_print)


これで最新のnum_print件が取得できます。

ではまず、これを使い、チャットの表示更新のところを書いてみましょう。まず、得られたrecentsをxhtmlに変換します。

update_chat() = 
// 最新の20件を取得
recents = Db.history(@/chat, 0, -num_print)
// 発言をxhtmlに変換
lines = List.map((x -> <div class="line">
<
div class="user">{x.name}:</div>
<div class="text">{x.text}</div>
</div>), recents)
// 表示!
Dom.transform([#chat <- lines])


あとはDom.transformで<div id=#chat>に書き出すだけです。

「え、この処理はどこで実行されるの?」と疑問に思う方もいるかと思います。答えは、ブラウザとwebサーバー両方です。Dom.transformなどの処理はブラウザでjavascriptとして実行され、Dbアクセスはwebサーバーで実行されます。Dbアクセスはブラウザ側のjavascriptからRPCとして呼び出され、実行されます。プログラマはこのRPCを個別に書く必要が全くありません! これはOpaの非常によい特性であると思います。この機能を使う際にはCSRFに注意してください。見知らぬ人に「こんにちはこんにちは!」などと書かれることのありませぬよう。

最後に、ページを表示し、ボタンを押したら発言を更新するようにしましょう。これでとりあえず、手動更新のチャットの完成です。

// chatは投稿者名とテキストからなる
db /chat : {name: string; text: string}

num_print = 20

update_chat() =
// 最新の20件を取得
recents = Db.history(@/chat, 0, -num_print)
// 発言をxhtmlに変換
lines = List.map((x -> <div class="line">
<
div class="user">{x.name}:</div>
<div class="text">{x.text}</div>
</div>), recents)
// 表示!
Dom.transform([#chat <- lines])

submit_chat() = (
name = Dom.get_value(#name)
text = Dom.get_value(#text)
// textが空でなければ発言
do (
if text != "" then
do /chat <- {~name; ~text}
Dom.clear_value(#text))
// textの中身にかかわらず更新はする
update_chat()
)

show_page() =
<div>
<
input id=#name />
<
input id=#text onnewline={_ -> submit_chat()}/>
<
button type="button" onclick={_ -> submit_chat()}>投稿・更新</>
</>
<div id=#chat onready={_ -> update_chat()}></>

server = Server.one_page_bundle("Chat",
[@static_resource_directory("resources")],
["resources/css.css"], show_page)


(次回に続く)
posted by chun at 02:30| OPA