ドキュメントオブジェクトメソッドの記述
各テーブルセルに、changeDate()という関数をポイントするonClickイベントハンドラと、changeMonth()という関数を呼び出す4つのナビゲーション文字列が含まれていることに気付いた人もいるのではないでしょうか。この2つの関数は、カプセル化というオブジェクト指向の原則に反しても、カレンダーオブジェクト外に宣言する必要があります。なぜなら、この2つの関数が取り扱うイベントは、カレンダーオブジェクトではなく、ドキュメントオブジェクトによって発行されるからです。
このプロジェクトでは、現在のカレンダーオブジェクトへの参照を取得するために、JavaScriptのトリックをいくつか使用しています。基本的には、eval()関数を通じて引数を渡すことで、文字列パラメータを現在のカレンダーオブジェクトに変換しています。ここで注意したいのは、カレンダーオブジェクトの作成時に渡すidパラメータは、宣言した変数名と同じでなければならないということです。これは現在のカレンダーへの参照を保持するためのちょっとした代償です。changeDate()関数のコードを以下に示します。
function changeDate(td,cal){ // Some JavaScript trickery // Change the cal argument to the existing // calendar object // This is why the first argument in the // constructor must match the variable name // The cal reference also allows for // multiple calendars on a page cal = eval(cal); document.getElementById(cal.id + "selected").className = "days"; document.getElementById(cal.id + "selected").id = ""; td.className = "date"; td.id = cal.id + "selected"; // set the calendar object to the new date cal.dateObject.setDate(td.firstChild.nodeValue); cal = new calendar(cal.id,cal.dateObject,cal.pix); // here is where you could react to a date change? // I'll just display the formatted date alert(cal.getFormattedDate()); }
changeDate()関数は基本的に、cal引数をカレンダーオブジェクトに変換した後、td参照を使用して、新しくクリックされた日付に現在の日付のCSSクラスを割り当てます。その後、内部のDateオブジェクトの日付を、クリックされたセルの値で書き換えます。最後に、テストのため、書式設定済みの日付を警告ボックスに表示します。ここではこのような方法を使用していますが、日付の切り替えはどんな方法で実現しても構いません。
changeMonth()関数では、カレンダーの月を次に進める(または前にさかのぼる)処理を行います。この関数は、先ほど現在のカレンダーオブジェクトへの参照を保持するために使ったeval()関数のトリックを使用しています。ここで嬉しいのは、Dateオブジェクト(ひいてはカレンダーオブジェクト)は月の折り返しを自動的に処理してくれるということです。つまり、「12月の次は1月」、「1月の前は12月」と自動的に判断してくれます。changeMonth()関数のコードを以下に示します。
function changeMonth(mo,cal){ // more trickery! cal = eval(cal); // The Date object is smart enough to // know that it should roll over in December // when going forward and in January // when going back cal.dateObject.setMonth(cal.dateObject.getMonth() + mo); cal = new calendar(cal.id,cal.dateObject,cal.pix); cal.formattedDate = cal.getFormattedDate(); document.getElementById('calContainer').innerHTML = cal.write(); }
ここまで作成したファイルに「calendar.js」という名前を付け、CSSファイルと同じフォルダに保存します。
HTMLファイルの作成
ここまでくれば、カレンダーを表示するHTMLファイルの作成は非常に簡単です。必要な処理のほとんどはカレンダーオブジェクトが行ってくれるからです。テキストエディタで新しいファイルを開き、次のHTMLファイルを作成します。
<html>
<head>
<title>Calendar Demo</title>
<script src="calendar.js" type="text/javascript"></script>
<link rel="stylesheet" type="text/css" href="calendar.css"/>
</head>
<body>
<script language="JavaScript">
// create the pix array
var pix = new Array();
for(i = 0; i < 12; i++){
pix[i] = new Image();
pix[i].src = 'images/fractal' + i + '.jpg';
}
// Place this script wherever you want your calendar
// The first argument must match the var name
var thisMonth = new calendar('thisMonth',new Date(),pix);
document.write(thisMonth.write());
</script>
</body>
</html>
画像を格納するpix配列は、JavaScriptファイルではなく、HTMLページ上で作成する必要があります。このことは、オブジェクト指向の観点から見ても理にかなっています(カレンダーで使用する画像は各ページに固有のものだからです)。今回のサンプルコードでは、命名規則を設け、forループを使用して画像配列を作成しています。このファイルをCSSファイルおよびJavaScriptファイルと同じディレクトリに保存します。
おわりに
Facadeデザインパターンは、このアプリケーションにうまく適合します。Facadeデザインパターンを採用することで、JavaScriptのDateオブジェクトで使用できるデータを公開しつつ、Dateオブジェクトそのものを直接操作する必要性を排除し、その機能をカレンダーアプリケーション用にカスタマイズすることができます。
なお、このカレンダーはchangeDate()メソッド内で複数のW3C DOMメソッドを使用しているため、W3C DOMの仕様に準拠しているブラウザでしか利用できません。Mozilla Firebird 0.7、Opera 7.1、およびInternet Explorer 6でテストした結果、この3つのブラウザすべてで正常に動作しました。
