You are here

date_all_day.module in Date 7.3

Adds All Day functionality to the Date field.

This module implements a number of hooks in the Date field and Date API element processing and to add an All Day checkbox to date widgets, and also adds an All Day theme and All Day information to the formatting.

Keep in mind that the process hooks are fired from the top down, first date_combo, then the date_select or date_popup.

Validation fires from the bottom up, first date_select and date_popup, then date_combo.

File

date_all_day/date_all_day.module
View source
<?php

/**
 * @file
 * Adds All Day functionality to the Date field.
 *
 * This module implements a number of hooks in the Date field and Date API
 * element processing and to add an All Day checkbox to date widgets, and also
 * adds an All Day theme and All Day information to the formatting.
 *
 * Keep in mind that the process hooks are fired from the top down, first
 * date_combo, then the date_select or date_popup.
 *
 * Validation fires from the bottom up, first date_select and date_popup, then
 * date_combo.
 */

/**
 * Implements hook_theme().
 */
function date_all_day_theme() {
  $themes = array(
    'date_all_day' => array(
      'variables' => array(
        'field' => NULL,
        'instance' => NULL,
        'which' => NULL,
        'date1' => NULL,
        'date2' => NULL,
        'format' => NULL,
        'entity_type' => NULL,
        'entity' => NULL,
        'view' => NULL,
      ),
    ),
    'date_all_day_label' => array(
      'variables' => array(),
    ),
  );
  return $themes;
}

/**
 * Implements hook_date_formatter_dates_alter().
 */
function date_all_day_date_formatter_dates_alter(&$dates, $context) {

  // This allows us to alter the $dates array created by date_formatter_process.
  $field = $context['field'];
  $instance = $context['instance'];
  $format = $context['format'];
  $entity_type = $context['entity_type'];
  $entity = $context['entity'];
  $date1 = $dates['value']['local']['object'];
  $date2 = $dates['value2']['local']['object'];
  $is_all_day = date_all_day_field($field, $instance, $dates);
  $all_day1 = '';
  $all_day2 = '';
  if ($format != 'format_interval' && $is_all_day) {
    $all_day1 = theme('date_all_day', array(
      'field' => $field,
      'instance' => $instance,
      'which' => 'date1',
      'date1' => $date1,
      'date2' => $date2,
      'format' => $format,
      'entity_type' => $entity_type,
      'entity' => $entity,
    ));
    $all_day2 = theme('date_all_day', array(
      'field' => $field,
      'instance' => $instance,
      'which' => 'date2',
      'date1' => $date1,
      'date2' => $date2,
      'format' => $format,
      'entity_type' => $entity_type,
      'entity' => $entity,
    ));
    $dates['value']['formatted_time'] = theme('date_all_day_label');
    $dates['value2']['formatted_time'] = theme('date_all_day_label');
    $dates['value']['formatted'] = $all_day1;
    $dates['value2']['formatted'] = $all_day2;
  }
}

/**
 * Adjust start/end date format to account for 'all day' .
 *
 * @param array $vars
 *   Contains the following items:
 *   'field' - The field definition for this date field.
 *    'which' - Which value to return, 'date1' or 'date2'.
 *    'date1' - A date/time object for the 'start' date.
 *    'date2' - A date/time object for the 'end' date.
 *    'format' - A date/time format.
 *    'entity' - The node this date comes from (may be incomplete, always
 *       contains nid).
 *    'view' - The view this node comes from, if applicable.
 *
 * @return string|null
 *   Formatted date.
 */
function theme_date_all_day($vars) {
  $field = $vars['field'];
  $instance = $vars['instance'];
  $which = $vars['which'];
  $date1 = $vars['date1'];
  $date2 = $vars['date2'];
  $format = $vars['format'];
  $entity = $vars['entity'];
  $view = !empty($vars['view']) ? $vars['view'] : NULL;
  if (empty($date1) || !is_object($date1) || $format == 'format_interval') {
    return;
  }
  if (empty($date2)) {
    $date2 = $date1;
  }
  $suffix = '';
  if (date_has_time($field['settings']['granularity'])) {
    $format = date_limit_format($format, array(
      'year',
      'month',
      'day',
    ));
  }

  // Theme the all-day value.
  $suffix = ' ' . theme('date_all_day_label');
  return trim(date_format_date(${$which}, 'custom', $format) . $suffix);
}

/**
 * Theme the way an 'all day' label will look.
 */
function theme_date_all_day_label() {
  return t('(All day)', array(), array(
    'context' => 'datetime',
  ));
}

/**
 * Determine if a field qualifies as 'All day'.
 *
 * @param array $field
 *   The field definition for this date field.
 * @param array $instance
 *   The field instance for this date field.
 * @param array $value
 *   A date field value.
 *
 * @return bool
 *   TRUE or FALSE.
 */
function date_all_day_field(array $field, array $instance, array $value) {
  if (empty($value)) {
    return FALSE;
  }
  elseif (empty($instance['widget']['settings']['display_all_day'])) {
    return FALSE;
  }

  // As of 7.x-3.x the logic for whether a field counts as "all day" is based
  // purely on this one value.
  return !empty($value['value']['local']['all_day']);
}

/**
 * Implements hook_date_combo_process_alter().
 */
function date_all_day_date_combo_process_alter(&$element, &$form_state, $context) {

  // This hook lets us make changes to the date_combo element.
  $field = $context['field'];
  $instance = $context['instance'];

  // Add the all_day checkbox to the combo element.
  if (!empty($instance['widget']['settings']['display_all_day'])) {
    $parents = $element['#parents'];
    $first_parent = array_shift($parents);
    $all_day_id = $first_parent . '[' . implode('][', $parents) . '][all_day]';
    foreach (array(
      'value',
      'value2',
    ) as $key) {
      if (array_key_exists($key, $element)) {
        $element[$key]['#date_all_day_id'] = $all_day_id;
      }
    }
  }
  else {

    // @todo This seems like unused code? There is no $form here.
    $form['all_day']['#type'] = 'hidden';
    $form['all_day']['#value'] = 0;
  }
}

/**
 * Implements hook_date_text_process_alter().
 */
function date_all_day_date_text_process_alter(&$element, &$form_state, $context) {

  // This hook lets us make changes to the date_select widget.
  $all_day_id = !empty($element['#date_all_day_id']) ? $element['#date_all_day_id'] : '';
  if ($all_day_id != '') {

    // All Day handling on text dates works only if the user leaves the time
    // out of the input value. There is no element to hide or show.
  }
}

/**
 * Implements hook_date_select_process_alter().
 */
function date_all_day_date_select_process_alter(&$element, &$form_state, $context) {

  // This hook lets us make changes to the date_select widget. Hide or show
  // this element in reaction to the all_day status for this element.
  $all_day_id = !empty($element['#date_all_day_id']) ? $element['#date_all_day_id'] : '';
  if ($all_day_id != '') {
    foreach (array(
      'hour',
      'minute',
      'second',
      'ampm',
    ) as $field) {
      if (array_key_exists($field, $element)) {
        $element[$field]['#states'] = array(
          'visible' => array(
            'input[name="' . $all_day_id . '"]' => array(
              'checked' => FALSE,
            ),
          ),
        );
      }
    }
  }
}

/**
 * Implements hook_date_popup_process_alter().
 */
function date_all_day_date_popup_process_alter(&$element, &$form_state, $context) {

  // This hook lets us make changes to the date_popup element. Hide or show
  // this element in reaction to the all_day status for this element.
  $all_day_id = !empty($element['#date_all_day_id']) ? $element['#date_all_day_id'] : '';
  if ($all_day_id != '' && array_key_exists('time', $element)) {
    $element['time']['#states'] = array(
      'visible' => array(
        'input[name="' . $all_day_id . '"]' => array(
          'checked' => FALSE,
        ),
      ),
    );
  }
}

/**
 * Implements hook_date_select_pre_validate_alter().
 */
function date_all_day_date_text_pre_validate_alter(&$element, &$form_state, &$input) {

  // This hook lets us alter the element or the form_state before the rest of
  // the date_select validation gets fired. Let Date module massage the format
  // for all day values so they will pass validation. The All day flag, if
  // used, actually exists on the parent element.
  return date_all_day_value($element, $form_state);
}

/**
 * Implements hook_date_select_pre_validate_alter().
 */
function date_all_day_date_select_pre_validate_alter(&$element, &$form_state, &$input) {

  // This hook lets us alter the element or the form_state before the rest of
  // the date_select validation gets fired. Let Date module massage the format
  // for all day values so they will pass validation. The All day flag, if
  // used, actually exists on the parent element.
  return date_all_day_value($element, $form_state);
}

/**
 * Implements hook_date_select_pre_validate_alter().
 */
function date_all_day_date_popup_pre_validate_alter(&$element, &$form_state, &$input) {

  // This hook lets us alter the element or the form_state before the rest of
  // the date_popup validation gets fired. Let Date module massage the format
  // for all day values so they will pass validation. The All day flag, if
  // used, actually exists on the parent element.
  return date_all_day_value($element, $form_state);
}

/**
 * Ensure date fields have the all-day flag set.
 *
 * To check if the all day flag is set on the parent of an element, and adjust
 * the date_format accordingly so the missing time will not cause validation
 * errors.
 *
 * @return bool
 *   Whether this field is configured to allow all-day values.
 *
 * @todo Is the return value used anywhere?
 *
 * @see date_all_day_date_popup_pre_validate_alter()
 * @see date_all_day_date_select_pre_validate_alter()
 * @see date_all_day_date_text_pre_validate_alter()
 */
function date_all_day_value(&$element, $form_state) {
  if (!empty($element['#date_all_day_id'])) {
    $parents = $element['#parents'];
    array_pop($parents);
    $parent_element = drupal_array_get_nested_value($form_state['values'], $parents);
    if (!empty($parent_element) && !empty($parent_element['all_day'])) {
      return $parent_element['all_day'];
    }
  }
  return FALSE;
}

/**
 * Implements hook_date_combo_pre_validate_alter().
 */
function date_all_day_date_combo_pre_validate_alter(&$element, &$form_state, $context) {

  // This hook lets the element or the form_state be altered before the rest of
  // the date_combo validation gets fired.
  if (!empty($context['item']['all_day'])) {
    $field = $context['field'];

    // If there is an all day flag on this date and the time is empty, change
    // the format to match the input value so it doesn't get validation errors.
    $element['#date_is_all_day'] = TRUE;
  }
}

/**
 * Implements hook_date_combo_validate_date_start_alter().
 */
function date_all_day_date_combo_validate_date_start_alter(&$date, &$form_state, $context) {

  // This hook lets us alter the local date objects created by the date_combo
  // validation before they are converted back to the database timezone and
  // stored. If this is an 'All day' value, set the time to midnight.
  if (!empty($context['element']['#date_is_all_day'])) {
    $date
      ->setTime(0, 0, 0);
  }
}

/**
 * Implements hook_date_combo_validate_date_end_alter().
 */
function date_all_day_date_combo_validate_date_end_alter(&$date, &$form_state, $context) {

  // This hook lets us alter the local date objects created by the date_combo
  // validation before they are converted back to the database timezone and
  // stored. If this is an 'All day' value, set the time as close to midnight as
  // possible.
  if (!empty($context['element']['#date_is_all_day'])) {
    $increment = isset($context['instance']['widget']['settings']['increment']) ? $context['instance']['widget']['settings']['increment'] : 1;

    // @todo Should this reduce by an additional 1 minute if the increment is
    // more than 1? For example, if the increment is 15 should the upper value
    // be 23:45:59 or 23:44:59?
    $date
      ->setTime(23, 60 - $increment, 59);
  }
}

/**
 * Implements hook_field_widget_info_alter().
 */
function date_all_day_field_widget_info_alter(&$info) {

  // This Field API hook lets us add a new setting to the widgets.
  // Add a setting to a widget type.
  $info['date_select']['settings'] += array(
    'display_all_day' => 0,
  );
  $info['date_text']['settings'] += array(
    'display_all_day' => 0,
  );
  if (module_exists('date_popup')) {
    $info['date_popup']['settings'] += array(
      'display_all_day' => 0,
    );
  }
}

/**
 * Implements hook_date_field_widget_settings_form_alter().
 */
function date_all_day_date_field_widget_settings_form_alter(&$form, $context) {

  // This hook lets us alter the field settings form by adding a place to set
  // the value added above.
  $field = $context['field'];
  $instance = $context['instance'];
  $settings = $instance['widget']['settings'];
  $form['display_all_day'] = array(
    '#type' => 'checkbox',
    '#title' => t('Display all day checkbox'),
    '#default_value' => $settings['display_all_day'],
    '#description' => t("Determines whether to display the 'All Day' checkbox to the user."),
    '#weight' => 8,
    '#fieldset' => 'date_format',
  );

  // Hide the option to use the all day checkbox for dates with no time.
  if (!date_has_time($field['settings']['granularity'])) {
    $form['display_all_day']['#type'] = 'hidden';
    $form['display_all_day']['#value'] = 0;
  }
}

/**
 * Implements hook_field_widget_form_alter().
 */
function date_all_day_field_widget_form_alter(&$element, &$form_state, $context) {
  if ($context['instance']['widget']['type'] == 'date_text') {
    $date_is_all_day = !empty($element['#default_value']['all_day']);
    $element['all_day'] = array(
      '#title' => t('All Day'),
      '#type' => 'checkbox',
      '#default_value' => !empty($form_state['values']['all_day']) || $date_is_all_day,
      '#weight' => -21,
      '#prefix' => '<div class="date-float">',
      '#suffix' => '</div>',
      '#description' => t('If present, the time portion of the date string will be ignored when this option is checked.'),
    );
  }
  elseif ($context['instance']['widget']['type'] == 'date_select') {
    $date_is_all_day = !empty($element['#default_value']['all_day']);
    $element['all_day'] = array(
      '#title' => t('All Day'),
      '#type' => 'checkbox',
      '#default_value' => !empty($form_state['values']['all_day']) || $date_is_all_day,
      '#weight' => -21,
      '#prefix' => '<div class="date-float">',
      '#suffix' => '</div>',
    );
  }
  elseif ($context['instance']['widget']['type'] == 'date_popup') {
    $date_is_all_day = !empty($element['#default_value']['all_day']);
    $element['all_day'] = array(
      '#title' => t('All Day'),
      '#type' => 'checkbox',
      '#default_value' => !empty($form_state['values']['all_day']) || $date_is_all_day,
      '#weight' => -21,
      '#prefix' => '<div class="date-float">',
      '#suffix' => '</div>',
    );
  }
}

Functions

Namesort descending Description
date_all_day_date_combo_pre_validate_alter Implements hook_date_combo_pre_validate_alter().
date_all_day_date_combo_process_alter Implements hook_date_combo_process_alter().
date_all_day_date_combo_validate_date_end_alter Implements hook_date_combo_validate_date_end_alter().
date_all_day_date_combo_validate_date_start_alter Implements hook_date_combo_validate_date_start_alter().
date_all_day_date_field_widget_settings_form_alter Implements hook_date_field_widget_settings_form_alter().
date_all_day_date_formatter_dates_alter Implements hook_date_formatter_dates_alter().
date_all_day_date_popup_pre_validate_alter Implements hook_date_select_pre_validate_alter().
date_all_day_date_popup_process_alter Implements hook_date_popup_process_alter().
date_all_day_date_select_pre_validate_alter Implements hook_date_select_pre_validate_alter().
date_all_day_date_select_process_alter Implements hook_date_select_process_alter().
date_all_day_date_text_pre_validate_alter Implements hook_date_select_pre_validate_alter().
date_all_day_date_text_process_alter Implements hook_date_text_process_alter().
date_all_day_field Determine if a field qualifies as 'All day'.
date_all_day_field_widget_form_alter Implements hook_field_widget_form_alter().
date_all_day_field_widget_info_alter Implements hook_field_widget_info_alter().
date_all_day_theme Implements hook_theme().
date_all_day_value Ensure date fields have the all-day flag set.
theme_date_all_day Adjust start/end date format to account for 'all day' .
theme_date_all_day_label Theme the way an 'all day' label will look.