1/* 2The jQuery UI Month Picker Version 3.0.4 3https://github.com/KidSysco/jquery-ui-month-picker/ 4 5Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> 6This program is free software: you can redistribute it and/or modify 7it under the terms of the GNU General Public License as published by 8the Free Software Foundation, either version 3 of the License, or 9(at your option) any later version. 10 11This program is distributed in the hope that it will be useful, 12but WITHOUT ANY WARRANTY; without even the implied warranty of 13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14GNU General Public License for more details. 15 16You should have received a copy of the GNU General Public License 17along with this program. If not, see 18<http://www.gnu.org/licenses/gpl-3.0.txt>. 19*/ 20 21(function ($, window, document, Date) { 22 'use strict'; 23 24 var _setupErr = 'MonthPicker Error: '; 25 // This test must be run before any rererence is made to jQuery. 26 // In case the user didn't load jQuery or jQuery UI the plugin 27 // will fail before it get's to this test + there is no reason 28 // to perform this test for every MonthPicker instance being created. 29 if (!$ || !$.ui || !$.ui.button || !$.ui.datepicker) { 30 alert(_setupErr + 'The jQuery UI button and datepicker plug-ins must be loaded.'); 31 return; 32 } 33 34 // Creates an alias to jQuery UI's .button() that dosen't 35 // conflict with Bootstrap.js button (#35) 36 $.widget.bridge('jqueryUIButton', $.ui.button); 37 38 var _speeds = $.fx.speeds; 39 var _eventsNs = '.MonthPicker'; 40 var _textfieldClass = 'month-year-input'; 41 var _clearHint = 'month-picker-clear-hint'; 42 var _iconClass = '.ui-button-icon-primary'; 43 var _disabledClass = 'month-picker-disabled'; 44 var _todayClass = 'ui-state-highlight'; 45 var _selectedClass = 'ui-state-active'; 46 var _defaultClass = 'ui-state-default'; 47 var _defaultPos = { my: 'left top+1', at: 'left bottom' }; 48 var _RTL_defaultPos = { my: 'right top+1', at: 'right bottom' }; 49 var _posErr = _setupErr + 'The jQuery UI position plug-in must be loaded.'; 50 var _badOptValErr = _setupErr + 'Unsupported % option value, supported values are: '; 51 var _badMinMaxVal = _setupErr + '"_" is not a valid %Month value.'; 52 var _openedInstance = null; 53 var _hasPosition = !!$.ui.position; 54 var _animVals = { 55 Animation: ['slideToggle', 'fadeToggle', 'none'], 56 ShowAnim: ['fadeIn', 'slideDown', 'none'], 57 HideAnim: ['fadeOut', 'slideUp', 'none'] 58 }; 59 var _setOptionHooks = { 60 ValidationErrorMessage: '_createValidationMessage', 61 Disabled: '_setDisabledState', 62 ShowIcon: '_updateButton', 63 Button: '_updateButton', 64 ShowOn: '_updateFieldEvents', 65 IsRTL: '_setRTL', 66 AltFormat: '_updateAlt', 67 AltField: '_updateAlt', 68 StartYear: '_setPickerYear', 69 MinMonth: '_setMinMonth', 70 MaxMonth: '_setMaxMonth', 71 SelectedMonth: '_setSelectedMonth' 72 }; 73 var $noop = $.noop; 74 var $proxy = $.proxy; 75 var $datepicker = $.datepicker; 76 var click = 'click' + _eventsNs; 77 78 function _toMonth(date) { 79 return date.getMonth() + (date.getFullYear() * 12); 80 } 81 82 function _toYear(month) { 83 return Math.floor(month / 12); 84 } 85 86 function _stayActive() { 87 $(this).addClass(_selectedClass); 88 } 89 90 function _setActive( el, state ) { 91 return el[ state ? 'on' : 'off' ]('mousenter mouseout', _stayActive ) 92 .toggleClass(_selectedClass, state); 93 } 94 95 function _between(month, from, until) { 96 return (!from || month >= from) && (!until || month <= until); 97 } 98 99 function _encodeMonth(_inst, _val) { 100 if (_val === null) { 101 return _val; 102 } else if (_val instanceof Date) { 103 return _toMonth(_val); 104 } else if ($.isNumeric(_val)) { 105 return _toMonth(new Date) + parseInt(_val, 10); 106 } 107 108 var _date = _inst._parseMonth(_val); 109 if (_date) { 110 return _toMonth(_date); 111 } 112 113 return _parsePeriod(_val); 114 } 115 116 function _event(_name, _inst) { 117 return $proxy(_inst.options[_name] || $noop, _inst.element[0]); 118 } 119 120 function _parsePeriod(_val, _initDate) { 121 // Parsing is done by replacing tokens in the value to form 122 // a JSON object with it's keys and values reversed 123 // (example '+1y +2m' will turn into {"+1":"y","+2":"m"}) 124 // After that we just revers the keys and values. 125 var _json = $.trim(_val); 126 _json = _json.replace(/y/i, '":"y"'); 127 _json = _json.replace(/m/i, '":"m"'); 128 129 try { 130 var _rev = JSON.parse( '{"' + _json.replace(/ /g, ',"') + '}' ), obj = {}; 131 132 for (var key in _rev) { 133 obj[ _rev[key] ] = key; 134 } 135
136 var _month = _toMonth(new Date); 137 _month += (parseInt(obj.m, 10) || 0); 138 return _month + (parseInt(obj.y, 10) || 0) * 12; 139 } catch (e) { 140 return false; 141 } 142 } 143 144 function _makeDefaultButton(options) { 145 // this refers to the associated input field. 146 return $('<span id="MonthPicker_Button_' + this.id + '" class="month-picker-open-button">' + options.i18n.buttonText + '</span>') 147 .jqueryUIButton({ 148 text: false, 149 icons: { 150 // Defaults to 'ui-icon-calculator'. 151 primary: options.ButtonIcon 152 } 153 }); 154 } 155 156 function _applyArrowButton($el, dir) { 157 $el.jqueryUIButton('option', { 158 icons: { 159 primary: 'ui-icon-circle-triangle-' + (dir ? 'w' : 'e') 160 } 161 }); 162 } 163 164 function _isInline(elem) { 165 return !elem.is('input'); 166 } 167 168 $.MonthPicker = { 169 VERSION: '3.0.4', // Added in version 2.4; 170 i18n: { 171 year: 'Year', 172 prevYear: 'Previous Year', 173 nextYear: 'Next Year', 174 next12Years: 'Jump Forward 12 Years', 175 prev12Years: 'Jump Back 12 Years', 176 nextLabel: 'Next', 177 prevLabel: 'Prev', 178 buttonText: 'Open Month Chooser', 179 jumpYears: 'Jump Years', 180 backTo: 'Back to', 181 months: ['Jan.', 'Feb.', 'Mar.', 'Apr.', 'May', 'June', 'July', 'Aug.', 'Sep.', 'Oct.', 'Nov.', 'Dec.'] 182 } 183 }; 184 185 var _markup = 186 '<div class="ui-widget-header month-picker-header ui-corner-all">' + 187 '<table class="month-picker-year-table">' + 188 '<tr>' + 189 '<td class="month-picker-previous"><a /></td>' + 190 '<td class="month-picker-title"><a /></td>' + 191 '<td class="month-picker-next"><a /></td>' + 192 '</tr>' + 193 '</table>' + 194 '</div>' + 195 '<div>' + 196 '<table class="month-picker-month-table" />' + 197 '</div>'; 198 199 // Groups state and functionallity to fade in the jump years hint 200 // when the user mouses over the Year 2016 text. 201 // NOTE: An invocation of this function: 202 // 1: Is an independent instance with it's own unique state. 203 // 2: Assumes that there is no previous hint applied to the 204 // button (it dosen't remove the existing hint). 205 function _applyButtonHint(_button, _hintText) { 206 var _speed = 125, _currentLabel, _startTimeout, _labelElem = $(); 207 208 _button.on('mouseenter' + _eventsNs + 'h', _prepareToStart); 209 210 // Setp 1: Wait to make sure the user isn't just mousing over and 211 // away from the button. 212 // NOTE: If _fadeOutHint() is triggered on mouseleave before the 213 // timeout is triggered the animation is canceled. 214 function _prepareToStart() { 215 _startTimeout = setTimeout(_fadeOutLabel, 175); 216 } 217 218 // Setp 2: Fade out the label (Year 2016) text to 45%. 219 function _fadeOutLabel() { 220 _startTimeout = null; 221 _labelElem = $('span', _button).animate({ opacity: 0.45 }, _speed, _fadeInHint); 222 } 223 224 // Setp 3: Fade in the hint text (Jump years). 225 function _fadeInHint() { 226 _currentLabel = _labelElem.text(); 227 _labelElem.animate({ opacity: 1 }, _speed).text(_hintText); 228 } 229 230 _button.on('mouseleave' + _eventsNs + 'h', _fadeOutHint); 231 232 function _fadeOutHint() { 233 if (_startTimeout) { 234 // If the user is just moving over and away from the button, cancel 235 // the animation completely. 236 clearTimeout(_startTimeout); 237 } else { 238 // Setp 4: Fade out the hint text (Jump years) to 45%. 239 _labelElem = $('span', _button).animate({ opacity: 0.45 }, _speed, _fadeInLabel); 240 } 241 } 242 243 // Setp 5: Fade in the label (Year 2016) text. 244 function _fadeInLabel() { 245 _labelElem.text( _currentLabel ).animate({opacity: 1}, _speed); 246 } 247 248 // Adds a function to the button elemene which is called when the 249 // user clicks the button (the hint needs to be removed). 250 _button.data(_clearHint, function() { 251 clearTimeout(_startTimeout); 252 _labelElem.stop().css({ opacity: 1 }); 253 _button.off(_eventsNs + 'h'); 254 }); 255 } // End _applyButtonHint() 256 257 function _setDisabled(_button, _value) { 258 var _btnWidget = _button.data('ui-button'); 259 if (_btnWidget.option('disabled') !== _value) { 260 _btnWidget.option('disabled', _value); 261 } 262 } 263 264 $.widget("KidSysco.MonthPicker", { 265 266 /******* Properties *******/ 267 268 options: { 269 i18n: {}, 270 IsRTL: false, 271 Position: null, 272 StartYear: null, 273 ShowIcon: true, 274 UseInputMask: false, 275 ValidationErrorMessage: null, 276 Disabled: false, 277 MonthFormat: 'mm/yy', 278 Animation: 'fadeToggle',
279 ShowAnim: null, 280 HideAnim: null, 281 ShowOn: null, 282 MinMonth: null, 283 MaxMonth: null, 284 Duration: 'normal', 285 Button: _makeDefaultButton, 286 ButtonIcon: 'ui-icon-calculator' 287 }, 288 289 _monthPickerButton: $(), 290 _validationMessage: $(), 291 _selectedBtn: $(), 292 293 /******* jQuery UI Widget Factory Overrides ********/ 294 295 _destroy: function () { 296 var _elem = this.element; 297 if ($.mask && this.options.UseInputMask) { 298 _elem.unmask(); 299 300 if (!this.GetSelectedDate()) { 301 _elem.val(''); 302 } 303 } 304 305 _elem.removeClass(_textfieldClass).off(_eventsNs); 306 307 $(document).off(_eventsNs + this.uuid); 308 309 this._monthPickerMenu.remove(); 310 311 var _button = this._monthPickerButton.off(click); 312 if (this._removeOldBtn) { 313 _button.remove(); 314 } 315 316 this._validationMessage.remove(); 317 318 if (_openedInstance === this) { 319 _openedInstance = null; 320 } 321 }, 322 323 _setOption: function (key, value) { 324 switch (key) { 325 case 'i18n': 326 // Pass a clone i18n object to the this._super. 327 value = $.extend({}, value); 328 break; 329 case 'Position': 330 if (!_hasPosition) { 331 alert(_posErr); 332 return; 333 } 334 break; 335 case 'MonthFormat': 336 var date = this.GetSelectedDate(); 337 if (date) { 338 this.element.val( this.FormatMonth(date, value) ); 339 } 340 break; 341 } 342 343 // Make sure the user passed in a valid Animation, ShowAnim and HideAnim options values. 344 if (key in _animVals && $.inArray(value, _animVals[key]) === -1) { 345 alert(_badOptValErr.replace(/%/, key) + _animVals[key]); 346 return; 347 } 348 349 // In jQuery UI 1.8, manually invoke the _setOption method from the base widget. 350 //$.Widget.prototype._setOption.apply(this, arguments); 351 // In jQuery UI 1.9 and above, you use the _super method instead. 352 this._super(key, value); 353 354 _setOptionHooks[key] ? this[ _setOptionHooks[key] ](value) : 0; 355 }, 356 357 _create: function () { 358 var _el = this.element, _opts = this.options, _type = _el.attr('type'); 359 // According to http://www.w3.org/TR/html-markup/input.html#input 360 // An input element with no type attribute specified represents the same thing as an 361 // input element with its type attribute set to "text". 362 // TLDR: 363 // http://www.w3.org/TR/html5/forms.html#the-input-element 364 // https://api.jquery.com/text-selector/ 365 366 // $.inArray(void 0, ['text', 'month', void 0]) returns -1 when searching for undefined in IE8 (#45) 367 // This is only noticable in the real version of IE8, emulated versions 368 // from the dev tools in modern browsers do not suffer from this issue. 369 // if (!_el.is('input,div,span') || $.inArray(_el.attr('type'), ['text', 'month', void 0]) === -1) { 370 if (!_el.is('input,div,span') || (_type !== 'text' && _type !== 'month' && _type !== void 0)) { 371 var error = _setupErr + 'MonthPicker can only be called on text or month inputs.'; 372 // Call alert first so that IE<10 won't trip over console.log and swallow all errors. 373 alert(error + ' \n\nSee (developer tools) for more details.'); 374 375 console.error(error + '\n Caused by:'); 376 console.log(_el[0]); 377 return false; 378 } 379 380 if (!$.mask && _opts.UseInputMask) { 381 alert(_setupErr + 'The UseInputMask option requires the Input Mask Plugin. Get it from digitalbush.com'); 382 return false;
383 } 384 385 if (_opts.Position !== null && !_hasPosition) { 386 alert(_posErr); 387 return false; 388 } 389 390 // Make sure the user passed in a valid Animation, ShowAnim and HideAnim options values. 391 for (var opt in _animVals) { 392 if (_opts[opt] !== null && $.inArray(_opts[opt], _animVals[opt]) === -1) { 393 alert(_badOptValErr.replace(/%/, opt) + _animVals[opt]); 394 return false; 395 } 396 } 397 398 this._isMonthInputType = _el.attr('type') === 'month'; 399 if (this._isMonthInputType) { 400 this.options.MonthFormat = this.MonthInputFormat; 401 _el.css('width', 'auto'); 402 } 403 404 var _menu = this._monthPickerMenu = $('<div id="MonthPicker_' + _el[0].id + '" class="month-picker ui-widget ui-widget-content ui-corner-all"></div>').hide(); 405 var isInline = _isInline(_el); 406 407 $(_markup).appendTo(_menu); 408 _menu.appendTo( isInline ? _el : document.body ); 409 410 this._titleButton = 411 $('.month-picker-title', _menu) 412 .click($proxy(this._showYearsClickHandler, this)) 413 .find('a').jqueryUIButton() 414 .removeClass(_defaultClass); 415 416 this._applyJumpYearsHint(); 417 this._createValidationMessage(); 418 419 this._prevButton = $('.month-picker-previous>a', _menu) 420 .jqueryUIButton({ text: false }) 421 .removeClass(_defaultClass); 422 423 this._nextButton = $('.month-picker-next>a', _menu) 424 .jqueryUIButton({ text: false }) 425 .removeClass(_defaultClass); 426 427 this._setRTL(_opts.IsRTL); //Assigns icons to the next/prev buttons. 428 429 $(_iconClass, this._nextButton).text(this._i18n('nextLabel')); 430 $(_iconClass, this._prevButton).text(this._i18n('prevLabel')); 431 432 var $table = $('.month-picker-month-table', _menu); 433 for (var i = 0; i < 12; i++) { 434 var $tr = !(i % 3) ? $('<tr />').appendTo($table) : $tr; 435 436 // Use <a> tag instead of <button> to avoid issues 437 // only with Google Chrome (#50). 438 $tr.append('<td><a class="button-' + (i + 1) + '" /></td>'); 439 } 440 441 this._buttons = $('a', $table).jqueryUIButton(); 442 443 _menu.on('mousedown' + _eventsNs, function (event) { 444 event.preventDefault(); 445 }); 446 447 // Checks and initailizes Min/MaxMonth properties 448 // (creates _setMinMonth and _setMaxMonth methods). 449 var me = this, Month = 'Month'; 450 $.each(['Min', 'Max'], function(i, type) { 451 me["_set" + type + Month] = function(val) { 452 if ((me['_' + type + Month] = _encodeMonth(me, val)) === false) { 453 alert(_badMinMaxVal.replace(/%/, type).replace(/_/, val)); 454 } 455 }; 456 457 me._setOption(type + Month, me.options[type + Month]); 458 }); 459 460 var _selMonth = _opts.SelectedMonth; 461 if (_selMonth !== void 0) { 462 var month = _encodeMonth(this, _selMonth); 463 _el.val( this._formatMonth(new Date( _toYear(month), month % 12, 1)) ); 464 } 465 466 this._updateAlt(); 467 468 this._setUseInputMask(); 469 this._setDisabledState(); 470 this.Destroy = this.destroy; 471 472 if (isInline) { 473 this.Open(); 474 } else { 475 // Update the alt field if the user manually changes 476 // the input field. 477 _el.addClass(_textfieldClass); 478 _el.change($proxy(this._updateAlt, this)); 479 } 480 }, 481 482 /****** Publicly Accessible API functions ******/ 483 484 GetSelectedDate: function () { 485 return this._parseMonth(); 486 }, 487 488 GetSelectedYear: function () { 489 var date = this.GetSelectedDate(); 490 return date ? date.getFullYear() : NaN; 491 }, 492 493 GetSelectedMonth: function () {
494 var date = this.GetSelectedDate(); 495 return date ? date.getMonth()+1 : NaN; 496 }, 497 498 Validate: function() { 499 var _date = this.GetSelectedDate(); 500 501 if (this.options.ValidationErrorMessage !== null && !this.options.Disabled) { 502 this._validationMessage.toggle(!_date); 503 } 504 505 return _date; 506 }, 507 508 GetSelectedMonthYear: function () { 509 var date = this.Validate(); 510 return date ? (date.getMonth() + 1) + '/' + date.getFullYear() : null; 511 }, 512 513 Disable: function () { 514 this._setOption("Disabled", true); 515 }, 516 517 Enable: function () { 518 this._setOption("Disabled", false); 519 }, 520 521 ClearAllCallbacks: function () { 522 for (var _opt in this.options) { 523 if (_opt.indexOf('On') === 0) { 524 this.options[_opt] = $noop; 525 } 526 } 527 }, 528 529 Clear: function () { 530 this.element.val(''); 531 $(this.options.AltField).val(''); 532 this._validationMessage.hide(); 533 }, 534 535 Toggle: function (event) { 536 return this._visible ? this.Close(event) : this.Open(event); 537 }, 538 539 Open: function (event) { 540 var _elem = this.element, _opts = this.options; 541 if (!_opts.Disabled && !this._visible) { 542 // Allow the user to prevent opening the menu. 543 event = event || $.Event(); 544 if (_event('OnBeforeMenuOpen', this)(event) === false || event.isDefaultPrevented()) { 545 return; 546 } 547 548 this._visible = true; 549 this._ajustYear(_opts); 550
551 var _menu = this._monthPickerMenu; 552 this._showMonths(); 553 554 if (_isInline(_elem)) { 555 _menu.css('position', 'static').show(); 556 _event('OnAfterMenuOpen', this)(); 557 } else { 558 // If there is an open menu close it first. 559 if (_openedInstance) { 560 _openedInstance.Close(event); 561 } 562 563 _openedInstance = this; 564 $(document).on('mousedown' + _eventsNs + this.uuid, $proxy(this.Close, this)) 565 .on('keydown' + _eventsNs + this.uuid, $proxy(this._keyDown, this)); 566 567 // Trun off validation so that clicking one of the months 568 // won't blur the input field and trogger vlaidation 569 // befroe the month was chosen (click event was triggered). 570 // It is turned back on when Hide() is called. 571 _elem.off('blur' + _eventsNs).focus(); 572 573 var _anim = _opts.ShowAnim || _opts.Animation, 574 _noAnim = _anim === 'none'; 575 576 // jQuery UI overrides jQuery.show and dosen't 577 // call the start callback. 578 // see: http://api.jqueryui.com/show/ 579 _menu[ _noAnim ? 'fadeIn' : _anim ]({ 580 duration: _noAnim ? 0 : this._duration(), 581 start: $proxy(this._position, this, _menu), 582 complete: _event('OnAfterMenuOpen', this) 583 }); 584 } 585 } 586 }, 587 588 Close: function (event) { 589 var _elem = this.element; 590 if (!_isInline(_elem) && this._visible) {
591 var _menu = this._monthPickerMenu, 592 _opts = this.options; 593 594 event = event || $.Event(); 595 if (_event('OnBeforeMenuClose', this)(event) === false || event.isDefaultPrevented()) { 596 return; 597 } 598 599 // If the menu is closed while in jump years mode, bring back 600 // the jump years hint. 601 if (this._backToYear) { 602 this._applyJumpYearsHint(); 603 this._backToYear = 0; 604 } 605 606 this._visible = false; 607 _openedInstance = null; 608 $(document).off('keydown' + _eventsNs + this.uuid) 609 .off('mousedown' + _eventsNs + this.uuid); 610 611 this.Validate(); 612 _elem.on('blur' + _eventsNs, $proxy(this.Validate, this)); 613 var _callback = _event('OnAfterMenuClose', this); 614 615 var _anim = _opts.HideAnim || _opts.Animation; 616 if (_anim === 'none') { 617 _menu.hide(0, _callback); 618 } else { 619 _menu[ _anim ](this._duration(), _callback); 620 } 621 } 622 }, 623 624 /** 625 * Methods the user can override to use a third party library 626 * such as http://momentjs.com for parsing and formatting months. 627 */ 628 MonthInputFormat: 'yy-mm', 629 630 ParseMonth: function (str, format) { 631 try { 632 return $datepicker.parseDate('dd' + format, '01' + str); 633 } catch (e) { 634 return null; 635 } 636 }, 637 638 FormatMonth: function (date, format) { 639 try { 640 return $datepicker.formatDate(format, date) || null; 641 } catch (e) { 642 return null; 643 } 644 }, 645 646 /****** Private and Misc Utility functions ******/ 647 648 _setSelectedMonth: function (_selMonth) { 649 var month = _encodeMonth(this, _selMonth), _el = this.element; 650 651 if (month) { 652 var date = new Date( _toYear(month), month % 12, 1 ); 653 _el.val( this._formatMonth( date ) ); 654 655 this._updateAlt(0, date); 656 this._validationMessage.hide(); 657 } else { 658 this.Clear(); 659 } 660 661 this._ajustYear(this.options); 662 this._showMonths(); 663 }, 664 665 _applyJumpYearsHint: function() { 666 _applyButtonHint(this._titleButton, this._i18n('jumpYears')); 667 }, 668 669 _i18n: function(str) { 670 var _trans = this.options.i18n[str]; 671 672 if (typeof _trans === 'undefined') { 673 return $.MonthPicker.i18n[str]; 674 } else { 675 return _trans; 676 } 677 }, 678 679 _parseMonth: function (str, format) { 680 return this.ParseMonth(str || this.element.val(), format || this.options.MonthFormat); 681 }, 682 683 _formatMonth: function (date, format) { 684 return this.FormatMonth(date || this._parseMonth(), format || this.options.MonthFormat); 685 }, 686 687 _updateButton: function () { 688 var isDisabled = this.options.Disabled; 689 690 this._createButton(); 691 692 // If the button is a jQuery UI button, 693 // plain HTML button or an input we support disable it, 694 // otherwise the user must handle the diabled state 695 // by creating an appropriate button by passing 696 // a function. See Button option: Img tag tests for 697 // more details. 698 var _button = this._monthPickerButton; 699 try { 700 _button.jqueryUIButton('option', 'disabled', isDisabled); 701 } catch (e) { 702 _button.filter('button,input').prop('disabled', isDisabled); 703 } 704 705 this._updateFieldEvents(); 706 }, 707 708 _createButton: function () { 709 var _elem = this.element, _opts = this.options; 710 if (_isInline(_elem)) return; 711 712 var _oldButton = this._monthPickerButton.off(_eventsNs); 713 var _btnOpt = _opts.ShowIcon ? _opts.Button : false;
714 715 if ($.isFunction(_btnOpt)) { 716 var _params = $.extend(true, {i18n: $.extend(true, {}, $.MonthPicker.i18n)}, this.options); 717 _btnOpt = _btnOpt.call(_elem[0], _params); 718 } 719 720 var _removeOldBtn = false; 721 this._monthPickerButton = ( _btnOpt instanceof $ ? _btnOpt : $(_btnOpt) ) 722 .each(function() { 723 if (!$.contains(document.body, this)) { 724 _removeOldBtn = true; 725 $(this).insertAfter(_elem); 726 } 727 }) 728 .on(click, $proxy(this.Toggle, this)) 729 .on('mousedown' + _eventsNs, function(r) { 730 r.preventDefault(); 731 }); 732 733 if (this._removeOldBtn) { 734 _oldButton.remove(); 735 } 736 737 this._removeOldBtn = _removeOldBtn; 738 }, 739 740 _updateFieldEvents: function () { 741 var _events = click + ' focus' + _eventsNs; 742 this.element.off(_events); 743 if (this.options.ShowOn === 'both' || !this._monthPickerButton.length) { 744 this.element.on(_events, $proxy(this.Open, this)); 745 } 746 }, 747 748 _createValidationMessage: function () { 749 var _errMsg = this.options.ValidationErrorMessage, _elem = this.element; 750 if ($.inArray(_errMsg, [null, '']) === -1) { 751 var _msgEl = $('<span id="MonthPicker_Validation_' + _elem[0].id + '" class="month-picker-invalid-message">' + _errMsg + '</span>'); 752 753 var _button = this._monthPickerButton; 754 this._validationMessage = _msgEl.insertAfter(_button.length ? _button : _elem); 755 756 _elem.on('blur' + _eventsNs, $proxy(this.Validate, this)); 757 } else { 758 this._validationMessage.remove(); 759 } 760 }, 761 762 _setRTL: function(value) { 763 _applyArrowButton( this._prevButton.css('float', value ? 'right' : 'left'), !value ); 764 _applyArrowButton( this._nextButton.css('float', value ? 'left' : 'right'), value ); 765 }, 766 767 _keyDown: function (event) { 768 // Don't use $.ui.keyCode to help minification. 769 switch (event.keyCode) { 770 case 13: // Enter. 771 if (!this.element.val()) { 772 this._chooseMonth(new Date().getMonth() + 1); 773 } 774 this.Close(event); 775 break; 776 case 27: // Escape 777 case 9: // Tab 778 this.Close(event); 779 break; 780 } 781 }, 782 783 _duration: function() { 784 var _dur = this.options.Duration; 785 786 if ($.isNumeric(_dur)) { 787 return _dur; 788 } 789 790 return _dur in _speeds ? _speeds[ _dur ] : _speeds._default; 791 }, 792 793 _position: _hasPosition ? 794 function($menu) { 795 var _defauts = this.options.IsRTL ? _RTL_defaultPos : _defaultPos; 796 var _posOpts = $.extend(_defauts, this.options.Position); 797 798 // Only in IE and jQuery 1.12.0 or 2.2.0, .position() will add scrollTop to the top coordinate (#40) 799 return $menu.position($.extend({of: this.element}, _posOpts)); 800 } : 801 function($menu) { 802 // Only in IE and jQuery 1.12.0 or 2.2.0, .offset() will add scrollTop to the top coordinate (#40) 803 var _el = this.element, 804 _css = { top: (_el.offset().top + _el.height() + 7) + 'px' }; 805 806 if (this.options.IsRTL) { 807 _css.left = (_el.offset().left-$menu.width()+_el.width() + 7) + 'px'; 808 } else { 809 _css.left = _el.offset().left + 'px'; 810 } 811 812 return $menu.css(_css); 813 }, 814 815 _setUseInputMask: function () { 816 if (!this._isMonthInputType) { 817 try { 818 if (this.options.UseInputMask) { 819 this.element.mask( this._formatMonth(new Date).replace(/\d/g, 9) ); 820 } else { 821 this.element.unmask(); 822 } 823 } catch (e) {} 824 } 825 }, 826 827 _setDisabledState: function () { 828 var isDisabled = this.options.Disabled, _elem = this.element; 829 830 // Disable the associated input field. 831 _elem[0].disabled = isDisabled; 832 _elem.toggleClass(_disabledClass, isDisabled); 833 834 if (isDisabled) {
835 this._validationMessage.hide(); 836 } 837 838 this.Close(); 839 this._updateButton(); 840 841 _event('OnAfterSetDisabled', this)(isDisabled); 842 }, 843 844 _getPickerYear: function () { 845 return this._pickerYear; 846 }, 847 848 _setPickerYear: function (year) { 849 this._pickerYear = year || new Date().getFullYear(); 850 this._titleButton.jqueryUIButton({ label: this._i18n('year') + ' ' + this._pickerYear }); 851 }, 852 853 // When calling this method with a falsy (undefined) date 854 // value, this.element.val() is used as the date value. 855 // 856 // Therefore it's important to update the input field 857 // before calling this method. 858 _updateAlt: function (noop, date) { 859 var _field = $(this.options.AltField); 860 if (_field.length) { 861 _field.val( this._formatMonth(date, this.options.AltFormat) ); 862 } 863 }, 864 865 _chooseMonth: function (month) { 866 var _year = this._getPickerYear(); 867 var date = new Date(_year, month-1); 868 this.element.val(this._formatMonth( date )).blur(); 869 this._updateAlt(0, date); 870 871 _setActive( this._selectedBtn, false ); 872 this._selectedBtn = _setActive( $(this._buttons[month-1]), true ); 873 874 _event('OnAfterChooseMonth', this)(date); 875 }, 876 877 _chooseYear: function (year) { 878 this._backToYear = 0; 879 this._setPickerYear(year); 880 this._buttons.removeClass(_todayClass); 881 this._showMonths(); 882 this._applyJumpYearsHint(); 883 884 _event('OnAfterChooseYear', this)(); 885 }, 886 887 _showMonths: function () { 888 var _months = this._i18n('months'); 889 890 this._prevButton 891 .attr('title', this._i18n('prevYear')) 892 .off(click) 893 .on(click, $proxy(this._addToYear, this, -1)); 894 895 this._nextButton 896 .attr('title', this._i18n('nextYear')) 897 .off(click) 898 .on(click, $proxy(this._addToYear, this, 1)); 899 900 this._buttons.off(_eventsNs); 901 902 var me = this, _onMonthClick = $proxy(me._onMonthClick, me); 903 $.each(_months, function(index, monthName) { 904 $(me._buttons[index]) 905 .on(click, {month: index+1}, _onMonthClick ) 906 .jqueryUIButton('option', 'label', monthName); 907 }); 908 909 this._decorateButtons(); 910 }, 911 912 _showYearsClickHandler: function () { 913 this._buttons.removeClass(_todayClass); 914 if (!this._backToYear) { 915 this._backToYear = this._getPickerYear(); 916 this._showYears(); 917 918 var _label = this._i18n('backTo') + ' ' + this._getPickerYear(); 919 this._titleButton.jqueryUIButton({ label: _label }).data( _clearHint )(); 920 921 _event('OnAfterChooseYears', this)(); 922 } else { 923 this._setPickerYear(this._backToYear); 924 this._applyJumpYearsHint(); 925 this._showMonths(); 926 this._backToYear = 0; 927 } 928 }, 929 930 _showYears: function () { 931 var _currYear = this._getPickerYear(), 932 _yearDifferential = -4, 933 _firstYear = (_currYear + _yearDifferential), 934 AMOUNT_TO_ADD = 12, 935 _thisYear = new Date().getFullYear(); 936 937 var _minDate = this._MinMonth; 938 var _maxDate = this._MaxMonth; 939 var _minYear = _minDate ? _toYear(_minDate) : 0; 940 var _maxYear = _maxDate ? _toYear(_maxDate) : 0; 941 this._prevButton 942 .attr('title', this._i18n('prev12Years')) 943 .off(click) 944 .on(click, $proxy(this._addToYears, this, -AMOUNT_TO_ADD)); 945 946 this._nextButton 947 .attr('title', this._i18n('next12Years')) 948 .off(click) 949 .on(click, $proxy(this._addToYears, this, AMOUNT_TO_ADD)); 950 951 _setDisabled(this._prevButton, _minYear && (_firstYear - 1) < _minYear); 952 _setDisabled(this._nextButton, _maxYear && (_firstYear + 12) -1 > _maxYear); 953 954 this._buttons.off(_eventsNs); 955
956 _setActive( this._selectedBtn, false ); 957 958 var _selYear = this.GetSelectedYear(); 959 var _onClick = $proxy(this._onYearClick, this); 960 var _todayWithinBounds = _between(_thisYear, _minYear, _maxYear); 961 var _selWithinBounds = _between(_selYear, _minYear, _maxYear); 962 963 for (var _counter = 0; _counter < 12; _counter++) { 964 var _year = _currYear + _yearDifferential; 965 966 var _btn = $( this._buttons[_counter] ).jqueryUIButton({ 967 disabled: !_between(_year, _minYear, _maxYear), 968 label: _year 969 }) 970 .toggleClass(_todayClass, _year === _thisYear && _todayWithinBounds) // Heighlight the current year. 971 .on(click, { year: _year }, _onClick ); 972 973 // Heighlight the selected year. 974 if (_selWithinBounds && _selYear && _selYear === _year) { 975 this._selectedBtn = _setActive( _btn , true ); 976 } 977 978 _yearDifferential++; 979 } 980 }, 981 982 _onMonthClick: function(event) { 983 this._chooseMonth(event.data.month); 984 this.Close(event); 985 }, 986 987 _onYearClick: function(event) { 988 this._chooseYear(event.data.year); 989 }, 990 991 _addToYear: function(amount) { 992 this._setPickerYear( this._getPickerYear() + amount ); 993 this.element.focus(); 994 this._decorateButtons(); 995 996 _event('OnAfter' + (amount > 0 ? 'Next' : 'Previous') + 'Year', this)(); 997 }, 998 999 _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));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.