Make WordPress Core

Changeset 42042


Ignore:
Timestamp:
10/30/2017 04:39:06 PM (8 years ago)
Author:
westonruter
Message:

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.

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/js/customize-controls.js

    r42040 r42042  
    55435543            control.invalidDate = false;
    55445544
    5545             _.bindAll( control, 'populateSetting', 'updateDaysForMonth', 'updateMinutesForHour', 'populateDateInputs' );
     5545            _.bindAll( control, 'populateSetting', 'updateDaysForMonth', 'populateDateInputs' );
    55465546
    55475547            if ( ! control.setting ) {
     
    55535553                component = input.data( 'component' );
    55545554                element = new api.Element( input );
    5555                 if ( 'meridian' === component ) {
    5556                     element.validate = function( value ) {
    5557                         if ( 'am' !== value && 'pm' !== value ) {
    5558                             return null;
    5559                         }
    5560                         return value;
    5561                     };
    5562                 } else {
    5563                     element.validate = function( value ) {
    5564                         var val = parseInt( value, 10 );
    5565                         if ( isNaN( val ) ) {
    5566                             return null;
    5567                         }
    5568                         return val;
    5569                     };
    5570                 }
    5571                 element.bind( control.populateSetting );
    55725555                control.inputElements[ component ] = element;
    55735556                control.elements.push( element );
     5557
     5558                // Add invalid date error once user changes (and has blurred the input).
     5559                input.on( 'change', function() {
     5560                    if ( control.invalidDate ) {
     5561                        control.notifications.add( new api.Notification( 'invalid_date', {
     5562                            message: api.l10n.invalidDate
     5563                        } ) );
     5564                    }
     5565                } );
     5566
     5567                // Remove the error immediately after validity change.
     5568                input.on( 'input', _.debounce( function() {
     5569                    if ( ! control.invalidDate ) {
     5570                        control.notifications.remove( 'invalid_date' );
     5571                    }
     5572                } ) );
    55745573            } );
    55755574
    55765575            control.inputElements.month.bind( control.updateDaysForMonth );
    55775576            control.inputElements.year.bind( control.updateDaysForMonth );
    5578             if ( control.params.includeTime ) {
    5579                 control.inputElements.hour.bind( control.updateMinutesForHour );
    5580             }
    55815577            control.populateDateInputs();
    55825578            control.setting.bind( control.populateDateInputs );
     5579
     5580            // Start populating setting after inputs have been populated.
     5581            _.each( control.inputElements, function( element ) {
     5582                element.bind( control.populateSetting );
     5583            } );
    55835584        },
    55845585
     
    56305631         */
    56315632        validateInputs: function validateInputs() {
    5632             var control = this, errorMessage, components;
     5633            var control = this, components, validityInput;
    56335634
    56345635            control.invalidDate = false;
     
    56395640            }
    56405641
    5641             _.each( components, function( component ) {
    5642                 var element, el, max, min, value;
     5642            _.find( components, function( component ) {
     5643                var element, max, min, value;
     5644
     5645                element = control.inputElements[ component ];
     5646                validityInput = element.element.get( 0 );
     5647                max = parseInt( element.element.attr( 'max' ), 10 );
     5648                min = parseInt( element.element.attr( 'min' ), 10 );
     5649                value = parseInt( element(), 10 );
     5650                control.invalidDate = isNaN( value ) || value > max || value < min;
    56435651
    56445652                if ( ! control.invalidDate ) {
    5645                     element = control.inputElements[ component ];
    5646                     el = element.element.get( 0 );
    5647                     max = parseInt( element.element.attr( 'max' ), 10 );
    5648                     min = parseInt( element.element.attr( 'min' ), 10 );
    5649                     value = element();
    5650                     control.invalidDate = value > max || value < min;
    5651                     errorMessage = control.invalidDate ? api.l10n.invalid + ' ' + component : '';
    5652 
    5653                     el.setCustomValidity( errorMessage );
    5654                     if ( ! control.section() || api.section.has( control.section() ) && api.section( control.section() ).expanded() ) {
    5655                         _.result( el, 'reportValidity' );
    5656                     }
    5657                 }
     5653                    validityInput.setCustomValidity( '' );
     5654                }
     5655
     5656                return control.invalidDate;
    56585657            } );
     5658
     5659            if ( control.inputElements.meridian && ! control.invalidDate ) {
     5660                validityInput = control.inputElements.meridian.element.get( 0 );
     5661                if ( 'am' !== control.inputElements.meridian.get() && 'pm' !== control.inputElements.meridian.get() ) {
     5662                    control.invalidDate = true;
     5663                } else {
     5664                    validityInput.setCustomValidity( '' );
     5665                }
     5666            }
     5667
     5668            if ( control.invalidDate ) {
     5669                validityInput.setCustomValidity( api.l10n.invalidValue );
     5670            } else {
     5671                validityInput.setCustomValidity( '' );
     5672            }
     5673            if ( ! control.section() || api.section.has( control.section() ) && api.section( control.section() ).expanded() ) {
     5674                _.result( validityInput, 'reportValidity' );
     5675            }
    56595676
    56605677            return control.invalidDate;
     
    56705687            var control = this, daysInMonth, year, month, day;
    56715688
    5672             month = control.inputElements.month();
    5673             year = control.inputElements.year();
    5674             day = control.inputElements.day();
     5689            month = parseInt( control.inputElements.month(), 10 );
     5690            year = parseInt( control.inputElements.year(), 10 );
     5691            day = parseInt( control.inputElements.day(), 10 );
    56755692
    56765693            if ( month && year ) {
     
    56795696
    56805697                if ( day > daysInMonth ) {
    5681                     control.inputElements.day( daysInMonth );
    5682                 }
    5683             }
    5684         },
    5685 
    5686         /**
    5687          * Updates number of minutes according to the hour selected.
    5688          *
    5689          * @since 4.9.0
    5690          * @return {void}
    5691          */
    5692         updateMinutesForHour: function updateMinutesForHour() {
    5693             var control = this, maxHours = 24, minuteEl;
    5694 
    5695             if ( control.inputElements.meridian ) {
    5696                 return;
    5697             }
    5698 
    5699             minuteEl = control.inputElements.minute.element;
    5700 
    5701             if ( maxHours === control.inputElements.hour() ) {
    5702                 control.inputElements.minute( 0 );
    5703                 minuteEl.data( 'default-max', minuteEl.attr( 'max' ) );
    5704                 minuteEl.attr( 'max', '0' );
    5705             } else if ( minuteEl.data( 'default-max' ) ) {
    5706                 minuteEl.attr( 'max', minuteEl.data( 'default-max' ) );
     5698                    control.inputElements.day( String( daysInMonth ) );
     5699                }
    57075700            }
    57085701        },
     
    57465739
    57475740            getElementValue = function( component ) {
    5748                 var value = control.inputElements[ component ].get();
     5741                var value = parseInt( control.inputElements[ component ].get(), 10 );
    57495742
    57505743                if ( _.contains( [ 'month', 'day', 'hour', 'minute' ], component ) ) {
     
    58235816
    58245817            _.each( control.inputElements, function( element, component ) {
    5825                 element.set( parsed[ component ] );
     5818                if ( 'meridian' === component || parseInt( parsed[ component ], 10 ) !== parseInt( element(), 10 ) ) {
     5819                    element.set( parsed[ component ] );
     5820                }
    58265821            } );
    58275822
  • trunk/src/wp-includes/customize/class-wp-customize-date-time-control.php

    r41750 r42042  
    142142                    <div class="time-fields clear">
    143143                        <label for="{{ idPrefix }}date-time-hour" class="screen-reader-text"><?php esc_html_e( 'Hour' ); ?></label>
    144                         <# var maxHour = data.twelveHourFormat ? 12 : 24; #>
    145                         <input id="{{ idPrefix }}date-time-hour" type="number" size="2" autocomplete="off" class="date-input hour" data-component="hour" min="1" max="{{ maxHour }}">
     144                        <# var maxHour = data.twelveHourFormat ? 12 : 23; #>
     145                        <# var minHour = data.twelveHourFormat ? 1 : 0; #>
     146                        <input id="{{ idPrefix }}date-time-hour" type="number" size="2" autocomplete="off" class="date-input hour" data-component="hour" min="{{ minHour }}" max="{{ maxHour }}">
    146147                        <span class="time-special-char date-time-separator">:</span>
    147148                        <label for="{{ idPrefix }}date-time-minute" class="screen-reader-text"><?php esc_html_e( 'Minute' ); ?></label>
  • trunk/src/wp-includes/script-loader.php

    r42025 r42042  
    600600        ),
    601601        'publishSettings' => __( 'Publish Settings' ),
     602        'invalidDate'     => __( 'Invalid date.' ),
     603        'invalidValue'    => __( 'Invalid value.' ),
    602604    ) );
    603605    $scripts->add( 'customize-selective-refresh', "/wp-includes/js/customize-selective-refresh$suffix.js", array( 'jquery', 'wp-util', 'customize-preview' ), false, 1 );
  • trunk/tests/qunit/wp-admin/js/customize-controls.js

    r41750 r42042  
    733733
    734734        year( '23' );
    735         assert.equal( typeof year(), 'number', 'Should always return integer' );
    736 
     735        assert.ok( control.invalidDate );
     736
     737        year( '2100' );
    737738        month( '8' );
    738         month( 'test' );
    739         assert.equal( 8, month(), 'Should not accept text' );
     739        assert.ok( ! control.invalidDate );
     740        day( 'test' );
     741        assert.ok( control.invalidDate );
     742        day( '3' );
     743        assert.ok( ! control.invalidDate );
    740744
    741745        // Test control.parseDateTime();
     
    785789        year( 2017 );
    786790        month( 2 );
     791        day( 28 );
     792        assert.ok( ! control.invalidDate );
    787793        day( 31 );
    788         control.updateDaysForMonth();
    789         assert.deepEqual( day(), 28, 'Should update to the correct days' );
     794        assert.ok( control.invalidDate );
    790795
    791796        day( 20 );
    792         assert.deepEqual( day(), 20, 'Should not update if its less the correct number of days' );
     797        assert.equal( day(), 20, 'Should not update if its less the correct number of days' );
    793798
    794799        // Test control.convertHourToTwentyFourHourFormat().
     
    855860        assert.notOk( control.isFutureDate() );
    856861
    857         /**
    858          * Test control.updateMinutesForHour().
    859          * Run this at the end or else the above tests may fail.
    860          */
    861         hour( 24 );
    862         minute( 32 );
    863         control.inputElements.meridian = false; // Because it works only when the time is twenty four hour format.
    864         control.updateMinutesForHour();
    865         assert.deepEqual( minute(), 0 );
    866 
    867862        // Tear Down.
    868863        wp.customize.control.remove( controlId );
Note: See TracChangeset for help on using the changeset viewer.