Community Events: Display dates and times in the user's time zone.
Fixes #51130 Props sippis, hlashbrooke, audrasjb, Rarst, iandunn Built from https://develop.svn.wordpress.org/trunk@49146 git-svn-id: http://core.svn.wordpress.org/trunk@48908 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
parent
5d42748c18
commit
5bf0005827
|
@ -77,6 +77,8 @@ class WP_Community_Events {
|
|||
* mitigates possible privacy concerns.
|
||||
*
|
||||
* @since 4.8.0
|
||||
* @since 5.6.0 Response no longer contains formatted date field. They're added
|
||||
* in `wp.communityEvents.populateDynamicEventFields()` now.
|
||||
*
|
||||
* @param string $location_search Optional. City name to help determine the location.
|
||||
* e.g., "Seattle". Default empty string.
|
||||
|
@ -165,7 +167,6 @@ class WP_Community_Events {
|
|||
$this->cache_events( $response_body, $expiration );
|
||||
|
||||
$response_body['events'] = $this->trim_events( $response_body['events'] );
|
||||
$response_body = $this->format_event_data_time( $response_body );
|
||||
|
||||
return $response_body;
|
||||
}
|
||||
|
@ -344,6 +345,8 @@ class WP_Community_Events {
|
|||
* Gets cached events.
|
||||
*
|
||||
* @since 4.8.0
|
||||
* @since 5.6.0 Response no longer contains formatted date field. They're added
|
||||
* in `wp.communityEvents.populateDynamicEventFields()` now.
|
||||
*
|
||||
* @return array|false An array containing `location` and `events` items
|
||||
* on success, false on failure.
|
||||
|
@ -355,7 +358,7 @@ class WP_Community_Events {
|
|||
$cached_response['events'] = $this->trim_events( $cached_response['events'] );
|
||||
}
|
||||
|
||||
return $this->format_event_data_time( $cached_response );
|
||||
return $cached_response;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -372,6 +375,12 @@ class WP_Community_Events {
|
|||
* @return array The response with dates and times formatted.
|
||||
*/
|
||||
protected function format_event_data_time( $response_body ) {
|
||||
_deprecated_function(
|
||||
__METHOD__,
|
||||
'5.6.0',
|
||||
'This is no longer used by Core, and only kept for backwards-compatibility.'
|
||||
);
|
||||
|
||||
if ( isset( $response_body['events'] ) ) {
|
||||
foreach ( $response_body['events'] as $key => $event ) {
|
||||
$timestamp = strtotime( $event['date'] );
|
||||
|
|
|
@ -1389,9 +1389,11 @@ function wp_print_community_events_templates() {
|
|||
</div>
|
||||
|
||||
<div class="event-date-time">
|
||||
<span class="event-date">{{ event.formatted_date }}</span>
|
||||
<span class="event-date">{{ event.user_formatted_date }}</span>
|
||||
<# if ( 'meetup' === event.type ) { #>
|
||||
<span class="event-time">{{ event.formatted_time }}</span>
|
||||
<span class="event-time">
|
||||
{{ event.user_formatted_time }} {{ event.timeZoneAbbreviation }}
|
||||
</span>
|
||||
<# } #>
|
||||
</div>
|
||||
</li>
|
||||
|
|
|
@ -266,6 +266,11 @@ jQuery( function( $ ) {
|
|||
'use strict';
|
||||
|
||||
var communityEventsData = window.communityEventsData || {},
|
||||
dateI18n = wp.date.dateI18n,
|
||||
format = wp.date.format,
|
||||
sprintf = wp.i18n.sprintf,
|
||||
__ = wp.i18n.__,
|
||||
_x = wp.i18n._x,
|
||||
app;
|
||||
|
||||
/**
|
||||
|
@ -441,6 +446,7 @@ jQuery( function( $ ) {
|
|||
.fail( function() {
|
||||
app.renderEventsTemplate({
|
||||
'location' : false,
|
||||
'events' : [],
|
||||
'error' : true
|
||||
}, initiatedBy );
|
||||
});
|
||||
|
@ -465,6 +471,11 @@ jQuery( function( $ ) {
|
|||
$locationMessage = $( '#community-events-location-message' ),
|
||||
$results = $( '.community-events-results' );
|
||||
|
||||
templateParams.events = app.populateDynamicEventFields(
|
||||
templateParams.events,
|
||||
communityEventsData.time_format
|
||||
);
|
||||
|
||||
/*
|
||||
* Hide all toggleable elements by default, to keep the logic simple.
|
||||
* Otherwise, each block below would have to turn hide everything that
|
||||
|
@ -576,6 +587,195 @@ jQuery( function( $ ) {
|
|||
} else {
|
||||
app.toggleLocationForm( 'show' );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Populate event fields that have to be calculated on the fly.
|
||||
*
|
||||
* These can't be stored in the database, because they're dependent on
|
||||
* the user's current time zone, locale, etc.
|
||||
*
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param {Array} rawEvents The events that should have dynamic fields added to them.
|
||||
* @param {string} timeFormat A time format acceptable by `wp.date.dateI18n()`.
|
||||
*
|
||||
* @returns {Array}
|
||||
*/
|
||||
populateDynamicEventFields: function( rawEvents, timeFormat ) {
|
||||
// Clone the parameter to avoid mutating it, so that this can remain a pure function.
|
||||
var populatedEvents = JSON.parse( JSON.stringify( rawEvents ) );
|
||||
|
||||
$.each( populatedEvents, function( index, event ) {
|
||||
var timeZone = app.getTimeZone( event.start_unix_timestamp * 1000 );
|
||||
|
||||
event.user_formatted_date = app.getFormattedDate(
|
||||
event.start_unix_timestamp * 1000,
|
||||
event.end_unix_timestamp * 1000,
|
||||
timeZone
|
||||
);
|
||||
|
||||
event.user_formatted_time = dateI18n(
|
||||
timeFormat,
|
||||
event.start_unix_timestamp * 1000,
|
||||
timeZone
|
||||
);
|
||||
|
||||
event.timeZoneAbbreviation = app.getTimeZoneAbbreviation( event.start_unix_timestamp * 1000 );
|
||||
} );
|
||||
|
||||
return populatedEvents;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the user's local/browser time zone, in a form suitable for `wp.date.i18n()`.
|
||||
*
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param startTimestamp
|
||||
*
|
||||
* @returns {string|number}
|
||||
*/
|
||||
getTimeZone: function( startTimestamp ) {
|
||||
/*
|
||||
* Prefer a name like `Europe/Helsinki`, since that automatically tracks daylight savings. This
|
||||
* doesn't need to take `startTimestamp` into account for that reason.
|
||||
*/
|
||||
var timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
|
||||
/*
|
||||
* Fall back to an offset for IE11, which declares the property but doesn't assign a value.
|
||||
*/
|
||||
if ( 'undefined' === typeof timeZone ) {
|
||||
/*
|
||||
* It's important to use the _event_ time, not the _current_
|
||||
* time, so that daylight savings time is accounted for.
|
||||
*/
|
||||
timeZone = app.getFlippedTimeZoneOffset( startTimestamp );
|
||||
}
|
||||
|
||||
return timeZone;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get intuitive time zone offset.
|
||||
*
|
||||
* `Data.prototype.getTimezoneOffset()` returns a positive value for time zones
|
||||
* that are _behind_ UTC, and a _negative_ value for ones that are ahead.
|
||||
*
|
||||
* See https://stackoverflow.com/questions/21102435/why-does-javascript-date-gettimezoneoffset-consider-0500-as-a-positive-off.
|
||||
*
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param {number} startTimestamp
|
||||
*
|
||||
* @returns {number}
|
||||
*/
|
||||
getFlippedTimeZoneOffset: function( startTimestamp ) {
|
||||
return new Date( startTimestamp ).getTimezoneOffset() * -1;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get a short time zone name, like `PST`.
|
||||
*
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param {number} startTimestamp
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
getTimeZoneAbbreviation: function( startTimestamp ) {
|
||||
var timeZoneAbbreviation,
|
||||
eventDateTime = new Date( startTimestamp );
|
||||
|
||||
/*
|
||||
* Leaving the `locales` argument undefined is important, so that the browser
|
||||
* displays the abbreviation that's most appropriate for the current locale. For
|
||||
* some that will be `UTC{+|-}{n}`, and for others it will be a code like `PST`.
|
||||
*
|
||||
* This doesn't need to take `startTimestamp` into account, because a name like
|
||||
* `America/Chicago` automatically tracks daylight savings.
|
||||
*/
|
||||
var shortTimeStringParts = eventDateTime.toLocaleTimeString( undefined, { timeZoneName : 'short' } ).split( ' ' );
|
||||
|
||||
if ( 3 === shortTimeStringParts.length ) {
|
||||
timeZoneAbbreviation = shortTimeStringParts[2];
|
||||
}
|
||||
|
||||
if ( 'undefined' === typeof timeZoneAbbreviation ) {
|
||||
/*
|
||||
* It's important to use the _event_ time, not the _current_
|
||||
* time, so that daylight savings time is accounted for.
|
||||
*/
|
||||
var timeZoneOffset = app.getFlippedTimeZoneOffset( startTimestamp ),
|
||||
sign = -1 === Math.sign( timeZoneOffset ) ? '' : '+';
|
||||
|
||||
// translators: Used as part of a string like `GMT+5` in the Events Widget.
|
||||
timeZoneAbbreviation = _x( 'GMT', 'Events widget offset prefix' ) + sign + ( timeZoneOffset / 60 );
|
||||
}
|
||||
|
||||
return timeZoneAbbreviation;
|
||||
},
|
||||
|
||||
/**
|
||||
* Format a start/end date in the user's local time zone and locale.
|
||||
*
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param {int} startDate The Unix timestamp in milliseconds when the the event starts.
|
||||
* @param {int} endDate The Unix timestamp in milliseconds when the the event ends.
|
||||
* @param {string} timeZone A time zone string or offset which is parsable by `wp.date.i18n()`.
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
getFormattedDate: function( startDate, endDate, timeZone ) {
|
||||
var formattedDate;
|
||||
|
||||
/*
|
||||
* The `date_format` option is not used because it's important
|
||||
* in this context to keep the day of the week in the displayed date,
|
||||
* so that users can tell at a glance if the event is on a day they
|
||||
* are available, without having to open the link.
|
||||
*
|
||||
* The case of crossing a year boundary is intentionally not handled.
|
||||
* It's so rare in practice that it's not worth the complexity
|
||||
* tradeoff. The _ending_ year should be passed to
|
||||
* `multiple_month_event`, though, just in case.
|
||||
*/
|
||||
/* translators: Date format for upcoming events on the dashboard. Include the day of the week. See https://www.php.net/manual/datetime.format.php */
|
||||
var singleDayEvent = __( 'l, M j, Y' ),
|
||||
/* translators: Date string for upcoming events. 1: Month, 2: Starting day, 3: Ending day, 4: Year. */
|
||||
multipleDayEvent = __( '%1$s %2$d–%3$d, %4$d' ),
|
||||
/* translators: Date string for upcoming events. 1: Starting month, 2: Starting day, 3: Ending month, 4: Ending day, 5: Ending year. */
|
||||
multipleMonthEvent = __( '%1$s %2$d – %3$s %4$d, %5$d' );
|
||||
|
||||
// Detect single-day events.
|
||||
if ( ! endDate || format( 'Y-m-d', startDate ) === format( 'Y-m-d', endDate ) ) {
|
||||
formattedDate = dateI18n( singleDayEvent, startDate, timeZone );
|
||||
|
||||
// Multiple day events.
|
||||
} else if ( format( 'Y-m', startDate ) === format( 'Y-m', endDate ) ) {
|
||||
formattedDate = sprintf(
|
||||
multipleDayEvent,
|
||||
dateI18n( _x( 'F', 'upcoming events month format' ), startDate, timeZone ),
|
||||
dateI18n( _x( 'j', 'upcoming events day format' ), startDate, timeZone ),
|
||||
dateI18n( _x( 'j', 'upcoming events day format' ), endDate, timeZone ),
|
||||
dateI18n( _x( 'Y', 'upcoming events year format' ), endDate, timeZone )
|
||||
);
|
||||
|
||||
// Multi-day events that cross a month boundary.
|
||||
} else {
|
||||
formattedDate = sprintf(
|
||||
multipleMonthEvent,
|
||||
dateI18n( _x( 'F', 'upcoming events month format' ), startDate, timeZone ),
|
||||
dateI18n( _x( 'j', 'upcoming events day format' ), startDate, timeZone ),
|
||||
dateI18n( _x( 'F', 'upcoming events month format' ), endDate, timeZone ),
|
||||
dateI18n( _x( 'j', 'upcoming events day format' ), endDate, timeZone ),
|
||||
dateI18n( _x( 'Y', 'upcoming events year format' ), endDate, timeZone )
|
||||
);
|
||||
}
|
||||
|
||||
return formattedDate;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1308,7 +1308,8 @@ function wp_default_scripts( $scripts ) {
|
|||
$scripts->add( 'wp-color-picker', "/wp-admin/js/color-picker$suffix.js", array( 'iris' ), false, 1 );
|
||||
$scripts->set_translations( 'wp-color-picker' );
|
||||
|
||||
$scripts->add( 'dashboard', "/wp-admin/js/dashboard$suffix.js", array( 'jquery', 'admin-comments', 'postbox', 'wp-util', 'wp-a11y' ), false, 1 );
|
||||
$scripts->add( 'dashboard', "/wp-admin/js/dashboard$suffix.js", array( 'jquery', 'admin-comments', 'postbox', 'wp-util', 'wp-a11y', 'wp-date' ), false, 1 );
|
||||
$scripts->set_translations( 'dashboard' );
|
||||
|
||||
$scripts->add( 'list-revisions', "/wp-includes/js/wp-list-revisions$suffix.js" );
|
||||
|
||||
|
@ -1755,6 +1756,7 @@ function wp_localize_community_events() {
|
|||
array(
|
||||
'nonce' => wp_create_nonce( 'community_events' ),
|
||||
'cache' => $events_client->get_cached_events(),
|
||||
'time_format' => get_option( 'time_format' ),
|
||||
|
||||
'l10n' => array(
|
||||
'enter_closest_city' => __( 'Enter your closest city to find nearby events.' ),
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
*
|
||||
* @global string $wp_version
|
||||
*/
|
||||
$wp_version = '5.6-alpha-49145';
|
||||
$wp_version = '5.6-alpha-49146';
|
||||
|
||||
/**
|
||||
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
||||
|
|
Loading…
Reference in New Issue