View complete documentation at !link.

", array('!link' => 'http://drupal.org/node/120710')); } } /** * Implementation of hook_menu(). */ function calendar_menu($may_cache) { $items = array(); if (!$may_cache) { drupal_add_css(drupal_get_path('module', 'calendar') .'/calendar.css'); define('CALENDAR_EMPTY_ARG', variable_get('calendar_empty_arg', 'all')); include_once(drupal_get_path('module', 'calendar') .'/calendar_admin.inc'); $first = TRUE; foreach (calendar_info() as $view_name => $view) { if ($first) { $items[] = array( 'path' => 'admin/settings/calendar', 'title' => t('Calendar Setup'), 'description' => t('Customize calendar settings options.'), 'access' => user_access('administer views'), 'type' => MENU_NORMAL_ITEM, 'callback' => 'drupal_get_form', 'callback arguments' => array('_calendar_setup_form', $view_name), ); } $items[] = array( 'path' => 'admin/settings/calendar/'. $view_name, 'title' => $view_name, 'access' => user_access('administer views'), 'callback' => 'drupal_get_form', 'callback arguments' => array('_calendar_setup_form', $view_name), 'type' => $first ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK, ); $items[] = array( 'path' => 'admin/settings/calendar/'. $view_name .'/setup', 'title' => t('Setup'), 'access' => user_access('administer views'), 'callback' => 'drupal_get_form', 'callback arguments' => array('_calendar_setup_form', $view_name), 'type' => MENU_DEFAULT_LOCAL_TASK, ); $first = FALSE; } } return $items; } /** * Find the number of calendar weeks for a year. * * @param int $year * @return int number of calendar weeks in selected year. */ function calendar_max_weeks($year) { $date = date_make_date(($year+1) . '-01-01 12:00:00', 'UTC'); date_modify($date, '-1 day'); return calendar_date_week(date_format($date, 'Y-m-d')); } /** * Find the calendar week number for a date. * * @param string $date, in the format Y-m-d * @return int calendar week number. */ function calendar_date_week($date) { $parts = explode('-', $date); $date = date_make_date($date . ' 12:00:00', 'UTC'); $year_date = date_make_date($parts[0] . '-01-01 12:00:00', 'UTC'); $week = intval(date_format($date, 'W')); $year_week = intval(date_format($year_date, 'W')); $date_year = intval(date_format($date, 'o')); // remove the leap week if it's present if ($date_year > intval($parts[0])) { $last_date = drupal_clone($date); date_modify($last_date, '-7 days'); $week = date_format($last_date, 'W') + 1; } else if ($date_year < intval($parts[0])) { $week = 0; } if ($year_week != 1) $week++; // convert to ISO-8601 day number, to match weeks calculated above $iso_first_day = 1 + (variable_get('date_first_day', 0) + 6) % 7; // if it's before the starting day, it's the previous week if (intval(date_format($date, 'N')) < $iso_first_day) $week--; // if the year starts before, it's an extra week at the beginning if (intval(date_format($year_date, 'N')) < $iso_first_day) $week++; return $week; } /** * Implementation of hook_form_alter(). * Make sure calendar_info() and calendar_fields() get updated. */ function calendar_form_alter($form_id, &$form) { if ($form_id == 'views_edit_view') { $form['#submit'] = array_merge($form['#submit'], array('calendar_clear_all' => array())); } } /** * 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); } /** * Custom views handler for all calendar arguments. */ function calendar_handler_arg_type($op, &$query, $argtype, $arg, $field_type) { switch ($op) { case 'summary': case 'link': // The query to do summaries when date ranges 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_is_last_arg($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; } /** * 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) { $query->calendar_type = 'year'; $query->year = calendar_part_is_valid($arg, 'year') ? $arg : date_format(date_now(), 'Y'); $query->month = CALENDAR_EMPTY_ARG; $query->day = CALENDAR_EMPTY_ARG; } /** * 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) { $now = date_now(); $query->calendar_type = 'month'; if (!isset($query->year)) { calendar_filter_year($query, date_format($now, 'Y')); } $query->month = calendar_part_is_valid($arg, 'month') ? $arg : date_format($now, 'm'); $query->day = CALENDAR_EMPTY_ARG; } /** * 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) { $now = date_now(); if (!isset($query->month)) { calendar_filter_month($query, date_format($now, 'm')); } $query->calendar_type = 'day'; $query->day = calendar_part_is_valid($arg, 'day') ? $arg : date_format($now, 'j'); } /** * 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) { $now = date_now(); if (!isset($query->year)) { calendar_filter_year($query, date_format($now, 'Y')); } $arg = str_replace('W', '', $arg); $query->calendar_type = 'week'; $query->week = calendar_part_is_valid($arg, 'week') ? $arg : NULL; $range = calendar_week_range($query); $query->month = date_format($range[0], 'n'); $query->day = date_format($range[0], 'j'); } /** * 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) || (empty($view->args) && !calendar_is_calendar_arg($view) && $view->argument[0]['argdefault'] != 2)) { return; } // Check if a new date has been selected and if so redirect. if (isset($_POST['calendar_goto'])) { $parts = explode('/', $_POST['calendar_goto']['date']); $type = $_POST['calendar_type']; if ($type == 'year') { unset($parts[1], $parts[2]); } elseif ($type == 'month') { unset($parts[2]); } elseif ($type == 'week') { $date = implode('-', $parts); $parts[1] = 'W'. calendar_date_week($date); unset($parts[2]); } drupal_goto($view->url .'/'. implode('/', $parts)); drupal_exit(); } include_once('./'. drupal_get_path('module', 'calendar') .'/calendar.inc'); include_once('./'. drupal_get_path('module', 'calendar') .'/calendar.theme'); return _calendar_views_query_alter($query, $view); } /** * Implementation of hook_views_pre_view() */ function calendar_views_pre_view(&$view, &$items) { include_once('./'. drupal_get_path('module', 'calendar') .'/calendar.theme'); // If no part of this view has calendar elements, exit. if ((!calendar_is_calendar($view) || !calendar_has_calendar_args($view))) { return; } if (!calendar_is_calendar_arg($view)) { return; } include_once('./'. drupal_get_path('module', 'calendar') .'/calendar.inc'); // Massage the resulting items into formatted calendar items. $items = calendar_build_nodes($view, $items); // Merge in items from other sources. foreach (module_implements('calendar_add_items') as $module) { $function = $module .'_calendar_add_items'; if (function_exists($function)) { if ($feeds = $function($view)) { foreach ($feeds as $feed) { $items[] = $feed; } } } } if ($view->build_type == 'block' || $view->calendar_type == 'year') $view->mini = TRUE; // Construct a formatted title for the view from the last calendar // argument encountered. $view->subtitle = theme('calendar_nav_title', $view->calendar_type, $view); // 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 = check_markup($view->page_header, $view->page_header_format) . check_markup($view->page_empty, $view->page_empty_format) . theme('calendar_display', $view, array(), 'page') . check_markup($view->page_footer, $view->page_footer_format); $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 = check_markup($view->block_header, $view->block_header_format) . check_markup($view->block_empty, $view->block_empty_format) . theme('calendar_display', $view, array(), 'block') . check_markup($view->block_footer, $view->block_footer_format); $view->block_empty_format = 3; } } } /** * Implementation of hook_views_post_view(). * * Views automatically sets the page title to the value of the last argument. * The calendar module has already created a proper title within the * calendar, so override Views to set the page title to match the View title. */ function calendar_views_post_view(&$view, $items, $output) { // If no part of this view has calendar elements, exit. if ($view->build_type != 'page' || !calendar_is_calendar($view) || !calendar_has_calendar_args($view)) { return; } include_once('./'. drupal_get_path('module', 'calendar') .'/calendar.inc'); $title = theme('calendar_page_title', $view, $items, $output); drupal_set_title($title); } /** * 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() */ 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; } /** * Valid calendar arguments. */ function calendar_args() { return array('calendar_year', 'calendar_week', 'calendar_month', 'calendar_day'); } /** * Figure out what the URL of the calendar view we're currently looking at is. */ function calendar_real_url($view, $args) { // Add non-calendar arguments to the base url. $parts = explode('/', $view->url); $bump = 0; foreach ($parts as $delta => $part) { // If one of the args is buried in the url, add it here and adjust // the delta values we'll compare the calendar arg positions to. if (in_array($part, array('$arg', '$node', '$user', '$group'))) { $parts[$delta] = array_shift($args); $bump++; } } foreach ($args as $delta => $arg) { if (!in_array($delta + $bump, calendar_arg_positions($view)) && !empty($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; } /** * Function to test whether this is a view that uses the calendar plugin theme. */ function calendar_is_calendar($view) { $calendar_info = calendar_info(); return $calendar_info[$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) { $calendar_info = calendar_info(); if (count($calendar_info[$view->name]['args']) > 0) { return TRUE; } else { return FALSE; } } /** * The positions in the view that hold calendar arguments. */ function calendar_arg_positions($view) { $calendar_info = calendar_info(); if (array_key_exists($view->name, $calendar_info)) { return array_keys($calendar_info[$view->name]['args']); } else { return array(); } } /** * Is the current argument a calendar argument. * Used to sort out whether or not to display the calendar at each point. */ function calendar_is_calendar_arg($view) { if (empty($view->real_args)) { $delta = 0; } else { $delta = max(array_keys($view->real_args)); } if (in_array($delta, calendar_arg_positions($view))) { return TRUE; } return FALSE; } /** * 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_is_last_arg($view, $reset = FALSE) { foreach ($view->argument as $argument) { if (in_array($argument['id'], calendar_args())) { $calendar_arg = $argument['id']; } $max = $argument['id']; } return $max < $calendar_arg; } /** * Helper function to find the display formats * for each part of this view. */ function calendar_get_formats($view) { return variable_get('calendar_display_format_'. $view->name, array( 'year' => 'calendar', 'month' => 'calendar', 'week' => 'calendar', 'day' => 'calendar', 'block' => 'calendar')); } /** * 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 = $type_names[$node->type] .' '. $view->field[$delta]['label']; } 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; } /** * Moved the following infrequently-used functions to separate file * so the code is not parsed on every page. */ /** * Implementation of hook_views_style_plugins() */ function calendar_views_style_plugins() { include_once('./'. drupal_get_path('module', 'calendar') .'/calendar_admin.inc'); return _calendar_views_style_plugins(); } /** * Implementation of hook_views_default_views() */ function calendar_views_default_views() { include_once('./'. drupal_get_path('module', 'calendar') .'/calendar_admin.inc'); return _calendar_views_default_views(); } /** * Implementation of hook_views_arguments() */ function calendar_views_arguments() { include_once('./'. drupal_get_path('module', 'calendar') .'/calendar_admin.inc'); return _calendar_views_arguments(); } /** * Function to return all possible calendar views page display types. */ function calendar_view_types($reset = FALSE) { include_once('./'. drupal_get_path('module', 'calendar') .'/calendar_admin.inc'); return _calendar_view_types($reset); } /** * Function to get information about all views that have calendar components. */ function calendar_info($reset = FALSE) { static $calendar_views; if (empty($calendar_views) || $reset) { $cid = 'calendar_views'; if (!$reset && $cached = cache_get($cid, 'cache_views')) { $calendar_views = unserialize($cached->data); } else { include_once('./'. drupal_get_path('module', 'calendar') .'/calendar_admin.inc'); $calendar_views = _calendar_info(); } } return $calendar_views; } /** * Identify all potential date/timestamp fields */ function calendar_fields($reset = FALSE) { static $fields; if (empty($fields) || $reset) { $cid = 'calendar_fields'; if (!$reset && $cached = cache_get($cid, 'cache_views')) { $fields = unserialize($cached->data); } else { include_once('./'. drupal_get_path('module', 'calendar') .'/calendar_admin.inc'); $fields = _calendar_fields(); } } return $fields; } /** * Validate a view during Views administration. */ function calendar_views_validate($type, $view, $form) { include_once('./'. drupal_get_path('module', 'calendar') .'/calendar_admin.inc'); return _calendar_views_validate($type, $view, $form); } /** * Setup Calendar parameters in the Setup Tab. */ function calendar_setup_form($view_name) { include_once('./'. drupal_get_path('module', 'calendar') .'/calendar_admin.inc'); return _calendar_setup_form($view_name); } /** * Save Setup values. */ function calendar_setup_form_submit($form_id, $form_values) { include_once('./'. drupal_get_path('module', 'calendar') .'/calendar_admin.inc'); return _calendar_setup_form_submit($form_id, $form_values); } /** * Empty or reset cached values. * * @param $remove * whether or not to completely remove the caches. */ function calendar_clear_all($remove = FALSE) { if ($remove) { cache_clear_all('calendar_views', 'cache_views'); cache_clear_all('calendar_fields', 'cache_views'); } else { calendar_fields(TRUE); calendar_info(TRUE); } } /** * 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 '
'. drupal_get_form('calendar_date_select_form', $view) .'
'; } /** * 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($view) { $format = 'Y/m/d'; $form['calendar_goto'] = array( //'#title' => t('Calendar date'), '#type' => 'date_popup', '#default_value' => date_format($view->min_date, 'Y-m-d'), '#date_timezone' => date_default_timezone_name(), '#date_format' => $format, ); $form['calendar_type'] = array( '#type' => 'hidden', '#value' => $view->calendar_type, ); $form['submit'] = array( '#type' => 'submit', '#value' => t('Change date'), ); return $form; }