// // This program is free software: you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but // *WITHOUT ANY WARRANTY*; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General // Public License for more details. // // You should have received a copy of the GNU General Public License along // with this program. If not, see . // Topic: TODO // // Implement 's year mode. // Topic: Description // // This class specifically addresses the issue of displaying calendars of // various kinds, possibly with events involved. It is *not* an events // manager. // // Example: // // > require_once 'Calendar.inc'; // > $cal = new Calendar(); // > echo $cal->XHTML(); // // TODO: // // There is still no linking nor pop-up possibilities. Year view is not yet // implemented. // // My private properties. var $weekstart; var $monthstart; var $events; var $days; var $ds; var $months; // Group: Methods // Constructor: Calendar // // Instantiate the class. Note that this class is designed to be reusable // as many times as needed: once events are loaded with , // multiple calendars of any kind can be generated with that same // instance. This could be useful, for example, to load a single list of // events to display a current month in 's 'full' mode along with // the previous and next months in its 'compact' mode. // // Parameters: // $weekstart - Which day (0-6) to start weeks at. (Optional.) // $monthstart - Which month (1-12) to start year at. (Optional.) // function Calendar($weekstart = 0, $monthstart = 1) { $this->weekstart = $weekstart; $this->monthstart = $monthstart; $this->SetDays('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'); $this->SetMonths('January','February','March','April','May','June','July','August','September','October','November','December'); $this->events = array(); } // Method: SetDays // // Specify non-English day names. Single letter short versions will be // derived from this as well. // // Parameters: // $sun - String to identify Sunday. // $mon - String to identify Monday. // $tue - String to identify Tuesday. // $wed - String to identify Wednesday. // $thu - String to identify Thursday. // $fri - String to identify Friday. // $sat - String to identify Saturday. // // Returns: // // Always returns true. // function SetDays($sun, $mon, $tue, $wed, $thu, $fri, $sat) { $this->days = array($sun, $mon, $tue, $wed, $thu, $fri, $sat); $this->ds = array(); foreach ($this->days as $day) { array_push($this->ds, substr($day,0,1)); }; return(true); } // Method: SetMonths // // Specify non-English month names. // // Parameters: // $m1 - String to identify month 1 (January). // $m2 - String to identify month 2 (February). // $m3 - String to identify month 3 (March). // $m4 - String to identify month 4 (April). // $m5 - String to identify month 5 (May). // $m6 - String to identify month 6 (June). // $m7 - String to identify month 7 (July). // $m8 - String to identify month 8 (August). // $m9 - String to identify month 9 (September). // $m10 - String to identify month 10 (October). // $m11 - String to identify month 11 (November). // $m12 - String to identify month 12 (December). // // Returns: // // Always returns true. // function SetMonths($m1, $m2, $m3, $m4, $m5, $m6, $m7, $m8, $m9, $m10, $m11, $m12) { $this->months = array($m1, $m2, $m3, $m4, $m5, $m6, $m7, $m8, $m9, $m10, $m11, $m12); return(true); } // Method: AddEvent // // Add an event to the in-memory calendar, for a specific date. Optional // start and stop times may be specified as well as a long description. // // Internally, events are sorted as they are added, so that displaying can // be quick and repeatable. For each day, timeless events are added in // the order in which they were added. Next, events with start times are // sorted in chronological order. If two events start at the same time, // they are sorted in the order in which they were added. // // Parameters: // $year - Event's year (4-digit format). // $month - Event's month in the year (1-12). // $day - Event's day of the month (1-31). // $class - CSS class to highlight the day with. (Used in display methods.) // $title - Short description of the event. // $starttime - Start time in "hh:mm" format. (Optional.) // $stoptime - Stop time in "hh:mm" format. (Optional, even when $starttime is defined.) // $body - Long description of the event. (Optional.) // // Returns: // // Always returns true. // function AddEvent($year, $month, $day, $class, $title, $starttime = null, $stoptime = null, $body = null) { if (!is_array($this->events[$year])) $this->events[$year] = array(); if (!is_array($this->events[$year][$month])) $this->events[$year][$month] = array(); if (!is_array($this->events[$year][$month][$day])) $this->events[$year][$month][$day] = array(); $idx = 0; foreach ($this->events[$year][$month][$day] as $key => $event) { if ($event['start'] == null) $idx = $key; elseif ($event['start'] <= $starttime) $idx = $key; }; array_splice($this->events[$year][$month][$day], $idx+1, 0, array(array( 'start' => $starttime, 'stop' => $stoptime, 'class' => $class, 'title' => $title, 'body' => $body, ))); return(true); } // Method: XHTML // // Display a calendar in XHTML 1.1 Strict. Each mode returns a different // kind of calendar. In each case, it is up to the caller to use some CSS // to achieve the desired display characteristics. // // Compact mode: // // A table of class 'calendar_compact' is generated. First, a row of // headers lists the first letters of each day of the week. Next, as many // rows of cells as necessary are generated to contain actual days. Each // day cell which is within the current month gets attributed a class, one // of: // // weekday - By default, days 1-5 receive this class. // weekend - By default, days 0 and 6 receive this class. // today - By default, the current day gets this class. // // If there are events for a day, the class of the day's first event (see // for sort order) is used instead of one of the above. // // Full mode: // // A table of class 'calendar_full' is generated. First, a row of headers // lists the full names of each day of the week. Next, as many rows of // cells as necessary are generated to contain actual days. Like compact // mode, each day cell can be of class 'weekday', 'weekend', or 'today'. // However, cells are not directly affected by events, as they contain a // list of the day's events in this mode. // // For each event, in order (see for sort order), a div of // class 'event' is created. Inside, first a span containing a small space // is displayed, member of the event's class. This is intended for // color-coding. Next, the event's short title is displayed. // // Year mode: // // NOT YET IMPLEMENTED. This will essentially call itself 12 times in // compact mode, starting with <$monthstart>. I believe 12 tables in a row // would wrap according to their containing block, but some testing should // confirm this. // // Parameters: // $mode - One of: compact, full, year. (Optional.) // $year - 4-digit year. (Optional.) // $month - Month (1-12). (Optional.) // // Returns: // // The generated XHTML code ready to output. // function XHTML($mode = 'compact', $year = null, $month = null) { $out = ''; if ($year == null) { $d = getdate(); $year = $d['year']; $month = $d['mon']; }; $today = getdate(); switch ($mode) { // Compact, highlighted month view. case 'compact': $length = $this->mlength($month, $year); $startday = $this->mstart($month, $year); $out .= "\n"; $out .= "\t"; for ($i=0; $i < 7; $i++) $out .= ""; $out .= "\n"; $current = 1; while ($current < $length) { $out .= "\t\n"; for ($i=0; $i < 7; $i++ ) { $wday = ($this->weekstart + $i) % 7; if ((($current == 1) && ($wday != $startday)) || ($current > $length)) { $out .= "\t\t\n"; } else { $class = 'weekday'; if (is_array($this->events[$year][$month][$current])) { // Class for the day is that of first event found. $class = $this->events[$year][$month][$current][0]['class']; } elseif ($i == 0 || $i == 6) $class = 'weekend'; if ($year == $today['year'] && $month == $today['mon'] && $current == $today['mday']) $class = 'today'; $out .= "\t\t\n"; $current++; }; }; $out .= "\t\n"; }; $out .= "
". $this->ds[($this->weekstart + $i) % 7] ."
 $current
\n"; break; // Full size month view. case 'full': $length = $this->mlength($month, $year); $startday = $this->mstart($month, $year); $out .= "\n"; $out .= "\t"; for ($i=0; $i < 7; $i++) $out .= ""; $out .= "\n"; $current = 1; while ($current < $length) { $out .= "\t\n"; for ($i=0; $i < 7; $i++ ) { $wday = ($this->weekstart + $i) % 7; if ((($current == 1) && ($wday != $startday)) || ($current > $length)) { $out .= "\t\t\n"; } else { $class = 'weekday'; $events = false; if (is_array($this->events[$year][$month][$current])) { // Class for the day is that of first event found. $class = $this->events[$year][$month][$current][0]['class']; $events = true; } elseif ($i == 0 || $i == 6) $class = 'weekend'; if ($year == $today['year'] && $month == $today['mon'] && $current == $today['mday']) $class = 'today'; $out .= "\t\t\n"; $current++; }; }; $out .= "\t\n"; }; $out .= "
". $this->days[($this->weekstart + $i) % 7] ."
 
$current
\n"; if ($events) foreach ($this->events[$year][$month][$current] as $event) { $out .= "\t\t\t
 {$event['title']}
\n"; }; $out .= "\t\t
\n"; break; // Compact, highlighted year view. case 'year': break; default: $out .= "Calendar::XHTML() ERROR: Unknown mode $mode."; }; return($out); } function mlength($month, $year) { $result = 30; switch ($month) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: $result = 31; break; case 4: case 6: case 9: case 11: $result = 30; break; case 2: // Those darn leap years. // CAUTION: I don't check the 4000 rule here. Seriously, this is 2006... if ($year % 400 == 0) $result = 29; elseif ($year % 100 == 0) $result = 28; elseif ($year % 4 == 0) $result = 29; else $result = 28; break; default: echo "Calendar::mlength(): Unknown month $month."; }; return($result); } function mstart($month, $year) { $d = getdate(mktime(0, 0, 0, $month, 1, $year)); return($d['wday']); } } ?>