Simon Egersand
2016-12-21 cf1e721e0d7c69b5ce55978c213ef463ab477ebc
Properly set lower/higher case with timeFormat

According to the moment.js API using a lower case 'a' in timeFormat
should make it use lower case 'am' and 'pm', and vice versa with higher
case. This commit also adds tests for these two specific cases and
formats the code with consistency in mind.
2 files modified
113 ■■■■■ changed files
src/TimeView.js 96 ●●●● patch | view | raw | blame | history
tests/datetime-spec.js 17 ●●●●● patch | view | raw | blame | history
src/TimeView.js
@@ -5,28 +5,32 @@
var DOM = React.DOM;
var DateTimePickerTime = React.createClass({
    getInitialState: function(){
    getInitialState: function() {
        return this.calculateState( this.props );
    },
    calculateState: function( props ){
    calculateState: function( props ) {
        var date = props.selectedDate || props.viewDate,
            format = props.timeFormat,
            counters = []
        ;
        if ( format.indexOf('H') !== -1 || format.indexOf('h') !== -1 ){
        if ( format.toLowerCase().indexOf('h') !== -1 ) {
            counters.push('hours');
            if ( format.indexOf('m') !== -1 ){
            if ( format.indexOf('m') !== -1 ) {
                counters.push('minutes');
                if ( format.indexOf('s') !== -1 ){
                if ( format.indexOf('s') !== -1 ) {
                    counters.push('seconds');
                }
            }
        }
        var daypart = false;
        if ( this.props.timeFormat.indexOf(' A') !== -1  && this.state !== null ){
            daypart = ( this.state.hours >= 12 ) ? 'PM' : 'AM';
        if ( this.state !== null && this.props.timeFormat.toLowerCase().indexOf(' a') !== -1 ) {
            if ( this.props.timeFormat.indexOf(' A') !== -1 ) {
                daypart = ( this.state.hours >= 12 ) ? 'PM' : 'AM';
            } else {
                daypart = ( this.state.hours >= 12 ) ? 'pm' : 'am';
            }
        }
        return {
@@ -38,29 +42,29 @@
            counters: counters
        };
    },
    renderCounter: function( type ){
    renderCounter: function( type ) {
        if (type !== 'daypart') {
            var value = this.state[ type ];
            if (type === 'hours' && this.props.timeFormat.indexOf(' A') !== -1) {
            if ( type === 'hours' && this.props.timeFormat.toLowerCase().indexOf(' a') !== -1 ) {
                value = (value - 1) % 12 + 1;
                if (value === 0) {
                    value = 12;
                }
            }
            return DOM.div({ key: type, className: 'rdtCounter'}, [
                DOM.span({ key:'up', className: 'rdtBtn', onMouseDown: this.onStartClicking( 'increase', type ) }, '▲' ),
                DOM.div({ key:'c', className: 'rdtCount' }, value ),
                DOM.span({ key:'do', className: 'rdtBtn', onMouseDown: this.onStartClicking( 'decrease', type ) }, '▼' )
            return DOM.div( { key: type, className: 'rdtCounter' }, [
                DOM.span( { key: 'up', className: 'rdtBtn', onMouseDown: this.onStartClicking( 'increase', type ) }, '▲' ),
                DOM.div( { key: 'c', className: 'rdtCount' }, value ),
                DOM.span( { key: 'do', className: 'rdtBtn', onMouseDown: this.onStartClicking( 'decrease', type ) }, '▼' )
            ]);
        }
        return '';
    },
    renderDayPart: function() {
        return DOM.div({ className: 'rdtCounter', key: 'dayPart'}, [
            DOM.span({ key:'up', className: 'rdtBtn', onMouseDown: this.onStartClicking( 'toggleDayPart', 'hours') }, '▲' ),
            DOM.div({ key: this.state.daypart, className: 'rdtCount'}, this.state.daypart ),
            DOM.span({ key:'do', className: 'rdtBtn', onMouseDown: this.onStartClicking( 'toggleDayPart', 'hours') }, '▼' )
        return DOM.div( { key: 'dayPart', className: 'rdtCounter' }, [
            DOM.span( { key: 'up', className: 'rdtBtn', onMouseDown: this.onStartClicking( 'toggleDayPart', 'hours') }, '▲' ),
            DOM.div( { key: this.state.daypart, className: 'rdtCount' }, this.state.daypart ),
            DOM.span( { key: 'do', className: 'rdtBtn', onMouseDown: this.onStartClicking( 'toggleDayPart', 'hours') }, '▼' )
        ]);
    },
    render: function() {
@@ -68,9 +72,9 @@
            counters = []
        ;
        this.state.counters.forEach( function(c){
        this.state.counters.forEach( function(c) {
            if ( counters.length )
                counters.push( DOM.div( {key: 'sep' + counters.length, className: 'rdtCounterSeparator' }, ':' ));
                counters.push( DOM.div( { key: 'sep' + counters.length, className: 'rdtCounterSeparator' }, ':' ));
            counters.push( me.renderCounter( c ) );
        });
@@ -78,20 +82,20 @@
            counters.push( me.renderDayPart() );
        }
        if ( this.state.counters.length === 3 && this.props.timeFormat.indexOf('S') !== -1 ){
            counters.push( DOM.div( {className: 'rdtCounterSeparator', key: 'sep5' }, ':' ));
        if ( this.state.counters.length === 3 && this.props.timeFormat.indexOf('S') !== -1 ) {
            counters.push( DOM.div( { className: 'rdtCounterSeparator', key: 'sep5' }, ':' ) );
            counters.push(
                DOM.div( {className: 'rdtCounter rdtMilli', key:'m'},
                    DOM.input({ value: this.state.milliseconds, type: 'text', onChange: this.updateMilli })
                DOM.div( { className: 'rdtCounter rdtMilli', key: 'm' },
                    DOM.input( { value: this.state.milliseconds, type: 'text', onChange: this.updateMilli } )
                    )
                );
        }
        return DOM.div( {className: 'rdtTime'},
        return DOM.div( { className: 'rdtTime' },
            DOM.table( {}, [
                this.renderHeader(),
                DOM.tbody({key: 'b'}, DOM.tr({}, DOM.td({},
                    DOM.div({ className: 'rdtCounters' }, counters )
                DOM.tbody( { key: 'b'}, DOM.tr({}, DOM.td({},
                    DOM.div( { className: 'rdtCounters' }, counters )
                )))
            ])
        );
@@ -112,7 +116,7 @@
            seconds: {
                min: 0,
                max: 59,
                step: 1,
                step: 1
            },
            milliseconds: {
                min: 0,
@@ -121,45 +125,45 @@
            }
        };
        ['hours', 'minutes', 'seconds', 'milliseconds'].forEach(function(type) {
            assign(me.timeConstraints[type], me.props.timeConstraints[type]);
            assign(me.timeConstraints[ type ], me.props.timeConstraints[ type ]);
        });
        this.setState( this.calculateState( this.props ) );
    },
    componentWillReceiveProps: function( nextProps ){
    componentWillReceiveProps: function( nextProps ) {
        this.setState( this.calculateState( nextProps ) );
    },
    updateMilli: function( e ){
    updateMilli: function( e ) {
        var milli = parseInt( e.target.value, 10 );
        if ( milli === e.target.value && milli >= 0 && milli < 1000 ){
        if ( milli === e.target.value && milli >= 0 && milli < 1000 ) {
            this.props.setTime( 'milliseconds', milli );
            this.setState({ milliseconds: milli });
            this.setState( { milliseconds: milli } );
        }
    },
    renderHeader: function(){
    renderHeader: function() {
        if ( !this.props.dateFormat )
            return null;
        var date = this.props.selectedDate || this.props.viewDate;
        return DOM.thead({ key: 'h'}, DOM.tr({},
            DOM.th( {className: 'rdtSwitch', colSpan: 4, onClick: this.props.showView('days')}, date.format( this.props.dateFormat ) )
        return DOM.thead( { key: 'h' }, DOM.tr({},
            DOM.th( { className: 'rdtSwitch', colSpan: 4, onClick: this.props.showView( 'days' ) }, date.format( this.props.dateFormat ) )
        ));
    },
    onStartClicking: function( action, type ){
    onStartClicking: function( action, type ) {
        var me = this;
        return function(){
        return function() {
            var update = {};
            update[ type ] = me[ action ]( type );
            me.setState( update );
            me.timer = setTimeout( function(){
                me.increaseTimer = setInterval( function(){
            me.timer = setTimeout( function() {
                me.increaseTimer = setInterval( function() {
                    update[ type ] = me[ action ]( type );
                    me.setState( update );
                }, 70);
            }, 500);
            me.mouseUpListener = function(){
            me.mouseUpListener = function() {
                clearTimeout( me.timer );
                clearInterval( me.increaseTimer );
                me.props.setTime( type, me.state[ type ] );
@@ -175,25 +179,25 @@
        seconds: 2,
        milliseconds: 3
    },
    toggleDayPart: function( type ){ // type is always 'hours'
    toggleDayPart: function( type ) { // type is always 'hours'
        var value = parseInt(this.state[ type ], 10) + 12;
        if ( value > this.timeConstraints[ type ].max )
            value = this.timeConstraints[ type ].min + (value - (this.timeConstraints[ type ].max + 1));
            value = this.timeConstraints[ type ].min + ( value - (this.timeConstraints[ type ].max + 1 ) );
        return this.pad( type, value );
    },
    increase: function( type ){
    increase: function( type ) {
        var value = parseInt(this.state[ type ], 10) + this.timeConstraints[ type ].step;
        if ( value > this.timeConstraints[ type ].max )
            value = this.timeConstraints[ type ].min + ( value - ( this.timeConstraints[ type ].max  + 1) );
            value = this.timeConstraints[ type ].min + ( value - ( this.timeConstraints[ type ].max + 1 ) );
        return this.pad( type, value );
    },
    decrease: function( type ){
    decrease: function( type ) {
        var value = parseInt(this.state[ type ], 10) - this.timeConstraints[ type ].step;
        if ( value < this.timeConstraints[ type ].min )
            value = this.timeConstraints[ type ].max + 1 - ( this.timeConstraints[ type ].min - value );
        return this.pad( type, value );
    },
    pad: function( type, value ){
    pad: function( type, value ) {
        var str = value + '';
        while ( str.length < this.padValues[ type ] )
            str = '0' + str;
tests/datetime-spec.js
@@ -2,7 +2,6 @@
var DOM = require( './testdom');
DOM();
// Needs to be global to work in Travis CI
React = require('react');
ReactDOM = require('react-dom');
@@ -216,6 +215,22 @@
        assert.equal( view.querySelectorAll('.timeToggle').length, 0);
    });
    it( 'timeFormat with lowercase am', function(){
        var format = 'HH:mm:ss:SSS a',
            component = createDatetime({ value: date, timeFormat: format }),
            input = component.children[0]
            ;
        assert.notEqual( input.value.indexOf('am'), -1 );
    });
    it( 'timeFormat with uppercase AM', function(){
        var format = 'HH:mm:ss:SSS A',
            component = createDatetime({ value: date, timeFormat: format }),
            input = component.children[0]
            ;
        assert.notEqual( input.value.indexOf('AM'), -1 );
    });
    it( 'viewMode=years', function(){
        var component = createDatetime({ viewMode: 'years' }),
            view = dt.view()