prototype.jsとscript.aculo.usを配置
http://script.aculo.us/downloads からscript.aculo.usの最新版をダウンロード。僕の場合は,scriptaculous-js-1.8.0.zipをダウンロードしました。解凍したらlibフォルダの中のprototype.jsと,srcフォルダにあるすべてのjsファイルを,appフォルダのwebapp/jsフォルダにコピーしました。
$ajax->linkを使ってみる
$ajax->linkを使って,カレンダーを翌月前月と切り替えることをやってみます。カレンダーに前月・翌月のリンクをつけて,クリックされると前月・翌月の間レンダーが表示されるというのをajaxで実現しようというわけです。前月・翌月という風に相対的に変わって行くと言うことは,現在表示されている年月を保存しなければ成りません。それらはセッションに保存することにしました。
function _saveData($field, $data){ $this->Session->write($field, $data); } function _loadData($field){ return $this->Session->read($field); } function index(){ $this->_saveData('year', date('Y', time())); $this->_saveData('month', date('n', time())); $this->set('year', $this->_loadData('year')); $this->set('month', $this->_loadData('month')); $this->layout = 'default'; }
indexが最初にページを表示させるメソッドです。年と月をセッションに保存してからビューにそれらを渡して表示しています。
<div> <?php $opt = array( 'update'=>'calendar', 'loading'=>"Element.hide('calendar')", 'complete'=>"Effect.Appear('calendar',{duration: 1.0})" ); echo $ajax->link('前月', 'prev', $opt, null, false); echo ' | '; echo $ajax->link('翌月', 'next', $opt, null, false); ?> </div> <div id="calendar"> <?php $calendar->showCalendar($year, $month); ?> </div>
index.thtmlの中身です。$ajax->linkで交信用のメソッドを呼び出しています。ついでにEffectをかけてみました。Effectでは前のカレンダーをフェードアウトさせるのもやってみたかったのですが,loadingのところで,Effect.Fadeを指定するとフェードアウトはするものの,次にフェードインしても直後にマッシロケに戻ってしまいます。どうしたら望んだ動作になるのかわかりません。まだajaxの使い方がわかっていませんね要勉強です。
function prev(){ $this->addMonth(-1); } function next(){ $this->addMonth(1); } function addMonth($value){ $this->layout = 'ajax'; $year = $this->_loadData('year'); $month = $this->_loadData('month'); $d = mktime(0,0,0, $month $value, 1, $year); $this->_saveData('year', date('Y', $d)); $this->_saveData('month', date('n', $d)); $this->set('year', $this->_loadData('year')); $this->set('month', $this->_loadData('month')); $this->render('view'); }
prevとnextが$ajax->linkから呼ばれてカレンダーを表示するメソッドです。その本体はaddMonthです。prevやnextメソッドがなくても,$ajax->linkのurlでaddMonth/1などとしてもよいですね。addMonthメソッドではview.thtmlを表示しています(最終行)。そのview.thtmlはたった一行です。
<?php $calendar->showCalendar($year,$month);?>
これで表示されるのが次のような画面。翌月・前月をクリックするとカレンダーが変化します。ajaxしているって感じで良いです。

$ajax->observeFormを使ってみる
observeFormはフォームを監視して変化があった場合に,アクションを起こすものです。画面上のフォームで年・月を変更するとカレンダーが変わるというのを狙ってみます。index2というメソッド名にしてみます。
function index2(){ $this->set('year', date('Y', time())); $this->set('month', date('n', time())); }
次がindex2.thtmlです。
<form id="ajform"> <input type="text" name="year" value="<?php echo $year;?>" size="4" style="{display: inline}"> <label style="{display: inline}">%u5E74</label> <input type="text" name="month" value="<?php echo $month;?>" size="2" style="{display: inline}"> <label style="{display: inline}">%u6708</label> </form> <?php $opt = array( 'frequency'=>'1', 'update'=>'calendar', 'url'=>'view' ); echo $ajax->observeForm("ajform", $opt); ?> <div id="calendar" class="mydiv2"> <?php $calendar->showCalendar($year, $month); ?> </div>
フォームにはsubmitボタンもありませんが,テキストボックスの年・月を変更するとobserveFormがそれを監視して,viewメソッドを呼び出します。
function view(){ $this->layout = 'ajax'; $this->set('year', $this->params['form']['year']); $this->set('month', $this->params['form']['month']); }
viewメソッドでは,params配列から年・月を取り出し,viewに渡しています。viewは先ほどのものと同じです。

年と月のテキストボックスを変更するとたちまちカレンダーが変化します。13月とかやっても表示されるのは愛嬌です。実際にはSelectTagを使ったりすることになりそうです。
Helperの作法について
昨日ポストしたエントリーでカレンダーヘルパーを発表してみたのですが,なんとCakePHP User's in Japanのフォーラムで紹介していただけました。ありがとうございました。しかし,あとから考えるとどうもこのHelperは作法に則っていないのではないかと不安になっています。CakePHPのHelperのメソッドはみな文字列を返すのみで,それを出力させるにはビューの中でechoしてやるようになっていますよね。僕の作ったカレンダーヘルパーは,メソッドを呼ぶだけでechoされちゃうんですね。ここは他のHelperのように文字列を返すようにするべきなのでしょうか。