fix: prevent asset conflicts between React and Grid.js versions

Add coexistence checks to all enqueue methods to prevent loading
both React and Grid.js assets simultaneously.

Changes:
- ReactAdmin.php: Only enqueue React assets when ?react=1
- Init.php: Skip Grid.js when React active on admin pages
- Form.php, Coupon.php, Access.php: Restore classic assets when ?react=0
- Customer.php, Product.php, License.php: Add coexistence checks

Now the toggle between Classic and React versions works correctly.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
dwindown
2026-04-18 17:02:14 +07:00
parent bd9cdac02e
commit e8fbfb14c1
74973 changed files with 6658406 additions and 71 deletions

665
node_modules/@wordpress/date/src/index.js generated vendored Normal file
View File

@@ -0,0 +1,665 @@
/**
* External dependencies
*/
import momentLib from 'moment';
import 'moment-timezone/moment-timezone';
import 'moment-timezone/moment-timezone-utils';
/**
* WordPress dependencies
*/
import deprecated from '@wordpress/deprecated';
/** @typedef {import('moment').Moment} Moment */
/** @typedef {import('moment').LocaleSpecification} MomentLocaleSpecification */
/**
* @typedef MeridiemConfig
* @property {string} am Lowercase AM.
* @property {string} AM Uppercase AM.
* @property {string} pm Lowercase PM.
* @property {string} PM Uppercase PM.
*/
/**
* @typedef FormatsConfig
* @property {string} time Time format.
* @property {string} date Date format.
* @property {string} datetime Datetime format.
* @property {string} datetimeAbbreviated Abbreviated datetime format.
*/
/**
* @typedef TimezoneConfig
* @property {string} offset Offset setting.
* @property {string} offsetFormatted Offset setting with decimals formatted to minutes.
* @property {string} string The timezone as a string (e.g., `'America/Los_Angeles'`).
* @property {string} abbr Abbreviation for the timezone.
*/
/* eslint-disable jsdoc/valid-types */
/**
* @typedef L10nSettings
* @property {string} locale Moment locale.
* @property {MomentLocaleSpecification['months']} months Locale months.
* @property {MomentLocaleSpecification['monthsShort']} monthsShort Locale months short.
* @property {MomentLocaleSpecification['weekdays']} weekdays Locale weekdays.
* @property {MomentLocaleSpecification['weekdaysShort']} weekdaysShort Locale weekdays short.
* @property {MeridiemConfig} meridiem Meridiem config.
* @property {MomentLocaleSpecification['relativeTime']} relative Relative time config.
* @property {0|1|2|3|4|5|6} startOfWeek Day that the week starts on.
*/
/* eslint-enable jsdoc/valid-types */
/**
* @typedef DateSettings
* @property {L10nSettings} l10n Localization settings.
* @property {FormatsConfig} formats Date/time formats config.
* @property {TimezoneConfig} timezone Timezone settings.
*/
const WP_ZONE = 'WP';
// This regular expression tests positive for UTC offsets as described in ISO 8601.
// See: https://en.wikipedia.org/wiki/ISO_8601#Time_offsets_from_UTC
const VALID_UTC_OFFSET = /^[+-][0-1][0-9](:?[0-9][0-9])?$/;
// Changes made here will likely need to be synced with Core in the file
// src/wp-includes/script-loader.php in `wp_default_packages_inline_scripts()`.
/** @type {DateSettings} */
let settings = {
l10n: {
locale: 'en',
months: [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
],
monthsShort: [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec',
],
weekdays: [
'Sunday',
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
],
weekdaysShort: [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ],
meridiem: { am: 'am', pm: 'pm', AM: 'AM', PM: 'PM' },
relative: {
future: '%s from now',
past: '%s ago',
s: 'a few seconds',
ss: '%d seconds',
m: 'a minute',
mm: '%d minutes',
h: 'an hour',
hh: '%d hours',
d: 'a day',
dd: '%d days',
M: 'a month',
MM: '%d months',
y: 'a year',
yy: '%d years',
},
startOfWeek: 0,
},
formats: {
time: 'g: i a',
date: 'F j, Y',
datetime: 'F j, Y g: i a',
datetimeAbbreviated: 'M j, Y g: i a',
},
timezone: { offset: '0', offsetFormatted: '0', string: '', abbr: '' },
};
/**
* Adds a locale to moment, using the format supplied by `wp_localize_script()`.
*
* @param {DateSettings} dateSettings Settings, including locale data.
*/
export function setSettings( dateSettings ) {
settings = dateSettings;
setupWPTimezone();
// Does moment already have a locale with the right name?
if ( momentLib.locales().includes( dateSettings.l10n.locale ) ) {
// Is that locale misconfigured, e.g. because we are on a site running
// WordPress < 6.0?
if (
momentLib
.localeData( dateSettings.l10n.locale )
.longDateFormat( 'LTS' ) === null
) {
// Delete the misconfigured locale.
// @ts-ignore Type definitions are incorrect - null is permitted.
momentLib.defineLocale( dateSettings.l10n.locale, null );
} else {
// We have a properly configured locale, so no need to create one.
return;
}
}
// defineLocale() will modify the current locale, so back it up.
const currentLocale = momentLib.locale();
// Create locale.
momentLib.defineLocale( dateSettings.l10n.locale, {
// Inherit anything missing from English. We don't load
// moment-with-locales.js so English is all there is.
parentLocale: 'en',
months: dateSettings.l10n.months,
monthsShort: dateSettings.l10n.monthsShort,
weekdays: dateSettings.l10n.weekdays,
weekdaysShort: dateSettings.l10n.weekdaysShort,
meridiem( hour, minute, isLowercase ) {
if ( hour < 12 ) {
return isLowercase
? dateSettings.l10n.meridiem.am
: dateSettings.l10n.meridiem.AM;
}
return isLowercase
? dateSettings.l10n.meridiem.pm
: dateSettings.l10n.meridiem.PM;
},
longDateFormat: {
LT: dateSettings.formats.time,
LTS: momentLib.localeData( 'en' ).longDateFormat( 'LTS' ),
L: momentLib.localeData( 'en' ).longDateFormat( 'L' ),
LL: dateSettings.formats.date,
LLL: dateSettings.formats.datetime,
LLLL: momentLib.localeData( 'en' ).longDateFormat( 'LLLL' ),
},
// From human_time_diff?
// Set to `(number, withoutSuffix, key, isFuture) => {}` instead.
relativeTime: dateSettings.l10n.relative,
} );
// Restore the locale to what it was.
momentLib.locale( currentLocale );
}
/**
* Returns the currently defined date settings.
*
* @return {DateSettings} Settings, including locale data.
*/
export function getSettings() {
return settings;
}
/**
* Returns the currently defined date settings.
*
* @deprecated
* @return {DateSettings} Settings, including locale data.
*/
export function __experimentalGetSettings() {
deprecated( 'wp.date.__experimentalGetSettings', {
since: '6.1',
alternative: 'wp.date.getSettings',
} );
return getSettings();
}
function setupWPTimezone() {
// Get the current timezone settings from the WP timezone string.
const currentTimezone = momentLib.tz.zone( settings.timezone.string );
// Check to see if we have a valid TZ data, if so, use it for the custom WP_ZONE timezone, otherwise just use the offset.
if ( currentTimezone ) {
// Create WP timezone based off settings.timezone.string. We need to include the additional data so that we
// don't lose information about daylight savings time and other items.
// See https://github.com/WordPress/gutenberg/pull/48083
momentLib.tz.add(
momentLib.tz.pack( {
name: WP_ZONE,
abbrs: currentTimezone.abbrs,
untils: currentTimezone.untils,
offsets: currentTimezone.offsets,
} )
);
} else {
// Create WP timezone based off dateSettings.
momentLib.tz.add(
momentLib.tz.pack( {
name: WP_ZONE,
abbrs: [ WP_ZONE ],
untils: [ null ],
offsets: [ -settings.timezone.offset * 60 || 0 ],
} )
);
}
}
// Date constants.
/**
* Number of seconds in one minute.
*
* @type {number}
*/
const MINUTE_IN_SECONDS = 60;
/**
* Number of minutes in one hour.
*
* @type {number}
*/
const HOUR_IN_MINUTES = 60;
/**
* Number of seconds in one hour.
*
* @type {number}
*/
const HOUR_IN_SECONDS = 60 * MINUTE_IN_SECONDS;
/**
* Map of PHP formats to Moment.js formats.
*
* These are used internally by {@link wp.date.format}, and are either
* a string representing the corresponding Moment.js format code, or a
* function which returns the formatted string.
*
* This should only be used through {@link wp.date.format}, not
* directly.
*/
const formatMap = {
// Day.
d: 'DD',
D: 'ddd',
j: 'D',
l: 'dddd',
N: 'E',
/**
* Gets the ordinal suffix.
*
* @param {Moment} momentDate Moment instance.
*
* @return {string} Formatted date.
*/
S( momentDate ) {
// Do - D.
const num = momentDate.format( 'D' );
const withOrdinal = momentDate.format( 'Do' );
return withOrdinal.replace( num, '' );
},
w: 'd',
/**
* Gets the day of the year (zero-indexed).
*
* @param {Moment} momentDate Moment instance.
*
* @return {string} Formatted date.
*/
z( momentDate ) {
// DDD - 1.
return ( parseInt( momentDate.format( 'DDD' ), 10 ) - 1 ).toString();
},
// Week.
W: 'W',
// Month.
F: 'MMMM',
m: 'MM',
M: 'MMM',
n: 'M',
/**
* Gets the days in the month.
*
* @param {Moment} momentDate Moment instance.
*
* @return {number} Formatted date.
*/
t( momentDate ) {
return momentDate.daysInMonth();
},
// Year.
/**
* Gets whether the current year is a leap year.
*
* @param {Moment} momentDate Moment instance.
*
* @return {string} Formatted date.
*/
L( momentDate ) {
return momentDate.isLeapYear() ? '1' : '0';
},
o: 'GGGG',
Y: 'YYYY',
y: 'YY',
// Time.
a: 'a',
A: 'A',
/**
* Gets the current time in Swatch Internet Time (.beats).
*
* @param {Moment} momentDate Moment instance.
*
* @return {number} Formatted date.
*/
B( momentDate ) {
const timezoned = momentLib( momentDate ).utcOffset( 60 );
const seconds = parseInt( timezoned.format( 's' ), 10 ),
minutes = parseInt( timezoned.format( 'm' ), 10 ),
hours = parseInt( timezoned.format( 'H' ), 10 );
return parseInt(
(
( seconds +
minutes * MINUTE_IN_SECONDS +
hours * HOUR_IN_SECONDS ) /
86.4
).toString(),
10
);
},
g: 'h',
G: 'H',
h: 'hh',
H: 'HH',
i: 'mm',
s: 'ss',
u: 'SSSSSS',
v: 'SSS',
// Timezone.
e: 'zz',
/**
* Gets whether the timezone is in DST currently.
*
* @param {Moment} momentDate Moment instance.
*
* @return {string} Formatted date.
*/
I( momentDate ) {
return momentDate.isDST() ? '1' : '0';
},
O: 'ZZ',
P: 'Z',
T: 'z',
/**
* Gets the timezone offset in seconds.
*
* @param {Moment} momentDate Moment instance.
*
* @return {number} Formatted date.
*/
Z( momentDate ) {
// Timezone offset in seconds.
const offset = momentDate.format( 'Z' );
const sign = offset[ 0 ] === '-' ? -1 : 1;
const parts = offset
.substring( 1 )
.split( ':' )
.map( ( n ) => parseInt( n, 10 ) );
return (
sign *
( parts[ 0 ] * HOUR_IN_MINUTES + parts[ 1 ] ) *
MINUTE_IN_SECONDS
);
},
// Full date/time.
c: 'YYYY-MM-DDTHH:mm:ssZ', // .toISOString.
/**
* Formats the date as RFC2822.
*
* @param {Moment} momentDate Moment instance.
*
* @return {string} Formatted date.
*/
r( momentDate ) {
return momentDate
.locale( 'en' )
.format( 'ddd, DD MMM YYYY HH:mm:ss ZZ' );
},
U: 'X',
};
/**
* Formats a date. Does not alter the date's timezone.
*
* @param {string} dateFormat PHP-style formatting string.
* See php.net/date.
* @param {Moment | Date | string | undefined} dateValue Date object or string,
* parsable by moment.js.
*
* @return {string} Formatted date.
*/
export function format( dateFormat, dateValue = new Date() ) {
let i, char;
const newFormat = [];
const momentDate = momentLib( dateValue );
for ( i = 0; i < dateFormat.length; i++ ) {
char = dateFormat[ i ];
// Is this an escape?
if ( '\\' === char ) {
// Add next character, then move on.
i++;
newFormat.push( '[' + dateFormat[ i ] + ']' );
continue;
}
if ( char in formatMap ) {
const formatter =
formatMap[ /** @type {keyof formatMap} */ ( char ) ];
if ( typeof formatter !== 'string' ) {
// If the format is a function, call it.
newFormat.push( '[' + formatter( momentDate ) + ']' );
} else {
// Otherwise, add as a formatting string.
newFormat.push( formatter );
}
} else {
newFormat.push( '[' + char + ']' );
}
}
// Join with [] between to separate characters, and replace
// unneeded separators with static text.
return momentDate.format( newFormat.join( '[]' ) );
}
/**
* Formats a date (like `date()` in PHP).
*
* @param {string} dateFormat PHP-style formatting string.
* See php.net/date.
* @param {Moment | Date | string | undefined} dateValue Date object or string, parsable
* by moment.js.
* @param {string | number | undefined} timezone Timezone to output result in or a
* UTC offset. Defaults to timezone from
* site.
*
* @see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
* @see https://en.wikipedia.org/wiki/ISO_8601#Time_offsets_from_UTC
*
* @return {string} Formatted date in English.
*/
export function date( dateFormat, dateValue = new Date(), timezone ) {
const dateMoment = buildMoment( dateValue, timezone );
return format( dateFormat, dateMoment );
}
/**
* Formats a date (like `date()` in PHP), in the UTC timezone.
*
* @param {string} dateFormat PHP-style formatting string.
* See php.net/date.
* @param {Moment | Date | string | undefined} dateValue Date object or string,
* parsable by moment.js.
*
* @return {string} Formatted date in English.
*/
export function gmdate( dateFormat, dateValue = new Date() ) {
const dateMoment = momentLib( dateValue ).utc();
return format( dateFormat, dateMoment );
}
/**
* Formats a date (like `wp_date()` in PHP), translating it into site's locale.
*
* Backward Compatibility Notice: if `timezone` is set to `true`, the function
* behaves like `gmdateI18n`.
*
* @param {string} dateFormat PHP-style formatting string.
* See php.net/date.
* @param {Moment | Date | string | undefined} dateValue Date object or string, parsable by
* moment.js.
* @param {string | number | boolean | undefined} timezone Timezone to output result in or a
* UTC offset. Defaults to timezone from
* site. Notice: `boolean` is effectively
* deprecated, but still supported for
* backward compatibility reasons.
*
* @see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
* @see https://en.wikipedia.org/wiki/ISO_8601#Time_offsets_from_UTC
*
* @return {string} Formatted date.
*/
export function dateI18n( dateFormat, dateValue = new Date(), timezone ) {
if ( true === timezone ) {
return gmdateI18n( dateFormat, dateValue );
}
if ( false === timezone ) {
timezone = undefined;
}
const dateMoment = buildMoment( dateValue, timezone );
dateMoment.locale( settings.l10n.locale );
return format( dateFormat, dateMoment );
}
/**
* Formats a date (like `wp_date()` in PHP), translating it into site's locale
* and using the UTC timezone.
*
* @param {string} dateFormat PHP-style formatting string.
* See php.net/date.
* @param {Moment | Date | string | undefined} dateValue Date object or string,
* parsable by moment.js.
*
* @return {string} Formatted date.
*/
export function gmdateI18n( dateFormat, dateValue = new Date() ) {
const dateMoment = momentLib( dateValue ).utc();
dateMoment.locale( settings.l10n.locale );
return format( dateFormat, dateMoment );
}
/**
* Check whether a date is considered in the future according to the WordPress settings.
*
* @param {string} dateValue Date String or Date object in the Defined WP Timezone.
*
* @return {boolean} Is in the future.
*/
export function isInTheFuture( dateValue ) {
const now = momentLib.tz( WP_ZONE );
const momentObject = momentLib.tz( dateValue, WP_ZONE );
return momentObject.isAfter( now );
}
/**
* Create and return a JavaScript Date Object from a date string in the WP timezone.
*
* @param {string?} dateString Date formatted in the WP timezone.
*
* @return {Date} Date
*/
export function getDate( dateString ) {
if ( ! dateString ) {
return momentLib.tz( WP_ZONE ).toDate();
}
return momentLib.tz( dateString, WP_ZONE ).toDate();
}
/**
* Returns a human-readable time difference between two dates, like human_time_diff() in PHP.
*
* @param {Moment | Date | string} from From date, in the WP timezone.
* @param {Moment | Date | string | undefined} to To date, formatted in the WP timezone.
*
* @return {string} Human-readable time difference.
*/
export function humanTimeDiff( from, to ) {
const fromMoment = momentLib.tz( from, WP_ZONE );
const toMoment = to ? momentLib.tz( to, WP_ZONE ) : momentLib.tz( WP_ZONE );
return fromMoment.from( toMoment );
}
/**
* Creates a moment instance using the given timezone or, if none is provided, using global settings.
*
* @param {Moment | Date | string | undefined} dateValue Date object or string, parsable
* by moment.js.
* @param {string | number | undefined} timezone Timezone to output result in or a
* UTC offset. Defaults to timezone from
* site.
*
* @see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
* @see https://en.wikipedia.org/wiki/ISO_8601#Time_offsets_from_UTC
*
* @return {Moment} a moment instance.
*/
function buildMoment( dateValue, timezone = '' ) {
const dateMoment = momentLib( dateValue );
if ( timezone && ! isUTCOffset( timezone ) ) {
// The ! isUTCOffset() check guarantees that timezone is a string.
return dateMoment.tz( /** @type {string} */ ( timezone ) );
}
if ( timezone && isUTCOffset( timezone ) ) {
return dateMoment.utcOffset( timezone );
}
if ( settings.timezone.string ) {
return dateMoment.tz( settings.timezone.string );
}
return dateMoment.utcOffset( +settings.timezone.offset );
}
/**
* Returns whether a certain UTC offset is valid or not.
*
* @param {number|string} offset a UTC offset.
*
* @return {boolean} whether a certain UTC offset is valid or not.
*/
function isUTCOffset( offset ) {
if ( 'number' === typeof offset ) {
return true;
}
return VALID_UTC_OFFSET.test( offset );
}
setupWPTimezone();

662
node_modules/@wordpress/date/src/test/index.js generated vendored Normal file
View File

@@ -0,0 +1,662 @@
/**
* Internal dependencies
*/
import {
getSettings,
date as dateNoI18n,
dateI18n,
getDate,
gmdate,
gmdateI18n,
isInTheFuture,
setSettings,
humanTimeDiff,
} from '../';
describe( 'isInTheFuture', () => {
it( 'should return true if the date is in the future', () => {
// Create a Date object 1 minute in the future.
const date = new Date( Number( getDate() ) + 1000 * 60 );
expect( isInTheFuture( date ) ).toBe( true );
} );
it( 'should return false if the date is in the past', () => {
// Create a Date object 1 minute in the past.
const date = new Date( Number( getDate() ) - 1000 * 60 );
expect( isInTheFuture( date ) ).toBe( false );
} );
it( 'should ignore the timezone', () => {
const settings = getSettings();
// Set a timezone in the future.
setSettings( {
...settings,
timezone: { offset: '4', string: '' },
} );
// Create a Date object 1 minute in the past.
let date = new Date( Number( getDate() ) - 1000 * 60 );
expect( isInTheFuture( date ) ).toBe( false );
// Create a Date object 1 minute in the future.
date = new Date( Number( getDate() ) + 1000 * 60 );
expect( isInTheFuture( date ) ).toBe( true );
// Restore default settings.
setSettings( settings );
} );
} );
describe( 'Function date', () => {
test.each( [
[ 'j/n/y', '18/6/19' ],
[ 'd/m/y', '18/06/19' ],
[ 'D j M Y', 'Tue 18 Jun 2019' ],
[ 'l jS F Y', 'Tuesday 18th June 2019' ],
[ 'N w', '2 2' ],
[ 'z', '168' ],
[ 'W', '25' ],
[ 't', '30' ],
[ 'L', '0' ],
[ 'o', '2019' ],
[ 'g:i a', '11:00 am' ],
[ 'h:i A', '11:00 AM' ],
[ 'G:i:s', '11:00:00' ],
[ 'H:i:s', '11:00:00' ],
[ 'B', '499' ],
[ 'u', '000000' ],
[ 'v', '000' ],
[ 'e I T', 'Coordinated Universal Time 0 UTC' ],
[ 'O P Z', '+0000 +00:00 0' ],
[ 'c', '2019-06-18T11:00:00+00:00' ],
[ 'r', 'Tue, 18 Jun 2019 11:00:00 +0000' ],
[ 'U', '1560855600' ],
] )(
'should format date as "%s", ignoring locale settings',
( formatString, expected ) => {
const settings = getSettings();
// Simulate different locale.
const l10n = settings.l10n;
setSettings( {
...settings,
l10n: {
...l10n,
locale: 'es',
months: l10n.months.map( ( month ) => `es_${ month }` ),
monthsShort: l10n.monthsShort.map(
( month ) => `es_${ month }`
),
weekdays: l10n.weekdays.map(
( weekday ) => `es_${ weekday }`
),
weekdaysShort: l10n.weekdaysShort.map(
( weekday ) => `es_${ weekday }`
),
},
} );
// Check.
const formattedDate = dateNoI18n(
formatString,
'2019-06-18T11:00:00.000Z'
);
expect( formattedDate ).toBe( expected );
// Restore default settings.
setSettings( settings );
}
);
it( 'should format date into a date that uses sites timezone, if no timezone was provided and theres a site timezone set', () => {
const settings = getSettings();
// Simulate different timezone.
setSettings( {
...settings,
timezone: { offset: -4, string: 'America/New_York' },
} );
// Check.
const winterFormattedDate = dateNoI18n(
'Y-m-d H:i',
'2019-01-18T11:00:00.000Z'
);
expect( winterFormattedDate ).toBe( '2019-01-18 06:00' );
const summerFormattedDate = dateNoI18n(
'Y-m-d H:i',
'2019-06-18T11:00:00.000Z'
);
expect( summerFormattedDate ).toBe( '2019-06-18 07:00' );
// Restore default settings.
setSettings( settings );
} );
it( 'should format date into a date that uses sites UTC offset setting, if no timezone was provided and there isnt a timezone set in the site', () => {
const settings = getSettings();
// Simulate different timezone.
setSettings( {
...settings,
timezone: { offset: -4, string: '' },
} );
// Check.
const winterFormattedDate = dateNoI18n(
'Y-m-d H:i',
'2019-01-18T11:00:00.000Z'
);
expect( winterFormattedDate ).toBe( '2019-01-18 07:00' );
const summerFormattedDate = dateNoI18n(
'Y-m-d H:i',
'2019-06-18T11:00:00.000Z'
);
expect( summerFormattedDate ).toBe( '2019-06-18 07:00' );
// Restore default settings.
setSettings( settings );
} );
it( 'should format date into a date that uses the given timezone, if said timezone is valid', () => {
const settings = getSettings();
// Simulate different timezone.
setSettings( {
...settings,
timezone: { offset: -4, string: 'America/New_York' },
} );
// Check.
const formattedDate = dateNoI18n(
'Y-m-d H:i',
'2019-06-18T11:00:00.000Z',
'Asia/Macau'
);
expect( formattedDate ).toBe( '2019-06-18 19:00' );
// Restore default settings.
setSettings( settings );
} );
it( 'should format date into a date that uses the given UTC offset, if given timezone is actually a UTC offset', () => {
const settings = getSettings();
// Simulate different timezone.
setSettings( {
...settings,
timezone: { offset: -4, string: 'America/New_York' },
} );
// Check.
let formattedDate;
formattedDate = dateNoI18n(
'Y-m-d H:i',
'2019-06-18T11:00:00.000Z',
'+08:00'
);
expect( formattedDate ).toBe( '2019-06-18 19:00' );
formattedDate = dateNoI18n(
'Y-m-d H:i',
'2019-06-18T11:00:00.000Z',
8
);
expect( formattedDate ).toBe( '2019-06-18 19:00' );
formattedDate = dateNoI18n(
'Y-m-d H:i',
'2019-06-18T11:00:00.000Z',
480
);
expect( formattedDate ).toBe( '2019-06-18 19:00' );
// Restore default settings.
setSettings( settings );
} );
} );
describe( 'Function gmdate', () => {
test.each( [
[ 'j/n/y', '18/6/19' ],
[ 'd/m/y', '18/06/19' ],
[ 'D j M Y', 'Tue 18 Jun 2019' ],
[ 'l jS F Y', 'Tuesday 18th June 2019' ],
[ 'N w', '2 2' ],
[ 'z', '168' ],
[ 'W', '25' ],
[ 't', '30' ],
[ 'L', '0' ],
[ 'o', '2019' ],
[ 'g:i a', '11:00 am' ],
[ 'h:i A', '11:00 AM' ],
[ 'G:i:s', '11:00:00' ],
[ 'H:i:s', '11:00:00' ],
[ 'B', '499' ],
[ 'u', '000000' ],
[ 'v', '000' ],
[ 'e I T', 'Coordinated Universal Time 0 UTC' ],
[ 'O P Z', '+0000 +00:00 0' ],
[ 'c', '2019-06-18T11:00:00+00:00' ],
[ 'r', 'Tue, 18 Jun 2019 11:00:00 +0000' ],
[ 'U', '1560855600' ],
] )(
'should format date as "%s", ignoring locale settings',
( formatString, expected ) => {
const settings = getSettings();
// Simulate different locale.
const l10n = settings.l10n;
setSettings( {
...settings,
l10n: {
...l10n,
locale: 'es',
months: l10n.months.map( ( month ) => `es_${ month }` ),
monthsShort: l10n.monthsShort.map(
( month ) => `es_${ month }`
),
weekdays: l10n.weekdays.map(
( weekday ) => `es_${ weekday }`
),
weekdaysShort: l10n.weekdaysShort.map(
( weekday ) => `es_${ weekday }`
),
},
} );
// Check.
const formattedDate = gmdate(
formatString,
'2019-06-18T11:00:00.000Z'
);
expect( formattedDate ).toBe( expected );
// Restore default settings.
setSettings( settings );
}
);
it( 'should format date into a UTC date', () => {
const settings = getSettings();
// Simulate different timezone.
setSettings( {
...settings,
timezone: { offset: -4, string: 'America/New_York' },
} );
// Check.
const formattedDate = gmdate( 'Y-m-d H:i', '2019-06-18T11:00:00.000Z' );
expect( formattedDate ).toBe( '2019-06-18 11:00' );
// Restore default settings.
setSettings( settings );
} );
} );
describe( 'Function dateI18n', () => {
test.each( [
[ 'j/n/y', '18/6/19' ],
[ 'd/m/y', '18/06/19' ],
[ 'D j M Y', 'es_Tue 18 es_Jun 2019' ],
[ 'l jS F Y', 'es_Tuesday 18th es_June 2019' ], // Day ordinal should be in English, matching wp_date().
[ 'N w', '2 2' ],
[ 'z', '168' ],
[ 'W', '25' ],
[ 't', '30' ],
[ 'L', '0' ],
[ 'o', '2019' ],
[ 'g:i a', '11:00 am' ],
[ 'h:i A', '11:00 AM' ],
[ 'G:i:s', '11:00:00' ],
[ 'H:i:s', '11:00:00' ],
[ 'B', '499' ],
[ 'u', '000000' ],
[ 'v', '000' ],
[ 'e I T', 'Coordinated Universal Time 0 UTC' ],
[ 'O P Z', '+0000 +00:00 0' ],
[ 'c', '2019-06-18T11:00:00+00:00' ],
[ 'r', 'Tue, 18 Jun 2019 11:00:00 +0000' ], // Day and month should be in English, as per RFC 2822.
[ 'U', '1560855600' ],
] )(
'should format date as "%s", using locale settings',
( formatString, expected ) => {
const settings = getSettings();
// Simulate different locale.
const l10n = settings.l10n;
setSettings( {
...settings,
l10n: {
...l10n,
locale: 'es',
months: l10n.months.map( ( month ) => `es_${ month }` ),
monthsShort: l10n.monthsShort.map(
( month ) => `es_${ month }`
),
weekdays: l10n.weekdays.map(
( weekday ) => `es_${ weekday }`
),
weekdaysShort: l10n.weekdaysShort.map(
( weekday ) => `es_${ weekday }`
),
},
} );
// Check.
const formattedDate = dateI18n(
formatString,
'2019-06-18T11:00:00.000Z',
true
);
expect( formattedDate ).toBe( expected );
// Restore default settings.
setSettings( settings );
}
);
it( 'should format date into a date that uses sites timezone, if no timezone was provided and theres a site timezone set', () => {
const settings = getSettings();
// Simulate different timezone.
setSettings( {
...settings,
timezone: { offset: -4, string: 'America/New_York' },
} );
// Check.
const winterFormattedDate = dateI18n(
'Y-m-d H:i',
'2019-01-18T11:00:00.000Z'
);
expect( winterFormattedDate ).toBe( '2019-01-18 06:00' );
const summerFormattedDate = dateI18n(
'Y-m-d H:i',
'2019-06-18T11:00:00.000Z'
);
expect( summerFormattedDate ).toBe( '2019-06-18 07:00' );
// Restore default settings.
setSettings( settings );
} );
it( 'should format date into a date that uses sites UTC offset setting, if no timezone was provided and there isnt a timezone set in the site', () => {
const settings = getSettings();
// Simulate different timezone.
setSettings( {
...settings,
timezone: { offset: -4, string: '' },
} );
// Check.
const winterFormattedDate = dateI18n(
'Y-m-d H:i',
'2019-01-18T11:00:00.000Z'
);
expect( winterFormattedDate ).toBe( '2019-01-18 07:00' );
const summerFormattedDate = dateI18n(
'Y-m-d H:i',
'2019-06-18T11:00:00.000Z'
);
expect( summerFormattedDate ).toBe( '2019-06-18 07:00' );
// Restore default settings.
setSettings( settings );
} );
it( 'should format date into a date that uses the given timezone, if said timezone is valid', () => {
const settings = getSettings();
// Simulate different timezone.
setSettings( {
...settings,
timezone: { offset: -4, string: 'America/New_York' },
} );
// Check.
const formattedDate = dateI18n(
'Y-m-d H:i',
'2019-06-18T11:00:00.000Z',
'Asia/Macau'
);
expect( formattedDate ).toBe( '2019-06-18 19:00' );
// Restore default settings.
setSettings( settings );
} );
it( 'should format date into a date that uses the given UTC offset, if given timezone is actually a UTC offset', () => {
const settings = getSettings();
// Simulate different timezone.
setSettings( {
...settings,
timezone: { offset: -4, string: 'America/New_York' },
} );
// Check.
let formattedDate;
formattedDate = dateI18n(
'Y-m-d H:i',
'2019-06-18T11:00:00.000Z',
'+08:00'
);
expect( formattedDate ).toBe( '2019-06-18 19:00' );
formattedDate = dateI18n( 'Y-m-d H:i', '2019-06-18T11:00:00.000Z', 8 );
expect( formattedDate ).toBe( '2019-06-18 19:00' );
formattedDate = dateI18n(
'Y-m-d H:i',
'2019-06-18T11:00:00.000Z',
480
);
expect( formattedDate ).toBe( '2019-06-18 19:00' );
// Restore default settings.
setSettings( settings );
} );
it( 'should format date into a UTC date if `gmt` is set to `true`', () => {
const settings = getSettings();
// Simulate different timezone.
setSettings( {
...settings,
timezone: { offset: -4, string: 'America/New_York' },
} );
// Check.
const formattedDate = dateI18n(
'Y-m-d H:i',
'2019-06-18T11:00:00.000Z',
true
);
expect( formattedDate ).toBe( '2019-06-18 11:00' );
// Restore default settings.
setSettings( settings );
} );
it( 'should format date into a date that uses sites timezone if `gmt` is set to `false`', () => {
const settings = getSettings();
// Simulate different timezone.
setSettings( {
...settings,
timezone: { offset: -4, string: 'America/New_York' },
} );
// Check.
const formattedDate = dateI18n(
'Y-m-d H:i',
'2019-06-18T11:00:00.000Z',
false
);
expect( formattedDate ).toBe( '2019-06-18 07:00' );
// Restore default settings.
setSettings( settings );
} );
} );
describe( 'Function gmdateI18n', () => {
test.each( [
[ 'j/n/y', '18/6/19' ],
[ 'd/m/y', '18/06/19' ],
[ 'D j M Y', 'es_Tue 18 es_Jun 2019' ],
[ 'l jS F Y', 'es_Tuesday 18th es_June 2019' ], // Day ordinal should be in English, matching wp_date().
[ 'N w', '2 2' ],
[ 'z', '168' ],
[ 'W', '25' ],
[ 't', '30' ],
[ 'L', '0' ],
[ 'o', '2019' ],
[ 'g:i a', '11:00 am' ],
[ 'h:i A', '11:00 AM' ],
[ 'G:i:s', '11:00:00' ],
[ 'H:i:s', '11:00:00' ],
[ 'B', '499' ],
[ 'u', '000000' ],
[ 'v', '000' ],
[ 'e I T', 'Coordinated Universal Time 0 UTC' ],
[ 'O P Z', '+0000 +00:00 0' ],
[ 'c', '2019-06-18T11:00:00+00:00' ],
[ 'r', 'Tue, 18 Jun 2019 11:00:00 +0000' ], // Day and month should be in English, as per RFC 2822.
[ 'U', '1560855600' ],
] )(
'should format date as "%s", using locale settings',
( formatString, expected ) => {
const settings = getSettings();
// Simulate different locale.
const l10n = settings.l10n;
setSettings( {
...settings,
l10n: {
...l10n,
locale: 'es',
months: l10n.months.map( ( month ) => `es_${ month }` ),
monthsShort: l10n.monthsShort.map(
( month ) => `es_${ month }`
),
weekdays: l10n.weekdays.map(
( weekday ) => `es_${ weekday }`
),
weekdaysShort: l10n.weekdaysShort.map(
( weekday ) => `es_${ weekday }`
),
},
} );
// Check.
const formattedDate = gmdateI18n(
formatString,
'2019-06-18T11:00:00.000Z'
);
expect( formattedDate ).toBe( expected );
// Restore default settings.
setSettings( settings );
}
);
it( 'should format date into a UTC date', () => {
const settings = getSettings();
// Simulate different timezone.
setSettings( {
...settings,
timezone: { offset: -4, string: 'America/New_York' },
} );
// Check.
const formattedDate = gmdateI18n(
'Y-m-d H:i',
'2019-06-18T11:00:00.000Z'
);
expect( formattedDate ).toBe( '2019-06-18 11:00' );
// Restore default settings.
setSettings( settings );
} );
} );
describe( 'Moment.js Localization', () => {
it( 'should change the relative time strings', () => {
const settings = getSettings();
// Change the locale strings for tests.
setSettings( {
...settings,
l10n: {
...settings.l10n,
relative: {
...settings.l10n.relative,
mm: '%d localized minutes',
hh: '%d localized hours',
},
},
} );
// Get the freshly changed setings.
const newSettings = getSettings();
// Test the unchanged values.
expect( newSettings.l10n.locale ).toBe( settings.l10n.locale );
// Test the changed values.
expect( newSettings.l10n.relative.mm ).toBe( '%d localized minutes' );
expect( newSettings.l10n.relative.hh ).toBe( '%d localized hours' );
// Restore default settings.
setSettings( settings );
} );
describe( 'humanTimeDiff', () => {
it( 'should return human readable time differences in the past', () => {
expect(
humanTimeDiff(
'2023-04-28T11:00:00.000Z',
'2023-04-28T12:00:00.000Z'
)
).toBe( 'an hour ago' );
expect(
humanTimeDiff(
'2023-04-28T11:00:00.000Z',
'2023-04-28T13:00:00.000Z'
)
).toBe( '2 hours ago' );
expect(
humanTimeDiff(
'2023-04-28T11:00:00.000Z',
'2023-04-30T13:00:00.000Z'
)
).toBe( '2 days ago' );
} );
it( 'should return human readable time differences in the future', () => {
// Future.
const now = new Date();
const twoHoursLater = new Date(
now.getTime() + 2 * 60 * 60 * 1000
);
expect( humanTimeDiff( twoHoursLater ) ).toBe( 'in 2 hours' );
const twoDaysLater = new Date(
now.getTime() + 2 * 24 * 60 * 60 * 1000
); // Adding 2 days in milliseconds
expect( humanTimeDiff( twoDaysLater ) ).toBe( 'in 2 days' );
} );
} );
} );