first commit
[step2_drupal.git] / date / date_repeat / date_repeat_form.inc
blobe6365c3ec729b572895c09e84b5fde9283519eb0
1 <?php
2 // $Id: date_repeat_form.inc,v 1.15.4.13 2009/02/16 23:46:08 karens Exp $
3 /**
4  * @file
5  * Code to add a date repeat selection form to a date field and create
6  * an iCal RRULE from the chosen selections.
7  *
8  * Moved to a separate file since it is not used on most pages
9  * so the code is not parsed unless needed.
10  *
11  * Currently implemented:
12  * INTERVAL, UNTIL, EXDATE, BYDAY, BYMONTHDAY, BYMONTH,
13  * YEARLY, MONTHLY, WEEKLY, DAILY
14  *
15  * Currently not implemented:
16  *
17  * BYYEARDAY, MINUTELY, HOURLY, SECONDLY, BYMINUTE, BYHOUR, BYSECOND
18  *   These could be implemented in the future.
19  *
20  * COUNT
21  *   The goal of this module is to create a way we can parse an iCal
22  *   RRULE and pull out just dates for a specified date range, for
23  *   instance with a date that repeats daily for several years, we might
24  *   want to only be able to pull out the dates for the current year.
25  *
26  *   Adding COUNT to the rules we create makes it impossible to do that
27  *   without parsing and computing the whole range of dates that the rule
28  *   will create. COUNT is left off of the user form completely for this
29  *   reason.
30  *
31  * BYSETPOS
32  *   Seldom used anywhere, so no reason to complicated the code.
33  */
34 /**
35  * Generate the repeat setting form.
36  */
37 function _date_repeat_rrule_process($element, $edit, $form_state, $form) {
38   require_once('./'. drupal_get_path('module', 'date_api') .'/date_api_ical.inc');
39   
40   if (empty($element['#date_repeat_widget'])) {
41     $element['#date_repeat_widget'] = module_exists('date_popup') ? 'date_popup' : 'date_select';
42   }
43   if (is_array($element['#value'])) {
44     $element['#value'] = date_repeat_merge($element['#value'], $element);
45     $rrule = date_api_ical_build_rrule($element['#value']);
46   }
47   else {
48     $rrule = $element['#value'];
49   }
50   // Empty the original string value of the RRULE so we can create
51   // an array of values for the form from the RRULE's contents.
52   $element['#value'] = '';
54   $parts = date_repeat_split_rrule($rrule);
55   $rrule = $parts[0];
56   $exceptions = $parts[1];
57   $timezone = !empty($element['#date_timezone']) ? $element['#date_timezone'] : date_default_timezone_name();
58   $merged_values = date_repeat_merge($rrule, $element);
59   
60   $UNTIL = '';
61   if (!empty($merged_values['UNTIL']['datetime'])) {
62     $until_date = date_make_date($merged_values['UNTIL']['datetime'], $merged_values['UNTIL']['tz']);
63     date_timezone_set($until_date, timezone_open($timezone));
64     $UNTIL = date_format($until_date, DATE_FORMAT_DATETIME);
65   }
66   $parent_collapsed = !empty($rrule['INTERVAL']) || !empty($rrule['FREQ']) ? 0 : (!empty($element['#date_repeat_collapsed']) ? $element['#date_repeat_collapsed'] : 0);
67   $element['#type'] = 'fieldset';
68   $element['#title'] = t('Repeat');
69   $element['#description'] = theme('advanced_help_topic', 'date_api', 'date-repeat-form') . t('Choose a frequency and period to repeat this date. If nothing is selected, the date will not repeat.');
70   $element['#collapsible'] = TRUE;
71   $element['#collapsed'] = $parent_collapsed;
72   
73   // Make sure we don't get floating parts where we don't want them.
74   $element['#prefix'] = '<div class="date-clear">';
75   $element['#suffix'] = '</div>';
76   
77   $element['INTERVAL'] = array(
78     '#type' => 'select',
79     //'#title' => t('Interval'),
80     '#default_value' => (!empty($rrule['INTERVAL']) ? $rrule['INTERVAL'] : 0),
81     '#options' => INTERVAL_options(),
82     '#prefix' => '<div class="date-repeat-input">',
83     '#suffix' => '</div>',
84   );
86   $element['FREQ'] = array(
87     '#type' => 'select',
88     //'#title' => t('Frequency'),
89     '#default_value' => !empty($rrule['FREQ']) ? $rrule['FREQ'] : 'NONE',
90     '#options' => FREQ_options(),
91     '#prefix' => '<div class="date-repeat-input">',
92     '#suffix' => '</div>',
93   );
95   $element['UNTIL'] = array(
96     '#tree' => TRUE,
97     '#prefix' => '<div class="date-clear">',
98     '#suffix' => '</div>',
99     'datetime' => array(
100       '#type' => $element['#date_repeat_widget'],
101       '#title' => t('Until'),
102       '#description' => t('Date to stop repeating this item.'),
103       '#default_value' => $UNTIL,
104       '#date_timezone' => $timezone,
105       '#date_format' => !empty($element['#date_format']) ? $element['#date_format'] : 'Y-m-d',
106       '#date_text_parts'  => !empty($element['#date_text_parts']) ? $element['#date_text_parts'] : array(),
107       '#date_year_range'  => !empty($element['#date_year_range']) ? $element['#date_year_range'] : '-3:+3',
108       '#date_label_position' => !empty($element['#date_label_position']) ? $element['#date_label_position'] : 'within',
109       ),
110     'tz' => array('#type' => 'hidden', '#value' => $element['#date_timezone']),
111     'all_day' => array('#type' => 'hidden', '#value' => 1),
112     'granularity' => array('#type' => 'hidden', '#value' => serialize(array('year', 'month', 'day'))),
113     );
114   
115   $collapsed = TRUE;
116   if (!empty($merged_values['BYDAY']) || !empty($merged_values['BYMONTH'])) {
117     $collapsed = FALSE;
118   }
119         // start the advanced fieldset
120   $element['advanced'] = array(
121     '#type' => 'fieldset',
122     '#title' => t('Advanced'),
123     '#collapsible' => TRUE,
124     '#collapsed' => $collapsed,
125     '#description' => t("If no advanced options are selected, the date will repeat on the day of week of the start date for weekly repeats, otherwise on the month and day of the start date. Use the options below to override that behavior to select specific months and days to repeat on. Use the 'Except' box to input dates that should be omitted from the results.") .' ',
126     '#prefix' => '<div class="date-clear">',
127     '#suffix' => '</div>',
128     );
130   $element['advanced']['BYMONTH'] = array(
131     '#type' => 'select',
132     '#title' => date_t('Month', 'datetime'),
133     '#default_value' => !empty($rrule['BYMONTH']) ? $rrule['BYMONTH'] : '',
134     '#options' => array('' => t('-- Any')) + date_month_names(TRUE),
135     '#multiple' => TRUE,
136     '#size' => 10,
137     '#prefix' => '<div class="date-repeat-input">',
138     '#suffix' => '</div>',
139   );
141   $element['advanced']['BYMONTHDAY'] = array(
142     '#type' => 'select',
143     '#title' => t('Day of Month'),
144     '#default_value' => !empty($rrule['BYMONTHDAY']) ? $rrule['BYMONTHDAY'] : '',
145     '#options' => array('' => t('-- Any')) + drupal_map_assoc(range(1, 31)) + drupal_map_assoc(range(-1, -31)),
146     '#multiple' => TRUE,
147     '#size' => 10,
148     '#prefix' => '<div class="date-repeat-input">',
149     '#suffix' => '</div>',
150   );
152   $element['advanced']['BYDAY'] = array(
153     '#type' => 'select',
154     '#title' => t('Day of Week'),
155     '#default_value' => !empty($rrule['BYDAY']) ? $rrule['BYDAY'] : '',
156     '#options' => array('' => t('-- Any')) + date_repeat_dow_options(),
157     //'#attributes' => array('size' => '5'),
158     '#multiple' => TRUE,
159     '#size' => 10,
160     '#prefix' => '<div class="date-repeat-input">',
161     '#suffix' => '</div>',
162   );
164   $element['exceptions'] = array(
165     '#type' => 'fieldset',
166     '#collapsible' => TRUE,
167     '#collapsed' => empty($exceptions) ? TRUE : FALSE,
168     '#title' => t('Except'),
169     '#description' => t('Dates to omit from the list of repeating dates.'),
170     '#prefix' => '<div class="date-repeat">',
171     '#suffix' => '</div>',
172     );
173   $max = !empty($exceptions) ? sizeof($exceptions) : 0;
174   for ($i = 0; $i <= $max; $i++) {
175     $EXCEPT = '';
176     if (!empty($exceptions[$i]['datetime'])) {
177       $EXCEPT = $exceptions[$i]['datetime'];
178     }
179     $element['exceptions']['EXDATE'][$i] = array(
180       '#tree' => TRUE,
181       'datetime' => array(
182         '#type' => $element['#date_repeat_widget'],
183         '#default_value' => $EXCEPT,
184         '#date_timezone' => !empty($element['#date_timezone']) ? $element['#date_timezone'] : date_default_timezone_name(),
185         '#date_format' => !empty($element['#date_format']) ? $element['#date_format'] : 'Y-m-d',
186         '#date_text_parts'  => !empty($element['#date_text_parts']) ? $element['#date_text_parts'] : array(),
187         '#date_year_range'  => !empty($element['#date_year_range']) ? $element['#date_year_range'] : '-3:+3',
188         '#date_label_position' => !empty($element['#date_label_position']) ? $element['#date_label_position'] : 'within',
189         ),
190       'tz' => array('#type' => 'hidden', '#value' => $element['#date_timezone']),
191       'all_day' => array('#type' => 'hidden', '#value' => 1),
192       'granularity' => array('#type' => 'hidden', '#value' => serialize(array('year', 'month', 'day'))),
193       );
194   }
195   return $element;
199  * Regroup values back into a consistant array, no matter what state it is in.
200  */
201 function date_repeat_merge($form_values, $element) {
202   if (empty($form_values) || !is_array($form_values)) {
203     return $form_values;
204   }
205   if (array_key_exists('advanced', $form_values) || array_key_exists('exceptions', $form_values)) {
206     if (!array_key_exists('advanced', $form_values)) $form_values['advanced'] = array();
207     if (!array_key_exists('exceptions', $form_values)) $form_values['exceptions'] = array();
208     $form_values = array_merge($form_values, (array) $form_values['advanced'], (array) $form_values['exceptions']);
209     unset($form_values['advanced']);
210     unset($form_values['exceptions']);
211   }
212   if (array_key_exists('BYDAY', $form_values)) unset($form_values['BYDAY']['']);
213   if (array_key_exists('BYMONTH', $form_values)) unset($form_values['BYMONTH']['']);
214   if (array_key_exists('BYMONTHDAY', $form_values)) unset($form_values['BYMONTHDAY']['']);
215       
216   if (is_array($form_values['UNTIL']['datetime'])) {
217     $function = $element['#date_repeat_widget'] .'_input_value';
218     $until_element = $element;
219     $until_element['#value'] = $form_values['UNTIL']['datetime'];
220     $form_values['UNTIL']['datetime'] = $function($until_element);
221   }
222   if (isset($form_values['EXDATE']) && is_array($form_values['EXDATE'])) {
223     $function = $element['#date_repeat_widget'] .'_input_value';
224     $exdate_element = $element;
225     foreach ($form_values['EXDATE'] as $delta => $value) {
226       if (is_array($value['datetime'])) {
227         $exdate_element['#value'] = $form_values['EXDATE'][$delta]['datetime'];
228         $form_values['EXDATE'][$delta]['datetime'] = $function($exdate_element);
229       }
230     }
231   }
232   return $form_values;
236  * Build a RRULE out of the form values.
237  */
238 function date_repeat_rrule_validate($element, &$form_state) {
239   require_once('./'. drupal_get_path('module', 'date_api') .'/date_api_ical.inc');
240   $form_values = $form_state['values'];
241   $field_name = $element['#parents'][0];
242   $item = $form_values[$field_name]['rrule'];
243   $item = date_repeat_merge($item, $element);
244   $rrule = date_api_ical_build_rrule($item);
245   form_set_value($element, $rrule, $form_state);
249  * Theme the exception list as a table so the buttons line up
250  */
251 function theme_date_repeat_current_exceptions($rows = array()) {
252   $rows_info = array();
253   foreach ($rows as $key => $value) {
254     if (substr($key, 0, 1) != '#') {
255       $rows_info[] = array(drupal_render($value['action']), drupal_render($value['display']));
256     }
257   }
258   return theme('table', array(t('Delete'), t('Current exceptions')), $rows_info);
262  * Themes the date repeat element.
263  */
264 function theme_date_repeat($element) {
265   return theme('form_element', $element, '<div class="container-inline">'. drupal_render($element). '</div>');