vendor: 36,173 bytes, lines 1-1151
1/*! 2 * Datepicker for Bootstrap v1.7.0-dev (https://github.com/uxsolutions/bootstrap-datepicker) 3 * 4 * Licensed under the Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0) 5 */ 6 7(function(factory) { 8 if (typeof define === "function" && define.amd) { 9 define(["jquery"], factory); 10 } else if (typeof exports === 'object') { 11 factory(require('jquery')); 12 } else { 13 factory(jQuery); 14 } 15}(function($, undefined) { 16 function UTCDate() { 17 return new Date(Date.UTC.apply(Date, arguments)); 18 } 19 20 function UTCToday() { 21 var today = new Date(); 22 return UTCDate(today.getFullYear(), today.getMonth(), today.getDate()); 23 } 24 25 function isUTCEquals(date1, date2) { 26 return ( 27 date1.getUTCFullYear() === date2.getUTCFullYear() && 28 date1.getUTCMonth() === date2.getUTCMonth() && 29 date1.getUTCDate() === date2.getUTCDate() 30 ); 31 } 32 33 function alias(method, deprecationMsg) { 34 return function() { 35 if (deprecationMsg !== undefined) { 36 $.fn.datepicker.deprecated(deprecationMsg); 37 } 38 39 return this[method].apply(this, arguments); 40 }; 41 } 42 43 function isValidDate(d) { 44 return d && !isNaN(d.getTime()); 45 } 46 47 var DateArray = (function() { 48 var extras = { 49 get: function(i) { 50 return this.slice(i)[0]; 51 }, 52 contains: function(d) { 53 // Array.indexOf is not cross-browser; 54 // $.inArray doesn't work with Dates 55 var val = d && d.valueOf(); 56 for (var i = 0, l = this.length; i < l; i++) 57 // Use date arithmetic to allow dates with different times to match 58 if (0 <= this[i].valueOf() - val && this[i].valueOf() - val < 1000 * 60 * 60 * 24) 59 return i; 60 return -1; 61 }, 62 remove: function(i) { 63 this.splice(i, 1); 64 }, 65 replace: function(new_array) { 66 if (!new_array) 67 return; 68 if (!$.isArray(new_array)) 69 new_array = [new_array]; 70 this.clear(); 71 this.push.apply(this, new_array); 72 }, 73 clear: function() { 74 this.length = 0; 75 }, 76 copy: function() { 77 var a = new DateArray(); 78 a.replace(this); 79 return a; 80 } 81 }; 82 83 return function() { 84 var a = []; 85 a.push.apply(a, arguments); 86 $.extend(a, extras); 87 return a; 88 }; 89 })(); 90 91 92 // Picker object 93 94 var Datepicker = function(element, options) { 95 $.data(element, 'datepicker', this); 96 this._process_options(options); 97 98 this.dates = new DateArray(); 99 this.viewDate = this.o.defaultViewDate; 100 this.focusDate = null; 101 102 this.element = $(element); 103 this.isInput = this.element.is('input'); 104 this.inputField = this.isInput ? this.element : this.element.find('input'); 105 this.component = this.element.hasClass('date') ? this.element.find('.add-on, .input-group-addon, .btn') : false; 106 if (this.component && this.component.length === 0) 107 this.component = false; 108 this.isInline = !this.component && this.element.is('div'); 109 110 this.picker = $(DPGlobal.template); 111 112 // Checking templates and inserting 113 if (this._check_template(this.o.templates.leftArrow)) { 114 this.picker.find('.prev').html(this.o.templates.leftArrow); 115 } 116 117 if (this._check_template(this.o.templates.rightArrow)) { 118 this.picker.find('.next').html(this.o.templates.rightArrow); 119 } 120 121 this._buildEvents(); 122 this._attachEvents(); 123 124 if (this.isInline) { 125 this.picker.addClass('datepicker-inline').appendTo(this.element); 126 } else { 127 this.picker.addClass('datepicker-dropdown dropdown-menu'); 128 } 129 130 if (this.o.rtl) { 131 this.picker.addClass('datepicker-rtl'); 132 } 133 134 if (this.o.calendarWeeks) { 135 this.picker.find('.datepicker-days .datepicker-switch, thead .datepicker-title, tfoot .today, tfoot .clear') 136 .attr('colspan', function(i, val) { 137 return Number(val) + 1; 138 }); 139 } 140 141 this._process_options({ 142 startDate: this._o.startDate, 143 endDate: this._o.endDate, 144 daysOfWeekDisabled: this.o.daysOfWeekDisabled, 145 daysOfWeekHighlighted: this.o.daysOfWeekHighlighted, 146 datesDisabled: this.o.datesDisabled 147 }); 148 149 this._allow_update = false; 150 this.setViewMode(this.o.startView); 151 this._allow_update = true; 152 153 this.fillDow(); 154 this.fillMonths(); 155 156 this.update(); 157 158 if (this.isInline) { 159 this.show(); 160 } 161 }; 162 163 Datepicker.prototype = { 164 constructor: Datepicker, 165 166 _resolveViewName: function(view) { 167 $.each(DPGlobal.viewModes, function(i, viewMode) { 168 if (view === i || $.inArray(view, viewMode.names) !== -1) { 169 view = i; 170 return false; 171 } 172 }); 173 174 return view; 175 }, 176 177 _resolveDaysOfWeek: function(daysOfWeek) { 178 if (!$.isArray(daysOfWeek)) 179 daysOfWeek = daysOfWeek.split(/[,\s]*/); 180 return $.map(daysOfWeek, Number); 181 }, 182 183 _check_template: function(tmp) { 184 try { 185 // If empty 186 if (tmp === undefined || tmp === "") { 187 return false; 188 } 189 // If no html, everything ok 190 if ((tmp.match(/[<>]/g) || []).length <= 0) { 191 return true; 192 } 193 // Checking if html is fine 194 var jDom = $(tmp); 195 return jDom.length > 0; 196 } catch (ex) { 197 return false; 198 } 199 }, 200 201 _process_options: function(opts) { 202 // Store raw options for reference 203 this._o = $.extend({}, this._o, opts); 204 // Processed options 205 var o = this.o = $.extend({}, this._o); 206 207 // Check if "de-DE" style date is available, if not language should 208 // fallback to 2 letter code eg "de" 209 var lang = o.language; 210 if (!dates[lang]) { 211 lang = lang.split('-')[0]; 212 if (!dates[lang]) 213 lang = defaults.language; 214 } 215 o.language = lang; 216 217 // Retrieve view index from any aliases 218 o.startView = this._resolveViewName(o.startView); 219 o.minViewMode = this._resolveViewName(o.minViewMode); 220 o.maxViewMode = this._resolveViewName(o.maxViewMode); 221 222 // Check view is between min and max 223 o.startView = Math.max(this.o.minViewMode, Math.min(this.o.maxViewMode, o.startView)); 224 225 // true, false, or Number > 0 226 if (o.multidate !== true) { 227 o.multidate = Number(o.multidate) || false; 228 if (o.multidate !== false) 229 o.multidate = Math.max(0, o.multidate); 230 } 231 o.multidateSeparator = String(o.multidateSeparator); 232 233 o.weekStart %= 7; 234 o.weekEnd = (o.weekStart + 6) % 7; 235 236 var format = DPGlobal.parseFormat(o.format); 237 if (o.startDate !== -Infinity) { 238 if (!!o.startDate) { 239 if (o.startDate instanceof Date) 240 o.startDate = this._local_to_utc(this._zero_time(o.startDate)); 241 else 242 o.startDate = DPGlobal.parseDate(o.startDate, format, o.language, o.assumeNearbyYear); 243 } else { 244 o.startDate = -Infinity; 245 } 246 } 247 if (o.endDate !== Infinity) { 248 if (!!o.endDate) { 249 if (o.endDate instanceof Date) 250 o.endDate = this._local_to_utc(this._zero_time(o.endDate)); 251 else 252 o.endDate = DPGlobal.parseDate(o.endDate, format, o.language, o.assumeNearbyYear); 253 } else { 254 o.endDate = Infinity; 255 } 256 } 257 258 o.daysOfWeekDisabled = this._resolveDaysOfWeek(o.daysOfWeekDisabled || []); 259 o.daysOfWeekHighlighted = this._resolveDaysOfWeek(o.daysOfWeekHighlighted || []); 260 261 o.datesDisabled = o.datesDisabled || []; 262 if (!$.isArray(o.datesDisabled)) { 263 o.datesDisabled = o.datesDisabled.split(','); 264 } 265 o.datesDisabled = $.map(o.datesDisabled, function(d) { 266 return DPGlobal.parseDate(d, format, o.language, o.assumeNearbyYear); 267 }); 268 269 var plc = String(o.orientation).toLowerCase().split(/\s+/g), 270 _plc = o.orientation.toLowerCase(); 271 plc = $.grep(plc, function(word) { 272 return /^auto|left|right|top|bottom$/.test(word); 273 }); 274 o.orientation = { 275 x: 'auto', 276 y: 'auto' 277 }; 278 if (!_plc || _plc === 'auto') 279 ; // no action 280 else if (plc.length === 1) { 281 switch (plc[0]) { 282 case 'top': 283 case 'bottom': 284 o.orientation.y = plc[0]; 285 break; 286 case 'left': 287 case 'right': 288 o.orientation.x = plc[0]; 289 break; 290 } 291 } else { 292 _plc = $.grep(plc, function(word) { 293 return /^left|right$/.test(word); 294 }); 295 o.orientation.x = _plc[0] || 'auto'; 296 297 _plc = $.grep(plc, function(word) { 298 return /^top|bottom$/.test(word); 299 }); 300 o.orientation.y = _plc[0] || 'auto'; 301 } 302 if (o.defaultViewDate instanceof Date || typeof o.defaultViewDate === 'string') { 303 o.defaultViewDate = DPGlobal.parseDate(o.defaultViewDate, format, o.language, o.assumeNearbyYear); 304 } else if (o.defaultViewDate) { 305 var year = o.defaultViewDate.year || new Date().getFullYear(); 306 var month = o.defaultViewDate.month || 0; 307 var day = o.defaultViewDate.day || 1; 308 o.defaultViewDate = UTCDate(year, month, day); 309 } else { 310 o.defaultViewDate = UTCToday(); 311 } 312 }, 313 _events: [], 314 _secondaryEvents: [], 315 _applyEvents: function(evs) { 316 for (var i = 0, el, ch, ev; i < evs.length; i++) { 317 el = evs[i][0]; 318 if (evs[i].length === 2) { 319 ch = undefined; 320 ev = evs[i][1]; 321 } else if (evs[i].length === 3) { 322 ch = evs[i][1]; 323 ev = evs[i][2]; 324 } 325 el.on(ev, ch); 326 } 327 }, 328 _unapplyEvents: function(evs) { 329 for (var i = 0, el, ev, ch; i < evs.length; i++) { 330 el = evs[i][0]; 331 if (evs[i].length === 2) { 332 ch = undefined; 333 ev = evs[i][1]; 334 } else if (evs[i].length === 3) { 335 ch = evs[i][1]; 336 ev = evs[i][2]; 337 } 338 el.off(ev, ch); 339 } 340 }, 341 _buildEvents: function() { 342 var events = { 343 keyup: $.proxy(function(e) { 344 if ($.inArray(e.keyCode, [27, 37, 39, 38, 40, 32, 13, 9]) === -1) 345 this.update(); 346 }, this), 347 keydown: $.proxy(this.keydown, this), 348 paste: $.proxy(this.paste, this) 349 }; 350 351 if (this.o.showOnFocus === true) { 352 events.focus = $.proxy(this.show, this); 353 } 354 355 if (this.isInput) { // single input 356 this._events = [ 357 [this.element, events] 358 ]; 359 } 360 // component: input + button 361 else if (this.component && this.inputField.length) { 362 this._events = [ 363 // For components that are not readonly, allow keyboard nav 364 [this.inputField, events], 365 [this.component, { 366 click: $.proxy(this.show, this) 367 }] 368 ]; 369 } else { 370 this._events = [ 371 [this.element, { 372 click: $.proxy(this.show, this), 373 keydown: $.proxy(this.keydown, this) 374 }] 375 ]; 376 } 377 this._events.push( 378 // Component: listen for blur on element descendants 379 [this.element, '*', { 380 blur: $.proxy(function(e) { 381 this._focused_from = e.target; 382 }, this) 383 }], 384 // Input: listen for blur on element 385 [this.element, { 386 blur: $.proxy(function(e) { 387 this._focused_from = e.target; 388 }, this) 389 }] 390 ); 391 392 if (this.o.immediateUpdates) { 393 // Trigger input updates immediately on changed year/month 394 this._events.push([this.element, { 395 'changeYear changeMonth': $.proxy(function(e) { 396 this.update(e.date); 397 }, this) 398 }]); 399 } 400 401 this._secondaryEvents = [ 402 [this.picker, { 403 click: $.proxy(this.click, this) 404 }], 405 [this.picker, '.prev, .next', { 406 click: $.proxy(this.navArrowsClick, this) 407 }], 408 [$(window), { 409 resize: $.proxy(this.place, this) 410 }], 411 [$(document), { 412 'mousedown touchstart': $.proxy(function(e) { 413 // Clicked outside the datepicker, hide it 414 if (!( 415 this.element.is(e.target) || 416 this.element.find(e.target).length || 417 this.picker.is(e.target) || 418 this.picker.find(e.target).length || 419 this.isInline 420 )) { 421 this.hide(); 422 } 423 }, this) 424 }] 425 ]; 426 }, 427 _attachEvents: function() { 428 this._detachEvents(); 429 this._applyEvents(this._events); 430 }, 431 _detachEvents: function() { 432 this._unapplyEvents(this._events); 433 }, 434 _attachSecondaryEvents: function() { 435 this._detachSecondaryEvents(); 436 this._applyEvents(this._secondaryEvents); 437 }, 438 _detachSecondaryEvents: function() { 439 this._unapplyEvents(this._secondaryEvents); 440 }, 441 _trigger: function(event, altdate) { 442 var date = altdate || this.dates.get(-1), 443 local_date = this._utc_to_local(date); 444 445 this.element.trigger({ 446 type: event, 447 date: local_date, 448 viewMode: this.viewMode, 449 dates: $.map(this.dates, this._utc_to_local), 450 format: $.proxy(function(ix, format) { 451 if (arguments.length === 0) { 452 ix = this.dates.length - 1; 453 format = this.o.format; 454 } else if (typeof ix === 'string') { 455 format = ix; 456 ix = this.dates.length - 1; 457 } 458 format = format || this.o.format; 459 var date = this.dates.get(ix); 460 return DPGlobal.formatDate(date, format, this.o.language); 461 }, this) 462 }); 463 }, 464 465 show: function() { 466 if (this.inputField.prop('disabled') || (this.inputField.prop('readonly') && this.o.enableOnReadonly === false)) 467 return; 468 if (!this.isInline) 469 this.picker.appendTo(this.o.container); 470 this.place(); 471 this.picker.show(); 472 this._attachSecondaryEvents(); 473 this._trigger('show'); 474 if ((window.navigator.msMaxTouchPoints || 'ontouchstart' in document) && this.o.disableTouchKeyboard) { 475 $(this.element).blur(); 476 } 477 return this; 478 }, 479 480 hide: function() { 481 if (this.isInline || !this.picker.is(':visible')) 482 return this; 483 this.focusDate = null; 484 this.picker.hide().detach(); 485 this._detachSecondaryEvents(); 486 this.setViewMode(this.o.startView); 487 488 if (this.o.forceParse && this.inputField.val()) 489 this.setValue(); 490 this._trigger('hide'); 491 return this; 492 }, 493 494 destroy: function() { 495 this.hide(); 496 this._detachEvents(); 497 this._detachSecondaryEvents(); 498 this.picker.remove(); 499 delete this.element.data().datepicker; 500 if (!this.isInput) { 501 delete this.element.data().date; 502 } 503 return this; 504 }, 505 506 paste: function(e) { 507 var dateString; 508 if (e.originalEvent.clipboardData && e.originalEvent.clipboardData.types && 509 $.inArray('text/plain', e.originalEvent.clipboardData.types) !== -1) { 510 dateString = e.originalEvent.clipboardData.getData('text/plain'); 511 } else if (window.clipboardData) { 512 dateString = window.clipboardData.getData('Text'); 513 } else { 514 return; 515 } 516 this.setDate(dateString); 517 this.update(); 518 e.preventDefault(); 519 }, 520 521 _utc_to_local: function(utc) { 522 if (!utc) { 523 return utc; 524 } 525 526 var local = new Date(utc.getTime() + (utc.getTimezoneOffset() * 60000)); 527 528 if (local.getTimezoneOffset() !== utc.getTimezoneOffset()) { 529 local = new Date(utc.getTime() + (local.getTimezoneOffset() * 60000)); 530 } 531 532 return local; 533 }, 534 _local_to_utc: function(local) { 535 return local && new Date(local.getTime() - (local.getTimezoneOffset() * 60000)); 536 }, 537 _zero_time: function(local) { 538 return local && new Date(local.getFullYear(), local.getMonth(), local.getDate()); 539 }, 540 _zero_utc_time: function(utc) { 541 return utc && UTCDate(utc.getUTCFullYear(), utc.getUTCMonth(), utc.getUTCDate()); 542 }, 543 544 getDates: function() { 545 return $.map(this.dates, this._utc_to_local); 546 }, 547 548 getUTCDates: function() { 549 return $.map(this.dates, function(d) { 550 return new Date(d); 551 }); 552 }, 553 554 getDate: function() { 555 return this._utc_to_local(this.getUTCDate()); 556 }, 557 558 getUTCDate: function() { 559 var selected_date = this.dates.get(-1); 560 if (selected_date !== undefined) { 561 return new Date(selected_date); 562 } else { 563 return null; 564 } 565 }, 566 567 clearDates: function() { 568 this.inputField.val(''); 569 this.update(); 570 this._trigger('changeDate'); 571 572 if (this.o.autoclose) { 573 this.hide(); 574 } 575 }, 576 577 setDates: function() { 578 var args = $.isArray(arguments[0]) ? arguments[0] : arguments; 579 this.update.apply(this, args); 580 this._trigger('changeDate'); 581 this.setValue(); 582 return this; 583 }, 584 585 setUTCDates: function() { 586 var args = $.isArray(arguments[0]) ? arguments[0] : arguments; 587 this.setDates.apply(this, $.map(args, this._utc_to_local)); 588 return this; 589 }, 590 591 setDate: alias('setDates'), 592 setUTCDate: alias('setUTCDates'), 593 remove: alias('destroy', 'Method `remove` is deprecated and will be removed in version 2.0. Use `destroy` instead'), 594 595 setValue: function() { 596 var formatted = this.getFormattedDate(); 597 this.inputField.val(formatted); 598 return this; 599 }, 600 601 getFormattedDate: function(format) { 602 if (format === undefined) 603 format = this.o.format; 604 605 var lang = this.o.language; 606 return $.map(this.dates, function(d) { 607 return DPGlobal.formatDate(d, format, lang); 608 }).join(this.o.multidateSeparator); 609 }, 610 611 getStartDate: function() { 612 return this.o.startDate; 613 }, 614 615 setStartDate: function(startDate) { 616 this._process_options({ 617 startDate: startDate 618 }); 619 this.update(); 620 this.updateNavArrows(); 621 return this; 622 }, 623 624 getEndDate: function() { 625 return this.o.endDate; 626 }, 627 628 setEndDate: function(endDate) { 629 this._process_options({ 630 endDate: endDate 631 }); 632 this.update(); 633 this.updateNavArrows(); 634 return this; 635 }, 636 637 setDaysOfWeekDisabled: function(daysOfWeekDisabled) { 638 this._process_options({ 639 daysOfWeekDisabled: daysOfWeekDisabled 640 }); 641 this.update(); 642 return this; 643 }, 644 645 setDaysOfWeekHighlighted: function(daysOfWeekHighlighted) { 646 this._process_options({ 647 daysOfWeekHighlighted: daysOfWeekHighlighted 648 }); 649 this.update(); 650 return this; 651 }, 652 653 setDatesDisabled: function(datesDisabled) { 654 this._process_options({ 655 datesDisabled: datesDisabled 656 }); 657 this.update(); 658 return this; 659 }, 660 661 place: function() { 662 if (this.isInline) 663 return this; 664 var calendarWidth = this.picker.outerWidth(), 665 calendarHeight = this.picker.outerHeight(), 666 visualPadding = 10, 667 container = $(this.o.container), 668 windowWidth = container.width(), 669 scrollTop = this.o.container === 'body' ? $(document).scrollTop() : container.scrollTop(), 670 appendOffset = container.offset(); 671 672 var parentsZindex = [0]; 673 this.element.parents().each(function() { 674 var itemZIndex = $(this).css('z-index'); 675 if (itemZIndex !== 'auto' && Number(itemZIndex) !== 0) parentsZindex.push(Number(itemZIndex)); 676 }); 677 var zIndex = Math.max.apply(Math, parentsZindex) + this.o.zIndexOffset; 678 var offset = this.component ? this.component.parent().offset() : this.element.offset(); 679 var height = this.component ? this.component.outerHeight(true) : this.element.outerHeight(false); 680 var width = this.component ? this.component.outerWidth(true) : this.element.outerWidth(false); 681 var left = offset.left - appendOffset.left; 682 var top = offset.top - appendOffset.top; 683 684 if (this.o.container !== 'body') { 685 top += scrollTop; 686 } 687 688 this.picker.removeClass( 689 'datepicker-orient-top datepicker-orient-bottom ' + 690 'datepicker-orient-right datepicker-orient-left' 691 ); 692 693 if (this.o.orientation.x !== 'auto') { 694 this.picker.addClass('datepicker-orient-' + this.o.orientation.x); 695 if (this.o.orientation.x === 'right') 696 left -= calendarWidth - width; 697 } 698 // auto x orientation is best-placement: if it crosses a window 699 // edge, fudge it sideways 700 else { 701 if (offset.left < 0) { 702 // component is outside the window on the left side. Move it into visible range 703 this.picker.addClass('datepicker-orient-left'); 704 left -= offset.left - visualPadding; 705 } else if (left + calendarWidth > windowWidth) { 706 // the calendar passes the widow right edge. Align it to component right side 707 this.picker.addClass('datepicker-orient-right'); 708 left += width - calendarWidth; 709 } else { 710 if (this.o.rtl) { 711 // Default to right 712 this.picker.addClass('datepicker-orient-right'); 713 } else { 714 // Default to left 715 this.picker.addClass('datepicker-orient-left'); 716 } 717 } 718 } 719 720 // auto y orientation is best-situation: top or bottom, no fudging, 721 // decision based on which shows more of the calendar 722 var yorient = this.o.orientation.y, 723 top_overflow; 724 if (yorient === 'auto') { 725 top_overflow = -scrollTop + top - calendarHeight; 726 yorient = top_overflow < 0 ? 'bottom' : 'top'; 727 } 728 729 this.picker.addClass('datepicker-orient-' + yorient); 730 if (yorient === 'top') 731 top -= calendarHeight + parseInt(this.picker.css('padding-top')); 732 else 733 top += height; 734 735 if (this.o.rtl) { 736 var right = windowWidth - (left + width); 737 this.picker.css({ 738 top: top, 739 right: right, 740 zIndex: zIndex 741 }); 742 } else { 743 this.picker.css({ 744 top: top, 745 left: left, 746 zIndex: zIndex 747 }); 748 } 749 return this; 750 }, 751 752 _allow_update: true, 753 update: function() { 754 if (!this._allow_update) 755 return this; 756 757 var oldDates = this.dates.copy(), 758 dates = [], 759 fromArgs = false; 760 if (arguments.length) { 761 $.each(arguments, $.proxy(function(i, date) { 762 if (date instanceof Date) 763 date = this._local_to_utc(date); 764 dates.push(date); 765 }, this)); 766 fromArgs = true; 767 } else { 768 dates = this.isInput ? 769 this.element.val() : 770 this.element.data('date') || this.inputField.val(); 771 if (dates && this.o.multidate) 772 dates = dates.split(this.o.multidateSeparator); 773 else 774 dates = [dates]; 775 delete this.element.data().date; 776 } 777 778 dates = $.map(dates, $.proxy(function(date) { 779 return DPGlobal.parseDate(date, this.o.format, this.o.language, this.o.assumeNearbyYear); 780 }, this)); 781 dates = $.grep(dates, $.proxy(function(date) { 782 return (!this.dateWithinRange(date) || 783 !date 784 ); 785 }, this), true); 786 this.dates.replace(dates); 787 788 if (this.o.updateViewDate) { 789 if (this.dates.length) 790 this.viewDate = new Date(this.dates.get(-1)); 791 else if (this.viewDate < this.o.startDate) 792 this.viewDate = new Date(this.o.startDate); 793 else if (this.viewDate > this.o.endDate) 794 this.viewDate = new Date(this.o.endDate); 795 else 796 this.viewDate = this.o.defaultViewDate; 797 } 798 799 if (fromArgs) { 800 // setting date by clicking 801 this.setValue(); 802 this.element.change(); 803 } else if (this.dates.length) { 804 // setting date by typing 805 if (typeof this.o.format === 'string') { 806 if ((String(this.element[0].value).length === String(this.o.format).length) && (String(oldDates) !== String(this.dates))) 807 this._trigger('changeDate'); 808 this.element.change(); 809 } else if (String(oldDates) !== String(this.dates)) { 810 this._trigger('changeDate'); 811 this.element.change(); 812 } 813 } 814 if (!this.dates.length && oldDates.length) { 815 this._trigger('clearDate'); 816 this.element.change(); 817 } 818 819 this.fill(); 820 return this; 821 }, 822 823 fillDow: function() { 824 var dowCnt = this.o.weekStart, 825 html = '<tr>'; 826 if (this.o.calendarWeeks) { 827 html += '<th class="cw"> </th>'; 828 } 829 while (dowCnt < this.o.weekStart + 7) { 830 html += '<th class="dow'; 831 if ($.inArray(dowCnt, this.o.daysOfWeekDisabled) !== -1) 832 html += ' disabled'; 833 html += '">' + dates[this.o.language].daysMin[(dowCnt++) % 7] + '</th>'; 834 } 835 html += '</tr>'; 836 this.picker.find('.datepicker-days thead').append(html); 837 }, 838 839 fillMonths: function() { 840 var localDate = this._utc_to_local(this.viewDate); 841 var html = ''; 842 var focused; 843 for (var i = 0; i < 12; i++) { 844 focused = localDate && localDate.getMonth() === i ? ' focused' : ''; 845 html += '<span class="month' + focused + '">' + dates[this.o.language].monthsShort[i] + '</span>'; 846 } 847 this.picker.find('.datepicker-months td').html(html); 848 }, 849 850 setRange: function(range) { 851 if (!range || !range.length) 852 delete this.range; 853 else 854 this.range = $.map(range, function(d) { 855 return d.valueOf(); 856 }); 857 this.fill(); 858 }, 859 860 getClassNames: function(date) { 861 var cls = [], 862 year = this.viewDate.getUTCFullYear(), 863 month = this.viewDate.getUTCMonth(), 864 today = UTCToday(); 865 if (date.getUTCFullYear() < year || (date.getUTCFullYear() === year && date.getUTCMonth() < month)) { 866 cls.push('old'); 867 } else if (date.getUTCFullYear() > year || (date.getUTCFullYear() === year && date.getUTCMonth() > month)) { 868 cls.push('new'); 869 } 870 if (this.focusDate && date.valueOf() === this.focusDate.valueOf()) 871 cls.push('focused'); 872 // Compare internal UTC date with UTC today, not local today 873 if (this.o.todayHighlight && isUTCEquals(date, today)) { 874 cls.push('today'); 875 } 876 if (this.dates.contains(date) !== -1) 877 cls.push('active'); 878 if (!this.dateWithinRange(date)) { 879 cls.push('disabled'); 880 } 881 if (this.dateIsDisabled(date)) { 882 cls.push('disabled', 'disabled-date'); 883 } 884 if ($.inArray(date.getUTCDay(), this.o.daysOfWeekHighlighted) !== -1) { 885 cls.push('highlighted'); 886 } 887 888 if (this.range) { 889 if (date > this.range[0] && date < this.range[this.range.length - 1]) { 890 cls.push('range'); 891 } 892 if ($.inArray(date.valueOf(), this.range) !== -1) { 893 cls.push('selected'); 894 } 895 if (date.valueOf() === this.range[0]) { 896 cls.push('range-start'); 897 } 898 if (date.valueOf() === this.range[this.range.length - 1]) { 899 cls.push('range-end'); 900 } 901 } 902 return cls; 903 }, 904 905 _fill_yearsView: function(selector, cssClass, factor, year, startYear, endYear, beforeFn) { 906 var html = ''; 907 var step = factor / 10; 908 var view = this.picker.find(selector); 909 var startVal = Math.floor(year / factor) * factor; 910 var endVal = startVal + step * 9; 911 var focusedVal = Math.floor(this.viewDate.getFullYear() / step) * step; 912 var selected = $.map(this.dates, function(d) { 913 return Math.floor(d.getUTCFullYear() / step) * step; 914 }); 915 916 var classes, tooltip, before; 917 for (var currVal = startVal - step; currVal <= endVal + step; currVal += step) { 918 classes = [cssClass]; 919 tooltip = null; 920 921 if (currVal === startVal - step) { 922 classes.push('old'); 923 } else if (currVal === endVal + step) { 924 classes.push('new'); 925 } 926 if ($.inArray(currVal, selected) !== -1) { 927 classes.push('active'); 928 } 929 if (currVal < startYear || currVal > endYear) { 930 classes.push('disabled'); 931 } 932 if (currVal === focusedVal) { 933 classes.push('focused'); 934 } 935 936 if (beforeFn !== $.noop) { 937 before = beforeFn(new Date(currVal, 0, 1)); 938 if (before === undefined) { 939 before = {}; 940 } else if (typeof before === 'boolean') { 941 before = { 942 enabled: before 943 }; 944 } else if (typeof before === 'string') { 945 before = { 946 classes: before 947 }; 948 } 949 if (before.enabled === false) { 950 classes.push('disabled'); 951 } 952 if (before.classes) { 953 classes = classes.concat(before.classes.split(/\s+/)); 954 } 955 if (before.tooltip) { 956 tooltip = before.tooltip; 957 } 958 } 959 960 html += '<span class="' + classes.join(' ') + '"' + (tooltip ? ' title="' + tooltip + '"' : '') + '>' + currVal + '</span>'; 961 } 962 963 view.find('.datepicker-switch').text(startVal + '-' + endVal); 964 view.find('td').html(html); 965 }, 966 967 fill: function() { 968 var d = new Date(this.viewDate), 969 year = d.getUTCFullYear(), 970 month = d.getUTCMonth(), 971 startYear = this.o.startDate !== -Infinity ? this.o.startDate.getUTCFullYear() : -Infinity, 972 startMonth = this.o.startDate !== -Infinity ? this.o.startDate.getUTCMonth() : -Infinity, 973 endYear = this.o.endDate !== Infinity ? this.o.endDate.getUTCFullYear() : Infinity, 974 endMonth = this.o.endDate !== Infinity ? this.o.endDate.getUTCMonth() : Infinity, 975 todaytxt = dates[this.o.language].today || dates['en'].today || '', 976 cleartxt = dates[this.o.language].clear || dates['en'].clear || '', 977 titleFormat = dates[this.o.language].titleFormat || dates['en'].titleFormat, 978 tooltip, 979 before; 980 if (isNaN(year) || isNaN(month)) 981 return; 982 this.picker.find('.datepicker-days .datepicker-switch') 983 .text(DPGlobal.formatDate(d, titleFormat, this.o.language)); 984 this.picker.find('tfoot .today') 985 .text(todaytxt) 986 .toggle(this.o.todayBtn !== false); 987 this.picker.find('tfoot .clear') 988 .text(cleartxt) 989 .toggle(this.o.clearBtn !== false); 990 this.picker.find('thead .datepicker-title') 991 .text(this.o.title) 992 .toggle(this.o.title !== ''); 993 this.updateNavArrows(); 994 this.fillMonths(); 995 var prevMonth = UTCDate(year, month, 0), 996 day = prevMonth.getUTCDate(); 997 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.o.weekStart + 7) % 7); 998 var nextMonth = new Date(prevMonth); 999 if (prevMonth.getUTCFullYear() < 100) { 1000 nextMonth.setUTCFullYear(prevMonth.getUTCFullYear()); 1001 } 1002 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42); 1003 nextMonth = nextMonth.valueOf(); 1004 var html = []; 1005 var weekDay, clsName; 1006 while (prevMonth.valueOf() < nextMonth) { 1007 weekDay = prevMonth.getUTCDay(); 1008 if (weekDay === this.o.weekStart) { 1009 html.push('<tr>'); 1010 if (this.o.calendarWeeks) { 1011 // ISO 8601: First week contains first thursday. 1012 // ISO also states week starts on Monday, but we can be more abstract here. 1013 var 1014 // Start of current week: based on weekstart/current date 1015 ws = new Date(+prevMonth + (this.o.weekStart - weekDay - 7) % 7 * 864e5), 1016 // Thursday of this week 1017 th = new Date(Number(ws) + (7 + 4 - ws.getUTCDay()) % 7 * 864e5), 1018 // First Thursday of year, year from thursday 1019 yth = new Date(Number(yth = UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay()) % 7 * 864e5), 1020 // Calendar week: ms between thursdays, div ms per day, div 7 days 1021 calWeek = (th - yth) / 864e5 / 7 + 1; 1022 html.push('<td class="cw">' + calWeek + '</td>'); 1023 } 1024 } 1025 clsName = this.getClassNames(prevMonth); 1026 clsName.push('day'); 1027 1028 if (this.o.beforeShowDay !== $.noop) { 1029 before = this.o.beforeShowDay(this._utc_to_local(prevMonth)); 1030 if (before === undefined) 1031 before = {}; 1032 else if (typeof before === 'boolean') 1033 before = { 1034 enabled: before 1035 }; 1036 else if (typeof before === 'string') 1037 before = { 1038 classes: before 1039 }; 1040 if (before.enabled === false) 1041 clsName.push('disabled'); 1042 if (before.classes) 1043 clsName = clsName.concat(before.classes.split(/\s+/)); 1044 if (before.tooltip) 1045 tooltip = before.tooltip; 1046 } 1047 1048 //Check if uniqueSort exists (supported by jquery >=1.12 and >=2.2) 1049 //Fallback to unique function for older jquery versions 1050 if ($.isFunction($.uniqueSort)) { 1051 clsName = $.uniqueSort(clsName); 1052 } else { 1053 clsName = $.unique(clsName); 1054 } 1055 1056 // Creative Tim - we added a div inside each td for design purposes 1057 html.push('<td class="' + clsName.join(' ') + '"' + (tooltip ? ' title="' + tooltip + '"' : '') + (this.o.dateCells ? ' data-date="' + prevMonth.getTime().toString() + '"' : '') + '><div>' + prevMonth.getUTCDate() + '</div></td>'); 1058 tooltip = null; 1059 if (weekDay === this.o.weekEnd) { 1060 html.push('</tr>'); 1061 } 1062 prevMonth.setUTCDate(prevMonth.getUTCDate() + 1); 1063 } 1064 this.picker.find('.datepicker-days tbody').html(html.join('')); 1065 1066 var monthsTitle = dates[this.o.language].monthsTitle || dates['en'].monthsTitle || 'Months'; 1067 var months = this.picker.find('.datepicker-months') 1068 .find('.datepicker-switch') 1069 .text(this.o.maxViewMode < 2 ? monthsTitle : year) 1070 .end() 1071 .find('tbody span').removeClass('active'); 1072 1073 $.each(this.dates, function(i, d) { 1074 if (d.getUTCFullYear() === year) 1075 months.eq(d.getUTCMonth()).addClass('active'); 1076 }); 1077 1078 if (year < startYear || year > endYear) { 1079 months.addClass('disabled'); 1080 } 1081 if (year === startYear) { 1082 months.slice(0, startMonth).addClass('disabled'); 1083 } 1084 if (year === endYear) { 1085 months.slice(endMonth + 1).addClass('disabled'); 1086 } 1087 1088 if (this.o.beforeShowMonth !== $.noop) { 1089 var that = this; 1090 $.each(months, function(i, month) { 1091 var moDate = new Date(year, i, 1); 1092 var before = that.o.beforeShowMonth(moDate); 1093 if (before === undefined) 1094 before = {}; 1095 else if (typeof before === 'boolean') 1096 before = { 1097 enabled: before 1098 }; 1099 else if (typeof before === 'string') 1100 before = { 1101 classes: before 1102 }; 1103 if (before.enabled === false && !$(month).hasClass('disabled')) 1104 $(month).addClass('disabled'); 1105 if (before.classes) 1106 $(month).addClass(before.classes); 1107 if (before.tooltip) 1108 $(month).prop('title', before.tooltip); 1109 }); 1110 } 1111 1112 // Generating decade/years picker 1113 this._fill_yearsView( 1114 '.datepicker-years', 1115 'year', 1116 10, 1117 year, 1118 startYear, 1119 endYear, 1120 this.o.beforeShowYear 1121 ); 1122 1123 // Generating century/decades picker 1124 this._fill_yearsView( 1125 '.datepicker-decades', 1126 'decade', 1127 100, 1128 year, 1129 startYear, 1130 endYear, 1131 this.o.beforeShowDecade 1132 ); 1133 1134 // Generating millennium/centuries picker 1135 this._fill_yearsView( 1136 '.datepicker-centuries', 1137 'century', 1138 1000, 1139 year, 1140 startYear, 1141 endYear, 1142 this.o.beforeShowCentury 1143 ); 1144 }, 1145 1146 updateNavArrows: function() { 1147 if (!this._allow_update) 1148 return; 1149 1150 var d = new Date(this.viewDate), 1151 year = d.getUTCFullYear(),
1152 month = d.getUTCMonth(), 1153 startYear = this.o.startDate !== -Infinity ? this.o.startDate.getUTCFullYear() : -Infinity, 1154 startMonth = this.o.startDate !== -Infinity ? this.o.startDate.getUTCMonth() : -Infinity, 1155 endYear = this.o.endDate !== Infinity ? this.o.endDate.getUTCFullYear() : Infinity, 1156 endMonth = this.o.endDate !== Infinity ? this.o.endDate.getUTCMonth() : Infinity, 1157 prevIsDisabled, 1158 nextIsDisabled, 1159 factor = 1; 1160 switch (this.viewMode) { 1161 case 0: 1162 prevIsDisabled = year <= startYear && month <= startMonth; 1163 nextIsDisabled = year >= endYear && month >= endMonth; 1164 break; 1165 case 4: 1166 factor *= 10; 1167 /* falls through */ 1168 case 3: 1169 factor *= 10; 1170 /* falls through */ 1171 case 2: 1172 factor *= 10; 1173 /* falls through */ 1174 case 1: 1175 prevIsDisabled = Math.floor(year / factor) * factor <= startYear; 1176 nextIsDisabled = Math.floor(year / factor) * factor + factor >= endYear; 1177 break; 1178 } 1179 1180 this.picker.find('.prev').toggleClass('disabled', prevIsDisabled); 1181 this.picker.find('.next').toggleClass('disabled', nextIsDisabled); 1182 }, 1183 1184 click: function(e) { 1185 e.preventDefault(); 1186 e.stopPropagation(); 1187 1188 var target, dir, day, year, month; 1189 target = $(e.target); 1190 1191 // Clicked on the switch 1192 if (target.hasClass('datepicker-switch') && this.viewMode !== this.o.maxViewMode) { 1193 this.setViewMode(this.viewMode + 1); 1194 } 1195 1196 // Clicked on today button 1197 if (target.hasClass('today') && !target.hasClass('day')) { 1198 this.setViewMode(0); 1199 this._setDate(UTCToday(), this.o.todayBtn === 'linked' ? null : 'view'); 1200 } 1201 1202 // Clicked on clear button 1203 if (target.hasClass('clear')) { 1204 this.clearDates(); 1205 } 1206 1207 if (!target.hasClass('disabled')) { 1208 // Clicked on a day 1209 if (target.hasClass('day')) { 1210 day = Number(target.text()); 1211 year = this.viewDate.getUTCFullYear(); 1212 month = this.viewDate.getUTCMonth(); 1213 1214 if (target.hasClass('old') || target.hasClass('new')) { 1215 dir = target.hasClass('old') ? -1 : 1; 1216 month = (month + dir + 12) % 12; 1217 if ((dir === -1 && month === 11) || (dir === 1 && month === 0)) { 1218 year += dir; 1219 if (this.o.updateViewDate) { 1220 this._trigger('changeYear', this.viewDate); 1221 } 1222 } 1223 if (this.o.updateViewDate) { 1224 this._trigger('changeMonth', this.viewDate); 1225 } 1226 } 1227 this._setDate(UTCDate(year, month, day)); 1228 } 1229 1230 // Clicked on a month, year, decade, century 1231 if (target.hasClass('month') || 1232 target.hasClass('year') || 1233 target.hasClass('decade') || 1234 target.hasClass('century')) { 1235 this.viewDate.setUTCDate(1); 1236 1237 day = 1; 1238 if (this.viewMode === 1) { 1239 month = target.parent().find('span').index(target); 1240 year = this.viewDate.getUTCFullYear(); 1241 this.viewDate.setUTCMonth(month); 1242 } else { 1243 month = 0; 1244 year = Number(target.text()); 1245 this.viewDate.setUTCFullYear(year); 1246 } 1247 1248 this._trigger(DPGlobal.viewModes[this.viewMode - 1].e, this.viewDate); 1249 1250 if (this.viewMode === this.o.minViewMode) { 1251 this._setDate(UTCDate(year, month, day)); 1252 } else { 1253 this.setViewMode(this.viewMode - 1); 1254 this.fill(); 1255 } 1256 } 1257 } 1258 1259 if (this.picker.is(':visible') && this._focused_from) { 1260 this._focused_from.focus(); 1261 } 1262 delete this._focused_from; 1263 }, 1264 1265 // Clicked on prev or next 1266 navArrowsClick: function(e) { 1267 var target = $(e.target); 1268 var dir = target.hasClass('prev') ? -1 : 1; 1269 if (this.viewMode !== 0) { 1270 dir *= DPGlobal.viewModes[this.viewMode].navStep * 12; 1271 } 1272 this.viewDate = this.moveMonth(this.viewDate, dir);
vendor: 23,277 bytes, lines 1273-2040
1273 this._trigger(DPGlobal.viewModes[this.viewMode].e, this.viewDate); 1274 this.fill(); 1275 }, 1276 1277 _toggle_multidate: function(date) { 1278 var ix = this.dates.contains(date); 1279 if (!date) { 1280 this.dates.clear(); 1281 } 1282 1283 if (ix !== -1) { 1284 if (this.o.multidate === true || this.o.multidate > 1 || this.o.toggleActive) { 1285 this.dates.remove(ix); 1286 } 1287 } else if (this.o.multidate === false) { 1288 this.dates.clear(); 1289 this.dates.push(date); 1290 } else { 1291 this.dates.push(date); 1292 } 1293 1294 if (typeof this.o.multidate === 'number') 1295 while (this.dates.length > this.o.multidate) 1296 this.dates.remove(0); 1297 }, 1298 1299 _setDate: function(date, which) { 1300 if (!which || which === 'date') 1301 this._toggle_multidate(date && new Date(date)); 1302 if ((!which && this.o.updateViewDate) || which === 'view') 1303 this.viewDate = date && new Date(date); 1304 1305 this.fill(); 1306 this.setValue(); 1307 if (!which || which !== 'view') { 1308 this._trigger('changeDate'); 1309 } 1310 this.inputField.trigger('change'); 1311 if (this.o.autoclose && (!which || which === 'date')) { 1312 this.hide(); 1313 } 1314 }, 1315 1316 moveDay: function(date, dir) { 1317 var newDate = new Date(date); 1318 newDate.setUTCDate(date.getUTCDate() + dir); 1319 1320 return newDate; 1321 }, 1322 1323 moveWeek: function(date, dir) { 1324 return this.moveDay(date, dir * 7); 1325 }, 1326 1327 moveMonth: function(date, dir) { 1328 if (!isValidDate(date)) 1329 return this.o.defaultViewDate; 1330 if (!dir) 1331 return date; 1332 var new_date = new Date(date.valueOf()), 1333 day = new_date.getUTCDate(), 1334 month = new_date.getUTCMonth(), 1335 mag = Math.abs(dir), 1336 new_month, test; 1337 dir = dir > 0 ? 1 : -1; 1338 if (mag === 1) { 1339 test = dir === -1 1340 // If going back one month, make sure month is not current month 1341 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02) 1342 ? 1343 function() { 1344 return new_date.getUTCMonth() === month; 1345 } 1346 // If going forward one month, make sure month is as expected 1347 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02) 1348 : 1349 function() { 1350 return new_date.getUTCMonth() !== new_month; 1351 }; 1352 new_month = month + dir; 1353 new_date.setUTCMonth(new_month); 1354 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11 1355 new_month = (new_month + 12) % 12; 1356 } else { 1357 // For magnitudes >1, move one month at a time... 1358 for (var i = 0; i < mag; i++) 1359 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)... 1360 new_date = this.moveMonth(new_date, dir); 1361 // ...then reset the day, keeping it in the new month 1362 new_month = new_date.getUTCMonth(); 1363 new_date.setUTCDate(day); 1364 test = function() { 1365 return new_month !== new_date.getUTCMonth(); 1366 }; 1367 } 1368 // Common date-resetting loop -- if date is beyond end of month, make it 1369 // end of month 1370 while (test()) { 1371 new_date.setUTCDate(--day); 1372 new_date.setUTCMonth(new_month); 1373 } 1374 return new_date; 1375 }, 1376 1377 moveYear: function(date, dir) { 1378 return this.moveMonth(date, dir * 12); 1379 }, 1380 1381 moveAvailableDate: function(date, dir, fn) { 1382 do { 1383 date = this[fn](date, dir); 1384 1385 if (!this.dateWithinRange(date)) 1386 return false; 1387 1388 fn = 'moveDay'; 1389 } 1390 while (this.dateIsDisabled(date)); 1391 1392 return date; 1393 }, 1394 1395 weekOfDateIsDisabled: function(date) { 1396 return $.inArray(date.getUTCDay(), this.o.daysOfWeekDisabled) !== -1; 1397 }, 1398 1399 dateIsDisabled: function(date) { 1400 return ( 1401 this.weekOfDateIsDisabled(date) || 1402 $.grep(this.o.datesDisabled, function(d) { 1403 return isUTCEquals(date, d); 1404 }).length > 0 1405 ); 1406 }, 1407 1408 dateWithinRange: function(date) { 1409 return date >= this.o.startDate && date <= this.o.endDate; 1410 }, 1411 1412 keydown: function(e) { 1413 if (!this.picker.is(':visible')) { 1414 if (e.keyCode === 40 || e.keyCode === 27) { // allow down to re-show picker 1415 this.show(); 1416 e.stopPropagation(); 1417 } 1418 return; 1419 } 1420 var dateChanged = false, 1421 dir, newViewDate, 1422 focusDate = this.focusDate || this.viewDate; 1423 switch (e.keyCode) { 1424 case 27: // escape 1425 if (this.focusDate) { 1426 this.focusDate = null; 1427 this.viewDate = this.dates.get(-1) || this.viewDate; 1428 this.fill(); 1429 } else 1430 this.hide(); 1431 e.preventDefault(); 1432 e.stopPropagation(); 1433 break; 1434 case 37: // left 1435 case 38: // up 1436 case 39: // right 1437 case 40: // down 1438 if (!this.o.keyboardNavigation || this.o.daysOfWeekDisabled.length === 7) 1439 break; 1440 dir = e.keyCode === 37 || e.keyCode === 38 ? -1 : 1; 1441 if (this.viewMode === 0) { 1442 if (e.ctrlKey) { 1443 newViewDate = this.moveAvailableDate(focusDate, dir, 'moveYear'); 1444 1445 if (newViewDate) 1446 this._trigger('changeYear', this.viewDate); 1447 } else if (e.shiftKey) { 1448 newViewDate = this.moveAvailableDate(focusDate, dir, 'moveMonth'); 1449 1450 if (newViewDate) 1451 this._trigger('changeMonth', this.viewDate); 1452 } else if (e.keyCode === 37 || e.keyCode === 39) { 1453 newViewDate = this.moveAvailableDate(focusDate, dir, 'moveDay'); 1454 } else if (!this.weekOfDateIsDisabled(focusDate)) { 1455 newViewDate = this.moveAvailableDate(focusDate, dir, 'moveWeek'); 1456 } 1457 } else if (this.viewMode === 1) { 1458 if (e.keyCode === 38 || e.keyCode === 40) { 1459 dir = dir * 4; 1460 } 1461 newViewDate = this.moveAvailableDate(focusDate, dir, 'moveMonth'); 1462 } else if (this.viewMode === 2) { 1463 if (e.keyCode === 38 || e.keyCode === 40) { 1464 dir = dir * 4; 1465 } 1466 newViewDate = this.moveAvailableDate(focusDate, dir, 'moveYear'); 1467 } 1468 if (newViewDate) { 1469 this.focusDate = this.viewDate = newViewDate; 1470 this.setValue(); 1471 this.fill(); 1472 e.preventDefault(); 1473 } 1474 break; 1475 case 13: // enter 1476 if (!this.o.forceParse) 1477 break; 1478 focusDate = this.focusDate || this.dates.get(-1) || this.viewDate; 1479 if (this.o.keyboardNavigation) { 1480 this._toggle_multidate(focusDate); 1481 dateChanged = true; 1482 } 1483 this.focusDate = null; 1484 this.viewDate = this.dates.get(-1) || this.viewDate; 1485 this.setValue(); 1486 this.fill(); 1487 if (this.picker.is(':visible')) { 1488 e.preventDefault(); 1489 e.stopPropagation(); 1490 if (this.o.autoclose) 1491 this.hide(); 1492 } 1493 break; 1494 case 9: // tab 1495 this.focusDate = null; 1496 this.viewDate = this.dates.get(-1) || this.viewDate; 1497 this.fill(); 1498 this.hide(); 1499 break; 1500 } 1501 if (dateChanged) { 1502 if (this.dates.length) 1503 this._trigger('changeDate'); 1504 else 1505 this._trigger('clearDate'); 1506 this.inputField.trigger('change'); 1507 } 1508 }, 1509 1510 setViewMode: function(viewMode) { 1511 this.viewMode = viewMode; 1512 this.picker 1513 .children('div') 1514 .hide() 1515 .filter('.datepicker-' + DPGlobal.viewModes[this.viewMode].clsName) 1516 .show(); 1517 this.updateNavArrows(); 1518 this._trigger('changeViewMode', new Date(this.viewDate)); 1519 } 1520 }; 1521 1522 var DateRangePicker = function(element, options) { 1523 $.data(element, 'datepicker', this); 1524 this.element = $(element); 1525 this.inputs = $.map(options.inputs, function(i) { 1526 return i.jquery ? i[0] : i; 1527 }); 1528 delete options.inputs; 1529 1530 this.keepEmptyValues = options.keepEmptyValues; 1531 delete options.keepEmptyValues; 1532 1533 datepickerPlugin.call($(this.inputs), options) 1534 .on('changeDate', $.proxy(this.dateUpdated, this)); 1535 1536 this.pickers = $.map(this.inputs, function(i) { 1537 return $.data(i, 'datepicker'); 1538 }); 1539 this.updateDates(); 1540 }; 1541 DateRangePicker.prototype = { 1542 updateDates: function() { 1543 this.dates = $.map(this.pickers, function(i) { 1544 return i.getUTCDate(); 1545 }); 1546 this.updateRanges(); 1547 }, 1548 updateRanges: function() { 1549 var range = $.map(this.dates, function(d) { 1550 return d.valueOf(); 1551 }); 1552 $.each(this.pickers, function(i, p) { 1553 p.setRange(range); 1554 }); 1555 }, 1556 dateUpdated: function(e) { 1557 // `this.updating` is a workaround for preventing infinite recursion 1558 // between `changeDate` triggering and `setUTCDate` calling. Until 1559 // there is a better mechanism. 1560 if (this.updating) 1561 return; 1562 this.updating = true; 1563 1564 var dp = $.data(e.target, 'datepicker'); 1565 1566 if (dp === undefined) { 1567 return; 1568 } 1569 1570 var new_date = dp.getUTCDate(), 1571 keep_empty_values = this.keepEmptyValues, 1572 i = $.inArray(e.target, this.inputs), 1573 j = i - 1, 1574 k = i + 1, 1575 l = this.inputs.length; 1576 if (i === -1) 1577 return; 1578 1579 $.each(this.pickers, function(i, p) { 1580 if (!p.getUTCDate() && (p === dp || !keep_empty_values)) 1581 p.setUTCDate(new_date); 1582 }); 1583 1584 if (new_date < this.dates[j]) { 1585 // Date being moved earlier/left 1586 while (j >= 0 && new_date < this.dates[j]) { 1587 this.pickers[j--].setUTCDate(new_date); 1588 } 1589 } else if (new_date > this.dates[k]) { 1590 // Date being moved later/right 1591 while (k < l && new_date > this.dates[k]) { 1592 this.pickers[k++].setUTCDate(new_date); 1593 } 1594 } 1595 this.updateDates(); 1596 1597 delete this.updating; 1598 }, 1599 destroy: function() { 1600 $.map(this.pickers, function(p) { 1601 p.destroy(); 1602 }); 1603 $(this.inputs).off('changeDate', this.dateUpdated); 1604 delete this.element.data().datepicker; 1605 }, 1606 remove: alias('destroy', 'Method `remove` is deprecated and will be removed in version 2.0. Use `destroy` instead') 1607 }; 1608 1609 function opts_from_el(el, prefix) { 1610 // Derive options from element data-attrs 1611 var data = $(el).data(), 1612 out = {}, 1613 inkey, 1614 replace = new RegExp('^' + prefix.toLowerCase() + '([A-Z])'); 1615 prefix = new RegExp('^' + prefix.toLowerCase()); 1616 1617 function re_lower(_, a) { 1618 return a.toLowerCase(); 1619 } 1620 for (var key in data) 1621 if (prefix.test(key)) { 1622 inkey = key.replace(replace, re_lower); 1623 out[inkey] = data[key]; 1624 } 1625 return out; 1626 } 1627 1628 function opts_from_locale(lang) { 1629 // Derive options from locale plugins 1630 var out = {}; 1631 // Check if "de-DE" style date is available, if not language should 1632 // fallback to 2 letter code eg "de" 1633 if (!dates[lang]) { 1634 lang = lang.split('-')[0]; 1635 if (!dates[lang]) 1636 return; 1637 } 1638 var d = dates[lang]; 1639 $.each(locale_opts, function(i, k) { 1640 if (k in d) 1641 out[k] = d[k]; 1642 }); 1643 return out; 1644 } 1645 1646 var old = $.fn.datepicker; 1647 var datepickerPlugin = function(option) { 1648 var args = Array.apply(null, arguments); 1649 args.shift(); 1650 var internal_return; 1651 this.each(function() { 1652 var $this = $(this), 1653 data = $this.data('datepicker'), 1654 options = typeof option === 'object' && option; 1655 if (!data) { 1656 var elopts = opts_from_el(this, 'date'), 1657 // Preliminary otions 1658 xopts = $.extend({}, defaults, elopts, options), 1659 locopts = opts_from_locale(xopts.language), 1660 // Options priority: js args, data-attrs, locales, defaults 1661 opts = $.extend({}, defaults, locopts, elopts, options); 1662 if ($this.hasClass('input-daterange') || opts.inputs) { 1663 $.extend(opts, { 1664 inputs: opts.inputs || $this.find('input').toArray() 1665 }); 1666 data = new DateRangePicker(this, opts); 1667 } else { 1668 data = new Datepicker(this, opts); 1669 } 1670 $this.data('datepicker', data); 1671 } 1672 if (typeof option === 'string' && typeof data[option] === 'function') { 1673 internal_return = data[option].apply(data, args); 1674 } 1675 }); 1676 1677 if ( 1678 internal_return === undefined || 1679 internal_return instanceof Datepicker || 1680 internal_return instanceof DateRangePicker 1681 ) 1682 return this; 1683 1684 if (this.length > 1) 1685 throw new Error('Using only allowed for the collection of a single element (' + option + ' function)'); 1686 else 1687 return internal_return; 1688 }; 1689 $.fn.datepicker = datepickerPlugin; 1690 1691 var defaults = $.fn.datepicker.defaults = { 1692 assumeNearbyYear: false, 1693 autoclose: false, 1694 beforeShowDay: $.noop, 1695 beforeShowMonth: $.noop, 1696 beforeShowYear: $.noop, 1697 beforeShowDecade: $.noop, 1698 beforeShowCentury: $.noop, 1699 calendarWeeks: false, 1700 clearBtn: false, 1701 toggleActive: false, 1702 daysOfWeekDisabled: [], 1703 daysOfWeekHighlighted: [], 1704 datesDisabled: [], 1705 endDate: Infinity, 1706 forceParse: true, 1707 format: 'mm/dd/yyyy', 1708 keepEmptyValues: false, 1709 keyboardNavigation: true, 1710 language: 'en', 1711 minViewMode: 0, 1712 maxViewMode: 4, 1713 multidate: false, 1714 multidateSeparator: ',', 1715 orientation: "auto", 1716 rtl: false, 1717 startDate: -Infinity, 1718 startView: 0, 1719 todayBtn: false, 1720 todayHighlight: false, 1721 updateViewDate: true, 1722 weekStart: 0, 1723 disableTouchKeyboard: false, 1724 enableOnReadonly: true, 1725 showOnFocus: true, 1726 zIndexOffset: 10, 1727 container: 'body', 1728 immediateUpdates: false, 1729 dateCells: false, 1730 title: '', 1731 templates: { 1732 leftArrow: '«', 1733 rightArrow: '»' 1734 } 1735 }; 1736 var locale_opts = $.fn.datepicker.locale_opts = [ 1737 'format', 1738 'rtl', 1739 'weekStart' 1740 ]; 1741 $.fn.datepicker.Constructor = Datepicker; 1742 var dates = $.fn.datepicker.dates = { 1743 en: { 1744 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], 1745 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], 1746 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"], 1747 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], 1748 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], 1749 today: "Today", 1750 clear: "Clear", 1751 titleFormat: "MM yyyy" 1752 } 1753 }; 1754 1755 var DPGlobal = { 1756 viewModes: [{ 1757 names: ['days', 'month'], 1758 clsName: 'days', 1759 e: 'changeMonth' 1760 }, 1761 { 1762 names: ['months', 'year'], 1763 clsName: 'months', 1764 e: 'changeYear', 1765 navStep: 1 1766 }, 1767 { 1768 names: ['years', 'decade'], 1769 clsName: 'years', 1770 e: 'changeDecade', 1771 navStep: 10 1772 }, 1773 { 1774 names: ['decades', 'century'], 1775 clsName: 'decades', 1776 e: 'changeCentury', 1777 navStep: 100 1778 }, 1779 { 1780 names: ['centuries', 'millennium'], 1781 clsName: 'centuries', 1782 e: 'changeMillennium', 1783 navStep: 1000 1784 } 1785 ], 1786 validParts: /dd?|DD?|mm?|MM?|yy(?:yy)?/g, 1787 nonpunctuation: /[^ -\/:-@\u5e74\u6708\u65e5\[-`{-~\t\n\r]+/g, 1788 parseFormat: function(format) { 1789 if (typeof format.toValue === 'function' && typeof format.toDisplay === 'function') 1790 return format; 1791 // IE treats \0 as a string end in inputs (truncating the value), 1792 // so it's a bad format delimiter, anyway 1793 var separators = format.replace(this.validParts, '\0').split('\0'), 1794 parts = format.match(this.validParts); 1795 if (!separators || !separators.length || !parts || parts.length === 0) { 1796 throw new Error("Invalid date format."); 1797 } 1798 return { 1799 separators: separators, 1800 parts: parts 1801 }; 1802 }, 1803 parseDate: function(date, format, language, assumeNearby) { 1804 if (!date) 1805 return undefined; 1806 if (date instanceof Date) 1807 return date; 1808 if (typeof format === 'string') 1809 format = DPGlobal.parseFormat(format); 1810 if (format.toValue) 1811 return format.toValue(date, format, language); 1812 var fn_map = { 1813 d: 'moveDay', 1814 m: 'moveMonth', 1815 w: 'moveWeek', 1816 y: 'moveYear' 1817 }, 1818 dateAliases = { 1819 yesterday: '-1d', 1820 today: '+0d', 1821 tomorrow: '+1d' 1822 }, 1823 parts, part, dir, i, fn; 1824 if (date in dateAliases) { 1825 date = dateAliases[date]; 1826 } 1827 if (/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/i.test(date)) { 1828 parts = date.match(/([\-+]\d+)([dmwy])/gi); 1829 date = new Date(); 1830 for (i = 0; i < parts.length; i++) { 1831 part = parts[i].match(/([\-+]\d+)([dmwy])/i); 1832 dir = Number(part[1]); 1833 fn = fn_map[part[2].toLowerCase()]; 1834 date = Datepicker.prototype[fn](date, dir); 1835 } 1836 return Datepicker.prototype._zero_utc_time(date); 1837 } 1838 1839 parts = date && date.match(this.nonpunctuation) || []; 1840 1841 function applyNearbyYear(year, threshold) { 1842 if (threshold === true) 1843 threshold = 10; 1844 1845 // if year is 2 digits or less, than the user most likely is trying to get a recent century 1846 if (year < 100) { 1847 year += 2000; 1848 // if the new year is more than threshold years in advance, use last century 1849 if (year > ((new Date()).getFullYear() + threshold)) { 1850 year -= 100; 1851 } 1852 } 1853 1854 return year; 1855 } 1856 1857 var parsed = {}, 1858 setters_order = ['yyyy', 'yy', 'M', 'MM', 'm', 'mm', 'd', 'dd'], 1859 setters_map = { 1860 yyyy: function(d, v) { 1861 return d.setUTCFullYear(assumeNearby ? applyNearbyYear(v, assumeNearby) : v); 1862 }, 1863 m: function(d, v) { 1864 if (isNaN(d)) 1865 return d; 1866 v -= 1; 1867 while (v < 0) v += 12; 1868 v %= 12; 1869 d.setUTCMonth(v); 1870 while (d.getUTCMonth() !== v) 1871 d.setUTCDate(d.getUTCDate() - 1); 1872 return d; 1873 }, 1874 d: function(d, v) { 1875 return d.setUTCDate(v); 1876 } 1877 }, 1878 val, filtered; 1879 setters_map['yy'] = setters_map['yyyy']; 1880 setters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m']; 1881 setters_map['dd'] = setters_map['d']; 1882 date = UTCToday(); 1883 var fparts = format.parts.slice(); 1884 // Remove noop parts 1885 if (parts.length !== fparts.length) { 1886 fparts = $(fparts).filter(function(i, p) { 1887 return $.inArray(p, setters_order) !== -1; 1888 }).toArray(); 1889 } 1890 // Process remainder 1891 function match_part() { 1892 var m = this.slice(0, parts[i].length), 1893 p = parts[i].slice(0, m.length); 1894 return m.toLowerCase() === p.toLowerCase(); 1895 } 1896 if (parts.length === fparts.length) { 1897 var cnt; 1898 for (i = 0, cnt = fparts.length; i < cnt; i++) { 1899 val = parseInt(parts[i], 10); 1900 part = fparts[i]; 1901 if (isNaN(val)) { 1902 switch (part) { 1903 case 'MM': 1904 filtered = $(dates[language].months).filter(match_part); 1905 val = $.inArray(filtered[0], dates[language].months) + 1; 1906 break; 1907 case 'M': 1908 filtered = $(dates[language].monthsShort).filter(match_part); 1909 val = $.inArray(filtered[0], dates[language].monthsShort) + 1; 1910 break; 1911 } 1912 } 1913 parsed[part] = val; 1914 } 1915 var _date, s; 1916 for (i = 0; i < setters_order.length; i++) { 1917 s = setters_order[i]; 1918 if (s in parsed && !isNaN(parsed[s])) { 1919 _date = new Date(date); 1920 setters_map[s](_date, parsed[s]); 1921 if (!isNaN(_date)) 1922 date = _date; 1923 } 1924 } 1925 } 1926 return date; 1927 }, 1928 formatDate: function(date, format, language) { 1929 if (!date) 1930 return ''; 1931 if (typeof format === 'string') 1932 format = DPGlobal.parseFormat(format); 1933 if (format.toDisplay) 1934 return format.toDisplay(date, format, language); 1935 var val = { 1936 d: date.getUTCDate(), 1937 D: dates[language].daysShort[date.getUTCDay()], 1938 DD: dates[language].days[date.getUTCDay()], 1939 m: date.getUTCMonth() + 1, 1940 M: dates[language].monthsShort[date.getUTCMonth()], 1941 MM: dates[language].months[date.getUTCMonth()], 1942 yy: date.getUTCFullYear().toString().substring(2), 1943 yyyy: date.getUTCFullYear() 1944 }; 1945 val.dd = (val.d < 10 ? '0' : '') + val.d; 1946 val.mm = (val.m < 10 ? '0' : '') + val.m; 1947 date = []; 1948 var seps = $.extend([], format.separators); 1949 for (var i = 0, cnt = format.parts.length; i <= cnt; i++) { 1950 if (seps.length) 1951 date.push(seps.shift()); 1952 date.push(val[format.parts[i]]); 1953 } 1954 return date.join(''); 1955 }, 1956 headTemplate: '<thead>' + 1957 '<tr>' + 1958 '<th colspan="7" class="datepicker-title"></th>' + 1959 '</tr>' + 1960 '<tr>' + 1961 '<th class="prev">«</th>' + 1962 '<th colspan="5" class="datepicker-switch"></th>' + 1963 '<th class="next">»</th>' + 1964 '</tr>' + 1965 '</thead>', 1966 contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>', 1967 footTemplate: '<tfoot>' + 1968 '<tr>' + 1969 '<th colspan="7" class="today"></th>' + 1970 '</tr>' + 1971 '<tr>' + 1972 '<th colspan="7" class="clear"></th>' + 1973 '</tr>' + 1974 '</tfoot>' 1975 }; 1976 DPGlobal.template = '<div class="datepicker">' + 1977 '<div class="datepicker-days">' + 1978 '<table class="table-condensed">' + 1979 DPGlobal.headTemplate + 1980 '<tbody></tbody>' + 1981 DPGlobal.footTemplate + 1982 '</table>' + 1983 '</div>' + 1984 '<div class="datepicker-months">' + 1985 '<table class="table-condensed">' + 1986 DPGlobal.headTemplate + 1987 DPGlobal.contTemplate + 1988 DPGlobal.footTemplate + 1989 '</table>' + 1990 '</div>' + 1991 '<div class="datepicker-years">' + 1992 '<table class="table-condensed">' + 1993 DPGlobal.headTemplate + 1994 DPGlobal.contTemplate + 1995 DPGlobal.footTemplate + 1996 '</table>' + 1997 '</div>' + 1998 '<div class="datepicker-decades">' + 1999 '<table class="table-condensed">' + 2000 DPGlobal.headTemplate + 2001 DPGlobal.contTemplate + 2002 DPGlobal.footTemplate + 2003 '</table>' + 2004 '</div>' + 2005 '<div class="datepicker-centuries">' + 2006 '<table class="table-condensed">' + 2007 DPGlobal.headTemplate + 2008 DPGlobal.contTemplate + 2009 DPGlobal.footTemplate + 2010 '</table>' + 2011 '</div>' + 2012 '</div>'; 2013 2014 $.fn.datepicker.DPGlobal = DPGlobal; 2015 2016 2017 /* DATEPICKER NO CONFLICT 2018 * =================== */ 2019 2020 $.fn.datepicker.noConflict = function() { 2021 $.fn.datepicker = old; 2022 return this; 2023 }; 2024 2025 /* DATEPICKER VERSION 2026 * =================== */ 2027 $.fn.datepicker.version = '1.7.0-dev'; 2028 2029 $.fn.datepicker.deprecated = function(msg) { 2030 var console = window.console; 2031 if (console && console.warn) { 2032 console.warn('DEPRECATED: ' + msg); 2033 } 2034 }; 2035 2036 2037 /* DATEPICKER DATA-API 2038 * ================== */ 2039 2040 $(document).on(
2041 'focus.datepicker.data-api click.datepicker.data-api', 2042 '[data-provide="datepicker"]', 2043 function(e) { 2044 var $this = $(this); 2045 if ($this.data('datepicker')) 2046 return; 2047 e.preventDefault(); 2048 // component click requires us to explicitly show it 2049 datepickerPlugin.call($this, 'show'); 2050 } 2051 ); 2052 $(function() { 2053 datepickerPlugin.call($('[data-provide="datepicker-inline"]')); 2054 }); 2055 2056}));
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.