[ Index ]

PHP Cross Reference of Drupal 6 (yi-drupal)

title

Body

[close]

/sites/all/modules/date/date_repeat/ -> date_repeat_form.inc (source)

   1  <?php
   2  /**
   3   * @file
   4   * Code to add a date repeat selection form to a date field and create
   5   * an iCal RRULE from the chosen selections.
   6   *
   7   * Moved to a separate file since it is not used on most pages
   8   * so the code is not parsed unless needed.
   9   *
  10   * Currently implemented:
  11   * INTERVAL, UNTIL, EXDATE, RDATE, BYDAY, BYMONTHDAY, BYMONTH,
  12   * YEARLY, MONTHLY, WEEKLY, DAILY
  13   *
  14   * Currently not implemented:
  15   *
  16   * BYYEARDAY, MINUTELY, HOURLY, SECONDLY, BYMINUTE, BYHOUR, BYSECOND
  17   *   These could be implemented in the future.
  18   *
  19   * COUNT
  20   *   The goal of this module is to create a way we can parse an iCal
  21   *   RRULE and pull out just dates for a specified date range, for
  22   *   instance with a date that repeats daily for several years, we might
  23   *   want to only be able to pull out the dates for the current year.
  24   *
  25   *   Adding COUNT to the rules we create makes it impossible to do that
  26   *   without parsing and computing the whole range of dates that the rule
  27   *   will create. COUNT is left off of the user form completely for this
  28   *   reason.
  29   *
  30   * BYSETPOS
  31   *   Seldom used anywhere, so no reason to complicated the code.
  32   */
  33  /**
  34   * Generate the repeat setting form.
  35   */
  36  function _date_repeat_rrule_process($element, $edit, $form_state, $form) {
  37    require_once('./'. drupal_get_path('module', 'date_api') .'/date_api_ical.inc');
  38  
  39    if (empty($element['#date_repeat_widget'])) {
  40      $element['#date_repeat_widget'] = module_exists('date_popup') ? 'date_popup' : 'date_select';
  41    }
  42    if (is_array($element['#value'])) {
  43      $element['#value'] = date_repeat_merge($element['#value'], $element);
  44      $rrule = date_api_ical_build_rrule($element['#value']);
  45    }
  46    else {
  47      $rrule = $element['#value'];
  48    }
  49    // Empty the original string value of the RRULE so we can create
  50    // an array of values for the form from the RRULE's contents.
  51    $element['#value'] = '';
  52  
  53    $parts = date_repeat_split_rrule($rrule);
  54    $rrule = $parts[0];
  55    $exceptions = $parts[1];
  56    $additions = $parts[2];
  57  
  58    $timezone = !empty($element['#date_timezone']) ? $element['#date_timezone'] : date_default_timezone_name();
  59    $merged_values = date_repeat_merge($rrule, $element);
  60  
  61    $UNTIL = '';
  62    if (!empty($merged_values['UNTIL']['datetime'])) {
  63      $until_date = date_make_date($merged_values['UNTIL']['datetime'], $merged_values['UNTIL']['tz']);
  64      date_timezone_set($until_date, timezone_open($timezone));
  65      $UNTIL = date_format($until_date, DATE_FORMAT_DATETIME);
  66    }
  67    $parent_collapsed = !empty($rrule['INTERVAL']) || !empty($rrule['FREQ']) ? 0 : (!empty($element['#date_repeat_collapsed']) ? $element['#date_repeat_collapsed'] : 0);
  68    $element['#type'] = 'fieldset';
  69    $element['#title'] = t('Repeat');
  70    $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.');
  71    $element['#collapsible'] = TRUE;
  72    $element['#collapsed'] = $parent_collapsed;
  73  
  74    // Make sure we don't get floating parts where we don't want them.
  75    $element['#prefix'] = '<div class="date-clear">';
  76    $element['#suffix'] = '</div>';
  77  
  78    $element['INTERVAL'] = array(
  79      '#type' => 'select',
  80      //'#title' => t('Interval'),
  81      '#default_value' => (!empty($rrule['INTERVAL']) ? $rrule['INTERVAL'] : 0),
  82      '#options' => INTERVAL_options(),
  83      '#prefix' => '<div class="date-repeat-input">',
  84      '#suffix' => '</div>',
  85    );
  86  
  87    $element['FREQ'] = array(
  88      '#type' => 'select',
  89      //'#title' => t('Frequency'),
  90      '#default_value' => !empty($rrule['FREQ']) ? $rrule['FREQ'] : 'NONE',
  91      '#options' => FREQ_options(),
  92      '#prefix' => '<div class="date-repeat-input">',
  93      '#suffix' => '</div>',
  94    );
  95  
  96    $element['UNTIL'] = array(
  97      '#tree' => TRUE,
  98      '#prefix' => '<div class="date-clear">',
  99      '#suffix' => '</div>',
 100      'datetime' => array(
 101        '#type' => $element['#date_repeat_widget'],
 102        '#title' => t('Until'),
 103        '#description' => t('Date to stop repeating this item.'),
 104        '#default_value' => $UNTIL,
 105        '#date_timezone' => $timezone,
 106        '#date_format' => !empty($element['#date_format']) ? date_limit_format($element['#date_format'], array('year', 'month', 'day')) : 'Y-m-d',
 107        '#date_text_parts'  => !empty($element['#date_text_parts']) ? $element['#date_text_parts'] : array(),
 108        '#date_year_range'  => !empty($element['#date_year_range']) ? $element['#date_year_range'] : '-3:+3',
 109        '#date_label_position' => !empty($element['#date_label_position']) ? $element['#date_label_position'] : 'within',
 110        ),
 111      'tz' => array('#type' => 'hidden', '#value' => $element['#date_timezone']),
 112      'all_day' => array('#type' => 'hidden', '#value' => 1),
 113      'granularity' => array('#type' => 'hidden', '#value' => serialize(array('year', 'month', 'day'))),
 114      );
 115  
 116    $collapsed = TRUE;
 117    if (!empty($merged_values['BYDAY']) || !empty($merged_values['BYMONTH'])) {
 118      $collapsed = FALSE;
 119    }
 120      // start the advanced fieldset
 121    $element['advanced'] = array(
 122      '#type' => 'fieldset',
 123      '#title' => t('Advanced'),
 124      '#collapsible' => TRUE,
 125      '#collapsed' => $collapsed,
 126      '#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.") .' ',
 127      '#prefix' => '<div class="date-clear">',
 128      '#suffix' => '</div>',
 129      );
 130  
 131    $element['advanced']['BYMONTH'] = array(
 132      '#type' => 'select',
 133      '#title' => date_t('Month', 'datetime'),
 134      '#default_value' => !empty($rrule['BYMONTH']) ? $rrule['BYMONTH'] : '',
 135      '#options' => array('' => t('-- Any')) + date_month_names(TRUE),
 136      '#multiple' => TRUE,
 137      '#size' => 10,
 138      '#prefix' => '<div class="date-repeat-input">',
 139      '#suffix' => '</div>',
 140    );
 141  
 142    $element['advanced']['BYMONTHDAY'] = array(
 143      '#type' => 'select',
 144      '#title' => t('Day of Month'),
 145      '#default_value' => !empty($rrule['BYMONTHDAY']) ? $rrule['BYMONTHDAY'] : '',
 146      '#options' => array('' => t('-- Any')) + drupal_map_assoc(range(1, 31)) + drupal_map_assoc(range(-1, -31)),
 147      '#multiple' => TRUE,
 148      '#size' => 10,
 149      '#prefix' => '<div class="date-repeat-input">',
 150      '#suffix' => '</div>',
 151    );
 152  
 153    $element['advanced']['BYDAY'] = array(
 154      '#type' => 'select',
 155      '#title' => t('Day of Week'),
 156      '#default_value' => !empty($rrule['BYDAY']) ? $rrule['BYDAY'] : '',
 157      '#options' => array('' => t('-- Any')) + date_repeat_dow_options(),
 158      //'#attributes' => array('size' => '5'),
 159      '#multiple' => TRUE,
 160      '#size' => 10,
 161      '#prefix' => '<div class="date-repeat-input">',
 162      '#suffix' => '</div>',
 163    );
 164  
 165    $element['exceptions'] = array(
 166      '#type' => 'fieldset',
 167      '#collapsible' => TRUE,
 168      '#collapsed' => empty($exceptions) ? TRUE : FALSE,
 169      '#title' => t('Except'),
 170      '#description' => t('Dates to omit from the list of repeating dates.'),
 171      '#prefix' => '<div id="date-repeat-exceptions" class="date-repeat">',
 172      '#suffix' => '</div>',
 173      );
 174    $max = !empty($exceptions) ? sizeof($exceptions) : 0;
 175    for ($i = 0; $i <= $max; $i++) {
 176      $EXCEPT = '';
 177      if (!empty($exceptions[$i]['datetime'])) {
 178        $EXCEPT = $exceptions[$i]['datetime'];
 179      }
 180      $element['exceptions']['EXDATE'][$i] = array(
 181        '#tree' => TRUE,
 182        'datetime' => array(
 183          '#type' => $element['#date_repeat_widget'],
 184          '#default_value' => $EXCEPT,
 185          '#date_timezone' => !empty($element['#date_timezone']) ? $element['#date_timezone'] : date_default_timezone_name(),
 186          '#date_format' => !empty($element['#date_format']) ? date_limit_format($element['#date_format'], array('year', 'month', 'day')) : 'Y-m-d',
 187          '#date_text_parts'  => !empty($element['#date_text_parts']) ? $element['#date_text_parts'] : array(),
 188          '#date_year_range'  => !empty($element['#date_year_range']) ? $element['#date_year_range'] : '-3:+3',
 189          '#date_label_position' => !empty($element['#date_label_position']) ? $element['#date_label_position'] : 'within',
 190          ),
 191        'tz' => array('#type' => 'hidden', '#value' => $element['#date_timezone']),
 192        'all_day' => array('#type' => 'hidden', '#value' => 1),
 193        'granularity' => array('#type' => 'hidden', '#value' => serialize(array('year', 'month', 'day'))),
 194        );
 195    }
 196  
 197    // collect additions in the same way as exceptions - implements RDATE.
 198    $element['additions'] = array(
 199      '#type' => 'fieldset',
 200      '#collapsible' => TRUE,
 201      '#collapsed' => empty($additions) ? TRUE : FALSE,
 202      '#title' => t('Additional'),
 203      '#description' => t('Dates to add to the list of repeating dates.'),
 204      '#prefix' => '<div id="date-repeat-additions" class="date-repeat">',
 205      '#suffix' => '</div>',
 206      );
 207    $max = !empty($additions) ? sizeof($additions) : 0;
 208    for ($i = 0; $i <= $max; $i++) {
 209      $RDATE = '';
 210      if (!empty($additions[$i]['datetime'])) {
 211        $RDATE = $additions[$i]['datetime'];
 212      }
 213      $element['additions']['RDATE'][$i] = array(
 214        '#tree' => TRUE,
 215        'datetime' => array(
 216          '#type' => $element['#date_repeat_widget'],
 217          '#default_value' => $RDATE,
 218          '#date_timezone' => !empty($element['#date_timezone']) ? $element['#date_timezone'] : date_default_timezone_name(),
 219          '#date_format' => !empty($element['#date_format']) ? date_limit_format($element['#date_format'], array('year', 'month', 'day')) : 'Y-m-d',
 220          '#date_text_parts'  => !empty($element['#date_text_parts']) ? $element['#date_text_parts'] : array(),
 221          '#date_year_range'  => !empty($element['#date_year_range']) ? $element['#date_year_range'] : '-3:+3',
 222          '#date_label_position' => !empty($element['#date_label_position']) ? $element['#date_label_position'] : 'within',
 223          ),
 224        'tz' => array('#type' => 'hidden', '#value' => $element['#date_timezone']),
 225        'all_day' => array('#type' => 'hidden', '#value' => 1),
 226        'granularity' => array('#type' => 'hidden', '#value' => serialize(array('year', 'month', 'day'))),
 227        );
 228    }
 229  
 230    // Create an "Add another" button for the exceptions.
 231    $field_name = $element['#parents'][0];
 232    $element['exceptions']['exceptions_addmore'] = array(
 233      '#type' => 'button',
 234      '#value' => t('Add more exceptions'),
 235      '#ahah' => array(
 236        'event' => 'click',
 237        'path' => 'date_repeat_get_exception_form_ajax/exceptions/' . $field_name,
 238        'wrapper' => 'date-repeat-exceptions',
 239        'method' => 'replace',
 240        'effect' => 'fade'
 241      )
 242    );
 243    // Create an "Add another" button for the additions.
 244    $field_name = $element['#parents'][0];
 245    $element['additions']['additions_addmore'] = array(
 246      '#type' => 'button',
 247      '#value' => t('Add more additions'),
 248      '#ahah' => array(
 249        'event' => 'click',
 250        'path' => 'date_repeat_get_exception_form_ajax/additions/' . $field_name,
 251        'wrapper' => 'date-repeat-additions',
 252        'method' => 'replace',
 253        'effect' => 'fade'
 254      )
 255    );
 256  
 257    return $element;
 258  }
 259  
 260  /**
 261   * Ajax callback to get the exceptions form.  This is needed to
 262   * implement the "Add another" button for the date repeat exceptions.
 263   * 
 264   * @param $type - 'exceptions' or 'additions'.
 265   * @param $field_name - The name of the date field.
 266   */
 267  function date_repeat_get_exception_form_ajax($type, $field_name) {
 268    // Get the cached form.  
 269    $form_state = array('storage' => NULL, 'submitted' => FALSE);
 270    if( !($form = form_get_cache($_POST['form_build_id'], $form_state)) ) {
 271      drupal_json(array('status' => FALSE, 'data' => ''));
 272      exit();
 273    }
 274  
 275    // Set the form state values.
 276    $form_state = array_merge($form_state, array('values' => $_POST));
 277  
 278    // Set the new form rrule value.
 279    $form[$field_name]['rrule']['#value'] = $form_state['values'][$field_name]['rrule'];
 280  
 281    // Cache the new form state.
 282    form_set_cache($_POST['form_build_id'], $form, $form_state);
 283  
 284    // Rebuild the form.
 285    $form_state = array();
 286    $form['#post'] = array();
 287    $form = form_builder($form['form_id']['#value'] , $form, $form_state);
 288  
 289    // Force a rebuild of the Drupal.settings javascript object.
 290    //   - Borrowed from content.node_form.inc, content_add_more_js function
 291    $javascript = drupal_add_js(NULL, NULL);
 292    $output_js = isset($javascript['setting']) ? '<script type="text/javascript">jQuery.extend(Drupal.settings, '. drupal_to_js(call_user_func_array('array_merge_recursive', $javascript['setting'])) .');</script>' : '';
 293  
 294    // Create our output.
 295    $output = drupal_render($form[$field_name]['rrule'][$type]) . $output_js;
 296  
 297    // Set the new exceptions form.
 298    drupal_json(array('status' => TRUE, 'data' => $output));
 299    exit();
 300  }
 301  
 302  /**
 303   * Regroup values back into a consistant array, no matter what state it is in.
 304   */
 305  function date_repeat_merge($form_values, $element) {
 306    if (empty($form_values) || !is_array($form_values)) {
 307      return $form_values;
 308    }
 309    if (array_key_exists('advanced', $form_values) || array_key_exists('exceptions', $form_values) || array_key_exists('additions', $form_values)) {
 310      if (!array_key_exists('advanced', $form_values)) $form_values['advanced'] = array();
 311      if (!array_key_exists('exceptions', $form_values)) $form_values['exceptions'] = array();
 312      if (!array_key_exists('additions', $form_values)) $form_values['additions'] = array();
 313      $form_values = array_merge($form_values, (array) $form_values['advanced'], (array) $form_values['exceptions'], (array) $form_values['additions']);
 314      unset($form_values['advanced']);
 315      unset($form_values['exceptions']);
 316      unset($form_values['additions']);
 317    }
 318    if (array_key_exists('BYDAY', $form_values)) unset($form_values['BYDAY']['']);
 319    if (array_key_exists('BYMONTH', $form_values)) unset($form_values['BYMONTH']['']);
 320    if (array_key_exists('BYMONTHDAY', $form_values)) unset($form_values['BYMONTHDAY']['']);
 321  
 322    if (array_key_exists('UNTIL', $form_values) && is_array($form_values['UNTIL']['datetime'])) {
 323      $function = $element['#date_repeat_widget'] .'_input_value';
 324      $until_element = $element;
 325      $until_element['#value'] = $form_values['UNTIL']['datetime'];
 326      $until_element['#date_format'] = date_limit_format($element['#date_format'], array('year', 'month', 'day'));
 327      $form_values['UNTIL']['datetime'] = $function($until_element);
 328    }
 329    if (array_key_exists('EXDATE', $form_values) && is_array($form_values['EXDATE'])) {
 330      $function = $element['#date_repeat_widget'] .'_input_value';
 331      $exdate_element = $element;
 332      foreach ($form_values['EXDATE'] as $delta => $value) {
 333        if (is_array($value['datetime'])) {
 334          $exdate_element['#value'] = $form_values['EXDATE'][$delta]['datetime'];
 335          $exdate_element['#date_format'] = date_limit_format($element['#date_format'], array('year', 'month', 'day'));
 336          $form_values['EXDATE'][$delta]['datetime'] = $function($exdate_element);
 337        }
 338      }
 339    }
 340    if (array_key_exists('RDATE', $form_values) && is_array($form_values['RDATE'])) {
 341      $function = $element['#date_repeat_widget'] .'_input_value';
 342      $rdate_element = $element;
 343      foreach ($form_values['RDATE'] as $delta => $value) {
 344        if (is_array($value['datetime'])) {
 345          $rdate_element['#value'] = $form_values['RDATE'][$delta]['datetime'];
 346          $rdate_element['#date_format'] = date_limit_format($element['#date_format'], array('year', 'month', 'day'));
 347          $form_values['RDATE'][$delta]['datetime'] = $function($rdate_element);
 348        }
 349      }
 350    }
 351    return $form_values;
 352  }
 353  
 354  /**
 355   * Build a RRULE out of the form values.
 356   */
 357  function date_repeat_rrule_validate($element, &$form_state) {
 358    require_once('./'. drupal_get_path('module', 'date_api') .'/date_api_ical.inc');
 359    $form_values = $form_state['values'];
 360    $field_name = $element['#parents'][0];
 361    $item = $form_values[$field_name]['rrule'];
 362    $item = date_repeat_merge($item, $element);
 363    if (!empty($item['UNTIL']['datetime'])) {
 364      $date = date_make_date($item['UNTIL']['datetime'], $item['UNTIL']['tz']);
 365      date_time_set($date, 23, 59, 59);
 366      date_timezone_set($date, timezone_open('UTC'));
 367      $item['UNTIL']['datetime'] = date_format($date, DATE_FORMAT_DATETIME);
 368      $item['UNTIL']['tz'] = 'UTC';
 369    }
 370    $rrule = date_api_ical_build_rrule($item);
 371    form_set_value($element, $rrule, $form_state);
 372  }
 373  
 374  /**
 375   * Theme the exception list as a table so the buttons line up
 376   */
 377  function theme_date_repeat_current_exceptions($rows = array()) {
 378    $rows_info = array();
 379    foreach ($rows as $key => $value) {
 380      if (substr($key, 0, 1) != '#') {
 381        $rows_info[] = array(drupal_render($value['action']), drupal_render($value['display']));
 382      }
 383    }
 384    return theme('table', array(t('Delete'), t('Current exceptions')), $rows_info);
 385  }
 386  
 387  /**
 388   * Theme the exception list as a table so the buttons line up
 389   */
 390  function theme_date_repeat_current_additions($rows = array()) {
 391    $rows_info = array();
 392    foreach ($rows as $key => $value) {
 393      if (substr($key, 0, 1) != '#') {
 394        $rows_info[] = array(drupal_render($value['action']), drupal_render($value['display']));
 395      }
 396    }
 397    return theme('table', array(t('Delete'), t('Current additions')), $rows_info);
 398  }
 399  
 400  /**
 401   * Themes the date repeat element.
 402   */
 403  function theme_date_repeat($element) {
 404    return theme('form_element', $element, '<div class="container-inline">'. drupal_render($element). '</div>');
 405  }


Generated: Mon Jul 9 18:01:44 2012 Cross-referenced by PHPXref 0.7