diff --git a/core/modules/datetime_range/config/schema/datetime_range.schema.yml b/core/modules/datetime_range/config/schema/datetime_range.schema.yml index f0f9325..df4c1ab 100644 --- a/core/modules/datetime_range/config/schema/datetime_range.schema.yml +++ b/core/modules/datetime_range/config/schema/datetime_range.schema.yml @@ -31,6 +31,9 @@ field.formatter.settings.daterange_default: type: field.formatter.settings.datetime_default label: 'Date range default display format settings' mapping: + fromto: + type: string + label: 'Display' separator: type: label label: 'Separator' @@ -40,6 +43,9 @@ field.formatter.settings.daterange_plain: type: field.formatter.settings.datetime_plain label: 'Date range plain display format settings' mapping: + fromto: + type: string + label: 'Display' separator: type: label label: 'Separator' @@ -49,6 +55,9 @@ field.formatter.settings.daterange_custom: type: field.formatter.settings.datetime_custom label: 'Date range custom display format settings' mapping: + fromto: + type: string + label: 'Display' separator: type: label label: 'Separator' diff --git a/core/modules/datetime_range/src/DateTimeRangeTrait.php b/core/modules/datetime_range/src/DateTimeRangeTrait.php index 3f05b82..0d45c70 100644 --- a/core/modules/datetime_range/src/DateTimeRangeTrait.php +++ b/core/modules/datetime_range/src/DateTimeRangeTrait.php @@ -3,6 +3,7 @@ namespace Drupal\datetime_range; use Drupal\Core\Field\FieldItemListInterface; +use Drupal\Core\Form\FormStateInterface; /** * Provides friendly methods for datetime range. @@ -12,6 +13,16 @@ /** * {@inheritdoc} */ + public static function defaultSettings() { + return [ + 'fromto' => 'both', + 'separator' => '-', + ]; + } + + /** + * {@inheritdoc} + */ public function viewElements(FieldItemListInterface $items, $langcode) { $elements = []; $separator = $this->getSetting('separator'); @@ -24,15 +35,19 @@ public function viewElements(FieldItemListInterface $items, $langcode) { $end_date = $item->end_date; if ($start_date->getTimestamp() !== $end_date->getTimestamp()) { - $elements[$delta] = [ - 'start_date' => $this->buildDateWithIsoAttribute($start_date), - 'separator' => ['#plain_text' => ' ' . $separator . ' '], - 'end_date' => $this->buildDateWithIsoAttribute($end_date), - ]; + $elements[$delta] = []; + if ($this->startDateIsDisplayed()) { + $elements[$delta]['start_date'] = $this->buildDateWithIsoAttribute($start_date); + } + if ($this->startDateIsDisplayed() && $this->endDateIsDisplayed()) { + $elements[$delta]['separator'] = ['#plain_text' => ' ' . $separator . ' ']; + } + if ($this->endDateIsDisplayed()) { + $elements[$delta]['end_date'] = $this->buildDateWithIsoAttribute($end_date); + } } else { $elements[$delta] = $this->buildDateWithIsoAttribute($start_date); - if (!empty($item->_attributes)) { $elements[$delta]['#attributes'] += $item->_attributes; // Unset field item attributes since they have been included in the @@ -46,4 +61,94 @@ public function viewElements(FieldItemListInterface $items, $langcode) { return $elements; } + /** + * {@inheritdoc} + */ + public function settingsForm(array $form, FormStateInterface $form_state) { + $form['fromto'] = [ + '#type' => 'select', + '#title' => $this->t('Display'), + '#options' => $this->getFromToOptions(), + '#default_value' => $this->getSetting('fromto'), + ]; + + $form['separator'] = [ + '#type' => 'textfield', + '#title' => $this->t('Date separator'), + '#description' => $this->t('The string to separate the start and end dates'), + '#default_value' => $this->getSetting('separator'), + '#states' => [ + 'visible' => [ + ':input[name="options[settings][fromto]"]' => ['value' => 'both'], + ], + ], + ]; + + return $form; + } + + /** + * {@inheritdoc} + */ + public function settingsSummary() { + if ($fromto = $this->getSetting('fromto')) { + $fromto_options = $this->getFromToOptions(); + if (isset($fromto_options[$fromto])) { + $summary[] = $fromto_options[$fromto]; + } + } + + if ($separator = $this->getSetting('separator') && $this->getSetting('fromto') == 'both') { + $summary[] = $this->t('Separator: %separator', ['%separator' => $separator]); + } + + return $summary; + } + + /** + * Returns a list of possible values for the 'fromto' setting. + * + * @return array + * A list of 'fromto' options. + */ + public function getFromToOptions() { + return [ + 'both' => $this->t('Display both Start and End dates'), + 'start_date' => $this->t('Display Start date only'), + 'end_date' => $this->t('Display End date only'), + ]; + } + + /** + * Returns whether or not the start date should be displayed. + * + * @return bool + * True if the start date should be displayed. False otherwise. + */ + public function startDateIsDisplayed() { + switch ($this->getSetting('fromto')) { + case 'both': + case 'start_date': + return TRUE; + } + + return FALSE; + } + + /** + * Returns whether or not the end date should be displayed. + * + * @return bool + * True if the end date should be displayed. False otherwise. + */ + public function endDateIsDisplayed() { + switch ($this->getSetting('fromto')) { + case 'both': + case 'end_date': + return TRUE; + } + + return FALSE; + } + } diff --git a/core/modules/datetime_range/src/Plugin/Field/FieldFormatter/DateRangeCustomFormatter.php b/core/modules/datetime_range/src/Plugin/Field/FieldFormatter/DateRangeCustomFormatter.php index 78aa8aa..c83de02 100644 --- a/core/modules/datetime_range/src/Plugin/Field/FieldFormatter/DateRangeCustomFormatter.php +++ b/core/modules/datetime_range/src/Plugin/Field/FieldFormatter/DateRangeCustomFormatter.php @@ -23,15 +23,17 @@ */ class DateRangeCustomFormatter extends DateTimeCustomFormatter { - use DateTimeRangeTrait; + use DateTimeRangeTrait { + DateTimeRangeTrait::defaultSettings as traitDefaultSettings; + DateTimeRangeTrait::settingsForm as traitSettingsForm; + DateTimeRangeTrait::settingsSummary as traitSettingsSummary; + } /** * {@inheritdoc} */ public static function defaultSettings() { - return [ - 'separator' => '-', - ] + parent::defaultSettings(); + return static::traitDefaultSettings() + parent::defaultSettings(); } /** @@ -52,11 +54,16 @@ public function viewElements(FieldItemListInterface $items, $langcode) { $end_date = $item->end_date; if ($start_date->getTimestamp() !== $end_date->getTimestamp()) { - $elements[$delta] = [ - 'start_date' => $this->buildDate($start_date), - 'separator' => ['#plain_text' => ' ' . $separator . ' '], - 'end_date' => $this->buildDate($end_date), - ]; + $elements[$delta] = []; + if ($this->startDateIsDisplayed()) { + $elements[$delta]['start_date'] = $this->buildDate($start_date); + } + if ($this->startDateIsDisplayed() && $this->endDateIsDisplayed()) { + $elements[$delta]['separator'] = ['#plain_text' => ' ' . $separator . ' ']; + } + if ($this->endDateIsDisplayed()) { + $elements[$delta]['end_date'] = $this->buildDate($end_date); + } } else { $elements[$delta] = $this->buildDate($start_date); @@ -72,14 +79,7 @@ public function viewElements(FieldItemListInterface $items, $langcode) { */ public function settingsForm(array $form, FormStateInterface $form_state) { $form = parent::settingsForm($form, $form_state); - - $form['separator'] = [ - '#type' => 'textfield', - '#title' => $this->t('Date separator'), - '#description' => $this->t('The string to separate the start and end dates'), - '#default_value' => $this->getSetting('separator'), - ]; - + $form = $this->traitSettingsForm($form, $form_state); return $form; } @@ -87,13 +87,7 @@ public function settingsForm(array $form, FormStateInterface $form_state) { * {@inheritdoc} */ public function settingsSummary() { - $summary = parent::settingsSummary(); - - if ($separator = $this->getSetting('separator')) { - $summary[] = $this->t('Separator: %separator', ['%separator' => $separator]); - } - - return $summary; + return array_merge(parent::settingsSummary(), $this->traitSettingsSummary()); } } diff --git a/core/modules/datetime_range/src/Plugin/Field/FieldFormatter/DateRangeDefaultFormatter.php b/core/modules/datetime_range/src/Plugin/Field/FieldFormatter/DateRangeDefaultFormatter.php index b93851b..6f24ce4 100644 --- a/core/modules/datetime_range/src/Plugin/Field/FieldFormatter/DateRangeDefaultFormatter.php +++ b/core/modules/datetime_range/src/Plugin/Field/FieldFormatter/DateRangeDefaultFormatter.php @@ -23,15 +23,17 @@ */ class DateRangeDefaultFormatter extends DateTimeDefaultFormatter { - use DateTimeRangeTrait; + use DateTimeRangeTrait { + DateTimeRangeTrait::defaultSettings as traitDefaultSettings; + DateTimeRangeTrait::settingsForm as traitSettingsForm; + DateTimeRangeTrait::settingsSummary as traitSettingsSummary; + } /** * {@inheritdoc} */ public static function defaultSettings() { - return [ - 'separator' => '-', - ] + parent::defaultSettings(); + return static::traitDefaultSettings() + parent::defaultSettings(); } /** @@ -39,13 +41,7 @@ public static function defaultSettings() { */ public function settingsForm(array $form, FormStateInterface $form_state) { $form = parent::settingsForm($form, $form_state); - - $form['separator'] = [ - '#type' => 'textfield', - '#title' => $this->t('Date separator'), - '#description' => $this->t('The string to separate the start and end dates'), - '#default_value' => $this->getSetting('separator'), - ]; + $form = $this->traitSettingsForm($form, $form_state); return $form; } @@ -54,13 +50,7 @@ public function settingsForm(array $form, FormStateInterface $form_state) { * {@inheritdoc} */ public function settingsSummary() { - $summary = parent::settingsSummary(); - - if ($separator = $this->getSetting('separator')) { - $summary[] = $this->t('Separator: %separator', ['%separator' => $separator]); - } - - return $summary; + return array_merge(parent::settingsSummary(), $this->traitSettingsSummary()); } } diff --git a/core/modules/datetime_range/src/Plugin/Field/FieldFormatter/DateRangePlainFormatter.php b/core/modules/datetime_range/src/Plugin/Field/FieldFormatter/DateRangePlainFormatter.php index 0f74fba..896caf1 100644 --- a/core/modules/datetime_range/src/Plugin/Field/FieldFormatter/DateRangePlainFormatter.php +++ b/core/modules/datetime_range/src/Plugin/Field/FieldFormatter/DateRangePlainFormatter.php @@ -23,15 +23,17 @@ */ class DateRangePlainFormatter extends DateTimePlainFormatter { - use DateTimeRangeTrait; + use DateTimeRangeTrait { + DateTimeRangeTrait::defaultSettings as traitDefaultSettings; + DateTimeRangeTrait::settingsForm as traitSettingsForm; + DateTimeRangeTrait::settingsSummary as traitSettingsSummary; + } /** * {@inheritdoc} */ public static function defaultSettings() { - return [ - 'separator' => '-', - ] + parent::defaultSettings(); + return static::traitDefaultSettings() + parent::defaultSettings(); } /** @@ -49,11 +51,16 @@ public function viewElements(FieldItemListInterface $items, $langcode) { $end_date = $item->end_date; if ($start_date->getTimestamp() !== $end_date->getTimestamp()) { - $elements[$delta] = [ - 'start_date' => $this->buildDate($start_date), - 'separator' => ['#plain_text' => ' ' . $separator . ' '], - 'end_date' => $this->buildDate($end_date), - ]; + $elements[$delta] = []; + if ($this->startDateIsDisplayed()) { + $elements[$delta]['start_date'] = $this->buildDate($start_date); + } + if ($this->startDateIsDisplayed() && $this->endDateIsDisplayed()) { + $elements[$delta]['separator'] = ['#plain_text' => ' ' . $separator . ' ']; + } + if ($this->endDateIsDisplayed()) { + $elements[$delta]['end_date'] = $this->buildDate($end_date); + } } else { $elements[$delta] = $this->buildDate($start_date); @@ -76,14 +83,7 @@ public function viewElements(FieldItemListInterface $items, $langcode) { */ public function settingsForm(array $form, FormStateInterface $form_state) { $form = parent::settingsForm($form, $form_state); - - $form['separator'] = [ - '#type' => 'textfield', - '#title' => $this->t('Date separator'), - '#description' => $this->t('The string to separate the start and end dates'), - '#default_value' => $this->getSetting('separator'), - ]; - + $form = $this->traitSettingsForm($form, $form_state); return $form; } @@ -91,13 +91,7 @@ public function settingsForm(array $form, FormStateInterface $form_state) { * {@inheritdoc} */ public function settingsSummary() { - $summary = parent::settingsSummary(); - - if ($separator = $this->getSetting('separator')) { - $summary[] = $this->t('Separator: %separator', ['%separator' => $separator]); - } - - return $summary; + return array_merge(parent::settingsSummary(), $this->traitSettingsSummary()); } } diff --git a/core/modules/datetime_range/tests/src/Functional/DateRangeFieldTest.php b/core/modules/datetime_range/tests/src/Functional/DateRangeFieldTest.php index 9cecd60..50b9e6b 100644 --- a/core/modules/datetime_range/tests/src/Functional/DateRangeFieldTest.php +++ b/core/modules/datetime_range/tests/src/Functional/DateRangeFieldTest.php @@ -32,7 +32,7 @@ class DateRangeFieldTest extends DateTestBase { * * @var array */ - protected $defaultSettings = ['timezone_override' => '', 'separator' => '-']; + protected $defaultSettings = ['timezone_override' => '', 'separator' => '-', 'fromto' => 'both']; /** * {@inheritdoc} @@ -1378,4 +1378,146 @@ public function testDateStorageSettings() { $this->assertText('There is data for this field in the database. The field settings can no longer be changed.'); } + /** + * Tests displaying dates with the 'fromto' setting. + * + * @dataProvider fromtoSettingDataProvider + */ + public function testFromtoSetting(array $expected, $datetime_type, $field_formatter_type, array $display_settings = []) { + $field_name = $this->fieldStorage->getName(); + + // Create a test content type. + $this->drupalCreateContentType(['type' => 'date_content']); + + // Ensure the field to a datetime field. + $this->fieldStorage->setSetting('datetime_type', $datetime_type); + $this->fieldStorage->save(); + + // Build up dates in the UTC timezone. + $value = '2012-12-31 00:00:00'; + $start_date = new DrupalDateTime($value, 'UTC'); + $end_value = '2013-06-06 00:00:00'; + $end_date = new DrupalDateTime($end_value, 'UTC'); + + // Update the timezone to the system default. + $start_date->setTimezone(timezone_open(drupal_get_user_timezone())); + $end_date->setTimezone(timezone_open(drupal_get_user_timezone())); + + // Submit a valid date and ensure it is accepted. + $date_format = DateFormat::load('html_date')->getPattern(); + + $edit = [ + "{$field_name}[0][value][date]" => $start_date->format($date_format), + "{$field_name}[0][end_value][date]" => $end_date->format($date_format), + ]; + + // Supply time as well when field is a datetime field. + if ($datetime_type == DateRangeItem::DATETIME_TYPE_DATETIME) { + $time_format = DateFormat::load('html_time')->getPattern(); + $edit["{$field_name}[0][value][time]"] = $start_date->format($time_format); + $edit["{$field_name}[0][end_value][time]"] = $end_date->format($time_format); + } + + $this->drupalPostForm('entity_test/add', $edit, t('Save')); + preg_match('|entity_test/manage/(\d+)|', $this->getUrl(), $match); + $id = $match[1]; + $this->assertText(t('entity_test @id has been created.', ['@id' => $id])); + + // Now set display options. + $this->displayOptions = [ + 'type' => $field_formatter_type, + 'label' => 'hidden', + 'settings' => $display_settings + [ + 'format_type' => 'short', + 'separator' => 'THESEPARATOR', + ] + $this->defaultSettings, + ]; + + entity_get_display($this->field->getTargetEntityTypeId(), $this->field->getTargetBundle(), 'full') + ->setComponent($field_name, $this->displayOptions) + ->save(); + + $output = $this->renderTestEntity($id); + foreach ($expected as $content => $is_expected) { + if ($is_expected) { + $this->assertContains($content, $output); + } + else { + $this->assertNotContains($content, $output); + } + } + } + + /** + * The data provider for testing the 'fromto' setting. + * + * @return array + * An array of different date settings to test the behavior of the 'fromto' setting. + */ + public function fromtoSettingDataProvider() { + $field_formatters = [ + 'daterange_default' => [ + 'start_date' => '12/31/2012', + 'separator' => ' THESEPARATOR ', + 'end_date' => '06/06/2013', + ], + 'daterange_plain' => [ + 'start_date' => '2012-12-31', + 'separator' => ' THESEPARATOR ', + 'end_date' => '2013-06-06', + ], + 'daterange_custom' => [ + 'start_date' => '2012-12-31', + 'separator' => ' THESEPARATOR ', + 'end_date' => '2013-06-06', + ], + ]; + $datetime_types = [ + DateRangeItem::DATETIME_TYPE_DATE, + DateRangeItem::DATETIME_TYPE_DATETIME, + ]; + + $return = []; + foreach ($datetime_types as $datetime_type) { + foreach ($field_formatters as $field_formatter_type => $dates) { + // Both start and end date. + $return[$datetime_type . '-' . $field_formatter_type . '-both'] = [ + 'expected' => [ + $dates['start_date'] => TRUE, + $dates['separator'] => TRUE, + $dates['end_date'] => TRUE, + ], + 'datetime_type' => $datetime_type, + 'field_formatter_type' => $field_formatter_type, + ]; + + // Only start date. + $return[$datetime_type . '-' . $field_formatter_type . '-start_date'] = [ + 'expected' => [ + $dates['start_date'] => TRUE, + $dates['separator'] => FALSE, + $dates['end_date'] => FALSE, + ], + 'datetime_type' => $datetime_type, + 'field_formatter_type' => $field_formatter_type, + ['fromto' => 'start_date'], + ]; + + // Only end date. + $return[$datetime_type . '-' . $field_formatter_type . '-end_date'] = [ + 'expected' => [ + $dates['start_date'] => FALSE, + $dates['separator'] => FALSE, + $dates['end_date'] => TRUE, + ], + 'datetime_type' => $datetime_type, + 'field_formatter_type' => $field_formatter_type, + ['fromto' => 'end_date'], + ]; + } + } + + return $return; + } + }