diff --git a/datetime_extras.info.yml b/datetime_extras.info.yml new file mode 100644 index 0000000..4c20faf --- /dev/null +++ b/datetime_extras.info.yml @@ -0,0 +1,9 @@ +name: 'Datetime Extras' +type: module +description: 'Provides the extra widgets and formatters for datetime module.' +package: Custom +version: 8.0-dev +core: 8.x +dependencies: + - datetime + - datetime_range diff --git a/datetime_extras.module b/datetime_extras.module new file mode 100644 index 0000000..af825ed --- /dev/null +++ b/datetime_extras.module @@ -0,0 +1,28 @@ +' . t('About') . ''; + $output .= '

' . t('The Datetime Range module provides a Date field that stores start dates and times, as well as end dates and times. See the Field module help and the Field UI module help pages for general information on fields and how to create and manage them. For more information, see the online documentation for the Datetime Range module.', array(':field' => \Drupal::url('help.page', array('name' => 'field')), ':field_ui' => (\Drupal::moduleHandler()->moduleExists('field_ui')) ? \Drupal::url('help.page', array('name' => 'field_ui')) : '#', ':datetime_do' => 'https://www.drupal.org/documentation/modules/datetime_range')) . '

'; + $output .= '

' . t('Uses') . '

'; + $output .= '
'; + $output .= '
' . t('Managing and displaying date fields') . '
'; + $output .= '
' . t('The settings and the display of the Date field can be configured separately. See the Field UI help for more information on how to manage fields and their display.', array(':field_ui' => (\Drupal::moduleHandler()->moduleExists('field_ui')) ? \Drupal::url('help.page', array('name' => 'field_ui')) : '#')) . '
'; + $output .= '
' . t('Displaying dates') . '
'; + $output .= '
' . t('Dates can be displayed using the Plain or the Default formatter. The Plain formatter displays the date in the ISO 8601 format. If you choose the Default formatter, you can choose a format from a predefined list that can be managed on the Date and time formats page.', array(':date_format_list' => \Drupal::url('entity.date_format.collection'))) . '
'; + $output .= '
'; + return $output; + } +} diff --git a/src/DateTimeExtraTrait.php b/src/DateTimeExtraTrait.php new file mode 100644 index 0000000..4303d2b --- /dev/null +++ b/src/DateTimeExtraTrait.php @@ -0,0 +1,50 @@ +getFieldSetting('datetime_type') == DateTimeItem::DATETIME_TYPE_DATE) { + // A date without time will pick up the current time, use the default. + datetime_date_default_time($date); + } + + // Create the ISO date in Universal Time. + $iso_date = $date->format("Y-m-d\TH:i:s") . 'Z'; + + $this->setTimeZone($date); + + $build = [ + '#theme' => 'time', + '#text' => $this->formatDate($date, $format), + '#html' => FALSE, + '#attributes' => [ + 'datetime' => $iso_date, + ], + '#cache' => [ + 'contexts' => [ + 'timezone', + ], + ], + ]; + + return $build; + } + +} diff --git a/src/Plugin/Field/FieldFormatter/DateRangeNiceFormatter.php b/src/Plugin/Field/FieldFormatter/DateRangeNiceFormatter.php new file mode 100644 index 0000000..e55f93f --- /dev/null +++ b/src/Plugin/Field/FieldFormatter/DateRangeNiceFormatter.php @@ -0,0 +1,176 @@ + elements, with + * configurable date formats (from the list of configured formats) and a + * separator. + * + * @FieldFormatter( + * id = "daterange_nice", + * label = @Translation("Nice"), + * field_types = { + * "daterange" + * } + * ) + */ +class DateRangeNiceFormatter extends DateTimeDefaultFormatter { + + use DateTimeExtraTrait; + + /** + * {@inheritdoc} + */ + public static function defaultSettings() { + return [ + 'separator' => '-', + ] + parent::defaultSettings(); + } + + /** + * {@inheritdoc} + */ + public function viewElements(FieldItemListInterface $items, $langcode) { + $elements = []; + $separator = $this->getSetting('separator'); + + foreach ($items as $delta => $item) { + if (!empty($item->start_date) && !empty($item->end_date)) { + /** @var \Drupal\Core\Datetime\DrupalDateTime $start_date */ + $start_date = $item->start_date; + /** @var \Drupal\Core\Datetime\DrupalDateTime $end_date */ + $end_date = $item->end_date; + $format_types = $this->niceFormats(); + + if ($start_date->format('U') !== $end_date->format('U')) { + $format_start = + $format_end = $format_types[$this->getSetting('format_type')]['format']; + if ($start_date->format('Y-m-d') == $end_date->format('Y-m-d')) { + $format_start = $format_types[$this->getSetting('format_type')]['format_time_start']; + $format_end = $format_types[$this->getSetting('format_type')]['format_time_end']; + } + else if ($start_date->format('Y-m') == $end_date->format('Y-m')) { + $format_start = $format_types[$this->getSetting('format_type')]['format_day_start']; + $format_end = $format_types[$this->getSetting('format_type')]['format_day_end']; + } + else if ($start_date->format('Y') == $end_date->format('Y')) { + $format_start = $format_types[$this->getSetting('format_type')]['format_month_start']; + $format_end = $format_types[$this->getSetting('format_type')]['format_month_end']; + } + else { + $format_start = $format_types[$this->getSetting('format_type')]['format_year_start']; + $format_end = $format_types[$this->getSetting('format_type')]['format_year_end']; + } + $elements[$delta] = [ + 'start_date' => $this->buildDateWithIsoAttribute($start_date, $format_start), + 'separator' => ['#plain_text' => ' ' . $separator . ' '], + 'end_date' => $this->buildDateWithIsoAttribute($end_date, $format_end), + ]; + } + else { + if (!empty($item->_attributes)) { + $elements[$delta]['#attributes'] += $item->_attributes; + // Unset field item attributes since they have been included in the + // formatter output and should not be rendered in the field template. + unset($item->_attributes); + } + } + } + } + + return $elements; + } + + /** + * {@inheritdoc} + */ + protected function formatDate($date, $format = NULL) { + $format_type = 'custom'; + $format = $format ? $format : 'm/d/Y'; + $timezone = $this->getSetting('timezone_override') ?: $date->getTimezone()->getName(); + return $this->dateFormatter->format($date->getTimestamp(), $format_type, $format, $timezone != '' ? $timezone : NULL); + } + + /** + * {@inheritdoc} + */ + public function settingsForm(array $form, FormStateInterface $form_state) { + $form = parent::settingsForm($form, $form_state); + + $time = new DrupalDateTime(); + $format_types = $this->niceFormats(); + $options = []; + foreach ($format_types as $type => $type_info) { + $format = $this->dateFormatter->format($time->format('U'), 'custom', $type_info['format']); + $options[$type] = $type_info['label'] . ' (' . $format . ')'; + } + + $form['format_type'] = array( + '#type' => 'select', + '#title' => t('Date format'), + '#description' => t("Choose a format for displaying the date. Be sure to set a format appropriate for the field, i.e. omitting time for a field that only has a date."), + '#options' => $options, + '#default_value' => $this->getSetting('format_type'), + ); + + $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'), + ]; + return $form; + } + + /** + * {@inheritdoc} + */ + public function settingsSummary() { + $summary = parent::settingsSummary(); + + if ($separator = $this->getSetting('separator')) { + $summary[] = $this->t('Separator: %separator', ['%separator' => $separator]); + } + + return $summary; + } + + public function niceFormats() { + $formats = []; + $formats['nice_long'] = [ + 'label' => t('Nice long'), + 'format' => 'F d, Y - h:i A', + 'format_time_start' => 'F d, Y - h:i A', + 'format_time_end' => 'h:i A', + 'format_day_start' => 'F d', + 'format_day_end' => 'd, Y', + 'format_month_start' => 'F d', + 'format_month_end' => 'F d, Y', + 'format_year_start' => 'F d, Y', + 'format_year_end' => 'F d, Y', + ]; + $formats['nice_short'] = [ + 'label' => t('Nice short'), + 'format' => 'm/d/Y - h:i a', + 'format_time_start' => 'm/d/Y - h:i a', + 'format_time_end' => 'h:i a', + 'format_day_start' => 'm/d', + 'format_day_end' => 'd/Y', + 'format_month_start' => 'm/d', + 'format_month_end' => 'm/d/Y', + 'format_year_start' => 'm/d/Y', + 'format_year_end' => 'm/d/Y', + ]; + return $formats; + } + +} diff --git a/src/Plugin/Field/FieldWidget/DateRangeNiceWidget.php b/src/Plugin/Field/FieldWidget/DateRangeNiceWidget.php new file mode 100644 index 0000000..da74eb3 --- /dev/null +++ b/src/Plugin/Field/FieldWidget/DateRangeNiceWidget.php @@ -0,0 +1,101 @@ +dateStorage = $date_storage; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $plugin_id, + $plugin_definition, + $configuration['field_definition'], + $configuration['settings'], + $configuration['third_party_settings'], + $container->get('entity_type.manager')->getStorage('date_format') + ); + } + + /** + * {@inheritdoc} + */ + public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) { + $element = parent::formElement($items, $delta, $element, $form, $form_state); + + // Identify the type of date and time elements to use. + switch ($this->getFieldSetting('datetime_type')) { + case DateRangeItem::DATETIME_TYPE_DATE: + case DateRangeItem::DATETIME_TYPE_ALLDAY: + $date_type = 'date'; + $time_type = 'none'; + $date_format = $this->dateStorage->load('html_date')->getPattern(); + $time_format = ''; + break; + + default: + $date_type = 'date'; + $time_type = 'time'; + $date_format = $this->dateStorage->load('html_date')->getPattern(); + $time_format = $this->dateStorage->load('html_time')->getPattern(); + break; + } + + $element['value'] += [ + '#date_date_format' => $date_format, + '#date_date_element' => $date_type, + '#date_date_callbacks' => [], + '#date_time_format' => $time_format, + '#date_time_element' => $time_type, + '#date_time_callbacks' => [], + ]; + + $element['end_value'] += [ + '#date_date_format' => $date_format, + '#date_date_element' => $date_type, + '#date_date_callbacks' => [], + '#date_time_format' => $time_format, + '#date_time_element' => $time_type, + '#date_time_callbacks' => [], + ]; + + return $element; + } + +}