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

Contents of /contributions/modules/eventrepeat/eventrepeat.module

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


Revision 1.65 - (show annotations) (download) (as text)
Sun May 10 00:25:38 2009 UTC (6 months, 2 weeks ago) by rmiddle
Branch: MAIN
CVS Tags: HEAD
Changes since 1.64: +37 -37 lines
File MIME type: text/x-php
Part of the D6 update.
1 <?php
2 // $Id: eventrepeat.module,v 1.64 2009/05/10 00:03:05 rmiddle Exp $
3
4 // TODO: Update this section
5
6 //KNOWN BUGS
7 //this module is currently in beta release. known bugs include:
8 // 1. exception editor not working
9 // 2. editing the repeat sequence itself after it's already been created is inconsistent. nodes don't map to the exact
10 // date they're being moved to
11 // 3. bug: items getting rendered on day previous to creation day
12
13 //TODO
14 // 1. put form_set_error in place of drupal_set_message where appropriate. change drupal_set_message to warning
15 // where appropriate
16 // 2. add watchdog entries
17
18
19 // WISH LIST
20 // 1. invoke hook 'delete pre' for multi deletions (single node only?)
21 // 2. add ical support
22
23 //include_once(drupal_get_path('module', 'event') .'/event_timezones.inc');
24 include(drupal_get_path('module', 'eventrepeat') .'/eventrepeat.theme');
25
26 /**
27 * @file
28 *
29 * Event Repeats and repeating events to the event module.
30 */
31
32 /**
33 * @defgroup eventrepeat_core Core drupal hooks
34 */
35
36 /**
37 * Implementation of hook_cron().
38 *
39 * @ingroup eventrepeat_core
40 */
41 function eventrepeat_cron() {
42
43 //this value determines the maximum number of rows that can be added to the calmap table in one cron run, and should be
44 //set to a reasonable value to avoid server timeouts that could occur. this will most likely only happen when initially
45 //seeding the table. default value is 2000 rows
46 $_BAILOUT_VALUE = variable_get('eventrepeat_maximum_rows', 2000);
47
48 //the table values for eventrepeat_calmap
49 //day_stamp: human readable date in the format Y-m-d. also used in SQL queries
50 //date_stamp: date for which the RRULE values are being generated, timestamp is last second of the day, in UTC
51 //day_of_week: day of the week in the following format 'SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA'
52 //day_in_month: iteration of the day of the week in the month in the following format '1SU', '3MO'
53 //day_in_month_R: iteration of the day of the week in the month, counting from the end, in the following format '-1SU', '-3MO'
54 //month_day: numeric day of the month in the following format '1', '15'
55 //month_day_R: numeric day of the month, counting from the end, in the following format '-1', '-15'
56 //month: numeric month number, in the following format '1', '12'
57 //year_day: numeric day of the year in the following format '1', '226'
58 //year_day_R: numeric day of the year, counting from the end, in the following format '-1', '-226'
59 //week_number: numeric ISO-8601 week in the following format '1', '24'
60 //week_number_R: numeric ISO-8601 week, counting from the end, in the following format '-1', '-24'
61
62 //first thing is to determine the exact range that's going to be rendered, and calculate start and end timestamps.
63 //current time is calculated in GMT, then we check the table for the last created date. if no records are in the
64 //table, set start date to the end of the day on the day before the current date, and enable the seed.
65 $curtime = time();
66 $result = db_query("SELECT MAX(date_stamp) FROM {eventrepeat_calendar_map}");
67 $start = db_fetch_array($result);
68 if ($start['MAX(date_stamp)']) {
69 $start = $start['MAX(date_stamp)'];
70 }
71 else {
72 $start = gmmktime(23, 59, 59, (int) gmdate('n', $curtime), (int) gmdate('j', $curtime), (int) gmdate('Y', $curtime)) - 86400;
73 $seed = TRUE;
74 }
75
76 //end date is the current day, plus one day, plus the render support period
77 $curtime_end = gmmktime(23, 59, 59, (int) gmdate('n', $curtime), (int) gmdate('j', $curtime), (int) gmdate('Y', $curtime));
78 $end = $curtime_end + 86400 + (variable_get('eventrepeat_render_support', 2000) * 86400);
79
80 //next, we want to delete any table entries that are no longer needed. leave yesterday's date in as a precaution.
81 //since cron will probably be run more than once a day, and it's also possible that the admin may have shortened the
82 //render period since the last cron run, we put in a few checks for that, too, and exit the function if it doesn't
83 //need to be run now
84 if ($end < $start) {
85 db_query('DELETE FROM {eventrepeat_calendar_map} WHERE date_stamp > %d', $end);
86 return;
87 }
88
89 $result = db_query('SELECT date_stamp FROM {eventrepeat_calendar_map} WHERE date_stamp < %d', $curtime - 86400);
90 if (db_result($result) > 0 || $seed) {
91 $result = db_query('DELETE FROM {eventrepeat_calendar_map} WHERE date_stamp < %d', $curtime - 86400);
92 }
93 else {
94 return;
95 }
96
97 //set the insert query line, initialize the array where we'll dump the values initially, and start a bailout counter:
98 //this counter will count up and bail out of the calmap cycle when it hits _BAIL_OUT_VALUE, which can be set at the top
99 //of the function
100 $insert_line = "INSERT INTO {eventrepeat_calendar_map} (day_stamp, date_stamp, day_of_week, day_in_month,
101 day_in_month_R, month_day ,month_day_R, month, year_day, year_day_R, week_number, week_number_R) VALUES";
102 $values = array();
103 $bailout = 1;
104
105 //create timestamp for first day of the month which $start is in. this is the easiest way to count to generate info
106 //for the date range that needs to be rendered. also create the other initial calendar values we'll need here, based
107 //on the beginning of the month timestamp
108 $BOM = gmmktime(23, 59, 59, (int) gmdate('n', $start), 1, (int) gmdate('Y', $start));
109 $master_year = (int) gmdate('Y', $BOM); //current year
110 $leap_year = (int) gmdate('L', $BOM); //Whether it's a leap year
111 $days_in_month = (int) gmdate('t', $BOM); //Number of days in the given month
112 $days_of_week = array('SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA');
113 $master_month = (int) gmdate('n', $BOM); //current month
114 $master_month_day = 1; //current numeric day of the month
115 $master_month_day_R = -$days_in_month; //current numeric day of the month, counting backwards
116 $master_day = (int) gmdate('w', $BOM); //day of the week of the first day of the month, for incrementing day counts
117 $master_last_day = (int) gmdate('w', gmmktime(23, 59, 59, (int) gmdate('n', $start), $days_in_month,
118 (int) gmdate('Y', $start)));
119 $dow = $master_day; //current day of the week
120
121 //1st day of the month will always be the first of it's kind with respect to the day of the week, so we set that
122 //to one here. months will have certain days of the week that occur 4 times, and others that occur 5 times, so
123 //here we also build an incrementer that will help with correct reverse day in month calculations
124 $master_day_in_month = 1;
125 $master_day_in_month_R = -4;
126 $day_in_month_incrementer = _eventrepeat_day_in_month_incrementer($master_day, $days_in_month);
127
128 $master_year_day = (int) gmdate('z', $BOM) + 1; //current numeric day of the year
129 $master_year_day_R = $master_year_day - 365 - $leap_year - 1; //current numeric day of the year, counting backwards
130 $master_week_no = (int) gmdate('W', $BOM); //generate the ISO-8601 week no.
131
132 //figure out how many ISO-8601 weeks are in the current year. this seems like a hack but i wasn't sure how
133 //else to do it w/ php's date function
134 for ($n = 28; $n <= 31; $n++) {
135 $WN_stamp = gmmktime(23, 59, 59, 12, $n, $master_year);
136 $master_weeks_in_year = (int) gmdate('W', $WN_stamp) > $master_weeks_in_year ? (int) gmdate('W', $WN_stamp) :
137 $master_weeks_in_year;
138 }
139 $master_week_no_R = $master_week_no - $master_weeks_in_year - 1; //ISO-8601 week no. in year counting backwards
140
141 //now we move from the beginning of the month to the day before the start of the rendering period, adjusting values
142 //for everything we set above as we go. set the counter that increments by one day, and if the start of the rendering
143 //cycle is the beginning of the month, skip this step
144 $counter = $BOM + 86400;
145 if ($BOM != $start) {
146 while ($counter <= $start) {
147
148 //cycle through the numeric days of the week
149 if ($dow == 6) {
150 $dow = 0;
151 }
152 else {
153 $dow++;
154 }
155
156 //each time we get back around to the day of the week of the first day of the month, we increment the
157 //master_day_in_month counters
158 if ($master_day == $dow) {
159 $master_day_in_month++;
160 $master_day_in_month_R++;
161 }
162
163 //increment the master_month_day and master_year_day counters
164 $master_month_day++;
165 $master_month_day_R++;
166 $master_year_day++;
167 $master_year_day_R++;
168
169 //increment the weekno. variables if the day of the week is monday
170 if ($dow == 1) {
171 $master_week_no++;
172 $master_week_no_R++;
173 }
174 $counter += 86400;
175 }
176 }
177
178 //now we start the cycle for days where values need to be created
179 while ($counter <= $end) {
180
181 //cycle through the numeric days of the week
182 if ($dow == 6) {
183 $dow = 0;
184 }
185 else {
186 $dow++;
187 }
188
189 //each time we get back around to the day of the week of the first day of the month, we increment the
190 //master_day_in_month counters
191 if ($master_day == $dow) {
192 $master_day_in_month++;
193 $master_day_in_month_R++;
194 }
195
196 //increment the master_month_day and master_year_day counters
197 $master_month_day++;
198 $master_month_day_R++;
199 $master_year_day++;
200 $master_year_day_R++;
201
202 //january 4th is the first day of the year that's guaranteed to be in the first ISO-8601 week of the year
203 //so here we check to see if it's the 4th and reset the week no. variables if so
204 if ($master_month == 1 && $master_month_day == 4) {
205 $master_week_no = 1;
206
207 //figure out how many ISO-8601 weeks are in the current year. this seems like a hack but i wasn't sure how
208 //else to do it w/ php's date function. here also we need to set $master_weeks_in_year back to 52 so the
209 //hack will work
210 for ($n = 28; $n <= 31; $n++) {
211 $master_weeks_in_year = 52;
212 $WN_stamp = gmmktime(23, 59, 59, 12, $n, $master_year);
213 $master_weeks_in_year = (int) gmdate('W', $WN_stamp) > $master_weeks_in_year ? (int) gmdate('W', $WN_stamp) :
214 $master_weeks_in_year;
215 }
216
217 $master_week_no_R = $master_week_no - $master_weeks_in_year - 1; //ISO-8601 week no. in year counting backwards
218
219 //it's not the 4th of january, so increment the weekno. variables if the day of the week is monday
220 }
221 else {
222 if ($dow == 1) {
223 $master_week_no++;
224 $master_week_no_R++;
225 }
226 }
227
228 //if the date is between december 28th and january 4th, then we need to manually calculate the weekno.
229 //variables, b/c days in this range can fall into either the last week of the year, or the first week
230 //of the next year, depending upon which year it is.
231 if (($master_month == 12 && $master_month_day > 28) || ($master_month == 1 && $master_month_day < 4)) {
232 $master_week_no = (int) gmdate('W', $counter); //generate the ISO-8601 week no.
233
234 //if the weekno value calculates to 1, then the day is in week of the year we're changing to. if it's
235 //still december then push the temp year forward by one to ensure accurate calculation of the total
236 //number of weeks in this new year. don't forget to set $master_weeks_in_year to 52 again!
237 if ($master_week_no == 1) {
238 if ($master_month == 12) {
239 $master_year_temp = $master_year +1;
240 }
241 else {
242 $master_year_temp = $master_year;
243 }
244 for ($n = 28; $n <= 31; $n++) {
245 $master_weeks_in_year = 52;
246 $WN_stamp = gmmktime(23, 59, 59, 12, $n, $master_year_temp);
247 $master_weeks_in_year = (int) gmdate('W', $WN_stamp) > $master_weeks_in_year ? (int) gmdate('W', $WN_stamp) :
248 $master_weeks_in_year;
249 }
250 }
251 $master_week_no_R = $master_week_no - $master_weeks_in_year - 1; //ISO-8601 week no. in year counting backwards
252 }
253
254 //make day of the week the custom string value, and adjust the reverse day in month value according to the current
255 //month's incrementer array
256 $day_of_the_week = $days_of_week[$dow];
257 $day_of_the_month_R = $master_day_in_month_R - $day_in_month_incrementer[$dow];
258 $day_stamp = gmdate('Y-m-d', $counter);
259
260 //populate a new element of the values array with the RRULE data for the day in question
261 $values[] = "('$day_stamp', $counter,'$day_of_the_week','". $master_day_in_month.$day_of_the_week ."','".
262 $day_of_the_month_R.$day_of_the_week."','".$master_month_day."','".$master_month_day_R."','".
263 $master_month ."','". $master_year_day."','". $master_year_day_R."','".$master_week_no."','". $master_week_no_R."')";
264
265 //increment the bailout counter, and check to see if it's at 500. if so
266 //then send the query and bail out
267 $bailout++;
268 if ($bailout > $_BAILOUT_VALUE) {
269 //$result = db_query($insert_line.implode(',', $values));
270 foreach ($values as $v) {
271 db_query($insert_line . $v);
272 }
273 return;
274 }
275 $counter += 86400;
276
277 //here we start checks to see if we're at the end of the current month--if it's december then increment the
278 //year counter and reset leap year, and set the month values for january (we need to set the month day values
279 //one less than they actually are, b/c they'll be incremented when the code swings around)
280 if ($days_in_month == $master_month_day) {
281 if ($master_month == 12) {
282 $master_year++;
283 $leap_year = (int) gmdate('L', $counter);
284 $days_in_month = 31;
285 $master_month = 1;
286 $master_month_day = 0;
287 $master_month_day_R = -32;
288
289 //set master day as the next day of the week in the cycle--this is the day of the week of the first
290 //day in january
291 if ($dow == 6) {
292 $master_day = 0;
293 }
294 else {
295 $master_day = $dow + 1;
296 }
297
298 //set these 1 less than they need to be here, b/c they'll be incremented to their correct value on next
299 //cycle through
300 $master_day_in_month = 0;
301 $master_day_in_month_R = -5;
302 $day_in_month_incrementer = _eventrepeat_day_in_month_incrementer($master_day, $days_in_month);
303 $master_year_day = 0;
304 $master_year_day_R = -366 - $leap_year;
305
306 //it's not december, so increment the month value, and set the new days in month and month day values
307 //once again the month day values need to be one less than their actual value
308 }
309 else {
310 $days_in_month = (int) gmdate('t', $counter);
311 $master_month++;
312 $master_month_day = 0;
313 $master_month_day_R = -$days_in_month -1;
314
315 //set master day as the next day of the week in the cycle--this is the day of the week of the first
316 //day of the next month
317 if ($dow == 6) {
318 $master_day = 0;
319 }
320 else {
321 $master_day = $dow + 1;
322 }
323
324 //set these 1 less than they need to be here, b/c they'll be incremented to their correct value on next
325 //cycle through, and reset the incrementer for the new month
326 $master_day_in_month = 0;
327 $master_day_in_month_R = -5;
328 $day_in_month_incrementer = _eventrepeat_day_in_month_incrementer($master_day, $days_in_month);
329 }
330 }
331 }
332
333 //we didn't bail out, so insert the new rows into the table, if there any rows to insert
334 if (count($values)) {
335 //$result = db_query($insert_line.implode(',', $values));
336 foreach ($values as $v) {
337 db_query($insert_line . $v);
338 }
339 }
340
341 //we've added new data to the calmap table, so render nodes for all repeat sequences
342 $endtime = $curtime + (variable_get('eventrepeat_initial_render', 90) * 86400);
343 _eventrepeat_render_nodes('all', $endtime, FALSE, FALSE, FALSE);
344 }
345
346 /**
347 * Implementation of form API hook_elements()
348 */
349 function eventrepeat_elements() {
350 $type['eventrepeat_date'] = array('#input' => TRUE, );
351 return $type;
352 }
353
354 /**
355 * Implementation of hook_form_alter().
356 *
357 * @ingroup eventrepeat_core
358 * @param $form_id The form being altered.
359 * @param $form The form array.
360 */
361 function eventrepeat_form_alter(&$form, $form_state, $form_id) {
362
363 //check here to see if the node is part of a repeat sequence
364 if ($form_id == 'node_delete_confirm') {
365 $node = node_load($form['nid']['#value']);
366 if ($node->eventrepeat_rid) {
367
368 //create the option array
369 $options = array(
370 'this' => t('This occurrence only'),
371 'future' => t('This occurrence and all future occurrences'),
372 'all' => t('All occurrences')
373 );
374
375 //construct the radio buttons. NOTE: in order to prevent name collisions in the admin
376 //delete process for multiple nodes, these form elements are named in array fashion, with nid to distinguish
377 //the elements of the array
378 $form['eventrepeat_delete_type']['#tree'] = TRUE;
379 $form['eventrepeat_delete_type']['#weight'] = -12;
380 $form['eventrepeat_delete_type'][$node->nid] = array(
381 '#type' => 'radios',
382 '#title' => t('Repeat event--delete the following'),
383 '#default_value' => variable_get('eventrepeat_default_edit_type', 'future'),
384 '#options' => $options,
385 '#description' => t('\'This occurrence and all future occurrences\' will delete repeat events from the date of the selected node forward, \'All occurrences\' will delete repeat events after today\'s date.'),
386
387 );
388 }
389 }
390
391 //inject node type settings checkbox for repeat events
392 elseif ($form_id == 'node_type_form') {
393 $node_type = $form['old_type']['#value'];
394 $form['workflow']["eventrepeat_nodeapi"] = array(
395 '#type' => 'checkbox',
396 '#title' => t('Allow repeat events'),
397 '#default_value' => variable_get("eventrepeat_nodeapi_$node_type", FALSE),
398 '#description' => t('If selected, users will be allowed to add repeating events for this node type'),
399 );
400 }
401
402 //inject the appropriate repeat data into the node form if the node type is repeat enabled
403 elseif ($form['type']['#value'] .'_node_form' == $form_id) {
404 if (variable_get('event_nodeapi_'. $form['type']['#value'], 'never') != 'never' &&
405 variable_get('eventrepeat_nodeapi_'. $form['type']['#value'], 0) == 1) {
406
407 //get the node info from the db if not in edit (remember the edit means we are previewing, usually)
408 if (isset($_POST['edit']) && (!empty($_POST['edit']))) {
409 $edit = $_POST['edit'];
410 $node = (object) $edit;
411 }
412 elseif (isset($form['nid']['#value'])) {
413 $node = node_load($form['nid']['#value']);
414 }
415
416 // If this is a new node and this user
417 // doesn't have access to create repeating events
418 // just return.
419 if (!$node->nid && !user_access('create repeat events')) {
420 return;
421 }
422 // If, however, this is an existing event that has
423 // a repeating pattern attached to it, we need to
424 // show the form because otherwise the user would
425 // end up breaking this node out of the repeat.
426 else if ($node->nid && (!$node->eventrepeat_rid && !user_access('create repeat events')) ) {
427 return;
428 }
429
430 // TODO: I'm not sure if this is in the right spot, but this seems to be the only reliable place to put it right now
431 // adds a new exception to the list if needed
432 _eventrepeat_form_add_exception($node);
433
434 // add the repeat pattern form elements
435 $form += theme('eventrepeat_form', $node);
436
437 }
438 }
439
440 /* this is a check for module dependencies. the only way we
441 can ensure this check happening when the module is initially
442 enabled is to insert the check for when the form is initially
443 built, which will also be caught when the admin/module page is
444 reloaded upon submission. this means we never want to call this
445 function when the form has been submitted, so make sure there's
446 no $_POST. */
447 elseif ($form_id == 'system_modules' && !$_POST) {
448 _eventrepeat_system_module_validate($form);
449 }
450 }
451
452 /**
453 * Implementation of hook_help().
454 *
455 * @ingroup eventrepeat_core
456 * @param $section The page which is requesting help.
457 * @return The help text.
458 */
459 function eventrepeat_help($path, $arg) {
460 switch ($path) {
461 // General help page
462 case 'admin/help#eventrepeat':
463 $output = '';
464 $output .= t('<p>Eventrepeat enables the creation of repeating event patterns for node types that are event-enabled. In order for repeating events to be created for a node type, you must first configure that node type to be enabled for repeating events. This is done from the <a href="!content_types">content types configuration page</a>. While you\'re in the configuration screen, check that the node type is also able to be viewed in the event calendar.</p>', array('!content_types' => url('admin/content/types')));
465 $output .= _eventrepeat_user_help_content(TRUE);
466 $output .= t('<p>Eventrepeat\'s pattern creation was largely modeled on the iCal RRULE specification. At this time, it should support all RRULE parameters, with the following exceptions:</p>');
467 $output .= t('<ol><li>Recurrance periods less than DAILY</li><li>BYDAY declarations greater than 5 and less than -5 (ex. 20th Monday of the year is not supported).Other similar patterns can be built that should approximate this functionality.</li> <li>BYSETPOS parameter</li><li>EXRULE parameter</li></ol>');
468 return $output;
469
470 // Settings page help
471 case 'admin/settings/eventrepeat':
472 return t('<p>Adjust how events repeat using the form below. To add the event repeat form to node forms, visit the <a href="!settings">content types page</a>.</p>', array('!settings' => url('admin/content/types')));
473 }
474 }
475
476 /**
477 * Implementation of hook_menu().
478 *
479 * @ingroup eventrepeat_core
480 * @param $may_cache A boolean indicating whether cacheable menu items should be returned.
481 * @return An array of menu items. Each menu item is an associative array.
482 */
483 function eventrepeat_menu() {
484
485 $items['admin/settings/eventrepeat'] = array(
486 'title' => 'Repeating Events',
487 'description' => 'Change how repeating events are handled.',
488 'page callback' => 'drupal_get_form',
489 'page arguments' => array('eventrepeat_admin_settings'),
490 'access arguments' => array('administer site configuration'),
491 'type' => MENU_NORMAL_ITEM, // optional
492 'weight' => 0
493 );
494 $items['admin/settings/eventrepeat/debug'] = array(
495 'title' => 'Debug',
496 'description' => 'Debug repeating events by seeing all patterns at a glance.',
497 'page callback' => 'eventrepeat_debug',
498 'access arguments' => array('administer site configuration'),
499 'weight' => 0
500 );
501 $items['admin/settings/eventrepeat/reset'] = array(
502 'title' => 'Reset',
503 'description' => 'Reset the event repeat map.',
504 'page callback' => 'drupal_get_form',
505 'page arguments' => array('eventrepeat_refresh_calendar_map'),
506 'access arguments' => array('administer site configuration'),
507 'weight' => 1
508 );
509 $items['eventrepeat/help'] = array(
510 'title' => 'How to create repeating events',
511 'description' => 'How to create repeating events.',
512 'page callback' => 'eventrepeat_user_help_page',
513 'access arguments' => array('access content'),
514 'type' => MENU_CALLBACK,
515 );
516 return $items;
517 }
518
519 /**
520 * Implementation of hook_perm().
521 * @ingroup eventrepeat_core
522 */
523 function eventrepeat_perm() {
524 return array('create repeat events');
525 }
526
527 /**
528 * @defgroup eventrepeat_nodeapi Functions for nodeapi integration
529 */
530
531 /**
532 * hook_nodeapi implementation
533 *
534 * @ingroup eventrepeat_nodeapi
535 * @param &$node The node the action is being performed on.
536 * @param $op What kind of action is being performed.
537 * @return This varies depending on the operation.
538 */
539 function eventrepeat_nodeapi(&$node, $op) {
540
541 // only continue if this node is event and event_repeat enabled
542 if (variable_get('event_nodeapi_'. $node->type, 'never') == 'never' &&
543 variable_get('eventrepeat_nodeapi_'. $node->type, 0) == 0) {
544 return;
545 }
546
547 //this holds the old start time of an event, for use in mass updates
548 static $old_times;
549
550 //for all ops except settings, make sure that the node is event & eventrepeat enabled before executing
551 switch ($op) {
552
553 case 'validate':
554 // no break. both need a node with a formatted date and event_start
555 // and event_end set, 'validate' for the previewing and 'submit' for
556 // update/insert.
557
558 case 'presave':
559
560 // TODO: what if the user wants to "turn off" the repeating event
561 // the user is trying to turn off repeating events for all future events
562 if (($node->eventrepeat_FREQ == '' || $node->eventrepeat_FREQ == 'NONE') && ($node->eventrepeat_edit_type == 'future' || $node->eventrepeat_edit_type == 'all')) {
563 form_set_error('eventrepeat_FREQ', t('Trying to remove a repeat setting from a repeating event is not currently supported. Please try deleting the events you don\'t want instead.'));
564 }
565
566 //validate the repeat end date
567 _eventrepeat_validate_form_date('eventrepeat_end', t('Repeat end'), $node);
568
569 // TODO: this would cause an odd error if the person wanted
570 // to remove the repeating sequence so I removed it for now.
571 //if they have some repeat options chosen,
572 // make sure a repeat type is selected
573 /*
574 if ($node->eventrepeat_FREQ == 'NONE' &&
575 ($node->eventrepeat_COUNT
576 || $node->eventrepeat_INTERVAL > 1
577 || $node->eventrepeat_BYDAY
578 || $node->eventrepeat_BYWEEKNO
579 || $node->eventrepeat_BYMONTH
580 || $node->eventrepeat_BYMONTHDAY
581 || $node->eventrepeat_BYYEARDAY
582 || $node->eventrepeat_EXDATE)
583 ) {
584 form_set_error('eventrepeat_FREQ', t('You must select a Repeat Type if you want this event to repeat.'));
585 }
586 */
587
588 //warn if user entered values for both repeat end and COUNT
589 if ($node->eventrepeat_end && $node->eventrepeat_COUNT) {
590 form_set_error('eventrepeat_end', t('\'Repeat end date\' and \'count\' cannot both be set--select only one to provide a valid end point for the sequence'));
591 }
592
593 // TODO: if this is unsupported, can we just use end date after the initial render?
594 //warn if user tries to edit a sequence based on COUNT--this is currently not supported
595 if ($node->eventrepeat_rid && $node->eventrepeat_COUNT) {
596 form_set_error('eventrepeat_COUNT', t('Editing a sequence which uses the \'count\' parameter is not currently supported. You may need to delete this event.'));
597 }
598
599 break;
600
601 case 'delete':
602 static $mass_delete;
603 global $form_values;
604 //determine what kind of delete we're doing here. check $form_values to see if it's a mass delete
605 //and mark it as such if so. otherwise just delete the node from the detail table
606 if ($form_values['eventrepeat_delete_type'][$node->nid] &&
607 $form_values['eventrepeat_delete_type'][$node->nid] != 'this') {
608
609 $mass_delete = TRUE;
610 _eventrepeat_delete_nodes($form_values['eventrepeat_delete_type'][$node->nid], $node);
611 //this line necessary to clean up mods after eventrepeat
612 node_invoke_nodeapi($node, 'delete');
613 }
614 else {
615 db_query("DELETE FROM {eventrepeat_nodes} WHERE nid = %d", $node->nid);
616
617 //if not a mass delete, check to see if this is the last repeat event in this sequence. if so, then
618 //delete the sequence
619 if (!$mass_delete) {
620 db_query("DELETE FROM {eventrepeat} WHERE rid = %d", $node->eventrepeat_rid);
621 }
622 }
623
624
625 break;
626 case 'load':
627
628 if (variable_get('event_nodeapi_'. $node->type, 'never') != 'never') {
629
630 //if the old start time hasn't been saved to the update code yet, then save it. this is a total hack,
631 //but i don't know any other way to do it
632 if (!$old_times && $form_state['values']['op'] == t('Submit')) {
633 $old_times = db_query('SELECT e.event_start, e.event_end, e.timezone FROM {event} e WHERE e.nid = %d', $node->nid);
634 if (db_num_rows($old_times)) {
635 $old_times = db_fetch_object($old_times);
636 $old_times->eventrepeat_old_times = TRUE;
637 _eventrepeat_update_nodes($old_times, NULL);
638 }
639 }
640
641 //if it's a repeat node, grab the repeat data for the node
642 if (variable_get('eventrepeat_nodeapi_'. $node->type, 0) == 1) {
643 $object = db_fetch_object(db_query('SELECT e_r.rid, repeat_RRULE, repeat_end
644 FROM {eventrepeat} e_r INNER JOIN {eventrepeat_nodes} e_r_n ON
645 e_r.rid = e_r_n.rid WHERE e_r_n.nid = %d', $node->nid));
646
647 //if this node is in a repeat sequence, parse the RRULE, and return repeat data to the node
648 if ($object->rid) {
649
650 //append the repeat tag to the title if it's an event page
651 if (arg(0) == 'event') {
652 $node->title = theme("eventrepeat_title_tag", $node->title);
653 }
654 $items = _eventrepeat_parse_ical($object->repeat_RRULE);
655 return array('eventrepeat_rid' => $object->rid,
656 'eventrepeat_FREQ' => $items[0]['FREQ'],
657 'eventrepeat_COUNT' => $items[0]['COUNT'],
658 'eventrepeat_INTERVAL' => $items[0]['INTERVAL'],
659 'eventrepeat_BYDAY' => $items[0]['BYDAY'],
660 'eventrepeat_BYWEEKNO' => $items[0]['BYWEEKNO'],
661 'eventrepeat_BYMONTH' => $items[0]['BYMONTH'],
662 'eventrepeat_BYMONTHDAY' => $items[0]['BYMONTHDAY'],
663 'eventrepeat_BYYEARDAY' => $items[0]['BYYEARDAY'],
664 'eventrepeat_EXDATE' => $items[0]['EXDATE'],
665 'eventrepeat_end' => $object->repeat_end, // placeholder in case the end date processing changes
666 'eventrepeat_endyear' => $object->repeat_end ? _event_date('Y', $object->repeat_end) : 0,
667 'eventrepeat_endmonth' => $object->repeat_end ? _event_date('n', $object->repeat_end) : 0,
668 'eventrepeat_endday' => $object->repeat_end ? _event_date('d', $object->repeat_end) : 0
669 );
670 }
671 }
672 }
673 break;
674
675 case 'insert':
676
677 // add a new exception to the list if needed
678 _eventrepeat_form_add_exception($node);
679
680 // if this node has eventrepeat_FREQ info
681 // remember that we strip this for new instances
682 // in _eventrepeat_render_nodes
683 if ($node->eventrepeat_FREQ != '' && $node->eventrepeat_FREQ != 'NONE') {
684 _eventrepeat_save_repeat($node);
685 }
686
687 break;
688
689
690 case 'update':
691 //setting a static indicator here--this case will more than likely get called
692 //multiple times as nodes are updated, but we only want the repeat update
693 //itself to run once per page load.
694 static $update_run = NULL;
695 if (!isset($update_run)) {
696 $update_run = TRUE;
697 // add a new exception to the list if needed
698 _eventrepeat_form_add_exception($node);
699
700 //determine what kind of update we're doing here. it's either all (from current date
701 //forward), future (current node and all future nodes) or just an individual node update
702 //pass all and future to the mass edit code
703 if ($node->eventrepeat_edit_type == 'future') {
704 //we have to update the existing nodes first before we update the repeat pattern
705 //only update the repeat pattern if the node update was successful.
706 if (_eventrepeat_update_nodes($node, $node->event_start) === TRUE) {
707 _eventrepeat_save_repeat($node);
708 }
709 }
710 elseif ($node->eventrepeat_edit_type == 'all') {
711 //we have to update the existing nodes first before we update the repeat pattern
712 //only update the repeat pattern if the node update was successful.
713 if (_eventrepeat_update_nodes($node, time()) === TRUE) {
714 _eventrepeat_save_repeat($node);
715 }
716 }
717 elseif ($node->eventrepeat_edit_type == 'this') {
718 //if it's an individual edit, and admin has selected that they are to be removed from sequences,
719 //then delete from detail table
720 if (!variable_get('eventrepeat_single_edit_in_sequence', FALSE)) {
721 db_query("DELETE FROM {eventrepeat_nodes} WHERE nid = %d", $node->nid);
722 }
723 }
724 // the user is turning a non-repeat event into a repeat event
725 elseif (($node->eventrepeat_FREQ != '' && $node->eventrepeat_FREQ != 'NONE') && !$node->eventrepeat_rid) {
726 _eventrepeat_save_repeat($node);
727 }
728 }
729 break;
730
731
732 case 'view':
733 break;
734 }
735 }
736
737 /**
738 * @defgroup eventrepeat_event Functions which use hooks in event.module
739 */
740
741 /**
742 * hook_event_edit_upcoming implementation
743 *
744 * @ingroup eventrepeat_event
745 * @param $node The node the action is being performed on (not a full node).
746 * @return None--edits are made directly to the $node object prior to rendering
747 */
748 function eventrepeat_event_edit_upcoming(&$node) {
749
750 //if this node appears in the detail table, then add the repeat tag to it
751 if (db_result(db_query('SELECT nid FROM {eventrepeat_nodes} WHERE nid = %d', $node->nid))) {
752 $node->title = theme("eventrepeat_title_tag", $node->title);
753 }
754 }
755
756 /**
757 * hook_event_load implementation
758 *
759 * @ingroup eventrepeat_event
760 * @param $year The year of the rendered calendar view.
761 * @param $month The month of the rendered calendar view.
762 * @param $day The day of the rendered calendar view. No leading zeroes.
763 * @param $view The calendar view being rendered
764 * @param $types unused
765 * @param $terms unused
766 * @return None--allows for node creation which only.
767 */
768 function eventrepeat_event_load($year, $month, $day, $view, $types, $terms) {
769
770 //only should be run once per page call
771 static $execute;
772 if (!$execute) {
773 $execute = 1;
774
775 //default $view to either the default view setting, or 'month' if it's not set
776 $view = $view ? $view : variable_get('event_overview', 'month');
777
778 //first thing is to determine the exact range that's going to be rendered, and calculate start and end timestamps
779 $calendar_period_start = _event_mktime(23, 59, 59, $month, $day, $year);
780 switch ($view) {
781 case 'day':
782 $endtime = $calendar_period_start;
783 break;
784
785 case 'week':
786 //calculate the end of the week (not perfect, but close enough!)
787 $endtime = $calendar_period_start + (86400*7);
788 break;
789
790 case 'month':
791 //generate the end date based on number of days in the month
792 $endtime = gmmktime(23, 59, 59, $month, gmdate('t', $calendar_period_start), $year);
793 break;
794
795 case 'table':
796 case 'list':
797 //table/list end is simply the start day of the viewing period plus the event_table_duration. if duration
798 //is specified as an argument, then make sure it's not longer than a year. if not, then just use the
799 //table duration default or 30 days
800 $duration = arg(7);
801 $numberofdays = $duration && $duration < 366 ? $duration : variable_get('event_table_duration', '30');
802 $endtime = gmmktime(23, 59, 59, $month, $day + $numberofdays, $year);
803 break;
804
805 default:
806 return;
807 }
808
809 //check here to see if the user is viewing a date outside of the rendering range. if so, warn and exit
810 $curtime = time();
811 $curtime_end = gmmktime(23, 59, 59, (int) gmdate('n', $curtime), (int) gmdate('j', $curtime),
812 (int) gmdate('Y', $curtime));
813 $render_support = $curtime_end + (variable_get('eventrepeat_render_support', 2000) * 86400);
814 if ($endtime > $render_support) {
815 drupal_set_message(t('This calendar view is outside of the range of repeat event support'));
816 return;
817 }
818
819 //check here to see if the calendar is outside of the initial render range. if so, then render all repeat
820 //sequences through the end time of the calendar period
821 $past_initial_render = $curtime_end - 86400 + (variable_get('eventrepeat_initial_render', 90) * 86400);
822 if ($endtime > $past_initial_render) {
823 _eventrepeat_render_nodes('all', $endtime, FALSE, FALSE, FALSE);
824 }
825 }
826 }
827
828 /**
829 * @defgroup eventrepeat_support Functions that support the eventrepeat system
830 */
831
832 /**
833 * Helper function that corrects for date GMT date changes based on timezone
834 *
835 * @ingroup eventrepeat_support
836 * @param $starthour The start hour of the event.
837 * @param $startminute The start minute of the event.
838 * @param $offset The timezone offset of the event.
839 * @return Day offset in seconds.
840 */
841 function _eventrepeat_day_correction($starthour, $startminute, $offset) {
842
843 //if the GMT day for the event falls on a different day than the local day, we have to account for that
844 //since the event_repeat_calendar map table has all of it's day info in GMT
845 //here we check that by adding the timezone offset to the starthour--if the result is less than zero, then
846 //we need to add a day to the rendering date, and if it's greater than 24, we need to subtract a day from the
847 //rendering date
848 if ($offset > 0) {
849 $day_offset = (((($starthour * 3600) + ($startminute * 60)) + $offset) > 86400) ? -86400 : 0;
850 }
851 elseif ($offset < 0) {
852 $day_offset = (((($starthour * 3600) + ($startminute * 60)) + $offset) < 0) ? 86400 : 0;
853 }
854 else {
855 $day_offset = 0;
856 }
857
858 return $day_offset;
859 }
860
861 /**
862 * Helper function that gives information on the number of each of the days in the month for each of the seven days
863 *
864 * @ingroup eventrepeat_support
865 * @param $master_day The day of the week of the first day of the month.
866 * @param $days_in_month The number of days in the month.
867 * @return An array in the same order as the days of the week (Sun-Sat), with values of 0 for days of the week with 4 occurrences, and 1 for days of the week with 5 occurrences.
868 */
869 function _eventrepeat_day_in_month_incrementer($master_day, $days_in_month) {
870
871 //some days of the week in a month occur 4 times, and some occur 5 times. here we're building an array that will
872 //store data of this kind for the current month. any days of the week that occur five times in the month are given
873 //a value of 1 in this array, so that the $master_day_in_month_R counter can be adjusted correctly for these days
874 $day_in_month_incrementer = array(0, 0, 0, 0, 0, 0, 0);
875 for ($i = 29; $i <= $days_in_month; $i++) {
876 $day_in_month_incrementer[$master_day] = 1;
877 $master_day == 6 ? $master_day = 0 : $master_day++;
878 }
879 return $day_in_month_incrementer;
880 }
881
882 /**
883 * Helper function that handles mass deletion of nodes in a repeat sequence
884 *
885 * @ingroup eventrepeat_support
886 * @param $op The operation to be performed (either 'this', 'all', or 'future').
887 * @param $node The root node which the mass delete operation is based on.
888 * @return None.
889 */
890 function _eventrepeat_delete_nodes($op, $node) {
891
892 global $form_values;
893
894 //unset eventrepeat_delete_type for this nid to prevent this function from being called mutliple times
895 //also set the current GMT timestamp
896 unset($form_values['eventrepeat_delete_type'][$node->nid]);
897 $curtime = time();
898
899 //delete the entry in the repeat_nodes table for the current node being deleted
900 db_query("DELETE FROM {eventrepeat_nodes} WHERE nid = %d", $node->nid);
901
902 //set the proper timestamp for the nodes to delete query. for 'all' this will be from the current
903 //date forward, and for 'future', it will be from the node's event->start time--if this is an update
904 //delete, it will be just after the passed in update end time
905 if ($op == 'all') {
906 $timestamp = $curtime;
907 }
908 elseif ($op == 'future') {
909 $timestamp = $node->event_start;
910 }
911
912 //pull all of the nids for nodes that are to be deleted from this sequence
913 $result = db_query("SELECT e_r_n.nid FROM {eventrepeat_nodes} e_r_n INNER JOIN {event} e ON
914 e_r_n.nid = e.nid WHERE e_r_n.rid = %d AND e.event_start >= %d", $node->eventrepeat_rid, $timestamp);
915
916 //loop through the nids, calling node_delete for all nodes in the result set
917 while ($node_to_delete = db_fetch_object($result)) {
918 node_delete($node_to_delete->nid);
919 }
920
921 //pull the start times for the remaining nodes in this repeat sequence
922 $result = db_query("SELECT e.event_start FROM {eventrepeat_nodes} e_r_n INNER JOIN {event} e ON
923 e_r_n.nid = e.nid WHERE e_r_n.rid = %d ORDER BY e.event_start DESC", $node->eventrepeat_rid);
924 $num_rows = FALSE;
925 if ($last_rendered = db_fetch_object($result)) {
926 //there are still nodes in the repeat sequence--in this case we want to keep the repeat sequence intact
927 //since it may still need to be mass edited/deleted, but we also want to end creation of any new nodes,
928 //so here we grab the start date of the latest node in the sequence and set the end date of the sequence equal
929 //to it.
930 $last_rendered = gmmktime(23, 59, 59,
931 (int) gmdate('n', $last_rendered->event_start),
932 (int) gmdate('j', $last_rendered->event_start),
933 (int) gmdate('Y', $last_rendered->event_start)
934 );
935 db_query("UPDATE {eventrepeat} SET repeat_end = %d, repeat_last_rendered = %d WHERE rid = %d",
936 $last_rendered, $last_rendered, $node->eventrepeat_rid);
937 }
938 else {
939 //no nodes left in the sequence, so delete the repeat data
940 db_query("DELETE FROM {eventrepeat} WHERE rid = %d", $node->eventrepeat_rid);
941 }
942 }
943
944 /**
945 * Generates the repeat setting form under the repeat tab, and saves repeat data to the repeat tables.
946 *
947 * @ingroup eventrepeat_support
948 * @param $node Either the $node object from the db or the node object from $_POST['edit']
949 * @return Fully themed page containing the repeat setting form.
950 */
951 function theme_eventrepeat_form($node) {
952
953 //if the node is part of a repeat sequence, then construct the radio buttons for mass edit
954 // TODO: review default change: moved to default of future because
955 // otherwise I found that users would keep trying to change exceptions and
956 // make other repeat pattern updates on occurrences by accident.
957 // The "this" options is also the most destructive of the three.
958 // The "future" maps a bit better to how iCal works.
959 if ($node->eventrepeat_rid) {
960 $form['eventrepeat_rid'] = array('#type' => 'hidden', '#value' => $node->eventrepeat_rid);
961 $options = array(
962 'this' => t('This occurrence only'),
963 'future' => t('This occurrence and all future occurrences'),
964 'all' => t('All occurrences')
965 );
966 $form['eventrepeat_edit_type'] = array(
967 '#type' => 'radios',
968 '#title' => t('Apply edit(s) to'),
969 '#default_value' => variable_get('eventrepeat_default_edit_type', 'future'),
970 '#options' => $options,
971 '#description' => t('\'This occurrence and all future occurrences\' will edit repeat events from the date of the selected node forward, \'All occurrences\' will edit repeat events after today\'s date. <br />Note: editing a single occurrence will remove it from the repeat sequence.'),
972 '#weight' => -12
973 );
974 }
975
976 // figure out what we are expanding and create the main fieldset
977 $exception_collapsed = ($node->eventrepeat_EXDATE) ? FALSE : TRUE;
978 $advanced_collapsed = ($node->eventrepeat_INTERVAL > 1
979 || $node->eventrepeat_BYDAY
980 || $node->eventrepeat_BYMONTH
981 || $node->eventrepeat_BYMONTHDAY
982 || $node->eventrepeat_BYYEARDAY
983 || $node->eventrepeat_BYWEEKNO
984 ) ? FALSE: TRUE;
985 $collapsed = TRUE;
986 if (($node->eventrepeat_FREQ != '' && $node->eventrepeat_FREQ != 'NONE')
987 || $exception_collapsed == FALSE
988 || $advanced_collapsed == FALSE
989 ) {
990 $collapsed = FALSE;
991 }
992 $help = '<p>'. l(t('Need help creating a repeat pattern?'), 'eventrepeat/help', array('target' => '_blank')) .'<br />'. t('NOTE: Editing an existing repeat pattern maps previously created events to the new pattern, in sequential order, on all dates from the date where the edit is performed.') .'</p>';
993 $form['eventrepeat'] = array(
994 '#type' => 'fieldset',
995 '#title' => t('Repeat'),
996 '#tree' => FALSE,
997 '#collapsible' => TRUE,
998 '#collapsed' => $collapsed,
999 '#weight' => -12,
1000 '#description' => $help,
1001 );
1002
1003 //link to user help for repeat patterns
1004 //$form['eventrepeat_advanced']['help'] = array('#type' => 'markup', '#value' => '<p>'. l(t('Need help creating a repeat pattern?'), 'eventrepeat/help') .'<br />'. t('NOTE: Editing an existing repeat pattern maps previously created events to the new pattern, in sequential order, on all dates from the date where the edit is performed.') .'</p>');
1005
1006
1007 //FREQ param select box
1008 $options = array(
1009 'NONE' => t('none'),
1010 'DAILY' => t('Daily'),
1011 'WEEKLY' => t('Weekly'),
1012 'MONTHLY' => t('Monthly'),
1013 'YEARLY' => t('Yearly')
1014 );
1015 $form['eventrepeat']['eventrepeat_FREQ'] = array(
1016 '#type' => 'select',
1017 '#title' => t('Repeat type'),
1018 '#default_value' => $node->eventrepeat_FREQ ? $node->eventrepeat_FREQ : 'NONE',
1019 '#options' => $options,
1020 '#description' => t('select \'none\' to disable repeats for this event')
1021 );
1022
1023 //put end controls in a group to make them less confusing
1024 $form['eventrepeat']['end_controls'] = array(
1025 '#type' => 'fieldset',
1026 '#title' => t('End Settings'),
1027 '#collapsible' => TRUE,
1028 '#description' => t('Select either the end date or the number of times you want this event to repeat.')
1029 );
1030
1031 //date box for end date
1032 $form['eventrepeat']['end_controls']['end_date'] = array(
1033 '#type' => 'eventrepeat_date',
1034 '#title' => t('Repeat end date'),
1035 '#process' => array('_eventrepeat_form_date' => array($node, 'eventrepeat_end'))
1036 );
1037
1038 // the - or - markup
1039 $form['eventrepeat']['end_controls']['or'] = array('#type' => 'markup', '#value' => '<b>---'. t('OR') .'---</b>');
1040
1041 // TODO: if editing based on count is unsupported, can we just use end date after the initial render?
1042 //COUNT param select box
1043 $options = array(0 => '--'. t('Select') .'--');
1044 for ($i = 2; $i <= 100; $i++) {
1045 $options[$i] = $i;
1046 }
1047 $form['eventrepeat']['end_controls']['eventrepeat_COUNT'] = array(
1048 '#type' => 'select',
1049 '#title' => t('count'),
1050 '#default_value' => $node->eventrepeat_COUNT ? $node->eventrepeat_COUNT : 0,
1051 '#options' => $options,
1052 '#description' => t('Determines the number of repeat nodes that will be created for the repeat sequence')
1053 );
1054
1055 // Add the advanced options
1056 $form['eventrepeat'][] = theme('eventrepeat_form_advanced', $node, $advanced_collapsed);
1057
1058 // Removed the exception form because it wasn't working right. You can just delete the instances you want anyway.
1059 //$form['eventrepeat'][] = theme('eventrepeat_form_exception', $node, $exception_collapsed);
1060
1061 return $form;
1062
1063 }
1064
1065 /**
1066 * theme the advanced fieldset of form elements
1067 */
1068 function theme_eventrepeat_form_advanced($node, $advanced_collapsed) {
1069 $options = array();
1070
1071 $show_advanced = variable_get('eventrepeat_showadvanced', array());
1072 if ($show_advanced['eventrepeat_INTERVAL'] == FALSE
1073 && $show_advanced['eventrepeat_BYDAY'] == FALSE
1074 && $show_advanced['eventrepeat_BYWEEKNO'] == FALSE
1075 && $show_advanced['eventrepeat_BYMONTH'] == FALSE
1076 && $show_advanced['eventrepeat_BYMONTHDAY'] == FALSE
1077 && $show_advanced['eventrepeat_BYYEARDAY'] == FALSE
1078 ) {
1079 return;
1080 }
1081 $form = array();
1082
1083 // start the advanced fieldset
1084 $form['eventrepeat_advanced'] = array(
1085 '#type' => 'fieldset',
1086 '#title' => t('Advanced'),
1087 '#collapsible' => TRUE,
1088 '#collapsed' => $advanced_collapsed,
1089 '#tree' => FALSE,
1090 );
1091
1092 //INTERVAL param select box
1093 if ($show_advanced['eventrepeat_INTERVAL']) {
1094 for ($i = 1; $i <= 60; $i++) {
1095 $options[$i] = $i;
1096 }
1097 $form['eventrepeat_advanced']['eventrepeat_INTERVAL'] = array(
1098 '#type' => 'select',
1099 '#title' => t('Interval'),
1100 '#default_value' => ($node->eventrepeat_INTERVAL) ? $node->eventrepeat_INTERVAL : 1, '#options' => $options,
1101 '#description' => t('Frequency of repeat: 1 = every, 2 = every other, 3 = every 3rd, etc.')
1102 );
1103 }
1104
1105 //set days of the week array, and copy it into $dow
1106 $options = array(
1107 'SU' => t('Sunday'),
1108 'MO' => t('Monday'),
1109 'TU' => t('Tuesday'),
1110 'WE' => t('Wednesday'),
1111 'TH' => t('Thursday'),
1112 'FR' => t('Friday'),
1113 'SA' => t('Saturday')
1114 );
1115 $dow = $options;
1116
1117 //set the count options array
1118 $dowcount = array(
1119 '1' => t('1st'),
1120 '2' => t('2nd'),
1121 '3' => t('3rd'),
1122 '4' => t('4th'),
1123 '5' => t('5th'),
1124 '-1' => t('Last'),
1125 '-2' => t('Next to Last'),
1126 '-3' => t('2nd from Last'),
1127 '-4' => t('3rd from Last'),
1128 '-5' => t('4th from Last')
1129 );
1130
1131 //loop through each day of the week, looping through each count option, and build an array of all combinations
1132 foreach ($dow as $dowkey => $dowvalue) {
1133 foreach ($dowcount as $countkey => $countvalue) {
1134 $options[$countkey . $dowkey] = $countvalue .' '. $dowvalue;
1135 }
1136 }
1137
1138 //BYDAY param select box
1139 if ($show_advanced['eventrepeat_BYDAY']) {
1140 $form['eventrepeat_advanced']['eventrepeat_BYDAY'] = array(
1141 '#type' => 'select',
1142 '#title' => t('Day(s)'),
1143 '#default_value' => $node->eventrepeat_BYDAY ? $node->eventrepeat_BYDAY : '',
1144 '#options' => $options, '#description' => t('Determines what day(s) of the week/month this event repeats on (by day of the week). Lots of options available, scroll down!'),
1145 '#attributes' => array('size' => '7'),
1146 '#multiple' => TRUE
1147 );
1148 }
1149
1150
1151 //BYMONTH param select box
1152 if ($show_advanced['eventrepeat_BYMONTH']) {
1153 $options = array(
1154 1 => t('January'),
1155 2 => t('February'),
1156 3 => t('March'),
1157 4 => t('April'),
1158 5 => t('May'),
1159 6 => t('June'),
1160 7 => t('July'),
1161 8 => t('August'),
1162 9 => t('September'),
1163 10 => t('October'),
1164 11 => t('November'),
1165 12 => t('December'),
1166 );
1167 $form['eventrepeat_advanced']['eventrepeat_BYMONTH'] = array(
1168 '#type' => 'select',
1169 '#title' => t('Month(s)'),
1170 '#default_value' => $node->eventrepeat_BYMONTH ? $node->eventrepeat_BYMONTH : '',
1171 '#options' => $options,
1172 '#description' => t('Selects what month(s) of the year this event repeats on'),
1173 '#multiple' => TRUE,
1174 '#size' => 5,
1175 );
1176 }