File indexing completed on 2024-06-02 06:06:32

0001 /*
0002 The jQuery UI Month Picker Version 3.0.4
0003 https://github.com/KidSysco/jquery-ui-month-picker/
0004 
0005 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
0006 This program is free software: you can redistribute it and/or modify
0007 it under the terms of the GNU General Public License as published by
0008 the Free Software Foundation, either version 3 of the License, or
0009 (at your option) any later version.
0010 
0011 This program is distributed in the hope that it will be useful,
0012 but WITHOUT ANY WARRANTY; without even the implied warranty of
0013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014 GNU General Public License for more details.
0015 
0016 You should have received a copy of the GNU General Public License
0017 along with this program.  If not, see
0018 <http://www.gnu.org/licenses/gpl-3.0.txt>.
0019 */
0020 
0021 (function ($, window, document, Date) {
0022     'use strict';
0023 
0024     var _setupErr = 'MonthPicker Error: ';
0025     // This test must be run before any rererence is made to jQuery.
0026     // In case the user didn't load jQuery or jQuery UI the plugin
0027     // will fail before it get's to this test + there is no reason
0028     // to perform this test for every MonthPicker instance being created.
0029     if (!$ || !$.ui || !$.ui.button || !$.ui.datepicker) {
0030         alert(_setupErr + 'The jQuery UI button and datepicker plug-ins must be loaded.');
0031         return;
0032     }
0033 
0034     // Creates an alias to jQuery UI's .button() that dosen't
0035     // conflict with Bootstrap.js button (#35)
0036     $.widget.bridge('jqueryUIButton', $.ui.button);
0037 
0038     var _speeds = $.fx.speeds;
0039     var _eventsNs = '.MonthPicker';
0040     var _textfieldClass = 'month-year-input';
0041     var _clearHint = 'month-picker-clear-hint';
0042     var _iconClass = '.ui-button-icon-primary';
0043     var _disabledClass = 'month-picker-disabled';
0044     var _todayClass = 'ui-state-highlight';
0045     var _selectedClass = 'ui-state-active';
0046     var _defaultClass = 'ui-state-default';
0047     var _defaultPos = { my: 'left top+1', at: 'left bottom' };
0048     var _RTL_defaultPos = { my: 'right top+1', at: 'right bottom' };
0049     var _posErr = _setupErr + 'The jQuery UI position plug-in must be loaded.';
0050     var _badOptValErr = _setupErr + 'Unsupported % option value, supported values are: ';
0051     var _badMinMaxVal =  _setupErr + '"_" is not a valid %Month value.';
0052     var _openedInstance = null;
0053     var _hasPosition = !!$.ui.position;
0054     var _animVals = {
0055         Animation: ['slideToggle', 'fadeToggle', 'none'],
0056         ShowAnim: ['fadeIn', 'slideDown', 'none'],
0057         HideAnim: ['fadeOut', 'slideUp', 'none']
0058     };
0059     var _setOptionHooks = {
0060         ValidationErrorMessage: '_createValidationMessage',
0061         Disabled: '_setDisabledState',
0062         ShowIcon: '_updateButton',
0063         Button: '_updateButton',
0064         ShowOn: '_updateFieldEvents',
0065         IsRTL: '_setRTL',
0066         AltFormat: '_updateAlt',
0067         AltField: '_updateAlt',
0068         StartYear: '_setPickerYear',
0069         MinMonth: '_setMinMonth',
0070         MaxMonth: '_setMaxMonth',
0071         SelectedMonth: '_setSelectedMonth'
0072     };
0073     var $noop = $.noop;
0074     var $proxy = $.proxy;
0075     var $datepicker = $.datepicker;
0076     var click = 'click' + _eventsNs;
0077 
0078     function _toMonth(date) {
0079         return date.getMonth() + (date.getFullYear() * 12);
0080     }
0081 
0082     function _toYear(month) {
0083         return Math.floor(month / 12);
0084     }
0085 
0086     function _stayActive() {
0087         $(this).addClass(_selectedClass);
0088     }
0089 
0090     function _setActive( el, state ) {
0091         return el[ state ? 'on' : 'off' ]('mousenter mouseout',  _stayActive )
0092               .toggleClass(_selectedClass, state);
0093     }
0094 
0095     function _between(month, from, until) {
0096         return (!from || month >= from) && (!until || month <= until);
0097     }
0098 
0099     function _encodeMonth(_inst, _val) {
0100         if (_val === null) {
0101             return _val;
0102         } else if (_val instanceof Date) {
0103             return _toMonth(_val);
0104         } else if ($.isNumeric(_val)) {
0105             return _toMonth(new Date) + parseInt(_val, 10);
0106         }
0107 
0108         var _date = _inst._parseMonth(_val);
0109         if (_date) {
0110             return _toMonth(_date);
0111         }
0112 
0113         return _parsePeriod(_val);
0114     }
0115 
0116     function _event(_name, _inst) {
0117         return $proxy(_inst.options[_name] || $noop, _inst.element[0]);
0118     }
0119 
0120     function _parsePeriod(_val, _initDate) {
0121         // Parsing is done by replacing tokens in the value to form
0122         // a JSON object with it's keys and values reversed
0123         // (example '+1y +2m' will turn into {"+1":"y","+2":"m"})
0124         // After that we just revers the keys and values.
0125         var _json = $.trim(_val);
0126         _json = _json.replace(/y/i, '":"y"');
0127         _json = _json.replace(/m/i, '":"m"');
0128 
0129         try {
0130             var _rev = JSON.parse( '{"' + _json.replace(/ /g, ',"') + '}' ), obj = {};
0131 
0132             for (var key in _rev) {
0133                 obj[ _rev[key] ] = key;
0134             }
0135 
0136             var _month = _toMonth(new Date);
0137             _month += (parseInt(obj.m, 10) || 0);
0138             return _month + (parseInt(obj.y, 10) || 0) * 12;
0139         } catch (e) {
0140             return false;
0141         }
0142     }
0143 
0144     function _makeDefaultButton(options) {
0145         // this refers to the associated input field.
0146         return $('<span id="MonthPicker_Button_' + this.id + '" class="month-picker-open-button">' + options.i18n.buttonText + '</span>')
0147             .jqueryUIButton({
0148                 text: false,
0149                 icons: {
0150                     // Defaults to 'ui-icon-calculator'.
0151                     primary: options.ButtonIcon
0152                 }
0153             });
0154     }
0155 
0156     function _applyArrowButton($el, dir) {
0157         $el.jqueryUIButton('option', {
0158             icons: {
0159                 primary: 'ui-icon-circle-triangle-' + (dir ? 'w' : 'e')
0160             }
0161         });
0162     }
0163 
0164     function _isInline(elem) {
0165         return !elem.is('input');
0166     }
0167 
0168     $.MonthPicker = {
0169         VERSION: '3.0.4', // Added in version 2.4;
0170         i18n: {
0171             year: 'Year',
0172             prevYear: 'Previous Year',
0173             nextYear: 'Next Year',
0174             next12Years: 'Jump Forward 12 Years',
0175             prev12Years: 'Jump Back 12 Years',
0176             nextLabel: 'Next',
0177             prevLabel: 'Prev',
0178             buttonText: 'Open Month Chooser',
0179             jumpYears: 'Jump Years',
0180             backTo: 'Back to',
0181             months: ['Jan.', 'Feb.', 'Mar.', 'Apr.', 'May', 'June', 'July', 'Aug.', 'Sep.', 'Oct.', 'Nov.', 'Dec.']
0182         }
0183     };
0184 
0185     var _markup =
0186         '<div class="ui-widget-header month-picker-header ui-corner-all">' +
0187             '<table class="month-picker-year-table">' +
0188                 '<tr>' +
0189                     '<td class="month-picker-previous"><a /></td>' +
0190                     '<td class="month-picker-title"><a /></td>' +
0191                     '<td class="month-picker-next"><a /></td>' +
0192                 '</tr>' +
0193             '</table>' +
0194         '</div>' +
0195         '<div>' +
0196             '<table class="month-picker-month-table" />' +
0197         '</div>';
0198 
0199     // Groups state and functionallity to fade in the jump years hint
0200     // when the user mouses over the Year 2016 text.
0201     // NOTE: An invocation of this function:
0202     // 1: Is an independent instance with it's own unique state.
0203     // 2: Assumes that there is no previous hint applied to the
0204     //    button (it dosen't remove the existing hint).
0205     function _applyButtonHint(_button, _hintText) {
0206       var _speed = 125, _currentLabel, _startTimeout, _labelElem = $();
0207 
0208       _button.on('mouseenter' + _eventsNs + 'h', _prepareToStart);
0209 
0210       // Setp 1: Wait to make sure the user isn't just mousing over and
0211       // away from the button.
0212       // NOTE: If _fadeOutHint() is triggered on mouseleave before the
0213       // timeout is triggered the animation is canceled.
0214       function _prepareToStart() {
0215         _startTimeout = setTimeout(_fadeOutLabel, 175);
0216       }
0217 
0218       // Setp 2: Fade out the label (Year 2016) text to 45%.
0219       function _fadeOutLabel() {
0220         _startTimeout = null;
0221         _labelElem = $('span', _button).animate({ opacity: 0.45 }, _speed, _fadeInHint);
0222       }
0223 
0224       // Setp 3: Fade in the hint text (Jump years).
0225       function _fadeInHint() {
0226         _currentLabel = _labelElem.text();
0227         _labelElem.animate({ opacity: 1 }, _speed).text(_hintText);
0228       }
0229 
0230       _button.on('mouseleave' + _eventsNs + 'h', _fadeOutHint);
0231 
0232       function _fadeOutHint() {
0233         if (_startTimeout) {
0234           // If the user is just moving over and away from the button, cancel
0235           // the animation completely.
0236           clearTimeout(_startTimeout);
0237         } else {
0238           // Setp 4: Fade out the hint text (Jump years) to 45%.
0239           _labelElem = $('span', _button).animate({ opacity: 0.45 }, _speed, _fadeInLabel);
0240         }
0241       }
0242 
0243       // Setp 5: Fade in the label (Year 2016) text.
0244       function _fadeInLabel() {
0245         _labelElem.text( _currentLabel ).animate({opacity: 1}, _speed);
0246       }
0247 
0248       // Adds a function to the button elemene which is called when the
0249       // user clicks the button (the hint needs to be removed).
0250       _button.data(_clearHint, function() {
0251         clearTimeout(_startTimeout);
0252         _labelElem.stop().css({ opacity: 1 });
0253         _button.off(_eventsNs + 'h');
0254       });
0255     } // End _applyButtonHint()
0256 
0257     function _setDisabled(_button, _value) {
0258       var _btnWidget = _button.data('ui-button');
0259       if (_btnWidget.option('disabled') !== _value) {
0260         _btnWidget.option('disabled', _value);
0261       }
0262     }
0263 
0264     $.widget("KidSysco.MonthPicker", {
0265 
0266         /******* Properties *******/
0267 
0268         options: {
0269             i18n: {},
0270             IsRTL: false,
0271             Position: null,
0272             StartYear: null,
0273             ShowIcon: true,
0274             UseInputMask: false,
0275             ValidationErrorMessage: null,
0276             Disabled: false,
0277             MonthFormat: 'mm/yy',
0278             Animation: 'fadeToggle',
0279             ShowAnim: null,
0280             HideAnim: null,
0281             ShowOn: null,
0282             MinMonth: null,
0283             MaxMonth: null,
0284             Duration: 'normal',
0285             Button: _makeDefaultButton,
0286             ButtonIcon: 'ui-icon-calculator'
0287         },
0288 
0289         _monthPickerButton: $(),
0290         _validationMessage: $(),
0291         _selectedBtn: $(),
0292 
0293         /******* jQuery UI Widget Factory Overrides ********/
0294 
0295         _destroy: function () {
0296             var _elem = this.element;
0297             if ($.mask && this.options.UseInputMask) {
0298                 _elem.unmask();
0299 
0300                 if (!this.GetSelectedDate()) {
0301                     _elem.val('');
0302                 }
0303             }
0304 
0305             _elem.removeClass(_textfieldClass).off(_eventsNs);
0306 
0307             $(document).off(_eventsNs + this.uuid);
0308 
0309             this._monthPickerMenu.remove();
0310 
0311             var _button = this._monthPickerButton.off(click);
0312             if (this._removeOldBtn) {
0313                 _button.remove();
0314             }
0315 
0316             this._validationMessage.remove();
0317 
0318             if (_openedInstance === this) {
0319               _openedInstance = null;
0320             }
0321         },
0322 
0323         _setOption: function (key, value) {
0324             switch (key) {
0325                 case 'i18n':
0326                     // Pass a clone i18n object to the this._super.
0327                     value = $.extend({}, value);
0328                     break;
0329                 case 'Position':
0330                     if (!_hasPosition) {
0331                         alert(_posErr);
0332                         return;
0333                     }
0334                     break;
0335                 case 'MonthFormat':
0336                     var date = this.GetSelectedDate();
0337                     if (date) {
0338                         this.element.val( this.FormatMonth(date, value) );
0339                     }
0340                     break;
0341             }
0342 
0343             // Make sure the user passed in a valid Animation, ShowAnim and HideAnim options values.
0344             if (key in _animVals && $.inArray(value, _animVals[key]) === -1) {
0345                 alert(_badOptValErr.replace(/%/, key) + _animVals[key]);
0346                 return;
0347             }
0348 
0349             // In jQuery UI 1.8, manually invoke the _setOption method from the base widget.
0350             //$.Widget.prototype._setOption.apply(this, arguments);
0351             // In jQuery UI 1.9 and above, you use the _super method instead.
0352             this._super(key, value);
0353 
0354             _setOptionHooks[key] ? this[ _setOptionHooks[key] ](value) : 0;
0355         },
0356 
0357         _create: function () {
0358             var _el = this.element, _opts = this.options, _type = _el.attr('type');
0359             // According to http://www.w3.org/TR/html-markup/input.html#input
0360             // An input element with no type attribute specified represents the same thing as an
0361             // input element with its type attribute set to "text".
0362             // TLDR:
0363             // http://www.w3.org/TR/html5/forms.html#the-input-element
0364             // https://api.jquery.com/text-selector/
0365 
0366             // $.inArray(void 0, ['text', 'month', void 0]) returns -1 when searching for undefined in IE8 (#45)
0367             // This is only noticable in the real version of IE8, emulated versions
0368             // from the dev tools in modern browsers do not suffer from this issue.
0369             // if (!_el.is('input,div,span') || $.inArray(_el.attr('type'), ['text', 'month', void 0]) === -1) {
0370             if (!_el.is('input,div,span') || (_type !== 'text' && _type !== 'month' && _type !==  void 0)) {
0371                 var error = _setupErr + 'MonthPicker can only be called on text or month inputs.';
0372                 // Call alert first so that IE<10 won't trip over console.log and swallow all errors.
0373                 alert(error + ' \n\nSee (developer tools) for more details.');
0374 
0375                 console.error(error + '\n Caused by:');
0376                 console.log(_el[0]);
0377                 return false;
0378             }
0379 
0380             if (!$.mask && _opts.UseInputMask) {
0381                 alert(_setupErr + 'The UseInputMask option requires the Input Mask Plugin. Get it from digitalbush.com');
0382                 return false;
0383             }
0384 
0385             if (_opts.Position !== null && !_hasPosition) {
0386                 alert(_posErr);
0387                 return false;
0388             }
0389 
0390             // Make sure the user passed in a valid Animation, ShowAnim and HideAnim options values.
0391             for (var opt in _animVals) {
0392                 if (_opts[opt] !== null && $.inArray(_opts[opt], _animVals[opt]) === -1) {
0393                     alert(_badOptValErr.replace(/%/, opt) + _animVals[opt]);
0394                     return false;
0395                 }
0396             }
0397 
0398             this._isMonthInputType = _el.attr('type') === 'month';
0399             if (this._isMonthInputType) {
0400                 this.options.MonthFormat = this.MonthInputFormat;
0401                 _el.css('width', 'auto');
0402             }
0403 
0404             var _menu = this._monthPickerMenu = $('<div id="MonthPicker_' + _el[0].id + '" class="month-picker ui-widget ui-widget-content ui-corner-all"></div>').hide();
0405             var isInline = _isInline(_el);
0406 
0407             $(_markup).appendTo(_menu);
0408             _menu.appendTo( isInline ? _el : document.body );
0409 
0410             this._titleButton =
0411                 $('.month-picker-title', _menu)
0412                 .click($proxy(this._showYearsClickHandler, this))
0413                 .find('a').jqueryUIButton()
0414                 .removeClass(_defaultClass);
0415 
0416             this._applyJumpYearsHint();
0417             this._createValidationMessage();
0418 
0419             this._prevButton = $('.month-picker-previous>a', _menu)
0420               .jqueryUIButton({ text: false })
0421               .removeClass(_defaultClass);
0422 
0423             this._nextButton = $('.month-picker-next>a', _menu)
0424               .jqueryUIButton({ text: false })
0425               .removeClass(_defaultClass);
0426 
0427             this._setRTL(_opts.IsRTL); //Assigns icons to the next/prev buttons.
0428 
0429             $(_iconClass, this._nextButton).text(this._i18n('nextLabel'));
0430             $(_iconClass, this._prevButton).text(this._i18n('prevLabel'));
0431 
0432             var $table = $('.month-picker-month-table', _menu);
0433             for (var i = 0; i < 12; i++) {
0434                 var $tr = !(i % 3) ? $('<tr />').appendTo($table) : $tr;
0435 
0436                 // Use <a> tag instead of <button> to avoid issues
0437                 // only with Google Chrome (#50).
0438                 $tr.append('<td><a class="button-' + (i + 1) + '" /></td>');
0439             }
0440 
0441             this._buttons = $('a', $table).jqueryUIButton();
0442 
0443             _menu.on('mousedown' + _eventsNs, function (event) {
0444                 event.preventDefault();
0445             });
0446 
0447             // Checks and initailizes Min/MaxMonth properties
0448             // (creates _setMinMonth and _setMaxMonth methods).
0449             var me = this, Month = 'Month';
0450             $.each(['Min', 'Max'], function(i, type) {
0451                 me["_set" + type + Month] = function(val) {
0452                     if ((me['_' + type + Month] = _encodeMonth(me, val)) === false) {
0453                         alert(_badMinMaxVal.replace(/%/, type).replace(/_/, val));
0454                     }
0455                 };
0456 
0457                 me._setOption(type + Month, me.options[type + Month]);
0458             });
0459 
0460             var _selMonth = _opts.SelectedMonth;
0461             if (_selMonth !== void 0) {
0462                 var month = _encodeMonth(this, _selMonth);
0463                 _el.val( this._formatMonth(new Date( _toYear(month), month % 12, 1)) );
0464             }
0465 
0466             this._updateAlt();
0467 
0468             this._setUseInputMask();
0469             this._setDisabledState();
0470             this.Destroy = this.destroy;
0471 
0472             if (isInline) {
0473                 this.Open();
0474             } else {
0475                // Update the alt field if the user manually changes
0476                // the input field.
0477                _el.addClass(_textfieldClass);
0478                _el.change($proxy(this._updateAlt, this));
0479             }
0480         },
0481 
0482         /****** Publicly Accessible API functions ******/
0483 
0484         GetSelectedDate: function () {
0485             return this._parseMonth();
0486         },
0487 
0488         GetSelectedYear: function () {
0489             var date = this.GetSelectedDate();
0490             return date ? date.getFullYear() : NaN;
0491         },
0492 
0493         GetSelectedMonth: function () {
0494             var date = this.GetSelectedDate();
0495             return date ? date.getMonth()+1 : NaN;
0496         },
0497 
0498         Validate: function() {
0499             var _date = this.GetSelectedDate();
0500 
0501             if (this.options.ValidationErrorMessage !== null && !this.options.Disabled) {
0502                 this._validationMessage.toggle(!_date);
0503             }
0504 
0505             return _date;
0506         },
0507 
0508         GetSelectedMonthYear: function () {
0509             var date = this.Validate();
0510             return date ? (date.getMonth() + 1) + '/' + date.getFullYear() : null;
0511         },
0512 
0513         Disable: function () {
0514             this._setOption("Disabled", true);
0515         },
0516 
0517         Enable: function () {
0518             this._setOption("Disabled", false);
0519         },
0520 
0521         ClearAllCallbacks: function () {
0522             for (var _opt in this.options) {
0523                 if (_opt.indexOf('On') === 0) {
0524                     this.options[_opt] = $noop;
0525                 }
0526             }
0527         },
0528 
0529         Clear: function () {
0530             this.element.val('');
0531             $(this.options.AltField).val('');
0532             this._validationMessage.hide();
0533         },
0534 
0535         Toggle: function (event) {
0536             return this._visible ? this.Close(event) : this.Open(event);
0537         },
0538 
0539         Open: function (event) {
0540             var _elem = this.element, _opts = this.options;
0541             if (!_opts.Disabled && !this._visible) {
0542                 // Allow the user to prevent opening the menu.
0543                 event = event || $.Event();
0544                 if (_event('OnBeforeMenuOpen', this)(event) === false || event.isDefaultPrevented()) {
0545                     return;
0546                 }
0547 
0548                 this._visible = true;
0549                 this._ajustYear(_opts);
0550 
0551                 var _menu = this._monthPickerMenu;
0552                 this._showMonths();
0553 
0554                 if (_isInline(_elem)) {
0555                     _menu.css('position', 'static').show();
0556                     _event('OnAfterMenuOpen', this)();
0557                 } else {
0558                     // If there is an open menu close it first.
0559                     if (_openedInstance) {
0560                         _openedInstance.Close(event);
0561                     }
0562 
0563                     _openedInstance = this;
0564                     $(document).on('mousedown' + _eventsNs + this.uuid, $proxy(this.Close, this))
0565                                .on('keydown' + _eventsNs + this.uuid, $proxy(this._keyDown, this));
0566 
0567                     // Trun off validation so that clicking one of the months
0568                     // won't blur the input field and trogger vlaidation
0569                     // befroe the month was chosen (click event was triggered).
0570                     // It is turned back on when Hide() is called.
0571                     _elem.off('blur' + _eventsNs).focus();
0572 
0573                     var _anim = _opts.ShowAnim || _opts.Animation,
0574                         _noAnim = _anim === 'none';
0575 
0576                     // jQuery UI overrides jQuery.show and dosen't
0577                     // call the start callback.
0578                     // see: http://api.jqueryui.com/show/
0579                     _menu[ _noAnim ? 'fadeIn' : _anim ]({
0580                        duration: _noAnim ? 0 : this._duration(),
0581                        start: $proxy(this._position, this, _menu),
0582                        complete: _event('OnAfterMenuOpen', this)
0583                     });
0584                 }
0585             }
0586         },
0587 
0588         Close: function (event) {
0589             var _elem = this.element;
0590             if (!_isInline(_elem) && this._visible) {
0591                 var _menu = this._monthPickerMenu,
0592                     _opts = this.options;
0593 
0594                 event = event || $.Event();
0595                 if (_event('OnBeforeMenuClose', this)(event) === false || event.isDefaultPrevented()) {
0596                     return;
0597                 }
0598 
0599                 // If the menu is closed while in jump years mode, bring back
0600                 // the jump years hint.
0601                 if (this._backToYear) {
0602                   this._applyJumpYearsHint();
0603                   this._backToYear = 0;
0604                 }
0605 
0606                 this._visible = false;
0607                 _openedInstance = null;
0608                 $(document).off('keydown' + _eventsNs + this.uuid)
0609                            .off('mousedown' + _eventsNs + this.uuid);
0610 
0611                 this.Validate();
0612                 _elem.on('blur' + _eventsNs, $proxy(this.Validate, this));
0613                 var _callback = _event('OnAfterMenuClose', this);
0614 
0615                 var _anim = _opts.HideAnim || _opts.Animation;
0616                 if (_anim === 'none') {
0617                     _menu.hide(0, _callback);
0618                 } else {
0619                     _menu[ _anim ](this._duration(), _callback);
0620                 }
0621             }
0622         },
0623 
0624         /**
0625          * Methods the user can override to use a third party library
0626          * such as http://momentjs.com for parsing and formatting months.
0627          */
0628         MonthInputFormat: 'yy-mm',
0629 
0630         ParseMonth: function (str, format) {
0631             try {
0632                 return $datepicker.parseDate('dd' + format, '01' + str);
0633             } catch (e) {
0634                 return null;
0635             }
0636         },
0637 
0638         FormatMonth: function (date, format) {
0639             try {
0640                 return $datepicker.formatDate(format, date) || null;
0641             } catch (e) {
0642                 return null;
0643             }
0644         },
0645 
0646         /****** Private and Misc Utility functions ******/
0647 
0648         _setSelectedMonth: function (_selMonth) {
0649             var month = _encodeMonth(this, _selMonth), _el = this.element;
0650 
0651             if (month) {
0652                 var date = new Date( _toYear(month), month % 12, 1 );
0653                 _el.val( this._formatMonth( date ) );
0654 
0655                 this._updateAlt(0, date);
0656                 this._validationMessage.hide();
0657             } else {
0658                 this.Clear();
0659             }
0660 
0661             this._ajustYear(this.options);
0662             this._showMonths();
0663         },
0664 
0665         _applyJumpYearsHint: function() {
0666           _applyButtonHint(this._titleButton, this._i18n('jumpYears'));
0667         },
0668 
0669         _i18n: function(str) {
0670           var _trans = this.options.i18n[str];
0671 
0672           if (typeof _trans === 'undefined') {
0673             return $.MonthPicker.i18n[str];
0674           } else {
0675             return _trans;
0676           }
0677         },
0678 
0679         _parseMonth: function (str, format) {
0680             return this.ParseMonth(str || this.element.val(), format || this.options.MonthFormat);
0681         },
0682 
0683         _formatMonth: function (date, format) {
0684             return this.FormatMonth(date || this._parseMonth(), format || this.options.MonthFormat);
0685         },
0686 
0687         _updateButton: function () {
0688             var isDisabled = this.options.Disabled;
0689 
0690             this._createButton();
0691 
0692             // If the button is a jQuery UI button,
0693             // plain HTML button or an input we support disable it,
0694             // otherwise the user must handle the diabled state
0695             // by creating an appropriate button by passing
0696             // a function. See Button option: Img tag tests for
0697             // more details.
0698             var _button = this._monthPickerButton;
0699             try {
0700                 _button.jqueryUIButton('option', 'disabled', isDisabled);
0701             } catch (e) {
0702                 _button.filter('button,input').prop('disabled', isDisabled);
0703             }
0704 
0705             this._updateFieldEvents();
0706         },
0707 
0708         _createButton: function () {
0709             var _elem = this.element, _opts = this.options;
0710             if (_isInline(_elem)) return;
0711 
0712             var _oldButton = this._monthPickerButton.off(_eventsNs);
0713             var _btnOpt = _opts.ShowIcon ? _opts.Button : false;
0714 
0715             if ($.isFunction(_btnOpt)) {
0716                 var _params = $.extend(true, {i18n: $.extend(true, {}, $.MonthPicker.i18n)}, this.options);
0717                 _btnOpt = _btnOpt.call(_elem[0], _params);
0718             }
0719 
0720             var _removeOldBtn = false;
0721             this._monthPickerButton = ( _btnOpt instanceof $ ? _btnOpt : $(_btnOpt) )
0722                 .each(function() {
0723                     if (!$.contains(document.body, this)) {
0724                         _removeOldBtn = true;
0725                         $(this).insertAfter(_elem);
0726                     }
0727                 })
0728                 .on(click, $proxy(this.Toggle, this))
0729                 .on('mousedown' + _eventsNs, function(r) {
0730                   r.preventDefault();
0731                 });
0732 
0733             if (this._removeOldBtn) {
0734                 _oldButton.remove();
0735             }
0736 
0737             this._removeOldBtn = _removeOldBtn;
0738         },
0739 
0740         _updateFieldEvents: function () {
0741             var _events = click + ' focus' + _eventsNs;
0742             this.element.off(_events);
0743             if (this.options.ShowOn === 'both' || !this._monthPickerButton.length) {
0744                 this.element.on(_events, $proxy(this.Open, this));
0745             }
0746         },
0747 
0748         _createValidationMessage: function () {
0749             var _errMsg = this.options.ValidationErrorMessage, _elem = this.element;
0750             if ($.inArray(_errMsg, [null, '']) === -1) {
0751                 var _msgEl = $('<span id="MonthPicker_Validation_' + _elem[0].id + '" class="month-picker-invalid-message">' + _errMsg + '</span>');
0752 
0753                 var _button = this._monthPickerButton;
0754                 this._validationMessage = _msgEl.insertAfter(_button.length ? _button : _elem);
0755 
0756                 _elem.on('blur' + _eventsNs, $proxy(this.Validate, this));
0757             } else {
0758                 this._validationMessage.remove();
0759             }
0760         },
0761 
0762         _setRTL: function(value) {
0763             _applyArrowButton( this._prevButton.css('float', value ? 'right' : 'left'), !value );
0764             _applyArrowButton( this._nextButton.css('float', value ? 'left' : 'right'), value );
0765         },
0766 
0767         _keyDown: function (event) {
0768             // Don't use $.ui.keyCode to help minification.
0769             switch (event.keyCode) {
0770                 case 13: // Enter.
0771                     if (!this.element.val()) {
0772                         this._chooseMonth(new Date().getMonth() + 1);
0773                     }
0774                     this.Close(event);
0775                     break;
0776                 case 27: // Escape
0777                 case 9: // Tab
0778                     this.Close(event);
0779                     break;
0780             }
0781         },
0782 
0783         _duration: function() {
0784             var _dur = this.options.Duration;
0785 
0786             if ($.isNumeric(_dur)) {
0787                 return _dur;
0788             }
0789 
0790             return _dur in _speeds ? _speeds[ _dur ] : _speeds._default;
0791         },
0792 
0793         _position: _hasPosition ?
0794             function($menu) {
0795                 var _defauts = this.options.IsRTL ? _RTL_defaultPos : _defaultPos;
0796                 var _posOpts = $.extend(_defauts, this.options.Position);
0797 
0798                 // Only in IE and jQuery 1.12.0 or 2.2.0, .position() will add scrollTop to the top coordinate (#40)
0799                 return $menu.position($.extend({of: this.element}, _posOpts));
0800             } :
0801             function($menu) {
0802                 // Only in IE and jQuery 1.12.0 or 2.2.0, .offset() will add scrollTop to the top coordinate (#40)
0803                 var _el = this.element,
0804                     _css = { top: (_el.offset().top + _el.height() + 7) + 'px' };
0805 
0806                 if (this.options.IsRTL) {
0807                     _css.left = (_el.offset().left-$menu.width()+_el.width() + 7) + 'px';
0808                 } else {
0809                     _css.left = _el.offset().left + 'px';
0810                 }
0811 
0812                 return $menu.css(_css);
0813             },
0814 
0815         _setUseInputMask: function () {
0816             if (!this._isMonthInputType) {
0817                 try {
0818                     if (this.options.UseInputMask) {
0819                         this.element.mask( this._formatMonth(new Date).replace(/\d/g, 9) );
0820                     } else {
0821                         this.element.unmask();
0822                     }
0823                 } catch (e) {}
0824             }
0825         },
0826 
0827         _setDisabledState: function () {
0828             var isDisabled = this.options.Disabled, _elem = this.element;
0829 
0830             // Disable the associated input field.
0831             _elem[0].disabled = isDisabled;
0832             _elem.toggleClass(_disabledClass, isDisabled);
0833 
0834             if (isDisabled) {
0835                 this._validationMessage.hide();
0836             }
0837 
0838             this.Close();
0839             this._updateButton();
0840 
0841             _event('OnAfterSetDisabled', this)(isDisabled);
0842         },
0843 
0844         _getPickerYear: function () {
0845             return this._pickerYear;
0846         },
0847 
0848         _setPickerYear: function (year) {
0849             this._pickerYear = year || new Date().getFullYear();
0850             this._titleButton.jqueryUIButton({ label: this._i18n('year') + ' ' + this._pickerYear });
0851         },
0852 
0853         // When calling this method with a falsy (undefined) date
0854         // value, this.element.val() is used as the date value.
0855         //
0856         // Therefore it's important to update the input field
0857         // before calling this method.
0858         _updateAlt: function (noop, date) {
0859             var _field = $(this.options.AltField);
0860             if (_field.length) {
0861                 _field.val( this._formatMonth(date, this.options.AltFormat) );
0862             }
0863         },
0864 
0865         _chooseMonth: function (month) {
0866             var _year = this._getPickerYear();
0867             var date = new Date(_year, month-1);
0868             this.element.val(this._formatMonth( date )).blur();
0869             this._updateAlt(0, date);
0870 
0871             _setActive( this._selectedBtn, false );
0872             this._selectedBtn = _setActive( $(this._buttons[month-1]), true );
0873 
0874             _event('OnAfterChooseMonth', this)(date);
0875         },
0876 
0877         _chooseYear: function (year) {
0878             this._backToYear = 0;
0879             this._setPickerYear(year);
0880             this._buttons.removeClass(_todayClass);
0881             this._showMonths();
0882             this._applyJumpYearsHint();
0883 
0884             _event('OnAfterChooseYear', this)();
0885         },
0886 
0887         _showMonths: function () {
0888             var _months = this._i18n('months');
0889 
0890             this._prevButton
0891                 .attr('title', this._i18n('prevYear'))
0892                 .off(click)
0893                 .on(click, $proxy(this._addToYear, this, -1));
0894 
0895             this._nextButton
0896                 .attr('title', this._i18n('nextYear'))
0897                 .off(click)
0898                 .on(click, $proxy(this._addToYear, this, 1));
0899 
0900             this._buttons.off(_eventsNs);
0901 
0902             var me = this, _onMonthClick = $proxy(me._onMonthClick, me);
0903             $.each(_months, function(index, monthName) {
0904                 $(me._buttons[index])
0905                     .on(click, {month: index+1}, _onMonthClick )
0906                     .jqueryUIButton('option', 'label', monthName);
0907             });
0908 
0909             this._decorateButtons();
0910         },
0911 
0912         _showYearsClickHandler: function () {
0913             this._buttons.removeClass(_todayClass);
0914             if (!this._backToYear) {
0915                 this._backToYear = this._getPickerYear();
0916                 this._showYears();
0917 
0918                 var _label = this._i18n('backTo') + ' ' + this._getPickerYear();
0919                 this._titleButton.jqueryUIButton({ label: _label }).data( _clearHint )();
0920 
0921                 _event('OnAfterChooseYears', this)();
0922             } else {
0923                 this._setPickerYear(this._backToYear);
0924                 this._applyJumpYearsHint();
0925                 this._showMonths();
0926                 this._backToYear = 0;
0927             }
0928         },
0929 
0930         _showYears: function () {
0931             var _currYear = this._getPickerYear(),
0932                 _yearDifferential = -4,
0933                 _firstYear = (_currYear + _yearDifferential),
0934                 AMOUNT_TO_ADD = 12,
0935                 _thisYear = new Date().getFullYear();
0936 
0937             var _minDate = this._MinMonth;
0938             var _maxDate = this._MaxMonth;
0939             var _minYear = _minDate ? _toYear(_minDate) : 0;
0940             var _maxYear = _maxDate ? _toYear(_maxDate) : 0;
0941             this._prevButton
0942                 .attr('title', this._i18n('prev12Years'))
0943                 .off(click)
0944                 .on(click, $proxy(this._addToYears, this, -AMOUNT_TO_ADD));
0945 
0946             this._nextButton
0947                 .attr('title', this._i18n('next12Years'))
0948                 .off(click)
0949                 .on(click, $proxy(this._addToYears, this, AMOUNT_TO_ADD));
0950 
0951             _setDisabled(this._prevButton, _minYear && (_firstYear - 1) < _minYear);
0952             _setDisabled(this._nextButton, _maxYear && (_firstYear + 12) -1 > _maxYear);
0953 
0954             this._buttons.off(_eventsNs);
0955 
0956             _setActive( this._selectedBtn, false );
0957 
0958             var _selYear = this.GetSelectedYear();
0959             var _onClick = $proxy(this._onYearClick, this);
0960             var _todayWithinBounds = _between(_thisYear, _minYear, _maxYear);
0961             var _selWithinBounds = _between(_selYear, _minYear, _maxYear);
0962 
0963             for (var _counter = 0; _counter < 12; _counter++) {
0964                 var _year = _currYear + _yearDifferential;
0965 
0966                 var _btn = $( this._buttons[_counter] ).jqueryUIButton({
0967                         disabled: !_between(_year, _minYear, _maxYear),
0968                         label: _year
0969                     })
0970                     .toggleClass(_todayClass, _year === _thisYear && _todayWithinBounds) // Heighlight the current year.
0971                     .on(click, { year: _year }, _onClick );
0972 
0973                  // Heighlight the selected year.
0974                 if (_selWithinBounds && _selYear && _selYear === _year) {
0975                     this._selectedBtn = _setActive( _btn , true );
0976                 }
0977 
0978                 _yearDifferential++;
0979             }
0980         },
0981 
0982         _onMonthClick: function(event) {
0983             this._chooseMonth(event.data.month);
0984             this.Close(event);
0985         },
0986 
0987         _onYearClick: function(event) {
0988             this._chooseYear(event.data.year);
0989         },
0990 
0991         _addToYear: function(amount) {
0992             this._setPickerYear( this._getPickerYear() + amount );
0993             this.element.focus();
0994             this._decorateButtons();
0995 
0996             _event('OnAfter' + (amount > 0 ? 'Next' : 'Previous') + 'Year', this)();
0997         },
0998 
0999         _addToYears: function(amount) {
1000             this._pickerYear = this._getPickerYear() + amount;
1001             this._showYears();
1002             this.element.focus();
1003 
1004             _event('OnAfter' + (amount > 0 ? 'Next' : 'Previous') + 'Years', this)();
1005         },
1006 
1007         _ajustYear: function(_opts) {
1008             var _year = _opts.StartYear || this.GetSelectedYear() || new Date().getFullYear();
1009             if (this._MinMonth !== null) {
1010                 _year = Math.max(_toYear(this._MinMonth), _year);
1011             }
1012             if (this._MaxMonth !== null) {
1013                 _year = Math.min(_toYear(this._MaxMonth), _year);
1014             }
1015 
1016             this._setPickerYear( _year );
1017         },
1018 
1019         _decorateButtons: function() {
1020             var _curYear = this._getPickerYear(), _todaysMonth = _toMonth(new Date),
1021                 _minDate = this._MinMonth, _maxDate = this._MaxMonth;
1022 
1023             // Heighlight the selected month.
1024             _setActive( this._selectedBtn, false );
1025             var _sel = this.GetSelectedDate();
1026             var _withinBounds = _between(_sel ? _toMonth(_sel) : null, _minDate, _maxDate);
1027 
1028             if (_sel && _sel.getFullYear() === _curYear) {
1029                 this._selectedBtn = _setActive( $(this._buttons[_sel.getMonth()]) , _withinBounds );
1030             }
1031 
1032             // Disable the next/prev button if we've reached the min/max year.
1033             _setDisabled(this._prevButton,  _minDate && _curYear == _toYear(_minDate));
1034             _setDisabled(this._nextButton,  _maxDate && _curYear == _toYear(_maxDate));
1035 
1036             for (var i = 0; i < 12; i++) {
1037                 // Disable the button if the month is not between the
1038                 // min and max interval.
1039                 var _month = (_curYear * 12) + i, _isBetween = _between(_month, _minDate, _maxDate);
1040 
1041                 $(this._buttons[i])
1042                     .jqueryUIButton({ disabled: !_isBetween })
1043                     .toggleClass(_todayClass, _isBetween && _month == _todaysMonth); // Highlights today's month.
1044             }
1045         }
1046     });
1047 }(jQuery, window, document, Date));