コンストラクタの作成
次に、テキストエディタで新しいファイルを開き、次のようにカレンダーオブジェクトのコンストラクタを入力します。
// Constructor function calendar(id, d, p){ this.id = id; this.dateObject = d; this.pix = p; this.write = writeCalendar; this.length = getLength(); this.month = d.getMonth(); this.date = d.getDate(); this.day = d.getDay(); this.year = d.getFullYear(); this.getFormattedDate = getFormattedDate; // get the first day of the month's day d.setDate(1); this.firstDay = d.getDay(); // then reset the date object to the correct date d.setDate(this.date); }
このコンストラクタには3つのパラメータがあり、それぞれID値(1つのページに複数のカレンダーを配置するために必要)、JavaScriptのDateオブジェクト(カレンダーを任意の日付から開始するために必要)、JavaScriptのImageオブジェクトの配列(必要に応じてプログラムで操作可能)を受け取ります。
このコンストラクタでは、3つのパラメータをそれぞれ対応するプロパティに割り当てるだけでなく、カレンダーオブジェクトを機能させるための補助的なプロパティとメソッドを追加しています。これらのプロパティはラップされるDateオブジェクトの値を公開し、これらのメソッドはカレンダーの情報を表示するために必要な仕組みを提供します。このようにDateオブジェクトをカレンダーオブジェクト内に隠すことが、Facadeデザインパターンになっています。
メソッドの記述
このカレンダーには、writeCalendar()、getLength()、getFormattedDate()という3つの便利なメソッドが含まれています。getFormattedDate()を実装するには、月名と曜日名を格納している2つの便利な配列を使用します。スクリプトファイルに次のコードを追加します。
var days = new Array('Sunday','Monday','Tuesday', 'Wednesday','Thursday','Friday','Saturday'); var months = new Array('January', 'February','March','April', 'May','June','July','August','September', 'October','November','December'); function getFormattedDate(){ return days[this.day] + ', ' + months[this.month] + ' ' + this.date + ', ' + this.year; // return this.month + '/' + this.date + '/' + this.year; }
この便利な配列を使用しない場合は、カレンダーオブジェクト自体から書式設定済みの日付を取得します。そのためのコードをgetFormattedDate()メソッド内にコメントとして記述しておきました。こちらの方法を使用する場合でも、便利な配列は削除しないでください。後で必要になります。
ひと月の日数はさまざまなので、それぞれの月の日数を把握する必要があります。getLength()メソッドは日数の計算を行うので、このメソッドにより、カレンダーのlengthプロパティには現在表示されている月の日数が格納されます。月の日数を覚える方法として英語圏では古くから「Thirty days hath September, April, June and November...」(30日は9月、4月、6月、11月...)という文章が使われていますが、getLength()メソッドでもこれと似たような処理をします。スクリプトに次のgetLength()メソッドを追加します。
function getLength(){ // thirty days has September... switch(this.month){ case 1: if ((this.dateObject.getFullYear()%4==0 && this.dateObject.getFullYear()%100!=0) || this.dateObject.getFullYear()%400==0) return 29; // leap year else return 28; case 3: return 30; case 5: return 30; case 8: return 30; case 10: return 30 default: return 31; } }
このgetLength()メソッドは、うるう年についても正確に判断し、それに応じて戻り値を調整します。
writeCalendar()メソッドは、今回のカレンダーアプリケーションの心臓部です。writeCalendar()メソッドは、Webページにカレンダーを表示するためのHTML生成処理を担当します。基本的にwriteCalendar()メソッドは、カレンダーオブジェクトのプロパティから構成される非常に長い文字列を生成します。難しそうに見えるかもしれませんが、一度書いておけば済む話です。writeCalendar()メソッドのコードを以下に示します。
function writeCalendar(){ var calString = '<div id="calContainer">'; // write month and year at top of table calString += '<table id="cal' + this.id + '" cellspacing="0" width="200"' + ' style="border:1px black solid;">'; // write the image -- comment out to hide images calString += '<tr><th colspan="7"><img src="' + this.pix[this.month].src + '"/></th></tr>'; // write the month calString += '<tr><th colspan="7" class="month">' + months[this.month] + ', ' + this.year + '</th></tr>'; // write a row containing days of the week calString += '<tr>'; for(i=0;i<days.length;i++){ calString += '<th class="dayHeader">' + days[i].substring(0,3) + '</th>'; } // write the body of the calendar calString += '<tr>'; // create 6 rows so the calendar doesn't resize for(j=0;j<42;j++){ var displayNum = (j-this.firstDay+1); if(j<this.firstDay){ // write the leading empty cells calString += '<td class="empty"> </td>'; }else if(displayNum==this.date){ calString += '<td id="' + this.id + 'selected" class="date" ' + 'onClick="javascript:changeDate(this,\'' + this.id + '\')">' + displayNum + '</td>'; }else if(displayNum > this.length()){ // Empty cells at bottom of calendar calString += '<td> </td>'; }else{ // the rest of the numbered cells calString += '<td id="" class="days" ' + 'onClick="javascript:changeDate(this,\'' + this.id + '\')">' + displayNum + '</td>'; } if(j%7==6){ calString += '</tr><tr>'; } } // close the last number row calString += '</tr>'; // write the nav row calString += '<tr>'; calString += '<td class="nav" ' + 'style="text-decoration:underline;"' + ' onClick="changeMonth(-12,\'' + this.id + '\')"><</td>'; calString += '<td class="nav" ' + 'onClick="changeMonth(-1,\'' + this.id + '\')"><</td>'; calString += '<td class="month" ' + 'colspan="3"> </td>'; calString += '<td class="nav"' + ' onClick="changeMonth(1,\'' + this.id + '\')">></td>'; calString += '<td class="nav" ' + 'style="text-decoration:underline;text-' + 'align:right;" onClick="changeMonth(12,\'' + this.id + '\')">></td>'; calString += '</tr>'; calString += '</table>'; calString += '</div>'; return calString; }
このメソッドでは、さまざまな処理が行われています。最初の数行では、カレンダーのコンテナ部分と表示する画像、さらに年+月のバナーに関するHTMLを生成しています。画像のない単純な日付ピッカーを作成する場合は、画像に関する行をコメントアウトします。
次に、曜日を表示するために曜日配列をループ処理し、各曜日名の最初の3文字を取得します。その後、カレンダー本体のHTML生成に進み、カレンダーオブジェクトのfirstDayプロパティに基づいて、最初に用意しなければならない空白セルの数を決定します。
続いて各日付を表すテーブルセルを作成し、現在の日付には専用のCSSスタイルを適用します。最後に、カレンダー下部のナビゲーションバーを作成します。
