View complete documentation at !link.

", array('!link' => 'http://drupal.org/node/120710')); } } /** * Implementation of hook_menu(). */ function calendar_menu($may_cache) { include_once(drupal_get_path('module', 'calendar') .'/calendar.theme'); drupal_add_css(drupal_get_path('module', 'calendar') .'/calendar.css'); define('CALENDAR_EMPTY_ARG', variable_get('calendar_empty_arg', 'all')); $items = array(); if (!$may_cache) { foreach (calendar_views('page') as $view_name) { $items[] = array( 'path' => $view_name['url'] .'/setup', 'title' => t('Setup'), 'description' => t('Calendar setup.'), 'access' => user_access('administer views'), 'callback' => 'drupal_get_form', 'callback arguments' => array('calendar_setup_form', $view_name['name']), 'type' => MENU_LOCAL_TASK, 'weight' => 5, ); } } return $items; } /** * Implementation of hook_views_tabs(). */ function calendar_views_tabs($op) { switch ($op) { case 'names': return array('setup'); } } /** * Helper function for loading date_api. */ function calendar_load_date_api() { include_once(drupal_get_path('module', 'date_api') .'/date.inc'); } /** * Helper function for loading calendar_api. */ function calendar_load_calendar_api() { include_once(drupal_get_path('module', 'calendar') .'/calendar_api.inc'); } /** * Implementation of hook_views_style_plugins() */ function calendar_views_style_plugins() { $plugins = array(); $types = array('calendar' => t('Calendar')); foreach ($types as $name => $type) { $plugins[$name] = array( 'name' => $type, 'theme' => 'calendar_display', 'summary_theme' => 'calendar_display', 'validate' => 'calendar_views_validate', 'needs_fields' => TRUE, 'needs_table_header' => FALSE, ); } return $plugins; } /** * Validate a view. */ function calendar_views_validate($type, $view, $form) { // list (and table) modes require there to be at least 1 field active. if (is_array($view['field'])) { $fields = array_filter(array_keys($view['field']), 'is_numeric'); } if (!$fields) { form_error($form["$type-info"][$type . '_type'], t('The Calendar View requires at least one field.')); } if (isset($view['field']['count'])) { $defaultsort = false; for ($i = 0; $i < $view['field']['count']; $i++) { if ($view['field'][$i]['defaultsort']) { if ($defaultsort) { form_error($form['field'][$i]['defaultsort'], t('You can only set on Default Sort on one field.')); break; } $defaultsort = true; } } } // Make sure all arguments are set to 'Display all values'. $arg_types = array(); $cal_args = array('calendar_year', 'calendar_month', 'calendar_day', 'calendar_week'); foreach ($view['argument'] as $delta => $argument) { if (in_array($argument['type'], $cal_args)) { $view['argument'][$delta]['argdefault'] = 2; if ($argument['argdefault'] != 2) { form_error($form['argument'][$delta]['argdefault'], t('Calendar arguments must be set to \'Display All Values\'.')); } $arg_types[] = $argument['type']; } } // Must have Year, Month, and Day or Year and Week calendar arguments. if (!in_array('calendar_year', $arg_types) && ((!in_array('calendar_month', $arg_types) && !in_array('calendar_day', $arg_types) || !in_array('calendar_week', $arg_types)))) { form_error($form['argument'], t('The Calendar requres as arguments Calendar: Year, Calendar: Month, and Calendar: Day, or Calendar: Year and Calendar: Week')); } // CCK date fields cannot use grouped handler. $calendar_fields = array_keys(calendar_fields()); foreach ($view['field'] as $delta => $field) { if (in_array($field['field'], $calendar_fields) && $field['handler'] == 'content_views_field_handler_group') { form_error($form['field'][$delta]['handler'], t('Calendar CCK Date fields must be set to \'Do not group multiple values\'.')); } } } /** * Function to return all possible calendar views page display types. * Implements hook_calendar_add_types($view) for other modules to add calendar types. */ function calendar_view_types($reset = FALSE) { static $types; if ($reset || !isset($types)) { $types = array('calendar' => t('Calendar')); foreach (module_implements('calendar_add_items') as $module) { $function = $module .'_calendar_add_types'; $types += $function($view); } } return $types; } /** * Function to return all views that are of the type 'calendar'. */ function calendar_views($build_type = 'page', $reset = FALSE) { static $calendar_views; views_load_cache(); if (empty($calendar_views)) { $calendar_views = array($build_type => ''); } if ($reset || empty($calendar_views[$build_type])) { $calendar_views = array(); $result = db_query("SELECT vid, name, url FROM {view_view} ORDER BY name"); while ($view = db_fetch_object($result)) { $view->build_type = $build_type; if (calendar_is_calendar($view)) { $calendar_views[$build_type][] = array('name' => $view->name, 'url' => $view->url); } } $check = $build_type .'_type'; foreach (_views_get_default_views() as $view) { if ($view->$check == 'calendar' && empty($view->disabled)) { $calendar_views[$build_type][] = array('name' => $view->name, 'url' => $view->url); } } } if (empty($calendar_views) || !array_key_exists($build_type, $calendar_views)) { $calendar_views = array($build_type => array()); } return $calendar_views[$build_type]; } /** * Function to test whether this is a view that uses the calendar plugin theme. */ function calendar_is_calendar($view, $reset = FALSE) { static $is_calendar; if (empty($is_calendar)) { $is_calendar = array($view->name => array($view->build_type => FALSE)); } if ($reset || empty($is_calendar[$view->name][$view->build_type])) { $is_calendar = FALSE; if ($view->build_type == 'page' && !array_key_exists($view->page_type, calendar_view_types())) { $is_calendar[$view->name][$view->build_type] = FALSE; } elseif ($view->build_type == 'page' && calendar_has_calendar_args($view)) { $is_calendar[$view->name][$view->build_type] = TRUE; } if ($view->build_type == 'block' && !array_key_exists($view->block_type, calendar_view_types())) { $is_calendar[$view->name][$view->build_type] = FALSE; } elseif ($view->build_type == 'block' && calendar_has_calendar_args($view)) { $is_calendar[$view->name][$view->build_type] = TRUE; } } return $is_calendar[$view->name][$view->build_type]; } /** * Function to test whether any calendar args are used in this view. */ function calendar_has_calendar_args($view, $reset = FALSE) { static $has_args; if (empty($has_args)) { $has_args = array($view->name => FALSE); } if ($reset || empty($has_args[$view->name])) { foreach ($view->argument as $delta => $argument) { if (in_array($argument['type'], array('calendar_year', 'calendar_month', 'calendar_day', 'calendar_week'))) { $has_args[$view->name] = TRUE; } } } return $has_args[$view->name]; } /** * Identify the final calendar argument in this view. * Needed because we can't construct a query until we know all the calendar elements. * Used to tell when to add the filter to the query object. * * @param object $view * @return string $argtype */ function calendar_last_argtype($view, $reset = FALSE) { static $argtype; if (empty($argtype)) { $argtype = array($view->name => ''); } if ($reset || empty($argtype[$view->name])) { $calendar_args[] = array(); foreach ($view->argument as $argument) { if (in_array($argument['id'], array('calendar_year', 'calendar_month', 'calendar_week', 'calendar_day'))) { $calendar_args[] = $argument['id']; } } $argtype[$view->name] = array_pop($calendar_args); } return $argtype[$view->name]; } /** * Identify all potential date/timestamp fields * @return an array with fieldname, type, and table * TODO add caching */ function calendar_fields($reset = FALSE) { static $fields; if ($reset || empty($fields)) { // iterate through all the views fields $delta = 0; foreach (_views_get_fields() as $name => $val) { $timestamp_fromto = array(); $string_fromto = array(); $type = ''; // for cck fields, get the date type if ($val['content_field']['type'] == 'date' || $val['content_field']['type'] == 'datestamp') { $type = $val['content_field']['type'] == 'date' ? 'cck_string' : 'cck_timestamp'; } // all other fields that use the views date handler are timestamps elseif ($val['handler'] == views_handler_field_dates()) { $type = 'timestamp'; } // don't do anything if this is not a date field if ($type) { // dates with from and to dates need to handle both fields as one // add the from and to dates to the first one found and ignore the second // Handling for event fromto dates if (module_exists('event') && !$event_field_processed && ($name == 'event.event_start' || $name == 'event.event_end')) { $timestamp_fromto = array('event.event_start', 'event.event_end'); $offset_field = 'event.timezone'; $tz_handling = variable_get('event_timezone_display', 'site'); $event_field_processed = TRUE; } elseif ($val['content_field']['tz_handling']) { $tz_handling = $val['content_field']['tz_handling']; if ($tz_handling == 'date') $offset_field = $val['table'] .'.'. $val['content_db_info']['columns']['offset']['column']; } else { $tz_handling = 'site'; } // Handling for cck fromto dates if (!$event_field_processed && $val['content_field']['todate']) { switch ($val['content_field']['type']) { case 'datestamp': $timestamp_fromto = array($val['table'] .'.'. $val['content_field']['field_name'] .'_value', $val['table'] .'.'. $val['content_field']['field_name'] .'_value2'); break; case 'date': $string_fromto = array($val['table'] .'.'. $val['content_field']['field_name'] .'_value', $val['table'] .'.'. $val['content_field']['field_name'] .'_value2'); break; } $event_field_processed == TRUE; } // skip this step on second occurance of fromto date fields, if more than one exists in view if (!$event_field_processed || $timestamp_fromto || $string_fromto) { // cck fields append a column name to the field, others do not // need a real field_name with no column name appended for cck date formatters $tmp = explode('.', $name); $field_name = $val['content_field']['field_name'] ? $val['content_field']['field_name'] : $tmp[1]; $fields[$tmp[1]] = array( 'type' => $type, 'delta' => $delta, 'label' => $val['name'], 'granularity' => is_array($val['content_field']['granularity']) ? (array) array_keys($val['content_field']['granularity']) : array('Y', 'M', 'D', 'H', 'N'), 'fullname' => $name, 'table' => $tmp[0], 'field' => $tmp[1], 'field_name' => $field_name, 'query_name' => str_replace('.', '_', $name), 'timestamp_fromto' => $timestamp_fromto, 'string_fromto' => $string_fromto, 'tz_handling' => $tz_handling, 'offset_field' => $offset_field, ); } } } } return $fields; } /** * Calendar Views plugin theme, overrides default views theme */ function theme_calendar_display(&$view, &$items, $type) { if ($type == 'block') { $view->calendar_type = 'month'; } $mini = $view->calendar_type == 'year' || $view->build_type == 'block' ? TRUE : FALSE; $links = $view->build_type == 'block' ? FALSE : TRUE; // Bail out here to display regular views views instead of calendar. // Check first for 'view' in url, then for 'calendar_display_format' variable, default to normal calendar display. if ($_GET['view'] && $view->build_type == 'page') { $display = check_plain($_GET['view']); } else { $display_formats = variable_get('calendar_display_format_'. $view->name, array('year' => 'calendar', 'month' => 'calendar', 'week' => 'calendar', 'day' => 'calendar', 'block' => 'calendar')); $display = $view->build_type == 'block' ? $display_formats['block'] : $display_formats[$view->calendar_type]; } switch($display) { case ('table') : $view->table_header = _views_construct_header($view, _views_get_fields()); return theme('calendar_show_nav', $view, $mini, $links) . theme('calendar_view_table', $view, $items, $type); case ('teasers') : return theme('calendar_show_nav', $view, $mini, $links) . theme('calendar_view_teasers', $view, $items, $type); case ('nodes') : return theme('calendar_show_nav', $view, $mini, $links) . theme('calendar_view_nodes', $view, $items, $type); case ('list') : return theme('calendar_show_nav', $view, $mini, $links) . theme('calendar_view_list', $view, $items, $type); } $results = calendar_get_nodes($view, $items, $type); $nodes = (array) $results['nodes']; $params = (array) $results['params']; // Weeks still aren't working right in all situations, turning them off for now. $params[with_weekno] = FALSE; $nodes += calendar_add_items($view, 'calendar'); return theme('calendar_show_nav', $view, $mini, $links) . calendar_get_calendar($view->calendar_type, $nodes, 'calendar', '', $params); } /** * Display the nodes of a view as a list. */ function theme_calendar_view_list($view, $nodes, $type) { $fields = _views_get_fields(); $items = array(); foreach ($nodes as $node) { $item = ''; foreach ($view->field as $field) { if ($fields[$field['id']]['visible'] !== FALSE) { if ($field['label']) { $item .= "
" . $field['label'] . "
"; } $item .= "
" . views_theme_field('views_handle_field', $field['queryname'], $fields, $field, $node, $view) . "
"; } } $items[] = "
name) ."'>$item
\n"; // l($node->title, "node/$node->nid"); } $items += calendar_add_items($view, 'list'); if ($items) { return theme('item_list', $items); } } /** * Display the nodes of a view as a table. */ function theme_calendar_view_table($view, $nodes, $type) { $fields = _views_get_fields(); $rows = array(); foreach ($nodes as $node) { $row = array(); foreach ($view->field as $field) { if ($fields[$field['id']]['visible'] !== FALSE) { $cell['data'] = views_theme_field('views_handle_field', $field['queryname'], $fields, $field, $node, $view); $cell['class'] = "view-field ". views_css_safe('view-field-'. $field['queryname']); $row[] = $cell; } } $rows[] = $row; } $rows += calendar_add_items($view, 'table'); return theme('table', $view->table_header, $rows); } /** * Display the nodes of a view as teasers. */ function theme_calendar_view_teasers($view, $nodes, $type) { return views_theme('calendar_view_nodes', $view, $nodes, 'teasers'); } /** * Display the nodes of a view as plain nodes. */ function theme_calendar_view_nodes($view, $nodes, $type, $teasers = false, $links = true) { $output = array(); foreach ($nodes as $n) { $node = node_load($n->nid); $output[] = node_view($node, $teasers, false, $links); } $output += calendar_add_items($view, $teasers ? 'teasers' : 'nodes'); return implode($output); } /** * Call hooks in other modules to add other items to a calendar view. * * @param object $view * @param string $type - display type, 'table', 'teasers', 'nodes', 'list', 'calendar' * @return array of additional items to add. */ function calendar_add_items($view, $type) { $new_items = array(); foreach (module_implements('calendar_add_items') as $module) { $function = $module .'_calendar_add_items'; if (function_exists($function)) { $feeds = $function($view); // Calendar items are just added as objects, themeing will be done by the calendar api. // For other types, theme the items and add them. foreach ($feeds as $feed) { if ($type == 'calendar') { $new_items[] = $feed; } else { switch ($type) { case 'table': $output = array('data' => array(theme('calendar_node_month', $feed))); break; case 'nodes': case 'teasers': case 'list': $output = theme('calendar_node_day', $feed); break; } if (!empty($output)) $new_items[] = $output; } } } } return $new_items; } /** * The workhorse function that takes the beginning array of items and alters it * to an array of calendar nodes that the theme can handle. */ function calendar_get_nodes(&$view, &$items, $type) { calendar_load_calendar_api(); calendar_load_date_api(); $view->nodes_per_page = 0; $type_names = node_get_types('names'); unset($params['limit']); if ($type == 'block' || $view->calendar_type == 'year') $params['mini'] = TRUE; $fields = calendar_fields(); $calendar_fields = (array) array_keys($fields); $nodes = array(); $i = 0; $items_in = $items; // explode out field and format info from the view foreach ($view->field as $delta => $data) { if (in_array($data['field'], $calendar_fields)) { $option = $fields[$data['field']]; $field_type = strstr($option['type'], 'string') ? 'string' : 'timestamp'; $field_function = strstr($option['type'], 'cck') ? 'content_format' : $data['handler']; $field_formatter = $data['options']; $field_field = $option['query_name']; $field_end = $field_field .'2'; $field_field_name = $option['field_name']; $timestamp_fromto = $option['timestamp_fromto']; $string_fromto = $option['string_fromto']; $field_id = $delta; $tz_handling = $option['tz_handling']; $offset_field = $option['offset_field']; $label = $data['label']; $granularity = $option['granularity']; $view_fields = _views_get_fields(); // iterate through the $items array returned by the query and create date or pseudo date nodes foreach ($items as $delta => $item) { // we have to serialize and unserialize to force a completely new copy of $item when duplicate fields use the same node // without doing this, values added to the item in later iterations get applied to earlier ones $node = unserialize(serialize($item)); $node->title = $node->node_title; $node->label = $label; foreach ($view->field as $field) { if (!in_array($field['field'], $calendar_fields) && $field['field'] != 'title') { if ($view_fields[$field['id']]['visible'] !== FALSE) { $node->fields[$field['queryname']] = views_theme_field('views_handle_field', $field['queryname'], $view_fields, $field, $node, $view); } } } // If we're dealing with an event node, join the start and to dates together in one node and get rid of the other if (module_exists('event') && ($field_field == 'event_event_start' || $field_field == 'event_event_end') && !$event_field_processed[$item->nid]) { if ($node->event_event_start > 0) { $node->calendar_start = $node->event_event_start; $node->calendar_end = $node->event_event_end; $event_field_processed[$item->nid] = TRUE; } } elseif (module_exists('event') && ($field_field == 'event_event_start' || $field_field == 'event_event_end') && $event_field_processed[$item->nid]) { // if more than one event field was added to the view (like start and end dates) // don't process it more than once unset($node); } if (isset($node) && !isset($node->calendar_start) && !isset($item->$field_field)) { // if no date for the node and no date in the item // there is no way to display it on the calendar unset($node); } if (isset($node) && !$node->calendar_start && $item->$field_field) { // if calendar_start field holds a numeric value, treat it as a unix timestamp // if string, convert to timestamp if ($field_type == 'timestamp') { $node->calendar_start = $item->$field_field; $node->calendar_end = $item->$field_end ? $item->$field_end : $item->$field_field; } else { // get the timestamp value for this date, use UTC to make sure no timezone conversion gets done on it $node->calendar_start = date_iso2unix($item->$field_field); $node->calendar_end = $item->$field_end ? date_iso2unix($item->$field_end) : date_iso2unix($item->$field_field); } } if (isset($node)) { // get appropriate timezone offset switch ($tz_handling) { case 'user' : global $user; $node->start_offset = $node->end_offset = $user->timezone; break; case 'none': case 'GMT' : $node->start_offset = $node->end_offset = 0; break; case 'date' : $node->start_offset = $node->end_offset = $offset_field; break; case 'event' : include_once(DATE_TIMEZONES); $node->start_offset = event_get_offset($node->event_timezone, $node->event_event_start); $node->end_offset = event_get_offset($node->event_timezone, $node->event_event_end); break; default : $node->start_offset = $node->end_offset = variable_get('date_default_timezone', 0); break; } } if (isset($node) && function_exists($field_function) && $node->calendar_start && $item->$field_field) { if ($field_function == 'content_format') { // force the original value for this field into the array that content_format expects $node->start_format = content_format($field_field_name, array('value' => $item->$field_field, 'value2' => $item->$field_field), $field_formatter); if ($node->calendar_end) $node->end_format = content_format($field_field_name, array('value' => $item->$field_end, 'value2' => $item->$field_end), $field_formatter); } else { // or call date format function if (!$node->start_format) { $node->start_format = $field_function(NULL, NULL, $item->$field_field, NULL); if ($node->calendar_end && !$node->end_format) $node->end_format = $field_function(NULL, NULL, $node->calendar_end, NULL); } } // format a time-only display for the month calendar for dates that have time elements if (array_intersect($granularity, array('H', 'N', 'S'))) { $node->start_time_format = date_format_date(variable_get('calendar_time_format_'. $view->name, 'H:i'), intval($node->calendar_start + $node->start_offset)); if ($node->calendar_end) $node->end_time_format = date_format_date(variable_get('calendar_time_format_'. $view->name, 'H:i'), intval($node->calendar_end + $node->end_offset)); } else { $node->start_time_format = $node->start_format; $node->end_time_format = $node->end_format; } if ($node) { // we can have multiple representations with the same nid, like multi-day values // or different fields that refer to the same node // create a unique id so it gets displayed in the calendar // Add delta to key to make multiple value CCK fields display as separate items. if (strstr($option['type'], 'cck')) { $id = $item->nid .':'. $delta .':'. $field_field; } else { $id = $item->nid .':0:'. $field_field; } $node->nid = $id; if ($view->build_type == 'page' && $view->calendar_type != 'year') { $node->stripe = calendar_node_stripe($view, $node, $option['query_name'], $field_field); } $nodes[$id] = $node; unset($node); } } } } } // make sure there is at least one item in $nodes to force the calendar to display // set the hour to 12 to minimize timezone adjustments that might push it to previous or next day if ($view->calendar_type == 'year') { // for the year view to work, must have at least one node in each month for ($i=1; $i<13; $i++) { $nodes[] = _calendar_make_node(NULL, NULL, _views_get_timezone(), $view->year, $i, 1, 12, 0); } } elseif ($view->calendar_type == 'week') { // make sure at least one node is created for the current week // add both start and end of week in case week crosses from one month to next $week_range = calendar_week_range($view->year, $view->week); $nodes[] = _calendar_make_node(NULL, NULL, _views_get_timezone(), date_format_date('Y', $week_range[0]), date_format_date('m', $week_range[0]), date_format_date('j', $week_range[0]), 12, 0); $nodes[] = _calendar_make_node(NULL, NULL, _views_get_timezone(), date_format_date('Y', $week_range[1]), date_format_date('m', $week_range[1]), date_format_date('j', $week_range[1]), 12, 0); } elseif (sizeof($nodes) == 0) { // otherwise add a blank node for the current day $nodes = array(_calendar_make_node(NULL, NULL, _views_get_timezone(), $view->year, $view->month, $view->day, 12, 0)); } if (_calendar_is_valid($view->year, 'year')) { // valid year is a test that indicates if arguments were available to establish a date for the calendar // a full view with an argument date will display a single month, day or week calendar page // with navigation that mimics regular calendar // trim off date values that are outside the selected range to prevent display of incomplete extra calendars $params['limit'] = _calendar_limit_nodes($nodes, $view->calendar_type, $view->year, $view->month, $view->day, $view->week, _views_get_timezone()); // hide the intermediate header rows created by the event api and // push title and navigation into calendar header $params['hide_header'] = $view->calendar_type == 'week' ? false : true; //$title = theme('calendar_nav_wrapper', calendar_nav($view, $params['mini']), array()); // standard api displays a whole month instead of a single week // adjust here for single week display if ($view->calendar_type == 'week' && $view->week) { $params['force_week'] = $view->week; } } // use calendar_get_calendar api to draw the calendar $params['url'] = calendar_get_url($view, $view->args); $params['append'] = calendar_url_append($view); $params['stripe'] = 'stripe'; $params['with_weekno'] = $view->build_type == 'block' || $view->calendar_type == 'year' || $view->year < 1970 ? FALSE : TRUE; return array('nodes' => $nodes, 'params' => $params); } /** * Function to construct back and next navigation from views arguments */ function calendar_nav($view, $mini = FALSE) { if (!_calendar_is_valid($view->year, 'year')) { return $view->subtitle; } calendar_load_date_api(); if ($view->calendar_type == 'week' && _calendar_is_valid($view->week, 'week')) { $range = calendar_week_range($view->year, $view->week + 1); $cur_stamp = $range[0]; } else { $cur_stamp = date_gmmktime(array('mon' => $view->month ? $view->month : 1, 'mday' => $view->day ? $view->day : 1, 'year' => $view->year ? $view->year : date_format_date("Y", (date_time())))); } // make the navigation into a header, with prev and next links // use the calendar_nav themes to mimic standard calendar navigation $paths = calendar_get_paths($cur_stamp, $view); $prev_path = implode('/', array_reverse($paths[0])); $next_path = implode('/', array_reverse($paths[1])); $prev_query = $next_query = array(); if ($_GET['view']) { $prev_query[] = 'view='. $_GET['view']; $next_query[] = 'view='. $_GET['view']; } // for the mini calendar in a block, treat the url as a querystring to avoid actually changing the page if ($mini && $view->calendar_type == 'month') { $prev_query[] = 'mini='. $prev_path; $prev_path = $_GET['q']; $next_query[] = 'mini='. $next_path; $next_path = $_GET['q']; } $prev_query[] = calendar_url_append($view); $next_query[] = calendar_url_append($view); $header = array(); $header[] = array('data' => theme('calendar_nav_prev', $prev_path, $mini ? FALSE : TRUE, implode('&', $prev_query)), 'class' => 'prev'); $header[] = array('data' => $view->subtitle, 'class' => 'heading', 'colspan' => 5); $header[] = array('data' => theme('calendar_nav_next', $next_path, $mini ? FALSE : TRUE, implode('&', $next_query)), 'class' => 'next'); return $header; } function calendar_get_paths($cur_stamp, $view) { calendar_load_date_api(); $path = array(); // build an array of the current path and its parts $i = 0; $path[$i] = array( 'path' => $view->real_url, 'type' => 'url', ); foreach ($view->argument as $delta => $arg) { if ($view->args[$delta]) { $i++; $pathtype = str_replace('calendar_', '', $arg['type']); $path[$i] = array( 'path' => $view->args[$delta] != CALENDAR_EMPTY_ARG ? $view->$pathtype : CALENDAR_EMPTY_ARG, 'type' => $pathtype, ); } } // if there are other arguments after the view arguments, add them to the navigation links while($i < sizeof($view->args)) { $i++; $path[$i] = array( 'path' => $view->args[intval($i - 1)], 'type' => '', ); } // reverse through the path, creating a $nextpath and $prevpath arrays for ($x = $i; $x >= 0; $x--) { if ($path[$x]['path'] != CALENDAR_EMPTY_ARG) { switch ($path[$x]['type']) { case ('day'): $day = $path[$x]['path']; $next_stamp = $cur_stamp + (86400); $prev_stamp = $cur_stamp - (86400); $nextpath[$x] = date_format_date('j', $next_stamp); $prevpath[$x] = date_format_date('j', $prev_stamp); break; case ('week'): $week = $path[$x]['path']; $year = $view->year; if (!$next_stamp) { $cal_range = calendar_week_range($year, $week); $next_stamp = $cal_range[1] + 1; $prev_stamp = $cal_range[0] - 1; } $week_year = calendar_week_year($next_stamp); $next_year = $week_year[1]; $nextpath[$x] = 'W'. sprintf("%02d", $week_year[0]); $week_year = calendar_week_year($prev_stamp); $prev_year = $week_year[1]; $prevpath[$x] = 'W'. sprintf("%02d", $week_year[0]); break; case ('month'): $month = $path[$x]['path']; $year = $view->year; $next_year = $month < 12 ? $year : $year + 1; $prev_year = $month > 1 ? $year : $year - 1; if (!$next_stamp) { $next_stamp = date_gmmktime(array('mon' => $month < 12 ? $month + 1 : 1, 'mday' => 1, 'year' => $next_year)); $prev_stamp = date_gmmktime(array('mon' => $month > 1 ? $month - 1 : 12, 'mday' => 1, 'year' => $prev_year)); } $nextpath[$x] = date_format_date('n', $next_stamp); $prevpath[$x] = date_format_date('n', $prev_stamp); break; case ('year'): $year = $view->year; if (!$next_stamp) { $next_stamp = date_gmmktime(array('mon' => 1, 'mday' => 1, 'year' => $next_year ? $next_year : $year + 1)); $prev_stamp = date_gmmktime(array('mon' => 12, 'mday' => 1, 'year' => $prev_year ? $prev_year : $year - 1)); } $nextpath[$x] = date_format_date('Y', $next_stamp); $prevpath[$x] = date_format_date('Y', $prev_stamp); break; default: // all other arguments are just passed through if ($path[$x]['path']) { $nextpath[$x] = $path[$x]['path']; $prevpath[$x] = $path[$x]['path']; } break; } } else { $nextpath[$x] = $path[$x]['path']; $prevpath[$x] = $path[$x]['path']; } } return array($prevpath, $nextpath); } /** * A function to create a blank date to force a calendar display when there is no data */ function _calendar_make_node($node = NULL, $timestamp = NULL, $offset = NULL, $year = NULL, $month = NULL, $day = NULL, $hour = NULL, $minute = NULL) { calendar_load_date_api(); $offset = $offset ? $offset : _views_get_timezone(); if (!$timestamp) { $year = _calendar_is_valid($year, 'year') ? $year : date_format_date('Y', date_time()); $month = _calendar_is_valid($month, 'month') ? $month : date_format_date('m', date_time()); $day = _calendar_is_valid($day, 'day') ? $day : date_format_date('j', date_time()); $hour = _calendar_is_valid($hour, 'hour') ? $hour : date_format_date('H', date_time()); $minute = _calendar_is_valid($minute, 'minute') ? $minute : date_format_date('i', date_time()); while (!checkdate($month, $day, $year)) $day--; // Account for days that don't exist $timestamp = date_gmmktime(array('hours' => $hour, 'minutes' => $minute, 'mon' => $month, 'mday' => $day, 'year' => $year)); } if (!$node) { $node = new stdClass(); $node->nid = 0; } $node->calendar_start = $timestamp; $node->start_offset = $offset; $node->calendar_end = $timestamp; $node->end_offset = $offset; return $node; } /** * A function to adjust node values to slice off times before and after the selected view * used for calendars that span days, months, or years since the calendar api * automatically creates additional calendars for calendars that extend into another time period * and the additional calendars will be incomplete (only containing cross-over calendars) */ function _calendar_limit_nodes($nodes, $type, $year, $month, $day, $week, $offset) { calendar_load_date_api(); if (!_calendar_is_valid($day, 'day')) $day = 1; if (!_calendar_is_valid($month, 'month')) $month = date_format_date('m', date_time()); if (!_calendar_is_valid($year, 'year')) $year = date_format_date('Y', date_time()); switch ($type) { case ('day'): $min_date = date_gmmktime(array('mon' => $month, 'mday' => $day, 'year' => $year)); $max_date = $min_date + 86400 - 1; break; case ('week'): return calendar_week_range($year, $week); case ('month'); $min_date = date_gmmktime(array('mon' => $month, 'mday' => 1, 'year' => $year)); // find the first day of the next month and subtract one day if (intval($month) < 12) { $max_date = date_gmmktime(array('mon' => intval($month + 1), 'day' => 1, 'year' => $year, 'hours' => 23, 'minutes' => 59, 'seconds' => 59)); } else { $max_date = date_gmmktime(array('mon' => 1, 'mday' => 1, 'year' => intval($year + 1), 'hours' => 23, 'minutes' => 59, 'seconds' => 59)); } break; case ('year'): $min_date = date_gmmktime(array('hours' => 0, 'minutes' => 0, 'seconds' => 0, 'mon' => 1, 'mday' => 1, 'year' => $year)); $max_date = date_gmmktime(array('hours' => 23, 'minutes' => 59, 'seconds' => 59, 'mon' => 12, 'mday' => 31, 'year' => $year)); } return array($min_date, $max_date); } /** * 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); } /** * Implementation of hook_views_arguments() */ function calendar_views_arguments() { $arguments = array( 'calendar_year' => array( 'name' => t('Calendar: Year'), 'handler' => 'calendar_handler_arg_year', 'help' => t('Filter by the calendar year (YYYY).'), ), 'calendar_month' => array( 'name' => t('Calendar: Month'), 'handler' => 'calendar_handler_arg_month', 'help' => t("Filter by the calendar month (1-12). Place this argument after a 'Year' argument."), ), 'calendar_day' => array( 'name' => t('Calendar: Day'), 'handler' => 'calendar_handler_arg_day', 'help' => t("Filter by the calendar day (1-31). Place this argument after a 'Year' and a 'Month' argument."), ), 'calendar_week' => array( 'name' => t('Calendar: Week'), 'handler' => 'calendar_handler_arg_week', 'help' => t("Filter by the week number (1-52). Place this argument after a 'Year' argument and use a 'W' in front of the week number in the url."), ), ); return $arguments; } /** * Custom views handler for the year argument. */ function calendar_handler_arg_year($op, &$query, $argtype, $arg = '') { if ($op == 'filter' && !empty($arg) && $arg != CALENDAR_EMPTY_ARG) { calendar_filter_year($query, $arg); } return calendar_handler_arg_type($op, $query, $argtype, $arg, 'YEAR'); } /** * Callback for year filter. * Build year, month, day, min, and max into query object. * * @param object $query * @param integer $arg */ function calendar_filter_year(&$query, $arg) { calendar_load_calendar_api(); $query->calendar_type = 'year'; $query->year = _calendar_is_valid($arg, 'year') ? $arg : calendar_user_date('year'); $query->month = CALENDAR_EMPTY_ARG; $query->day = CALENDAR_EMPTY_ARG; $query->min = $query->year; $query->max = $query->year; } /** * Custom views handler for the month argument. */ function calendar_handler_arg_month($op, &$query, $argtype, $arg = '') { if ($op == 'filter' && !empty($arg) && $arg != CALENDAR_EMPTY_ARG) { calendar_filter_month($query, $arg); } return calendar_handler_arg_type($op, $query, $argtype, $arg, 'MONTH'); } /** * Callback for month filter. * Build year, month, day, min, and max into query object. * * @param object $query * @param integer $arg */ function calendar_filter_month(&$query, $arg) { calendar_load_calendar_api(); $query->calendar_type = 'month'; if (!isset($query->year)) { calendar_filter_year($query, calendar_user_date('year')); } $query->month = _calendar_is_valid($arg, 'month') ? $arg : calendar_user_date('month'); $query->day = CALENDAR_EMPTY_ARG; $query->min .= '-'. sprintf('%02d', $query->month); $query->max .= '-'. sprintf('%02d', $query->month); } /** * Custom views handler for the day argument. */ function calendar_handler_arg_day($op, &$query, $argtype, $arg = '') { if ($op == 'filter' && !empty($arg) && $arg != CALENDAR_EMPTY_ARG) { calendar_filter_day($query, $arg); } return calendar_handler_arg_type($op, $query, $argtype, $arg, 'DAY'); } /** * Callback for day filter. * Build year, month, day, min, and max into query object. * * @param object $query * @param integer $arg */ function calendar_filter_day(&$query, $arg) { calendar_load_calendar_api(); if (!isset($query->month)) { calendar_filter_month($query, calendar_user_date('month')); } $query->calendar_type = 'day'; $query->day = _calendar_is_valid($arg, 'day') ? $arg : calendar_user_date('day'); $query->min .= '-'. sprintf('%02d', $query->day); $query->max .= '-'. sprintf('%02d', $query->day); } /** * Custom views handlers for the week argument. */ function calendar_handler_arg_week($op, &$query, $argtype, $arg = '') { if ($op == 'filter' && !empty($arg) && $arg != CALENDAR_EMPTY_ARG) { calendar_filter_week($query, $arg); } return calendar_handler_arg_type($op, $query, $argtype, $arg, 'WEEK'); } /** * Callback for week filter. * Build year, month, day, min, and max into query object. * * @param object $query * @param integer $arg */ function calendar_filter_week(&$query, $arg) { calendar_load_calendar_api(); if (!isset($query->year)) { calendar_filter_year($query, calendar_user_date('year')); } $arg = str_replace('W', '', $arg); $query->calendar_type = 'week'; $query->week = _calendar_is_valid($arg, 'week') ? $arg : calendar_user_date('week'); $query->month = calendar_week('start_month', $query, $query->week); $query->day = calendar_week('start_day', $query, $query->week); $query->min = calendar_week('start_year', $query, $query->week) .'-'. sprintf('%02d', calendar_week('start_month', $query, $query->week)) .'-'. calendar_week('start_day', $query, $query->week) .' 00:00:00'; $query->max = calendar_week('end_year', $query, $query->week) .'-'. sprintf('%02d', calendar_week('end_month', $query, $query->week)) .'-'. calendar_week('end_day', $query, $query->week) .' 23:59:59'; } /** * Custom views handler for all calendar arguments. */ function calendar_handler_arg_type($op, &$query, $argtype, $arg, $field_type) { calendar_load_date_api(); switch ($op) { case 'summary': case 'link': // The query to do summaries when date rangess can include multiple days, months, and years // is extremely complex and has been omitted, so summary views with these arguments just will not work. // TODO add some kind of validation or warning to keep people from trying to use summary views. break; case 'filter': // Figure out which will be the final calendar argument in this view so we know when to insert the query. $view = $GLOBALS['current_view']; if ($argtype['type'] == calendar_last_argtype($view)) { $query->calendar_finished = TRUE; calendar_build_filter($query, $view); } break; case 'title': // Set titles for each argument. $value = intval(str_replace('W', '', $arg ? $arg : $query)); return theme('calendar_arg_title', $field_type, $value, $query); } return; } /** * Compile the filter query for this view. * * @param object $query * @param object $view */ function calendar_build_filter(&$query, &$view) { if (!isset($query->week)) { $query->week = calendar_week('week', $query); } if (!$query->min) { return; } // Add elements to the query min and max values to create a complete date value // for the minimum and maximum once all the View's args have been used. $minmax = array( 'year' => array('-01-01 00:00:00', "-12-31 23:59:59"), 'month' => array('-01 00:00:00', '-'. sprintf("%02d", date_last_day_of_month($query->month, $query->year)) .' 23:59:59'), 'day' => array(' 00:00:00', ' 23:59:59'), 'hour' => array(':00:00', ':59:59'), 'minute' => array(':00', ':59'), ); $query->min .= $minmax[$query->calendar_type][0]; $query->max .= $minmax[$query->calendar_type][1]; // find all datetime fields in this view and add filters for them to the query $queries = array(); foreach ($view->field as $delta => $field) { $query_strings = calendar_build_field_query($query, $field); if (!empty($query_strings)) $queries = array_merge($queries, $query_strings); } // bring the node type into the query so we can use it in the theme $query->add_field('type', 'node'); if ($queries) $query->add_where(implode(" OR ", $queries)); return; } /** * Build a filtering query for an individual date field * * @param object $query - the query object * @param array $field - the view field array */ function calendar_build_field_query(&$query, $field) { $queries = array(); $fields = calendar_fields(); $field_name = $field['field']; $this_field = $fields[$field_name]; $view_fields[] = $field_name; if (array_key_exists($field_name, $fields)) { $query->ensure_table($this_field['table'], $this_field['table']); $tz_handling = $this_field['tz_handling']; $offset_field = $this_field['offset_field']; $field_type = strstr($this_field['type'], 'string') ? 'iso' : 'int'; // get appropriate timezone offset switch ($tz_handling) { case 'user' : global $user; $start_offset = $end_offset = $user->timezone; break; case 'none': case 'GMT': $start_offset = $end_offset = 0; break; case 'date' : $start_offset = $end_offset = $offset_field; break; case 'event' : // event-specific timezones won't work right here because no offset is stored in the database // the best we can do is treat it the same as if it was a site timezone default : $start_offset = $end_offset = variable_get('date_default_timezone', 0); break; } // handling for from and to date ranges if ($this_field['timestamp_fromto']) { $queries[] = "(". date_sql('DATE', $this_field['timestamp_fromto'][1], $field_type, $end_offset) ." >='". $query->min ."' AND ". date_sql('DATE', $this_field['timestamp_fromto'][0], $field_type, $start_offset) ." <='". $query->max ."')"; $event_field_processed = TRUE; } elseif ($this_field['string_fromto']) { $queries[] = "(". date_sql('DATE', $this_field['string_fromto'][1], $field_type, $end_offset) ." >='". $query->min ."' AND ". date_sql('DATE', $this_field['string_fromto'][0], $field_type, $start_offset) ." <='". $query->max ."')"; $event_field_processed = TRUE; } // handling for single day dates elseif ($this_field['type'] == 'cck_string') { $queries[] = "(". date_sql('DATE', $this_field['fullname'], $field_type, $start_offset) .">='". $query->min ."' AND ". date_sql('DATE', $field['fullname'], $field_type, $end_offset) ."<='". $query->max ."')"; } elseif (strstr($this_field['type'], 'timestamp')) { $queries[] = "(". date_sql('DATE', $this_field['fullname'], $field_type, $start_offset) .">='". $query->min ."' AND ". date_sql('DATE', $this_field['fullname'], $field_type, $end_offset) ."<='". $query->max ."')"; } } return $queries; } /** * Implementation of hook_views_query() * Insert filters into the query based on the current calendar view and the selected fields * Used when the actual view arguments don't provide enough info to construct the query. * i.e. on a view with no arguments or one with partial arguments like year or year/month. * * @param object $query * @param object $view */ function calendar_views_query_alter(&$query, &$view) { if (!calendar_has_calendar_args($view)) { return; } $view->real_url = calendar_get_url($view, $view->args); calendar_load_calendar_api(); calendar_load_date_api(); // make sure block views default to the current month // and make sure day view is not selected if ($view->build_type == 'block') { $query->calendar_type = 'month'; $view->args = explode('/', str_replace($view->url .'/', '', $_GET['mini'])); foreach ($view->argument as $delta => $argument) { if ($argument['type'] == 'calendar_year') { if (!$view->args[$delta]) $view->args[$delta] = calendar_user_date('year'); $query->year = $view->args[$delta]; calendar_filter_year($query, $query->year); } elseif (($argument['type'] == 'calendar_month' || $argument['type'] == 'calendar_week')) { if (!$view->args[$delta]) $view->args[$delta] = calendar_user_date('month'); $query->month = $view->args[$delta]; calendar_filter_month($query, $query->month); } elseif ($argument['type'] == 'calendar_day') { $query->day = CALENDAR_EMPTY_ARG; $view->args[$delta] = CALENDAR_EMPTY_ARG; } } } // Either a month or a week argument could occupy the second position of the group // this is done so that a single view has the capability to switch between all calendar layouts // to make this work we must make some adjustments to the view if ($view->build_type == 'page') { $GLOBALS['calendar_is_calendar'] = TRUE; if (empty($view->args)) { // If no arguments are provided, default to current month view. $query->calendar_type = 'month'; foreach ($view->argument as $delta => $argument) { if ($argument['type'] == 'calendar_year' && !$view->args[$delta]) { $view->args[$delta] = calendar_user_date('year'); calendar_filter_year($query, calendar_user_date('year')); } elseif ($argument['type'] == 'calendar_month' && !$view->args[$delta]) { $view->args[$delta] = calendar_user_date('month'); calendar_filter_month($query, calendar_user_date('month')); } elseif ($argument['type'] == 'calendar_day' && !$view->args[$delta]) { $view->args[$delta] = CALENDAR_EMPTY_ARG; } } } foreach ($view->argument as $delta => $argument) { if (in_array($argument['type'], array('calendar_year', 'calendar_month', 'calendar_day', 'calendar_week'))) { // make sure 'display all values' is selected for the calendar arguments // summary views are meaningless and create errors in this context $view->argument[$delta]['argdefault'] = 2; // Pad any unused values in the view arguments with CALENDAR_EMPTY_ARG to indicate all values. if (empty($view->args[$delta])) { $view->args[$delta] = CALENDAR_EMPTY_ARG; } } // Calendar_week and Calendar_month can swap positions as the second arg in the url. // Do some work here to make sure we know which is which and swap view data to match it. // the difference between a calendar_month arg and a calendar_week arg is the preceeding 'W' if ($argument['type'] == 'calendar_week' || $argument['type'] == 'calendar_month') { if (strstr($view->args[$delta], 'W')) { calendar_filter_week($query, $view->args[$delta]); $view->argument[$delta]['type'] = 'calendar_week'; $view->argument[$delta]['id'] = 'calendar_week'; $view->argument[$delta + 1]['type'] = 'calendar_day'; $view->argument[$delta + 1]['id'] = 'calendar_day'; // Make sure that there is no day set for the week view. $view->args[$delta + 1] = CALENDAR_EMPTY_ARG; } // if this is not a week argument and view was created with a week argument, change it back elseif (!strstr($view->args[$delta], 'W') && $view->build_type == 'page' && $view->argument[$delta]['type'] == 'calendar_week') { calendar_filter_month($query, $view->args[$delta]); $view->argument[$delta]['type'] = 'calendar_month'; $view->argument[$delta]['id'] = 'calendar_month'; $view->argument[$delta + 1]['type'] = 'calendar_day'; $view->argument[$delta + 1]['id'] = 'calendar_day'; } } } } // Make sure the calendar query gets inserted. May not have finished yet on views like year or year/month. if (!$query->calendar_finished) { calendar_build_filter($query, $view); } $view->calendar_type = $query->calendar_type; $view->year = $query->year; $view->month = $query->month; $view->day = $query->day; $view->week = $query->week; } /** * Implementation of hook_views_pre_view() */ function calendar_views_pre_view(&$view, &$items) { // If no part of this view has calendar elements, exit. if (!calendar_is_calendar($view) && !calendar_has_calendar_args($view)) { return; } // Construct a formatted title for the view from the last calendar argument encountered. switch ($view->calendar_type) { case 'year': $view->subtitle = theme('calendar_nav_title', 'YEAR', $view); break; case 'month': $view->subtitle = theme('calendar_nav_title', 'MONTH', $view); break; case 'day': $view->subtitle = theme('calendar_nav_title', 'DAY', $view); break; case 'week': $view->subtitle = theme('calendar_nav_title', 'WEEK', $view); break; } // If this is a view with calendar arguments but not a calendar view, // add navigation to the top of the view and return. if (!calendar_is_calendar($view) && calendar_has_calendar_args($view)) { return theme('calendar_show_nav', $view, $view->build_type == 'block', calendar_is_calendar($view)); } // If this is a calendar plugin theme view, make sure empty results // will produce blank calendar page if (array_key_exists($view->page_type, calendar_view_types())) { if (!$items && $view->build_type == 'page' && $view->year) { $view->page_empty = $view->page_header . $view->page_empty . theme('calendar_display', $view, array(), 'page'); $view->page_empty_format = 3; } } if (array_key_exists($view->block_type, calendar_view_types())) { if (!$items && $view->build_type == 'block' && $view->year) { $view->block_empty = $view->block_header . $view->block_empty . theme('calendar_display', $view, array(), 'block'); $view->block_empty_format = 3; } } } /** * Get the start and end datestamp for a calendar week. */ function calendar_week_range($year, $week) { calendar_load_date_api(); // Get timestamp for January 1 of the requested year. $min_date = date_gmmktime(array('mon' => 1, 'mday' => 1, 'year' => $year)); // Adjust back or forward to the first day of the calendar week for the specified first day of week. $dow = date_format_date('w', $min_date); $first_day = variable_get('date_first_day', 0); $diff = -((7 - $first_day + $dow) % 7); $min_date += $diff * 86400; // Add the requested number of weeks to that date. $min_date += intval(($week - 1) * 604800); // Find the end date, which is one week later, less one second. $max_date = $min_date + 604800 - 1; return array($min_date, $max_date); } /** * Find the calendar week number and year for a date. * * This is complicated by the fact that the calendar week does not match the ISO week, * since the ISO week starts on Monday for the first week that has 4 or more days in the new year * while the calendar week starts on the site's preferred first day of the week regardless * of the number of days that are in the first week or the year. * * @param unknown_type $timestamp * @return array of calendar week number and year */ function calendar_week_year($timestamp) { $first_day = variable_get('date_first_day', 0); $iso_week = intval(date_format_date('W', $timestamp)); $year = date_format_date('Y', $timestamp); // Where does this timestamp fall within the range for the iso week number. $range = calendar_week_range($year, $iso_week); // If the timestamp is in the range, the ISO week number is correct. if ($timestamp >= $range[0] && $timestamp <= $range[1]) { return array($iso_week, $year); } // If the timestamp is earlier, the calendar week is earlier than the ISO week. elseif ($timestamp < $range[1]) { if ($iso_week >= 2) { return array(intval($iso_week - 1), $year); } else { return array(1, $year); } } // If the timestamp is later, the calendar week is later than the ISO week. elseif ($timestamp > $range[0]) { if ($iso_week < 52) { return array(intval($iso_week + 1), $year); } else { return array(1, intval($year + 1)); } } } /** * Handle a lot of messy week calculations all in one place to make maintenance easier */ function calendar_week($op, $view, $week = 0) { calendar_load_date_api(); if ($week == 0) { $day = !empty($view->day) && $view->day != CALENDAR_EMPTY_ARG ? $view->day : calendar_user_date('day'); $month = !empty($view->month) && $view->month != CALENDAR_EMPTY_ARG ? $view->month : calendar_user_date('month'); $isodate = $view->year .'-'. sprintf('%02d', $month) .'-'. sprintf('%02d', $day) .'T00:00:00'; $week_year = calendar_week_year(date_iso2unix($isodate)); if ($op == 'week') return $week_year[0]; } $range = calendar_week_range($view->year, $week); $week_start = $range[0]; $week_end = $range[1]; switch ($op) { case ('start_year'): return date_format_date('Y', $week_start); case ('end_year'): return date_format_date('Y', $week_end); case ('start_month'): return date_format_date('n', $week_start); case ('end_month'): return date_format_date('n', $week_end); case ('start_day'): return date_format_date('d', $week_start); case ('end_day'): return date_format_date('d', $week_end); default: return $week_start; } } /** * A function to test the validity of various date parts */ function _calendar_is_valid($value, $type) { calendar_load_date_api(); $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; } function calendar_views_default_views() { $view = new stdClass(); $view->name = t('calendar'); $view->description = t('Calendar view of any date field'); $view->access = array (); $view->view_args_php = ''; $view->page = TRUE; $view->page_title = t('Calendar'); $view->page_header = ""; $view->page_header_format = '1'; $view->page_footer = ""; $view->page_footer_format = '1'; $view->page_empty = ""; $view->page_empty_format = '1'; $view->page_type = 'calendar'; $view->url = t('calendar'); $view->use_pager = FALSE; $view->nodes_per_page = '0'; $view->block = TRUE; $view->block_title = t('Calendar'); $view->block_header = ""; $view->block_header_format = '1'; $view->block_footer = ""; $view->block_footer_format = '1'; $view->block_empty = ""; $view->block_empty_format = '1'; $view->block_type = 'calendar'; $view->nodes_per_block = '99'; $view->block_more = '1'; $view->block_use_page_header = FALSE; $view->block_use_page_footer = FALSE; $view->block_use_page_empty = FALSE; $view->sort = array ( array ( 'tablename' => 'node', 'field' => 'changed', 'sortorder' => 'ASC', 'options' => '', ), ); $view->argument = array ( array ( 'type' => 'calendar_year', 'argdefault' => '2', 'title' => '%1', 'options' => '', 'wildcard' => '', 'wildcard_substitution' => '', ), array ( 'type' => 'calendar_month', 'argdefault' => '2', 'title' => '%2', 'options' => '', 'wildcard' => '', 'wildcard_substitution' => '', ), array ( 'type' => 'calendar_day', 'argdefault' => '2', 'title' => '%3', 'options' => '', 'wildcard' => '', 'wildcard_substitution' => '', ), ); $view->field = array ( array ( 'tablename' => 'node', 'field' => 'title', 'label' => 'Title:', 'handler' => 'views_handler_field_nodelink', 'options' => 'link', ), array ( 'tablename' => 'node', 'field' => 'changed', 'label' => 'Updated:', 'handler' => 'views_handler_field_date_small', ), ); $view->filter = array ( array ( 'tablename' => 'node', 'field' => 'status', 'operator' => '=', 'options' => '', 'value' => '1', ), ); $view->exposed_filter = array ( ); $view->requires = array(node); $views[$view->name] = $view; return $views; } /** * implementation of hook_block() */ function calendar_block($op = 'list', $delta = 0) { switch ($op) { case 'list' : $blocks[0]['info'] = t('Calendar Legend.'); $blocks[1]['info'] = t('Switch Calendar.'); return $blocks; break; case 'view' : switch ($delta) { case 0: $block['subject'] = t('Calendar Legend'); $block['content'] = $GLOBALS['calendar_stripe_labels'] ? '
'. theme('calendar_stripe_legend', $GLOBALS['calendar_stripe_labels']) .'
' : ''; return $block; case 1: $block['subject'] = t('Switch Calendar'); $block['content'] = $GLOBALS['calendar_is_calendar'] ? drupal_get_form('calendar_switch_view') : ''; return $block; } } } /** * A block with a drop-down list that allows the user to switch between views of the current period */ function calendar_switch_view() { $options[''] = t('Calendar'); $options['list'] = t('List'); $options['teasers'] = t('Teasers'); $options['nodes'] = t('Nodes'); $options['table'] = t('Table'); $form = array( '#method' => 'GET', 'view' => array( '#type' => 'select', '#default_value' => $_GET['view'], '#options' => $options, ), 'q' => array( '#type' => 'hidden', '#value' => $_GET['q'], ), 'submit' => array('#type' => 'submit', '#value' => t('Switch')), ); return $form; } /** * Implementation of hook_calendar_node() from the calendar_get_calendar() api * calendar api is expecting a function for each calendar type but * all of them need the same processing, so run them through a single function * instead of duplicating the processing for each one */ function calendar_calendar_node_month($node) { return calendar_calendar_node($node, 'calendar_node_month'); } function calendar_calendar_node_day($node) { return calendar_calendar_node($node, 'calendar_node_day'); } function calendar_calendar_node_week($node) { return calendar_calendar_node($node, 'calendar_node_week'); } function calendar_calendar_node($node, $type) { calendar_load_calendar_api(); if ($node->nid && $node->nid !== 0 && $node->calendar_start) { // this is a real calendar, go ahead and display it if (!$node->remote) { // switch our psuedo nids back to the right values $tmp = explode(':', $node->nid); $node->nid = $tmp[0]; } return theme('calendar_calendar_node', $node, $type); } else { // surpress display of psuedo calendars added to force display of a blank calendar // have to return some value for blank day so not overridden by normal calendar node theme // a blank space seems to be sufficient to do that return ' '; } } /** * Figure out what the URL of the calendar view we're currently looking at is. */ function calendar_get_url($view, $args) { static $cal_args; // Figure out which arguments are calendar arguments. if (!is_array($cal_args)) $cal_args = array(); if (empty($cal_args[$view->name])) { foreach ($view->argument as $delta => $arg) { if (in_array($arg['type'], array('calendar_year', 'calendar_week', 'calendar_month', 'calendar_day', 'calendar_ical'))) { $cal_args[$view->name][] = $delta; } } } // Add non-calendar arguments to the base url. $parts = array($view->url); foreach ($args as $delta => $arg) { if (!in_array($delta, $cal_args[$view->name]) && $arg) { array_push($parts, $arg); } } return implode('/', $parts); } /** * Pick up filter and sort info from url. */ function calendar_url_append($view) { if ($view->build_type == 'page') { foreach ($_GET as $key => $val) { if ($key != 'q' && $key != 'view') { if (!is_array($val)) { $url .= '&'. $key .'='. $val; } else { foreach ($val as $v) { $url .= '&'. $key .'[]='. $v; } } } } } return $url; } /** * Setup Calendar parameters. */ function calendar_setup_form($view_name) { calendar_load_date_api(); $view = views_load_view($view_name); $form = array(); $time = mktime(1, 15, 0, 1, 1, date('Y', date_time())); $time_options = array( 'G:i' => date('G:i', $time), 'g:ia' => date('g:ia', $time), 'g:iA' => date('g:iA', $time), 'g:i a' => date('g:i a', $time), 'g:i A' => date('g:i A', $time), 'H:i' => date('H:i', $time), 'h:ia' => date('h:ia', $time), 'h:iA' => date('h:iA', $time), 'h:i a' => date('h:i a', $time), 'h:i A' => date('h:i A', $time), ); $form['calendar_time_format'] = array( '#title' => t('Time format'), '#default_value' => variable_get('calendar_time_format_'. $view->name, 'H:i'), '#type' => 'select', '#options' => $time_options, '#description' => t('The format to use for the time-only date display.'), ); $display_options = array('calendar' => t('Calendar'), 'table' => t('Table'), 'teasers' => t('Teasers'), 'nodes' => t('Full Nodes'), 'list' => t('List')); $display_format = variable_get('calendar_display_format_'. $view->name, array('year' => 'calendar', 'month' => 'calendar', 'week' => 'calendar', 'day' => 'calendar', 'block' => 'calendar')); $form['year'] = array( '#title' => t('Year display'), '#default_value' => $display_format['year'], '#type' => 'select', '#options' => $display_options, ); $form['month'] = array( '#title' => t('Month display'), '#default_value' => $display_format['month'], '#type' => 'select', '#options' => $display_options, ); $form['week'] = array( '#title' => t('Week display'), '#default_value' => $display_format['week'], '#type' => 'select', '#options' => $display_options, ); $form['day'] = array( '#title' => t('Day display'), '#default_value' => $display_format['day'], '#type' => 'select', '#options' => $display_options, ); $form['block'] = array( '#title' => t('Block display'), '#default_value' => $display_format['block'], '#type' => 'select', '#options' => $display_options, ); $form['calendar_empty_arg'] = array( '#title' => t('Wildcard argument'), '#type' => 'textfield', '#default_value' => variable_get('calendar_empty_arg', 'all'), '#description' => t('A character or short text string to use for empty calendar arguments. For instance, \'all\' would create the url 2007/12/all to show all days in December of 2007. Note that non-ASCII characters will not display correctly in urls.') ); $form['view_name'] = array( '#type' => 'hidden', '#value' => $view->name, ); $form['submit'] = array( '#type' => 'submit', '#value' => t('Submit'), ); return $form; } /** * Save requested values. */ function calendar_setup_form_submit($form_id, $form_values) { $view_name = $form_values['view_name']; $display_format = array(); variable_set('calendar_empty_arg', check_plain($form_values['calendar_empty_arg'])); foreach ($form_values as $value_name => $value) { switch ($value_name) { case 'calendar_time_format': variable_set('calendar_time_format_'. $view_name, $value); break; case 'year': case 'month': case 'week': case 'day': case 'block': $display_format[$value_name] = $value; break; } } variable_set('calendar_display_format_'. $view_name, $display_format); } /** * create a stripe id from a combination of the field and content types * and store value for legend * formula tries to create a unique id for each possible combination * * @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 $label - the label to give this stripe. */ function calendar_node_stripe($view, $node, $query_name, $delta, $stripe = NULL, $label = '') { $type_names = node_get_types('names'); if (!$label) { $label = $view->field[$delta]['label'] .' ('. $type_names[$node->type] .')'; } if (!$stripe) { $i = 1; foreach ($type_names as $k => $v) { if ($k == $node->type) { break; } $i++; } $stripe = intval((20 * $delta) + $i); } $GLOBALS['calendar_stripe_labels'][$stripe] = $label; return $stripe; }