Skip to content
Snippets Groups Projects
Commit 75535b92 authored by Tamás Pintér's avatar Tamás Pintér
Browse files

Issue #3144069: Support date range field

parent 786e8c83
No related branches found
No related tags found
1 merge request!4Issue #3144069: Support date range field
field.widget.settings.datetime_flatpickr:
datetime_flatpickr_config:
type: mapping
label: 'Datetime flat pickr display format settings'
mapping:
dateFormat:
type: string
......@@ -65,3 +64,11 @@ field.widget.settings.datetime_flatpickr:
weekNumbers:
type: boolean
label: 'Week numbers'
field.widget.settings.datetime_flatpickr:
label: 'Datetime flatpickr display format settings'
type: datetime_flatpickr_config
field.widget.settings.datetime_range_flatpickr:
label: 'Datetime range flatpickr display format settings'
type: datetime_flatpickr_config
......@@ -23,7 +23,7 @@ use Drupal\Component\Utility\Html;
*/
class DateTimeFlatPickrWidget extends DateTimeWidgetBase {
private const AVAILABLE_LANGUAGE = [
protected const AVAILABLE_LANGUAGE = [
'ar',
'at',
'az',
......@@ -539,7 +539,9 @@ class DateTimeFlatPickrWidget extends DateTimeWidgetBase {
array_walk_recursive($options, $filter, $groups);
$options['dateFormat'] = str_replace('s', 'S', $options['dateFormat']);
$options['altFormat'] = str_replace('s', 'S', $options['altFormat']);
if (isset($options['altFormat'])) {
$options['altFormat'] = str_replace('s', 'S', $options['altFormat']);
}
}
$lang_code = $items->getLangcode();
......@@ -575,13 +577,18 @@ class DateTimeFlatPickrWidget extends DateTimeWidgetBase {
}
}
if ('' !== $settings['minTime']['hour'] && '' !== $settings['minTime']['min']) {
$new['minTime'] = $settings['minTime']['hour'] . ':' . $settings['minTime']['min'];
if (isset($settings['minTime'])) {
if ('' !== $settings['minTime']['hour'] && '' !== $settings['minTime']['min']) {
$new['minTime'] = $settings['minTime']['hour'] . ':' . $settings['minTime']['min'];
}
}
if (!empty($settings['maxTime']['hour']) && !empty($settings['maxTime']['min'])) {
$new['maxTime'] = $settings['maxTime']['hour'] . ':' . $settings['maxTime']['min'];
if (isset($settings['maxTime'])) {
if (!empty($settings['maxTime']['hour']) && !empty($settings['maxTime']['min'])) {
$new['maxTime'] = $settings['maxTime']['hour'] . ':' . $settings['maxTime']['min'];
}
}
$format_array = [
'altFormat',
'dateFormat',
......@@ -597,7 +604,7 @@ class DateTimeFlatPickrWidget extends DateTimeWidgetBase {
}
}
if (!$settings['altInput']) {
if (isset($settings['altInput']) && !$settings['altInput']) {
unset($new['altInput'], $new['altFormat']);
}
......
<?php
namespace Drupal\datetime_flatpickr\Plugin\Field\FieldWidget;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\datetime\Plugin\Field\FieldType\DateTimeItem;
use Drupal\datetime\Plugin\Field\FieldType\DateTimeItemInterface;
use Drupal\datetime_range\Plugin\Field\FieldType\DateRangeItem;
/**
* Plugin implementation of the 'datetime_flatpickr' widget.
*
* @FieldWidget(
* id = "datetime_range_flatpickr",
* label = @Translation("Flatpickr datetime range picker"),
* field_types = {
* "daterange"
* }
* )
*/
class DateTimeRangeFlatPickrWidget extends DateTimeFlatPickrWidget {
/**
* {@inheritdoc}
*/
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
$element['value'] = $element + [
'#type' => 'textfield',
'#default_value' => NULL,
'#required' => $element['#required'],
'#date_timezone' => date_default_timezone_get(),
];
if ($this->getFieldSetting('datetime_type') == DateTimeItem::DATETIME_TYPE_DATE) {
// A date-only field should have no timezone conversion performed, so
// use the same timezone as for storage.
$element['value']['#date_timezone'] = DateTimeItemInterface::STORAGE_TIMEZONE;
}
if ($items[$delta]->start_date) {
/** @var \Drupal\Core\Datetime\DrupalDateTime $start_date */
$start_date = $items[$delta]->start_date;
$start_date->setTimezone(new \DateTimeZone($element['value']['#date_timezone']));
$date_start = $this->createDefaultValue($start_date, $element['value']['#date_timezone']);
$element['value']['#default_value'] = $date_start;
$default_date[] = $date_start;
}
else {
$default_date[] = '';
}
if ($items[$delta]->end_date) {
/** @var \Drupal\Core\Datetime\DrupalDateTime $end_date */
$end_date = $items[$delta]->end_date;
$end_date->setTimezone(new \DateTimeZone($element['value']['#date_timezone']));
$date_end = $this->createDefaultValue($end_date, $element['value']['#date_timezone']);
$element['value']['#default_value'] .= ' - ' . $date_end;
$default_date[] = $date_end;
}
$entity_type = $items->getEntity()->getEntityTypeId();
$name = $entity_type . '-' . $items->getName();
$settings = self::processFieldSettings($this->getSettings(), $items);
if (isset($default_date)) {
$settings['defaultDate'] = $default_date;
}
$element['value']['#attributes']['flatpickr-name'] = $name;
$element['value']['#attached']['library'][] = 'datetime_flatpickr/flatpickr-init';
$element['value']['#attached']['drupalSettings']['datetimeFlatPickr'][$name] = [
'settings' => $settings,
];
$lang_code = $items->getLangcode();
if (in_array($lang_code, static::AVAILABLE_LANGUAGE)) {
$form['value']['#attached']['library'][] = 'datetime_flatpickr/flatpickr_' . mb_strtolower($lang_code);
}
return $element;
}
/**
* {@inheritdoc}
*/
public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {
// The widget form element type has transformed the value to a
// DrupalDateTime object at this point. We need to convert it back to the
// storage timezone and format.
$datetime_type = $this->getFieldSetting('datetime_type');
if ($datetime_type === DateTimeItem::DATETIME_TYPE_DATE) {
$storage_format = DateTimeItemInterface::DATE_STORAGE_FORMAT;
}
else {
$storage_format = DateTimeItemInterface::DATETIME_STORAGE_FORMAT;
}
$storage_timezone = new \DateTimezone(DateTimeItemInterface::STORAGE_TIMEZONE);
$user_timezone = new \DateTimeZone(date_default_timezone_get());
$settings = $this->getSettings();
foreach ($values as &$item) {
if (!empty($item['value'])) {
$start_date = $end_date = [];
$split_date = explode(' ', $item['value']);
while (count($split_date) > 1) {
$start_date[] = array_shift($split_date);
array_unshift($end_date, array_pop($split_date));
}
$start_date = implode(' ', $start_date);
$end_date = implode(' ', $end_date);
try {
$date_start = DrupalDateTime::createFromFormat($settings['dateFormat'], $start_date);
}
catch (\Exception $exception) {
// Fallback time conversation.
$timestamp = strtotime($start_date);
$date_start = DrupalDateTime::createFromTimestamp($timestamp);
}
// Adjust the date for storage.
$item['value'] = $date_start->setTimezone($storage_timezone)->format($storage_format);
try {
$date_end = DrupalDateTime::createFromFormat($settings['dateFormat'], $end_date);
}
catch (\Exception $exception) {
// Fallback time conversation.
$timestamp = strtotime($end_date);
$date_end = DrupalDateTime::createFromTimestamp($timestamp);
}
// Adjust the date for storage.
$item['end_value'] = $date_end->setTimezone($storage_timezone)->format($storage_format);
}
if (!empty($item['value']) && $item['value'] instanceof DrupalDateTime) {
/** @var \Drupal\Core\Datetime\DrupalDateTime $date_start */
$date_start = $item['value'];
if ($datetime_type === DateRangeItem::DATETIME_TYPE_ALLDAY) {
// All day fields start at midnight on the starting date, but are
// stored like datetime fields, so we need to adjust the time.
// This function is called twice, so to prevent a double conversion
// we need to explicitly set the timezone.
$date_start->setTimeZone($user_timezone)->setTime(0, 0, 0);
}
// Adjust the date for storage.
$item['value'] = $date_start->setTimezone($storage_timezone)->format($storage_format);
}
if (!empty($item['end_value']) && $item['end_value'] instanceof DrupalDateTime) {
/** @var \Drupal\Core\Datetime\DrupalDateTime $date_end */
$date_end = $item['end_value'];
if ($datetime_type === DateRangeItem::DATETIME_TYPE_ALLDAY) {
// All day fields start at midnight on the starting date, but are
// stored like datetime fields, so we need to adjust the time.
// This function is called twice, so to prevent a double conversion
// we need to explicitly set the timezone.
$date_end->setTimeZone($user_timezone)->setTime(23, 59, 59);
}
// Adjust the date for storage.
$item['end_value'] = $date_end->setTimezone($storage_timezone)->format($storage_format);
}
}
return $values;
}
/**
* {@inheritdoc}
*/
public static function fieldSettingsFinalNullCleanType(array &$settings) {
$new = parent::fieldSettingsFinalNullCleanType($settings);
$new['mode'] = 'range';
return $new;
}
}
<?php
namespace Drupal\Tests\datetime_flatpickr\Functional;
use Drupal\Tests\datetime\Functional\DateTestBase;
/**
* Datetime flatpickr form test.
*
* @group datetime_flatpickr
*/
class DateTimeRangeFlatPickrWidgetTest extends DateTestBase {
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* The default display settings to use for the formatters.
*
* @var array
*/
protected $defaultSettings = ['timezone_override' => ''];
/**
* Modules to enable.
*
* @var array
*/
protected static $modules = [
'node',
'entity_test',
'datetime_range',
'field_ui',
'datetime_flatpickr',
];
/**
* {@inheritdoc}
*/
protected function getTestFieldType() {
return 'daterange';
}
/**
* Tests Date Time Flat Pickr functionality.
*/
public function testDateTimeFlatPickrWidget() {
$field_name = $this->fieldStorage->getName();
$field_label = $this->field->label();
// Ensure field is set to a date only field.
$this->fieldStorage->setSetting('datetime_type', 'date');
$this->fieldStorage->save();
/** @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface $display_repository */
$display_repository = \Drupal::service('entity_display.repository');
// Change the widget to a datelist widget.
$display_repository->getFormDisplay($this->field->getTargetEntityTypeId(), $this->field->getTargetBundle())
->setComponent($field_name, [
'type' => 'datetime_range_flatpickr',
'settings' => [
'date_order' => 'YMD',
'dateFormat' => 'Y-m-d H:i',
],
])
->save();
\Drupal::service('entity_field.manager')->clearCachedFieldDefinitions();
// Display creation form.
$this->drupalGet('entity_test/add');
$this->assertSession()->elementTextContains('xpath', '//div[@id="edit-' . $field_name . '-wrapper"]/*/label', $field_label);
$this->assertSession()->elementExists('xpath', '//input[@flatpickr-name="entity_test-' . $field_name . '"]');
$this->assertSession()->elementExists('xpath', '//input[@id="edit-' . $field_name . '-0-value"]');
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment