'date_repeat_rrule', '#theme_wrappers' => array('date_repeat_rrule'), '#default_value' => isset($items[0]['rrule']) ? $items[0]['rrule'] : '', '#date_timezone' => $element['#date_timezone'], '#date_format' => date_limit_format(date_input_format($element, $field, $instance), $field['settings']['granularity']), '#date_text_parts' => (array) $instance['widget']['settings']['text_parts'], '#date_increment' => $instance['widget']['settings']['increment'], '#date_year_range' => $instance['widget']['settings']['year_range'], '#date_label_position' => $instance['widget']['settings']['label_position'], '#prev_value' => isset($items[0]['value']) ? $items[0]['value'] : '', '#prev_value2' => isset($items[0]['value2']) ? $items[0]['value2'] : '', '#prev_rrule' => isset($items[0]['rrule']) ? $items[0]['rrule'] : '', '#date_repeat_widget' => str_replace('_repeat', '', $instance['widget']['type']), '#date_repeat_collapsed' => $instance['settings']['repeat_collapsed'], ); return $element; } /** * Validation for date repeat form element. * * Create multiple values from the RRULE results. * Lots more work needed here. */ function _date_repeat_widget_validate($element, &$form_state) { module_load_include('inc', 'date_repeat', 'date_repeat_form'); $field_name = $element['#field_name']; $field = field_widget_field($element, $form_state); $instance = field_widget_instance($element, $form_state); $form_values = $form_state['values']; $item = $form_values; $input = $form_state['input']; foreach ($element['#parents'] as $key) { $item = $item[$key]; $input = $input[$key]; } $rrule_values = date_repeat_merge($input['rrule'], $element['rrule']); // If no start date was set, clean up the form and return. // If no repeats are set, clean up the form and return. if (empty($item['value']) || $rrule_values['FREQ'] == 'NONE') { $item['rrule'] = NULL; form_set_value($element, array($item), $form_state); return; } // Require the UNTIL date for now. // The RRULE has already been created by this point, so go back // to the posted values to see if this was filled out. $error_field = implode('][', $element['#parents']) . '][rrule][UNTIL][datetime][date'; if (empty($rrule_values['UNTIL']['datetime'])) { form_set_error($error_field, t('The UNTIL value is required for repeating dates.')); } if (form_get_errors()) { return; } // If the rule, the start date, or the end date have changed, re-calculate // the repeating dates, wipe out the previous values, and populate the // field with the new values. // TODO // Is it right to not do anything unless there are changes? Will that // confuse anyone? Commenting that out for now... $rrule = $item['rrule']; if (!empty($rrule) //&& ($rrule != $element['rrule']['#prev_rrule'] //|| $item['value'] != $element['rrule']['#prev_value'] //|| $item['value2'] != $element['rrule']['#prev_value2']) ) { // Avoid undefined index problems on dates that don't have all parts. $possible_items = array('value', 'value2', 'timezone', 'offset', 'offset2'); foreach ($possible_items as $key) { if (empty($item[$key])) { $item[$key] = ''; } } $value = date_repeat_build_dates($rrule, $rrule_values, $field, $item); form_set_value($element, $value, $form_state); } else { // If no changes are needed, move the RRULE back to the zero value // item of the field. form_set_value(array('#parents' => array($field_name, $element['#language'], 0, 'rrule')), $rrule, $form_state); form_set_value($element, NULL, $form_state); } } /** * Helper function to build repeating dates from a $node_field. * * Pass in either the RRULE or the $form_values array for the RRULE, * whichever is missing will be created when needed. */ function date_repeat_build_dates($rrule = NULL, $rrule_values = NULL, $field, $item) { include_once(DRUPAL_ROOT . '/' . drupal_get_path('module', 'date_api') . '/date_api_ical.inc'); $field_name = $field['field_name']; if (empty($rrule)) { $rrule = date_api_ical_build_rrule($rrule_values); } elseif (empty($rrule_values)) { $rrule_values = date_ical_parse($rrule); } // By the time we get here, the start and end dates have been // adjusted back to UTC, but we want localtime dates to do // things like '+1 Tuesday', so adjust back to localtime. $timezone = date_get_timezone($field['settings']['tz_handling'], $item['timezone']); $timezone_db = date_get_timezone_db($field['settings']['tz_handling']); $start = new DateObject($item['value'], $timezone_db, date_type_format($field['type'])); $start->limitGranularity($field['settings']['granularity']); if ($timezone != $timezone_db) { date_timezone_set($start, timezone_open($timezone)); } if (!empty($item['value2']) && $item['value2'] != $item['value']) { $end = new DateObject($item['value2'], date_get_timezone_db($field['settings']['tz_handling']), date_type_format($field['type'])); $end->limitGranularity($field['settings']['granularity']); date_timezone_set($end, timezone_open($timezone)); } else { $end = $start; } $duration = $start->difference($end); $start_datetime = date_format($start, DATE_FORMAT_DATETIME); if (!empty($rrule_values['UNTIL']['datetime'])) { $end = date_ical_date($rrule_values['UNTIL'], $timezone); } $end_datetime = date_format($end, DATE_FORMAT_DATETIME); // Split the RRULE into RRULE, EXDATE, and RDATE parts. $parts = date_repeat_split_rrule($rrule); $parsed_exceptions = (array) $parts[1]; $exceptions = array(); foreach ($parsed_exceptions as $exception) { $date = date_ical_date($exception, $timezone); $exceptions[] = date_format($date, 'Y-m-d'); } $parsed_rdates = (array) $parts[2]; $additions = array(); foreach ($parsed_rdates as $rdate) { $additions[] = date_ical_date($rdate, $timezone); } $dates = date_repeat_calc($rrule, $start_datetime, $end_datetime, $exceptions, $timezone, $additions); $value = array(); foreach ($dates as $delta => $date) { // date_repeat_calc always returns DATE_DATETIME dates, which is // not necessarily $field['type'] dates. // Convert returned dates back to db timezone before storing. $date_start = new DateObject($date, $timezone, DATE_FORMAT_DATETIME); $date_start->limitGranularity($field['settings']['granularity']); date_timezone_set($date_start, timezone_open($timezone_db)); $date_end = clone($date_start); date_modify($date_end, '+' . $duration . ' seconds'); $value[$delta] = array( 'value' => date_format($date_start, date_type_format($field['type'])), 'value2' => date_format($date_end, date_type_format($field['type'])), 'offset' => date_offset_get($date_start), 'offset2' => date_offset_get($date_end), 'timezone' => $timezone, 'rrule' => $rrule, ); } return $value; }