1;(function (window, $, undefined) { ;(function () { 2 "use strict"; 3 var VERSION = '2.2.3', 4 pluginName = 'airdatepicker', 5 autoInitSelector = '.airdatepicker-here', 6 $body, $airdatepickersContainer, 7 containerBuilt = false, 8 baseTemplate = '' + 9 '<div class="airdatepicker">' + 10 '<i class="airdatepicker--pointer"></i>' + 11 '<nav class="airdatepicker--nav"></nav>' + 12 '<div class="airdatepicker--content"></div>' + 13 '</div>', 14 defaults = { 15 classes: '', 16 inline: false, 17// Modified by halfdata - 2018-10-11 - begin 18 inline_popup: false, 19// Modified by halfdata - 2018-10-11 - begin 20 language: 'en', 21 startDate: new Date(), 22 firstDay: '', 23 weekends: [6, 0], 24 dateFormat: '', 25 altField: '', 26 altFieldDateFormat: '@', 27 toggleSelected: true, 28 keyboardNav: true, 29 30 position: 'bottom left', 31 offset: 12, 32 33 view: 'days', 34 minView: 'days', 35 36 showOtherMonths: true, 37 selectOtherMonths: true, 38 moveToOtherMonthsOnSelect: true, 39 40 showOtherYears: true, 41 selectOtherYears: true, 42 moveToOtherYearsOnSelect: true, 43 44 minDate: '', 45 maxDate: '', 46 disableNavWhenOutOfRange: true, 47 48 multipleDates: false, // Boolean or Number 49 multipleDatesSeparator: ',', 50 range: false, 51 52 todayButton: false,
53 clearButton: false, 54 55 showEvent: 'focus', 56 autoClose: false, 57 58 // navigation 59 monthsField: 'monthsShort', 60 prevHtml: '<svg><path d="M 17,12 l -5,5 l 5,5"></path></svg>', 61 nextHtml: '<svg><path d="M 14,12 l 5,5 l -5,5"></path></svg>', 62 navTitles: { 63 days: 'MM, <i>yyyy</i>', 64 months: 'yyyy', 65 years: 'yyyy1 - yyyy2' 66 }, 67 68 // timepicker 69 timepicker: false, 70 onlyTimepicker: false, 71 dateTimeSeparator: ' ', 72 timeFormat: '', 73 minHours: 0, 74 maxHours: 24, 75 minMinutes: 0, 76 maxMinutes: 59, 77 hoursStep: 1, 78 minutesStep: 1, 79 80 // events 81 onSelect: '', 82 onShow: '', 83 onHide: '', 84 onChangeMonth: '', 85 onChangeYear: '', 86 onChangeDecade: '', 87 onChangeView: '', 88 onRenderCell: '' 89 }, 90 hotKeys = { 91 'ctrlRight': [17, 39], 92 'ctrlUp': [17, 38], 93 'ctrlLeft': [17, 37], 94 'ctrlDown': [17, 40], 95 'shiftRight': [16, 39], 96 'shiftUp': [16, 38], 97 'shiftLeft': [16, 37], 98 'shiftDown': [16, 40], 99 'altUp': [18, 38], 100 'altRight': [18, 39], 101 'altLeft': [18, 37], 102 'altDown': [18, 40], 103 'ctrlShiftUp': [16, 17, 38] 104 }, 105 airdatepicker; 106 107 var Datepicker = function (el, options) { 108 this.el = el; 109 this.$el = $(el); 110 111 this.opts = $.extend(true, {}, defaults, options, this.$el.data()); 112 113 if ($body == undefined) { 114 $body = $('body'); 115 } 116 117 if (!this.opts.startDate) { 118 this.opts.startDate = new Date(); 119 } 120 121 if (this.el.nodeName == 'INPUT') { 122 this.elIsInput = true; 123 } 124 125 if (this.opts.altField) { 126 this.$altField = typeof this.opts.altField == 'string' ? $(this.opts.altField) : this.opts.altField; 127 } 128 129 this.inited = false; 130 this.visible = false; 131 this.silent = false; // Need to prevent unnecessary rendering 132 133 this.currentDate = this.opts.startDate; 134 this.currentView = this.opts.view; 135 this._createShortCuts(); 136 this.selectedDates = []; 137 this.views = {}; 138 this.keys = []; 139 this.minRange = ''; 140 this.maxRange = ''; 141 this._prevOnSelectValue = ''; 142 143 this.init() 144 }; 145 146 airdatepicker = Datepicker; 147 148 airdatepicker.prototype = { 149 VERSION: VERSION, 150 viewIndexes: ['days', 'months', 'years'], 151 152 init: function () { 153 if (!containerBuilt && !this.opts.inline && this.elIsInput) { 154 this._buildDatepickersContainer(); 155 } 156 this._buildBaseHtml(); 157 this._defineLocale(this.opts.language); 158 this._syncWithMinMaxDates(); 159 160 if (this.elIsInput) { 161 if (!this.opts.inline) { 162 // Set extra classes for proper transitions 163 this._setPositionClasses(this.opts.position); 164 this._bindEvents() 165 } 166 if (this.opts.keyboardNav && !this.opts.onlyTimepicker) { 167 this._bindKeyboardEvents(); 168 } 169 this.$airdatepicker.on('mousedown', this._onMouseDownDatepicker.bind(this)); 170 this.$airdatepicker.on('mouseup', this._onMouseUpDatepicker.bind(this)); 171 } 172 173 if (this.opts.classes) { 174 this.$airdatepicker.addClass(this.opts.classes) 175 } 176 177 if (this.opts.timepicker) { 178 this.timepicker = new $.fn.airdatepicker.Timepicker(this, this.opts); 179 this._bindTimepickerEvents(); 180 } 181 182 if (this.opts.onlyTimepicker) { 183 this.$airdatepicker.addClass('-only-timepicker-'); 184 } 185 186 this.views[this.currentView] = new $.fn.airdatepicker.Body(this, this.currentView, this.opts); 187 this.views[this.currentView].show(); 188 this.nav = new $.fn.airdatepicker.Navigation(this, this.opts); 189 this.view = this.currentView; 190 191 this.$el.on('clickCell.adp', this._onClickCell.bind(this)); 192 this.$airdatepicker.on('mouseenter', '.airdatepicker--cell', this._onMouseEnterCell.bind(this)); 193 this.$airdatepicker.on('mouseleave', '.airdatepicker--cell', this._onMouseLeaveCell.bind(this)); 194 195 this.inited = true; 196 }, 197 198 _createShortCuts: function () { 199 this.minDate = this.opts.minDate ? this.opts.minDate : new Date(-8639999913600000); 200 this.maxDate = this.opts.maxDate ? this.opts.maxDate : new Date(8639999913600000); 201 }, 202 203 _bindEvents : function () { 204 this.$el.on(this.opts.showEvent + '.adp', this._onShowEvent.bind(this)); 205 this.$el.on('mouseup.adp', this._onMouseUpEl.bind(this)); 206 this.$el.on('blur.adp', this._onBlur.bind(this)); 207 this.$el.on('keyup.adp', this._onKeyUpGeneral.bind(this)); 208 $(window).on('resize.adp', this._onResize.bind(this)); 209 $('body').on('mouseup.adp', this._onMouseUpBody.bind(this)); 210 }, 211 212 _bindKeyboardEvents: function () { 213 this.$el.on('keydown.adp', this._onKeyDown.bind(this)); 214 this.$el.on('keyup.adp', this._onKeyUp.bind(this)); 215 this.$el.on('hotKey.adp', this._onHotKey.bind(this)); 216 }, 217 218 _bindTimepickerEvents: function () { 219 this.$el.on('timeChange.adp', this._onTimeChange.bind(this)); 220 }, 221 222 isWeekend: function (day) { 223 return this.opts.weekends.indexOf(day) !== -1; 224 }, 225 226 _defineLocale: function (lang) { 227 if (typeof lang == 'string') { 228 this.loc = $.fn.airdatepicker.language[lang]; 229 if (!this.loc) { 230 console.warn('Can\'t find language "' + lang + '" in Datepicker.language, will use "en" instead'); 231 this.loc = $.extend(true, {}, $.fn.airdatepicker.language.ru) 232 } 233 234 this.loc = $.extend(true, {}, $.fn.airdatepicker.language.ru, $.fn.airdatepicker.language[lang]) 235 } else { 236 this.loc = $.extend(true, {}, $.fn.airdatepicker.language.ru, lang) 237 } 238 239 if (this.opts.dateFormat) { 240 this.loc.dateFormat = this.opts.dateFormat 241 } 242 243 if (this.opts.timeFormat) { 244 this.loc.timeFormat = this.opts.timeFormat 245 } 246 247 if (this.opts.firstDay !== '') { 248 this.loc.firstDay = this.opts.firstDay 249 } 250 251 if (this.opts.timepicker) { 252 this.loc.dateFormat = [this.loc.dateFormat, this.loc.timeFormat].join(this.opts.dateTimeSeparator); 253 } 254 255 if (this.opts.onlyTimepicker) { 256 this.loc.dateFormat = this.loc.timeFormat; 257 } 258 259 var boundary = this._getWordBoundaryRegExp; 260 if (this.loc.timeFormat.match(boundary('aa')) || 261 this.loc.timeFormat.match(boundary('AA')) 262 ) { 263 this.ampm = true; 264 } 265 }, 266 267 _buildDatepickersContainer: function () { 268 containerBuilt = true; 269 $body.append('<div class="airdatepickers-container" id="airdatepickers-container"></div>'); 270 $airdatepickersContainer = $('#airdatepickers-container'); 271 }, 272 273 _buildBaseHtml: function () { 274 var $appendTarget,
275 $inline = $('<div class="airdatepicker-inline">'); 276 277 if(this.el.nodeName == 'INPUT') { 278 if (!this.opts.inline) { 279// Modified by halfdata - 2018-10-11 - begin 280 //$appendTarget = $airdatepickersContainer; 281 if (!this.opts.inline_popup) $appendTarget = $airdatepickersContainer; 282 else $appendTarget = jQuery(this.$el).parent(); 283// Modified by halfdata - 2018-10-11 - end 284 } else { 285 $appendTarget = $inline.insertAfter(this.$el) 286 } 287 } else { 288 $appendTarget = $inline.appendTo(this.$el) 289 } 290 291 this.$airdatepicker = $(baseTemplate).appendTo($appendTarget); 292 this.$content = $('.airdatepicker--content', this.$airdatepicker); 293 this.$nav = $('.airdatepicker--nav', this.$airdatepicker); 294 }, 295 296 _triggerOnChange: function () { 297 if (!this.selectedDates.length) { 298 // Prevent from triggering multiple onSelect callback with same argument (empty string) in IE10-11 299 if (this._prevOnSelectValue === '') return; 300 this._prevOnSelectValue = ''; 301 return this.opts.onSelect('', '', this); 302 } 303 304 var selectedDates = this.selectedDates, 305 parsedSelected = airdatepicker.getParsedDate(selectedDates[0]), 306 formattedDates, 307 _this = this, 308 dates = new Date( 309 parsedSelected.year, 310 parsedSelected.month, 311 parsedSelected.date, 312 parsedSelected.hours, 313 parsedSelected.minutes 314 ); 315 316 formattedDates = selectedDates.map(function (date) { 317 return _this.formatDate(_this.loc.dateFormat, date) 318 }).join(this.opts.multipleDatesSeparator); 319 320 // Create new dates array, to separate it from original selectedDates 321 if (this.opts.multipleDates || this.opts.range) { 322 dates = selectedDates.map(function(date) { 323 var parsedDate = airdatepicker.getParsedDate(date); 324 return new Date( 325 parsedDate.year, 326 parsedDate.month, 327 parsedDate.date, 328 parsedDate.hours, 329 parsedDate.minutes 330 ); 331 }) 332 } 333 334 this._prevOnSelectValue = formattedDates; 335 this.opts.onSelect(formattedDates, dates, this); 336 }, 337 338 next: function () { 339 var d = this.parsedDate, 340 o = this.opts; 341 switch (this.view) { 342 case 'days': 343 this.date = new Date(d.year, d.month + 1, 1); 344 if (o.onChangeMonth) o.onChangeMonth(this.parsedDate.month, this.parsedDate.year); 345 break; 346 case 'months': 347 this.date = new Date(d.year + 1, d.month, 1); 348 if (o.onChangeYear) o.onChangeYear(this.parsedDate.year); 349 break; 350 case 'years': 351 this.date = new Date(d.year + 10, 0, 1); 352 if (o.onChangeDecade) o.onChangeDecade(this.curDecade); 353 break; 354 } 355 }, 356 357 prev: function () { 358 var d = this.parsedDate, 359 o = this.opts; 360 switch (this.view) { 361 case 'days': 362 this.date = new Date(d.year, d.month - 1, 1); 363 if (o.onChangeMonth) o.onChangeMonth(this.parsedDate.month, this.parsedDate.year); 364 break; 365 case 'months': 366 this.date = new Date(d.year - 1, d.month, 1); 367 if (o.onChangeYear) o.onChangeYear(this.parsedDate.year); 368 break; 369 case 'years': 370 this.date = new Date(d.year - 10, 0, 1); 371 if (o.onChangeDecade) o.onChangeDecade(this.curDecade); 372 break; 373 } 374 }, 375 376 formatDate: function (string, date) { 377 date = date || this.date; 378 var result = string, 379 boundary = this._getWordBoundaryRegExp, 380 locale = this.loc, 381 leadingZero = airdatepicker.getLeadingZeroNum, 382 decade = airdatepicker.getDecade(date), 383 d = airdatepicker.getParsedDate(date), 384 fullHours = d.fullHours, 385 hours = d.hours, 386 ampm = string.match(boundary('aa')) || string.match(boundary('AA')), 387 dayPeriod = 'am', 388 replacer = this._replacer, 389 validHours; 390 391 if (this.opts.timepicker && this.timepicker && ampm) { 392 validHours = this.timepicker._getValidHoursFromDate(date, ampm); 393 fullHours = leadingZero(validHours.hours); 394 hours = validHours.hours; 395 dayPeriod = validHours.dayPeriod; 396 } 397 398 switch (true) { 399 case /@/.test(result): 400 result = result.replace(/@/, date.getTime()); 401 case /aa/.test(result): 402 result = replacer(result, boundary('aa'), dayPeriod); 403 case /AA/.test(result): 404 result = replacer(result, boundary('AA'), dayPeriod.toUpperCase()); 405 case /dd/.test(result): 406 result = replacer(result, boundary('dd'), d.fullDate); 407 case /d/.test(result): 408 result = replacer(result, boundary('d'), d.date); 409 case /DD/.test(result): 410 result = replacer(result, boundary('DD'), locale.days[d.day]); 411 case /D/.test(result): 412 result = replacer(result, boundary('D'), locale.daysShort[d.day]); 413 case /mm/.test(result): 414 result = replacer(result, boundary('mm'), d.fullMonth); 415 case /m/.test(result): 416 result = replacer(result, boundary('m'), d.month + 1); 417 case /MM/.test(result): 418 result = replacer(result, boundary('MM'), this.loc.months[d.month]); 419 case /M/.test(result): 420 result = replacer(result, boundary('M'), locale.monthsShort[d.month]); 421 case /ii/.test(result): 422 result = replacer(result, boundary('ii'), d.fullMinutes); 423 case /i/.test(result): 424 result = replacer(result, boundary('i'), d.minutes); 425 case /hh/.test(result): 426 result = replacer(result, boundary('hh'), fullHours); 427 case /h/.test(result): 428 result = replacer(result, boundary('h'), hours); 429 case /yyyy/.test(result): 430 result = replacer(result, boundary('yyyy'), d.year); 431 case /yyyy1/.test(result): 432 result = replacer(result, boundary('yyyy1'), decade[0]); 433 case /yyyy2/.test(result): 434 result = replacer(result, boundary('yyyy2'), decade[1]); 435 case /yy/.test(result): 436 result = replacer(result, boundary('yy'), d.year.toString().slice(-2)); 437 } 438 439 return result; 440 }, 441 442 _replacer: function (str, reg, data) { 443 return str.replace(reg, function (match, p1,p2,p3) { 444 return p1 + data + p3; 445 }) 446 }, 447 448 _getWordBoundaryRegExp: function (sign) { 449 var symbols = '\\s|\\.|-|/|\\\\|,|\\$|\\!|\\?|:|;'; 450 451 return new RegExp('(^|>|' + symbols + ')(' + sign + ')($|<|' + symbols + ')', 'g'); 452 }, 453 454 455 selectDate: function (date) { 456 var _this = this, 457 opts = _this.opts, 458 d = _this.parsedDate, 459 selectedDates = _this.selectedDates, 460 len = selectedDates.length, 461 newDate = ''; 462 463 if (Array.isArray(date)) { 464 date.forEach(function (d) { 465 _this.selectDate(d) 466 }); 467 return; 468 } 469 470 if (!(date instanceof Date)) return; 471 472 this.lastSelectedDate = date; 473 474 // Set new time values from Date 475 if (this.timepicker) { 476 this.timepicker._setTime(date); 477 } 478
479 // On this step timepicker will set valid values in it's instance 480 _this._trigger('selectDate', date); 481 482 // Set correct time values after timepicker's validation 483 // Prevent from setting hours or minutes which values are lesser then `min` value or 484 // greater then `max` value 485 if (this.timepicker) { 486 date.setHours(this.timepicker.hours); 487 date.setMinutes(this.timepicker.minutes) 488 } 489 490 if (_this.view == 'days') { 491 if (date.getMonth() != d.month && opts.moveToOtherMonthsOnSelect) { 492 newDate = new Date(date.getFullYear(), date.getMonth(), 1); 493 } 494 } 495 496 if (_this.view == 'years') { 497 if (date.getFullYear() != d.year && opts.moveToOtherYearsOnSelect) { 498 newDate = new Date(date.getFullYear(), 0, 1); 499 } 500 } 501 502 if (newDate) { 503 _this.silent = true; 504 _this.date = newDate; 505 _this.silent = false; 506 _this.nav._render() 507 } 508 509 if (opts.multipleDates && !opts.range) { // Set priority to range functionality 510 if (len === opts.multipleDates) return; 511 if (!_this._isSelected(date)) { 512 _this.selectedDates.push(date); 513 } 514 } else if (opts.range) { 515 if (len == 2) { 516 _this.selectedDates = [date]; 517 _this.minRange = date; 518 _this.maxRange = ''; 519 } else if (len == 1) { 520 _this.selectedDates.push(date); 521 if (!_this.maxRange){ 522 _this.maxRange = date; 523 } else { 524 _this.minRange = date; 525 } 526 // Swap dates if they were selected via dp.selectDate() and second date was smaller then first 527 if (airdatepicker.bigger(_this.maxRange, _this.minRange)) { 528 _this.maxRange = _this.minRange; 529 _this.minRange = date; 530 } 531 _this.selectedDates = [_this.minRange, _this.maxRange] 532 533 } else { 534 _this.selectedDates = [date]; 535 _this.minRange = date; 536 } 537 } else { 538 _this.selectedDates = [date]; 539 } 540 541 _this._setInputValue(); 542 543 if (opts.onSelect) { 544 _this._triggerOnChange(); 545 } 546 547 if (opts.autoClose && !this.timepickerIsActive) { 548 if (!opts.multipleDates && !opts.range) { 549 _this.hide(); 550 } else if (opts.range && _this.selectedDates.length == 2) { 551 _this.hide(); 552 } 553 } 554 555 _this.views[this.currentView]._render() 556 }, 557 558 removeDate: function (date) { 559 var selected = this.selectedDates, 560 _this = this; 561 562 if (!(date instanceof Date)) return; 563 564 return selected.some(function (curDate, i) { 565 if (airdatepicker.isSame(curDate, date)) { 566 selected.splice(i, 1); 567 568 if (!_this.selectedDates.length) { 569 _this.minRange = ''; 570 _this.maxRange = ''; 571 _this.lastSelectedDate = ''; 572 } else { 573 _this.lastSelectedDate = _this.selectedDates[_this.selectedDates.length - 1]; 574 } 575 576 _this.views[_this.currentView]._render(); 577 _this._setInputValue(); 578 579 if (_this.opts.onSelect) { 580 _this._triggerOnChange(); 581 } 582 583 return true 584 } 585 }) 586 }, 587 588 today: function () { 589 this.silent = true; 590 this.view = this.opts.minView; 591 this.silent = false; 592 this.date = new Date(); 593 594 if (this.opts.todayButton instanceof Date) { 595 this.selectDate(this.opts.todayButton) 596 } 597 }, 598 599 clear: function () { 600 this.selectedDates = []; 601 this.minRange = ''; 602 this.maxRange = ''; 603 this.views[this.currentView]._render(); 604 this._setInputValue(); 605 if (this.opts.onSelect) { 606 this._triggerOnChange() 607 } 608 }, 609 610 /** 611 * Updates airdatepicker options 612 * @param {String|Object} param - parameter's name to update. If object then it will extend current options 613 * @param {String|Number|Object} [value] - new param value 614 */ 615 update: function (param, value) { 616 var len = arguments.length, 617 lastSelectedDate = this.lastSelectedDate; 618 619 if (len == 2) { 620 this.opts[param] = value; 621 } else if (len == 1 && typeof param == 'object') { 622 this.opts = $.extend(true, this.opts, param) 623 } 624 625 this._createShortCuts(); 626 this._syncWithMinMaxDates(); 627 this._defineLocale(this.opts.language); 628 this.nav._addButtonsIfNeed(); 629 if (!this.opts.onlyTimepicker) this.nav._render(); 630 this.views[this.currentView]._render(); 631 632 if (this.elIsInput && !this.opts.inline) { 633 this._setPositionClasses(this.opts.position); 634 if (this.visible) { 635 this.setPosition(this.opts.position) 636 } 637 } 638 639 if (this.opts.classes) { 640 this.$airdatepicker.addClass(this.opts.classes) 641 } 642 643 if (this.opts.onlyTimepicker) { 644 this.$airdatepicker.addClass('-only-timepicker-'); 645 } 646 647 if (this.opts.timepicker) { 648 if (lastSelectedDate) this.timepicker._handleDate(lastSelectedDate); 649 this.timepicker._updateRanges(); 650 this.timepicker._updateCurrentTime(); 651 // Change hours and minutes if it's values have been changed through min/max hours/minutes 652 if (lastSelectedDate) { 653 lastSelectedDate.setHours(this.timepicker.hours); 654 lastSelectedDate.setMinutes(this.timepicker.minutes); 655 } 656 } 657 658 this._setInputValue(); 659 660 return this; 661 }, 662 663 _syncWithMinMaxDates: function () { 664 var curTime = this.date.getTime(); 665 this.silent = true; 666 if (this.minTime > curTime) { 667 this.date = this.minDate; 668 } 669 670 if (this.maxTime < curTime) { 671 this.date = this.maxDate; 672 } 673 this.silent = false;
674 }, 675 676 _isSelected: function (checkDate, cellType) { 677 var res = false; 678 this.selectedDates.some(function (date) { 679 if (airdatepicker.isSame(date, checkDate, cellType)) { 680 res = date; 681 return true; 682 } 683 }); 684 return res; 685 }, 686 687 _setInputValue: function () { 688 var _this = this, 689 opts = _this.opts, 690 format = _this.loc.dateFormat, 691 altFormat = opts.altFieldDateFormat, 692 value = _this.selectedDates.map(function (date) { 693 return _this.formatDate(format, date) 694 }), 695 altValues; 696 697 if (opts.altField && _this.$altField.length) { 698 altValues = this.selectedDates.map(function (date) { 699 return _this.formatDate(altFormat, date) 700 }); 701 altValues = altValues.join(this.opts.multipleDatesSeparator); 702 this.$altField.val(altValues); 703 } 704 705 value = value.join(this.opts.multipleDatesSeparator); 706 707 this.$el.val(value) 708 }, 709 710 /** 711 * Check if date is between minDate and maxDate 712 * @param date {object} - date object 713 * @param type {string} - cell type 714 * @returns {boolean} 715 * @private 716 */ 717 _isInRange: function (date, type) { 718 var time = date.getTime(), 719 d = airdatepicker.getParsedDate(date), 720 min = airdatepicker.getParsedDate(this.minDate), 721 max = airdatepicker.getParsedDate(this.maxDate), 722 dMinTime = new Date(d.year, d.month, min.date).getTime(), 723 dMaxTime = new Date(d.year, d.month, max.date).getTime(), 724 types = { 725 day: time >= this.minTime && time <= this.maxTime, 726 month: dMinTime >= this.minTime && dMaxTime <= this.maxTime, 727 year: d.year >= min.year && d.year <= max.year 728 }; 729 return type ? types[type] : types.day 730 }, 731 732 _getDimensions: function ($el) { 733 var offset = $el.offset(); 734 735 return { 736 width: $el.outerWidth(), 737 height: $el.outerHeight(), 738 left: offset.left, 739 top: offset.top 740 } 741 }, 742 743 _getDateFromCell: function (cell) { 744 var curDate = this.parsedDate, 745 year = cell.data('year') || curDate.year, 746 month = cell.data('month') == undefined ? curDate.month : cell.data('month'), 747 date = cell.data('date') || 1; 748 749 return new Date(year, month, date); 750 }, 751 752 _setPositionClasses: function (pos) { 753 pos = pos.split(' '); 754 var main = pos[0], 755 sec = pos[1], 756 classes = 'airdatepicker -' + main + '-' + sec + '- -from-' + main + '-'; 757 758 if (this.visible) classes += ' active'; 759 760 this.$airdatepicker 761 .removeAttr('class')
762 .addClass(classes); 763 }, 764 765 setPosition: function (position) { 766 position = position || this.opts.position; 767 768 var dims = this._getDimensions(this.$el), 769 selfDims = this._getDimensions(this.$airdatepicker), 770 pos = position.split(' '), 771 top, left, 772 offset = this.opts.offset, 773 main = pos[0], 774 secondary = pos[1]; 775 776// Modified by halfdata - 2018-10-11 - begin 777 if (this.opts.inline_popup) { 778 dims.left = 0; 779 dims.top = 0; 780 } 781// Modified by halfdata - 2018-10-11 - end 782 783 switch (main) { 784 case 'top': 785 top = dims.top - selfDims.height - offset; 786 break; 787 case 'right': 788 left = dims.left + dims.width + offset; 789 break; 790 case 'bottom': 791 top = dims.top + dims.height + offset; 792 break; 793 case 'left': 794 left = dims.left - selfDims.width - offset; 795 break; 796 } 797 798 switch(secondary) { 799 case 'top': 800 top = dims.top; 801 break; 802 case 'right': 803 left = dims.left + dims.width - selfDims.width; 804 break; 805 case 'bottom': 806 top = dims.top + dims.height - selfDims.height; 807 break; 808 case 'left': 809 left = dims.left; 810 break; 811 case 'center': 812 if (/left|right/.test(main)) { 813 top = dims.top + dims.height/2 - selfDims.height/2; 814 } else { 815 left = dims.left + dims.width/2 - selfDims.width/2; 816 } 817 } 818 819 this.$airdatepicker 820 .css({ 821 left: left, 822 top: top 823 }) 824 }, 825 826 show: function () { 827 var onShow = this.opts.onShow; 828 829 this.setPosition(this.opts.position); 830 this.$airdatepicker.addClass('active'); 831 this.visible = true; 832 833 if (onShow) { 834 this._bindVisionEvents(onShow) 835 } 836 }, 837 838 hide: function () { 839 var onHide = this.opts.onHide; 840 841 this.$airdatepicker 842 .removeClass('active') 843 .css({ 844 left: '-100000px' 845 }); 846 847 this.focused = ''; 848 this.keys = []; 849 850 this.inFocus = false; 851 this.visible = false; 852 this.$el.blur(); 853 854 if (onHide) { 855 this._bindVisionEvents(onHide) 856 } 857 }, 858 859 down: function (date) { 860 this._changeView(date, 'down'); 861 }, 862 863 up: function (date) { 864 this._changeView(date, 'up'); 865 }, 866 867 _bindVisionEvents: function (event) { 868 this.$airdatepicker.off('transitionend.dp'); 869 event(this, false); 870 this.$airdatepicker.one('transitionend.dp', event.bind(this, this, true)) 871 }, 872 873 _changeView: function (date, dir) { 874 date = date || this.focused || this.date; 875 876 var nextView = dir == 'up' ? this.viewIndex + 1 : this.viewIndex - 1; 877 if (nextView > 2) nextView = 2; 878 if (nextView < 0) nextView = 0; 879 880 this.silent = true; 881 this.date = new Date(date.getFullYear(), date.getMonth(), 1); 882 this.silent = false; 883 this.view = this.viewIndexes[nextView]; 884 885 }, 886 887 _handleHotKey: function (key) { 888 var date = airdatepicker.getParsedDate(this._getFocusedDate()), 889 focusedParsed, 890 o = this.opts, 891 newDate, 892 totalDaysInNextMonth, 893 monthChanged = false, 894 yearChanged = false, 895 decadeChanged = false, 896 y = date.year, 897 m = date.month, 898 d = date.date; 899 900 switch (key) { 901 case 'ctrlRight': 902 case 'ctrlUp': 903 m += 1; 904 monthChanged = true; 905 break; 906 case 'ctrlLeft': 907 case 'ctrlDown': 908 m -= 1; 909 monthChanged = true; 910 break; 911 case 'shiftRight': 912 case 'shiftUp': 913 yearChanged = true; 914 y += 1; 915 break; 916 case 'shiftLeft': 917 case 'shiftDown': 918 yearChanged = true; 919 y -= 1; 920 break; 921 case 'altRight': 922 case 'altUp': 923 decadeChanged = true; 924 y += 10; 925 break; 926 case 'altLeft': 927 case 'altDown': 928 decadeChanged = true; 929 y -= 10; 930 break; 931 case 'ctrlShiftUp': 932 this.up(); 933 break; 934 } 935 936 totalDaysInNextMonth = airdatepicker.getDaysCount(new Date(y,m)); 937 newDate = new Date(y,m,d); 938 939 // If next month has less days than current, set date to total days in that month 940 if (totalDaysInNextMonth < d) d = totalDaysInNextMonth; 941 942 // Check if newDate is in valid range 943 if (newDate.getTime() < this.minTime) { 944 newDate = this.minDate; 945 } else if (newDate.getTime() > this.maxTime) { 946 newDate = this.maxDate; 947 } 948 949 this.focused = newDate; 950 951 focusedParsed = airdatepicker.getParsedDate(newDate);
952 if (monthChanged && o.onChangeMonth) { 953 o.onChangeMonth(focusedParsed.month, focusedParsed.year) 954 } 955 if (yearChanged && o.onChangeYear) { 956 o.onChangeYear(focusedParsed.year) 957 } 958 if (decadeChanged && o.onChangeDecade) { 959 o.onChangeDecade(this.curDecade) 960 } 961 }, 962 963 _registerKey: function (key) { 964 var exists = this.keys.some(function (curKey) { 965 return curKey == key; 966 }); 967 968 if (!exists) { 969 this.keys.push(key) 970 } 971 }, 972 973 _unRegisterKey: function (key) { 974 var index = this.keys.indexOf(key); 975 976 this.keys.splice(index, 1); 977 }, 978 979 _isHotKeyPressed: function () { 980 var currentHotKey, 981 found = false, 982 _this = this, 983 pressedKeys = this.keys.sort(); 984 985 for (var hotKey in hotKeys) { 986 currentHotKey = hotKeys[hotKey]; 987 if (pressedKeys.length != currentHotKey.length) continue; 988 989 if (currentHotKey.every(function (key, i) { return key == pressedKeys[i]})) { 990 _this._trigger('hotKey', hotKey); 991 found = true; 992 } 993 } 994 995 return found; 996 }, 997 998 _trigger: function (event, args) { 999 this.$el.trigger(event, args) 1000 }, 1001 1002 _focusNextCell: function (keyCode, type) { 1003 type = type || this.cellType; 1004 1005 var date = airdatepicker.getParsedDate(this._getFocusedDate()), 1006 y = date.year, 1007 m = date.month, 1008 d = date.date; 1009 1010 if (this._isHotKeyPressed()){ 1011 return; 1012 } 1013 1014 switch(keyCode) { 1015 case 37: // left 1016 type == 'day' ? (d -= 1) : ''; 1017 type == 'month' ? (m -= 1) : ''; 1018 type == 'year' ? (y -= 1) : ''; 1019 break; 1020 case 38: // up 1021 type == 'day' ? (d -= 7) : ''; 1022 type == 'month' ? (m -= 3) : ''; 1023 type == 'year' ? (y -= 4) : ''; 1024 break; 1025 case 39: // right 1026 type == 'day' ? (d += 1) : ''; 1027 type == 'month' ? (m += 1) : ''; 1028 type == 'year' ? (y += 1) : ''; 1029 break; 1030 case 40: // down 1031 type == 'day' ? (d += 7) : ''; 1032 type == 'month' ? (m += 3) : ''; 1033 type == 'year' ? (y += 4) : ''; 1034 break; 1035 } 1036 1037 var nd = new Date(y,m,d); 1038 if (nd.getTime() < this.minTime) { 1039 nd = this.minDate; 1040 } else if (nd.getTime() > this.maxTime) { 1041 nd = this.maxDate; 1042 } 1043 1044 this.focused = nd; 1045 1046 }, 1047 1048 _getFocusedDate: function () { 1049 var focused = this.focused || this.selectedDates[this.selectedDates.length - 1], 1050 d = this.parsedDate; 1051 1052 if (!focused) { 1053 switch (this.view) { 1054 case 'days': 1055 focused = new Date(d.year, d.month, new Date().getDate()); 1056 break; 1057 case 'months': 1058 focused = new Date(d.year, d.month, 1); 1059 break; 1060 case 'years': 1061 focused = new Date(d.year, 0, 1); 1062 break; 1063 } 1064 } 1065 1066 return focused; 1067 }, 1068 1069 _getCell: function (date, type) { 1070 type = type || this.cellType; 1071 1072 var d = airdatepicker.getParsedDate(date), 1073 selector = '.airdatepicker--cell[data-year="' + d.year + '"]', 1074 $cell; 1075 1076 switch (type) { 1077 case 'month': 1078 selector = '[data-month="' + d.month + '"]'; 1079 break; 1080 case 'day': 1081 selector += '[data-month="' + d.month + '"][data-date="' + d.date + '"]'; 1082 break; 1083 } 1084 $cell = this.views[this.currentView].$el.find(selector); 1085 1086 return $cell.length ? $cell : $(''); 1087 }, 1088 1089 destroy: function () { 1090 var _this = this; 1091 _this.$el 1092 .off('.adp') 1093 .data('airdatepicker', ''); 1094 1095 _this.selectedDates = []; 1096 _this.focused = ''; 1097 _this.views = {}; 1098 _this.keys = []; 1099 _this.minRange = ''; 1100 _this.maxRange = ''; 1101 1102 if (_this.opts.inline || !_this.elIsInput) { 1103 _this.$airdatepicker.closest('.airdatepicker-inline').remove(); 1104 } else { 1105 _this.$airdatepicker.remove(); 1106 } 1107 }, 1108 1109 _handleAlreadySelectedDates: function (alreadySelected, selectedDate) { 1110 if (this.opts.range) { 1111 if (!this.opts.toggleSelected) { 1112 // Add possibility to select same date when range is true 1113 if (this.selectedDates.length != 2) { 1114 this._trigger('clickCell', selectedDate); 1115 } 1116 } else { 1117 this.removeDate(selectedDate); 1118 } 1119 } else if (this.opts.toggleSelected){ 1120 this.removeDate(selectedDate); 1121 } 1122 1123 // Change last selected date to be able to change time when clicking on this cell 1124 if (!this.opts.toggleSelected) { 1125 this.lastSelectedDate = alreadySelected; 1126 if (this.opts.timepicker) { 1127 this.timepicker._setTime(alreadySelected);
1128 this.timepicker.update(); 1129 } 1130 } 1131 }, 1132 1133 _onShowEvent: function (e) { 1134 if (!this.visible) { 1135 this.show(); 1136 } 1137 }, 1138 1139 _onBlur: function () { 1140 if (!this.inFocus && this.visible) { 1141 this.hide(); 1142 } 1143 }, 1144 1145 _onMouseDownDatepicker: function (e) { 1146 this.inFocus = true; 1147 }, 1148 1149 _onMouseUpDatepicker: function (e) { 1150 this.inFocus = false; 1151 e.originalEvent.inFocus = true; 1152 if (!e.originalEvent.timepickerFocus) this.$el.focus(); 1153 }, 1154 1155 _onKeyUpGeneral: function (e) { 1156 var val = this.$el.val(); 1157 1158 if (!val) { 1159 this.clear(); 1160 } 1161 }, 1162 1163 _onResize: function () { 1164 if (this.visible) { 1165 this.setPosition(); 1166 } 1167 }, 1168 1169 _onMouseUpBody: function (e) { 1170 if (e.originalEvent.inFocus) return; 1171 1172 if (this.visible && !this.inFocus) { 1173 this.hide(); 1174 } 1175 }, 1176 1177 _onMouseUpEl: function (e) { 1178 e.originalEvent.inFocus = true; 1179 setTimeout(this._onKeyUpGeneral.bind(this),4); 1180 }, 1181 1182 _onKeyDown: function (e) { 1183 var code = e.which; 1184 this._registerKey(code); 1185 1186 // Arrows 1187 if (code >= 37 && code <= 40) { 1188 e.preventDefault(); 1189 this._focusNextCell(code); 1190 } 1191 1192 // Enter 1193 if (code == 13) { 1194 if (this.focused) { 1195 if (this._getCell(this.focused).hasClass('-disabled-')) return; 1196 if (this.view != this.opts.minView) { 1197 this.down() 1198 } else { 1199 var alreadySelected = this._isSelected(this.focused, this.cellType); 1200 1201 if (!alreadySelected) { 1202 if (this.timepicker) { 1203 this.focused.setHours(this.timepicker.hours); 1204 this.focused.setMinutes(this.timepicker.minutes); 1205 } 1206 this.selectDate(this.focused); 1207 return; 1208 } 1209 this._handleAlreadySelectedDates(alreadySelected, this.focused) 1210 } 1211 } 1212 } 1213 1214 // Esc 1215 if (code == 27) { 1216 this.hide(); 1217 } 1218 }, 1219 1220 _onKeyUp: function (e) { 1221 var code = e.which; 1222 this._unRegisterKey(code); 1223 }, 1224 1225 _onHotKey: function (e, hotKey) { 1226 this._handleHotKey(hotKey); 1227 }, 1228 1229 _onMouseEnterCell: function (e) { 1230 var $cell = $(e.target).closest('.airdatepicker--cell'), 1231 date = this._getDateFromCell($cell); 1232 1233 // Prevent from unnecessary rendering and setting new currentDate 1234 this.silent = true; 1235 1236 if (this.focused) { 1237 this.focused = '' 1238 } 1239 1240 $cell.addClass('-focus-'); 1241 1242 this.focused = date; 1243 this.silent = false; 1244 1245 if (this.opts.range && this.selectedDates.length == 1) { 1246 this.minRange = this.selectedDates[0]; 1247 this.maxRange = ''; 1248 if (airdatepicker.less(this.minRange, this.focused)) { 1249 this.maxRange = this.minRange; 1250 this.minRange = ''; 1251 } 1252 this.views[this.currentView]._update(); 1253 } 1254 }, 1255 1256 _onMouseLeaveCell: function (e) { 1257 var $cell = $(e.target).closest('.airdatepicker--cell'); 1258 1259 $cell.removeClass('-focus-'); 1260 1261 this.silent = true; 1262 this.focused = ''; 1263 this.silent = false; 1264 }, 1265 1266 _onTimeChange: function (e, h, m) { 1267 var date = new Date(), 1268 selectedDates = this.selectedDates, 1269 selected = false; 1270 1271 if (selectedDates.length) { 1272 selected = true; 1273 date = this.lastSelectedDate; 1274 } 1275 1276 date.setHours(h); 1277 date.setMinutes(m); 1278 1279 if (!selected && !this._getCell(date).hasClass('-disabled-')) { 1280 this.selectDate(date); 1281 } else { 1282 this._setInputValue(); 1283 if (this.opts.onSelect) { 1284 this._triggerOnChange(); 1285 } 1286 } 1287 }, 1288 1289 _onClickCell: function (e, date) { 1290 if (this.timepicker) { 1291 date.setHours(this.timepicker.hours); 1292 date.setMinutes(this.timepicker.minutes); 1293 } 1294 this.selectDate(date); 1295 }, 1296 1297 set focused(val) { 1298 if (!val && this.focused) { 1299 var $cell = this._getCell(this.focused); 1300 1301 if ($cell.length) { 1302 $cell.removeClass('-focus-') 1303 } 1304 } 1305 this._focused = val; 1306 if (this.opts.range && this.selectedDates.length == 1) { 1307 this.minRange = this.selectedDates[0]; 1308 this.maxRange = ''; 1309 if (airdatepicker.less(this.minRange, this._focused)) { 1310 this.maxRange = this.minRange; 1311 this.minRange = ''; 1312 } 1313 } 1314 if (this.silent) return; 1315 this.date = val; 1316 }, 1317 1318 get focused() { 1319 return this._focused; 1320 }, 1321 1322 get parsedDate() { 1323 return airdatepicker.getParsedDate(this.date); 1324 }, 1325 1326 set date (val) { 1327 if (!(val instanceof Date)) return; 1328 1329 this.currentDate = val; 1330 1331 if (this.inited && !this.silent) { 1332 this.views[this.view]._render(); 1333 this.nav._render(); 1334 if (this.visible && this.elIsInput) { 1335 this.setPosition(); 1336 } 1337 } 1338 return val; 1339 }, 1340 1341 get date () { 1342 return this.currentDate 1343 }, 1344 1345 set view (val) { 1346 this.viewIndex = this.viewIndexes.indexOf(val); 1347 1348 if (this.viewIndex < 0) { 1349 return; 1350 } 1351 1352 this.prevView = this.currentView; 1353 this.currentView = val; 1354 1355 if (this.inited) { 1356 if (!this.views[val]) { 1357 this.views[val] = new $.fn.airdatepicker.Body(this, val, this.opts) 1358 } else { 1359 this.views[val]._render(); 1360 } 1361 1362 this.views[this.prevView].hide(); 1363 this.views[val].show(); 1364 this.nav._render(); 1365 1366 if (this.opts.onChangeView) { 1367 this.opts.onChangeView(val) 1368 } 1369 if (this.elIsInput && this.visible) this.setPosition(); 1370 } 1371 1372 return val 1373 }, 1374 1375 get view() { 1376 return this.currentView; 1377 }, 1378 1379 get cellType() { 1380 return this.view.substring(0, this.view.length - 1) 1381 }, 1382 1383 get minTime() { 1384 var min = airdatepicker.getParsedDate(this.minDate); 1385 return new Date(min.year, min.month, min.date).getTime() 1386 }, 1387 1388 get maxTime() { 1389 var max = airdatepicker.getParsedDate(this.maxDate); 1390 return new Date(max.year, max.month, max.date).getTime() 1391 }, 1392 1393 get curDecade() { 1394 return airdatepicker.getDecade(this.date) 1395 } 1396 }; 1397 1398 // Utils 1399 // ------------------------------------------------- 1400 1401 airdatepicker.getDaysCount = function (date) { 1402 return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate(); 1403 }; 1404 1405 airdatepicker.getParsedDate = function (date) { 1406 return { 1407 year: date.getFullYear(), 1408 month: date.getMonth(), 1409 fullMonth: (date.getMonth() + 1) < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1, // One based 1410 date: date.getDate(), 1411 fullDate: date.getDate() < 10 ? '0' + date.getDate() : date.getDate(), 1412 day: date.getDay(), 1413 hours: date.getHours(), 1414 fullHours: date.getHours() < 10 ? '0' + date.getHours() : date.getHours() , 1415 minutes: date.getMinutes(), 1416 fullMinutes: date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes() 1417 } 1418 }; 1419 1420 airdatepicker.getDecade = function (date) { 1421 var firstYear = Math.floor(date.getFullYear() / 10) * 10; 1422 1423 return [firstYear, firstYear + 9]; 1424 }; 1425 1426 airdatepicker.template = function (str, data) { 1427 return str.replace(/#\{([\w]+)\}/g, function (source, match) { 1428 if (data[match] || data[match] === 0) { 1429 return data[match] 1430 } 1431 }); 1432 }; 1433 1434 airdatepicker.isSame = function (date1, date2, type) { 1435 if (!date1 || !date2) return false;
1436 var d1 = airdatepicker.getParsedDate(date1), 1437 d2 = airdatepicker.getParsedDate(date2), 1438 _type = type ? type : 'day', 1439 1440 conditions = { 1441 day: d1.date == d2.date && d1.month == d2.month && d1.year == d2.year, 1442 month: d1.month == d2.month && d1.year == d2.year, 1443 year: d1.year == d2.year 1444 }; 1445 1446 return conditions[_type]; 1447 }; 1448 1449 airdatepicker.less = function (dateCompareTo, date, type) { 1450 if (!dateCompareTo || !date) return false; 1451 return date.getTime() < dateCompareTo.getTime(); 1452 }; 1453 1454 airdatepicker.bigger = function (dateCompareTo, date, type) { 1455 if (!dateCompareTo || !date) return false; 1456 return date.getTime() > dateCompareTo.getTime(); 1457 }; 1458 1459 airdatepicker.getLeadingZeroNum = function (num) { 1460 return parseInt(num) < 10 ? '0' + num : num; 1461 }; 1462 1463 /** 1464 * Returns copy of date with hours and minutes equals to 0 1465 * @param date {Date} 1466 */ 1467 airdatepicker.resetTime = function (date) { 1468 if (typeof date != 'object') return; 1469 date = airdatepicker.getParsedDate(date); 1470 return new Date(date.year, date.month, date.date) 1471 }; 1472 1473 $.fn.airdatepicker = function ( options ) { 1474 return this.each(function () { 1475 if (!$.data(this, pluginName)) { 1476 $.data(this, pluginName, 1477 new Datepicker( this, options )); 1478 } else { 1479 var _this = $.data(this, pluginName); 1480 1481 _this.opts = $.extend(true, _this.opts, options); 1482 _this.update(); 1483 } 1484 }); 1485 }; 1486 1487 $.fn.airdatepicker.Constructor = Datepicker; 1488 1489 $.fn.airdatepicker.language = { 1490 en: { 1491 days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], 1492 daysShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], 1493 daysMin: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'], 1494 months: ['January','February','March','April','May','June', 'July','August','September','October','November','December'], 1495 monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], 1496 today: 'Today', 1497 clear: 'Clear', 1498 dateFormat: 'mm/dd/yyyy', 1499 timeFormat: 'hh:ii aa', 1500 firstDay: 0 1501 }, 1502 cs: { 1503 days: ['NedÄle', 'PondÄlÃ', 'Ãterý', 'StÅeda', 'Ätvrtek', 'Pátek', 'Sobota'], 1504 daysShort: ['Ne', 'Po', 'Ãt', 'St', 'Ät', 'Pá', 'So'], 1505 daysMin: ['Ne', 'Po', 'Ãt', 'St', 'Ät', 'Pá', 'So'], 1506 months: ['Leden', 'Ãnor', 'BÅezen', 'Duben', 'KvÄten', 'Äerven', 'Äervenec', 'Srpen', 'ZáÅÃ', 'ÅÃjen', 'Listopad', 'Prosinec'], 1507 monthsShort: ['Led', 'Ãno', 'BÅe', 'Dub', 'KvÄ', 'Ävn', 'Ävc', 'Srp', 'ZáÅ', 'ÅÃj', 'Lis', 'Pro'], 1508 today: 'Dnes', 1509 clear: 'Vymazat', 1510 dateFormat: 'dd.mm.yyyy', 1511 timeFormat: 'hh:ii', 1512 firstDay: 1 1513 }, 1514 da: { 1515 days: ['Søndag', 'Mandag', 'Tirsdag', 'Onsdag', 'Torsdag', 'Fredag', 'Lørdag'], 1516 daysShort: ['Søn', 'Man', 'Tir', 'Ons', 'Tor', 'Fre', 'Lør'], 1517 daysMin: ['Sø', 'Ma', 'Ti', 'On', 'To', 'Fr', 'Lø'], 1518 months: ['Januar','Februar','Marts','April','Maj','Juni', 'Juli','August','September','Oktober','November','December'], 1519 monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'Maj', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec'], 1520 today: 'I dag', 1521 clear: 'Nulstil', 1522 dateFormat: 'dd/mm/yyyy', 1523 timeFormat: 'hh:ii', 1524 firstDay: 1 1525 }, 1526 de: { 1527 days: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'], 1528 daysShort: ['Son', 'Mon', 'Die', 'Mit', 'Don', 'Fre', 'Sam'], 1529 daysMin: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'], 1530 months: ['Januar','Februar','März','April','Mai','Juni', 'Juli','August','September','Oktober','November','Dezember'], 1531 monthsShort: ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'], 1532 today: 'Heute', 1533 clear: 'Aufräumen', 1534 dateFormat: 'dd.mm.yyyy', 1535 timeFormat: 'hh:ii', 1536 firstDay: 1 1537 }, 1538 es: { 1539 days: ['Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado'], 1540 daysShort: ['Dom', 'Lun', 'Mar', 'Mie', 'Jue', 'Vie', 'Sab'], 1541 daysMin: ['Do', 'Lu', 'Ma', 'Mi', 'Ju', 'Vi', 'Sa'], 1542 months: ['Enero','Febrero','Marzo','Abril','Mayo','Junio', 'Julio','Augosto','Septiembre','Octubre','Noviembre','Diciembre'], 1543 monthsShort: ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'], 1544 today: 'Hoy', 1545 clear: 'Limpiar', 1546 dateFormat: 'dd/mm/yyyy', 1547 timeFormat: 'hh:ii aa', 1548 firstDay: 1 1549 }, 1550 fi: { 1551 days: ['Sunnuntai', 'Maanantai', 'Tiistai', 'Keskiviikko', 'Torstai', 'Perjantai', 'Lauantai'], 1552 daysShort: ['Su', 'Ma', 'Ti', 'Ke', 'To', 'Pe', 'La'], 1553 daysMin: ['Su', 'Ma', 'Ti', 'Ke', 'To', 'Pe', 'La'], 1554 months: ['Tammikuu','Helmikuu','Maaliskuu','Huhtikuu','Toukokuu','Kesäkuu', 'Heinäkuu','Elokuu','Syyskuu','Lokakuu','Marraskuu','Joulukuu'], 1555 monthsShort: ['Tammi', 'Helmi', 'Maalis', 'Huhti', 'Touko', 'Kesä', 'Heinä', 'Elo', 'Syys', 'L
1555oka', 'Marras', 'Joulu'], 1556 today: 'Tänään', 1557 clear: 'Tyhjennä', 1558 dateFormat: 'dd.mm.yyyy', 1559 timeFormat: 'hh:ii', 1560 firstDay: 1 1561 }, 1562 fr: { 1563 days: ['Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi'], 1564 daysShort: ['Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam'], 1565 daysMin: ['Di', 'Lu', 'Ma', 'Me', 'Je', 'Ve', 'Sa'], 1566 months: ['Janvier','Février','Mars','Avril','Mai','Juin', 'Juillet','Août','Septembre','Octobre','Novembre','Decembre'], 1567 monthsShort: ['Jan', 'Fév', 'Mars', 'Avr', 'Mai', 'Juin', 'Juil', 'Août', 'Sep', 'Oct', 'Nov', 'Dec'], 1568 today: "Aujourd'hui", 1569 clear: 'Effacer', 1570 dateFormat: 'dd/mm/yyyy', 1571 timeFormat: 'hh:ii', 1572 firstDay: 1 1573 }, 1574 hu: { 1575 days: ['Vasárnap', 'HétfÅ', 'Kedd', 'Szerda', 'Csütörtök', 'Péntek', 'Szombat'], 1576 daysShort: ['Va', 'Hé', 'Ke', 'Sze', 'Cs', 'Pé', 'Szo'], 1577 daysMin: ['V', 'H', 'K', 'Sz', 'Cs', 'P', 'Sz'], 1578 months: ['Január', 'Február', 'Március', 'Ãprilis', 'Május', 'Június', 'Július', 'Augusztus', 'Szeptember', 'Október', 'November', 'December'], 1579 monthsShort: ['Jan', 'Feb', 'Már', 'Ãpr', 'Máj', 'Jún', 'Júl', 'Aug', 'Szep', 'Okt', 'Nov', 'Dec'], 1580 today: 'Ma', 1581 clear: 'Törlés', 1582 dateFormat: 'yyyy-mm-dd', 1583 timeFormat: 'hh:ii aa', 1584 firstDay: 1 1585 }, 1586 it: { 1587 days: ['Domenica', 'Lunedì', 'Martedì', 'Mercoledì', 'Giovedì', 'Venerdì', 'Sabato'], 1588 daysShort: ['Dom', 'Lun', 'Mar', 'Mer', 'Gio', 'Ven', 'Sab'], 1589 daysMin: ['Do', 'Lu', 'Ma', 'Me', 'Gi', 'Ve', 'Sa'], 1590 months: ['Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giugno', 'Luglio', 'Agosto', 'Settembre', 'Ottobre', 'Novembre', 'Dicembre'], 1591 monthsShort: ['Gen', 'Feb', 'Mar', 'Apr', 'Mag', 'Giu', 'Lug', 'Ago', 'Set', 'Ott', 'Nov', 'Dic'], 1592 today: 'Oggi', 1593 clear: 'Pulisci', 1594 dateFormat: 'dd/mm/yyyy', 1595 timeFormat: 'hh:ii aa', 1596 firstDay: 1 1597 }, 1598 nl: { 1599 days: ['zondag', 'maandag', 'dinsdag', 'woensdag', 'donderdag', 'vrijdag', 'zaterdag'], 1600 daysShort: ['zo', 'ma', 'di', 'wo', 'do', 'vr', 'za'], 1601 daysMin: ['zo', 'ma', 'di', 'wo', 'do', 'vr', 'za'], 1602 months: ['Januari', 'Februari', 'Maart', 'April', 'Mei', 'Juni', 'Juli', 'Augustus', 'September', 'Oktober', 'November', 'December'], 1603 monthsShort: ['Jan', 'Feb', 'Mrt', 'Apr', 'Mei', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec'], 1604 today: 'Vandaag', 1605 clear: 'Legen', 1606 dateFormat: 'dd-mm-yyyy', 1607 timeFormat: 'hh:ii', 1608 firstDay: 1 1609 }, 1610 pl: { 1611 days: ['Niedziela', 'PoniedziaÅek', 'Wtorek', 'Åroda', 'Czwartek', 'PiÄ tek', 'Sobota'], 1612 daysShort: ['Nie', 'Pon', 'Wto', 'Åro', 'Czw', 'PiÄ ', 'Sob'], 1613 daysMin: ['Nd', 'Pn', 'Wt', 'År', 'Czw', 'Pt', 'So'], 1614 months: ['StyczeÅ','Luty','Marzec','KwiecieÅ','Maj','Czerwiec', 'Lipiec','SierpieÅ','WrzesieÅ','Październik','Listopad','GrudzieÅ'], 1615 monthsShort: ['Sty', 'Lut', 'Mar', 'Kwi', 'Maj', 'Cze', 'Lip', 'Sie', 'Wrz', 'Paź', 'Lis', 'Gru'], 1616 today: 'Dzisiaj', 1617 clear: 'WyczyÅÄ', 1618 dateFormat: 'yyyy-mm-dd', 1619 timeFormat: 'hh:ii aa', 1620 firstDay: 1 1621 }, 1622 pt: { 1623 days: ['Domingo', 'Segunda', 'Terça', 'Quarta', 'Quinta', 'Sexta', 'Sábado'], 1624 daysShort: ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sab'], 1625 daysMin: ['Do', 'Se', 'Te', 'Qa', 'Qi', 'Sx', 'Sa'], 1626 months: ['Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro'], 1627 monthsShort: ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'], 1628 today: 'Hoje', 1629 clear: 'Limpar', 1630 dateFormat: 'dd/mm/yyyy', 1631 timeFormat: 'hh:ii', 1632 firstDay: 1 1633 }, 1634 ro: { 1635 days: ['DuminicÄ', 'Luni', 'MarÅ£i', 'Miercuri', 'Joi', 'Vineri', 'SâmbÄtÄ'], 1636 daysShort: ['Dum', 'Lun', 'Mar', 'Mie', 'Joi', 'Vin', 'Sâm'], 1637 daysMin: ['D', 'L', 'Ma', 'Mi', 'J', 'V', 'S'], 1638 months: ['Ianuarie','Februarie','Martie','Aprilie','Mai','Iunie','Iulie','August','Septembrie','Octombrie','Noiembrie','Decembrie'], 1639 monthsShort: ['Ian', 'Feb', 'Mar', 'Apr', 'Mai', 'Iun', 'Iul', 'Aug', 'Sept', 'Oct', 'Nov', 'Dec'], 1640 today: 'Azi', 1641 clear: 'Återge', 1642 dateFormat: 'dd.mm.yyyy', 1643 timeFormat: 'hh:ii', 1644 firstDay: 1 1645 }, 1646 ru: { 1647 days: ['ÐоÑкÑеÑенÑе', 'ÐонеделÑник', 'ÐÑоÑник', 'СÑеда', 'ЧеÑвеÑг', 'ÐÑÑниÑа', 'СÑббоÑа'], 1648 daysShort: ['ÐоÑ','Ðон','ÐÑо','СÑе','ЧеÑ','ÐÑÑ','СÑб'], 1649 daysMin: ['ÐÑ','Ðн','ÐÑ','СÑ','ЧÑ','ÐÑ','Сб'], 1650 months: ['ЯнваÑÑ', 'ФевÑалÑ', 'ÐаÑÑ', 'ÐпÑелÑ', 'Ðай', 'ÐÑнÑ', 'ÐÑлÑ', 'ÐвгÑÑÑ', 'СенÑÑбÑÑ', 'ÐкÑÑбÑÑ', 'ÐоÑбÑÑ', 'ÐекабÑÑ'], 1651 monthsShort: ['Янв', 'Фев', 'ÐаÑ', 'ÐпÑ', 'Ðай', 'ÐÑн', 'ÐÑл', 'Ðвг', 'Сен', 'ÐкÑ', 'ÐоÑ', 'Ðек'], 1652 today: 'СегоднÑ', 1653 clear: 'ÐÑиÑÑиÑÑ', 1654 dateFormat: 'dd.mm.yyyy', 1655 timeFormat: 'hh:ii', 1656 firstDay: 1 1657 }, 1658 sk: { 1659 days: ['Nedeľa', 'Pondelok', 'Utorok', 'Streda', 'Å tvrtok', 'Piatok', 'Sobota'], 1660 daysShort: ['Ned', 'Pon', 'Uto', 'Str', 'Å tv', 'Pia', 'Sob'], 1661 daysMin: ['Ne', 'Po', 'Ut', 'St', 'Å t', 'Pi', 'So'], 1662 months: ['Január','Február','Marec','AprÃl','Máj','Jún', 'Júl','August','September','Október','November','December'], 1663 monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'Máj', 'Jún', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec'], 1664 today: 'Dnes', 1665 clear: 'VymazaÅ¥', 1666 dateFormat: 'dd.mm.yyyy', 1667 timeFormat: 'hh:ii', 1668 firstDay: 1 1669 }, 1670 tr: {
1671 days: ['Pazar', 'Pazartesi', 'Salı', 'ÃarÅamba', 'PerÅembe', 'Cuma', 'Cumartesi'], 1672 daysShort: ['Paz', 'Pzt', 'Sal', 'Ãar', 'Per', 'Cum', 'Cmt'], 1673 daysMin: ['Pz', 'Pt', 'Sa', 'Ãa', 'Pe', 'Cu', 'Ct'], 1674 months: ['Ocak','Åubat','Mart','Nisan','Mayıs','Haziran', 'Temmuz','AÄustos','Eylül','Ekim','Kasım','Aralık'], 1675 monthsShort: ['Oca', 'Åub', 'Mar', 'Nis', 'May', 'Haz', 'Tem', 'AÄu', 'Eyl', 'Eki', 'Kas', 'Ara'], 1676 today: 'Bugün', 1677 clear: 'Temizle', 1678 dateFormat: 'dd.mm.yyyy', 1679 timeFormat: 'hh:ii', 1680 firstDay: 1 1681 }, 1682 zh: { 1683 days: ['卿¥', 'å¨ä¸', 'å¨äº', 'å¨ä¸', 'å¨å', 'å¨äº', 'å¨å '], 1684 daysShort: ['æ¥', 'ä¸', 'äº', 'ä¸', 'å', 'äº', 'å '], 1685 daysMin: ['æ¥', 'ä¸', 'äº', 'ä¸', 'å', 'äº', 'å '], 1686 months: ['䏿', 'äºæ', '䏿', 'åæ', 'äºæ', 'å æ', '䏿', 'å «æ', '乿', 'åæ', 'å䏿', 'åäºæ'], 1687 monthsShort: ['䏿', 'äºæ', '䏿', 'åæ', 'äºæ', 'å æ', '䏿', 'å «æ', '乿', 'åæ', 'å䏿', 'åäºæ'], 1688 today: 'ä»å¤©', 1689 clear: 'æ¸ é¤', 1690 dateFormat: 'yyyy-mm-dd', 1691 timeFormat: 'hh:ii', 1692 firstDay: 1 1693 } 1694 }; 1695 1696 $(function () { 1697 $(autoInitSelector).airdatepicker(); 1698 }) 1699 1700})(); 1701 1702;(function () { 1703 var templates = { 1704 days:'' + 1705 '<div class="airdatepicker--days airdatepicker--body">' + 1706 '<div class="airdatepicker--days-names"></div>' + 1707 '<div class="airdatepicker--cells airdatepicker--cells-days"></div>' + 1708 '</div>', 1709 months: '' + 1710 '<div class="airdatepicker--months airdatepicker--body">' + 1711 '<div class="airdatepicker--cells airdatepicker--cells-months"></div>' + 1712 '</div>', 1713 years: '' + 1714 '<div class="airdatepicker--years airdatepicker--body">' + 1715 '<div class="airdatepicker--cells airdatepicker--cells-years"></div>' + 1716 '</div>' 1717 }, 1718 airdatepicker = $.fn.airdatepicker, 1719 dp = airdatepicker.Constructor; 1720 1721 airdatepicker.Body = function (d, type, opts) { 1722 this.d = d; 1723 this.type = type; 1724 this.opts = opts; 1725 this.$el = $(''); 1726 1727 if (this.opts.onlyTimepicker) return; 1728 this.init(); 1729 }; 1730 1731 airdatepicker.Body.prototype = { 1732 init: function () { 1733 this._buildBaseHtml(); 1734 this._render(); 1735 1736 this._bindEvents(); 1737 }, 1738 1739 _bindEvents: function () { 1740 this.$el.on('click', '.airdatepicker--cell', $.proxy(this._onClickCell, this)); 1741 }, 1742 1743 _buildBaseHtml: function () { 1744 this.$el = $(templates[this.type]).appendTo(this.d.$content); 1745 this.$names = $('.airdatepicker--days-names', this.$el); 1746 this.$cells = $('.airdatepicker--cells', this.$el); 1747 }, 1748 1749 _getDayNamesHtml: function (firstDay, curDay, html, i) { 1750 curDay = curDay != undefined ? curDay : firstDay; 1751 html = html ? html : ''; 1752 i = i != undefined ? i : 0; 1753 1754 if (i > 7) return html; 1755 if (curDay == 7) return this._getDayNamesHtml(firstDay, 0, html, ++i); 1756 1757 html += '<div class="airdatepicker--day-name' + (this.d.isWeekend(curDay) ? " -weekend-" : "") + '">' + this.d.loc.daysMin[curDay] + '</div>'; 1758 1759 return this._getDayNamesHtml(firstDay, ++curDay, html, ++i); 1760 }, 1761 1762 _getCellContents: function (date, type) { 1763 var classes = "airdatepicker--cell airdatepicker--cell-" + type, 1764 currentDate = new Date(), 1765 parent = this.d, 1766 minRange = dp.resetTime(parent.minRange), 1767 maxRange = dp.resetTime(parent.maxRange), 1768 opts = parent.opts, 1769 d = dp.getParsedDate(date), 1770 render = {}, 1771 html = d.date; 1772 1773 switch (type) { 1774 case 'day': 1775 if (parent.isWeekend(d.day)) classes += " -weekend-"; 1776 if (d.month != this.d.parsedDate.month) { 1777 classes += " -other-month-"; 1778 if (!opts.selectOtherMonths) { 1779 classes += " -disabled-"; 1780 } 1781 if (!opts.showOtherMonths) html = ''; 1782 } 1783 break; 1784 case 'month': 1785 html = parent.loc[parent.opts.monthsField][d.month]; 1786 break; 1787 case 'year': 1788 var decade = parent.curDecade; 1789 html = d.year; 1790 if (d.year < decade[0] || d.year > decade[1]) { 1791 classes += ' -other-decade-'; 1792 if (!opts.selectOtherYears) { 1793 classes += " -disabled-"; 1794 } 1795 if (!opts.showOtherYears) html = ''; 1796 } 1797 break; 1798 } 1799 1800 if (opts.onRenderCell) { 1801 render = opts.onRenderCell(date, type) || {}; 1802 html = render.html ? render.html : html; 1803 classes += render.classes ? ' ' + render.classes : ''; 1804 } 1805 1806 if (opts.range) { 1807 if (dp.isSame(minRange, date, type)) classes += ' -range-from-'; 1808 if (dp.isSame(maxRange, date, type)) classes += ' -range-to-'; 1809 1810 if (parent.selectedDates.length == 1 && parent.focused) { 1811 if ( 1812 (dp.bigger(minRange, date) && dp.less(parent.focused, date)) || 1813 (dp.less(maxRange, date) && dp.bigger(parent.focused, date))) 1814 { 1815 classes += ' -in-range-' 1816 } 1817 1818 if (dp.less(maxRange, date) && dp.isSame(parent.focused, date)) { 1819 classes += ' -range-from-' 1820 } 1821 if (dp.bigger(minRange, date) && dp.isSame(parent.focused, date)) { 1822 classes += ' -range-to-' 1823 } 1824 1825 } else if (parent.selectedDates.length == 2) { 1826 if (dp.bigger(minRange, date) && dp.less(maxRange, date)) { 1827 classes += ' -in-range-' 1828 } 1829 } 1830 } 1831 1832 1833 if (dp.isSame(currentDate, date, type)) classes += ' -current-'; 1834 if (parent.focused && dp.isSame(date, parent.focused, type)) classes += ' -focus-'; 1835 if (parent._isSelected(date, type)) classes += ' -selected-'; 1836 if (!parent._isInRange(date, type) || render.disabled) classes += ' -disabled-'; 1837 1838 return { 1839 html: html, 1840 classes: classes 1841 } 1842 }, 1843 1844 /** 1845 * Calculates days number to render. Generates days html and returns it. 1846 * @param {object} date - Date object 1847 * @returns {string} 1848 * @private 1849 */ 1850 _getDaysHtml: function (date) { 1851 var totalMonthDays = dp.getDaysCount(date),
1852 firstMonthDay = new Date(date.getFullYear(), date.getMonth(), 1).getDay(), 1853 lastMonthDay = new Date(date.getFullYear(), date.getMonth(), totalMonthDays).getDay(), 1854 daysFromPevMonth = firstMonthDay - this.d.loc.firstDay, 1855 daysFromNextMonth = 6 - lastMonthDay + this.d.loc.firstDay; 1856 1857 daysFromPevMonth = daysFromPevMonth < 0 ? daysFromPevMonth + 7 : daysFromPevMonth; 1858 daysFromNextMonth = daysFromNextMonth > 6 ? daysFromNextMonth - 7 : daysFromNextMonth; 1859 1860 var startDayIndex = -daysFromPevMonth + 1, 1861 m, y, 1862 html = ''; 1863 1864 for (var i = startDayIndex, max = totalMonthDays + daysFromNextMonth; i <= max; i++) { 1865 y = date.getFullYear(); 1866 m = date.getMonth(); 1867 1868 html += this._getDayHtml(new Date(y, m, i)) 1869 } 1870 1871 return html; 1872 }, 1873 1874 _getDayHtml: function (date) { 1875 var content = this._getCellContents(date, 'day'); 1876 1877 return '<div class="' + content.classes + '" ' + 1878 'data-date="' + date.getDate() + '" ' + 1879 'data-month="' + date.getMonth() + '" ' + 1880 'data-year="' + date.getFullYear() + '">' + content.html + '</div>'; 1881 }, 1882 1883 /** 1884 * Generates months html 1885 * @param {object} date - date instance 1886 * @returns {string} 1887 * @private 1888 */ 1889 _getMonthsHtml: function (date) { 1890 var html = '', 1891 d = dp.getParsedDate(date), 1892 i = 0; 1893 1894 while(i < 12) { 1895 html += this._getMonthHtml(new Date(d.year, i)); 1896 i++ 1897 } 1898 1899 return html; 1900 }, 1901 1902 _getMonthHtml: function (date) { 1903 var content = this._getCellContents(date, 'month'); 1904 1905 return '<div class="' + content.classes + '" data-month="' + date.getMonth() + '">' + content.html + '</div>' 1906 }, 1907 1908 _getYearsHtml: function (date) { 1909 var d = dp.getParsedDate(date), 1910 decade = dp.getDecade(date), 1911 firstYear = decade[0] - 1, 1912 html = '', 1913 i = firstYear; 1914 1915 for (i; i <= decade[1] + 1; i++) { 1916 html += this._getYearHtml(new Date(i , 0)); 1917 } 1918 1919 return html; 1920 }, 1921 1922 _getYearHtml: function (date) { 1923 var content = this._getCellContents(date, 'year'); 1924 1925 return '<div class="' + content.classes + '" data-year="' + date.getFullYear() + '">' + content.html + '</div>' 1926 }, 1927 1928 _renderTypes: { 1929 days: function () { 1930 var dayNames = this._getDayNamesHtml(this.d.loc.firstDay), 1931 days = this._getDaysHtml(this.d.currentDate); 1932 1933 this.$cells.html(days); 1934 this.$names.html(dayNames) 1935 }, 1936 months: function () { 1937 var html = this._getMonthsHtml(this.d.currentDate); 1938 1939 this.$cells.html(html) 1940 }, 1941 years: function () { 1942 var html = this._getYearsHtml(this.d.currentDate); 1943 1944 this.$cells.html(html) 1945 } 1946 }, 1947 1948 _render: function () { 1949 if (this.opts.onlyTimepicker) return; 1950 this._renderTypes[this.type].bind(this)(); 1951 }, 1952 1953 _update: function () { 1954 var $cells = $('.airdatepicker--cell', this.$cells), 1955 _this = this, 1956 classes, 1957 $cell, 1958 date; 1959 $cells.each(function (cell, i) { 1960 $cell = $(this); 1961 date = _this.d._getDateFromCell($(this)); 1962 classes = _this._getCellContents(date, _this.d.cellType); 1963 $cell.attr('class',classes.classes) 1964 }); 1965 }, 1966 1967 show: function () { 1968 if (this.opts.onlyTimepicker) return; 1969 this.$el.addClass('active'); 1970 this.acitve = true; 1971 }, 1972 1973 hide: function () { 1974 this.$el.removeClass('active'); 1975 this.active = false; 1976 }, 1977 1978 // Events 1979 // ------------------------------------------------- 1980 1981 _handleClick: function (el) { 1982 var date = el.data('date') || 1, 1983 month = el.data('month') || 0, 1984 year = el.data('year') || this.d.parsedDate.year, 1985 dp = this.d; 1986 // Change view if min view does not reach yet 1987 if (dp.view != this.opts.minView) { 1988 dp.down(new Date(year, month, date)); 1989 return; 1990 } 1991 // Select date if min view is reached 1992 var selectedDate = new Date(year, month, date), 1993 alreadySelected = this.d._isSelected(selectedDate, this.d.cellType); 1994 1995 if (!alreadySelected) { 1996 dp._trigger('clickCell', selectedDate); 1997 return; 1998 } 1999 2000 dp._handleAlreadySelectedDates.bind(dp, alreadySelected, selectedDate)(); 2001 2002 }, 2003 2004 _onClickCell: function (e) { 2005 var $el = $(e.target).closest('.airdatepicker--cell'); 2006 2007 if ($el.hasClass('-disabled-')) return; 2008 2009 this._handleClick.bind(this)($el); 2010 } 2011 }; 2012})(); 2013 2014;(function () { 2015 var template = '' + 2016 '<div class="airdatepicker--nav-action" data-action="prev">#{prevHtml}</div>' + 2017 '<div class="airdatepicker--nav-title">#{title}</div>' + 2018 '<div class="airdatepicker--nav-action" data-action="next">#{nextHtml}</div>', 2019 buttonsContainerTemplate = '<div class="airdatepicker--buttons"></div>', 2020 button = '<span class="airdatepicker--button" data-action="#{action}">#{label}</span>', 2021 airdatepicker = $.fn.airdatepicker, 2022 dp = airdatepicker.Constructor; 2023 2024 airdatepicker.Navigation = function (d, opts) { 2025 this.d = d; 2026 this.opts = opts; 2027 2028 this.$buttonsContainer = ''; 2029 2030 this.init(); 2031 }; 2032 2033 airdatepicker.Navigation.prototype = { 2034 init: function () { 2035 this._buildBaseHtml(); 2036 this._bindEvents(); 2037 }, 2038 2039 _bindEvents: function () { 2040 this.d.$nav.on('click', '.airdatepicker--nav-action', $.proxy(this._onClickNavButton, this)); 2041 this.d.$nav.on('click', '.airdatepicker--nav-title', $.proxy(this._onClickNavTitle, this)); 2042 this.d.$airdatepicker.on('click', '.airdatepicker--button', $.proxy(this._onClickNavButton, this)); 2043 }, 2044 2045 _buildBaseHtml: function () { 2046 if (!this.opts.onlyTimepicker) { 2047 this._render(); 2048 } 2049 this._addButtonsIfNeed(); 2050 }, 2051 2052 _addButtonsIfNeed: function () { 2053 if (this.opts.todayButton) { 2054 this._addButton('today') 2055 } 2056 if (this.opts.clearButton) { 2057 this._addButton('clear') 2058 } 2059 }, 2060 2061 _render: function () { 2062 var title = this._getTitle(this.d.currentDate), 2063 html = dp.template(template, $.extend({title: title}, this.opts)); 2064 this.d.$nav.html(html); 2065 if (this.d.view == 'years') { 2066 $('.airdatepicker--nav-title', this.d.$nav).addClass('-disabled-'); 2067 } 2068 this.setNavStatus(); 2069 }, 2070 2071 _getTitle: function (date) { 2072 return this.d.formatDate(this.opts.navTitles[this.d.view], date) 2073 }, 2074 2075 _addButton: function (type) { 2076 if (!this.$buttonsContainer.length) { 2077 this._addButtonsContainer(); 2078 } 2079 2080 var data = { 2081 action: type, 2082 label: this.d.loc[type] 2083 }, 2084 html = dp.template(button, data); 2085 2086 if ($('[data-action=' + type + ']', this.$buttonsContainer).length) return; 2087 this.$buttonsContainer.append(html); 2088 }, 2089 2090 _addButtonsContainer: function () { 2091 this.d.$airdatepicker.append(buttonsContainerTemplate); 2092 this.$buttonsContainer = $('.airdatepicker--buttons', this.d.$airdatepicker); 2093 }, 2094 2095 setNavStatus: function () { 2096 if (!(this.opts.minDate || this.opts.maxDate) || !this.opts.disableNavWhenOutOfRange) return; 2097 2098 var date = this.d.parsedDate, 2099 m = date.month, 2100 y = date.year, 2101 d = date.date; 2102 2103 switch (this.d.view) { 2104 case 'days': 2105 if (!this.d._isInRange(new Date(y, m-1, 1), 'month')) { 2106 this._disableNav('prev') 2107 } 2108 if (!this.d._isInRange(new Date(y, m+1, 1), 'month')) { 2109 this._disableNav('next') 2110 } 2111 break; 2112 case 'months': 2113 if (!this.d._isInRange(new Date(y-1, m, d), 'year')) { 2114 this._disableNav('prev') 2115 } 2116 if (!this.d._isInRange(new Date(y+1, m, d), 'year')) { 2117 this._disableNav('next') 2118 } 2119 break; 2120 case 'years': 2121 var decade = dp.getDecade(this.d.date); 2122 if (!this.d._isInRange(new Date(decade[0] - 1, 0, 1), 'year')) { 2123 this._disableNav('prev') 2124 } 2125 if (!this.d._isInRange(new Date(decade[1] + 1, 0, 1), 'year')) { 2126 this._disableNav('next') 2127 } 2128 break; 2129 } 2130 }, 2131 2132 _disableNav: function (nav) { 2133 $('[data-action="' + nav + '"]', this.d.$nav).addClass('-disabled-') 2134 }, 2135 2136 _activateNav: function (nav) { 2137 $('[data-action="' + nav + '"]', this.d.$nav).removeClass('-disabled-') 2138 }, 2139 2140 _onClickNavButton: function (e) { 2141 var $el = $(e.target).closest('[data-action]'), 2142 action = $el.data('action'); 2143 2144 this.d[action](); 2145 }, 2146 2147 _onClickNavTitle: function (e) { 2148 if ($(e.target).hasClass('-disabled-')) return; 2149 2150 if (this.d.view == 'days') { 2151 return this.d.view = 'months' 2152 } 2153 2154 this.d.view = 'years'; 2155 } 2156 } 2157 2158})(); 2159 2160;(function () { 2161 var template = '<div class="airdatepicker--time">' + 2162 '<div class="airdatepicker--time-current">' + 2163 ' <span class="airdatepicker--time-current-hours">#{hourVisible}</span>' + 2164 ' <span class="airdatepicker--time-current-colon">:</span>' + 2165 ' <span class="airdatepicker--time-current-minutes">#{minValue}</span>' + 2166 '</div>' + 2167 '<div class="airdatepicker--time-sliders">' + 2168 ' <div class="airdatepicker--time-row">' + 2169 ' <input type="range" name="hours" value="#{hourValue}" min="#{hourMin}" max="#{hourMax}" step="#{hourStep}"/>' + 2170 ' </div>' + 2171 ' <div class="airdatepicker--time-row">' + 2172 ' <input type="range" name="minutes" value="#{minValue}" min="#{minMin}" max="#{minMax}" step="#{minStep}"/>' + 2173 ' </div>' + 2174 '</div>' + 2175 '</div>', 2176 airdatepicker = $.fn.airdatepicker, 2177 dp = airdatepicker.Constructor; 2178 2179 airdatepicker.Timepicker = function (inst, opts) { 2180 this.d = inst; 2181 this.opts = opts; 2182 2183 this.init(); 2184 }; 2185 2186 airdatepicker.Timepicker.prototype = { 2187 init: function () { 2188 var input = 'input'; 2189 this._setTime(this.d.date); 2190 this._buildHTML(); 2191
2192 if (navigator.userAgent.match(/trident/gi)) { 2193 input = 'change'; 2194 } 2195 2196 this.d.$el.on('selectDate', this._onSelectDate.bind(this)); 2197 this.$ranges.on(input, this._onChangeRange.bind(this)); 2198 this.$ranges.on('mouseup', this._onMouseUpRange.bind(this)); 2199 this.$ranges.on('mousemove focus ', this._onMouseEnterRange.bind(this)); 2200 this.$ranges.on('mouseout blur', this._onMouseOutRange.bind(this)); 2201 }, 2202 2203 _setTime: function (date) { 2204 var _date = dp.getParsedDate(date); 2205 2206 this._handleDate(date); 2207 this.hours = _date.hours < this.minHours ? this.minHours : _date.hours; 2208 this.minutes = _date.minutes < this.minMinutes ? this.minMinutes : _date.minutes; 2209 }, 2210 2211 /** 2212 * Sets minHours and minMinutes from date (usually it's a minDate) 2213 * Also changes minMinutes if current hours are bigger then @date hours 2214 * @param date {Date} 2215 * @private 2216 */ 2217 _setMinTimeFromDate: function (date) { 2218 this.minHours = date.getHours(); 2219 this.minMinutes = date.getMinutes(); 2220 2221 // If, for example, min hours are 10, and current hours are 12, 2222 // update minMinutes to default value, to be able to choose whole range of values 2223 if (this.d.lastSelectedDate) { 2224 if (this.d.lastSelectedDate.getHours() > date.getHours()) { 2225 this.minMinutes = this.opts.minMinutes; 2226 } 2227 } 2228 }, 2229 2230 _setMaxTimeFromDate: function (date) { 2231 this.maxHours = date.getHours(); 2232 this.maxMinutes = date.getMinutes(); 2233 2234 if (this.d.lastSelectedDate) { 2235 if (this.d.lastSelectedDate.getHours() < date.getHours()) { 2236 this.maxMinutes = this.opts.maxMinutes; 2237 } 2238 } 2239 }, 2240 2241 _setDefaultMinMaxTime: function () { 2242 var maxHours = 23, 2243 maxMinutes = 59, 2244 opts = this.opts; 2245 2246 this.minHours = opts.minHours < 0 || opts.minHours > maxHours ? 0 : opts.minHours; 2247 this.minMinutes = opts.minMinutes < 0 || opts.minMinutes > maxMinutes ? 0 : opts.minMinutes; 2248 this.maxHours = opts.maxHours < 0 || opts.maxHours > maxHours ? maxHours : opts.maxHours; 2249 this.maxMinutes = opts.maxMinutes < 0 || opts.maxMinutes > maxMinutes ? maxMinutes : opts.maxMinutes; 2250 }, 2251 2252 /** 2253 * Looks for min/max hours/minutes and if current values 2254 * are out of range sets valid values. 2255 * @private 2256 */ 2257 _validateHoursMinutes: function (date) { 2258 if (this.hours < this.minHours) { 2259 this.hours = this.minHours; 2260 } else if (this.hours > this.maxHours) { 2261 this.hours = this.maxHours; 2262 } 2263 2264 if (this.minutes < this.minMinutes) { 2265 this.minutes = this.minMinutes; 2266 } else if (this.minutes > this.maxMinutes) { 2267 this.minutes = this.maxMinutes; 2268 } 2269 }, 2270 2271 _buildHTML: function () { 2272 var lz = dp.getLeadingZeroNum, 2273 data = { 2274 hourMin: this.minHours, 2275 hourMax: lz(this.maxHours), 2276 hourStep: this.opts.hoursStep, 2277 hourValue: this.hours, 2278 hourVisible: lz(this.displayHours), 2279 minMin: this.minMinutes, 2280 minMax: lz(this.maxMinutes), 2281 minStep: this.opts.minutesStep, 2282 minValue: lz(this.minutes) 2283 }, 2284 _template = dp.template(template, data); 2285 2286 this.$timepicker = $(_template).appendTo(this.d.$airdatepicker); 2287 this.$ranges = $('[type="range"]', this.$timepicker); 2288 this.$hours = $('[name="hours"]', this.$timepicker); 2289 this.$minutes = $('[name="minutes"]', this.$timepicker); 2290 this.$hoursText = $('.airdatepicker--time-current-hours', this.$timepicker); 2291 this.$minutesText = $('.airdatepicker--time-current-minutes', this.$timepicker); 2292 2293 if (this.d.ampm) { 2294 this.$ampm = $('<span class="airdatepicker--time-current-ampm">') 2295 .appendTo($('.airdatepicker--time-current', this.$timepicker)) 2296 .html(this.dayPeriod); 2297 2298 this.$timepicker.addClass('-am-pm-'); 2299 } 2300 }, 2301 2302 _updateCurrentTime: function () { 2303 var h = dp.getLeadingZeroNum(this.displayHours), 2304 m = dp.getLeadingZeroNum(this.minutes); 2305 2306 this.$hoursText.html(h); 2307 this.$minutesText.html(m); 2308 2309 if (this.d.ampm) { 2310 this.$ampm.html(this.dayPeriod); 2311 } 2312 }, 2313 2314 _updateRanges: function () { 2315 this.$hours.attr({ 2316 min: this.minHours, 2317 max: this.maxHours 2318 }).val(this.hours); 2319 2320 this.$minutes.attr({ 2321 min: this.minMinutes, 2322 max: this.maxMinutes 2323 }).val(this.minutes) 2324 }, 2325 2326 /** 2327 * Sets minHours, minMinutes etc. from date. If date is not passed, than sets 2328 * values from options 2329 * @param [date] {object} - Date object, to get values from 2330 * @private 2331 */ 2332 _handleDate: function (date) { 2333 this._setDefaultMinMaxTime(); 2334 if (date) { 2335 if (dp.isSame(date, this.d.opts.minDate)) { 2336 this._setMinTimeFromDate(this.d.opts.minDate); 2337 } else if (dp.isSame(date, this.d.opts.maxDate)) { 2338 this._setMaxTimeFromDate(this.d.opts.maxDate); 2339 } 2340 } 2341
2342 this._validateHoursMinutes(date); 2343 }, 2344 2345 update: function () { 2346 this._updateRanges(); 2347 this._updateCurrentTime(); 2348 }, 2349 2350 /** 2351 * Calculates valid hour value to display in text input and airdatepicker's body. 2352 * @param date {Date|Number} - date or hours 2353 * @param [ampm] {Boolean} - 12 hours mode 2354 * @returns {{hours: *, dayPeriod: string}} 2355 * @private 2356 */ 2357 _getValidHoursFromDate: function (date, ampm) { 2358 var d = date, 2359 hours = date; 2360 2361 if (date instanceof Date) { 2362 d = dp.getParsedDate(date); 2363 hours = d.hours; 2364 } 2365 2366 var _ampm = ampm || this.d.ampm, 2367 dayPeriod = 'am'; 2368 2369 if (_ampm) { 2370 switch(true) { 2371 case hours == 0: 2372 hours = 12; 2373 break; 2374 case hours == 12: 2375 dayPeriod = 'pm'; 2376 break; 2377 case hours > 11: 2378 hours = hours - 12; 2379 dayPeriod = 'pm'; 2380 break; 2381 default: 2382 break; 2383 } 2384 } 2385 2386 return { 2387 hours: hours, 2388 dayPeriod: dayPeriod 2389 } 2390 }, 2391 2392 set hours (val) { 2393 this._hours = val; 2394 2395 var displayHours = this._getValidHoursFromDate(val); 2396 2397 this.displayHours = displayHours.hours; 2398 this.dayPeriod = displayHours.dayPeriod; 2399 }, 2400 2401 get hours() { 2402 return this._hours; 2403 }, 2404 2405 // Events 2406 // ------------------------------------------------- 2407 2408 _onChangeRange: function (e) { 2409 var $target = $(e.target), 2410 name = $target.attr('name'); 2411 2412 this.d.timepickerIsActive = true; 2413 2414 this[name] = $target.val(); 2415 this._updateCurrentTime(); 2416 this.d._trigger('timeChange', [this.hours, this.minutes]); 2417 2418 this._handleDate(this.d.lastSelectedDate); 2419 this.update() 2420 }, 2421 2422 _onSelectDate: function (e, data) { 2423 this._handleDate(data); 2424 this.update(); 2425 }, 2426 2427 _onMouseEnterRange: function (e) { 2428 var name = $(e.target).attr('name'); 2429 $('.airdatepicker--time-current-' + name, this.$timepicker).addClass('-focus-'); 2430 }, 2431 2432 _onMouseOutRange: function (e) { 2433 var name = $(e.target).attr('name'); 2434 if (this.d.inFocus) return; // Prevent removing focus when mouse out of range slider 2435 $('.airdatepicker--time-current-' + name, this.$timepicker).removeClass('-focus-'); 2436 }, 2437 2438 _onMouseUpRange: function (e) { 2439 this.d.timepickerIsActive = false; 2440 } 2441 }; 2442})(); 2443 })(window, jQuery);
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.