'Calendar', 'description' => 'Calendar administration.', 'page callback' => 'calendar_admin', 'access callback' => 'user_access', 'access arguments' => array('administer site configuration'), ); $items['admin/config/date/calendar/remove'] = array( 'title' => 'Remove calendar', 'access arguments' => array('administer views'), 'page callback' => 'drupal_get_form', 'page arguments' => array('calendar_remove_form', 4), 'type' => MENU_CALLBACK, ); return $items; } /** * General Calendar administration. */ function calendar_admin() { $content = '

Calendar Administration

'; $content .= t('This is the future home for calendar administration tasks.'); $calendar_options = variable_get('calendar_default_view_options', array()); if (!empty($calendar_options)) { $content .= t('

Deleting Calendars

Calendars that were created using older versions of the !date_wizard cannot be deleted in the Views listing. You can delete them using the links below. The newer version of the Date Wizard creates views from templates that can be deleted normally.', array('!date_wizard' => l(t('Date wizard'), 'admin/config/date/tools/date_wizard'))); $calendars = array(); $node_types = node_type_get_names(); foreach ($calendar_options as $key => $option) { $bundle = str_replace(array('calendar_', 'cal_'), '', $key); if (array_key_exists($bundle, $node_types)) { $type = $node_types[$bundle]; $calendars[] = array( l($type, 'admin/structure/types/manage/' . $bundle . '/fields'), l($key, 'admin/structure/views/edit/' . $key), t('The calendar %view is a default calendar created for the content type %bundle. ', array('%view' => $key, '%bundle' => $type)), l(t('remove !view', array('!view' => $key)), 'admin/structure/date/remove/' . $key), ); } else { // Do some cleanup while we're here if we have default calendars // for non-existent content types. calendar_remove($bundle); } } if (!empty($calendars)) { $header = array(t('Content Type'), t('Calendar'), t('Description'), t('Operations')); $content .= theme('table', array('header' => $header, 'rows' => $calendars)); } } return $content; } /** * Form constructor for the date field removal form. * * Path: admin/config/date/tools/remove * * @see date_tools_remove_form_submit() */ function calendar_remove_form($form, &$form_state, $view_name) { $form = array(); $form['view_name'] = array( '#type' => 'value', '#value' => $view_name, ); $output = confirm_form($form, t('Are you sure you want to remove the view %view?', array('%view' => $view_name)), 'admin/config/date/calendar', t('This action cannot be undone.'), t('Remove'), t('Cancel') ); return $output; } /** * Form submission handler for date_tools_remove_form(). */ function calendar_remove_form_submit($form, &$form_state) { $form_values = $form_state['values']; $view_name = $form_values['view_name']; if ($view_name && $form_values['confirm']) { calendar_remove($view_name); drupal_set_message(t('Removed calendar %calendar.', array('%calendar' => $view_name))); } $form_state['redirect'] = 'admin/config/date'; } /** * Implements hook_preprocess_date_views_pager(). * * Creates a calendar_links array which is stored in the session and used * in calendar_menu_local_tasks_alter() to display the links as action items and dynamic tabs. * The links can be altered or deleted using hook_calendar_links_alter(). * */ function calendar_preprocess_date_views_pager(&$vars) { $view = $vars['plugin']->view; // If no one has added date information, nothing to do here. if (empty($view->date_info) || empty($view->argument)) { return; } $options = $view->style_options; $pager_format = $view->date_info->date_pager_format; // If we're not on a view with a path (a page), no links are needed. $current_path = !empty($view->display_handler->options['path']) ? $view->display_handler->options['path'] : ''; if (empty($current_path)) { return; } // Find all the displays in this view that use the calendar style and have a path and create links to each. $calendar_links[$current_path] = array(); $base = array('attributes' => array('rel' => 'nofollow')); foreach ($view->display as $id => $display) { // Check for !empty() in case the view is not fully formed or has displays that are marked to be deleted. if (!empty($display->deleted) || empty($display->display_options['style_plugin']) || (isset($display->display_options['enabled']) && $display->display_options['enabled'] == FALSE)) { continue; } if ($display->display_plugin != 'feed' && !empty($display->display_options['path'])) { //$path = $display->display_options['path']; $title = $display->display_title; foreach ($display->display_options['arguments'] as $name => $argument) { if (!empty($argument['granularity'])) { $type = $argument['granularity']; } } //$type = !empty($display->display_options['style_options']['calendar_type']) ? $display->display_options['style_options']['calendar_type'] : ''; $path = calendar_granularity_path($view, $type); $calendar_links[$current_path]['tabs'][$type] = array('title' => $title, 'path' => $path); $calendar_links[$current_path]['types'][] = $type; } } // If an 'Add new ... link is provided, add it here. if (!empty($view->date_info->calendar_date_link) && !empty($view->date_info->url) && (user_access("administer nodes") || user_access('create ' . $view->date_info->calendar_date_link . ' content'))) { $name = node_type_get_name($view->date_info->calendar_date_link); $href = 'node/add/' . str_replace('_', '-', $view->date_info->calendar_date_link); $calendar_links[$current_path]['actions'][] = array('title' => t('Add @name', array('@name' => $name)), 'path' => $href); } // Pass this through drupal_alter() so it can be adjusted in custom code or in the theme. drupal_alter('calendar_links', $calendar_links); // Add the value to the session so it can be used to create the tabs. if (!empty($calendar_links[$current_path])) { $_SESSION['calendar_links'][$current_path] = $calendar_links[$current_path]; } } /** * Implements hook_menu_local_tasks_alter(). * * Takes the calendar links created in calendar_preprocess_date_views_pager() * and reconfigures them as action items and tabs. The links can be altered * before they are displayed using hook_calendar_links_alter(). * * We do this with an alter rather than in hook_menu() because the * specific path we want to go to will vary depending on the page we * are looking at at the time. */ function calendar_menu_local_tasks_alter(&$data, $router_item, $root_path) { if (!empty($_SESSION['calendar_links']) && array_key_exists($root_path, $_SESSION['calendar_links'])) { $calendar_data = $_SESSION['calendar_links'][$root_path]; if (!empty($calendar_data['actions'])) { foreach ($calendar_data['actions'] as $action) { $item = menu_get_item($action['path']); $item['title'] = $action['title']; // The add new content page would redirect to the new event // if we did not override that here. This way they will // redirect back to the calendar. $item['localized_options'] += array('query' => array()); $item['localized_options']['query'] += drupal_get_destination(); if (array_key_exists('access', $item) && $item['access']) { $data['actions']['output'][] = array( '#theme' => 'menu_local_action', '#link' => $item, ); } } } if (!empty($calendar_data['tabs'])) { $delta = !empty($data['tabs'][0]['count']) ? $data['tabs'][0]['count'] - 1 : 0; foreach ($calendar_data['tabs'] as $tab) { $clean_path = str_replace('?q=', '', $tab['path']); $item = menu_get_item($clean_path); if (!empty($item)) { $item['title'] = $tab['title']; // If we have moved off the default page for the calendar, the // links to the other views will have been adjusted to keep information // about the right year/month/week/day to go to. $item['href'] = $clean_path; if (array_key_exists('access', $item) && $item['access']) { $data['tabs'][0]['output'][$delta] = array( '#theme' => 'menu_local_task', '#link' => $item, ); $path_parts = explode('/', $root_path); if (in_array('%', $path_parts)) { $clean_parts = explode('/', $clean_path); $count = count($clean_parts); $match = TRUE; foreach ($path_parts as $key => $part) { if (empty($clean_parts[$key])) { $match = FALSE; } elseif ($part != '%' && $part != $clean_parts[$key]) { $match = FALSE; } } if ($match) { $data['tabs'][0]['output'][$delta]['#active'] = TRUE; } } elseif (strpos($clean_path, $root_path) === 0) { $data['tabs'][0]['output'][$delta]['#active'] = TRUE; } $delta++; } } $data['tabs'][0]['count'] = $delta + 1; } } } return; } /** * Implements hook_views_api(). */ function calendar_views_api() { return array( 'api' => 3.0, 'path' => drupal_get_path('module', 'calendar') . '/includes', ); } /** * Calendar display types. */ function calendar_display_types() { return array('year' => t('Year'), 'month' => t('Month'), 'day' => t('Day'), 'week' => t('Week')); } /** * Implementation of hook_help(). */ function calendar_help($section, $arg) { switch ($section) { case 'admin/help#calendar': return t("

View complete documentation at !link.

", array('!link' => l(t('Date and Calendar Documentation'), 'http://drupal.org/node/262062'))); } } /** * Implements hook_theme(). */ function calendar_theme() { $module_path = drupal_get_path('module', 'calendar'); $base = array( 'file' => 'theme.inc', 'path' => "$module_path/theme", ); return array( 'calendar_item' => $base + array( 'template' => 'calendar-item', 'variables' => array('view' => NULL, 'rendered_fields' => NULL, 'item' => NULL), ), 'calendar_datebox' => $base + array( 'template' => 'calendar-datebox', 'variables' => array( 'date' => NULL, 'view' => NULL, 'items' => NULL, 'selected' => 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), ), 'calendar_month_multiple_entity' => $base + array( 'template' => 'calendar-month-multiple-entity', 'variables' => array(' curday' => NULL, 'count' => NULL, 'view' => NULL, 'ids' => NULL), ), ); } /** * Implements hook_node_view(). * * Add link to calendar to nodes, formerly hook_link(). * Controlled by value of 'calendar_date_link' in the view. */ function calendar_node_view($node, $view_mode, $langcode) { $path = variable_get('calendar_date_link_' . $node->type); if (!empty($path)) { $links['calendar_link'] = array( 'title' => t('Calendar'), 'href' => $path, 'attributes' => array('title' => t('View the calendar.')), ); $node->content['links']['calendar'] = array( '#theme' => 'links__node__caledar', '#links' => $links, '#attributes' => array('class' => array('links', 'inline')), ); } } /** * Helper function to link an entity type to a calendar. * * @param $entity_type - the type of entity. * @param $bundle - the entity bundle name. * @param $path - the calendar path to use for this bundle. */ function calendar_set_link($entity_type, $bundle, $path) { switch ($entity_type) { case 'node': variable_set('calendar_date_link_' . $bundle, $path); break; default: variable_set('calendar_date_link_' . $entity_type . '_' . $bundle, $path); break; } } /** * Helper function to clear previously-set links to calendars. * * @param $bundle, Clear all links for this bundle. If NULL, clear all links. */ function calendar_clear_link_bundle($bundle = NULL) { if (empty($bundle)) { $result = db_select('variable', 'v') ->fields('v', 'name') ->condition('name', 'calendar_date_link_%', 'LIKE') ->execute()->fetchAll(PDO::FETCH_ASSOC); } else { $result = db_select('variable', 'v') ->fields('v', 'name') ->condition('name', 'calendar_date_link_' . $bundle) ->execute()->fetchAll(PDO::FETCH_ASSOC); } // Iterate over all the values and delete them. foreach ($result as $row) { variable_del($row['name']); } } /** * Helper function to clear previously-set links to calendars. * * @param $path, Clear all links to this path. If NULL, clear all links. */ function calendar_clear_link_path($path = NULL) { $result = db_select('variable', 'v') ->fields('v', array('name', 'value')) ->condition('name', 'calendar_date_link_%', 'LIKE') ->execute()->fetchAll(PDO::FETCH_ASSOC); // Iterate over all the values and delete them. foreach ($result as $row) { if (empty($path) || unserialize($row['value']) == $path) { variable_del($row['name']); } } } /** * 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' => ' '); } 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; } /** * Default settings array for calendar time grouping. */ 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; } /** * Implementation of hook_block_info() */ function calendar_block_info() { $blocks['calendar_legend'] = array( 'info' => t('Calendar Legend'), 'cache' => DRUPAL_NO_CACHE, ); return $blocks; } /** * Implementation of hook_block_view(). */ function calendar_block_view($delta = '') { switch ($delta) { case 'calendar_legend': $block['subject'] = t('Calendar Legend'); $block['content'] = array( '#theme' => 'calendar_stripe_legend', ); return $block; } } /** * Find the path for the calendar display that has a specific granularity. */ function calendar_granularity_path(&$view, $granularity) { $paths = &drupal_static(__FUNCTION__, array()); if (!array_key_exists($view->name, $paths) || !(array_key_exists($granularity, $paths[$view->name]))) { $paths[$view->name][$granularity] = ''; foreach ($view->display as $id => $display) { // Check for !empty() in case the view is not fully formed or has displays that are marked to be deleted if (!empty($display->deleted) || empty($display->display_options['style_plugin']) || (isset($display->display_options['enabled']) && $display->display_options['enabled'] == FALSE)) { continue; } if ($display->display_plugin != 'feed' && !empty($display->display_options['path'])) { foreach ($display->display_options['arguments'] as $name => $argument) { if (!empty($argument['granularity'])) { $type = $argument['granularity']; } } if ($type == $granularity) { $part_path = $display->display_options['path']; $parts = explode('/', $part_path); if (in_array('%', $parts)) { $current_path = parse_url($_GET['q']); $current_parts = explode('/', $current_path['path']); foreach ($parts as $key => $part) { if ($part == '%' && !empty($current_parts[$key])) { $parts[$key] = $current_parts[$key]; } } $part_path = implode('/', $parts); } $paths[$view->name][$granularity] = $part_path; } } } } return $paths[$view->name][$granularity]; } /** * 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(); } /** * Check to make sure the user has entered a valid 6 digit hex color. */ function calendar_validate_hex_color($element, &$form_state) { if (!$element['#required'] && empty($element['#value'])) { return; } if (!preg_match('/^#(?:(?:[a-f\d]{3}){1,2})$/i', $element['#value'])) { form_error($element, t("'@color' is not a valid hex color", array('@color' => $element['#value']))); } else { form_set_value($element, $element['#value'], $form_state); } }