You are here

timefield.module in Timefield 1.0.x

Same filename and directory in other branches
  1. 7 timefield.module

Contains timefield.module.

File

timefield.module
View source
<?php

/**
 * @file
 * Contains timefield.module.
 */
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Component\Render\FormattableMarkup;

/**
 * Timefield js settings.
 *
 * @param $class
 * @param $settings
 * @return array
 */
function _timefield_js_settings($class, $settings) {
  $js_settings = array(
    'showLeadingZero' => $settings['showLeadingZero'],
    'timeSeparator' => $settings['separator'],
    'showPeriod' => $settings['showPeriod'],
    'showPeriodLabels' => $settings['showPeriod'],
    'periodSeparator' => $settings['periodSeparator'],
    'amPmText' => array(
      $settings['am_text'],
      $settings['pm_text'],
    ),
    'showMinutesLeadingZero' => TRUE,
    'showCloseButton' => $settings['showCloseButton'],
    'closeButtonText' => $settings['closeButtonText'],
    'showNowButton' => $settings['showNowButton'],
    'nowButtonText' => $settings['nowButtonText'],
    'showDeselectButton' => $settings['showDeselectButton'],
    'deselectButtonText' => $settings['deselectButtonText'],
    'myPosition' => $settings['myPosition'],
    'atPosition' => $settings['atPosition'],
  );
  return $js_settings;
}

/**
 * Helper function to return time value from a timefield integer.
 *
 * @param array $settings
 *   Field formatter settings.  This is a structured array used to format a date
 *   with PHP's date() function.  This array has the following keys:
 *     -separator
 *       The character(s) the go(es) between the hour and minute value
 *     -period_separator
 *       The character(s) the go(es) between the time string and the period
 *       (AM/PM)
 *     -period
 *       The PHP formatting option for period, or "none" to omit display
 *     -hour
 *       The PHP formatting option for hour
 *     -minute
 *       The PHP formatting option for minute
 *    @see _timefield_time_part_format() for some possible options.  It is worth
 *    noting that no assumptions are made about how one wishes to format date
 *    output, e.g., 24-hour formatted times are not assumed to not have AM/PM
 *    period information.
 * @param integer $value
 *   Integer offset from midnight to be converted to human-readable time.  This
 *   value is basically number of seconds from midnight.  If you wish to
 *   to show a time +1 day, your value can be greater than 86400.
 *
 * @return string
 *   Human-readable time string
 */
function timefield_integer_to_time($settings, $value) {
  $format = timefield_build_time_format($settings);
  if (isset($value)) {
    if ($value >= 86400) {
      $value = $value - 86400;
    }
    return date($format, mktime(0, 0, $value));
  }
  else {
    return '';
  }
}

/**
 * Helper function to return duration value from a timefield integer value, in
 * specified format.
 *
 * @param integer $value
 *   Time value in seconds
 * @param string $format
 *   Out format options. Possible options are:
 *     -hours
 *     -minutes
 *     -seconds
 *     -time
 *
 *  @return string
 *    Integer cast to string or string depending on $format passed.
 */
function timefield_integer_to_duration($value, $format) {
  switch ($format) {
    case 'hours':
      return (string) round($value / 60 / 60, 2);
      break;
    case 'minutes':
      return (string) round($value / 60, 2);
      break;
    case 'seconds':
      return (string) $value;
      break;
    case 'time':
      return date('g:i', mktime(NULL, NULL, $value));
      break;
  }
}

/**
 * Helper function to return integer value offset from midnight from time
 * format.
 *
 * @param string $value
 *   Time format that should be parsable via date_parse().
 */
function timefield_time_to_integer($value) {
  $time = date_parse($value);
  $output = 0;
  if ($time['error_count'] == 0) {
    $output += $time['hour'] * 60 * 60;
    $output += $time['minute'] * 60;
    $output += $time['second'];
    return $output;
  }
  else {
    return 0;
  }
}

/**
 * Helper function to return duration value from 2 values, in specified format.
 *
 * @param integer $value
 *   First time value
 * @param integer $value2
 *   Second time value
 * @param string $format
 *   Out format options. Possible options are:
 *     -hours
 *     -minutes
 *     -seconds
 *     -time
 *
 *  @return mixed
 *    Integer or string depending on $format passed
 */
function timefield_time_to_duration($value, $value2, $format) {
  if ($value2 < $value) {
    $value2 += 86400;
  }
  $duration = $value2 - $value;
  switch ($format) {
    case 'hours':
      return round($duration / 60 / 60, 2);
      break;
    case 'minutes':
      return round($duration / 60, 2);
      break;
    case 'seconds':
      return $duration;
      break;
    case 'time':
      return date('g:i', mktime(NULL, NULL, $duration));
      break;
  }
  return 0;
}
function template_preprocess_timefield(&$variables) {
  if ($variables['format'] == 'default') {

    // Encode the time elements.
    $variables['time']['value'] = \Drupal\Component\Utility\Html::escape($variables['time']['value']);
    $variables['time']['formatted_value'] = trim(timefield_integer_to_time($variables['settings']['display_format'], $variables['time']['value']));
    $variables['time']['time'] = $variables['time']['formatted_value'];
    if (isset($variables['time']['value2'])) {
      $variables['time']['value2'] = \Drupal\Component\Utility\Html::escape($variables['time']['value2']);
      $variables['time']['formatted_value2'] = trim(timefield_integer_to_time($variables['settings']['display_format'], $variables['time']['value2']));
      $variables['time']['time'] .= ' - ' . $variables['time']['formatted_value2'];
    }
    if ($variables['settings']['weekly_summary'] || $variables['settings']['weekly_summary_with_label']) {
      foreach (_timefield_weekly_summary_days() as $day => $day_text) {
        $days = array();
        if ((bool) $variables['time'][$day]) {
          $days[$day] = $day_text;
        }
      }
      if ($days) {
        $variables['time']['days'] = $days;
        $variables['time']['time'] = implode(', ', $days) . ' ' . $variables['time']['time'];
      }
    }
  }
}
function _timefield_display_format_form($name, $fieldset_header, $settings) {
  $element[$name] = array(
    '#title' => \Drupal\Component\Utility\Html::escape($fieldset_header),
    '#type' => 'fieldset',
  );
  $element[$name]['hour'] = array(
    '#title' => t('Hour Format'),
    '#type' => 'select',
    '#default_value' => isset($settings[$name]['hour']) ? $settings[$name]['hour'] : 'g',
    '#options' => _timefield_time_part_format('hour'),
  );
  $element[$name]['minute'] = array(
    '#title' => t('Minute Format'),
    '#type' => 'select',
    '#default_value' => isset($settings[$name]['minute']) ? $settings[$name]['minute'] : 'i',
    '#options' => _timefield_time_part_format('minute'),
  );
  $element[$name]['separator'] = array(
    '#title' => t('Hour and Minute Separator'),
    '#type' => 'textfield',
    '#default_value' => isset($settings[$name]['separator']) ? $settings[$name]['separator'] : ':',
    '#size' => 10,
  );
  $element[$name]['period'] = array(
    '#title' => t('AM/PM format'),
    '#type' => 'select',
    '#default_value' => isset($settings[$name]['period']) ? $settings[$name]['period'] : 'a',
    '#options' => _timefield_time_part_format('period'),
  );
  $element[$name]['periodSeparator'] = array(
    '#title' => t('Minute and period separtor'),
    '#type' => 'textfield',
    '#default_value' => isset($settings[$name]['periodSeparator']) ? $settings[$name]['periodSeparator'] : '',
    '#size' => 10,
    '#description' => t('The character used to separate the time from the time period (AM/PM)'),
  );
  return $element;
}
function _timefield_time_part_format($part) {
  $values = array(
    'hour' => array(
      'g' => t('12-hour format of an hour without leading zeros'),
      'G' => t('24-hour format of an hour without leading zeros'),
      'h' => t('12-hour format of an hour with leading zeros'),
      'H' => t('24-hour format of an hour with leading zeros'),
    ),
    'minute' => array(
      'i' => t('Minutes with leading Zeros'),
      'none' => t('Do not display minutes'),
    ),
    'period' => array(
      'a' => t('Lowercase Ante meridiem and Post meridiem (am/pm)'),
      'A' => t('Uppercase Ante meridiem and Post meridiem (AM/PM)'),
      'none' => t('Do not display period'),
    ),
  );
  return $values[$part];
}
function timefield_build_time_format($settings) {
  if (isset($settings['showPeriod'])) {
    $format = $settings['showLeadingZero'] ? 'h' : 'g';

    //convert to 12/24 format based on period
    $format = $settings['showPeriod'] ? strtolower($format) : strtoupper($format);
    $format .= $settings['separator'] . 'i';
    $format .= $settings['periodSeparator'] != '' && $settings['showPeriod'] ? strtolower($settings['periodSeparator']) : '';
    $format .= $settings['showPeriod'] ? 'a' : '';
  }
  else {
    $format = $settings['hour'];
    $format .= $settings['minute'] == 'none' ? '' : $settings['separator'] . $settings['minute'];
    $format .= $settings['period'] == 'none' ? '' : (isset($settings['periodSeparator']) ? $settings['periodSeparator'] : '') . $settings['period'];
  }
  return $format;
}

/**
 * Map first day of week
 */
function _timefield_weekly_summary_days_map($item) {
  $days = _timefield_weekly_summary_days();
  $output = array();
  foreach ($days as $day => $label) {
    $output[$day] = $item->{$day} === 0 || $item->{$day} == "0" ? 0 : $day;
  }
  return $output;
}

/**
 * Helper function days array
 */
function _timefield_weekly_summary_days() {
  $days = array(
    'mon' => t('Monday'),
    'tue' => t('Tuesday'),
    'wed' => t('Wednesday'),
    'thu' => t('Thursday'),
    'fri' => t('Friday'),
    'sat' => t('Saturday'),
    'sun' => t('Sunday'),
  );
  return $days;
}

/**
 * Implements hook_theme().
 */
function timefield_theme() {
  return array(
    'timefield_formatter' => array(
      'render element' => 'element',
      'variables' => array(
        'label' => NULL,
        'label_display' => NULL,
        'label_hidden' => NULL,
        'items' => NULL,
        'settings' => NULL,
        'format' => NULL,
      ),
      'template' => 'timefield',
    ),
    'timefield_duration' => array(
      'render element' => 'element',
      'variables' => array(
        'label' => NULL,
        'label_display' => NULL,
        'label_hidden' => NULL,
        'items' => NULL,
        'settings' => NULL,
        'format' => NULL,
      ),
      'template' => 'timefield-duration',
    ),
    'timefield_weekly_summary_minical_box' => array(
      'render element' => 'element',
      'variables' => array(
        'label' => NULL,
        'label_display' => NULL,
        'label_hidden' => NULL,
        'items' => NULL,
        'settings' => NULL,
        'format' => NULL,
        'time' => NULL,
      ),
      'template' => 'timefield-weekly-minical-box',
    ),
    'timefield_mini_calendar' => array(
      'render element' => 'element',
      'variables' => array(
        'label' => NULL,
        'label_display' => NULL,
        'label_hidden' => NULL,
        'header' => NULL,
        'rows' => NULL,
        'content' => NULL,
      ),
      'template' => 'timefield-mini-calendar',
    ),
  );
}

/**
 * Helper function to build options array
 */
function _timefield_duration_options($current_option = NULL) {
  $values = array(
    'hours' => t('Duration in decimal hours, e.g. 1.5'),
    'seconds' => t('Duration in seconds'),
    'minutes' => t('Duration in minutes'),
    'time' => t('Duration in time format hours, e.g. 1:30'),
  );
  if (is_null($current_option)) {
    return $values;
  }
  else {
    return $values[$current_option];
  }
}

/**
 * Build a header for a schedule table
 */
function _timefield_weekly_summary_build_header($first_day) {
  $days = _timefield_weekly_summary_days();
  $day_list = $days;
  $header = array(
    'time' => t('Time'),
  );
  $found_header = FALSE;
  foreach ($days as $index => $day) {
    if ($index == $first_day) {
      $found_header = TRUE;
    }
    if ($found_header) {
      $header[$index] = $day;
      unset($day_list[$index]);
    }
  }
  $header += $day_list;
  return $header;
}

/**
 * Add rows to the table
 */
function timefield_weekly_summary_build_rows($item, $header, $settings) {
  _timefield_weekly_summary_explode_items($item);
  $times = _timefield_weekly_summary_build_time_column($settings);
  $abs_start = timefield_time_to_integer($settings['absolute_start']);
  $abs_end = timefield_time_to_integer($settings['absolute_end']);
  $total_range = $abs_end - $abs_start;
  $cell_data = array();
  $count = 0;
  foreach ($times as $time_index => $time) {
    $row['time'] = array(
      'data' => $time['display'],
    );
    if (!isset($cell_data[$time_index])) {
      $cell_data[$time_index] = array();
    }
    foreach ($header as $index => $label) {
      if ($index == 'time') {
        continue;
      }
      if (!isset($cell_data[$time_index][$index])) {
        $cell_data[$time_index][$index] = array();
      }
      foreach ($item as $i => $v) {
        if ($v['value'] >= $time['start'] && $v['value'] < $time['stop'] && $v[$index] == '1') {
          $row_data = array(
            'element' => $v,
            'settings' => $settings,
            'day' => array(
              $index => $label,
            ),
          );
          $row_data['span_time'] = ($v['value2'] - $v['value']) / $total_range * 100;
          $row_data['offset_time'] = ($v['value'] - $abs_start) / $total_range * 100;
          $start_time = trim(timefield_integer_to_time($settings['display_format'], $v['value']));
          $end_time = trim(timefield_integer_to_time($settings['display_format'], $v['value2']));
          $renderer = \Drupal::service('renderer');
          $t = array(
            '#theme' => 'timefield_weekly_summary_minical_box',
            '#label' => $v['label'],
            '#time' => $start_time . '-' . $end_time,
          );
          $cell_data[$time_index][$index][] = new FormattableMarkup($renderer
            ->renderPlain($t), []);
        }
      }
      $row[$index] = array(
        'data' => [
          '#markup' => !empty($cell_data[$time_index][$index]) ? implode(' ', $cell_data[$time_index][$index]) : '',
        ],
      );
    }
    $rows[] = array(
      'data' => $row,
      'class' => array(
        'row-' . $count,
      ),
    );
    $count += 1;
  }
  return $rows;
}

/**
 * Helper function to explode all items in a timefield value array so that
 * we can sort across multivalue fields
 */
function _timefield_weekly_summary_explode_items(&$items) {
  $new_array = array();
  foreach ($items as $item) {
    foreach (array_keys(_timefield_weekly_summary_days()) as $day) {
      if ($item->{$day}) {
        $ar = array(
          'label' => isset($item->label) ? $item->label : '',
          'mon' => FALSE,
          'tue' => FALSE,
          'wed' => FALSE,
          'thu' => FALSE,
          'fri' => FALSE,
          'sat' => FALSE,
          'sun' => FALSE,
          'value' => $item->value,
          'value2' => $item->value2,
        );
        $ar[$day] = TRUE;
        $new_array[] = $ar;
      }
    }
  }

  // Sort our new array.
  uasort($new_array, '_timefield_weekly_summary_time_sort');
  $items = $new_array;
}

/**
 * Uasort callback function
 */
function _timefield_weekly_summary_time_sort($a, $b) {
  $calca = _timefield_weekly_summary_week_time_offset($a);
  $calcb = _timefield_weekly_summary_week_time_offset($b);
  if ($calca == $calcb) {
    return 0;
  }
  return $calca < $calcb ? -1 : 1;
}

/**
 *  Calculate offset from beginning of week.
 */
function _timefield_weekly_summary_week_time_offset($elem) {
  $multiplier = 60 * 60 * 24;
  if ($elem['mon']) {
    $mult = 0;
  }
  if ($elem['tue']) {
    $mult = 1;
  }
  if ($elem['wed']) {
    $mult = 2;
  }
  if ($elem['thu']) {
    $mult = 3;
  }
  if ($elem['fri']) {
    $mult = 4;
  }
  if ($elem['sat']) {
    $mult = 5;
  }
  if ($elem['sun']) {
    $mult = 6;
  }
  return $multiplier * $mult + $elem['value'];
}

/**
 * Helper function to build the time column for the minical table.
 */
function _timefield_weekly_summary_build_time_column($settings, $start_times = array()) {
  $time_array = array();
  $start = timefield_time_to_integer($settings['absolute_start']);
  $end = timefield_time_to_integer($settings['absolute_end']);
  $total_range = $end - $start;
  $step_amount = $settings['range'] * 60;
  $steps = ceil($total_range / $step_amount);
  for ($index = 0; $index < $steps; $index++) {
    if ($index == 0) {
      $current = $start;
    }
    $time_array[$current] = array(
      'start' => $current,
      'stop' => $current + $step_amount,
      'display' => timefield_integer_to_time($settings['column_format'], $current) . ' - ' . timefield_integer_to_time($settings['column_format'], $current + $step_amount),
      'last_row' => $index + 1 == $steps ? TRUE : FALSE,
    );
    $current += $step_amount;
  }
  return $time_array;
}

/**
 * Implements hook_help().
 */
function timefield_help($route_name, RouteMatchInterface $route_match) {
  if ($route_name === 'help.page.timefield') {
    $path = __DIR__ . '/README.md';
    if (file_exists($path)) {
      return '<pre>' . file_get_contents($path) . '</pre>';
    }
  }
  return NULL;
}

Functions

Namesort descending Description
template_preprocess_timefield
timefield_build_time_format
timefield_help Implements hook_help().
timefield_integer_to_duration Helper function to return duration value from a timefield integer value, in specified format.
timefield_integer_to_time Helper function to return time value from a timefield integer.
timefield_theme Implements hook_theme().
timefield_time_to_duration Helper function to return duration value from 2 values, in specified format.
timefield_time_to_integer Helper function to return integer value offset from midnight from time format.
timefield_weekly_summary_build_rows Add rows to the table
_timefield_display_format_form
_timefield_duration_options Helper function to build options array
_timefield_js_settings Timefield js settings.
_timefield_time_part_format
_timefield_weekly_summary_build_header Build a header for a schedule table
_timefield_weekly_summary_build_time_column Helper function to build the time column for the minical table.
_timefield_weekly_summary_days Helper function days array
_timefield_weekly_summary_days_map Map first day of week
_timefield_weekly_summary_explode_items Helper function to explode all items in a timefield value array so that we can sort across multivalue fields
_timefield_weekly_summary_time_sort Uasort callback function
_timefield_weekly_summary_week_time_offset Calculate offset from beginning of week.