event_start). * Optionally, an end value ($node->event_end) and a time zone offset value * in the same format as drupal core ($node->tz). If a node has no end * value, it is rendered on only one day. If no time zone value is displayed * the time is rendered with no time zone offset (GMT). * @param $module - String containing the name of the module calling the function * @param $title - A string value that will be printed into the header of the calendar * @param $params - an optional array of additional values that may be needed * $params[force_week] - a week number to limit the displayed calendar to only that week * $params[with_weekno] - add a column for the week number to the calendar * $params[hide_header] - true to omit td header row(s) * $params[as_array] - true to return the rows array instead of the themed table * $params[mini] - this is a mini calendar, don't display item details * $params[url] - an url to use as a base url in month and days * $params[stripe] - an node field to use instead of nid for stripes * $params[limit] - an array of a minimum and maximum timestamp to include on the calendar used in case node array has values that overlap periods * @return Themed calendar view of nodes or array of calendar rows */ function calendar_get_calendar($view, $nodes, $module, $title = NULL, $params = array()) { $today = calendar_user_date(); if ($params['limit'][0]) { $min_date = $params['limit'][0]; $max_date = $params['limit'][1]; } else { $min_date = 0; $max_date = 999999999999; } $data = array(); foreach ($nodes as $nid => $node) { $node->stripe = $params['stripe'] ? $node->$params['stripe'] : $node->nid; $calendar = new stdClass(); $nodes[$node->nid] = $node; $calendar->nid = $node->nid; // $node_start and $node_end are local timestamp values if ($min_date - $node->start_offset > $node->calendar_start) { $node->calendar_start = $min_date - $node->start_offset; } if ($max_date - $node->end_offset < $node->calendar_end) { $node->calendar_end = $max_date - $node->end_offset; } $node_start = gmmktime(0, 0, 0, calendar_event_date('m', $node->calendar_start, $node->start_offset), calendar_event_date('d', $node->calendar_start, $node->start_offset), calendar_event_date('Y', $node->calendar_start, $node->start_offset)); if ($node->calendar_end) { $node_end = gmmktime(0, 0, 0, calendar_event_date('m', $node->calendar_end, $node->end_offset), calendar_event_date('d', $node->calendar_end, $node->end_offset), calendar_event_date('Y', $node->calendar_end, $node->end_offset)); } else { $node_end = $node_start; } if ($node_start == $node_end) { $calendar->calendar_state = 'singleday'; $calendar->stamp = $node_start; $calendar->stripe = $node->stripe; $data[gmdate('Y', $node_start)][gmdate('m', $node_start)][gmdate('j', $node_start)][] = $calendar; } else { // roll through each day the calendar occurs and set an entry for each for ($x = $node_start; $x <= $node_end; $x += 86400) { if ($x == $node_end) { $calendar = new StdClass(); $calendar->nid = $node->nid; $calendar->stripe = $node->stripe; $calendar->calendar_state = 'end'; $calendar->stamp = $x; $data[gmdate('Y', $x)][gmdate('m', $x)][gmdate('j', $x)][] = $calendar; } elseif ($x == $node_start) { $calendar = new StdClass(); $calendar->nid = $node->nid; $calendar->stripe = $node->stripe; $calendar->calendar_state = 'start'; $calendar->stamp = $x; $data[gmdate('Y', $x)][gmdate('m', $x)][gmdate('j', $x)][] = $calendar; } else { $calendar = new StdClass(); $calendar->nid = $node->nid; $calendar->stripe = $node->stripe; $calendar->calendar_state = 'ongoing'; $calendar->stamp = $x; $data[gmdate('Y', $x)][gmdate('m', $x)][gmdate('j', $x)][] = $calendar; } } } } // order the years, months and days ksort($data, SORT_NUMERIC); foreach($data as $year => $months) { ksort($data[$year], SORT_NUMERIC); foreach($data[$year] as $month => $days) { ksort($data[$year][$month], SORT_NUMERIC); } } $weekdays = calendar_week_days(); switch ($view) { case 'day': case 'table': foreach ($data as $year => $months) { if(count($data) > 1 && !$params['hide_header']) { // add year heading $rows[][] = array( 'class' => 'heading year', 'id' => 'year'.$year, 'data' => $year); } foreach($months as $month => $days) { foreach($days as $day => $calendars) { $content = theme('calendar_date_box', $year, $month, $day, 'table', $params['mini'], $calendars, $params['url']); foreach($calendars as $calendar) { if(!$month_name) { $month_name = gmdate('M', $calendar->stamp); $dow = _calendar_day_of_week($calendar->stamp); } $node = $nodes[$calendar->nid]; $node->calendar_state = $calendar->calendar_state; if($output = module_invoke($module, 'calendar_node_'. $view, $node)) { $content .= $output; } else { $content .= theme('calendar_node_'. $view, $node); } } $rows[][] = array( 'class' => strtolower("$month_name ". $weekdays[$dow]['day'] . ($calendar->stamp == $today ? ' today' : '')), 'id' => strtolower($month_name . $day), 'data' => $content); $month_name = NULL; } } } break; case 'week': case 'month': case 'year': $colspan = $params['with_weekno'] ? '8' : '7'; foreach ($data as $year => $months) { $month_rows[] = $title; if(count($data) > 1 && !$params['hide_header']) { // add year heading $rows[][] = array( 'class' => 'heading year', 'id' => 'year'. $year, 'data' => $year, 'colspan' => $colspan); } foreach ($months as $month => $days) { // timestamp of first day in month $curstamp = gmmktime(0, 0, 0, $month, 1, $year); // timestamp of last day in month $lastday = gmmktime(0, 0, 0, $month, gmdate('t', $curstamp), $year); // pad the first week row array to fill up days in the previous month we don't build $row = array_fill(0, 6, ''); // get the day of week offset value for the first day of the month $start = $offset = _calendar_day_of_week($curstamp); // get name of month $month_name = gmdate('M', $curstamp); $month_link = $params['url'] ? l($month_name, $params['url'] .'/'. $year .'/'. intval($month)) : $month_name; // set week counter $week = 0; if (!$params['hide_header']) { $rows[][] = array( 'class' => 'heading month', 'id' => 'month'. $month, 'data' => $month_name, 'colspan' => $colspan); } $rows[] = calendar_week_header($params['mini'], $params['with_weekno']); while ($curstamp <= $lastday) { for ($x = $start; $x < 7; $x++) { $cur_day = (($week * 7) + ($x + 1) - $offset); $selected = FALSE; if(is_array($days[$cur_day])) { // make sure dummy nodes added to create blank calendars don't get marked as having content foreach ($items = $days[$cur_day] as $item) { if ($item->nid) { $selected = TRUE; } } } $content = theme('calendar_date_box', $year, $month, $cur_day, $view, $params['mini'], $selected, $params['url']); // render nodes for the day if(is_array($days[$cur_day]) && !$params['mini']) { foreach($days[$cur_day] as $calendar) { $node = $nodes[$calendar->nid]; $node->calendar_state = $calendar->calendar_state; if($output = module_invoke($module, 'calendar_node_'. $view, $node)) { $content .= $output; } elseif (!$params['mini'] && $node->nid > 0) { $content .= theme('calendar_node_'. $view, $node); } } } $row[$x] = array( 'class' => strtolower("$month_name ". $weekdays[$x]['day'] . ($curstamp == $today ? ' today' : '') . ($params['mini'] ? ' mini' : '')), 'id' => strtolower($month_name . $cur_day), 'data' => $params['mini'] ? $content : '
'. $content .'
'); $curstamp += 86400; if ($curstamp > $lastday) { $x = 8; } } $cur_week = date('W', $curstamp); // print week unless this is a week view and force_week is set and this is not the forced week if (!($view == 'week' && $params['force_week'] && $params['force_week'] != date('W', $curstamp))) { if ($params['with_weekno']) { $week_row = array(0 => array( 'class' => 'week', 'data' => l(sprintf('%02d', $cur_week), $params['url'] .'/'. $year .'/W'. $cur_week), )); $rows[] = array_merge($week_row, array_pad($row, 7, ' ')); } else { $rows[] = array_pad($row, 7, ' '); } } $week++; $start = 0; $row = array(); } if ($view == 'year' && !$params['as_array']) { $header = array($month_name ? array('class' => 'heading', 'data' => $month_link, 'colspan' => $colspan) : array()); $output = theme('calendar_month', 'page', $header, $rows); unset($rows); $month_rows[] = $output; } } } break; } // if only the rows array is requested, return it if ($params['as_array']) return $rows; $header = $title ? array(array('class' => 'heading', 'data' => $title, 'colspan' => $colspan)) : array(); $op = $params['mini'] ? 'mini' : 'page'; return theme('calendar_'. $view, $op, $header, $rows, $month_rows); } /** * Formats local time values to GMT timestamp using time zone offset supplied. * All time values in the database are GMT and translated here prior to insertion. * * Time zone settings are applied in the following order: * 1. If supplied, time zone offset is applied * 2. If user time zones are enabled, user time zone offset is applied * 3. If neither 1 nor 2 apply, the site time zone offset is applied * * @param $format The date() format to apply to the timestamp. * @param $timestamp The GMT timestamp value. * @param $offset Time zone offset to apply to the timestamp. * @ingroup event_support * @return gmdate() formatted date value */ function calendar_mktime($hour, $minute, $second, $month, $day, $year, $offset = NULL) { global $user; $timestamp = gmmktime($hour, $minute, $second, $month, $day, $year); if (isset($offset)) { return $timestamp - $offset; } elseif (variable_get('configurable_timezones', 1) && $user->uid && strlen($user->timezone) && (variable_get('event_timezone_display', 'event') == 'user')) { return $timestamp - $user->timezone; } else { return $timestamp - variable_get('date_default_timezone', 0); } } /** * Returns a local timestamp based on the user or site time zone. * @return integer timestamp */ function calendar_user_time() { global $user; if (variable_get('configurable_timezones', 1) && $user->uid && strlen($user->timezone)) { return (time() - date("Z")) + $user->timezone; } else { return (time() - date("Z")) + variable_get('date_default_timezone', 0); } } /** * Returns a local timestamp (as defined by the user or site's timezone) for * midnight GMT. * @return integer timestamp */ function calendar_user_date($part = 'timestamp') { global $user; static $date; if (!$date) { $now = calendar_user_time(); if (variable_get('configurable_timezones', 1) && $user->uid && strlen($user->timezone)) { $user_offset = $user->timezone; } else { $user_offset = variable_get('date_default_timezone', 0); } $now += $user_offset; $date = gmmktime(0, 0, 0, gmdate('m', $now), gmdate('j', $now), gmdate('Y', $now)); } switch ($part) { case ('year'): return gmdate('Y', $date); case ('month'): return gmdate('m', $date); case ('day'): return gmdate('j', $date); case ('hour'): return gmdate('H', $date); case ('minute'): return gmdate('i', $date); case ('week'): return gmdate('W', $date); default: return $date; } } /** * Formats a GMT timestamp to local date values using time zone offset supplied. * All timestamp values in event nodes are GMT and translated for display here. * * Time zone settings are applied in the following order * 1. If supplied, time zone offset is applied * 2. If user time zones are enabled, user time zone offset is applied * 3. If neither 1 nor 2 apply, the site time zone offset is applied * * @param $format The date() format to apply to the timestamp. * @param $timestamp The GMT timestamp value. * @param $offset Time zone offset to apply to the timestamp. * @ingroup event_support * @return gmdate() formatted date value */ function calendar_event_date($format, $timestamp, $offset = null) { global $user; if (isset($offset)) { $timestamp += $offset; } elseif (variable_get('configurable_timezones', 1) && $user->uid && strlen($user->timezone)) { $timestamp += $user->timezone; } else { $timestamp += variable_get('date_default_timezone', 0); } // make sure we apply the site first day of the week setting for dow requests if ($format == 'w') { $result = calendar_day_of_week($timestamp); } else { $result = gmdate($format, $timestamp); } return $result; } /** * Returns week day names and thier translated values, corrected for the start of week day settings (mon or sun) * * @ingroup event_support * @return an associative array containing weekday names */ function calendar_week_days() { static $weekdays; if (!$weekdays) { if (variable_get('date_first_day', 1)) { $weekdays = array(array('day' => 'Mon', 't' => t('Mon')), array('day' => 'Tue', 't' => t('Tue')), array('day' => 'Wed', 't' => t('Wed')), array('day' => 'Thu', 't' => t('Thu')), array('day' => 'Fri', 't' => t('Fri')), array('day' => 'Sat', 't' => t('Sat')), array('day' => 'Sun', 't' => t('Sun'))); } else { $weekdays = array(array('day' => 'Sun', 't' => t('Sun')), array('day' => 'Mon', 't' => t('Mon')), array('day' => 'Tue', 't' => t('Tue')), array('day' => 'Wed', 't' => t('Wed')), array('day' => 'Thu', 't' => t('Thu')), array('day' => 'Fri', 't' => t('Fri')), array('day' => 'Sat', 't' => t('Sat'))); } } return $weekdays; } /** * Formats the weekday information into table header format * * @ingroup event_support * @return array with weekday table header data */ function calendar_week_header($mini = FALSE, $with_week = TRUE) { // create week header $days = calendar_week_days(); if ($with_week) { $row[] = array('class' => "days week", 'data' => ' '); } foreach ($days as $day) { $row[] = array('class' => strtolower("days ". $day['day']), 'data' => $mini ? drupal_substr($day['t'], 0 , 1) : $day['t']); } return $row; } /** * Return the day of week with start of week offset applied * @param $stamp GMT timestamp * @return integer day of the week */ function _calendar_day_of_week($stamp) { $dow = gmdate('w', $stamp); $dow = (variable_get('date_first_day', 1) ? ($dow == 0 ? 6 : --$dow ) : $dow); return $dow; } /** * @addtogroup themeable * @{ */ /** * Format a node stripe legend */ function theme_calendar_stripe_legend($stripe_labels) { $header = array( array('class' => 'legend', 'data' => t('Item')), array('class' => 'legend', 'data' => t('Key')) ); foreach ($stripe_labels as $stripe => $label) { $node = new StdClass(); $node->stripe = $stripe; $rows[] = array($label, theme('calendar_stripe_stripe', $node), array('class' => 'stripe')); } $output = theme('table', $header, $rows, array('class' => 'mini')); return $output; } /** * Format node stripes * Add key value to text, then hide it with css for accessibility to screen readers */ function theme_calendar_stripe_stripe($node) { static $stripe, $stripe_map; if(!$stripe_map[$node->stripe]) { if($stripe >= 10) { $stripe = 1; } else { $stripe++; } $stripe_map[$node->stripe] = $stripe; } $output .= '
Key '.$stripe_map[$node->stripe] .'
'."\n"; return $output; } /** * Format a calendar view * * @param day * The day to display. */ function theme_calendar_year($op, $header, $rows, $month_rows) { $year = array_shift($month_rows); $output = '
'; $output .= $year; $i = 0; foreach ($month_rows as $month) { $i++; $row .= '
'. $month .'
'; if ($i == 3) { $output .= '
'. $row .'
'; $row = ''; $i = 0; } } $output .= "
\n"; return $output; } /** * Format a calendar view * * @param day * The day to display. */ function theme_calendar_month($op, $header, $rows) { $attrs = array(); if ($op == 'mini') { $attrs = array('class' => 'mini'); } $output = theme("table", $header, $rows, $attrs); return '
'. $output ."
\n"; } /** * Format a calendar view * * @param day * The day to display. */ function theme_calendar_week($op, $header, $rows) { $output = theme("table", $header, $rows); return '
'. $output ."
\n"; } /** * Format a calendar view * * @param day * The day to display. */ function theme_calendar_day($op, $header, $rows) { if (strstr($header[0]['data'], '
'. $output ."
\n"; } /** * Format a calendar view * * @param day * The day to display. */ function theme_calendar_table($op, $header, $rows) { $output = theme("table", $header, $rows); return '
'. $output ."
\n"; } /** * Format a calendar view * * @param day * The day to display. */ function theme_calendar_list($op, $header, $rows) { return '
'. $rows ."
\n"; } /** * Format an calendar node for display in an expanded calendar, like a calendar page * * @param node * The node being displayed */ function theme_calendar_node_day($node) { $output .= '
'."\n"; $output .= theme('calendar_stripe_stripe', $node); if ($node->calendar_start != $node->calendar_end && $node->start_time_format) { $start_label = t('Start: '); $end_label = t('End: '); } else { $start_label = ''; $end_label = ''; } $output .= '
'. l($node->title, "node/$node->nid", array('title' => t('view this item'))) .'
'."\n"; $output .= '
'. $start_label . $node->start_format .'
'."\n"; if ($node->calendar_start != $node->calendar_end && $node->calendar_end) { $output .= '
'. $end_label . $node->end_format .'
'."\n"; } if ($node->teaser) { $output .= '
'. check_markup($node->teaser) ."
\n"; } $output .= '"; $output .= "
\n"; return $output; } /** * Format an calendar node for display in an expanded calendar, like a calendar page * * @param node * The node being displayed */ function theme_calendar_node_week($node) { $output .= '
'."\n"; $output .= theme('calendar_stripe_stripe', $node); if ($node->calendar_start != $node->calendar_end && $node->start_time_format) { $start_label = t('Start: '); $end_label = t('End: '); } else { $start_label = ''; $end_label = ''; } switch ($node->calendar_state) { case 'singleday': $times = '
'. $start_label . $node->start_time_format .'
'."\n"; if ($node->calendar_start != $node->calendar_end && $node->calendar_end) { $times .= '
'. $end_label . $node->end_time_format .'
'."\n"; } break; case 'start': $times = '
'. $start_label . $node->start_time_format .'
'."\n"; break; case 'end': $times = '
'. $end_label . $node->end_time_format .'
'."\n"; break; case 'ongoing': $times = '
'. t('all day') .'
'."\n"; break; } $output .= '
'. l($node->title, "node/$node->nid", array('title' => t('view this item'))) .'
'."\n"; $output .= $times; $output .= '"; $output .= '
' . "\n"; return $output; } /** * Format an calendar node for display in an expanded calendar, like a calendar page * * @param node * The node being displayed */ function theme_calendar_node_month($node) { $output .= '
'."\n"; $output .= theme('calendar_stripe_stripe', $node); if ($node->calendar_start != $node->calendar_end && $node->start_time_format) { $start_label = t('Start: '); $end_label = t('End: '); } else { $start_label = ''; $end_label = ''; } switch ($node->calendar_state) { case 'singleday': if ($node->start_time_format != $node->end_time_format) { $times = '
'. $start_label . $node->start_time_format .'
'."\n"; } if ($node->calendar_start != $node->calendar_end && $node->calendar_end) { $times .= '
'. $end_label . $node->end_time_format .'
'."\n"; } else { $times = '
'. $node->start_time_format .'
'."\n"; } break; case 'start': $times = '
'. $start_label . $node->start_time_format .'
'."\n"; break; case 'end': $times = '
'. $end_label . $node->end_time_format .'
'."\n"; break; case 'ongoing': $times = '
'. t('all day') .'
'."\n"; break; } $output .= '
'. l($node->title, "node/$node->nid", array('title' => t('view this item'))) .'
'."\n"; $output .= $times; $output .= $node->teaser; $output .= '"; $output .= '
' . "\n"; return $output; } /** * Format an calendar node for display in an expanded calendar, like a calendar page * * @param node * The node being displayed */ function theme_calendar_node_table($node) { static $link_count; drupal_add_js(drupal_get_path('module', 'calendar') .'/calendar.js'); $link_count++; $output .= '
'."\n"; $output .= theme('calendar_stripe_stripe', $node); $output .= '
'. l($node->title, "node/$node->nid", array('title' => t('view this item'))) .'
'."\n"; switch ($node->calendar_state) { case 'singleday': $output .= '
'. t('Start: ') . $node->start_time_format ."
\n"; if ($node->calendar_start != $node->calendar_end) { $output .= '
'. t('End: ') . $node->end_time_format ."
\n"; } break; case 'start': $output .= '
'. t('Start: ') . $node->start_time_format ."
\n"; break; case 'end': $output .= '
'. t('End: ') . $node->end_time_format ."
\n"; break; case 'ongoing': $output .= '
('. t('all day') .')
'."\n"; break; } $output .= ''."\n"; $links = $node->calendar_links; $links[] = l(t('more info'), 'node/'.$node->nid, array('onclick' => "popupnotes('info-". $link_count ."'); return false;", 'title' => t('Show detailed information for this calendar.'))); $output .= '"; $output .= '
'."\n"; return $output; } function theme_calendar_node_list($node, $module = NULL) { static $link_count; drupal_add_js(drupal_get_path('module', 'calendar') .'/calendar.js'); $link_count++; $output = '
'."\n"; $output .= theme('calendar_stripe_stripe', $node); $output .= '
'. l($node->title, "node/$node->nid", array('title' => t('view this item'))) .'
'."\n"; switch ($node->calendar_state) { case 'singleday': $output .= '
'. t('Start') .': '. $node->start_time_format ."
\n"; if ($node->calendar_start != $node->calendar_end) { $output .= '
'. t('End') .': '. $node->end_time_format ."
\n"; } break; case 'start': $output .= '
'. t('Start') .': '. $node->start_time_format ."
\n"; break; case 'end': $output .= '
'. t('End') .': '. $node->end_time_format ."
\n"; break; case 'ongoing': $output .= '
('. t('all day') .')
'."\n"; break; } $output .= ''."\n"; $links = $node->calendar_links; $links[] = l(t('more info'), 'node/'.$node->nid, array('onclick' => "popupnotes('info-". $link_count ."'); return false;", 'title' => t('Show detailed information for this calendar.'))); $output .= '"; $output .= '
'."\n"; return $output; } /** * Format an date's day box in a calendar * * @param day * The day to display. */ function theme_calendar_date_box($year, $month, $day, $view, $mini = FALSE, $selected = FALSE, $url) { $url = $url ? $url .'/'. $year .'/'. $month .'/'. $day : 'calendar/'. $year .'/'. $month .'/'. $day; if ($mini) { if ($selected) { return '
'. l($day, $url) .'
'; } else { return '
'. l($day, $url) .'
'; } } switch ($view) { case 'table': $output = '
'. l(t('!month / !day', array('!month' => $month, '!day' => $day)), $url) .'
'."\n"; break; case 'list': $output = '
'. l(format_date(_calendar_mktime(0, 0, 0, $month, $day, $year), 'custom', 'l, F j, Y'), $url) .'
'."\n"; break; case 'day': break; default: $output = '
'. l($day, $url) .'
'."\n"; break; } return $output; } /** * Format an empty day on a calendar * * @param day * The day to display. */ function theme_calendar_empty_day($year, $month, $day, $view) { switch ($view) { case 'table': $output = '
'. t('%month / %day', array('%month' => $month, '%day' => $day)) .'
'."\n"; $output .= '
'."\n"; break; case 'day': case 'list': break; default: $output = '
'. $day .'
'."\n"; $output .= '
'."\n"; break; } return $output; } /** * Format an date value for a nodeapi insert * * @param node * The node which needs it's dates formatted */ function theme_calendar_nodeapi($node) { $output = '
'. $node->start_format .'
'."\n"; if ($node->calendar_start != $node->calendar_end) { $output .= '
'. $node->end_format .'
'."\n"; } if (variable_get('configurable_timezones', 1)) { include_once(EVENT_PATH .'/calendar_timezones.inc'); $zones = calendar_zonelist(); $output .= '
'. $zones[$node->timezone] .'
'."\n"; } return $output; } /** * Format the calendar filter control dropdown * * @param form * The form containing the taxonomy controls */ function theme_calendar_filter_control($form) { return '
'. $form .'
'; } /** * Format the 'next' navigation controls for calendar calendars * * @param link * The url for the navigation */ function theme_calendar_nav_next($url, $text = TRUE, $querystring = NULL) { return ''. l(($text ? t('next') : '') .' »', $url, array(), (!empty($querystring) ? $querystring : NULL)) .''; } /** * Format the 'previous' navigation controls for calendar calendars * * @param link * The url for the navigation */ function theme_calendar_nav_prev($url, $text = TRUE, $querystring = NULL) { return ''. l('« '. ($text ? t('prev') : ''), $url, array(), (!empty($querystring) ? $querystring : NULL)) .''; } /** * Theme for the back/next navigation bar * This is really hackish to put it in a table, but so many themes break otherwise that I gave up on anything else */ function theme_calendar_nav_wrapper($array) { return theme('table', $array, array()); } /** * Format the links for calendar calendars * * @param links * An array of links to render * @param view * The current view being rendered */ function theme_calendar_links($links, $view) { return theme('links', $links); } /** * Format the ical link * * @param path * The url for the ical feed */ function theme_calendar_ical_link($path) { $ical_link = ''; return preg_replace("|http://|","webcal://", $ical_link); } /** * Format the 'read more' link for calendars * * @param path * The url to use for the read more link */ function theme_calendar_more_link($path) { return ''; } /** * Format an individual upcoming calendar block item * * @param node * The node to render as an upcoming calendar */ function theme_calendar_upcoming_item($node) { $output = l($node->title, "node/$node->nid", array('title' => $node->title)); $output .= '('. $node->timeleft .')'; return $output; } /** * Format the upcoming calendar block for calendar calendars * * @param items * An array of themed upcoming calendars */ function theme_calendar_upcoming_block($items) { $output = theme("item_list", $items); return $output; }