Kahua Release
- Release Note
- Download
- Current Version 1.0.7.3 (2008-05-08)
kahua-web Release
- kahua-webとは
- Release Note
- Download
- Current Version 0.3.1 (2007-06-12)
Security Advisory
Event Log
Documentation
For developers
Site info
Related Site
ソーシャルブックマークを作る(2)
さて、いちいちkahua-shellからブックマークを登録するわけにもいかないので、 ブックマークを追加するための画面とエントリを追加してみましょう。
登録画面を作る
まずはブックマークを登録するフォームを生成する手続きを書いてみましょう。
(define (bookmark-form/)
(form/cont/
(@@/ (cont (entry-lambda (:keyword title url)
(make <bookmark> :title title :url url)
(redirect/cont (cont all)))))
(table/
(tr/ (th/ "Title: ")
(td/ (input/ (@/ (type "text") (name "title") (value "")))))
(tr/ (th/ "URL: ")
(td/ (input/ (@/ (type "text") (name "url") (value "")))))
(tr/ (th/) (td/ (input/ (@/ (type "submit") (value "Register"))))))))
一見ややこしく見えますが、form要素の中でテーブルを組んで体裁を整えている だけです。ここでキモになるのは、 form/cont/ という見慣れない高階タグ関数です。
form/cont/ は、エントリをactionに指定した form 高階タグを生成する特殊な 高階タグ関数です。
(@@/ (cont (entry-lambda (:keyword title url)
(make <bookmark> :title title :url url)
(redirect/cont (cont all)))))
という部分が、実際にエントリをactionに結びつけているところです。@/ では なく @@/ であることに注意しましょう。これは、SXMLで言うところの補助属性 で、エントリ(継続)は、この補助属性として form/cont/ や a/cont/ などに渡 されます。
この例では、entry-lambda で作った無名のエントリ(継続)を渡しています。 このエントリは「title」と「url」という2つのパラメータを受け取り、 <bookmark> のインスタンスを作ってから、一覧のエントリにリダイレクト しています。:keyword をつけるのをお忘れなく。これをつけないと、 title と url をフォームのパラメータではなくリクエストURIのパス要素として 受け取ることになってしまいます。well knownエントリとは違い、無名エントリ はこのページにアクセスしない限り作られません。ブックマークの追加は 必ずこのページを経由して欲しいので、ここでは無名エントリを使いました。
redirect/cont は、エントリにリダイレクトを行う手続きです。最後に / は つきません。これは高階タグを生成する手続きではないからです。
ではこれを呼び出すエントリを書きましょう。名前は「new」にします。
(define-entry (new)
(kahua:xml-template->sxml
page-template
:title (title/ (@/ (id "title"))
"New Bookmark")
:body (div/ (@/ (id "body"))
(h1/ "New Bookmark")
(bookmark-form/))))
ページの体裁を整えている以外は、本当に呼び出すだけですね。では、 http://localhost:8088/bookmarks/new にブラウザでアクセスして、実際にブッ クマークを追加してみましょう。
ちょっとリファクタリング
さて、ここまでのコード全体を眺めてみましょう。
(use gauche.collection)
(load "bookmarks/version.kahua")
(define page-template
(kahua:make-xml-template
(kahua-template-path "bookmarks/page.xml")))
(define-class <bookmark> (<kahua-persistent-base>)
((title :allocation :persistent :init-keyword :title :init-value "")
(url :allocation :persistent :init-keyword :url :init-value "")))
(define (bookmark-entry/ bm)
(li/ (a/ (@/ (href (slot-ref bm 'url))) (slot-ref bm 'title))))
(define (bookmark-list/ bm-collection)
(ul/ (map/ bookmark-entry/ bm-collection)))
(define-entry (all)
(kahua:xml-template->sxml
page-template
:title (title/ (@/ (id "title")) "All Bookmarks")
:body (div/ (@/ (id "body"))
(h1/ "All Bookmarks")
(bookmark-list/ (make-kahua-collection <bookmark>)))))
(define (bookmark-form/)
(form/cont/
(@@/ (cont (entry-lambda (:keyword title url)
(make <bookmark> :title title :url url)
(redirect/cont (cont all)))))
(table/
(tr/ (th/ "Title: ")
(td/ (input/ (@/ (type "text") (name "title") (value "")))))
(tr/ (th/ "URL: ")
(td/ (input/ (@/ (type "text") (name "url") (value "")))))
(tr/ (th/) (td/ (input/ (@/ (type "submit") (value "Register"))))))))
(define-entry (new)
(kahua:xml-template->sxml
page-template
:title (title/ (@/ (id "title"))
"New Bookmark")
:body (div/ (@/ (id "body"))
(h1/ "New Bookmark")
(bookmark-form/))))
(define-entry (version)
(kahua:xml-template->sxml
page-template
:title (title/ (@/ (id "title"))
"bookmarks")
:body (div/ (@/ (id "body"))
(h1/ (format "bookmarks: version ~a"
*bookmarks-version*))
(a/cont/ (@@/ (cont greeting))
"greeting"))))
;
; initialization
;
(initialize-main-proc all)
何だか似たようなコードがたくさん並んでいます。リファクタリングなんて 言葉を持ち出すまでもなく、そろそろ整理しときたいですよね。
ということでざっと整理してみました。
(use gauche.collection)
(load "bookmarks/version.kahua")
(define page-template
(kahua:make-xml-template
(kahua-template-path "bookmarks/page.xml")))
(define (standard-page title body)
(kahua:xml-template->sxml
page-template
:title (title/ (@/ (id "title")) title)
:body (div/ (@/ (id "body")) (h1/ title) body)))
(define (make-link/ entry text)
(p/ (a/cont/ (@@/ (cont entry)) text)))
(define-class <bookmark> (<kahua-persistent-base>)
((title :allocation :persistent :init-keyword :title :init-value "")
(url :allocation :persistent :init-keyword :url :init-value "")))
(define (bookmark-entry/ bm)
(li/ (a/ (@/ (href (slot-ref bm 'url))) (slot-ref bm 'title))))
(define (bookmark-list/ bm-collection)
(ul/ (map/ bookmark-entry/ bm-collection)))
(define-entry (all)
(standard-page "All Bookmarks"
(node-set/
(new-bookmark-link/)
(bookmark-list/ (make-kahua-collection <bookmark>))
(version-link/))))
(define all-bookmarks-link/ (cut make-link/ all "[All Bookmarks]"))
(define (textbox/ name value . maybe-size)
(input/ (@/ (type "text") (name name) (value value)
(size (get-optional maybe-size #f)))))
(define (submit/ value)
(input/ (@/ (type "submit") (value value))))
(define (bookmark-form/ title url)
(form/cont/
(@@/ (cont (entry-lambda (:keyword title url)
(make <bookmark> :title title :url url)
(redirect/cont (cont all)))))
(table/
(tr/ (th/ "Title: ") (td/ (textbox/ "title" title 50)))
(tr/ (th/ "URL: ") (td/ (textbox/ "url" url 50)))
(tr/ (th/) (td/ (submit/ "Register"))))))
(define-entry (new)
(standard-page "New Bookmark"
(node-set/
(all-bookmarks-link/)
(bookmark-form/ "" ""))))
(define new-bookmark-link/ (cut make-link/ new "[New Bookmark]"))
(define-entry (version)
(standard-page "bookmarks version"
(node-set/
(h2/ *bookmarks-version*)
(all-bookmarks-link/))))
(define version-link/ (cut make-link/ version "[Version]"))
;
; initialization
;
(initialize-main-proc all)
基本的には input/ で生成されるテキストボックスやsubmitボタンを部品化す るために関数としてくくりだした他、ページ全体の生成もエントリごとにでは なく、standard-page という関数を使って行うようにしました。さらに、各 well knownエントリ間をリンクで結んであります。a/cont/ は form/cont/ と 同様、リンク先としてエントリ(継続)を埋め込むための特殊な高階タグ関数です。
もう1点。属性値として#fを渡すと、最終的に生成される(X)HTMLにその属性自 体が出力されません。条件によってある属性を出したり出さなかったりしたい 時に使えるでしょう。