Customize: Allow 0:00-0:59 in date/time control when 24-hour time used.
* Let min hour be 0 and max be 23 in 24-hour time; let min hour be 1 and max be 12 in 12-hour time. * Show error notification when an invalid date value is provided, not just when not a future date. * Fix translation of custom validity message. * Start checking for validity after all inputs have been initially populated. * Remove support for being able to enter 24:00. * Cease forcing date input elements from being casted to integers, to allow for invalid inputs to be detected. Props westonruter, Presskopp, peterwilsoncc, atachibana for testing. See #39896, #28721. Fixes #42373. git-svn-id: https://develop.svn.wordpress.org/trunk@42042 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
parent
a9405baf66
commit
8f661ef667
|
@ -5542,7 +5542,7 @@
|
||||||
control.inputElements = {};
|
control.inputElements = {};
|
||||||
control.invalidDate = false;
|
control.invalidDate = false;
|
||||||
|
|
||||||
_.bindAll( control, 'populateSetting', 'updateDaysForMonth', 'updateMinutesForHour', 'populateDateInputs' );
|
_.bindAll( control, 'populateSetting', 'updateDaysForMonth', 'populateDateInputs' );
|
||||||
|
|
||||||
if ( ! control.setting ) {
|
if ( ! control.setting ) {
|
||||||
throw new Error( 'Missing setting' );
|
throw new Error( 'Missing setting' );
|
||||||
|
@ -5552,34 +5552,35 @@
|
||||||
var input = $( this ), component, element;
|
var input = $( this ), component, element;
|
||||||
component = input.data( 'component' );
|
component = input.data( 'component' );
|
||||||
element = new api.Element( input );
|
element = new api.Element( input );
|
||||||
if ( 'meridian' === component ) {
|
|
||||||
element.validate = function( value ) {
|
|
||||||
if ( 'am' !== value && 'pm' !== value ) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
element.validate = function( value ) {
|
|
||||||
var val = parseInt( value, 10 );
|
|
||||||
if ( isNaN( val ) ) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return val;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
element.bind( control.populateSetting );
|
|
||||||
control.inputElements[ component ] = element;
|
control.inputElements[ component ] = element;
|
||||||
control.elements.push( element );
|
control.elements.push( element );
|
||||||
|
|
||||||
|
// Add invalid date error once user changes (and has blurred the input).
|
||||||
|
input.on( 'change', function() {
|
||||||
|
if ( control.invalidDate ) {
|
||||||
|
control.notifications.add( new api.Notification( 'invalid_date', {
|
||||||
|
message: api.l10n.invalidDate
|
||||||
|
} ) );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
// Remove the error immediately after validity change.
|
||||||
|
input.on( 'input', _.debounce( function() {
|
||||||
|
if ( ! control.invalidDate ) {
|
||||||
|
control.notifications.remove( 'invalid_date' );
|
||||||
|
}
|
||||||
|
} ) );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
control.inputElements.month.bind( control.updateDaysForMonth );
|
control.inputElements.month.bind( control.updateDaysForMonth );
|
||||||
control.inputElements.year.bind( control.updateDaysForMonth );
|
control.inputElements.year.bind( control.updateDaysForMonth );
|
||||||
if ( control.params.includeTime ) {
|
|
||||||
control.inputElements.hour.bind( control.updateMinutesForHour );
|
|
||||||
}
|
|
||||||
control.populateDateInputs();
|
control.populateDateInputs();
|
||||||
control.setting.bind( control.populateDateInputs );
|
control.setting.bind( control.populateDateInputs );
|
||||||
|
|
||||||
|
// Start populating setting after inputs have been populated.
|
||||||
|
_.each( control.inputElements, function( element ) {
|
||||||
|
element.bind( control.populateSetting );
|
||||||
|
} );
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -5629,7 +5630,7 @@
|
||||||
* @return {boolean} If date input fields has error.
|
* @return {boolean} If date input fields has error.
|
||||||
*/
|
*/
|
||||||
validateInputs: function validateInputs() {
|
validateInputs: function validateInputs() {
|
||||||
var control = this, errorMessage, components;
|
var control = this, components, validityInput;
|
||||||
|
|
||||||
control.invalidDate = false;
|
control.invalidDate = false;
|
||||||
|
|
||||||
|
@ -5638,25 +5639,41 @@
|
||||||
components.push( 'hour', 'minute' );
|
components.push( 'hour', 'minute' );
|
||||||
}
|
}
|
||||||
|
|
||||||
_.each( components, function( component ) {
|
_.find( components, function( component ) {
|
||||||
var element, el, max, min, value;
|
var element, max, min, value;
|
||||||
|
|
||||||
|
element = control.inputElements[ component ];
|
||||||
|
validityInput = element.element.get( 0 );
|
||||||
|
max = parseInt( element.element.attr( 'max' ), 10 );
|
||||||
|
min = parseInt( element.element.attr( 'min' ), 10 );
|
||||||
|
value = parseInt( element(), 10 );
|
||||||
|
control.invalidDate = isNaN( value ) || value > max || value < min;
|
||||||
|
|
||||||
if ( ! control.invalidDate ) {
|
if ( ! control.invalidDate ) {
|
||||||
element = control.inputElements[ component ];
|
validityInput.setCustomValidity( '' );
|
||||||
el = element.element.get( 0 );
|
|
||||||
max = parseInt( element.element.attr( 'max' ), 10 );
|
|
||||||
min = parseInt( element.element.attr( 'min' ), 10 );
|
|
||||||
value = element();
|
|
||||||
control.invalidDate = value > max || value < min;
|
|
||||||
errorMessage = control.invalidDate ? api.l10n.invalid + ' ' + component : '';
|
|
||||||
|
|
||||||
el.setCustomValidity( errorMessage );
|
|
||||||
if ( ! control.section() || api.section.has( control.section() ) && api.section( control.section() ).expanded() ) {
|
|
||||||
_.result( el, 'reportValidity' );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return control.invalidDate;
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
if ( control.inputElements.meridian && ! control.invalidDate ) {
|
||||||
|
validityInput = control.inputElements.meridian.element.get( 0 );
|
||||||
|
if ( 'am' !== control.inputElements.meridian.get() && 'pm' !== control.inputElements.meridian.get() ) {
|
||||||
|
control.invalidDate = true;
|
||||||
|
} else {
|
||||||
|
validityInput.setCustomValidity( '' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( control.invalidDate ) {
|
||||||
|
validityInput.setCustomValidity( api.l10n.invalidValue );
|
||||||
|
} else {
|
||||||
|
validityInput.setCustomValidity( '' );
|
||||||
|
}
|
||||||
|
if ( ! control.section() || api.section.has( control.section() ) && api.section( control.section() ).expanded() ) {
|
||||||
|
_.result( validityInput, 'reportValidity' );
|
||||||
|
}
|
||||||
|
|
||||||
return control.invalidDate;
|
return control.invalidDate;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -5669,44 +5686,20 @@
|
||||||
updateDaysForMonth: function updateDaysForMonth() {
|
updateDaysForMonth: function updateDaysForMonth() {
|
||||||
var control = this, daysInMonth, year, month, day;
|
var control = this, daysInMonth, year, month, day;
|
||||||
|
|
||||||
month = control.inputElements.month();
|
month = parseInt( control.inputElements.month(), 10 );
|
||||||
year = control.inputElements.year();
|
year = parseInt( control.inputElements.year(), 10 );
|
||||||
day = control.inputElements.day();
|
day = parseInt( control.inputElements.day(), 10 );
|
||||||
|
|
||||||
if ( month && year ) {
|
if ( month && year ) {
|
||||||
daysInMonth = new Date( year, month, 0 ).getDate();
|
daysInMonth = new Date( year, month, 0 ).getDate();
|
||||||
control.inputElements.day.element.attr( 'max', daysInMonth );
|
control.inputElements.day.element.attr( 'max', daysInMonth );
|
||||||
|
|
||||||
if ( day > daysInMonth ) {
|
if ( day > daysInMonth ) {
|
||||||
control.inputElements.day( daysInMonth );
|
control.inputElements.day( String( daysInMonth ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates number of minutes according to the hour selected.
|
|
||||||
*
|
|
||||||
* @since 4.9.0
|
|
||||||
* @return {void}
|
|
||||||
*/
|
|
||||||
updateMinutesForHour: function updateMinutesForHour() {
|
|
||||||
var control = this, maxHours = 24, minuteEl;
|
|
||||||
|
|
||||||
if ( control.inputElements.meridian ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
minuteEl = control.inputElements.minute.element;
|
|
||||||
|
|
||||||
if ( maxHours === control.inputElements.hour() ) {
|
|
||||||
control.inputElements.minute( 0 );
|
|
||||||
minuteEl.data( 'default-max', minuteEl.attr( 'max' ) );
|
|
||||||
minuteEl.attr( 'max', '0' );
|
|
||||||
} else if ( minuteEl.data( 'default-max' ) ) {
|
|
||||||
minuteEl.attr( 'max', minuteEl.data( 'default-max' ) );
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populate setting value from the inputs.
|
* Populate setting value from the inputs.
|
||||||
*
|
*
|
||||||
|
@ -5745,7 +5738,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
getElementValue = function( component ) {
|
getElementValue = function( component ) {
|
||||||
var value = control.inputElements[ component ].get();
|
var value = parseInt( control.inputElements[ component ].get(), 10 );
|
||||||
|
|
||||||
if ( _.contains( [ 'month', 'day', 'hour', 'minute' ], component ) ) {
|
if ( _.contains( [ 'month', 'day', 'hour', 'minute' ], component ) ) {
|
||||||
value = pad( value, 2 );
|
value = pad( value, 2 );
|
||||||
|
@ -5822,7 +5815,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
_.each( control.inputElements, function( element, component ) {
|
_.each( control.inputElements, function( element, component ) {
|
||||||
element.set( parsed[ component ] );
|
if ( 'meridian' === component || parseInt( parsed[ component ], 10 ) !== parseInt( element(), 10 ) ) {
|
||||||
|
element.set( parsed[ component ] );
|
||||||
|
}
|
||||||
} );
|
} );
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -141,8 +141,9 @@ class WP_Customize_Date_Time_Control extends WP_Customize_Control {
|
||||||
<legend class="title-time"><?php esc_html_e( 'Time' ); ?></legend>
|
<legend class="title-time"><?php esc_html_e( 'Time' ); ?></legend>
|
||||||
<div class="time-fields clear">
|
<div class="time-fields clear">
|
||||||
<label for="{{ idPrefix }}date-time-hour" class="screen-reader-text"><?php esc_html_e( 'Hour' ); ?></label>
|
<label for="{{ idPrefix }}date-time-hour" class="screen-reader-text"><?php esc_html_e( 'Hour' ); ?></label>
|
||||||
<# var maxHour = data.twelveHourFormat ? 12 : 24; #>
|
<# var maxHour = data.twelveHourFormat ? 12 : 23; #>
|
||||||
<input id="{{ idPrefix }}date-time-hour" type="number" size="2" autocomplete="off" class="date-input hour" data-component="hour" min="1" max="{{ maxHour }}">
|
<# var minHour = data.twelveHourFormat ? 1 : 0; #>
|
||||||
|
<input id="{{ idPrefix }}date-time-hour" type="number" size="2" autocomplete="off" class="date-input hour" data-component="hour" min="{{ minHour }}" max="{{ maxHour }}">
|
||||||
<span class="time-special-char date-time-separator">:</span>
|
<span class="time-special-char date-time-separator">:</span>
|
||||||
<label for="{{ idPrefix }}date-time-minute" class="screen-reader-text"><?php esc_html_e( 'Minute' ); ?></label>
|
<label for="{{ idPrefix }}date-time-minute" class="screen-reader-text"><?php esc_html_e( 'Minute' ); ?></label>
|
||||||
<input id="{{ idPrefix }}date-time-minute" type="number" size="2" autocomplete="off" class="date-input minute" data-component="minute" min="0" max="59">
|
<input id="{{ idPrefix }}date-time-minute" type="number" size="2" autocomplete="off" class="date-input minute" data-component="minute" min="0" max="59">
|
||||||
|
|
|
@ -599,6 +599,8 @@ function wp_default_scripts( &$scripts ) {
|
||||||
esc_url( admin_url( 'theme-install.php' ) )
|
esc_url( admin_url( 'theme-install.php' ) )
|
||||||
),
|
),
|
||||||
'publishSettings' => __( 'Publish Settings' ),
|
'publishSettings' => __( 'Publish Settings' ),
|
||||||
|
'invalidDate' => __( 'Invalid date.' ),
|
||||||
|
'invalidValue' => __( 'Invalid value.' ),
|
||||||
) );
|
) );
|
||||||
$scripts->add( 'customize-selective-refresh', "/wp-includes/js/customize-selective-refresh$suffix.js", array( 'jquery', 'wp-util', 'customize-preview' ), false, 1 );
|
$scripts->add( 'customize-selective-refresh', "/wp-includes/js/customize-selective-refresh$suffix.js", array( 'jquery', 'wp-util', 'customize-preview' ), false, 1 );
|
||||||
|
|
||||||
|
|
|
@ -732,11 +732,15 @@ jQuery( window ).load( function (){
|
||||||
meridian = control.inputElements.meridian;
|
meridian = control.inputElements.meridian;
|
||||||
|
|
||||||
year( '23' );
|
year( '23' );
|
||||||
assert.equal( typeof year(), 'number', 'Should always return integer' );
|
assert.ok( control.invalidDate );
|
||||||
|
|
||||||
|
year( '2100' );
|
||||||
month( '8' );
|
month( '8' );
|
||||||
month( 'test' );
|
assert.ok( ! control.invalidDate );
|
||||||
assert.equal( 8, month(), 'Should not accept text' );
|
day( 'test' );
|
||||||
|
assert.ok( control.invalidDate );
|
||||||
|
day( '3' );
|
||||||
|
assert.ok( ! control.invalidDate );
|
||||||
|
|
||||||
// Test control.parseDateTime();
|
// Test control.parseDateTime();
|
||||||
control.params.twelveHourFormat = false;
|
control.params.twelveHourFormat = false;
|
||||||
|
@ -784,12 +788,13 @@ jQuery( window ).load( function (){
|
||||||
// Test control.updateDaysForMonth();.
|
// Test control.updateDaysForMonth();.
|
||||||
year( 2017 );
|
year( 2017 );
|
||||||
month( 2 );
|
month( 2 );
|
||||||
|
day( 28 );
|
||||||
|
assert.ok( ! control.invalidDate );
|
||||||
day( 31 );
|
day( 31 );
|
||||||
control.updateDaysForMonth();
|
assert.ok( control.invalidDate );
|
||||||
assert.deepEqual( day(), 28, 'Should update to the correct days' );
|
|
||||||
|
|
||||||
day( 20 );
|
day( 20 );
|
||||||
assert.deepEqual( day(), 20, 'Should not update if its less the correct number of days' );
|
assert.equal( day(), 20, 'Should not update if its less the correct number of days' );
|
||||||
|
|
||||||
// Test control.convertHourToTwentyFourHourFormat().
|
// Test control.convertHourToTwentyFourHourFormat().
|
||||||
assert.equal( control.convertHourToTwentyFourHourFormat( 11, 'pm' ), 23 );
|
assert.equal( control.convertHourToTwentyFourHourFormat( 11, 'pm' ), 23 );
|
||||||
|
@ -854,16 +859,6 @@ jQuery( window ).load( function (){
|
||||||
year( 2016 );
|
year( 2016 );
|
||||||
assert.notOk( control.isFutureDate() );
|
assert.notOk( control.isFutureDate() );
|
||||||
|
|
||||||
/**
|
|
||||||
* Test control.updateMinutesForHour().
|
|
||||||
* Run this at the end or else the above tests may fail.
|
|
||||||
*/
|
|
||||||
hour( 24 );
|
|
||||||
minute( 32 );
|
|
||||||
control.inputElements.meridian = false; // Because it works only when the time is twenty four hour format.
|
|
||||||
control.updateMinutesForHour();
|
|
||||||
assert.deepEqual( minute(), 0 );
|
|
||||||
|
|
||||||
// Tear Down.
|
// Tear Down.
|
||||||
wp.customize.control.remove( controlId );
|
wp.customize.control.remove( controlId );
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue