/[drupal]/contributions/modules/event/event.module
ViewVC logotype

Contents of /contributions/modules/event/event.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.405 - (show annotations) (download) (as text)
Sun Jul 5 00:34:15 2009 UTC (4 months, 3 weeks ago) by killes
Branch: MAIN
CVS Tags: HEAD
Changes since 1.404: +5 -3 lines
File MIME type: text/x-php
#440670, fix issues with timezones which affected ical
1 <?php
2 // $Id: event.module,v 1.404 2009/06/05 20:39:03 killes Exp $
3
4 define('EVENT_API', '5.2');
5 define('EVENT_PATH', drupal_get_path('module', 'event'));
6
7 /**
8 * Includes files needed for this module
9 * @ingroup event_support
10 */
11 function event_include_files() {
12 include_once(EVENT_PATH .'/event.theme');
13 global $db_type;
14 include_once(EVENT_PATH ."/event_database.$db_type.inc");
15
16 if (file_exists($file = path_to_theme() .'/event.css')) {
17 drupal_add_css($file);
18 }
19 else {
20 drupal_add_css(EVENT_PATH .'/event.css');
21 }
22 }
23
24 /**
25 * @defgroup event_core Core drupal hooks
26 */
27
28 /**
29 * Implementation of hook_theme()
30 * @ingroup event_core
31 */
32 function event_theme() {
33 event_include_files();
34 return array(
35 'event' => array(
36 'arguments' => array('element' => NULL),
37 'file' => 'event.theme',
38 ),
39 'event_calendar_month' => array(
40 'arguments' => array('op' => NULL, 'header' => NULL, 'rows' => NULL, 'attributes' => NULL, 'caption' => NULL)),
41 'event_calendar_week' => array(
42 'arguments' => array('op' => NULL, 'header' => NULL, 'rows' => NULL, 'attributes' => NULL, 'caption' => NULL)),
43 'event_calendar_day' => array(
44 'arguments' => array('op' => NULL, 'header' => NULL, 'rows' => NULL, 'attributes' => NULL, 'caption' => NULL)),
45 'event_calendar_table' => array(
46 'arguments' => array('op' => NULL, 'header' => NULL, 'rows' => NULL, 'attributes' => NULL, 'caption' => NULL)),
47 'event_calendar_list' => array(
48 'template' => 'event-calendar-list',
49 'arguments' => array('op' => NULL, 'header' => NULL, 'rows' => NULL)),
50 'event_node_day' => array(
51 'template' => 'event-node-day',
52 'arguments' => array('node' => NULL),
53 ),
54 'event_node_week' => array(
55 'template' => 'event-node-week',
56 'arguments' => array('node' => NULL),
57 ),
58 'event_node_month' => array(
59 'template' => 'event-node-month',
60 'arguments' => array('node' => NULL),
61 ),
62 'event_node_table' => array(
63 'template' => 'event-node-table',
64 'arguments' => array('node' => NULL),
65 ),
66 'event_node_list' => array(
67 'template' => 'event-node-list',
68 'arguments' => array('node' => NULL),
69 ),
70 'event_calendar_date_box' => array('arguments' => array('date' => NULL, 'view' => NULL)),
71 'event_empty_day' => array('arguments' => array('date' => NULL, 'view' => NULL)),
72 'event_nodeapi' => array(
73 'template' => 'event-nodeapi',
74 'arguments' => array('node' => NULL)
75 ),
76 'event_filter_control' => array('arguments' => array('form' => NULL)),
77 'event_nav_next' => array('arguments' => array('url' => NULL, 'attributes' => NULL)),
78 'event_nav_prev' => array('arguments' => array('url' => NULL, 'attributes' => NULL)),
79 'event_nav_stop_next' => array('arguments' => array('text' => NULL)),
80 'event_nav_stop_prev' => array('arguments' => array('text' => NULL)),
81 'event_links' => array('arguments' => array('links' => NULL, 'view' => NULL)),
82 'event_ical_link' => array('arguments' => array('path' => NULL)),
83 'event_more_link' => array('arguments' => array('path' => NULL)),
84 'event_upcoming_item' => array('arguments' => array('node' => NULL, 'types' => NULL)),
85 'event_upcoming_block' => array('arguments' => array('items' => NULL)),
86 );
87 }
88
89 /**
90 * Implementation of hook_elements()
91 * @ingroup event_core
92 */
93 function event_elements() {
94 $type['event'] = array('#input' => TRUE, '#process' => array('expand_event'), '#element_validate' => array('event_validate'));
95 return $type;
96 }
97
98 /**
99 * Provides the links that should be displayed when viewing events.
100 *
101 * @ingroup event_core
102 * @param $type the type of link (for example, 'node', 'page', or 'system') being requested
103 * @param $node the node that is requesting the link. This is used in conjunction with $type to further determine
104 * what sort of link to display.
105 * @param $main unused in this method.
106 * @return an array of links, or an empty array if no links apply for the criteria passed to this method.
107 */
108 function event_link($type, $node = NULL, $teaser = FALSE) {
109 $links = array();
110
111 if ($type == 'node') {
112 // node links
113 if (event_enabled_state($node->type) == 'all') {
114 $links['event_calendar'] = array('title' => t('Calendar'), 'href' => 'event/'. _event_format_url($node->event['start_exploded']));
115 }
116 elseif (event_enabled_state($node->type) == 'solo') {
117 $links['event_calendar'] = array('title' => t('Calendar'), 'href' => 'event/'. _event_format_url($node->event['start_exploded']) .'/month/'. $node->type);
118 }
119 }
120 elseif (user_access('access content')) {
121 // calendar links
122 // build a full list of links...
123 $base = 'event/'. _event_format_url($node->event['start_exploded']) .'/';
124 if (!isset($node->filter)) {
125 $node->filter = '';
126 }
127 $links['event_month'] = array('title' => t('Month'),
128 'href' => $base .'month/'. $node->filter,
129 'attributes' => array('title' => t('Month view')));
130 $links['event_week'] = array('title' => t('Week'),
131 'href' => $base .'week/'. $node->filter,
132 'attributes' => array('title' => t('Week view')));
133 $links['event_day'] = array('title' => t('Day'),
134 'href' => $base .'day/'. $node->filter,
135 'attributes' => array('title' => t('Day view')));
136 $links['event_table'] = array('title' => t('Table'),
137 'href' => $base .'table/'. $node->filter,
138 'attributes' => array('title' => t('Table view')));
139 $links['event_list'] = array('title' => t('List'),
140 'href' => $base .'list/'. $node->filter,
141 'attributes' => array('title' => t('List view')));
142
143 // ...then subtract out the one we're viewing.
144 switch ($type) {
145 case 'event_month':
146 unset($links['event_month']);
147 break;
148 case 'event_week':
149 unset($links['event_week']);
150 break;
151 case 'event_day':
152 unset($links['event_day']);
153 break;
154 case 'event_table':
155 unset($links['event_table']);
156 break;
157 case 'event_list':
158 unset($links['event_list']);
159 break;
160 default:
161 $links = array();
162 }
163 }
164
165 return $links;
166 }
167
168 /**
169 * Implementation of hook_menu()
170 *
171 * @ingroup event_core
172 */
173 function event_menu() {
174 $items = array();
175 $items['event'] = array(
176 'title' => 'Events',
177 'page callback' => 'event_page',
178 'access callback' => 'user_access',
179 'access arguments' => array('access content'),
180 'file' => 'ical.inc',
181 'type' => MENU_SUGGESTED_ITEM
182 );
183 $items['event/type'] = array(
184 'title' => 'Filter by content type',
185 'page callback' => 'event_type',
186 'access callback' => 'user_access',
187 'access arguments' => array('access content'),
188 'type' => MENU_CALLBACK
189 );
190 $items['event/term'] = array(
191 'title' => 'Filter by taxonomy',
192 'page callback' => 'event_term',
193 'access callback' => 'user_access',
194 'access arguments' => array('access content'),
195 'type' => MENU_CALLBACK
196 );
197 $items['event/feed'] = array(
198 'title' => 'Event rss feed',
199 'page callback' => 'event_feed',
200 'access callback' => 'user_access',
201 'access arguments' => array('access content'),
202 'type' => MENU_CALLBACK
203 );
204 $items['event/dst'] = array(
205 'title' => 'Event dst view',
206 'page callback' => 'event_dst',
207 'access callback' => 'user_access',
208 'access arguments' => array('access content'),
209 'type' => MENU_CALLBACK
210 );
211 $items['event/ical'] = array(
212 'title' => 'Event ical feed',
213 'page callback' => 'event_ical',
214 'access callback' => 'user_access',
215 'access arguments' => array('access content'),
216 'file' => 'ical.inc',
217 'type' => MENU_CALLBACK
218 );
219 $items['admin/settings/event'] = array(
220 'title' => 'Events',
221 'page callback' => 'system_admin_menu_block_page',
222 'description' => 'Set up how your site handles events.',
223 'access callback' => 'user_access',
224 'access arguments' => array('administer site configuration'),
225 'file' => 'system.admin.inc',
226 'file path' => drupal_get_path('module', 'system')
227 );
228 $items['admin/settings/event/timezone'] = array(
229 'title' => 'Timezone handling',
230 'page callback' => 'drupal_get_form',
231 'page arguments' => array('event_admin_timezone_settings'),
232 'description' => 'Change how timezone information is saved and displayed.',
233 'access callback' => 'user_access',
234 'access arguments' => array('administer site configuration')
235 );
236 $items['admin/settings/event/overview'] = array(
237 'title' => 'Event overview',
238 'page callback' => 'drupal_get_form',
239 'page arguments' => array('event_admin_overview_settings'),
240 'description' => 'Change how event summary information is displayed.',
241 'access callback' => 'user_access',
242 'access arguments' => array('administer site configuration')
243 );
244
245 // http://drupalbin.com/312
246 $items['node/%/ical'] = array(
247 'title' => 'Event ical',
248 'page callback' => 'event_node_ical',
249 'access callback' => 'event_ical_access',
250 'access arguments' => array(1),
251 'file' => 'ical.inc',
252 'type' => MENU_CALLBACK
253 );
254 return $items;
255 }
256
257 /*
258 * Access function for node/%/ical
259 */
260 function event_ical_access($nid) {
261 $type = db_result(db_query("SELECT n.type FROM {node} n WHERE n.nid = %d", $nid));
262 return user_access('access content') && event_is_enabled($type);
263 }
264
265 /**
266 * Implementation of hook_user.
267 * @ingroup event_core
268 */
269 function event_user($type, &$edit, &$user) {
270 if ($type == 'login') {
271 if (!$user->timezone_id && is_numeric($user->timezone)) {
272 // Lookup TZ ID based on TZ offset
273 $timezone_id = event_timezone_map($user->timezone);
274 // Update all users with the same offset.
275 db_query('UPDATE {users} SET timezone_id = %d WHERE timezone = %d AND timezone_id = 0', $timezone_id, $user->timezone);
276 }
277 }
278 }
279
280 /**
281 * Displays and allows an administrator to change the timezone settings for this module.
282 *
283 * @ingroup event_core
284 * @return the content for the timezone settings page.
285 */
286 function event_admin_timezone_settings() {
287
288 if (variable_get('configurable_timezones', 0)) {
289 $form['event_timezone_input'] = array(
290 '#type' => 'radios',
291 '#title' => t('Event time zone input'),
292 '#default_value' => variable_get('event_timezone_input', 'site'),
293 '#options' => array('site' => t('Use the sitewide time zone'), 'user' => t('Use the time zone of the user editing or creating the event'), 'input' => t('Allow users to set event time zones')),
294 '#description' => t('Events are saved with a time zone value. This setting allows you to determine how the time zone is determined when creating or editing an event.'),
295 '#required' => TRUE);
296
297 $form['event_timezone_display'] = array(
298 '#type' => 'radios',
299 '#title' => t('Event time zone display'),
300 '#default_value' => variable_get('event_timezone_display', 'event'),
301 '#options' => array('event' => t("Use the event's time zone"), 'user' => t("Use the user's time zone"), 'site' => t('Use the sitewide time zone')),
302 '#description' => t("Events are saved with a time zone value. This setting allows you to determine if the event's time zone, the sitewide time zone, or the user's personal time zone setting is used to display the time for an event."),
303 '#required' => TRUE);
304 }
305 else {
306 if (variable_get('event_timezone_input', 'site') == 'user') {
307 variable_set('event_timezone_input', 'site');
308 }
309 variable_set('event_timezone_display', 'event');
310
311 $form['event_timezone_input'] = array(
312 '#type' => 'radios',
313 '#title' => t('Event time zone input'),
314 '#default_value' => variable_get('event_timezone_input', 'site'),
315 '#options' => array('site' => t('Use the sitewide time zone'), 'user' => t('Use the time zone of the user editing or creating the event'), 'input' => t('Allow users to set event time zones')),
316 '#description' => t("Events are saved with a time zone value. This setting allows you to determine how the time zone is determined when creating or editing an event. You must have 'Configurable time zones' enabled in the !url before you can enable user's time zones for this feature.", array('!url' => l(t('date/time settings'), 'admin/settings/date-time'))),
317 '#required' => TRUE);
318
319 $form['event_timezone_display'] = array(
320 '#type' => 'radios',
321 '#title' => t('Event time zone display'),
322 '#default_value' => variable_get('event_timezone_display', 'event'),
323 '#options' => array('event' => t("Use the event's time zone"), 'site' => t('Use the sitewide time zone')),
324 '#description' => t("Events are saved with a time zone value. This setting allows you to determine if the event's time zone, the sitewide time zone, or the user's personal time zone setting is used to display the time for an event. You must have 'Configurable time zones' enabled in the !url before you can enable user's time zones for this feature.", array('!url' => l(t('date/time settings'), 'admin/settings/date-time'))),
325 '#required' => TRUE);
326 }
327 $form['event_ampm'] = array(
328 '#type' => 'radios',
329 '#title' => t('Time notation preference'),
330 '#default_value' => variable_get('event_ampm', '0'),
331 '#options' => array('0' => t('24h'), '1' => t('12h')),
332 '#description' => t('The time notation system used for entering event times.'),
333 '#required' => TRUE);
334
335 return system_settings_form($form);
336 }
337
338 /**
339 * Displays and allows an administrator to change the user overview settings for this module.
340 *
341 * @ingroup event_core
342 * @return the content for the user overview settings page.
343 */
344 function event_admin_overview_settings() {
345
346 $form['event_upcoming_limit'] = array(
347 '#type' => 'textfield',
348 '#title' => t('Upcoming event block limit'),
349 '#default_value' => variable_get('event_upcoming_limit', '6'),
350 '#maxlength' => 5,
351 '#size' => 2,
352 '#description' => t('Limit the amount of events displayed in the upcoming events block by this amount.'));
353
354 $form['event_overview'] = array(
355 '#type' => 'radios',
356 '#title' => t('Default overview'),
357 '#default_value' => variable_get('event_overview', 'month'),
358 '#options' => array('day' => t('Day'), 'week' => t('Week'), 'month' => t('Month'), 'table' => t('Table'), 'list' => t('List')),
359 '#description' => t('The default event view to display when no format is specifically requested. This is also the view that will be displayed from the block calendar links.'));
360 $form['event_table_duration'] = array(
361 '#type' => 'textfield',
362 '#title' => t('Table view default period'),
363 '#default_value' => variable_get('event_table_duration', '30'),
364 '#maxlength' => 5,
365 '#size' => 3,
366 '#description' => t('The default number of days to display in the table view. You can specify a different number of days in the url. More info on the event url format !link', array('!link' => l(t('here'), 'admin/help/event#url-format'))));
367
368 if (module_exists('taxonomy')) {
369 $form['event_taxonomy_control'] = array(
370 '#type' => 'radios',
371 '#title' => t('Taxonomy filter controls'),
372 '#default_value' => variable_get('event_taxonomy_control', 'all'),
373 '#options' => array('all' => t('Show taxonomy filter control on calendar views'), 'request' => t('Only show taxonomy filter control when taxonomy filter view is requested'), 'never' => t('Never show taxonomy filter control')));
374 }
375 $form['event_type_control'] = array(
376 '#type' => 'radios',
377 '#title' => t('Content type filter controls'),
378 '#default_value' => variable_get('event_type_control', 'all'),
379 '#options' => array('all' => t('Show content type filter control on calendar views'), 'request' => t('Only show content type filter control when content type filter view is requested'), 'never' => t('Never show content type filter control')));
380
381 return system_settings_form($form);
382 }
383
384 /**
385 * @defgroup event_callback Functions which are the menu callbacks for this module
386 */
387
388 /**
389 * Displays a page containing event information. The page layout defaults to a
390 * graphical calendar.
391 *
392 * @ingroup event_callback
393 * @return the content for the event page.
394 */
395 function event_page($year = NULL, $month = NULL, $day = NULL, $view = NULL, $types = NULL, $tids = NULL, $duration = NULL) {
396 event_include_files();
397
398 // get local date value
399 $now = _event_user_date();
400
401 // date values
402 $year = (isset($year) && is_numeric($year)) ? $year : $now['year'];
403 $month = (isset($month) && is_numeric($month)) ? $month : $now['month'];
404 $day = (isset($day) && is_numeric($day)) ? $day : $now['day'];
405
406 $date = $now;
407 $date['year'] = $year;
408 $date['month'] = $month;
409 $date['day'] = $day;
410 $date['second'] = '00';
411 $view = $view ? $view : variable_get('event_overview', 'month');
412 if (isset($_POST['event_type_select'])) {
413 drupal_goto('event/'. $year .'/'. $month .'/'. $day .'/'. $view .'/'. check_plain($_POST['event_type_select']) .'/'. $tids .'/'. check_plain($duration));
414 }
415
416 if (isset($_POST['event_term_select'])) {
417 drupal_goto('event/'. $year .'/'. $month .'/'. $day .'/'. $view .'/'. ($types ? $types : 'all') .'/'. check_plain($_POST['event_term_select']) .'/'. check_plain($duration));
418 }
419
420 $breadcrumbs[] = l(t('Home'), NULL);
421 $breadcrumbs[] = l(t('Events'), 'event');
422 $links = array();
423 $filter = array();
424
425 if (!empty($types)) {
426 // The '+' character in a query string may be parsed as ' '.
427 $types = preg_split('/[+ ]/', $types);
428 foreach ($types as $type) {
429 if ($name = node_get_types('name', $type)) {
430 $x = module_invoke($type, 'node_name', $node);
431 $temp[$x] = $type;
432 $filter[] = module_invoke($type, 'node_name', $node);
433 }
434 }
435
436 if (!empty($filter)) {
437 $links['event_all'] = array('title' => t('View all'), 'href' => 'event/'. $year .'/'. $month .'/'. $day .'/'. $view .'/');
438 $title = t('Filter') .': '. implode(', ', $filter);
439 $types = $temp;
440 }
441 else {
442 $types = null;
443 $title = '';
444 }
445 }
446
447 $terms = null;
448 if (!empty($tids) && $tids != 'all') {
449 $links['event_all'] = array('title' => t('View all'), 'href' => 'event/'. $year .'/'. $month .'/'. $day .'/day');
450 if (preg_match('/^([0-9]+[+ ])+[0-9]+$/', $tids)) {
451 // The '+' character in a query string may be parsed as ' '.
452 $terms = preg_split('/[+ ]/', $tids);
453 }
454 else if (preg_match('/^([0-9]+,)*[0-9]+$/', $tids)) {
455 $terms = explode(',', $tids);
456 }
457 }
458
459 $output = '';
460
461 // add taxonomy filter controls to top of calendar
462 if (variable_get('event_taxonomy_control', 'all') == 'all' || (variable_get('event_taxonomy_control', 'all') == 'request' && isset($terms))) {
463 $output .= _event_get_taxonomy_control($terms);
464 }
465 // add content type filter controls to top of calendar
466 if (variable_get('event_type_control', 'all') == 'all' || (variable_get('event_type_control', 'all') == 'request' && isset($types))) {
467 $output .= _event_get_type_control($types);
468 }
469
470 switch ($view) {
471 case 'day':
472 // day view
473 $caption = event_format_date($date, 'custom', t('l F d, Y'));
474 list($thead, $tbody) = event_calendar_day('page', $date, $types, $terms);
475 $ical_date = $date;
476 $duration = 1;
477 break;
478 case 'week':
479 // week view
480 // setup calendar table header
481 $dow = _event_day_of_week($date);
482 $start_date = event_date_later($date, -1 * $dow);
483 $temp = event_format_date($start_date, 'custom', 'F-j-Y');
484 $temp = explode('-', $temp);
485 $caption = t('Week of !month !day, !year', array('!month' => $temp[0], '!day' => $temp[1], '!year' => $temp[2]));
486 $colspan = 5;
487 list($thead, $tbody) = event_calendar_week('page', $date, $types, $terms);
488 $ical_date = $start_date;
489 $ical_date['hour'] = '00';
490 $ical_date['minute'] = '00';
491 $ical_date['second'] = '00';
492 $ical_duration = 7;
493 break;
494 case 'month':
495 // month view
496 $caption = event_format_date($date, 'custom', t('F Y'));
497 $colspan = 5;
498 list($thead, $tbody) = event_calendar_month('page', $date, $types, $terms);
499 $ical_date = $date;
500 $ical_date['day'] = '01';
501 $ical_date['hour'] = '00';
502 $ical_date['minute'] = '00';
503 $ical_date['second'] = '00';
504 $ical_duration = date('t', mktime(0, 0, 0, $date['month'], 1, $date['year']));
505 break;
506 case 'table':
507 // table view
508 // next 30 day view, $duration can be set for different ranges
509 // but set a maximum $duration of 1 year.
510 $duration = $duration && $duration <= 366 ? $duration : variable_get('event_table_duration', '30');
511 $end_date = event_date_later($date, $duration);
512 $caption = event_format_date($date, 'custom', t('F d Y')) .' - '. event_format_date($end_date, 'custom', t('F d Y'));
513 list($thead, $tbody) = event_calendar_table('page', $date, $end_date, $types, $terms);
514 $ical_date = $date;
515 $ical_duration = $duration;
516 $ical_date['hour'] = '00';
517 $ical_date['minute'] = '00';
518 $ical_date['second'] = '00';
519 break;
520 case 'list':
521 // list view
522 // next 30 day view, $duration can be set for different ranges
523 // but set a maximum $duration of 1 year.
524 $duration = $duration && $duration <= 366 ? $duration : variable_get('event_table_duration', '30');
525 $end_date = event_date_later($date, $duration);
526 $caption = event_format_date($date, 'custom', t('F d Y')) .' - '. event_format_date($end_date, 'custom', t('F d Y'));
527 $tbody = event_calendar_list('page', $date, $end_date, $types, $terms);
528 $ical_date = $date;
529 $ical_duration = $duration;
530 $ical_date['hour'] = '00';
531 $ical_date['minute'] = '00';
532 $ical_date['second'] = '00';
533 break;
534 case 'feed':
535 // rss feed
536 drupal_set_header('Content-Type: text/xml; charset=utf-8');
537 $duration = $duration ? $duration : variable_get('event_table_duration', '30');
538 print event_calendar_rss($date, $duration, $types, $terms, $title);
539 break;
540 case 'ical':
541 // ical feed
542 drupal_set_header('Content-Type: text/calendar; charset=utf-8');
543 drupal_set_header('Content-Disposition: attachment; filename="calendar.ics"; ');
544 $duration = $duration ? $duration : variable_get('event_table_duration', '30');
545 print event_calendar_ical($date, $duration, $types, $terms, $title);
546 break;
547 case 'block':
548 // block update
549 $date = _event_user_date();
550 if (arg(0) == 'event' && is_numeric(arg(1))) {
551 // follow event calendar
552 $date['year'] = (arg(1) ? arg(1) : $time['year']);
553 $date['month'] = (arg(2) ? arg(2) : $time['month']);
554 $date['day'] = (arg(3) ? arg(3) : $time['day']);
555 }
556 print event_calendar_month('block', $date);
557 break;
558 }
559
560 if ($view != 'feed' && $view != 'ical' && $view != 'block') {
561 // build header navigation
562 $prev = _event_nav($date, 'prev', $view, $types, $terms, $duration);
563 $next = _event_nav($date, 'next', $view, $types, $terms, $duration);
564
565 // setup calendar table header
566 $caption = $prev .' '. $caption .' '. $next;
567 $node->event = array();
568 $node->event['start_exploded'] = array('year' => $year, 'month' => $month, 'day' => $day);
569 $node->event['filter'] = ($types ? implode('+', $types) : 'all') .'/'. ($terms ? implode('+', $terms) : 'all');
570
571 $output .= theme('event_links', array_merge(module_invoke_all('link', 'event_'. $view, $node, FALSE), $links), $view);
572
573 $output .= theme('event_calendar_'. $view, 'page', (!empty($thead) ? $thead : array()), $tbody, array(), $caption);
574 $output .= theme('event_ical_link', 'event/'. (isset($ical_date) ? _event_format_url($ical_date) : _event_format_url($date)) .'/ical/'. $node->event['filter'] . (isset($ical_duration) ? "/$ical_duration" :''));
575
576 // Add RSS feed and icon to events page
577 drupal_add_feed(url('event/feed', array('absolute' => TRUE)), t('Events at %site', array('%site' => variable_get('site_name', 'drupal'))));
578
579 drupal_set_title(t('Events') . (!empty($title) ? ' - '. $title : ''));
580 drupal_set_breadcrumb($breadcrumbs);
581 return $output;
582 }
583 }
584
585 /**
586 * Url wrapper function for static link to calendar by content type.
587 *
588 * @ingroup event_callback
589 * @return redirect to the event page for calendar node type.
590 */
591 function event_type($types = NULL, $view = NULL, $terms = NULL) {
592 drupal_goto('event/'. _event_format_url(_event_user_time()) .'/'. ($view ? $view : variable_get('event_overview', 'month')) .'/'. $types);
593 }
594
595 /**
596 * Url wrapper function for static link to calendar by taxonomy terms.
597 *
598 * @ingroup event_callback
599 * @return redirect to the event page for calendar taxonomy term.
600 */
601 function event_term($filter = NULL, $view = NULL) {
602 drupal_goto('event/'. _event_format_url(_event_user_time()) .'/'. ($view ? $view : variable_get('event_overview', 'month')) .'/all/'. $filter);
603 }
604
605 /**
606 * Url wrapper function for rss feeds
607 *
608 * @ingroup event_callback
609 * @return redirect to the event rss feed page at current day
610 */
611 function event_feed($types = 'all', $terms = 'all', $duration = NULL) {
612 drupal_goto('event/'. _event_format_url(_event_user_time()) .'/feed/'. $types .'/'. $terms .'/'. $duration);
613 }
614
615 /**
616 * Url wrapper function for ical feeds
617 *
618 * @ingroup event_callback
619 * @return redirect to the event ical feed page at current day
620 */
621 function event_ical($types = 'all', $terms = 'all', $duration = NULL) {
622
623 drupal_goto('event/'. _event_format_url(_event_user_time()) .'/ical/'. $types .'/'. $terms .'/'. $duration);
624
625 drupal_set_title(t('iCal support not enabled'));
626 return $output;
627 }
628
629 /**
630 * @defgroup event_view Functions which handle the display of event nodes
631 */
632
633 /**
634 * Displays a monthly event calendar.
635 *
636 * @ingroup event_view
637 * @return a themed monthly event calendar.
638 */
639 function event_calendar_month($op, $date, $types = NULL, $terms = NULL, $rewrite_parameter = array()) {
640 $year = $date['year'];
641 $month = $date['month'];
642 $day = $date['day'];
643
644 switch ($op) {
645 case 'page':
646 // setup callback for data population
647 $callback = 'event_render_day';
648 $view = 'month';
649 break;
650
651 case 'block':
652 // create caption and navigation links
653 $caption = _event_nav($date, 'prev', 'block', $types, $terms) .' '. l(event_format_date($date, 'custom', t('F Y')), 'event/'. _event_format_url($date) .'/month') .' '. _event_nav($date, 'next', 'block', $types, $terms);
654
655 $callback = 'event_render_day_single';
656 $view = 'block';
657 break;
658 }
659
660 event_calendar_data($date, $view, $types, $terms, 'prepopulate', array(), $rewrite_parameter);
661
662 // get weekdays array and header information
663 $weekdays = event_week_days();
664 $thead = event_week_header();
665 $tbody = array();
666
667 // get GMT current date value
668 $today = _event_user_date();
669
670 // name of the month
671 $month_name = event_format_date($date, 'custom', 'F');
672
673 // date of first day of month
674 $cur_date = $date;
675 $cur_date['day'] = '01';
676
677 // last day in month
678 $last_date = $date;
679 $last_date['day'] = date('t', mktime(0, 0, 0, $date['month'], 1, $date['year']));
680
681 // pad the first week row array to fill up days in the previous month we don't build
682 $row = array_fill(0, 6, array('class' => 'pad'));
683 // get the day of week offset value for the first day of the month
684 $start = $offset = _event_day_of_week($cur_date);
685 // render the month calendar
686 while (event_is_later($last_date, $cur_date)) {
687 $week = 0;
688 for ($x = $start; $x < 7 && event_is_later($last_date, $cur_date); $x++) {
689 $cur_day = (($week * 7) + ($x + 1) - $offset);
690 $row[$x] = array(
691 'class' => strtolower($weekdays[$x]['day']) .' day-'. $cur_date['day'] . ($cur_date == $today ? ' today' : '') . ($cur_date['day'] == $day ? ' selected' : ''),
692 'data' => $callback($cur_date, $view, $types, $terms, $rewrite_parameter));
693 $cur_date = event_date_later($cur_date, 1);
694 }
695 $week++;
696 $start = 0;
697 $tbody[] = array_pad($row, 7, array('class' => 'pad'));
698 $row = array();
699 }
700
701 switch ($op) {
702 case 'page':
703 return array($thead, $tbody);
704 break;
705 case 'block':
706 return theme('event_calendar_month', $op, $thead, $tbody, $attributes = array('class' => 'event-block '. strtolower($month_name)), $caption);
707 break;
708 }
709 }
710
711 /**
712 * Displays a weekly event calendar.
713 *
714 * @ingroup event_view
715 * @return a themed weekly event calendar.
716 */
717 function event_calendar_week($op, $date, $types = NULL, $terms = NULL, $rewrite_parameter = array()) {
718 // get weekdays array and header information
719 $weekdays = event_week_days();
720 $thead = event_week_header();
721
722 // get current date value
723 $today = _event_user_date();
724
725 // apply offset to goto first day of week
726 $cur_date = event_date_later($date, -1 * _event_day_of_week($date));
727 event_calendar_data($date, 'week', $types, $terms, 'prepopulate', array(), $rewrite_parameter);
728
729 for ($x = 0; $x < 7; $x++) {
730
731 $year = $date['year'];
732 $month = $date['month'];
733 $month_name = event_format_date($cur_date, 'custom', 'M');
734
735 $row[$x] = array(
736 'class' => strtolower("$month_name ". $weekdays[$x]['day'] . ($date == $today ? ' today' : '') . ($cur_date['day'] == $date['day'] ? ' selected' : '')),
737 'id' => strtolower($month_name . $cur_date['day']),
738 'data' => event_render_day($cur_date, 'week', $types, $terms, $rewrite_parameter));
739 $cur_date = event_date_later($cur_date, 1);
740 }
741 $tbody[] = $row;
742 return array($thead, $tbody);
743 }
744
745 /**
746 * Displays a daily event calendar.
747 *
748 * @ingroup event_view
749 * @return a themed daily event calendar.
750 */
751 function event_calendar_day($op, $date, $types = NULL, $terms = NULL, $rewrite_parameter = array()) {
752
753 $today = _event_user_date();
754
755 $dow = _event_day_of_week($date);
756 $month_name = event_format_date($date, 'custom', 'M');
757 $weekdays = event_week_days();
758 event_calendar_data($date, 'day', $types, $terms, 'prepopulate', array(), $rewrite_parameter);
759
760 $thead[] = array('data' => event_format_date($date, 'custom', 'D'));
761 $tbody[][] = array(
762 'class' => strtolower("$month_name ". $weekdays[$dow]['day'] . ($date['day'] == $today['day'] ? ' today' : '')),
763 'id' => strtolower($month_name . $date['day']),
764 'data' => event_render_day($date, 'day', $types, $terms, $rewrite_parameter),
765 'colspan' => 3);
766
767 return array($thead, $tbody);
768 }
769
770 /**
771 * Creates a themed table of events.
772 *
773 * @ingroup event_view
774 * @param $op
775 * @param $date The date
776 * @param $end_date end of the menu
777 * @param $types limit to given event node types
778 * @param $terms limit to nodes with these
779 * @return A fully themed table.
780 */
781 function event_calendar_table($op, $date, $end_date, $types = NULL, $terms = NULL, $rewrite_parameter = array()) {
782
783 $today = _event_user_date();
784 $thead[] = array('data' => '&nbsp;');
785
786 $cur_day = $today['day'];
787 $cur_date = $date;
788 $cur_date['hour'] = '00';
789 $cur_date['minute'] = '00';
790
791 $weekdays = event_week_days();
792 event_calendar_data($date, 'table', $types, $terms, 'prepopulate', $end_date, $rewrite_parameter);
793
794 while (event_is_later($end_date, $cur_date)) {
795 $month_name = event_format_date($cur_date, 'custom', 'M');
796 $dow = _event_day_of_week($cur_date) + 1;
797
798 $tbody[][] = array('colspan' => 3,
799 'class' => strtolower("$month_name ". (!empty($weekdays[$dow]['day']) ? $weekdays[$dow]['day'] : '') . ($cur_date == $today ? ' today' : '') . ($cur_date['day'] == $date['day'] ? ' selected' : '')),
800 'id' => strtolower($month_name . (!empty($cur_date['date']) ? $cur_date['date'] : '')),
801 'data' => event_render_day($cur_date, 'table', $types, $terms, $rewrite_parameter));
802 $cur_date = event_date_later($cur_date, 1);
803 }
804
805 return array($thead, $tbody);
806 }
807
808 /**
809 * Creates a themed list of events.
810 *
811 * @ingroup event_view
812 * @param $op
813 * @param $date The date
814 * @param $end_date end date of the menu
815 * @param $types
816 * @param $terms
817 * @return A themed list of events.
818 */
819 function event_calendar_list($op, $date, $end_date, $types = NULL, $terms = NULL, $rewrite_parameter = array()) {
820
821 $rows = '';
822
823 $cur_date = $date;
824 event_calendar_data($date, 'list', $types, $terms, 'prepopulate', $end_date, $rewrite_parameter);
825
826 while (event_is_later($end_date, $cur_date)) {
827 $rows .= event_render_day($cur_date, 'list', $types, $terms, $rewrite_parameter);
828 $cur_date = event_date_later($cur_date, 1);
829 }
830
831 return $rows;
832 }
833
834 /**
835 * Creates an rss feed of events.
836 *
837 * @ingroup event_view
838 * @param $date The starting date for the feed.
839 * @param $duration The number of days the feeds duration is.
840 * @param $types The content types to filter the feed by.
841 * @param $terms The taxonomy term tids to filter the feed by.
842 * @param $title The filter title to append to the channel description.
843 * @param $rewrite_parameter optional array that will be passed on to queries
844 * in event_database.*.inc files and merged into the
845 * fourth argument of db_rewrite_sql.
846 *
847 * @return A formatted rss feed.
848 */
849 function event_calendar_rss($date, $duration, $types = NULL, $terms = NULL, $title = NULL, $rewrite_parameter = array()) {
850 global $base_url;
851
852 $end_date = event_date_later($date, $duration);
853
854 $headertitle = event_format_date($date, 'custom', t('F d Y')) .'-'. event_format_date($end_date, 'custom', t('F d Y'));
855
856 $result = event_get_events(event_implode_date($date), event_implode_date($end_date), 'ASC', $rewrite_parameter);
857
858 $nodes = array();
859 while ($nid = db_fetch_object($result)) {
860 $node = node_load($nid->nid);
861 node_invoke_nodeapi($node, 'view', FALSE, FALSE);
862
863 $nodes[] = $node;
864 }
865
866 $filtered = event_filter_nodes($nodes, $types, $terms);
867 $items = '';
868 foreach ($filtered as $node) {
869 $body = '<div class="start">'. t('Start') .': '. $node->event['start_format'] .'</div>'."\n";
870 $body .= '<div class="end">'. t('End') .': '. $node->event['end_format'] .'</div>'."\n";
871 $body .= check_markup($node->teaser, $node->format);
872 $link = url('node/'. $node->nid, array('absolute' => TRUE));
873 // Allow modules to add additional item fields
874 $extra = node_invoke_nodeapi($node, 'rss item');
875 $extra = array_merge($extra, array(array('key' => 'pubDate', 'value' => date('r', $node->changed))));
876 $items .= format_rss_item($node->title, $link, $body, $extra);
877 }
878
879 $description = $headertitle . ($title ? ' | '. $title : '');
880
881 $output = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
882 if (module_exists('location')) {
883 $output .= "<rss version=\"2.0\" xmlns:geo=\"http://www.w3.org/2003/01/geo/wgs84_pos#\" xmlns:geourl=\"http://geourl.org/rss/module/\" xmlns:icbm=\"http://postneo.com/icbm\" xml:base=\"". $base_url ."\">\n";
884 }
885 else {
886 $output .= "<rss version=\"2.0\" xml:base=\"". $base_url ."\">\n";
887 }
888 $output .= format_rss_channel(variable_get('site_name', 'drupal') . t(' - Events Feed'), url('event/feed', array('absolute' => TRUE)), $description, $items);
889 $output .= "</rss>\n";
890
891 return $output;
892 }
893
894 /**
895 * Creates an ical feed of events.
896 *
897 * @ingroup event_view
898 * @param $date The date for the feed.
899 * @param $duration The number of days the feeds duration is.
900 * @param $types The content types to filter the feed by.
901 * @param $terms The taxonomy term tids to filter the feed by.
902 * @param $title The filter title to append to the channel description.
903 * @param $rewrite_parameter optional array that will be passed on to queries
904 * in event_database.*.inc files and merged into the
905 * fourth argument of db_rewrite_sql.
906 *
907 * @return A formatted ical feed.
908 */
909 function event_calendar_ical($date, $duration, $types = NULL, $terms = NULL, $title = NULL, $rewrite_parameter = array()) {
910 global $base_url, $language;
911
912 $end_date = event_date_later($date, $duration);
913
914 $headertitle = event_format_date($date, 'custom', t('F d Y')) .'-'. event_format_date($end_date, 'custom', t('F d Y'));
915
916 $result = event_get_events(event_implode_date($date), event_implode_date($end_date), 'ASC', $rewrite_parameter);
917
918 $events = array();
919 while ($nid = db_fetch_object($result)) {
920 $node = node_load($nid->nid);
921 if (event_filter_node($node, $types, $terms)) {
922 $events[] = _event_node_ical($node);
923 }
924 }
925
926 $description = $headertitle . ($title ? ' | '. $title : '');
927
928 include_once(EVENT_PATH .'/ical.inc');
929 return ical_export($events, $description);
930 }
931
932 /**
933 * Return an ical for a specific event
934 */
935 function event_node_ical() {
936 $node = node_load(arg(1));
937 $event = _event_node_ical($node);
938 drupal_set_header('Content-Type: text/calendar; charset=utf-8');
939 drupal_set_header('Content-Disposition: attachment; filename="calendar.ics"; ');
940 print ical_export(array($event), $event['summary']);
941 }
942
943 function _event_node_ical($node) {
944 include_once(EVENT_PATH .'/ical.inc');
945 $event = array();
946 // Allow modules to affect item fields
947 node_invoke_nodeapi($node, 'ical item');
948 $event = $node->event;
949 $event['uid'] = $node->uid;
950 $event['summary'] = $node->title;
951 $event['description'] = check_markup($node->teaser ? $node->teaser : $node->body, $node->format);
952 $event['uid'] = url("node/$node->nid", array('absolute' => TRUE));
953 $event['url'] = url("node/$node->nid", array('absolute' => TRUE));
954
955 return $event;
956 }
957
958 /**
959 * @defgroup event_support Functions that support the event system
960 */
961
962
963 /**
964 * Returns an array of nodes that occur on a given date.
965 * Handles content type and taxonomy filters.
966 *
967 * @ingroup event_support
968 * @param $date A date array.
969 * @param $view Who's calling this
970 * @param $types Limit to nodes of these types
971 * @param $terms Limit to events with these taxonomy terms
972 * @param $type 'prepopulate' or 'lookup', default 'lookup', whether
973 * to prepopulate the data array or return nodes.
974 * @param $end_date optional end date for list and table views
975 * @param $rewrite_parameter optional array that will be passed on to queries
976 * in event_database.*.inc files and merged into the
977 * fourth argument of db_rewrite_sql.
978 *
979 * @return An array containing all of the events taking place on the
980 * specified date, or an empty array if none exist or $type is
981 * 'prepopulate'.
982 */
983 function event_calendar_data($date, $view = NULL, $types = NULL, $terms = NULL, $type = 'lookup', $end_date