Merge "DateTimeInputWidget: Only show calendar when focusing date components, not...
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Tue, 3 Jan 2017 20:27:47 +0000 (20:27 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Tue, 3 Jan 2017 20:27:48 +0000 (20:27 +0000)
1  2 
resources/src/mediawiki.widgets.datetime/DateTimeFormatter.js
resources/src/mediawiki.widgets.datetime/DateTimeInputWidget.js
resources/src/mediawiki.widgets.datetime/DiscordianDateTimeFormatter.js
resources/src/mediawiki.widgets.datetime/ProlepticGregorianDateTimeFormatter.js

         *  Defaults to the current date and time (with 0 milliseconds).
         */
        mw.widgets.datetime.DateTimeFormatter = function MwWidgetsDatetimeDateTimeFormatter( config ) {
 -              var statick = this.constructor[ 'static' ];
 -
 -              statick.setupDefaults();
 +              this.constructor.static.setupDefaults();
  
                config = $.extend( {
                        format: '@default',
                        local: false,
 -                      fullZones: statick.fullZones,
 -                      shortZones: statick.shortZones
 +                      fullZones: this.constructor.static.fullZones,
 +                      shortZones: this.constructor.static.shortZones
                }, config );
  
                // Mixin constructors
                OO.EventEmitter.call( this );
  
                // Properties
 -              if ( statick.formats[ config.format ] ) {
 -                      this.format = statick.formats[ config.format ];
 +              if ( this.constructor.static.formats[ config.format ] ) {
 +                      this.format = this.constructor.static.formats[ config.format ];
                } else {
                        this.format = config.format;
                }
@@@ -68,7 -70,7 +68,7 @@@
         * @inheritable
         * @property {Object}
         */
 -      mw.widgets.datetime.DateTimeFormatter[ 'static' ].formats = {};
 +      mw.widgets.datetime.DateTimeFormatter.static.formats = {};
  
        /**
         * Default time zone indicators
@@@ -77,7 -79,7 +77,7 @@@
         * @inheritable
         * @property {string[]}
         */
 -      mw.widgets.datetime.DateTimeFormatter[ 'static' ].fullZones = null;
 +      mw.widgets.datetime.DateTimeFormatter.static.fullZones = null;
  
        /**
         * Default abbreviated time zone indicators
@@@ -86,9 -88,9 +86,9 @@@
         * @inheritable
         * @property {string[]}
         */
 -      mw.widgets.datetime.DateTimeFormatter[ 'static' ].shortZones = null;
 +      mw.widgets.datetime.DateTimeFormatter.static.shortZones = null;
  
 -      mw.widgets.datetime.DateTimeFormatter[ 'static' ].setupDefaults = function () {
 +      mw.widgets.datetime.DateTimeFormatter.static.setupDefaults = function () {
                if ( !this.fullZones ) {
                        this.fullZones = [
                                mw.msg( 'timezone-utc' ),
                return this.local;
        };
  
 +      // eslint-disable-next-line valid-jsdoc
        /**
         * Toggle whether dates are in local time or UTC
         *
         *  - 'boolean': The field is a boolean.
         *  - 'toggleLocal': The field represents {@link #getLocal this.getLocal()}.
         *    Editing should directly call {@link #toggleLocal this.toggleLocal()}.
+        * @return {boolean} return.calendarComponent Whether this field is part of a calendar, e.g.
+        *  part of the date instead of the time.
         * @return {number} return.size Maximum number of characters in the field (when
         *  the 'intercalary' component is falsey). If 0, the field should be hidden entirely.
         * @return {Object.<string,number>} return.intercalarySize Map from
                                }
                                spec = {
                                        component: null,
+                                       calendarComponent: false,
                                        editable: false,
                                        type: 'static',
                                        value: params.slice( 1 ).join( '|' ),
                                                c = params[ 0 ] === '#' ? '' : ':';
                                                return {
                                                        component: 'zone',
+                                                       calendarComponent: false,
                                                        editable: true,
                                                        type: 'toggleLocal',
                                                        size: 5 + c.length,
                                        case 'full':
                                                spec = {
                                                        component: 'zone',
+                                                       calendarComponent: false,
                                                        editable: true,
                                                        type: 'toggleLocal',
                                                        values: params[ 0 ] === 'short' ? this.shortZones : this.fullZones,
         *  - 'clip': "Jan 32" => "Jan 31", "Feb 32" => "Feb 28" (or 29), "Feb 0" => "Feb 1", etc.
         * @return {Date} Adjusted date
         */
 -      mw.widgets.datetime.DateTimeFormatter.prototype.adjustComponent = function ( date /*, component, delta, mode */ ) {
 +      mw.widgets.datetime.DateTimeFormatter.prototype.adjustComponent = function ( date /* , component, delta, mode */ ) {
                // Should be overridden by subclass
                return date;
        };
                        calendar: {}
                }, config );
  
 +              // See InputWidget#reusePreInfuseDOM about config.$input
 +              if ( config.$input ) {
 +                      config.$input.addClass( 'oo-ui-element-hidden' );
 +              }
 +
                if ( $.isPlainObject( config.formatter ) && config.formatter.format === undefined ) {
                        config.formatter.format = '@' + config.type;
                }
  
        /* Static properties */
  
 -      mw.widgets.datetime.DateTimeInputWidget[ 'static' ].supportsSimpleLabel = false;
 +      mw.widgets.datetime.DateTimeInputWidget.static.supportsSimpleLabel = false;
  
        /* Events */
  
                                $field = $( '<span>' )
                                        .width( sz )
                                        .data( 'mw-widgets-datetime-dateTimeInputWidget-placeholder', placeholder );
+                               if ( spec.type !== 'static' ) {
+                                       $field.prop( 'tabIndex', -1 );
+                                       $field.on( 'focus', this.onFieldFocus.bind( this, $field ) );
+                               }
                                if ( spec.type === 'static' ) {
                                        $field.text( spec.value );
                                } else {
         * @private
         * @param {jQuery} $field
         * @param {jQuery.Event} e Key down event
 +       * @return {boolean} False to cancel the default event
         */
        mw.widgets.datetime.DateTimeInputWidget.prototype.onFieldKeyDown = function ( $field, e ) {
                var spec = $field.data( 'mw-widgets-datetime-dateTimeInputWidget-fieldSpec' );
         * @param {jQuery.Event} e Focus event
         */
        mw.widgets.datetime.DateTimeInputWidget.prototype.onFieldFocus = function ( $field ) {
+               var spec = $field.data( 'mw-widgets-datetime-dateTimeInputWidget-fieldSpec' );
                if ( !this.isDisabled() ) {
                        if ( this.getValueAsDate() === null ) {
                                this.setValue( this.formatter.getDefaultDate() );
                        }
  
                        if ( this.calendar ) {
-                               this.calendar.toggle( true );
+                               this.calendar.toggle( !!spec.calendarComponent );
                        }
                }
        };
         * @private
         * @param {jQuery} $field
         * @param {jQuery.Event} e Change event
 +       * @return {boolean} False to cancel the default event
         */
        mw.widgets.datetime.DateTimeInputWidget.prototype.onFieldWheel = function ( $field, e ) {
                var delta = 0,
@@@ -32,7 -32,7 +32,7 @@@
        /**
         * @inheritdoc
         */
 -      mw.widgets.datetime.DiscordianDateTimeFormatter[ 'static' ].formats = {
 +      mw.widgets.datetime.DiscordianDateTimeFormatter.static.formats = {
                '@time': '${hour|0}:${minute|0}:${second|0}',
                '@date': '$!{dow|full}${not-intercalary|1|, }${season|full}${not-intercalary|1| }${day|#}, ${year|#}',
                '@datetime': '$!{dow|full}${not-intercalary|1|, }${season|full}${not-intercalary|1| }${day|#}, ${year|#} ${hour|0}:${minute|0}:${second|0} $!{zone|short}',
@@@ -67,6 -67,7 +67,7 @@@
                        case 'year|#':
                                spec = {
                                        component: 'Year',
+                                       calendarComponent: true,
                                        type: 'number',
                                        size: 4,
                                        zeropad: false
@@@ -76,6 -77,7 +77,7 @@@
                        case 'season|#':
                                spec = {
                                        component: 'Season',
+                                       calendarComponent: true,
                                        type: 'number',
                                        size: 1,
                                        intercalarySize: { 1: 0 },
@@@ -86,6 -88,7 +88,7 @@@
                        case 'season|full':
                                spec = {
                                        component: 'Season',
+                                       calendarComponent: true,
                                        type: 'string',
                                        intercalarySize: { 1: 0 },
                                        values: {
                        case 'dow|full':
                                spec = {
                                        component: 'DOW',
+                                       calendarComponent: true,
                                        editable: false,
                                        type: 'string',
                                        intercalarySize: { 1: 0 },
                        case 'day|0':
                                spec = {
                                        component: 'Day',
+                                       calendarComponent: true,
                                        type: 'string',
                                        size: 2,
                                        intercalarySize: { 1: 13 },
                        case 'second|0':
                                spec = {
                                        component: tag.charAt( 0 ).toUpperCase() + tag.slice( 1 ),
+                                       calendarComponent: false,
                                        type: 'number',
                                        size: 2,
                                        zeropad: params[ 0 ] === '0'
                        case 'millisecond|0':
                                spec = {
                                        component: 'Millisecond',
+                                       calendarComponent: false,
                                        type: 'number',
                                        size: 3,
                                        zeropad: params[ 0 ] === '0'
@@@ -2,7 -2,7 +2,7 @@@
  
        /**
         * Provides various methods needed for formatting dates and times. This
-        * implementation implments the proleptic Gregorian calendar over years
+        * implementation implements the proleptic Gregorian calendar over years
         * 0000–9999.
         *
         * @class
         * @cfg {number} [weekStartsOn=0] What day the week starts on: 0 is Sunday, 1 is Monday, 6 is Saturday.
         */
        mw.widgets.datetime.ProlepticGregorianDateTimeFormatter = function MwWidgetsDatetimeProlepticGregorianDateTimeFormatter( config ) {
 -              var statick = this.constructor[ 'static' ];
 -
 -              statick.setupDefaults();
 +              this.constructor.static.setupDefaults();
  
                config = $.extend( {
                        weekStartsOn: 0,
 -                      hour12Periods: statick.hour12Periods
 +                      hour12Periods: this.constructor.static.hour12Periods
                }, config );
  
                if ( config.fullMonthNames && !config.shortMonthNames ) {
                        }.bind( this ) );
                }
                config = $.extend( {
 -                      fullMonthNames: statick.fullMonthNames,
 -                      shortMonthNames: statick.shortMonthNames,
 -                      fullDayNames: statick.fullDayNames,
 -                      shortDayNames: statick.shortDayNames,
 -                      dayLetters: statick.dayLetters
 +                      fullMonthNames: this.constructor.static.fullMonthNames,
 +                      shortMonthNames: this.constructor.static.shortMonthNames,
 +                      fullDayNames: this.constructor.static.fullDayNames,
 +                      shortDayNames: this.constructor.static.shortDayNames,
 +                      dayLetters: this.constructor.static.dayLetters
                }, config );
  
                // Parent constructor
@@@ -87,7 -89,7 +87,7 @@@
        /**
         * @inheritdoc
         */
 -      mw.widgets.datetime.ProlepticGregorianDateTimeFormatter[ 'static' ].formats = {
 +      mw.widgets.datetime.ProlepticGregorianDateTimeFormatter.static.formats = {
                '@time': '${hour|0}:${minute|0}:${second|0}',
                '@date': '$!{dow|short} ${day|#} ${month|short} ${year|#}',
                '@datetime': '$!{dow|short} ${day|#} ${month|short} ${year|#} ${hour|0}:${minute|0}:${second|0} $!{zone|short}',
         * @inheritable
         * @property {Object}
         */
 -      mw.widgets.datetime.ProlepticGregorianDateTimeFormatter[ 'static' ].fullMonthNames = null;
 +      mw.widgets.datetime.ProlepticGregorianDateTimeFormatter.static.fullMonthNames = null;
  
        /**
         * Default abbreviated month names.
         * @inheritable
         * @property {Object}
         */
 -      mw.widgets.datetime.ProlepticGregorianDateTimeFormatter[ 'static' ].shortMonthNames = null;
 +      mw.widgets.datetime.ProlepticGregorianDateTimeFormatter.static.shortMonthNames = null;
  
        /**
         * Default full day of week names.
         * @inheritable
         * @property {Object}
         */
 -      mw.widgets.datetime.ProlepticGregorianDateTimeFormatter[ 'static' ].fullDayNames = null;
 +      mw.widgets.datetime.ProlepticGregorianDateTimeFormatter.static.fullDayNames = null;
  
        /**
         * Default abbreviated day of week names.
         * @inheritable
         * @property {Object}
         */
 -      mw.widgets.datetime.ProlepticGregorianDateTimeFormatter[ 'static' ].shortDayNames = null;
 +      mw.widgets.datetime.ProlepticGregorianDateTimeFormatter.static.shortDayNames = null;
  
        /**
         * Default day letters.
         * @inheritable
         * @property {string[]}
         */
 -      mw.widgets.datetime.ProlepticGregorianDateTimeFormatter[ 'static' ].dayLetters = null;
 +      mw.widgets.datetime.ProlepticGregorianDateTimeFormatter.static.dayLetters = null;
  
        /**
         * Default AM/PM indicators
         * @inheritable
         * @property {string[]}
         */
 -      mw.widgets.datetime.ProlepticGregorianDateTimeFormatter[ 'static' ].hour12Periods = null;
 +      mw.widgets.datetime.ProlepticGregorianDateTimeFormatter.static.hour12Periods = null;
  
 -      mw.widgets.datetime.ProlepticGregorianDateTimeFormatter[ 'static' ].setupDefaults = function () {
 -              mw.widgets.datetime.DateTimeFormatter[ 'static' ].setupDefaults.call( this );
 +      mw.widgets.datetime.ProlepticGregorianDateTimeFormatter.static.setupDefaults = function () {
 +              mw.widgets.datetime.DateTimeFormatter.static.setupDefaults.call( this );
  
                if ( this.fullMonthNames && !this.shortMonthNames ) {
                        this.shortMonthNames = {};
                        case 'year|0':
                                spec = {
                                        component: 'year',
+                                       calendarComponent: true,
                                        type: 'number',
                                        size: 4,
                                        zeropad: params[ 0 ] === '0'
                        case 'month|full':
                                spec = {
                                        component: 'month',
+                                       calendarComponent: true,
                                        type: 'string',
                                        values: params[ 0 ] === 'short' ? this.shortMonthNames : this.fullMonthNames
                                };
                        case 'dow|full':
                                spec = {
                                        component: 'dow',
+                                       calendarComponent: true,
                                        editable: false,
                                        type: 'string',
                                        values: params[ 0 ] === 'short' ? this.shortDayNames : this.fullDayNames
                        case 'month|0':
                        case 'day|#':
                        case 'day|0':
+                               spec = {
+                                       component: tag,
+                                       calendarComponent: true,
+                                       type: 'number',
+                                       size: 2,
+                                       zeropad: params[ 0 ] === '0'
+                               };
+                               break;
                        case 'hour|#':
                        case 'hour|0':
                        case 'minute|#':
                        case 'second|0':
                                spec = {
                                        component: tag,
+                                       calendarComponent: false,
                                        type: 'number',
                                        size: 2,
                                        zeropad: params[ 0 ] === '0'
                        case 'hour|012':
                                spec = {
                                        component: 'hour12',
+                                       calendarComponent: false,
                                        type: 'number',
                                        size: 2,
                                        zeropad: params[ 0 ] === '012'
                        case 'hour|period':
                                spec = {
                                        component: 'hour12period',
+                                       calendarComponent: false,
                                        type: 'boolean',
                                        values: this.hour12Periods
                                };
                        case 'millisecond|0':
                                spec = {
                                        component: 'millisecond',
+                                       calendarComponent: false,
                                        type: 'number',
                                        size: 3,
                                        zeropad: params[ 0 ] === '0'