- <?php
- * @file
- * Date forms and form themes and validation.
- *
- * All code used in form editing and processing is in this file,
- * included only during form editing.
- */
-
- * Implements hook_element_info().
- *
- * Parameters for date form elements, designed to have sane defaults so any
- * or all can be omitted.
- *
- * Fill the element #default_value with a date in datetime format,
- * (YYYY-MM-DD HH:MM:SS), adjusted to the proper local timezone.
- *
- * NOTE - Converting a date stored in the database from UTC to the local zone
- * and converting it back to UTC before storing it is not handled by this
- * element and must be done in pre-form and post-form processing!
- *
- * The date_select element will create a collection of form elements, with a
- * separate select or textfield for each date part. The whole collection will
- * get reformatted back to a date value of the requested type during validation.
- *
- * The date_text element will create a textfield that can contain a whole
- * date or any part of a date as text. The user input value will be re-formatted
- * back into a date value of the requested type during validation.
- *
- * The date_popup element will create two textfields, one for the date and one
- * for the time. The date textfield will include a jQuery popup calendar date
- * picker, and the time textfield uses a jQuery timepicker.
- *
- * The date_timezone element will create a drop-down selector to pick a
- * timezone name.
- *
- * The date_year_range element will create two textfields (for users with
- * JavaScript enabled they will appear as drop-down selectors with an option
- * for custom text entry) to pick a range of years that will be passed to form
- * submit handlers as a single string (e.g., -3:+3).
- *
- * The date_combo element will create a 'start' and optional 'end' date, along
- * with an optional 'timezone' column for date-specific timezones. Each
- * 'start' and 'end' date will be constructed from date_select or date_text.
- *
- * #date_timezone
- * The local timezone to be used to create this date.
- *
- * #date_format
- * A format string that describes the format and order of date parts to
- * display in the edit form for this element. This makes it possible
- * to show date parts in a custom order, or to leave some of them out.
- * Be sure to add 'A' or 'a' to get an am/pm selector. Defaults to the
- * short site default format.
- *
- * #date_label_position
- * Handling option for date part labels, like 'Year', 'Month', and 'Day',
- * can be 'above' the date part, 'within' it, or 'none', default is 'above' .
- * The 'within' option shows the label as the first option in a select list
- * or the default value for an empty textfield, taking up less screen space.
- *
- * #date_increment
- * Increment minutes and seconds by this amount, default is 1.
- *
- * #date_year_range
- * The number of years to go back and forward in a year selector,
- * default is -3:+3 (3 back and 3 forward).
- *
- * #date_text_parts
- * Array of date parts that should use textfields instead of selects
- * i.e. array('year') will format the year as a textfield and other
- * date parts as drop-down selects.
- *
- * Additionally, the date_popup element supports the additional properties:
- *
- * #datepicker_options
- * An associative array representing the jQuery datepicker options you want
- * to set for this element. Use the jQuery datepicker option names as keys.
- * Defaults include:
- * - changeMonth => TRUE
- * - changeYear => TRUE
- * - autoPopUp => 'focus'
- * - closeAtTop => FALSE
- * - speed => 'immediate'
- */
- function _date_element_info() {
- $date_base = array(
- '#input' => TRUE,
- '#tree' => TRUE,
- '#date_timezone' => date_default_timezone(),
- '#date_flexible' => 0,
- '#date_format' => system_date_format_load('short'),
- '#date_text_parts' => array(),
- '#date_increment' => 1,
- '#date_year_range' => '-3:+3',
- '#date_label_position' => 'above',
- );
- $type['date_select'] = array(
- '#process' => array('date_select_element_process'),
- '#theme_wrappers' => array('date_select'),
- '#value_callback' => 'date_select_element_value_callback',
- ) + $date_base;
- $type['date_text'] = array(
- '#process' => array('date_text_element_process'),
- '#theme_wrappers' => array('date_text'),
- '#value_callback' => 'date_text_element_value_callback',
- ) + $date_base;
- $type['date_popup'] = array(
- '#datepicker_options' => array(),
- '#timepicker' => TRUE,
- '#process' => array('date_popup_element_process'),
- '#value_callback' => 'date_popup_element_value_callback',
- '#theme_wrappers' => array('date_popup'),
- ) + $date_base;
- $type['date_timezone'] = array(
- '#input' => TRUE,
- '#tree' => TRUE,
- '#process' => array('date_timezone_element_process'),
- '#theme_wrappers' => array('date_text'),
- '#value_callback' => 'date_timezone_element_value_callback',
- );
- $type['date_year_range'] = array(
- '#input' => TRUE,
- '#process' => array('date_year_range_element_process'),
- '#value_callback' => 'date_year_range_element_value_callback',
- '#element_validate' => array('date_year_range_validate'),
- );
- $type['date_combo'] = array(
- '#input' => TRUE,
- '#delta' => 0,
- '#columns' => array('value', 'value2', 'timezone', 'offset', 'offset2'),
- '#process' => array('date_combo_element_process'),
- '#element_validate' => array('date_combo_validate'),
- '#theme_wrappers' => array('date_combo'),
- );
- return $type;
- }
-
- * Create a date object from a datetime string value.
- */
- function date_default_date($element) {
- $granularity = date_format_order($element['#date_format']);
- $default_value = $element['#default_value'];
- $format = DATE_FORMAT_DATETIME;
-
-
- if (strlen($element['#default_value']) < 19) {
- switch (strlen($element['#default_value'])) {
- case 16:
- $format = 'Y-m-d H:i';
- break;
-
- case 13:
- $format = 'Y-m-d H';
- break;
-
- case 10:
- $format = 'Y-m-d';
- break;
-
- case 7:
- $format = 'Y-m';
- break;
-
- case 4:
- $format = 'Y';
- break;
- }
- }
- $date = new BackdropDateTime($default_value, $element['#date_timezone'], $format);
- if (is_object($date)) {
- $date->limitGranularity($granularity);
- if ($date->validGranularity($granularity, $element['#date_flexible'])) {
- date_increment_round($date, $element['#date_increment']);
- }
- return $date;
- }
- return NULL;
- }
-
- * Process callback which creates a date_year_range form element.
- */
- function date_year_range_element_process($element, &$form_state, $form) {
-
-
- $element['years_back'] = array(
- '#type' => 'textfield',
- '#title' => t('Starting year'),
- '#default_value' => $element['#value']['years_back'],
- '#size' => 10,
- '#maxsize' => 10,
- '#attributes' => array('class' => array('select-list-with-custom-option', 'back')),
- '#description' => t('Enter a relative value (-9, +9) or an absolute year such as 2015.'),
- );
- $element['years_forward'] = array(
- '#type' => 'textfield',
- '#title' => t('Ending year'),
- '#default_value' => $element['#value']['years_forward'],
- '#size' => 10,
- '#maxsize' => 10,
- '#attributes' => array('class' => array('select-list-with-custom-option', 'forward')),
- '#description' => t('Enter a relative value (-9, +9) or an absolute year such as 2015.'),
- );
-
- $element['#tree'] = TRUE;
- $element['#attached']['js'][] = backdrop_get_path('module', 'date') . '/js/date-year-range.js';
-
- $context = array(
- 'form' => $form,
- );
- backdrop_alter('date_year_range_process', $element, $form_state, $context);
-
- return $element;
- }
-
- * Element value callback for the date_year_range form element.
- */
- function date_year_range_element_value_callback($element, $input = FALSE, &$form_state = array()) {
-
-
- if ($input === FALSE) {
- list($years_back, $years_forward) = explode(':', $element['#default_value']);
- return array(
- 'years_back' => $years_back,
- 'years_forward' => $years_forward,
- );
- }
- return NULL;
- }
-
- * Element validation function for the date_year_range form element.
- */
- function date_year_range_validate(&$element, &$form_state) {
-
-
- $year_range_submitted = backdrop_array_get_nested_value($form_state['values'], $element['#parents']);
- $year_range = $year_range_submitted['years_back'] . ':' . $year_range_submitted['years_forward'];
- backdrop_array_set_nested_value($form_state['values'], $element['#parents'], $year_range);
- if (!date_range_valid($year_range)) {
- form_error($element['years_back'], t('Starting year must be in the format -9, or an absolute year such as 1980.'));
- form_error($element['years_forward'], t('Ending year must be in the format +9, or an absolute year such as 2030.'));
- }
- }
-
- * Element value callback for date_timezone element.
- */
- function date_timezone_element_value_callback($element, $input = FALSE, &$form_state = array()) {
- $return = '';
- if ($input !== FALSE) {
- $return = $input;
- }
- elseif (!empty($element['#default_value'])) {
- $return = array('timezone' => $element['#default_value']);
- }
- return $return;
- }
-
- * Creates a timezone form element.
- *
- * @param array $element
- * The timezone form element.
- *
- * @return array
- * the timezone form element
- */
- function date_timezone_element_process($element, &$form_state, $form) {
- if (date_hidden_element($element)) {
- return $element;
- }
-
- $element['#tree'] = TRUE;
- $element['timezone'] = array(
- '#type' => 'select',
- '#title' => t('Timezone'),
- '#title_display' => $element['#date_label_position'] == 'above' ? 'before' : 'invisible',
- '#options' => date_timezone_names($element['#required']),
- '#value' => $element['#value'],
- '#weight' => $element['#weight'],
- '#required' => $element['#required'],
- '#theme' => 'date_select_element',
- '#theme_wrappers' => array('form_element'),
- );
- if (isset($element['#element_validate'])) {
- array_push($element['#element_validate'], 'date_timezone_validate');
- }
- else {
- $element['#element_validate'] = array('date_timezone_validate');
- }
-
- $context = array(
- 'form' => $form,
- );
- backdrop_alter('date_timezone_process', $element, $form_state, $context);
-
- return $element;
- }
-
- * Validation for timezone input.
- *
- * Move the timezone value from the nested field back to the original field.
- */
- function date_timezone_validate($element, &$form_state) {
- if (date_hidden_element($element)) {
- return;
- }
-
- form_set_value($element, $element['#value']['timezone'], $form_state);
- }
-
- * Element value callback for date_text element.
- */
- function date_text_element_value_callback($element, $input = FALSE, &$form_state = array()) {
- $return = array('date' => '');
- $date = NULL;
-
-
-
-
- if ($input != FALSE && is_array($input)) {
- $return = $input;
- $date = date_text_input_date($element, $input);
- }
-
- elseif (!empty($element['#default_value'])) {
- $date = date_default_date($element);
- }
- if (date_is_date($date)) {
- $return['date'] = date_format_date($date, 'custom', $element['#date_format']);
- }
- return $return;
- }
-
- * Text date input form.
- *
- * Display all or part of a date in a single textfield.
- *
- * The exact parts displayed in the field are those in #date_granularity.
- * The display of each part comes from #date_format.
- */
- function date_text_element_process($element, &$form_state, $form) {
- if (date_hidden_element($element)) {
- return $element;
- }
-
- $element['#tree'] = TRUE;
- $element['#theme_wrappers'] = array('date_text');
- $element['date']['#value'] = isset($element['#value']['date']) ? $element['#value']['date'] : '';
- $element['date']['#type'] = 'textfield';
- $element['date']['#weight'] = !empty($element['date']['#weight']) ? $element['date']['#weight'] : $element['#weight'];
- $element['date']['#attributes'] = array('class' => isset($element['#attributes']['class']) ? $element['#attributes']['class'] += array('date-date') : array('date-date'));
- $element['date']['#description'] = ' ' . t('Format: @date', array('@date' => date_format_date(date_example_date(), 'custom', $element['#date_format'])));
- $element['date']['#ajax'] = !empty($element['#ajax']) ? $element['#ajax'] : FALSE;
- $element['date']['#title_display'] = $element['#date_label_position'] == 'above' ? 'before' : 'invisible';
-
-
- if (empty($element['#date_title_printed'])) {
- $element['date']['#title'] = $element['#title'];
- $element['date']['#title_display'] = 'before';
- $element['#date_title_printed'] = TRUE;
- }
-
-
-
- $element['#date_title'] = $element['#title'];
- $element['#title'] = NULL;
-
-
- $element['date']['#required'] = !empty($element['#required']);
-
-
-
- if (isset($element['#element_validate'])) {
- array_push($element['#element_validate'], 'date_text_validate');
- }
- else {
- $element['#element_validate'] = array('date_text_validate');
- }
- if (!empty($element['#force_value'])) {
- $element['date']['#value'] = $element['date']['#default_value'];
- }
-
- $context = array(
- 'form' => $form,
- );
- backdrop_alter('date_text_process', $element, $form_state, $context);
-
- return $element;
- }
-
- * Validation for text input.
- *
- * When used as a Views widget, the validation step always gets triggered,
- * even with no form submission. Before form submission $element['#value']
- * contains a string, after submission it contains an array.
- */
- function date_text_validate($element, &$form_state) {
- if (date_hidden_element($element)) {
- return;
- }
-
- if (is_string($element['#value'])) {
- return;
- }
- $input_exists = NULL;
- $input = backdrop_array_get_nested_value($form_state['values'], $element['#parents'], $input_exists);
-
-
- if (isset($input['date'])) {
- $input['date'] = trim($input['date']);
- }
-
- backdrop_alter('date_text_pre_validate', $element, $form_state, $input);
-
- $label = !empty($element['#date_title']) ? $element['#date_title'] : (!empty($element['#title']) ? $element['#title'] : '');
- $date = date_text_input_date($element, $input);
-
-
-
-
- $error_field = implode('][', $element['#parents']);
- if (empty($date) || !empty($date->errors)) {
- if (is_object($date) && !empty($date->errors)) {
- if (count($date->errors) === 1) {
- $error_list = ' ' . reset($date->errors);
- }
- else {
- $error_list = theme('item_list', array('items' => $date->errors));
- }
- $message = t('The value input for field %field is invalid:', array('%field' => $label)) . $error_list;
- form_set_error($error_field, $message);
- return;
- }
- if (!empty($element['#required'])) {
- $message = t('A valid date is required for %title.', array('%title' => $label));
- form_set_error($error_field, $message);
- return;
- }
-
- if (!empty($input['date'])) {
- form_error($element, t('%title is invalid.', array('%title' => $label)));
- return;
- }
- }
- $value = date_is_date($date) ? $date->format(DATE_FORMAT_DATETIME) : NULL;
- form_set_value($element, $value, $form_state);
- }
-
- * Helper function for creating a date object out of user input.
- */
- function date_text_input_date($element, $input) {
- if (empty($input) || !is_array($input) || !array_key_exists('date', $input) || empty($input['date'])) {
- return NULL;
- }
- $granularity = date_format_order($element['#date_format']);
-
- $date = new BackdropDateTime($input['date'], $element['#date_timezone'], $element['#date_format']);
-
- if (is_object($date)) {
- $date->limitGranularity($granularity);
- if ($date->validGranularity($granularity, $element['#date_flexible'])) {
- date_increment_round($date, $element['#date_increment']);
- }
- return $date;
- }
- return NULL;
- }
-
- * Element value callback for date_select element.
- */
- function date_select_element_value_callback($element, $input = FALSE, &$form_state = array()) {
- $return = array(
- 'year' => '',
- 'month' => '',
- 'day' => '',
- 'hour' => '',
- 'minute' => '',
- 'second' => '',
- );
- $date = NULL;
- if ($input !== FALSE) {
- $return = $input;
- $date = date_select_input_date($element, $input);
- }
- elseif (!empty($element['#default_value'])) {
- $date = date_default_date($element);
- }
- $granularity = date_format_order($element['#date_format']);
- $formats = array(
- 'year' => 'Y',
- 'month' => 'n',
- 'day' => 'j',
- 'hour' => 'H',
- 'minute' => 'i',
- 'second' => 's',
- );
- foreach ($granularity as $field) {
- if ($field != 'timezone') {
- $return[$field] = date_is_date($date) ? $date->format($formats[$field]) : '';
- }
- }
- return $return;
- }
-
- * Flexible date/time drop-down selector.
- *
- * Splits date into a collection of date and time sub-elements, one
- * for each date part. Each sub-element can be either a textfield or a
- * select, based on the value of ['#date_settings']['text_fields'].
- *
- * The exact parts displayed in the field are those in #date_granularity.
- * The display of each part comes from ['#date_settings']['format'].
- */
- function date_select_element_process($element, &$form_state, $form) {
- if (date_hidden_element($element)) {
- return $element;
- }
-
- $date = NULL;
- if (is_array($element['#default_value'])) {
- $date = date_select_input_date($element, $element['#default_value']);
- }
- elseif (!empty($element['#default_value'])) {
- $date = date_default_date($element);
- }
-
- $element['#tree'] = TRUE;
- $element['#theme_wrappers'] = array('date_select');
- $element['#attached']['css'][] = backdrop_get_path('module', 'date') . '/css/date.css';
- $element += (array) date_parts_element($element, $date, $element['#date_format']);
-
-
- $granularity = date_format_order($element['#date_format']);
- foreach (date_nongranularity($granularity) as $field) {
- if ($field != 'timezone') {
- $element[$field] = array(
- '#type' => 'value',
- '#value' => 0,
- );
- }
- }
- if (isset($element['#element_validate'])) {
- array_push($element['#element_validate'], 'date_select_validate');
- }
- else {
- $element['#element_validate'] = array('date_select_validate');
- }
-
- $context = array(
- 'form' => $form,
- );
- backdrop_alter('date_select_process', $element, $form_state, $context);
-
- return $element;
- }
-
- * Creates form elements for one or more date parts.
- *
- * Get the order of date elements from the provided format.
- * If the format order omits any date parts in the granularity, alter the
- * granularity array to match the format, then flip the $order array
- * to get the position for each element. Then iterate through the
- * elements and create a sub-form for each part.
- *
- * @param array $element
- * The date element.
- * @param object $date
- * The date object.
- * @param string $format
- * A date format string.
- *
- * @return array
- * The form array for the submitted date parts.
- */
- function date_parts_element($element, $date, $format) {
- $granularity = date_format_order($format);
- $sub_element = array('#granularity' => $granularity);
- $order = array_flip($granularity);
-
- $hours_format = strpos(strtolower($element['#date_format']), 'a') ? 'g' : 'G';
- $month_function = strpos($element['#date_format'], 'F') !== FALSE ? 'date_month_names' : 'date_month_names_abbr';
-
-
- $part_required = (bool) $element['#required'] && is_object($date);
- foreach ($granularity as $field) {
- $part_type = in_array($field, $element['#date_text_parts']) ? 'textfield' : 'select';
- $sub_element[$field] = array(
- '#weight' => $order[$field],
- '#required' => $part_required,
- '#attributes' => array('class' => isset($element['#attributes']['class']) ? $element['#attributes']['class'] += array('date-' . $field) : array('date-' . $field)),
- '#ajax' => !empty($element['#ajax']) ? $element['#ajax'] : FALSE,
- );
- switch ($field) {
- case 'year':
- $range = date_range_years($element['#date_year_range'], $date);
- $start_year = $range[0];
- $end_year = $range[1];
-
- $sub_element[$field]['#title'] = t('Year');
- $sub_element[$field]['#default_value'] = date_is_date($date) ? $date->format('Y') : '';
- if ($part_type == 'select') {
- $sub_element[$field]['#options'] = backdrop_map_assoc(date_years($start_year, $end_year, $part_required));
- }
- break;
-
- case 'month':
- $sub_element[$field]['#title'] = t('Month');
- $sub_element[$field]['#default_value'] = date_is_date($date) ? $date->format('n') : '';
- if ($part_type == 'select') {
- $sub_element[$field]['#options'] = $month_function($part_required);
- }
- break;
-
- case 'day':
- $sub_element[$field]['#title'] = t('Day');
- $sub_element[$field]['#default_value'] = date_is_date($date) ? $date->format('j') : '';
- if ($part_type == 'select') {
- $sub_element[$field]['#options'] = backdrop_map_assoc(date_days($part_required));
- }
- break;
-
- case 'hour':
- $sub_element[$field]['#title'] = t('Hour');
- $sub_element[$field]['#default_value'] = date_is_date($date) ? $date->format($hours_format) : '';
- if ($part_type == 'select') {
- $sub_element[$field]['#options'] = backdrop_map_assoc(date_hours($hours_format, $part_required));
- }
- if ($element['#date_label_position'] != 'above') {
- $sub_element[$field]['#prefix'] = '<span class="date-spacer date-parts-spacer">-</span>';
- }
- break;
-
- case 'minute':
- $sub_element[$field]['#title'] = t('Minute');
- $sub_element[$field]['#default_value'] = date_is_date($date) ? $date->format('i') : '';
- if ($part_type == 'select') {
- $sub_element[$field]['#options'] = backdrop_map_assoc(date_minutes('i', $part_required, $element['#date_increment']));
- }
- if ($element['#date_label_position'] != 'above') {
- $sub_element[$field]['#prefix'] = '<span class="date-spacer date-time-spacer">:</span>';
- }
- break;
-
- case 'second':
- $sub_element[$field]['#title'] = t('Second');
- $sub_element[$field]['#default_value'] = date_is_date($date) ? $date->format('s') : '';
- if ($part_type == 'select') {
- $sub_element[$field]['#options'] = backdrop_map_assoc(date_seconds('s', $part_required, $element['#date_increment']));
- }
- if ($element['#date_label_position'] != 'above') {
- $sub_element[$field]['#prefix'] = '<span class="date-spacer">:</span>';
- }
- break;
- }
-
-
- $label = $sub_element[$field]['#title'];
- if (in_array($field, $element['#date_text_parts'])) {
- $sub_element[$field]['#type'] = 'textfield';
- $sub_element[$field]['#theme'] = 'date_textfield_element';
- $sub_element[$field]['#size'] = 7;
- $sub_element[$field]['#title_display'] = in_array($element['#date_label_position'], array('within', 'none')) ? 'invisible' : 'before';
- if ($element['#date_label_position'] == 'within') {
- if (!empty($sub_element[$field]['#options']) && is_array($sub_element[$field]['#options'])) {
- $sub_element[$field]['#options'] = array('' => $label) + $sub_element[$field]['#options'];
- }
- }
- }
- else {
- $sub_element[$field]['#type'] = 'select';
- $sub_element[$field]['#theme'] = 'date_select_element';
- $sub_element[$field]['#title_display'] = in_array($element['#date_label_position'], array('within', 'none')) ? 'invisible' : 'before';
- if ($element['#date_label_position'] == 'within') {
- $sub_element[$field]['#options'] = array('' => $label) + $sub_element[$field]['#options'];
- }
- }
-
-
-
-
- if (!empty($element['#force_value']) && isset($sub_element[$field]['#options'])) {
- $options = $sub_element[$field]['#options'];
- $default = !empty($sub_element[$field]['#default_value']) ? $sub_element[$field]['#default_value'] : array_shift($options);
- $sub_element[$field]['#value'] = $default;
- }
- }
-
- if (($hours_format == 'g' || $hours_format == 'h') && date_has_time($granularity)) {
- $label = ' ';
- $sub_element['ampm'] = array(
- '#type' => 'select',
- '#theme' => 'date_select_element',
- '#title' => $label,
- '#title_display' => in_array($element['#date_label_position'], array('within', 'none')) ? 'invisible' : 'before',
- '#default_value' => is_object($date) ? (date_format($date, 'G') >= 12 ? 'pm' : 'am') : '',
- '#options' => backdrop_map_assoc(date_ampm($part_required)),
- '#required' => $part_required,
- '#weight' => 8,
- '#attributes' => array('class' => array('date-ampm')),
- );
- }
-
- return $sub_element;
- }
-
- * Validation function for date selector.
- *
- * When used as a Views widget, the validation step always gets triggered,
- * even with no form submission. Before form submission $element['#value']
- * contains a string, after submission it contains an array.
- */
- function date_select_validate($element, &$form_state) {
- if (date_hidden_element($element)) {
- return;
- }
-
- if (is_string($element['#value'])) {
- return;
- }
-
- $input_exists = NULL;
- $input = backdrop_array_get_nested_value($form_state['values'], $element['#parents'], $input_exists);
- backdrop_alter('date_select_pre_validate', $element, $form_state, $input);
-
- $label = !empty($element['#date_title']) ? $element['#date_title'] : (!empty($element['#title']) ? $element['#title'] : '');
- if (isset($input['ampm'])) {
- if ($input['ampm'] == 'pm' && $input['hour'] < 12) {
- $input['hour'] += 12;
- }
- elseif ($input['ampm'] == 'am' && $input['hour'] == 12) {
- $input['hour'] -= 12;
- }
- }
- unset($input['ampm']);
- $date = date_select_input_date($element, $input);
-
-
- $error_field = implode('][', $element['#parents']);
- $entered = array_values(array_filter($input));
- if (empty($date) || !empty($date->errors)) {
-
- if (is_object($date) && !empty($date->errors)) {
- if (count($date->errors) === 1) {
- $error_list = ' ' . reset($date->errors);
- }
- else {
- $error_list = theme('item_list', array('items' => $date->errors));
- }
- $message = t('The value input for field %field is invalid:', array('%field' => $label)) . $error_list;
- form_set_error($error_field, $message);
- return;
- }
-
- elseif (empty($entered) && $element['#required']) {
- $message = t('A valid date is required for %title.', array('%title' => $label));
- form_set_error($error_field, $message);
- return;
- }
-
- elseif (!empty($entered)) {
- $message = t('The value input for field %field is invalid.', array('%field' => $label));
- form_set_error($error_field, $message);
- return;
- }
- }
- $value = date_is_date($date) ? $date->format(DATE_FORMAT_DATETIME) : NULL;
- form_set_value($element, $value, $form_state);
- }
-
- * Helper function for creating a date object out of user input.
- */
- function date_select_input_date($element, $input) {
-
- if (!is_array($input)) {
- return NULL;
- }
- else {
- $entered = array_values(array_filter($input));
- if (empty($entered)) {
- return NULL;
- }
- }
- $granularity = date_format_order($element['#date_format']);
- if (isset($input['ampm'])) {
- if ($input['ampm'] == 'pm' && $input['hour'] < 12) {
- $input['hour'] += 12;
- }
- elseif ($input['ampm'] == 'am' && $input['hour'] == 12) {
- $input['hour'] -= 12;
- }
- }
- unset($input['ampm']);
-
-
- foreach (date_nongranularity($granularity) as $part) {
- unset($input[$part]);
- }
-
- $date = new BackdropDateTime($input, $element['#date_timezone']);
- if (is_object($date)) {
- $date->limitGranularity($granularity);
- if ($date->validGranularity($granularity, $element['#date_flexible'])) {
- date_increment_round($date, $element['#date_increment']);
- }
- return $date;
- }
- return NULL;
- }
-
- * Create local date object.
- *
- * Create a date object set to local time from the field and
- * widget settings and item values. Default values for new entities
- * are set by the default value callback, so don't need to be accounted for here.
- */
- function date_local_date($item, $timezone, $field, $instance, $part = 'value') {
-
- $value = (!empty($item[$part])) ? $item[$part]: '';
-
-
-
- if (empty($value)) {
- return NULL;
- }
-
- $date = new BackdropDateTime($value, date_get_timezone_db($field['settings']['tz_handling']));
- $date->limitGranularity($field['settings']['granularity']);
- if (empty($date)) {
- return NULL;
- }
- date_timezone_set($date, timezone_open($timezone));
-
- return $date;
- }
-
- * The callback for setting a default value for an empty date field.
- */
- function date_default_value($field, $instance, $langcode) {
- $item = array();
- $db_format = date_type_format($field['type']);
- $date = date_default_value_part($item, $field, $instance, $langcode, 'value');
- if (is_object($date) && empty($date->errors)) {
- $item[0]['value'] = date_format($date, $db_format);
- }
- else {
- $item[0]['value'] = '';
- }
- if (!empty($field['settings']['todate'])) {
- $date2 = date_default_value_part($item, $field, $instance, $langcode, 'value2');
- if (is_object($date2) && empty($date2->errors)) {
- $item[0]['value2'] = date_format($date2, $db_format);
- }
- else {
- $item[0]['value2'] = '';
- }
- }
-
-
-
- $item[0]['timezone'] = date_get_timezone($field['settings']['tz_handling']);
- $item[0]['timezone_db'] = date_get_timezone_db($field['settings']['tz_handling']);
- $item[0]['date_type'] = $field['type'];
- if (!isset($item[0]['value2'])) {
- $item[0]['value2'] = $item[0]['value'];
- }
- return $item;
- }
-
- * Helper function for the date default value callback to set either 'value' or 'value2' to its default value.
- */
- function date_default_value_part($item, $field, $instance, $langcode, $part = 'value') {
- $timezone = date_get_timezone($field['settings']['tz_handling']);
- $timezone_db = date_get_timezone_db($field['settings']['tz_handling']);
- $date = NULL;
- if ($part == 'value') {
- $default_value = $instance['settings']['default_value'];
- $default_value_code = $instance['settings']['default_value_code'];
- }
- else {
- $default_value = $instance['settings']['default_value2'];
- $default_value_code = $instance['settings']['default_value_code2'];
- }
- if (empty($default_value) || $default_value == 'blank') {
- return NULL;
- }
- elseif ($default_value == 'strtotime' && !empty($default_value_code)) {
- $date = new BackdropDateTime($default_value_code, date_default_timezone());
- }
- elseif ($part == 'value2' && $default_value == 'same') {
- if ($instance['settings']['default_value'] == 'blank' || empty($item[0]['value'])) {
- return NULL;
- }
- else {
-
- $string = is_numeric($item[0]['value']) ? '@' . $item[0]['value'] : $item[0]['value'];
-
- $date = new BackdropDateTime($string, $timezone_db, DATE_FORMAT_DATETIME);
- }
- }
-
-
- elseif ($field['settings']['tz_handling'] == 'none') {
- $date = date_now();
- }
- else {
- $date = date_now($timezone);
- }
-
- if (empty($date->errors)) {
- date_timezone_set($date, timezone_open($timezone_db));
- }
- $date->limitGranularity($field['settings']['granularity']);
- return $date;
- }
-
-
- * Element value callback for date_popup element.
- */
- function date_popup_element_value_callback($element, $input, &$form_state) {
- $granularity = date_format_order($element['#date_format']);
- $has_time = date_has_time($granularity);
- $date = NULL;
- $return = $has_time ? array('date' => '', 'time' => '') : array('date' => '');
-
-
-
- if ($input !== FALSE && is_array($input)) {
- $return = $input;
- $date = date_popup_input_date($element, $input);
- }
-
- elseif (!empty($element['#default_value'])) {
- $date = date_default_date($element);
- }
-
- if (date_is_date($date)) {
- $return['date'] = !$date->timeOnly ? date_format_date($date, 'custom', _date_popup_date_format($element)) : '';
- $return['time'] = $has_time ? date_format_date($date, 'custom', _date_popup_time_format($element)) : '';
- }
- elseif (!empty($input)) {
- $return = $input;
- }
- return $return;
-
- }
-
- * Javascript popup element processing.
- *
- * Add popup attributes to $element.
- */
- function date_popup_element_process($element, &$form_state, $form) {
- if (date_hidden_element($element)) {
- return $element;
- }
-
- module_load_include('inc', 'date', 'date.elements');
-
- $element['#tree'] = TRUE;
- $element['#theme_wrappers'] = array('date_popup');
- $element['#attached']['library'][] = array('date_popup', 'date_popup');
-
- if (!empty($element['#ajax'])) {
- $element['#ajax'] += array(
- 'trigger_as' => array(
- 'name' => $element['#name'],
- ),
- 'event' => 'change',
- );
- }
-
- $element['date'] = _date_popup_process_date_part($element);
- $element['time'] = _date_popup_process_time_part($element);
-
-
- if (empty($element['#date_title_printed'])) {
-
- if (!empty($element['date']) && !empty($element['time'])) {
- $element['date']['#title'] = $element['#title'];
- $element['date']['#title_display'] = $element['#title_display'];
- $element['date']['#required'] = $element['#required'];
- }
-
- elseif (!empty($element['date']) && empty($element['time'])) {
- $element['date']['#title'] = $element['#title'];
- $element['date']['#title_display'] = $element['#title_display'];
- $element['date']['#required'] = $element['#required'];
- }
-
- elseif (empty($element['date']) && !empty($element['time'])) {
- $element['time']['#title'] = $element['#title'];
- $element['time']['#title_display'] = $element['#title_display'];
- $element['time']['#required'] = $element['#required'];
- }
-
- }
-
-
-
- $element['#date_title'] = $element['#title'];
- $element['#title'] = NULL;
-
- if (isset($element['#element_validate'])) {
- array_push($element['#element_validate'], 'date_popup_validate');
- }
- else {
- $element['#element_validate'] = array('date_popup_validate');
- }
-
- $context = array(
- 'form' => $form,
- );
- backdrop_alter('date_popup_process', $element, $form_state, $context);
-
- return $element;
- }
-
- * Process the date portion of the element.
- */
- function _date_popup_process_date_part(&$element) {
- $date_granularity = _date_popup_date_granularity($element);
- if (empty($date_granularity)) {
- return array();
- }
-
-
-
- $mock = NULL;
- $callback_values = date_popup_element_value_callback($element, FALSE, $mock);
- if (!isset($element['#value']['date']) && isset($callback_values['date'])) {
- $element['#value']['date'] = $callback_values['date'];
- }
-
-
-
-
-
- $date = '';
- if (!empty($element['#value']['date'])) {
- $date = new BackdropDateTime($element['#value']['date'], $element['#date_timezone'], _date_popup_date_format($element));
- }
- $range = date_range_years($element['#date_year_range'], $date);
- $year_range = date_range_string($range);
-
-
-
- $settings = $element['#datepicker_options'] + array(
- 'changeMonth' => TRUE,
- 'changeYear' => TRUE,
- 'autoPopUp' => 'focus',
- 'closeAtTop' => FALSE,
- 'speed' => 'immediate',
- 'firstDay' => intval(config_get('system.date','first_day')),
- 'dateFormat' => _date_popup_format_to_popup(_date_popup_date_format($element)),
- 'yearRange' => $year_range,
- );
-
-
- if (!empty($settings['yearRange'])) {
- $parts = explode(':', $settings['yearRange']);
-
-
-
- $default_date = ($parts[0] > 0 || 0 > $parts[1]) ? $parts[0] : 0;
- $settings += array('defaultDate' => (string) $default_date . 'y');
- }
-
-
-
- $parents = array_merge($element['#parents'], array('date'));
- $sub_element = array(
- '#type' => 'textfield',
- '#title' => $element['#title'],
- '#title_display' => $element['#date_label_position'] == 'above' ? 'before' : 'invisible',
- '#default_value' => date_format_date($date, 'custom', _date_popup_date_format($element)),
- '#input' => FALSE,
- '#size' => !empty($element['#size']) ? $element['#size'] : 20,
- '#maxlength' => !empty($element['#maxlength']) ? $element['#maxlength'] : 30,
- '#attributes' => $element['#attributes'] + array('data-date-popup' => json_encode($settings)),
- '#parents' => $parents,
- '#name' => array_shift($parents) . '[' . implode('][', $parents) . ']',
- '#ajax' => !empty($element['#ajax']) ? $element['#ajax'] : FALSE,
- '#attached' => array('library' => array(
- array('system', 'ui.datepicker')
- )),
- );
- $sub_element['#value'] = $sub_element['#default_value'];
-
-
- if (!isset($sub_element['#attributes']['placeholder'])) {
- $sub_element['#attributes']['placeholder'] = t('e.g. @date', array(
- '@date' => date_format_date(
- date_example_date(),
- 'custom',
- _date_popup_date_format($element)
- ),
- )
- );
- }
-
- return $sub_element;
- }
-
- * Process the time portion of the element.
- */
- function _date_popup_process_time_part(&$element) {
- $granularity = date_format_order($element['#date_format']);
- $has_time = date_has_time($granularity);
- if (empty($has_time)) {
- return array();
- }
-
-
-
- $mock = NULL;
- $callback_values = date_popup_element_value_callback($element, FALSE, $mock);
- if (!isset($element['#value']['time']) && isset($callback_values['time'])) {
- $element['#value']['time'] = $callback_values['time'];
- }
-
-
-
- $parents = array_merge($element['#parents'], array('time'));
- $sub_element = array(
- '#type' => 'textfield',
- '#title' => isset($element['#title']) ? t('Time for @label', array('@label' => $element['#title'])) : t('Time'),
- '#title_display' => 'invisible',
- '#default_value' => $element['#value']['time'],
- '#size' => 15,
- '#maxlength' => 10,
- '#parents' => $parents,
- '#name' => array_shift($parents) . '[' . implode('][', $parents) . ']',
- '#ajax' => !empty($element['#ajax']) ? $element['#ajax'] : FALSE,
- '#attached' => array('library' => array(
- array('system', 'jquery.timeentry')
- )),
- '#attributes' => $element['#attributes'],
- );
-
- $sub_element['#value'] = $sub_element['#default_value'];
-
-
- if (!isset($sub_element['#attributes']['placeholder'])) {
- $example_date = date_now();
- date_increment_round($example_date, $element['#date_increment']);
- $sub_element['#attributes']['placeholder'] = t('e.g. @date', array(
- '@date' => date_format_date(
- $example_date,
- 'custom',
- _date_popup_time_format($element)
- )));
- }
-
-
- if ($element['#timepicker']) {
- $settings = array(
- 'show24Hours' => (strpos($element['#date_format'], 'H') !== FALSE || strpos($element['#date_format'], 'G') !== FALSE) ? TRUE : FALSE,
- 'showSeconds' => (in_array('second', $granularity) ? TRUE : FALSE),
- 'timeSteps' => array(1, intval($element['#date_increment']), (in_array('second', $granularity) ? $element['#date_increment'] : 0)),
- 'fromTo' => isset($fromto),
- 'spinnerImage' => '',
- );
-
- if (strpos($element['#date_format'], 'a') !== FALSE) {
- $settings['ampmNames'] = array(t('am'), t('pm'));
- }
- else {
- $settings['ampmNames'] = array(t('AM'), t('PM'));
- }
-
- if (strpos($element['#date_format'], ' A') !== FALSE || strpos($element['#date_format'], ' a') !== FALSE) {
- $settings['ampmPrefix'] = ' ';
- }
- $sub_element['#attributes'] += array('data-timeentry' => json_encode($settings));
- }
-
- return ($sub_element);
- }
-
- * Massage the input values back into a single date.
- *
- * When used as a Views widget, the validation step always gets triggered,
- * even with no form submission. Before form submission $element['#value']
- * contains a string, after submission it contains an array.
- */
- function date_popup_validate($element, &$form_state) {
- if (date_hidden_element($element)) {
- return;
- }
- if (is_string($element['#value'])) {
- return;
- }
-
- module_load_include('inc', 'date', 'date.elements');
- $input_exists = NULL;
- $input = backdrop_array_get_nested_value($form_state['values'], $element['#parents'], $input_exists);
-
-
- if (is_string($input)) {
- return;
- }
-
- backdrop_alter('date_popup_pre_validate', $element, $form_state, $input);
-
- $label = '';
- if (!empty($element['#date_title'])) {
- $label = t($element['#date_title']);
- }
- elseif (!empty($element['#title'])) {
- $label = t($element['#title']);
- }
- $date = date_popup_input_date($element, $input);
-
-
-
-
- $error_field = implode('][', $element['#parents']);
- if (empty($date) || !empty($date->errors)) {
- if (is_object($date) && !empty($date->errors)) {
- if (count($date->errors) === 1) {
- $error_list = ' ' . reset($date->errors);
- }
- else {
- $error_list = theme('item_list', array('items' => $date->errors));
- }
- $message = t('The value input for field %field is invalid:', array('%field' => $label)) . $error_list;
- form_set_error($error_field, $message);
- return;
- }
- if (!empty($input['date'])) {
- $message = t('The value input for field %field is invalid.', array('%field' => $label));
- form_set_error($error_field, $message);
- return;
- }
- if ($element['#required']) {
- $message = t('A valid date is required for %title.', array('%title' => $label));
- form_set_error($error_field, $message);
- return;
- }
- }
-
-
- $value = date_is_date($date) ? $date->format(DATE_FORMAT_DATETIME) : NULL;
- form_set_value($element, $value, $form_state);
- }
-
- * Helper function for extracting a date value out of user input.
- *
- * @param bool $auto_complete
- * Should we add a time value to complete the date if there is no time?
- * Useful anytime the time value is optional.
- */
- function date_popup_input_date($element, $input, $auto_complete = FALSE) {
- if (empty($input) || !is_array($input) || !array_key_exists('date', $input) || empty($input['date'])) {
- return NULL;
- }
- $granularity = date_format_order($element['#date_format']);
- $has_time = date_has_time($granularity);
- $flexible = !empty($element['#date_flexible']) ? $element['#date_flexible'] : 0;
-
- $format = _date_popup_date_format($element);
- $format .= $has_time ? ' ' . _date_popup_time_format($element) : '';
- $datetime = trim($input['date']);
- $datetime .= $has_time ? ' ' . trim($input['time']) : '';
- $date = new BackdropDateTime($datetime, $element['#date_timezone'], $format);
- if (is_object($date)) {
- $date->limitGranularity($granularity);
- if ($date->validGranularity($granularity, $flexible)) {
- date_increment_round($date, $element['#date_increment']);
- }
- return $date;
- }
- return NULL;
- }
-
- * Date popup date granularity.
- */
- function _date_popup_date_granularity($element) {
- $granularity = date_format_order($element['#date_format']);
- return array_intersect($granularity, array('month', 'day', 'year'));
- }
-
- * Date popup time granularity.
- */
- function _date_popup_time_granularity($element) {
- $granularity = date_format_order($element['#date_format']);
- return array_intersect($granularity, array('hour', 'minute', 'second'));
- }
-
- * Date popup date format.
- */
- function _date_popup_date_format($element) {
- return (date_limit_format($element['#date_format'], _date_popup_date_granularity($element)));
- }
-
- * Date popup time format.
- */
- function _date_popup_time_format($element) {
- return _date_popup_format_to_popup_time(date_limit_format($element['#date_format'], _date_popup_time_granularity($element)));
- }
-
- * Allowable time formats.
- */
- function _date_popup_time_formats($with_seconds = FALSE) {
- return array(
- 'H:i:s',
- 'h:i:sA',
- );
- }
-
- * Recreate a date format string so it has the values popup expects.
- *
- * @param string $format
- * A normal date format string, like Y-m-d
- *
- * @return string
- * A format string in popup format, like YMD-, for the
- * earlier 'calendar' version, or m/d/Y for the later 'datepicker'
- * version.
- */
- function _date_popup_format_to_popup($format) {
- if (empty($format)) {
- $format = 'Y-m-d';
- }
- $replace = _date_popup_datepicker_format_replacements();
- return strtr($format, $replace);
- }
-
- * Recreate a time format string so it has the values popup expects.
- *
- * @param string $format
- * A normal time format string, like h:i (a)
- *
- * @return string
- * A format string that the popup can accept like h:i a
- */
- function _date_popup_format_to_popup_time($format) {
- if (empty($format)) {
- $format = 'H:i';
- }
- $symbols = array(
- '/',
- '-',
- ' .',
- ',',
- 'F',
- 'M',
- 'l',
- 'z',
- 'w',
- 'W',
- 'd',
- 'j',
- 'm',
- 'n',
- 'y',
- 'Y',
- );
- $format = str_replace($symbols, '', $format);
- $format = strtr($format, array('G' => 'H', 'g' => 'h'));
- return $format;
- }
-
- * The format replacement patterns for the new datepicker.
- */
- function _date_popup_datepicker_format_replacements() {
- return array(
- 'd' => 'dd',
- 'j' => 'd',
- 'l' => 'DD',
- 'D' => 'D',
- 'm' => 'mm',
- 'n' => 'm',
- 'F' => 'MM',
- 'M' => 'M',
- 'Y' => 'yy',
- 'y' => 'y',
- 'S' => '',
- );
- }
-
- * Process an individual date element.
- */
- function date_combo_element_process($element, &$form_state, $form) {
- if (date_hidden_element($element)) {
-
-
- if (isset($element['#value']['value2']) && empty($element['#value']['value2'])) {
- $element['#value']['value2'] = $element['#value']['value'];
- }
- return $element;
- }
-
- $delta = $element['#delta'];
- $date_is_default = $element['#date_is_default'];
-
- $field = field_widget_field($element, $form_state);
- $instance = field_widget_instance($element, $form_state);
-
- $from_field = 'value';
- $to_field = 'value2';
-
-
-
-
-
-
-
-
-
-
- $process = date_process_values($field, $instance);
- if (empty($element['#default_value'])) {
- $element['#default_value'] = array();
- }
- foreach ($process as $processed) {
- if (!isset($element['#default_value'][$processed])) {
- $element['#default_value'][$processed] = '';
- }
- $date = date_local_date($element['#default_value'], $element['#date_timezone'], $field, $instance, $processed);
- $element['#default_value'][$processed] = is_object($date) ? date_format($date, DATE_FORMAT_DATETIME) : '';
- }
-
-
-
- if (!$date_is_default && $field['settings']['todate'] != 'required'
- && !empty($element['#default_value'][$to_field])
- && $element['#default_value'][$to_field] == $element['#default_value'][$from_field]) {
- unset($element['#default_value'][$to_field]);
- }
-
- $show_todate = !empty($form_state['values']['show_todate']) || !empty($element['#default_value'][$to_field]) || $field['settings']['todate'] == 'required';
- $element['show_todate'] = array(
- '#title' => t('Show end date'),
- '#type' => 'checkbox',
- '#default_value' => $show_todate,
- '#weight' => -20,
- '#attributes' => array('data-toggle-todate' => TRUE),
- '#access' => $field['settings']['todate'] == 'optional',
- );
-
- $element[$from_field] = array(
- '#field' => $field,
- '#instance' => $instance,
- '#weight' => $instance['widget']['weight'],
- '#required' => ($element['#required'] && $delta == 0) ? 1 : 0,
- '#default_value' => isset($element['#default_value'][$from_field]) ? $element['#default_value'][$from_field] : '',
- '#delta' => $delta,
- '#date_title' => $instance['label'],
- '#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'],
- );
-
- $description = !empty($element['#description']) ? t($element['#description']) : '';
- unset($element['#description']);
-
- switch ($instance['widget']['type']) {
- case 'date_select':
- $element[$from_field]['#type'] = 'date_select';
- $element[$from_field]['#theme_wrappers'] = array('date_select');
- $element[$from_field]['#ajax'] = !empty($element['#ajax']) ? $element['#ajax'] : FALSE;
- break;
-
- case 'date_popup':
- $element[$from_field]['#type'] = 'date_popup';
- $element[$from_field]['#theme_wrappers'] = array('date_popup');
- $element[$from_field]['#ajax'] = !empty($element['#ajax']) ? $element['#ajax'] : FALSE;
- break;
-
- default:
- $element[$from_field]['#type'] = 'date_text';
- $element[$from_field]['#theme_wrappers'] = array('date_text');
- $element[$from_field]['#ajax'] = !empty($element['#ajax']) ? $element['#ajax'] : FALSE;
- break;
- }
-
-
-
-
- if (!empty($field['settings']['todate'])) {
- $element[$to_field] = $element[$from_field];
- $element[$from_field]['#wrapper_attributes']['class'][] = 'start-date-wrapper';
- $element[$to_field]['#wrapper_attributes']['class'][] = 'end-date-wrapper';
- $element[$to_field]['#default_value'] = isset($element['#default_value'][$to_field]) ? $element['#default_value'][$to_field] : '';
- $element[$to_field]['#required'] = ($element[$from_field]['#required'] && $field['settings']['todate'] == 'required');
- $element[$to_field]['#weight'] += .2;
- $element[$to_field]['#prefix'] = '';
- $element[$to_field]['#date_title'] = $instance['label'];
- $element['#attached']['js'][] = backdrop_get_path('module', 'date') . '/js/date-range.js';
- }
- else {
- $element[$from_field]['#description'] = $description;
- }
-
-
- if ($field['cardinality'] != 1) {
- $element[$from_field]['#title'] = t('Date');
- $element[$from_field]['#date_title_printed'] = TRUE;
- if (!empty($field['settings']['todate'])) {
- $element[$from_field]['#title'] = t('Start date');
- $element[$to_field]['#title'] = t('End date');
- $element[$to_field]['#date_title_printed'] = TRUE;
- }
- }
-
- elseif (!empty($field['settings']['todate'])) {
- $element[$from_field]['#title'] = t('@field_name start date', array('@field_name' => $instance['label']));
- $element[$from_field]['#date_title_printed'] = $element['#date_title_printed'];
- $element[$to_field]['#title'] = t('@field_name end date', array('@field_name' => $instance['label']));
- $element[$to_field]['#date_title_printed'] = $element['#date_title_printed'];
- }
-
- else {
- $element[$from_field]['#title'] = check_plain($instance['label']);
- $element[$from_field]['#date_title_printed'] = $element['#date_title_printed'];
- }
-
- $context = array(
- 'field' => $field,
- 'instance' => $instance,
- 'form' => $form,
- );
- backdrop_alter('date_combo_process', $element, $form_state, $context);
-
- return $element;
- }
-
- * Empty a date element.
- */
- function date_element_empty($element, &$form_state) {
- $item = array();
- $item['value'] = NULL;
- $item['value2'] = NULL;
- $item['timezone'] = NULL;
- $item['offset'] = NULL;
- $item['offset2'] = NULL;
- form_set_value($element, $item, $form_state);
- return $item;
- }
-
- * Validate and update a combo element.
- *
- * Don't try this if there were errors before reaching this point.
- */
- function date_combo_validate($element, &$form_state) {
-
-
-
- if (date_hidden_element($element) || !empty($element['#disabled'])) {
- form_set_value($element, $element['#date_items'], $form_state);
- return;
- }
-
- $field_name = $element['#field_name'];
- $delta = $element['#delta'];
-
-
- if (!is_array($element['#field_parents'])) {
- $element['#field_parents'] = array();
- }
- $form_input = backdrop_array_get_nested_value($form_state['input'], $element['#field_parents']);
-
-
- if (empty($form_input[$field_name]) && !$element['#required']) {
- return;
- }
-
- $item = backdrop_array_get_nested_value($form_state['values'], $element['#parents']);
- $posted = backdrop_array_get_nested_value($form_state['input'], $element['#parents']);
-
- $field = field_widget_field($element, $form_state);
- $instance = field_widget_instance($element, $form_state);
-
- $context = array(
- 'field' => $field,
- 'instance' => $instance,
- 'item' => $item,
- );
-
- backdrop_alter('date_combo_pre_validate', $element, $form_state, $context);
-
- $from_field = 'value';
- $to_field = 'value2';
- $tz_field = 'timezone';
- $offset_field = 'offset';
- $offset_field2 = 'offset2';
-
- $errors = array();
-
-
-
- $empty = TRUE;
- if (!empty($item[$from_field])) {
- if (!is_array($item[$from_field])) {
- $empty = FALSE;
- }
- else {
- foreach ($item[$from_field] as $key => $value) {
- if (!empty($value)) {
- $empty = FALSE;
- break;
- }
- }
- }
- }
-
-
- if ($empty && !empty($item[$to_field])) {
- if (!is_array($item[$to_field])) {
- $errors[] = t("A start date is required if an end date is supplied.", array(
- '%field' => $instance['label'],
- ));
- $empty = FALSE;
- }
- else {
- foreach ($item[$to_field] as $key => $value) {
- if (!empty($value)) {
- $errors[] = t("A start date is required if an end date is supplied for field %field #@delta.", array(
- '@delta' => $field['cardinality'] ? intval($delta + 1) : '',
- '%field' => $instance['label'],
- ));
- $empty = FALSE;
- break;
- }
- }
- }
- }
-
-
-
- if ($field['settings']['todate'] == 'optional' && empty($item['show_todate'])) {
- $item[$to_field] = $item[$from_field];
- $posted[$to_field] = $posted[$from_field];
- }
-
- if ($empty) {
- date_element_empty($element, $form_state);
- if (!$element['#required']) {
- return;
- }
- }
- else {
- $timezone = !empty($item[$tz_field]) ? $item[$tz_field] : $element['#date_timezone'];
- $timezone_db = date_get_timezone_db($field['settings']['tz_handling']);
- $element[$from_field]['#date_timezone'] = $timezone;
- $from_date = date_input_date($field, $instance, $element[$from_field], $posted[$from_field]);
-
- if (!empty($field['settings']['todate'])) {
- $element[$to_field]['#date_timezone'] = $timezone;
- $to_date = date_input_date($field, $instance, $element[$to_field], $posted[$to_field]);
- }
- else {
- $to_date = $from_date;
- }
-
- if (!$instance['required'] && (!date_is_date($from_date) || !date_is_date($to_date))) {
- $errors[] = t('The dates are invalid.');
- }
- elseif (!empty($field['settings']['todate']) && $from_date > $to_date) {
- form_set_value($element[$to_field], $to_date, $form_state);
- $errors[] = t('The end date must be greater than the start date.');
- }
-
- if (empty($errors) && !empty($from_date)) {
-
-
- $item[$tz_field] = $timezone;
-
-
-
- $context['item'] = $item;
-
-
- $context['element'] = $element;
- backdrop_alter('date_combo_validate_date_start', $from_date, $form_state, $context);
- backdrop_alter('date_combo_validate_date_end', $to_date, $form_state, $context);
-
- $item[$offset_field] = date_offset_get($from_date);
-
- $test_from = date_format($from_date, 'r');
- $test_to = date_format($to_date, 'r');
-
- $item[$offset_field2] = date_offset_get($to_date);
- date_timezone_set($from_date, timezone_open($timezone_db));
- date_timezone_set($to_date, timezone_open($timezone_db));
- $item[$from_field] = date_format($from_date, date_type_format($field['type']));
- $item[$to_field] = date_format($to_date, date_type_format($field['type']));
-
-
-
-
-
-
- $granularity = date_format_order($element[$from_field]['#date_format']);
- if ($timezone != $timezone_db && date_has_time($granularity)) {
- date_timezone_set($from_date, timezone_open($timezone));
- date_timezone_set($to_date, timezone_open($timezone));
-
- if ($test_from != date_format($from_date, 'r')) {
- $errors[] = t('The start date is invalid.');
- }
- if ($test_to != date_format($to_date, 'r')) {
- $errors[] = t('The end date is invalid.');
- }
- }
- if (empty($errors)) {
- form_set_value($element, $item, $form_state);
- }
- }
- }
-
-
-
- if (!empty($errors)) {
- if (count($errors) === 1) {
- $error_list = ' ' . reset($errors);
- }
- else {
- $error_list = theme('item_list', array('items' => $errors));
- }
- if ($field['cardinality'] != 1) {
- form_error($element, t('There are errors in %field_name value #@delta:', array(
- '%field_name' => $instance['label'],
- '@delta' => $delta + 1,
- )) . $error_list);
- }
- else {
- form_error($element, t('There are errors in %field_name:', array(
- '%field_name' => $instance['label'],
- )) . $error_list);
- }
- }
- }
-
- * Determine the input format for this element.
- */
- function date_input_format($element, $field, $instance) {
- if (!empty($instance['widget']['settings']['input_format_custom'])) {
- return $instance['widget']['settings']['input_format_custom'];
- }
- elseif (!empty($instance['widget']['settings']['input_format']) && $instance['widget']['settings']['input_format'] != 'site-wide') {
- return $instance['widget']['settings']['input_format'];
- }
- $shortformat = system_date_format_load('short');
- return $shortformat['pattern'];
- }
-
-
- * Implements hook_date_select_pre_validate_alter().
- */
- function date_date_select_pre_validate_alter(&$element, &$form_state, &$input) {
- date_empty_end_date($element, $form_state, $input);
- }
-
- * Implements hook_date_text_pre_validate_alter().
- */
- function date_date_text_pre_validate_alter(&$element, &$form_state, &$input) {
- date_empty_end_date($element, $form_state, $input);
- }
-
- * Implements hook_date_popup_pre_validate_alter().
- */
- function date_date_popup_pre_validate_alter(&$element, &$form_state, &$input) {
- date_empty_end_date($element, $form_state, $input);
- }
-
- * Helper function to clear out end date when not being used.
- */
- function date_empty_end_date(&$element, &$form_state, &$input) {
-
-
-
- $parents = $element['#parents'];
- $parent = array_pop($parents);
- if ($parent == 'value2') {
- $parent_values = backdrop_array_get_nested_value($form_state['values'], $parents);
- if (isset($parent_values['show_todate']) && $parent_values['show_todate'] != 1) {
- $input = array();
- form_set_value($element, NULL, $form_state);
- }
- }
- }
-
- * Determines if the date element needs to be processed.
- *
- * Helper function to see if date element has been hidden by FAPI to see if it
- * needs to be processed or just pass the value through. This is needed since
- * normal date processing expands the date element into parts and then
- * reconstructs it, which is not needed or desirable if the field is hidden.
- *
- * @param array $element
- * The date element to check.
- *
- * @return bool
- * TRUE if the element is effectively hidden, FALSE otherwise.
- */
- function date_hidden_element($element) {
- if ((isset($element['#access']) && empty($element['#access']))
- || !empty($element['#programmed'])
- || in_array($element['#type'], array('hidden', 'value'))) {
- return TRUE;
- }
- return FALSE;
- }
-
- * Element validation callback for the HTML5 widget.
- *
- * This runs once over the whole value array.
- *
- * @param array $element
- * Form element structure.
- * @param array $form_state
- * The form state of this form submission.
- */
- function date_html5_element_validate(array $element, array &$form_state) {
- $field_name = $element['#field_name'];
-
- if (!empty(backdrop_array_get_nested_value($form_state['values'], $element['#parents']))) {
- $values = array();
- $trimmed_parents = array_slice($element['#parents'], 0, -1);
- $items = backdrop_array_get_nested_value($form_state['values'], $trimmed_parents);
- $field_type = $element['#field_type'];
- $field_label = $element['#field_label'];
-
- foreach ($items as $delta => $date_values) {
- if (is_string($date_values)) {
-
- continue;
- }
- array_pop($element['#parents']);
- array_push($element['#parents'], $delta);
- $item_parents = implode('][', $element['#parents']);
- $multi_value = (count($items) > 1);
-
- $date_only = (is_string($date_values['value']) && strlen($date_values['value']) == 10);
- if ($date_only) {
- $start = $date_values['value'];
- $date_values['value'] = array(
- 'date' => $start,
- );
- }
-
- if (empty($date_values['value']['date'])) {
- if (!empty($element['value']['#required']) && $delta < 1) {
- if ($multi_value) {
- form_set_error($item_parents . '][value', t('A start date for value #1 is required in %field.', array(
- '%field' => $field_label,
- )));
- }
- else {
- form_set_error($item_parents . '][value', t('A start date is required in %field.', array(
- '%field' => $field_label,
- )));
- }
- }
-
- continue;
- }
-
-
- $timezone = $element['value']['#date_timezone'];
- $timezone_db = $element['value']['#timezone_db'];
- if (!empty($date_values['timezone'])) {
-
- if (is_array($date_values['timezone'])) {
- $timezone = $date_values['timezone']['timezone'];
- }
- else {
- $timezone = $date_values['timezone'];
- }
- }
-
- $values[$delta]['timezone'] = $timezone;
-
- $string = implode(' ', array_values($date_values['value']));
-
-
- $date = new BackdropDateTime($string, $timezone);
-
-
- if (!empty($element['value']['#min'])) {
- $min_date = new BackdropDateTime($element['value']['#min'], $timezone);
- if ($date < $min_date) {
- if ($multi_value) {
- form_set_error($item_parents . '][value', t('The date of value #!delta in %field may not be before @date.', array(
- '!delta' => $delta + 1,
- '%field' => $field_label,
- '@date' => $element['value']['#min'],
- )));
- }
- else {
- form_set_error($item_parents . '][value', t('The date in %field may not be before @date.', array(
- '%field' => $field_label,
- '@date' => $element['value']['#min'],
- )));
- }
- }
- }
- if (!empty($element['value']['#max'])) {
- $max_date = new BackdropDateTime($element['value']['#max'], $timezone);
- if ($date > $max_date) {
- if ($multi_value) {
- form_set_error($item_parents . '][value', t('The date of value #!delta in %field may not be after @date.', array(
- '!delta' => $delta + 1,
- '%field' => $field_label,
- '@date' => $element['value']['#max'],
- )));
- }
- else {
- form_set_error($item_parents . '][value', t('The date in %field may not be after @date.', array(
- '%field' => $field_label,
- '@date' => $element['value']['#max'],
- )));
- }
- }
- }
-
- $values[$delta]['offset'] = $date->getOffset();
-
-
- $date->setTimezone(new DateTimeZone($timezone_db));
- $values[$delta]['value'] = _date_html5_format_value_db($date, $field_type);
-
- if (!empty($date_values['value2']) && $date_only) {
- $end = $date_values['value2'];
- $date_values['value2'] = array(
- 'date' => $end,
- );
- }
- if (!empty($date_values['value2']['date'])) {
- $string2 = implode(' ', array_values($date_values['value2']));
- $date2 = new BackdropDateTime($string2, $timezone);
-
- if (isset($min_date) && $date2 < $min_date) {
- if ($multi_value) {
- form_set_error($item_parents . '][value2', t('The end date of value #!delta in %field may not be before @date.', array(
- '!delta' => $delta + 1,
- '%field' => $field_label,
- '@date' => $element['value']['#min'],
- )));
- }
- else {
- form_set_error($item_parents . '][value2', t('The end date in %field may not be before @date.', array(
- '%field' => $field_label,
- '@date' => $element['value']['#min'],
- )));
- }
- }
- if (isset($max_date) && $date2 > $max_date) {
- if ($multi_value) {
- form_set_error($item_parents . '][value2', t('The end date of value #!delta in %field may not be after @date.', array(
- '!delta' => $delta + 1,
- '%field' => $field_label,
- '@date' => $element['value']['#max'],
- )));
- }
- else {
- form_set_error($item_parents . '][value2', t('The end date in %field may not be after @date.', array(
- '%field' => $field_label,
- '@date' => $element['value']['#max'],
- )));
- }
- }
- $values[$delta]['offset2'] = $date2->getOffset();
- $date2->setTimezone(new DateTimeZone($timezone_db));
- $values[$delta]['value2'] = _date_html5_format_value_db($date2, $field_type);
- if ($date2 <= $date) {
- if ($multi_value) {
- form_set_error($item_parents . '][value2', t('The end date of value #!delta in %field must be greater than the start date.', array(
- '!delta' => ($delta + 1),
- '%field' => $field_label,
- )));
- }
- else {
- form_set_error($item_parents . '][value2', t('The end date in %field must be greater than the start date.', array(
- '%field' => $field_label,
- )));
- }
- }
- }
- else {
- if (!empty($element['value2']['#required']) && $delta < 1) {
- if ($multi_value) {
- form_set_error($item_parents . '][value2', t('An end date for value #1 is required in %field.', array(
- '%field' => $field_label,
- )));
- }
- else {
- form_set_error($item_parents . '][value2', t('An end date is required in %field.', array(
- '%field' => $field_label,
- )));
- }
- }
-
- $values[$delta]['value2'] = NULL;
- }
- }
-
-
- backdrop_array_set_nested_value($form_state['values'], $trimmed_parents, $values);
- }
- }
-
- * Prepare values from database for the widget form.
- *
- * @param string $value_orig
- * Original value from database.
- * @param string $type
- * Form API type of the widget.
- * @param int $timestep
- * Step value for the form, 1 or 60.
- * @param string $timezone_db
- * Timezone of the database value.
- * @param string $timezone
- * Actual timezone for output.
- *
- * @return array
- */
- function _date_html5_get_form_value($value_orig, $type, $timestep, $timezone_db, $timezone) {
- $needs_conversion = ($timezone_db != $timezone);
- if (is_numeric($value_orig)) {
- $datetime = new DateTime('@' . $value_orig, new DateTimeZone('UTC'));
- $needs_conversion = TRUE;
- }
- else {
- $datetime = new DateTime($value_orig, new DateTimeZone($timezone_db));
- }
-
-
- if ($needs_conversion) {
- $datetime->setTimezone(new DateTimeZone($timezone));
- }
-
- $value = array(
- 'date' => $datetime->format('Y-m-d'),
- );
- if ($type == 'html_datetime') {
- $pattern = ($timestep > 1) ? 'H:i' : 'H:i:s';
- $value['time'] = $datetime->format($pattern);
- }
-
- return $value;
- }
-
- * Helper function to return default values as expected by the form item.
- *
- * @param array $field
- * Field structure.
- * @param array $instance
- * Field instance structure.
- * @param string $langcode
- * Language code.
- *
- * @return array
- */
- function _date_html5_get_default_value(array $field, array $instance, $langcode) {
- $default = array(
- 'start' => NULL,
- 'end' => NULL,
- );
- $granularity = $field['settings']['granularity'];
- $date_defaults = date_default_value($field, $instance, $langcode);
- $values = reset($date_defaults);
- $timezone_db = $values['timezone_db'];
- $timezone = $values['timezone'];
- $type = empty($granularity['hour']) ? 'html_date' : 'html_datetime';
- $timestep = empty($granularity['second']) ? 60 : 1;
-
- if (!empty($values['value'])) {
- $default['start'] = _date_html5_get_form_value($values['value'], $type, $timestep, $timezone_db, $timezone);
- }
- if (!empty($values['value2'])) {
- $default['end'] = _date_html5_get_form_value($values['value2'], $type, $timestep, $timezone_db, $timezone);
- }
-
- return $default;
- }
-
- * Helper function to return a formatted date string.
- *
- * @param BackdropDateTime $datetime
- * Datetime object.
- * @param string $field_type
- * Date field type.
- *
- * @return string
- */
- function _date_html5_format_value_db(BackdropDateTime $datetime, $field_type) {
- $date_string = '';
- switch ($field_type) {
- case 'datestamp':
- $date_string = $datetime->format('U');
- break;
-
- case 'datetime':
- $date_string = $datetime->format(DATE_FORMAT_DATETIME);
- break;
-
- case 'date':
- $date_string = $datetime->format(DATE_FORMAT_ISO);
- break;
- }
-
- return $date_string;
- }
-
- * Helper function to get widget settings for date limits.
- *
- * @param array $limit_settings
- * Widget settings for date limits.
- *
- * @return array
- */
- function _date_html5_get_date_limits(array $limit_settings) {
- $date_limits = array(
- 'min' => NULL,
- 'max' => NULL,
- );
- if ($limit_settings['mode'] == 'byyear') {
- $now = date_now();
- if ($limit_settings['years_back'] !== '') {
- $min_year = (int) $now->format('Y') + $limit_settings['years_back'];
- $date_limits['min'] = $min_year . '-01-01';
- }
- if ($limit_settings['years_forward'] !== '') {
- $max_year = (int) $now->format('Y') + $limit_settings['years_forward'];
- $date_limits['max'] = $max_year . '-12-31';
- }
- }
-
- return $date_limits;
- }
-
- * Helper function to construct form item attributes.
- *
- * Takes care of nested (html_datetime) and unnested (html_date) form items.
- *
- * @param array $date_limits
- * Array keyed by min/max.
- * @param array $granularity
- * Field's date granularity settings.
- *
- * @return array
- */
- function _date_html5_get_attributes(array $date_limits, array $granularity) {
- $attributes = array();
- $has_time = !empty($granularity['hour']);
-
- if (!empty($date_limits['min'])) {
- if ($has_time) {
- $attributes['date']['min'] = $date_limits['min'];
- }
- else {
- $attributes['min'] = $date_limits['min'];
- }
- }
-
- if (!empty($date_limits['max'])) {
- if ($has_time) {
- $attributes['date']['max'] = $date_limits['max'];
- }
- else {
- $attributes['max'] = $date_limits['max'];
- }
- }
-
- if ($has_time && empty($granularity['second'])) {
- $attributes['time']['step'] = 60;
- }
-
- return $attributes;
- }
-
- * Helper for the default widget form.
- *
- * @param array $field
- * The field structure.
- * @param array $instance
- * The field instance.
- * @param string $langcode
- * The language associated with $items.
- * @param array $items
- * Array of default values for this field.
- * @param int $delta
- * The order of this item in the array of subelements (0, 1, 2, etc).
- * @param array $base
- * A form element array containing basic properties for the widget.
- *
- * @return array
- * The form elements for a single widget for this field.
- */
- function _date_default_field_widget_form(array $field, array $instance, $langcode, array $items, $delta, array $base) {
- $element = $base;
-
-
-
-
-
-
-
-
-
-
-
-
-
- $is_default = FALSE;
- if (!isset($items[$delta]['value'])) {
- if (!empty($instance['widget']['is_new'])) {
-
- $items = date_default_value($field, $instance, $langcode);
- $is_default = TRUE;
- }
- else {
-
- $keys = date_process_values($field);
- $items[$delta] = array_fill_keys($keys, '');
- }
- }
-
- $timezone = date_get_timezone($field['settings']['tz_handling'], isset($items[$delta]['timezone']) ? $items[$delta]['timezone'] : date_default_timezone());
-
-
-
-
-
-
- if (is_array($timezone)) {
- $timezone = $timezone['timezone'];
- }
-
- $element += array(
- '#type' => 'date_combo',
- '#theme_wrappers' => array('date_combo'),
- '#weight' => $delta,
- '#default_value' => isset($items[$delta]) ? $items[$delta] : '',
- '#date_timezone' => $timezone,
- '#element_validate' => array('date_combo_validate'),
- '#date_is_default' => $is_default,
-
-
- '#date_items' => isset($items[$delta]) ? $items[$delta] : '',
- );
-
- if ($field['settings']['tz_handling'] == 'date') {
- $element['timezone'] = array(
- '#type' => 'date_timezone',
- '#theme_wrappers' => array('date_timezone'),
- '#delta' => $delta,
- '#default_value' => $timezone,
- '#weight' => $instance['widget']['weight'] + 1,
- '#date_label_position' => $instance['widget']['settings']['label_position'],
- );
- }
-
-
- if ($instance['widget']['settings']['no_fieldset']) {
- $element['#title'] = NULL;
- $element['#theme_wrappers'] = array();
- $element['#date_title_printed'] = FALSE;
- } else {
- $element['#title'] = $instance['label'];
- $element['#date_title_printed'] = TRUE;
- }
-
- return $element;
- }
-
- * Helper for the HTML5 widget form.
- *
- * @param array $field
- * The field structure.
- * @param array $instance
- * The field instance.
- * @param string $langcode
- * The language associated with $items.
- * @param array $items
- * Array of default values for this field.
- * @param int $delta
- * The order of this item in the array of subelements (0, 1, 2, etc).
- * @param array $element
- * A form element array containing basic properties for the widget.
- *
- * @return array
- * The form elements for a single widget for this field.
- */
- function _date_html5_field_widget_form(array $field, array $instance, $langcode, array $items, $delta, array $element) {
- $field_settings = $field['settings'];
- $widget_settings = $instance['widget']['settings'];
-
-
-
- $granularity = array_filter($field_settings['granularity']);
- $type = empty($granularity['hour']) ? 'html_date' : 'html_datetime';
- $timestep = empty($granularity['second']) ? 60 : 1;
-
- $date_limits = _date_html5_get_date_limits($widget_settings['limits']);
- $attributes = _date_html5_get_attributes($date_limits, $granularity);
-
- $timezone_db = date_get_timezone_db($field_settings['tz_handling']);
- $timezone = date_get_timezone($field_settings['tz_handling']);
- if (isset($items[$delta]['timezone'])) {
- $timezone = $items[$delta]['timezone'];
- }
-
- $value = '';
- $has_todate = !empty($field_settings['todate']);
- if ($delta == 0) {
- $default = _date_html5_get_default_value($field, $instance, $langcode);
- }
-
- if (isset($items[$delta]['value'])) {
- $value = _date_html5_get_form_value($items[$delta]['value'], $type, $timestep, $timezone_db, $timezone);
- } elseif ($delta == 0) {
- $value = $default['start'];
- }
- $element['value'] = array(
- '#type' => $type,
- '#title' => ($has_todate) ? t('Start date') : t('Date'),
- '#default_value' => $value,
- '#required' => ($instance['required'] && $delta == 0),
- '#attributes' => $attributes,
- '#date_timezone' => $timezone,
- '#timezone_db' => $timezone_db,
- '#min' => $date_limits['min'],
- '#max' => $date_limits['max'],
- );
-
- if ($has_todate) {
- $value2 = '';
- if (isset($items[$delta]['value2'])) {
- $value2 = _date_html5_get_form_value($items[$delta]['value2'], $type, $timestep, $timezone_db, $timezone);
- } elseif ($delta == 0) {
- $value2 = $default['end'];
- }
- $element['value2'] = array(
- '#type' => $type,
- '#title' => t('End date'),
- '#default_value' => $value2,
- '#required' => (($field_settings['todate'] != 'optional') && $delta == 0),
- '#attributes' => $attributes,
- '#date_timezone' => $timezone,
- );
- }
- if ($field_settings['tz_handling'] == 'date') {
- $element['timezone'] = array(
- '#type' => 'date_timezone',
- '#title' => t('Timezone'),
- '#date_label_position' => NULL,
- '#default_value' => isset($items[$delta]['timezone']) ? $items[$delta]['timezone'] : '',
- );
- }
-
-
- if ($delta == 0) {
- $element['#element_validate'] = array('date_html5_element_validate');
- $element['#attached']['css'][] = backdrop_get_path('module', 'date') . '/css/date-html5.css';
- }
-
-
- if ($widget_settings['no_fieldset']) {
- if ($field['cardinality'] == '1') {
- $element['value']['#title'] = check_plain($instance['label']);
- if (!empty($instance['description'])) {
- $element['value']['#description'] = field_filter_xss($instance['description']);
- }
- }
- } else {
- $element['#theme_wrappers'][] = 'fieldset';
- $element['#title'] = check_plain($instance['label']);
- $element['#description'] = field_filter_xss($instance['description']);
- }
- $element['#field_name'] = $field['field_name'];
- $element['#field_type'] = $field['type'];
- $element['#field_label'] = $instance['label'];
-
- return $element;
- }