Skip to content
Snippets Groups Projects
Commit bf9a52d0 authored by Martin Anderson-Clutz's avatar Martin Anderson-Clutz
Browse files

Resolve merge conflict in smart_date.js, merge with latest commits in 3.3.x branch

parents d97598bc 84a1622a
No related branches found
No related tags found
No related merge requests found
Showing
with 622 additions and 30 deletions
......@@ -16,5 +16,12 @@
},
"suggest": {
"drupal/multiple_fields_remove_button": "Provides a button for editors to remove unwanted rows."
},
"extra": {
"drush": {
"services": {
"drush.services.yml": "^9"
}
}
}
}
......@@ -60,9 +60,46 @@ field.formatter.settings.smartdate_default:
label: 'Format Type'
translation context: 'Smart date display'
add_classes:
type: integer
type: boolean
label: 'Add Classes'
translation context: 'Add classed spans around the time and date values.'
translation context: 'Smart date display'
time_wrapper:
type: boolean
label: 'Add time wrapper'
translation context: 'Smart date display'
field.formatter.settings.smartdate_duration:
type: field.formatter.settings.smartdate_duration
label: 'Smart date duration display format settings'
mapping:
timezone_override:
type: string
label: 'Time zone override'
translation context: 'Smart date display'
format:
type: string
label: 'Format'
translation context: 'Smart date display'
force_chronological:
type: boolean
label: 'Force chronological'
translation context: 'Smart date display'
format_type:
type: string
label: 'Format Type'
translation context: 'Smart date display'
add_classes:
type: boolean
label: 'Add Classes'
translation context: 'Smart date display'
time_wrapper:
type: boolean
label: 'Add time wrapper'
translation context: 'Smart date display'
duration_separator:
type: string
label: 'Duration Separator'
translation context: 'Smart date display'
field.formatter.settings.smartdate_plain:
type: field.formatter.settings.datetime_plain
......@@ -103,6 +140,9 @@ field.widget.settings.smartdate_default:
type: mapping
label: 'Smart date default display format settings'
mapping:
modal:
type: boolean
label: 'Use modal for managing instances'
default_duration:
type: integer
label: 'Default duration'
......@@ -112,11 +152,17 @@ field.widget.settings.smartdate_default:
show_extra:
type: boolean
label: 'Show extra'
hide_date:
type: boolean
label: 'Hide end date unless different'
field.widget.settings.smartdate_timezone:
type: mapping
label: 'Smart date timezone display format settings'
mapping:
modal:
type: boolean
label: 'Use modal for managing instances'
default_tz:
type: string
label: 'Default timezone'
......@@ -125,7 +171,7 @@ field.widget.settings.smartdate_timezone:
label: 'Custom timezone'
allowed_timezones:
type: sequence
label: 'Allowed timeones'
label: 'Allowed timezones'
sequence:
type: string
label: 'Timezone'
......@@ -138,6 +184,9 @@ field.widget.settings.smartdate_timezone:
show_extra:
type: boolean
label: 'Show extra'
hide_date:
type: boolean
label: 'Hide end date unless different'
smart_date.smart_date_format.*:
type: config_entity
......
......@@ -134,3 +134,60 @@ tr.even .smartdate--widget .form-type--select label {
display: inline-block;
}
/* Restyle Smart Date fieldsets to allow more room */
.smartdate--widget.fieldset {
border-width: 0 0 0 1px;
border-radius: 0;
box-shadow: none;
/* border-left: 1px solid #dedfe4; */
}
.smartdate--widget .fieldset__wrapper {
margin: 0 0 0 1.5rem;
}
/* Styles for the inline version */
.smartdate--time-inline .form-datetime-wrapper h4.form-item__label,
.smartdate--time-inline h4.label {
display: none;
}
.smartdate--time-inline .smartdate--separator {
margin: 0 0.5rem 0.5rem;
display: block;
text-align: center;
}
.smartdate--time-inline .form-datetime-wrapper .form-items-inline,
.smartdate--time-inline div.time-start,
.smartdate--time-inline div.time-end {
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.smartdate--time-inline .form-datetime-wrapper:nth-of-type(2) .form-items-inline,
.smartdate--time-inline div.time-end {
flex-wrap: wrap-reverse;
}
.smartdate--time-inline div.time-end .form-item {
text-align: center;
}
@media (min-width: 56em) {
.smartdate--time-inline {
display: flex;
align-items: flex-end;
}
/* Use a different bottom margin for Claro and Gin */
.fieldset__wrapper .smartdate--time-inline .smartdate--separator {
margin: 0 0.5rem 1.5rem;
}
.smartdate--time-inline .form-datetime-wrapper .form-items-inline,
.smartdate--time-inline div.time-start,
.smartdate--time-inline div.time-end {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: flex-end;
}
.smartdate--time-inline .form-datetime-wrapper:nth-of-type(2) .form-items-inline,
.smartdate--time-inline div.time-end {
flex-direction: row-reverse;
flex-wrap: wrap;
}
}
services:
smart_date.commands:
class: \Drupal\smart_date\Commands\SmartDateDrushCommands
tags:
- { name: drush.command }
......@@ -87,6 +87,7 @@
// Update End Date input.
var new_end = end.getFullYear() + '-' + pad(end.getMonth() + 1, 2) + '-' + pad(end.getDate(), 2);
wrapper.find('.time-end.form-date').val(new_end);
checkEndDate(wrapper);
}
function durationChanged(element) {
......@@ -94,19 +95,22 @@
var wrapper = $(element).parents('fieldset');
var end_time_input = wrapper.find('.time-end.form-time');
var end_date_input = wrapper.find('.time-end.form-date');
var end_date_label = wrapper.find('.time-start + .label, .form-datetime-wrapper:nth-child(2) .form-item__label')
var end_date_label = wrapper.find('.time-start + .label, .form-datetime-wrapper:nth-child(2) .form-item__label');
var separator = wrapper.find('.smartdate--separator');
// A strict comparison is needed, but not sure which type we'll get.
if (current_val === 0 || current_val === '0') {
// hide the end date and time
end_time_input.fadeOut(0);
end_date_input.fadeOut(0);
end_date_label.fadeOut(0);
separator.fadeOut(0);
}
else {
// if they're hidden, show them
end_time_input.fadeIn(0);
end_date_input.fadeIn(0);
end_date_label.fadeIn(0);
separator.fadeIn(0);
}
if ($(element).val() === 'custom') {
// reset end time and add focus
......@@ -118,6 +122,7 @@
// fire normal setEndDate()
setEndDate(element);
}
checkEndDate(wrapper);
}
function setInitialDuration(element) {
......@@ -156,6 +161,7 @@
end_time_input.attr('aria-readonly', true);
end_date_input.prop('readonly', true);
end_date_input.attr('aria-readonly', true);
checkEndDate(wrapper);
}
}
......@@ -225,6 +231,7 @@
else {
checkbox.prop('data-duration', duration.val());
}
checkEndDate(wrapper);
}
function checkAllDay(element) {
......@@ -261,6 +268,9 @@
end_time.fadeOut(0).val('23:59');
end_time_label.fadeOut(0);
duration_wrapper.fadeOut(0);
// Force the end date visible.
var end_date = wrapper.find('.time-end.form-date');
end_date.css('visibility', 'visible');
}
else {
// restore from data $values
......@@ -293,6 +303,7 @@
// call this to hide the end date and time
durationChanged(duration);
}
checkEndDate(wrapper);
}
}
......@@ -324,6 +335,20 @@
str = str.toString();
return str.length < max ? pad("0" + str, max) : str;
}
function checkEndDate(wrapper) {
//var wrapper = $(element).parents('fieldset');
var start_date = wrapper.find('.time-start.form-date');
var end_date = wrapper.find('.time-end.form-date');
var hide_me = end_date.data('hide');
var allday = wrapper.find('.allday');
if (hide_me && end_date.val() == start_date.val() && !allday.is(':checked')) {
end_date.css('visibility', 'hidden');
}
else {
end_date.css('visibility', 'visible');
}
}
}
};
})(jQuery, Drupal);
......@@ -15,6 +15,14 @@ field.formatter.settings.smartdate_recurring:
type: boolean
label: 'Force chronological'
translation context: 'Smart date display'
add_classes:
type: boolean
label: 'Add Classes'
translation context: 'Smart date display'
time_wrapper:
type: boolean
label: 'Add time wrapper'
translation context: 'Smart date display'
past_display:
type: integer
label: 'Recent Instances'
......@@ -27,3 +35,68 @@ field.formatter.settings.smartdate_recurring:
type: boolean
label: 'Show next instance separately'
translation context: 'Smart date display'
field.formatter.settings.smartdate_dailyrange:
type: field.formatter.settings.smartdate_dailyrange
label: 'Smart date daily range display format settings'
mapping:
timezone_override:
type: string
label: 'Time zone override'
translation context: 'Smart date display'
format:
type: string
label: 'Format'
translation context: 'Smart date display'
force_chronological:
type: boolean
label: 'Force chronological'
translation context: 'Smart date display'
add_classes:
type: boolean
label: 'Add Classes'
translation context: 'Smart date display'
time_wrapper:
type: boolean
label: 'Add time wrapper'
translation context: 'Smart date display'
field.field.*.*.*.third_party.smart_date_recur:
type: mapping
label: 'Recurring Dates'
mapping:
allow_recurring:
type: boolean
label: 'Allow recurring date values'
month_limit:
type: integer
label: 'Months to extend'
field.widget.third_party.smart_date_recur:
type: mapping
label: 'Recurring Dates'
mapping:
modal:
type: boolean
label: 'Use modal for managing instances'
allowed_recur_freq_values:
type: mapping
mapping:
MINUTELY:
label: Minutely
type: string
HOURLY:
label: Hourly
type: string
DAILY:
label: Daily
type: string
WEEKLY:
label: Weekly
type: string
MONTHLY:
label: Monthly
type: string
YEARLY:
label: Yearly
type: string
......@@ -3,7 +3,7 @@
* Styles for Smart Date Recur management.
*
*/
/* Formatting for instance form */
/* Formatting for instance form */
.smart-date-instance--cancelled {
text-decoration: line-through;
}
......
......@@ -74,8 +74,9 @@ function smart_date_recur_update_8303(&$sandbox) {
}
if (!function_exists('db_change_varchar_field')) {
/**
* Change length of a varchar entity field with data, safe with entity-updates.
* Change length of varchar entity field with data, safe with entity-updates.
*
* This updates the storage schema, the database schema, and the last
* installed schema.
......@@ -119,4 +120,5 @@ if (!function_exists('db_change_varchar_field')) {
$db->schema()->changeField($table_name, $field_name, $field_name, $table_schema['fields'][$field_name]);
}
}
}
......@@ -224,7 +224,7 @@ function smart_date_recur_widget_extra_fields(&$element, $item, $context) {
$select_repeat_end = 'select[name$="[' . $element['#delta'] . '][repeat-end]"]';
$element['repeat-label'] = [
'#type' => 'label',
'#title' => t('Repeats '),
'#title' => t('Repeats') . ' ',
'#prefix' => '<div class="clearfix"></div>',
'#attributes' => ['class' => ['repeat--label']],
];
......@@ -818,7 +818,7 @@ function smart_date_recur_field_widget_settings_summary_alter(&$summary, $contex
}
if ($freq_values = SmartDateRule::getThirdPartyFallback($context['widget'], 'allowed_recur_freq_values', _smart_date_recur_get_freq_defaults())) {
$labels = _smart_date_recur_label_freq_defaults($freq_values);
$summary[] = t('Dates can recur: ') . implode(', ', $labels);
$summary[] = t('Dates can recur:') . ' ' . implode(', ', $labels);
}
}
}
......
......@@ -132,7 +132,7 @@ class SmartDateRule extends ContentEntityBase {
$end = $this->get('limit')->getString();
if (!empty($end)) {
$rule .= ';' . $end;
if (strpos($end, 'UNTIL') === 0) {
if (strpos($end, 'UNTIL') === 0 && strpos($end, 'T') === FALSE) {
// Add midnight to specify the end of the last day.
$rule .= 'T235959';
}
......@@ -376,7 +376,8 @@ class SmartDateRule extends ContentEntityBase {
$range_end = array_pop($range);
$current_time->setTime($range_end + 1, 0);
$range_end_ts = $current_time->getTimestamp();
} else {
}
else {
$range_end_ts = $range_start_ts;
}
$range_text[] = SmartDateTrait::formatSmartDate($range_start_ts, $range_end_ts, $format->getOptions(), $tz_string, 'string');
......@@ -392,7 +393,8 @@ class SmartDateRule extends ContentEntityBase {
if ($range) {
$range_end = array_pop($range);
$range_text[] = $this->t(':start to :end', [':start' => $range_start, ':end' => $range_end], ['context' => 'Rule text']);
} else {
}
else {
$range_text[] = $range_start;
}
}
......@@ -514,7 +516,8 @@ class SmartDateRule extends ContentEntityBase {
$end_ts = $this->end->getValue()[0]['value'];
if (SmartDateTrait::isAllDay($start_ts, $end_ts, $tz_string)) {
$time = SmartDateTrait::formatSmartDate($start_ts, $end_ts, $format->getOptions(), $tz_string, 'string');
} else {
}
else {
$time_string = SmartDateTrait::formatSmartDate($start_ts, $start_ts, $format->getOptions(), $tz_string, 'string');
$time = $this->t('at :time', [':time' => ''], ['context' => 'Rule text']) . $time_string;
}
......@@ -580,7 +583,7 @@ class SmartDateRule extends ContentEntityBase {
// Add the final range.
$ranges[] = $range;
return $ranges;
}
}
/**
* Retrieve the months_limit value from the field definition.
......@@ -591,7 +594,8 @@ class SmartDateRule extends ContentEntityBase {
// Works for field definitions and rule objects.
$value = $field_def
->getThirdPartySetting('smart_date_recur', $property, $default);
} elseif (method_exists($field_def, 'getSetting')) {
}
elseif (method_exists($field_def, 'getSetting')) {
// For custom entities, set value in your field definition.
$value = $field_def->getSetting($property);
}
......@@ -717,6 +721,29 @@ class SmartDateRule extends ContentEntityBase {
return $return_array;
}
/**
* Return an array of all rule properties.
*/
public function getAllProperties() {
$array = $this->getParametersArray();
$array['freq'] = $this->get('freq')->getString();
$end = $this->get('limit')->getString();
if (empty($end)) {
$array['limit'] = NULL;
$array['limit_val'] = NULL;
}
else {
list($limit, $limit_val) = explode('=', $end);
if ($limit == 'UNTIL') {
// Add midnight to specify the end of the last day.
$limit_val .= 'T235959';
}
$array['limit'] = $limit;
$array['limit_val'] = $limit_val;
}
return $array;
}
/**
* {@inheritdoc}
*/
......
......@@ -33,10 +33,7 @@ class SmartDateDailyRangeFormatter extends SmartDateDefaultFormatter {
* {@inheritdoc}
*/
public static function defaultSettings() {
return [
'past_display' => '2',
'upcoming_display' => '2',
] + parent::defaultSettings();
return [] + parent::defaultSettings();
}
/**
......@@ -75,6 +72,7 @@ class SmartDateDailyRangeFormatter extends SmartDateDefaultFormatter {
];
}
$add_classes = $this->getSetting('add_classes');
$time_wrapper = $this->getSetting('time_wrapper');
$rrules = [];
$rrules_nondaily = [];
foreach ($items as $delta => $item) {
......@@ -92,12 +90,23 @@ class SmartDateDailyRangeFormatter extends SmartDateDefaultFormatter {
// Already established as NOT daily, so list as normal.
}
else {
// New rule to process, so load it.
$rrule_obj = SmartDateRule::load($item->rrule);
$rule_props = $rrule_obj->toArray();
$allowed_freq = ['HOURLY', 'MINUTELY'];
// Check that no extra parameters have been set.
// TODO: Separate handling for daily ranges with no end?
// TODO: Check for overrides.
if ($rule_props['freq'] && (($rule_props['freq'][0]['value'] == 'DAILY' && $rule_props['limit'] && !$rule_props['parameters']) || in_array($rule_props['freq'][0]['value'], ['DAILY', 'HOURLY', 'MINUTELY']))) {
if ($rule_props['freq']) {
if ($rule_props['freq'][0]['value'] == 'DAILY' && $rule_props['limit'] && !$rule_props['parameters']) {
$is_daily = TRUE;
}
elseif (in_array($rule_props['freq'][0]['value'], $allowed_freq)) {
$is_daily = TRUE;
}
}
if ($is_daily) {
// Uses a daily rule, so render a range instead.
$is_daily = TRUE;
$elements[$delta] = $item->rrule;
......@@ -119,6 +128,9 @@ class SmartDateDailyRangeFormatter extends SmartDateDefaultFormatter {
if ($add_classes) {
$this->addRangeClasses($elements[$delta]);
}
if ($time_wrapper) {
$this->addTimeWrapper($elements[$delta], $item->value, $item->end_value, $timezone);
}
}
}
foreach ($rrules as $rrule_collected) {
......
......@@ -104,8 +104,10 @@ class SmartDateRecurrenceFormatter extends SmartDateDefaultFormatter {
$elements = [];
// TODO: intellident switching between retrieval methods
// Look for a defined format and use it if specified.
$timezone_override = $this->getSetting('timezone_override') ?: NULL;
$format_label = $this->getSetting('format');
$add_classes = $this->getSetting('add_classes');
$time_wrapper = $this->getSetting('time_wrapper');
if ($format_label) {
$format = SmartDateFormat::load($format_label);
$settings = $format->getOptions();
......@@ -124,7 +126,7 @@ class SmartDateRecurrenceFormatter extends SmartDateDefaultFormatter {
}
$rrules = [];
foreach ($items as $delta => $item) {
$timezone = $item->timezone ? $item->timezone : NULL;
$timezone = $item->timezone ? $item->timezone : $timezone_override;
if (empty($item->value) || empty($item->end_value)) {
continue;
}
......@@ -134,6 +136,9 @@ class SmartDateRecurrenceFormatter extends SmartDateDefaultFormatter {
if ($add_classes) {
$this->addRangeClasses($elements[$delta]);
}
if ($time_wrapper) {
$this->addTimeWrapper($elements[$delta], $item->value, $item->end_value, $timezone);
}
}
else {
// Uses a rule, so use a placeholder instead.
......@@ -156,6 +161,9 @@ class SmartDateRecurrenceFormatter extends SmartDateDefaultFormatter {
$delta = $rrule_collected['delta'];
// Retrieve the text of the rrule.
$rrule = SmartDateRule::load($rrid);
if (empty($rrule)) {
continue;
}
$rrule_output['#rule_text'] = $rrule->getTextRule();
// Get the specified number of past instances.
......@@ -163,7 +171,8 @@ class SmartDateRecurrenceFormatter extends SmartDateDefaultFormatter {
if (in_array($rrule->get('freq')->getString(), ['MINUTELY', 'HOURLY'])) {
$within_day = TRUE;
} else {
}
else {
$within_day = FALSE;
}
......@@ -216,6 +225,9 @@ class SmartDateRecurrenceFormatter extends SmartDateDefaultFormatter {
if ($add_classes) {
$this->addRangeClasses($items[$key]);
}
if ($time_wrapper) {
$this->addTimeWrapper($items[$key], $item->value, $item->end_value, $item->timezone);
}
}
}
foreach ($items as $item) {
......@@ -243,6 +255,9 @@ class SmartDateRecurrenceFormatter extends SmartDateDefaultFormatter {
if ($add_classes) {
$this->addRangeClasses($items[$key]);
}
if ($time_wrapper) {
$this->addTimeWrapper($items[$key], $item->value, $item->end_value, $item->timezone);
}
}
}
foreach ($items as $item) {
......
......@@ -44,7 +44,7 @@ trait SmartDateRecurTrait {
$time_output[] = static::formatSmartDate($last_time->value, $last_time->end_value, $settings_nodate, $last_time->timezone);
$this_output['time'] = $time_output;
$this_output['join'] = ['#markup' => $settings['join']];
$this_output['date']['#markup'] = static::formatSmartDate($last_time->value, $last_time->value, $settings_notime, $last_time->timezone, 'string');
$this_output['date']['#markup'] = static::formatSmartDate($last_time->value, $last_time->value, $settings_notime, $last_time->timezone, 'string');
$this_output['#attributes']['class'] = ['smart-date--daily-times'];
$this_output['#type'] = 'container';
$output[] = $this->massageForOutput($this_output, $settings);
......
<?php
namespace Drupal\smart_date\Commands;
use Drush\Commands\DrushCommands;
/**
* A drush command file.
*
* @package Drupal\smart_date\Commands
*/
class SmartDateDrushCommands extends DrushCommands {
/**
* Drush command to migrate core fields to Smart Date fields.
*
* @param string $bundle
* Content type or other bundle whose data will be used.
* @param string $dest
* Field data will be copied to.
* @param string $source_start
* Field to copy data from.
* @param string $source_end
* Field to copy data from.
* @param string $source_all_day
* Field to copy data from.
*
* @command smart_date:migrate
* @alises sdm
* @option clear
* Clear any data in the destination field.
* @option entity
* Which entity to use as the destination.
* @option default_duration
* If no end date, assumed duration.
* @option langcode
* Language code to store.
*/
public function migrate($bundle, $dest, $source_start, $source_end = NULL, $source_all_day = NULL, $options = ['clear' => FALSE, 'entity' => 'node', 'default_duration' => 0, 'langcode' => NULL]) {
// TODO: Sanitize provide input.
$entity = $options['entity'];
$dest_table = $entity . '__' . $dest;
$def_duration = (int) $options['default_duration'];
$connection = \Drupal::service('database');
if ($options['clear']) {
$this->output()->writeln('Clearing existing values.');
$connection->truncate($dest_table)->execute();
}
$this->output()->writeln('Starting date migration.');
// Get all events.
$events = \Drupal::entityTypeManager()->getStorage($entity)
->loadByProperties(['type' => $bundle]);
$utc = new \DateTimeZone('UTC');
foreach ($events as $event) {
$dates = $event->get($source_start)->getValue();
$all_day_set = [];
if ($source_all_day) {
$all_day_set = $event->get($source_all_day)->getValue();
}
$end_dates_set = [];
if ($source_end && $source_start != $source_end) {
$end_dates_set = $event->get($source_end)->getValue();
}
$fallback_langcode = $event->get($source_start)->getLangcode();
// Hardcoded last resort langcode value of 'und'.
if (empty($fallback_langcode)) {
$fallback_langcode = 'und';
}
$langcode = $options['langcode'] ?? $fallback_langcode;
foreach ($dates as $delta => $date) {
$start_date = $date['value'];
// If a field was provided to check for all day, check it.
if ($all_day_set) {
$all_day = $all_day_set[$delta]['value'];
}
else {
$all_day = FALSE;
}
if (!empty($all_day)) {
$date = new \DateTime(substr($start_date, 0, -8) . '00:00:00', $utc);
$date = $date->format('U');
$start_date = $date;
$end_date = $date + 86340;
$duration = 1439;
}
else {
$start_date = new \DateTime($start_date, $utc);
$start_date = $start_date->format('U');
// Remove any seconds from the incoming value.
$start_date -= $start_date % 60;
$end_date = NULL;
if ($end_dates_set && isset($end_dates_set[$delta]['value'])) {
$end_date = $end_dates_set[$delta]['value'];
}
else {
// Assume a datetime range, so look for the end_value.
if (!empty($date['end_value'])) {
$end_date = $date['end_value'];
}
}
if (!empty($end_date)) {
$end_date = new \DateTime($end_date, $utc);
$end_date = $end_date->format('U');
// Remove any seconds from the incoming value.
$end_date -= $end_date % 60;
// If valid end date, set duration. Otherwise make a new end date.
if ($start_date < $end_date) {
$duration = round(($end_date - $start_date) / 60);
}
else {
$end_date = NULL;
}
}
if (!$end_date) {
// If the end date is bogus, use default duration.
$end_date = $start_date + ($def_duration * 60);
$duration = $def_duration;
}
// Insert the resulting data.
$result = $connection->insert($dest_table)
->fields([
'bundle' => $bundle,
'deleted' => 0,
'entity_id' => $event->id(),
'revision_id' => $event->getRevisionId(),
'langcode' => $langcode,
'delta' => $delta,
$dest . '_value' => $start_date,
$dest . '_end_value' => $end_date,
$dest . '_duration' => $duration,
$dest . '_rrule' => NULL,
$dest . '_rrule_index' => NULL,
$dest . '_timezone' => '',
])
->execute();
}
}
}
$this->output()->writeln('Finished date migration, flushing caches.');
drupal_flush_all_caches();
}
}
......@@ -152,8 +152,8 @@ class FullCalendarController extends CalendarEventController {
}
// Log the content changed.
$this->loggerFactory->get($entity_type)->notice('%entity_type: updated %title', [
'%entity_type' => $entity->getType(),
'%title' => $entity->getTitle(),
'%entity_type' => $entity->bundle(),
'%title' => $entity->label(),
]);
return new Response(1);
}
......
......@@ -20,7 +20,9 @@ use Drupal\smart_date\SmartDateTrait;
* field_types = {
* "smartdate",
* "daterange",
* "datetime"
* "datetime",
* "timestamp",
* "published_at"
* }
* )
*/
......@@ -36,6 +38,7 @@ class SmartDateDefaultFormatter extends DateTimeDefaultFormatter {
'format' => 'default',
'force_chronological' => 0,
'add_classes' => 0,
'time_wrapper' => 1,
] + parent::defaultSettings();
}
......@@ -82,6 +85,14 @@ class SmartDateDefaultFormatter extends DateTimeDefaultFormatter {
'#default_value' => $this->getSetting('add_classes'),
];
// Provide an option to add spans around the date and time values.
$form['time_wrapper'] = [
'#type' => 'checkbox',
'#title' => $this->t('Add time wrapper'),
'#description' => $this->t('Include an HTML5 time wrapper in the markup. Start and end dates will be individually wrapped.'),
'#default_value' => $this->getSetting('time_wrapper'),
];
return $form;
}
......
......@@ -47,10 +47,13 @@ class SmartDateDurationFormatter extends SmartDateDefaultFormatter {
$form['duration_separator'] = [
'#type' => 'text',
'#title' => $this->t('Duration Separator'),
'#description' => $this->t('Choose which display configuration to use.'),
'#description' => $this->t('Specify what characters should be used to separate the duration from the time.'),
'#default_value' => $this->getSetting('duration_separator'),
];
// Adjust the time_wrapper description.
$form['time_wrapper']['#description'] = $this->t('Include an HTML5 time wrapper in the markup. Time and duration will be individually wrapped.');
return $form;
}
......@@ -103,10 +106,13 @@ class SmartDateDurationFormatter extends SmartDateDefaultFormatter {
'allday_label' => $this->getSetting('allday_label'),
];
}
$timezone_override = $this->getSetting('timezone_override') ?: NULL;
$add_classes = $this->getSetting('add_classes');
$time_wrapper = $this->getSetting('time_wrapper');
foreach ($items as $delta => $item) {
if ($field_type == 'smartdate') {
$timezone = $item->timezone ? $item->timezone : $timezone_override;
if (empty($item->value) || empty($item->end_value)) {
continue;
}
......@@ -114,6 +120,7 @@ class SmartDateDurationFormatter extends SmartDateDefaultFormatter {
$end_ts = $item->end_value;
}
elseif ($field_type == 'daterange') {
$timezone = $timezone_override;
if (empty($item->start_date) || empty($item->end_date)) {
continue;
}
......@@ -124,7 +131,7 @@ class SmartDateDurationFormatter extends SmartDateDefaultFormatter {
// Not sure how to handle anything else, so return an empty set.
return $elements;
}
$elements[$delta] = static::formatSmartDate($start_ts, $start_ts, $settings);
$elements[$delta] = static::formatSmartDate($start_ts, $start_ts, $settings, $timezone);
$elements[$delta]['spacer'] = ['#markup' => $this->getSetting('duration_separator')];
// TODO: Include timezone in isAllDay check.
if (static::isAllDay($start_ts, $end_ts)) {
......@@ -152,6 +159,24 @@ class SmartDateDurationFormatter extends SmartDateDefaultFormatter {
}
}
if ($time_wrapper) {
$this->addTimeWrapper($elements[$delta], $start_ts, $end_ts, $timezone);
// For the sake of finding differences, "fix" all day events.
if ($this->isAllDay($start_ts, $end_ts, $timezone)) {
$adjusted_end = $end_ts + 60;
}
else {
$adjusted_end = $end_ts;
}
$diff = \Drupal::service('date.formatter')->formatDiff($start_ts, $adjusted_end, ['strict' => FALSE, 'language' => 'en']);
$current_contents = $elements[$delta]['duration'];
$elements[$delta]['duration'] = [
'#theme' => 'time',
'#attributes' => ['datetime' => $this->formatDurationTime($diff)],
'#text' => $current_contents,
];
}
if (!empty($item->_attributes)) {
$elements[$delta]['#attributes'] += $item->_attributes;
// Unset field item attributes since they have been included in the
......@@ -163,4 +188,38 @@ class SmartDateDurationFormatter extends SmartDateDefaultFormatter {
return $elements;
}
/**
* Format the string to be used as the datetime value.
*
* @param string $string
* The string returned by DateFormatter::formatDiff.
*
* @return string
* The formatted duration string.
*/
private function formatDurationTime($string) {
if (empty($string)) {
return '';
}
$abbr_string = 'P';
$intervals = [
'Y' => 'year',
'D' => 'day',
'H' => 'hour',
'M' => 'minute',
];
foreach ($intervals as $key => $match_string) {
$pattern = '/(\d)+ ' . $match_string . '(s)?/i';
preg_match($pattern, $string, $matches);
if ($matches) {
$abbr_string .= $matches[1] . $key;
}
}
if (strlen($abbr_string) == 1) {
$abbr_string = '';
}
return $abbr_string;
}
}
......@@ -15,7 +15,7 @@ use Drupal\datetime\DateTimeComputed;
* id = "smartdate",
* label = @Translation("Smart date range"),
* description = @Translation("Create and store timestamp ranges, with an intelligent UI."),
* default_widget = "smartdate_default",
* default_widget = "smartdate_inline",
* default_formatter = "smartdate_default",
* list_class = "\Drupal\smart_date\Plugin\Field\FieldType\SmartDateFieldItemList"
* )
......
<?php
namespace Drupal\smart_date\Plugin\Field\FieldWidget;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Form\FormStateInterface;
/**
* Plugin implementation of the 'smartdate_inline' widget.
*
* @FieldWidget(
* id = "smartdate_inline",
* label = @Translation("Smart Date inline range"),
* field_types = {
* "smartdate",
* "daterange"
* }
* )
*/
class SmartDateInlineWidget extends SmartDateDefaultWidget {
/**
* {@inheritdoc}
*/
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
$element = parent::formElement($items, $delta, $element, $form, $form_state);
$time_wrapper = [
'#type' => 'container',
'#attributes' => [
'class' => ['smartdate--time-inline'],
],
'#tree' => TRUE,
];
$element = array_merge(['time_wrapper' => $time_wrapper], $element);
// Move the start and end elements into our new container.
$element['time_wrapper']['value'] = $element['value'];
$element['time_wrapper']['separator']['#markup'] = '<span class="smartdate--separator">' . $this->t('to') . '</span>';
$element['time_wrapper']['end_value'] = (isset($element['end_value'])) ? $element['end_value'] : $element['value'];
unset($element['value']);
unset($element['end_value']);
if (!isset($element['value']) || (isset($element['#access']) && $element['#access'] === FALSE)) {
return $element;
}
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 timestamp.
foreach ($values as &$item) {
if (isset($item['time_wrapper']['value'])) {
$item['value'] = $item['time_wrapper']['value'];
}
if (isset($item['time_wrapper']['end_value'])) {
$item['end_value'] = $item['time_wrapper']['end_value'];
}
}
$values = parent::massageFormValues($values, $form, $form_state);
return $values;
}
}
......@@ -28,6 +28,7 @@ class SmartDateWidgetBase extends DateTimeWidgetBase {
public static function defaultSettings() {
return [
'show_extra' => TRUE,
'hide_date' => TRUE,
] + parent::defaultSettings();
}
......@@ -48,6 +49,12 @@ class SmartDateWidgetBase extends DateTimeWidgetBase {
];
}
$element['hide_date'] = [
'#type' => 'checkbox',
'#title' => $this->t("Hide the end date field unless it's different from the start date."),
'#default_value' => $this->getSetting('hide_date'),
];
return $element;
}
......@@ -136,6 +143,8 @@ class SmartDateWidgetBase extends DateTimeWidgetBase {
$defaults['default_duration_increments'] = $default_duration_increments;
}
}
$defaults['hide_date'] = $this->getSetting('hide_date');
$values['storage'] = $field_type;
$form['#attached']['library'][] = 'smart_date/smart_date';
$element['#attributes']['class'][] = 'smartdate--widget';
......@@ -188,6 +197,9 @@ class SmartDateWidgetBase extends DateTimeWidgetBase {
];
}
// Make the hide_date value available to the form.
$element['end_value']['#attributes']['data-hide'] = (isset($defaults['hide_date']) && $defaults['hide_date']) ? 1 : 0;
// Parse the allowed duration increments and create labels if not provided.
$increments = SmartDateListItemBase::parseValues($defaults['default_duration_increments']);
foreach ($increments as $key => $label) {
......@@ -358,8 +370,18 @@ class SmartDateWidgetBase extends DateTimeWidgetBase {
* The complete form structure.
*/
public static function validateStartEnd(array &$element, FormStateInterface $form_state, array &$complete_form) {
$start_time = $element['value']['#value']['object'];
$end_time = $element['end_value']['#value']['object'];
if (isset($element['time_wrapper']['value']) && empty($element['value'])) {
$start_time = $element['time_wrapper']['value']['#value']['object'];
}
else {
$start_time = $element['value']['#value']['object'];
}
if (isset($element['time_wrapper']['end_value']) && empty($element['end_value'])) {
$end_time = $element['time_wrapper']['end_value']['#value']['object'];
}
else {
$end_time = $element['end_value']['#value']['object'];
}
if ($start_time instanceof DrupalDateTime && $end_time instanceof DrupalDateTime) {
if ($start_time->getTimestamp() !== $end_time->getTimestamp()) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment