-
Notifications
You must be signed in to change notification settings - Fork 4
/
calendar.module
561 lines (511 loc) · 18.8 KB
/
calendar.module
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
<?php
define('CALENDAR_SHOW_ALL', 0);
define('CALENDAR_HIDE_ALL', -1);
define('CALENDAR_EMPTY_STRIPE', '#ffffff');
/**
* @file
* Adds calendar filtering and displays to Views.
*/
/**
* Implements hook_menu().
*/
function calendar_menu() {
$items = array();
$items['admin/config/date/calendar'] = array(
'title' => 'Calendar',
'description' => 'Calendar administration.',
'page callback' => 'backdrop_get_form',
'page arguments' => array('calendar_admin_settings'),
'access callback' => 'user_access',
'access arguments' => array('administer site configuration'),
);
return $items;
}
/**
* General Calendar administration.
*/
function calendar_admin_settings() {
$form = array();
$form['#prefix'] = '<h2>Calendar Administration</h2>';
$form['track_date'] = array(
'#title' => t('Track current date in session'),
'#type' => 'radios',
'#options' => array(0 => t("Never"), 1 => t('For authenticated users'), 2 => t('For all users')),
'#default_value' => config_get('calendar.settings','track_date'),
'#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."),
);
// Add a submit button
$form['actions']['#type'] = 'actions';
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Save configuration'),
);
return $form;
}
/**
* Submit handler for module_settings_form().
*/
function calendar_admin_settings_submit($form, &$form_state) {
$config = config('calendar.settings');
$config->set('track_date', $form_state['values']['track_date']);
$config->save();
backdrop_set_message(t('The configuration options have been saved.'));
}
/**
* 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.
* 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;
}
// 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;
}
// If this display has been set up as a default tab, the current path
// is actually the base path, i.e. if the path is 'calendar/month'
// and this is a default tab, the path for this display will actually
// be 'calendar'.
if ($view->display_handler->options['menu']['type'] == 'default tab') {
$parts = explode('/', $current_path);
array_pop($parts);
$current_path = implode('/', $parts);
}
// 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 backdrop_alter() so it can be adjusted in custom code or in the theme.
backdrop_alter('calendar_links', $calendar_links);
// Add the value to the session so it can be used to create the action links.
if (!empty($calendar_links[$current_path])) {
$_SESSION['calendar_links'][$current_path] = $calendar_links[$current_path];
}
}
/**
* Implements hook_date_default_argument_alter().
*
* Adjust the default date for a view based on the stored session value.
*/
function calendar_date_default_argument_alter(&$argument, &$value) {
global $user;
$style_options = $argument->view->display_handler->get_option('style_options');
$tracking = config_get('calendar.settings','track_date');
if (!empty($tracking) && ($tracking == 2 || !empty($user->uid))) {
// If this is a default date, i.e. we are visiting a new calendar display,
// set the default date for the display. See if we already have a session
// date to use. If so, use it. Otherwise the default is the current date.
if (!empty($_SESSION[$argument->view->name]['default_date'])) {
$default_date = $_SESSION[$argument->view->name]['default_date'];
}
else {
$default_date = date_now();
$_SESSION[$argument->view->name]['default_date'] = $default_date;
}
// Get the current date from the session.
$value = $default_date->format($argument->arg_format);
}
}
/**
* Implements hook_views_pre_render().
*
* Track the current date as the user moves from calendar display to calendar display.
*/
function calendar_views_pre_render(&$view) {
global $user;
$style_options = $view->display_handler->get_option('style_options');
$tracking = config_get('calendar.settings','track_date');
if (!empty($tracking) && ($tracking == 2 || !empty($user->uid))) {
foreach ($view->argument as $id => &$argument) {
// If this is not a default date, i.e. we have browsed to a new calendar
// period on a display we were already on, store the midpoint of the current
// view as the current date in a session.
if (date_views_handler_is_date($argument, 'argument') && empty($argument->is_default)) {
$date_range = $argument->date_handler->arg_range($argument->argument);
$session_date = $date_range[0];
$days = intval(($date_range[1]->format('U') - $date_range[0]->format('U')) / 3600 / 24 / 2);
date_modify($session_date, "+$days days");
$_SESSION[$view->name]['default_date'] = $session_date;
}
}
}
}
/**
* Implements hook_menu_local_tasks_alter().
*
* Takes the calendar links created in calendar_preprocess_date_views_pager()
* and reconfigures them as action items. The links can be altered
* before they are displayed using hook_calendar_links_alter().
*/
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.
if (!isset($item['localized_options'])) {
$item['localized_options'] = array();
}
$item['localized_options'] += array('query' => array());
$item['localized_options']['query'] += backdrop_get_destination();
if (array_key_exists('access', $item) && $item['access']) {
$data['actions']['output'][] = array(
'#theme' => 'menu_local_action',
'#link' => $item,
);
}
}
}
}
return;
}
/**
* Implements hook_views_api().
*/
function calendar_views_api() {
return array(
'api' => 3.0,
'path' => backdrop_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("<p>View complete documentation at !link.</p>", array('!link' => l(t('Date and Calendar Documentation'), 'http://drupal.org/node/262062')));
}
}
/**
* Implements hook_theme().
*/
function calendar_theme() {
$module_path = backdrop_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('view' => 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 = config_get('calendar.settings','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__calendar',
'#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':
config_set('calendar.settings','calendar_date_link_' . $bundle, $path);
break;
default:
config_set('calendar.settings','calendar_date_link_' . $entity_type . '_' . $bundle, $path);
break;
}
}
/**
* 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) {
$config = config('calendar.settings');
$settings = $config->get();
// Iterate over all the values and delete them.
foreach ($settings as $key => $value) {
if (is_array($value) || strpos($key, 'calendar_date_link_') === FALSE) {
continue;
}
if (empty($path) || $value == $path) {
$config->clear($key);
}
}
$config->save();
if (isset($_SESSION['calendar_links'][$path]['actions'])) {
unset($_SESSION['calendar_links'][$path]['actions']);
if (empty($_SESSION['calendar_links'][$path])) {
unset($_SESSION['calendar_links'][$path]);
}
}
}
/**
* 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();
$full_translated_days = date_week_days_ordered(date_week_days(TRUE));
if ($len == 99) {
$translated_days = $full_translated_days;
}
else {
$translated_days = date_week_days_ordered(date_week_days_abbr(TRUE));
}
if ($with_week) {
$row[] = array('header' => TRUE, 'class' => "days week", 'data' => ' ', 'header_id' => 'Week');
}
foreach ($untranslated_days as $delta => $day) {
$label = $len < 3 ? backdrop_substr($translated_days[$delta], 0 , $len) : $translated_days[$delta];
$row[] = array('header' => TRUE, 'class' => "days " . $day, 'data' => $label, 'header_id' => $full_translated_days[$delta]);
}
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;
}
function calendar_list_views() {
$calendar_views = array();
$views = views_get_enabled_views();
foreach ($views as $view) {
$displays = array();
$view->init_display(); // Make sure all the handlers are set up
foreach ($view->display as $display_id => $display) {
if ($display_id != 'default' && !empty($display->display_options['style_plugin']) && $display->display_options['style_plugin'] == 'calendar_style') {
$index = $view->name . ':' . $display_id;
$calendar_views[$index] = ucfirst($view->name) . ' ' . strtolower($view->display[$display_id]->display_title) . ' [' . $view->name . ':' . $display_id . ']';
}
}
}
return $calendar_views;
}
/**
* Implementation of hook_block_info()
*/
function calendar_block_info() {
$blocks['calendar_legend'] = array(
'info' => t('Calendar Legend'),
'description' => t('Calendar Legend.'),
);
return $blocks;
}
/**
* Implementation of hook_block_configure().
*/
function calendar_block_configure($delta = '', $settings = array()) {
switch ($delta) {
case 'calendar_legend':
$options = calendar_list_views();
$form['calendar_legend_view'] = array(
'#type' => 'select',
'#title' => t('Legend View'),
'#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.'),
'#default_value' => $settings['calendar_legend_view'],
'#options' => $options,
);
return $form;
}
}
/**
* Implementation of hook_block_save().
*/
function calendar_block_save($delta, &$edit = array()) {
if ($delta == 'calendar_legend') {
backdrop_set_message(t('The view for the calendar legend has been set.'));
}
}
/**
* Implementation of hook_block_view().
*/
function calendar_block_view($delta = '', $settings = array(), $contexts = array()) {
switch ($delta) {
case 'calendar_legend':
// Create the content before returning the block
// so empty content won't still create the block.
$view = $settings['calendar_legend_view'];
$content = theme('calendar_stripe_legend', array('view' => $view));
$block['subject'] = t('Calendar Legend');
$block['content'] = $content;
return $block;
}
}
/**
* Find the path for the calendar display that has a specific granularity.
*/
function calendar_granularity_path(&$view, $granularity) {
$paths = &backdrop_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']) && !empty($display->display_options['arguments'])) {
// Set to the default value, reset below if another value is found.
$type = 'month';
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];
}
/**
* 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);
}
}
/**
* Implements hook_config_info().
*/
function calendar_config_info()
{
$prefixes['calendar.settings'] = array(
'label' => t('Calendar'),
'group' => t('Configuration'),
);
return $prefixes;
}
/**
* Implements hook_autoload_info().
*/
function calendar_autoload_info()
{
return array(
'calendar_plugin_style' => 'includes/calendar_plugin_style.inc',
'calendar_plugin_row' => 'includes/calendar_plugin_row.inc'
);
}