Merge "HTMLMultiSelectField: Add 'dropdown' option for 'mw-chosen' behavior and document"
[lhc/web/wiklou.git] / resources / src / mediawiki.widgets / mw.widgets.CalendarWidget.js
index d5e5b96..3daa70a 100644 (file)
@@ -19,6 +19,8 @@
         *
         * @constructor
         * @param {Object} [config] Configuration options
+        * @cfg {boolean} [lazyInitOnToggle=false] Don't build most of the interface until
+        *     `.toggle( true )` is called. Meant to be used when the calendar is not immediately visible.
         * @cfg {string} [precision='day'] Date precision to use, 'day' or 'month'
         * @cfg {string|null} [date=null] Day or month date (depending on `precision`), in the format
         *     'YYYY-MM-DD' or 'YYYY-MM'. When null, the calendar will show today's date, but not select
@@ -36,6 +38,7 @@
                OO.ui.mixin.FloatableElement.call( this, config );
 
                // Properties
+               this.lazyInitOnToggle = !!config.lazyInitOnToggle;
                this.precision = config.precision || 'day';
                // Currently selected date (day or month)
                this.date = null;
                this.$bodyOuterWrapper = $( '<div>' ).addClass( 'mw-widget-calendarWidget-body-outer-wrapper' );
                this.$bodyWrapper = $( '<div>' ).addClass( 'mw-widget-calendarWidget-body-wrapper' );
                this.$body = $( '<div>' ).addClass( 'mw-widget-calendarWidget-body' );
-               this.labelButton = new OO.ui.ButtonWidget( {
-                       tabIndex: -1,
-                       label: '',
-                       framed: false,
-                       classes: [ 'mw-widget-calendarWidget-labelButton' ]
-               } );
-               this.upButton = new OO.ui.ButtonWidget( {
-                       tabIndex: -1,
-                       framed: false,
-                       icon: 'collapse',
-                       classes: [ 'mw-widget-calendarWidget-upButton' ]
-               } );
-               this.prevButton = new OO.ui.ButtonWidget( {
-                       tabIndex: -1,
-                       framed: false,
-                       icon: 'previous',
-                       classes: [ 'mw-widget-calendarWidget-prevButton' ]
-               } );
-               this.nextButton = new OO.ui.ButtonWidget( {
-                       tabIndex: -1,
-                       framed: false,
-                       icon: 'next',
-                       classes: [ 'mw-widget-calendarWidget-nextButton' ]
-               } );
 
                // Events
-               this.labelButton.connect( this, { click: 'onUpButtonClick' } );
-               this.upButton.connect( this, { click: 'onUpButtonClick' } );
-               this.prevButton.connect( this, { click: 'onPrevButtonClick' } );
-               this.nextButton.connect( this, { click: 'onNextButtonClick' } );
                this.$element.on( {
                        focus: this.onFocus.bind( this ),
                        mousedown: this.onClick.bind( this ),
                this.$element
                        .addClass( 'mw-widget-calendarWidget' )
                        .append( this.$header, this.$bodyOuterWrapper.append( this.$bodyWrapper.append( this.$body ) ) );
-               this.$header.append(
-                       this.prevButton.$element,
-                       this.nextButton.$element,
-                       this.upButton.$element,
-                       this.labelButton.$element
-               );
+               if ( !this.lazyInitOnToggle ) {
+                       this.buildHeaderButtons();
+               }
                this.setDate( config.date !== undefined ? config.date : null );
        };
 
         * internally and for dates accepted by #setDate and returned by #getDate.
         *
         * @private
-        * @returns {string} Format
+        * @return {string} Format
         */
        mw.widgets.CalendarWidget.prototype.getDateFormat = function () {
                return {
         * Get the date precision this calendar uses, 'day' or 'month'.
         *
         * @private
-        * @returns {string} Precision, 'day' or 'month'
+        * @return {string} Precision, 'day' or 'month'
         */
        mw.widgets.CalendarWidget.prototype.getPrecision = function () {
                return this.precision;
         * Get list of possible display layers.
         *
         * @private
-        * @returns {string[]} Layers
+        * @return {string[]} Layers
         */
        mw.widgets.CalendarWidget.prototype.getDisplayLayers = function () {
                return [ 'month', 'year', 'duodecade' ].slice( this.precision === 'month' ? 1 : 0 );
                var items, today, selected, currentMonth, currentYear, currentDay, i, needsFade,
                        $bodyWrapper = this.$bodyWrapper;
 
+               if ( this.lazyInitOnToggle ) {
+                       // We're being called from the constructor and not being shown yet, do nothing
+                       return;
+               }
+
                if (
                        this.displayLayer === this.previousDisplayLayer &&
                        this.date === this.previousDate &&
                this.$body.on( 'click', this.onBodyClick.bind( this ) );
        };
 
+       /**
+        * Construct and display buttons to navigate the calendar.
+        *
+        * @private
+        */
+       mw.widgets.CalendarWidget.prototype.buildHeaderButtons = function () {
+               this.labelButton = new OO.ui.ButtonWidget( {
+                       tabIndex: -1,
+                       label: '',
+                       framed: false,
+                       classes: [ 'mw-widget-calendarWidget-labelButton' ]
+               } );
+               this.upButton = new OO.ui.ButtonWidget( {
+                       tabIndex: -1,
+                       framed: false,
+                       icon: 'collapse',
+                       classes: [ 'mw-widget-calendarWidget-upButton' ]
+               } );
+               this.prevButton = new OO.ui.ButtonWidget( {
+                       tabIndex: -1,
+                       framed: false,
+                       icon: 'previous',
+                       classes: [ 'mw-widget-calendarWidget-prevButton' ]
+               } );
+               this.nextButton = new OO.ui.ButtonWidget( {
+                       tabIndex: -1,
+                       framed: false,
+                       icon: 'next',
+                       classes: [ 'mw-widget-calendarWidget-nextButton' ]
+               } );
+
+               this.labelButton.connect( this, { click: 'onUpButtonClick' } );
+               this.upButton.connect( this, { click: 'onUpButtonClick' } );
+               this.prevButton.connect( this, { click: 'onPrevButtonClick' } );
+               this.nextButton.connect( this, { click: 'onNextButtonClick' } );
+
+               this.$header.append(
+                       this.prevButton.$element,
+                       this.nextButton.$element,
+                       this.upButton.$element,
+                       this.labelButton.$element
+               );
+       };
+
        /**
         * Handle click events on the "up" button, switching to less precise view.
         *
         * Get current date, in the format 'YYYY-MM-DD' or 'YYYY-MM', depending on precision. Digits will
         * not be localised.
         *
-        * @returns {string|null} Date string
+        * @return {string|null} Date string
         */
        mw.widgets.CalendarWidget.prototype.getDate = function () {
                return this.date;
         * @inheritdoc
         */
        mw.widgets.CalendarWidget.prototype.toggle = function ( visible ) {
+               if ( this.lazyInitOnToggle && visible ) {
+                       this.lazyInitOnToggle = false;
+                       this.buildHeaderButtons();
+                       this.updateUI();
+               }
+
                // Parent method
                mw.widgets.CalendarWidget.parent.prototype.toggle.call( this, visible );