You are here

function _date_repeat_rrule_process in Date 8

Same name and namespace in other branches
  1. 5.2 date_repeat/date_repeat_form.inc \_date_repeat_rrule_process()
  2. 6.2 date_repeat/date_repeat_form.inc \_date_repeat_rrule_process()
  3. 6 date_repeat/date_repeat_form.inc \_date_repeat_rrule_process()
  4. 7.3 date_repeat/date_repeat_form.inc \_date_repeat_rrule_process()
  5. 7 date_repeat/date_repeat_form.inc \_date_repeat_rrule_process()
  6. 7.2 date_repeat/date_repeat_form.inc \_date_repeat_rrule_process()

Generate the repeat setting form.

1 call to _date_repeat_rrule_process()
date_repeat_rrule_process in date_repeat/date_repeat.module
Generate the repeat rule setting form.

File

date_repeat/date_repeat_form.inc, line 44
Code to add a date repeat selection form to a date field and create an iCal RRULE from the chosen selections.

Code

function _date_repeat_rrule_process($element, &$form_state, $form) {

  // If the RRULE field is not visible to the user, needs no processing or validation.
  // The Date field module is not adding this element to forms if the field is hidden,
  // this test is just in case some other module attempts to do so.
  if (date_hidden_element($element)) {
    return $element;
  }
  $calendar = system_calendar();
  if (empty($element['#date_repeat_widget'])) {
    $element['#date_repeat_widget'] = module_exists('date_popup') ? 'date_popup' : 'date_select';
  }
  if (is_array($element['#default_value'])) {
    $element['#value'] = date_repeat_merge($element['#value'], $element);
    $rrule = DateiCalParse::build_rrule($element['#value']);
  }
  else {
    $rrule = $element['#default_value'];
  }

  // Empty the original string value of the RRULE so we can create
  // an array of values for the form from the RRULE's contents.
  $element['#value'] = '';
  $raw_rrule = $rrule;
  $parts = DateiCalParse::split_rrule($rrule);
  $rrule = $parts[0];
  $exceptions = $parts[1];
  $additions = $parts[2];
  $timezone = !empty($element['#date_timezone']) ? $element['#date_timezone'] : drupal_get_user_timezone();
  $merged_values = date_repeat_merge($rrule, $element);
  $UNTIL = '';
  if (!empty($merged_values['UNTIL']['datetime'])) {
    $until_date = new DrupalDateTime($merged_values['UNTIL']['datetime'], $merged_values['UNTIL']['tz']);
    date_timezone_set($until_date, timezone_open($timezone));
    $UNTIL = date_format($until_date, DATE_FORMAT_DATETIME);
  }
  $COUNT = '';
  if (!empty($merged_values['COUNT'])) {
    $COUNT = $merged_values['COUNT'];
  }
  $element['FREQ'] = array(
    '#type' => 'select',
    '#title' => t('Repeats', array(), array(
      'context' => 'Date repeat',
    )),
    '#default_value' => !empty($rrule['FREQ']) ? $rrule['FREQ'] : 'WEEKLY',
    '#options' => date_repeat_freq_options(),
    '#prefix' => '<div class="date-repeat-input">',
    '#suffix' => '</div>',
  );
  $element['daily'] = array(
    '#type' => 'container',
    '#tree' => TRUE,
    '#prefix' => '<div class="date-clear daily">',
    '#suffix' => '</div>',
    '#states' => array(
      'visible' => array(
        ":input[name=\"{$element['#name']}[FREQ]\"]" => array(
          'value' => 'DAILY',
        ),
      ),
    ),
  );
  $element['weekly'] = array(
    '#type' => 'container',
    '#tree' => TRUE,
    '#prefix' => '<div class="date-clear weekly">',
    '#suffix' => '</div>',
    '#states' => array(
      'visible' => array(
        ":input[name=\"{$element['#name']}[FREQ]\"]" => array(
          'value' => 'WEEKLY',
        ),
      ),
    ),
  );
  $element['monthly'] = array(
    '#type' => 'container',
    '#tree' => TRUE,
    '#prefix' => '<div class="date-clear monthly">',
    '#suffix' => '</div>',
    '#states' => array(
      'visible' => array(
        ":input[name=\"{$element['#name']}[FREQ]\"]" => array(
          'value' => 'MONTHLY',
        ),
      ),
    ),
  );
  $element['yearly'] = array(
    '#type' => 'container',
    '#tree' => TRUE,
    '#prefix' => '<div class="date-clear yearly">',
    '#suffix' => '</div>',
    '#states' => array(
      'visible' => array(
        ":input[name=\"{$element['#name']}[FREQ]\"]" => array(
          'value' => 'YEARLY',
        ),
      ),
    ),
  );
  list($prefix, $suffix) = explode('@interval', t('Every @interval days', array(), array(
    'context' => 'Date repeat',
  )));
  $DAILY_INTERVAL = array(
    '#type' => 'number',
    '#title' => t('Repeats', array(), array(
      'context' => 'Date repeat',
    )),
    '#title_display' => 'invisible',
    '#default_value' => !empty($rrule['INTERVAL']) ? $rrule['INTERVAL'] : 1,
    '#min' => 0,
    '#attributes' => array(
      'placeholder' => array(
        '#',
      ),
    ),
    '#size' => 3,
    '#maxlength' => 3,
    '#prefix' => '<div class="date-clear">',
    '#suffix' => t('days') . '</div>',
    '#field_prefix' => $prefix,
    '#field_suffix' => $suffix,
  );
  list($prefix, $suffix) = explode('@interval', t('Every @interval weeks', array(), array(
    'context' => 'Date repeat',
  )));
  $element['weekly']['INTERVAL'] = array(
    '#type' => 'number',
    '#title' => t('Repeats', array(), array(
      'context' => 'Date repeat',
    )),
    '#default_value' => !empty($rrule['INTERVAL']) ? $rrule['INTERVAL'] : 1,
    '#min' => 0,
    '#attributes' => array(
      'placeholder' => array(
        '#',
      ),
    ),
    '#size' => 3,
    '#maxlength' => 3,
    '#prefix' => '<div class="date-clear">',
    '#suffix' => '</div>',
    '#field_prefix' => $prefix,
    '#field_suffix' => $suffix,
  );
  list($prefix, $suffix) = explode('@interval', t('Every @interval months', array(), array(
    'context' => 'Date repeat',
  )));
  $element['monthly']['INTERVAL'] = array(
    '#access' => FALSE,
    '#type' => 'number',
    '#title' => t('Repeats', array(), array(
      'context' => 'Date repeat',
    )),
    '#default_value' => !empty($rrule['INTERVAL']) ? $rrule['INTERVAL'] : 1,
    '#min' => 0,
    '#attributes' => array(
      'placeholder' => array(
        '#',
      ),
    ),
    '#size' => 3,
    '#maxlength' => 3,
    '#prefix' => '<div class="date-clear">',
    '#suffix' => '</div>',
    '#field_prefix' => $prefix,
    '#field_suffix' => $suffix,
  );
  list($prefix, $suffix) = explode('@interval', t('Every @interval years', array(), array(
    'context' => 'Date repeat',
  )));
  $element['yearly']['INTERVAL'] = array(
    '#type' => 'number',
    '#title' => t('Repeats', array(), array(
      'context' => 'Date repeat',
    )),
    '#default_value' => !empty($rrule['INTERVAL']) ? $rrule['INTERVAL'] : 1,
    '#min' => 0,
    '#attributes' => array(
      'placeholder' => array(
        '#',
      ),
    ),
    '#size' => 3,
    '#maxlength' => 3,
    '#prefix' => '<div class="date-clear">',
    '#suffix' => '</div>',
    '#field_prefix' => $prefix,
    '#field_suffix' => $suffix,
  );
  $options = date_repeat_dow_day_options_abbr(TRUE);
  $options = date_repeat_dow_day_options_ordered($options);
  $element['weekly']['BYDAY'] = array(
    '#type' => 'checkboxes',
    '#title' => t('Repeat on', array(), array(
      'context' => 'Date repeat',
    )),
    '#default_value' => !empty($rrule['BYDAY']) && $rrule['FREQ'] === 'WEEKLY' ? $rrule['BYDAY'] : array(),
    '#options' => $options,
    '#attributes' => array(
      'class' => array(
        'container-inline byday',
      ),
    ),
    '#multiple' => TRUE,
    '#prefix' => '<div class="date-clear">',
    '#suffix' => '</div>',
  );
  $DAILY_radios_default = 'INTERVAL';
  if (isset($rrule['FREQ']) && $rrule['FREQ'] === 'DAILY' && !empty($rrule['BYDAY'])) {
    switch (count($rrule['BYDAY'])) {
      case 2:
        $DAILY_radios_default = 'every_tu_th';
        break;
      case 3:
        $DAILY_radios_default = 'every_mo_we_fr';
        break;
      case 5:
        $DAILY_radios_default = 'every_weekday';
        break;
    }
  }
  $DAILY_every_weekday = array(
    '#type' => 'item',
    '#markup' => '<div>' . t('Every weekday', array(), array(
      'context' => 'Date repeat',
    )) . '</div>',
  );
  $DAILY_mo_we_fr = array(
    '#type' => 'item',
    '#markup' => '<div>' . t('Every Mon, Wed, Fri', array(), array(
      'context' => 'Date repeat',
    )) . '</div>',
  );
  $DAILY_tu_th = array(
    '#type' => 'item',
    '#markup' => '<div>' . t('Every Tue, Thu', array(), array(
      'context' => 'Date repeat',
    )) . '</div>',
  );
  $element['daily']['byday_radios'] = array(
    '#type' => 'date_repeat_form_element_radios',
    '#tree' => TRUE,
    '#title' => t('Repeats every', array(), array(
      'context' => 'Date repeat',
    )),
    '#prefix' => '<div class="date-clear">',
    '#suffix' => '</div>',
    '#states' => array(
      'visible' => array(
        ":input[name=\"{$element['#name']}[FREQ]\"]" => array(
          'value' => 'DAILY',
        ),
      ),
    ),
    '#default_value' => $DAILY_radios_default,
    '#options' => array(
      'INTERVAL' => t('interval'),
      'every_weekday' => t('every weekday'),
      'every_mo_we_fr' => t('monday wednesday friday'),
      'every_tu_th' => t('tuesday thursday'),
    ),
    'INTERVAL_child' => $DAILY_INTERVAL,
    'every_weekday_child' => $DAILY_every_weekday,
    'mo_we_fr_child' => $DAILY_mo_we_fr,
    'tu_th_child' => $DAILY_tu_th,
    '#div_classes' => array(
      'container-inline interval',
      'container-inline weekday',
      'container-inline mo-we-fr',
      'container-inline tu-th',
    ),
  );
  $MONTHLY_day_month_default = 'BYMONTHDAY_BYMONTH';
  if (isset($rrule['FREQ']) && $rrule['FREQ'] === 'MONTHLY' && !empty($rrule['BYDAY'])) {
    $MONTHLY_day_month_default = 'BYDAY_BYMONTH';
  }
  $MONTHLY_on_day_BYMONTHDAY_of_BYMONTH = array(
    '#type' => 'container',
    '#tree' => TRUE,
  );
  list($bymonthday_title, $bymonthday_suffix) = explode('@bymonthday', t('On day @bymonthday of', array(), array(
    'context' => 'Date repeat',
  )));
  $MONTHLY_on_day_BYMONTHDAY_of_BYMONTH['BYMONTHDAY'] = array(
    '#type' => 'select',
    '#title' => $bymonthday_title,
    '#default_value' => !empty($rrule['BYMONTHDAY']) && $rrule['FREQ'] === 'MONTHLY' ? $rrule['BYMONTHDAY'] : '',
    '#options' => drupal_map_assoc(range(1, 31)) + drupal_map_assoc(range(-1, -31)),
    '#multiple' => FALSE,
    '#prefix' => '<div class="date-clear bymonthday">',
    '#suffix' => '</div>',
    '#field_suffix' => $bymonthday_suffix,
  );
  $MONTHLY_on_day_BYMONTHDAY_of_BYMONTH['BYMONTH'] = array(
    '#type' => 'checkboxes',
    '#title' => t('Bymonth', array(), array(
      'context' => 'Date repeat',
    )),
    '#title_display' => 'invisible',
    '#default_value' => !empty($rrule['BYMONTH']) && $rrule['FREQ'] === 'MONTHLY' && $MONTHLY_day_month_default === 'BYMONTHDAY_BYMONTH' ? $rrule['BYMONTH'] : array(),
    '#options' => $calendar
      ->month_names_abbr(TRUE),
    '#attributes' => array(
      'class' => array(
        'container-inline',
      ),
    ),
    '#multiple' => TRUE,
    '#prefix' => '<div class="date-clear bymonth">',
    '#suffix' => '</div>',
  );
  $MONTHLY_on_the_BYDAY_of_BYMONTH = array(
    '#type' => 'container',
    '#tree' => TRUE,
  );
  $MONTHLY_BYDAY_COUNT = '';
  $MONTHLY_BYDAY_DAY = '';
  if (isset($rrule['BYDAY']) && !empty($rrule['BYDAY']) && $rrule['FREQ'] === 'MONTHLY') {
    $MONTHLY_BYDAY_COUNT = substr($rrule['BYDAY'][0], 0, -2);
    $MONTHLY_BYDAY_DAY = substr($rrule['BYDAY'][0], -2);
  }
  list($byday_count_title, $byday_day_title) = explode('@byday', t('On the @byday of', array(), array(
    'context' => 'Date repeat',
  )));
  $MONTHLY_on_the_BYDAY_of_BYMONTH['BYDAY_COUNT'] = array(
    '#type' => 'select',
    '#title' => $byday_count_title,
    '#default_value' => !empty($MONTHLY_BYDAY_COUNT) ? $MONTHLY_BYDAY_COUNT : '',
    '#options' => date_order_translated(),
    '#multiple' => FALSE,
    '#prefix' => '<div class="date-repeat-input byday-count">',
    '#suffix' => '</div>',
  );
  $MONTHLY_on_the_BYDAY_of_BYMONTH['BYDAY_DAY'] = array(
    '#type' => 'select',
    '#title' => $byday_day_title,
    '#title_display' => 'after',
    '#default_value' => !empty($MONTHLY_BYDAY_DAY) ? $MONTHLY_BYDAY_DAY : '',
    '#options' => date_repeat_dow_day_options(TRUE),
    '#multiple' => FALSE,
    '#prefix' => '<div class="date-repeat-input byday-day">',
    '#suffix' => '</div>',
  );
  $MONTHLY_on_the_BYDAY_of_BYMONTH['BYMONTH'] = array(
    '#type' => 'checkboxes',
    '#title' => t('Bymonth', array(), array(
      'context' => 'Date repeat',
    )),
    '#title_display' => 'invisible',
    '#default_value' => !empty($rrule['BYMONTH']) && $rrule['FREQ'] === 'MONTHLY' && $MONTHLY_day_month_default === 'BYDAY_BYMONTH' ? $rrule['BYMONTH'] : array(),
    '#options' => $calendar
      ->month_names_abbr(TRUE),
    '#attributes' => array(
      'class' => array(
        'container-inline',
      ),
    ),
    '#multiple' => TRUE,
    '#prefix' => '<div class="date-clear bymonth">',
    '#suffix' => '</div>',
  );
  $element['monthly']['day_month'] = array(
    '#type' => 'date_repeat_form_element_radios',
    '#tree' => TRUE,
    '#prefix' => '<div class="date-clear">',
    '#suffix' => '</div>',
    '#states' => array(
      'visible' => array(
        ":input[name=\"{$element['#name']}[FREQ]\"]" => array(
          'value' => 'MONTHLY',
        ),
      ),
    ),
    '#attributes' => array(
      'class' => array(
        'date-repeat-radios clearfix',
      ),
    ),
    '#default_value' => $MONTHLY_day_month_default,
    '#options' => array(
      'BYMONTHDAY_BYMONTH' => t('On day ... of ...'),
      'BYDAY_BYMONTH' => t('On the ... of ...'),
    ),
    'BYMONTHDAY_BYMONTH_child' => $MONTHLY_on_day_BYMONTHDAY_of_BYMONTH,
    'BYDAY_BYMONTH_child' => $MONTHLY_on_the_BYDAY_of_BYMONTH,
    '#div_classes' => array(
      'date-repeat-radios-item date-clear clearfix bymonthday-bymonth',
      'date-repeat-radios-item date-clear clearfix byday-bymonth',
    ),
  );
  $YEARLY_day_month_default = 'BYMONTHDAY_BYMONTH';
  if (isset($rrule['FREQ']) && $rrule['FREQ'] === 'YEARLY' && !empty($rrule['BYDAY'])) {
    $YEARLY_day_month_default = 'BYDAY_BYMONTH';
  }
  $YEARLY_on_day_BYMONTHDAY_of_BYMONTH = array(
    '#type' => 'container',
    '#tree' => TRUE,
  );
  list($bymonthday_title, $bymonthday_suffix) = explode('@bymonthday', t('On day @bymonthday of', array(), array(
    'context' => 'Date repeat',
  )));
  $YEARLY_on_day_BYMONTHDAY_of_BYMONTH['BYMONTHDAY'] = array(
    '#type' => 'select',
    '#title' => $bymonthday_title,
    '#default_value' => !empty($rrule['BYMONTHDAY']) && $rrule['FREQ'] === 'YEARLY' ? $rrule['BYMONTHDAY'] : '',
    '#options' => drupal_map_assoc(range(1, 31)) + drupal_map_assoc(range(-1, -31)),
    '#multiple' => FALSE,
    '#prefix' => '<div class="date-clear bymonthday">',
    '#suffix' => '</div>',
    '#field_suffix' => $bymonthday_suffix,
  );
  $YEARLY_on_day_BYMONTHDAY_of_BYMONTH['BYMONTH'] = array(
    '#type' => 'checkboxes',
    '#title' => t('Bymonth', array(), array(
      'context' => 'Date repeat',
    )),
    '#title_display' => 'invisible',
    '#default_value' => !empty($rrule['BYMONTH']) && $rrule['FREQ'] === 'YEARLY' && $YEARLY_day_month_default === 'BYMONTHDAY_BYMONTH' ? $rrule['BYMONTH'] : array(),
    '#options' => $calendar
      ->month_names_abbr(TRUE),
    '#attributes' => array(
      'class' => array(
        'container-inline',
      ),
    ),
    '#multiple' => TRUE,
    '#prefix' => '<div class="date-clear bymonth">',
    '#suffix' => '</div>',
  );
  $YEARLY_on_the_BYDAY_of_BYMONTH = array(
    '#type' => 'container',
    '#tree' => TRUE,
  );
  $YEARLY_BYDAY_COUNT = '';
  $YEARLY_BYDAY_DAY = '';
  if (isset($rrule['BYDAY']) && !empty($rrule['BYDAY']) && $rrule['FREQ'] === 'YEARLY') {
    $YEARLY_BYDAY_COUNT = substr($rrule['BYDAY'][0], 0, -2);
    $YEARLY_BYDAY_DAY = substr($rrule['BYDAY'][0], -2);
  }
  list($byday_count_title, $byday_day_title) = explode('@byday', t('On the @byday of', array(), array(
    'context' => 'Date repeat',
  )));
  $YEARLY_on_the_BYDAY_of_BYMONTH['BYDAY_COUNT'] = array(
    '#type' => 'select',
    '#title' => $byday_count_title,
    '#default_value' => !empty($YEARLY_BYDAY_COUNT) ? $YEARLY_BYDAY_COUNT : '',
    '#options' => date_order_translated(),
    '#multiple' => FALSE,
    '#prefix' => '<div class="date-repeat-input byday-count">',
    '#suffix' => '</div>',
  );
  $YEARLY_on_the_BYDAY_of_BYMONTH['BYDAY_DAY'] = array(
    '#type' => 'select',
    '#title' => $byday_day_title,
    '#title_display' => 'after',
    '#default_value' => !empty($YEARLY_BYDAY_DAY) ? $YEARLY_BYDAY_DAY : '',
    '#options' => date_repeat_dow_day_options(TRUE),
    '#multiple' => FALSE,
    '#prefix' => '<div class="date-repeat-input byday-day">',
    '#suffix' => '</div>',
  );
  $YEARLY_on_the_BYDAY_of_BYMONTH['BYMONTH'] = array(
    '#type' => 'checkboxes',
    '#title' => t('Bymonth', array(), array(
      'context' => 'Date repeat',
    )),
    '#title_display' => 'invisible',
    '#default_value' => !empty($rrule['BYMONTH']) && $rrule['FREQ'] === 'YEARLY' && $YEARLY_day_month_default === 'BYDAY_BYMONTH' ? $rrule['BYMONTH'] : array(),
    '#options' => $calendar
      ->month_names_abbr(TRUE),
    '#attributes' => array(
      'class' => array(
        'container-inline',
      ),
    ),
    '#multiple' => TRUE,
    '#prefix' => '<div class="date-clear bymonth">',
    '#suffix' => '</div>',
  );
  $element['yearly']['day_month'] = array(
    '#type' => 'date_repeat_form_element_radios',
    '#tree' => TRUE,
    '#prefix' => '<div class="date-clear">',
    '#suffix' => '</div>',
    '#states' => array(
      'visible' => array(
        ":input[name=\"{$element['#name']}[FREQ]\"]" => array(
          'value' => 'YEARLY',
        ),
      ),
    ),
    '#attributes' => array(
      'class' => array(
        'date-repeat-radios clearfix',
      ),
    ),
    '#default_value' => $YEARLY_day_month_default,
    '#options' => array(
      'BYMONTHDAY_BYMONTH' => t('On day ... of ...'),
      'BYDAY_BYMONTH' => t('On the ... of ...'),
    ),
    'BYMONTHDAY_BYMONTH_child' => $YEARLY_on_day_BYMONTHDAY_of_BYMONTH,
    'BYDAY_BYMONTH_child' => $YEARLY_on_the_BYDAY_of_BYMONTH,
    '#div_classes' => array(
      'date-repeat-radios-item date-clear clearfix bymonthday-bymonth',
      'date-repeat-radios-item date-clear clearfix byday-bymonth',
    ),
  );
  list($prefix, $suffix) = explode('@count', t('After @count occurrences', array(), array(
    'context' => 'Date repeat',
  )));
  $count_form_element = array(
    '#type' => 'number',
    '#title' => t('Count', array(), array(
      'context' => 'Date repeat',
    )),
    '#default_value' => $COUNT,
    '#min' => 0,
    '#attributes' => array(
      'placeholder' => array(
        '#',
      ),
    ),
    '#prefix' => $prefix,
    '#suffix' => $suffix,
    '#size' => 10,
    '#maxlength' => 10,
  );
  $until_form_element = array(
    '#type' => 'container',
    '#tree' => TRUE,
    '#prefix' => '<div class="date-prefix-inline">' . t('On', array(), array(
      'context' => 'Date repeat',
    )) . '</div>',
    'datetime' => array(
      '#type' => $element['#date_repeat_widget'],
      '#title' => t('Until', array(), array(
        'context' => 'Date repeat',
      )),
      '#title_display' => 'invisible',
      '#default_value' => $UNTIL,
      '#date_date_format' => !empty($element['#date_date_format']) ? $element['#date_date_format'] : 'Y-m-d',
      '#date_timezone' => $timezone,
      '#date_text_parts' => !empty($element['#date_text_parts']) ? $element['#date_text_parts'] : array(),
      '#date_year_range' => !empty($element['#date_year_range']) ? $element['#date_year_range'] : '-3:+3',
      '#date_label_position' => !empty($element['#date_label_position']) ? $element['#date_label_position'] : 'within',
      '#date_flexible' => 0,
    ),
    'tz' => array(
      '#type' => 'hidden',
      '#value' => $element['#date_timezone'],
    ),
    'all_day' => array(
      '#type' => 'hidden',
      '#value' => 1,
    ),
    'granularity' => array(
      '#type' => 'hidden',
      '#value' => serialize(array(
        'year',
        'month',
        'day',
      )),
    ),
  );
  $range_of_repeat_default = 'COUNT';
  if (!empty($UNTIL)) {
    $range_of_repeat_default = 'UNTIL';
  }
  $element['range_of_repeat'] = array(
    '#type' => 'date_repeat_form_element_radios',
    '#tree' => TRUE,
    '#title' => t('Stop repeating', array(), array(
      'context' => 'Date repeat',
    )),
    '#title_display' => 'before',
    '#prefix' => '<div class="date-clear range-of-repeat">',
    '#suffix' => '</div>',
    '#states' => array(
      'invisible' => array(
        ":input[name=\"{$element['#name']}[FREQ]\"]" => array(
          'value' => 'NONE',
        ),
      ),
    ),
    '#default_value' => $range_of_repeat_default,
    '#options' => array(
      'COUNT' => t('Count'),
      'UNTIL' => t('Until'),
    ),
    'count_child' => $count_form_element,
    'until_child' => $until_form_element,
    '#div_classes' => array(
      'container-inline count',
      "until widget-{$element['#date_repeat_widget']} label-{$element['#date_label_position']}",
    ),
  );
  $parents = $element['#array_parents'];
  $instance = implode('-', $parents);

  // Make sure this will work right either in the normal form or in an ajax callback from the 'Add more' button.
  if (empty($form_state['num_exceptions'][$instance])) {
    $form_state['num_exceptions'][$instance] = count($exceptions);
  }
  if ($form_state['num_exceptions'][$instance] == 0) {
    $collapsed = TRUE;
  }
  else {
    $collapsed = FALSE;
  }
  $element['show_exceptions'] = array(
    '#type' => 'checkbox',
    '#title' => t('Exclude dates', array(), array(
      'context' => 'Date repeat',
    )),
    '#states' => array(
      'invisible' => array(
        ":input[name=\"{$element['#name']}[FREQ]\"]" => array(
          'value' => 'NONE',
        ),
      ),
    ),
    '#default_value' => empty($form_state['num_exceptions'][$instance]) ? 0 : 1,
  );
  $element['exceptions'] = array(
    '#type' => 'container',
    '#prefix' => '<div id="date-repeat-exceptions-' . $instance . '" class="date-repeat">',
    '#suffix' => '</div>',
    '#states' => array(
      'visible' => array(
        ":input[name=\"{$element['#name']}[show_exceptions]\"]" => array(
          'checked' => TRUE,
        ),
      ),
    ),
  );
  for ($i = 0; $i < max($form_state['num_exceptions'][$instance], 1); $i++) {
    $EXCEPT = '';
    if (!empty($exceptions[$i]['datetime'])) {
      $ex_date = new DrupalDateTime($exceptions[$i]['datetime'], $exceptions[$i]['tz']);
      date_timezone_set($ex_date, timezone_open($timezone));
      $EXCEPT = date_format($ex_date, DATE_FORMAT_DATETIME);
    }
    $element['exceptions']['EXDATE'][$i] = array(
      '#tree' => TRUE,
      'datetime' => array(
        '#name' => 'exceptions|' . $instance,
        '#type' => $element['#date_repeat_widget'],
        '#default_value' => $EXCEPT,
        '#date_timezone' => !empty($element['#date_timezone']) ? $element['#date_timezone'] : drupal_get_user_timezone(),
        '#date_date_format' => !empty($element['#date_date_format']) ? DateGranularity::limitFormat($element['#date_date_format'], array(
          'year',
          'month',
          'day',
        )) : 'Y-m-d',
        '#date_text_parts' => !empty($element['#date_text_parts']) ? $element['#date_text_parts'] : array(),
        '#date_year_range' => !empty($element['#date_year_range']) ? $element['#date_year_range'] : '-3:+3',
        '#date_label_position' => !empty($element['#date_label_position']) ? $element['#date_label_position'] : 'within',
        '#date_flexible' => 0,
      ),
      'tz' => array(
        '#type' => 'hidden',
        '#value' => $element['#date_timezone'],
      ),
      'all_day' => array(
        '#type' => 'hidden',
        '#value' => 1,
      ),
      'granularity' => array(
        '#type' => 'hidden',
        '#value' => serialize(array(
          'year',
          'month',
          'day',
        )),
      ),
    );
  }

  // collect additions in the same way as exceptions - implements RDATE.
  if (empty($form_state['num_additions'][$instance])) {
    $form_state['num_additions'][$instance] = count($additions);
  }
  if ($form_state['num_additions'][$instance] == 0) {
    $collapsed = TRUE;
  }
  else {
    $collapsed = FALSE;
  }
  $element['show_additions'] = array(
    '#type' => 'checkbox',
    '#title' => t('Include dates', array(), array(
      'context' => 'Date repeat',
    )),
    '#states' => array(
      'invisible' => array(
        ":input[name=\"{$element['#name']}[FREQ]\"]" => array(
          'value' => 'NONE',
        ),
      ),
    ),
    '#default_value' => empty($form_state['num_additions'][$instance]) ? 0 : 1,
  );
  $element['additions'] = array(
    '#type' => 'container',
    '#prefix' => '<div id="date-repeat-additions-' . $instance . '" class="date-repeat">',
    '#suffix' => '</div>',
    '#states' => array(
      'visible' => array(
        ":input[name=\"{$element['#name']}[show_additions]\"]" => array(
          'checked' => TRUE,
        ),
      ),
    ),
  );
  for ($i = 0; $i < max($form_state['num_additions'][$instance], 1); $i++) {
    $RDATE = '';
    if (!empty($additions[$i]['datetime'])) {
      $rdate = new DrupalDateTime($additions[$i]['datetime'], $additions[$i]['tz']);
      date_timezone_set($rdate, timezone_open($timezone));
      $RDATE = date_format($rdate, DATE_FORMAT_DATETIME);
    }
    $element['additions']['RDATE'][$i] = array(
      '#tree' => TRUE,
      'datetime' => array(
        '#type' => $element['#date_repeat_widget'],
        '#name' => 'additions|' . $instance,
        '#default_value' => $RDATE,
        '#date_timezone' => !empty($element['#date_timezone']) ? $element['#date_timezone'] : drupal_get_user_timezone(),
        '#date_date_format' => !empty($element['#date_date_format']) ? DateGranularity::limitFormat($element['#date_date_format'], array(
          'year',
          'month',
          'day',
        )) : 'Y-m-d',
        '#date_text_parts' => !empty($element['#date_text_parts']) ? $element['#date_text_parts'] : array(),
        '#date_year_range' => !empty($element['#date_year_range']) ? $element['#date_year_range'] : '-3:+3',
        '#date_label_position' => !empty($element['#date_label_position']) ? $element['#date_label_position'] : 'within',
        '#date_flexible' => 0,
      ),
      'tz' => array(
        '#type' => 'hidden',
        '#value' => $element['#date_timezone'],
      ),
      'all_day' => array(
        '#type' => 'hidden',
        '#value' => 1,
      ),
      'granularity' => array(
        '#type' => 'hidden',
        '#value' => serialize(array(
          'year',
          'month',
          'day',
        )),
      ),
    );
  }
  $element['exceptions']['exceptions_add'] = array(
    '#type' => 'submit',
    '#name' => 'exceptions_add|' . $instance,
    '#value' => t('Add exception'),
    '#submit' => array(
      'date_repeat_add_exception',
    ),
    '#limit_validation_errors' => array(),
    '#ajax' => array(
      'callback' => 'date_repeat_add_exception_callback',
      'wrapper' => 'date-repeat-exceptions-' . $instance,
    ),
  );
  $element['additions']['additions_add'] = array(
    '#type' => 'submit',
    '#name' => 'additions_add|' . $instance,
    '#value' => t('Add addition'),
    '#submit' => array(
      'date_repeat_add_addition',
    ),
    '#limit_validation_errors' => array(),
    '#ajax' => array(
      'callback' => 'date_repeat_add_addition_callback',
      'wrapper' => 'date-repeat-additions-' . $instance,
    ),
  );
  return $element;
}