calendar.module

Tracking 7.x-3.x branch
  1. drupal
    1. 5 contributions/calendar/calendar.module
    2. 6 contributions/calendar/calendar.module
    3. 7 contributions/calendar/calendar.module

Adds calendar filtering and displays to Views.

Functions & methods

NameDescription
calendar_admin_settingsGeneral Calendar administration.
calendar_block_configureImplementation of hook_block_configure().
calendar_block_infoImplementation of hook_block_info()
calendar_block_saveImplementation of hook_block_save().
calendar_block_viewImplementation of hook_block_view().
calendar_clear_link_bundleHelper function to clear previously-set links to calendars.
calendar_clear_link_pathHelper function to clear previously-set links to calendars.
calendar_date_default_argument_alterImplements hook_date_default_argument_alter().
calendar_display_typesCalendar display types.
calendar_granularity_pathFind the path for the calendar display that has a specific granularity.
calendar_groupby_timesDefault settings array for calendar time grouping.
calendar_helpImplementation of hook_help().
calendar_list_views
calendar_menuImplements hook_menu().
calendar_menu_local_tasks_alterImplements hook_menu_local_tasks_alter().
calendar_node_viewImplements hook_node_view().
calendar_preprocess_date_views_pagerImplements hook_preprocess_date_views_pager().
calendar_set_linkHelper function to link an entity type to a calendar.
calendar_themeImplements hook_theme().
calendar_untranslated_daysArray of untranslated day name abbreviations, forced to lowercase and ordered appropriately for the site setting for the first day of week.
calendar_validate_hex_colorCheck to make sure the user has entered a valid 6 digit hex color.
calendar_views_apiImplements hook_views_api().
calendar_views_pre_renderImplements hook_views_pre_render().
calendar_week_headerFormats the weekday information into table header format

Constants

NameDescription
CALENDAR_EMPTY_STRIPE
CALENDAR_HIDE_ALL
CALENDAR_SHOW_ALL

File

View source
  1. <?php
  2. define('CALENDAR_SHOW_ALL', 0);
  3. define('CALENDAR_HIDE_ALL', -1);
  4. define('CALENDAR_EMPTY_STRIPE', '#ffffff');
  5. /**
  6. * @file
  7. * Adds calendar filtering and displays to Views.
  8. */
  9. /**
  10. * Implements hook_menu().
  11. */
  12. function calendar_menu() {
  13. $items = array();
  14. $items['admin/config/date/calendar'] = array(
  15. 'title' => 'Calendar',
  16. 'description' => 'Calendar administration.',
  17. 'page callback' => 'drupal_get_form',
  18. 'page arguments' => array('calendar_admin_settings'),
  19. 'access callback' => 'user_access',
  20. 'access arguments' => array('administer site configuration'),
  21. );
  22. return $items;
  23. }
  24. /**
  25. * General Calendar administration.
  26. */
  27. function calendar_admin_settings() {
  28. $form = array();
  29. $form['#prefix'] = '<h2>Calendar Administration</h2>';
  30. $form['calendar_track_date'] = array(
  31. '#title' => t('Track current date in session'),
  32. '#type' => 'radios',
  33. '#options' => array(0 => t("Never"), 1 => t('For authenticated users'), 2 => t('For all users')),
  34. '#default_value' => variable_get('calendar_track_date', 0),
  35. '#description' => t("Store session information about the user's current date as they move back and forth through the calendar. Without this setting users will revert to the current day each time they choose a new calendar period (year, month, week, or day). With this option set they will move to a day that conforms to the time period they were viewing before they switched. Requires session tracking which is not ordinarily enabled for anonymous users."),
  36. );
  37. $form['calendar_add_colorbox'] = array(
  38. '#title' => t('Add Colorbox settings to Node calendar templates'),
  39. '#default_value' => variable_get('calendar_add_colorbox'),
  40. '#type' => 'radios',
  41. '#options' => array(0 => t('No'), 1 => t('Yes')),
  42. '#description' => t('To try the Colorbox settings, choose the option to add Colorbox settings to the calendar templates. Install and enable the Colorbox module, following the instructions on the Colorbox project page, then create a new calendar from a template using any date field in the Node base table. The calendar will be set up to display the calendar items in a Colorbox.'),
  43. );
  44. return system_settings_form($form);
  45. }
  46. /**
  47. * Implements hook_preprocess_date_views_pager().
  48. *
  49. * Creates a calendar_links array which is stored in the session and used
  50. * in calendar_menu_local_tasks_alter() to display the links as action items.
  51. * The links can be altered or deleted using hook_calendar_links_alter().
  52. *
  53. */
  54. function calendar_preprocess_date_views_pager(&$vars) {
  55. $view = $vars['plugin']->view;
  56. // If no one has added date information, nothing to do here.
  57. if (empty($view->date_info) || empty($view->argument)) {
  58. return;
  59. }
  60. // If we're not on a view with a path (a page), no links are needed.
  61. $current_path = !empty($view->display_handler->options['path']) ? $view->display_handler->options['path'] : '';
  62. if (empty($current_path)) {
  63. return;
  64. }
  65. // If this display has been set up as a default tab, the current path
  66. // is actually the base path, i.e. if the path is 'calendar/month'
  67. // and this is a default tab, the path for this display will actually
  68. // be 'calendar'.
  69. if ($view->display_handler->options['menu']['type'] == 'default tab') {
  70. $parts = explode('/', $current_path);
  71. array_pop($parts);
  72. $current_path = implode('/', $parts);
  73. }
  74. // If an 'Add new ... link is provided, add it here.
  75. if (!empty($view->date_info->calendar_date_link) && !empty($view->date_info->url)
  76. && (user_access("administer nodes") || user_access('create ' . $view->date_info->calendar_date_link . ' content'))) {
  77. $name = node_type_get_name($view->date_info->calendar_date_link);
  78. $href = 'node/add/' . str_replace('_', '-', $view->date_info->calendar_date_link);
  79. $calendar_links[$current_path]['actions'][] = array('title' => t('Add @name', array('@name' => $name)), 'path' => $href);
  80. }
  81. // Pass this through drupal_alter() so it can be adjusted in custom code or in the theme.
  82. drupal_alter('calendar_links', $calendar_links);
  83. // Add the value to the session so it can be used to create the action links.
  84. if (!empty($calendar_links[$current_path])) {
  85. $_SESSION['calendar_links'][$current_path] = $calendar_links[$current_path];
  86. }
  87. }
  88. /**
  89. * Implements hook_date_default_argument_alter().
  90. *
  91. * Adjust the default date for a view based on the stored session value.
  92. */
  93. function calendar_date_default_argument_alter(&$argument, &$value) {
  94. global $user;
  95. $style_options = $argument->view->display_handler->get_option('style_options');
  96. $tracking = variable_get('calendar_track_date', 0);
  97. if (!empty($tracking) && ($tracking == 2 || !empty($user->uid))) {
  98. // If this is a default date, i.e. we are visiting a new calendar display,
  99. // set the default date for the display. See if we already have a session
  100. // date to use. If so, use it. Otherwise the default is the current date.
  101. if (!empty($_SESSION[$argument->view->name]['default_date'])) {
  102. $default_date = $_SESSION[$argument->view->name]['default_date'];
  103. }
  104. else {
  105. $default_date = date_now();
  106. $_SESSION[$argument->view->name]['default_date'] = $default_date;
  107. }
  108. // Get the current date from the session.
  109. $value = $default_date->format($argument->arg_format);
  110. }
  111. }
  112. /**
  113. * Implements hook_views_pre_render().
  114. *
  115. * Track the current date as the user moves from calendar display to calendar display.
  116. */
  117. function calendar_views_pre_render(&$view) {
  118. global $user;
  119. $style_options = $view->display_handler->get_option('style_options');
  120. $tracking = variable_get('calendar_track_date', 0);
  121. if (!empty($tracking) && ($tracking == 2 || !empty($user->uid))) {
  122. foreach ($view->argument as $id => &$argument) {
  123. // If this is not a default date, i.e. we have browsed to a new calendar
  124. // period on a display we were already on, store the midpoint of the current
  125. // view as the current date in a session.
  126. if (date_views_handler_is_date($argument, 'argument') && empty($argument->is_default)) {
  127. $date_range = $argument->date_handler->arg_range($argument->argument);
  128. $session_date = $date_range[0];
  129. $days = intval(($date_range[1]->format('U') - $date_range[0]->format('U')) / 3600 / 24 / 2);
  130. date_modify($session_date, "+$days days");
  131. $_SESSION[$view->name]['default_date'] = $session_date;
  132. }
  133. }
  134. }
  135. }
  136. /**
  137. * Implements hook_menu_local_tasks_alter().
  138. *
  139. * Takes the calendar links created in calendar_preprocess_date_views_pager()
  140. * and reconfigures them as action items. The links can be altered
  141. * before they are displayed using hook_calendar_links_alter().
  142. */
  143. function calendar_menu_local_tasks_alter(&$data, $router_item, $root_path) {
  144. if (!empty($_SESSION['calendar_links']) && array_key_exists($root_path, $_SESSION['calendar_links'])) {
  145. $calendar_data = $_SESSION['calendar_links'][$root_path];
  146. if (!empty($calendar_data['actions'])) {
  147. foreach ($calendar_data['actions'] as $action) {
  148. $item = menu_get_item($action['path']);
  149. $item['title'] = $action['title'];
  150. // The add new content page would redirect to the new event
  151. // if we did not override that here. This way they will
  152. // redirect back to the calendar.
  153. $item['localized_options'] += array('query' => array());
  154. $item['localized_options']['query'] += drupal_get_destination();
  155. if (array_key_exists('access', $item) && $item['access']) {
  156. $data['actions']['output'][] = array(
  157. '#theme' => 'menu_local_action',
  158. '#link' => $item,
  159. );
  160. }
  161. }
  162. }
  163. }
  164. return;
  165. }
  166. /**
  167. * Implements hook_views_api().
  168. */
  169. function calendar_views_api() {
  170. return array(
  171. 'api' => 3.0,
  172. 'path' => drupal_get_path('module', 'calendar') . '/includes',
  173. );
  174. }
  175. /**
  176. * Calendar display types.
  177. */
  178. function calendar_display_types() {
  179. return array('year' => t('Year'), 'month' => t('Month'), 'day' => t('Day'), 'week' => t('Week'));
  180. }
  181. /**
  182. * Implementation of hook_help().
  183. */
  184. function calendar_help($section, $arg) {
  185. switch ($section) {
  186. case 'admin/help#calendar':
  187. return t("<p>View complete documentation at !link.</p>", array('!link' => l(t('Date and Calendar Documentation'), 'http://drupal.org/node/262062')));
  188. }
  189. }
  190. /**
  191. * Implements hook_theme().
  192. */
  193. function calendar_theme() {
  194. $module_path = drupal_get_path('module', 'calendar');
  195. $base = array(
  196. 'file' => 'theme.inc',
  197. 'path' => "$module_path/theme",
  198. );
  199. return array(
  200. 'calendar_item' => $base + array(
  201. 'template' => 'calendar-item',
  202. 'variables' => array('view' => NULL, 'rendered_fields' => NULL, 'item' => NULL),
  203. ),
  204. 'calendar_datebox' => $base + array(
  205. 'template' => 'calendar-datebox',
  206. 'variables' => array(
  207. 'date' => NULL, 'view' => NULL, 'items' => NULL, 'selected' => NULL),
  208. ),
  209. 'calendar_empty_day' => $base + array(
  210. 'variables' => array('curday' => NULL, 'view' => NULL),
  211. ),
  212. 'calendar_stripe_legend' => $base + array(
  213. 'variables' => array('view' => NULL),
  214. ),
  215. 'calendar_stripe_stripe' => $base + array(
  216. 'variables' => array('node' => NULL),
  217. ),
  218. 'calendar_time_row_heading' => $base + array(
  219. 'variables' => array('start_time' => NULL, 'next_start_time' => NULL, 'curday_date' => NULL),
  220. ),
  221. 'calendar_month_col' => $base + array(
  222. 'template' => 'calendar-month-col',
  223. 'variables' => array('item' => NULL),
  224. ),
  225. 'calendar_month_row' => $base + array(
  226. 'template' => 'calendar-month-row',
  227. 'variables' => array('inner' => NULL, 'class' => NULL, 'iehint' => NULL),
  228. ),
  229. 'calendar_month_multiple_entity' => $base + array(
  230. 'template' => 'calendar-month-multiple-entity',
  231. 'variables' => array('
  232. curday' => NULL, 'count' => NULL, 'view' => NULL, 'ids' => NULL),
  233. ),
  234. );
  235. }
  236. /**
  237. * Implements hook_node_view().
  238. *
  239. * Add link to calendar to nodes, formerly hook_link().
  240. * Controlled by value of 'calendar_date_link' in the view.
  241. */
  242. function calendar_node_view($node, $view_mode, $langcode) {
  243. $path = variable_get('calendar_date_link_' . $node->type);
  244. if (!empty($path)) {
  245. $links['calendar_link'] = array(
  246. 'title' => t('Calendar'),
  247. 'href' => $path,
  248. 'attributes' => array('title' => t('View the calendar.')),
  249. );
  250. $node->content['links']['calendar'] = array(
  251. '#theme' => 'links__node__caledar',
  252. '#links' => $links,
  253. '#attributes' => array('class' => array('links', 'inline')),
  254. );
  255. }
  256. }
  257. /**
  258. * Helper function to link an entity type to a calendar.
  259. *
  260. * @param $entity_type - the type of entity.
  261. * @param $bundle - the entity bundle name.
  262. * @param $path - the calendar path to use for this bundle.
  263. */
  264. function calendar_set_link($entity_type, $bundle, $path) {
  265. switch ($entity_type) {
  266. case 'node':
  267. variable_set('calendar_date_link_' . $bundle, $path);
  268. break;
  269. default:
  270. variable_set('calendar_date_link_' . $entity_type . '_' . $bundle, $path);
  271. break;
  272. }
  273. }
  274. /**
  275. * Helper function to clear previously-set links to calendars.
  276. *
  277. * @param $bundle, Clear all links for this bundle. If NULL, clear all links.
  278. */
  279. function calendar_clear_link_bundle($bundle = NULL) {
  280. if (empty($bundle)) {
  281. $result = db_select('variable', 'v')
  282. ->fields('v', 'name')
  283. ->condition('name', 'calendar_date_link_%', 'LIKE')
  284. ->execute()->fetchAll(PDO::FETCH_ASSOC);
  285. }
  286. else {
  287. $result = db_select('variable', 'v')
  288. ->fields('v', 'name')
  289. ->condition('name', 'calendar_date_link_' . $bundle)
  290. ->execute()->fetchAll(PDO::FETCH_ASSOC);
  291. }
  292. // Iterate over all the values and delete them.
  293. foreach ($result as $row) {
  294. variable_del($row['name']);
  295. }
  296. }
  297. /**
  298. * Helper function to clear previously-set links to calendars.
  299. *
  300. * @param $path, Clear all links to this path. If NULL, clear all links.
  301. */
  302. function calendar_clear_link_path($path = NULL) {
  303. $result = db_select('variable', 'v')
  304. ->fields('v', array('name', 'value'))
  305. ->condition('name', 'calendar_date_link_%', 'LIKE')
  306. ->execute()->fetchAll(PDO::FETCH_ASSOC);
  307. // Iterate over all the values and delete them.
  308. foreach ($result as $row) {
  309. if (empty($path) || unserialize($row['value']) == $path) {
  310. variable_del($row['name']);
  311. }
  312. }
  313. if (isset($_SESSION['calendar_links'][$path]['actions'])) {
  314. unset($_SESSION['calendar_links'][$path]['actions']);
  315. if (empty($_SESSION['calendar_links'][$path])) {
  316. unset($_SESSION['calendar_links'][$path]);
  317. }
  318. }
  319. }
  320. /**
  321. * Formats the weekday information into table header format
  322. *
  323. * @ingroup event_support
  324. * @return array with weekday table header data
  325. */
  326. function calendar_week_header($view) {
  327. $len = isset($view->date_info->style_name_size) ? $view->date_info->style_name_size : (!empty($view->date_info->mini) ? 1 : 3);
  328. $with_week = !empty($view->date_info->style_with_weekno);
  329. // create week header
  330. $untranslated_days = calendar_untranslated_days();
  331. $full_translated_days = date_week_days_ordered(date_week_days(TRUE));
  332. if ($len == 99) {
  333. $translated_days = $full_translated_days;
  334. }
  335. else {
  336. $translated_days = date_week_days_ordered(date_week_days_abbr(TRUE));
  337. }
  338. if ($with_week) {
  339. $row[] = array('header' => TRUE, 'class' => "days week", 'data' => '&nbsp;', 'header_id' => 'Week');
  340. }
  341. foreach ($untranslated_days as $delta => $day) {
  342. $label = $len < 3 ? drupal_substr($translated_days[$delta], 0 , $len) : $translated_days[$delta];
  343. $row[] = array('header' => TRUE, 'class' => "days " . $day, 'data' => $label, 'header_id' => $full_translated_days[$delta]);
  344. }
  345. return $row;
  346. }
  347. /**
  348. * Array of untranslated day name abbreviations, forced to lowercase
  349. * and ordered appropriately for the site setting for the first day of week.
  350. *
  351. * The untranslated day abbreviation is used in css classes.
  352. */
  353. function calendar_untranslated_days() {
  354. $untranslated_days = date_week_days_ordered(date_week_days_untranslated());
  355. foreach ($untranslated_days as $delta => $day) {
  356. $untranslated_days[$delta] = strtolower(substr($day, 0, 3));
  357. }
  358. return $untranslated_days;
  359. }
  360. /**
  361. * Default settings array for calendar time grouping.
  362. */
  363. function calendar_groupby_times($type = '') {
  364. $times = array();
  365. switch ($type) {
  366. case 'hour':
  367. for ($i = 0; $i <= 23; $i++) {
  368. $times[] = date_pad($i) . ':00:00';
  369. }
  370. break;
  371. case 'half':
  372. for ($i = 0; $i <= 23; $i++) {
  373. $times[] = date_pad($i) . ':00:00';
  374. $times[] = date_pad($i) . ':30:00';
  375. }
  376. break;
  377. default:
  378. break;
  379. }
  380. return $times;
  381. }
  382. function calendar_list_views() {
  383. $calendar_views = array();
  384. $views = views_get_enabled_views();
  385. foreach ($views as $view) {
  386. $displays = array();
  387. $view->init_display(); // Make sure all the handlers are set up
  388. foreach ($view->display as $display_id => $display) {
  389. if ($display_id != 'default' && !empty($display->display_options['style_plugin']) && $display->display_options['style_plugin'] == 'calendar_style') {
  390. $index = $view->name . ':' . $display_id;
  391. $calendar_views[$index] = ucfirst($view->name) . ' ' . strtolower($view->display[$display_id]->display_title) . ' [' . $view->name . ':' . $display_id . ']';
  392. }
  393. }
  394. }
  395. return $calendar_views;
  396. }
  397. /**
  398. * Implementation of hook_block_info()
  399. */
  400. function calendar_block_info() {
  401. $blocks['calendar_legend'] = array(
  402. 'info' => t('Calendar Legend'),
  403. );
  404. return $blocks;
  405. }
  406. /**
  407. * Implementation of hook_block_configure().
  408. */
  409. function calendar_block_configure($delta = '') {
  410. switch ($delta) {
  411. case 'calendar_legend':
  412. $options = calendar_list_views();
  413. $form['calendar_legend_view'] = array(
  414. '#type' => 'select',
  415. '#title' => t('Legend View'),
  416. '#description' => t('Choose the view display that contains the settings for the stripes that should be displayed in a legend in this block. Note that if you change the stripe values in that view you will need to clear the cache to pick up the new values in this block.'),
  417. '#default_value' => variable_get('calendar_legend_view_' . $delta, ''),
  418. '#options' => $options,
  419. );
  420. return $form;
  421. }
  422. }
  423. /**
  424. * Implementation of hook_block_save().
  425. */
  426. function calendar_block_save($delta, $edit = array()) {
  427. if ($delta == 'calendar_legend') {
  428. variable_set('calendar_legend_view_' . $delta, $edit['calendar_legend_view']);
  429. drupal_set_message(t('The view for the calendar legend has been set.'));
  430. }
  431. }
  432. /**
  433. * Implementation of hook_block_view().
  434. */
  435. function calendar_block_view($delta = '') {
  436. switch ($delta) {
  437. case 'calendar_legend':
  438. // Create the content before returning the block
  439. // so empty content won't still create the block.
  440. $view = variable_get('calendar_legend_view_' . $delta, '');
  441. $content = theme('calendar_stripe_legend', array('view' => $view));
  442. $block['subject'] = t('Calendar Legend');
  443. $block['content'] = $content;
  444. return $block;
  445. }
  446. }
  447. /**
  448. * Find the path for the calendar display that has a specific granularity.
  449. */
  450. function calendar_granularity_path(&$view, $granularity) {
  451. $paths = &drupal_static(__FUNCTION__, array());
  452. if (!array_key_exists($view->name, $paths) || !(array_key_exists($granularity, $paths[$view->name]))) {
  453. $paths[$view->name][$granularity] = '';
  454. foreach ($view->display as $id => $display) {
  455. // Check for !empty() in case the view is not fully formed or has displays that are marked to be deleted
  456. if (!empty($display->deleted) || empty($display->display_options['style_plugin']) || (isset($display->display_options['enabled']) && $display->display_options['enabled'] == FALSE)) {
  457. continue;
  458. }
  459. if ($display->display_plugin != 'feed' && !empty($display->display_options['path']) && !empty($display->display_options['arguments'])) {
  460. // Set to the default value, reset below if another value is found.
  461. $type = 'month';
  462. foreach ($display->display_options['arguments'] as $name => $argument) {
  463. if (!empty($argument['granularity'])) {
  464. $type = $argument['granularity'];
  465. }
  466. }
  467. if ($type == $granularity) {
  468. $part_path = $display->display_options['path'];
  469. $parts = explode('/', $part_path);
  470. if (in_array('%', $parts)) {
  471. $current_path = parse_url($_GET['q']);
  472. $current_parts = explode('/', $current_path['path']);
  473. foreach ($parts as $key => $part) {
  474. if ($part == '%' && !empty($current_parts[$key])) {
  475. $parts[$key] = $current_parts[$key];
  476. }
  477. }
  478. $part_path = implode('/', $parts);
  479. }
  480. $paths[$view->name][$granularity] = $part_path;
  481. }
  482. }
  483. }
  484. }
  485. return $paths[$view->name][$granularity];
  486. }
  487. /**
  488. * Check to make sure the user has entered a valid 6 digit hex color.
  489. */
  490. function calendar_validate_hex_color($element, &$form_state) {
  491. if (!$element['#required'] && empty($element['#value'])) {
  492. return;
  493. }
  494. if (!preg_match('/^#(?:(?:[a-f\d]{3}){1,2})$/i', $element['#value'])) {
  495. form_error($element, t("'@color' is not a valid hex color", array('@color' => $element['#value'])));
  496. }
  497. else {
  498. form_set_value($element, $element['#value'], $form_state);
  499. }
  500. }