/[drupal]/contributions/sandbox/frjo/event/event.module
ViewVC logotype

Contents of /contributions/sandbox/frjo/event/event.module

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


Revision 1.2 - (show annotations) (download) (as text)
Fri Apr 22 07:25:33 2005 UTC (4 years, 7 months ago) by frjo
Branch: MAIN
CVS Tags: HEAD
Changes since 1.1: +5 -3 lines
File MIME type: text/x-php
My patch version2 of event.module for Drupal 4.5
1 <?php
2 // $Id: event.module, frjo Exp $
3
4 /**
5 * Retrieves all of the fields from fields.inc. To add extra fields you might need, add them to the file called
6 * fields.inc in the event module directory.
7 *
8 * This version add end time, you need to add a end field to the event table:
9 * ALTER TABLE event ADD end int(10) unsigned NOT NULL default '0';
10 *
11 * You probably need to change the time zone for the iCalender.
12 * Do a search/replace for "Europe/Stockholm" to whatever you want.
13 * I know, this you be set automatically or via a setting.
14 *
15 * This version of the event.module can be downloaded from my sandbox
16 * <http://cvs.drupal.org/viewcvs/drupal/contributions/sandbox/frjo/>
17 *
18 * @return an array of fields
19 */
20 function event_fields() {
21 if (file_exists('modules/event/fields.inc')) {
22 include_once 'modules/event/fields.inc';
23 return event_extra_fields();
24 }
25
26 return array();
27 }
28
29 /**
30 * Displays the help text for this module.
31 *
32 * @param $section the page which is requesting help
33 * @return the help text
34 */
35 function event_help($section) {
36 switch ($section) {
37 case 'admin/modules#description':
38 return t('Lets users make events and keep calendars.');
39 case 'node/add/event':
40 return variable_get('event_help', '');
41 case 'node/add#event':
42 return t('Events are happenings scheduled for a specific date and time.');
43 }
44 }
45
46 /**
47 * Provides a link to the CSS stylesheet associated with this module.
48 *
49 * @return a &lt;style&gt; tag that indicates what file browsers should import
50 */
51 function event_html_head() {
52 return '<style type="text/css">@import url(modules/event/event.css);</style>';
53 }
54
55 /**
56 * Provides the blocks that this module is capable of displaying.
57 *
58 * @param $op the operation that is being requested. This defaults to 'list', which indicates that the method should
59 * which blocks are available.
60 * @param $delta the specific block to display. This is actually the offset into an array.
61 * @return one of two possibilities. The first is an array of available blocks. The other is an array containing a
62 * block.
63 */
64 function event_block($op = 'list', $delta = 0) {
65 if ($op == 'list') {
66 $blocks[0]['info'] = t('Calendar to browse events.');
67 $blocks[1]['info'] = t('List of upcoming events.');
68 return $blocks;
69 }
70 else {
71 if (($op == 'view') && user_access('access content')) {
72 switch ($delta) {
73 case 0:
74 $block['subject'] = t('Browse events');
75 $block['content'] = event_display('event_calendar_simple', $year, $month, $day);
76 return $block;
77 case 1:
78 $ical_url = l(t('subscribe iCal'), 'event/ical', array('title' => t('Add this calendar to your iCalendar')), NULL, NULL, true);
79 $ical_url = preg_replace("|http://|","webcal://", $ical_url);
80
81 $block['subject'] = t('Upcoming events');
82 $block['content'] = event_block_upcoming();
83 $block['content'] .= '<div class="more-link">'. $ical_url .' | '. l(t('more'), 'event', array('title' => t('More events.'))) .'</div>';
84 return $block;
85 }
86 }
87 }
88 }
89
90 /**
91 * Displays and allows an administrator to change the settings for this module.
92 *
93 * @return the content for a settings page.
94 */
95 function event_settings() {
96 $output = form_textarea(t('Explanation or submission guidelines'), 'event_help', variable_get('event_help', ''), 70, 5, t('This text will be displayed at the top of the event submission form. Useful for helping or instructing your users.'));
97 $output .= form_radios(t('Time notation preference'), 'event_ampm', variable_get('event_ampm', '0'), array('0' => t('24h'), '1' => t('12h')), t('The time notation system used for entering event start times.'));
98 $output .= form_radios(t('Timezone handling'), 'event_timezone', variable_get('event_timezone', '1'), array('1' => t('Yes'), '0' => t('No')), t("Yes: Times are saved relative to the user's timezone. No: Times are displayed exactly as the user inputted them."));
99 $output .= form_select(t('Type of overview'), 'event_overview', variable_get('event_overview', 'calendar'), array('calendar' => t('Calendar'), 'table' => t('Table')), t('The type of overview to show the user when he clicks on the block calendar.'));
100
101 $extra = event_fields();
102 $headerarray = array();
103 foreach($extra as $key => $value) {
104 if ($value[0] == ('textfield' || 'textarea' || 'select') && $value[3]) {
105 $headerarray['e.'. $key] = $value[1];
106 }
107 }
108 $headerarray = array_merge(array('e.start' => t('Date'), 'n.title' => t('Title'), 'n.teaser' => t('Teaser'), 'n.body' => t('Body')), $headerarray);
109 $output .= form_select(t('Table headers'), 'event_table_headers', variable_get('event_table_headers', array('e.start', 'n.title', 'n.teaser')), $headerarray, t('The table headers used in the table view. Only entries that have their own database column in the event table and are of type "textfield", "textarea", or "select" can be used.'), 0, 1);
110
111 // Dummy arrays to be used by extractor.php
112 // Dummy array with abbreviations of months.
113 $month_abbr_dummy = array(t('Jan'), t('Feb'), t('Mar'), t('Apr'), t('May'), t('Jun'), t('Jul'), t('Aug'), t('Sep'), t('Oct'), t('Nov'), t('Dec'));
114 return $output;
115 }
116
117 /**
118 * Displays a page containing event information. The page layout defaults to a graphical calendar.
119 */
120 function event_page() {
121 $breadcrumbs = array(
122 l(t('Home'), NULL),
123 l(t('Events'), 'event')
124 );
125
126 if (arg(1) == 'search') {
127 $breadcrumbs[] = l(t('Search'), 'event/search');
128 print theme('page', event_query(), t('Search Events'), $breadcrumbs);
129 return;
130 }
131 elseif (!arg(1)) {
132 global $user;
133 $time = time();
134 $result = pager_query('SELECT DISTINCT(n.nid), e.start FROM {event} e INNER JOIN {node} n USING (nid) '. node_access_join_sql() .' WHERE '. node_access_where_sql() ." AND n.status = 1 AND e.start >= $time ORDER BY e.start", variable_get('default_nodes_main', 10));
135 if (db_num_rows($result)) {
136 $output = "";
137 $breadcrumbs[] = t('Upcoming');
138 while ($node = db_fetch_object($result)) {
139 unset($node->start); // we need to select e.start for pgsql's sake but it confuses node_load.
140 $output .= node_view(node_load($node), 1);
141 }
142 $output .= theme("pager", NULL, variable_get('default_nodes_main', 10));
143 print theme('page', $output, t('Upcoming events'), $breadcrumbs);
144 return;
145 }
146 }
147
148 // Show calendar by default
149 if (arg(1) == 'today') {
150 $current = event_format_date(time(), 'custom', 'Y/m/d');
151 $pieces = explode('/', $current);
152 $year = $pieces[0];
153 $month = $pieces[1];
154 $day = $pieces[2];
155 }
156 else {
157 $year = arg(1); $month = arg(2); $day = arg(3);
158 }
159
160 $output = '<div id="event">';
161 if (variable_get('event_overview', 'calendar') == 'table') {
162 $output .= event_display('event_table', $year, $month, $day, 1, 1);
163 }
164 else {
165 $output .= event_display('event_calendar_expanded', $year, $month, $day, 1);
166 }
167 $ical_url = l(t('subscribe iCal'), 'event/ical', array('title' => t('Add this calendar to your iCalendar')), NULL, NULL, true);
168 $ical_url = preg_replace("|http://|","webcal://", $ical_url);
169 $output .= '<br />'.theme('links', array(l(t('search events'), "event/search"), $ical_url));
170 $output .= '</div>';
171
172 $timestamp = gmmktime(0, 0, 0, $month, ($day ? $day : 1), $year);
173 $breadcrumbs[] = l($year, "event/$year");
174 $breadcrumbs[] = l(t(format_date($timestamp, 'custom', 'F', 0)), "event/$year/$month");
175 print theme('page', $output, t('Events'), $breadcrumbs);
176 }
177
178 /**
179 * Provides an array of permissions associated with this module.
180 *
181 * @return an array of permissions
182 */
183 function event_perm() {
184 return array('maintain events');
185 }
186
187 /**
188 * Provides the links that should be displayed when viewing events.
189 *
190 * @param $type the type of link (for example, 'node', 'page', or 'system') being requested
191 * @param $node the node that is requesting the link. This is used in conjunction with $type to further determine
192 * what sort of link to display.
193 * @param $main unused in this method.
194 * @return an array of links, or an empty array if no links apply for the criteria passed to this method.
195 */
196 function event_link($type, $node = 0, $main) {
197
198 switch ($type) {
199 case 'node':
200 if ($node->type == 'event') {
201 if (node_access('update', $node) && !user_access('administer nodes')) {
202 $links[] = l(t('edit event'), "node/$node->nid/edit", array('title' => t('Edit this event.')));
203 }
204 else {
205 $links[] = l(t('calendar'), 'event/'. event_format_date($node->start, 'custom', 'Y/m/d'));
206 }
207 }
208 break;
209 case 'page':
210 if (user_access('access content')) {
211 $links[] = l(t('events'), 'event', array('title' => t('Show events')));
212 }
213 break;
214 }
215
216 return $links ? $links : array();
217 }
218
219 /**
220 * Implementation of hook_cron().
221 * It finds the last and the first event to limit links created by the calendars.
222 */
223 function event_cron() {
224 if (time() - variable_set('event_cron_run', 0) > 600) {
225 $max = db_fetch_object(db_query('SELECT MAX(start) AS max FROM {event}'));
226 $min = db_fetch_object(db_query('SELECT MIN(start) AS min FROM {event}'));
227 variable_set('event_start_max', $max->max);
228 variable_set('event_start_min', $min->min);
229 variable_set('event_cron_run', time());
230 }
231 }
232
233 /**
234 * Implementation of hook_menu()
235 */
236 function event_menu($may_cache) {
237 global $user;
238
239 $items = array();
240 if ($may_cache) {
241 $items[] = array('path' => 'node/add/event', 'title' => t('event'),
242 'access' => user_access('maintain events'));
243 $items[] = array('path' => 'event', 'title' => t('events'),
244 'callback' => 'event_page',
245 'access' => user_access('access content'),
246 'type' => MENU_SUGGESTED_ITEM);
247 $items[] = array('path' => 'event/'.event_format_date(time(), 'custom', 'Y/m/d'), 'title' => t('calendar'),
248 'access' => user_access('access content'),
249 'type' => MENU_DYNAMIC_ITEM);
250 $items[] = array('path' => 'event/search', 'title' => t('search'),
251 'callback' => 'event_page',
252 'type' => MENU_SUGGESTED_ITEM);
253 $items[] = array('path' => 'event/ical', 'title' => t('iCal'),
254 'access' => user_access('access content'),
255 'callback' => '_event_ical',
256 'type' => MENU_SUGGESTED_ITEM);
257 }
258 else {
259 drupal_set_html_head(event_html_head());
260 }
261
262 return $items;
263 }
264
265 /**
266 * @defgroup event_node Methods that implement node hooks.
267 */
268
269 /**
270 * Indicates what type of nodes this module generates.
271 *
272 * @ingroup event_node
273 * @return the type of node
274 */
275 function event_node_name() {
276 return t('event');
277 }
278
279 /**
280 * Determines whether a user has permission to execute a specified operation. When no permission
281 * is specified, the node_access table determines access
282 *
283 * @ingroup event_node
284 * @param $op the operation that is being requested.
285 * @param &$node the node on which the operation will be executed.
286 * @return whether the user has sufficient access to execute the operation.
287 */
288 function event_access($op, &$node) {
289 global $user;
290 switch ($op) {
291 case 'create':
292 return user_access('maintain events');
293 case 'update':
294 if ($user->uid == $node->uid && user_access('maintain events')) {
295 return TRUE;
296 }
297 case 'delete':
298 if ($user->uid == $node->uid && user_access('maintain events')) {
299 return TRUE;
300 }
301 }
302 }
303
304 /**
305 * Verifies that the details of an event are properly set.
306 * - Changes 24 hour time to 12 hour time (if the module is configured to do this).
307 * - Adjusts times for timezone offsets.
308 * - Verifies that all required fields have values.
309 *
310 * @ingroup event_node
311 * @param &$node the event node to validate
312 * @return any error messages this method generates.
313 */
314 function event_validate(&$node) {
315 // Re-calculate $node->start and $node->end if we have all the parameters.
316 event_validate_time($node, 'start');
317 event_validate_time($node, 'end');
318
319 $fields = event_fields();
320 foreach ($fields as $field => $def) {
321 if ($def[2] && isset($node->$field) && empty($node->$field)) {
322 form_set_error($field, t($def[1]).' '.t('is a required field.'));
323 }
324 }
325 if (isset($node->body) && empty($node->body)) {
326 form_set_error('body', t('Specify details for this event'));
327 }
328 }
329
330
331 function event_validate_time(&$node, $time) {
332 $year = $time . '_year';
333 $month = $time . '_month';
334 $day = $time . '_day';
335 $hour = $time . '_hour';
336 $minute = $time . '_minute';
337 $ampm = $time . '_ampm';
338 if (isset($node->$year) && isset($node->$month) && isset($node->$day) && isset($node->$hour) && isset($node->$minute)) {
339 $the_hour = $node->$hour;
340 if (variable_get('event_ampm', '0')) {
341 if ($node->$ampm == 'pm' && $the_hour != 12) {
342 $the_hour += 12;
343 }
344 if ($the_hour == 12 && $node->$ampm == 'am') {
345 $the_hour -= 12;
346 }
347 }
348 $node->$time = _event_mktime($the_hour, $node->$minute, 0, $node->$month, $node->$day, $node->$year);
349 if (variable_get('event_timezone', '1')) {
350 $node->$time -= $GLOBALS['user']->timezone;
351 }
352 }
353
354 if (empty($node->$time)) {
355 if ($time == 'start') {
356 $node->$time = time();
357 }
358 else {
359 $node->$time = $node->start - 0;
360 }
361 // Round to nearest hour:
362 $node->$time -= $node->$time % (60 * 60);
363 }
364 }
365
366
367 /**
368 * Completes an event node by setting the teaser and body fields.
369 *
370 * @ingroup event_node
371 * @param &$node the node to be completed
372 * @param $main unused in this method
373 * @return the same node passed with the teaser and body fields properly set
374 */
375 function event_content(&$node, $main = 0) {
376 $fields = event_fields();
377
378 $output = '<div class="event">';
379 $output .= '<div class="details">';
380 $output .= form_item(t('Start'), event_format_date($node->start, 'large'));
381 if ($node->end > $node->start) {
382 $output .= form_item(t('End'), event_format_date($node->end, 'large'));
383 }
384 foreach ($fields as $field => $def) {
385 if ($node->$field) {
386 if ($def[0] == "select") {
387 if ($def[10]) { // multi-select
388 foreach ($node->$field as $val) {
389 $vals[] = $def[7][$val];
390 }
391 $output .= form_item($def[1], implode(", ", $vals));
392 }
393 else {
394 $output .= form_item($def[1], $def[7][$node->$field]);
395 }
396 }
397 else {
398 $output .= form_item($def[1], $node->$field);
399 }
400 }
401 }
402 $output .= '</div>';
403
404 $node->teaser = $output . ($node->teaser ? '<div class="content">'. check_output($node->teaser, $node->format) .'</div></div>' : '</div>');
405 $node->body = $output . ($node->body ? '<div class="content">'. check_output($node->body, $node->format) .'</div></div>' : '</div>');
406
407 $node->readmore = (strlen($node->teaser) < strlen($node->body));
408
409 return $node;
410 }
411
412 /**
413 * Prepares an event for viewing.
414 *
415 * @ingroup event_node
416 * @param &$node the event to be prepared
417 * @param $main whether or not the main page is requesting the node
418 * @param $page whether or not the event is being viewed by itself
419 * @return a string containing the event after it has been passed through the theme subsystem
420 */
421 function event_view(&$node, $main = 0, $page = 0) {
422 $node = event_content($node, $main);
423 if ($page) {
424 // Breadcrumb navigation
425 $breadcrumb[] = l(t('Home'), NULL);
426 $breadcrumb[] = l(t('Events'), 'event');
427 drupal_set_breadcrumb($breadcrumb);
428 }
429 return theme('node', $node, $main, $page);
430 }
431
432 /**
433 * Constructs the start time select boxes.
434 *
435 * @param $timestamp The time already selected. This is applicable if the user is editing an event.
436 * @param $prefix
437 * @return A set of select boxes that contain options for month, day, year, hour, and minute
438 * @todo Make the years automatically populated instead of static.
439 */
440 function event_form_date($timestamp, $prefix = '') {
441
442 //determine settings for form's hour selector
443 if (variable_get('event_ampm', '0')) {
444 $hour_format = t('g');
445 $first_hour = 1;
446 $last_hour = 12;
447 }
448 else {
449 $hour_format = t('H');
450 $first_hour = 0;
451 $last_hour = 23;
452 }
453
454 $years = array(2000 => 2000, 2001 => 2001, 2002 => 2002, 2003 => 2003, 2004 => 2004, 2005 => 2005, 2006 => 2006, 2007 => 2007, 2008 => 2008, 2009 => 2009);
455 $months = array(1 => t('January'), t('February'), t('March'), t('April'), t('May'), t('June'), t('July'), t('August'), t('September'), t('October'), t('November'), t('December'));
456 for ($i = 1; $i <= 31; $i++) $days[$i] = $i;
457 for ($i = $first_hour; $i <= $last_hour; $i++) $hours[$i] = $i;
458 for ($i = 0; $i <= 59; $i++) $minutes[$i] = $i < 10 ? "0$i" : $i;
459 $am_pms = array('am' => t('am'), 'pm' => t('pm'));
460
461 if ($timestamp) {
462 // Use event_format_date(), it handles user timezone and locale.
463 $year = event_format_date($timestamp, 'custom', 'Y');
464 $month = event_format_date($timestamp, 'custom', 'm');
465 $day = event_format_date($timestamp, 'custom', 'd');
466 $hour = event_format_date($timestamp, 'custom', $hour_format);
467 $minute = event_format_date($timestamp, 'custom', 'i');
468 $am_pm = event_format_date($timestamp, 'custom', 'a');
469 }
470
471 $when = '<div class="container-inline">';
472 $when .= '<div class="day">';
473 $when .= form_select('', $prefix .'month', $month, $months);
474 $when .= form_select('', $prefix .'day', $day, $days);
475 $when .= form_select('', $prefix .'year', $year, $years);
476 $when .= '</div><div class="time">';
477 $when .= form_select('', $prefix .'hour', $hour, $hours);
478 $when .= ':';
479 $when .= form_select('', $prefix .'minute', $minute, $minutes);
480 if (variable_get('event_ampm', '0')) {
481 $when .= form_select('', $prefix .'ampm', $am_pm, $am_pms);
482 }
483 $when .= '</div></div>';
484
485 return $when;
486 }
487
488 /**
489 * Prepares the event editing page.
490 *
491 * @ingroup event_node
492 * @param &$node The event to be edited.
493 * @param &$error Any error messages that need to be displayed. These are returned from event_validate().
494 * @return The form elements needed to edit the event.
495 */
496 function event_form(&$node, &$error) {
497
498 $output = '';
499 if (module_exist('taxonomy')) {
500 $output .= implode('', taxonomy_node_form('event', $node));
501 }
502 $output .= form_item(t('Start'), event_form_date($node->start, 'start_'), t('When is this event taking place.'));
503 $output .= form_item(t('End'), event_form_date($node->end, 'end_'), t('Scheduled end time. If you do not wish to display and end time for this event, do not adjust this time.'));
504 $fields = event_fields();
505 foreach ($fields as $field => $def) {
506 $function = "form_$def[0]";
507 $output .= $function($def[1], $field, $node->$field, $def[7], $def[8], $def[9], NULL, $def[2]);
508 }
509 $output .= form_textarea(t('Details'), 'body', $node->body, 60, 15, '', NULL, TRUE);
510 $output .= filter_form('format', $node->format);
511
512 return $output;
513 }
514
515 /**
516 * Creates a query to either insert or update an event in the database.
517 *
518 * @param $fields The fields to be retrieved.
519 * @param $node The node we are inserting or updating.
520 * @param &$v
521 * @param $insert Whether or not this is an insert query.
522 * @return The SQL statement generated by the above criteria.
523 */
524 function event_create_query($fields, $node, &$v, $insert = 1) {
525 $node->data = array();
526 $extra_fields = event_fields();
527 foreach ($extra_fields as $field => $def) {
528 if (isset($node->$field)) {
529 if ($def[3]) { // Store in separate database field
530 $fields[] = $field;
531 }
532 else {
533 $node->data[$field] = $node->$field;
534 }
535 }
536 }
537 $node->data = serialize($node->data);
538
539 foreach ($fields as $field) {
540 if ($insert) {
541 $k[] = check_query($field);
542 $s[] = "'%s'";
543 }
544 else {
545 $q[] = check_query($field) ." = '%s'";
546 }
547 $v[] = $node->$field;
548 }
549
550 if ($insert) {
551 return "INSERT INTO {event} (". implode(", ", $k) .") VALUES(". implode(", ", $s) .")";
552 }
553 else {
554 return "UPDATE {event} SET ". implode(", ", $q) ." WHERE nid = '$node->nid'";
555 }
556 }
557
558 /**
559 * Updates the event database table when event nodes are inserted.
560 *
561 * @ingroup event_node
562 * @param @$node The node that is being inserted.
563 */
564 function event_insert(&$node) {
565 $fields = array('nid', 'start', 'end', 'data');
566 $sql = event_create_query($fields, $node, $values);
567 foreach ($values as $value) {
568 $vals[] = is_array($value) ? serialize($value) : $value;
569 }
570 db_query($sql, $vals);
571 }
572
573 /**
574 * Updates the event database table when event nodes are updated.
575 *
576 * @ingroup event_node
577 * @param &$node The node that is being updated.
578 */
579 function event_update(&$node) {
580 $fields = array('start', 'end', 'data');
581 $sql = event_create_query($fields, $node, $values, 0);
582 foreach ($values as $value) {
583 $vals[] = is_array($value) ? serialize($value) : $value;
584 }
585 db_query($sql, $vals);
586 }
587
588 /**
589 * Deletes rows from the event database table when event nodes are deleted.
590 *
591 * @ingroup event_node
592 * @param &$node The node that is being deleted.
593 */
594 function event_delete(&$node) {
595 db_query("DELETE FROM {event} WHERE nid = %d", $node->nid);
596 }
597
598 /**
599 * Loads all of the event-specific information when an event node is viewed.
600 *
601 * @ingroup event_node
602 * @param &$node The node being viewed.
603 * @return An array of event-specific information.
604 */
605 function event_load(&$node) {
606 $event = db_fetch_object(db_query("SELECT * FROM {event} WHERE nid = %d", $node->nid));
607 $extra_fields = event_fields();
608 foreach ($extra_fields as $field => $def) {
609 if ($def[3]) { // Stored in separate database field
610 if ($def[0] == "select" && $def[10]) { // multi-select
611 $event->$field = unserialize($event->$field);
612 }
613 }
614 }
615 $event->data = unserialize($event->data);
616 if (is_array($event->data)) {
617 foreach ($event->data as $field => $value) {
618 $event->$field = $value;
619 }
620 }
621 return $event;
622 }
623
624 /**
625 * @defgroup event_support Support functions to accomplish event-specific tasks.
626 */
627
628 /**
629 * Creates a list of events that are occurring on a given year, month, and day.
630 *
631 * @ingroup event_support
632 * @param $year The year the event is taking place.
633 * @param $month The month the event is taking place.
634 * @param $day The day the event is taking place.
635 * @return An array containing all of the events taking place on the specified date, or an empty array if none exist.
636 */
637 function event_calendar_data($year, $month, $day) {
638 static $data;
639 if (!is_array($data[$year][$month])) {
640 global $user;
641 $data[$year][$month] = array();
642 $days = _event_date('j', _event_mktime(0, 0, 0, $month + 1, 0, $year));
643 $first = _event_mktime(0, 0, 0, $month, 1, $year);
644 $last = _event_mktime(23, 59, 59, $month, $days, $year);
645 if (variable_get('event_timezone', '1')) {
646 $first += $user->timezone;
647 $last += $user->timezone;
648 }
649
650 $result = db_query('SELECT DISTINCT(n.nid), e.start FROM {event} e INNER JOIN {node} n USING (nid) '. node_access_join_sql() .' WHERE '. node_access_where_sql() .' AND n.status = 1 AND e.start > %d AND e.start < %d ORDER BY e.start', $first, $last);
651 while ($node = db_fetch_object($result)) {
652 unset($node->start); // we need to select e.start for pgsql's sake but it confuses node_load.
653 $node = node_load($node);
654 $data[$year][$month][event_format_date($node->start, 'custom', 'j')][] = $node;
655 }
656 }
657
658 return $data[$year][$month][$day] ? $data[$year][$month][$day] : array();
659 }
660
661 /**
662 * Creates a list of events that are occurring on a given year, month, and day.
663 *
664 * @ingroup event_support
665 * @param $year The year the event is taking place.
666 * @param $month The month the event is taking place.
667 * @param $day The day the event is taking place.
668 * @return An array containing a title parameter for events taking place on the specified date, or an empty array if none exist.
669 */
670 function event_calendar_data_title($year, $month, $day) {
671 static $data;
672 if (!is_array($data[$year][$month])) {
673 global $user;
674 $data[$year][$month] = array();
675 $days = _event_date('j', _event_mktime(0, 0, 0, $month + 1, 0, $year));
676 $first = _event_mktime(0, 0, 0, $month, 1, $year);
677 $last = _event_mktime(23, 59, 59, $month, $days, $year);
678 if (variable_get('event_timezone', '1')) {
679 $first += $user->timezone;
680 $last += $user->timezone;
681 }
682 $result = db_query('SELECT DISTINCT(n.nid), n.title, e.start FROM {event} e INNER JOIN {node} n USING (nid) '. node_access_join_sql() .' WHERE '. node_access_where_sql() .' AND n.status = 1 AND e.start > %d AND e.start < %d ORDER BY e.start', $first, $last);
683 while ($node = db_fetch_object($result)) {
684 $data[$year][$month][event_format_date($node->start, 'custom', 'j')] = $node;
685 }
686 }
687 if ($data[$year][$month][$day]) {
688 $title = array();
689 $node = $data[$year][$month][$day];
690 $title[] = event_format_date($node->start, 'custom', 'H:i') .": ". $node->title;
691 if (module_exist('over_text')) {
692 $params = over_text_make(event_format_date($node->start, 'custom', 'l F jS'), join(" | ", $title));
693 }
694 else {
695 $params["title"] = join(" | ", $title);
696 }
697 return $params;
698 }
699 else {
700 return false;
701 }
702 }
703
704 /**
705 * Creates an abbreviated calendar of events.
706 *
707 * @ingroup event_support
708 * @param $year The year the event is taking place.
709 * @param $month The month the event is taking place.
710 * @param $day The day the event is taking place.
711 * @param $timestamp Unused in this method.
712 * @return A link to a page containing more details about events occurring on the given date, or if no events are
713 * taking place just the plaintext $day.
714 */
715 function event_calendar_simple($year, $month, $day, $timestamp) {
716 return count(event_calendar_data($year, $month, $day)) ? l($day, "event/$year/$month/$day", event_calendar_data_title($year, $month, $day)) : $day;
717 }
718
719 /**
720 * Creates a detailed calendar of events.
721 *
722 * @ingroup event_support
723 * @param $year The year the event is taking place.
724 * @param $month The month the event is taking place.
725 * @param $day The day the event is taking place.
726 * @param $timestamp Unused in this function.
727 * @return A string containing all of the events taking place.
728 */
729 function event_calendar_expanded($year, $month, $day, $timestamp) {
730
731 if (variable_get('event_ampm', '0')) {
732 $date_format = t('g:ia');
733 }
734 else {
735 $date_format = t('G:i');
736 }
737
738 $fields = event_fields();
739 $output = "<div class=\"day\">$day</div>\n";
740 if (count($data = event_calendar_data($year, $month, $day))) {
741 foreach ($data as $node) {
742 $output .= '<div class="event">';
743 $output .= '<span class="time">'. event_format_date($node->start, 'custom', $date_format) .'</span>';
744 $output .= '<span class="title">'. l($node->title, "node/$node->nid") .'</span>';
745 foreach ($fields as $field => $def) {
746 if ($def[4] && $node->$field) {
747 if ($node->$field) {
748 $output .= "<span class=\"$field\">";
749 if ($def[0] == "select") {
750 if ($def[10]) { // multi-select
751 foreach ($node->$field as $val) {
752 $vals[] = $def[7][$val];
753 }
754 $output .= implode(", ", $vals);
755 }
756 else {
757 $output .= $def[7][$node->$field];
758 }
759 }
760 else {
761 $output .= $node->$field;
762 }
763 $output .= '</span>';
764 }
765 }
766 }
767 $output .= '</div>';
768 }
769 }
770 else {
771 $output .= '<div class="event-empty"></div>';
772 }
773 return $output;
774 }
775
776 /**
777 * Creates the graphical calendar and table views for events.
778 *
779 * @ingroup event_support
780 * @param $callback
781 * @param &$year The year the event is taking place.
782 * @param &$month The month the event is taking place.
783 * @param &$day The day the event is taking place.
784 * @param $navigation
785 * @param $extra
786 * @return The fully formatted calendar or table.
787 */
788 function event_display($callback, &$year, &$month, &$day, $navigation = 0, $extra = 0) {
789 global $user;
790 $time = time();
791 if (variable_get('event_timezone', '1')) {
792 $time += $user->timezone;
793 }
794 if (!$year) {
795 $year = _event_date('Y', $time);
796 }
797 if (!$month) {
798 $month = _event_date('m', $time);
799 }
800
801 // Sanitize date:
802 $eom = _event_mktime(0, 0, 0, $month + 1, 0, $year);
803 $days = _event_date('j', $eom);
804 $date = _event_mktime(0, 0, 0, $month, ($day && $day <= $days ? $day : 1), $year);
805 $today = _event_mktime(0, 0, 0, _event_date('m', $time), _event_date('j', $time), _event_date('Y', $time));
806
807 // Extract key data from date:
808 $month_name = _event_date('M', $date); // do not translate, used only for css
809 $weeks = ceil($days / 7);
810
811 // Initialize the header/week days:
812 if (variable_get('event_start_min', 0) < $date) {
813 // $prev = '<span class="prev">'. l('&laquo;', 'event/'. ($month - 1 < 1 ? $year - 1 .'/12' : "$year/". ($month - 1)) . ($day ? "/$day" : '')) .'</span>';
814 $prev = '<span class="prev">'. l('&laquo;', 'event/'. ($month - 1 < 1 ? $year - 1 .'/12' : "$year/". ($month - 1))) .'</span>';
815 }
816 else {
817 $prev = '<span class="prev">&nbsp;</span>';
818 }
819 if (variable_get('event_start_max', 10000000000) > $eom) {
820 // $next = '<span class="next">'. l('&raquo;', 'event/'. ($month + 1 > 12 ? $year + 1 .'/1' : "$year/". ($month + 1)) . ($day ? "/$day" : '')) .'</span>';
821 $next = '<span class="next">'. l('&raquo;', 'event/'. ($month + 1 > 12 ? $year + 1 .'/1' : "$year/". ($month + 1))) .'</span>';
822 }
823 else {
824 $next = '<span class="next">&nbsp;</span>';
825 }
826 if (!$navigation) {
827 $name = l(t(_event_date('F', $date)) .' '. _event_date('Y', $date), 'event/'. ("$year/". ($month)));
828 }
829 else {
830 $name = t(_event_date('F', $date)) .' '. _event_date('Y', $date);
831 }
832 $header = array(
833 array('class' => 'prev', 'data' => $prev),
834 array('class' => 'heading', 'colspan' => 5, 'data' => $name),
835 array('class' => 'next', 'data' => $next)
836 );
837
838 if (!$extra) { // calendar views
839 $day_name = array('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat');
840 $day_trans = array(t('Sun'), t('Mon'), t('Tue'), t('Wed'), t('Thu'), t('Fri'), t('Sat'));
841 $weekstart = variable_get('date_first_day', 0);
842
843 // Week starts when?
844 $day_name = array_merge(array_slice($day_name, $weekstart), array_slice($day_name, 0, $weekstart));
845 $day_trans = array_merge(array_slice($day_trans, $weekstart), array_slice($day_trans, 0, $weekstart));
846
847 foreach ($day_name as $key => $_day) {
848 $row[] = array('class' => strtolower("days $_day"), 'data' => $day_trans[$key]);
849 }
850 $rows = array($row);
851 $week = 1;
852
853 // Create table days.
854 $row = array_fill(0, 6, '');
855 for ($_day = 1; $_day <= $days; $_day++) {
856 $timestamp = _event_mktime(0, 0, 0, $month, $_day, $year);
857 // Make sure we have the right day (week starts on).
858 $week_day = (_event_date('w', $timestamp) - $weekstart + 7) % 7;
859 $row[$week_day] = array(
860 'class' => strtolower("$month_name $day_name[$week_day]". ($weeks == $week ? ' lastweek' : '') . ($timestamp == $today ? ' today' : '') . ($_day == $day ? ' selected' : '')),
861 'id' => strtolower($month_name . $_day),
862 'data' => $callback($year, $month, $_day, $timestamp)
863 );
864
865 if ($week_day == 6 || $_day == $days) {
866 $rows[] = array_pad($row, 7, '&nbsp;');
867 $row = array();
868 $week++;
869 }
870 }
871 $output = '<div class="event-calendar">';
872 $output .= theme("table", $header, $rows);
873 }
874 else { // table view
875 $start = _event_mktime(0, 0, 0, $month, ($day ? $day : 1), $year);
876 $days = _event_date('j', _event_mktime(0, 0, 0, $month + 1, 0, $year));
877 $last = _event_mktime(23, 59, 59, $month, $days, $year);
878 if (variable_get('event_timezone', '1')) {
879 $start += $user->timezone;
880 $last += $user->timezone;
881 }
882 $output = '<div class="event-calendar">';
883 $output .= theme('table', $header, NULL);
884 $output .= $callback($start, $last, $today);
885 }
886
887 $output .= '</div>';
888
889 return $output;
890 }
891
892 /**
893 * Creates a themed table of events.
894 *
895 * @ingroup event_support
896 * @param $start The starting date for the table.
897 * @param $month The ending date for the table.
898 * @param $today The date to be indicated as current in the table.
899 * @return A fully themed table.
900 */
901 function event_table($start, $end, $today) {
902 $extra = event_fields();
903 $headerarray = $type = array();
904 foreach($extra as $key => $def) {
905 if ($def[3]) {
906 $headerarray[$def[1]] = 'e.'. $key;
907 $type['e.'. $key]['type'] = $def[0];
908 $type['e.'. $key]['fields'] = $def[7];
909 }
910 }
911 $headerkeys = variable_get('event_table_headers', array('e.start', 'n.title', 'n.teaser'));
912 $headerarray = array_merge(array(t('Date') => 'e.start', t('Title') => 'n.title', t('Teaser') => 'n.teaser', t('Body') => 'n.body'), $headerarray);
913 $type = array_merge(array('e.start' => array('type' => 'time'), 'n.title' => array('type' => 'textfield'), 'n.teaser' => array('type' => 'textarea'), 'n.body' => array('type' => 'textarea')), $type);
914 $headerarray = array_intersect($headerarray, $headerkeys);
915 $header = array();
916 foreach ($headerarray as $name => $column) {
917 $header[] = array('data' => $name, 'field' => $column);
918 }
919 $sql = 'SELECT n.nid, n.title, n.teaser, n.body, e.* FROM {node} n '. node_access_join_sql() .' INNER JOIN {event} e ON n.nid = e.nid WHERE '. node_access_where_sql() ." AND n.status = 1 AND e.start > $start AND e.start < $end";
920 $sql .= tablesort_sql($header);
921 $result = pager_query($sql, 10);
922 $rows = array();
923 while ($event = db_fetch_object($result)) {
924 $row = array();
925 foreach ($headerarray as $column) {
926 $field = substr($column, 2);
927 $row[] = array('data' => event_format_field($type[$column], $event->$field, $field, $event->nid), 'class' => $type[$column]['type'] .' '. $field . (($today == _event_mktime(0, 0, 0, _event_date('m', $event->start), _event_date('j', $event->start), _event_date('Y', $event->start))) ? ' today': ''));
928 }
929 $rows[] = $row;
930 }
931 if ($pager = theme('pager', NULL, 10, 0, tablesort_pager())) {
932 $rows[] = array(array('data' => $pager, "colspan" => count($headerfields)));
933 }
934
935 return theme('table', $header, $rows);
936 }
937
938 function event_format_field($type, $data, $field, $nid) {
939 switch ($type['type']) {
940 case 'textarea':
941 case 'textfield':
942 if ($field == 'title') {
943 return l($data, "node/$nid", array("title" => t('Click here to see the full event.')));
944 }
945 return $data;
946 break;
947 case 'time':
948 return event_format_date($data, 'custom', t('M, j'));
949 break;
950 case 'select':
951 $arr = array();
952 foreach (unserialize($data) as $key) {
953 $arr[] = $type['fields'][$key];
954 }
955 return implode(', ', $arr);
956 break;
957 }
958 }
959
960 /**
961 * Formats a date for display to the user.
962 *
963 * @ingroup event_support
964 * @param $timestamp The date to be displayed.
965 * @param $type The format to display the date in.
966 * @param $format A PHP date format string. This is only applicable if $type is 'custom'.
967 * @return A string containing the formatted date.
968 */
969 function event_format_date($timestamp, $type = 'medium', $format = '') {
970 $tz = variable_get('event_timezone', '1') ? NULL : 0;
971 return format_date($timestamp, $type, $format, $tz);
972 }
973
974 function _event_date($time, $format) {
975 return gmdate($time, $format);
976 }
977
978 function _event_mktime($hour, $minute, $second, $month, $day, $year) {
979 return gmmktime($hour, $minute, $second, $month, $day, $year);
980 }
981
982 /**
983 * Creates a page that the user may use to search for events.
984 *
985 * @ingroup event_support
986 * @return A string containing the search form and any results returned.
987 */
988 function event_query() {
989 $output = event_query_form();
990 switch ($_POST['op']) {
991 case t('Search'):
992 $result = event_query_parse((object) $_POST['edit']);
993 if (db_num_rows($result)) {
994 $output .= theme('event_query_results', $result);
995 }
996 else {
997 drupal_set_message(t('No matches found.'));
998 }
999 break;
1000 }
1001 return $output;
1002 }
1003
1004 function event_query_parse($edit) {
1005 $fields = event_fields();
1006 $query = array('n.status = 1');
1007
1008 // Calculate timestamps if we have all the parameters.
1009 if (isset($edit->from['year']) && isset($edit->from['month']) && isset($edit->from['day']) && isset($edit->from['hour']) && isset($edit->from['minute'])) {
1010 $str = _event_mktime($edit->from['hour'], $edit->from['minute'], 0, $edit->from['month'], $edit->from['day'], $edit->from['year']);
1011 if (variable_get('event_timezone', '1&