* 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 = '
'."\n";
$out .= $this->getHead();
$out .= $this->getBody();
$out .= '
'."\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 = ''."\n";
$inters = $this->getTimeIntervals();
$groups = $this->getGroups();
for ($i=0;$i<(count($inters)-1);$i++) {
$out .= ''."\n";
$out .= ' '.$inters[$i].' - '.$inters[$i+1].' | '."\n";
foreach ($groups as $group) {
$out .= $this->getEventCell($group, $inters[$i]);
}
$out .= '
'."\n";
}
$out .= ''."\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 .= ''.htmlspecialchars($event['title']).'';
}
if (strlen($event['content']) == 0 and strlen($event['url']) == 0) {
$content .= htmlspecialchars($event['title']);
}
$out .= ' '.$content.' | '."\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 .= ' | '."\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 = ''."\n".''."\n".' | '."\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 .= ' '.$this->getGroupName($group).' | '."\n";
}
$out .= '
'."\n".''."\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;
}
}