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