You are here

calendar.module in Calendar 7

Adds calendar filtering and displays to Views.

File

calendar.module
View source
<?php

define('CALENDAR_SHOW_ALL', 0);
define('CALENDAR_HIDE_ALL', -1);

/**
 * Implementation of hook_views_api().
 *
 * This one is used as the base to reduce errors when updating.
 */
function calendar_views_api() {
  return array(
    'api' => 3.0,
    'path' => drupal_get_path('module', 'calendar') . '/includes',
  );
}

/**
 * @file
 * Adds calendar filtering and displays to Views.
 */

/**
 * Implementation of hook_help().
 */
function calendar_help($section, $arg) {
  switch ($section) {
    case 'admin/help#calendar':
      return t("<p>View complete documentation at !link.</p>", array(
        '!link' => 'http://drupal.org/node/120710',
      ));
  }
}
function calendar_init() {

  // If the multiday module is enabled, let it control the css.
  if (module_exists('calendar_multiday') || substr($_GET['q'], 0, 24) == 'admin/build/modules/list') {
    return;
  }

  // The css for Farbtastic color picker, painless to add it here
  // even though it isn't needed everywhere.
  drupal_add_css('misc/farbtastic/farbtastic.css');
  drupal_add_css(drupal_get_path('module', 'calendar') . '/calendar.css');
  module_load_include('inc', 'calendar', 'theme/theme.inc');
}
function calendar_theme() {

  // If the multiday module is enabled, let it control the theme.
  if (module_exists('calendar_multiday')) {
    return array();
  }
  $module_path = drupal_get_path('module', 'calendar');
  $base = array(
    'file' => 'theme.inc',
    'path' => "{$module_path}/theme",
  );
  return array(
    'calendar_day_node' => $base + array(
      'template' => 'calendar-day-node',
      'variables' => array(
        'node' => NULL,
        'view' => NULL,
      ),
    ),
    'calendar_month_node' => $base + array(
      'template' => 'calendar-month-node',
      'variables' => array(
        'node' => NULL,
        'view' => NULL,
      ),
    ),
    'calendar_week_node' => $base + array(
      'template' => 'calendar-week-node',
      'variables' => array(
        'node' => NULL,
        'view' => NULL,
      ),
    ),
    'calendar_month_multiple_node' => $base + array(
      'template' => 'calendar-month-multiple-node',
      'variables' => array(
        'curday' => NULL,
        'count' => NULL,
        'view' => NULL,
        'types' => NULL,
      ),
    ),
    'calendar_week_multiple_node' => $base + array(
      'template' => 'calendar-week-multiple-node',
      'variables' => array(
        'curday' => NULL,
        'count' => NULL,
        'view' => NULL,
        'types' => NULL,
      ),
    ),
    'calendar_datebox' => $base + array(
      'template' => 'calendar-datebox',
      'variables' => array(
        'date' => NULL,
        'view' => NULL,
        'items' => NULL,
        'selected' => NULL,
      ),
    ),
    'calendar_date_combo' => $base + array(
      'variables' => array(
        'node' => NULL,
        'lable' => NULL,
        'view' => NULL,
      ),
    ),
    'calendar_empty_day' => $base + array(
      'variables' => array(
        'curday' => NULL,
        'view' => NULL,
      ),
    ),
    'calendar_stripe_legend' => $base + array(
      'variables' => array(
        'stripe_labels' => NULL,
      ),
    ),
    'calendar_stripe_stripe' => $base + array(
      'variables' => array(
        'node' => NULL,
      ),
    ),
    'calendar_time_row_heading' => $base + array(
      'variables' => array(
        'start_time' => NULL,
        'next_start_time' => NULL,
        'curday_date' => NULL,
      ),
    ),
    'calendar_month_col' => $base + array(
      'template' => 'calendar-month-col',
      'variables' => array(
        'item' => NULL,
      ),
    ),
    'calendar_month_row' => $base + array(
      'template' => 'calendar-month-row',
      'variables' => array(
        'inner' => NULL,
        'class' => NULL,
        'iehint' => NULL,
      ),
    ),
  );
}

/**
 *  TODO need to identify type of timezone handling needed for each date field
 */
function calendar_offset($field_name) {
  $default_offset = variable_get('date_default_timezone', 0);
  $configurable_zones = variable_get('configurable_timezones', 1);
}

/**
 *  A function to test the validity of various date parts
 */
function calendar_part_is_valid($value, $type) {
  if (!preg_match('/^[0-9]*$/', $value)) {
    return FALSE;
  }
  $value = intval($value);
  if ($value <= 0) {
    return FALSE;
  }
  switch ($type) {
    case 'year':
      if ($value < DATE_MIN_YEAR) {
        return FALSE;
      }
      break;
    case 'month':
      if ($value < 0 || $value > 12) {
        return FALSE;
      }
      break;
    case 'day':
      if ($value < 0 || $value > 31) {
        return FALSE;
      }
      break;
    case 'week':
      if ($value < 0 || $value > 53) {
        return FALSE;
      }
  }
  return TRUE;
}

/**
 *  implementation of hook_block_list()
 */
function calendar_block_list($delta = 0) {
  $blocks[0]['info'] = t('Calendar Legend.');
  return $blocks;
}

/**
 *  implementation of hook_block_view()
 */
function calendar_block_view($delta = 0) {
  switch ($delta) {
    case 0:
      $block['subject'] = t('Calendar Legend');
      $content = theme('calendar_stripe_legend');
      $block['content'] = !empty($content) ? '<div class="calendar legend">' . $content . '</div>' : '';
      return $block;
  }
}

/**
 * Calendar display types
 */
function calendar_display_types() {
  return array(
    'year' => t('Year'),
    'month' => t('Month'),
    'day' => t('Day'),
    'week' => t('Week'),
  );
}

/**
 * Figure out which type of display to use, 
 * based on the current argument.
 *
 * @return year, month, day, or week.
 */
function calendar_current_type($view) {
  if (!is_object($view) || !isset($view->argument) || !is_array($view->argument)) {
    if (!empty($view->date_info->default_display)) {
      return $view->date_info->default_display;
    }
    return FALSE;
  }
  $i = 0;
  $date_handler = new date_sql_handler();
  foreach ($view->argument as $argument) {
    if ($argument['id'] == 'date_argument') {
      $parts = array_keys($date_handler
        ->arg_parts($view->args[$i]));
      break;
    }
    $i++;
  }
  return array_pop($parts);
}

/**
 * Create a stripe.
 *
 * @param $node - the node object
 * @param $query_name - the views queryname for this date field
 * @param $delta - the delta for this field, used to distinguish fields that appear more than once in the calendar
 * @param $stripe - the hex code for this stripe.
 * @param $label - the label to give this stripe.
 * 
 * TODO Reconsider use of $GLOBALS as a method of triggering the legend, there
 * may be a better way.
 */
function calendar_node_stripe($view, &$node, $query_name, $delta, $stripe = NULL, $label = '') {
  $colors = isset($view->date_info->calendar_colors) ? $view->date_info->calendar_colors : array();
  if (empty($colors)) {
    return;
  }
  $type_names = node_type_get_names();
  $type = $node->raw->node_type;
  if (!isset($node->stripe)) {
    $node->stripe = array();
    $node->stripe_label = array();
  }
  if (!$label && array_key_exists($type, $type_names)) {
    $label = $type_names[$type];
  }
  if (!$stripe) {
    if (array_key_exists($type, $colors)) {
      $stripe = $colors[$type];
    }
    else {
      $stripe = '';
    }
  }
  $node->stripe[] = $stripe;
  $node->stripe_label[] = $label;
  $GLOBALS['calendar_stripe_labels'][][$type] = array(
    'stripe' => $stripe,
    'label' => $label,
  );
  return $stripe;
}

/**
 * Create a stripe based on a taxonomy term.
 *
 * @param $node - the node object
 * @param $query_name - the views queryname for this date field
 * @param $delta - the delta for this field, used to distinguish fields that appear more than once in the calendar
 * @param $stripe - the hex code for this stripe.
 * @param $label - the label to give this stripe.
 * 
 * TODO Reconsider use of $GLOBALS as a method of triggering the legend, there
 * may be a better way.
 */
function calendar_node_taxonomy_stripe($view, &$node, $query_name, $delta, $stripe = NULL, $label = '') {
  $colors_taxonomy = isset($view->date_info->calendar_colors_taxonomy) ? $view->date_info->calendar_colors_taxonomy : array();
  if (empty($colors_taxonomy)) {
    return;
  }
  if (empty($node->raw->taxonomy_term_data_tid)) {
    return;
  }

  // Rename the vid added by Views to the normal name that
  // taxonomy will expect, it's in the raw results.
  $node->vid = $node->raw->node_vid;
  $terms_for_node = (array) $node->raw->taxonomy_term_data_tid;
  if (!isset($node->stripe)) {
    $node->stripe = array();
    $node->stripe_label = array();
  }
  if (count($terms_for_node)) {
    foreach ($terms_for_node as $tid) {
      $term_for_node = taxonomy_term_load($tid);
      if (!array_key_exists($term_for_node->tid, $colors_taxonomy)) {
        continue;
      }
      $stripe = $colors_taxonomy[$term_for_node->tid];
      $stripe_label = $term_for_node->name;
      $node->stripe[] = $stripe;
      $node->stripe_label[] = $stripe_label;
      $GLOBALS['calendar_stripe_labels'][][$term_for_node->tid] = array(
        'stripe' => $stripe,
        'label' => $stripe_label,
      );
    }
  }
  else {
    $node->stripe[] = '';
    $node->stripe_label[] = '';
  }
  return;
}

/**
 * Create a stripe based on group.
 *
 * @param $node - the node object
 * @param $query_name - the views queryname for this date field
 * @param $delta - the delta for this field, used to distinguish fields that appear more than once in the calendar
 * @param $stripe - the hex code for this stripe.
 * @param $label - the label to give this stripe.
 * 
 * TODO Reconsider use of $GLOBALS as a method of triggering the legend, there
 * may be a better way.
 */
function calendar_node_group_stripe($view, &$node, $query_name, $delta, $stripe = NULL, $label = '') {
  $colors_group = isset($view->date_info->calendar_colors_group) ? $view->date_info->calendar_colors_group : array();
  if (empty($colors_group)) {
    return;
  }
  if (!function_exists('og_get_node_groups')) {
    return;
  }
  $groups_for_node = og_get_node_groups($node);
  if (!isset($node->stripe)) {
    $node->stripe = array();
    $node->stripe_label = array();
  }
  if (count($groups_for_node)) {
    foreach ($groups_for_node as $gid => $group_name) {
      if (!array_key_exists($gid, $colors_group)) {
        continue;
      }
      $stripe = $colors_group[$gid];
      $stripe_label = $group_name;
      $node->stripe[] = $stripe;
      $node->stripe_label[] = $stripe_label;
      $GLOBALS['calendar_stripe_labels'][][$gid] = array(
        'stripe' => $stripe,
        'label' => $stripe_label,
      );
    }
  }
  else {
    $node->stripe[] = '';
    $node->stripe_label[] = '';
  }
  return $stripe;
}

/**
 * Helper function to figure out a group gid to use in blocks.
 *
 * @return an array of group nodes that are relevant.
 * @todo this may need more work.
 */
function calendar_og_groups($view) {
  if (!($groupnode = og_get_group_context())) {
    global $user;
    $groupnodes = array_keys($user->og_groups);
  }
  else {
    $groupnodes = array(
      $groupnode->nid,
    );
  }
  return $groupnodes;
}

/**
 * A selector to jump to a new date in the calendar.
 *
 * @param unknown_type $view
 * @return unknown
 */
function calendar_date_select($view) {
  return '<div class="calendar-date-select">' . drupal_render(drupal_get_form('calendar_date_select_form', $view)) . '</div>';
}

/**
 * The date selector form.
 *
 * @param object $view
 * @return the form element
 *
 * @TODO is the title desired here or does it take up too much space??
 */
function calendar_date_select_form($form, &$form_state, $view) {
  $format = date_limit_format(variable_get('date_format_short', 'm/d/Y - H:i'), array(
    'year',
    'month',
    'day',
  ));
  $form['calendar_goto'] = array(
    //'#title' => t('Calendar date'),
    '#type' => module_exists('date_popup') ? 'date_popup' : 'date_select',
    '#default_value' => date_format($view->date_info->min_date, 'Y-m-d'),
    '#date_timezone' => date_default_timezone(),
    '#date_format' => $format,
  );
  $form['calendar_type'] = array(
    '#type' => 'hidden',
    '#value' => $view->date_info->calendar_type,
  );
  $form['view_name'] = array(
    '#type' => 'hidden',
    '#value' => $view->name,
  );
  $form['view_url'] = array(
    '#type' => 'hidden',
    '#value' => $view
      ->get_url(),
  );
  $pos = calendar_arg_position($view);
  $form['calendar_previous_arg'] = array(
    '#type' => 'hidden',
    '#value' => $view->args[$pos],
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Change date'),
  );
  return $form;
}
function calendar_arg_position($view) {
  $pos = 0;
  foreach ($view->argument as $argument) {
    if ($argument->definition['handler'] == 'date_views_argument_handler') {
      return $pos;
    }
    $pos++;
  }
}

/**
 * Get the url for a calendar node.
 * 
 * @param $node - a calendar node object
 * @param $default - a default url to use when nothing specific is provided.
 */
function calendar_get_node_link($node, $default = NULL) {
  if (isset($node->url)) {
    return url($node->url, array(
      'absolute' => TRUE,
    ));
  }
  elseif (empty($node->remote) && is_numeric($node->nid)) {
    return url("node/{$node->nid}", array(
      'absolute' => TRUE,
    ));
  }
  elseif (!empty($default)) {
    return url($default, array(
      'absolute' => TRUE,
    ));
  }
}
function calendar_groupby_times($type = '') {
  $times = array();
  switch ($type) {
    case 'hour':
      for ($i = 0; $i <= 23; $i++) {
        $times[] = date_pad($i) . ':00:00';
      }
      break;
    case 'half':
      for ($i = 0; $i <= 23; $i++) {
        $times[] = date_pad($i) . ':00:00';
        $times[] = date_pad($i) . ':30:00';
      }
      break;
    default:
      break;
  }
  return $times;
}

/**
 * Define some error messages.
 */
function calendar_errors($error) {
  switch ($error) {
    case 'missing_argument_default':
      return t("The Date argument in this view must be set up to provide a default value set to the current date. Edit the argument, find 'Action to take if argument is not present.', choose 'Provide default argument', then select 'Current date'.");
  }
}

/**
 *  Check to make sure the user has entered a valid 6 digit hex color.
 */
function calendar_validate_hex_color($element) {
  if (!$element['#required'] && empty($element['#value'])) {
    return;
  }
  if (!preg_match('/^#(?:(?:[a-f\\d]{3}) {1,2})$/i', $element['#value'])) {
    form_error($element, t('@value is not a valid hex color', array(
      '@value' => check_plain($element['#value']),
    )));
  }
  else {
    form_set_value($element, $element['#value']);
  }
}

/**
 * Add link to calendar to nodes.
 * 
 * Controlled by value of 'calendar_date_link' in the view.
 */
function calendar_link($type, $object, $teaser = FALSE) {
  if ($type == 'node' && !$teaser) {
    $path = variable_get('calendar_date_link_' . $object->type);
    if (!empty($path)) {
      return array(
        'calendar_link' => array(
          'title' => t('Calendar'),
          'href' => $path,
          'attributes' => array(
            'title' => t('View the calendar.'),
          ),
        ),
      );
    }
  }
}

/**
 * Callback to remove a default calendar from the system.
 */
function calendar_remove($view_name) {

  // Remove any variable that creates a default view with this name.
  $calendar_options = variable_get('calendar_default_view_options', array());
  if (array_key_exists($view_name, $calendar_options)) {
    unset($calendar_options[$view_name]);
  }
  variable_set('calendar_default_view_options', $calendar_options);

  // Delete it from the database, if stored there.
  if ($view = views_get_view($view_name)) {
    $view
      ->delete();
  }
  views_invalidate_cache();
}

/**
 * Formats the weekday information into table header format
 *
 * @ingroup event_support
 * @return array with weekday table header data
 */
function calendar_week_header($view) {
  $len = isset($view->date_info->style_name_size) ? $view->date_info->style_name_size : (!empty($view->date_info->mini) ? 1 : 3);
  $with_week = !empty($view->date_info->style_with_weekno);

  // create week header
  $untranslated_days = calendar_untranslated_days();
  if ($len == 99) {
    $translated_days = date_week_days_ordered(date_week_days(TRUE));
  }
  else {
    $translated_days = date_week_days_ordered(date_week_days_abbr(TRUE));
  }
  if ($with_week) {
    $row[] = array(
      'header' => TRUE,
      'class' => "days week",
      'data' => '&nbsp;',
    );
  }
  foreach ($untranslated_days as $delta => $day) {
    $label = $len < 3 ? drupal_substr($translated_days[$delta], 0, $len) : $translated_days[$delta];
    $row[] = array(
      'header' => TRUE,
      'class' => "days " . $day,
      'data' => $label,
    );
  }
  return $row;
}

/**
 * Array of untranslated day name abbreviations, forced to lowercase
 * and ordered appropriately for the site setting for the first day of week.
 *
 * The untranslated day abbreviation is used in css classes.
 */
function calendar_untranslated_days() {
  $untranslated_days = date_week_days_ordered(date_week_days_untranslated());
  foreach ($untranslated_days as $delta => $day) {
    $untranslated_days[$delta] = strtolower(substr($day, 0, 3));
  }
  return $untranslated_days;
}

/**
 * Take the array of items and alter it to an array of
 * calendar nodes that the theme can handle.
 *
 * Iterate through each datefield in the view and each item
 * returned by the query, and create pseudo date nodes.
 *
 * If there is more than one date field in the node, this will create
 * multiple nodes, one each with the right calendar date for that
 * field's value. If a field value has a date range that covers more than
 * one day, separate nodes will be created for each day in the field's
 * day range, limited to the minimum and maximum dates for the view.
 *
 * When we finish, we will have a distinct node for each distinct day
 * and date field.
 */
function calendar_build_nodes(&$view, &$items) {
  if (empty($view->date_info->min_date) || empty($view->date_info->max_date)) {
    return $items;
  }

  // Midnights are determined based on the same timezone as the View uses
  $display_timezone = date_timezone_get($view->date_info->min_date);
  $display_timezone_name = timezone_name_get($display_timezone);

  // Translate the view min and max dates to UTC values
  // so we can compare UTC dates to the view range.
  $min_utc = clone $view->date_info->min_date;
  date_timezone_set($min_utc, timezone_open('UTC'));
  $max_utc = clone $view->date_info->max_date;
  date_timezone_set($max_utc, timezone_open('UTC'));
  $min_zone_string = array();

  // Will cache $min_utc-strings in various timezones
  $max_zone_string = array();
  $view->date_info->nodes_per_page = 0;
  $type_names = node_type_get_names();
  $datefields = array();
  $fields = date_views_fields();
  if (!empty($view->filter['date_filter'])) {
    $date_filter = $view->filter['date_filter'];
    foreach ($view->filter['date_filter']->options['date_fields'] as $name) {
      $datefields[] = $fields['name'][$name]['query_name'];
    }
  }
  if (!empty($view->argument['date_argument'])) {
    $date_filter = $view->argument['date_argument'];
    foreach ($view->argument['date_argument']->options['date_fields'] as $name) {
      $datefields[] = $fields['name'][$name]['query_name'];
    }
  }
  $view_fields = date_views_views_fetch_fields('node', 'field');
  $field_names = (array) array_keys($fields['name']);
  $nodes = array();
  $i = 0;
  foreach ($date_filter->options['date_fields'] as $name) {
    $field = $fields['name'][$name];
    $field_type = strstr($field['type'], 'string') ? 'string' : 'timestamp';
    $alias = $field['query_name'];
    $field_name = $field['field_name'];
    $fromto = $field['fromto'];
    $tz_handling = $field['tz_handling'];
    $label = isset($view->field[$name]) ? $view->field[$name]['label'] : $field['field_name'];
    $tz_alias = str_replace('.', '_', $field['timezone_field']);
    $db_tz = date_get_timezone_db($field['tz_handling']);
    $local_tz = date_get_timezone($field['tz_handling'], 'date');
    $field_name = $field['field_name'];
    $real_field = $field['real_field_name'];

    // If there is no field for this item, just default to the site format.
    if (!isset($view->field[$field_name])) {
      $format = variable_get('date_format_short', 'm/d/Y - H:i');
    }
    else {
      if (strstr($field['type'], 'cck')) {
        $formatter = $view->field[$field_name]->options['type'];
        $format = date_formatter_format($formatter, $view->field[$field_name]->options['type']);
      }
      else {
        $format = $view->field[$field_name]->options['date_format'];
        switch ($format) {
          case 'long':
            $format = variable_get('date_format_long', 'l, F j, Y - H:i');
            break;
          case 'medium':
            $format = variable_get('date_format_medium', 'D, m/d/Y - H:i');
            break;
          case 'custom':
            $format = $view->field[$field_name]->options['custom_date_format'];
            break;
          case 'time ago':
            break;
          default:
            $format = variable_get('date_format_short', 'm/d/Y - H:i');
            break;
        }
      }
    }

    // set the domain part of the id
    $domain = check_plain($_SERVER['SERVER_NAME']);

    // If there are multiple date fields in this calendar we may get
    // duplicate items from the other date fields, so add a way to
    // make sure each individual date field only gets added to the
    // calendar one time.
    $processed = array();
    $rrule_processed = array();
    foreach ($items as $pos => $item) {
      $delta = !empty($field['delta_field']) && !empty($item->{$field['delta_field']}) ? $item->{$field['delta_field']} : 0;
      $id = 'calendar.' . $item->id . '.' . $real_field . '.' . $delta;

      // When creating iCal feeds for repeating dates we don't want all
      // the multiple values, send only the first value.
      if (strstr($view->current_display, '_ical')) {
        if (!isset($rrule_processed[$item->id])) {
          $rrule_processed[$item->id] = TRUE;
        }
        else {
          continue;
        }
      }
      if (!in_array($id, $processed) && isset($item->calendar_fields->{$alias})) {

        // Create from and to date values for each item, adjusted to
        // the correct timezone.
        $values[0] = $item->calendar_fields->{$fromto}[0];
        $values[1] = $item->calendar_fields->{$fromto}[1];
        $db_tz = date_get_timezone_db($tz_handling, isset($item->{$tz_alias}) ? $item->{$tz_alias} : $display_timezone_name);
        $to_zone = date_get_timezone($tz_handling, isset($item->{$tz_alias}) ? $item->{$tz_alias} : $display_timezone_name);

        // Now $display_timezone determines how $item is split into
        // one entry per day, while $to_zone determines how date is displayed.
        // For now, use the date fields's timezone for the day splitting.
        $display_timezone_name = $to_zone;
        $values_display = array();

        // Start date
        $date = new DateObject($values[0], $db_tz);
        if ($db_tz != $to_zone) {
          date_timezone_set($date, timezone_open($to_zone));
        }
        $values[0] = date_format($date, DATE_FORMAT_DATETIME);
        if ($display_timezone_name != $to_zone) {
          date_timezone_set($date, $display_timezone);
          $values_display[0] = date_format($date, DATE_FORMAT_DATETIME);
        }
        else {
          $values_display[0] = $values[0];
        }

        // End date
        $date = new DateObject($values[1], $db_tz);
        if ($db_tz != $to_zone) {
          date_timezone_set($date, timezone_open($to_zone));
        }
        $values[1] = date_format($date, DATE_FORMAT_DATETIME);
        if ($display_timezone_name != $to_zone) {
          date_timezone_set($date, $display_timezone);
          $values_display[1] = date_format($date, DATE_FORMAT_DATETIME);
        }
        else {
          $values_display[1] = $values[1];
        }

        // Now $values contain start and end date of a node,
        // expressed as strings in the display (local) timezone.
        // $values_utc does the same in UTC timezone.
        // Get calendar min and max day (not time) as strings in the
        // $display_timezone. Cache in $min_zone_string and $max_zone_string,
        // since many items or fields typically use the samee timezone.
        if (!isset($min_zone_string[$display_timezone_name])) {
          $date = clone $view->date_info->min_date;
          date_timezone_set($date, $display_timezone);
          $min_zone_string[$display_timezone_name] = date_format($date, DATE_FORMAT_DATE);
          $date = clone $view->date_info->max_date;
          date_timezone_set($date, $display_timezone);
          $max_zone_string[$display_timezone_name] = date_format($date, DATE_FORMAT_DATE);
        }

        // Create a node for each date within the field's date range,
        // limited to the view's date range (regarding only day, not time).
        $now = max($min_zone_string[$display_timezone_name], substr($values_display[0], 0, 10));
        $to = min($max_zone_string[$display_timezone_name], substr($values_display[1], 0, 10));
        $next = new DateObject($now, $display_timezone);
        if ($display_timezone_name != $to_zone) {

          // Make $start and $end (derived from $node) use the timezone $to_zone, just as $values[..] do
          date_timezone_set($next, timezone_open($to_zone));
        }
        if (empty($to)) {
          $to = $now;
        }

        // $now and $next are midnight (in display timezone) on the first day where node will occur.
        // $to is midnight on the last day where node will occur.
        // All three were limited by the min-max date range of the view.
        while ($now <= $to) {
          $node = clone $item;

          // Make sure the pseudo node has the same properties a
          // regular node would have.
          if (isset($node->node_title) && !isset($node->title)) {
            $node->title = $node->node_title;
          }
          if (isset($node->node_type) && !isset($node->type)) {
            $node->type = $node->node_type;
          }
          $exceptions = array(
            'format_interval',
            'time ago',
          );
          $node->label = $label;
          $node->format = $format;
          if (!in_array($node->format, $exceptions)) {
            if (!isset($formats[$format])) {
              $formats[$format] = date_limit_format($format, array(
                'hour',
                'minute',
                'second',
              ));
              $node->format_time = $formats[$format];
            }
          }
          else {
            $node->format_time = '';
          }
          $node->url = calendar_get_node_link($node);

          //$node->$fromto[0] = $values[0];

          //$node->$fromto[1] = $values[1];

          // Flag which datefield this node is using, in case
          // there are multiple date fields in the view.
          $node->datefield = $alias;

          // If there are other datefields in the View, get rid
          // of them in this pseudo node. There should only be one
          // date in each calendar node.
          foreach ($node as $key => $val) {
            if ($key != $alias && in_array($key, $datefields)) {
              unset($node->{$key});
              foreach ($fields['name'] as $other_fields) {

                // If the unused date has other fields, unset them, too.
                if ($other_fields['query_name'] == $key) {
                  foreach ($other_fields['related_fields'] as $related_field) {
                    $key2 = str_replace('.', '_', $related_field);
                    unset($node->{$key2});
                  }
                }
              }
            }
          }

          // Get start and end of current day
          $start = date_format($next, DATE_FORMAT_DATETIME);
          date_modify($next, '+1 day');
          date_modify($next, '-1 second');
          $end = date_format($next, DATE_FORMAT_DATETIME);

          // Get intersection of current day and the node value's duration (as strings in $to_zone timezone)
          $node->calendar_start = $values[0] < $start ? $start : $values[0];
          $node->calendar_end = !empty($values[1]) ? $values[1] > $end ? $end : $values[1] : $node->calendar_start;
          $node->date_start = date_create($values[0], timezone_open($to_zone));
          $node->date_end = date_create(!empty($values[1]) ? $values[1] : $values[0], timezone_open($to_zone));

          // Actual start and end date as set in the node object
          $node->date_start = date_create($values[0], timezone_open($to_zone));
          $node->date_end = date_create(!empty($values[1]) ? $values[1] : $values[0], timezone_open($to_zone));

          // Make date objects
          $node->calendar_start_date = date_create($node->calendar_start, timezone_open($to_zone));
          $node->calendar_end_date = date_create($node->calendar_end, timezone_open($to_zone));

          // Change string timezones into
          // calendar_start and calendar_end are UTC dates as formatted strings
          $node->calendar_start = date_format($node->calendar_start_date, DATE_FORMAT_DATETIME);
          $node->calendar_end = date_format($node->calendar_end_date, DATE_FORMAT_DATETIME);
          if (substr($real_field, 0, 6) == 'field_') {
            $cck_field = field_info_field($real_field);
            $instance = field_info_instance($view->base_table, $real_field, $node->type);
            $granularity = $cck_field['settings']['granularity'];
            $increment = $instance['widget']['settings']['increment'];
          }
          else {
            $granularity = 'second';
            $increment = 1;
          }
          $node->calendar_all_day = date_is_all_day($node->calendar_start, $node->calendar_end, $granularity, $increment);

          // Change string timezones into
          // calendar_start and calendar_end are UTC dates as formatted strings
          $node->calendar_start = date_format($node->calendar_start_date, DATE_FORMAT_DATETIME);
          $node->calendar_end = date_format($node->calendar_end_date, DATE_FORMAT_DATETIME);
          unset($node->calendar_fields);
          if (isset($node) && empty($node->calendar_start)) {

            // if no date for the node and no date in the item
            // there is no way to display it on the calendar
            unset($node);
          }
          else {
            calendar_node_stripe($view, $node, $alias, $alias);
            calendar_node_taxonomy_stripe($view, $node, $alias, $alias);
            calendar_node_group_stripe($view, $node, $alias, $alias);
            $node->date_id = $id . '.' . $pos;
            $nodes[] = $node;
            unset($node);
          }
          date_modify($next, '+1 second');
          $processed[] = $id;
          $now = date_format($next, DATE_FORMAT_DATE);
        }
      }
    }
  }
  return $nodes;
}

Functions

Namesort descending Description
calendar_arg_position
calendar_block_list implementation of hook_block_list()
calendar_block_view implementation of hook_block_view()
calendar_build_nodes Take the array of items and alter it to an array of calendar nodes that the theme can handle.
calendar_current_type Figure out which type of display to use, based on the current argument.
calendar_date_select A selector to jump to a new date in the calendar.
calendar_date_select_form The date selector form.
calendar_display_types Calendar display types
calendar_errors Define some error messages.
calendar_get_node_link Get the url for a calendar node.
calendar_groupby_times
calendar_help Implementation of hook_help().
calendar_init
calendar_link Add link to calendar to nodes.
calendar_node_group_stripe Create a stripe based on group.
calendar_node_stripe Create a stripe.
calendar_node_taxonomy_stripe Create a stripe based on a taxonomy term.
calendar_offset TODO need to identify type of timezone handling needed for each date field
calendar_og_groups Helper function to figure out a group gid to use in blocks.
calendar_part_is_valid A function to test the validity of various date parts
calendar_remove Callback to remove a default calendar from the system.
calendar_theme
calendar_untranslated_days Array of untranslated day name abbreviations, forced to lowercase and ordered appropriately for the site setting for the first day of week.
calendar_validate_hex_color Check to make sure the user has entered a valid 6 digit hex color.
calendar_views_api Implementation of hook_views_api().
calendar_week_header Formats the weekday information into table header format

Constants