Root/
<?php /* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* # ***** BEGIN LICENSE BLOCK ***** # This file is part of Plume Framework, a simple PHP Application Framework. # Copyright (C) 2001-2007 Loic d'Anterroches and contributors. # # Plume Framework is free software; you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. # # Plume Framework 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # ***** END LICENSE BLOCK ***** */ /** * Calendar to display a list of events in a calendar table. * * The calendar is independent of other elements of Pluf, you can use * it standalone if you want. * * The principle is that you set options and feed the calendar with a * list of events. Based on the options, the render() method will * produce different views of the calendar. */ class Pluf_Calendar { /** * The list of events to display. */ var $events = array (); var $summary = '' ; /** * The display options of the calendar. */ var $opts = array (); // When updating an interval, if a col span more rows and columns, // store the info for the next rows to compensate as needed. var $bspans = array (); /** * List of events without the events not between the start/end * days. */ var $_events = array (); /** * List of time intervals in the $_events list. */ var $_time_intervals = array (); /** * Simultaneous events at a given time slot, for a given group. * * array('2007-03-25' => * array(array('time' => '10:15', * 'start' => 4 , * 'continued' => 5), * array('time' => '11:30', * 'start' => 3 , * 'continued' => 0), * ) * '2007-03-24' => * array(array('time' => '11:30', * 'start' => 2 , * 'continued' => 3), * ) * ) * */ var $_simultaneous = array (); var $_max_simultaneous = array (); var $_groups = array (); /** * Render the calendar based on the options. */ public function render() { if ( count ( $this ->events) == 0) { return '' ; } $this ->cleanEventList(); $this ->getTimeIntervals(); $this ->getSimultaneous(); $this ->getMaxSimultaneous(); $s = '' ; if ( $this ->summary) { $s = 'summary="' .htmlspecialchars( $this ->summary). '" ' ; } $out = '<table ' . $s . 'cellspacing="0" class="px-calendar">' . "\n" ; $out .= $this ->getHead(); $out .= $this ->getBody(); $out .= '</table>' . "\n" ; return Pluf_Template_SafeString::markSafe( $out ); } /** * Event are grouped by day per default, you can group as you * want, just subclass this method. Groups are used to make * columns in the table with the headings. */ function getEventGroup( $event ) { return substr ( $event [ 'start' ], 0, 10); } /** * Get all the available groups. */ function getGroups() { if ( count ( $this ->_groups)) { return $this ->_groups; } foreach ( $this ->_events as $event ) { $group = $this ->getEventGroup( $event ); if (!in_array( $group , $this ->_groups)) { $this ->_groups[] = $group ; } } return $this ->_groups; } /** * Get the name of a group to print in the headers. */ function getGroupName( $group ) { $dw = $this ->daysOfWeek(); $days = date ( 'w' , strtotime ( $group )); return htmlspecialchars( $dw [ $days %7]); } /** * Generate the body of the calendar. */ function getBody() { $out = '<tbody>' . "\n" ; $inters = $this ->getTimeIntervals(); $groups = $this ->getGroups(); for ( $i =0; $i <( count ( $inters )-1); $i ++) { $out .= '<tr>' . "\n" ; $out .= ' <th scope="row">' . $inters [ $i ]. ' - ' . $inters [ $i +1]. '</th>' . "\n" ; foreach ( $groups as $group ) { $out .= $this ->getEventCell( $group , $inters [ $i ]); } $out .= '</tr>' . "\n" ; } $out .= '</tbody>' . "\n" ; return $out ; } /** * Get the value to print for the given cell * * @param string Current group * @param string Current interval * @return string Table cells */ function getEventCell( $group , $inter ) { $out = '' ; $max = $this ->getMaxSimultaneous(); $fullspanevent = false; foreach ( $this ->_events as $event ) { // Get the start time of the event $e_start = substr ( $event [ 'start' ], 11, 5); if ( $e_start != $inter ) { // If the event does not start at the current time, // skip it continue ; } if ( $group != $this ->getEventGroup( $event )) { // Check if full span even at this time interval if (! empty ( $event [ 'fullspan' ])) { $fullspanevent = true; } continue ; } // Find how many rows the event will span $extra = '' ; $content = '' ; if (!isset( $event [ 'content' ])) $event [ 'content' ] = '' ; $row_span = $this ->getEventRowSpanning( $event , $this ->_time_intervals); if ( $row_span > 1) { $extra .= ' rowspan="' . $row_span . '"' ; } if (! empty ( $event [ 'fullspan' ])) { $colspan = 0; foreach ( $max as $_s ) { $colspan += $_s ; } $extra .= ' colspan="' . $colspan . '"' ; $fullspanevent = true; } if ( strlen ( $event [ 'color' ]) > 0) { $extra .= ' style="background-color: ' . $event [ 'color' ]. ';"' ; } if ( strlen ( $event [ 'content' ]) > 0) { $content .= $event [ 'content' ]; } if ( strlen ( $event [ 'url' ]) > 0) { $content .= '<a href="' . $event [ 'url' ]. '">' .htmlspecialchars( $event [ 'title' ]). '</a>' ; } if ( strlen ( $event [ 'content' ]) == 0 and strlen ( $event [ 'url' ]) == 0) { $content .= htmlspecialchars( $event [ 'title' ]); } $out .= ' <td' . $extra . '>' . $content . '</td>' . "\n" ; } if (! $fullspanevent ) { $sim = null; foreach ( $this ->_simultaneous[ $group ] as $_sim ) { if ( $_sim [ 'time' ] == $inter ) { $sim = $_sim ; break ; } } $diff = $max [ $group ] - ( $sim [ 'start' ] + $sim [ 'continued' ]); for ( $k =0; $k < $diff ; $k ++) { $out .= ' <td class="empty"> </td>' . "\n" ; } } return $out ; } /** * Get event spanning over the rows. * * @param array Event * @param array Intervals * @return int Spanning */ function getEventRowSpanning( $event , $inters ) { $start = substr ( $event [ 'start' ], 11, 5); $end = substr ( $event [ 'end' ], 11, 5); $span = 1; foreach ( $inters as $inter ) { if ( $inter < $end and $inter > $start ) { $span ++; } } return $span ; } /** * Generate the head of the calendar. */ function getHead() { $out = '<thead>' . "\n" . '<tr>' . "\n" . ' <th> </th>' . "\n" ; // Print the groups. $groups = $this ->getGroups(); $max = $this ->getMaxSimultaneous(); foreach ( $groups as $group ) { if ( $max [ $group ] > 1) { $span = ' colspan="' . $max [ $group ]. '"' ; } else { $span = '' ; } $out .= ' <th scope="col"' . $span . '>' . $this ->getGroupName( $group ). '</th>' . "\n" ; } $out .= '</tr>' . "\n" . '</thead>' . "\n" ; return $out ; } /** * Get the rowspan for each day. */ function getDaySpanning() { list( $start , $end ) = $this ->getStartEndDays(); $inters = $this ->getTimeIntervals( $start , $end ); $n = $this ->getDayNumber( $start , $end ); $inter_n = array_fill (0, count ( $inters ), 0); $day_span = array_fill (0, $n +1, $inter_n ); foreach ( $this ->events as $event ) { // The event must be between $start and $end $e_dstart = substr ( $event [ 'start' ], 0, 10); $e_dend = substr ( $event [ 'end' ], 0, 10); if ( $e_dend < $start or $e_dstart > $end ) { continue ; } $day = $this ->getDayNumber( $start , substr ( $event [ 'end' ], 0, 10)); $e_start = substr ( $event [ 'start' ], 11, 5); $e_end = substr ( $event [ 'end' ], 11, 5); $i = 0; foreach ( $inters as $inter ) { if ( $inter < $e_end and $inter >= $e_start ) { $day_span [ $day ][ $i ]++; } $i ++; } } return $day_span ; } /** * Get an array with the days of the week. */ function daysOfWeek() { return array ( __( 'Sunday' ), __( 'Monday' ), __( 'Tuesday' ), __( 'Wednesday' ), __( 'Thursday' ), __( 'Friday' ), __( 'Saturday' ), ); } /** * Get the number of days to list. * * @param string Start date * @param string End date * @return int Number of days */ function getDayNumber( $start , $end ) { Pluf::loadFunction( 'Pluf_Date_Compare' ); $diff = Pluf_Date_Compare( $start . ' 00:00:00' , $end . ' 00:00:00' ); return (int) $diff /86400; } /** * Get the start and end dates based on the event list. * * @return array (start day, end day) */ function getStartEndDays() { $start = '9999-12-31' ; $end = '0000-01-01' ; if (!isset( $this ->opts[ 'start-day' ]) or !isset( $this ->opts[ 'end-day' ])) { foreach ( $this ->events as $event ) { $t_start = substr ( $event [ 'start' ], 0, 10); $t_end = substr ( $event [ 'end' ], 0, 10); if ( $t_start < $start ) { $start = $t_start ; } if ( $t_end > $end ) { $end = $t_end ; } } } if (isset( $this ->opts[ 'start-day' ])) { $start = $this ->opts[ 'start-day' ]; } else { $this ->opts[ 'start-day' ] = $start ; } if (isset( $this ->opts[ 'end-day' ])) { $end = $this ->opts[ 'end-day' ]; } else { $this ->opts[ 'end-day' ] = $end ; } return array ( $start , $end ); } /** * Clean event list. */ function cleanEventList() { list( $start , $end ) = $this ->getStartEndDays(); $this ->_events = array (); foreach ( $this ->events as $event ) { $e_dstart = substr ( $event [ 'start' ], 0, 10); $e_dend = substr ( $event [ 'end' ], 0, 10); if ( $e_dend < $start or $e_dstart > $end ) { continue ; } $this ->_events[] = $event ; } return true; } /** * Get the time intervals. They span all the groups. */ function getTimeIntervals( $start = '' , $end = '' ) { if ( count ( $this ->_time_intervals)) { return $this ->_time_intervals; } $intervals = array (); foreach ( $this ->_events as $event ) { $t = substr ( $event [ 'start' ], 11, 5); if (!in_array( $t , $intervals )) { $intervals [] = $t ; } $t = substr ( $event [ 'end' ], 11, 5); if (!in_array( $t , $intervals )) { $intervals [] = $t ; } } sort( $intervals ); $this ->_time_intervals = $intervals ; return $intervals ; } /** * Get simultaneous events at the same time slot and same group. */ function getSimultaneous() { foreach ( $this ->getGroups() as $group ) { $this ->_simultaneous[ $group ] = array (); foreach ( $this ->_time_intervals as $inter ) { $this ->_simultaneous[ $group ][] = array ( 'time' => $inter , 'start' => 0, 'continued' => 0); } } foreach ( $this ->_events as $event ) { $group = $this ->getEventGroup( $event ); $e_tstart = substr ( $event [ 'start' ], 11, 5); $e_tend = substr ( $event [ 'end' ], 11, 5); foreach ( $this ->_simultaneous[ $group ] as $index => $inter ) { if ( $e_tstart == $inter [ 'time' ]) { $inter [ 'start' ] += 1; $this ->_simultaneous[ $group ][ $index ] = $inter ; continue ; } if ( $e_tstart < $inter [ 'time' ] and $e_tend > $inter [ 'time' ]) { $inter [ 'continued' ] += 1; $this ->_simultaneous[ $group ][ $index ] = $inter ; continue ; } } } return $this ->_simultaneous; } /** * Get maximum simultaneous events */ function getMaxSimultaneous() { if ( count ( $this ->_max_simultaneous) > 0) { return $this ->_max_simultaneous; } foreach ( $this ->getGroups() as $group ) { $this ->_max_simultaneous[ $group ] = 0; } foreach ( $this ->_simultaneous as $group => $choices ) { foreach ( $choices as $count ) { if ( $this ->_max_simultaneous[ $group ] < $count [ 'start' ] + $count [ 'continued' ]) { $this ->_max_simultaneous[ $group ] = $count [ 'start' ] + $count [ 'continued' ]; } } } return $this ->_max_simultaneous; } /** * Overloading of the get method. * * @param string Property to get */ function __get( $prop ) { if ( $prop == 'render' ) return $this ->render(); return $this -> $prop ; } } |