Project

General

Profile

Paste
Download (19.6 KB) Statistics
| Branch: | Revision:

root / drupal7 / sites / all / modules / calendar / calendar.module @ 62e0cc08

1
<?php
2
define('CALENDAR_SHOW_ALL', 0);
3
define('CALENDAR_HIDE_ALL', -1);
4
define('CALENDAR_EMPTY_STRIPE', '#ffffff');
5

    
6
/**
7
 * @file
8
 * Adds calendar filtering and displays to Views.
9
 */
10
/**
11
 * Implements hook_menu().
12
 */
13
function calendar_menu() {
14
  $items = array();
15
  $items['admin/config/date/calendar'] = array(
16
    'title' => 'Calendar',
17
    'description' => 'Calendar administration.',
18
    'page callback' => 'drupal_get_form',
19
    'page arguments' => array('calendar_admin_settings'),
20
    'access callback' => 'user_access',
21
    'access arguments' => array('administer site configuration'),
22
  );
23
  return $items;
24
}
25

    
26
/**
27
 * General Calendar administration.
28
 */
29
function calendar_admin_settings() {
30
  $form = array();
31

    
32
  $form['#prefix']  = '<h2>Calendar Administration</h2>';
33

    
34
  $form['calendar_track_date'] = array(
35
    '#title' => t('Track current date in session'),
36
    '#type' => 'radios',
37
    '#options' => array(0 => t("Never"), 1 => t('For authenticated users'), 2 => t('For all users')),
38
    '#default_value' => variable_get('calendar_track_date', 0),
39
    '#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."),
40
    );
41

    
42
  $form['calendar_add_colorbox'] = array(
43
    '#title' => t('Add Colorbox settings to Node calendar templates'),
44
    '#default_value' => variable_get('calendar_add_colorbox'),
45
    '#type' => 'radios',
46
    '#options' => array(0 => t('No'), 1 => t('Yes')),
47
    '#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.'),
48
    );
49

    
50
  $form['calendar_provide_views_templates'] = array(
51
    '#title' => t('Provide Views templates for calendar'),
52
    '#type' => 'radios',
53
    '#options' => array(0 => t('No'), 1 => t('Yes')),
54
    '#default_value' => variable_get('calendar_provide_views_templates', 1),
55
    '#description' => t("Views calendar templates are created for every date field by default, see !url. You can disable this to improve Views UI performance.",
56
      array('!url' => l(t('Views templates'), 'admin/structure/views/add-template'))),
57
  );
58

    
59
  return system_settings_form($form);
60
}
61

    
62
/**
63
 * Implements hook_preprocess_date_views_pager().
64
 *
65
 * Creates a calendar_links array which is stored in the session and used
66
 * in calendar_menu_local_tasks_alter() to display the links as action items.
67
 * The links can be altered or deleted using hook_calendar_links_alter().
68
 *
69
 */
70
function calendar_preprocess_date_views_pager(&$vars) {
71
  $view = $vars['plugin']->view;
72

    
73
  // If no one has added date information, nothing to do here.
74
  if (empty($view->date_info) || empty($view->argument)) {
75
    return;
76
  }
77

    
78
  // If we're not on a view with a path (a page), no links are needed.
79
  $current_path = !empty($view->display_handler->options['path']) ? $view->display_handler->options['path'] : '';
80
  if (empty($current_path)) {
81
    return;
82
  }
83

    
84
  // If this display has been set up as a default tab, the current path
85
  // is actually the base path, i.e. if the path is 'calendar/month'
86
  // and this is a default tab, the path for this display will actually
87
  // be 'calendar'.
88
  if ($view->display_handler->options['menu']['type'] == 'default tab') {
89
    $parts = explode('/', $current_path);
90
    array_pop($parts);
91
    $current_path = implode('/', $parts);
92
  }
93

    
94
  // If an 'Add new ... link is provided, add it here.
95
  if (!empty($view->date_info->calendar_date_link) && !empty($view->date_info->url)
96
  && (user_access("administer nodes") || user_access('create ' . $view->date_info->calendar_date_link . ' content'))) {
97
    $name = node_type_get_name($view->date_info->calendar_date_link);
98
    $href = 'node/add/' . str_replace('_', '-', $view->date_info->calendar_date_link);
99
    $calendar_links[$current_path]['actions'][] = array('title' => t('Add @name', array('@name' => $name)), 'path' => $href);
100
  }
101

    
102
  // Pass this through drupal_alter() so it can be adjusted in custom code or in the theme.
103
  drupal_alter('calendar_links', $calendar_links);
104

    
105
  // Add the value to the session so it can be used to create the action links.
106
  if (!empty($calendar_links[$current_path])) {
107
    $_SESSION['calendar_links'][$current_path] = $calendar_links[$current_path];
108
  }
109
}
110

    
111
/**
112
 * Implements hook_date_default_argument_alter().
113
 *
114
 * Adjust the default date for a view based on the stored session value.
115
 */
116
function calendar_date_default_argument_alter(&$argument, &$value) {
117
  global $user;
118
  $style_options = $argument->view->display_handler->get_option('style_options');
119
  $tracking = variable_get('calendar_track_date', 0);
120
  if (!empty($tracking) && ($tracking == 2 || !empty($user->uid))) {
121

    
122
    // If this is a default date, i.e. we are visiting a new calendar display,
123
    // set the default date for the display. See if we already have a session
124
    // date to use. If so, use it. Otherwise the default is the current date.
125
    if (!empty($_SESSION[$argument->view->name]['default_date'])) {
126
      $default_date = $_SESSION[$argument->view->name]['default_date'];
127
    }
128
    else {
129
      $default_date = date_now();
130
      $_SESSION[$argument->view->name]['default_date'] = $default_date;
131
    }
132
    // Get the current date from the session.
133
    $value = $default_date->format($argument->arg_format);
134
  }
135
}
136

    
137
/**
138
 * Implements hook_views_pre_render().
139
 *
140
 * Track the current date as the user moves from calendar display to calendar display.
141
 */
142
function calendar_views_pre_render(&$view) {
143
  global $user;
144

    
145
  $style_options = $view->display_handler->get_option('style_options');
146
  $tracking = variable_get('calendar_track_date', 0);
147
  if (!empty($tracking) && ($tracking == 2 || !empty($user->uid))) {
148
    foreach ($view->argument as $id => &$argument) {
149

    
150
      // If this is not a default date, i.e. we have browsed to a new calendar
151
      // period on a display we were already on, store the midpoint of the current
152
      // view as the current date in a session.
153
      if (date_views_handler_is_date($argument, 'argument') && empty($argument->is_default)) {
154
        $date_range = $argument->date_handler->arg_range($argument->argument);
155
        $session_date = $date_range[0];
156
        $days = intval(($date_range[1]->format('U') - $date_range[0]->format('U')) / 3600 / 24 / 2);
157
        date_modify($session_date, "+$days days");
158
        $_SESSION[$view->name]['default_date'] = $session_date;
159
      }
160
    }
161
  }
162
}
163

    
164
/**
165
 * Implements hook_menu_local_tasks_alter().
166
 *
167
 * Takes the calendar links created in calendar_preprocess_date_views_pager()
168
 * and reconfigures them as action items. The links can be altered
169
 * before they are displayed using hook_calendar_links_alter().
170
 */
171
function calendar_menu_local_tasks_alter(&$data, $router_item, $root_path) {
172
  if (!empty($_SESSION['calendar_links']) && array_key_exists($root_path, $_SESSION['calendar_links'])) {
173
    $calendar_data = $_SESSION['calendar_links'][$root_path];
174
    if (!empty($calendar_data['actions'])) {
175
      foreach ($calendar_data['actions'] as $action) {
176
        $item = menu_get_item($action['path']);
177
        $item['title'] = $action['title'];
178
        // The add new content page would redirect to the new event
179
        // if we did not override that here. This way they will
180
        // redirect back to the calendar.
181
	if (!isset($item['localized_options'])) {
182
          $item['localized_options'] = array();
183
        }
184
        $item['localized_options'] += array('query' => array());
185
        $item['localized_options']['query'] += drupal_get_destination();
186
        if (array_key_exists('access', $item) && $item['access']) {
187
          $data['actions']['output'][] = array(
188
            '#theme' => 'menu_local_action',
189
            '#link' => $item,
190
          );
191
        }
192
      }
193
    }
194
  }
195
  return;
196
}
197

    
198
/**
199
 * Implements hook_views_api().
200
 */
201
function calendar_views_api() {
202
  return array(
203
    'api' => 3.0,
204
    'path' => drupal_get_path('module', 'calendar') . '/includes',
205
  );
206
}
207

    
208
/**
209
 * Calendar display types.
210
 */
211
function calendar_display_types() {
212
  return array('year' => t('Year'), 'month' => t('Month'), 'day' => t('Day'), 'week' => t('Week'));
213
}
214

    
215
/**
216
 * Implementation of hook_help().
217
 */
218
function calendar_help($section, $arg) {
219
  switch ($section) {
220
    case 'admin/help#calendar':
221
      return t("<p>View complete documentation at !link.</p>", array('!link' => l(t('Date and Calendar Documentation'), 'http://drupal.org/node/262062')));
222
  }
223
}
224

    
225
/**
226
 * Implements hook_theme().
227
 */
228
function calendar_theme() {
229
  $module_path = drupal_get_path('module', 'calendar');
230

    
231
  $base = array(
232
    'file' => 'theme.inc',
233
    'path' => "$module_path/theme",
234
  );
235
  return array(
236
    'calendar_item' => $base + array(
237
      'template' => 'calendar-item',
238
      'variables' => array('view' => NULL, 'rendered_fields' => NULL, 'item' => NULL),
239
      ),
240
    'calendar_datebox' => $base + array(
241
      'template' => 'calendar-datebox',
242
      'variables' => array(
243
        'date' => NULL, 'view' => NULL, 'items' => NULL, 'selected' => NULL),
244
      ),
245
    'calendar_empty_day' => $base + array(
246
      'variables' => array('curday' => NULL, 'view' => NULL),
247
      ),
248
    'calendar_stripe_legend' => $base + array(
249
      'variables' => array('view' => NULL),
250
      ),
251
    'calendar_stripe_stripe' => $base + array(
252
      'variables' => array('node' => NULL),
253
      ),
254
    'calendar_time_row_heading' => $base + array(
255
      'variables' => array('start_time' => NULL, 'next_start_time' => NULL, 'curday_date' => NULL),
256
      ),
257
    'calendar_month_col' => $base + array(
258
      'template' => 'calendar-month-col',
259
      'variables' => array('item' => NULL),
260
      ),
261
    'calendar_month_row' => $base + array(
262
      'template' => 'calendar-month-row',
263
      'variables' => array('inner' => NULL, 'class' => NULL, 'iehint' => NULL),
264
      ),
265
    'calendar_month_multiple_entity' => $base + array(
266
      'template' => 'calendar-month-multiple-entity',
267
      'variables' => array('
268
         curday' => NULL, 'count' => NULL, 'view' => NULL, 'ids' => NULL),
269
      ),
270
    );
271
}
272

    
273
/**
274
 * Implements hook_node_view().
275
 *
276
 * Add link to calendar to nodes, formerly hook_link().
277
 * Controlled by value of 'calendar_date_link' in the view.
278
 */
279
function calendar_node_view($node, $view_mode, $langcode) {
280
  $path = variable_get('calendar_date_link_' . $node->type);
281
  if (!empty($path)) {
282
    $links['calendar_link'] = array(
283
      'title' => t('Calendar'),
284
      'href' => $path,
285
      'attributes' => array('title' => t('View the calendar.')),
286
    );
287
    $node->content['links']['calendar'] = array(
288
      '#theme' => 'links__node__calendar',
289
      '#links' => $links,
290
      '#attributes' => array('class' => array('links', 'inline')),
291
    );
292
  }
293
}
294

    
295
/**
296
 * Helper function to link an entity type to a calendar.
297
 *
298
 * @param $entity_type - the type of entity.
299
 * @param $bundle - the entity bundle name.
300
 * @param $path - the calendar path to use for this bundle.
301
 */
302
function calendar_set_link($entity_type, $bundle, $path) {
303
  switch ($entity_type) {
304
    case 'node':
305
      variable_set('calendar_date_link_' . $bundle, $path);
306
      break;
307
    default:
308
      variable_set('calendar_date_link_' . $entity_type . '_' . $bundle, $path);
309
      break;
310
  }
311
}
312

    
313
/**
314
 * Helper function to clear previously-set links to calendars.
315
 *
316
 * @param $bundle, Clear all links for this bundle. If NULL, clear all links.
317
 */
318
function calendar_clear_link_bundle($bundle = NULL) {
319
  if (empty($bundle)) {
320
    $result = db_select('variable', 'v')
321
      ->fields('v', 'name')
322
      ->condition('name', 'calendar_date_link_%', 'LIKE')
323
      ->execute()->fetchAll(PDO::FETCH_ASSOC);
324
  }
325
  else {
326
    $result = db_select('variable', 'v')
327
      ->fields('v', 'name')
328
      ->condition('name', 'calendar_date_link_' . $bundle)
329
      ->execute()->fetchAll(PDO::FETCH_ASSOC);
330
  }
331
  // Iterate over all the values and delete them.
332
  foreach ($result as $row) {
333
    variable_del($row['name']);
334
  }
335
}
336

    
337
/**
338
 * Helper function to clear previously-set links to calendars.
339
 *
340
 * @param $path, Clear all links to this path. If NULL, clear all links.
341
 */
342
function calendar_clear_link_path($path = NULL) {
343
  $result = db_select('variable', 'v')
344
    ->fields('v', array('name', 'value'))
345
    ->condition('name', 'calendar_date_link_%', 'LIKE')
346
    ->execute()->fetchAll(PDO::FETCH_ASSOC);
347
  // Iterate over all the values and delete them.
348
  foreach ($result as $row) {
349
    if (empty($path) || unserialize($row['value']) == $path) {
350
      variable_del($row['name']);
351
    }
352
  }
353
  if (isset($_SESSION['calendar_links'][$path]['actions'])) {
354
    unset($_SESSION['calendar_links'][$path]['actions']);
355
    if (empty($_SESSION['calendar_links'][$path])) {
356
      unset($_SESSION['calendar_links'][$path]);
357
    }
358
  }
359
}
360

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

    
371
  // create week header
372
  $untranslated_days = calendar_untranslated_days();
373
  $full_translated_days = date_week_days_ordered(date_week_days(TRUE));
374
  if ($len == 99) {
375
    $translated_days = $full_translated_days;
376
  }
377
  else {
378
    $translated_days = date_week_days_ordered(date_week_days_abbr(TRUE));
379
  }
380
  if ($with_week) {
381
    $row[] = array('header' => TRUE, 'class' => "days week", 'data' => '&nbsp;', 'header_id' => 'Week');
382
  }
383
  foreach ($untranslated_days as $delta => $day) {
384
    $label = $len < 3 ? drupal_substr($translated_days[$delta], 0 , $len) : $translated_days[$delta];
385
    $row[] = array('header' => TRUE, 'class' => "days " . $day, 'data' => $label, 'header_id' => $full_translated_days[$delta]);
386
  }
387
  return $row;
388
}
389

    
390
/**
391
 * Array of untranslated day name abbreviations, forced to lowercase
392
 * and ordered appropriately for the site setting for the first day of week.
393
 *
394
 * The untranslated day abbreviation is used in css classes.
395
 */
396
function calendar_untranslated_days() {
397
  $untranslated_days = date_week_days_ordered(date_week_days_untranslated());
398
  foreach ($untranslated_days as $delta => $day) {
399
    $untranslated_days[$delta] = strtolower(substr($day, 0, 3));
400
  }
401
  return $untranslated_days;
402
}
403

    
404
/**
405
 * Default settings array for calendar time grouping.
406
 */
407
function calendar_groupby_times($type = '') {
408
  $times = array();
409
  switch ($type) {
410
    case 'hour':
411
      for ($i = 0; $i <= 23; $i++) {
412
        $times[] = date_pad($i) . ':00:00';
413
      }
414
      break;
415
    case 'half':
416
      for ($i = 0; $i <= 23; $i++) {
417
        $times[] = date_pad($i) . ':00:00';
418
        $times[] = date_pad($i) . ':30:00';
419
      }
420
      break;
421
    default:
422
      break;
423
  }
424
  return $times;
425
}
426

    
427
function calendar_list_views() {
428
  $calendar_views = array();
429
  $views = views_get_enabled_views();
430
  foreach ($views as $view) {
431
    $displays = array();
432
    $view->init_display();   // Make sure all the handlers are set up
433
    foreach ($view->display as $display_id => $display) {
434
      if ($display_id != 'default' && !empty($display->display_options['style_plugin']) && $display->display_options['style_plugin'] == 'calendar_style') {
435
        $index = $view->name . ':' . $display_id;
436
        $calendar_views[$index] = ucfirst($view->name) . ' ' . strtolower($view->display[$display_id]->display_title) . ' [' . $view->name . ':' . $display_id . ']';
437
      }
438
    }
439
  }
440
  return $calendar_views;
441
}
442

    
443
/**
444
 *  Implementation of hook_block_info()
445
 */
446
function calendar_block_info() {
447
  $blocks['calendar_legend'] = array(
448
    'info' => t('Calendar Legend'),
449
  );
450
  return $blocks;
451
}
452

    
453
/**
454
 * Implementation of hook_block_configure().
455
 */
456
function calendar_block_configure($delta = '') {
457
  switch ($delta) {
458
    case 'calendar_legend':
459
    $options = calendar_list_views();
460
    $form['calendar_legend_view'] = array(
461
      '#type' => 'select',
462
      '#title' => t('Legend View'),
463
      '#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.'),
464
      '#default_value' => variable_get('calendar_legend_view_' . $delta, ''),
465
      '#options' => $options,
466
    );
467
    return $form;
468
  }
469
}
470

    
471
/**
472
 * Implementation of hook_block_save().
473
 */
474
function calendar_block_save($delta, $edit = array()) {
475
  if ($delta == 'calendar_legend') {
476
    variable_set('calendar_legend_view_' . $delta, $edit['calendar_legend_view']);
477
    drupal_set_message(t('The view for the calendar legend has been set.'));
478
  }
479
}
480

    
481
/**
482
 *  Implementation of hook_block_view().
483
 */
484
function calendar_block_view($delta = '') {
485
  switch ($delta) {
486
    case 'calendar_legend':
487
      // Create the content before returning the block
488
      // so empty content won't still create the block.
489
      $view = variable_get('calendar_legend_view_' . $delta, '');
490
      $content = theme('calendar_stripe_legend', array('view' => $view));
491
      $block['subject'] = t('Calendar Legend');
492
      $block['content'] = $content;
493
      return $block;
494
  }
495
}
496

    
497
/**
498
 * Find the path for the calendar display that has a specific granularity.
499
 */
500
function calendar_granularity_path(&$view, $granularity) {
501
  $paths = &drupal_static(__FUNCTION__, array());
502
  if (!array_key_exists($view->name, $paths) || !(array_key_exists($granularity, $paths[$view->name]))) {
503
    $paths[$view->name][$granularity] = '';
504
    foreach ($view->display as $id => $display) {
505
      // Check for !empty() in case the view is not fully formed or has displays that are marked to be deleted
506
      if (!empty($display->deleted) || empty($display->display_options['style_plugin']) || (isset($display->display_options['enabled']) && $display->display_options['enabled'] == FALSE)) {
507
        continue;
508
      }
509

    
510
      if ($display->display_plugin != 'feed' && !empty($display->display_options['path']) && !empty($display->display_options['arguments'])) {
511

    
512
        // Set to the default value, reset below if another value is found.
513
        $type = 'month';
514
        foreach ($display->display_options['arguments'] as $name => $argument) {
515
          if (!empty($argument['granularity'])) {
516
            $type = $argument['granularity'];
517
          }
518
        }
519

    
520
        if ($type == $granularity) {
521
          $part_path =  $display->display_options['path'];
522
          $parts = explode('/', $part_path);
523
          if (in_array('%', $parts)) {
524
            $current_path = parse_url($_GET['q']);
525
            $current_parts = explode('/', $current_path['path']);
526
            foreach ($parts as $key => $part) {
527
              if ($part == '%' && !empty($current_parts[$key])) {
528
                $parts[$key] = $current_parts[$key];
529
              }
530
            }
531
            $part_path = implode('/', $parts);
532
          }
533
          $paths[$view->name][$granularity] = $part_path;
534
        }
535
      }
536
    }
537
  }
538
  return $paths[$view->name][$granularity];
539
}
540

    
541
/**
542
 *  Check to make sure the user has entered a valid 6 digit hex color.
543
 */
544
function calendar_validate_hex_color($element, &$form_state) {
545
  if (!$element['#required'] && empty($element['#value'])) {
546
    return;
547
  }
548
  if (!preg_match('/^#(?:(?:[a-f\d]{3}){1,2})$/i', $element['#value'])) {
549
    form_error($element, t("'@color' is not a valid hex color", array('@color' => $element['#value'])));
550
  }
551
  else {
552
    form_set_value($element, $element['#value'], $form_state);
553
  }
554
}