View source
<?php
namespace Drupal\webform\Plugin\WebformElement;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\Datetime\Element\Datelist as DatelistElement;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\webform\WebformSubmissionConditionsValidator;
use Drupal\webform\WebformSubmissionInterface;
class DateList extends DateBase {
protected function defineDefaultProperties() {
return [
'date_min' => '',
'date_max' => '',
'date_part_order' => [
'year',
'month',
'day',
'hour',
'minute',
],
'date_text_parts' => [],
'date_year_range' => '1900:2050',
'date_year_range_reverse' => FALSE,
'date_increment' => 1,
'date_abbreviate' => TRUE,
] + parent::defineDefaultProperties();
}
public function prepare(array &$element, WebformSubmissionInterface $webform_submission = NULL) {
parent::prepare($element, $webform_submission);
if (isset($element['#date_abbreviate']) && $element['#date_abbreviate'] === FALSE) {
$element['#date_date_callbacks'][] = '_webform_datelist_date_date_callback';
}
$element['#label_attributes']['webform-remove-for-attribute'] = TRUE;
$element['#attached']['library'][] = 'webform/webform.element.datelist';
}
protected function getElementSelectorInputsOptions(array $element) {
$date_parts = isset($element['#date_part_order']) ? $element['#date_part_order'] : [
'year',
'month',
'day',
'hour',
'minute',
];
$t_args = [
'@title' => $this
->getAdminLabel($element),
];
$selectors = [
'day' => (string) $this
->t('@title days', $t_args),
'month' => (string) $this
->t('@title months', $t_args),
'year' => (string) $this
->t('@title years', $t_args),
'hour' => (string) $this
->t('@title hours', $t_args),
'minute' => (string) $this
->t('@title minutes', $t_args),
'second' => (string) $this
->t('@title seconds', $t_args),
'ampm' => (string) $this
->t('@title am/pm', $t_args),
];
$selectors = array_intersect_key($selectors, array_combine($date_parts, $date_parts));
foreach ($selectors as &$selector) {
$selector .= ' [' . $this
->t('Select') . ']';
}
return $selectors;
}
public function getElementSelectorInputValue($selector, $trigger, array $element, WebformSubmissionInterface $webform_submission) {
$value = $this
->getRawValue($element, $webform_submission);
if (empty($value)) {
return NULL;
}
$input_name = WebformSubmissionConditionsValidator::getSelectorInputName($selector);
$part = WebformSubmissionConditionsValidator::getInputNameAsArray($input_name, 1);
switch ($part) {
case 'day':
$format = 'j';
break;
case 'month':
$format = 'n';
break;
case 'year':
$format = 'Y';
break;
case 'hour':
$format = in_array('ampm', $element['#date_part_order']) ? 'g' : 'G';
break;
case 'minute':
$format = 'i';
break;
case 'second':
$format = 's';
break;
case 'ampm':
$format = 'a';
break;
default:
$format = '';
}
$date = DrupalDateTime::createFromTimestamp(strtotime($value));
return $date
->format($format);
}
public function form(array $form, FormStateInterface $form_state) {
$form = parent::form($form, $form_state);
$form['date']['#title'] = $this
->t('Date list settings');
$form['date']['date_part_order_label'] = [
'#type' => 'item',
'#title' => $this
->t('Date part and order'),
'#description' => $this
->t("Select the date parts and order that should be used in the element."),
'#access' => TRUE,
];
$form['date']['date_part_order'] = [
'#type' => 'webform_tableselect_sort',
'#header' => [
'part' => 'Date part',
],
'#options' => [
'day' => [
'part' => $this
->t('Days'),
],
'month' => [
'part' => $this
->t('Months'),
],
'year' => [
'part' => $this
->t('Years'),
],
'hour' => [
'part' => $this
->t('Hours'),
],
'minute' => [
'part' => $this
->t('Minutes'),
],
'second' => [
'part' => $this
->t('Seconds'),
],
'ampm' => [
'part' => $this
->t('AM/PM'),
],
],
];
$form['date']['date_text_parts'] = [
'#type' => 'checkboxes',
'#options_display' => 'side_by_side',
'#title' => $this
->t('Date text parts'),
'#description' => $this
->t("Select date parts that should be presented as text fields instead of drop-down selectors."),
'#options' => [
'day' => $this
->t('Days'),
'month' => $this
->t('Months'),
'year' => $this
->t('Years'),
'hour' => $this
->t('Hours'),
'minute' => $this
->t('Minutes'),
'second' => $this
->t('Seconds'),
],
];
$form['date']['date_year_range'] = [
'#type' => 'textfield',
'#title' => $this
->t('Date year range'),
'#description' => $this
->t("A description of the range of years to allow, like '1900:2050', '-3:+3' or '2000:+3', where the first value describes the earliest year and the second the latest year in the range.") . ' ' . $this
->t('Use min/max validation to define a more specific date range.'),
];
$form['date']['date_year_range_reverse'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Date year range reverse'),
'#description' => $this
->t('If checked date year range will be listed from max to min.'),
'#return_type' => TRUE,
];
$form['date']['date_increment'] = [
'#type' => 'number',
'#title' => $this
->t('Date increment'),
'#description' => $this
->t('The increment to use for minutes and seconds'),
'#min' => 1,
'#size' => 4,
'#weight' => 10,
];
$form['date']['date_abbreviate'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Abbreviate month'),
'#description' => $this
->t('If checked, month will be abbreviated to three letters.'),
'#return_value' => TRUE,
];
return $form;
}
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
parent::validateConfigurationForm($form, $form_state);
$values = $form_state
->getValues();
$values['date_part_order'] = array_values($values['date_part_order']);
$values['date_text_parts'] = array_values(array_filter($values['date_text_parts']));
$form_state
->setValues($values);
}
protected function setConfigurationFormDefaultValue(array &$form, array &$element_properties, array &$property_element, $property_name) {
if (in_array($property_name, [
'date_text_parts',
'date_part_order',
])) {
$element_properties[$property_name] = array_combine($element_properties[$property_name], $element_properties[$property_name]);
}
parent::setConfigurationFormDefaultValue($form, $element_properties, $property_element, $property_name);
}
public static function afterBuild(array $element, FormStateInterface $form_state) {
$element = parent::afterBuild($element, $form_state);
if (!empty($element['#date_year_range_reverse']) && isset($element['year']) && isset($element['year']['#options'])) {
$options = $element['year']['#options'];
$element['year']['#options'] = [
'' => $options[''],
] + array_reverse($options, TRUE);
}
foreach (Element::children($element) as $child_key) {
$element[$child_key]['#error_no_message'] = TRUE;
}
foreach ($element['#element_validate'] as &$validate_callback) {
if (is_array($validate_callback) && $validate_callback[0] === 'Drupal\\Core\\Datetime\\Element\\Datelist') {
$validate_callback[0] = DateList::class;
}
}
return $element;
}
public static function validateDatelist(&$element, FormStateInterface $form_state, &$complete_form) {
$has_required_error = !empty($element['#required']) && !empty($element['#required_error']);
if (!$has_required_error) {
DatelistElement::validateDatelist($element, $form_state, $complete_form);
return;
}
$temp_form_state = clone $form_state;
DatelistElement::validateDatelist($element, $temp_form_state, $complete_form);
$original_errors = $form_state
->getErrors();
$errors = $temp_form_state
->getErrors();
foreach ($errors as $name => $message) {
if (empty($original_errors[$name])) {
if ($message instanceof TranslatableMarkup && $message
->getUntranslatedString() === "The %field date is required.") {
$message = $element['#required_error'];
}
$form_state
->setErrorByName($name, $message);
}
}
}
}